From 80378101101ca1762bbf5638a9e3566893096d8a Mon Sep 17 00:00:00 2001 From: TTimo Date: Wed, 12 Sep 2007 18:54:28 +0000 Subject: [PATCH] transfer from internal tree r5311 branches/1.4-gpl git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant@177 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- BSD | 28 + CHANGES-MACOS | 11 + COMPILING | 7 + CONTRIBUTORS | 65 + CONTRIBUTOR_AGREEMENT | 0 DarwinCompileInfo.rtf | 55 + DoxyConfig | 47 + Doxyfile | 170 + Doxygen_files/Doxyfile | 159 + Doxygen_files/doxy_mainpage.h | 45 + Doxygen_files/doxygen_gtkradiant.css | 34 + Doxygen_files/doxygen_gtkradiant_foot.html | 49 + Doxygen_files/doxygen_gtkradiant_head.html | 38 + Doxygen_files/doxygen_index.html | 7 + Doxygen_files/doxygen_reference_foot.html | 46 + Doxygen_files/doxygen_reference_head.html | 38 + Doxygen_files/example/annotated.html | 103 + .../example/classIEpair-members.html | 110 + Doxygen_files/example/classIEpair.html | 414 + Doxygen_files/example/classes.html | 103 + Doxygen_files/example/doxygen.gif | Bin 0 -> 2378 bytes Doxygen_files/example/doxygen_gtkradiant.css | 35 + Doxygen_files/example/files.html | 102 + Doxygen_files/example/functions.html | 110 + Doxygen_files/example/graph_legend.dot | 16 + Doxygen_files/example/graph_legend.gif | Bin 0 -> 9344 bytes Doxygen_files/example/graph_legend.html | 141 + Doxygen_files/example/index.html | 102 + Doxygen_files/example/pages.html | 104 + Doxygen_files/example/test_8c-source.html | 140 + Doxygen_files/example/test_8c.html | 107 + Doxygen_files/example/todo.html | 105 + Doxygen_files/genDoxyfile | 159 + Doxygen_files/gendoxfunctions | 421 + Doxygen_files/images/body-left-tile.gif | Bin 0 -> 94 bytes Doxygen_files/images/body-lower-left.gif | Bin 0 -> 366 bytes Doxygen_files/images/body-lower-right.gif | Bin 0 -> 352 bytes Doxygen_files/images/body-lower-tile.gif | Bin 0 -> 67 bytes Doxygen_files/images/body-right-tile.gif | Bin 0 -> 94 bytes Doxygen_files/images/body-upper-left.gif | Bin 0 -> 358 bytes Doxygen_files/images/body-upper-right.gif | Bin 0 -> 362 bytes Doxygen_files/images/body-upper-tile.gif | Bin 0 -> 92 bytes Doxygen_files/images/gtkr_splash.jpg | Bin 0 -> 25053 bytes Doxygen_files/images/gtkr_splash_sm.jpg | Bin 0 -> 7599 bytes Doxygen_files/images/history_id_logo.gif | Bin 0 -> 1427 bytes Doxygen_files/images/top-right.gif | Bin 0 -> 606 bytes Doxygen_files/images/top-tile.gif | Bin 0 -> 122 bytes Doxygen_files/images/top-title.gif | Bin 0 -> 5356 bytes Doxygen_files/reference1.html | 333 + GPL | 280 + GtkRadiant.prj | 688 + INSTALL.txt | 7 + LGPL | 458 + LICENSE | 36 + LICENSE_ID | 0 README | 49 + README.doxygen | 51 + SConscript | 839 + SConstruct | 291 + contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp | Bin 0 -> 216 bytes .../bkgrnd2d/bitmaps/bkgrnd2d_xy_toggle.bmp | Bin 0 -> 220 bytes .../bkgrnd2d/bitmaps/bkgrnd2d_xz_toggle.bmp | Bin 0 -> 220 bytes .../bkgrnd2d/bitmaps/bkgrnd2d_yz_toggle.bmp | Bin 0 -> 220 bytes contrib/bkgrnd2d/bkgrnd2d.cpp | 319 + contrib/bkgrnd2d/bkgrnd2d.def | 8 + contrib/bkgrnd2d/bkgrnd2d.h | 83 + contrib/bkgrnd2d/bkgrnd2d.vcproj | 75 + contrib/bkgrnd2d/dialog.cpp | 365 + contrib/bkgrnd2d/dialog.h | 36 + contrib/bkgrnd2d/plugin.cpp | 320 + contrib/bkgrnd2d/plugin.h | 80 + contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt | 131 + contrib/bobtoolz/CPortals.h | 63 + contrib/bobtoolz/DBobView.cpp | 361 + contrib/bobtoolz/DBobView.h | 72 + contrib/bobtoolz/DBrush.cpp | 848 + contrib/bobtoolz/DBrush.h | 101 + contrib/bobtoolz/DEPair.cpp | 49 + contrib/bobtoolz/DEPair.h | 45 + contrib/bobtoolz/DEntity.cpp | 675 + contrib/bobtoolz/DEntity.h | 115 + contrib/bobtoolz/DListener.cpp | 93 + contrib/bobtoolz/DListener.h | 62 + contrib/bobtoolz/DMap.cpp | 166 + contrib/bobtoolz/DMap.h | 56 + contrib/bobtoolz/DPatch.cpp | 414 + contrib/bobtoolz/DPatch.h | 62 + contrib/bobtoolz/DPlane.cpp | 256 + contrib/bobtoolz/DPlane.h | 67 + contrib/bobtoolz/DPoint.cpp | 52 + contrib/bobtoolz/DPoint.h | 45 + contrib/bobtoolz/DShape.cpp | 459 + contrib/bobtoolz/DShape.h | 60 + contrib/bobtoolz/DTrainDrawer.cpp | 358 + contrib/bobtoolz/DTrainDrawer.h | 82 + contrib/bobtoolz/DTreePlanter.cpp | 287 + contrib/bobtoolz/DTreePlanter.h | 223 + contrib/bobtoolz/DVisDrawer.cpp | 179 + contrib/bobtoolz/DVisDrawer.h | 58 + contrib/bobtoolz/DWinding.cpp | 483 + contrib/bobtoolz/DWinding.h | 68 + contrib/bobtoolz/ScriptParser.cpp | 267 + contrib/bobtoolz/ScriptParser.h | 41 + contrib/bobtoolz/StdAfx.cpp | 25 + contrib/bobtoolz/StdAfx.h | 154 + contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp | Bin 0 -> 320 bytes contrib/bobtoolz/bitmaps/bobtoolz_cleanup.bmp | Bin 0 -> 316 bytes contrib/bobtoolz/bitmaps/bobtoolz_dropent.bmp | Bin 0 -> 312 bytes contrib/bobtoolz/bitmaps/bobtoolz_merge.bmp | Bin 0 -> 312 bytes contrib/bobtoolz/bitmaps/bobtoolz_poly.bmp | Bin 0 -> 320 bytes contrib/bobtoolz/bitmaps/bobtoolz_split.bmp | Bin 0 -> 312 bytes .../bitmaps/bobtoolz_trainpathplot.bmp | Bin 0 -> 324 bytes .../bobtoolz/bitmaps/bobtoolz_treeplanter.bmp | Bin 0 -> 356 bytes .../bobtoolz/bitmaps/bobtoolz_turnedge.bmp | Bin 0 -> 332 bytes contrib/bobtoolz/bobToolz-GTK.cpp | 292 + contrib/bobtoolz/bobToolz.def | 8 + contrib/bobtoolz/bobToolz.h | 64 + contrib/bobtoolz/bobToolz.rc | 533 + contrib/bobtoolz/bobToolz_gtk.vcproj | 177 + contrib/bobtoolz/bobtoolz-gtk.rc | 109 + contrib/bobtoolz/bsploader.cpp | 258 + contrib/bobtoolz/bsploader.h | 134 + contrib/bobtoolz/bt/bt-el1.txt | 17 + contrib/bobtoolz/bt/bt-el2.txt | 0 contrib/bobtoolz/bt/ctf-blue.txt | 61 + contrib/bobtoolz/bt/ctf-red.txt | 61 + contrib/bobtoolz/bt/door-tex-trim.txt | 5 + contrib/bobtoolz/bt/door-tex.txt | 10 + contrib/bobtoolz/bt/tp_ent.txt | 14 + contrib/bobtoolz/cportals.cpp | 340 + contrib/bobtoolz/ctfToolz-GTK.cpp | 97 + contrib/bobtoolz/ctfresource_gtk.h | 34 + contrib/bobtoolz/ctfresource_gtk.rc | 109 + contrib/bobtoolz/ctftoolz.def | 12 + contrib/bobtoolz/dialogs/AboutDialog.cpp | 62 + contrib/bobtoolz/dialogs/AboutDialog.h | 64 + contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp | 63 + contrib/bobtoolz/dialogs/AutoCaulkDialog.h | 66 + .../bobtoolz/dialogs/AutoCaulkStartDialog.cpp | 66 + .../bobtoolz/dialogs/AutoCaulkStartDialog.h | 71 + contrib/bobtoolz/dialogs/BrushCheckDialog.h | 65 + contrib/bobtoolz/dialogs/DoorDialog.cpp | 92 + contrib/bobtoolz/dialogs/DoorDialog.h | 74 + contrib/bobtoolz/dialogs/IntersectDialog.cpp | 65 + contrib/bobtoolz/dialogs/IntersectDialog.h | 70 + .../bobtoolz/dialogs/IntersectInfoDialog.cpp | 61 + .../bobtoolz/dialogs/IntersectInfoDialog.h | 65 + contrib/bobtoolz/dialogs/PolygonDialog.cpp | 116 + contrib/bobtoolz/dialogs/PolygonDialog.h | 74 + contrib/bobtoolz/dialogs/StairDialog.cpp | 105 + contrib/bobtoolz/dialogs/StairDialog.h | 74 + .../bobtoolz/dialogs/TextureResetDialog.cpp | 81 + contrib/bobtoolz/dialogs/TextureResetDialog.h | 73 + contrib/bobtoolz/dialogs/brushcheckdialog.cpp | 61 + contrib/bobtoolz/dialogs/dialogs-gtk.cpp | 1894 + contrib/bobtoolz/dialogs/dialogs-gtk.h | 98 + .../bobtoolz/dialogs/pathplotterdialog.cpp | 85 + contrib/bobtoolz/dialogs/pathplotterdialog.h | 70 + contrib/bobtoolz/funchandlers-GTK.cpp | 800 + contrib/bobtoolz/funchandlers-ctf-GTK.cpp | 214 + contrib/bobtoolz/funchandlers.cpp | 503 + contrib/bobtoolz/funchandlers.h | 72 + contrib/bobtoolz/interfaces/IScriptParser.h | 23 + contrib/bobtoolz/lists.cpp | 85 + contrib/bobtoolz/lists.h | 21 + contrib/bobtoolz/misc.cpp | 424 + contrib/bobtoolz/misc.h | 48 + contrib/bobtoolz/res/plugin.rc2 | 13 + contrib/bobtoolz/resource-gtk.h | 15 + contrib/bobtoolz/resource.h | 115 + contrib/bobtoolz/shapes.cpp | 666 + contrib/bobtoolz/shapes.h | 49 + contrib/bobtoolz/txt/changelog.txt | 96 + contrib/bobtoolz/txt/readme.txt | 77 + contrib/bobtoolz/visfind.cpp | 245 + contrib/bobtoolz/visfind.h | 1 + contrib/camera/bitmaps/camera_insp.bmp | Bin 0 -> 320 bytes contrib/camera/camera.cpp | 292 + contrib/camera/camera.def | 8 + contrib/camera/camera.h | 162 + contrib/camera/camera.vcproj | 89 + contrib/camera/dialogs.cpp | 1352 + contrib/camera/dialogs.h | 37 + contrib/camera/dialogs_common.cpp | 51 + contrib/camera/funchandlers.cpp | 272 + contrib/camera/funchandlers.h | 37 + contrib/camera/listener.cpp | 234 + contrib/camera/listener.h | 64 + contrib/camera/misc.cpp | 243 + contrib/camera/misc.h | 91 + contrib/camera/renderer.cpp | 183 + contrib/camera/renderer.h | 46 + contrib/gtkgensurf/.cvsignore | 4 + contrib/gtkgensurf/CHANGES | 73 + contrib/gtkgensurf/bitmap.cpp | 434 + contrib/gtkgensurf/dec.cpp | 1328 + contrib/gtkgensurf/face.cpp | 450 + contrib/gtkgensurf/font.cpp | 270 + contrib/gtkgensurf/gendlgs.cpp | 2364 + contrib/gtkgensurf/gendlgs.h | 151 + contrib/gtkgensurf/genmap.cpp | 2056 + contrib/gtkgensurf/gensurf.cpp | 467 + contrib/gtkgensurf/gensurf.def | 8 + contrib/gtkgensurf/gensurf.h | 395 + contrib/gtkgensurf/gtkgensurf.vcproj | 91 + contrib/gtkgensurf/heretic.cpp | 150 + contrib/gtkgensurf/plugin.cpp | 227 + contrib/gtkgensurf/triangle.c | 13236 +++ contrib/gtkgensurf/triangle.h | 288 + contrib/gtkgensurf/view.cpp | 1287 + contrib/hydratoolz/hydratoolz.def | 8 + contrib/hydratoolz/hydratoolz.vcproj | 67 + contrib/hydratoolz/plugin.cpp | 412 + contrib/hydratoolz/plugin.h | 51 + contrib/prtview/.cvsignore | 8 + contrib/prtview/AboutDialog.cpp | 139 + contrib/prtview/AboutDialog.h | 72 + contrib/prtview/ConfigDialog.cpp | 925 + contrib/prtview/ConfigDialog.h | 107 + contrib/prtview/LoadPortalFileDialog.cpp | 288 + contrib/prtview/LoadPortalFileDialog.h | 77 + contrib/prtview/PrtView.aps | Bin 0 -> 21916 bytes contrib/prtview/PrtView.def | 8 + contrib/prtview/PrtView.rc | 264 + contrib/prtview/PrtView.txt | 12 + contrib/prtview/PrtView.vcproj | 103 + contrib/prtview/gtkdlgs.cpp | 732 + contrib/prtview/gtkdlgs.h | 27 + contrib/prtview/portals.cpp | 802 + contrib/prtview/portals.h | 125 + contrib/prtview/prtview.cpp | 543 + contrib/prtview/prtview.h | 29 + contrib/prtview/res/PrtView.rc2 | 13 + contrib/prtview/resource.h | 42 + contrib/prtview/stdafx.cpp | 25 + contrib/prtview/stdafx.h | 79 + docs/developer/.cvsignore | 1 + docs/developer/CHANGES | 5616 + docs/developer/DRAFT | 130 + docs/developer/HEAP | 33 + docs/developer/Inspector/Inspectors.argo | 76 + docs/developer/Inspector/Inspectors.xmi | 247 + .../Inspector/Inspectors_classdiagram1.pgml | 571 + .../Inspectors_collaborationdiagram1.pgml | 6 + .../Inspector/Inspectors_usecasediagram1.pgml | 6 + docs/developer/Inspector/classdiagram1.gif | Bin 0 -> 6693 bytes .../Inspector/collaborationdiagram1.pgml | 6 + docs/developer/Inspector/inspector.txt | 266 + docs/developer/RegExp/Go | 92 + docs/developer/RegExp/Go.cleaned | 92 + docs/developer/RegExp/pattern | 4 + docs/developer/RegExp/replace.pl | 17 + docs/developer/RegExp/tstscrpt.pl | 17 + docs/developer/TESTERS | 19 + docs/developer/TODO | 123 + docs/developer/TstMaps/Desktop_pb_leaf.map | 9221 ++ docs/developer/TstMaps/komap1.map | 3452 + docs/developer/TstMaps/realloc.map | 4661 + docs/developer/TstMaps/sput.map | 1887 + docs/developer/TstMaps/ttq3dm3.map | 1099 + docs/developer/TstMaps/western.map | 5062 + docs/developer/UML/modules.zargo | Bin 0 -> 4763 bytes docs/developer/WIN32BETA | 247 + docs/developer/WIN32SETUP | 36 + docs/developer/XML.txt | 27 + docs/developer/XMLPush/ReadMe.txt | 34 + docs/developer/XMLPush/StdAfx.cpp | 8 + docs/developer/XMLPush/StdAfx.h | 22 + docs/developer/XMLPush/XMLDump.xml | 8 + docs/developer/XMLPush/XMLPush.cpp | 30 + docs/developer/XMLmap.txt | 27 + docs/developer/changes.201.202 | 455 + docs/developer/d2u | 17 + docs/developer/data-driven-design.txt | 76 + docs/developer/frp | 6 + docs/developer/q3mapfeedback.txt | 33 + .../Q3Rad_Manual_files/image002.png | Bin 0 -> 10232 bytes .../Q3Rad_Manual_files/image003.png | Bin 0 -> 12471 bytes .../Q3Rad_Manual_files/image004.png | Bin 0 -> 262 bytes .../Q3Rad_Manual_files/image006.png | Bin 0 -> 266 bytes .../Q3Rad_Manual_files/image008.png | Bin 0 -> 249 bytes .../Q3Rad_Manual_files/image010.png | Bin 0 -> 265 bytes .../Q3Rad_Manual_files/image012.png | Bin 0 -> 430 bytes .../Q3Rad_Manual_files/image014.png | Bin 0 -> 207 bytes .../Q3Rad_Manual_files/image016.png | Bin 0 -> 216 bytes .../Q3Rad_Manual_files/image018.png | Bin 0 -> 234 bytes .../Q3Rad_Manual_files/image020.png | Bin 0 -> 211 bytes .../Q3Rad_Manual_files/image022.png | Bin 0 -> 186 bytes .../Q3Rad_Manual_files/image024.png | Bin 0 -> 189 bytes .../Q3Rad_Manual_files/image026.png | Bin 0 -> 258 bytes .../Q3Rad_Manual_files/image028.png | Bin 0 -> 7249 bytes .../Q3Rad_Manual_files/image030.png | Bin 0 -> 241 bytes .../Q3Rad_Manual_files/image032.png | Bin 0 -> 3057 bytes .../Q3Rad_Manual_files/image034.png | Bin 0 -> 1097 bytes .../Q3Rad_Manual_files/image035.png | Bin 0 -> 6455 bytes .../Q3Rad_Manual_files/image038.png | Bin 0 -> 18912 bytes .../Q3Rad_Manual_files/image040.png | Bin 0 -> 241 bytes docs/manual/Q3Rad_Manual/appndx/appn_a.htm | 56 + docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm | 228 + docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm | 651 + docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm | 150 + docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm | 209 + docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm | 487 + docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm | 332 + docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm | 637 + docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm | 352 + docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm | 224 + docs/manual/Q3Rad_Manual/appndx/appn_c.htm | 654 + docs/manual/Q3Rad_Manual/appndx/appn_d.htm | 243 + docs/manual/Q3Rad_Manual/appndx/appn_e.htm | 225 + docs/manual/Q3Rad_Manual/appndx/appn_f.htm | 144 + docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm | 977 + docs/manual/Q3Rad_Manual/ch01/pg1_1.htm | 179 + docs/manual/Q3Rad_Manual/ch01/pg1_2.htm | 391 + docs/manual/Q3Rad_Manual/ch02/pg2_1.htm | 213 + docs/manual/Q3Rad_Manual/ch03/pg3_1.htm | 265 + docs/manual/Q3Rad_Manual/ch04/pg4_1.htm | 174 + docs/manual/Q3Rad_Manual/ch05/pg5_1.htm | 784 + docs/manual/Q3Rad_Manual/ch06/pg6_1.htm | 624 + docs/manual/Q3Rad_Manual/ch07/pg7_1.htm | 945 + docs/manual/Q3Rad_Manual/ch08/pg8_1.htm | 347 + docs/manual/Q3Rad_Manual/ch09/pg9_1.htm | 87 + docs/manual/Q3Rad_Manual/ch10/pg10_1.htm | 858 + docs/manual/Q3Rad_Manual/ch11/pg11_1.htm | 116 + docs/manual/Q3Rad_Manual/ch12/pg12_1.htm | 285 + docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm | 69 + docs/manual/Q3Rad_Manual/index.htm | 180 + docs/manual/Q3Rad_Manual/styles/q3rad.css | 23 + docs/manual/quake3/Compile_Manual/bspc.txt | 565 + docs/manual/quake3/Compile_Manual/cfgq3.c | 78 + .../quake3/Compile_Manual/headskins.txt | 75 + docs/manual/quake3/Compile_Manual/index.html | 65 + .../quake3/Compile_Manual/modelskins.txt | 73 + docs/manual/quake3/Compile_Manual/q3map.html | 410 + .../quake3/Model_Manual/model_manual.htm | 217 + .../quake3/Model_Manual/styles/q3rad.css | 23 + .../quake3/New_Teams_For_Q3TA/index.html | 2258 + .../Q3AShader_Manual/appendix/appA.html | 60 + .../quake3/Q3AShader_Manual/ch01/pg1_1.htm | 126 + .../quake3/Q3AShader_Manual/ch02/pg2_1.htm | 222 + .../quake3/Q3AShader_Manual/ch03/pg3_1.htm | 197 + .../quake3/Q3AShader_Manual/ch04/pg4_1.htm | 64 + .../quake3/Q3AShader_Manual/ch05/pg5_1.htm | 483 + .../quake3/Q3AShader_Manual/ch06/pg6_1.htm | 145 + docs/manual/quake3/Q3AShader_Manual/index.htm | 76 + .../q3ashader_manual_files/image002.jpg | Bin 0 -> 26981 bytes .../quake3/Q3AShader_Manual/styles/q3rad.css | 23 + .../pages/design_tips.html | 113 + .../pages/map_converters_checklist.html | 101 + .../pages/preface.html | 40 + .../pages/related_links.html | 51 + .../pages/ta_game_types.html | 199 + .../pages/table_of_contents.htm | 77 + .../pages/team_arena_entity_definitions.html | 66 + .../pages/team_arena_prefabs.html | 96 + .../pages/team_powerup_bases.html | 62 + .../pages/using_new_game_entities.html | 115 + .../Team_Arena_Mapping_Help/pics/CRUSADER.gif | Bin 0 -> 4292 bytes .../Team_Arena_Mapping_Help/pics/INTRUDER.gif | Bin 0 -> 4732 bytes .../Team_Arena_Mapping_Help/pics/MAINPOP.gif | Bin 0 -> 25903 bytes .../pics/MENUBACKgif.gif | Bin 0 -> 21338 bytes .../Team_Arena_Mapping_Help/pics/PAGANs.gif | Bin 0 -> 3861 bytes .../Team_Arena_Mapping_Help/pics/STROGGS.gif | Bin 0 -> 4884 bytes .../pics/THEFALLEN.gif | Bin 0 -> 5367 bytes .../Team_Arena_Mapping_Help/pics/logo.gif | Bin 0 -> 42182 bytes .../quake3/Team_Arena_Mapping_Help/start.html | 30 + .../quake3/Terrain_Manual/pages/Image3.gif | Bin 0 -> 46899 bytes .../quake3/Terrain_Manual/pages/Image4.gif | Bin 0 -> 24307 bytes .../quake3/Terrain_Manual/pages/Image5.gif | Bin 0 -> 27694 bytes .../quake3/Terrain_Manual/pages/Image6.gif | Bin 0 -> 46899 bytes .../Terrain_Manual/pages/adding_bots.html | 40 + .../pages/adding_buildings_to_terrain.html | 85 + .../Terrain_Manual/pages/art_tools.html | 39 + .../Terrain_Manual/pages/blocking_vis.html | 101 + .../pages/boxing_in_the_world.html | 48 + .../pages/clipping_the_terrain.html | 58 + .../pages/creating_the_alphamap.html | 194 + .../pages/creating_the_terrain.html | 63 + .../pages/entity_keys_and_values.html | 102 + .../quake3/Terrain_Manual/pages/glossary.html | 52 + .../pages/height_map_into_terrain_mesh.html | 41 + .../Terrain_Manual/pages/height_maps.html | 174 + .../Terrain_Manual/pages/introduction.html | 49 + .../Terrain_Manual/pages/key_changes.html | 64 + .../pages/lighting_the_terrain.html | 135 + .../pages/manipulating_the_terrain_mesh.html | 42 + .../pages/mapping_the_textures.html | 71 + .../new_or_revised_q3map_shader_comm.html | 361 + .../other_possible_height_map_tools.html | 62 + .../Terrain_Manual/pages/related_links.html | 40 + .../pages/suggested_gensurf_settings.html | 135 + .../pages/table_of_contents.html | 88 + .../Terrain_Manual/pages/terrain_entity.html | 50 + .../terrain_mesh_into_terrain_entity.html | 44 + .../terrain_related_worldspawn_features.html | 222 + .../Terrain_Manual/pages/terrain_texture.html | 65 + .../Terrain_Manual/pages/the_meta_shader.html | 192 + .../quake3/Terrain_Manual/pics/background.jpg | Bin 0 -> 31101 bytes .../quake3/Terrain_Manual/pics/start.gif | Bin 0 -> 218030 bytes .../quake3/Terrain_Manual/pics/terrain.jpg | Bin 0 -> 25120 bytes docs/manual/quake3/Terrain_Manual/start.html | 30 + gen.readme | 4 + gen.vcproj | 71 + gendox | 150 + include/.cvsignore | 8 + include/aboutmsg.default | 1 + include/aboutmsg.h | 2 + include/gtkr_list.h | 23 + include/gtkr_vector.h | 23 + include/ibrush.h | 73 + include/ibspfrontend.h | 77 + include/icamera.h | 45 + include/idata.h | 57 + include/idatastream.h | 71 + include/ieclass.h | 84 + include/ientity.h | 116 + include/ifilesystem.h | 140 + include/igl.h | 266 + include/iimage.h | 40 + include/imap.h | 82 + include/imodel.h | 106 + include/ipatch.h | 53 + include/iplugin.h | 41 + include/irefcount.h | 62 + include/iscriplib.h | 86 + include/iselectedface.h | 88 + include/ishaders.h | 284 + include/ishadersmanager.h | 102 + include/isurfaceplugin.h | 158 + include/itoolbar.h | 61 + include/iui.h | 158 + include/iui_gtk.h | 59 + include/iundo.h | 87 + include/misc_def.h | 64 + include/qerplugin.h | 787 + include/qertypes.h | 911 + include/qsysprintf.h | 67 + include/stl_check.h | 60 + include/stream_version.h | 3 + include/version.default | 1 + include/version.h | 4 + install.py | 48 + libs/.cvsignore | 1 + libs/bytebool.h | 20 + libs/cmdlib.h | 111 + libs/cmdlib/.cvsignore | 1 + libs/cmdlib/.cvswrappers | 3 + libs/cmdlib/cmdlib.cpp | 496 + libs/cmdlib/cmdlib.vcproj | 53 + libs/ddslib.h | 250 + libs/ddslib/ddslib.c | 781 + libs/ddslib/ddslib.vcproj | 57 + libs/igl_to_qgl.h | 806 + libs/jpeg6/.cvsignore | 8 + libs/jpeg6/.cvswrappers | 3 + libs/jpeg6/jchuff.h | 68 + libs/jpeg6/jcomapi.cpp | 188 + libs/jpeg6/jconfig.h | 82 + libs/jpeg6/jdapimin.cpp | 800 + libs/jpeg6/jdapistd.cpp | 550 + libs/jpeg6/jdatasrc.cpp | 215 + libs/jpeg6/jdcoefct.cpp | 1450 + libs/jpeg6/jdcolor.cpp | 734 + libs/jpeg6/jdct.h | 352 + libs/jpeg6/jddctmgr.cpp | 540 + libs/jpeg6/jdhuff.cpp | 574 + libs/jpeg6/jdhuff.h | 202 + libs/jpeg6/jdinput.cpp | 762 + libs/jpeg6/jdmainct.cpp | 1024 + libs/jpeg6/jdmarker.cpp | 1052 + libs/jpeg6/jdmaster.cpp | 558 + libs/jpeg6/jdpostct.cpp | 580 + libs/jpeg6/jdsample.cpp | 956 + libs/jpeg6/jdtrans.cpp | 244 + libs/jpeg6/jerror.cpp | 233 + libs/jpeg6/jerror.h | 278 + libs/jpeg6/jfdctflt.cpp | 336 + libs/jpeg6/jidctflt.cpp | 482 + libs/jpeg6/jinclude.h | 91 + libs/jpeg6/jmemmgr.cpp | 2230 + libs/jpeg6/jmemnobs.cpp | 206 + libs/jpeg6/jmemsys.h | 364 + libs/jpeg6/jmorecfg.h | 693 + libs/jpeg6/jpeg6.vcproj | 113 + libs/jpeg6/jpegint.h | 776 + libs/jpeg6/jpgload.cpp | 167 + libs/jpeg6/jutils.cpp | 350 + libs/jpeg6/jversion.h | 28 + libs/jpeglib.h | 1123 + libs/l_net/.cvsignore | 5 + libs/l_net/l_net.c | 627 + libs/l_net/l_net.h | 125 + libs/l_net/l_net.vcproj | 61 + libs/l_net/l_net_berkley.c | 770 + libs/l_net/l_net_wins.c | 789 + libs/l_net/l_net_wins.h | 52 + libs/mathlib.h | 305 + libs/mathlib/bbox.c | 391 + libs/mathlib/linear.c | 100 + libs/mathlib/m4x4.c | 790 + libs/mathlib/mathlib.c | 593 + libs/mathlib/mathlib.vcproj | 65 + libs/mathlib/ray.c | 135 + libs/md5lib.h | 91 + libs/md5lib/Conscript | 11 + libs/md5lib/md5lib.c | 395 + libs/md5lib/md5lib.vcproj | 57 + libs/missing.h | 212 + libs/multimon.h | 381 + libs/pak/.cvsignore | 1 + libs/pak/.cvswrappers | 3 + libs/pak/pakstuff.cpp | 979 + libs/pak/unzip.cpp | 4534 + libs/pak/unzip.h | 300 + libs/pakstuff.h | 150 + libs/picomodel.h | 345 + libs/picomodel/lwo/clip.c | 249 + libs/picomodel/lwo/envelope.c | 600 + libs/picomodel/lwo/list.c | 101 + libs/picomodel/lwo/lwio.c | 442 + libs/picomodel/lwo/lwo2.c | 308 + libs/picomodel/lwo/lwo2.h | 651 + libs/picomodel/lwo/lwob.c | 723 + libs/picomodel/lwo/pntspols.c | 537 + libs/picomodel/lwo/surface.c | 1004 + libs/picomodel/lwo/vecmath.c | 37 + libs/picomodel/lwo/vmap.c | 243 + libs/picomodel/picointernal.c | 1353 + libs/picomodel/picointernal.h | 205 + libs/picomodel/picomodel.c | 1995 + libs/picomodel/picomodel.vcproj | 107 + libs/picomodel/picomodules.c | 92 + libs/picomodel/pm_3ds.c | 771 + libs/picomodel/pm_ase.c | 1001 + libs/picomodel/pm_fm.c | 670 + libs/picomodel/pm_fm.h | 367 + libs/picomodel/pm_lwo.c | 430 + libs/picomodel/pm_md2.c | 670 + libs/picomodel/pm_md3.c | 425 + libs/picomodel/pm_mdc.c | 750 + libs/picomodel/pm_ms3d.c | 494 + libs/picomodel/pm_obj.c | 858 + libs/radiant_jpeglib.h | 1123 + libs/splines/.cvsignore | 1 + libs/splines/Splines.vcproj | 85 + libs/splines/math_angles.cpp | 150 + libs/splines/math_angles.h | 195 + libs/splines/math_matrix.cpp | 134 + libs/splines/math_matrix.h | 223 + libs/splines/math_quaternion.cpp | 78 + libs/splines/math_quaternion.h | 190 + libs/splines/math_vector.cpp | 143 + libs/splines/math_vector.h | 574 + libs/splines/q_parse.cpp | 535 + libs/splines/q_shared.cpp | 976 + libs/splines/q_shared.h | 796 + libs/splines/splines.cpp | 1421 + libs/splines/splines.h | 1102 + libs/splines/util_list.h | 346 + libs/splines/util_str.cpp | 628 + libs/splines/util_str.h | 817 + libs/str.h | 479 + libs/synapse.h | 660 + libs/synapse/doc/design.txt | 190 + libs/synapse/doc/runtime.txt | 59 + libs/synapse/doc/unload.txt | 85 + libs/synapse/synapse.cpp | 1100 + libs/synapse/synapse.vcproj | 57 + makeversion.py | 72 + osx_setup.py | 38 + plugins/config.mk | 32 + plugins/eclassfgd/fgd.def | 8 + plugins/eclassfgd/fgd.vcproj | 67 + plugins/eclassfgd/plugin.cpp | 1136 + plugins/eclassfgd/plugin.h | 49 + plugins/entity/eclassmodel.cpp | 175 + plugins/entity/entity.cpp | 377 + plugins/entity/entity.def | 8 + plugins/entity/entity.h | 52 + plugins/entity/entity.vcproj | 101 + plugins/entity/entity_entitymodel.cpp | 138 + plugins/entity/entity_entitymodel.h | 150 + plugins/entity/light.cpp | 536 + plugins/entity/light.h | 26 + plugins/entity/miscmodel.cpp | 254 + plugins/entity/plugin.cpp | 116 + plugins/entity/plugin.h | 58 + plugins/image/.cvsignore | 8 + plugins/image/bmp.cpp | 402 + plugins/image/bmp.h | 101 + plugins/image/image.cpp | 128 + plugins/image/image.def | 8 + plugins/image/image.h | 68 + plugins/image/image.vcproj | 79 + plugins/image/jpeg.cpp | 411 + plugins/image/lbmlib.cpp | 762 + plugins/image/lbmlib.h | 46 + plugins/imagehl/imagehl.cpp | 99 + plugins/imagehl/imagehl.def | 8 + plugins/imagehl/imagehl.h | 80 + plugins/imagehl/imagehl.txt | 30 + plugins/imagehl/imagehl.vcproj | 75 + plugins/imagehl/lbmlib.cpp | 609 + plugins/imagehl/lbmlib.h | 35 + plugins/imagem8/imagem8.cpp | 123 + plugins/imagem8/imagem8.def | 8 + plugins/imagem8/imagem8.h | 70 + plugins/imagem8/imagem8.vcproj | 73 + plugins/imagem8/m32.cpp | 77 + plugins/imagem8/m32.h | 64 + plugins/imagem8/m8.cpp | 108 + plugins/imagem8/m8.h | 61 + plugins/imagepng/imagepng.def | 8 + plugins/imagepng/imagepng.vcproj | 67 + plugins/imagepng/plugin.cpp | 242 + plugins/imagepng/plugin.h | 31 + plugins/imagewal/imagewal.cpp | 92 + plugins/imagewal/imagewal.def | 8 + plugins/imagewal/imagewal.h | 60 + plugins/imagewal/imagewal.vcproj | 71 + plugins/imagewal/q2_palette.h | 66 + plugins/imagewal/wal.cpp | 93 + plugins/imagewal/wal.h | 51 + plugins/map/map.def | 8 + plugins/map/map.vcproj | 85 + plugins/map/parse.cpp | 679 + plugins/map/plugin.cpp | 129 + plugins/map/plugin.h | 92 + plugins/map/write.cpp | 227 + plugins/mapxml/mapxml.def | 8 + plugins/mapxml/mapxml.vcproj | 85 + plugins/mapxml/plugin.cpp | 73 + plugins/mapxml/plugin.h | 49 + plugins/mapxml/xmlparse.cpp | 295 + plugins/mapxml/xmlwrite.cpp | 217 + plugins/model/bitmaps/model_reload_entity.bmp | Bin 0 -> 308 bytes plugins/model/bitmaps/picomodel.bmp | Bin 0 -> 192660 bytes plugins/model/cpicomodel.cpp | 220 + plugins/model/cpicomodel.h | 94 + plugins/model/cpicosurface.cpp | 203 + plugins/model/cpicosurface.h | 55 + plugins/model/miscmodel.cpp | 451 + plugins/model/model.cpp | 88 + plugins/model/model.def | 8 + plugins/model/model.vcproj | 99 + plugins/model/plugin.cpp | 429 + plugins/model/plugin.h | 76 + plugins/model/remap.cpp | 318 + plugins/model/surface.h | 38 + plugins/shaders/plugin.cpp | 98 + plugins/shaders/plugin.h | 69 + plugins/shaders/shaders.cpp | 989 + plugins/shaders/shaders.def | 8 + plugins/shaders/shaders.h | 167 + plugins/shaders/shaders.proj | Bin 0 -> 73728 bytes plugins/shaders/shaders.vcproj | 71 + plugins/shaders/shadershl.def | 8 + plugins/spritemodel/plugin.cpp | 274 + plugins/spritemodel/plugin.h | 78 + plugins/spritemodel/spritemodel.cpp | 178 + plugins/spritemodel/spritemodel.def | 8 + plugins/spritemodel/spritemodel.h | 57 + plugins/spritemodel/spritemodel.vcproj | 87 + plugins/surface/.cvsignore | 11 + plugins/surface/surface.def | 8 + plugins/surface/surface.vcproj | 73 + plugins/surface/surfacedialog.cpp | 1925 + plugins/surface/surfacedialog.h | 31 + plugins/surface/surfdlg_plugin.cpp | 122 + plugins/surface/surfdlg_plugin.h | 94 + plugins/surface_heretic2/surface_heretic2.def | 8 + .../surface_heretic2/surface_heretic2.vcproj | 83 + plugins/surface_heretic2/surfacedialog.cpp | 1940 + plugins/surface_heretic2/surfacedialog.h | 31 + .../surfaceflagsdialog_heretic2.cpp | 1417 + .../surfaceflagsdialog_heretic2.h | 76 + plugins/surface_heretic2/surfdlg_plugin.cpp | 122 + plugins/surface_heretic2/surfdlg_plugin.h | 94 + plugins/surface_quake2/surface_quake2.def | 8 + plugins/surface_quake2/surface_quake2.vcproj | 75 + plugins/surface_quake2/surfacedialog.cpp | 1939 + plugins/surface_quake2/surfacedialog.h | 31 + .../surfaceflagsdialog_quake2.cpp | 1168 + .../surfaceflagsdialog_quake2.h | 108 + plugins/surface_quake2/surfdlg_plugin.cpp | 122 + plugins/surface_quake2/surfdlg_plugin.h | 94 + plugins/textool/.cvsignore | 13 + plugins/textool/.cvswrappers | 2 + plugins/textool/2DView.cpp | 202 + plugins/textool/2DView.h | 70 + plugins/textool/ControlPointsManager.cpp | 332 + plugins/textool/ControlPointsManager.h | 133 + plugins/textool/Doc/.cvswrappers | 1 + plugins/textool/Doc/Image2.jpg | Bin 0 -> 50020 bytes plugins/textool/Doc/TexTool.html | 123 + plugins/textool/StdAfx.cpp | 28 + plugins/textool/StdAfx.h | 154 + plugins/textool/TexTool.cpp | 962 + plugins/textool/TexTool.def | 12 + plugins/textool/TexTool.rc | 136 + plugins/textool/TexTool.vcproj | 99 + plugins/textool/changelog.txt | 8 + plugins/textool/resource.h | 23 + plugins/vfspak/vfs.cpp | 803 + plugins/vfspak/vfs.h | 52 + plugins/vfspak/vfspak.cpp | 101 + plugins/vfspak/vfspak.def | 8 + plugins/vfspak/vfspak.h | 64 + plugins/vfspak/vfspak.vcproj | 71 + plugins/vfspk3/.cvsignore | 11 + plugins/vfspk3/unzip-vfspk3.h | 299 + plugins/vfspk3/unzip.cpp | 4537 + plugins/vfspk3/vfs.cpp | 854 + plugins/vfspk3/vfs.h | 68 + plugins/vfspk3/vfspk3.cpp | 99 + plugins/vfspk3/vfspk3.def | 8 + plugins/vfspk3/vfspk3.h | 63 + plugins/vfspk3/vfspk3.proj | Bin 0 -> 16384 bytes plugins/vfspk3/vfspk3.vcproj | 75 + plugins/vfswad/unwad.cpp | 251 + plugins/vfswad/unwad.h | 111 + plugins/vfswad/vfs.cpp | 759 + plugins/vfswad/vfs.h | 69 + plugins/vfswad/vfswad.cpp | 101 + plugins/vfswad/vfswad.def | 8 + plugins/vfswad/vfswad.h | 63 + plugins/vfswad/vfswad.txt | 30 + plugins/vfswad/vfswad.vcproj | 77 + radiant.sln | 168 + radiant.sln.ref | 1174 + radiant.xcode/apple.pbxuser | 496 + radiant.xcode/project.pbxproj | 95793 ++++++++++++++++ radiant/.cvsignore | 16 + radiant/Makefile.mac | 91 + radiant/bitmaps/brush_flipx.bmp | Bin 0 -> 238 bytes radiant/bitmaps/brush_flipy.bmp | Bin 0 -> 238 bytes radiant/bitmaps/brush_flipz.bmp | Bin 0 -> 238 bytes radiant/bitmaps/brush_rotatex.bmp | Bin 0 -> 238 bytes radiant/bitmaps/brush_rotatey.bmp | Bin 0 -> 238 bytes radiant/bitmaps/brush_rotatez.bmp | Bin 0 -> 238 bytes radiant/bitmaps/cap_bevel.bmp | Bin 0 -> 154 bytes radiant/bitmaps/cap_endcap.bmp | Bin 0 -> 154 bytes radiant/bitmaps/cap_ibevel.bmp | Bin 0 -> 154 bytes radiant/bitmaps/cap_iendcap.bmp | Bin 0 -> 154 bytes radiant/bitmaps/curve_cap.bmp | Bin 0 -> 238 bytes radiant/bitmaps/dontselectcurve.bmp | Bin 0 -> 238 bytes radiant/bitmaps/dontselectmodel.bmp | Bin 0 -> 238 bytes radiant/bitmaps/file_open.bmp | Bin 0 -> 238 bytes radiant/bitmaps/file_save.bmp | Bin 0 -> 238 bytes radiant/bitmaps/icon.bmp | Bin 0 -> 630 bytes radiant/bitmaps/logo.bmp | Bin 0 -> 47936 bytes radiant/bitmaps/patch_bend.bmp | Bin 0 -> 238 bytes radiant/bitmaps/patch_drilldown.bmp | Bin 0 -> 238 bytes radiant/bitmaps/patch_insdel.bmp | Bin 0 -> 238 bytes radiant/bitmaps/patch_showboundingbox.bmp | Bin 0 -> 238 bytes radiant/bitmaps/patch_weld.bmp | Bin 0 -> 238 bytes radiant/bitmaps/patch_wireframe.bmp | Bin 0 -> 238 bytes radiant/bitmaps/popup_selection.bmp | Bin 0 -> 238 bytes radiant/bitmaps/scalelockx.bmp | Bin 0 -> 238 bytes radiant/bitmaps/scalelocky.bmp | Bin 0 -> 238 bytes radiant/bitmaps/scalelockz.bmp | Bin 0 -> 238 bytes radiant/bitmaps/select_mouserotate.bmp | Bin 0 -> 238 bytes radiant/bitmaps/select_mousescale.bmp | Bin 0 -> 238 bytes radiant/bitmaps/selection_csgmerge.bmp | Bin 0 -> 238 bytes radiant/bitmaps/selection_csgsubtract.bmp | Bin 0 -> 238 bytes radiant/bitmaps/selection_makehollow.bmp | Bin 0 -> 238 bytes .../bitmaps/selection_selectcompletetall.bmp | Bin 0 -> 238 bytes radiant/bitmaps/selection_selectinside.bmp | Bin 0 -> 238 bytes .../bitmaps/selection_selectpartialtall.bmp | Bin 0 -> 238 bytes radiant/bitmaps/selection_selecttouching.bmp | Bin 0 -> 238 bytes radiant/bitmaps/show_entities.bmp | Bin 0 -> 238 bytes radiant/bitmaps/splash.bmp | Bin 0 -> 299934 bytes radiant/bitmaps/textures_popup.bmp | Bin 0 -> 238 bytes radiant/bitmaps/view_cameratoggle.bmp | Bin 0 -> 238 bytes radiant/bitmaps/view_cameraupdate.bmp | Bin 0 -> 238 bytes radiant/bitmaps/view_change.bmp | Bin 0 -> 126 bytes radiant/bitmaps/view_clipper.bmp | Bin 0 -> 238 bytes radiant/bitmaps/view_cubicclipping.bmp | Bin 0 -> 238 bytes radiant/bitmaps/view_entity.bmp | Bin 0 -> 238 bytes radiant/bitmaps/window1.bmp | Bin 0 -> 614 bytes radiant/bitmaps/window2.bmp | Bin 0 -> 614 bytes radiant/bitmaps/window3.bmp | Bin 0 -> 614 bytes radiant/bitmaps/window4.bmp | Bin 0 -> 614 bytes radiant/bp_dlg.cpp | 155 + radiant/brush.cpp | 3644 + radiant/brush.h | 89 + radiant/brush_primit.cpp | 600 + radiant/brushscript.cpp | 698 + radiant/camera.h | 83 + radiant/camwindow.cpp | 1700 + radiant/camwindow.h | 171 + radiant/csg.cpp | 687 + radiant/dialog.cpp | 295 + radiant/dialog.h | 85 + radiant/dialoginfo.cpp | 75 + radiant/drag.cpp | 845 + radiant/eclass.cpp | 497 + radiant/eclass_def.cpp | 306 + radiant/eclass_def.h | 44 + radiant/error.cpp | 151 + radiant/feedback.cpp | 368 + radiant/feedback.h | 125 + radiant/file.cpp | 390 + radiant/file.h | 119 + radiant/filters.cpp | 242 + radiant/filters.h | 30 + radiant/findtexturedialog.cpp | 289 + radiant/findtexturedialog.h | 49 + radiant/glinterface.cpp | 91 + radiant/glwidget.cpp | 254 + radiant/glwidget.h | 45 + radiant/glwindow.cpp | 287 + radiant/glwindow.h | 108 + radiant/groupdialog.cpp | 1713 + radiant/groupdialog.h | 108 + radiant/gtkdlgs.cpp | 4045 + radiant/gtkfilesel-darwin.c | 3360 + radiant/gtkfilesel-darwin.h | 129 + radiant/gtkfilesel-linux.c | 4987 + radiant/gtkfilesel-linux.h | 143 + radiant/gtkfilesel.c | 3337 + radiant/gtkfilesel.h | 143 + radiant/gtkmisc.cpp | 1610 + radiant/gtkmisc.h | 100 + radiant/main.cpp | 1246 + radiant/mainframe.cpp | 7785 ++ radiant/mainframe.h | 909 + radiant/map.cpp | 1322 + radiant/map.h | 72 + radiant/missing.cpp | 203 + radiant/parse.cpp | 220 + radiant/parse.h | 35 + radiant/patchdialog.cpp | 745 + radiant/patchdialog.h | 85 + radiant/plugin.h | 45 + radiant/pluginentities.cpp | 74 + radiant/pluginmanager.cpp | 2522 + radiant/pluginmanager.h | 212 + radiant/pmesh.cpp | 6427 ++ radiant/points.cpp | 249 + radiant/points.h | 57 + radiant/preferences.cpp | 3102 + radiant/preferences.h | 628 + radiant/profile.cpp | 293 + radiant/qe3.cpp | 1797 + radiant/qe3.h | 912 + radiant/qedefs.h | 128 + radiant/qfiles.h | 480 + radiant/qgl-mac.c | 1775 + radiant/qgl.c | 1797 + radiant/qgl.h | 600 + radiant/qgl_ext.cpp | 46 + radiant/queuedraw.cpp | 158 + radiant/radiant.ico | Bin 0 -> 1078 bytes radiant/radiant.rc | 72 + radiant/radiant.vcproj | 991 + radiant/resource.h | 37 + radiant/select.cpp | 2125 + radiant/select.h | 82 + radiant/selectedface.cpp | 128 + radiant/stdafx.cpp | 35 + radiant/stdafx.h | 39 + radiant/surfacedialog.cpp | 1134 + radiant/surfacedialog.h | 69 + radiant/surfaceplugin.cpp | 259 + radiant/surfaceplugin.h | 11 + radiant/targetname.cpp | 90 + radiant/texmanip.cpp | 380 + radiant/texmanip.h | 39 + radiant/textures.h | 52 + radiant/texwindow.cpp | 1965 + radiant/texwindow.h | 62 + radiant/ui.cpp | 268 + radiant/ui.h | 84 + radiant/undo.cpp | 973 + radiant/undo.h | 66 + radiant/vertsel.cpp | 386 + radiant/watchbsp.cpp | 774 + radiant/watchbsp.h | 91 + radiant/winding.cpp | 822 + radiant/winding.h | 70 + radiant/xmlstuff.h | 70 + radiant/xywindow.cpp | 3462 + radiant/xywindow.h | 194 + radiant/z.cpp | 466 + radiant/z.h | 42 + radiant/zwindow.cpp | 125 + radiant/zwindow.h | 46 + run_python.bat | 9 + tools/quake2/common/bspfile.c | 789 + tools/quake2/common/bspfile.h | 128 + tools/quake2/common/cmdlib.c | 1221 + tools/quake2/common/cmdlib.h | 170 + tools/quake2/common/inout.c | 367 + tools/quake2/common/inout.h | 63 + tools/quake2/common/l3dslib.c | 300 + tools/quake2/common/l3dslib.h | 25 + tools/quake2/common/lbmlib.c | 837 + tools/quake2/common/lbmlib.h | 38 + tools/quake2/common/mathlib.c | 172 + tools/quake2/common/mathlib.h | 75 + tools/quake2/common/md4.c | 0 tools/quake2/common/path_init.c | 400 + tools/quake2/common/polylib.c | 642 + tools/quake2/common/polylib.h | 54 + tools/quake2/common/q2_threads.h | 34 + tools/quake2/common/qfiles.h | 563 + tools/quake2/common/scriplib.c | 296 + tools/quake2/common/scriplib.h | 43 + tools/quake2/common/threads.c | 622 + tools/quake2/common/trilib.c | 186 + tools/quake2/common/trilib.h | 31 + tools/quake2/q2map/brushbsp.c | 1329 + tools/quake2/q2map/csg.c | 634 + tools/quake2/q2map/faces.c | 1076 + tools/quake2/q2map/flow.c | 787 + tools/quake2/q2map/gldraw.c | 231 + tools/quake2/q2map/glfile.c | 148 + tools/quake2/q2map/leakfile.c | 180 + tools/quake2/q2map/lightmap.c | 1315 + tools/quake2/q2map/main.c | 721 + tools/quake2/q2map/map.c | 1017 + tools/quake2/q2map/nodraw.c | 46 + tools/quake2/q2map/patches.c | 603 + tools/quake2/q2map/portals.c | 1110 + tools/quake2/q2map/prtfile.c | 286 + tools/quake2/q2map/q2map.h | 50 + tools/quake2/q2map/q2map.vcproj | 153 + tools/quake2/q2map/qbsp.c | 426 + tools/quake2/q2map/qbsp.h | 390 + tools/quake2/q2map/qrad.c | 647 + tools/quake2/q2map/qrad.h | 184 + tools/quake2/q2map/qvis.c | 581 + tools/quake2/q2map/qvis.h | 169 + tools/quake2/q2map/textures.c | 249 + tools/quake2/q2map/trace.c | 298 + tools/quake2/q2map/tree.c | 218 + tools/quake2/q2map/writebsp.c | 591 + tools/quake2/qdata/anorms.h | 162 + tools/quake2/qdata/images.c | 742 + tools/quake2/qdata/makefile | 81 + tools/quake2/qdata/models.c | 1132 + tools/quake2/qdata/qdata.c | 526 + tools/quake2/qdata/qdata.h | 75 + tools/quake2/qdata/qdata3.vcproj | 117 + tools/quake2/qdata/sprites.c | 208 + tools/quake2/qdata/tables.c | 150 + tools/quake2/qdata/video.c | 1238 + tools/quake2/qdata_heretic2/adpcm.h | 49 + tools/quake2/qdata_heretic2/animcomp.c | 351 + tools/quake2/qdata_heretic2/animcomp.h | 43 + tools/quake2/qdata_heretic2/anorms.h | 183 + tools/quake2/qdata_heretic2/book.c | 372 + tools/quake2/qdata_heretic2/common/bspfile.c | 793 + tools/quake2/qdata_heretic2/common/bspfile.h | 133 + tools/quake2/qdata_heretic2/common/cmdlib.c | 1238 + tools/quake2/qdata_heretic2/common/cmdlib.h | 177 + .../qdata_heretic2/common/her2_threads.h | 35 + tools/quake2/qdata_heretic2/common/inout.c | 367 + tools/quake2/qdata_heretic2/common/inout.h | 63 + tools/quake2/qdata_heretic2/common/l3dslib.c | 476 + tools/quake2/qdata_heretic2/common/l3dslib.h | 28 + tools/quake2/qdata_heretic2/common/lbmlib.c | 1052 + tools/quake2/qdata_heretic2/common/lbmlib.h | 41 + tools/quake2/qdata_heretic2/common/mathlib.c | 176 + tools/quake2/qdata_heretic2/common/mathlib.h | 76 + tools/quake2/qdata_heretic2/common/md4.c | 0 .../quake2/qdata_heretic2/common/path_init.c | 404 + tools/quake2/qdata_heretic2/common/polylib.c | 656 + tools/quake2/qdata_heretic2/common/polylib.h | 55 + tools/quake2/qdata_heretic2/common/qfiles.c | 82 + tools/quake2/qdata_heretic2/common/qfiles.h | 619 + tools/quake2/qdata_heretic2/common/scriplib.c | 297 + tools/quake2/qdata_heretic2/common/scriplib.h | 44 + tools/quake2/qdata_heretic2/common/threads.c | 620 + tools/quake2/qdata_heretic2/common/token.c | 550 + tools/quake2/qdata_heretic2/common/token.h | 132 + tools/quake2/qdata_heretic2/common/trilib.c | 1077 + tools/quake2/qdata_heretic2/common/trilib.h | 56 + tools/quake2/qdata_heretic2/fmodels.c | 3404 + tools/quake2/qdata_heretic2/icon1.ico | Bin 0 -> 766 bytes tools/quake2/qdata_heretic2/images.c | 1397 + tools/quake2/qdata_heretic2/jointed.c | 572 + tools/quake2/qdata_heretic2/jointed.h | 35 + tools/quake2/qdata_heretic2/joints.h | 144 + tools/quake2/qdata_heretic2/models.c | 2050 + tools/quake2/qdata_heretic2/pics.c | 198 + tools/quake2/qdata_heretic2/qcommon/angles.h | 76 + .../qdata_heretic2/qcommon/arrayedlist.h | 71 + tools/quake2/qdata_heretic2/qcommon/flex.h | 33 + tools/quake2/qdata_heretic2/qcommon/fmodel.h | 202 + .../quake2/qdata_heretic2/qcommon/h2common.h | 26 + .../quake2/qdata_heretic2/qcommon/placement.h | 38 + .../quake2/qdata_heretic2/qcommon/q_typedef.h | 63 + tools/quake2/qdata_heretic2/qcommon/qfiles.h | 604 + .../quake2/qdata_heretic2/qcommon/reference.c | 124 + .../quake2/qdata_heretic2/qcommon/reference.h | 126 + .../qdata_heretic2/qcommon/resourcemanager.c | 159 + .../qdata_heretic2/qcommon/resourcemanager.h | 47 + .../quake2/qdata_heretic2/qcommon/skeletons.c | 232 + .../quake2/qdata_heretic2/qcommon/skeletons.h | 107 + tools/quake2/qdata_heretic2/qd_fmodel.h | 61 + tools/quake2/qdata_heretic2/qd_skeletons.c | 1291 + tools/quake2/qdata_heretic2/qd_skeletons.h | 84 + tools/quake2/qdata_heretic2/qdata.c | 730 + tools/quake2/qdata_heretic2/qdata.h | 166 + .../qdata_heretic2/qdata3_heretic2.vcproj | 179 + tools/quake2/qdata_heretic2/resource.h | 18 + tools/quake2/qdata_heretic2/script1.aps | Bin 0 -> 18732 bytes tools/quake2/qdata_heretic2/script1.rc | 115 + tools/quake2/qdata_heretic2/sprites.c | 349 + tools/quake2/qdata_heretic2/svdcmp.c | 490 + tools/quake2/qdata_heretic2/tables.c | 171 + tools/quake2/qdata_heretic2/tmix.c | 698 + tools/quake2/qdata_heretic2/video.c | 1149 + tools/quake3/common/aselib.c | 965 + tools/quake3/common/aselib.h | 31 + tools/quake3/common/bspfile.c | 706 + tools/quake3/common/bspfile.h | 121 + tools/quake3/common/cmdlib.c | 1153 + tools/quake3/common/cmdlib.h | 160 + tools/quake3/common/imagelib.c | 1220 + tools/quake3/common/imagelib.h | 44 + tools/quake3/common/inout.c | 367 + tools/quake3/common/inout.h | 61 + tools/quake3/common/l3dslib.c | 301 + tools/quake3/common/l3dslib.h | 26 + tools/quake3/common/md4.c | 0 tools/quake3/common/mutex.c | 197 + tools/quake3/common/mutex.h | 28 + tools/quake3/common/polylib.c | 745 + tools/quake3/common/polylib.h | 57 + tools/quake3/common/polyset.h | 51 + tools/quake3/common/qfiles.h | 489 + tools/quake3/common/qthreads.h | 31 + tools/quake3/common/scriplib.c | 409 + tools/quake3/common/scriplib.h | 55 + tools/quake3/common/surfaceflags.h | 112 + tools/quake3/common/threads.c | 620 + tools/quake3/common/trilib.c | 235 + tools/quake3/common/trilib.h | 26 + tools/quake3/common/unzip.c | 4596 + tools/quake3/common/unzip.h | 321 + tools/quake3/common/vfs.c | 365 + tools/quake3/common/vfs.h | 41 + tools/quake3/q3data/.cvsignore | 12 + tools/quake3/q3data/.cvswrappers | 2 + tools/quake3/q3data/3dslib.c | 630 + tools/quake3/q3data/3dslib.h | 118 + tools/quake3/q3data/compress.c | 750 + tools/quake3/q3data/images.c | 465 + tools/quake3/q3data/md3lib.c | 193 + tools/quake3/q3data/md3lib.h | 7 + tools/quake3/q3data/models.c | 2134 + tools/quake3/q3data/oldstuff.c | 130 + tools/quake3/q3data/p3dlib.c | 324 + tools/quake3/q3data/p3dlib.h | 8 + tools/quake3/q3data/polyset.c | 252 + tools/quake3/q3data/q3data.c | 643 + tools/quake3/q3data/q3data.h | 78 + tools/quake3/q3data/q3data.vcproj | 107 + tools/quake3/q3data/stripper.c | 282 + tools/quake3/q3data/video.c | 1132 + tools/quake3/q3map2/.cvsignore | 12 + tools/quake3/q3map2/brush.c | 982 + tools/quake3/q3map2/brush_primit.c | 80 + tools/quake3/q3map2/bsp.c | 853 + tools/quake3/q3map2/bspfile_abstract.c | 834 + tools/quake3/q3map2/bspfile_ibsp.c | 584 + tools/quake3/q3map2/bspfile_rbsp.c | 339 + tools/quake3/q3map2/changelog.q3map1 | 371 + tools/quake3/q3map2/changelog.q3map2.txt | 607 + tools/quake3/q3map2/convert_ase.c | 374 + tools/quake3/q3map2/convert_map.c | 443 + tools/quake3/q3map2/decals.c | 908 + tools/quake3/q3map2/facebsp.c | 453 + tools/quake3/q3map2/fog.c | 804 + tools/quake3/q3map2/game_ef.h | 186 + tools/quake3/q3map2/game_ja.h | 180 + tools/quake3/q3map2/game_jk2.h | 174 + tools/quake3/q3map2/game_quake3.h | 184 + tools/quake3/q3map2/game_sof2.h | 249 + tools/quake3/q3map2/game_t.h | 34 + tools/quake3/q3map2/game_tenebrae.h | 184 + tools/quake3/q3map2/game_wolf.h | 230 + tools/quake3/q3map2/game_wolfet.h | 169 + tools/quake3/q3map2/image.c | 467 + tools/quake3/q3map2/leakfile.c | 126 + tools/quake3/q3map2/light.c | 2182 + tools/quake3/q3map2/light_bounce.c | 954 + tools/quake3/q3map2/light_shadows.c | 124 + tools/quake3/q3map2/light_trace.c | 1754 + tools/quake3/q3map2/light_ydnar.c | 3129 + tools/quake3/q3map2/lightmaps.c | 496 + tools/quake3/q3map2/lightmaps_ydnar.c | 2997 + tools/quake3/q3map2/listen.pl | 46 + tools/quake3/q3map2/main.c | 456 + tools/quake3/q3map2/map.c | 1649 + tools/quake3/q3map2/mesh.c | 825 + tools/quake3/q3map2/model.c | 706 + tools/quake3/q3map2/patch.c | 524 + tools/quake3/q3map2/path_init.c | 456 + tools/quake3/q3map2/portals.c | 970 + tools/quake3/q3map2/prtfile.c | 291 + tools/quake3/q3map2/q3map2.h | 2276 + tools/quake3/q3map2/q3map2.ico | Bin 0 -> 1078 bytes tools/quake3/q3map2/q3map2.rc | 1 + tools/quake3/q3map2/q3map2.vcproj | 469 + tools/quake3/q3map2/shaders.c | 1926 + tools/quake3/q3map2/surface.c | 3533 + tools/quake3/q3map2/surface_extra.c | 444 + tools/quake3/q3map2/surface_foliage.c | 327 + tools/quake3/q3map2/surface_fur.c | 128 + tools/quake3/q3map2/surface_meta.c | 1626 + tools/quake3/q3map2/tjunction.c | 727 + tools/quake3/q3map2/tree.c | 158 + tools/quake3/q3map2/vis.c | 1122 + tools/quake3/q3map2/visflow.c | 1709 + tools/quake3/q3map2/writebsp.c | 646 + win32_install.py | 166 + www/bug.shtml | 271 + www/coding.html | 154 + www/files.html | 166 + www/gtkradiant.html | 338 + www/hosted.html | 170 + www/index.html | 339 + www/reviews.html | 155 + 1127 files changed, 502475 insertions(+) create mode 100644 BSD create mode 100644 CHANGES-MACOS create mode 100644 COMPILING create mode 100644 CONTRIBUTORS create mode 100644 CONTRIBUTOR_AGREEMENT create mode 100644 DarwinCompileInfo.rtf create mode 100644 DoxyConfig create mode 100644 Doxyfile create mode 100644 Doxygen_files/Doxyfile create mode 100644 Doxygen_files/doxy_mainpage.h create mode 100644 Doxygen_files/doxygen_gtkradiant.css create mode 100644 Doxygen_files/doxygen_gtkradiant_foot.html create mode 100644 Doxygen_files/doxygen_gtkradiant_head.html create mode 100644 Doxygen_files/doxygen_index.html create mode 100644 Doxygen_files/doxygen_reference_foot.html create mode 100644 Doxygen_files/doxygen_reference_head.html create mode 100644 Doxygen_files/example/annotated.html create mode 100644 Doxygen_files/example/classIEpair-members.html create mode 100644 Doxygen_files/example/classIEpair.html create mode 100644 Doxygen_files/example/classes.html create mode 100644 Doxygen_files/example/doxygen.gif create mode 100644 Doxygen_files/example/doxygen_gtkradiant.css create mode 100644 Doxygen_files/example/files.html create mode 100644 Doxygen_files/example/functions.html create mode 100644 Doxygen_files/example/graph_legend.dot create mode 100644 Doxygen_files/example/graph_legend.gif create mode 100644 Doxygen_files/example/graph_legend.html create mode 100644 Doxygen_files/example/index.html create mode 100644 Doxygen_files/example/pages.html create mode 100644 Doxygen_files/example/test_8c-source.html create mode 100644 Doxygen_files/example/test_8c.html create mode 100644 Doxygen_files/example/todo.html create mode 100644 Doxygen_files/genDoxyfile create mode 100644 Doxygen_files/gendoxfunctions create mode 100644 Doxygen_files/images/body-left-tile.gif create mode 100644 Doxygen_files/images/body-lower-left.gif create mode 100644 Doxygen_files/images/body-lower-right.gif create mode 100644 Doxygen_files/images/body-lower-tile.gif create mode 100644 Doxygen_files/images/body-right-tile.gif create mode 100644 Doxygen_files/images/body-upper-left.gif create mode 100644 Doxygen_files/images/body-upper-right.gif create mode 100644 Doxygen_files/images/body-upper-tile.gif create mode 100644 Doxygen_files/images/gtkr_splash.jpg create mode 100644 Doxygen_files/images/gtkr_splash_sm.jpg create mode 100644 Doxygen_files/images/history_id_logo.gif create mode 100644 Doxygen_files/images/top-right.gif create mode 100644 Doxygen_files/images/top-tile.gif create mode 100644 Doxygen_files/images/top-title.gif create mode 100644 Doxygen_files/reference1.html create mode 100644 GPL create mode 100644 GtkRadiant.prj create mode 100644 INSTALL.txt create mode 100644 LGPL create mode 100644 LICENSE create mode 100644 LICENSE_ID create mode 100644 README create mode 100644 README.doxygen create mode 100644 SConscript create mode 100644 SConstruct create mode 100644 contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp create mode 100644 contrib/bkgrnd2d/bitmaps/bkgrnd2d_xy_toggle.bmp create mode 100644 contrib/bkgrnd2d/bitmaps/bkgrnd2d_xz_toggle.bmp create mode 100644 contrib/bkgrnd2d/bitmaps/bkgrnd2d_yz_toggle.bmp create mode 100644 contrib/bkgrnd2d/bkgrnd2d.cpp create mode 100644 contrib/bkgrnd2d/bkgrnd2d.def create mode 100644 contrib/bkgrnd2d/bkgrnd2d.h create mode 100644 contrib/bkgrnd2d/bkgrnd2d.vcproj create mode 100644 contrib/bkgrnd2d/dialog.cpp create mode 100644 contrib/bkgrnd2d/dialog.h create mode 100644 contrib/bkgrnd2d/plugin.cpp create mode 100644 contrib/bkgrnd2d/plugin.h create mode 100644 contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt create mode 100644 contrib/bobtoolz/CPortals.h create mode 100644 contrib/bobtoolz/DBobView.cpp create mode 100644 contrib/bobtoolz/DBobView.h create mode 100644 contrib/bobtoolz/DBrush.cpp create mode 100644 contrib/bobtoolz/DBrush.h create mode 100644 contrib/bobtoolz/DEPair.cpp create mode 100644 contrib/bobtoolz/DEPair.h create mode 100644 contrib/bobtoolz/DEntity.cpp create mode 100644 contrib/bobtoolz/DEntity.h create mode 100644 contrib/bobtoolz/DListener.cpp create mode 100644 contrib/bobtoolz/DListener.h create mode 100644 contrib/bobtoolz/DMap.cpp create mode 100644 contrib/bobtoolz/DMap.h create mode 100644 contrib/bobtoolz/DPatch.cpp create mode 100644 contrib/bobtoolz/DPatch.h create mode 100644 contrib/bobtoolz/DPlane.cpp create mode 100644 contrib/bobtoolz/DPlane.h create mode 100644 contrib/bobtoolz/DPoint.cpp create mode 100644 contrib/bobtoolz/DPoint.h create mode 100644 contrib/bobtoolz/DShape.cpp create mode 100644 contrib/bobtoolz/DShape.h create mode 100644 contrib/bobtoolz/DTrainDrawer.cpp create mode 100644 contrib/bobtoolz/DTrainDrawer.h create mode 100644 contrib/bobtoolz/DTreePlanter.cpp create mode 100644 contrib/bobtoolz/DTreePlanter.h create mode 100644 contrib/bobtoolz/DVisDrawer.cpp create mode 100644 contrib/bobtoolz/DVisDrawer.h create mode 100644 contrib/bobtoolz/DWinding.cpp create mode 100644 contrib/bobtoolz/DWinding.h create mode 100644 contrib/bobtoolz/ScriptParser.cpp create mode 100644 contrib/bobtoolz/ScriptParser.h create mode 100644 contrib/bobtoolz/StdAfx.cpp create mode 100644 contrib/bobtoolz/StdAfx.h create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_cleanup.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_dropent.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_merge.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_poly.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_split.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_trainpathplot.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_treeplanter.bmp create mode 100644 contrib/bobtoolz/bitmaps/bobtoolz_turnedge.bmp create mode 100644 contrib/bobtoolz/bobToolz-GTK.cpp create mode 100644 contrib/bobtoolz/bobToolz.def create mode 100644 contrib/bobtoolz/bobToolz.h create mode 100644 contrib/bobtoolz/bobToolz.rc create mode 100644 contrib/bobtoolz/bobToolz_gtk.vcproj create mode 100644 contrib/bobtoolz/bobtoolz-gtk.rc create mode 100644 contrib/bobtoolz/bsploader.cpp create mode 100644 contrib/bobtoolz/bsploader.h create mode 100644 contrib/bobtoolz/bt/bt-el1.txt create mode 100644 contrib/bobtoolz/bt/bt-el2.txt create mode 100644 contrib/bobtoolz/bt/ctf-blue.txt create mode 100644 contrib/bobtoolz/bt/ctf-red.txt create mode 100644 contrib/bobtoolz/bt/door-tex-trim.txt create mode 100644 contrib/bobtoolz/bt/door-tex.txt create mode 100644 contrib/bobtoolz/bt/tp_ent.txt create mode 100644 contrib/bobtoolz/cportals.cpp create mode 100644 contrib/bobtoolz/ctfToolz-GTK.cpp create mode 100644 contrib/bobtoolz/ctfresource_gtk.h create mode 100644 contrib/bobtoolz/ctfresource_gtk.rc create mode 100644 contrib/bobtoolz/ctftoolz.def create mode 100644 contrib/bobtoolz/dialogs/AboutDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/AboutDialog.h create mode 100644 contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/AutoCaulkDialog.h create mode 100644 contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h create mode 100644 contrib/bobtoolz/dialogs/BrushCheckDialog.h create mode 100644 contrib/bobtoolz/dialogs/DoorDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/DoorDialog.h create mode 100644 contrib/bobtoolz/dialogs/IntersectDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/IntersectDialog.h create mode 100644 contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/IntersectInfoDialog.h create mode 100644 contrib/bobtoolz/dialogs/PolygonDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/PolygonDialog.h create mode 100644 contrib/bobtoolz/dialogs/StairDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/StairDialog.h create mode 100644 contrib/bobtoolz/dialogs/TextureResetDialog.cpp create mode 100644 contrib/bobtoolz/dialogs/TextureResetDialog.h create mode 100644 contrib/bobtoolz/dialogs/brushcheckdialog.cpp create mode 100644 contrib/bobtoolz/dialogs/dialogs-gtk.cpp create mode 100644 contrib/bobtoolz/dialogs/dialogs-gtk.h create mode 100644 contrib/bobtoolz/dialogs/pathplotterdialog.cpp create mode 100644 contrib/bobtoolz/dialogs/pathplotterdialog.h create mode 100644 contrib/bobtoolz/funchandlers-GTK.cpp create mode 100644 contrib/bobtoolz/funchandlers-ctf-GTK.cpp create mode 100644 contrib/bobtoolz/funchandlers.cpp create mode 100644 contrib/bobtoolz/funchandlers.h create mode 100644 contrib/bobtoolz/interfaces/IScriptParser.h create mode 100644 contrib/bobtoolz/lists.cpp create mode 100644 contrib/bobtoolz/lists.h create mode 100644 contrib/bobtoolz/misc.cpp create mode 100644 contrib/bobtoolz/misc.h create mode 100644 contrib/bobtoolz/res/plugin.rc2 create mode 100644 contrib/bobtoolz/resource-gtk.h create mode 100644 contrib/bobtoolz/resource.h create mode 100644 contrib/bobtoolz/shapes.cpp create mode 100644 contrib/bobtoolz/shapes.h create mode 100644 contrib/bobtoolz/txt/changelog.txt create mode 100644 contrib/bobtoolz/txt/readme.txt create mode 100644 contrib/bobtoolz/visfind.cpp create mode 100644 contrib/bobtoolz/visfind.h create mode 100644 contrib/camera/bitmaps/camera_insp.bmp create mode 100644 contrib/camera/camera.cpp create mode 100644 contrib/camera/camera.def create mode 100644 contrib/camera/camera.h create mode 100644 contrib/camera/camera.vcproj create mode 100644 contrib/camera/dialogs.cpp create mode 100644 contrib/camera/dialogs.h create mode 100644 contrib/camera/dialogs_common.cpp create mode 100644 contrib/camera/funchandlers.cpp create mode 100644 contrib/camera/funchandlers.h create mode 100644 contrib/camera/listener.cpp create mode 100644 contrib/camera/listener.h create mode 100644 contrib/camera/misc.cpp create mode 100644 contrib/camera/misc.h create mode 100644 contrib/camera/renderer.cpp create mode 100644 contrib/camera/renderer.h create mode 100644 contrib/gtkgensurf/.cvsignore create mode 100644 contrib/gtkgensurf/CHANGES create mode 100644 contrib/gtkgensurf/bitmap.cpp create mode 100644 contrib/gtkgensurf/dec.cpp create mode 100644 contrib/gtkgensurf/face.cpp create mode 100644 contrib/gtkgensurf/font.cpp create mode 100644 contrib/gtkgensurf/gendlgs.cpp create mode 100644 contrib/gtkgensurf/gendlgs.h create mode 100644 contrib/gtkgensurf/genmap.cpp create mode 100644 contrib/gtkgensurf/gensurf.cpp create mode 100644 contrib/gtkgensurf/gensurf.def create mode 100644 contrib/gtkgensurf/gensurf.h create mode 100644 contrib/gtkgensurf/gtkgensurf.vcproj create mode 100644 contrib/gtkgensurf/heretic.cpp create mode 100644 contrib/gtkgensurf/plugin.cpp create mode 100644 contrib/gtkgensurf/triangle.c create mode 100644 contrib/gtkgensurf/triangle.h create mode 100644 contrib/gtkgensurf/view.cpp create mode 100644 contrib/hydratoolz/hydratoolz.def create mode 100644 contrib/hydratoolz/hydratoolz.vcproj create mode 100644 contrib/hydratoolz/plugin.cpp create mode 100644 contrib/hydratoolz/plugin.h create mode 100644 contrib/prtview/.cvsignore create mode 100644 contrib/prtview/AboutDialog.cpp create mode 100644 contrib/prtview/AboutDialog.h create mode 100644 contrib/prtview/ConfigDialog.cpp create mode 100644 contrib/prtview/ConfigDialog.h create mode 100644 contrib/prtview/LoadPortalFileDialog.cpp create mode 100644 contrib/prtview/LoadPortalFileDialog.h create mode 100644 contrib/prtview/PrtView.aps create mode 100644 contrib/prtview/PrtView.def create mode 100644 contrib/prtview/PrtView.rc create mode 100644 contrib/prtview/PrtView.txt create mode 100644 contrib/prtview/PrtView.vcproj create mode 100644 contrib/prtview/gtkdlgs.cpp create mode 100644 contrib/prtview/gtkdlgs.h create mode 100644 contrib/prtview/portals.cpp create mode 100644 contrib/prtview/portals.h create mode 100644 contrib/prtview/prtview.cpp create mode 100644 contrib/prtview/prtview.h create mode 100644 contrib/prtview/res/PrtView.rc2 create mode 100644 contrib/prtview/resource.h create mode 100644 contrib/prtview/stdafx.cpp create mode 100644 contrib/prtview/stdafx.h create mode 100644 docs/developer/.cvsignore create mode 100644 docs/developer/CHANGES create mode 100644 docs/developer/DRAFT create mode 100644 docs/developer/HEAP create mode 100644 docs/developer/Inspector/Inspectors.argo create mode 100644 docs/developer/Inspector/Inspectors.xmi create mode 100644 docs/developer/Inspector/Inspectors_classdiagram1.pgml create mode 100644 docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml create mode 100644 docs/developer/Inspector/Inspectors_usecasediagram1.pgml create mode 100644 docs/developer/Inspector/classdiagram1.gif create mode 100644 docs/developer/Inspector/collaborationdiagram1.pgml create mode 100644 docs/developer/Inspector/inspector.txt create mode 100644 docs/developer/RegExp/Go create mode 100644 docs/developer/RegExp/Go.cleaned create mode 100644 docs/developer/RegExp/pattern create mode 100644 docs/developer/RegExp/replace.pl create mode 100644 docs/developer/RegExp/tstscrpt.pl create mode 100644 docs/developer/TESTERS create mode 100644 docs/developer/TODO create mode 100644 docs/developer/TstMaps/Desktop_pb_leaf.map create mode 100644 docs/developer/TstMaps/komap1.map create mode 100644 docs/developer/TstMaps/realloc.map create mode 100644 docs/developer/TstMaps/sput.map create mode 100644 docs/developer/TstMaps/ttq3dm3.map create mode 100644 docs/developer/TstMaps/western.map create mode 100644 docs/developer/UML/modules.zargo create mode 100644 docs/developer/WIN32BETA create mode 100644 docs/developer/WIN32SETUP create mode 100644 docs/developer/XML.txt create mode 100644 docs/developer/XMLPush/ReadMe.txt create mode 100644 docs/developer/XMLPush/StdAfx.cpp create mode 100644 docs/developer/XMLPush/StdAfx.h create mode 100644 docs/developer/XMLPush/XMLDump.xml create mode 100644 docs/developer/XMLPush/XMLPush.cpp create mode 100644 docs/developer/XMLmap.txt create mode 100644 docs/developer/changes.201.202 create mode 100644 docs/developer/d2u create mode 100644 docs/developer/data-driven-design.txt create mode 100644 docs/developer/frp create mode 100644 docs/developer/q3mapfeedback.txt create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image004.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image006.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image008.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image020.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image022.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image026.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image032.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image034.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image038.png create mode 100644 docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image040.png create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_a.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_c.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_d.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_e.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/appn_f.htm create mode 100644 docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm create mode 100644 docs/manual/Q3Rad_Manual/ch01/pg1_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch01/pg1_2.htm create mode 100644 docs/manual/Q3Rad_Manual/ch02/pg2_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch03/pg3_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch04/pg4_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch05/pg5_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch06/pg6_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch07/pg7_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch08/pg8_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch09/pg9_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch10/pg10_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch11/pg11_1.htm create mode 100644 docs/manual/Q3Rad_Manual/ch12/pg12_1.htm create mode 100644 docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm create mode 100644 docs/manual/Q3Rad_Manual/index.htm create mode 100644 docs/manual/Q3Rad_Manual/styles/q3rad.css create mode 100644 docs/manual/quake3/Compile_Manual/bspc.txt create mode 100644 docs/manual/quake3/Compile_Manual/cfgq3.c create mode 100644 docs/manual/quake3/Compile_Manual/headskins.txt create mode 100644 docs/manual/quake3/Compile_Manual/index.html create mode 100644 docs/manual/quake3/Compile_Manual/modelskins.txt create mode 100644 docs/manual/quake3/Compile_Manual/q3map.html create mode 100644 docs/manual/quake3/Model_Manual/model_manual.htm create mode 100644 docs/manual/quake3/Model_Manual/styles/q3rad.css create mode 100644 docs/manual/quake3/New_Teams_For_Q3TA/index.html create mode 100644 docs/manual/quake3/Q3AShader_Manual/appendix/appA.html create mode 100644 docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/index.htm create mode 100644 docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg create mode 100644 docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/STROGGS.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/THEFALLEN.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif create mode 100644 docs/manual/quake3/Team_Arena_Mapping_Help/start.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/Image3.gif create mode 100644 docs/manual/quake3/Terrain_Manual/pages/Image4.gif create mode 100644 docs/manual/quake3/Terrain_Manual/pages/Image5.gif create mode 100644 docs/manual/quake3/Terrain_Manual/pages/Image6.gif create mode 100644 docs/manual/quake3/Terrain_Manual/pages/adding_bots.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/adding_buildings_to_terrain.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/art_tools.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/blocking_vis.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/boxing_in_the_world.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/clipping_the_terrain.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/creating_the_alphamap.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/creating_the_terrain.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/entity_keys_and_values.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/glossary.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/height_map_into_terrain_mesh.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/height_maps.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/introduction.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/key_changes.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/lighting_the_terrain.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/manipulating_the_terrain_mesh.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/mapping_the_textures.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/new_or_revised_q3map_shader_comm.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/other_possible_height_map_tools.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/related_links.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/suggested_gensurf_settings.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/table_of_contents.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/terrain_entity.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/terrain_mesh_into_terrain_entity.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/terrain_related_worldspawn_features.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/terrain_texture.html create mode 100644 docs/manual/quake3/Terrain_Manual/pages/the_meta_shader.html create mode 100644 docs/manual/quake3/Terrain_Manual/pics/background.jpg create mode 100644 docs/manual/quake3/Terrain_Manual/pics/start.gif create mode 100644 docs/manual/quake3/Terrain_Manual/pics/terrain.jpg create mode 100644 docs/manual/quake3/Terrain_Manual/start.html create mode 100644 gen.readme create mode 100644 gen.vcproj create mode 100644 gendox create mode 100644 include/.cvsignore create mode 100644 include/aboutmsg.default create mode 100644 include/aboutmsg.h create mode 100644 include/gtkr_list.h create mode 100644 include/gtkr_vector.h create mode 100644 include/ibrush.h create mode 100644 include/ibspfrontend.h create mode 100644 include/icamera.h create mode 100644 include/idata.h create mode 100644 include/idatastream.h create mode 100644 include/ieclass.h create mode 100644 include/ientity.h create mode 100644 include/ifilesystem.h create mode 100644 include/igl.h create mode 100644 include/iimage.h create mode 100644 include/imap.h create mode 100644 include/imodel.h create mode 100644 include/ipatch.h create mode 100644 include/iplugin.h create mode 100644 include/irefcount.h create mode 100644 include/iscriplib.h create mode 100644 include/iselectedface.h create mode 100644 include/ishaders.h create mode 100644 include/ishadersmanager.h create mode 100644 include/isurfaceplugin.h create mode 100644 include/itoolbar.h create mode 100644 include/iui.h create mode 100644 include/iui_gtk.h create mode 100644 include/iundo.h create mode 100644 include/misc_def.h create mode 100644 include/qerplugin.h create mode 100644 include/qertypes.h create mode 100644 include/qsysprintf.h create mode 100644 include/stl_check.h create mode 100644 include/stream_version.h create mode 100644 include/version.default create mode 100644 include/version.h create mode 100644 install.py create mode 100644 libs/.cvsignore create mode 100644 libs/bytebool.h create mode 100644 libs/cmdlib.h create mode 100644 libs/cmdlib/.cvsignore create mode 100644 libs/cmdlib/.cvswrappers create mode 100644 libs/cmdlib/cmdlib.cpp create mode 100644 libs/cmdlib/cmdlib.vcproj create mode 100644 libs/ddslib.h create mode 100644 libs/ddslib/ddslib.c create mode 100644 libs/ddslib/ddslib.vcproj create mode 100644 libs/igl_to_qgl.h create mode 100644 libs/jpeg6/.cvsignore create mode 100644 libs/jpeg6/.cvswrappers create mode 100644 libs/jpeg6/jchuff.h create mode 100644 libs/jpeg6/jcomapi.cpp create mode 100644 libs/jpeg6/jconfig.h create mode 100644 libs/jpeg6/jdapimin.cpp create mode 100644 libs/jpeg6/jdapistd.cpp create mode 100644 libs/jpeg6/jdatasrc.cpp create mode 100644 libs/jpeg6/jdcoefct.cpp create mode 100644 libs/jpeg6/jdcolor.cpp create mode 100644 libs/jpeg6/jdct.h create mode 100644 libs/jpeg6/jddctmgr.cpp create mode 100644 libs/jpeg6/jdhuff.cpp create mode 100644 libs/jpeg6/jdhuff.h create mode 100644 libs/jpeg6/jdinput.cpp create mode 100644 libs/jpeg6/jdmainct.cpp create mode 100644 libs/jpeg6/jdmarker.cpp create mode 100644 libs/jpeg6/jdmaster.cpp create mode 100644 libs/jpeg6/jdpostct.cpp create mode 100644 libs/jpeg6/jdsample.cpp create mode 100644 libs/jpeg6/jdtrans.cpp create mode 100644 libs/jpeg6/jerror.cpp create mode 100644 libs/jpeg6/jerror.h create mode 100644 libs/jpeg6/jfdctflt.cpp create mode 100644 libs/jpeg6/jidctflt.cpp create mode 100644 libs/jpeg6/jinclude.h create mode 100644 libs/jpeg6/jmemmgr.cpp create mode 100644 libs/jpeg6/jmemnobs.cpp create mode 100644 libs/jpeg6/jmemsys.h create mode 100644 libs/jpeg6/jmorecfg.h create mode 100644 libs/jpeg6/jpeg6.vcproj create mode 100644 libs/jpeg6/jpegint.h create mode 100644 libs/jpeg6/jpgload.cpp create mode 100644 libs/jpeg6/jutils.cpp create mode 100644 libs/jpeg6/jversion.h create mode 100644 libs/jpeglib.h create mode 100644 libs/l_net/.cvsignore create mode 100644 libs/l_net/l_net.c create mode 100644 libs/l_net/l_net.h create mode 100644 libs/l_net/l_net.vcproj create mode 100644 libs/l_net/l_net_berkley.c create mode 100644 libs/l_net/l_net_wins.c create mode 100644 libs/l_net/l_net_wins.h create mode 100644 libs/mathlib.h create mode 100644 libs/mathlib/bbox.c create mode 100644 libs/mathlib/linear.c create mode 100644 libs/mathlib/m4x4.c create mode 100644 libs/mathlib/mathlib.c create mode 100644 libs/mathlib/mathlib.vcproj create mode 100644 libs/mathlib/ray.c create mode 100644 libs/md5lib.h create mode 100644 libs/md5lib/Conscript create mode 100644 libs/md5lib/md5lib.c create mode 100644 libs/md5lib/md5lib.vcproj create mode 100644 libs/missing.h create mode 100644 libs/multimon.h create mode 100644 libs/pak/.cvsignore create mode 100644 libs/pak/.cvswrappers create mode 100644 libs/pak/pakstuff.cpp create mode 100644 libs/pak/unzip.cpp create mode 100644 libs/pak/unzip.h create mode 100644 libs/pakstuff.h create mode 100644 libs/picomodel.h create mode 100644 libs/picomodel/lwo/clip.c create mode 100644 libs/picomodel/lwo/envelope.c create mode 100644 libs/picomodel/lwo/list.c create mode 100644 libs/picomodel/lwo/lwio.c create mode 100644 libs/picomodel/lwo/lwo2.c create mode 100644 libs/picomodel/lwo/lwo2.h create mode 100644 libs/picomodel/lwo/lwob.c create mode 100644 libs/picomodel/lwo/pntspols.c create mode 100644 libs/picomodel/lwo/surface.c create mode 100644 libs/picomodel/lwo/vecmath.c create mode 100644 libs/picomodel/lwo/vmap.c create mode 100644 libs/picomodel/picointernal.c create mode 100644 libs/picomodel/picointernal.h create mode 100644 libs/picomodel/picomodel.c create mode 100644 libs/picomodel/picomodel.vcproj create mode 100644 libs/picomodel/picomodules.c create mode 100644 libs/picomodel/pm_3ds.c create mode 100644 libs/picomodel/pm_ase.c create mode 100644 libs/picomodel/pm_fm.c create mode 100644 libs/picomodel/pm_fm.h create mode 100644 libs/picomodel/pm_lwo.c create mode 100644 libs/picomodel/pm_md2.c create mode 100644 libs/picomodel/pm_md3.c create mode 100644 libs/picomodel/pm_mdc.c create mode 100644 libs/picomodel/pm_ms3d.c create mode 100644 libs/picomodel/pm_obj.c create mode 100644 libs/radiant_jpeglib.h create mode 100644 libs/splines/.cvsignore create mode 100644 libs/splines/Splines.vcproj create mode 100644 libs/splines/math_angles.cpp create mode 100644 libs/splines/math_angles.h create mode 100644 libs/splines/math_matrix.cpp create mode 100644 libs/splines/math_matrix.h create mode 100644 libs/splines/math_quaternion.cpp create mode 100644 libs/splines/math_quaternion.h create mode 100644 libs/splines/math_vector.cpp create mode 100644 libs/splines/math_vector.h create mode 100644 libs/splines/q_parse.cpp create mode 100644 libs/splines/q_shared.cpp create mode 100644 libs/splines/q_shared.h create mode 100644 libs/splines/splines.cpp create mode 100644 libs/splines/splines.h create mode 100644 libs/splines/util_list.h create mode 100644 libs/splines/util_str.cpp create mode 100644 libs/splines/util_str.h create mode 100644 libs/str.h create mode 100644 libs/synapse.h create mode 100644 libs/synapse/doc/design.txt create mode 100644 libs/synapse/doc/runtime.txt create mode 100644 libs/synapse/doc/unload.txt create mode 100644 libs/synapse/synapse.cpp create mode 100644 libs/synapse/synapse.vcproj create mode 100644 makeversion.py create mode 100644 osx_setup.py create mode 100644 plugins/config.mk create mode 100644 plugins/eclassfgd/fgd.def create mode 100644 plugins/eclassfgd/fgd.vcproj create mode 100644 plugins/eclassfgd/plugin.cpp create mode 100644 plugins/eclassfgd/plugin.h create mode 100644 plugins/entity/eclassmodel.cpp create mode 100644 plugins/entity/entity.cpp create mode 100644 plugins/entity/entity.def create mode 100644 plugins/entity/entity.h create mode 100644 plugins/entity/entity.vcproj create mode 100644 plugins/entity/entity_entitymodel.cpp create mode 100644 plugins/entity/entity_entitymodel.h create mode 100644 plugins/entity/light.cpp create mode 100644 plugins/entity/light.h create mode 100644 plugins/entity/miscmodel.cpp create mode 100644 plugins/entity/plugin.cpp create mode 100644 plugins/entity/plugin.h create mode 100644 plugins/image/.cvsignore create mode 100644 plugins/image/bmp.cpp create mode 100644 plugins/image/bmp.h create mode 100644 plugins/image/image.cpp create mode 100644 plugins/image/image.def create mode 100644 plugins/image/image.h create mode 100644 plugins/image/image.vcproj create mode 100644 plugins/image/jpeg.cpp create mode 100644 plugins/image/lbmlib.cpp create mode 100644 plugins/image/lbmlib.h create mode 100644 plugins/imagehl/imagehl.cpp create mode 100644 plugins/imagehl/imagehl.def create mode 100644 plugins/imagehl/imagehl.h create mode 100644 plugins/imagehl/imagehl.txt create mode 100644 plugins/imagehl/imagehl.vcproj create mode 100644 plugins/imagehl/lbmlib.cpp create mode 100644 plugins/imagehl/lbmlib.h create mode 100644 plugins/imagem8/imagem8.cpp create mode 100644 plugins/imagem8/imagem8.def create mode 100644 plugins/imagem8/imagem8.h create mode 100644 plugins/imagem8/imagem8.vcproj create mode 100644 plugins/imagem8/m32.cpp create mode 100644 plugins/imagem8/m32.h create mode 100644 plugins/imagem8/m8.cpp create mode 100644 plugins/imagem8/m8.h create mode 100644 plugins/imagepng/imagepng.def create mode 100644 plugins/imagepng/imagepng.vcproj create mode 100644 plugins/imagepng/plugin.cpp create mode 100644 plugins/imagepng/plugin.h create mode 100644 plugins/imagewal/imagewal.cpp create mode 100644 plugins/imagewal/imagewal.def create mode 100644 plugins/imagewal/imagewal.h create mode 100644 plugins/imagewal/imagewal.vcproj create mode 100644 plugins/imagewal/q2_palette.h create mode 100644 plugins/imagewal/wal.cpp create mode 100644 plugins/imagewal/wal.h create mode 100644 plugins/map/map.def create mode 100644 plugins/map/map.vcproj create mode 100644 plugins/map/parse.cpp create mode 100644 plugins/map/plugin.cpp create mode 100644 plugins/map/plugin.h create mode 100644 plugins/map/write.cpp create mode 100644 plugins/mapxml/mapxml.def create mode 100644 plugins/mapxml/mapxml.vcproj create mode 100644 plugins/mapxml/plugin.cpp create mode 100644 plugins/mapxml/plugin.h create mode 100644 plugins/mapxml/xmlparse.cpp create mode 100644 plugins/mapxml/xmlwrite.cpp create mode 100644 plugins/model/bitmaps/model_reload_entity.bmp create mode 100644 plugins/model/bitmaps/picomodel.bmp create mode 100644 plugins/model/cpicomodel.cpp create mode 100644 plugins/model/cpicomodel.h create mode 100644 plugins/model/cpicosurface.cpp create mode 100644 plugins/model/cpicosurface.h create mode 100644 plugins/model/miscmodel.cpp create mode 100644 plugins/model/model.cpp create mode 100644 plugins/model/model.def create mode 100644 plugins/model/model.vcproj create mode 100644 plugins/model/plugin.cpp create mode 100644 plugins/model/plugin.h create mode 100644 plugins/model/remap.cpp create mode 100644 plugins/model/surface.h create mode 100644 plugins/shaders/plugin.cpp create mode 100644 plugins/shaders/plugin.h create mode 100644 plugins/shaders/shaders.cpp create mode 100644 plugins/shaders/shaders.def create mode 100644 plugins/shaders/shaders.h create mode 100644 plugins/shaders/shaders.proj create mode 100644 plugins/shaders/shaders.vcproj create mode 100644 plugins/shaders/shadershl.def create mode 100644 plugins/spritemodel/plugin.cpp create mode 100644 plugins/spritemodel/plugin.h create mode 100644 plugins/spritemodel/spritemodel.cpp create mode 100644 plugins/spritemodel/spritemodel.def create mode 100644 plugins/spritemodel/spritemodel.h create mode 100644 plugins/spritemodel/spritemodel.vcproj create mode 100644 plugins/surface/.cvsignore create mode 100644 plugins/surface/surface.def create mode 100644 plugins/surface/surface.vcproj create mode 100644 plugins/surface/surfacedialog.cpp create mode 100644 plugins/surface/surfacedialog.h create mode 100644 plugins/surface/surfdlg_plugin.cpp create mode 100644 plugins/surface/surfdlg_plugin.h create mode 100644 plugins/surface_heretic2/surface_heretic2.def create mode 100644 plugins/surface_heretic2/surface_heretic2.vcproj create mode 100644 plugins/surface_heretic2/surfacedialog.cpp create mode 100644 plugins/surface_heretic2/surfacedialog.h create mode 100644 plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp create mode 100644 plugins/surface_heretic2/surfaceflagsdialog_heretic2.h create mode 100644 plugins/surface_heretic2/surfdlg_plugin.cpp create mode 100644 plugins/surface_heretic2/surfdlg_plugin.h create mode 100644 plugins/surface_quake2/surface_quake2.def create mode 100644 plugins/surface_quake2/surface_quake2.vcproj create mode 100644 plugins/surface_quake2/surfacedialog.cpp create mode 100644 plugins/surface_quake2/surfacedialog.h create mode 100644 plugins/surface_quake2/surfaceflagsdialog_quake2.cpp create mode 100644 plugins/surface_quake2/surfaceflagsdialog_quake2.h create mode 100644 plugins/surface_quake2/surfdlg_plugin.cpp create mode 100644 plugins/surface_quake2/surfdlg_plugin.h create mode 100644 plugins/textool/.cvsignore create mode 100644 plugins/textool/.cvswrappers create mode 100644 plugins/textool/2DView.cpp create mode 100644 plugins/textool/2DView.h create mode 100644 plugins/textool/ControlPointsManager.cpp create mode 100644 plugins/textool/ControlPointsManager.h create mode 100644 plugins/textool/Doc/.cvswrappers create mode 100644 plugins/textool/Doc/Image2.jpg create mode 100644 plugins/textool/Doc/TexTool.html create mode 100644 plugins/textool/StdAfx.cpp create mode 100644 plugins/textool/StdAfx.h create mode 100644 plugins/textool/TexTool.cpp create mode 100644 plugins/textool/TexTool.def create mode 100644 plugins/textool/TexTool.rc create mode 100644 plugins/textool/TexTool.vcproj create mode 100644 plugins/textool/changelog.txt create mode 100644 plugins/textool/resource.h create mode 100644 plugins/vfspak/vfs.cpp create mode 100644 plugins/vfspak/vfs.h create mode 100644 plugins/vfspak/vfspak.cpp create mode 100644 plugins/vfspak/vfspak.def create mode 100644 plugins/vfspak/vfspak.h create mode 100644 plugins/vfspak/vfspak.vcproj create mode 100644 plugins/vfspk3/.cvsignore create mode 100644 plugins/vfspk3/unzip-vfspk3.h create mode 100644 plugins/vfspk3/unzip.cpp create mode 100644 plugins/vfspk3/vfs.cpp create mode 100644 plugins/vfspk3/vfs.h create mode 100644 plugins/vfspk3/vfspk3.cpp create mode 100644 plugins/vfspk3/vfspk3.def create mode 100644 plugins/vfspk3/vfspk3.h create mode 100644 plugins/vfspk3/vfspk3.proj create mode 100644 plugins/vfspk3/vfspk3.vcproj create mode 100644 plugins/vfswad/unwad.cpp create mode 100644 plugins/vfswad/unwad.h create mode 100644 plugins/vfswad/vfs.cpp create mode 100644 plugins/vfswad/vfs.h create mode 100644 plugins/vfswad/vfswad.cpp create mode 100644 plugins/vfswad/vfswad.def create mode 100644 plugins/vfswad/vfswad.h create mode 100644 plugins/vfswad/vfswad.txt create mode 100644 plugins/vfswad/vfswad.vcproj create mode 100644 radiant.sln create mode 100644 radiant.sln.ref create mode 100644 radiant.xcode/apple.pbxuser create mode 100644 radiant.xcode/project.pbxproj create mode 100644 radiant/.cvsignore create mode 100644 radiant/Makefile.mac create mode 100644 radiant/bitmaps/brush_flipx.bmp create mode 100644 radiant/bitmaps/brush_flipy.bmp create mode 100644 radiant/bitmaps/brush_flipz.bmp create mode 100644 radiant/bitmaps/brush_rotatex.bmp create mode 100644 radiant/bitmaps/brush_rotatey.bmp create mode 100644 radiant/bitmaps/brush_rotatez.bmp create mode 100644 radiant/bitmaps/cap_bevel.bmp create mode 100644 radiant/bitmaps/cap_endcap.bmp create mode 100644 radiant/bitmaps/cap_ibevel.bmp create mode 100644 radiant/bitmaps/cap_iendcap.bmp create mode 100644 radiant/bitmaps/curve_cap.bmp create mode 100644 radiant/bitmaps/dontselectcurve.bmp create mode 100644 radiant/bitmaps/dontselectmodel.bmp create mode 100644 radiant/bitmaps/file_open.bmp create mode 100644 radiant/bitmaps/file_save.bmp create mode 100644 radiant/bitmaps/icon.bmp create mode 100644 radiant/bitmaps/logo.bmp create mode 100644 radiant/bitmaps/patch_bend.bmp create mode 100644 radiant/bitmaps/patch_drilldown.bmp create mode 100644 radiant/bitmaps/patch_insdel.bmp create mode 100644 radiant/bitmaps/patch_showboundingbox.bmp create mode 100644 radiant/bitmaps/patch_weld.bmp create mode 100644 radiant/bitmaps/patch_wireframe.bmp create mode 100644 radiant/bitmaps/popup_selection.bmp create mode 100644 radiant/bitmaps/scalelockx.bmp create mode 100644 radiant/bitmaps/scalelocky.bmp create mode 100644 radiant/bitmaps/scalelockz.bmp create mode 100644 radiant/bitmaps/select_mouserotate.bmp create mode 100644 radiant/bitmaps/select_mousescale.bmp create mode 100644 radiant/bitmaps/selection_csgmerge.bmp create mode 100644 radiant/bitmaps/selection_csgsubtract.bmp create mode 100644 radiant/bitmaps/selection_makehollow.bmp create mode 100644 radiant/bitmaps/selection_selectcompletetall.bmp create mode 100644 radiant/bitmaps/selection_selectinside.bmp create mode 100644 radiant/bitmaps/selection_selectpartialtall.bmp create mode 100644 radiant/bitmaps/selection_selecttouching.bmp create mode 100644 radiant/bitmaps/show_entities.bmp create mode 100644 radiant/bitmaps/splash.bmp create mode 100644 radiant/bitmaps/textures_popup.bmp create mode 100644 radiant/bitmaps/view_cameratoggle.bmp create mode 100644 radiant/bitmaps/view_cameraupdate.bmp create mode 100644 radiant/bitmaps/view_change.bmp create mode 100644 radiant/bitmaps/view_clipper.bmp create mode 100644 radiant/bitmaps/view_cubicclipping.bmp create mode 100644 radiant/bitmaps/view_entity.bmp create mode 100644 radiant/bitmaps/window1.bmp create mode 100644 radiant/bitmaps/window2.bmp create mode 100644 radiant/bitmaps/window3.bmp create mode 100644 radiant/bitmaps/window4.bmp create mode 100644 radiant/bp_dlg.cpp create mode 100644 radiant/brush.cpp create mode 100644 radiant/brush.h create mode 100644 radiant/brush_primit.cpp create mode 100644 radiant/brushscript.cpp create mode 100644 radiant/camera.h create mode 100644 radiant/camwindow.cpp create mode 100644 radiant/camwindow.h create mode 100644 radiant/csg.cpp create mode 100644 radiant/dialog.cpp create mode 100644 radiant/dialog.h create mode 100644 radiant/dialoginfo.cpp create mode 100644 radiant/drag.cpp create mode 100644 radiant/eclass.cpp create mode 100644 radiant/eclass_def.cpp create mode 100644 radiant/eclass_def.h create mode 100644 radiant/error.cpp create mode 100644 radiant/feedback.cpp create mode 100644 radiant/feedback.h create mode 100644 radiant/file.cpp create mode 100644 radiant/file.h create mode 100644 radiant/filters.cpp create mode 100644 radiant/filters.h create mode 100644 radiant/findtexturedialog.cpp create mode 100644 radiant/findtexturedialog.h create mode 100644 radiant/glinterface.cpp create mode 100644 radiant/glwidget.cpp create mode 100644 radiant/glwidget.h create mode 100644 radiant/glwindow.cpp create mode 100644 radiant/glwindow.h create mode 100644 radiant/groupdialog.cpp create mode 100644 radiant/groupdialog.h create mode 100644 radiant/gtkdlgs.cpp create mode 100644 radiant/gtkfilesel-darwin.c create mode 100644 radiant/gtkfilesel-darwin.h create mode 100644 radiant/gtkfilesel-linux.c create mode 100644 radiant/gtkfilesel-linux.h create mode 100644 radiant/gtkfilesel.c create mode 100644 radiant/gtkfilesel.h create mode 100644 radiant/gtkmisc.cpp create mode 100644 radiant/gtkmisc.h create mode 100644 radiant/main.cpp create mode 100644 radiant/mainframe.cpp create mode 100644 radiant/mainframe.h create mode 100644 radiant/map.cpp create mode 100644 radiant/map.h create mode 100644 radiant/missing.cpp create mode 100644 radiant/parse.cpp create mode 100644 radiant/parse.h create mode 100644 radiant/patchdialog.cpp create mode 100644 radiant/patchdialog.h create mode 100644 radiant/plugin.h create mode 100644 radiant/pluginentities.cpp create mode 100644 radiant/pluginmanager.cpp create mode 100644 radiant/pluginmanager.h create mode 100644 radiant/pmesh.cpp create mode 100644 radiant/points.cpp create mode 100644 radiant/points.h create mode 100644 radiant/preferences.cpp create mode 100644 radiant/preferences.h create mode 100644 radiant/profile.cpp create mode 100644 radiant/qe3.cpp create mode 100644 radiant/qe3.h create mode 100644 radiant/qedefs.h create mode 100644 radiant/qfiles.h create mode 100644 radiant/qgl-mac.c create mode 100644 radiant/qgl.c create mode 100644 radiant/qgl.h create mode 100644 radiant/qgl_ext.cpp create mode 100644 radiant/queuedraw.cpp create mode 100644 radiant/radiant.ico create mode 100644 radiant/radiant.rc create mode 100644 radiant/radiant.vcproj create mode 100644 radiant/resource.h create mode 100644 radiant/select.cpp create mode 100644 radiant/select.h create mode 100644 radiant/selectedface.cpp create mode 100644 radiant/stdafx.cpp create mode 100644 radiant/stdafx.h create mode 100644 radiant/surfacedialog.cpp create mode 100644 radiant/surfacedialog.h create mode 100644 radiant/surfaceplugin.cpp create mode 100644 radiant/surfaceplugin.h create mode 100644 radiant/targetname.cpp create mode 100644 radiant/texmanip.cpp create mode 100644 radiant/texmanip.h create mode 100644 radiant/textures.h create mode 100644 radiant/texwindow.cpp create mode 100644 radiant/texwindow.h create mode 100644 radiant/ui.cpp create mode 100644 radiant/ui.h create mode 100644 radiant/undo.cpp create mode 100644 radiant/undo.h create mode 100644 radiant/vertsel.cpp create mode 100644 radiant/watchbsp.cpp create mode 100644 radiant/watchbsp.h create mode 100644 radiant/winding.cpp create mode 100644 radiant/winding.h create mode 100644 radiant/xmlstuff.h create mode 100644 radiant/xywindow.cpp create mode 100644 radiant/xywindow.h create mode 100644 radiant/z.cpp create mode 100644 radiant/z.h create mode 100644 radiant/zwindow.cpp create mode 100644 radiant/zwindow.h create mode 100644 run_python.bat create mode 100644 tools/quake2/common/bspfile.c create mode 100644 tools/quake2/common/bspfile.h create mode 100644 tools/quake2/common/cmdlib.c create mode 100644 tools/quake2/common/cmdlib.h create mode 100644 tools/quake2/common/inout.c create mode 100644 tools/quake2/common/inout.h create mode 100644 tools/quake2/common/l3dslib.c create mode 100644 tools/quake2/common/l3dslib.h create mode 100644 tools/quake2/common/lbmlib.c create mode 100644 tools/quake2/common/lbmlib.h create mode 100644 tools/quake2/common/mathlib.c create mode 100644 tools/quake2/common/mathlib.h create mode 100644 tools/quake2/common/md4.c create mode 100644 tools/quake2/common/path_init.c create mode 100644 tools/quake2/common/polylib.c create mode 100644 tools/quake2/common/polylib.h create mode 100644 tools/quake2/common/q2_threads.h create mode 100644 tools/quake2/common/qfiles.h create mode 100644 tools/quake2/common/scriplib.c create mode 100644 tools/quake2/common/scriplib.h create mode 100644 tools/quake2/common/threads.c create mode 100644 tools/quake2/common/trilib.c create mode 100644 tools/quake2/common/trilib.h create mode 100644 tools/quake2/q2map/brushbsp.c create mode 100644 tools/quake2/q2map/csg.c create mode 100644 tools/quake2/q2map/faces.c create mode 100644 tools/quake2/q2map/flow.c create mode 100644 tools/quake2/q2map/gldraw.c create mode 100644 tools/quake2/q2map/glfile.c create mode 100644 tools/quake2/q2map/leakfile.c create mode 100644 tools/quake2/q2map/lightmap.c create mode 100644 tools/quake2/q2map/main.c create mode 100644 tools/quake2/q2map/map.c create mode 100644 tools/quake2/q2map/nodraw.c create mode 100644 tools/quake2/q2map/patches.c create mode 100644 tools/quake2/q2map/portals.c create mode 100644 tools/quake2/q2map/prtfile.c create mode 100644 tools/quake2/q2map/q2map.h create mode 100644 tools/quake2/q2map/q2map.vcproj create mode 100644 tools/quake2/q2map/qbsp.c create mode 100644 tools/quake2/q2map/qbsp.h create mode 100644 tools/quake2/q2map/qrad.c create mode 100644 tools/quake2/q2map/qrad.h create mode 100644 tools/quake2/q2map/qvis.c create mode 100644 tools/quake2/q2map/qvis.h create mode 100644 tools/quake2/q2map/textures.c create mode 100644 tools/quake2/q2map/trace.c create mode 100644 tools/quake2/q2map/tree.c create mode 100644 tools/quake2/q2map/writebsp.c create mode 100644 tools/quake2/qdata/anorms.h create mode 100644 tools/quake2/qdata/images.c create mode 100644 tools/quake2/qdata/makefile create mode 100644 tools/quake2/qdata/models.c create mode 100644 tools/quake2/qdata/qdata.c create mode 100644 tools/quake2/qdata/qdata.h create mode 100644 tools/quake2/qdata/qdata3.vcproj create mode 100644 tools/quake2/qdata/sprites.c create mode 100644 tools/quake2/qdata/tables.c create mode 100644 tools/quake2/qdata/video.c create mode 100644 tools/quake2/qdata_heretic2/adpcm.h create mode 100644 tools/quake2/qdata_heretic2/animcomp.c create mode 100644 tools/quake2/qdata_heretic2/animcomp.h create mode 100644 tools/quake2/qdata_heretic2/anorms.h create mode 100644 tools/quake2/qdata_heretic2/book.c create mode 100644 tools/quake2/qdata_heretic2/common/bspfile.c create mode 100644 tools/quake2/qdata_heretic2/common/bspfile.h create mode 100644 tools/quake2/qdata_heretic2/common/cmdlib.c create mode 100644 tools/quake2/qdata_heretic2/common/cmdlib.h create mode 100644 tools/quake2/qdata_heretic2/common/her2_threads.h create mode 100644 tools/quake2/qdata_heretic2/common/inout.c create mode 100644 tools/quake2/qdata_heretic2/common/inout.h create mode 100644 tools/quake2/qdata_heretic2/common/l3dslib.c create mode 100644 tools/quake2/qdata_heretic2/common/l3dslib.h create mode 100644 tools/quake2/qdata_heretic2/common/lbmlib.c create mode 100644 tools/quake2/qdata_heretic2/common/lbmlib.h create mode 100644 tools/quake2/qdata_heretic2/common/mathlib.c create mode 100644 tools/quake2/qdata_heretic2/common/mathlib.h create mode 100644 tools/quake2/qdata_heretic2/common/md4.c create mode 100644 tools/quake2/qdata_heretic2/common/path_init.c create mode 100644 tools/quake2/qdata_heretic2/common/polylib.c create mode 100644 tools/quake2/qdata_heretic2/common/polylib.h create mode 100644 tools/quake2/qdata_heretic2/common/qfiles.c create mode 100644 tools/quake2/qdata_heretic2/common/qfiles.h create mode 100644 tools/quake2/qdata_heretic2/common/scriplib.c create mode 100644 tools/quake2/qdata_heretic2/common/scriplib.h create mode 100644 tools/quake2/qdata_heretic2/common/threads.c create mode 100644 tools/quake2/qdata_heretic2/common/token.c create mode 100644 tools/quake2/qdata_heretic2/common/token.h create mode 100644 tools/quake2/qdata_heretic2/common/trilib.c create mode 100644 tools/quake2/qdata_heretic2/common/trilib.h create mode 100644 tools/quake2/qdata_heretic2/fmodels.c create mode 100644 tools/quake2/qdata_heretic2/icon1.ico create mode 100644 tools/quake2/qdata_heretic2/images.c create mode 100644 tools/quake2/qdata_heretic2/jointed.c create mode 100644 tools/quake2/qdata_heretic2/jointed.h create mode 100644 tools/quake2/qdata_heretic2/joints.h create mode 100644 tools/quake2/qdata_heretic2/models.c create mode 100644 tools/quake2/qdata_heretic2/pics.c create mode 100644 tools/quake2/qdata_heretic2/qcommon/angles.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/arrayedlist.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/flex.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/fmodel.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/h2common.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/placement.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/q_typedef.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/qfiles.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/reference.c create mode 100644 tools/quake2/qdata_heretic2/qcommon/reference.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/resourcemanager.c create mode 100644 tools/quake2/qdata_heretic2/qcommon/resourcemanager.h create mode 100644 tools/quake2/qdata_heretic2/qcommon/skeletons.c create mode 100644 tools/quake2/qdata_heretic2/qcommon/skeletons.h create mode 100644 tools/quake2/qdata_heretic2/qd_fmodel.h create mode 100644 tools/quake2/qdata_heretic2/qd_skeletons.c create mode 100644 tools/quake2/qdata_heretic2/qd_skeletons.h create mode 100644 tools/quake2/qdata_heretic2/qdata.c create mode 100644 tools/quake2/qdata_heretic2/qdata.h create mode 100644 tools/quake2/qdata_heretic2/qdata3_heretic2.vcproj create mode 100644 tools/quake2/qdata_heretic2/resource.h create mode 100644 tools/quake2/qdata_heretic2/script1.aps create mode 100644 tools/quake2/qdata_heretic2/script1.rc create mode 100644 tools/quake2/qdata_heretic2/sprites.c create mode 100644 tools/quake2/qdata_heretic2/svdcmp.c create mode 100644 tools/quake2/qdata_heretic2/tables.c create mode 100644 tools/quake2/qdata_heretic2/tmix.c create mode 100644 tools/quake2/qdata_heretic2/video.c create mode 100644 tools/quake3/common/aselib.c create mode 100644 tools/quake3/common/aselib.h create mode 100644 tools/quake3/common/bspfile.c create mode 100644 tools/quake3/common/bspfile.h create mode 100644 tools/quake3/common/cmdlib.c create mode 100644 tools/quake3/common/cmdlib.h create mode 100644 tools/quake3/common/imagelib.c create mode 100644 tools/quake3/common/imagelib.h create mode 100644 tools/quake3/common/inout.c create mode 100644 tools/quake3/common/inout.h create mode 100644 tools/quake3/common/l3dslib.c create mode 100644 tools/quake3/common/l3dslib.h create mode 100644 tools/quake3/common/md4.c create mode 100644 tools/quake3/common/mutex.c create mode 100644 tools/quake3/common/mutex.h create mode 100644 tools/quake3/common/polylib.c create mode 100644 tools/quake3/common/polylib.h create mode 100644 tools/quake3/common/polyset.h create mode 100644 tools/quake3/common/qfiles.h create mode 100644 tools/quake3/common/qthreads.h create mode 100644 tools/quake3/common/scriplib.c create mode 100644 tools/quake3/common/scriplib.h create mode 100644 tools/quake3/common/surfaceflags.h create mode 100644 tools/quake3/common/threads.c create mode 100644 tools/quake3/common/trilib.c create mode 100644 tools/quake3/common/trilib.h create mode 100644 tools/quake3/common/unzip.c create mode 100644 tools/quake3/common/unzip.h create mode 100644 tools/quake3/common/vfs.c create mode 100644 tools/quake3/common/vfs.h create mode 100644 tools/quake3/q3data/.cvsignore create mode 100644 tools/quake3/q3data/.cvswrappers create mode 100644 tools/quake3/q3data/3dslib.c create mode 100644 tools/quake3/q3data/3dslib.h create mode 100644 tools/quake3/q3data/compress.c create mode 100644 tools/quake3/q3data/images.c create mode 100644 tools/quake3/q3data/md3lib.c create mode 100644 tools/quake3/q3data/md3lib.h create mode 100644 tools/quake3/q3data/models.c create mode 100644 tools/quake3/q3data/oldstuff.c create mode 100644 tools/quake3/q3data/p3dlib.c create mode 100644 tools/quake3/q3data/p3dlib.h create mode 100644 tools/quake3/q3data/polyset.c create mode 100644 tools/quake3/q3data/q3data.c create mode 100644 tools/quake3/q3data/q3data.h create mode 100644 tools/quake3/q3data/q3data.vcproj create mode 100644 tools/quake3/q3data/stripper.c create mode 100644 tools/quake3/q3data/video.c create mode 100644 tools/quake3/q3map2/.cvsignore create mode 100644 tools/quake3/q3map2/brush.c create mode 100644 tools/quake3/q3map2/brush_primit.c create mode 100644 tools/quake3/q3map2/bsp.c create mode 100644 tools/quake3/q3map2/bspfile_abstract.c create mode 100644 tools/quake3/q3map2/bspfile_ibsp.c create mode 100644 tools/quake3/q3map2/bspfile_rbsp.c create mode 100644 tools/quake3/q3map2/changelog.q3map1 create mode 100644 tools/quake3/q3map2/changelog.q3map2.txt create mode 100644 tools/quake3/q3map2/convert_ase.c create mode 100644 tools/quake3/q3map2/convert_map.c create mode 100644 tools/quake3/q3map2/decals.c create mode 100644 tools/quake3/q3map2/facebsp.c create mode 100644 tools/quake3/q3map2/fog.c create mode 100644 tools/quake3/q3map2/game_ef.h create mode 100644 tools/quake3/q3map2/game_ja.h create mode 100644 tools/quake3/q3map2/game_jk2.h create mode 100644 tools/quake3/q3map2/game_quake3.h create mode 100644 tools/quake3/q3map2/game_sof2.h create mode 100644 tools/quake3/q3map2/game_t.h create mode 100644 tools/quake3/q3map2/game_tenebrae.h create mode 100644 tools/quake3/q3map2/game_wolf.h create mode 100644 tools/quake3/q3map2/game_wolfet.h create mode 100644 tools/quake3/q3map2/image.c create mode 100644 tools/quake3/q3map2/leakfile.c create mode 100644 tools/quake3/q3map2/light.c create mode 100644 tools/quake3/q3map2/light_bounce.c create mode 100644 tools/quake3/q3map2/light_shadows.c create mode 100644 tools/quake3/q3map2/light_trace.c create mode 100644 tools/quake3/q3map2/light_ydnar.c create mode 100644 tools/quake3/q3map2/lightmaps.c create mode 100644 tools/quake3/q3map2/lightmaps_ydnar.c create mode 100644 tools/quake3/q3map2/listen.pl create mode 100644 tools/quake3/q3map2/main.c create mode 100644 tools/quake3/q3map2/map.c create mode 100644 tools/quake3/q3map2/mesh.c create mode 100644 tools/quake3/q3map2/model.c create mode 100644 tools/quake3/q3map2/patch.c create mode 100644 tools/quake3/q3map2/path_init.c create mode 100644 tools/quake3/q3map2/portals.c create mode 100644 tools/quake3/q3map2/prtfile.c create mode 100644 tools/quake3/q3map2/q3map2.h create mode 100644 tools/quake3/q3map2/q3map2.ico create mode 100644 tools/quake3/q3map2/q3map2.rc create mode 100644 tools/quake3/q3map2/q3map2.vcproj create mode 100644 tools/quake3/q3map2/shaders.c create mode 100644 tools/quake3/q3map2/surface.c create mode 100644 tools/quake3/q3map2/surface_extra.c create mode 100644 tools/quake3/q3map2/surface_foliage.c create mode 100644 tools/quake3/q3map2/surface_fur.c create mode 100644 tools/quake3/q3map2/surface_meta.c create mode 100644 tools/quake3/q3map2/tjunction.c create mode 100644 tools/quake3/q3map2/tree.c create mode 100644 tools/quake3/q3map2/vis.c create mode 100644 tools/quake3/q3map2/visflow.c create mode 100644 tools/quake3/q3map2/writebsp.c create mode 100644 win32_install.py create mode 100644 www/bug.shtml create mode 100644 www/coding.html create mode 100644 www/files.html create mode 100644 www/gtkradiant.html create mode 100644 www/hosted.html create mode 100644 www/index.html create mode 100644 www/reviews.html diff --git a/BSD b/BSD new file mode 100644 index 00000000..79fe1f97 --- /dev/null +++ b/BSD @@ -0,0 +1,28 @@ +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. + diff --git a/CHANGES-MACOS b/CHANGES-MACOS new file mode 100644 index 00000000..fbe54618 --- /dev/null +++ b/CHANGES-MACOS @@ -0,0 +1,11 @@ +Changes file for the MacOS port of GtkRadiant 1.1-TA +---------------------------------------------------- +05/24/2001 +TTimo + Patching the MacOS branch to build on linux +04/15/2001 +Pradeep + Changes so that the whole project compiles under MacOSX/XFree. +03/28/2001 +TTimo + added this file and gave write access to pradeep on the tree (testing write access) diff --git a/COMPILING b/COMPILING new file mode 100644 index 00000000..a53331be --- /dev/null +++ b/COMPILING @@ -0,0 +1,7 @@ + * understand relative paths in the .game file + * ignore warnings: 4996 4244 4267 + ( some CRT API warning stuff, and size conversion warnings) + * using the same updated Gtk win32 as GtkR 1.5 (may be packaged a bit differently for sanity) + * converted the project files to VC8 + * disabled all the modules that are not necessary for Q3 editing + * default parameters can't be used in function typedefs anymore, removed those and fixed the code accordingly diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 00000000..3cfab6d2 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,65 @@ +GtkRadiant CONTRIBUTORS and CREDITS +last update: 01/15/2001 +======================= + +Loki +---- +Leonardo Zide leo@lokigames.com +Mike Phillips (Loki QA) +Bernd Kreimeier (overall coordination) + +QER.com +------- +TTimo timo@qeradiant.com +^Fishman (Pablo Zurita) fish@gamedesign.net +RR2DO2 rr2do2@q3f.com + +Curry plugin +------------ +Mike "mickey" Jackman +Tim "Maj" Rennie +William "SmallPileOfGibs" Joseph + +PrtView plugin, various bug fixes and q3map guru +------------------------------------------------ +Geoffrey DeWan + +Gensurf plugin +-------------- +David Hyde + +PicoModel +--------- +seaw0lf with assist by ydnar + +Q3Map2 +------ +Randy 'ydnar' Reddig + +Updated shader files, textures, entities.def, keyboard shortcut list +overall testing and feedback +---------------------------- +Jean-Francois "Eutectic" Groleau + +Improvements and bug fixing +--------------------------- +Jan Paul "MrElusive" van Waveren +Robert Duffy + +Web +--- +Dave "Bargle" Koenig and Jason "Wolfen" Spencer + +Thanks to John Hutton, AstroCreep and W2k for web help + +FAQ +--- +Equim and Wex + +Misc +---- +Thanks to everyone on the beta mailing list and +irc.telefragged.com #qeradiant for testing and feedback. +Updated icons by AstroCreep! +Bitch-slapping by RaYGunn! +Last minute bugs by SpoG! (SpoG--) diff --git a/CONTRIBUTOR_AGREEMENT b/CONTRIBUTOR_AGREEMENT new file mode 100644 index 00000000..e69de29b diff --git a/DarwinCompileInfo.rtf b/DarwinCompileInfo.rtf new file mode 100644 index 00000000..ff5cfb16 --- /dev/null +++ b/DarwinCompileInfo.rtf @@ -0,0 +1,55 @@ +{\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww9000\viewh9000\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\fs24 \cf0 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 Install XFree86\ + see\ + http://xfree86.org and http://mrcla.com/XonX \ + on installing X Window System on your OS X\ +\ +Download these:\ +ftp://gnu-darwin.sourceforge.net/pub/gnu-darwin/gtk+-1.2.8.tgz\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 ftp://gnu-darwin.sourceforge.net/pub/gnu-darwin/Mesa-3.4.tgz\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 Untar these with \ + tar xzvf gtk+-1.2.8.tgz\ + tar xzvf Mesa-3.4.tgz\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 \ +change to root , go into these directory and type:\ +make install\ +(This will install gtk and Mesa)\ +\ +download this:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 http://prdownloads.sourceforge.net/fink/dlcompat-20010123.tar.gz\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 tar xzvf dlcompat*\ +cd dlcompat*\ +make\ +make install # do this as soot\ +\ +cd GtkRadiant/libs/libxml2/\ +./configure\ +make\ +make install\ +\ +cd GtkRadiant/libs/\ +make\ +\ +cd GtrRadiant/tools/\ +make\ +(This will give you a q3map executable )\ +\ +cd GtkRadiant/radiant/\ +make\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 (This will give you a radiant executable )\ +\ +} diff --git a/DoxyConfig b/DoxyConfig new file mode 100644 index 00000000..fc7f6821 --- /dev/null +++ b/DoxyConfig @@ -0,0 +1,47 @@ +# Included Doxygen Config file +#--------------------------------------------------------------------------- +# Project name & version number +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = + +#--------------------------------------------------------------------------- +# Where to put the output +# Note: The images dir should be next to the created html dir within the +# output dir. +# eg; +# [Current Dir] +# L__[OUTPUT_DIRECTORY] +# L__[html] +# L__[images] +#--------------------------------------------------------------------------- +OUTPUT_DIRECTORY = ../GtkRadiant-doxygen + +#--------------------------------------------------------------------------- +# Where to read the sources +# you can add more than one source... +# INPUT = radiant/ \ +# tools/quake3/q3map \ +# tools/quake3/q3data +# +# Recursive is set on, so setting it to ./ (current dir) would read source +# files recursively from the current dir down. (which would take a while) +# +# eg: To document just include, if the current directory is ../GtkRadiant/ +# then... +#--------------------------------------------------------------------------- +INPUT = GtkRadiant/include/ + +#--------------------------------------------------------------------------- +# Misc settings +# TAB_SIZE - sets the indenting for the inline source and the source +# browser +# INCLUDE_PATH - will include documentation for included files from other +# packages. You can specify more than one path the same as +# shown in the INPUT example Leave it blank if you don't want +# this. +# PERL_PATH - path to the perl executable +# +#--------------------------------------------------------------------------- +PERL_PATH = /usr/bin/perl + diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..a992b3d4 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,170 @@ +# Doxyfile 1.2.5-20010304 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +INTERNAL_DOCS = YES +CLASS_DIAGRAMS = YES +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = +ENABLED_SECTIONS = +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = doxygen.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.c +RECURSIVE = YES +EXCLUDE = *.dsp \ + *.dsw \ + *.o \ + *.d \ + *.ico \ + *.bmp \ + *.txt \ + *.rc \ + Entries \ + Entries.Log \ + Repository \ + Root +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = Doxygen_extras/doxygen_gtkradiant_head.html +HTML_FOOTER = Doxygen_extras/doxygen_gtkradiant_foot.html +HTML_STYLESHEET = Doxygen_extras/doxygen_gtkradiant.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = + +#--------------------------------------------------------------------------- +# Include file, at the bottom to over-ride anything I missed. +#--------------------------------------------------------------------------- +@INCLUDE = DoxyConfig diff --git a/Doxygen_files/Doxyfile b/Doxygen_files/Doxyfile new file mode 100644 index 00000000..912e2b99 --- /dev/null +++ b/Doxygen_files/Doxyfile @@ -0,0 +1,159 @@ +# Doxyfile 1.2.5-20010304 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +INTERNAL_DOCS = YES +CLASS_DIAGRAMS = YES +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +ENABLED_SECTIONS = +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = doxygen.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.c +RECURSIVE = YES +EXCLUDE = +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = Doxygen_files/doxygen_gtkradiant_head.html +HTML_FOOTER = Doxygen_files/doxygen_gtkradiant_foot.html +HTML_STYLESHEET = Doxygen_files/doxygen_gtkradiant.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = + +#--------------------------------------------------------------------------- +# Include file, at the bottom to over-ride anything I missed. +#--------------------------------------------------------------------------- +@INCLUDE = genConf \ No newline at end of file diff --git a/Doxygen_files/doxy_mainpage.h b/Doxygen_files/doxy_mainpage.h new file mode 100644 index 00000000..34e4bc50 --- /dev/null +++ b/Doxygen_files/doxy_mainpage.h @@ -0,0 +1,45 @@ +/* +** Doxygen index.html generation file +** +*/ + +/*! \mainpage +project+ Doxygen Index + + \section intro Introduction + + This documentation was generated from GtkRadiant source code using Doxygen.
+ Generated from source in: +target+ + + \section links Links + General Links
+ Doxygen Homepage
+ GtkRadiant Homepage
+ Zerowing - GtkRadiant Development
+ + Local Links
+ Doxygen Quick Reference (Local)
+ +

+ GtkRadiant FAQ Links
+ GtkRadiant FAQ
+ GtkRadiant FAQ: Open Tasks
+ GtkRadiant FAQ: Compiling instructions
+ GtkRadiant FAQ: Creating/Submitting patches
+ GtkRadiant FAQ: Coding Conventions & Guidelines
+

+ + Misc Links
+ idsoftware.com
+ +

+ + * Note: The content on this page was generated from this file. + It is moved into the path when the doxygen documentation is generated, and removed immediately + afterwards. + +

+ + This page generated: by +user+ on +machine+
+ On +date+ +
+*/ diff --git a/Doxygen_files/doxygen_gtkradiant.css b/Doxygen_files/doxygen_gtkradiant.css new file mode 100644 index 00000000..b875556c --- /dev/null +++ b/Doxygen_files/doxygen_gtkradiant.css @@ -0,0 +1,34 @@ +body { background-color: black; } +IMG { border-color: #222222; border: 0; } +em { font-size: 11px; font-style: italic; font-weight: normal; color: #888888; } +H1 { text-align: center; font-size: 15px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +H3 { text-align: center; font-size: 18px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +A { text-decoration: none; color: #6666DD; } +A:HOVER { text-decoration: underline; color: #4444FF; } +A:VISITED { text-decoration: none; color: #8888AA; } +A.qindex { text-decoration: none; color: #6666DD; font-size: 11px; } +A.qindex:HOVER { text-decoration: underline; color: #4444FF; font-size: 11px; } +A.qindex:VISITED { text-decoration: none; color: #8888AA; font-size: 11px; } +A.qindexRef { font-size: 11px; } +A.el { text-decoration: none; font-weight: bold; } +A.elRef { font-weight: bold; } +A.code { text-decoration: none; font-weight: normal; color: #6666DD; } +A.code:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.code:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +A.codeRef { text-decoration: none; font-weight: normal; color: #6666DD; } +A.codeRef:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.codeRef:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +DL.el { margin-left: 2cm; width: 99%; } +DIV.fragment { background-color: #FFFFFF; width: 99%; } +DIV.ah { background-color: #AAAAAA; width: 99%; margin-bottom: 3; margin-top: 3; } +TD.md { cellpadding: 0; background-color: #DDDDDD; border: 0; width: 99%; color: #222222; } +DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold; color: #222222; } +DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller; } +FONT.keyword { color: #0080A0; } +FONT.keywordtype { color: #604020; } +FONT.keywordflow { color: #E08000; } +FONT.comment { color: #800000; } +FONT.comment { color: #009900; text-decoration: italic; } +FONT.preprocessor { color: #806020; } +FONT.stringliteral{ color: #002080; } +FONT.charliteral { color: #008080; } diff --git a/Doxygen_files/doxygen_gtkradiant_foot.html b/Doxygen_files/doxygen_gtkradiant_foot.html new file mode 100644 index 00000000..46162436 --- /dev/null +++ b/Doxygen_files/doxygen_gtkradiant_foot.html @@ -0,0 +1,49 @@ + + + + + +

+
+ + + + + +
+ Documentation generated by : Doxygen $doxygenversion + + + ttimo@idsoftware.com + +
+
+ +
+
+ +   + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doxygen_files/doxygen_gtkradiant_head.html b/Doxygen_files/doxygen_gtkradiant_head.html new file mode 100644 index 00000000..5e0a9eaf --- /dev/null +++ b/Doxygen_files/doxygen_gtkradiant_head.html @@ -0,0 +1,38 @@ + + + + $projectname $projectnumber Doxygen Documentation + + + + + +
+
+ + + + + + +
+ +
idsoftware
+
+ + + + + + + + + + + + +
+ + +
 
+

+
+ + + + + + + + +
+ \ No newline at end of file diff --git a/Doxygen_files/doxygen_index.html b/Doxygen_files/doxygen_index.html new file mode 100644 index 00000000..6b24c2fc --- /dev/null +++ b/Doxygen_files/doxygen_index.html @@ -0,0 +1,7 @@ + + + + + + Redirecting to Doxygen index + diff --git a/Doxygen_files/doxygen_reference_foot.html b/Doxygen_files/doxygen_reference_foot.html new file mode 100644 index 00000000..a7390bc5 --- /dev/null +++ b/Doxygen_files/doxygen_reference_foot.html @@ -0,0 +1,46 @@ + +

+
+ + + + + +
+ + Doxygen is: Copyright © 1997-2001 by Dimitri van Heesch. + + + GtkRadiant Doxygen Maintainer: Gef +
+
+ +
+
+
 
+ + + + + +
+ +
+
+
+ +
+ + + diff --git a/Doxygen_files/doxygen_reference_head.html b/Doxygen_files/doxygen_reference_head.html new file mode 100644 index 00000000..e735c9e4 --- /dev/null +++ b/Doxygen_files/doxygen_reference_head.html @@ -0,0 +1,38 @@ + + + + GtkRadiant - Doxygen Quick Reference + + + + + +
+ +
+ + + + + + +
+ + +
idsoftware
+
+ + + + + + + + + + + + +
+ + +
&nsbp;
+

+ \ No newline at end of file diff --git a/Doxygen_files/example/annotated.html b/Doxygen_files/example/annotated.html new file mode 100644 index 00000000..852a7f00 --- /dev/null +++ b/Doxygen_files/example/annotated.html @@ -0,0 +1,103 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Compound List

Here are the classes, structs, unions and interfaces with brief descriptions:
    +
  • IEpair (Virtual class to allow plugin operations on entity pairs) +
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ +
+
+ +
+ + + diff --git a/Doxygen_files/example/classIEpair-members.html b/Doxygen_files/example/classIEpair-members.html new file mode 100644 index 00000000..ed4d8778 --- /dev/null +++ b/Doxygen_files/example/classIEpair-members.html @@ -0,0 +1,110 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEpair Member List

This is the complete list of members for IEpair, including all inherited members. + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/classIEpair.html b/Doxygen_files/example/classIEpair.html new file mode 100644 index 00000000..cba38de1 --- /dev/null +++ b/Doxygen_files/example/classIEpair.html @@ -0,0 +1,414 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEpair Class Reference

Virtual class to allow plugin operations on entity pairs. +More... +

+List of all members. + + + + + + + + + + + + + + + + + +

Public Methods

virtual void IncRef ()=0
 Increment the number of references to this object. More...

virtual void DecRef ()=0
 Decrement the reference count. More...

virtual void GetVectorForKey (char *key, vec3_t vec)=0
 Get a vector from a key. More...

virtual float FloatForKey (char *key)=0
 Get a float from a key. More...

virtual char* ValueForKey (char *key)=0
 Get a string (char *) from a key. More...

virtual void SetKeyValue (char *key, char *value)=0
 Set a key value to char *value. More...

virtual void GetEntityOrigin (vec3_t vec)=0
 Get a vec3_t for the entities origin. More...

virtual void CalculateRotatedBounds (vec3_t mins, vec3_t maxs)=0
 Compute the rotated bounds of the BBox based on "angle" and "angles" keys. More...

+


Detailed Description

+Virtual class to allow plugin operations on entity pairs. +

+ +

+

+Todo:
+Write more complete documentation for this class so that it's use is clear
+

+An interface to entity keys and key pairs that allows plugins to; read and write entity keys and key values, get a key value as a vec3_t +

+ +

+Definition at line 10 of file iepairs.h.


Member Function Documentation

+

+ + + + +
+ + + + + + + + + + +
+void IEpair::CalculateRotatedBounds ( + +vec3_t mins, +
+vec3_t maxs ) [pure virtual] +
+
+ + + + + +
+   + + +

+Compute the rotated bounds of the BBox based on "angle" and "angles" keys. +

+

+

+ + + + +
+ + + + + + +
+void IEpair::DecRef ( + +) [pure virtual] +
+
+ + + + + +
+   + + +

+Decrement the reference count. +

+

+

+ + + + +
+ + + + + + +
+float IEpair::FloatForKey ( + +char * key ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a float from a key. +

+

+

+ + + + +
+ + + + + + +
+void IEpair::GetEntityOrigin ( + +vec3_t vec ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a vec3_t for the entities origin. +

+

+

+ + + + +
+ + + + + + + + + + +
+void IEpair::GetVectorForKey ( + +char * key, +
+vec3_t vec ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a vector from a key. +

+

+

+ + + + +
+ + + + + + +
+void IEpair::IncRef ( + +) [pure virtual] +
+
+ + + + + +
+   + + +

+Increment the number of references to this object. +

+

+

+ + + + +
+ + + + + + + + + + +
+void IEpair::SetKeyValue ( + +char * key, +
+char * value ) [pure virtual] +
+
+ + + + + +
+   + + +

+Set a key value to char *value. +

+

+Parameters:
+ + + +
key +The (char *) containing the keyname
value +The (char *) to set the key value to
+
+

+ + + + +
+ + + + + + +
+char * IEpair::ValueForKey ( + +char * key ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a string (char *) from a key. +

+

+


The documentation for this class was generated from the following file: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/classes.html b/Doxygen_files/example/classes.html new file mode 100644 index 00000000..7e5bd909 --- /dev/null +++ b/Doxygen_files/example/classes.html @@ -0,0 +1,103 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Compound Index

+ +
  I  
IEpair   
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/doxygen.gif b/Doxygen_files/example/doxygen.gif new file mode 100644 index 0000000000000000000000000000000000000000..192c83ce05078f6475c1e81290fdadded6d25467 GIT binary patch literal 2378 zcmV-Q3AOe|Nk%w1VQv650OtSz|Nr8jARx9SCIA26|Nq?I-^TyU%-^!I{`}Lwzp4NK z!AJl$=%to{Pn!Dk|EsHq~G7iKRhfS z91pmqSoh+E_1twJ9~uAt+rPi6_u+;4>Y>o9Ci2iy|NPV1&W%7nHQd#u_u_{7@UK2Q zC_q3tKtMO!(wV!kc>C|K*1%`_>!ID+u=e4G1Ox;A{M1}gCc3O{-`~UU#x(HCLb<7A z|Nh(_8x0>E5g#2C_1$(`Q6}BmuleerKRqwCoITdTXWY`6`s<+8yjR)DfImJmJ~}1- z_{iGMj36K!_vVw=#&tb69{caE{rSkgy`H408y_AP9~%w7zokGx zIN#j4{Pn%`)@AzYq1efR@XJEq-oPFh2KL-_zrU#1#&y=fX7}cj@ybHdvO2!LoQBU|vkZw|@5Fh4$iw4-E!FJ}bVvm)y~rJv0@)w~d&FKADM1?!`1GB^lw+ zgkWG&J~<&iI3ZwPPeepJ?#4A98VdH^cH7dJwVXcO(wK#985kE3(5)_$d?@b5G(0pF z-Py0>vxI<15b0p7VOf*ylGM zmLI?j=JM6&Sb2uIr(S>pw!{Zp1AH*R0}wXI)(37e!QcQ)L?|H>^(@HXT5K_4NXSa)9_?J1IWMk&ArPV+x2A*5hJ`3_9pmOL-8$fD8EQ1jLAnDWmYz6G0N0&Y^=Ub09#f zrBqo_fe00ta6$|mArZp~(TZ?FJdDM+T!|MGV&>46PA|-ed&|C`>Sc3M6#o z&JGh$K*0|6P@wS+Bp~r92`Y$8!7BA&v4hDd&_RJD9dks2B&SS}G0m%B!BHnZQ$R~7 z#mH}6d}F_8m!*E21V3xh%3P) zk_-Am)RV*O8XPjk6k;3?Jnt<<0>J_cAj1MUzyU7^5CZ?ZLp_!Nzy zXPBNRY=8&;8+ZW^I=};Gbl`_HNJc%XaD*e$paVxZf&-@Lhbr{pi7!|KH@Z=V7rfvI z8+bxJq%g)c2$2VC_zNnY&<9F9F^Dtd$P=8{0UG=;h-IipACCA8LP$Xhgm}RQI`D!# zI;0+jZ~zRZC=LgVVu}tRf(zI6VIArP_%gcG0&hC%iG@i_P4+du5gD-+~OMdxX4Yea+k~8<~sMeQwazFJ2OgsC;$Ke literal 0 HcmV?d00001 diff --git a/Doxygen_files/example/doxygen_gtkradiant.css b/Doxygen_files/example/doxygen_gtkradiant.css new file mode 100644 index 00000000..c0ddae2d --- /dev/null +++ b/Doxygen_files/example/doxygen_gtkradiant.css @@ -0,0 +1,35 @@ +body { background-color: black; } +IMG { border-color: #222222; border: 1; } +em { font-size: 11px; font-style: italic; font-weight: normal; color: #888888; } +H1 { text-align: center; font-size: 15px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +H3 { text-align: center; font-size: 18px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +A { text-decoration: none; color: #6666DD; } +A:HOVER { text-decoration: underline; color: #4444FF; } +A:VISITED { text-decoration: none; color: #8888AA; } +A.qindex { text-decoration: none; color: #6666DD; font-size: 11px; } +A.qindex:HOVER { text-decoration: underline; color: #4444FF; font-size: 11px; } +A.qindex:VISITED { text-decoration: none; color: #8888AA; font-size: 11px; } +A.qindexRef { font-size: 11px; } +A.el { text-decoration: none; font-weight: bold; } +A.elRef { font-weight: bold; } +A.code { text-decoration: none; font-weight: normal; color: #6666DD; } +A.code:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.code:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +A.codeRef { text-decoration: none; font-weight: normal; color: #6666DD; } +A.codeRef:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.codeRef:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +DL.el { margin-left: 2cm; width: 99%; } +DIV.fragment { background-color: #FFFFFF; width: 99%; } +DIV.ah { background-color: #AAAAAA; width: 99%; margin-bottom: 3; margin-top: 3; } +TD.md { cellpadding: 2; background-color: #DDDDDD; border: 1; width: 99%; color: #222222; } +DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold; color: #222222; } +DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller; } +FONT.keyword { color: #0080A0; } +FONT.keywordtype { color: #604020; } +FONT.keywordflow { color: #E08000; } +FONT.comment { color: #800000; } +FONT.comment { color: #009900; text-decoration: italic; } +FONT.preprocessor { color: #806020; } +FONT.stringliteral{ color: #002080; } +FONT.charliteral { color: #008080; } + diff --git a/Doxygen_files/example/files.html b/Doxygen_files/example/files.html new file mode 100644 index 00000000..5b00181d --- /dev/null +++ b/Doxygen_files/example/files.html @@ -0,0 +1,102 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample File List

Here is a list of all files with brief descriptions: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/functions.html b/Doxygen_files/example/functions.html new file mode 100644 index 00000000..0c245e22 --- /dev/null +++ b/Doxygen_files/example/functions.html @@ -0,0 +1,110 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Compound Members

Here is a list of all class members with links to the class documentation for each member: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/graph_legend.dot b/Doxygen_files/example/graph_legend.dot new file mode 100644 index 00000000..f4efdeb7 --- /dev/null +++ b/Doxygen_files/example/graph_legend.dot @@ -0,0 +1,16 @@ +digraph inheritance +{ + Node7 [shape="box",label="Inherited",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",style="filled" fontcolor="white"]; + Node8 -> Node7 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="doxfont"]; + Node8 [shape="box",label="PublicBase",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_publicbase.html"]; + Node9 -> Node8 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="doxfont"]; + Node9 [shape="box",label="Truncated",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="red",URL="$class_truncated.html"]; + Node11 -> Node7 [dir=back,color="darkgreen",fontsize=10,style="solid",fontname="doxfont"]; + Node11 [shape="box",label="ProtectedBase",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_protectedbase.html"]; + Node12 -> Node7 [dir=back,color="firebrick4",fontsize=10,style="solid",fontname="doxfont"]; + Node12 [shape="box",label="PrivateBase",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_privatebase.html"]; + Node13 -> Node7 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="doxfont"]; + Node13 [shape="box",label="Undocumented",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="grey75"]; + Node14 -> Node7 [dir=back,color="darkorchid3",fontsize=10,style="dashed",label="m_usedClass",fontname="doxfont"]; + Node14 [shape="box",label="Used",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_used.html"]; +} diff --git a/Doxygen_files/example/graph_legend.gif b/Doxygen_files/example/graph_legend.gif new file mode 100644 index 0000000000000000000000000000000000000000..f4f1a0053c470cf4d1cf5627049737676330ebac GIT binary patch literal 9344 zcmdT~4O~=Zx_{5%0B1&|!#ElsSI@{OGoZ<+DPwG&87YPlSsMIUQIkY7zg7i5QY_C5 zGp2+z3|OdBjk^PCg|?Mi6pC&rrlQqGr7Myl-clJ471EYhxxBKzy^5e&k zne)ES`+WVM_xU*K8IPvupLiHQf!;>Q$Nl^rA+%}JrpuQv&zm>z)mL8~I&|pKqemxA zniLbW!UxatQAupS=i6_43P4@9)~!wdXp~+itYT3kB&+lDruFXC0#T#o+-`H@p?aik% zAJ}#7n|C&x{q_5ozk7FM)`5#%KYZ})xvtwj)@m!ZJ2pSJWoyavrQ6CLp{8Wz-e{b) zLT+`xbK&{7TR*sc-{vc(7dy7r{OO}Z-#%~XhwB#~ynj*sRU0ELZ2epK2oQ zSvb49(Gx0eEHKaswYRRkF`?`4#k*5n)$4z=ukNkd+w;%EMoqhtm*}r;iQnCWPENL2 zTV0u@p?%JZtj9X-RQ7UWV_oYk8f038t_u&iC&FT!tg>wAtj!PQOb}KmdSdLc2>+N zTGg^^o$pw7+^J7eKb|)C%a&(!PZ{V=?Fc0zNw501aVm%1Xa))lP?!_U)V}LSqTivNh4RE2XPODKDsNKSPnk562BlC< z>(x<(A4ysdVy-=&`SOs>&TQ}_bjlOLvZNAYX%CgBAUx68_DahGWV`pX$KC(lacNVs zGX1S_zZ^Gx=Akw7B66uFedxeXx8&RHIHD2VNu!9=MI>?|_14L>^IEj3x>9n7_1!}w z8p}tX9WeE??aMFSUpz?E_vw2u_OJVquP;a9UG*OJ;XUwhP@M`Y%3DxTR(CZhrO1Gky z0)4$)t4wzf4fY{$2i=!yhJ2`~+bF z0`JeuHa|g{-nYoVB#bZclKo%wwEw0wPxMo8_v|Z)o$lcT+$v^`c(u%BAPCGbs)Ur_ zIS3ZD_AD`h7{vi?xRTqrUkYYL4qU|l!M4E)fBy3xT*tY!%I?;puKN9_Z3MTo`hD)> znz^5^dCXZXJ=O{d2Bb`ZlqC8;m5`M(s?)R-)ui=S<;YcOHj-zPEIsgMwyB%~e%3Fk z-P59_k&)y-E_wakZu6?$&S5IDU0K+yJ?GA0RB1+zkJ>A(NtZxQZKJyohm3*Cw^BFA zN$={yW_@Sn{45hgS69LR)xIi)T#5$uMp(*Z7HUFmW(@={Tz7Wg!4|WMBao|oqpD+0 zKN+l@{)dSU<);lH9NENg>n(FM2zBsA_(EHwZ^?a;;8uNRUiZkr&pC?R;mV+g-*tAj z3eqL|X$8jcSpgHmLZXTxGd?7Qjk-c3lOj2aY_GIg%-59DjF8LXNEb=VO43*gcd8W_ zf54j`kRch7AlaKQsL(X7m5S}UN&aVW#)Y*uB zMW9BMgEV2sIBSt84GVh(gM^pLlcQ{99)WPy$XY|$`ApOuN^oEuO-3|Md~}BrRCZHZ ziIzsTrg#UJl&Vx$0imiK!vOdCj!G~B?~{NT6QT$<1f?JbYrs$(io_63!$&rx0i!4k zDJ_wJk1+$s9owha1Dz{I9Wl;s8r;9tPHVg6^$dgR^`l*Lw%ByE#ut*Fk#Yo z2?mVj%r?n*EfXyAgrJzKBqB47H1aqVJlFxzRRdTEUbxPY+GZM)r^f+5N(*QNeS?@b zO*&#+6p1umy8r}VmfxBXcZ?7soJKRPrYsEYAdE)UaDW)+g*e9m$V^!3^nf3;EmG#2FAj;XaZpYq-2`ntCb4I2Pd^LbZ2>5 zCI`?g{)o&4u5s1+o5I(3_@!Y_avrJ8!v%1v1#o8K3{92*Lc!euoQfWBg4yXObpR%k zaG(lg3i~(Y;VUH6$l{@(+&l%sF~HDC6pu6nQvq5%0}|wv=rPV&q4bO|Rg$)0;N?&_ z;$S;A1Cc}ti{e5`oj}veMI->jwFk@uRRxv;duhTNhQXgIoEbw70nkr|?+{<6aZIqh zNr7BMCi3xxsCj}A6Ybf8S;H~f zPHjbbk*SjrTSkQ;mnVh5_0^tA%f!&_yeCws%eQ3Wxa&g|au!l3S;n|h2;?lY;s{_) zpu)&F9Idt|L!@m}0UE_fiNM7MY|*NtK6QsYhiGA!#>;JJrVt}+i0p|{C)<9{sR>UqB`PM|yaILxjM7 zRYi`(`qBP=)}s^kQa51H5AELjdez;H9~bu&;y=RKQde-}_%C8Pz;GQk`F8gJanFQ} z1%BzcX3|N@((}dOG5Q2)&zE^iB_Wfh6-Xkre0K_N)n2`}bZ9xSAdio~l!5;WN#;HM z54A}7*v!4{(?n`7UoJ)s3B#ph_-3DsF()EaC7q{RV3Cw?pcj$Zd*QMbLdAa$Arv2U z4+$WW!8LTM{q_Cm;!^B{bpDht{9CgIPGkISobF%1Js6NqqoO2>&td|L@T!}>8f8I z^VdMsK%d?0cf7+3f$aoCf5GRsZNE@-aeTxE5g+|OOiSKsgi^0}^eG>y6FkHR-Rb?M zqP$Bl7Ol7#D*D-j&#vfNesP2ek{V1M1DUTFl!P|_62C^~f<_KYXU`SS<|I~j#1)sZ zVYq%zl`&Qo>2h*qp;`v1NFzcfs32H{@+8W$r;sS#lOk06i|PfBZ>J?R7lAIaip7w) z^R@c!Lvzn_2uvCnS~Zrnf>c0W9&)DqO|IZ-WQQU4IWBL!8J$8^oT2(QLlrjem@Uw&qWl=b z01JMPvR)`!F+21Z+%1x;t*N?V)^J5TlnsaxYYRvgWm}Z4(gM3WS!P9a21$tM7A6iZ z$-$SNz16xa>_NfN-nQf}oqF2CyY}oxWzHN~C`yAoPJiV39vgLp=hu3esmu}Qgh*%=H|GeshEjw!#$ErC6&@gg|T~+G*hQ#`FGY^EWMT2I( z*)kTMGI`B0LOzT`jw^yk9MG*dn8iCLDZgmNu24}OuXE~nT~J5hJSmixP__L={b9Mt zOb#%U8(JT3^>OW)v8*vmY}E8j<+3EbUq5xLb+B~M9?(#&?Jg|td@WXrU9oT0caN9w zAjOA(>DX;QaCfxi&X!`yoiT?S>cvY$t8}#o9~FttlLQKwnhg;Buk-XfEgNhCUJgOC za4aV!--GHAt>#a;5(~a%z{3=ghiU#RruV#RyJXIq(#5q8ilI`_2a!3L0 znyn3DMFwJ$Yu7k<23Abx640PZ_{idP3H{ILx82`6`0)8sB4n#dDRzp{NEp7I74`7D zg(ExX?B;{>LsEJdIQ$en=iRs5V+E=+gU^e!;w_ySb6P(|P%Q4yof!0R5Yg5;L`76w zbz{poP#iR0D(VV7Ul9lpVS=3`!eo9!K{GGcbZ+f;ck9dt1Ib2Fu+jO^`Dic~DE8HL zx882M>w+EIL>-G@N8&4NoUY#G0F`@unozfXd_Ltw@=?cOzGX78%~=z<(?3l>vq zZ*Oo~vcZ4qQ?+m9*V&i!+$$*2bSIB?_No{pYVpkBc>)TOQhp6UzwdDhuLW(8&42M zq}oE+NP~w8H);8<#$E3<93W--P-h-48{vdT4FSz|70be)!2weVKU~&m(6(p>e^BD^H%;Ub;L_&7p=~%fAa99 n6;IE3c+clI)@^+JXlM7|HZ?HE49AVXpZsB3W8 + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

Graph Legend

This page explains how to interpret the graphs that are generated by doxygen. +

+ Consider the following example:

/*! Invisible class because of truncation */
+class Invisible { };
+
+/*! Truncated class, inheritance relation is hidden */
+class Truncated : public Invisible { };
+
+/* Class not documented with doxygen comments */
+class Undocumented { };
+
+/*! Class that is inherited using public inheritance */
+class PublicBase : public Truncated { };
+
+/*! Class that is inherited using protected inheritance */
+class ProtectedBase { };
+
+/*! Class that is inherited using private inheritance */
+class PrivateBase { };
+
+/*! Class that is used by the Inherited class */
+class Used { };
+
+/*! Super class that inherits a number of other classes */
+class Inherited : public PublicBase,
+                  protected ProtectedBase,
+                  private PrivateBase,
+                  public Undocumented
+{
+  private:
+    Used *m_usedClass;
+};
If the MAX_DOT_GRAPH_HEIGHT tag in the configuration file is set to 200 this will result in the following graph: +

+

+
+ +

+ The boxes in the above graph have the following meaning:

    +
  • A filled black box represents the struct or class for which the graph is generated.
  • A box with a black border denotes a documented struct or class.
  • A box with a grey border denotes an undocumented struct or class.
  • A box with a red border denotes a documented struct or class for which not all inheritance/containment relations are shown. A graph is truncated if it does not fit within the specified boundaries.
+ The arrows have the following meaning:
    +
  • A dark blue arrow is used to visualize a public inheritance relation between two classes.
  • A dark green arrow is used for protected inheritance.
  • A dark red arrow is used for private inheritance.
  • A purple dashed arrow is used if a class is contained or used by another class. The arrow is labeled with the variable(s) through which the pointed class or struct is accessible.
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/index.html b/Doxygen_files/example/index.html new file mode 100644 index 00000000..4cfcdd8a --- /dev/null +++ b/Doxygen_files/example/index.html @@ -0,0 +1,102 @@ + + + + IEPairs Class Example Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairs Class Example Documentation

+

+ + +

+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/pages.html b/Doxygen_files/example/pages.html new file mode 100644 index 00000000..24287679 --- /dev/null +++ b/Doxygen_files/example/pages.html @@ -0,0 +1,104 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Related Pages

Here is a list of all related documentation pages: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/test_8c-source.html b/Doxygen_files/example/test_8c-source.html new file mode 100644 index 00000000..9b67ae0a --- /dev/null +++ b/Doxygen_files/example/test_8c-source.html @@ -0,0 +1,140 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

iepairs.h

Go to the documentation of this file.
00001 //! Virtual class to allow plugin operations on entity pairs
+00002 /*!
+00003   \todo Write more complete documentation for this class so that it's use
+00004   is clear
+00005                         
+00006   An interface to entity keys and key pairs that allows plugins to;
+00007   read and write entity keys and key values, get a key value as a
+00008   vec3_t
+00009 */
+00010 class IEpair
+00011 {
+00012   public:
+00013     //! Increment the number of references to this object
+00014     virtual void IncRef () = 0;
+00015                                 
+00016     //! Decrement the reference count
+00017     virtual void DecRef () = 0;
+00018                                 
+00019     //! Get a vector from a key
+00020     virtual void GetVectorForKey( char* key, vec3_t vec ) = 0;
+00021                                 
+00022     //! Get a float from a key
+00023     virtual float FloatForKey( char *key ) = 0;
+00024                                 
+00025     //! Get a string (char *) from a key
+00026     virtual char* ValueForKey( char *key ) = 0;
+00027                                 
+00028     //! Set a key value to char *value
+00029     /*!
+00030       \param key The (char *) containing the keyname
+00031       \param value The (char *) to set the key value to
+00032     */
+00033     virtual void SetKeyValue( char *key, char *value ) = 0;
+00034                                 
+00035     //! Get a vec3_t for the entities origin
+00036     virtual void GetEntityOrigin( vec3_t vec ) = 0;
+00037                                 
+00038     //! Compute the rotated bounds of the BBox based on "angle" and "angles" keys
+00039     virtual void CalculateRotatedBounds( vec3_t mins, vec3_t maxs ) = 0;
+00040 };
+
+ +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/test_8c.html b/Doxygen_files/example/test_8c.html new file mode 100644 index 00000000..2b7d1cd7 --- /dev/null +++ b/Doxygen_files/example/test_8c.html @@ -0,0 +1,107 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

iepairs.h File Reference

+

+Go to the source code of this file. + + + +

Compounds

class  IEpair
 Virtual class to allow plugin operations on entity pairs. More...

+ + +

+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/todo.html b/Doxygen_files/example/todo.html new file mode 100644 index 00000000..88b90db9 --- /dev/null +++ b/Doxygen_files/example/todo.html @@ -0,0 +1,105 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

Todo List

+ +
+
Class IEpair
Write more complete documentation for this class so that it's use is clear +
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/genDoxyfile b/Doxygen_files/genDoxyfile new file mode 100644 index 00000000..9421dc18 --- /dev/null +++ b/Doxygen_files/genDoxyfile @@ -0,0 +1,159 @@ +# Doxyfile 1.2.5-20010304 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +INTERNAL_DOCS = YES +CLASS_DIAGRAMS = YES +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +ENABLED_SECTIONS = +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = doxygen.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.c +RECURSIVE = YES +EXCLUDE = +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = Doxygen_files/doxygen_gtkradiant_head.html +HTML_FOOTER = Doxygen_files/doxygen_gtkradiant_foot.html +HTML_STYLESHEET = Doxygen_files/doxygen_gtkradiant.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = + +#--------------------------------------------------------------------------- +# Include file, at the bottom to over-ride anything I missed. +#--------------------------------------------------------------------------- +@INCLUDE = ./Doxygen_files/genConf diff --git a/Doxygen_files/gendoxfunctions b/Doxygen_files/gendoxfunctions new file mode 100644 index 00000000..fd48dd85 --- /dev/null +++ b/Doxygen_files/gendoxfunctions @@ -0,0 +1,421 @@ +#!/bin/bash +# Functions for the gendox script +# +# Gef, Aug 2001 + +#------------------------------------------------------------------------ +# Set the doxygen output language from the system locale +#------------------------------------------------------------------------ +get_language() { + if [ -n "$LANG" ] ; then + local LANG=`locale | grep LANG | cut -d= -f2`; + fi + case "$LANG" in + czech) + OUPUTLANGUAGE="Czech"; + ;; + german) + OUPUTLANGUAGE="German"; + ;; + spanish) + OUPUTLANGUAGE="Spanish"; + ;; + finnish) + OUPUTLANGUAGE="Finnish"; + ;; + french) + OUPUTLANGUAGE="French"; + ;; + italian) + OUPUTLANGUAGE="Italian"; + ;; + japanese*) + OUPUTLANGUAGE="Japanese"; + ;; + dutch) + OUPUTLANGUAGE="Dutch"; + ;; + swedish) + OUPUTLANGUAGE="Swedish"; + ;; + *) + OUPUTLANGUAGE="English"; + ;; + esac +} + +#------------------------------------------------------------------------ +# Output usage info & output help +#------------------------------------------------------------------------ +output_usage() { + echo -e "Usage: $0 [] [-o ]"; + return; +} + +output_help() { + output_usage; + echo -e "\nOptions:"; + echo -e " []"; + echo -e " This is an optional parameter that specifies the directory, or multiple"; + echo -e " directories from which to generate the documentation."; + echo -e ""; + echo -e " [-o ]"; + echo -e " An optional parameter that specifies the output directory in which"; + echo -e " to save the generated documentation."; + echo -e ""; + echo -e " -q or --quiet"; + echo -e " Prevents the output of status information" + echo -e "" + echo -e " --help, or -h"; + echo -e " Displays this information"; + echo -e "" + echo -e " -q or --quiet"; + echo -e " Prevents the output of status information" + echo -e "" + echo -e " -k or --kill"; + echo -e " kills running doxygen pids." + echo -e "" + echo -e "* Further information on using this script, can be found in README.doxygen"; + echo -e "* in the current directory."; + +} + +#------------------------------------------------------------------------ +# Set the target to what was passed on the command line +#------------------------------------------------------------------------ +parse_commandline() { + # todo: + # need to add the ability to check for an auto gen'd version + # used for automatically generating new documentation for each commit + # to the cvs server + + # funky bash shell array + declare -a OPTLIST[$#]; + + if [ $OPTCOUNT == 0 ] ; then + # No options on the command line so set the target list to the core + TARGETCOUNT=0; + OUTPUTDIR="../$(basename `pwd`)-doxygen"; + else + # put all the command line options into an array + for f in $COMLINE ; do + OPTLIST[$COUNTER]="$f"; + let COUNTER++; + done + + for (( COUNTER=0 ; $COUNTER < $OPTCOUNT; $[COUNTER++] )) ; do + if [ "${OPTLIST[$COUNTER]}" == "--help" ] ; then + # output usage information + output_help; + RETVAL=1; + return; + elif [ "${OPTLIST[$COUNTER]}" == "-h" ] ; then + # output usage information + output_help; + RETVAL=1; + return; + fi + + case ${OPTLIST[$COUNTER]} in + -q) + QUIETMODE=1; + ;; + --quiet) + QUIETMODE=1; + ;; + -k) + KILLON=1; + ;; + --kill) + KILLON=1; + ;; + -o) + # look for the -o switch, and get the next command line option as the output dir + if [ -z ${OPTLIST[$COUNTER + 1]} ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " ** Output switch used, but no output dir passed..."; + [ $QUIETMODE -gt 0 ] || echo -e " ** Setting default output dir."; + else + let COUNTER++; + OUTPUTDIR=${OPTLIST[$COUNTER]}; + fi + break; + ;; + **) + # If the command line option is anything other that -o then assume it's a target + # Check to make sure the target exists first... + if [ -d ${OPTLIST[$COUNTER]} ] ; then + TARGETLIST[$COUNTER]=${OPTLIST[$COUNTER]}; + else + output_usage; + echo -e " ** Error: Non-existent directory specified as a target.\nExiting."; + RETVAL=1; + return; + fi + let TARGETCOUNT++; + ;; + esac + done + + fi # if [ $OPTCOUNT == 0 ] ; + + if [ $TARGETCOUNT == 0 ] ; then + TARGETCOUNT=4; + TARGETLIST[0]="include"; + TARGETLIST[1]="libs"; + TARGETLIST[2]="radiant"; + TARGETLIST[3]="plugins"; + # Gef: outputdir for default core when no targets are passed on the command line + # TTimo problem still there, if -o used on command line, don't override + if [ -z $OUTPUTDIR ] ; then + OUTPUTDIR="../$(basename `pwd`)-doxygen"; + fi + fi + + # Add trailing slash's to the lines that need them + TARGETSTRING=`echo ${TARGETLIST[*]} | sed -e 's/" "/", "/'` + [ $QUIETMODE -gt 0 ] || echo -ne " -> Set Input to: "; + for (( COUNTER=0; COUNTER < $TARGETCOUNT ; $[COUNTER++] )) ; do + if [ $COUNTER == $[TARGETCOUNT - 1] ] ; then + [ $QUIETMODE -gt 0 ] || echo -ne "${TARGETLIST[$COUNTER]}\n"; + TARGETLIST[$COUNTER]="${TARGETLIST[$COUNTER]}"; + else + [ $QUIETMODE -gt 0 ] || echo -ne "${TARGETLIST[$COUNTER]}, "; + TARGETLIST[$COUNTER]="${TARGETLIST[$COUNTER]} \\"; + fi + done + [ $QUIETMODE -gt 0 ] || echo -e " -> Set Output Dir to: $OUTPUTDIR"; + return; +} + +#------------------------------------------------------------------------ +# Try to extract the version number +# todo: find a better way to determine the version +#------------------------------------------------------------------------ +get_version() { + VERSION=`grep PROJECT_NUMBER $DOXYCONFIG | grep -v \# | cut -d= -f2`; + if [ -z $VERSION ] ; then + if [ -f "./include/version.default" ] ; then # checks that we are in the right dir + VERSION=`cat ./include/version.default`; + else + VERSION="(Unknown)"; + fi + fi + return; +} + +#------------------------------------------------------------------------ +# Create a projectname from the tree name +#------------------------------------------------------------------------ +get_projectname() { + PROJECTNAME=`grep PROJECT_NAME $DOXYCONFIG | grep -v \# | cut -d= -f2`; + if [ -z $PROJECTNAME ] ; then + # PROJECTNAME=`echo $TARGET | sed -e s/[^A-Za-z0-9]/!/ | cut -d! -f1`; + PROJECTNAME="$(basename `pwd`)"; + fi + return; +} + +#------------------------------------------------------------------------ +# function to determine the path to the perl executable +#------------------------------------------------------------------------ +get_perlpath() { + if [ -f "$DOXYCONFIG" ] ; then + PERLPATH=`grep PERL_PATH $DOXYCONFIG | grep = | cut -d= -f2` + fi + + if [ 'basename $PERLPATH &2>/dev/null' != "perl" ] ; then + PERLPATH=`which perl 2>/dev/null | sed -e 's/perl//'`; + elif [ 'basename $PERLPATH &2>/dev/null' != "perl" ] ; then + PERLPATH=""; + fi + return; +} + +#------------------------------------------------------------------------ +# Function to determine the path to the dot executable +#------------------------------------------------------------------------ +get_dotpath() { + if [ -f "$DOXYCONFIG" ] ; then + DOTPATH=`grep DOT_PATH $DOXYCONFIG | grep = | cut -d= -f2` + fi + + if [ -z $DOTPATH ] || [ `basename $DOTPATH 2>/dev/null` != "dot" ] ; then + DOTPATH=`which dot 2>/dev/null`; + fi + + if [ -z $DOTPATH ] || [ `basename $DOTPATH 2>/dev/null` != "dot" ] ; then + DOTPATH=""; + HAVEDOT="No"; + echo -e "** Warning: dot not found."; + [ $QUIETMODE -gt 0 ] || echo -e "** dot is part of the GraphVis package and is used to generate"; + [ $QUIETMODE -gt 0 ] || echo -e "** dependancy/inheritance/include (etc) diagrams."; + [ $QUIETMODE -gt 0 ] || echo -e "** It's suggested that you install the GraphVis package for those"; + [ $QUIETMODE -gt 0 ] || echo -e "** features."; + [ $QUIETMODE -gt 0 ] || echo -e "** GraphVis can be downloaded from www.graphvis.org"; + else + HAVEDOT="Yes"; + DOTPATH=`echo $DOTPATH | sed -e 's/dot//'`; + fi + + return; +} + +#------------------------------------------------------------------------ +# Function to move stuff around +#------------------------------------------------------------------------ +# eg: move the images into the output directory & the reference doc into the +# html directory. +# called after doxygen has finished generating documentation +move_stuff() { + [ $QUIETMODE -gt 0 ] || echo -ne " -> Move stuff.\n"; + if [ ! -d $OUTPUTDIR ] ; then + mkdir $OUTPUTDIR; + fi + + if [ ! -d "$EXTRAS_PATH/images/" ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " - Looking for images."; + [ $QUIETMODE -gt 0 ] || sleep 2; + [ $QUIETMODE -gt 0 ] || echo -e " - I can't find the images..."; + [ $QUIETMODE -gt 0 ] || sleep 1; + [ $QUIETMODE -gt 0 ] || echo -e " - Where did you put the images!?"; + [ $QUIETMODE -gt 0 ] || sleep 2; + [ $QUIETMODE -gt 0 ] || echo -e " - They have to be here somewhere..."; + [ $QUIETMODE -gt 0 ] || sleep 1; + [ $QUIETMODE -gt 0 ] || echo -e " - Looking in /dev/null"; + [ $QUIETMODE -gt 0 ] || sleep 3; + [ $QUIETMODE -gt 0 ] || echo -e " - YOU FOOL, YOU DELETED THE IMAGES!!!"; + [ $QUIETMODE -gt 0 ] || sleep 1; + [ $QUIETMODE -gt 0 ] || echo -e " - I quit!"; + RETVAL=666; + else + if [ ! -d $OUTPUTDIR/images ] ; then + mkdir $OUTPUTDIR/images ; + fi + cp $EXTRAS_PATH/images/* $OUTPUTDIR/images/ ; + RETVAL=0; + fi + return; +} + +#------------------------------------------------------------------------ +# clean_up() removes old versions of the documentation +#------------------------------------------------------------------------ +clean_up() { + if [ -f $OUTPUTDIR/html/index.html ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Trashing old dox."; + rm -f $OUTPUTDIR/html/* + fi + return; +} + +#------------------------------------------------------------------------ +# Create a new genConf & Doxyfile +#------------------------------------------------------------------------ +gen_doxyconfig() { + [ $QUIETMODE -gt 0 ] || echo -e " -> Generating DoxyConfig."; + RETVAL=0; + # first need to make sure there is a Doxyfile here + if [ ! -f $DOXYFILE ] ; then + # what now? (could generate one with 'doxygen -e Doxyfile') but it would be screwed. + echo -e "No Doxyfile here..."; + RETVAL=3; + return; + else + # Create a new doxyfile with the @INCLUDE statement including the generated stuff + echo "`cat $DOXYFILE | grep -v @INCLUDE`" > $NEWDOXYFILE + echo "@INCLUDE = $CONFIG_OUTPUT" >> $NEWDOXYFILE + fi + + # remove the old config file + rm -f $CONFIG_OUTPUT + + # create a new one + touch $CONFIG_OUTPUT + echo "# Generated configuration - Do Not Edit." >> $CONFIG_OUTPUT; + echo "# If you want to modify options, edit DoxyConfig and re-run genconf." >> $CONFIG_OUTPUT; + echo -e "\n" >> $CONFIG_OUTPUT; + echo -e "PROJECT_NAME=$PROJECTNAME" >> $CONFIG_OUTPUT; + echo -e "PROJECT_NUMBER=$VERSION" >> $CONFIG_OUTPUT; + echo -e "PERL_PATH=$PERLPATH" >> $CONFIG_OUTPUT; + echo -e "HAVE_DOT=$HAVEDOT" >> $CONFIG_OUTPUT; + echo -e "DOT_PATH=$DOTPATH" >> $CONFIG_OUTPUT; + echo -e "OUTPUT_LANGUAGE=$OUTPUTLANGUAGE" >> $CONFIG_OUTPUT; + + echo -n "INPUT=" >> $CONFIG_OUTPUT; + for (( COUNTER=0 ; COUNTER < $TARGETCOUNT; $[COUNTER++] )) ; do + # echo -e "${TARGETLIST[$COUNTER]}"; + echo -e "${TARGETLIST[$COUNTER]}" >> $CONFIG_OUTPUT + done + # echo -e "INPUT=$TARGET" >> $CONFIG_OUTPUT; + + echo -e "OUTPUT_DIRECTORY=$OUTPUTDIR" >> $CONFIG_OUTPUT; + echo -e "\n" >> $CONFIG_OUTPUT; + return; +} + +#------------------------------------------------------------------------ +# Build the reference page & index +#------------------------------------------------------------------------ +build_extra_html() { + # file locations + REF_OUT="$OUTPUTDIR/reference/index.html" + INDEX_OUT="$OUTPUTDIR/index.html" + + # Make the output directory if it doesn't exist + if [ ! -d $OUTPUTDIR/reference/ ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Making reference directory"; + mkdir $OUTPUTDIR/reference + fi + + # cat the files together and output the result to each file + [ $QUIETMODE -gt 0 ] || echo -e " -> Building reference document"; + cat $EXTRAS_PATH/doxygen_reference_head.html $EXTRAS_PATH/reference1.html $EXTRAS_PATH/doxygen_reference_foot.html > $REF_OUT; + + if [ ! -d $OUTPUTDIR/example/ ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Making example dir"; + mkdir $OUTPUTDIR/example + fi + [ $QUIETMODE -gt 0 ] || echo -e " -> Moving example docs"; + cp $EXTRAS_PATH/example/* $OUTPUTDIR/example/ + cp $EXTRAS_PATH/doxygen_gtkradiant.css $OUTPUTDIR/example/ + + # Make a redirecting index.html + cat $EXTRAS_PATH/doxygen_index.html > $INDEX_OUT; + return; +} + +#------------------------------------------------------------------------ +# Execute doxygen +#------------------------------------------------------------------------ +run_doxygen() { + # copy doxy_mainpage.h to the target directory + # pipe it through sed to add generation time/date and username - $machine + TEMPLOCATION=`echo $TARGETSTRING | cut -d' ' -f1`; + if [ X"$USERNAME" == "X" ] ; then + USERNAME=`whoami`; + fi + MACHINE=`uname -n`; # `uname -n` or `hostname` ?? + cp $EXTRAS_PATH/doxy_mainpage.h temp.h + cat temp.h | + sed "s/+project+/$PROJECTNAME/" | + sed "s|+target+|$TARGETSTRING|" | + sed "s/+user+/$USERNAME/" | + sed "s/+machine+/$MACHINE/" | + sed "s/+date+/$(date '+%b %d %Y')/" > $TEMPLOCATION/doxy_mainpage.h ; + + rm -f temp.h + + # Start doxygen with the command "doxygen $DOXYFILE" + [ $QUIETMODE -gt 0 ] || echo -e " -> Executing doxygen."; + [ $QUIETMODE -gt 0 ] || echo -e "> doxygen $NEWDOXYFILE"; + doxygen $NEWDOXYFILE + RETVAL=$? + + # remove doxy_mainpage.h from the target directory + rm -f $TEMPLOCATION/doxy_mainpage.h + return; +} + +#------------------------------------------------------------------------ +# End. + diff --git a/Doxygen_files/images/body-left-tile.gif b/Doxygen_files/images/body-left-tile.gif new file mode 100644 index 0000000000000000000000000000000000000000..676dda0a025db73f2ef92c29e463e7fe5177e953 GIT binary patch literal 94 zcmZ?wbhEHb6lP##*vtR|YFfrTy!^50wUsS%-2CF&CM>nI_m!4Y>72YAERRAc{$v63 ZbwDJ@33pF^7Hj*bc}L-m%YNyTxNXE(%ME& zUQ%0bG&)8%JxM!3Pho6=B`Gl@Cocd1046Fk|NsA2VReL#q+4ZsL`z#ID>QF=lw@y* zcY>OMi=i?%Ln<#gVr_&%Nm)KcQ?9kc`}_QpoUen8qx$;$2?`5TU2*E{?|Fore21O} z2M9$>Ts%Thu(rfONLL;qC_hG34-piYpt3GAJ-NTj7#koE5*2@np!WCpw!F#I*xz7l zflgOxA^8LV00000EC2ui022TV000JyK#6cDu?RQ_1wfXYI48uR$-=oPBRI%2D(vVq z6%615$!xhSPGJ!PcszhHlxrv;0-^>0bLk9jToMZv0W%E@4hj_-0yTj)3NH)|4j~Ew zDF`5eGyn_$E(-`g4-Xp~ff5l80S_xB128-X2dOOpAQmG%Dg-+xB&iZ8KLZH_6v@fL MLKy}L%E>_hJK58G{r~^~ literal 0 HcmV?d00001 diff --git a/Doxygen_files/images/body-lower-right.gif b/Doxygen_files/images/body-lower-right.gif new file mode 100644 index 0000000000000000000000000000000000000000..b9d1f99264c06faeab1fc6ed6f53075bd194afdd GIT binary patch literal 352 zcmV-m0iXUyNk%w1VG{rh0M!5ha(YJmrij=74=ul z)7#Y8->9#?#mdxNW_W yj1Y7eBmo%)KN2~N3kY;LGc_n66Qm0kbP7C}u8blTv9+WYxVf$_5T>zBK>$0RQLJtN literal 0 HcmV?d00001 diff --git a/Doxygen_files/images/body-lower-tile.gif b/Doxygen_files/images/body-lower-tile.gif new file mode 100644 index 0000000000000000000000000000000000000000..f9bfad723e1b4eb35a032738a30930d7d410fd56 GIT binary patch literal 67 zcmZ?wbhEHbWMtrBSj51fre*y9|NoTy_W8?q965RU_wPS@51mUb=urI0!TlwBKG(A zeu+SIF z@AAjY)x^ou&C%NX`}~BCq#`CQUuuA1Y=d5Ces6n}xW3Bw`1#=D=;!I}>g?~y&e!?* z`j(%uA^8LV00000EC2ui022TV000JqK!k8eLS0N@(%Ofak$qd=(H6xWr`V<~YI3lAtFAXfq|Fa`xF0}%}nAs<&21}8EK z4-pU-VL~Jo0yiljGZG&S85CC?0to~Q0}U4q6t!0g4jeQODjFB5woeHi1(>}OwY5P2 EJFW+l00000 literal 0 HcmV?d00001 diff --git a/Doxygen_files/images/body-upper-right.gif b/Doxygen_files/images/body-upper-right.gif new file mode 100644 index 0000000000000000000000000000000000000000..af29319ff6a3a46436e0877e88e92e5c73944d43 GIT binary patch literal 362 zcmV-w0hRtoNk%w1VG{rh0M!5h+1%q478)ihGh1bPW^su$IYrgk;8b04w!FzMGd;h= z&x@6*TxNWOjiY*noB#j-M^9frMpRZ{bWK%ffs3IbB`ifvT{%BZ2?`8AM^-^dSO5S2 z_V@TtSZbM}v*zgRps2V`S7~T;j8j~2aD0_RN?J%zVgCO9sIR`ArM4$4H1+oPH$6)6 z^7K+$Zsg|clAEq7FF4)c0D)4T-oinU_!8s?gE1J;B_Rl86d-5*86_ne5f&067Gwbd6)^=Y7a9j73lwn= zj0pu7CIm1y3S)rbf*fOj|uh&Tv;2LT@e00g9W zi2wHSe+3QYJt{f?84>BjyZ=BBpiak=71PE`rZ83wr&&qGMp<*gJkQP$GdxAV^?83F(S z`TueGe{BNZ{~Hv<0la&MfcOpx@jW6U65_vQA-qGxLBgfx0wCkjNNM4lyP^QO|2g>$ z@7p1ez9Qt&o}~@z|GNgjKt%YrF+?1I1mIhyA_cw2`T@@@xteo`PT$w>x8?02m{sOQsT7683o=fh4m(RgV&O8rS>f3bnG4m6JMI5Zt*}^(obKbf9bybj7 zEGDLPB*z=(1Y}k+%OCY4n9jcSwCddyOL#(K419&@jwa3 zt#6_;9YLpLI_DdIRBx-Ai|oZdG)uWQ@C{3(X9>xh(`YWU4wxXxy;9OpLs^-15{X!w%i+jp{elCB3|yXL$Ian4E7KZ)-PKrZX+o^%5$ zbFacY7tM?P*an~JV{1w*XZ=n>ed(RX=#7y2ezSpxrVR=H-H^;Wu=N8WiF%vdBahyOkGod`@-|^eA>0Qik z@iQH71)@+t>+A9xx|3ifbFyve+vtXS{^}`+-oq9 z135Hh7&mWmhXjH;6tg$T7*o&@kzm+S^!qzQ-rU_@2@=r0;0FJ3Eye<#`~n4@JW8c zzWqSBdgCu3C}=yx-bwr~;MRSHa*IBr{&=KPI5;vT?2)i;HkgUWbql(-gt7m9TYTaWOJk7{F3C4V+H?aiR3^>!&8bS@Od} z(V~11+eJw8rShiM7x7Y$C<3{NnrVif88YLO)>gmX>>2SO~Rx;UJugdvJru-t4TQyN{j5X%2lY@KArPd^J zD}^MMP>V~14U!C|p9ITi0l#O8;KX{rqkWvCR!u|Gf>Lh~?UoL^Ocy=FuT_q>mV72e z-0!#o6A#jVmwm0RZZOG*cla%_!rjouXs9kI1n4j=3yUxrJ{E+!rI7vk?kK>pISpHOscNKv*W4aBGV5F1*jh_fj8t9^u~{;=CuK3{ z%f6RjPbAB)3<2EUJ^2NT=L>SZi|)QV$X@bJ=g4Bnobq&1S}auaHSOqUXO+`3grC%L ziAB~y9O>!Y*NWVNA74O#xfwjC24X#7)CfkZ}|aMO8IEY zUVdl&-;#!`NU(v8;D$mzdSz%zWxP_eEhQqEwbs4pVilWMR)uQ;5nCAgyxJj zUwGIB#W~s0Y><}kMl%-E*46H{Uj8?61tY7`VX3w(BBags5YWR6<+ZABP)zMNm^AVI z|_?U`wT7DuDTszN)HgERK}<7a*Ejt^{Hs zkNiEvoG(xt6Myfvc9{~~+tnZN!%wtxz|~Jwqll@Sa;WdRqhd{jc5-0BDR;D$U*V5I z%8_ENg65`H4+YTL&ETzPgXYX4V|Cqoj=#ReI zQMvonO#Rk30gg;Ft+j23C)qokc_)NanWfL80^+V69vNB*=D^SnzNs2C!UdnQg!t9| zZ_T0aKSI~8x_2@iDV37pVK)3t-NLu2ivpjbvSV+HzBay2zlbH7TV-RA_`Gq{f3a4^ z)j;;V2+lDE8+edeA>>nePj#O)RC7wxxqzS?vo?I*>NwiaHIVymXfX($IB&du5N$oKc`HO60V{M|M4Y=iih%+%}cmbsRgWca|RWP<_%8hKnyy zSWVp$pvlAaV`K6A+;%-0ho&eXl|(LsE41NTn``*V4e$o*`uDF17-nj;Mb@xJm&;jc zd%;Ht%J;`F4)DoK&gD!%b!?K_H~0(g;$vSqI&v+fNQTsHKyZea6%Jsn|1aWmBeIFer zsukomOk>QNpn>ul1PT)+1czk*R9%Ux-g@1h=zZtI2?jTFVa!+jGv(LJ2Cj{0uHxF3 z-sNN_poKx+iQQy4-Du;%WNhp%pC+ptsSki%$=$#{9<4uA_Jh#o?Aov=_`rYpQa%^_ zZZ>zlTrE<+sddk)NkjW{a*<<^qb)W*W}#tyh21Y-2jiUQ7R#Z)IxbY`SaqZ@QaouE zyykO;0*w9q)C{;-@FgGnRzWAi0uMf2?a`~!NgR#mB-jog z=k01?-}@xh2%Hc`s8-YcZ9rE_{s?(+^j3W3^+;Yiy7fl1w(O?$Jg;c=l87JgdQIc| zS;Kd~HFyr+A0JUk8Y>I66RC77Z}YgPVas1 zb$I=@9YVzw;SCxLErArItj;zq6B9vBOhESYPnO3dzxan^b zLQRskjJG?#uA#>J+Jjx-I#oi4iW4@R^LoMr9xiE>1QO*DT9{_*8#Oj!RpV;U-^lQ8 z$o>K(DvZS~-afrVKfVh0{+IPpVu7Q!N9gFe*pp%8V^DBW%?wncF!cQ3&kun#ea&wC z+kuuVthj(){ukqL75f$Mr&k-bj`tid_M#*3>N9_H=sL9%5oZPoo2jc|uzs4jajFKP z6xJxu=1sUnn8wnufOn3E&0^2T1ii_QG4AQChb4hTon-~q_WNb;j(QeYRc$yvCUu!= zp}4LO92}X*G^vN-=)MtCe7RG!EHqqqZT5?dWF@OWD#CIkx$7Di?5igF{9(n@kU`U5 zc{fUREne};W{{$VwNilKlt%E)t}%eA=rWO3*56OPs5kWDX*cB@ zyXfJLNBEs@iA^ce+-JkE$QlRJ1Ri)aZz0%>>p$WtH zs;sPb(mrO6zI(5lmJ9uJ$fMNg^^?*lH4b*&NvbQ8mXNG8yI5`duglA`1Ko#*`-fLi zWa~QI!B6OqE9xNbEhnNBo+Zpa%=~(N|9IMw^AQ*9 z|B}*i=6o7wr~4Ls6}@2QeDoI}u5>#wGwjctRa-A8#G zh534ohfkM|wpDFEu14`}=?qVcmrnznX@<7qp*BK7+^RX#G-3DjBsAsIFscm0Alk$i zv~JJfF%zY~fPL}eE0LD|nZd61-vXb(v@D`F#d#(!eV`UiIK$j=8w(WL9-^)pl1xfw z!OJw`juNi!^E=;L#VLXJQoUR3b_RBzh>(nKF*F*A5YJ_9VBi3X?O zs(v%vms$t?7v8~cL-q8$d(-cCMa`Bg#Z!s?0*db#UV69pIxg~|^*V1j`e~$p0mtpj7Qq#0 z8V^37-#D7(t|L?8{{qss(%=4_ECr!I!4m&n>R0^*pjM1y2CHZKo&JkC-cH10k4_<@ zuf#-EH*3|u-~sdgCH5<&pqrTRMU7*#?_1bC$H(B~T=u;`e*xe#Q6K9NT1{lFU;Q!m zFYGTXg=4{M|JJdwZh_Qlq#%@t6|um4q2_L?2lf1OF28491Lvr%uuO1YuR&pTCXsk*XD;1|CxAK*4gjXIwUCXYa` z7CDRS{SfY(yVr@`abalQNy~pv^?@BJaZr2EN5`7i_m^XT0gHbD>^*D}Y!&vgSvhu2&Dk~rnBrXI zLyJcFR6z{P5$RuDF*dLF_<^PEUFpEK7`}sd^|}^)y-dBa;U%UCqFo(kzicYI{TB(| z*5(Zsw-6ld>p0oGlPz#hLJKUfIkogwx6jY?RxhF>G=@(r&`rqsM+&h%7kB7##u?gf z+hbcr(-TLMXIOzVYIJDPMHxnqI=JW*IWQ9tvTI!x5AJ0_>L4wx3~06`Y<)Z+&JsP> z&v!3bi#dznhH;9~g443hBSJ~Du7s~3b?x(*02?rd2jXA&(YQ+~aGc=KNa@5O$ zwk$Ovn^kzRoon4qsr_O7#>TyT;Mq)Ikr-@fx-MMFZIBS|Zb2YjA`<-~)s4SX;4AWN zGH4m$#31KCv18@Vay!2-23UZ=9E#}oU^~`^`7=hemcGRIxQ?c19{j7r6V?Xewx2PX zvFSx)?lAcM;au|rkff#MsZ#tX;5B+oV~#muyO{hGw1NlR90M^|4wHmbU#dm~qc7_@ z@v{|vesR{{)BDzL64FoX(V~UM+ep`?I0W1nrusbWzeu{P=mU&|N-MIELW85m4y<(b z1^mvO1iu14vdg^%Vp$thItj6wjRWA;j|lSnsb<2v!<63Qe%<0v5eFvk&Ya?1yQd&W zo1{*#*RAqR;sO%L;#hkkxTfBvTwerlWwkjLLa>CcU=*fe*9pc(MMLpb3>D??C0x!_ z`=;i#>RABWO#PM($DI2=OBa%496WX(G3XCRvsc|ZJaoKLr^vIZqe?kV2P1+6QYBU z?y!aNIw$vLE;V9&cgD)OIbWpd4l#HFm9I`UO0EFcdN~c#4cOk$AXLSe#(Pz+S-bAD zf$x>w7#u2HxNUBzlxb#F7``yGSHnmI8c?(h0R3qK8m1oX^C zLQppKQ>jKc7=N0S#u6>v-Cx1L{dJj)OPjv>zHDms(oGdug)GB9Q(u6&bfcBE#5SQA z!x*#f#5`mib3Pk8)otf~#R8jCvPj*^zD`fNN|R^5Uwt|3?e2J+Vy(?PiL*UD1H&mF zxK)^M46A%|n5a{9CAV;+ed5Mba9ScTDKnhD*p+;z zy)h&T9>`@EmA(4V&P>kgNK}3{#>0)png$1J63xOwuOfT{K^NVfCXU6=F_aZZ81LAd zSBRs~!qjH?tySqJ5erui1vf9o2A7G3ne8J(2A091fAYenqQ)(^2ZvWkJL=z^)<}qN zCHUpts9jH=@|gY1SJFSlg1m1vYqo97`|n-dwBvg25-n-{ieJuom8+W5@$k+P+qY5p z1Cq)XQhI-h5zGdw)KBD@t@*3Z<}eq}tNuwRs8A6ZW`5G6OA`E1|qtQI{Y&eQzc_|R@+bF_qSb8SS!GoS+K=#^6u!d8Q55+ENc0?S~m$;rdb0 zvH5qdNDnY$qkE4WY_McmbG=}|Mi|SPqb*rK#qo`i{U>Rkg3urYqY(SC_Ncr4gwpWk z*Y*$e4x)hPWz#4>p53Qo#4?MU3jqzq{aoiTa8+!?9GOeF+;*kIxM`R4w3qRgpVbnQ8RrQ=VPKU?s!`oe5` z-PgK7PS$rb%oSBji+}v+em9+*iq)%pQWM>u{*`Y)s*;z+O-%M)F&RgaaI6~SKzgqL zMIQvkVDmc4yDWW}Crz+$>+K#rWDzkQq3PTNZMbZ?jovo@RN^^$N96KnjVH;GTF_2t zl;5q6Wi58Vh#r=%r4>NbC&?DO=l=OWmD}~Zy<#6p1e?>2xV<1Bfo~ss^^Ug9a2RCP z8K(TdUbKDjJkrIvBT`)hS2_ANFthR9cO(`Vn4G`(|IRahY~gk6=FaKwU@g@*E*Jq; zBx8$quo_;-S@4Vd_XNEX`sR8ts%Lvpeptv5DM)p-pZp8B!mJAWOnlFpmQ~}B#xMB^ z!`a@NUm_;?{whfGWB4U^(-ytS`p$5=rlJDy?*`Cg z@k5ZL6zZKxEOY;%LUqS*$lMBhc<8OrpF2L?z5Z2@D0M0-0qaIv@L*exw!k-N1*h7c zd7B*iVA)7~tc7Twb#$+aPkz5fXY$3BbF765``KREmaDKTdS|!}^Y|oLJ~nlgqbsC! zOL)3yr(aN`s*#lxNaI}Si(UFZbhOX-ryCy$fu`N6tFK{uGnNgMRMh@RN8L&j1fR~9 z+G}O)aR>-R3OBmk^85ocPZonHW;(iY^f$F+hjc+N>HhQSZ^4Bz<&HCm2krmxqnj~N z-nLt!p!FYcv#Z;OU(J;+XO<(etj>DloMANIqPc2WW=W&Wst6KU$O3SMzXb=c!O?!P=iEMjrYW_Z1aTIlyipln3-!*s zQoh}=U&x<0KR>P-Ho{EACuAC!6SIG5Bg9uXfQ-!cg;t%;C@s~PkZ)IsT?zrit*POi zYZOkh(L)PyJ%=BIzkZ(wZhx%Bm(XBIwatM0yCZ)J1kuTNVFKHBqKW4t^#q?hLdu^& zf`x2TnnHC7_wD(|avILwz_l*s>#i34v^RWrP!$vJ;I-x!weJrG)a4ogKj08Y^k+6O0B;O~G)p3+j@bSsoa-TPmXvU>8|4QK! zTFOjoHN@_}^P62*UD!4B(=(Ws7w4p3*O#pht5@PK<15zdA>PLrFWOe`NFt#auh3kA zTC5U6Ta~M5B=A~=Q^UTtK3lzcB zLURKCy`GsQx7V+=!U*vK>0kJpkl2OHOe zI$IY|15&ael#vwb9bir916%Sc3hSuYfm@oW=MH%??+|ham)llC%;S(FyDt<1nJo0c z%`Kb|c1K88Ye>vagR~1cJbE;fvk#HtqPyaz!YRY;j1tKoVJg0gllhC*q2*Jo?e0J$ zlxSFo|0JM4wVT7yk_9)Hk}=Jth>1bG%Q?oMEcD^vKt;i%nQCv*^`rPHGoWmgPg?=w zK~Di5VW>)Ldl_wt#^Ye7o06s7Y6GseFP4~tYN>GMdz{6QbP}1`PbO03>Q~y)pnKj+ zB&snYdT6HggQvNYKb(#y(2LP3^Q_+J$qD1L;i0qHtmZk#j&n6j^~H=bWKc62q%}5- z#K|$<*h`1T3LEIB;dxw7a|6@HX_?3?lUSZClGV7fA?x^5$Z(ZP&Ktzp@M8tM>F4ZB zh}FuJsZPx8X2hgy{n{tg(ELJY5k@)>6~tZ7DGo0QXhwisQa1hr&M9_HD0&fASzf=u z(l?OcrSh8F5=dFTFioW?>O z2i{P9=dW{?n}4IzJwfd_RnW4*qXO4kI;e+L^99l(jhJ2U+v}a6F$|M`S2_EPZsh=` z!BWxH_pQBzh-F9uchKj&23~6l>+EZ}CbL^S`IzF>@vFjHD=-Y{JGJ`TQZdgAwIs*F z<6QF`-Agh8OzMm;ZW1ZgdBA(}6SO`j1U<)akAPUiKCe{ub~Rg=;=J6uVJlGDC1Rlgy%H>td58j*9QuAGTN){58VsDh(-!HNT*jf|cJMNlkiyJ?{K?LBl%L z0PaW}mx902HJ|}HE2$N6EP?ajgV($kb_+yPG0Ycr zqOjs&W@q}uzs_dm0rLSYrTBy4utwNt$MyeOZlOA zN-4|eGRmA_X(g!RdoehZ1ZdaDw2FmkpS+>{38mnIg4I>AsU)Ql7K@*etbC`Y?A4_AYD^8fJ|uv3f+M2!zIeLhhCr>TP=d!?JR zltZwBG^da)x$1=gmHnJtK?aSW9G`CO@eFruUzH8nOK4!(9nUu5orUdF^n}+yWEoH# z+<-=OdC7oJv*h`eX0AFciZxGqv}NQGuw>1rJ$&(wl-^lgav+2kmi+~U5>nTzTQ z4H+lpq%x$NS^G57unjU@Ih_70hz;J4Di78NbojI^4UBQXvrtA9z~nkVH3H%`yd<@v zbCji5rFaDv-UWJ~U73#}eIJeg_1v%lmj9gIUD3|rIY?qkwl`V{x9k%}^0~fC#5CgB zCG(;hCRAco46$qW3U==!7NSQ=ccZbf3G-R$7z0px=~tdHu8zft&DPKf!!WDZ*yPfO z2CvC*=AU3#qB);8DMdK|Z9?TzmL^OgMr^^Z!Z^-Z}QCC&}xv zjH99;k4UCf8nQ_#`5Yww&QY2KxdUHaGy?GT07jToA#QPennQD4MVb~U{Ll@Tk|6bf zl-N9f0u6pvio8`t!uDgB$E&kD9Qea7VdvxIc*^x5dX!vE`hrZ4 z_#k&Hv6tg{s-Oq6UY5N=;zsQ19?diRI3_y0&PA=hJE8^L%H&U@vs)#}AQ9sle?j$a zmkz#F?N%SMrT)5;>9?Oj-al4JbWOsreufCaUSWwYUMGrS*BHlRG$NG!e8<~L(+Ykp z{jhc*-b20IxvV=Ll(f3CR#)#%Z_v0NnVEs5AE1upqx#%s7 z`0W9eM2Xq|V>Z{*nS6WfSNUeTB!sxU^k!CJ{F_Tfq%X=^RSw@%*274#65c-y)9M;O zb4v$p@aeL%#9kB>8B`YkzSh;sxByM>y;y>- z?g(+)A$BDN*KGlOL=pBxh1b3>vtsR_2MySlSH}*#0KF_n zm|Z2qR^OmRowR4FPK`r9Y8g1D`31*6%gI-VM`}pAk?-;$mAc}L4}w^vEAOP>1Kv?1 zd}9oY!&)GoLr3()ryv}HhLwXeB};G~gk>#$)bNg>GA|il&E4c9tRe61*_?I(w7Quz zLNl5aH!L*F{D5OgDJ4(mo__9Eoq8kpD$1?E4^EsM)S9=9F9y^O1S`KHvvwfJ@h)1P zAFSYga8=Pamd643w5<(Ne@6 zM(me@71V7wo0f5_7DMSUVC4Nr)LD-gjT3HXhnHNr+~kzI7&6wlC8~a;SRQ+wd2Oq>EZb^HDy3R%IyZTrhg;g{ z)2KcnXIe2V?k>`d1ah&BBR2Da;&(!f%ow|I2;+z@I$V-s-Z*7?PU%6bZ5BKIfZCKV zjqU5_@gSO9?P^J4c&e6Oa<&WrUJ(`1RE0?;C#js0@_qvAfvsxw32T~OJ}NO*3tu(# zv%tDKngfKvzc{S*+Rx1cvvbVQ2I>2;tzFDsm`W`pPSF1K;)q4lCNirn*t}8wF}TbMVIT^IrJ&l%2U?TG^@fy zWcAkjYiS5cxUTdwKZn1m5OQ=vHn4#`mE<5)gzJfggzr)>Q{Np6>;=)iG@7Et!&vl=OT!_|fL6 z`K8(}oKAYM6E)m`s2FoA97C^NvXC+1W99e9PN)LZ@cP3b-FN~Q_z;RBi?b&U18Wbn zwqr!Dz>yuW!ZZnVH;`Af4j(MkNE`VZ>>*Fb>6XRq3uB=Nx3_gu&RnoR)fl6oX+}#c zo>f$j_pv(c0WxuXpe|c)*UugJwm5;Z7`XjHfZ;sIKz!j{XNtO z{*)9s_5Z9@{T!4cTQl4iP2V$F`f_y1kMg-zBR-aTVf8B%y>FM_mhHPOG`Ba+e1h7* zxh9Fotd75oG`O=6YwhSN0%hz1)N^$G+tTsaEO}+v63Qj131+u3FKvxhl11Zt0>54` zZIpbECncYJ+vL3tu2#Y*mcpMCm#38({(UFPLT!m|H9R*OGxy7z|8bTE%UFij^vgii zyHUtY8tH#!pcX)Xu4UQrf&<1hpB`VLJ%)50p~`!-k`dR(wkcrE2WNj@9VDlg))a55 z!{I94M)}XoDSV-pUOhwQ0zAGcrNk5fvMnIPmrzDmNRVf54b?HXx^1rdk5T4Rcw`zSd z`?%DAUc_8kiFXuFZ)welMqPI2M#8n&@R5FOh_;F?k<;zqG`uRI!s>7dL`+DLy6;|d zelXUMXuRS64koG%x7&D(rYq2(5d@;MgntrUT9w=QoP_zJX8ac*HgfiqKQ4YsE41RG zLdXkYU3IU~k|A%Hj4z?C+fp*5Va*+0Gk}Hl)oc539*&GphH1|TCwM}|)I>+Gd`$)1 zzcj0`am05pC3;afhNf?y2g*5`WLUGOrt~{~inh7UAVf*^=ia$CcviiTO6ZdRQb>MR zQzuY2_Bqo`S-sw}6^QANau8iPi%@Jq0vejR1{ULenYz@uBjq5C~_-ZQsU8#PI zm){H3M>JfcbtDn>-d|0Z+6&Hic3p|jH{1yLl`Q@2JIO*1W!lQ|y@b_Pjsj|&W_f^I zFsdj3cS|S;zE&A`_$a2z6f;+nSL;ez=IvI2T4NfRY#amYXUVIKAFmf>IH|q6XEO1s z^Zop_%%86b2$bThS|4H71LD`}{jRlrH7{m%%X96A)=l!?%~lMglp;kHQ7+T)hWm?0 z1J3M9a^#tRUsn0-jK>|qK z1HS`L-~7^*f8q?e%LECCzx{CwRM3iB%2+0HRiZA8T@nJtvj$)(Qe5_v#3WiU`2DW4 z_gAdy&r^5f^B4<2DFzyJSH{F{65Czit%_tu9{BwEQ{Q{o8;t7&@~8c9N=oc(_W(Ip z$AQW!P?L7?8Py(jcD571*87VeohRzKqOqY`d3HzLx(-QtoOX2}J+5xp+EV@8(#>r# zO_1rk-*)_^i5Y)f_)A76=I3)xc%)genNPR61^=-H3MVQuJ`lg558fIdb#@z$GsDPh z%%*(ywxKwcg_i0#`XlUej_3v1DpXUp<4|2vnBmM^bzFCMbxd4d_l4f;AOD{67Eku3 zL<8VN&Q1)Kxn=vbomUC*BIw+Cp-!8nQ-0|$Ai}Su76f`od}yb3Gt{Oh7~LsZ>66m0 z_b_m9|G`XHj{z*$S`-#Cy8M(bCj}!OQGO^(%0V49P_O-bN8YdMzQsrGf+35%`PkqG_XIO)Ntht{0J6L)~?}Z=q4`?Tg>?VTlZd_tCopB%I{STy7yR4&F&dU zK_kWuP0+v+RSaG&JgOI z-xl0wE{Tv47{H{9h@-=r9Jc}K121%F<(o4Rji3(?2GJi|^p*IlqUlt-#nJ?6)C5bAwx`tYb-xk|t?Li(rX`h;W zm`UxYfpb^+@HW^g+3*WV3oe`8`I{+z@?@=5F_;h3s6>1&XZ!Dx>_CheVKGfkCNLS$ z@B6w!CQ+eW7uONdf5}#)vKh6~#xJ2{%!C*G#fm#c%t?dLfpY{*jgrC!uNZ&_#Oj3X zf-|{}^w9@bJa!NQBIJbMxl3ORf{U?h)erqj+|sMn@iN*Cyx;^Iz@z|ybo*p>e+IWy zf%XSc`Jn*Ub+S34Yo$*D zGMU$p?ZDUQbB;Z*ASD<@FDpP-DH15}QD zYjd{OGLGr(a&~5{Ub>%QQ|fjbcMx9JF@K^^t0PKj-DpkY{+xqU{d@z412Y>XWA)7$ zwX9yo$Ksh)JA@$8W1L|}f>2843n7sA$0_~Wf5nJiN}{#v6vxf#0=`rjqUrCXIax4@ zQeNU687^}u`K|9OyO_e;zRJqOgFm0SxB5O7it?C5m?+T)_9%Dqgd(t~E{*ibAU-On z<}A=JJu1XXQrRblE>YVKl|qJzI=fanM*ucq{E~>$vwoLVPU4)_8vS4Gn42*_onzEG zyeyJ5BMydN%WCYD5olAIWMhhIna!2_HIAhKFOI0jWiSDT%)M26V6?Du^1?0JNnvQ~ zY3}H2lJcymT6{7Gwoz`e^Z`JhCFN5D_eM&>q-gc~BKVc4xAYq{pe)s2xC4T!+Qp#y zsl2H`qnYYa_9Mgj(xOI{K5}X%1KRqiRZ9;8H9SGLmP>9H1L~UAZ|aYH&|c*YWYcHnAzfDG0s<5_W-ft&DG&#QaXvy93UQF zE?rAI$G9p=7 z)wtWaOf*E{r>)G}Wr)%kX(U_NU1r4rRcmOHk;W46TZL#|20)~Gz~oVd1_<-3z)@=- z0yCi{m6i&O&m9RsOyruO<{HA?-$^pUj`&l9V^=GQ-Dh7+mL$vv$dyQBlvpwG(<lItF)>t7}j_lYc<%=cUKa@#d}03{D#?WM1N%sK|gaQ68mS@+FK^Lh$C+CqM>+ z|98fac=`b^-Ko1w!!b)=61g{k{p!k#l7)RPdLeZ~!ca`&Z7>16IT1^)dH`TXeX@!e z_bv$?%INOq+tR9aMbMIMqIpV!x2H$SxiP2G3^6oV-4+hj?!t)1fYZzSRoWkp7u*Y- zH$eN4C}CbbJyRXCirJQ(F7_A}o>(1YHC+9igjdJRg9}Y<)&6N;1M^K~Z0ubK{5p7J zTdoTBeb$zJM!oVJ-lku_?+y^fL)J>C)C6nu=4~ap_J$$cTwTtwtZ_7P2IaW}x=KZV zey*|aK5q82;_y!GsAXj}0;jnG_?KX;shvYy(ftVVqgSIbWQIzj;q@CmOZWSUp6#@w zn!FASW!p3c#R_%^1Sm1(X^dZqSAU^8F#`fa$?~X?f0H>YqVa_F*C(+c42A0Tsl;4m zaFKCK%)n*!yty_SU1q24s(;6fxUTn;)%=mw{=6tSZ5v}Xx$0NQZ$DAnN=*+^?P(n8 zL#h7!)#_(;Iz2w?9+`?OxSa<(TvO+?{CEA}ca8jCh8>*v!7mW_3qI*I}4Y)DPcW}`5!|Ahh#zfoZdn0p;(Ws-` z)iPF5aN|-^bOwFOjbkR-pa$u;y)j@VQoR#JtmNK3X}kd4=@{$rd( z8LnM}Rhq1bthnzRi7i>;4|z5ni`2kN(w!e%;XuKKULgmlgdw(w4k zgY*mDd>@|E1OHv>LEFK>GyTm?c{+ZQXB+-x!#$gHl@bG4~Bz2Msn_nkg5gzDrw-gZXb!K)RLoQ1s30rzpaJa+`9?!dv?s}SuBj4 zq|gQA!uhM)GSGLBTQe9N!sfl=q!e(JwQ9n7v4ZU>i|x86?MwHjqKJgQD1ruUhR1RT zs7?kG2VHA3bz>3LsMfV(ML~p~ScR-QRl~87k0+`9IiYJ_s93qzyv4Ni$7w&*7qw=p zj36Sm3>@Q?E*dK@ZqwIZa>)CwncSNxHNyyFTFSouihpdwSa%kMA|lac=iV_Ip*(y& zgvu*MyJ`=U7+O-N0Lky$PuVfjQt@f!;RQ{l3QsX=@?2diNr=TX$fS+nstuLEQxWD` zjShIcsD*VW>xM6qfwl6VY|vckGWWIEy7BW%!hiVE%L5Hz+6Yy+%D-2+Evsn0%l`#v zDUL7;bqNvF?HJX_>FTir&W=6E$sMJs6A*|>o~;UM?cB%u>&aOEl!**mG1SO-n#oK^ z8u~fK?moua4oSw=Ph~cwO{MKrzBm};zDcD$IIMF3k}+L#ivuY>8(WTKmj&a}4nx4I z9NY`=E9($STyqJV$xQJC(jx?WSaym)XA^B-LO^ zr82S+WRJ-g7M6(<3u+#l9D4ePlF;5 z90e?))RF*o)K=7!O-*WO-mOYTr64rgzgm|$x=)^S#Yq4ynPu{%YR-6^j`?5+Oh=KQ zG)DWsv0T8aJsOHYtELV=j8tMWURt_#%oJYC5kf(aQZda$M z&Q*LXwI;p2*W!5cJECO~O%`NWGV0$F;~$6^>lFbT@pwg&P#FS^Xu&kBjS;9-5;8h0 zf;dYuo$}iV;Sk8?xQNCpUBHojk;sURM|XXZUBjA+_N$nR?;dsC^26lFjLqT3Kmw!@ z?yKe`3S+>!*n*?n-S+qxAZ3kNn{o>wkxHNTt?C$OW$7pAs&~ggY6lS9b z^36dJ?^OKPw2xwNimJW8U((cSCkl(5Y^eO9ikqc0PMyd$2E=Z7JMq=bP|OvdNkhNKio19? z*iRx93M&Q`ZLQ%JELEjD%01~9@2(JBLGU>Tk(dxWhPnN<`z8diD$ z2HB|TETc)Ppi5~KNue_WBRqjgyJYf#a=w~0iU=;uXkCQ>6R=WxaCfy$E#^;1+W5|< z9DIFpGGwBBxS*wvDn*OuSbuB;q_q>7 zjpI2EO*k0Kh!?;9qyXs(iZZFn#|})I=-^f?qCLwY%^4J?dUuk3y*jTnD*TgBV)ET5 zI?N#k7Sp?rB*cx3W2J0!gI&_RhBSgsn;DG`Njgl424z7OsIGkbTc$(|Dy|FI_PN4y z9MUj|(FY*8QQI8M2lLAz0;rGUiC69}^@}5G%+$Bt=GG3p)ySVHyQ3I7NO% zsY6GD(ca(8)%jT^PQRhPASPG9&!E&0RoPuj!5%wn33FHvz~-cOv*sNZrEJ|f!LD>& z?qL$YBcry)hh|E$%JdEkSY$Bbicw`43CFNC-a-xwP3aY!&W~9-s4D;k9%<$4eWRa!D ziWx|XDOG?mEQ&rpMPJhc!_9uoOuHDti+~r5C zSE4A9cxlAG%lB1I=d}}#eVV)~d#64gV69w`ib!Qg^rQ%97kL8L`ekAfoy}LGwcV~x z6Tjz>Mp*0EYqmCR>xSc7R4L~|94 zMMjN^_ba(qv&3()o$_w?+jAh!#yI`YvF9gc?&?7>&)i38?Oo3zd}{#wG^^bc!%|qG zSB;pmkR^Bg2>X6)Pm1jLdGNM&0Vm9uXEQ4n6lMhKbU3UFQkJb+MTDKK(Rr)F> zqrcUe1G=8Ua>otL0F3Qsvx2=g3YIy{*i2Cn9O-1^>If@fGSB@ISjY#EA8j8LTdNWd=3~jV+ zby-!sC0$Ccyx8z$%8pEf3zJy$3aY}DlD`d`E*-6XdV<^V*G?1|kt^0iMe2Hxr>l5O z#PukgRv@QjmvyxLtyDx-jSX&hqm$X_(ZFa(p6UImu5+E-)lvPL?KpkAAG}40+Os<> z5qF89j}IZ^Yv!@v?F!h2#Oy#;}OwXq8Vx3X1;M8?^+dGlNL3O#0{Ww2+^Abw)pK_B|?eH zs`(Q@`C$5)+~q-o)oazxax{JJ8X$|N?;s5l@++$f;h_fS9DEgv?v4?LrjCEQE0La} zr?NYQ;Z?k!kF9B36)>dsJC`9?;i@7kqP0j9aH{0{@IFxyIQ=|YWq;E>?NsNa_)-cw z(OIb2B}9;h@erG@5;4tzsDslYT)bjl76cGQ0(c_0wIGW>gx@0ine;iXC^tr|fwBc2 z1mMan8yl4_IZWoo5G0u=PLSD>VjL}VP;uE-NfV6L!;Y^kficd8uHKU(XH(RKJu#sEBJsID_OYh1jaw;ziY*QVbuk0CpTQHWlA!>Yt2>!fSKC98~df9?J zhDe)Q`1qv6+Sh?8QAbug`v33mx0iIoKOud=MCljY+S z$9Uyfxgj6t6^kka81UhiIY=WG)<@5%k-skTMJf@oXLogVt}x0AtRtsN$BxETg@eCq zUZay&M9EGX5?vuC4dt`QLdJR!Y~qHxs-Z?J3g_C*P)dUUc3wldC(Ea!%`7Imy6K4{ zAEm8~8mf04NX9ZVYb(VXJgGx-gu$9%%`5kVL?ZI2tk|tuRY09RH*&03IZ+zrPh?N4 z_*c8^i|niK&)GaH|{SlG{y;yKUt zX3d>0L)`Ka%Bo2cWSp*Zp5<4RuU9$FbDhtPbjat4B$4ERfhgbFK$(sa8OO4<<8mX~ zsmBV{L~?$9{P^EeT)u+#mgEC>txIhJ#67C0sz?%nDZD)sp4TYRs*CKY%6+}OS=UL?BRe+ z2o0c$6<4v?aCRPtosU_$WznRtyR+`wh{BY#Q$2G4~-4S$`x-q!;CNXW(-PT`# z-iEUhb#?W8YYc8?8;WZ(-VkDkWR#Dk%JvcrP~n~kE+E-kkkj(Wa-+b9;}eB?q!O3)!3_NuBd?;16HDl{z2*ALcPKU|8|Wo8X^)DCx* zVYq~T_9Zw$#vv-~0dt%WPRtc4UdUjICk`wWup5pm1Y;yFElk@+HlEHjQpgF!^0rTD z0;F;%UnNHNv*wu5q6t9Kq1sN;#q4;BCRF{6?3ulfwq*9~kAsT|JEmLqJUk_BI9;5k zG;l|gJb+7;ot>2)Z+Oj~Msm45&P;T33=#DszV{gWj%wwpl1Ze;gl5ezm8Q(5X-si~ zQaCZuqr%5T2n-m}yC{*|k%!jK8?m}|qQD(sE5F-qHZrR>@zjW>&X0eM1(m#lY?E7}* z$WTmym1UIu@{?iR@S;dNcXPwWY<}OLhm8~=+TL8g-GhUR-R9E7xQ{|I2Z*+GcK)bhi{PzP;Hzn zC1Tj75i)&VRx13e(*FP+k0TVZ#&2iGg++Er!!dy@%L*EnLk@f$QGqDH!#8S!!8ifF@RthoYYM-3zhd=VT|#3O*}07*ZH znR!alO$w|~v~md;k`^pOkfl(q-8S~xO|ah8YeMc1nAo9J);~mXJhrpmk$Ql@_8vvK zx=HGjTi5Q5C7jgNS7Cb>BEl@-Qkyo`xqN$e<@nY)p5t|SU07tu1r_c*LfXT!{2eBS zeLZ!YS_mbxwKRtBHUFS@?VHMsh8*Biev-*r}cSTvffdwSmM6u{zT_#|B)VLu?I z{j+TaUAj@^BEFGdX=PziPc>~kSl(8p>S zmQ{H#$ybgnwnA4C1w@i0)LxaOks3z;8)Gw-c^Om{NXr@oRj8+sWYoknX$!alm26n@ zflH{-Bnxf%Heo-Pmao(OV|0J!E3)^8^t>zXjC8~;)e;WA%=PX$U7gk)xkSiRF{WDT z9E$G-zN)drdxez3pMM%eTU8J2{9lkNTCjd)-5pk99US?2^L?e zxy_5s+Pco;3z-VC%E~@vjML(w*!XS3!gkc(&crBZux_f7!AT}e_?5C>$}_0Wo%&Ph z%gsWYB7pJ(j_n+V)=p20{@+ce$TE>q>Rg73u7Ytg3Mj!fh@}=u z-(mCA5#mLAN`mt#>U*Vbzj}4i-B!0|)oLFwoDUMM(!E3U`THBPqifB-kKpW&Rflc; zDQ8iLO4m44lf!r>O2ejH;vh(0ISwcy&BiOwnI=PKG-Z`TA1Eh6tZadmnMA1>UNscI zCyA$4#E_BrV@NHe?hf`tYyqpkQK${d->4T{**N{RQQ{duViHkY0QQWeQk~p2(feM` zNcVT5H5#tv$@Hs8HAcDgk#p!bxOGW!2g93+%q5+42^gQHB6QPCJm3=4PKwf8m8G5O zMRde7#}F~%jZh#H6TOM-Lu1*#2XT|vM3qaACqBguCodbmuP=!xTd zhS5CesDwwS)Z#UZZ(U7~;Sek4=i|1FYFzfRRda1~n|So8Ytz0Br}gw~eV5Sd=fH&z zVNKkddnBi)_G6q%MZab6nu#G_D@prl^oZv4RR_4d25&1s*1d?vMR5F&o6yy z$d-}p#kDM5i-$15Gb_D&Uw^W$Al#0dXltv15QlDjS!r>rGQj3LXbfP59I+7V;4 zapBNl@ZpOp!_RS&SWaRV&$<0iNEnTSn&;Gee8JwUYxU@5Q-?9EXAx=bSctAyp(N10J$QN??>8v?#P?x@D~{27-uz{i6H z#XZeU=2tQcBio9eW%-X=Hg%7yJc(xc{kNlH-@vw-s)FB4%Yjh`{vFQ5`l@31UcOV>^}uU-HHyd(@zW z*~7DyJL{>1Pht`L^VK_sI8I~Sjv>*{^i!61sDrWsv5x>?re${-b78%FJVm%A&%}w3Try^vH!kGgiKi#~|6(6ehA1IO56@SwB&l z${ft?)An_?RaKc|y-?#gg-Y6NLIV&s=8=lmYP^!#1%SsH(Y0nH6CivfWhCS9TbxbhD`LZRg zY`A4`6{_|)ampr{>ThpLmbIjJA5tQ!tg^xSuHSGmC|Ho1GF9Uh6!rBCek?K`Na06F zaTa8+m-UUrc*0jZ)b2C8mG5_ViG443Yl?i784I@5_Tk6d7TYG@RMzDCCgvs0Mn%1L z&dIySq#Gikd|L?i+V3*OHTAV={{RAqkXc5z%Pi)k`oK3OPDtO{{zP1MH9p)nAUew} zlzV1Dx!d0}d0&;{l4Za%*Q@(eg>xA4v!6-sV!mwO7#k%>D>udZ#!Fc9DkHx$-Nz&t zg3u$v2^zqp0T##)-9QG(WO=2Z8IW3VqZs*8>CdTM--|jWgc5ZL{h-H!FpOCq<2`9; z1E4DPT-IAx6CRHQ^YR^mR{fhIAz|4LqIHDHFzsbqIMXLh_?(R;R#y!~D;6XvJQ4{P zM}5!A!0I@TI|S(>!C^pZ;_TMM-!<=Jb3^MfpSr5wo6*|G$Z26_cK-l~<&>ewlInM(k3yB zSiID2Y_qHa3l~ zN7;5OOSm>o?qgc&`_XjA)GVEUXCRyrIIc zi6IEOB8{1uQX=KrGzPRUi0>e(RxIU!VoQV`z2+-J;!kvk`OkU-B z!yJ^&>rI-?tA#-~RFW?Gcybw50==Z1wUC=-Z;!&Zu925Op?t^@riTut`h8xW`j6@Z zLC49Bl!Hg^-L0qtlNy!PCCG)XGrR0CccrRjoc2}{-IT4ceS0TOY$r%q&6gnthI!Gu z-Ppci($`OR+iR{}p_y#$G3FoAjZV4Id6rI*wC)elwhgK=$=LSjgQ;mLsxj)*LB6q@ zM{$-{&!?~uM`r~1=F-Zn z=gr03dA3J(J1SJ7o{>#sJgZvx%1N@H+;T_^%lKHW^F)jNI*+&0^5@@^{WW2xA;>_Mv7dvzVTUzy+M zxa;i-_mQr0x4E3Tu4@?ABavIe_cg6mU+-1t-=80sMkIj5F;yH@85pldF^a8Y+>Ax+ zYkBQYWL4!+KR+4cJVVI=rNfYbWbq|kWCHq5JCeGOnu!3BbzmMxQsO7U$y+*nG;KGw zp)^VwxUi&vd7?)Ltx!I`5#H#nPI>-nsK4s}0Qun{Mxv=zc~xu3iOQ;?BVLGziO&d# zpUdC#=f-%?20Rbv`&Xb2N7R2_mo2BQB}=3_D?Mhkd=alJ7wQ8Dy!Jh)yuHf4=)7~n zaEOSS3Y14kH+R+8GIn=zs-II+?!2n63aQHSym-$U;=2Le-fd3JQqa`I(A!~T*X7i# zrB(2>s9TH^Knpu=Yo5Ex7b}K{ zjqOg>sv`FB+U4b3imJTljPYYaz^#s(A5bs#>L*IV7^L-_LOJgL014dXRd;`~_bRWt zuRiO_`>(%_F(N8G%kJ*huRrD=<@Wyo8GpN;6WJ5Sc+Utn1Py=!hqV;~y{K)sr$~Re z{-dpwWJOl;h`!u?z4-0>bNAz)bx+NG*Wbckw4{BkwzD2!^W zQ4vu)RZ)3GUm4>(Dd2xU+Pye>{Xe+rROCjr$kgEzjuAihSN-4T@VC}^rd@&N6}es& zlHKBYHEcUF*WY8-QmSpBm9XBZNRy!yG9$e^Q9Fc2sTeB)OE(wpF$L{fwJyi#aU-!Umpw zjJYz5fe?g*E0AMjIBI8%@fHG15RyqID9I$*B%+c@JCaW)qD!>00k9G{1JDgeU_Cnj E*-?T=jsO4v literal 0 HcmV?d00001 diff --git a/Doxygen_files/images/gtkr_splash_sm.jpg b/Doxygen_files/images/gtkr_splash_sm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2f1f3cc5e5d1a8ee7f1516a01e520c30469d062c GIT binary patch literal 7599 zcmbtWRZtuNk6wxuiWYZwD8*XbT}qL~-JO=jwLo!Q++lHD+}+(-Tw2`S_4?n<&D{GX zkDnwnnN0Gw`1S{YB`+-}4S<7#1IYeMz}qW;K*Gt~*xB5S(#_i0ic;OmoKi+k>HFIX zK;l2N|5yCSe*ZLp{}KHIxv&B6-u<&ffJZ`t|L=R2%>tL@^a(>YvrPG@Sn6 zX(TRjNcXww-;1|p02(~pzlPzl0V03{P^$-MbHRUI`iC--fYe~LuZTNC>A70Xq`tyT zP9bDCv$*HFgJArUw2r5R;n92bC7EmCI>5eG3YIE#C6=&-636ku`2E+Wdz1sF^k+d~ zmAh9fOgc`*%*oiIOOel3O+y4P;-iKcS0tJ;gAY=l4w*lG!6zJdO%Y6vt~w+3PN>+u zJDUMpt@f#9tb-rd-6*DfR2~>u5A@ixZv=(oyH00YVw9(Tz;v-|JPm9&+%vJ9uO~W7 zt4mOQ*xa;u%eZZGs}d9NHq6QSu`0x}d{u$!zC_9@q&H;tK0;&+*#;^=;GBA}kPnbY z%CW-rx6R|>ANX)=0JIX75$U}cB-B_coX|KdwmMRV^wGOT?|QJ^qMgUXGAmh6x6lK< zWB++}@C>U>`Es`G#QC{Lud4AVN8H=5qX^2_9t~1aCKKPRdg1I#iE9pOTYg+3))Vj3 zqq8DU7t(|py|4%oEsZpd-5vM+F5I2chNtz+oGBoW4PL54|@z?5a`l^{C!{ zahRVeCCCt*g(aWKB0Uzq^3c2|R=dUfU5lID3xfC8CYoz>W` z_~ckwKVDYmBbf8;;NY>cr?;EwMfut9q9=QZyu&Yat#;60aGO{MKc(-aTcN*Bu#w3l z3=>E$PHF~OUUHpqaYc&u_3lM3R(O;<$nvH#9GW26WT)87Qh%j<15lTjKjBqIw;|(c zE;_bR54fyBKltA%k;ivm2*el!)|i8CImD){?+{YWGchTAdpW+(?N=T;fZXPsG}RZH z$Cqr}N(qV*0|$OHVV;xB=_QB33$N1f`xYD|$m|%KydHbOFmh{~H|j+G_5#sY>= zibJ8vI7)UmPl zY#-S4IC9e9X)wHT-nJ3>X#OMOC5HL$i>2i-%ae!etF%WzT_PFhAc~`$7i47bUH%NO z-5h@6#p2>VVK17Cj@G;mTJg8~co>i?v7FhG6NG zgLB<#c8OeF(bP`47~BG<#`Y|`jg(Sq(i$=SdPK3dFDZF?O1G-h*oIhp)2gLMl6`ff z!1#XsD>zHp5N1?+68hcLo?a3@coNp|IWP*Yf{d8)L^3S!4UlI21{k#5RD1(;v@iHQ zzn+%}Clv}??zx;aUp-`{s?!A#i+z=d$Po@aI+|I%dA(l0{6) zD{tiOa-mq(DfKR9_=q8d_Q$V^jIS(DwMF0S;!ck#hIo=jc%W!E2*& z%Jb<(NJf5(=)SOBlkbdqM-Y;RA><}Pqm#3D(71X$8XYqYT6!F2KDv5ATdKQI)rt7G zOkmED&9r2pqIS+I@e@asgb3w1&JN=v$R3(E&2S|d3r}0=QSyUQ(Its_+o*MOA3a%e z?Pb8MQqE!3RWH#Gssz|?E1qPxITH%{usV&Mw(32nvc>Dzp3VsI&M1~ zVeMUNt(;V0HYu-61dz|Y!Q354RXVrvS|A$2nQyy60#5@`y!3;#f zt$>quus&>JyBMkElYA<$=660^HqP?|{JCcuu>x+ybu7)ZpjAypobQX~TlMkv^>&sj ze3t7d6mx}oEEO<>j6(-6*CPgMbHj#N<5@m=6&&!nPRc#**Vr$iEo-4|HW%)WJl~J- zS{P#dEi_NJq#!7|nZL64V2JXz#F+Sm;n$m$8FnBT!Xm=ZNPNM4e`ud6ZIEA#qj9&- zw27(zgE{~Q`KQhDHsK&Y5#bGsk3YMQ9>7`3S2S(OjGu4tmI_rc)!1~!)3Ziocvu(r zlO(nwWADTauv&)dgP^@c*C|=(#Cc%rooF@vmT5Ljb86u?Tj+JKqJB44w~`9a)hq3^ z2Et+|a8|cVeNZ0dBAQ|)*33D`cr)WT5om%WY zH&P=)ZoCn~_c0Xe`5;H>VPY{f6#EW*55A+jna72=bp=)9Hm@C|2Z&q%GGuc7QX?_r z5IUK1Rs1l(ZkjTvu23?w>u55Jkhcg|i8gkcW@Y5k&V=@hP`l-U4<_W!=Vx(|Jj&*1 zcKxt;(&jeda_SZV8BWg2FW=|O`oqqv)ZyojpT^JYkjuNS8QN6AU!;`GT)5ec@ziNy z?jIa9ndmM;=uNeD%x5Vx;q03rN-9s?S$&J^-BPi42=}$ z=aHTLP4uxZ;M^fYtoC_ih4v$KK?H;;lw}dxmkcMR2X5t*{uao#1->J<7Kg)FF z0v>d-^wk!BDn#vO4<1&MpVq`*K7r4_+^-Jo=}tLm;Mc()$#fE^Nad{_uH#iL1V}$# zWgFNV(~R6`aLoyQwsrK#5-+wlUoeT@t(pNOVFX~o2DGGfy}W?#sh}GA5DgX(P(}$v zt3znV!jgm1ouv3fs1HQ9{WYAwlj!zVuv6anHa5yh9oC?OZC}Q~@I_^2V*f9)00R9u{197bzXWEUgU+JU}Aagv{< zjU6Mq@cd_lpYt#T5s9fEZ;*g|)u%uR*JE==c$<6n(TLd<>&{-F=kTcUmX;gPg-^g1FDfVAX2kz69)Kv zrI=mi^CoSNN)+!lEp8MhwmEs9dY)bPCx%rtXFe3{ zlZt<^7m9>KVzd+f({&94ZtG-X#g1ASx%gB4uC`301#i?n?lHA$)89qQnp$J|nf*KL zL?ond02fIR&UW_5*Cn+j?9!~E&}_ARdoGWujfGWD@RP45(CzCs`cZ)2)=lT#$Wqz} ziryanZV4i*;!`2s@nwPAFmWg1twv9ujaLm}2X=kd_VSe2UZ*l}UL1BQ}WrolnP1_qB3PBA~LbmG^W zGo9SN&U39{V-uG`J(-KTV?b=)@QHRV61_|2oKdMZ`mIiM3*Yo&ni@Zs-vm|9AiY00 zoo3n8NeTa4V|1TthZ+U2Pr=$!GVpv!{nSUnJoz9q&ZMibwl;dwTdh2 zH?|grYe$>vi8&{uvHa9n%+}>6IqKYpw#}LwLegS_L=CuuTFBXGbQY{2706QA&@5hi zH`Nn9genc-*ynGK@~`EC%4JkIi%QO?>1FR(Q8mSC$p&kr<0(a|h3er`^)3BL_?7Q0 z)yw^X)Tys#6mz)jrIYr-$Jwv^f`G!Bg`QF4bV&qQzPhGPdA)$P#hW%hO}ju zpz8_8klZS?WX=I;0^tg{ za9S{zKoM}a8I#s3QV3Jti4VD{2OcutBq2)vRiybFKxlTa+-?)5StCDHQDzP^HzxdL zp#sOB@@J2+iNcKrtFZ)4*DY%~ov1tA94O(Zs?q%@)kGvqOt#l zd}oTYQUH@)6*Cjjp2Z5?7u__gV-!|_E;sE}2n5p^k;kPYZHR=*qB-ztf>FoFx=fo_ zdQ>0}5y@MU2**5_iRN-FgS%_8>+>jvc-eMFTd@-fTV5e&!Pf0OVQbS)w>Br;soHQZ zT`;w$x7u3&gm`2Qt$sorT~L9ml~?p-5+_zXqE0jqrB#DlY>=4Z30pZvnSgaXfe0hi zJxQbhL6&)-`qa4}pF0|~lepb_ip`m;#P2gqUL%AZU8e=74?lwZ)7ieXRT}gFenjdP|F@jB`kWMBl1r=yl;Ijfl(i%c`m(zPK1Jpox}6wDMV$ zJ~fNp0#6xfX=usm*$On=z4unKgmRiBSc4UHtaN`!`HJet2142SMPG z`G7;X2#G2#XZ~doep}eQ*AFxRX1X_M#@An>$fKA`;0}T>?pvgT5Mt=g2RdCfdbVxy zeAYAZSDaWaF%*ZMCp{>nyY&|u9fQ}1Oz$}MZ%pO4er*&3G*SO1zgRuC`3IPYo) zzP*7KCDOPX=8ehWjYYf9SWF^hGw|a}mPD}AFA(#SsDH4Nd=9h|zQ&YYt_E8iRw0uW zu(I>EzRRMK!bSMx=Y-FsH5^bCsZq3x`DOLSw$(HjeZ~GVQ$B*0MUfGBn30j&|ZT$Q#A2S(=|_q_8!V{B#t^?CeASphY!eF@>j4m0DBp*7># zpaW&?N$-APUlQJ|FIP5Kw`}a}oT)FEcV5-1APvcIVV#lTvZ?#V3!%<%z6};j`z`Ly zCGpDiAZKLT4z8t*wBh&~>F2OKud^2(P+aQStxQ^TN^IBYFQ$U^x(}XREHlm0k^^nu zr3BzYR04Yqg7Ylh$(jBb(9ujL#>D?!`hn;HA2~Fm8n}6a=0VY1&Nu^p<`08NPO*RB zBF2;5mfP}407T?eQ)djl1E5eQnar_!9;{yg!uDK^_D_@%WE1XJzW0S~N)E=M_Bf>} zc5-_bN6(gvhWyT2W{M=qSv?I$iNnF;W_{5k}SFSTQ+O^u@J^H0dUM^oDw&?;DW%>1y((?FU zf~6wS{!F9sDhF7i-@zudUk8U};#j=~-vGppZ5iy}=*ZXO;-yq&)nZRfwAxsZbs=$_ zAhsamzFzJ=RC(ElcXVc+EURyT^p|A#?lu9|9bvo7MXWMb!u;PJq{Zm8`-K74I$GOw zsR6CbR^rP<4^uL~Ik5ARv{8ozNAJQuhBJMX9r>io&~&kCQvf!L6>uGYTzKy&QdBj* z(W;R2sRfQ{)4tkCcU$a*xI=Pun6*I3TEpD);|i8>LZK`IgXGBF0PiLb#8Gq?u=o9F z`GD5PC5>ODu!b%>J2JH}PKK}l*~I#){ct-G8cnS-1_su64V@KnS`lS6DvU$-uc)_f zWQ;EC)GTmBX6cfOyA)lNeqf0ax-{IlAC_6I@6)C1P)1;`^|Aga>-^rK1RA<~ z9+i-DF?Sqoai#h~xHw{V5*;r^mYUd3UNDyN^9{fqwJ_k4f|Re?v#e`VI;4=ASUPVj zlSDw!qxlv6g0uGT*fFI9h9Hg)C0@QN>VeDaKiT z5zMvvNjrGTVeiz!pVBcepDYzA|B=u4W-Ht-)Hqr@kToi3uM+pKhzGUYrWso*y{B}? zVT^P$_UIenlj-ud)SV0mP(@hoOgK0>nRUW5A1Y~AL(SZ5dS{z?y41>ictRfp6o@GW>=VQX@;!33s@&`vafvG&#U$o`Pl7 z`tmvFHNVCXFSP8(<7mzC8$g49DgkfI?PHR|Q>zw0tCTHzS8^y|Nq#q6r?3D5FdG`n~FFo={MkHepV8oI80nPk!RSB%p z!+Su=QI$?Y0zYI*I6r1RfJe>mWC`B32LTMOFAzpKJVylydF2PUwsXwr<%R zw^%*`m!BNl_*XPUd~P^u=>3DrMftX1p6NlLLSs7u?xldl7Dl|jqnu_VZ12`}_s{ck z^Vrh0@(kOJG-yr#n{Kei>{p5LQqXsMdz*$iAzdySr{*=ja+$V}sQDB6YHkdFeR(1K zOxc2lksQ@^R-9B-$qWbgttXxjx)M#vW}ZFej7*WhG^pwH&-ZOl!lwawpwB zF7*aD!B!!7Fx-0su-rUlMv5NmMcD{!A>YxckiFU|@2zayzjS7A-M$J3kIcRMHc5kI z7SSL-g-)r^{?+6(2>lnHoqUYb^e;q~j*8<0ahRxoyUJerSJ8Jd_FZGMDdzQ^2ER&t z$2jYlKrn2Bl;~!R_?LEBVhhnBnaHALISvG*lJ6*e{Pg2E(#hk9z-H(%cq6iNa25n{-(l%R8-!hzX2S;1h2Dy`fm-N zi#pGq-T;#e1s7685Za#ueIQd!8p8R!oZw&!O^alkf#UDp03m!LL55{XM!hU`4_9R)v^e4|6^vZ) zSt{XJ;OGFcA;M6DVWTV*;w7pyh8o$d&|5yJq+!Vrv4(~RStMJjkc>tWCBz(7rhv;D zl$0*P82~55?VygQk}r!Z^brL=A6`-m4N|-~2UpSJR&(!iaCmq~NxS_5V&OXQpXo0a zaPg@YutQ2i62^5kh5G{SM8nV-Xjo3GXt)c@h5fGHSef1#O1=g#Obu?_rW24U3e=}* zit=Q^@wK1F%{ LG^~E{d|Uc2vL2Ik literal 0 HcmV?d00001 diff --git a/Doxygen_files/images/history_id_logo.gif b/Doxygen_files/images/history_id_logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..117f9be1fcaf13da7a2f3be00f83e6cca1ce8d72 GIT binary patch literal 1427 zcmdUs`&Uv20Dv#Z<9c~`Bg9w2g&qo0A*G_W4MCAi7i!0{=>|TU?kqEBHaqixK!V~E zb*8Nn)RVKBO`Vl9qjE*oinL91t<==fDT~q{tQ=?CpRw;R_`dVS?vx0^6@1`B;3fb_ zLa7;2DgXda`;uq6CDT8MA9rkf+_t5zAS5>2H+%O+HbR{3m2sGGO&&KZfe{-<8>)+_ z&Sg$_ee}44Kd292)4{47f5~=o=B{A_*Gndy#UBcuaKTsD); zVNr&gq>@n2;l>y?gD_YTG}99|cS#}H4rj&tv+3?bHG-OhfwAF!Py17@wj^fDHVsvW zNF(TMggo3RsrxFdHa~c_do6bo&b24N~zXpkC*B68yy=tu+t8C0IaV91z0GT8%$F)(?}X&hxO6;H*U>9OfBX6mSI!aiy9yihhiHA(aI z^m;VmJ-IMu^P0ymnwn@{-ir>rr(2ezZAcOgH)%CTvA z)cLm45merkQNi>;7tjRlDott8I^Pmx57NR+MT<(Mds-i%MG&a9bEKF*qFhhD^WAT$ z5}FVFDqOdXmywwEO*y@?&(Ik(;9luUky1@B5sI3^z0gvH*5Nn4JeIy!(S=wU7%-2&25$BIcAE_+8hb4|ne$IZLVKAE+q`0VRU zSR3Qfss)RMO0|9!?zknKLFjrP=PBbpwrh4uSBst?Sfn)@&4nvlr;g z@sL`KqR7>1BzV*|hAs8y%`?Mc_!?U&3k6#`@gqRQDSj|WK)^LC8YSdXII3i;nk$OV>+(v=;0#-mFPAj zT^NNE=~HBf^%EsI8(^!r8mnVDEpBfXdR3d(Uqb4>ShQxMMk~3tAYsA^8LV00000EC2ui01Nw?S0T95b`mRh%)-x{(aqD?)y~V(*9FD=q??eg#R@#5Xv`t$bn z{qFtChmK#tbNdkb3kdKaJc9`zDip|&U_^Wn7dpf^vEjvm87XcA+0mlLj}=3DJjqfd z%8@CVZnP)>Awv|J9bQb} zF~LHE4LB~0FmYi(0u~9vJcuB}M2HtQm^A31gTV+H5nild!Q?>-2@x(hn$YCH0uCND swMbA{fPxx)3o{|`VToiW0xDZ>QsKb@C7?r#9!C>oFqYeT9JGjFfumAu6 literal 0 HcmV?d00001 diff --git a/Doxygen_files/images/top-tile.gif b/Doxygen_files/images/top-tile.gif new file mode 100644 index 0000000000000000000000000000000000000000..0c6d3b2f6713d9918c8e39cb65a6317dfe45bc3a GIT binary patch literal 122 zcmZ?wbhEHbWMYV6*v!D7re(~)!0`Y7|Ai}ersTK({{1I5z4pk-%MR{g^Ox^PE$G;L z=-l&{Z+UnHzJ31zRH^ur1xPY5=zs{284N7y7c3Peqz_B9L~%1J^rd9Z%UHE8=k>l1 Xg({tk1dePHVRdahus}eBk--`OiliG{(7iKLwBE9KX9_gIX~|A|Q{IU1ci zH1;gFxLtprb$w&=*}}TE?$M;w%%R~?74_YrapyZa@4NZO>@%}J=os*1a;mVnd}VuQ z>%Z@Q$5QA=LfJO217#m1wus^M7p35u;pHmjPXvyao-{^8@7 zjh!8@z>^N{A-CEF_L$nnB{J)~7JY(Ft-M{m(e^SjCLuk$;PaRDf{P_rs_vXGs!vKg ztEOf6{l|~7M^F5Zr7$8hom{*RhcQP+$Ni2bH8r=ITRQ}Xr>l|lT|Md54Q(EW%3OMKIYm5BYWU>ACWUTC2wj)mKBhTMkwAD}Euq`C{KWb}uR!6&GS7CRz@kNuv`A__o z8Dsnc$39?W?b~n8-U)fu=s(`xJl_$$v-GIKUOE!5d>CuMjG}cj#(+|Eym6**<7d;EEI-;&XK9ZvQ;r zc|xwXDv;?p;~yue=y<<#z5jm71t8KW3zip8HtnQ5%n~%lV(Ec>Z~NB&%>?;_`)*_v z7#Uao4zXB-A$|#UOzs8VU=G@0*>qNHm|B1(8gMC6#_HsU@{lE zGYVviI@%INq#5k0Z28mQt8xjIiHvi}x4yr*mZQ4&$oV3NKug(u{G2{mBB+1xV!yL9BcioFhP6!T@HiWm>qh=2N$G&b+Q(ViSfMT}slo}$+4=v=EszI0Hld^>bv{9HW zsTV%u(d|M9sEnc4+2^hfujIv39-dFjw?oNSQ%l8VmZ^E5g?uqXXsR86VP$M7ENM{Q zhXzfSTf%R9eu}mv*~;ef>sd15wS%a7V*50hwq zN$>78Nf5p+YLkTVOM^yL9iStjm?0?@%*sRSxXGk6yUa;{O!fU)mrhc-?7cT5!6Y$c zN5ev1{@B3&+oFjiT5gDv$mxD!8n^P7_oSAs*W>7jTq!Y7@HaUJN$|llTyOeUWZS+T*P`zrb(zeCT?|K zi`B`N`%|TaJkU2F@?|qkeGCPDZ4g1^vhw7th$j(B&#n}!iXAJWNZM0o+V%`pNoC&T zr-aYsQr!UeHm>iytMvvWME1>C$=xdSUnd2I$!)S9pw?#m0 z#4&#IO~3eTiCM%^Q7bhqi^Z;@>pGR(ES~HH-rX6{D;7OtfO!mV(U|;~fgRxl_8>wB z0FjlDu-o@(zJ8TjsJQ?W2d9(l2vx#%qA4#(>7=F!<%DY-Mfbti z>w1R1&4|7cxCQ^9-`wZ9!k3mkgn~P_)E`hMOzhc^fy#b-Ayv zyKcH@YUBD37t=4K<|Uypx0&UR>Gzg5P}FHgWVuIEtFoHZHF|UR(X$WMhIXnm^z!of zBisxW?oMFY?=wt-jv@HGtYzj@w2hoEmJ{`kkm$den_=c?I8U#L~T72*o;#vtZl>O601dU zp@z=uP};y)gYuB;*{#03T#HK#veJaVp!i6SNAR5-0cDb@+{{@1Nj*({-#CjgL3buE z@_34tgu@(z{vKA%;v1IBJop)Q-I^WOfV%pQZlboM-s3LZBSWJsuf4zsO<<03A zR--1&H=4&eIRny1_vn_TlxUp!HQOsYl3iz88>4x`=Mg{=^58-U0>|IgFO7n<5RYgU zoDEN_uW8I>=EeFV${CIDy7KO$@tQbc`3r3yi>NzEmYV?{pD4oH0yMF2zX*R^MEl-h zDidbC1rbijI$@kU*r=v=+4_5@zDh*c6SXdp#4jk>C%f+$=aaEFAav3toTG0bV+?ao zl2AHuE-lY*o}&a2>FLck+jf(dqbbO%UyvnClmE;ktP?8Iv8Od3l)Yl)+XqJ#hP%FY zadR=n&;W4~dFAIQhzK5CkMpm~!+p(fC;Qh+Kk!9-l`_)X=iZ;^9SAhk%(jKMQ!fg; z8YRfqBE@j#a1g?Zbepo@3x^f(aE508{9vW0Rwo3ic#akA?Oe6ag7FSl1WZQI8uU5( zs2_FsCW!RrPm>R}zJ?xMJm0{qIC6U@NxPv-Kk;J*=i+0NtnU}EceWMeH_PZF4Af7H zWXrUIco+cp5YUo11x;DSIUr2#R8YKKZsi5VIVk*otC1++s#z}{lNm4(c`7f@@|OwiVr4$2eHT-J zN(XgDp};vR+S5LJxpu}p={s}LR6HaS!(fg$Tr{EVj&pTK+#CI-jf=VQWBDw&k5Nwk z5Msvra6rubnP=K(@umU5m#zOT;yxlzP8~@L+QSYEBh}=Ty-z=*=K3%gMq+&UTW(U1>d>Z}6|ZR;uVUmKT3t`o~>+ z(QKIP1qM9 zw5s?q@m^%0^|`A`y|2eJut#0yez2aierN<47Gj~K2;rXbSyCP5OM^Q$VJ!drAd#D# zoVF=vQ;G&98Wu=|tl2m}@?pg__?>9nlL5$&4S2KQK+4$~cF42UQ}VRXUHURr78)&N zJ(a;IE6UM?Ek(X`K6xydJc6ds_)<1qBBs&8Gyrk0Af+Ce!$PWYV<9>u%nr{2;WZ-4 ziwzKnCfa>~KKFtU1z|#9!H4vY7lZ$-;&cYlPOQiqu8Iy!sGY_)Q?%>M3ll3uL(dLC ze>$P#Sk*cnuvffvH@S2-OJ9{8Kig_1EO1$I?+)X_lrxSFC%;pcUIR?^akUlesr&z%7KuX@8%V}AlDH%3qBDSiWzO9EkQ!Yy7s!4mEic|N# zwYsao+eZNb9OkH3S7%_OQ6gki{yN__^MW5U<^rN@#r*1{5T*?W)II{pu+NTID_u8& zh!n&+sA%UMe>z^Ran-F3S)Q+=>ndZZa1xMUpZ46qGjpzF6G5-FGx|mq+O!HO3u1^7 z%952<%|tpYpZj}Xt~UT}GKyjRVZ`XHk(tW4nY48oQwht1-)8yTIw4;UVz9m3rvqom zwbaByXo`Q^Ql%JB=0SrVm+l}*99VV@^yXc?-eKs@GbA!oz6L6~u~8DC1m);_oOE)D zr>_FZ*`0iCK-7&$cT;4Qp{x-66qG~Xwd_eKmJGyVp&%nRYZ$QXb5h_TJh4a<4tR8|uht2G8 zVpv6n5sJ*L-A}h@S%XCBCq^zK%}&PR0Kk}qurboynneDdOh+>EdyI(BTr%J0<}@9o z+dRv0?}OIX`G_<^Q zYY$e)v?)zqXcGX*YdAv=Vw+s}eE2TKQi-^6*N5J0Rg8>PJ+9J{-hC_)Z)kqKt_g(VOb=!robEhF3hebkI8ngI=$>EuP;Ev429Sy1mS{g}Sm;L5NL_d(P!HRD zlN_Fx)*VyUn`AQZsk>d}W&6J-545NczRVB&rHtc3%IuxufJ@c+^%o*rt45nn-Os}v zF|2iBAs{pnLrLYzKqu#LN@Pv9zQ~G4@O`-u)q&RVJ|JWo?Vr=tajth`zH3)I-={ffi^LG1 zLmNFW#d^bO$N=mCD=borV@jOpP)i*?xp{;!eZ_bb^)juBG~M z`Yr#mrudtCkh5q%!YCl@NPLC(l=2U-m6PdwOr)@91j zcfb4-2U}P_4tWH4Mp1a4y$G2qAjV^Wcphlc^PF;Afu9BY5ugaB64n2OFv&)d3+OXP zvF}i(^cQrYlb@?l*WZsDkYomcs0%{j-<-XNyy2ODkrt_RN+q%vNsCvK8iv zA0w41_!V8s30kTX7wPnL?$-7kM`6Bo|9qSOe0$1#XT^M1&;0#``QGjMyZ$I`CaAUitF(Evk-wyeQTpPDgkfQQs1aozG)^)Z5f4; z{=6aMm-NgIEhz^`?@3+SSGi=|yJY%m$?VS(1;1=zwrmx!d@yy{wsP67cbWQX+40XZ k4Zq@Iw&E7B;*q-IRk`BRyW;n1CE(8r9skx9&kvaV50ZNQ>Hq)$ literal 0 HcmV?d00001 diff --git a/Doxygen_files/reference1.html b/Doxygen_files/reference1.html new file mode 100644 index 00000000..51cff17d --- /dev/null +++ b/Doxygen_files/reference1.html @@ -0,0 +1,333 @@ +
+ + +
+GtkRadiant Doxygen Documentation + + +

Doxygen Quick Reference

+
+

+ +

Index

+
    +
  1. Commenting styles
  2. +
  3. Qt Style C++ Class Example
  4. +
  5. JavaDoc Style C++ Class Example
  6. +
  7. Special Tags
  8. +
  9. Structural Tags
  10. +
+

+ +
+ +

1. Commenting Styles

+There are two different styles of commenting that doxygen recognises. +

+Qt Style:
+ +/*!
+ .... text ....
+*/
+
+
+Qt Style Single line
+ +//! .... one line of text ....
+
+

+ +

+JavaDoc Style:
+ +/**
+ * .... text ....
+ */
+
+
+JavaDoc Style Single line
+ +/// .... one line of text ....
+
+

+ +

+ Doxygen only allows one brief and one detailed description for each declaration/definition. + If there is a brief description before a declaration, and one before the a definition, only + the one before the declaration will be used. If the same situation occurs for a detailed + description the one before the definition is preferred and the one before the declaration will + be ignored.
+ A useful method is to have the brief documentation with the declaration in the header file, + and the detailed documentation with the definition in the source file. +

+ Note: Standard C/C++ comments are ignored by doxygen, but will be included in the code listing + for that file. +

+

+

top

+
+ + +

2. Qt Style C++ Class Example

+

+ Here is an example of a C++ class using Qt Style documentation.
+ The IEpair class from include/iepairs.h is used here. The html result of using these comments + can be found here.
+

+ Note: The resulting html was generated from a single file. If it were generated as part of + the whole documentation, many of the function names and variables would be hyperlinks to + their definitions.
+

+
+//! Virtual class to allow plugin operations on entity pairs
+/*!
+  \todo Write more complete documentation for this class so that it's use
+  is clear
+			
+  An interface to entity keys and key pairs that allows plugins to;
+  read and write entity keys and key values, get a key value as a
+  vec3_t
+*/
+class IEpair
+{
+  public:
+    //! Increment the number of references to this object
+    virtual void IncRef () = 0;
+				
+    //! Decrement the reference count
+    virtual void DecRef () = 0;
+				
+    //! Get a vector from a key
+    virtual void GetVectorForKey( char* key, vec3_t vec ) = 0;
+				
+    //! Get a float from a key
+    virtual float FloatForKey( char *key ) = 0;
+				
+    //! Get a string (char *) from a key
+    virtual char* ValueForKey( char *key ) = 0;
+				
+    //! Set a key value to char *value
+    /*!
+      \param key The (char *) containing the keyname
+      \param value The (char *) to set the key value to
+    */
+    virtual void SetKeyValue( char *key, char *value ) = 0;
+				
+    //! Get a vec3_t for the entities origin
+    virtual void GetEntityOrigin( vec3_t vec ) = 0;
+				
+    //! Compute the rotated bounds of the BBox based on "angle" and "angles" keys
+    virtual void CalculateRotatedBounds( vec3_t mins, vec3_t maxs ) = 0;
+};
+
+

+

+

top

+ +

3. JavaDoc Style C++ Class Example

+ + The same class documented using JavaDoc Style comments +
+/// Virtual class to allow plugin operations on entity pairs
+/**
+  * @todo Write more complete documentation for this class so that it's use
+  * is clear
+  *	
+  * An interface to entity keys and key pairs that allows plugins to;
+  * read and write entity keys and key values, get a key value as a
+  * vec3_t
+  */
+class IEpair
+{
+  public:
+    /// Increment the number of references to this object
+    virtual void IncRef () = 0;
+				
+    /// Decrement the reference count
+    virtual void DecRef () = 0;
+				
+    /// Get a vector from a key
+    virtual void GetVectorForKey( char* key, vec3_t vec ) = 0;
+				
+    /// Get a float from a key
+    virtual float FloatForKey( char *key ) = 0;
+				
+    /// Get a string (char *) from a key
+    virtual char* ValueForKey( char *key ) = 0;
+				
+    /** Set a key value to char *value
+      * @param key The (char *) containing the keyname
+      * @param value The (char *) to set the key value to
+      */
+    virtual void SetKeyValue( char *key, char *value ) = 0;
+				
+    //! Get a vec3_t for the entities origin
+    virtual void GetEntityOrigin( vec3_t vec ) = 0;
+				
+    //! Compute the rotated bounds of the BBox based on "angle" and "angles" keys
+    virtual void CalculateRotatedBounds( vec3_t mins, vec3_t maxs ) = 0;
+};
+
+

+

top

+
+ + +

4. Special Tags

+

+ Special tags using the Qt style begin with a " \ ", or using JavaDoc style a " @ " (the two should not be mixed).
+
+ Common special tags
+

+ + + +
+ author + + The author or a list of comma separated authors/contributers +
+ see + + A reference to another class, class member, function, etc... +
+ param + + A description of a specific function argument or parameter +
+ return + + A description of the value returned from a function/method +
+ bug + + Starts a paragraph where one or more bugs may be listed. +
+ note + + Starts a paragraph where a note may be entered. +
+ todo + + Starts a paragraph where a TODO item is described.
+ Note: All TODO items are collated into a separate todo list, each linking to each other +
+ version + + Starts a paragraph where one or more version strings may be entered. +
+ warning + + Starts a paragraph where one or more warning messages may be entered. +
+ brief + + A single line comment in place of the //! or /// comment. +
+
+
+

top

+
+ +

5. Structural Tags

+

+These are used to document a named object, and are not required to be located near that +object definition or declaration. This allows the documentation for an object to be located +anywhere in the doxygen input files. The exception to this rule however, is that these +documentation blocks cannot be within the body of a function or within C style comment blocks. +All structural commands are preceded by either a " \ " or a " @ ", depending on the +documentation style, and require one or more parameters to specify the name of the object +the description is referring to.
+

+

+An example of the \file structural tag: +

+/*! \file iepairs.h
+    \brief One line documentation for this file
+    \author Author(s)
+    Long description of this file
+*/
+
+

+ +Common Structural Tags

+
+ + + +
+ class + + Documents a class
+ eg:
+ /*! \class IEpair
+ \brief Short description of the IEpair class
+
+ Detailed description of the IEpair class
+ */
+
+
+
+ def + + Describes a #define
+ eg:
+ /*! \def MAX_VALUE The name of the define
+ \brief Description of MAX_VALUE
+ */
+
+
+
+ file + + Describes a file
+ eg:
+ /*! \file iepairs.h The name of the file
+ \brief Description of the file iepairs.h
+
+ Details
+ */
+
+
+
+ struct + + Documents a struct
+ eg:
+ /*! \struct BTListList_t the name of the struct
+ \brief Description of BTListList_t
+
+ Details
+ */
+
+
+
+ var + + Documents a typedef, variable or enum value
+ eg:
+ /*! \var typedef unsigned int UINT32
+ \brief Short description
+ */
+
+
+
+ fn + + Documents a function + eg:
+ /*! \fn virtual void IEpair::DecRef() = 0;
+ \brief Short description of this function
+
+ Detailed description of this function
+ */
+
+ +
+
+ +
+

top

+
+
+
diff --git a/GPL b/GPL new file mode 100644 index 00000000..2128a66e --- /dev/null +++ b/GPL @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/GtkRadiant.prj b/GtkRadiant.prj new file mode 100644 index 00000000..c2af2961 --- /dev/null +++ b/GtkRadiant.prj @@ -0,0 +1,688 @@ +# Anjuta Version 1.1.97 +Compatibility Level: 1 + + +level editor for Id technology games + + + + + + + + + + + + + + + + + + +props.file.type=project + +anjuta.version=1.1.97 +anjuta.compatibility.level=1 + +project.name=GtkRadiant +project.type=GENERIC +project.target.type=EXECUTABLE +project.version=changesallthetime +project.author=qeradiant.com dev team +project.source.target=install/radiant.x86 +project.has.gettext=0 +project.gui.command= +project.programming.language=C_C++ +project.excluded.modules= intl + +project.config.extra.modules.before= +project.config.extra.modules.after= +project.config.blocked=1 +project.config.disable.overwriting=1 1 1 1 1 1 1 1 1 + +project.menu.entry=GtkRadiant Version changesallthetime +project.menu.group=Application +project.menu.comment=GtkRadiant Version changesallthetime +project.menu.icon= +project.menu.need.terminal=0 + +project.configure.options= +anjuta.program.arguments= +cons.linkeddir= + +preferences.build.option.jobs=0 +preferences.build.option.silent=0 +preferences.build.option.autosave=1 +preferences.make=scons +preferences.build.option.keep.going=1 +preferences.build.option.warn.undef=0 +preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss +preferences.autoformat.style=Style of Kangleipak +preferences.indent.opening=0 +preferences.autoformat.disable=0 +preferences.indent.automatic=1 +preferences.use.tabs=0 +preferences.indent.size=2 +preferences.tabsize=2 +preferences.indent.closing=0 + +module.include.name=. +module.include.type= +module.include.files=\ + Doxygen_files/doxy_mainpage.h\ + contrib/bobtoolz/CPortals.h\ + contrib/bobtoolz/DBobView.h\ + contrib/bobtoolz/DBrush.h\ + contrib/bobtoolz/DEPair.h\ + contrib/bobtoolz/DEntity.h\ + contrib/bobtoolz/DListener.h\ + contrib/bobtoolz/DMap.h\ + contrib/bobtoolz/DPatch.h\ + contrib/bobtoolz/DPlane.h\ + contrib/bobtoolz/DPoint.h\ + contrib/bobtoolz/DShape.h\ + contrib/bobtoolz/DVisDrawer.h\ + contrib/bobtoolz/DWinding.h\ + contrib/bobtoolz/StdAfx.h\ + contrib/bobtoolz/bobToolz.h\ + contrib/bobtoolz/bsploader.h\ + contrib/bobtoolz/ctfresource_gtk.h\ + contrib/bobtoolz/funchandlers.h\ + contrib/bobtoolz/lists.h\ + contrib/bobtoolz/misc.h\ + contrib/bobtoolz/resource-gtk.h\ + contrib/bobtoolz/resource.h\ + contrib/bobtoolz/shapes.h\ + contrib/bobtoolz/visfind.h\ + contrib/bobtoolz/dialogs/AboutDialog.h\ + contrib/bobtoolz/dialogs/AutoCaulkDialog.h\ + contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h\ + contrib/bobtoolz/dialogs/BrushCheckDialog.h\ + contrib/bobtoolz/dialogs/DoorDialog.h\ + contrib/bobtoolz/dialogs/IntersectDialog.h\ + contrib/bobtoolz/dialogs/IntersectInfoDialog.h\ + contrib/bobtoolz/dialogs/PolygonDialog.h\ + contrib/bobtoolz/dialogs/StairDialog.h\ + contrib/bobtoolz/dialogs/TextureResetDialog.h\ + contrib/bobtoolz/dialogs/dialogs-gtk.h\ + contrib/bobtoolz/dialogs/pathplotterdialog.h\ + contrib/gtkgensurf/gendlgs.h\ + contrib/gtkgensurf/gensurf.h\ + contrib/gtkgensurf/triangle.h\ + contrib/patches/Gtk/fileselect/linux/gtkfilesel-01222001.h\ + contrib/prtview/AboutDialog.h\ + contrib/prtview/ConfigDialog.h\ + contrib/prtview/LoadPortalFileDialog.h\ + contrib/prtview/gtkdlgs.h\ + contrib/prtview/portals.h\ + contrib/prtview/prtview.h\ + contrib/prtview/resource.h\ + contrib/prtview/stdafx.h\ + docs/developer/XMLPush/StdAfx.h\ + include/gtkr_list.h\ + include/gtkr_vector.h\ + include/ibrush.h\ + include/ibspfrontend.h\ + include/idata.h\ + include/idatastream.h\ + include/ientity.h\ + include/iepairs.h\ + include/ifilesystem.h\ + include/igl.h\ + include/iimage.h\ + include/imap.h\ + include/imodel.h\ + include/ipatch.h\ + include/ipluginentities.h\ + include/irefcount.h\ + include/iscriplib.h\ + include/iselectedface.h\ + include/ishaders.h\ + include/ishadersmanager.h\ + include/isurfaceplugin.h\ + include/iui.h\ + include/iui_gtk.h\ + include/qerplugin.h\ + include/qertypes.h\ + include/qsysprintf.h\ + include/stl_check.h\ + include/stream_version.h\ + libs/bytebool.h\ + libs/cmdlib.h\ + libs/jpeglib.h\ + libs/mathlib.h\ + libs/missing.h\ + libs/multimon.h\ + libs/pakstuff.h\ + libs/str.h\ + libs/synapse.h\ + libs/jpeg6/jchuff.h\ + libs/jpeg6/jconfig.h\ + libs/jpeg6/jdct.h\ + libs/jpeg6/jdhuff.h\ + libs/jpeg6/jerror.h\ + libs/jpeg6/jinclude.h\ + libs/jpeg6/jmemsys.h\ + libs/jpeg6/jmorecfg.h\ + libs/jpeg6/jpegint.h\ + libs/jpeg6/jversion.h\ + libs/l_net/l_net.h\ + libs/l_net/l_net_wins.h\ + libs/pak/unzip.h\ + plugins/image/bmp.h\ + plugins/image/image.h\ + plugins/image/lbmlib.h\ + plugins/mapq3/plugin.h\ + plugins/mapxml/plugin.h\ + plugins/md3model/entitymodel.h\ + plugins/md3model/md3.h\ + plugins/md3model/md3model.h\ + plugins/md3model/md3surface.h\ + plugins/md3model/plugin.h\ + plugins/md3model/surface.h\ + plugins/sample/stdafx.h\ + plugins/sample/str.h\ + plugins/shaders/plugin.h\ + plugins/shaders/shaders.h\ + plugins/surface/plugtexdef.h\ + plugins/surface/surfdlg.h\ + plugins/surface/surfplug.h\ + plugins/textool/2DView.h\ + plugins/textool/ControlPointsManager.h\ + plugins/textool/StdAfx.h\ + plugins/textool/resource.h\ + plugins/vfspak/vfs.h\ + plugins/vfspak/vfspak.h\ + plugins/vfspk3/unzip-vfspk3.h\ + plugins/vfspk3/vfs.h\ + plugins/vfspk3/vfspk3.h\ + radiant/brush.h\ + radiant/camera.h\ + radiant/camwindow.h\ + radiant/dialog.h\ + radiant/entity.h\ + radiant/epairswrapper.h\ + radiant/feedback.h\ + radiant/file.h\ + radiant/filters.h\ + radiant/findtexturedialog.h\ + radiant/glwidget.h\ + radiant/glwindow.h\ + radiant/groupdialog.h\ + radiant/gtkfilesel-darwin.h\ + radiant/gtkfilesel-linux.h\ + radiant/gtkfilesel.h\ + radiant/gtkmisc.h\ + radiant/mainframe.h\ + radiant/map.h\ + radiant/parse.h\ + radiant/patchdialog.h\ + radiant/plugin.h\ + radiant/pluginmanager.h\ + radiant/points.h\ + radiant/preferences.h\ + radiant/qe3.h\ + radiant/qedefs.h\ + radiant/qfiles.h\ + radiant/qgl.h\ + radiant/resource.h\ + radiant/select.h\ + radiant/stdafx.h\ + radiant/surfacedialog.h\ + radiant/texmanip.h\ + radiant/textures.h\ + radiant/texwindow.h\ + radiant/ui.h\ + radiant/undo.h\ + radiant/watchbsp.h\ + radiant/winding.h\ + radiant/xmlstuff.h\ + radiant/xywindow.h\ + radiant/z.h\ + radiant/zwindow.h\ + tools/quake3/common/aselib.h\ + tools/quake3/common/bspfile.h\ + tools/quake3/common/cmdlib.h\ + tools/quake3/common/imagelib.h\ + tools/quake3/common/inout.h\ + tools/quake3/common/l3dslib.h\ + tools/quake3/common/mutex.h\ + tools/quake3/common/polylib.h\ + tools/quake3/common/polyset.h\ + tools/quake3/common/qfiles.h\ + tools/quake3/common/qthreads.h\ + tools/quake3/common/scriplib.h\ + tools/quake3/common/surfaceflags.h\ + tools/quake3/common/trilib.h\ + tools/quake3/common/unzip.h\ + tools/quake3/common/vfs.h\ + tools/quake3/q3data/3dslib.h\ + tools/quake3/q3data/md3lib.h\ + tools/quake3/q3data/p3dlib.h\ + tools/quake3/q3data/q3data.h\ + tools/quake3/q3map/Heapagnt.h\ + tools/quake3/q3map/game_t.h\ + tools/quake3/q3map/light.h\ + tools/quake3/q3map/mesh.h\ + tools/quake3/q3map/qbsp.h\ + tools/quake3/q3map/shaders.h\ + tools/quake3/q3map/vis.h + +module.source.name=. +module.source.type= +module.source.files=\ + contrib/bobtoolz/DBobView.cpp\ + contrib/bobtoolz/DBrush.cpp\ + contrib/bobtoolz/DEPair.cpp\ + contrib/bobtoolz/DEntity.cpp\ + contrib/bobtoolz/DListener.cpp\ + contrib/bobtoolz/DMap.cpp\ + contrib/bobtoolz/DPatch.cpp\ + contrib/bobtoolz/DPlane.cpp\ + contrib/bobtoolz/DPoint.cpp\ + contrib/bobtoolz/DShape.cpp\ + contrib/bobtoolz/DVisDrawer.cpp\ + contrib/bobtoolz/DWinding.cpp\ + contrib/bobtoolz/StdAfx.cpp\ + contrib/bobtoolz/bobToolz-GTK.cpp\ + contrib/bobtoolz/bobToolz.cpp\ + contrib/bobtoolz/bsploader.cpp\ + contrib/bobtoolz/cportals.cpp\ + contrib/bobtoolz/ctfToolz-GTK.cpp\ + contrib/bobtoolz/funchandlers-GTK.cpp\ + contrib/bobtoolz/funchandlers-ctf-GTK.cpp\ + contrib/bobtoolz/funchandlers.cpp\ + contrib/bobtoolz/lists.cpp\ + contrib/bobtoolz/misc.cpp\ + contrib/bobtoolz/shapes.cpp\ + contrib/bobtoolz/visfind.cpp\ + contrib/bobtoolz/dialogs/AboutDialog.cpp\ + contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp\ + contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp\ + contrib/bobtoolz/dialogs/DoorDialog.cpp\ + contrib/bobtoolz/dialogs/IntersectDialog.cpp\ + contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp\ + contrib/bobtoolz/dialogs/PolygonDialog.cpp\ + contrib/bobtoolz/dialogs/StairDialog.cpp\ + contrib/bobtoolz/dialogs/TextureResetDialog.cpp\ + contrib/bobtoolz/dialogs/brushcheckdialog.cpp\ + contrib/bobtoolz/dialogs/dialogs-gtk.cpp\ + contrib/bobtoolz/dialogs/pathplotterdialog.cpp\ + contrib/gtkgensurf/bitmap.cpp\ + contrib/gtkgensurf/dec.cpp\ + contrib/gtkgensurf/face.cpp\ + contrib/gtkgensurf/font.cpp\ + contrib/gtkgensurf/gendlgs.cpp\ + contrib/gtkgensurf/genmap.cpp\ + contrib/gtkgensurf/gensurf.cpp\ + contrib/gtkgensurf/heretic.cpp\ + contrib/gtkgensurf/plugin.cpp\ + contrib/gtkgensurf/triangle.c\ + contrib/gtkgensurf/view.cpp\ + contrib/patches/Gtk/fileselect/linux/gtkfilesel-01222001.c\ + contrib/prtview/AboutDialog.cpp\ + contrib/prtview/ConfigDialog.cpp\ + contrib/prtview/LoadPortalFileDialog.cpp\ + contrib/prtview/gtkdlgs.cpp\ + contrib/prtview/portals.cpp\ + contrib/prtview/prtview.cpp\ + contrib/prtview/stdafx.cpp\ + docs/developer/XMLPush/StdAfx.cpp\ + docs/developer/XMLPush/XMLPush.cpp\ + docs/manual/quake3/Compile_Manual/cfgq3.c\ + libs/cmdlib/cmdlib.cpp\ + libs/jpeg6/jcomapi.cpp\ + libs/jpeg6/jdapimin.cpp\ + libs/jpeg6/jdapistd.cpp\ + libs/jpeg6/jdatasrc.cpp\ + libs/jpeg6/jdcoefct.cpp\ + libs/jpeg6/jdcolor.cpp\ + libs/jpeg6/jddctmgr.cpp\ + libs/jpeg6/jdhuff.cpp\ + libs/jpeg6/jdinput.cpp\ + libs/jpeg6/jdmainct.cpp\ + libs/jpeg6/jdmarker.cpp\ + libs/jpeg6/jdmaster.cpp\ + libs/jpeg6/jdpostct.cpp\ + libs/jpeg6/jdsample.cpp\ + libs/jpeg6/jdtrans.cpp\ + libs/jpeg6/jerror.cpp\ + libs/jpeg6/jfdctflt.cpp\ + libs/jpeg6/jidctflt.cpp\ + libs/jpeg6/jmemmgr.cpp\ + libs/jpeg6/jmemnobs.cpp\ + libs/jpeg6/jpgload.cpp\ + libs/jpeg6/jutils.cpp\ + libs/l_net/l_net.c\ + libs/l_net/l_net_berkley.c\ + libs/l_net/l_net_wins.c\ + libs/mathlib/bbox.c\ + libs/mathlib/linear.c\ + libs/mathlib/m4x4.c\ + libs/mathlib/mathlib.c\ + libs/mathlib/ray.c\ + libs/pak/pakstuff.cpp\ + libs/pak/unzip.cpp\ + libs/synapse/synapse.cpp\ + plugins/image/bmp.cpp\ + plugins/image/image.cpp\ + plugins/image/jpeg.cpp\ + plugins/image/lbmlib.cpp\ + plugins/mapq3/parse.cpp\ + plugins/mapq3/plugin.cpp\ + plugins/mapq3/write.cpp\ + plugins/mapxml/plugin.cpp\ + plugins/mapxml/xmlparse.cpp\ + plugins/mapxml/xmlwrite.cpp\ + plugins/md3model/eclassmodel.cpp\ + plugins/md3model/entitymodel.cpp\ + plugins/md3model/md3model.cpp\ + plugins/md3model/md3surface.cpp\ + plugins/md3model/miscmodel.cpp\ + plugins/md3model/plugin.cpp\ + plugins/sample/sample.cpp\ + plugins/sample/stdafx.cpp\ + plugins/shaders/plugin.cpp\ + plugins/shaders/shaders.cpp\ + plugins/surface/plugtexdef.cpp\ + plugins/surface/surfdlg.cpp\ + plugins/surface/surfplug.cpp\ + plugins/textool/2DView.cpp\ + plugins/textool/ControlPointsManager.cpp\ + plugins/textool/StdAfx.cpp\ + plugins/textool/TexTool.cpp\ + plugins/vfspak/vfs.cpp\ + plugins/vfspak/vfspak.cpp\ + plugins/vfspk3/unzip.cpp\ + plugins/vfspk3/vfs.cpp\ + plugins/vfspk3/vfspk3.cpp\ + radiant/bp_dlg.cpp\ + radiant/brush.cpp\ + radiant/brush_primit.cpp\ + radiant/brushscript.cpp\ + radiant/camwindow.cpp\ + radiant/csg.cpp\ + radiant/dialog.cpp\ + radiant/dialoginfo.cpp\ + radiant/drag.cpp\ + radiant/eclass.cpp\ + radiant/entity.cpp\ + radiant/feedback.cpp\ + radiant/file.cpp\ + radiant/filters.cpp\ + radiant/findtexturedialog.cpp\ + radiant/glinterface.cpp\ + radiant/glwidget.cpp\ + radiant/glwindow.cpp\ + radiant/groupdialog.cpp\ + radiant/gtkdlgs.cpp\ + radiant/gtkfilesel-darwin.c\ + radiant/gtkfilesel-linux.c\ + radiant/gtkfilesel.c\ + radiant/gtkmisc.cpp\ + radiant/iepairs.cpp\ + radiant/main.cpp\ + radiant/mainframe.cpp\ + radiant/map.cpp\ + radiant/missing.cpp\ + radiant/parse.cpp\ + radiant/patchdialog.cpp\ + radiant/plugin.cpp\ + radiant/pluginentities.cpp\ + radiant/pluginmanager.cpp\ + radiant/pmesh.cpp\ + radiant/points.cpp\ + radiant/preferences.cpp\ + radiant/profile.cpp\ + radiant/qe3.cpp\ + radiant/qgl-mac.c\ + radiant/qgl.c\ + radiant/queuedraw.cpp\ + radiant/select.cpp\ + radiant/selectedface.cpp\ + radiant/stdafx.cpp\ + radiant/surfacedialog.cpp\ + radiant/surfaceplugin.cpp\ + radiant/texmanip.cpp\ + radiant/texwindow.cpp\ + radiant/ui.cpp\ + radiant/undo.cpp\ + radiant/vertsel.cpp\ + radiant/watchbsp.cpp\ + radiant/winding.cpp\ + radiant/xywindow.cpp\ + radiant/z.cpp\ + radiant/zwindow.cpp\ + tools/quake3/common/aselib.c\ + tools/quake3/common/bspfile.c\ + tools/quake3/common/cmdlib.c\ + tools/quake3/common/imagelib.c\ + tools/quake3/common/inout.c\ + tools/quake3/common/l3dslib.c\ + tools/quake3/common/md4.c\ + tools/quake3/common/mutex.c\ + tools/quake3/common/polylib.c\ + tools/quake3/common/scriplib.c\ + tools/quake3/common/threads.c\ + tools/quake3/common/trilib.c\ + tools/quake3/common/unzip.c\ + tools/quake3/common/vfs.c\ + tools/quake3/q3data/3dslib.c\ + tools/quake3/q3data/compress.c\ + tools/quake3/q3data/images.c\ + tools/quake3/q3data/md3lib.c\ + tools/quake3/q3data/models.c\ + tools/quake3/q3data/oldstuff.c\ + tools/quake3/q3data/p3dlib.c\ + tools/quake3/q3data/polyset.c\ + tools/quake3/q3data/q3data.c\ + tools/quake3/q3data/stripper.c\ + tools/quake3/q3data/video.c\ + tools/quake3/q3map/NetConnect/main.c\ + tools/quake3/q3map/brush.c\ + tools/quake3/q3map/brush_primit.c\ + tools/quake3/q3map/bsp.c\ + tools/quake3/q3map/facebsp.c\ + tools/quake3/q3map/fog.c\ + tools/quake3/q3map/gldraw.c\ + tools/quake3/q3map/glfile.c\ + tools/quake3/q3map/leakfile.c\ + tools/quake3/q3map/light.c\ + tools/quake3/q3map/light_bounce.c\ + tools/quake3/q3map/light_trace.c\ + tools/quake3/q3map/lightmaps.c\ + tools/quake3/q3map/lightv.c\ + tools/quake3/q3map/map.c\ + tools/quake3/q3map/mesh.c\ + tools/quake3/q3map/misc_model.c\ + tools/quake3/q3map/nodraw.c\ + tools/quake3/q3map/patch.c\ + tools/quake3/q3map/path_init.c\ + tools/quake3/q3map/portals.c\ + tools/quake3/q3map/prtfile.c\ + tools/quake3/q3map/shaders.c\ + tools/quake3/q3map/surface.c\ + tools/quake3/q3map/terrain.c\ + tools/quake3/q3map/tjunction.c\ + tools/quake3/q3map/tree.c\ + tools/quake3/q3map/vis.c\ + tools/quake3/q3map/visflow.c\ + tools/quake3/q3map/writebsp.c\ + tools/quake3/q3map/NetTest/main.c + +module.pixmap.name=. +module.pixmap.type= +module.pixmap.files=\ + Doxygen_files/example/doxygen.gif\ + Doxygen_files/example/graph_legend.gif\ + Doxygen_files/images/body-left-tile.gif\ + Doxygen_files/images/body-lower-left.gif\ + Doxygen_files/images/body-lower-right.gif\ + Doxygen_files/images/body-lower-tile.gif\ + Doxygen_files/images/body-right-tile.gif\ + Doxygen_files/images/body-upper-left.gif\ + Doxygen_files/images/body-upper-right.gif\ + Doxygen_files/images/body-upper-tile.gif\ + Doxygen_files/images/gtkr_splash.jpg\ + Doxygen_files/images/gtkr_splash_sm.jpg\ + Doxygen_files/images/history_id_logo.gif\ + Doxygen_files/images/top-right.gif\ + Doxygen_files/images/top-tile.gif\ + Doxygen_files/images/top-title.gif\ + contrib/patches/Gtk/fileselect/back.xpm\ + contrib/patches/Gtk/fileselect/forward.xpm\ + contrib/patches/Gtk/fileselect/refresh.xpm\ + contrib/patches/Gtk/fileselect/up.xpm\ + docs/developer/Inspector/classdiagram1.gif\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image004.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image006.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image008.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image020.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image022.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image026.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image032.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image034.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image038.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image040.png\ + docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/STROGGS.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/THEFALLEN.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image3.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image4.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image5.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image6.gif\ + docs/manual/quake3/Terrain_Manual/pics/background.jpg\ + docs/manual/quake3/Terrain_Manual/pics/start.gif\ + docs/manual/quake3/Terrain_Manual/pics/terrain.jpg\ + plugins/textool/Doc/Image2.jpg\ + setup/linux/Help/DocsArt/toolback.jpg\ + setup/linux/radiant.xpm\ + setup/linux/setup.data/splash.xpm + +module.data.name=. +module.data.type= +module.data.files= + +module.help.name=. +module.help.type= +module.help.files= + +module.doc.name=. +module.doc.type= +module.doc.files=\ + INSTALL\ + README\ + Doxygen_files/example/annotated.html\ + Doxygen_files/example/classIEpair-members.html\ + Doxygen_files/example/classIEpair.html\ + Doxygen_files/example/classes.html\ + Doxygen_files/example/files.html\ + Doxygen_files/example/functions.html\ + Doxygen_files/example/graph_legend.html\ + Doxygen_files/example/index.html\ + Doxygen_files/example/pages.html\ + Doxygen_files/example/test_8c-source.html\ + Doxygen_files/example/test_8c.html\ + Doxygen_files/example/todo.html\ + Doxygen_files/doxygen_gtkradiant_foot.html\ + Doxygen_files/doxygen_gtkradiant_head.html\ + Doxygen_files/doxygen_index.html\ + Doxygen_files/doxygen_reference_foot.html\ + Doxygen_files/doxygen_reference_head.html\ + Doxygen_files/reference1.html\ + contrib/patches/Gtk/fileselect/README\ + docs/developer/TODO\ + docs/manual/quake3/Compile_Manual/index.html\ + docs/manual/quake3/Compile_Manual/q3map.html\ + docs/manual/quake3/New_Teams_For_Q3TA/index.html\ + docs/manual/quake3/Q3AShader_Manual/appendix/appA.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/start.html\ + docs/manual/quake3/Terrain_Manual/pages/adding_bots.html\ + docs/manual/quake3/Terrain_Manual/pages/adding_buildings_to_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/art_tools.html\ + docs/manual/quake3/Terrain_Manual/pages/blocking_vis.html\ + docs/manual/quake3/Terrain_Manual/pages/boxing_in_the_world.html\ + docs/manual/quake3/Terrain_Manual/pages/clipping_the_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/creating_the_alphamap.html\ + docs/manual/quake3/Terrain_Manual/pages/creating_the_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/entity_keys_and_values.html\ + docs/manual/quake3/Terrain_Manual/pages/glossary.html\ + docs/manual/quake3/Terrain_Manual/pages/height_map_into_terrain_mesh.html\ + docs/manual/quake3/Terrain_Manual/pages/height_maps.html\ + docs/manual/quake3/Terrain_Manual/pages/introduction.html\ + docs/manual/quake3/Terrain_Manual/pages/key_changes.html\ + docs/manual/quake3/Terrain_Manual/pages/lighting_the_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/manipulating_the_terrain_mesh.html\ + docs/manual/quake3/Terrain_Manual/pages/mapping_the_textures.html\ + docs/manual/quake3/Terrain_Manual/pages/new_or_revised_q3map_shader_comm.html\ + docs/manual/quake3/Terrain_Manual/pages/other_possible_height_map_tools.html\ + docs/manual/quake3/Terrain_Manual/pages/related_links.html\ + docs/manual/quake3/Terrain_Manual/pages/suggested_gensurf_settings.html\ + docs/manual/quake3/Terrain_Manual/pages/table_of_contents.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_entity.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_mesh_into_terrain_entity.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_related_worldspawn_features.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_texture.html\ + docs/manual/quake3/Terrain_Manual/pages/the_meta_shader.html\ + docs/manual/quake3/Terrain_Manual/start.html\ + plugins/textool/Doc/TexTool.html\ + setup/PluginSDK/README.html\ + setup/PluginSDK/TODO\ + setup/data/tools/credits.html\ + setup/linux/Help/Index.html\ + setup/win32/TODO\ + www/coding.html\ + www/files.html\ + www/gtkradiant.html\ + www/hosted.html\ + www/index.html\ + www/reviews.html + +module.po.files= + +compiler.options.supports= +compiler.options.include.paths=\ + .\ + .. +compiler.options.library.paths= +compiler.options.libraries= +compiler.options.libraries.selected= +compiler.options.defines=\ + HAVE_CONFIG_H +compiler.options.defines.selected= +compiler.options.warning.buttons=0 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0 +compiler.options.optimize.buttons=0 0 1 0 +compiler.options.other.buttons=1 0 +compiler.options.other.c.flags= +compiler.options.other.l.flags= +compiler.options.other.l.libs= + +project.src.paths= diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 00000000..022a6510 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,7 @@ +Compilation instructions +------------------------ + +See latest information for compiling and installation +on the developer pages: + +http://www.qeradiant.com/wikifaq/index.php?GtkRadiant%20Hacker diff --git a/LGPL b/LGPL new file mode 100644 index 00000000..f95d0f63 --- /dev/null +++ b/LGPL @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e8d70b6f --- /dev/null +++ b/LICENSE @@ -0,0 +1,36 @@ +LICENSE ( last update: Wed Feb 8 17:16:40 CST 2006 ) +----------------------------------------------------- + +There are 3 license types used throughout GtkRadiant source code. + +BSD - modified Berkeley Software Distribution license +( each BSD licensed source file starts with the appropriate header ) +LGPL - GNU Lesser General Public License v2.1 +( see LGPL at the root of the tree ) +GPL - GNU General Public License +( see GPL at the root of the tree ) + +How do I check which license applies to a given part of the source code? + +Each source file in the tree comes with a license header which explains what +license applies. To sum up shortly: + +GPL: ( except some files contributed by Loki Software under BSD license ) +GtkRadiant Core +GtkRadiant Modules +GtkRadiant Libraries +Quake III Tools +Quake II Tools +Background2D Plugin +HydraToolz Plugin + +BSD: +JPEG Library +MD5 Library +DDS Library +PicoModel Library +PrtView Plugin + +LGPL +BobToolz Plugin +GenSurf Plugin diff --git a/LICENSE_ID b/LICENSE_ID new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..c0370749 --- /dev/null +++ b/README @@ -0,0 +1,49 @@ +Terms and Conditions of Use + + +------- + +GTKRadiant contains software developed by Id Software, Loki Software and third +party contributors. + +All portions of GTKRadiant which are licensed by Id Software are subject to the +terms of its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included +with GTKRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE +AGREEMENT, please contact Id Software immediately at info@idsoftware.com. + +All portions of GTKRadiant which have been developed by Loki Software and/or +third party contributors are licensed under the terms set forth below. + +------- + +Copyright (c) 1999-2000, Loki Software, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki Software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. No license is hereby granted to any trademarks, tradenames +or logos. + +THIS SOFTWARE IS PROVIDED BY LOKI AND THE CONTRIBUTORS "AS IS." ANY AND ALL +WARRANTUES, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRENGEMENT ARE HEREBY DISCLAIMED. IN NO EVENT SHALL LOKI OR THE +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, WITHOUT LIMITATION, 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. + +------- diff --git a/README.doxygen b/README.doxygen new file mode 100644 index 00000000..effbf3f4 --- /dev/null +++ b/README.doxygen @@ -0,0 +1,51 @@ + Documentation for generating doxygen documentation +--------------------------------------------------------- + +1. Options for gendox +More up-to-date command line options are available via +the command ./gendox --help + +usage: "sh gendox [ ] [ -o ]" + or "./gendox [ ] [ -o ]" + + + The directory, or directories to generate the + documentation from. + +-o + Specifies the output directory which + should follow the -o switch + +-q --quiet + Stops the script from outputing status information, + other than errors. + +-k --kill + Kills other running doxygen pids. + +eg: ./gendox include/ -o ../Documentation + +* This will produce documentation for the include files, +and output to the directory specified one level above the +current directory. + +The target can be the current directory "./" in which case +doxygen will generate documentation for all subdirectories +of the current directory recursively. + +The default output directory is currently ... +> ../GtkRadiant-doxygen + +* If the script is called without any target directories +it will generate documentation for the core of radiant... +include/ libs/ radiant/ and plugins/ + +If there are specific options that you'd like to customise, +the DoxyConfig file is used to generate the file from which +doxygen gets its settings from. So any changes that need +to be made should be made to this file. + + +Gef :] +(gefdavis@dingoblue.net.au) +--------------------------------------------------------- diff --git a/SConscript b/SConscript new file mode 100644 index 00000000..aa055778 --- /dev/null +++ b/SConscript @@ -0,0 +1,839 @@ +import os, sys, commands, string +from makeversion import get_version +# OS Detection: +OS = commands.getoutput('uname') + +Import('GLOBALS') +Import(GLOBALS) + +# make scons link shared libs against static libs +g_env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + +# make gcc accept default parameters in function typedefs +g_env['CXXFLAGS'] += '-fpermissive ' + +g_env['CXXFLAGS'] += '-fPIC ' +g_env['CCFLAGS'] += '-fPIC ' + +def build_list(s_prefix, s_string): + s_list = Split(s_string) + for i in range(len(s_list)): + s_list[i] = s_prefix + '/' + s_list[i] + return s_list + +# common code ------------------------------------------------------ + +cmdlib_lib = g_env.StaticLibrary(target='libs/cmdlib', source='libs/cmdlib/cmdlib.cpp') + + +mathlib_src = 'mathlib.c bbox.c linear.c m4x4.c ray.c' +mathlib_lib = g_env.StaticLibrary(target='libs/mathlib', source=build_list('libs/mathlib', mathlib_src)) + + +md5lib_lib = g_env.StaticLibrary(target='libs/md5lib', source='libs/md5lib/md5lib.c') + + +ddslib_lib = g_env.StaticLibrary(target='libs/ddslib', source='libs/ddslib/ddslib.c') + + +jpeg_env = g_env.Copy() +jpeg_env.Prepend(CPPPATH = 'libs/jpeg6') +jpeg_src = 'jcomapi.cpp jdcoefct.cpp jdinput.cpp jdpostct.cpp jfdctflt.cpp jpgload.cpp jdapimin.cpp jdcolor.cpp jdmainct.cpp jdsample.cpp jidctflt.cpp jutils.cpp jdapistd.cpp jddctmgr.cpp jdmarker.cpp jdtrans.cpp jmemmgr.cpp jdatasrc.cpp jdhuff.cpp jdmaster.cpp jerror.cpp jmemnobs.cpp' +jpeg_lib = jpeg_env.StaticLibrary(target='libs/jpeg', source=build_list('libs/jpeg6', jpeg_src)) + + +net_lib = g_env.StaticLibrary(target='libs/l_net', source=['libs/l_net/l_net.c', 'libs/l_net/l_net_berkley.c']) + + +picomodel_src = 'picointernal.c picomodel.c picomodules.c pm_3ds.c pm_ase.c pm_md3.c pm_obj.c\ + pm_ms3d.c pm_mdc.c pm_fm.c pm_md2.c pm_lwo.c lwo/clip.c lwo/envelope.c lwo/list.c lwo/lwio.c\ + lwo/lwo2.c lwo/lwob.c lwo/pntspols.c lwo/surface.c lwo/vecmath.c lwo/vmap.c' +picomodel_lib = g_env.StaticLibrary(target='libs/picomodel', source=build_list('libs/picomodel', picomodel_src)) + + +synapse_env = g_env.Copy() +synapse_env.useGlib2() +synapse_env.useXML2() +synapse_env['CPPPATH'].append('include') +synapse_src = 'synapse.cpp' +synapse_lib = synapse_env.StaticLibrary(target='libs/synapse', source=build_list('libs/synapse', synapse_src)) +# scons 0.95. Doesn't recognize archive compatible for dynamic modules +# see thread: http://scons.tigris.org/servlets/BrowseList?listName=users&by=thread&from=168952&to=168952&first=1&count=2 + + +splines_env = g_env.Copy() +splines_src = build_list('libs/splines', +'math_angles.cpp math_matrix.cpp math_quaternion.cpp math_vector.cpp q_parse.cpp q_shared.cpp splines.cpp util_str.cpp') +splines_env['CPPPATH'].append('include') +splines_lib = splines_env.StaticLibrary(target='libs/splines', source=splines_src) + + +# end static / common libraries --------------------------------------------------- + +# q3map --------------------------------------------------------------------------- + +q3map_env = g_env.Copy() +q3map_env['CPPPATH'].append('include') +q3map_env.useXML2() +q3map_env.useGlib2() +q3map_env.usePNG() +q3map_env.usePThread() +q3map_env.Prepend(CPPPATH='tools/quake3/common') + +q3map_common_src = [ + 'common/cmdlib.c', + 'common/imagelib.c', + 'common/inout.c', + 'common/mutex.c', + 'common/polylib.c', + 'common/scriplib.c', + 'common/threads.c', + 'common/unzip.c', + 'common/vfs.c' ] + +q3map_src = [ + 'q3map2/brush.c', + 'q3map2/brush_primit.c', + 'q3map2/bsp.c', + 'q3map2/facebsp.c', + 'q3map2/fog.c', + 'q3map2/leakfile.c', + 'q3map2/map.c', + 'q3map2/model.c', + 'q3map2/patch.c', + 'q3map2/portals.c', + 'q3map2/prtfile.c', + 'q3map2/surface.c', + 'q3map2/surface_fur.c', + 'q3map2/surface_meta.c', + 'q3map2/tjunction.c', + 'q3map2/tree.c', + 'q3map2/writebsp.c', + 'q3map2/image.c', + 'q3map2/light.c', + 'q3map2/light_bounce.c', + 'q3map2/light_trace.c', + 'q3map2/light_ydnar.c', + 'q3map2/lightmaps_ydnar.c', + 'q3map2/vis.c', + 'q3map2/visflow.c', + 'q3map2/bspfile_abstract.c', + 'q3map2/bspfile_ibsp.c', + 'q3map2/bspfile_rbsp.c', + 'q3map2/decals.c', + 'q3map2/main.c', + 'q3map2/mesh.c', + 'q3map2/path_init.c', + 'q3map2/shaders.c', + 'q3map2/surface_extra.c', + 'q3map2/surface_foliage.c', + 'q3map2/convert_ase.c', + 'q3map2/convert_map.c' ] + +q3map_full_src = [ ] +for i in q3map_common_src + q3map_src: + q3map_full_src.append('tools/quake3/' + i) + +q3map_full_src.append('libs/libmathlib.a') +q3map_full_src.append('libs/libl_net.a') +q3map_full_src.append('libs/libjpeg.a') +q3map_full_src.append('libs/libpicomodel.a') +q3map_full_src.append('libs/libmd5lib.a') +q3map_full_src.append('libs/libddslib.a') + +q3map_env.Program(target='q3map2.' + g_cpu, source=q3map_full_src ) +q3map_env.Install(INSTALL, 'q3map2.' + g_cpu) + +# end q3map2 ---------------------------------------------------------------------- + +# q3data --------------------------------------------------------------------------- + +q3data_env = q3map_env.Copy() + +q3data_common_src = [ + 'common/aselib.c', + 'common/bspfile.c', + 'common/cmdlib.c', + 'common/imagelib.c', + 'common/inout.c', + 'common/scriplib.c', + 'common/trilib.c', + 'common/unzip.c', + 'common/vfs.c' + ] + +q3data_src = [ + 'q3data/3dslib.c', + 'q3data/compress.c', + 'q3data/images.c', + 'q3data/md3lib.c', + 'q3data/models.c', + 'q3data/p3dlib.c', + 'q3data/polyset.c', + 'q3data/q3data.c', + 'q3data/stripper.c', + 'q3data/video.c' ] + +q3data_full_src = [ ] +for i in q3data_common_src + q3data_src: + q3data_full_src.append('tools/quake3/' + i) + +q3data_full_src.append('libs/libmathlib.a') +q3data_full_src.append('libs/libl_net.a') + +q3data_env.Program( target = 'q3data.' + g_cpu, source = q3data_full_src ) +q3data_env.Install( INSTALL, 'q3data.' + g_cpu ) + +# end q3data ---------------------------------------------------------------------- + +# q2_tools --------------------------------------------------------------------------- + +q2_tools_env = g_env.Copy() +q2_tools_env['CPPPATH'].append('include') +q2_tools_env.useXML2() +q2_tools_env.usePThread() +q2_tools_env.Prepend(CPPPATH='tools/quake2/common') + +q2_tools_common_src = [ + 'common/bspfile.c', + 'common/cmdlib.c', + 'common/inout.c', + 'common/l3dslib.c', + 'common/lbmlib.c', + 'common/mathlib.c', + 'common/path_init.c', + 'common/polylib.c', + 'common/scriplib.c', + 'common/threads.c', + 'common/trilib.c' +] + + +q2_tools_q2map_src = [ + 'q2map/brushbsp.c', + 'q2map/csg.c', + 'q2map/faces.c', + 'q2map/flow.c', + 'q2map/glfile.c', + 'q2map/leakfile.c', + 'q2map/lightmap.c', + 'q2map/main.c', + 'q2map/map.c', + 'q2map/nodraw.c', + 'q2map/patches.c', + 'q2map/portals.c', + 'q2map/prtfile.c', + 'q2map/qbsp.c', + 'q2map/qrad.c', + 'q2map/qvis.c', + 'q2map/textures.c', + 'q2map/trace.c', + 'q2map/tree.c', + 'q2map/writebsp.c' +] + +q2_tools_qdata3_common_src = [ + 'common/bspfile.c', + 'common/cmdlib.c', + 'common/inout.c', + 'common/l3dslib.c', + 'common/lbmlib.c', + 'common/mathlib.c', + 'common/path_init.c', + 'common/scriplib.c', + 'common/threads.c', + 'common/trilib.c' +] + +q2_tools_qdata3_src = [ + 'qdata/images.c', + 'qdata/models.c', + 'qdata/qdata.c', + 'qdata/sprites.c', + 'qdata/tables.c', + 'qdata/video.c' +] + +q2_tools_q2map_full_src = [ ] +for i in q2_tools_common_src + q2_tools_q2map_src: + q2_tools_q2map_full_src.append('tools/quake2/' + i) + +q2_tools_q2map_full_src.append('libs/libl_net.a') + +q2_tools_qdata3_full_src = [ ] +for i in q2_tools_common_src + q2_tools_qdata3_src: + q2_tools_qdata3_full_src.append('tools/quake2/' + i) + +q2_tools_qdata3_full_src.append('libs/libl_net.a') + +if ( OS != 'Darwin' ): + q2_tools_env.Program(target='quake2_tools/q2map', source=q2_tools_q2map_full_src ) + q2_tools_env.Install(INSTALL + '/q2', 'quake2_tools/q2map' ) + + q2_tools_env.Program(target='quake2_tools/qdata3', source=q2_tools_qdata3_full_src ) + q2_tools_env.Install(INSTALL + '/q2', 'quake2_tools/qdata3' ) + + +# end q2_tools ---------------------------------------------------------------------- + +# qdata3_heretic2 --------------------------------------------------------------------------- + +heretic2_tools_env = g_env.Copy() +heretic2_tools_env['CPPPATH'].append('include') +heretic2_tools_env.useXML2() +heretic2_tools_env.usePThread() +heretic2_tools_env.Prepend(CPPPATH='tools/quake2/qdata_heretic2') +heretic2_tools_env.Prepend(CPPPATH='tools/quake2/qdata_heretic2/qcommon') +heretic2_tools_env.Prepend(CPPPATH='tools/quake2/qdata_heretic2/common') + +heretic2_tools_qdata3_common_src = [ + 'qdata_heretic2/common/bspfile.c', + 'qdata_heretic2/common/cmdlib.c', + 'qdata_heretic2/common/inout.c', + 'qdata_heretic2/common/l3dslib.c', + 'qdata_heretic2/common/lbmlib.c', + 'qdata_heretic2/common/mathlib.c', + 'qdata_heretic2/common/path_init.c', + 'qdata_heretic2/common/qfiles.c', + 'qdata_heretic2/common/scriplib.c', + 'qdata_heretic2/common/threads.c', + 'qdata_heretic2/common/token.c', + 'qdata_heretic2/common/trilib.c' +] + +heretic2_tools_qdata3_qcommon_src = [ + 'qdata_heretic2/qcommon/reference.c', + 'qdata_heretic2/qcommon/resourcemanager.c', + 'qdata_heretic2/qcommon/skeletons.c' +] + +heretic2_tools_qdata3_src = [ + 'qdata_heretic2/animcomp.c', + 'qdata_heretic2/book.c', + 'qdata_heretic2/fmodels.c', + 'qdata_heretic2/images.c', + 'qdata_heretic2/jointed.c', + 'qdata_heretic2/models.c', + 'qdata_heretic2/pics.c', + 'qdata_heretic2/qdata.c', + 'qdata_heretic2/qd_skeletons.c', + 'qdata_heretic2/sprites.c', + 'qdata_heretic2/svdcmp.c', + 'qdata_heretic2/tables.c', + 'qdata_heretic2/tmix.c', + 'qdata_heretic2/video.c' +] + +heretic2_tools_qdata3_full_src = [ ] +for i in heretic2_tools_qdata3_common_src + heretic2_tools_qdata3_qcommon_src + heretic2_tools_qdata3_src: + heretic2_tools_qdata3_full_src.append('tools/quake2/' + i) + +heretic2_tools_qdata3_full_src.append('libs/libl_net.a') + +heretic2_tools_env['CCFLAGS'] += '-D_LINUX ' + +if ( OS != 'Darwin' ): + heretic2_tools_env.Program(target='heretic2_tools/qdata3', source=heretic2_tools_qdata3_full_src ) + heretic2_tools_env.Install(INSTALL + '/heretic2', 'heretic2_tools/qdata3' ) + + heretic2_q2map_env = q2_tools_env + heretic2_q2map_env.Install(INSTALL + '/heretic2', 'quake2_tools/q2map' ) + +# end heretic2_tools ---------------------------------------------------------------------- + + + +# radiant, modules and plugins ---------------------------------------------------- + +module_env = g_env.Copy() +module_env['CPPPATH'].append('include') +if ( OS == 'Darwin' ): + module_env['LINKFLAGS'] += '-dynamiclib -ldl ' +else: + module_env['LINKFLAGS'] += '-ldl ' +module_env['LIBPREFIX'] = '' +module_env.useGlib2() +module_env.useXML2() + +module_env.SharedLibrarySafe(target='fgd', source=['plugins/eclassfgd/plugin.cpp', 'libs/libsynapse.a']) +module_env.Install(INSTALL + '/modules', 'fgd.so') + +vfspk3_lst=build_list('plugins/vfspk3', 'vfspk3.cpp vfs.cpp unzip.cpp') +vfspk3_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='vfspk3', source=vfspk3_lst) +module_env.Install(INSTALL + '/modules', 'vfspk3.so') + +vfswad_lst=build_list('plugins/vfswad', 'unwad.cpp vfs.cpp vfswad.cpp') +vfswad_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='vfswad', source=vfswad_lst) +module_env.Install(INSTALL + '/modules', 'vfswad.so') + +vfspak_lst=build_list('plugins/vfspak', 'vfspak.cpp vfs.cpp') +vfspak_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='vfspak', source=vfspak_lst) +module_env.Install(INSTALL + '/q2/modules', 'vfspak.so') +module_env.Install(INSTALL + '/heretic2/modules', 'vfspak.so') + +shaders_lst=build_list('plugins/shaders', 'shaders.cpp plugin.cpp') +shaders_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='shaders', source=shaders_lst) +module_env.Install(INSTALL + '/modules', 'shaders.so') + +image_lst=build_list('plugins/image', 'jpeg.cpp image.cpp lbmlib.cpp') +image_lst.append('libs/libsynapse.a') +image_lst.append('libs/libjpeg.a') +module_env.SharedLibrarySafe(target='image', source=image_lst) +module_env.Install(INSTALL + '/modules', 'image.so') + +imagewal_lst=build_list('plugins/imagewal', 'wal.cpp imagewal.cpp') +imagewal_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='imagewal', source=imagewal_lst) +module_env.Install(INSTALL + '/q2/modules', 'imagewal.so') + +imagem8_lst=build_list('plugins/imagem8', 'm8.cpp m32.cpp imagem8.cpp') +imagem8_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='imagem8', source=imagem8_lst) +module_env.Install(INSTALL + '/heretic2/modules', 'imagem8.so') + +imagehl_lst=build_list('plugins/imagehl', 'imagehl.cpp lbmlib.cpp') +imagehl_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='imagehl', source=imagehl_lst) +module_env.Install(INSTALL + '/modules', 'imagehl.so') + +imagepng_lst=build_list('plugins/imagepng', 'plugin.cpp') +imagepng_lst.append('libs/libsynapse.a') +module_env.usePNG() +module_env.SharedLibrarySafe(target='imagepng', source=imagepng_lst) +module_env.Install(INSTALL + '/modules', 'imagepng.so') + +map_lst=build_list('plugins/map', 'plugin.cpp parse.cpp write.cpp') +map_lst.append('libs/libsynapse.a') +map_lst.append('libs/libcmdlib.a') +module_env.SharedLibrarySafe(target='map', source=map_lst) +module_env.Install(INSTALL + '/modules', 'map.so') + +mapxml_lst=build_list('plugins/mapxml', 'plugin.cpp xmlparse.cpp xmlwrite.cpp') +mapxml_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='mapxml', source=mapxml_lst) +module_env.Install(INSTALL + '/modules', 'mapxml.so') + +model_lst=build_list('plugins/model', 'plugin.cpp model.cpp cpicomodel.cpp cpicosurface.cpp remap.cpp') +model_lst.append('libs/libsynapse.a') +model_lst.append('libs/libpicomodel.a') +model_lst.append('libs/libmathlib.a') +module_env.SharedLibrarySafe(target='model', source=model_lst) +module_env.Install(INSTALL + '/modules', 'model.so') + +entity_lst = build_list('plugins/entity', 'plugin.cpp entity_entitymodel.cpp miscmodel.cpp eclassmodel.cpp entity.cpp light.cpp') +entity_lst.append('libs/libsynapse.a') +entity_lst.append('libs/libmathlib.a') +module_env.SharedLibrarySafe(target='entity', source=entity_lst) +module_env.Install(INSTALL + '/modules', 'entity.so') + +bob_env = module_env.Copy() +bob_env.useGtk2() +bob_lst = build_list('contrib/bobtoolz/', +'dialogs/dialogs-gtk.cpp bobToolz-GTK.cpp bsploader.cpp cportals.cpp DBobView.cpp \ +DBrush.cpp DEntity.cpp DEPair.cpp DListener.cpp DMap.cpp DPatch.cpp DPlane.cpp DPoint.cpp \ +DShape.cpp DTrainDrawer.cpp DTreePlanter.cpp DVisDrawer.cpp DWinding.cpp funchandlers-GTK.cpp \ +lists.cpp misc.cpp ScriptParser.cpp shapes.cpp visfind.cpp') +bob_lst.append('libs/libsynapse.a') +bob_lst.append('libs/libmathlib.a') +bob_lst.append('libs/libcmdlib.a') +bob_env['CPPPATH'].append('contrib/bobtoolz/dialogs') +bob_env.SharedLibrarySafe(target='bobtoolz', source=bob_lst) +bob_env.Install(INSTALL + '/plugins', 'bobtoolz.so') + +camera_lst = build_list('contrib/camera', +'camera.cpp dialogs.cpp dialogs_common.cpp funchandlers.cpp listener.cpp misc.cpp renderer.cpp') +camera_lst.append('libs/libsynapse.a') +camera_lst.append('libs/libsplines.a') +bob_env.SharedLibrarySafe(target='camera', source=camera_lst) +bob_env.Install(INSTALL + '/plugins', 'camera.so') + +prtview_lst = build_list('contrib/prtview', +'AboutDialog.cpp ConfigDialog.cpp LoadPortalFileDialog.cpp portals.cpp prtview.cpp') +prtview_lst.append('libs/libsynapse.a') +prtview_env = bob_env.Copy() +prtview_env['CXXFLAGS'] += '-DGTK_PLUGIN ' +prtview_env.SharedLibrarySafe(target='prtview', source=prtview_lst) +prtview_env.Install(INSTALL + '/plugins', 'prtview.so') + +gensurf_lst = build_list('contrib/gtkgensurf', +'bitmap.cpp dec.cpp face.cpp font.cpp gendlgs.cpp genmap.cpp gensurf.cpp heretic.cpp plugin.cpp view.cpp triangle.c') +gensurf_lst.append('libs/libsynapse.a') +bob_env.SharedLibrarySafe(target='gensurf', source=gensurf_lst) +bob_env.Install(INSTALL + '/plugins', 'gensurf.so') + +surface_lst = build_list('plugins/surface', 'surfdlg_plugin.cpp surfacedialog.cpp') +surface_lst.append('libs/libsynapse.a') +surface_lst.append('libs/libmathlib.a') +surface_env = module_env.Copy() +surface_env.useGtk2() +surface_env.SharedLibrarySafe(target='surface', source=surface_lst) +surface_env.Install(INSTALL + '/modules', 'surface.so') + +surface_quake2_lst = build_list('plugins/surface_quake2', 'surfdlg_plugin.cpp surfacedialog.cpp surfaceflagsdialog_quake2.cpp') +surface_quake2_lst.append('libs/libsynapse.a') +surface_quake2_lst.append('libs/libmathlib.a') +surface_quake2_env = module_env.Copy() +surface_quake2_env.useGtk2() +surface_quake2_env.SharedLibrarySafe(target='surface_quake2', source=surface_quake2_lst) +surface_quake2_env.Install(INSTALL + '/q2/modules', 'surface_quake2.so') + +surface_heretic2_lst = build_list('plugins/surface_heretic2', 'surfdlg_plugin.cpp surfacedialog.cpp surfaceflagsdialog_heretic2.cpp') +surface_heretic2_lst.append('libs/libsynapse.a') +surface_heretic2_lst.append('libs/libmathlib.a') +surface_heretic2_env = module_env.Copy() +surface_heretic2_env.useGtk2() +surface_heretic2_env.SharedLibrarySafe(target='surface_heretic2', source=surface_heretic2_lst) +surface_heretic2_env.Install(INSTALL + '/heretic2/modules', 'surface_heretic2.so') + +bkgrnd2d_list = build_list( 'contrib/bkgrnd2d', 'bkgrnd2d.cpp plugin.cpp dialog.cpp' ) +bkgrnd2d_list.append( 'libs/libsynapse.a' ) +bkgrnd2d_env = module_env.Copy() +bkgrnd2d_env.useGtk2() +bkgrnd2d_env.SharedLibrarySafe( target='bkgrnd2d', source=bkgrnd2d_list ) +bkgrnd2d_env.Install( INSTALL + '/plugins', 'bkgrnd2d.so' ) + +radiant_env = g_env.Copy() +radiant_env['CPPPATH'].append('include') +radiant_env['LINKFLAGS'] += '-ldl ' +if ( OS == 'Darwin' ): + radiant_env['CXXFLAGS'] += '-fno-common ' + radiant_env['CCFLAGS'] += '-fno-common ' + radiant_env['LINKFLAGS'] += '-lX11 -lGL -lGLU ' +radiant_env['LIBPREFIX'] = '' +radiant_env.useGlib2() +radiant_env.useXML2() +radiant_env.useGtk2() +radiant_env.useGtkGLExt() + +radiant_src=[ 'qgl.c', 'brush.cpp', 'brush_primit.cpp', 'brushscript.cpp', 'camwindow.cpp', 'csg.cpp', + 'dialog.cpp', 'dialoginfo.cpp', 'drag.cpp', 'eclass.cpp', 'eclass_def.cpp', 'error.cpp', 'feedback.cpp', + 'file.cpp', 'findtexturedialog.cpp', 'glinterface.cpp', 'glwidget.cpp', 'glwindow.cpp', 'groupdialog.cpp', + 'gtkdlgs.cpp', 'gtkmisc.cpp', 'main.cpp', 'mainframe.cpp', 'map.cpp', 'missing.cpp', 'parse.cpp', + 'patchdialog.cpp', 'pluginentities.cpp', 'pluginmanager.cpp', 'pmesh.cpp', 'points.cpp', 'preferences.cpp', + 'profile.cpp', 'qe3.cpp', 'qgl_ext.cpp', 'select.cpp', 'selectedface.cpp', 'surfacedialog.cpp', + 'surfaceplugin.cpp', 'targetname.cpp', 'texmanip.cpp', 'texwindow.cpp', 'undo.cpp', 'vertsel.cpp', + 'watchbsp.cpp', 'winding.cpp', 'xywindow.cpp', 'z.cpp', 'zwindow.cpp', 'filters.cpp', 'bp_dlg.cpp', 'ui.cpp' ] + +for i in range(len(radiant_src)): + radiant_src[i] = 'radiant/' + radiant_src[i] + +radiant_src.append('libs/libmathlib.a') +radiant_src.append('libs/libcmdlib.a') +radiant_src.append('libs/libl_net.a') +radiant_src.append('libs/libsynapse.a') + +radiant_env.Program(target='radiant.' + g_cpu, source=radiant_src) +radiant_env.Install(INSTALL, 'radiant.' + g_cpu) + +# setup ------------------------------------------------------------------------------------------- + +class setup_builder: + + g_dryrun = 0 + + def system(self, cmd): + if (self.g_dryrun): + print cmd + else: + sys.stdout.write(cmd) + ret = commands.getstatusoutput(cmd) + print ret[1] + if (ret[0] != 0): + raise 'command failed' + + def copy_core(self): + # binaries and misc + self.system('mkdir -p %s/modules' % self.SETUP_BIN_DIR) + self.system('mkdir -p %s/plugins' % self.SETUP_BIN_DIR) + self.system('cp install/%s %s' % (self.EDITOR_BIN, self.SETUP_BIN_DIR)) + self.system('cp install/modules/*.so %s/modules' % self.SETUP_BIN_DIR ) + self.system('cp install/plugins/*.so %s/plugins' % self.SETUP_BIN_DIR ) + self.system('cp install/q3map2.%s %s' % ( g_cpu, self.SETUP_BIN_DIR ) ) + self.M4_STDC = '' + if (not self.g_darwin): + # fugly + # copy libgcc_s and stdc++ over to distribute it and reduce potential ABI fuckups + ret = commands.getstatusoutput('ldd -r install/' + self.EDITOR_BIN + ' 2>/dev/null | grep libgcc_s | sed -e \'s/.* => \\([^ ]*\\) .*/\\1/\'') + if (ret[0] != 0): + raise 'ldd command failed' + self.system('cp ' + ret[1] + ' ' + self.SETUP_BIN_DIR) + ret = commands.getstatusoutput('ldd -r install/' + self.EDITOR_BIN + ' 2>/dev/null | grep libstdc++ | sed -e \'s/.* => \\([^ ]*\\) .*/\\1/\'') + if (ret[0] != 0): + raise 'ldd command failed' + lines = string.split(ret[1], '\n') + self.M4_STDC = '"' + for i in lines: + self.system('cp ' + i + ' ' + self.SETUP_BIN_DIR) + self.M4_STDC += os.path.basename(i) + ' \n' + self.M4_STDC += '"' + # hack for symlink + # setup process generates the wrapper at install time + # but we need a dummy executable for symlink in loki_setup + self.system('echo -n "#!/bin/sh\necho If you read this then there was a bug during setup. Report the bug and try running %s directly from it\'s installation directory.\n" > %s/radiant' % (self.EDITOR_BIN, self.SETUP_BIN_DIR)); + self.system('echo -n "#!/bin/sh\necho If you read this then there was a bug during setup. Report the bug and try running %s directly from it\'s installation directory.\n" > %s/q3map2' % (self.EDITOR_BIN, self.SETUP_BIN_DIR)); + ## this goes to the core install directory + DEST = self.SETUP_DIR + '/core' + self.system('mkdir -p ' + DEST + '/modules/bitmaps') + # general content stuff + self.system('cp -R plugins/model/bitmaps/* ' + DEST + '/modules/bitmaps') + self.system('cp -R setup/data/tools/* ' + DEST) + self.system('cp -R radiant/bitmaps ' + DEST) + self.system('cp setup/changelog.txt ' + DEST) + self.system('cp setup/openurl.sh ' + DEST) + self.system('cp tools/quake3/q3map2/changelog.q3map2.txt ' + DEST) + # documentation + self.system('cp -R docs/manual/Q3Rad_Manual ' + DEST) + self.system('cp -R docs/manual/quake3/Compile_Manual ' + DEST) + self.system('cp -R docs/manual/quake3/Model_Manual ' + DEST) + self.system('cp -R docs/manual/quake3/Terrain_Manual ' + DEST) + # copy plugins media + self.system('mkdir -p ' + DEST + '/plugins/bitmaps') + self.system('cp -R contrib/bobtoolz/bitmaps/* ' + DEST + '/plugins/bitmaps') + self.system('cp -R contrib/bobtoolz/bt ' + DEST + '/plugins') + self.system('cp -R contrib/camera/bitmaps/* ' + DEST + '/plugins/bitmaps' ) + self.system('cp -R contrib/bkgrnd2d/bitmaps/* ' + DEST + '/plugins/bitmaps' ) + + def copy_q3(self): + # binaries + self.system('mkdir -p ' + self.SETUP_BIN_DIR + '/q3') + if ( self.g_darwin == 0 ): + self.system('cp setup/linux/bspc ' + self.SETUP_BIN_DIR + '/q3') + + # goes in core + DEST = self.SETUP_DIR + '/core/q3' + self.system('mkdir -p ' + DEST) + self.system('cp setup/data/tools/synapse.config ' + DEST) + self.system('cp setup/data/tools/game.xlink ' + DEST) + self.system('cp -R docs/manual/quake3/Team_Arena_Mapping_Help ' + DEST) + self.system('cp -R docs/manual/quake3/New_Teams_For_Q3TA ' + DEST) + self.system('cp -R docs/manual/quake3/Q3AShader_Manual ' + DEST) + + # goes in the game install path + DEST = self.SETUP_DIR + '/q3' + self.system('mkdir -p ' + DEST) + self.system('cp -R setup/data/baseq3 ' + DEST) + self.system('cp -R setup/data/missionpack ' + DEST) + + def copy_wolf(self): + # binaries + self.system('mkdir -p ' + self.SETUP_BIN_DIR + '/wolf') + if ( self.g_darwin == 0 ): + self.system('cp ../WolfPack/bin/Linux/bspc ' + self.SETUP_BIN_DIR + '/wolf') + + # goes in core + DEST = self.SETUP_DIR + '/core/wolf' + self.system('mkdir -p ' + DEST) + self.system('cp ../WolfPack/synapse.config ' + DEST) + self.system('cp -R ../WolfPack/docs ' + DEST) + self.system('cp ../WolfPack/game.xlink ' + DEST) + self.system('cp ../WolfPack/bin/aascfg_lg.c ' + DEST) + self.system('cp ../WolfPack/bin/aascfg_sm.c ' + DEST) + self.system('cp ../WolfPack/bin/bspc.ai ' + DEST) + + # goes in the game install path + DEST = self.SETUP_DIR + '/wolf/main' + self.system('mkdir -p ' + DEST) + self.system('cp ../WolfPack/astro-skies.pk3 ' + DEST) + self.system('cp ../WolfPack/common-astro-spog.pk3 ' + DEST) + self.system('cp ../WolfPack/lights.pk3 ' + DEST) + self.system('cp -R ../WolfPack/scripts ' + DEST) + self.system('cp -R ../WolfPack/maps ' + DEST) + self.system('cp -R ../WolfPack/models ' + DEST) + + def copy_et(self): + # goes in core + DEST = self.SETUP_DIR + '/core/et' + self.system('mkdir -p ' + DEST) + self.system('cp -R ../ETPack/bitmaps ' + DEST) + self.system('cp -R ../ETPack/docs ' + DEST) + self.system('cp ../ETPack/game.xlink ' + DEST) + self.system('cp ../ETPack/synapse.config ' + DEST) + + # goes in game install path + DEST = self.SETUP_DIR + '/et/etmain' + self.system('mkdir -p ' + DEST) + self.system('cp ../ETPack/astro-skies.pk3 ' + DEST) + self.system('cp ../ETPack/common.pk3 ' + DEST) + self.system('cp ../ETPack/goldrush.pcx ' + DEST) + self.system('cp ../ETPack/lights.pk3 ' + DEST) + self.system('cp ../ETPack/mapmedia.pk3 ' + DEST) + self.system('cp -R ../ETPack/scripts ' + DEST) + self.system('cp -R ../ETPack/maps ' + DEST) + self.system('cp -R ../ETPack/models ' + DEST) + + def copy_q2(self): + # binaries + self.system('cp -R install/q2 %s' % (self.SETUP_BIN_DIR)) + + # goes in core + DEST = self.SETUP_DIR + '/core/q2' + self.system('mkdir -p ' + DEST + '/modules') + self.system('cp ../Q2Pack/game.xlink ' + DEST) + self.system('cp ../Q2Pack/synapse.config ' + DEST) + self.system('cp install/q2/q2map install/q2/qdata3 ' + DEST) + self.system('cp -R install/q2/modules ' + DEST ) + + # goes in game install path + DEST = self.SETUP_DIR + '/q2' + self.system('mkdir -p ' + DEST + '/baseq2') + self.system('cp -R ../Q2Pack/baseq2/* ' + DEST + '/baseq2') + + def copy_her2(self): + # binaries + self.system('cp -R install/heretic2 %s' % (self.SETUP_BIN_DIR)) + + # goes in core + DEST = self.SETUP_DIR + '/core/heretic2' + self.system('mkdir -p ' + DEST + '/modules') + self.system('cp ../Her2Pack/game.xlink ' + DEST) + self.system('cp ../Her2Pack/synapse.config ' + DEST) + self.system('cp install/q2/q2map install/heretic2/qdata3 ' + DEST) + self.system('cp -R install/heretic2/modules ' + DEST ) + + # goes in game install path + DEST = self.SETUP_DIR + '/heretic2' + self.system('mkdir -p ' + DEST + '/base') + self.system('cp -R ../Her2Pack/base/* ' + DEST + '/base') + + def build_setup(self): + self.system( 'cp -R ' + self.SETUP_IMAGE_OS + '/* ' + self.SETUP_DIR ) + self.system( 'cp -fR ' + self.SETUP_IMAGE + '/* ' + self.SETUP_DIR ) + self.system('cp setup/license.txt ' + self.SETUP_DIR) + self.system('cp setup/linux/README ' + self.SETUP_DIR) + OS_DEFS='' + if (self.g_darwin): + OS_DEFS='--define=M4_OSX' + M4_LINE = OS_DEFS + ' --define=M4_VER_MAJOR=' + self.major + ' --define=M4_VER_MINOR=' + self.minor + ' --define=M4_VER=' + self.line + M4_LINE += ' --define=M4_GAME_ET=%d' % self.DO_GAME_ET + M4_LINE += ' --define=M4_GAME_Q2=%d' % self.DO_GAME_Q2 + if ( self.M4_STDC != '' ): + M4_LINE += ' --define=M4_STDC=' + self.M4_STDC + # setup.xml + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.data/setup.xml.in > ' + self.SETUP_DIR + '/setup.data/setup.xml') + # postinstall.sh + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.data/postinstall.sh.in > ' + self.SETUP_DIR + '/setup.data/postinstall.sh') + # config.sh + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.data/config.sh.in > ' + self.SETUP_DIR + '/setup.data/config.sh') + # setup.sh + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.sh.in > ' + self.SETUP_DIR + '/setup.sh') + self.system('chmod +x ' +self.SETUP_DIR + '/setup.sh') + self.system('find ' + self.SETUP_DIR + ' -name .svn | while read i ; do rm -r "$i" ; done') + # pack it up + self.system('setup/linux/makeself/makeself.sh ' + self.SETUP_DIR + ' ' + self.SETUP_TARGET + ' "GtkRadiant ' + self.line + ' setup" ./setup.sh') + if (self.g_darwin): + def build_fink_deb(self): + print "Building installer .deb\n" + self.F_REV = '1' + self.FINKINFO_DIR = '/sw/fink/10.2/unstable/main/finkinfo/games' + self.TARBALL_DIR='radiant-' + self.F_REV + '.' + self.major + self.TARBALL_NAME='radiant-' + self.F_REV + '.' + self.major + '.tar.gz' + self.TARBALL_DEST='/sw/src' + + # prepare package description + self.system('mkdir -p ' + self.FINKINFO_DIR) + self.system('m4 ' + M4_LINE + ' --define=M4_SETUP_TARGET=' + self.SETUP_TARGET + ' --define=M4_F_REV=' + self.F_REV + ' ' + 'setup/osx/radiant.info.m4 > ' + self.FINKINFO_DIR + '/radiant-' + self.TARBALL_DIR + '.info') + + # build the tarball + self.system('if [ -r /tmp/' + self.TARBALL_DIR + ' ] ; then rm -r ' '/tmp/' + self.TARBALL_DIR + ' ; fi') + self.system('mkdir -p ' '/tmp/' + self.TARBALL_DIR) + self.system('cp ' + self.SETUP_TARGET + ' ' + '/tmp/' + self.TARBALL_DIR) + self.system('cd /tmp ; tar -cvzf ' + self.TARBALL_NAME + ' ' + self.TARBALL_DIR + ' ; cp ' + self.TARBALL_NAME + ' ' + self.TARBALL_DEST + '/') + self.system('/sw/bin/fink rebuild radiant') + + build_fink_deb(self) + + def spawn_setup(self, env, target, source): + if ( OS == 'Darwin' ): + self.g_darwin = 1 + else: + self.g_darwin = 0 + (self.line, self.major, self.minor) = get_version() + print 'Setup: GtkRadiant %s' % self.line + if ( self.g_darwin ): + self.SETUP_IMAGE_OS = '../loki_setup/image' + else: + self.SETUP_IMAGE_OS = 'setup/linux/setup_image.Linux' + self.SETUP_IMAGE = 'setup/linux/setup_image' + self.SETUP_DIR = '/tmp/radiant-setup.%d' % os.getpid() + self.EDITOR_BIN='radiant.' + g_cpu + if ( self.g_darwin ): + self.SETUP_BIN_DIR = self.SETUP_DIR + '/bin/Darwin/ppc' + self.SETUP_TARGET = 'osx-radiant-%s.run' % self.line + else: + self.SETUP_BIN_DIR = self.SETUP_DIR + '/bin/Linux/x86' + self.SETUP_TARGET = 'linux-radiant-%s.run' % self.line + # TODO: eval a conf file instead + self.DO_CORE=1 + self.DO_GAME_Q3=1 + self.DO_GAME_WOLF=1 + self.DO_GAME_ET=1 + self.DO_GAME_Q2=1 + self.DO_GAME_HER2=1 + if ( self.g_darwin ): + self.DO_GAME_Q2=0 + self.DO_GAME_ET=0 + self.DO_GAME_HER2=0 + # verbose a bit + print 'version: %s major: %s minor: %s\neditor core: %d\nq3: %d\nwolf: %d\nq2: %d\nher2: %d' % (self.line, self.major, self.minor, self.DO_CORE, self.DO_GAME_Q3, self.DO_GAME_WOLF, self.DO_GAME_Q2, self.DO_GAME_HER2) + if (self.DO_CORE): + self.copy_core() + if (self.DO_GAME_Q3): + self.copy_q3() + if (self.DO_GAME_WOLF): + self.copy_wolf() + if (self.DO_GAME_ET): + self.copy_et() + if (self.DO_GAME_Q2): + self.copy_q2() + if (self.DO_GAME_HER2): + self.copy_her2() + self.build_setup() + return 0 + +def spawn_setup(env, target, source): + setup = setup_builder() + setup.spawn_setup(env, target, source) + +# NOTE: could modify g_env to add the deps auto when calling SharedLibrarySafe .. +if (SETUP == '1'): + g_env.Command('foo', INSTALL + '/radiant.' + g_cpu, [ spawn_setup ] ) + depends_list = [ + INSTALL + '/modules/entity.so', + INSTALL + '/modules/fgd.so', + INSTALL + '/modules/imagehl.so', + INSTALL + '/modules/image.so', + INSTALL + '/modules/imagepng.so', + INSTALL + '/modules/map.so', + INSTALL + '/modules/mapxml.so', + INSTALL + '/modules/model.so', + INSTALL + '/modules/shaders.so', + INSTALL + '/modules/surface.so', + INSTALL + '/modules/vfspk3.so', + INSTALL + '/modules/vfswad.so', + INSTALL + '/plugins/bobtoolz.so', + INSTALL + '/plugins/camera.so', + INSTALL + '/plugins/prtview.so', + INSTALL + '/plugins/gensurf.so', + INSTALL + '/plugins/bkgrnd2d.so', + INSTALL + '/q3map2.' + g_cpu, + INSTALL + '/radiant.' + g_cpu, + INSTALL + '/q3data.' + g_cpu ] + if ( OS != 'Darwin' ): + depends_list += [ + INSTALL + '/q2/modules/imagewal.so', + INSTALL + '/q2/modules/surface_quake2.so', + INSTALL + '/q2/modules/vfspak.so', + INSTALL + '/q2/q2map', + INSTALL + '/q2/qdata3', + INSTALL + '/heretic2/modules/imagem8.so', + INSTALL + '/heretic2/modules/surface_heretic2.so', + INSTALL + '/heretic2/modules/vfspak.so', + INSTALL + '/heretic2/qdata3', + INSTALL + '/heretic2/q2map' ] + g_env.Depends( 'foo', depends_list ) + +# end setup --------------------------------------------------------------------------------------- diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000..d5d6c824 --- /dev/null +++ b/SConstruct @@ -0,0 +1,291 @@ +# scons build script +# http://scons.sourceforge.net + +import commands, re, sys, os, pickle, string, popen2 +from makeversion import radiant_makeversion, get_version +from osx_setup import do_osx_setup + +# to access some internal stuff +import SCons + +conf_filename='site.conf' +# there is a default hardcoded value, you can override on command line, those are saved between runs +# we only handle strings +serialized=['CC', 'CXX', 'JOBS', 'BUILD', 'SETUP'] + +# help ------------------------------------------- + +Help(""" +Usage: scons [OPTIONS] [TARGET] [CONFIG] + +[OPTIONS] and [TARGET] are covered in command line options, use scons -H + +[CONFIG]: KEY="VALUE" [...] +a number of configuration options saved between runs in the """ + conf_filename + """ file +erase """ + conf_filename + """ to start with default settings again + +CC +CXX + Specify C and C++ compilers (defaults gcc and g++) + ex: CC="gcc-3.2" + You can use ccache and distcc, for instance: + CC="ccache distcc gcc" CXX="ccache distcc g++" + +JOBS + Parallel build + ex: JOBS="4" is a good setting on SMP machines + +BUILD + Use debug/release to select build settings + ex: BUILD="release" - default is debug + OSX: use BUILD="info" to generate the set of release files + +SETUP + Build a setup - default 0 +""" +) + +# end help --------------------------------------- + +# sanity ----------------------------------------- + +# use q decently recent python release +EnsurePythonVersion( 2, 1 ) +# above 0.90 +EnsureSConsVersion( 0, 95 ) +print 'SCons ' + SCons.__version__ + +# end sanity ------------------------------------- + +# system detection ------------------------------- + +# CPU type +g_cpu = commands.getoutput('uname -m') +exp = re.compile('.*i?86.*') +if (g_cpu == 'Power Macintosh'): + g_cpu = 'ppc' +elif exp.match(g_cpu): + g_cpu = 'x86' +else: + g_cpu = 'cpu' + +# OS +OS = commands.getoutput('uname') + +if (OS == 'Linux'): + # libc .. do the little magic! + # NOTE: this used to work fine up to libc 2.3 + libc = commands.getoutput('/lib/libc.so.6 |grep "GNU C "|grep version|awk -F "version " \'{ print $2 }\'|cut -b -3') + +# end system detection --------------------------- + +# default settings ------------------------------- + +CC='gcc' +CXX='g++' +JOBS='1' +BUILD='debug' +INSTALL='#install' +SETUP='0' +g_build_root = 'build' + +# end default settings --------------------------- + +# site settings ---------------------------------- + +site_dict = {} +if (os.path.exists(conf_filename)): + site_file = open(conf_filename, 'r') + p = pickle.Unpickler(site_file) + site_dict = p.load() + print 'Loading build configuration from ' + conf_filename + for k, v in site_dict.items(): + exec_cmd = k + '=\"' + v + '\"' + print exec_cmd + exec(exec_cmd) + +# end site settings ------------------------------ + +# command line settings -------------------------- + +for k in serialized: + if (ARGUMENTS.has_key(k)): + exec_cmd = k + '=\"' + ARGUMENTS[k] + '\"' + print 'Command line: ' + exec_cmd + exec(exec_cmd) + +# end command line settings ---------------------- + +# sanity check ----------------------------------- + +if (SETUP == '1' and BUILD != 'release' and BUILD != 'info'): + print 'Forcing release build for setup' + BUILD = 'release' + +def GetGCCVersion(name): + ret = commands.getstatusoutput('%s -dumpversion' % name) + if ( ret[0] != 0 ): + return None + vers = string.split(ret[1], '.') + if ( len(vers) == 2 ): + return [ vers[0], vers[1], 0 ] + elif ( len(vers) == 3 ): + return vers + return None + +ver_cc = GetGCCVersion(CC) +ver_cxx = GetGCCVersion(CXX) + +# end sanity check ------------------------------- + +# save site configuration ---------------------- + +for k in serialized: + exec_cmd = 'site_dict[\'' + k + '\'] = ' + k + exec(exec_cmd) + +site_file = open(conf_filename, 'w') +p = pickle.Pickler(site_file) +p.dump(site_dict) +site_file.close() + +# end save site configuration ------------------ + +# general configuration, target selection -------- + +SConsignFile( "scons.signatures" ) + +g_build = g_build_root + '/' + BUILD + +SetOption('num_jobs', JOBS) + +LINK = CXX +# common flags +CCFLAGS = '' +CXXFLAGS = '-pipe -DQ_NO_STLPORT ' +CPPPATH = [] +if (BUILD == 'debug'): + CXXFLAGS += '-g -D_DEBUG ' + CCFLAGS += '-g -D_DEBUG ' +elif (BUILD == 'release'): + CXXFLAGS += '-g -O2 ' + CCFLAGS += '-g -O2 ' +elif ( BUILD == 'info' ): + print 'Preparing OSX release' + ( line, major, minor ) = get_version() + do_osx_setup( major, minor, 'osx-radiant-%s.run' % line ) + sys.exit( 0 ) +else: + print 'Unknown build configuration ' + BUILD + sys.exit( 0 ) + +LINKFLAGS = '' +if ( OS == 'Linux' ): + LINKFLAGS += '-Wl,-fini,fini_stub ' +if ( OS == 'Darwin' ): + CCFLAGS += '-force_cpusubtype_ALL -fPIC ' + CXXFLAGS += '-force_cpusubtype_ALL -fPIC -fno-exceptions -fno-rtti ' + CPPPATH.append('/sw/include') + CPPPATH.append('/usr/X11R6/include') + LINKFLAGS += '-L/sw/lib -L/usr/lib -L/usr/X11R6/lib ' + +CPPPATH.append('libs') + +# extend the standard Environment a bit +class idEnvironment(Environment): + + def useGlib2(self): + self['CXXFLAGS'] += '`pkg-config glib-2.0 --cflags` ' + self['CCFLAGS'] += '`pkg-config glib-2.0 --cflags` ' + self['LINKFLAGS'] += '`pkg-config glib-2.0 --libs` ' + + def useXML2(self): + self['CXXFLAGS'] += '`xml2-config --cflags` ' + self['CCFLAGS'] += '`xml2-config --cflags` ' + self['LINKFLAGS'] += '`xml2-config --libs` ' + + def useGtk2(self): + self['CXXFLAGS'] += '`pkg-config gtk+-2.0 --cflags` ' + self['CCFLAGS'] += '`pkg-config gtk+-2.0 --cflags` ' + self['LINKFLAGS'] += '`pkg-config gtk+-2.0 --libs-only-L` `pkg-config gtk+-2.0 --libs-only-l` ' + + def useGtkGLExt(self): + self['CXXFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` ' + self['CCFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` ' + self['LINKFLAGS'] += '`pkg-config gtkglext-1.0 --libs-only-L` `pkg-config gtkglext-1.0 --libs-only-l` ' + + def usePNG(self): + self['CXXFLAGS'] += '`libpng-config --cflags` ' + self['CCFLAGS'] += '`libpng-config --cflags` ' + self['LINKFLAGS'] += '`libpng-config --ldflags` ' + + def usePThread(self): + if ( OS == 'Darwin' ): + self['LINKFLAGS'] += '-lpthread -Wl,-stack_size,0x400000 ' + else: + self['LINKFLAGS'] += '-lpthread ' + + def CheckLDD(self, target, source, env): + file = target[0] + if (not os.path.isfile(file.abspath)): + print('ERROR: CheckLDD: target %s not found\n' % target[0]) + Exit(1) + # not using os.popen3 as I want to check the return code + ldd = popen2.Popen3('`which ldd` -r %s' % target[0], 1) + stdout_lines = ldd.fromchild.readlines() + stderr_lines = ldd.childerr.readlines() + ldd_ret = ldd.wait() + del ldd + have_undef = 0 + if ( ldd_ret != 0 ): + print "ERROR: ldd command returned with exit code %d" % ldd_ret + os.system('rm %s' % target[0]) + Exit() + for i_line in stderr_lines: + print repr(i_line) + regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)\n') + if ( regex.match(i_line) ): + symbol = regex.sub('\\1', i_line) + try: + env['ALLOWED_SYMBOLS'].index(symbol) + except: + have_undef = 1 + else: + print "ERROR: failed to parse ldd stderr line: %s" % i_line + os.system('rm %s' % target[0]) + Exit(1) + if ( have_undef ): + print "ERROR: undefined symbols" + os.system('rm %s' % target[0]) + Exit(1) + + def SharedLibrarySafe(self, target, source): + self.SharedLibrary(target, source) + if (OS != 'Darwin'): + AddPostAction(target + '.so', self.CheckLDD) + +g_env = idEnvironment(ENV = os.environ, + CC = CC, + CXX = CXX, + LINK = LINK, + CCFLAGS = CCFLAGS, + CXXFLAGS = CXXFLAGS, + CPPPATH = CPPPATH, + LINKFLAGS = LINKFLAGS) + +# export the globals +GLOBALS = 'g_env INSTALL SETUP g_cpu' + +radiant_makeversion('\\ngcc version: %s.%s.%s' % ( ver_cc[0], ver_cc[1], ver_cc[2] ) ) + +# end general configuration ---------------------- + +# targets ---------------------------------------- + +Default('.') + +Export('GLOBALS ' + GLOBALS) +BuildDir(g_build, '.', duplicate = 0) +SConscript(g_build + '/SConscript') + +# end targets ------------------------------------ diff --git a/contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp new file mode 100644 index 0000000000000000000000000000000000000000..bc307e2615240b3b2c73eb6ec8b7fa5e7a94cc72 GIT binary patch literal 216 zcmYj|u?@o@6hx26l~V*VfrW(R(lSkuQl(Ex>scsVWCVKv@4*<}2H!VIl!xw455()e zqcU-NMl&}?p_g(sziL@%XC@dkKG%^U0wIQTn&~g47a5;Ch)?Ymg zD^*XHGdYkw*~pe&b=-**co#}Hr6idr#wd|F=Uj{(k!!KnNBX{((<m%UyqgRI`txz u6H)WeeXBitaiT|43EBixr;THd`6dMRoPS;upIH7TGL}73Qtexture_number); + g_free(m_tex); + m_tex = NULL; + } +} + +void CBackgroundImage::Render() +{ + if (!m_bActive || !Valid()) + return; + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglEnable(GL_TEXTURE_2D); + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + g_QglTable.m_pfn_qglPolygonMode(GL_FRONT,GL_FILL); + // TODO, just so we can tell if we end up going the wrong way + // g_QglTable.m_pfn_qglPolygonMode(GL_BACK,GL_LINE); + // TODO any other state we should not assume ? + + g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, m_tex->texture_number); + g_QglTable.m_pfn_qglBegin(GL_QUADS); + + g_QglTable.m_pfn_qglColor4f(1.0,1.0,1.0,m_alpha); + g_QglTable.m_pfn_qglTexCoord2f(0.0,1.0); + g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymin); + + g_QglTable.m_pfn_qglTexCoord2f(1.0,1.0); + g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymin); + + g_QglTable.m_pfn_qglTexCoord2f(1.0,0.0); + g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymax); + + g_QglTable.m_pfn_qglTexCoord2f(0.0,0.0); + g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymax); + + g_QglTable.m_pfn_qglEnd(); + g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, 0); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +bool CBackgroundImage::Load(const char *filename) +{ + qtexture_t *newtex; + + unsigned char *image = NULL; // gets allocated with what ? g_malloc + int width = 0, height = 0; + + g_FuncTable.m_pfnLoadImage(filename,&image,&width,&height); + + if(!image) { + Syn_Printf(MSG_WARN "load %s failed\n",filename); + return false; + } + +// just in case we want to build for an old version +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 +#ifdef BKGRND2D_JPG_WORKAROUND + if ( strlen(filename) > 4 && !strcmp(".jpg",filename + strlen(filename) - 4)) { + Syn_Printf(MSG_PREFIX ".jpg workaround, clearing alpha channel\n"); + int size = width*height*4; + int i; + for (i = 3; i < size; i+=4) { + image[i] = 255; + } + } +#endif + + //TODO bug for stored texture size + //TODO whose gl context are we in, anyway ? + newtex = g_FuncTable.m_pfnLoadTextureRGBA(image,width,height); + + g_free(image); + + if(!newtex) { + Syn_Printf(MSG_WARN "image to texture failed\n"); + return false; + } + + Cleanup(); + m_tex = newtex; + + g_FuncTable.m_pfnSysUpdateWindows(W_XY); + + return true; +} + +bool CBackgroundImage::SetExtentsMM() +{ + entity_s *worldentity; + const char *val; + int xmin = 0, ymin = 0, xmax = 0, ymax = 0; + + worldentity = (entity_s *)g_FuncTable.m_pfnGetEntityHandle(0); + if(!worldentity) { + Syn_Printf(MSG_WARN "SetExtentsMM worldspawn not found\n"); + return false; + } + //TODO val is not NULL even if key does not exist + val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmins"); + if(!val || !val[0]) { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins not found\n"); + return false; + } +// we could be more robust +// note contortions due to splashs strange idea of min and max + if(sscanf(val, "%d %d",&xmin,&ymax) != 2) + { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins malformed\n"); + return false; + } + + val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmaxs"); + if(!val || !val[0]) { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs not found\n"); + return false; + } + if(sscanf(val, "%d %d",&xmax,&ymin) != 2) + { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs malformed\n"); + return false; + } + //might do sanity check before we commit + m_xmin = (float)xmin; + m_ymin = (float)ymin; + m_xmax = (float)xmax; + m_ymax = (float)ymax; + + g_FuncTable.m_pfnSysUpdateWindows(W_XY); + return true; +} + +// TODO, this should just be exported from core +// ripped directly from radiant/select.cpp:Select_GetBounds +// +static bool get_selection_bounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + brush_t *selected_brushes = g_DataTable.m_pfnSelectedBrushes(); + //TODO should never happen + if(!selected_brushes) { + Sys_Printf (MSG_PREFIX "selected_brushes = NULL\n"); + return false; + } + // this should mean no selection + if(selected_brushes == selected_brushes->next) { + Sys_Printf (MSG_PREFIX "nothing selected\n"); + + return false; + } + + for (i=0 ; i<3 ; i++) + { + mins[i] = 99999; + maxs[i] = -99999; + } + + for (b=selected_brushes->next ; b != selected_brushes ; b=b->next) + { + if (b->owner->eclass->fixedsize) + { + for (i=0 ; i<3 ; i++) + { + if (b->owner->origin[i] < mins[i]) + mins[i] = b->owner->origin[i]; + if (b->owner->origin[i] > maxs[i]) + maxs[i] = b->owner->origin[i]; + } + } + else + { + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] < mins[i]) + mins[i] = b->mins[i]; + if (b->maxs[i] > maxs[i]) + maxs[i] = b->maxs[i]; + } + } + } + return true; +} + +bool CBackgroundImage::SetExtentsSel() +{ + vec3_t mins,maxs; + + if(!get_selection_bounds(mins,maxs)) + return false; + + if(((int)mins[m_ix] == (int)maxs[m_ix]) || + ((int)mins[m_iy] == (int)maxs[m_iy])) { + Syn_Printf(MSG_PREFIX "tiny selection\n"); + return false; + } + + m_xmin = mins[m_ix]; + m_ymin = mins[m_iy]; + m_xmax = maxs[m_ix]; + m_ymax = maxs[m_iy]; + + g_FuncTable.m_pfnSysUpdateWindows(W_XY); + + return true; +} + diff --git a/contrib/bkgrnd2d/bkgrnd2d.def b/contrib/bkgrnd2d/bkgrnd2d.def new file mode 100644 index 00000000..36c4457f --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.def @@ -0,0 +1,8 @@ +; bkgrnd2d.def : Declares the module parameters for the DLL. + +LIBRARY "BKGRND2D" +DESCRIPTION 'BKGRND2D Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/bkgrnd2d/bkgrnd2d.h b/contrib/bkgrnd2d/bkgrnd2d.h new file mode 100644 index 00000000..bee6e811 --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on spritemodel source code by hydra +// + +#include "plugin.h" + +class CBackgroundImage { +private: + qtexture_t *m_tex; + VIEWTYPE m_vt; + +// which components of a vec3_t correspond to x and y in the image + unsigned m_ix,m_iy; + +public: + CBackgroundImage(VIEWTYPE vt); +// ~CBackgroundImage(); + + float m_alpha; // vertex alpha + bool m_bActive; + +// x and y axis are in relation to the screen, not world, making rendering +// the same for each view type. Whoever sets them is responsible for +// shuffling. +// units are world units. +// TODO should be private + float m_xmin,m_ymin,m_xmax,m_ymax; + +// load file, create new tex, cleanup old tex, set new tex + bool Load(const char *filename); + void Cleanup(); // free texture, free tex, set make tex NULL + bool SetExtentsMM(); // set extents by ET mapcoordsmaxs/mapcoordsmins + bool SetExtentsSel(); // set extents by selection + void Render(); + bool Valid() { return (m_tex && (m_xmin != m_xmax) && (m_ymin != m_ymax)); } +}; + +class CBackgroundRender : public IGL2DWindow { +public: + + CBackgroundRender(); + virtual ~CBackgroundRender(); + +protected: + int refCount; + +public: + + // IGL2DWindow IGL3DWindow interface + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); + void Register(); +}; + +extern CBackgroundImage backgroundXY,backgroundXZ,backgroundYZ; +extern CBackgroundRender render; + diff --git a/contrib/bkgrnd2d/bkgrnd2d.vcproj b/contrib/bkgrnd2d/bkgrnd2d.vcproj new file mode 100644 index 00000000..e4b59896 --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.vcproj @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/bkgrnd2d/dialog.cpp b/contrib/bkgrnd2d/dialog.cpp new file mode 100644 index 00000000..43fe7717 --- /dev/null +++ b/contrib/bkgrnd2d/dialog.cpp @@ -0,0 +1,365 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin dialog +// +// Code by reyalP aka Reed Mideke +// +// Based on various other plugins +// + +#include + +#include "bkgrnd2d.h" +#include "dialog.h" + +// spaces to make label nice and big +#define NO_FILE_MSG " (no file loaded) " + +static GtkWidget *pDialogWnd; +static GtkWidget *pNotebook; +static GtkTooltips *pTooltips; + +class CBackgroundDialogPage +{ +private: + GtkWidget *m_pWidget; + GtkWidget *m_pTabLabel; + GtkWidget *m_pFileLabel; + GtkWidget *m_pPosLabel; + VIEWTYPE m_vt; + bool m_bValidFile; + +public: + CBackgroundImage *m_pImage; + CBackgroundDialogPage( VIEWTYPE vt ); + void Append(GtkWidget *notebook); + void Browse(); + void Reload(); + void SetPosLabel(); +// ~BackgroundDialogPage(); +}; + + +// dialog page callbacks +static void browse_callback( GtkWidget *widget, gpointer data ) +{ + ((CBackgroundDialogPage *)data)->Browse(); +} + +static void reload_callback( GtkWidget *widget, gpointer data ) +{ + ((CBackgroundDialogPage *)data)->Reload(); +} + +static void size_sel_callback( GtkWidget *widget, gpointer data ) +{ + CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data; + if (pPage->m_pImage->SetExtentsSel()) + pPage->SetPosLabel(); +} + +static void size_mm_callback( GtkWidget *widget, gpointer data ) +{ + CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data; + if(pPage->m_pImage->SetExtentsMM()) + pPage->SetPosLabel(); +} + +static void alpha_adjust_callback( GtkWidget *widget, gpointer data ) +{ + CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data; + pPage->m_pImage->m_alpha = (float)gtk_range_get_value (GTK_RANGE(widget)); + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +void CBackgroundDialogPage::Reload() +{ + if(m_bValidFile) + m_pImage->Load(gtk_label_get_text(GTK_LABEL(m_pFileLabel))); +} + +void CBackgroundDialogPage::Browse() +{ + char browsedir[PATH_MAX]; + const char *ct; + const char *newfile; + char *t; + + //TODO GetMapName saves the map. eeep! + //also with no map, returns unnamed.map, otherwise returns full path +// Syn_Printf(MSG_PREFIX "GetMapName() %s\n", +// g_FuncTable.m_pfnGetMapName()); + + ct = g_FuncTable.m_pfnReadProjectKey("basepath"); + // TODO shouldn't need this stuff + if(!ct || !strlen(ct)) { + Syn_Printf(MSG_PREFIX "basepath = NULL or empty\n"); + return; + } + Syn_Printf(MSG_PREFIX "basepath: %s\n",ct); + if(strlen(ct) >= PATH_MAX) { + Syn_Printf(MSG_PREFIX "base game dir too long\n"); + return; + } + + strcpy(browsedir,ct); + // make sure we have a trailing / + if(browsedir[strlen(browsedir) - 1] != '/') + strcat(browsedir,"/"); + + //if we dont have a file yet, don't try to use it for default dir + if(m_bValidFile) { + // filename should always be a nice clean unix style relative path + ct = gtk_label_get_text(GTK_LABEL(m_pFileLabel)); + strcat(browsedir,ct); + Syn_Printf(MSG_PREFIX "full path: %s\n",browsedir); + + // lop off the file part + t = browsedir + strlen(browsedir) - 1; + while (t != browsedir && *t != '/') + t--; + *t = 0; + } + Syn_Printf(MSG_PREFIX "browse directory %s\n",browsedir); + +//does NOT need freeing contrary to include/qerplugin.h comments +//TODO bug/patch for comments +//TODO patern gets fucked up sometimes if empty +//http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=915 + newfile = g_FuncTable.m_pfnFileDialog(pDialogWnd,TRUE, + "Load Background Image",browsedir,FILETYPE_KEY); + if(!newfile) { + Syn_Printf(MSG_PREFIX "newfile = NULL\n"); + return; + } + Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile); + newfile = g_FileSystemTable.m_pfnExtractRelativePath(newfile); + + if(!newfile) { + Syn_Printf(MSG_PREFIX "newfile = NULL\n"); + return; + } + Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile); + + if(m_pImage->Load(newfile)) { + m_bValidFile = true; + gtk_label_set_text(GTK_LABEL(m_pFileLabel),newfile); + } +} + +void CBackgroundDialogPage::SetPosLabel() +{ + char s[64]; + // TODO no snprintf ? + sprintf(s, "Size/Position (%d,%d) (%d,%d)",(int)(m_pImage->m_xmin), + (int)(m_pImage->m_ymin),(int)(m_pImage->m_xmax),(int)(m_pImage->m_ymax)); + gtk_label_set_text(GTK_LABEL(m_pPosLabel),s); +} + +CBackgroundDialogPage::CBackgroundDialogPage(VIEWTYPE vt ) +{ + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *w; + + m_vt = vt; + + m_bValidFile = false; + + switch(m_vt) + { + case XY: + m_pTabLabel = gtk_label_new("X/Y"); + m_pImage = &backgroundXY; + break; + case XZ: + m_pTabLabel = gtk_label_new("X/Z"); + m_pImage = &backgroundXZ; + break; + case YZ: + m_pTabLabel = gtk_label_new("Y/Z"); + m_pImage = &backgroundYZ; + break; + } +// A vbox to hold everything + m_pWidget = gtk_vbox_new(FALSE,0); +// Frame for file row + frame = gtk_frame_new("File"); + gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2); + +// hbox for first row + hbox = gtk_hbox_new(FALSE,5); + gtk_container_set_border_width(GTK_CONTAINER (hbox),4); + gtk_container_add (GTK_CONTAINER (frame), hbox); + +// label to display filename + m_pFileLabel = gtk_label_new(NO_FILE_MSG); + gtk_label_set_selectable(GTK_LABEL(m_pFileLabel),TRUE); +//TODO set min size ? done with spaces right now + gtk_box_pack_start (GTK_BOX (hbox),m_pFileLabel, TRUE, TRUE, 5); + + gtk_widget_show (m_pFileLabel); + + w = gtk_button_new_with_label ("Browse..."); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (browse_callback), + (gpointer)this); + gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5); + gtk_tooltips_set_tip (pTooltips, w, "Select a file", NULL); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Reload"); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (reload_callback), + (gpointer)this); + // TODO disable until we have file + // gtk_widget_set_sensitive(w,FALSE); + gtk_tooltips_set_tip (pTooltips, w, "Reload current file", NULL); + gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5); + gtk_widget_show (w); + + gtk_widget_show (hbox); + gtk_widget_show (frame); + +// second row (rendering options) + frame = gtk_frame_new("Rendering"); + gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2); + + hbox = gtk_hbox_new(FALSE,5); + gtk_container_set_border_width(GTK_CONTAINER (hbox),4); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + w = gtk_label_new("Vertex alpha:"); + gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5); + gtk_widget_show (w); + + w = gtk_hscale_new_with_range(0.0,1.0,0.01); + gtk_range_set_value(GTK_RANGE(w),0.5); + gtk_scale_set_value_pos(GTK_SCALE(w),GTK_POS_LEFT); + g_signal_connect (G_OBJECT (w), "value-changed", + G_CALLBACK (alpha_adjust_callback), (gpointer)this); + gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, TRUE, 5); + gtk_tooltips_set_tip (pTooltips, w, "Set image transparancy", NULL); + gtk_widget_show (w); + + gtk_widget_show (hbox); + gtk_widget_show (frame); +// Third row (size and position) + frame = gtk_frame_new("Size/Position (undefined)"); + m_pPosLabel = gtk_frame_get_label_widget (GTK_FRAME(frame)); + gtk_box_pack_start ( GTK_BOX (m_pWidget), frame, FALSE, FALSE, 2); + + hbox = gtk_hbox_new(FALSE,5); + gtk_container_add (GTK_CONTAINER (frame), hbox); + gtk_container_set_border_width(GTK_CONTAINER (hbox),4); + + w = gtk_button_new_with_label ("from selection"); + gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, FALSE, 5); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_sel_callback), + (gpointer)this); + gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image to the bounding rectangle of all selected brushes and entities", NULL); + gtk_widget_show (w); + + if(m_vt == XY) { + w = gtk_button_new_with_label ("from map mins/maxs"); + gtk_box_pack_start ( GTK_BOX (hbox),w, TRUE, FALSE, 2); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_mm_callback), + (gpointer)this); + gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image using the mapcoordsmins and mapcoordsmaxs keys of the worldspawn entity", NULL); + gtk_widget_show (w); + } + + gtk_widget_show (hbox); + gtk_widget_show (frame); + + gtk_widget_show ( m_pWidget ); +} + +void CBackgroundDialogPage::Append(GtkWidget *notebook) +{ + gtk_notebook_append_page( GTK_NOTEBOOK(notebook), m_pWidget, m_pTabLabel); +} + +// dialog global callbacks +/* +static gint expose_callback( GtkWidget *widget, gpointer data ) +{ + return FALSE; +} +*/ + +static void response_callback( GtkWidget *widget, gint response, gpointer data ) +{ + if( response == GTK_RESPONSE_CLOSE ) + gtk_widget_hide( pDialogWnd ); +} + +static gint close_callback( GtkWidget *widget, gpointer data ) +{ + gtk_widget_hide( pDialogWnd ); + return TRUE; +} + +void InitBackgroundDialog() +{ + CBackgroundDialogPage *pPage; + + pDialogWnd = gtk_dialog_new_with_buttons ("Background Images", + GTK_WINDOW(g_pMainWidget), + (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT), + // TODO dialog with no buttons + // GTK_STOCK_CLOSE, + // GTK_RESPONSE_CLOSE, + NULL); + gtk_signal_connect( GTK_OBJECT (pDialogWnd), "delete_event", + GTK_SIGNAL_FUNC( close_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (pDialogWnd), "response", + GTK_SIGNAL_FUNC( response_callback ), NULL ); +// gtk_signal_connect( GTK_OBJECT (pDialogWnd), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL ); + + pTooltips = gtk_tooltips_new(); + + pNotebook = gtk_notebook_new(); + pPage = new CBackgroundDialogPage(XY); + pPage->Append(pNotebook); + pPage = new CBackgroundDialogPage(XZ); + pPage->Append(pNotebook); + pPage = new CBackgroundDialogPage(YZ); + pPage->Append(pNotebook); + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(pDialogWnd)->vbox), pNotebook, TRUE, TRUE, 0); + + gtk_widget_show ( pNotebook ); + + gtk_widget_realize( pDialogWnd ); +} + +void ShowBackgroundDialog() +{ + gtk_window_present( GTK_WINDOW(pDialogWnd) ); +} + +void ShowBackgroundDialogPG(int page) +{ + gtk_notebook_set_current_page(GTK_NOTEBOOK(pNotebook),page); + ShowBackgroundDialog(); +} + diff --git a/contrib/bkgrnd2d/dialog.h b/contrib/bkgrnd2d/dialog.h new file mode 100644 index 00000000..7a82cdd6 --- /dev/null +++ b/contrib/bkgrnd2d/dialog.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin dialog box +// +// Code by reyalP aka Reed Mideke +// +// + +#ifndef _BKGRND2D_DIALOG_H_ +#define _BKGRND2D_DIALOG_H_ + +void InitBackgroundDialog(); +void ShowBackgroundDialog(); +void ShowBackgroundDialogPG(int page); + +#endif // _BKGRND2D_DIALOG_H_ diff --git a/contrib/bkgrnd2d/plugin.cpp b/contrib/bkgrnd2d/plugin.cpp new file mode 100644 index 00000000..56150e37 --- /dev/null +++ b/contrib/bkgrnd2d/plugin.cpp @@ -0,0 +1,320 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// 2d background Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on +// + +/* + Overview + ======== + This little plugin allows you to display an image in the background of the + gtkradiant XY window. + + Version History + =============== + + v0.1 + - Initial version. + v0.2 + - three views, dialog box, toolbar + v0.25 + - tooltips, follow gtkradiant coding conventions + + Why ? + ----- + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88 + + + How ? + ----- + - textures 'n widgets 'n stuff. +*/ + +//#include "plugin.h" +//TODO we just poke the objects directly +#include "bkgrnd2d.h" +#include "dialog.h" + +#define CMD_SEP "-" +#define CMD_CONFIG "Configure..." +#define CMD_ABOUT "About..." +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERFileSystemTable g_FileSystemTable; +_QEREntityTable g_EntityTable; +_QERAppDataTable g_DataTable; + +// for the file load dialog +void *g_pMainWidget; + +// ============================================================================= +// plugin implementation + +static const char *PLUGIN_NAME = "2d window background plugin"; + +//backwards for some reason +static const char *PLUGIN_COMMANDS = CMD_ABOUT ";" + CMD_SEP ";" + CMD_CONFIG + ; + +static const char *PLUGIN_ABOUT = "2d window background v0.25\n\n" + "By reyalP (hellsownpuppy@yahoo.com)"; + + + + +void DoBkgrndToggleXY(); +void DoBkgrndToggleXZ(); +void DoBkgrndToggleYZ(); + +#define NUM_TOOLBAR_BUTTONS 4 +struct toolbar_button_info_s +{ + char *image; + char *text; + char *tip; + void (*func)(); + IToolbarButton::EType type; +}; + +struct toolbar_button_info_s toolbar_buttons[NUM_TOOLBAR_BUTTONS] = +{ + { + "bkgrnd2d_xy_toggle.bmp", + "xy background", + "Toggle xy background image", + DoBkgrndToggleXY, + IToolbarButton::eToggleButton + }, + { + "bkgrnd2d_xz_toggle.bmp", + "xz background", + "Toggle xz background image", + DoBkgrndToggleXZ, + IToolbarButton::eToggleButton + }, + { + "bkgrnd2d_yz_toggle.bmp", + "yz background", + "Toggle yz background image", + DoBkgrndToggleYZ, + IToolbarButton::eToggleButton + }, + { + "bkgrnd2d_conf.bmp", + "Configure", + "Configure background images", + ShowBackgroundDialog, + IToolbarButton::eButton + }, +}; + +class Bkgrnd2dButton : public IToolbarButton +{ +public: + const toolbar_button_info_s *bi; + virtual const char* getImage() const + { + return bi->image; + } + virtual const char* getText() const + { + return bi->text; + } + virtual const char* getTooltip() const + { + return bi->tip; + } + virtual void activate() const + { + bi->func(); + return ; + } + virtual EType getType() const + { + return bi->type; + } +}; + +Bkgrnd2dButton g_bkgrnd2dbuttons[NUM_TOOLBAR_BUTTONS]; + +unsigned int ToolbarButtonCount() +{ + return NUM_TOOLBAR_BUTTONS; +} + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + g_bkgrnd2dbuttons[index].bi = &toolbar_buttons[index]; + return &g_bkgrnd2dbuttons[index]; +} + +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + g_pMainWidget = pMainWidget; + + InitBackgroundDialog(); + render.Register(); + +//TODO is it right ? is it wrong ? it works +//TODO figure out supported image types + GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("all files", "*.*")); + GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("jpeg files", "*.jpg")); + GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("targa files", "*.tga")); + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetName () +{ + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList () +{ + return (char *) PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p); + if(!strcmp(p, CMD_ABOUT)) { + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); + } + else if(!strcmp(p,CMD_CONFIG)) { + ShowBackgroundDialog(); + } +} + +//TODO these three suck +void DoBkgrndToggleXY() +{ + Sys_Printf (MSG_PREFIX "DoBkgrndToggleXY\n"); + // always toggle, since the buttons do + backgroundXY.m_bActive = (backgroundXY.m_bActive) ? false:true; + // if we don't have image or extents, and we activated, + // bring up the dialog with the corresponding page + // would be better to hide or grey out button, but we can't + if(backgroundXY.m_bActive && !backgroundXY.Valid()) + ShowBackgroundDialogPG(0); + else + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +void DoBkgrndToggleXZ() +{ + Sys_Printf (MSG_PREFIX "DoBkgrndToggleXZ\n"); + backgroundXZ.m_bActive = (backgroundXZ.m_bActive) ? false:true; + if(backgroundXZ.m_bActive && !backgroundXZ.Valid()) + ShowBackgroundDialogPG(1); + else + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +void DoBkgrndToggleYZ() +{ + Sys_Printf (MSG_PREFIX "DoBkgrndToggleYZ\n"); + backgroundYZ.m_bActive = (backgroundYZ.m_bActive) ? false:true; + if(backgroundYZ.m_bActive && !backgroundYZ.Valid()) + ShowBackgroundDialogPG(2); + else + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientBkgrnd2d g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, BKGRND2D_MINOR, sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, BKGRND2D_MINOR, sizeof( _QERPluginTable ) ); + + g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable ); + g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable ); +// TODO is this the right way to ask for 'whichever VFS we have loaded' ? Seems to work +// for misc filename functions + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); +// get worldspawn + g_SynapseClient.AddAPI( ENTITY_MAJOR, NULL, sizeof( g_EntityTable ), SYN_REQUIRE, &g_EntityTable ); +// selected brushes + g_SynapseClient.AddAPI( DATA_MAJOR, NULL, sizeof( g_DataTable ), SYN_REQUIRE, &g_DataTable ); + + return &g_SynapseClient; +} + +bool CSynapseClientBkgrnd2d::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientBkgrnd2d::GetInfo() +{ + return "2d Background plugin built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientBkgrnd2d::GetName() +{ + return "bkgrnd2d"; +} + diff --git a/contrib/bkgrnd2d/plugin.h b/contrib/bkgrnd2d/plugin.h new file mode 100644 index 00000000..84933ae0 --- /dev/null +++ b/contrib/bkgrnd2d/plugin.h @@ -0,0 +1,80 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on spritemodel source code by hydra +// + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/*! +\todo need general notice about lib purpose etc. +and the external dependencies (such as GLib, STL, mathlib etc.) +*/ + +#include +// for CPtrArray for idata.h +#include "missing.h" + +#include "synapse.h" +#include "iplugin.h" +#include "itoolbar.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "igl.h" +#include "ifilesystem.h" +#include "ientity.h" +#include "idata.h" + +// verbose messages +#define BKGRND2D_DEBUG + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERFileSystemTable g_FileSystemTable; +extern _QEREntityTable g_EntityTable; +extern _QERAppDataTable g_DataTable; +extern void *g_pMainWidget; + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientBkgrnd2d : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientBkgrnd2d() { } + virtual ~CSynapseClientBkgrnd2d() { } +}; +#define MSG_PREFIX "bkgrnd2d: " +#define MSG_WARN "bkgrnd2d WARNING: " +#define BKGRND2D_MINOR "bkgrnd2d" +#define FILETYPE_KEY "bkgrnd2d" + +#endif // _PLUGIN_H_ diff --git a/contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt b/contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt new file mode 100644 index 00000000..6184245e --- /dev/null +++ b/contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt @@ -0,0 +1,131 @@ +November 25 2003 +bkgrnd2d v 0.25 beta for radiant 1.3.13 +by SCDS_reyalP (email hellsownpuppy@yahoo.com) + +WARNING: +This is an beta release. It is provided with absolutely NO WARRANTY. +If it turns your data to mush and melts your CPU, don't blame me. + +Overview: +This little plugin allows you to display an image in the the gtkradiant 2d +windows. This is useful for layout sketches, maps made from +existing plans, building geometry based on photgraphs, viewing terrain +alphamaps in relation to your terrain, and so on. + +Installation: +extract the .dll and bitmaps into your gtkradiant/plugins directory, and +restart radiant. Be sure to use directory names, to ensure the bitmaps go +in your plugins/bitmaps directory. + +Uninstallation: +Close radiant, delete the bkgrnd2d.dll from the plugins directory, and +delete the bkgrnd2*.bmp files from the plugins/bitmaps directory. + +User Interface: +- The plugin adds 4 buttons to the radiant plugin toolbar. The first 3 + toggle the display of a background image in the specified view. The fourth + brings up a configuration dialog. The configuration dialog can also be + opened from the plugins menu. + +- If an image has not been loaded, or it's display size and location have + not been set, pushing one of the toggle buttons will bring up the dialog + with the corresponding page selected. + +- The configuration dialog is non-modal, meaning that you can leave it open + while you work in radiant. If it gets lost behind another window, clicking + on the configuration button will bring it to the forground. + +Usage: +- bring up the configuration dialog. + +- Choose the "Browse..." button. This will prompt you for an image file. + The file *MUST* be inside your basegame directory (baseq3, main, etmain or + whatever your chosen game uses). The image must be in a format supported by + the game in use. For q3 based games this is truecolor .jpg, .tga and + sometimes .png. For q2 this is .wal + +- Use one of the following methods to set the size (in game units) that the + file is displayed. + 1) select 1 or more brushes or entities and choose "from selection" + This will use the total dimensions off all selected brushes and entities + to size the image. + 2) For the X/Y view only, choose 'Size to min/max keys' This will look in + the worldspawn entity for the keys mapcoordsmins and mapcoordsmaxs (also + used for ET tracemap generation and command map sizing) and use those + dimensions to size the image. + +- Use the toggle buttons to show or hide the loaded images. The buttons will + press or unpress whenever you click them, but an image will only be + displayed once you have successfully loaded a file and set its size/postion. + +- Set the opacity of the image using the slider in the configuration dialog. + +- If any of these commands do not produce the expected results, there may be + an information in the radiant console. Please include this when reporting + bugs. + + +Notes and limitations: +- This plugin is compiled for GtkRadiant 1.3.13. It may or may not work with + later versions. It will *NOT* work with version 1.3.12 and below. If you + build from source (see below) you can build it for other versions. + +- As mentioned above, the image *MUST* be inside your basegame directory, or + another directory in which radiant looks for game files. + +- To prevent the image from being distorted, you should size it to the + original images aspect ratio. mapcoordsmaxs/mapcoordsmins and command maps + should always be square. + +- If you want a specific pixel to world unit relationship, you must arrange + that yourself. + +- On load, the image is converted to a texture whose dimensions are powers + of 2. If the original image dimensions are not powers of 2, some detail will + be lost due to resampling. If it is too large to fit on a single texture, + resolution is reduced. + +- radiants gamma and mipmap options are applied to the image. + +- If the image has an alpha channel, it will be included in the blending + process. 0 is transparent, 255 is opaque. .tga images are recommended if + you want to have an alpha channel. + +- since the plugin will only use true color files, you cannot use a terrain + indexmap (aka alphamap) or heightmap directly. You can of course, save a + copy of your indexmap in a 32 bit format. + +- There is no unload command. + +- You put the plugin in a game specific plugin directory, rather than the + radiant plugin directory. + +- You cannot set the image size with sub-unit precision. + +- Only win32 binaries are included. The source is available from: + http://www.cyberonic.net/~gdevault/rfm/mapstuff/bkgrnd2d-b0.25-src.zip + If you want to use it on another platform you will need a buildable gtkradiant + source tree to build it. For any non-windows platform you will also have to + figure out the compile options. I suggest ripping those off from some other + plugin. + +TODO: +- make file selection paterns match supported filetypes +- large images without downsampling +- bitmap and pcx support for indexmaps +- automatic size from indexmapped entities +- render under the grid instead of blending +- mac/*nix support +- remember/save/restore settings +- texture options independant of radiant prefs +- clean up icky code + +Changes from 0.1 +- all 2d views supported +- new ui +- file selection patterns, default directory improved + +Changes from 0.2 +- tooltips in dialog +- various code cleanup + diff --git a/contrib/bobtoolz/CPortals.h b/contrib/bobtoolz/CPortals.h new file mode 100644 index 00000000..bc9d16ac --- /dev/null +++ b/contrib/bobtoolz/CPortals.h @@ -0,0 +1,63 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" // Added by ClassView + +class CBspPoint { +public: + float p[3]; +}; + +class CBspPortal { +public: + CBspPortal(); + ~CBspPortal(); + + unsigned point_count; + CBspPoint *point; + bool Build(char *def, unsigned int pointCnt, bool bInverse); +}; + + +class CBspNode { +public: + CBspPortal *portal; + unsigned int portal_count; + + bool AddPortal(char* def, unsigned int pointCnt, bool bInverse); + unsigned int portal_next; + CBspNode(); + ~CBspNode(); +}; + + +class CPortals { +public: + + CPortals(); + ~CPortals(); + + void Load(); // use filename in fn + void Purge(); + + char fn[PATH_MAX]; + CBspNode *node; + + unsigned int node_count; +}; diff --git a/contrib/bobtoolz/DBobView.cpp b/contrib/bobtoolz/DBobView.cpp new file mode 100644 index 00000000..74fdacd3 --- /dev/null +++ b/contrib/bobtoolz/DBobView.cpp @@ -0,0 +1,361 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// BobView.cpp: implementation of the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DBobView.h" +#include "DListener.h" +#include "misc.h" +#include "funchandlers.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DBobView::DBobView() +{ + nPathCount = 0; + refCount = 1; + + m_bHooked = FALSE; + + path = NULL; + eyes = NULL; + + boundingShow = BOUNDS_APEX; +} + +DBobView::~DBobView() +{ + if(path) + delete[] path; + + // oops forgot to remove our eyes, was causing access violation when it tried + // to talk to it's parent + if(eyes) + delete eyes; + + if(m_bHooked) + UnRegister(); + + g_PathView = NULL; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DBobView::Draw2D(VIEWTYPE vt) +{ + if(!path) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + int i; + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + + for(i = 0; i < nPathCount; i++) + g_QglTable.m_pfn_qglVertex3fv(path[i]); + + g_QglTable.m_pfn_qglEnd(); + + if(m_bShowExtra) + { + // +mars + // for the bounding box stuff + g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f); + + g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f ); + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // --------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // -------------- + + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // ---------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were + +/* g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + if ( boundingShow == BOUNDS_ALL ) + { + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + } + else if ( boundingShow == BOUNDS_APEX ) + { + for ( i = (nPathCount/4); i < (nPathCount/4) * 3; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + } + + g_QglTable.m_pfn_qglEnd();*/ // djbob: er, um doesn't really seem to do anyhting + } + + // -mars + + g_QglTable.m_pfn_qglPopMatrix(); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DBobView::Draw3D() +{ + if(!path) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + + for(int i = 0; i < nPathCount; i++) + g_QglTable.m_pfn_qglVertex3fv(path[i]); + + g_QglTable.m_pfn_qglEnd(); + + if(m_bShowExtra) + { + // +mars + // ahhh -- a nice C&P job :) + // for the bounding box stuff + g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f); + + g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f ); + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + int i; + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // --------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // -------------- + + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // ---------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + } + // -mars + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DBobView::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DBobView::UnRegister() +{ + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void DBobView::SetPath(vec3_t *pPath) +{ + if(path) + delete[] path; + + path = pPath; +} + +#define LOCAL_GRAVITY -800.0f + +bool DBobView::CalculateTrajectory(vec3_t start, vec3_t apex, float multiplier, int points, float varGravity) +{ + if(apex[2] <= start[2]) + { + SetPath(NULL); + return FALSE; + } + // ----think q3a actually would allow these + //scrub that, coz the plugin wont :] + + vec3_t dist, speed; + VectorSubtract(apex, start, dist); + + vec_t speed_z = (float)sqrt(-2*LOCAL_GRAVITY*dist[2]); + float flight_time = -speed_z/LOCAL_GRAVITY; + + + VectorScale(dist, 1/flight_time, speed); + speed[2] = speed_z; + +// Sys_Printf("Speed: (%.4f %.4f %.4f)\n", speed[0], speed[1], speed[2]); + + vec3_t* pPath = new vec3_t[points]; + + float interval = multiplier*flight_time/points; + for(int i = 0; i < points; i++) + { + float ltime = interval*i; + + VectorScale(speed, ltime, pPath[i]); + VectorAdd(pPath[i], start, pPath[i]); + + // could do this all with vectors + // vGrav = {0, 0, -800.0f} + // VectorScale(vGrav, 0.5f*ltime*ltime, vAdd); + // VectorScale(speed, ltime, pPath[i]); + // _VectorAdd(pPath[i], start, pPath[i]) + // _VectorAdd(pPath[i], vAdd, pPath[i]) + + pPath[i][2] = start[2] + (speed_z*ltime) + (varGravity*0.5f*ltime*ltime); + } + + SetPath(pPath); + return TRUE; +} + +void DBobView::Begin(const char* trigger, const char *target, float multiplier, int points, float varGravity, bool bNoUpdate, bool bShowExtra) +{ + strcpy(entTrigger, trigger); + strcpy(entTarget, target); + + fMultiplier = multiplier; + fVarGravity = varGravity; + nPathCount = points; + m_bShowExtra = bShowExtra; + + Register(); + + if(UpdatePath()) + { + if(!bNoUpdate) + { + eyes = new DListener; + eyes->parent = this; + eyes->Register(); + } + } + else + { + Sys_ERROR("Initialization Failure in DBobView::Begin"); + delete this; + } +} + +bool DBobView::UpdatePath() +{ + vec3_t start, apex; + + if(GetEntityCentre(entTrigger, start)) + { + if(GetEntityCentre(entTarget, apex)) + { + CalculateTrajectory(start, apex, fMultiplier, nPathCount, fVarGravity); + return TRUE; + } + } + return FALSE; +} diff --git a/contrib/bobtoolz/DBobView.h b/contrib/bobtoolz/DBobView.h new file mode 100644 index 00000000..4259c97a --- /dev/null +++ b/contrib/bobtoolz/DBobView.h @@ -0,0 +1,72 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBobView.h: interface for the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +class DListener; + +#define BOUNDS_ALL 0 +#define BOUNDS_APEX 1 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DBobView : + public IGL2DWindow, + public IGL3DWindow +{ +public: + DBobView(); + virtual ~DBobView(); + +protected: + vec3_t* path; + int refCount; +public: + bool m_bShowExtra; + int boundingShow; + DListener* eyes; + float fVarGravity; + + bool UpdatePath(); + char entTarget[256]; + char entTrigger[256]; + void Begin(const char*, const char*, float, int, float, bool, bool); + bool CalculateTrajectory(vec3_t, vec3_t, float, int, float); + + void SetPath(vec3_t* pPath); + void UnRegister(); + void Register(); + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + float fMultiplier; + bool m_bHooked; + int nPathCount; +}; + +#endif // !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DBrush.cpp b/contrib/bobtoolz/DBrush.cpp new file mode 100644 index 00000000..e571a50a --- /dev/null +++ b/contrib/bobtoolz/DBrush.cpp @@ -0,0 +1,848 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBrush.cpp: implementation of the DBrush class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "DBrush.h" +#include "DWinding.h" +#include "dialogs-gtk.h" + +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DBrush::DBrush(int ID) +{ + m_nBrushID = ID; + bBoundsBuilt = FALSE; + QER_brush = NULL; +} + +DBrush::~DBrush() +{ + ClearFaces(); + ClearPoints(); +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData) +{ +#ifdef _DEBUG +// Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]); +#endif + bBoundsBuilt = FALSE; + DPlane* newFace = new DPlane(va, vb, vc, texData); + faceList.push_back(newFace); + + return newFace; +} + +int DBrush::BuildPoints() +{ + ClearPoints(); + + if(faceList.size() <= 3) // if less than 3 faces, there can be no points + return 0; // with only 3 faces u can't have a bounded soild + + for(list::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++) + { + list::const_iterator p2=p1; + for(p2++; p2!=faceList.end(); p2++) + { + list::const_iterator p3=p2; + for(p3++; p3!=faceList.end(); p3++) + { + vec3_t pnt; + if((*p1)->PlaneIntersection(*p2, *p3, pnt)) + { + int pos = PointPosition(pnt); + + if(pos == POINT_IN_BRUSH) + { // ???? shouldn't happen here + Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n"); + } + else if(pos == POINT_ON_BRUSH) + { // normal point + if(!HasPoint(pnt)) + AddPoint(pnt); +/* else + Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/ + // point lies on more that 3 planes + } + + // otherwise point is removed due to another plane.. + + // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]); + } + } + } + } + +#ifdef _DEBUG +// Sys_Printf("%i points on brush\n", pointList.size()); +#endif + + return pointList.size(); +} + +void DBrush::LoadFromBrush_t(brush_t* brush, bool textured) +{ + ClearFaces(); + ClearPoints(); + + for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--) + { // running backwards so i dont have to use the count function each time (OPT) + _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i); + + if(faceData == NULL) + DoMessageBox("Null pointer returned", "WARNING!", MB_OK); + + if(textured) + AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData); + else + AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL); + } + + QER_brush = brush; +} + +int DBrush::PointPosition(vec3_t pnt) +{ + int state = POINT_IN_BRUSH; // if nothing happens point is inside brush + + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + float dist = (*chkPlane)->DistanceToPoint(pnt); + + if(dist > MAX_ROUND_ERROR) + return POINT_OUT_BRUSH; // if point is in front of plane, it CANT be in the brush + else if(fabs(dist) < MAX_ROUND_ERROR) + state = POINT_ON_BRUSH; // if point is ON plane point is either ON the brush + // or outside it, it can no longer be in it + } + + return state; +} + +void DBrush::ClearPoints() +{ + for(list::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) { + delete *deadPoint; + } + pointList.clear(); +} + +void DBrush::ClearFaces() +{ + bBoundsBuilt = FALSE; + for(list::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++) + { + delete *deadPlane; + } + faceList.clear(); +} + +void DBrush::AddPoint(vec3_t pnt) +{ + DPoint* newPoint = new DPoint; + VectorCopy(pnt, newPoint->_pnt); + pointList.push_back(newPoint); +} + +bool DBrush::HasPoint(vec3_t pnt) +{ + for(list::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++) + { + if(**chkPoint == pnt) + return TRUE; + } + + return FALSE; +} + +int DBrush::RemoveRedundantPlanes() +{ + int cnt = 0; + list::iterator chkPlane; + + // find duplicate planes + list::iterator p1=faceList.begin(); + + while( p1!=faceList.end() ) + { + list::iterator p2 = p1; + + for(p2++; p2!=faceList.end(); p2++) + { + if(**p1 == **p2) + { + if(!strcmp((*p1)->texInfo.m_TextureName, "textures/common/caulk")) + { + delete *p1; + p1 = faceList.erase(p1); // duplicate plane + } + else + { + delete *p2; + p2 = faceList.erase(p2); // duplicate plane + } + + cnt++; + break; + } + } + + if( p2 == faceList.end() ) + p1++; + } + + //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush + chkPlane=faceList.begin(); + while( chkPlane!=faceList.end() ) + { + if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal + { + delete *chkPlane; + chkPlane = faceList.erase(chkPlane); + cnt++; + } else { + chkPlane++; + } + } + //-djbob + + if(pointList.size() == 0) // if points may not have been built, build them +/* if(BuildPoints() == 0) // just let the planes die if they are all bad + return cnt;*/ + BuildPoints(); + + chkPlane=faceList.begin(); + while(chkPlane != faceList.end()) + { + if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points + { + delete *chkPlane; + chkPlane = faceList.erase(chkPlane); + cnt++; + } + else + chkPlane++; + } + + return cnt; +} + +bool DBrush::GetBounds(vec3_t min, vec3_t max) +{ + BuildBounds(); + + if(!bBoundsBuilt) + return FALSE; + + VectorCopy(bbox_min, min); + VectorCopy(bbox_max, max); + + return TRUE; +} + +bool DBrush::BBoxCollision(DBrush* chkBrush) +{ + vec3_t min1, min2; + vec3_t max1, max2; + + GetBounds(min1, max1); + chkBrush->GetBounds(min2, max2); + + if(min1[0] >= max2[0]) + return FALSE; + if(min1[1] >= max2[1]) + return FALSE; + if(min1[2] >= max2[2]) + return FALSE; + + if(max1[0] <= min2[0]) + return FALSE; + if(max1[1] <= min2[1]) + return FALSE; + if(max1[2] <= min2[2]) + return FALSE; + + return TRUE; +} + +DPlane* DBrush::HasPlane(DPlane* chkPlane) +{ + for(list::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++) + { + if(**brushPlane == *chkPlane) + return *brushPlane; + } + return NULL; +} + +bool DBrush::IsCutByPlane(DPlane *cuttingPlane) +{ + bool isInFront; + + if(pointList.size() == 0) + if(BuildPoints() == 0) + return FALSE; + + list::const_iterator chkPnt = pointList.begin(); + + if(chkPnt == pointList.end()) + return FALSE; + + float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt); + + if(dist > MAX_ROUND_ERROR) + isInFront = FALSE; + else if(dist < MAX_ROUND_ERROR) + isInFront = TRUE; + else + return TRUE; + + for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++) + { + dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt); + + if(dist > MAX_ROUND_ERROR) + { + if(isInFront) + return TRUE; + } + else if(dist < MAX_ROUND_ERROR) + { + if(!isInFront) + return TRUE; + } + else + return TRUE; + } + + return FALSE; +} + +brush_t* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity) +{ + if(allowDestruction) + { + bool kill = TRUE; + + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if((*chkPlane)->m_bChkOk) + { + kill = FALSE; + break; + } + } + if(kill) + return NULL; + } + + //+djbob: fixed bug when brush had no faces "phantom brush" in radiant. + if(faceList.size() < 4) + { + Sys_Printf("Possible Phantom Brush Found, will not rebuild\n"); + return NULL; + } + //-djbob + + QER_brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + for(list::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) { + if((*buildPlane)->AddToBrush_t(QER_brush) && changeCnt) { + (*changeCnt)++; + } + } + + if(entity) { + g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity); + g_BrushTable.m_pfnBrush_Build(QER_brush); + g_BrushTable.m_pfnBrush_AddToList(QER_brush, g_AppDataTable.m_pfnSelectedBrushes()); + } else { + g_FuncTable.m_pfnCommitBrushHandle(QER_brush); + } + + return QER_brush; +} + +void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2) +{ + if(!IsCutByPlane(cutPlane)) + { + *newBrush1 = NULL; + *newBrush2 = NULL; + return; + } + + DBrush* b1 = new DBrush; + DBrush* b2 = new DBrush; + + for(list::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++) + { + b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL); + b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL); + } + + b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL); + b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL); + + b1->RemoveRedundantPlanes(); + b2->RemoveRedundantPlanes(); + + *newBrush1 = b1; + *newBrush2 = b2; +} + +bool DBrush::IntersectsWith(DBrush *chkBrush) +{ + if(pointList.size() == 0) + if(BuildPoints() == 0) + return FALSE; // invalid brush!!!! + + if(chkBrush->pointList.size() == 0) + if(chkBrush->BuildPoints() == 0) + return FALSE; // invalid brush!!!! + + if(!BBoxCollision(chkBrush)) + return FALSE; + + list::const_iterator iplPlane; + + for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++) + { + + bool allInFront = TRUE; + for(list::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++) + { + if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR) + { + allInFront = FALSE; + break; + } + } + if(allInFront) + return FALSE; + } + + for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++) + { + bool allInFront = TRUE; + for(list::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++) + { + if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR) + { + allInFront = FALSE; + break; + } + } + if(allInFront) + return FALSE; + } + + return TRUE; +} + +bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) { + vec3_t vDown = { 0, 0, -1 }; + + list::const_iterator iplPlane; + for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) { + DPlane* p = (*iplPlane); + + vec_t d = DotProduct( p->normal, vDown ); + if( d >= 0 ) { + continue; + } + if(p->PlaneIntersection(p1, p2, v)) { + if(PointPosition( v ) != POINT_OUT_BRUSH) { + return TRUE; + } + } + } + + return FALSE; +} + +void DBrush::BuildBounds() +{ + if(!bBoundsBuilt) + { + if(pointList.size() == 0) // if points may not have been built, build them + if(BuildPoints() == 0) + return; + + list::const_iterator first = pointList.begin(); + VectorCopy((*first)->_pnt, bbox_min); + VectorCopy((*first)->_pnt, bbox_max); + + list::const_iterator point=pointList.begin(); + for( point++; point!=pointList.end(); point++) + { + if((*point)->_pnt[0] > bbox_max[0]) + bbox_max[0] = (*point)->_pnt[0]; + if((*point)->_pnt[1] > bbox_max[1]) + bbox_max[1] = (*point)->_pnt[1]; + if((*point)->_pnt[2] > bbox_max[2]) + bbox_max[2] = (*point)->_pnt[2]; + + if((*point)->_pnt[0] < bbox_min[0]) + bbox_min[0] = (*point)->_pnt[0]; + if((*point)->_pnt[1] < bbox_min[1]) + bbox_min[1] = (*point)->_pnt[1]; + if((*point)->_pnt[2] < bbox_min[2]) + bbox_min[2] = (*point)->_pnt[2]; + } + + bBoundsBuilt = TRUE; + } +} + +bool DBrush::BBoxTouch(DBrush *chkBrush) +{ + vec3_t min1, min2; + vec3_t max1, max2; + + GetBounds(min1, max1); + chkBrush->GetBounds(min2, max2); + + if((min1[0] - max2[0]) > MAX_ROUND_ERROR) + return FALSE; + if((min1[1] - max2[1]) > MAX_ROUND_ERROR) + return FALSE; + if((min1[2] - max2[2]) > MAX_ROUND_ERROR) + return FALSE; + + if((min2[0] - max1[0]) > MAX_ROUND_ERROR) + return FALSE; + if((min2[1] - max1[1]) > MAX_ROUND_ERROR) + return FALSE; + if((min2[2] - max1[2]) > MAX_ROUND_ERROR) + return FALSE; + + int cnt = 0; + + if((min2[0] - max1[0]) == 0) + cnt++; + + if((min2[1] - max1[1]) == 0) + cnt++; + + if((min2[2] - max1[2]) == 0) + cnt++; + + if((min1[0] - max2[0]) == 0) + cnt++; + + if((min1[1] - max2[1]) == 0) + cnt++; + + if((min1[2] - max2[2]) == 0) + cnt++; + + if(cnt > 1) + return FALSE; + + return TRUE; +} + +void DBrush::ResetChecks(list* exclusionList) +{ + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + bool set = FALSE; + + if(exclusionList) + { + for(list::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++) + { + if(strstr((*resetPlane)->texInfo.m_TextureName, eTexture->GetBuffer())) + { + set = TRUE; + break; + } + } + } + + (*resetPlane)->m_bChkOk = set; + } +} + +DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane) +{ + for(list::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++) + { + if(**brushPlane != *chkPlane) + { + if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1) + return (*brushPlane); + } + } + return NULL; +} + +bool DBrush::HasTexture(const char *textureName) +{ + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if(strstr((*chkPlane)->texInfo.m_TextureName, textureName)) + return TRUE; + + } + return FALSE; +} + +bool DBrush::IsDetail() +{ + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if((*chkPlane)->texInfo.m_nContents & FACE_DETAIL) + return TRUE; + + } + return FALSE; +} + +void DBrush::BuildFromWinding(DWinding *w) +{ + if(w->numpoints < 3) + { + Sys_ERROR("Winding has invalid number of points"); + return; + } + + DPlane* wPlane = w->WindingPlane(); + + DWinding* w2; + w2 = w->CopyWinding(); + int i; + for(i = 0; i < w2->numpoints; i++) + VectorAdd(w2->p[i], wPlane->normal, w2->p[i]); + + AddFace(w2->p[0], w2->p[1], w2->p[2], NULL); + AddFace(w->p[2], w->p[1], w->p[0], NULL); + + for(i = 0; i < w->numpoints-1; i++) + AddFace(w2->p[i], w->p[i], w->p[i+1], NULL); + AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL); + + delete wPlane; + delete w2; +} + +void DBrush::SaveToFile(FILE *pFile) +{ + fprintf(pFile, "{\n"); + + for(list::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++) + { + char buffer[512]; + + sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n", + (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2], + (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2], + (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2], + (*pp)->texInfo.m_TextureName, + (*pp)->texInfo.m_fShift[0], (*pp)->texInfo.m_fShift[1], + (*pp)->texInfo.m_fScale[0], (*pp)->texInfo.m_fScale[0], + (*pp)->texInfo.m_fRotate); + + fprintf(pFile, buffer); + } + + fprintf(pFile, "}\n"); +} + +void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation) +{ + for(list::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++) + { + for(int i = 0; i < 3; i++) + VectorRotate((*rotPlane)->points[i], vRotation, vOrigin); + + (*rotPlane)->Rebuild(); + } +} + +void DBrush::RotateAboutCentre(vec3_t vRotation) +{ + vec3_t min, max, centre; + GetBounds(min, max); + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + Rotate(centre, vRotation); +} + +bool DBrush::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, + int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation) +{ + if(textureName) + { + bool changed = FALSE; + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + if(!strcmp((*resetPlane)->texInfo.m_TextureName, textureName)) + { + if(bResetTextureName) + strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName); + + if(bResetScale[0]) + (*resetPlane)->texInfo.m_fScale[0] = fScale[0]; + if(bResetScale[1]) + (*resetPlane)->texInfo.m_fScale[1] = fScale[1]; + + if(bResetShift[0]) + (*resetPlane)->texInfo.m_fShift[0] = fShift[0]; + if(bResetShift[1]) + (*resetPlane)->texInfo.m_fShift[1] = fShift[1]; + + if(bResetRotation) + (*resetPlane)->texInfo.m_fRotate = (float)rotation; + + changed = TRUE; + } + } + return changed; // no point rebuilding unless we need to, only slows things down + } + else + { + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + if(bResetTextureName) + strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName); + + if(bResetScale[0]) + (*resetPlane)->texInfo.m_fScale[0] = fScale[0]; + if(bResetScale[1]) + (*resetPlane)->texInfo.m_fScale[1] = fScale[1]; + + if(bResetShift[0]) + (*resetPlane)->texInfo.m_fShift[0] = fShift[0]; + if(bResetShift[1]) + (*resetPlane)->texInfo.m_fShift[1] = fShift[1]; + + if(bResetRotation) + (*resetPlane)->texInfo.m_fRotate = (float)rotation; + } + return TRUE; + } +} + +bool DBrush::operator ==(DBrush* other) +{ + list::const_iterator chkPlane; + + for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if(!other->HasPlane((*chkPlane))) + return FALSE; + } + + for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if(!HasPlane((*chkPlane))) + return FALSE; + } + + return TRUE; +} + +DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail) +{ + bBoundsBuilt = FALSE; + DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail); + faceList.push_back(newFace); + + return newFace; +} + +DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) { + vec_t bestDot = -2; + DPlane* bestDotPlane = NULL; + list::const_iterator chkPlane; + for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) { + DPlane* pPlane = (*chkPlane); + + vec_t dot = DotProduct( pPlane->normal, normal ); + if( dot > bestDot ) { + bestDot = dot; + bestDotPlane = pPlane; + } + } + + return bestDotPlane; +} + +int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) { + int numpnts = 0; + + if(!maxpnts) { + return 0; + } + + BuildPoints(); + + for( list::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) { + DPoint* point = (*points); + + if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) { + pnts[numpnts] = point; + numpnts++; + + if(numpnts >= maxpnts) { + return numpnts; + } + + } + } + + return numpnts; +} + +void DBrush::RemovePlane( DPlane* plane ) { + bBoundsBuilt = FALSE; + for( list::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) { + if(*deadPlane == plane) { + delete *deadPlane; + faceList.remove( plane ); + } + } +} + +void DBrush::RemoveFromRadiant( void ) { + if(QER_brush) { + g_FuncTable.m_pfnDeleteBrushHandle(QER_brush); + } +} diff --git a/contrib/bobtoolz/DBrush.h b/contrib/bobtoolz/DBrush.h new file mode 100644 index 00000000..7f2485cd --- /dev/null +++ b/contrib/bobtoolz/DBrush.h @@ -0,0 +1,101 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBrush.h: interface for the DBrush class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DPlane.h" + +#define POINT_IN_BRUSH 0 +#define POINT_ON_BRUSH 1 +#define POINT_OUT_BRUSH 2 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DBrush +{ +public: + DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); + void SaveToFile(FILE* pFile); + + void Rotate(vec3_t vOrigin, vec3_t vRotation); + void RotateAboutCentre(vec3_t vRotation); + + DPlane* HasPlaneInverted(DPlane* chkPlane); + DPlane* HasPlane(DPlane* chkPlane); + DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); + + bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); + bool IsDetail(); + bool HasTexture(const char* textureName); + bool IntersectsWith(DBrush *chkBrush); + bool IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v); + bool IsCutByPlane(DPlane* cuttingPlane); + bool GetBounds(vec3_t min, vec3_t max); + bool HasPoint(vec3_t pnt); + bool BBoxCollision(DBrush* chkBrush); + bool BBoxTouch(DBrush* chkBrush); + + int BuildPoints(); + void BuildBounds(); + void BuildFromWinding(DWinding* w); + brush_t* BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity = NULL); + + void ResetChecks(list* exclusionList); + + void ClearFaces(); + void ClearPoints(); + + int RemoveRedundantPlanes( void ); + void RemovePlane( DPlane* plane ); + int PointPosition(vec3_t pnt); + void RemoveFromRadiant( void ); + + + void CutByPlane(DPlane* cutPlane, DBrush** newBrush1, DBrush** newBrush2); + + void LoadFromBrush_t(brush_t* brush, bool textured); + void AddPoint(vec3_t pnt); + + DPlane* FindPlaneWithClosestNormal( vec_t* normal ); + int FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ); + + DBrush(int ID = -1); + virtual ~DBrush(); + + bool operator== (DBrush* other); + +// members + brush_t* QER_brush; + list faceList; + list pointList; + int m_nBrushID; + vec3_t bbox_min, bbox_max; + bool bBoundsBuilt; +}; + +//typedef CList DBrushList; + +#endif // !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEPair.cpp b/contrib/bobtoolz/DEPair.cpp new file mode 100644 index 00000000..b52ad5cb --- /dev/null +++ b/contrib/bobtoolz/DEPair.cpp @@ -0,0 +1,49 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEPair.cpp: implementation of the DEPair class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DEPair.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DEPair::DEPair() +{ + +} + +DEPair::~DEPair() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DEPair::Build(char *pKey, char *pValue) +{ + key = pKey; + value = pValue; +} diff --git a/contrib/bobtoolz/DEPair.h b/contrib/bobtoolz/DEPair.h new file mode 100644 index 00000000..e5438af4 --- /dev/null +++ b/contrib/bobtoolz/DEPair.h @@ -0,0 +1,45 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEPair.h: interface for the DEPair class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DEPair +{ +public: + DEPair(); + virtual ~DEPair(); + + void Build(char* pKey, char* pValue); + + Str key; + Str value; +}; + +//typedef CList DEPairList; + +#endif // !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEntity.cpp b/contrib/bobtoolz/DEntity.cpp new file mode 100644 index 00000000..2c4e8a2f --- /dev/null +++ b/contrib/bobtoolz/DEntity.cpp @@ -0,0 +1,675 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEntity.cpp: implementation of the DEntity class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "DEntity.h" + +#include "dialogs-gtk.h" +#include "misc.h" +#include "CPortals.h" + +const char* brushEntityList[] = { + "worldspawn", + "trigger_always", + "trigger_hurt", + "trigger_multiple", + "trigger_push", + "trigger_teleport", + "func_bobbing", + "func_button", + "func_door", + "func_group", + "func_pendulum", + "func_plat", + "func_rotating", + "func_static", + "func_timer", + "func_train", + 0 +}; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DEntity::DEntity(char *classname, int ID) +{ + SetClassname(classname); + m_nID = ID; + QER_Entity = NULL; +} + +DEntity::~DEntity() +{ + ClearPatches(); + ClearBrushes(); + ClearEPairs(); +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DEntity::ClearBrushes() +{ + for(list::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++) + { + delete *deadBrush; + } + brushList.clear(); +} + +void DEntity::ClearPatches() +{ + for(list::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++) + { + delete *deadPatch; + } + patchList.clear(); +} + +DPatch* DEntity::NewPatch() +{ + DPatch* newPatch = new DPatch; + + patchList.push_back(newPatch); + + return newPatch; +} + +DBrush* DEntity::NewBrush(int ID) +{ + DBrush* newBrush = new DBrush(ID); + + brushList.push_back(newBrush); + + return newBrush; +} + +char* getNextBracket(char* s) +{ + char* p = s; + while(*p) + { + p++; + if(*p == '(') + break; + } + + return p; +} + +bool DEntity::LoadFromPrt(char *filename) +{ + CPortals portals; + strcpy(portals.fn, filename); + portals.Load(); + + if(portals.node_count == 0) + return FALSE; + + ClearBrushes(); + ClearEPairs(); + + bool build = false; + for(unsigned int i = 0; i < portals.node_count; i++) + { + build = false; + DBrush* brush = NewBrush(); + + for(unsigned int j = 0; j < portals.node[i].portal_count; j++) + { + for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++) + { + vec3_t v1, v2, normal, n; + VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1); + VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2); + CrossProduct(v1, v2, n); + VectorNormalize(n, v2); + + if(k == 0) + { + VectorCopy(v2, normal); + } + else + { + VectorSubtract(v2, normal, v1); + if(VectorLength(v1) > 0.01) + { + build = true; + break; + } + } + } + + if(!build) + brush->AddFace(portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[0].p, "textures/common/caulk", FALSE); + else + brush->AddFace(portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[2].p, "textures/common/caulk", FALSE); + } + if(build) + brush->BuildInRadiant(FALSE, NULL); + } + + return TRUE; +} + +DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID) +{ + DBrush* buildBrush = GetBrushForID(ID); + return buildBrush->AddFace(va, vb, vc, faceData); + // slow, dont use much +} + +DBrush* DEntity::GetBrushForID(int ID) +{ + DBrush* buildBrush = NULL; + + for(list::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++) + { + if((*chkBrush)->m_nBrushID == ID) + { + buildBrush = (*chkBrush); + break; + } + } + + if(!buildBrush) + buildBrush = NewBrush(ID); + + return buildBrush; +} + +void DEntity::LoadSelectedBrushes() +{ + ClearBrushes(); + ClearEPairs(); + + int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + for(int i = 0; i < count; i++) { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + if(brush->pPatch) + continue; + + DBrush* loadBrush = NewBrush(i); + loadBrush->LoadFromBrush_t(brush, TRUE); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DEntity::LoadSelectedPatches() +{ + ClearPatches(); + ClearEPairs(); + + int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles(); + + for(int i = 0; i < count; i++) + { + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i); + + DPatch* loadPatch = NewPatch(); + loadPatch->LoadFromBrush_t(pmesh->pSymbiot); + } + + g_FuncTable.m_pfnReleasePatchHandles(); +} + +bool* DEntity::BuildIntersectList() +{ + int max = GetIDMax(); + if(max == 0) + return NULL; + + bool* pbIntList = new bool[max]; + memset(pbIntList, 0, sizeof(bool)*(max)); + + for(list::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) + { + list::const_iterator pB2=pB1; + for(pB2++; pB2!=brushList.end(); pB2++) + { + if((*pB1)->IntersectsWith((*pB2))) + { + pbIntList[(*pB1)->m_nBrushID] = TRUE; + pbIntList[(*pB2)->m_nBrushID] = TRUE; + } + } + } + + return pbIntList; +} + +bool* DEntity::BuildDuplicateList() +{ + int max = GetIDMax(); + if(max == 0) + return NULL; + + bool* pbDupList = new bool[max]; + memset(pbDupList, 0, sizeof(bool)*(max)); + + for(list::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) + { + list::const_iterator pB2=pB1; + for(pB2++; pB2!=brushList.end(); pB2++) + { + if(**pB1 == *pB2) + { + pbDupList[(*pB1)->m_nBrushID] = TRUE; + pbDupList[(*pB2)->m_nBrushID] = TRUE; + } + } + } + + return pbDupList; +} + +void DEntity::SelectBrushes(bool *selectList) +{ + if(selectList == NULL) + return; + + g_FuncTable.m_pfnDeselectAllBrushes(); + + g_FuncTable.m_pfnAllocateActiveBrushHandles(); + + for(std::list::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++) + { + if(selectList[(*pBrush)->m_nBrushID]) + g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush); + } + g_FuncTable.m_pfnReleaseActiveBrushHandles(); +} + +bool DEntity::LoadFromEntity(int id, bool bLoadPatches) { + return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches); +} + +bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) { + ClearPatches(); + ClearBrushes(); + ClearEPairs(); + + QER_Entity = ent; + + epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity); + LoadEPairList(epl); + + bool keep = FALSE; + int i; + for(i = 0; brushEntityList[i]; i++) + { + if(!stricmp(brushEntityList[i], m_Classname)) + { + keep = TRUE; + break; + } + } + + if(!keep) + return FALSE; + + int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity); + + for(i = 0; i < count; i++) + { + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i); + + if(brush == NULL) { + DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK); + continue; + } + + if(brush->pPatch) + { + if(bLoadPatches) + { + DPatch* loadPatch = NewPatch(); + loadPatch->LoadFromBrush_t(brush); + } + } + else + { + DBrush* loadBrush = NewBrush(i); + loadBrush->LoadFromBrush_t(brush, TRUE); + } + } + + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + + return TRUE; +} + +void DEntity::RemoveNonCheckBrushes(list* exclusionList, bool useDetail) +{ + list::iterator chkBrush=brushList.begin(); + + while( chkBrush!=brushList.end() ) + { + if(!useDetail) + { + if((*chkBrush)->IsDetail()) + { + delete *chkBrush; + chkBrush = brushList.erase(chkBrush); + continue; + } + } + + list::iterator eTexture; + + for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ ) + { + if((*chkBrush)->HasTexture((*eTexture).GetBuffer())) + { + delete *chkBrush; + chkBrush = brushList.erase(chkBrush); + break; + } + } + + if( eTexture == exclusionList->end() ) + chkBrush++; + } +} + +void DEntity::ResetChecks(list* exclusionList) +{ + for(list::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++) + { + (*resetBrush)->ResetChecks(exclusionList); + } +} + +int DEntity::FixBrushes(bool rebuild) +{ + g_FuncTable.m_pfnAllocateActiveBrushHandles(); + + int cnt = 0; + + for(list::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++) + { + int count = (*fixBrush)->RemoveRedundantPlanes(); + if(count) + { + cnt += count; + if(rebuild) + { + g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush); + + (*fixBrush)->BuildInRadiant(FALSE, NULL); + } + } + } + + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + return cnt; +} + +void DEntity::BuildInRadiant(bool allowDestruction) +{ + bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false; + + if(makeEntity) + { + entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + + epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname); + + epair_t* pEp = pEpS; + + for(list::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++) + { + pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value); + } + + g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS); + + g_FuncTable.m_pfnCommitEntityHandleToMap(pE); + + for(list::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) + (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE); + + for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) + (*buildPatch)->BuildInRadiant(pE); + + QER_Entity = pE; + } + else + { + for(list::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) + (*buildBrush)->BuildInRadiant(allowDestruction, NULL); + + for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) + (*buildPatch)->BuildInRadiant(); + } +} + + + +int DEntity::GetIDMax( void ) { + int max = -1; + for(list::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) { + if((*cntBrush)->m_nBrushID > max) + max = (*cntBrush)->m_nBrushID; + } + return max+1; +} + +void DEntity::SetClassname( char *classname ) { + m_Classname = classname; +} + +void DEntity::SaveToFile(FILE *pFile) +{ + fprintf(pFile, "{\n"); + + fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname); + + for(list::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++) + { + fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value); + } + + for(list::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++) + { + (*bp)->SaveToFile(pFile); + } + + fprintf(pFile, "}\n"); +} + +void DEntity::ClearEPairs() +{ + for(list::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++) + { + delete (*deadEPair); + } + epairList.clear(); +} + +void DEntity::AddEPair(char *key, char *value) { + DEPair* newEPair; + newEPair = FindEPairByKey( key ); + if(!newEPair) { + newEPair = new DEPair; + newEPair->Build(key, value); + epairList.push_back(newEPair); + } else { + newEPair->Build(key, value); + } +} + +void DEntity::LoadEPairList(epair_t *epl) +{ + epair_t* ep = epl; + while(ep) + { + if(!strcmp(ep->key, "classname")) + SetClassname(ep->value); + else + AddEPair(ep->key, ep->value); + + ep = ep->next; + } +} + +bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, + int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild) +{ + g_FuncTable.m_pfnDeselectAllBrushes(); + + g_FuncTable.m_pfnAllocateActiveBrushHandles(); + + bool reset = FALSE; + + for(list::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++) + { + bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, + bResetTextureName, bResetScale, bResetShift, bResetRotation); + + if(tmp) + { + reset = TRUE; + + if(rebuild) + { + entity_t *pE = (*resetBrush)->QER_brush->owner; + g_FuncTable.m_pfnDeleteBrushHandle((*resetBrush)->QER_brush); + (*resetBrush)->BuildInRadiant(FALSE, NULL, pE->entityId == 0 ? NULL : pE); + + if( pE->entityId == 0 ? NULL : pE ) + { + } + } + } + } + + if(bResetTextureName) + { + for(list::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++) + { + bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName); + + if(tmp) + { + reset = TRUE; + + if(rebuild) + { + entity_t *pE = (*resetPatch)->QER_brush->owner; + g_FuncTable.m_pfnDeleteBrushHandle((*resetPatch)->QER_brush); + (*resetPatch)->BuildInRadiant(pE->entityId == 0 ? NULL : pE); + } + } + } + } + + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + return reset; +} + +DEPair* DEntity::FindEPairByKey(const char* keyname) +{ + for(list::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++) + { + char* c = (*ep)->key; + if(!strcmp(c, keyname)) + return *ep; + } + return NULL; +} + +void DEntity::RemoveFromRadiant() +{ + g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity ); + + QER_Entity = NULL; +} + +void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + *out = pEP->value; + } else { + *out = defaultstring; + } +} + +void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + *out = atoi(pEP->value); + } else { + *out = atoi(defaultstring); + } +} + +void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + *out = static_cast< float >( atof( pEP->value ) ); + } else { + *out = static_cast< float >( atof(defaultstring) ); + } +} + +void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]); + } else { + sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]); + } +} + +int DEntity::GetBrushCount( void ) { + return brushList.size(); +} + +DBrush* DEntity::FindBrushByPointer( brush_t* brush ) { + for(list::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) { + DBrush* pBrush = (*listBrush); + if(pBrush->QER_brush == brush) { + return pBrush; + } + } + return NULL; +} diff --git a/contrib/bobtoolz/DEntity.h b/contrib/bobtoolz/DEntity.h new file mode 100644 index 00000000..382e8a0f --- /dev/null +++ b/contrib/bobtoolz/DEntity.h @@ -0,0 +1,115 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEntity.h: interface for the DEntity class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DBrush.h" +#include "DEPair.h" +#include "DPatch.h" +#include "StdAfx.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DEntity +{ +public: + void RemoveFromRadiant(); + entity_t* QER_Entity; + int m_nID; + +// Constrcution/Destruction + DEntity(char* classname = "worldspawn", int ID = -1); // sets classname + virtual ~DEntity(); +// --------------------------------------------- + +// epair functions........ + void LoadEPairList(epair_t* epl); + void AddEPair(char* key, char* value); + void ClearEPairs(); + DEPair* FindEPairByKey(const char* keyname); +// --------------------------------------------- + +// random functions........ + bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild); + void SaveToFile(FILE* pFile); + void SetClassname(char* classname); + int GetIDMax(); + + void BuildInRadiant(bool allowDestruction); + void ResetChecks(list* exclusionList); + void RemoveNonCheckBrushes(list* exclusionList, bool useDetail); + + DPlane* AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID); // slow, try not to use much + int GetBrushCount( void ); + DBrush* FindBrushByPointer( brush_t* brush ); +// --------------------------------------------- + + +// bool list functions + void SelectBrushes(bool* selectList); + bool* BuildDuplicateList(); + bool* BuildIntersectList(); +// --------------------------------------------- + + +// brush operations + void ClearBrushes(); // clears brush list and frees memory for brushes + + DBrush* GetBrushForID(int ID); + DBrush* NewBrush(int ID = -1); +// --------------------------------------------- + +// patch operations + void ClearPatches(); + + DPatch* NewPatch(); +// --------------------------------------------- + +// vars + list epairList; + list brushList; + // new patches, wahey!!! + list patchList; + Str m_Classname; +// --------------------------------------------- + + + int FixBrushes(bool rebuild); + + bool LoadFromEntity(int id, bool bLoadPatches = FALSE); + bool LoadFromEntity(entity_t* ent, bool bLoadPatches = FALSE); + void LoadSelectedBrushes(); + void LoadSelectedPatches(); + + bool LoadFromPrt(char* filename); +// --------------------------------------------- + void SpawnString(const char* key, const char* defaultstring, const char** out); + void SpawnInt(const char* key, const char* defaultstring, int* out); + void SpawnFloat(const char* key, const char* defaultstring, float* out); + void SpawnVector(const char* key, const char* defaultstring, vec_t* out); +}; + +#endif // !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DListener.cpp b/contrib/bobtoolz/DListener.cpp new file mode 100644 index 00000000..4927fe6e --- /dev/null +++ b/contrib/bobtoolz/DListener.cpp @@ -0,0 +1,93 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DListener.cpp: implementation of the DListener class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DListener.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DListener::DListener() +{ + refCount = 1; + m_bHooked = FALSE; +} + +DListener::~DListener() +{ + UnRegister(); +} + +void DListener::Register() +{ + g_MessageTable.m_pfnHookWindow( this ); + m_bHooked = TRUE; +} + +void DListener::UnRegister() +{ + if(m_bHooked) + { + g_MessageTable.m_pfnUnHookWindow( this ); + m_bHooked = FALSE; + } +} + +bool DListener::OnMouseMove(guint32 nFlags, gdouble x, gdouble y) +{ + if(!parent->UpdatePath()) + delete parent; + + return FALSE; +} + +bool DListener::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} diff --git a/contrib/bobtoolz/DListener.h b/contrib/bobtoolz/DListener.h new file mode 100644 index 00000000..0ef20577 --- /dev/null +++ b/contrib/bobtoolz/DListener.h @@ -0,0 +1,62 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DListener.h: interface for the DListener class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "DBobView.h" + +class DListener : public IWindowListener +{ +public: + DBobView* parent; + + bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnKeyPressed(char *s) { return false; } + bool Paint() { return true; } + void Close() { } + + void UnRegister(); + void Register(); + DListener(); + virtual ~DListener(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + +private: + bool m_bHooked; + int refCount; +}; + +#endif // !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DMap.cpp b/contrib/bobtoolz/DMap.cpp new file mode 100644 index 00000000..e827690f --- /dev/null +++ b/contrib/bobtoolz/DMap.cpp @@ -0,0 +1,166 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DMap.cpp: implementation of the DMap class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DMap.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DMap::DMap() +{ + m_nNextEntity = 1; + AddEntity("worldspawn", 0); +} + +DMap::~DMap() +{ + ClearEntities(); +} + +DEntity* DMap::AddEntity(char *classname, int ID) +{ + DEntity* newEntity; + if(ID == -1) + newEntity = new DEntity(classname, m_nNextEntity++); + else + newEntity = new DEntity(classname, ID); + + entityList.push_back(newEntity); + + return newEntity; +} + +void DMap::ClearEntities() +{ + m_nNextEntity = 1; + + for(list::const_iterator deadEntity=entityList.begin(); deadEntity!=entityList.end(); deadEntity++) + delete *deadEntity; + + entityList.clear(); +} + +DEntity* DMap::GetEntityForID(int ID) +{ + DEntity* findEntity = NULL; + + for(list::const_iterator chkEntity=entityList.begin(); chkEntity!=entityList.end(); chkEntity++) + { + if((*chkEntity)->m_nID == ID) + { + findEntity = (*chkEntity); + break; + } + } + + if(!findEntity) + findEntity = AddEntity("worldspawn", ID); + + return findEntity; +} + + +DEntity* DMap::GetWorldSpawn() +{ + return GetEntityForID(0); +} + +void DMap::BuildInRadiant(bool bAllowDestruction) +{ + for(list::const_iterator buildEntity=entityList.begin(); buildEntity!=entityList.end(); buildEntity++) + (*buildEntity)->BuildInRadiant(bAllowDestruction); +} + +void DMap::LoadAll(bool bLoadPatches) +{ + ClearEntities(); + + g_FuncTable.m_pfnDeselectAllBrushes(); + + int count = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < count; i++) + { + DEntity* loadEntity; + + if(i == 0) + loadEntity = GetWorldSpawn(); + else + loadEntity = AddEntity("", m_nNextEntity++); + + if(!loadEntity->LoadFromEntity(i, bLoadPatches)) + { + delete loadEntity; + entityList.pop_back(); + } + } +} + +int DMap::FixBrushes(bool rebuild) +{ + int count = 0; + for(list::const_iterator fixEntity=entityList.begin(); fixEntity!=entityList.end(); fixEntity++) + { + int cnt; + + if(!stricmp("worldspawn", (*fixEntity)->m_Classname)) + cnt = (*fixEntity)->FixBrushes(rebuild); + else + { + cnt = (*fixEntity)->FixBrushes(FALSE); + + if(cnt && rebuild) + RebuildEntity(*fixEntity); + } + + count += cnt; + } + + return count; +} + +void DMap::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, + int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation) +{ + for(list::const_iterator texEntity=entityList.begin(); texEntity!=entityList.end(); texEntity++) + { + if(!stricmp("worldspawn", (*texEntity)->m_Classname)) + (*texEntity)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, + bResetTextureName, bResetScale, bResetShift, bResetRotation, TRUE); + else + { + if((*texEntity)->ResetTextures( textureName, fScale, fShift, rotation, newTextureName, + bResetTextureName, bResetScale, bResetShift, bResetRotation, FALSE)) + RebuildEntity(*texEntity); + } + } +} + +void DMap::RebuildEntity(DEntity *ent) +{ + ent->RemoveFromRadiant(); + ent->BuildInRadiant(FALSE); +} diff --git a/contrib/bobtoolz/DMap.h b/contrib/bobtoolz/DMap.h new file mode 100644 index 00000000..1f814c23 --- /dev/null +++ b/contrib/bobtoolz/DMap.h @@ -0,0 +1,56 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DMap.h: interface for the DMap class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) +#define AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_ + +#include "DEntity.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DMap +{ +public: + static void RebuildEntity(DEntity* ent); + + void ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); + void LoadAll(bool bLoadPatches = FALSE); + void BuildInRadiant(bool bAllowDestruction); + int m_nNextEntity; + DEntity* GetWorldSpawn(); + void ClearEntities(); + + DEntity* DMap::GetEntityForID(int ID); + DEntity* AddEntity(char* classname = "worldspawn", int ID = -1); + + list entityList; + + DMap(); + virtual ~DMap(); + + int FixBrushes(bool rebuild); +}; + +#endif // !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) diff --git a/contrib/bobtoolz/DPatch.cpp b/contrib/bobtoolz/DPatch.cpp new file mode 100644 index 00000000..161420f3 --- /dev/null +++ b/contrib/bobtoolz/DPatch.cpp @@ -0,0 +1,414 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPatch.cpp: implementation of the DPatch class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPatch.h" +#include "misc.h" +#include "./dialogs/dialogs-gtk.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +// Added patch merging, wahey! + +// +// problem is, you cant put patches into entities as yet :( +// + +DPatch::DPatch() +{ + width = MIN_PATCH_WIDTH; + height = MIN_PATCH_HEIGHT; + QER_patch = NULL; + QER_brush = NULL; +} + +DPatch::~DPatch() +{ + +} + +void DPatch::SetTexture(const char *textureName) +{ + strcpy(texture, textureName); +} + +void CopyDrawVert(const drawVert_t* in, drawVert_t* out) +{ + out->lightmap[0] = in->lightmap[0]; + out->lightmap[1] = in->lightmap[1]; + out->st[0] = in->st[0]; + out->st[1] = in->st[1]; + VectorCopy(in->normal, out->normal); + VectorCopy(in->xyz, out->xyz); +} + +void DPatch::BuildInRadiant(void* entity) +{ + int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); + + pm->height = height; + pm->width = width; + + for(int x = 0; x < width; x++) + for(int y = 0; y < height; y++) + CopyDrawVert(&points[x][y], &pm->ctrl[x][y]); + + QER_patch = pm; + +/* if(entity) + { +// strcpy(pm->d_texture->name, texture); + + brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + brush->patchBrush = TRUE; + brush->pPatch = pm; + + pm->pSymbiot = brush; + pm->bSelected = false; + pm->bOverlay = false; // bleh, f*cks up, just have to wait for a proper function + pm->bDirty = true; // or get my own patch out.... + pm->nListID = -1; + + g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity); + } + else*/ // patch to entity just plain dont work atm + + if(entity) + g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity); + else + g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture); + + QER_brush = pm->pSymbiot; +} + +void DPatch::LoadFromBrush_t(brush_t* brush) +{ + QER_brush = brush; + QER_patch = brush->pPatch; + + SetTexture(QER_patch->pShader->getName()); + + for(int x = 0; x < QER_patch->width; x++) + for(int y = 0; y < QER_patch->height; y++) + CopyDrawVert(&QER_patch->ctrl[x][y], &points[x][y]); + + width = QER_patch->width; + height = QER_patch->height; +} + +void DPatch::RemoveFromRadiant() +{ + if(QER_brush) + g_FuncTable.m_pfnDeleteBrushHandle(QER_brush); +} + +bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName) +{ + if( !oldTextureName || !strcmp(texture, oldTextureName)) + { + strcpy(texture, newTextureName); + return TRUE; + } + + return FALSE; +} + +void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], + int startX, int startY, int number, bool horizontal, bool inverse) +{ + int x = startX, y = startY, i, step; + + if(inverse) + step = -1; + else + step = 1; + + for(i = 0; i < number; i++) + { + VectorCopy(points[x][y].xyz, array[i]); + + if(horizontal) + x+=step; + else + y+=step; + } +} + +void Print1dArray(vec3_t* array, int size) +{ + for(int i = 0; i < size; i++) + Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]); + Sys_Printf("\n"); +} + +bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size) +{ + int i; + bool equal = true; + + for(i = 0; i < size; i++) + { + if(!VectorCompare(a1[i], a2[size-i-1])) + { + equal = false; + break; + } + } + return equal; +} + +patch_merge_t DPatch::IsMergable(DPatch *other) +{ + int i, j; + vec3_t p1Array[4][MAX_PATCH_HEIGHT]; + vec3_t p2Array[4][MAX_PATCH_HEIGHT]; + + int p1ArraySizes[4]; + int p2ArraySizes[4]; + + patch_merge_t merge_info; + + Build1dArray(p1Array[0], this->points, 0, 0, this->width, true, false); + Build1dArray(p1Array[1], this->points, this->width-1, 0, this->height, false, false); + Build1dArray(p1Array[2], this->points, this->width-1, this->height-1, this->width, true, true); + Build1dArray(p1Array[3], this->points, 0, this->height-1, this->height, false, true); + + Build1dArray(p2Array[0], other->points, 0, 0, other->width, true, false); + Build1dArray(p2Array[1], other->points, other->width-1, 0, other->height, false, false); + Build1dArray(p2Array[2], other->points, other->width-1, other->height-1, other->width, true, true); + Build1dArray(p2Array[3], other->points, 0, other->height-1, other->height, false, true); + + p1ArraySizes[0] = this->width; + p1ArraySizes[1] = this->height; + p1ArraySizes[2] = this->width; + p1ArraySizes[3] = this->height; + + p2ArraySizes[0] = other->width; + p2ArraySizes[1] = other->height; + p2ArraySizes[2] = other->width; + p2ArraySizes[3] = other->height; + + for(i = 0; i < 4; i++) + { + for(j = 0; j < 4; j++) + { + if(p1ArraySizes[i] == p2ArraySizes[j]) + { + if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i])) + { + merge_info.pos1 = i; + merge_info.pos2 = j; + merge_info.mergable = true; + return merge_info; + } + } + } + } + + merge_info.mergable = false; + return merge_info; +} + +DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2) +{ + while(merge_info.pos1 != 2) + { + p1->Transpose(); + merge_info.pos1--; + if(merge_info.pos1 < 0) + merge_info.pos1 += 4; + } + + while(merge_info.pos2 != 0) + { + p2->Transpose(); + merge_info.pos2--; + if(merge_info.pos2 < 0) + merge_info.pos2 += 3; + } + + int newHeight = p1->height + p2->height - 1; + if(newHeight > MAX_PATCH_HEIGHT) + return NULL; + + DPatch* newPatch = new DPatch(); + + newPatch->height = newHeight; + newPatch->width = p1->width; + newPatch->SetTexture(p1->texture); + + int y = 0; + int i; + for(i = 0; i < p1->height; i++, y++) + for(int x = 0; x < p1->width; x++) + memcpy(&newPatch->points[x][y], &p1->points[x][i], sizeof(drawVert_t)); + + for(i = 1; i < p2->height; i++, y++) + for(int x = 0; x < p2->width; x++) + memcpy(&newPatch->points[x][y], &p2->points[x][i], sizeof(drawVert_t)); + +// newPatch->Invert(); + + return newPatch; +} + +void DPatch::Invert() +{ + drawVert_t vertTemp; + int i, j; + + for(i = 0 ; i < width ; i++ ) + { + for(j = 0; j < height / 2; j++) + { + memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t)); + memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t)); + } + } +} + +void DPatch::Transpose() +{ + int i, j, w; + drawVert_t dv; + + if ( width > height ) + { + for ( i = 0 ; i < height ; i++ ) + { + for ( j = i + 1 ; j < width ; j++ ) + { + if ( j < height ) + { + // swap the value + memcpy(&dv, &points[j][i], sizeof(drawVert_t)); + memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); + } + } + } + } + else + { + for ( i = 0 ; i < width ; i++ ) + { + for ( j = i + 1 ; j < height ; j++ ) + { + if ( j < width ) + { + // swap the value + memcpy(&dv, &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); + memcpy(&points[j][i], &dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); + } + } + } + } + + w = width; + width = height; + height = w; + + Invert(); +} + +list DPatch::Split(bool rows, bool cols) +{ + list patchList; + int i; + int x, y; + + if(rows && height >= 5) + { + for(i = 0; i < (height-1)/2; i++) + { + DPatch p; + + p.width = width; + p.height = 3; + p.SetTexture(texture); + + for(y = 0; y < 3; y++) + { + for(x = 0; x < p.width; x++) + { + memcpy(&p.points[x][y], &points[x][(i*2)+y], sizeof(drawVert_t)); + } + } + patchList.push_back(p); + } + + if(cols && width >= 5) + { + list patchList2; + + for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) + { + list patchList3 = (*patches).Split(false, true); + + for(list::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++) + patchList2.push_front(*patches2); + } + + return patchList2; + } + } + else if(cols && width >= 5) + { + for(i = 0; i < (width-1)/2; i++) + { + DPatch p; + + p.height = height; + p.width = 3; + p.SetTexture(texture); + + for(x = 0; x < 3; x++) + { + for(y = 0; y < p.height; y++) + { + memcpy(&p.points[x][y], &points[(i*2)+x][y], sizeof(drawVert_t)); + } + } + + patchList.push_back(p); + } + } + + return patchList; +} diff --git a/contrib/bobtoolz/DPatch.h b/contrib/bobtoolz/DPatch.h new file mode 100644 index 00000000..d04121ea --- /dev/null +++ b/contrib/bobtoolz/DPatch.h @@ -0,0 +1,62 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPatch.h: interface for the DPatch class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) +#define AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_ + +#include "StdAfx.h" // Added by ClassView +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct +{ + bool mergable; + int pos1; + int pos2; +} patch_merge_t; + +class DPatch +{ +public: + list Split(bool rows, bool cols); + void Transpose(); + void Invert(); + DPatch* MergePatches(patch_merge_t merge_info, DPatch* p1, DPatch* p2); + patch_merge_t IsMergable(DPatch* other); + bool ResetTextures(const char *oldTextureName, const char *newTextureName); + void RemoveFromRadiant(void); + brush_t* QER_brush; + void LoadFromBrush_t(brush_t* brush); + patchMesh_t* QER_patch; + void BuildInRadiant(void* entity = NULL); + void SetTexture(const char* textureName); + char texture[256]; + int width, height; + drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + DPatch(); + virtual ~DPatch(); + +}; + +#endif // !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) diff --git a/contrib/bobtoolz/DPlane.cpp b/contrib/bobtoolz/DPlane.cpp new file mode 100644 index 00000000..2fe24ecf --- /dev/null +++ b/contrib/bobtoolz/DPlane.cpp @@ -0,0 +1,256 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPlane.cpp: implementation of the DPlane class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPlane.h" +#include "DWinding.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData) +{ + MakeNormal( va, vb, vc, normal ); + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); + + _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); + + VectorCopy(va, points[0]); + VectorCopy(vb, points[1]); + VectorCopy(vc, points[2]); + + m_bChkOk = TRUE; + + if(texData) + memcpy(&texInfo, texData, sizeof(_QERFaceData)); + else + FillDefaultTexture(&texInfo, points[0], points[1], points[2], "textures/common/caulk"); +} + +DPlane::~DPlane() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +vec_t DPlane::DistanceToPoint(vec3_t pnt) +{ + vec3_t tmp; + VectorSubtract(pnt, points[0], tmp); + return DotProduct(tmp, normal); +} + +bool DPlane::PlaneIntersection(DPlane *pl1, DPlane *pl2, vec3_t out) +{ + float a1, a2, a3; + float b1, b2, b3; + float c1, c2, c3; + + a1 = normal[0]; a2 = normal[1]; a3 = normal[2]; + b1 = pl1->normal[0]; b2 = pl1->normal[1]; b3 = pl1->normal[2]; + c1 = pl2->normal[0]; c2 = pl2->normal[1]; c3 = pl2->normal[2]; + + float d = Determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); + + if(d == 0) + return FALSE; + + float v1 = _d; + float v2 = pl1->_d; + float v3 = pl2->_d; + + float d1 = Determinant3x3(v1, a2, a3, v2, b2, b3, v3, c2, c3); + float d2 = Determinant3x3(a1, v1, a3, b1, v2, b3, c1, v3, c3); + float d3 = Determinant3x3(a1, a2, v1, b1, b2, v2, c1, c2, v3); + + out[0] = d1/d; + out[1] = d2/d; + out[2] = d3/d; + + return TRUE; +} + +bool DPlane::IsRedundant(list& pointList) +{ + int cnt = 0; + + //list::const_iterator point=pointList.begin(); + for(list::const_iterator point=pointList.begin(); point!=pointList.end(); point++) + { + if(fabs(DistanceToPoint((*point)->_pnt)) < MAX_ROUND_ERROR) + cnt++; + + if(cnt == 3) + return FALSE; + } + return TRUE; +} + +bool DPlane::operator == (DPlane& other) +{ + vec3_t chk; + VectorSubtract(other.normal, normal, chk); + if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) + return FALSE; + + if(fabs(other._d - _d) > MAX_ROUND_ERROR) + return FALSE; + + return TRUE; +} + +bool DPlane::operator != (DPlane& other) +{ + vec3_t chk; + VectorAdd(other.normal, normal, chk); + if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) + return FALSE; + + return TRUE; +} + +DWinding* DPlane::BaseWindingForPlane() +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + +// find the major axis + + max = -131072; + x = -1; + for (i=0 ; i<3; i++) + { + v = (float)fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Sys_Printf ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, _d, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 131072, vup); + VectorScale (vright, 131072, vright); + +// project a really big axis aligned box onto the plane + DWinding* w = new DWinding; + w->AllocWinding(4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + return w; +} + +void DPlane::Rebuild() +{ + vec3_t v1, v2; + VectorSubtract(points[0], points[1], v1); + VectorSubtract(points[2], points[1], v2); + CrossProduct(v1, v2, normal); + + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::Rebuild: Bad Normal.\n"); + + _d = (normal[0]*points[0][0]) + (normal[1]*points[0][1]) + (normal[2]*points[0][2]); + + VectorCopy(points[0], texInfo.m_v1); + VectorCopy(points[1], texInfo.m_v2); + VectorCopy(points[2], texInfo.m_v3); +} + +bool DPlane::AddToBrush_t(brush_t *brush) +{ + if(m_bChkOk || !strcmp(texInfo.m_TextureName, "textures/common/caulk")) + { + g_FuncTable.m_pfnAddFaceData(brush, &texInfo); + return FALSE; + } + + strcpy(texInfo.m_TextureName, "textures/common/caulk"); + g_FuncTable.m_pfnAddFaceData(brush, &texInfo); + return TRUE; +} + +void DPlane::ScaleTexture() +{ } + +DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail) +{ + vec3_t v1, v2; + VectorSubtract(va, vb, v1); + VectorSubtract(vc, vb, v2); + CrossProduct(v1, v2, normal); + + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); + + _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); + + VectorCopy(va, points[0]); + VectorCopy(vb, points[1]); + VectorCopy(vc, points[2]); + + m_bChkOk = TRUE; + + FillDefaultTexture(&texInfo, points[0], points[1], points[2], textureName); + if(bDetail) + texInfo.m_nContents |= FACE_DETAIL; +} diff --git a/contrib/bobtoolz/DPlane.h b/contrib/bobtoolz/DPlane.h new file mode 100644 index 00000000..4399b841 --- /dev/null +++ b/contrib/bobtoolz/DPlane.h @@ -0,0 +1,67 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPlane.h: interface for the DPlane class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DPoint.h" + +#define FACE_DETAIL 0x8000000 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DWinding; + +class DPlane +{ +public: + DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); + void ScaleTexture(); + DWinding* BaseWindingForPlane(); + + void Rebuild(); + + bool AddToBrush_t(brush_t *brush); + bool operator != (DPlane& other); + bool operator == (DPlane& other); + + bool IsRedundant(list& pointList); + bool PlaneIntersection(DPlane* pl1, DPlane* pl2, vec3_t out);; + + vec_t DistanceToPoint(vec3_t pnt); + + DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); + DPlane() { } + virtual ~DPlane(); + + bool m_bChkOk; + _QERFaceData texInfo; + vec3_t points[3]; // djbob:do we really need these any more? + vec3_t normal; + float _d; +}; + +//typedef CList DPlaneList; +#endif // !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DPoint.cpp b/contrib/bobtoolz/DPoint.cpp new file mode 100644 index 00000000..e99911fd --- /dev/null +++ b/contrib/bobtoolz/DPoint.cpp @@ -0,0 +1,52 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPoint.cpp: implementation of the DPoint class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPoint.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DPoint::DPoint() +{ + +} + +DPoint::~DPoint() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +bool DPoint::operator ==(vec3_t other) +{ + vec3_t test; + VectorSubtract(other, _pnt, test); + if(fabs(VectorLength(test)) > MAX_ROUND_ERROR) + return FALSE; + return TRUE; +} diff --git a/contrib/bobtoolz/DPoint.h b/contrib/bobtoolz/DPoint.h new file mode 100644 index 00000000..22ae70bc --- /dev/null +++ b/contrib/bobtoolz/DPoint.h @@ -0,0 +1,45 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPoint.h: interface for the DPoint class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DPoint +{ +public: + DPoint(); + virtual ~DPoint(); + + bool operator ==(vec3_t other); + + vec3_t _pnt; + unsigned char m_uData; +}; + +//typedef CList DPointList; + +#endif // !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DShape.cpp b/contrib/bobtoolz/DShape.cpp new file mode 100644 index 00000000..83e68659 --- /dev/null +++ b/contrib/bobtoolz/DShape.cpp @@ -0,0 +1,459 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DShape.cpp: implementation of the DShape class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DShape.h" + +//#include "dialogs-gtk.h" + +#include "misc.h" +#include "shapes.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +bool bFacesAll[6] = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}; + +DShape::DShape() +{ + m_nNextBrush = 0; +} + +DShape::~DShape() +{ + +} + +void DShape::BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) +{ + vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; + + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, vc[i]); + VectorCopy(origin, vd[i]); + + vc[i][2] = min[2]; + vd[i][2] = max[2]; + + vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vd[i][0] = vc[i][0]; + vd[i][1] = vc[i][1]; + } + + VectorCopy(vc[0], vc[nSides]); + VectorCopy(vd[0], vd[nSides]); + VectorCopy(vc[1], vc[nSides+1]); + VectorCopy(vd[1], vd[nSides+1]); + + //---------------------------------- + + DBrush* pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); + + for(i = 1; i <= nSides; i++) + pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); + + pB->AddFace(vc[2], vc[1], vc[0], "textures/common/caulk", FALSE); + pB->AddFace(vd[0], vd[1], vd[2], "textures/common/caulk", FALSE); +} + +void DShape::Commit() +{ + m_Container.GetWorldSpawn()->FixBrushes(FALSE); + m_Container.BuildInRadiant(TRUE); +} + +void DShape::BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) +{ + vec3_t va[MAX_POLYGON_FACES+1], vb[MAX_POLYGON_FACES+1]; + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, va[i]); + VectorCopy(origin, vb[i]); + + va[i][2] = min[2]; + vb[i][2] = max[2]; + + va[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + va[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vb[i][0] = va[i][0]; + vb[i][1] = va[i][1]; + } + + VectorCopy(va[0], va[nSides]); + VectorCopy(vb[0], vb[nSides]); + + //---------------------------------- + + for(i = 1; i <= nSides; i++) + { + DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); + + vec3_t top, bottom; + VectorCopy(va[i-1], top); + VectorCopy(va[i], bottom); + + if(va[i-1][1] > va[i][1]) + { + top[0] += 5; + bottom[0] += 5; + } + else // flip direction of plane on crossover + { + top[0] -= 5; + bottom[0] -= 5; + } + + if(top[1] != bottom[1]) // internal line is flat already if true + { + pB->AddFace(va[i-1], top, vb[i-1], "textures/common/caulk", FALSE); + pB->AddFace(va[i], vb[i], bottom, "textures/common/caulk", FALSE); + } // add cut-off planes + + pB->AddFace(va[i-1], vb[i-1], vb[i], GetCurrentTexture(), FALSE); + // add internal polygon plane + } +} + +void DShape::BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop) +{ + vec3_t va[MAX_POLYGON_FACES+2], vb[MAX_POLYGON_FACES+2]; + vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; + + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + if(nBorder >= Min(radius[0], radius[1])) + { +// DoMessageBox("Border is too large", "Error", MB_OK); + return; + } + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, va[i]); + VectorCopy(origin, vb[i]); + VectorCopy(origin, vc[i]); + VectorCopy(origin, vd[i]); + + va[i][2] = min[2]; + vb[i][2] = max[2]; + + va[i][0] += (radius[0] - nBorder) * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + va[i][1] += (radius[1] - nBorder) * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vb[i][0] = va[i][0]; + vb[i][1] = va[i][1]; + + + + vc[i][2] = min[2]; + vd[i][2] = max[2]; + + vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vd[i][0] = vc[i][0]; + vd[i][1] = vc[i][1]; + } + + VectorCopy(va[0], va[nSides]); + VectorCopy(vb[0], vb[nSides]); + VectorCopy(va[1], va[nSides+1]); + VectorCopy(vb[1], vb[nSides+1]); + + VectorCopy(vc[0], vc[nSides]); + VectorCopy(vd[0], vd[nSides]); + VectorCopy(vc[1], vc[nSides+1]); + VectorCopy(vd[1], vd[nSides+1]); + + //---------------------------------- + + for(i = 1; i <= nSides; i++) + { + DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); + + pB->AddFace(origin, vc[i-1], vd[i-1], "textures/common/caulk", FALSE); + pB->AddFace(origin, vd[i], vc[i], "textures/common/caulk", FALSE); + + pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); + pB->AddFace(vb[i], va[i], va[i-1], GetCurrentTexture(), FALSE); + } +} + +DBrush* DShape::GetBoundingCube_Ext(vec3_t min, vec3_t max, const char *textureName, bool* bUseFaces, bool detail) +{ + DBrush* pB = new DBrush; + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(bUseFaces[0]) + pB->AddFace(v1, v2, v3, textureName, detail); + if(bUseFaces[1]) + pB->AddFace(v1, v3, v6, textureName, detail); + if(bUseFaces[2]) + pB->AddFace(v1, v7, v2, textureName, detail); + + if(bUseFaces[3]) + pB->AddFace(v5, v6, v3, textureName, detail); + if(bUseFaces[4]) + pB->AddFace(v5, v2, v7, textureName, detail); + if(bUseFaces[5]) + pB->AddFace(v5, v7, v6, textureName, detail); + + //---------------------------------- + + return pB; +} + +DBrush* DShape::GetBoundingCube(vec3_t min, vec3_t max, const char *textureName, DEntity* ent, bool* bUseFaces) +{ + DBrush* pB; + if(ent == NULL) + pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); + else + pB = ent->NewBrush(m_nNextBrush++); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(bUseFaces[0]) + pB->AddFace(v1, v2, v3, textureName, FALSE); + if(bUseFaces[1]) + pB->AddFace(v1, v3, v6, textureName, FALSE); + if(bUseFaces[2]) + pB->AddFace(v1, v7, v2, textureName, FALSE); + + if(bUseFaces[3]) + pB->AddFace(v5, v6, v3, textureName, FALSE); + if(bUseFaces[4]) + pB->AddFace(v5, v2, v7, textureName, FALSE); + if(bUseFaces[5]) + pB->AddFace(v5, v7, v6, textureName, FALSE); + + //---------------------------------- + + return pB; +} + +bool DShape::BuildPit(vec3_t min, vec3_t max) +{ + if((max[2] - min[2]) < 196) + return FALSE; + + srand(time(NULL)); + + vec3_t centre; + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + char buffer[256]; + + int team = (rand()%10000)+5000; + +// ************* SPEAKER *************** + sprintf(buffer, "t%i_1", team); + +// trigger for speaker + vec3_t triggerVoiceBtm; + VectorCopy(min, triggerVoiceBtm); + triggerVoiceBtm[2] = max[2] - 16; + + DEntity* triggerVoice = m_Container.AddEntity("trigger_multiple"); + GetBoundingCube(triggerVoiceBtm, max, "textures/common/trigger", triggerVoice); + triggerVoice->AddEPair("target", buffer); +//-------------------- + +// target for speaker + vec3_t voiceOrigin; + VectorCopy(centre, voiceOrigin); + voiceOrigin[2] = max[2]+16; + + + DEntity* targetVoice = m_Container.AddEntity("target_speaker"); + targetVoice->AddEPair("targetname", buffer); + + sprintf(buffer, "%f %f %f", voiceOrigin[0], voiceOrigin[1], voiceOrigin[2]); + targetVoice->AddEPair("origin", buffer); + targetVoice->AddEPair("spawnflags", "8"); + targetVoice->AddEPair("noise", "*falling1.wav"); +//-------------------- + +// *********** END SPEAKER ************* + +// ********* POWERUP REMOVAL *********** + sprintf(buffer, "t%i_2", team); + +// trigger for powerup removal + vec3_t triggerPwrRmvTop, triggerPwrRmvBtm; + VectorCopy(min, triggerPwrRmvBtm); + VectorCopy(max, triggerPwrRmvTop); + + triggerPwrRmvTop[2] = triggerVoiceBtm[2] - 64; + triggerPwrRmvBtm[2] = triggerPwrRmvTop[2] - 16; + + DEntity* triggerPwrRmv = m_Container.AddEntity("trigger_multiple"); + GetBoundingCube(triggerPwrRmvBtm, triggerPwrRmvTop, "textures/common/trigger", triggerPwrRmv); + triggerPwrRmv->AddEPair("target", buffer); +//-------------------- + +// target for powerup removal + vec3_t pwrRmvOrigin; + VectorCopy(centre, pwrRmvOrigin); + pwrRmvOrigin[2] = triggerPwrRmvTop[2]+16; + + DEntity* targetPwrRmv = m_Container.AddEntity("target_remove_powerups"); + targetPwrRmv->AddEPair("targetname", buffer); + + sprintf(buffer, "%f %f %f", pwrRmvOrigin[0], pwrRmvOrigin[1], pwrRmvOrigin[2]); + targetPwrRmv->AddEPair("origin", buffer); +//-------------------- + +// ****** END POWERUP REMOVAL ******** + +// ********* DAMAGE *********** + +// trigger for damage + vec3_t triggerDmgTop, triggerDmgBtm; + VectorCopy(min, triggerDmgBtm); + VectorCopy(max, triggerDmgTop); + + triggerDmgBtm[2] = min[2] + 64; + triggerDmgTop[2] = triggerDmgBtm[2] + 16; + + DEntity* triggerDmg = m_Container.AddEntity("trigger_hurt"); + GetBoundingCube(triggerDmgBtm, triggerDmgTop, "textures/common/trigger", triggerDmg); + triggerDmg->AddEPair("dmg", "9999"); + triggerDmg->AddEPair("spawnflags", "12"); +//-------------------- + +// ****** END DAMAGE ******** + +// ********* NODROP *********** + + vec3_t nodropTop; + VectorCopy(max, nodropTop); + + nodropTop[2] = min[2] + 64; + + GetBoundingCube(min, nodropTop, "textures/common/nodrop"); + +// ****** END NODROP ******** + + return TRUE; +} diff --git a/contrib/bobtoolz/DShape.h b/contrib/bobtoolz/DShape.h new file mode 100644 index 00000000..9564943d --- /dev/null +++ b/contrib/bobtoolz/DShape.h @@ -0,0 +1,60 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DShape.h: interface for the DShape class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) +#define AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_ + +#include "DMap.h" // Added by ClassView +#include "StdAfx.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// defines for polygon stuff +#define MAX_POLYGON_FACES 128 + +extern bool bFacesAll[]; + +class DShape +{ +public: + bool BuildPit(vec3_t min, vec3_t max); + void BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop); + void BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); + void BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); + + int m_nNextBrush; + static DBrush* GetBoundingCube_Ext(vec3_t min, vec3_t max, const char* textureName, bool* bUseFaces = bFacesAll, bool detail = false); + + DShape(); + virtual ~DShape(); + + void Commit(); +private: + DBrush* GetBoundingCube(vec3_t min, vec3_t max, const char* textureName, DEntity* ent = NULL, bool* bUseFaces = bFacesAll); + + DMap m_Container; +}; + +#endif // !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) diff --git a/contrib/bobtoolz/DTrainDrawer.cpp b/contrib/bobtoolz/DTrainDrawer.cpp new file mode 100644 index 00000000..83ddc3ec --- /dev/null +++ b/contrib/bobtoolz/DTrainDrawer.cpp @@ -0,0 +1,358 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "DPoint.h" + +#include "DTrainDrawer.h" +#include "DEPair.h" + +#include "misc.h" +#include "funchandlers.h" + +#include "dialogs/dialogs-gtk.h" + +DTrainDrawer::DTrainDrawer() { + refCount = 1; + m_bHooked = FALSE; + m_bDisplay = FALSE; + + BuildPaths(); +} + +DTrainDrawer::~DTrainDrawer(void) { + if(m_bHooked) + UnRegister(); + + ClearPoints(); + ClearSplines(); +} + +void DTrainDrawer::ClearSplines() { + for(list::const_iterator deadSpline = m_splineList.begin(); deadSpline != m_splineList.end(); deadSpline++) { + (*deadSpline)->m_pointList.clear(); + (*deadSpline)->m_vertexList.clear(); + delete (*deadSpline); + } + + m_splineList.clear(); +} + +void DTrainDrawer::ClearPoints() { + for(list::const_iterator deadPoint = m_pointList.begin(); deadPoint != m_pointList.end(); deadPoint++) { + delete *deadPoint; + } + + m_pointList.clear(); +} + +void DTrainDrawer::Register() { + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DTrainDrawer::UnRegister() { + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void CalculateSpline_r(vec3_t* v, int count, vec3_t out, float tension) { + vec3_t dist; + + if(count < 2) { + return; + } + + if(count == 2) { + VectorSubtract( v[1], v[0], dist ); + VectorMA(v[0], tension, dist, out); + return; + } + + vec3_t* v2 = new vec3_t[count-1]; + + for( int i = 0; i < count-1; i++ ) { + VectorSubtract( v[i+1], v[i], dist ); + VectorMA(v[i], tension, dist, v2[i]); + } + + CalculateSpline_r( v2, count-1, out, tension); + + delete[] v2; +} + +void DTrainDrawer::Draw3D() { + + if(!m_bDisplay) { + return; + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + g_QglTable.m_pfn_qglLineWidth(2.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { + g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); + } + g_QglTable.m_pfn_qglEnd(); + + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DTrainDrawer::Draw2D(VIEWTYPE vt) { + + if(!m_bDisplay) { + return; + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 0.5f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + g_QglTable.m_pfn_qglColor4f(1.f, 0.f, 0.f, 1.f); + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { + g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); + } + g_QglTable.m_pfn_qglEnd(); + + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void AddSplineControl(const char* control, splinePoint_t* pSP) { + controlPoint_t cp; + strncpy(cp.strName, control, 64); + + pSP->m_pointList.push_front(cp); +} + +void DTrainDrawer::BuildPaths() { + int count = g_FuncTable.m_pfnGetEntityCount(); + + DEntity e; + + for(int i = 0; i < count; i++) { + entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); + e.ClearEPairs(); + e.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); + + const char* classname = e.m_Classname.GetBuffer(); + const char* target; + const char* control; + const char* targetname; + vec3_t vOrigin; + + e.SpawnString("targetname", NULL, &targetname); + e.SpawnVector("origin", "0 0 0", vOrigin); + + if(!strcmp(classname, "info_train_spline_main")) { + if(!targetname) { + Sys_Printf( "info_train_spline_main with no targetname" ); + return; + } + + e.SpawnString("target", NULL, &target); + + if(!target) { + AddControlPoint( targetname, vOrigin ); + } else { + splinePoint_t* pSP = AddSplinePoint( targetname, target, vOrigin ); + + e.SpawnString("control", NULL, &control); + + if(control) { + AddSplineControl( control, pSP ); + + for(int j = 2;; j++) { + char buffer[16]; + sprintf(buffer, "control%i", j); + + e.SpawnString(buffer, NULL, &control); + if(!control) { + break; + } + + AddSplineControl( control, pSP ); + } + } + } + } else if(!strcmp(classname, "info_train_spline_control")) { + if(!targetname) { + Sys_Printf( "info_train_spline_control with no targetname" ); + return; + } + + AddControlPoint( targetname, vOrigin ); + } + } + + list::const_iterator sp; + for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + controlPoint_t* pTarget = FindControlPoint( pSP->strTarget ); + + if(!pTarget) { + Sys_Printf( "couldn't find target %s", pSP->strTarget ); + return; +// continue; + } + + pSP->pTarget = pTarget; + + + for(list::iterator cp = pSP->m_pointList.begin(); cp != pSP->m_pointList.end(); cp++) { + controlPoint_t* pControl = FindControlPoint( (*cp).strName ); + if(!pControl) { + Sys_Printf( "couldn't find control %s", (*cp).strName ); + return; + } + + VectorCopy(pControl->vOrigin, (*cp).vOrigin); + } + } + + m_bDisplay = TRUE; + Register(); + + for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + DPoint out; + + if(!pSP->pTarget) { + continue; + } + + int count = pSP->m_pointList.size() + 2; + vec3_t* v = new vec3_t[count]; + + VectorCopy(pSP->point.vOrigin, v[0]); + + int i = 1; + for(list::reverse_iterator cp = pSP->m_pointList.rbegin(); cp != pSP->m_pointList.rend(); cp++) { + VectorCopy((*cp).vOrigin, v[i]); + i++; + } + VectorCopy(pSP->pTarget->vOrigin, v[i]); + + for (float tension = 0.0f; tension <= 1.f; tension += 0.01f) { + CalculateSpline_r(v, count, out._pnt, tension); + pSP->m_vertexList.push_front(out); + } + + delete[] v; + + VectorCopy(pSP->pTarget->vOrigin, out._pnt); + pSP->m_vertexList.push_front(out); + } + + +} + +void DTrainDrawer::AddControlPoint(const char* name, vec_t* origin) +{ + controlPoint_t* pCP = new controlPoint_t; + + strncpy(pCP->strName, name, 64); + VectorCopy( origin, pCP->vOrigin ); + + m_pointList.push_back( pCP ); +} + +splinePoint_t* DTrainDrawer::AddSplinePoint(const char* name, const char* target, vec_t* origin) +{ + splinePoint_t* pSP = new splinePoint_t; + + strncpy(pSP->point.strName, name, 64); + strncpy(pSP->strTarget, target, 64); + VectorCopy( origin, pSP->point.vOrigin ); + m_splineList.push_back( pSP ); + + return pSP; +} + +controlPoint_t* DTrainDrawer::FindControlPoint(const char* name) +{ + for(list::const_iterator cp = m_pointList.begin(); cp != m_pointList.end(); cp++) { + if(!strcmp(name, (*cp)->strName)) { + return (*cp); + } + } + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + if(!strcmp(name, (*sp)->point.strName)) { + return &((*sp)->point); + } + } + + return NULL; +} diff --git a/contrib/bobtoolz/DTrainDrawer.h b/contrib/bobtoolz/DTrainDrawer.h new file mode 100644 index 00000000..5f424068 --- /dev/null +++ b/contrib/bobtoolz/DTrainDrawer.h @@ -0,0 +1,82 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DTrainDrawer.h: interface for the DTrainDrawer class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DEntity.h" + +#if _MSC_VER > 1000 + +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct { + char strName[64]; + + vec3_t vOrigin; +} controlPoint_t; + +typedef struct { + controlPoint_t point; + + char strControl[64]; + char strTarget[64]; + + list m_pointList; + list m_vertexList; + + controlPoint_t* pTarget; +} splinePoint_t; + +class DTrainDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +private: + list m_splineList; + list m_pointList; + int refCount; + + bool m_bHooked; + bool m_bDisplay; +public: + void UnRegister(); + void Register(); + + DTrainDrawer(); + virtual ~DTrainDrawer(void); + + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void ClearSplines(); + void ClearPoints(); + void BuildPaths(); + void AddControlPoint(const char* name, vec_t* origin); + splinePoint_t* AddSplinePoint(const char* name, const char* target, vec_t* origin); + controlPoint_t* FindControlPoint(const char* name); +}; + +#endif // !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DTreePlanter.cpp b/contrib/bobtoolz/DTreePlanter.cpp new file mode 100644 index 00000000..8655b36a --- /dev/null +++ b/contrib/bobtoolz/DTreePlanter.cpp @@ -0,0 +1,287 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "DTreePlanter.h" +#include "funchandlers.h" + +bool DTreePlanter::OnMouseMove(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) { + VIEWTYPE vt = m_XYWrapper->GetViewType(); + + switch(vt) { + case XY: + break; + case YZ: + case XZ: + default: + return false; + } + + vec3_t pt, vhit; + + m_XYWrapper->SnapToGrid( static_cast< int >( x ), static_cast< int >( y ), pt ); + + if(FindDropPoint(pt, vhit)) { + vhit[2] += m_offset; + + char buffer[128]; + DEntity e(m_entType); + + sprintf(buffer, "%i %i %i", (int)vhit[0], (int)vhit[1], (int)vhit[2]); + e.AddEPair("origin", buffer); + + if(m_autoLink) { + entity_t* pLastEntity = NULL; + entity_t* pThisEntity = NULL; + + int entNum = -1, lastEntNum = -1, entpos; + for(int i = 0; i < 256; i++) { + sprintf(buffer, m_linkName, i); + pThisEntity = FindEntityFromTargetname( buffer, &entNum ); + + if(pThisEntity) { + entpos = i; + lastEntNum = entNum; + pLastEntity = pThisEntity; + } + } + + if(!pLastEntity) { + sprintf(buffer, m_linkName, 0); + } else { + sprintf(buffer, m_linkName, entpos + 1); + } + + e.AddEPair( "targetname", buffer ); + + if(pLastEntity) { + DEntity e2; + e2.LoadFromEntity(lastEntNum, TRUE); + e2.AddEPair("target", buffer); + e2.RemoveFromRadiant(); + e2.BuildInRadiant(FALSE); + } + } + + if(m_setAngles) { + int angleYaw = (rand() % (m_maxYaw - m_minYaw + 1)) + m_minYaw; + int anglePitch = (rand() % (m_maxPitch - m_minPitch + 1)) + m_minPitch; + + sprintf(buffer, "%i %i 0", anglePitch, angleYaw); + e.AddEPair("angles", buffer); + } + + if(m_numModels) { + int treetype = rand() % m_numModels; + e.AddEPair("model", m_trees[treetype].name); + } + + if(m_useScale) { + float scale = (((rand()%1000)*0.001f) * (m_maxScale - m_minScale)) + m_minScale; + + sprintf(buffer, "%f", scale ); + e.AddEPair("modelscale", buffer); + } + + e.BuildInRadiant( FALSE ); + } + + if(m_autoLink) { + DoTrainPathPlot(); + } + + return true; +} + +bool DTreePlanter::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::FindDropPoint(vec3_t in, vec3_t out) { + DPlane p1; + DPlane p2; + + vec3_t vUp = { 0, 0, 1 }; + vec3_t vForward = { 0, 1, 0 }; + vec3_t vLeft = { 1, 0, 0 }; + + in[2] = 65535; + + VectorCopy(in, p1.points[0]); + VectorCopy(in, p1.points[1]); + VectorCopy(in, p1.points[2]); + VectorMA(p1.points[1], 20, vUp, p1.points[1]); + VectorMA(p1.points[1], 20, vLeft, p1.points[2]); + + VectorCopy(in, p2.points[0]); + VectorCopy(in, p2.points[1]); + VectorCopy(in, p2.points[2]); + VectorMA(p1.points[1], 20, vUp, p2.points[1]); + VectorMA(p1.points[1], 20, vForward, p2.points[2]); + + p1.Rebuild(); + p2.Rebuild(); + + bool found = false; + vec3_t temp; + vec_t dist; + int cnt = m_world.GetIDMax(); + for(int i = 0; i < cnt; i++) { + DBrush* pBrush = m_world.GetBrushForID( i ); + + if(pBrush->IntersectsWith( &p1, &p2, temp )) { + vec3_t diff; + vec_t tempdist; + VectorSubtract(in, temp, diff); + tempdist = VectorLength( diff ); + if(!found || (tempdist < dist)) { + dist = tempdist; + VectorCopy( temp, out ); + found = true; + } + } + } + + return found; +} + +void DTreePlanter::DropEntsToGround( void ) { + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + DEntity ent; + + int cnt = g_FuncTable.m_pfnSelectedBrushCount(); + for(int i = 0; i < cnt; i++) { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + ent.LoadFromEntity(brush->owner, TRUE); + + DEPair* pEpair = ent.FindEPairByKey("origin"); + if(!pEpair) { + continue; + } + + vec3_t vec, out; + sscanf( pEpair->value.GetBuffer(), "%f %f %f", &vec[0], &vec[1], &vec[2]); + + FindDropPoint( vec, out ); + + char buffer[256]; + sprintf( buffer, "%f %f %f", out[0], out[1], out[2] ); + ent.AddEPair( "origin", buffer ); + ent.RemoveFromRadiant(); + ent.BuildInRadiant(FALSE); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DTreePlanter::MakeChain( void ) { + char buffer[256]; + int i; + + for(i = 0; i < m_linkNum; i++) { + DEntity e("info_train_spline_main"); + + sprintf( buffer, "%s_pt%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", i * 64 ); + e.AddEPair( "origin", buffer ); + + if(i != m_linkNum-1) { + sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); + e.AddEPair( "target", buffer ); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "control", buffer ); + } + + e.BuildInRadiant( FALSE ); + } + + for(i = 0; i < m_linkNum-1; i++) { + DEntity e("info_train_spline_control"); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", (i * 64) + 32); + e.AddEPair( "origin", buffer ); + + e.BuildInRadiant( FALSE ); + } +} + +void DTreePlanter::SelectChain( void ) { +/* char buffer[256]; + + for(int i = 0; i < m_linkNum; i++) { + DEntity e("info_train_spline_main"); + + sprintf( buffer, "%s_pt%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", i * 64 ); + e.AddEPair( "origin", buffer ); + + if(i != m_linkNum-1) { + sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); + e.AddEPair( "target", buffer ); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "control", buffer ); + } + + e.BuildInRadiant( FALSE ); + } + + for(int i = 0; i < m_linkNum-1; i++) { + DEntity e("info_train_spline_control"); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", (i * 64) + 32); + e.AddEPair( "origin", buffer ); + + e.BuildInRadiant( FALSE ); + }*/ +} diff --git a/contrib/bobtoolz/DTreePlanter.h b/contrib/bobtoolz/DTreePlanter.h new file mode 100644 index 00000000..ab80abff --- /dev/null +++ b/contrib/bobtoolz/DTreePlanter.h @@ -0,0 +1,223 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __DTREE_H__ +#define __DTREE_H__ + +#include "../include/igl.h" +#include "DEntity.h" +#include "misc.h" +#include "ScriptParser.h" + +#define MAX_QPATH 64 + +typedef struct treeModel_s { + char name[MAX_QPATH]; +} treeModel_t; + +#define MAX_TP_MODELS 256 + +class DTreePlanter : public IWindowListener { +public: + virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnKeyPressed(char *s) { return false; } + virtual bool Paint() { return true; } + virtual void Close() { } + + DTreePlanter() { + m_refCount = 1; + m_hooked = false; + m_XYWrapper = NULL; + m_numModels = 0; + m_offset = 0; + m_maxPitch = 0; + m_minPitch = 0; + m_maxYaw = 0; + m_minYaw = 0; + m_setAngles = false; + m_useScale = false; + m_autoLink = false; + m_linkNum = 0; + + Register(); + + m_world.LoadSelectedBrushes(); + + char buffer[256]; + GetFilename( buffer, "bt/tp_ent.txt" ); + + FILE* file = fopen( buffer, "rb" ); + if(file) { + fseek( file, 0, SEEK_END ); + int len = ftell( file ); + fseek( file, 0, SEEK_SET ); + + if(len) { + char* buf = new char[len+1]; + buf[len] = '\0'; + // parser will do the cleanup, dont delete. + + fread( buf, len, 1, file ); + + CScriptParser parser; + parser.SetScript( buf ); + + ReadConfig( &parser ); + } + + fclose( file ); + } + } + +#define MT(t) !stricmp( pToken, t ) +#define GT pToken = pScriptParser->GetToken( true ) +#define CT if(!*pToken) { return; } + + void ReadConfig( CScriptParser* pScriptParser ) { + const char* GT; + CT; + + do { + GT; + if(*pToken == '}') { + break; + } + + if(MT("model")) { + if(m_numModels >= MAX_TP_MODELS) { + return; + } + + GT; CT; + + strncpy( m_trees[m_numModels++].name, pToken, MAX_QPATH ); + } else if(MT("link")) { + GT; CT; + + strncpy( m_linkName, pToken, MAX_QPATH ); + + m_autoLink = true; + } else if(MT("entity")) { + GT; CT; + + strncpy( m_entType, pToken, MAX_QPATH ); + } else if(MT("offset")) { + GT; CT; + + m_offset = atoi(pToken); + } else if(MT("pitch")) { + GT; CT; + + m_minPitch = atoi(pToken); + + GT; CT; + + m_maxPitch = atoi(pToken); + + m_setAngles = true; + } else if(MT("yaw")) { + GT; CT; + + m_minYaw = atoi(pToken); + + GT; CT; + + m_maxYaw = atoi(pToken); + + m_setAngles = true; + } else if(MT("scale")) { + GT; CT; + + m_minScale = static_cast< float >( atof( pToken ) ); + + GT; CT; + + m_maxScale = static_cast< float >( atof( pToken ) ); + + m_useScale = true; + } else if(MT("numlinks")) { + GT; CT; + + m_linkNum = atoi( pToken ); + } + } while( true ); + } + + virtual ~DTreePlanter() { + UnRegister(); + } + + virtual void IncRef() { m_refCount++; } + virtual void DecRef() { m_refCount--; if (m_refCount <= 0) delete this; } + + void Register() { + if(!m_hooked) { + g_MessageTable.m_pfnHookWindow( this ); + m_XYWrapper = g_MessageTable.m_pfnGetXYWndWrapper(); + m_hooked = true; + } + } + + void UnRegister() { + if(m_hooked) { + g_MessageTable.m_pfnUnHookWindow( this ); + m_XYWrapper = NULL; + m_hooked = false; + } + } + + bool FindDropPoint(vec3_t in, vec3_t out); + void DropEntsToGround( void ); + void MakeChain( void ); + void SelectChain( void ); + +private: + IXYWndWrapper* m_XYWrapper; + DEntity m_world; + + treeModel_t m_trees[MAX_TP_MODELS]; + + int m_refCount; + int m_numModels; + int m_offset; + int m_maxPitch; + int m_minPitch; + int m_maxYaw; + int m_minYaw; + + char m_entType[MAX_QPATH]; + char m_linkName[MAX_QPATH]; + int m_linkNum; + + float m_minScale; + float m_maxScale; + + bool m_hooked; + bool m_useScale; + bool m_setAngles; + bool m_autoLink; +}; + +#endif diff --git a/contrib/bobtoolz/DVisDrawer.cpp b/contrib/bobtoolz/DVisDrawer.cpp new file mode 100644 index 00000000..b954268f --- /dev/null +++ b/contrib/bobtoolz/DVisDrawer.cpp @@ -0,0 +1,179 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// BobView.cpp: implementation of the DVisDrawer class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPoint.h" +#include "DVisDrawer.h" +#include "misc.h" +#include "funchandlers.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DVisDrawer::DVisDrawer() +{ + refCount = 1; + m_bHooked = FALSE; + m_list = NULL; +} + +DVisDrawer::~DVisDrawer() +{ + if(m_bHooked) + UnRegister(); + + g_VisView = NULL; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DVisDrawer::Draw2D(VIEWTYPE vt) +{ + if(!m_list) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 0.5f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + //bleh + list::const_iterator l=m_list->begin(); + + for(; l != m_list->end(); l++) + { + DWinding* w = *l; + + g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + for(int i = 0; i < w->numpoints; i++) { + g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); + } + g_QglTable.m_pfn_qglEnd(); + } + + + g_QglTable.m_pfn_qglPopMatrix(); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DVisDrawer::Draw3D() +{ + if(!m_list) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglColor4f(1.0, 0.0, 0.0, 0.5f); + +// g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); + +// g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + +// g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +// g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + //bleh + list::const_iterator l=m_list->begin(); + + for(; l != m_list->end(); l++) + { + DWinding* w = *l; + + g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + for(int i = 0; i < w->numpoints; i++) { + g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); + } + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DVisDrawer::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DVisDrawer::UnRegister() +{ + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void DVisDrawer::SetList(std::list *pointList) +{ + if(m_list) + ClearPoints(); + + m_list = pointList; +} + +void DVisDrawer::ClearPoints() +{ + list::const_iterator deadPoint=m_list->begin(); + for(; deadPoint!=m_list->end(); deadPoint++) + delete *deadPoint; + m_list->clear(); +} diff --git a/contrib/bobtoolz/DVisDrawer.h b/contrib/bobtoolz/DVisDrawer.h new file mode 100644 index 00000000..c0ba1aa9 --- /dev/null +++ b/contrib/bobtoolz/DVisDrawer.h @@ -0,0 +1,58 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBobView.h: interface for the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DWinding.h" + +#if _MSC_VER > 1000 + +#pragma once +#endif // _MSC_VER > 1000 + +class DVisDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +public: + DVisDrawer(); + virtual ~DVisDrawer(); + +protected: + list* m_list; + int refCount; +public: + void ClearPoints(); + void SetList(list* pointList); + void UnRegister(); + void Register(); + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + bool m_bHooked; +}; + +#endif // !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DWinding.cpp b/contrib/bobtoolz/DWinding.cpp new file mode 100644 index 00000000..b99ede0a --- /dev/null +++ b/contrib/bobtoolz/DWinding.cpp @@ -0,0 +1,483 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DWinding.cpp: implementation of the DWinding class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DWinding.h" +#include "DPlane.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DWinding::DWinding() +{ + numpoints = 0; + p = NULL; +} + +DWinding::~DWinding() +{ + if(p) + delete[] p; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +#define BOGUS_RANGE 4096 + +void DWinding::AllocWinding(int points) +{ + numpoints = points; + if(p) + delete[] p; + p = new vec3_t[points]; +} + +vec_t DWinding::WindingArea() +{ + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (int i = 2; i < numpoints ; i++) + { + VectorSubtract (p[i-1], p[0], d1); + VectorSubtract (p[i], p[0], d2); + + CrossProduct (d1, d2, cross); + + total += 0.5f * VectorLength ( cross ); + } + + return total; +} + +void DWinding::RemoveColinearPoints() +{ + vec3_t p2[MAX_POINTS_ON_WINDING]; + + int nump = 0; + for (int i = 0; i < numpoints; i++) + { + int j = (i+1)%numpoints; + int k = (i+numpoints-1)%numpoints; + + vec3_t v1, v2; + VectorSubtract (p[j], p[i], v1); + VectorSubtract (p[i], p[k], v2); + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (p[i], p2[nump]); + nump++; + } + } + + if (nump == numpoints) + return; + + AllocWinding(nump); + memcpy (p, p2, nump*sizeof(vec3_t)); +} + +DPlane* DWinding::WindingPlane() +{ + DPlane* newPlane = new DPlane(p[0], p[1], p[2], NULL); + return newPlane; +} + +void DWinding::WindingBounds(vec3_t mins, vec3_t maxs) +{ + if(numpoints == 0) + return; + + VectorCopy(mins, p[0]); + VectorCopy(maxs, p[0]); + + for (int i = 1; i < numpoints ;i++) + { + for (int j = 0; j < 3; j++) + { + vec_t v = p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +void DWinding::WindingCentre(vec3_t centre) +{ + VectorCopy (vec3_origin, centre); + for (int i = 0; i < numpoints; i++) + VectorAdd (p[i], centre, centre); + + float scale = 1.0f/numpoints; + VectorScale (centre, scale, centre); +} + + +DWinding* DWinding::CopyWinding() +{ + DWinding* c = new DWinding; + c->AllocWinding(numpoints); + memcpy (c->p, p, numpoints*sizeof(vec3_t)); + return c; +} + + +int DWinding::WindingOnPlaneSide(vec3_t normal, vec_t dist) +{ + bool front = FALSE; + bool back = FALSE; + + for (int i = 0; i < numpoints; i++) + { + vec_t d = DotProduct (p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = TRUE; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = TRUE; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + +void DWinding::CheckWinding() +{ + vec_t *p1, *p2; + vec_t edgedist; + vec3_t dir, edgenormal; + + if (numpoints < 3) + Sys_Printf ("CheckWinding: %i points", numpoints); + + vec_t area = WindingArea(); + if (area < 1) + Sys_Printf ("CheckWinding: %f area", area); + + DPlane* wPlane = WindingPlane (); + int i; + for (i = 0; i < numpoints; i++) + { + p1 = p[i]; + + int j; + for (j = 0; j < 3; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Sys_Printf ("CheckFace: BUGUS_RANGE: %f", p1[j]); + + j = i + 1 == numpoints ? 0 : i + 1; + + // check the point is on the face plane + vec_t d = DotProduct (p1, wPlane->normal) - wPlane->_d; + if (d < -ON_EPSILON || d > ON_EPSILON) + Sys_Printf ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Sys_Printf ("CheckWinding: degenerate edge"); + + CrossProduct (wPlane->normal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + + // all other points must be on front side + for (j = 0 ; j < numpoints ; j++) + { + if (j == i) + continue; + + d = DotProduct (p[j], edgenormal); + if (d > (edgedist + ON_EPSILON)) + Sys_Printf ("CheckWinding: non-convex"); + } + } + + delete wPlane; +} + +DWinding* DWinding::ReverseWinding() +{ + DWinding* c = new DWinding; + c->AllocWinding(numpoints); + + for (int i = 0; i < numpoints ; i++) + VectorCopy (p[numpoints-1-i], c->p[i]); + + return c; +} + +bool DWinding::ChopWindingInPlace(DPlane* chopPlane, vec_t epsilon) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t *p1, *p2; + vec3_t mid; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + int i; + for (i = 0; i < numpoints; i++) + { + vec_t dot = DotProduct (p[i], chopPlane->normal); + dot -= chopPlane->_d; + dists[i] = dot; + + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + delete this; + return FALSE; + } + + if (!counts[1]) + return TRUE; + + int maxpts = numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + DWinding* f = new DWinding; + f->AllocWinding(maxpts); + f->numpoints = 0; + + for (i = 0; i < numpoints; i++) + { + p1 = p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = p[(i+1)%numpoints]; + + vec_t dot = dists[i] / (dists[i]-dists[i+1]); + for (int j = 0; j < 3; j++) + { + if (chopPlane->normal[j] == 1) + mid[j] = chopPlane->_d; + else if (chopPlane->normal[j] == -1) + mid[j] = -chopPlane->_d; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Sys_Printf ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); + + delete[] p; + p = f->p; + f->p = NULL; + delete f; + return TRUE; +} + +void DWinding::ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding **front, DWinding **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t *p1, *p2; + vec3_t mid; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + int i; + for (i = 0; i < numpoints; i++) + { + vec_t dot = -chopPlane->DistanceToPoint(p[i]); + dists[i] = dot; + + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding(); + return; + } + if (!counts[1]) + { + *front = CopyWinding(); + return; + } + + int maxpts = numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + DWinding* f = new DWinding; + DWinding* b = new DWinding; + + f->AllocWinding(maxpts); + f->numpoints = 0; + + b->AllocWinding(maxpts); + b->numpoints = 0; + + *front = f; + *back = b; + + for (i = 0; i < numpoints ; i++) + { + p1 = p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = p[(i+1)%numpoints]; + + vec_t dot = dists[i] / (dists[i]-dists[i+1]); + for (int j = 0; j < 3; j++) + { + if (chopPlane->normal[j] == 1) + mid[j] = chopPlane->_d; + else if (chopPlane->normal[j] == -1) + mid[j] = -chopPlane->_d; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Sys_Printf ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + +bool DWinding::ChopWinding(DPlane* chopPlane) +{ + DWinding *f, *b; + + ClipWindingEpsilon (chopPlane, (float)ON_EPSILON, &f, &b); + + if (b) + delete (b); + + + if(!f) + { + delete this; + return FALSE; + } + + delete[] p; + p = f->p; + f->p = NULL; + numpoints = f->numpoints; + delete f; + + return TRUE; +} diff --git a/contrib/bobtoolz/DWinding.h b/contrib/bobtoolz/DWinding.h new file mode 100644 index 00000000..d173fbf6 --- /dev/null +++ b/contrib/bobtoolz/DWinding.h @@ -0,0 +1,68 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DWinding.h: interface for the DWinding class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DPlane; + +class DWinding +{ +public: + DWinding(); + virtual ~DWinding(); + + void AllocWinding(int points); + + bool ChopWinding(DPlane* chopPlane); + bool ChopWindingInPlace(DPlane* chopPlane, vec_t ON_EPSILON); + void ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding** front, DWinding** back); + + void CheckWinding(); + void WindingCentre(vec3_t centre); + void WindingBounds(vec3_t mins, vec3_t maxs); + void RemoveColinearPoints(); + + DWinding* ReverseWinding(); + DWinding* CopyWinding(); + DPlane* WindingPlane(); + + int WindingOnPlaneSide(vec3_t normal, vec_t dist); + + vec_t WindingArea(); + +// members + int numpoints; + vec3_t* p; + vec3_t clr; +}; + +#define MAX_POINTS_ON_WINDING 64 + +#define ON_EPSILON 0.01 + +#endif // !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/ScriptParser.cpp b/contrib/bobtoolz/ScriptParser.cpp new file mode 100644 index 00000000..c94175e1 --- /dev/null +++ b/contrib/bobtoolz/ScriptParser.cpp @@ -0,0 +1,267 @@ +#include "StdAfx.h" +#include "ScriptParser.h" + +CScriptParser::CScriptParser(void): + m_pScript(NULL), + m_pScriptSection(NULL), + m_pLastScriptSection(NULL), + m_pToken(NULL) { + ClearBuffer(); +} + +CScriptParser::~CScriptParser(void) { + ClearBuffer(); +} + +void CScriptParser::ClearBuffer(void) { + if(m_pScript) { + delete[] m_pScript; + m_pScript = NULL; + } + if(m_pToken) { + delete[] m_pToken; + m_pToken = NULL; + } + m_pScriptSection = NULL; + m_pLastScriptSection = NULL; + memset(m_breakChars, 0, sizeof(m_breakChars)); +} + +const char* CScriptParser::MakeToken(const char* pToken) { + if(m_pToken) { + delete[] m_pToken; + m_pToken = NULL; + } + + if(!pToken) { + pToken = ""; + } + + int len = static_cast(strlen(pToken)); + + m_pToken = new char[len + 1]; + m_pToken[len] = '\0'; + strcpy(m_pToken, pToken); + + return m_pToken; +} + +#define MAX_TOKEN_STRING 1024 +// Should NEVER return NULL +const char* CScriptParser::GetToken(bool bAllowLinebreaks) { + int c = 0, len; + char token[MAX_TOKEN_STRING]; + bool bNewLines = false; + + m_pLastScriptSection = m_pScriptSection; + + len = 0; + *token = '\0'; + + if(!m_pScript || !m_pScriptSection) { + return MakeToken(token); + } + + while ( true ) { + SkipWhitespace( &bNewLines ); + if ( !*m_pScriptSection ) { + return MakeToken(token); + } + if ( bNewLines && !bAllowLinebreaks ) { + return MakeToken(token); + } + + c = *m_pScriptSection; + + if ( c == '/' && m_pScriptSection[1] == '/' ) { // C style comments + m_pScriptSection += 2; + while (*m_pScriptSection && *m_pScriptSection != '\n') { + m_pScriptSection++; + } + } else if ( c=='/' && m_pScriptSection[1] == '*' ) { // C++ style comments + m_pScriptSection += 2; + while ( *m_pScriptSection && ( *m_pScriptSection != '*' || m_pScriptSection[1] != '/' ) ) { + m_pScriptSection++; + } + if ( *m_pScriptSection ) { + m_pScriptSection += 2; + } + } else { + break; + } + } + + if (c == '\"') { + m_pScriptSection++; + while ( true ) { + c = *m_pScriptSection++; + if (c=='\"' || !c) { + token[len] = 0; + return MakeToken(token); + } + if (len < MAX_TOKEN_STRING) { + token[len] = c; + len++; + } + } + } + + do { + if(len > 0 && IsBreakChar(*m_pScriptSection)) { + break; + } + + if (len < MAX_TOKEN_STRING) { + token[len] = c; + len++; + } + m_pScriptSection++; + + if(IsBreakChar(c)) { + break; + } + + c = *m_pScriptSection; + } while (c > 32); + + if (len == MAX_TOKEN_STRING) { + len = 0; + } + token[len] = 0; + + return MakeToken(token); +} + +void CScriptParser::SkipWhitespace(bool* pbNewLines) { + int c; + + if(!m_pScript || !m_pScriptSection) { + return; + } + + while( (c = *m_pScriptSection) <= ' ') { + if( !c ) { + return; + } + if( c == '\n' ) { + *pbNewLines = true; + } + m_pScriptSection++; + } +} + +void CScriptParser::SkipBracedSection(void) { + const char *token; + int depth; + + depth = 0; + do { + token = GetToken( true ); + if( token[1] == 0 ) { + if( *token == '{' ) { + depth++; + } else if( *token == '}' ) { + depth--; + } + } + } while( depth && *m_pScriptSection ); +} + +void CScriptParser::SkipRestOfLine(void) { + char *p; + int c; + + p = m_pScriptSection; + while ( (c = *p++) != 0 ) { + if ( c == '\n' ) { + break; + } + } + m_pScriptSection = p; +} + +void CScriptParser::UndoGetToken(void) { + if(!m_pLastScriptSection) { + return; + } + m_pScriptSection = m_pLastScriptSection; + m_pLastScriptSection = NULL; +} + +void CScriptParser::ResetParseSession(void) { + if(!m_pScript) { + return; + } + + m_pScriptSection = m_pScript; + m_pLastScriptSection = NULL; +} + +char* CScriptParser::GetBufferCopy(void) { + if(!m_pScript) { + return NULL; + } + + int len = static_cast(strlen(m_pScript)); + char* pBuffer = new char[len + 1]; + strcpy(pBuffer, m_pScript); + return pBuffer; +} + +int CScriptParser::GetTokenOffset(void) { + if(!m_pScript || !m_pScriptSection) { + return 0; + } + + return static_cast(m_pScriptSection - m_pScript); +} + +void CScriptParser::LoadScript(const char* pScript) { + ClearBuffer(); + + int len = static_cast(strlen(pScript)); + if(len <= 0) { + return; + } + + m_pScript = new char[len + 1]; + m_pScript[len] = '\0'; + + strcpy(m_pScript, pScript); + m_pScriptSection = m_pScript; +} + +void CScriptParser::AddBreakChar(char c) { + for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { + if(!m_breakChars[i]) { + m_breakChars[i] = c; + return; + } + } + + // TODO: Error: max break chars hit +} + +bool CScriptParser::IsBreakChar(char c) { + for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { + if(!m_breakChars[i]) { + return false; + } + if(m_breakChars[i] == c) { + return true; + } + } + return false; +} + +void CScriptParser::SetScript(char* pScript) { + ClearBuffer(); + + int len = static_cast(strlen(pScript)); + if(len <= 0) { + return; + } + + m_pScript = pScript; + m_pScriptSection = m_pScript; +} diff --git a/contrib/bobtoolz/ScriptParser.h b/contrib/bobtoolz/ScriptParser.h new file mode 100644 index 00000000..60c92f51 --- /dev/null +++ b/contrib/bobtoolz/ScriptParser.h @@ -0,0 +1,41 @@ + +#ifndef _SCRIPTPARSER_H_ +#define _SCRIPTPARSER_H_ + +#include "interfaces/IScriptParser.h" + +#define SP_MAX_BREAKCHARS 16 + +class CScriptParser: public IScriptParser { +public: + CScriptParser(void); + ~CScriptParser(void); +private: + char m_breakChars[SP_MAX_BREAKCHARS]; + char* m_pScript; + char* m_pScriptSection; + char* m_pLastScriptSection; + char* m_pToken; + + void SkipWhitespace(bool* pbNewLines); + void ClearBuffer(void); + const char* MakeToken(const char* pToken); + bool IsBreakChar(char c); +public: + const char* GetToken(bool bAllowLinebreaks); + void SkipBracedSection(void); + void SkipRestOfLine(void); + void UndoGetToken(void); + void ResetParseSession(void); + + char* GetBufferCopy(void); + int GetTokenOffset(void); + + void LoadScript(const char* pScript); + void SetScript(char* pScript); + + void AddBreakChar(char c); +private: +}; + +#endif diff --git a/contrib/bobtoolz/StdAfx.cpp b/contrib/bobtoolz/StdAfx.cpp new file mode 100644 index 00000000..eab4b5a5 --- /dev/null +++ b/contrib/bobtoolz/StdAfx.cpp @@ -0,0 +1,25 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// stdafx.cpp : source file that includes just the standard includes +// plugin.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "StdAfx.h" + diff --git a/contrib/bobtoolz/StdAfx.h b/contrib/bobtoolz/StdAfx.h new file mode 100644 index 00000000..88183232 --- /dev/null +++ b/contrib/bobtoolz/StdAfx.h @@ -0,0 +1,154 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __STDAFX_BOBTOOLZ__ +#define __STDAFX_BOBTOOLZ__ + +#define VC_EXTRALEAN + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#define BOBTOOLZ_MINOR "bobtoolz" + +#include +#include +#include +#include + +#include "time.h" + +#if defined (__linux__) || defined (__APPLE__) + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +#include + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; +//typedef int bool; + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L + + +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L + +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND + +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 + +#define WINAPI +#define APIENTRY + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; + +#define stricmp strcasecmp + +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#endif + +typedef struct tagRECT +{ + long left; + long top; + long right; + long bottom; +} RECT, *PRECT, *LPRECT; + +typedef uint UINT; + +#endif // __linux__ + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE + +#include "missing.h" // temporary stuff, needs to be removed + +#include "str.h" +#include "qertypes.h" +#include "qerplugin.h" +#include "idata.h" +#include "ibrush.h" +#include "iselectedface.h" +#include "ishaders.h" +#include "ibspfrontend.h" +#include "iui.h" +#include "igl.h" +#include "itoolbar.h" +#include "ientity.h" + +#include "mathlib.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERAppDataTable g_AppDataTable; +extern _QERBrushTable g_BrushTable; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERShadersTable g_ShadersTable; +extern _QERQglTable g_QglTable; +extern _QERUITable g_MessageTable; +extern _QEREntityTable g_EntityTable; + + +#define MAX_ROUND_ERROR 0.05 + +#include "gtkr_list.h" + +#endif diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp new file mode 100644 index 0000000000000000000000000000000000000000..522395034ccf7b609f78b287d027a125bac211a9 GIT binary patch literal 320 zcmZusK?;B%5S&CK=ukwD=o3M7uLt%PpZtHaK$x*uBu#mTymBRP-_I@W}# z2ZSx9P!MB;td+~p9^ncwek?|Ah$&k-ib0))637(kd6$OYm5K=^pAGz04teun@5|3g(_ zQedN*KmaVq$OsZZ=A!dK%9ubZfHXukSOkp^QGk#qjt@2v?jnc%a^)Uk83x?I_Vp=P%~v1>A*v+ zQ)*zAUT!&XQ*F7o7{TgkAP O)&Ebeo`0--ib0))637(kc}$OYm5K==m;e*&Q$5Q4z}|Np@> z7J>yuj0FVXA`muQ1TF(*ASncEp_mUffDvX9&}JqE1{P){gMmT_9>`Wy9^C051^~OX B3%~#X literal 0 HcmV?d00001 diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_split.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_split.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fbb1571ce1c870ddc44f5aa9eaa6106ba261274d GIT binary patch literal 312 zcmaKmF%p0v3!zxzy&rTA=|MU!gl(Fny8U7^z^_* z%|lYhyL5BO11D9?0q$ySoO>(g0()P$CAL)JRyYF0ml+UNw!nsY{p9&u%P~={57a0z MPcva~&g%H%2bECipJOMNtNMH`363}GgS?TM zOt`QDAM$<;p1Btr*Sc<~wW5@QoYld+HP^AsGqfP3Xe0c54 z5eK4R&knqaV-t`rEIe3*YcO72;!u^(jQO?0Gy&rX3`2+0<<5wVf2(b`vYFLdQ{l>* xmHUd#5D|IZuZS_@lm2`{0gCR^ljLrayy2m{puJmsuY1Vrk5Y)4{pU-X^9x&$8s7i_ literal 0 HcmV?d00001 diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_turnedge.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_turnedge.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b72cb2aae6326e7c82b8be43f02ff38910d8eaf2 GIT binary patch literal 332 zcmZvW!3{zo5JZR1hiE)#j6LYZ9?U-&588m0dD7;rzy@$;7e0w`$t?R|Sa!Ny11#>$ z2WmsDselDD@S(OV*OIkVxL)Ty@IC?0BXHT-Deyokh4r5pLXUy>AvRM^nt>YaBq!C9 rIf#wr5O$7+opZ7t^}Wp2qq3XnaCVf#xFXw+#`?%3iht*Cm-GGw>kkck literal 0 HcmV?d00001 diff --git a/contrib/bobtoolz/bobToolz-GTK.cpp b/contrib/bobtoolz/bobToolz-GTK.cpp new file mode 100644 index 00000000..3df73c4c --- /dev/null +++ b/contrib/bobtoolz/bobToolz-GTK.cpp @@ -0,0 +1,292 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" +#include "misc.h" + +#include "dialogs/dialogs-gtk.h" +#include "../../libs/cmdlib.h" + +// Radiant function table +_QERFuncTable_1 g_FuncTable; +_QERAppDataTable g_AppDataTable; +_QERBrushTable g_BrushTable; +_QERShadersTable g_ShadersTable; // vvvvvvvvvvvvvvvvvvvv +_QERSelectedFaceTable g_SelectedFaceTable; // to get texture sizes +_QERQglTable g_QglTable; // for path plotting (hooking to DBobView) +_QERUITable g_MessageTable; // for path plotting (listening for update) +_QEREntityTable g_EntityTable; + +// plugin name +char* PLUGIN_NAME = "bobToolz"; + +// commands in the menu +static char* PLUGIN_COMMANDS = "About...,-,Reset Textures...,PitOMatic,-,Vis Viewer,Brush Cleanup,Polygon Builder,Caulk Selection,-,Tree Planter,Drop Entity,Plot Splines,-,Merge Patches,Split patches,Turn edge"; + +// globals +GtkWidget *g_pRadiantWnd = NULL; + +static const char *PLUGIN_ABOUT = "bobToolz for SDRadiant\n" + "by digibob (digibob@splashdamage.com)\n" + "http://www.splashdamage.com\n\n" + "Additional Contributors:\n" + "MarsMattel, RR2DO2\n"; + +extern "C" const char* QERPlug_Init( void* hApp, void* pMainWidget ) { + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + return "bobToolz for GTKradiant"; +} + +extern "C" const char* QERPlug_GetName() { + return PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList() { + return PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) { + LoadLists(); + + if( !stricmp( p, "brush cleanup" ) ) { + DoFixBrushes(); + } else if( !stricmp( p, "polygon builder" ) ) { + DoPolygonsTB(); + } else if( !stricmp( p, "caulk selection" ) ) { + DoCaulkSelection(); + } else if( !stricmp( p, "tree planter" ) ) { + DoTreePlanter(); + } else if( !stricmp( p, "plot splines" ) ) { + DoTrainPathPlot(); + } else if( !stricmp( p, "drop entity" ) ) { + DoDropEnts(); + } else if( !stricmp( p, "merge patches" ) ) { + DoMergePatches(); + } else if( !stricmp( p, "split patches" ) ) { + DoSplitPatch(); + } else if( !stricmp( p, "turn edge" ) ) { + DoFlipTerrain(); + } else if( !stricmp(p, "reset textures...") ) { + DoResetTextures(); + } else if( !stricmp(p, "pitomatic") ) { + DoPitBuilder(vMin, vMax); + } else if( !stricmp(p, "vis viewer") ) { + DoVisAnalyse(); + } else if( !stricmp(p, "about...") ) { + DoMessageBox(PLUGIN_ABOUT, "About", IDOK); + } +} + +#define NUM_TOOLBARBUTTONS 9 + +unsigned int ToolbarButtonCount( void ) { + return NUM_TOOLBARBUTTONS; +} + +// Load a xpm file and return a pixmap widget. +GtkWidget* new_pixmap (char* filename) { + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + g_FuncTable.m_pfnLoadBitmap(filename, (void **)&gdkpixmap, (void **)&mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + + gdk_pixmap_unref (gdkpixmap); + gdk_pixmap_unref (mask); + + return pixmap; +} + +class CBobtoolzToolbarButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + switch( mIndex ) { + case 0: return "bobtoolz_cleanup.bmp"; + case 1: return "bobtoolz_poly.bmp"; + case 2: return "bobtoolz_caulk.bmp"; + case 3: return "bobtoolz_treeplanter.bmp"; + case 4: return "bobtoolz_trainpathplot.bmp"; + case 5: return "bobtoolz_dropent.bmp"; + case 6: return "bobtoolz_merge.bmp"; + case 7: return "bobtoolz_split.bmp"; + case 8: return "bobtoolz_turnedge.bmp"; + } + return NULL; + } + virtual EType getType() const + { + switch( mIndex ) { + case 3: return eToggleButton; + default: return eButton; + } + } + virtual const char* getText() const + { + switch( mIndex ) { + case 0: return "Cleanup"; + case 1: return "Polygons"; + case 2: return "Caulk"; + case 3: return "Tree Planter"; + case 4: return "Plot Splines"; + case 5: return "Drop Entity"; + case 6: return "Merge Patches"; + case 7: return "Split Patches"; + case 8: return "Flip Terrain"; + } + return NULL; + } + virtual const char* getTooltip() const + { + switch( mIndex ) { + case 0: return "Brush Cleanup"; + case 1: return "Polygons"; + case 2: return "Caulk selection"; + case 3: return "Tree Planter"; + case 4: return "Plot Splines"; + case 5: return "Drop Entity"; + case 6: return "Merge Patches"; + case 7: return "Split Patches"; + case 8: return "Flip Terrain"; + } + return NULL; + } + + virtual void activate() const + { + LoadLists(); + + switch( mIndex ) { + case 0: DoFixBrushes(); break; + case 1: DoPolygonsTB(); break; + case 2: DoCaulkSelection(); break; + case 3: DoTreePlanter(); break; + case 4: DoTrainPathPlot(); break; + case 5: DoDropEnts(); break; + case 6: DoMergePatches(); break; + case 7: DoSplitPatch(); break; + case 8: DoFlipTerrain(); break; + } + } + + int mIndex; +}; + +CBobtoolzToolbarButton g_bobtoolzToolbarButtons[NUM_TOOLBARBUTTONS]; + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + g_bobtoolzToolbarButtons[index].mIndex = index; + return &g_bobtoolzToolbarButtons[index]; +} + +// ============================================================================= +// SYNAPSE + +class CSynapseClientBobtoolz : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientBobtoolz() { } + virtual ~CSynapseClientBobtoolz() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientBobtoolz g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, BOBTOOLZ_MINOR, sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, BOBTOOLZ_MINOR, sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(g_AppDataTable), SYN_REQUIRE, &g_AppDataTable); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(g_ShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(g_MessageTable), SYN_REQUIRE, &g_MessageTable); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable); + + return &g_SynapseClient; +} + +bool CSynapseClientBobtoolz::RequestAPI(APIDescriptor_t *pAPI) +{ + if( !strcmp(pAPI->minor_name, BOBTOOLZ_MINOR) ) + { + if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) ) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + + return true; + } + else if( !strcmp(pAPI->major_name, TOOLBAR_MAJOR) ) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientBobtoolz::GetInfo() +{ + return "bobToolz module built " __DATE__ " " RADIANT_VERSION; +} + +char* GetFilename(char* buffer, const char* filename) { + strcpy(buffer, g_pSynapseServer->GetModuleFilename(&g_SynapseClient)); + StripFilename( buffer ); + strcat(buffer, "/"); + strcat(buffer, filename); + buffer = UnixToDosPath(buffer); + return buffer; +} diff --git a/contrib/bobtoolz/bobToolz.def b/contrib/bobtoolz/bobToolz.def new file mode 100644 index 00000000..9ff9f292 --- /dev/null +++ b/contrib/bobtoolz/bobToolz.def @@ -0,0 +1,8 @@ +; plugin.def : Declares the module parameters for the DLL. + +LIBRARY "bobToolz" +; DESCRIPTION 'bobToolz Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/bobtoolz/bobToolz.h b/contrib/bobtoolz/bobToolz.h new file mode 100644 index 00000000..d4290099 --- /dev/null +++ b/contrib/bobtoolz/bobToolz.h @@ -0,0 +1,64 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// plugin.h : main header file for the PLUGIN DLL +// + +#if !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +#define AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef __AFXWIN_H__ + #error include 'StdAfx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CPluginApp +// See plugin.cpp for the implementation of this class +// + +class CPluginApp : public CWinApp +{ +public: + CPluginApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPluginApp) + //}}AFX_VIRTUAL + + //{{AFX_MSG(CPluginApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) diff --git a/contrib/bobtoolz/bobToolz.rc b/contrib/bobtoolz/bobToolz.rc new file mode 100644 index 00000000..1140cdd2 --- /dev/null +++ b/contrib/bobtoolz/bobToolz.rc @@ -0,0 +1,533 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,1,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "by djbob :P and MarsMattel ~:]\0" + VALUE "CompanyName", "bobCo\0" + VALUE "FileDescription", "All your plugins are belong to us\0" + VALUE "FileVersion", "1, 1, 1, 0\0" + VALUE "InternalName", "bobToolz\0" + VALUE "LegalCopyright", "Copyright (C) y2k\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "bobToolz.DLL\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "\0" + VALUE "ProductVersion", "2, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Sys. Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 361, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,305,100,50,14 + CTEXT "BobToolz - Q3radiant version by djbob &&&& Mars Mattel", + IDC_STATIC,5,5,350,14,SS_CENTERIMAGE + CTEXT "Latest Version Can Be Found At http://djbob.fortefide.com", + IDC_STATIC,5,20,350,15,SS_CENTERIMAGE + LTEXT "Random bobToolz comments:",IDC_STATIC,5,35,355,10 + CTEXT "Texture Alignments Are Irrelevant, You Will Be Caulked\n-QPSiren\nCaulk Me Baby One More Time\n-TTimo\nWe're Up The Creek Without A Penguin\n-Mars Mattel", + IDC_STATIC,5,45,355,50 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 354 + TOPMARGIN, 7 + BOTTOMMARGIN, 111 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral (Sys. Default) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_STAIR_DIALOG DIALOG DISCARDABLE 0, 0, 246, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Stair Designer" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,189,83,50,12 + PUSHBUTTON "Cancel",IDCANCEL,189,99,50,12 + EDITTEXT IDC_EDIT1,5,5,86,12,ES_AUTOHSCROLL + LTEXT "Stair Height",IDC_STATIC,95,5,42,15,SS_CENTERIMAGE + GROUPBOX "Direction",IDC_STATIC,7,26,85,64 + CONTROL "North",IDC_DIR_N_RADIO,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,14,38,33,10 + CONTROL "South",IDC_DIR_S_RADIO,"Button",BS_AUTORADIOBUTTON,14, + 50,35,10 + CONTROL "East",IDC_DIR_E_RADIO,"Button",BS_AUTORADIOBUTTON,14,62, + 30,10 + CONTROL "West",IDC_DIR_W_RADIO,"Button",BS_AUTORADIOBUTTON,14,74, + 33,10 + GROUPBOX "Style",IDC_STATIC,97,26,82,49 + CONTROL "Original",IDC_STYLE_ORIG_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,105,35,39,10 + CONTROL "Bob's Style",IDC_STYLE_BOB_RADIO,"Button", + BS_AUTORADIOBUTTON,105,47,51,10 + CONTROL "Corner",IDC_STYLE_CORNER_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_DISABLED,105,59,51,10 + EDITTEXT IDC_RISER_EDIT,7,99,85,12,ES_AUTOHSCROLL + LTEXT "Riser Texture",IDC_STATIC,95,100,60,11,SS_CENTERIMAGE + CONTROL "Use Detail Brushes",IDC_DETAIL_CHK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,100,80,75,10 +END + +IDD_POLYGON_DIALOG DIALOG DISCARDABLE 0, 0, 271, 68 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Polygon Builder" +FONT 8, "Arial" +BEGIN + PUSHBUTTON "OK",IDOK,150,50,50,14 + PUSHBUTTON "Cancel",IDCANCEL,215,50,50,14 + EDITTEXT IDC_EDIT1,7,7,76,13,ES_AUTOHSCROLL + LTEXT "Number Of Sides",IDC_STATIC,85,7,60,13,SS_CENTERIMAGE + CONTROL "Inverse Polygon",IDC_INVERSE_CHK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,149,21,75,10 + CONTROL "Use Border",IDC_BORDER_CHK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,149,7,66,10 + EDITTEXT IDC_BORDER_EDIT,7,28,76,13,ES_AUTOHSCROLL + LTEXT "Border Size",IDC_STATIC,86,28,60,13,SS_CENTERIMAGE + CONTROL "Align Top Edge",IDC_ALIGN_CHK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,149,35,75,10 +END + +IDD_DOOR_DIALOG DIALOG DISCARDABLE 0, 0, 327, 119 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Door Builder" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,270,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,270,24,50,14 + EDITTEXT IDC_FBTEXTURE_EDIT,7,7,125,14,ES_AUTOHSCROLL + LTEXT "Door Front/Back Texture",IDC_STATIC,137,7,86,14, + SS_CENTERIMAGE + EDITTEXT IDC_TRIMTEXTURE_EDIT,7,26,125,14,ES_AUTOHSCROLL + LTEXT "Door Trim Texture",IDC_STATIC,137,26,86,14, + SS_CENTERIMAGE + CONTROL "Scale Main Texture Horizontally",IDC_TEXSCALE1_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,46,115,10 + CONTROL "Scale Main Texture Vertically",IDC_TEXSCALE2_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,60,107,10 + CONTROL "Scale Trim Texture Horizontally",IDC_TEXSCALE3_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,136,46,113,10 + CONTROL "Scale Trim Texture Vertically",IDC_TEXSCALE4_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,136,60,105,10 + COMBOBOX IDC_MAINTEX_COMBO,7,76,126,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_TRIMTEX_COMBO,7,99,126,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Set As Main Texture",IDC_SET_MAINTEX_BTN,139,76,82,14 + PUSHBUTTON "Set As Trim Texture",IDC_SET_TRIMTEX_BTN,139,98,82,14 + GROUPBOX "Orientation",IDC_DIR_GROUP,225,72,95,40 + CONTROL "North - South",IDC_DIR_NS_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,230,82,85,10 + CONTROL "East - West",IDC_DIR_EW_RADIO,"Button", + BS_AUTORADIOBUTTON,230,97,85,10 +END + +IDD_INTERSECT_DIALOG DIALOG DISCARDABLE 0, 0, 245, 58 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Intersecting Brush Finder" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,40,50,14 + PUSHBUTTON "Cancel",IDCANCEL,185,40,50,14 + CONTROL "Include Detail Brushes",IDC_DETAIL_INCLUDE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,130,10,111,10 + GROUPBOX "Brush Options",IDC_STATIC,10,5,111,45 + CONTROL "Use Whole Map",IDC_WHOLEMAP_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,15,15,95,10 + CONTROL "Use Selected Brushes",IDC_SELECTED_RADIO,"Button", + BS_AUTORADIOBUTTON,15,30,95,10 + CONTROL "Only Select Duplicate Brushes",IDC_DUPLICATEONLY_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,25,113,10 +END + +IDD_INTERSECT_INFO_DIALOG DIALOG DISCARDABLE 0, 0, 187, 33 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH, + 5,15,175,10 + CTEXT "Brush Loading",IDC_STATIC,5,5,175,10,SS_CENTERIMAGE +END + +IDD_BRUSHCHECKER_DIALOG DIALOG DISCARDABLE 0, 0, 182, 38 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH, + 5,21,172,10 + CTEXT "Checking Brushes",IDC_STATIC,5,5,170,15,SS_CENTERIMAGE +END + +IDD_AUTOCAULK_DIALOG DIALOG DISCARDABLE 0, 0, 187, 52 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH, + 5,15,175,10 + CTEXT "Loading Portal Data",IDC_STATIC,5,5,175,10, + SS_CENTERIMAGE + CONTROL "Progress1",IDC_PROGRESS2,"msctls_progress32",PBS_SMOOTH, + 5,35,175,10 + CTEXT "Auto Caulking",IDC_STATIC,5,25,175,10,SS_CENTERIMAGE +END + +IDD_AUTOCAULKSTART_DIALOG DIALOG DISCARDABLE 0, 0, 237, 83 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Auto Caulk" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,125,10,50,14 + PUSHBUTTON "Cancel",IDCANCEL,180,10,50,14 + CONTROL "Destroy Invisible Brushes",IDC_KILLBRUSHES_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,125,50,95,10 + LTEXT "",IDC_WARNING1_STATIC,5,65,223,11,NOT WS_GROUP + GROUPBOX "Static",IDC_STATIC,5,5,115,57 + CONTROL "Autocaulk",IDC_AC_NORMAL_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,10,15,48,10 + CONTROL "Build Mini Prt",IDC_AC_BUILD_MINI_PRT_RADIO,"Button", + BS_AUTORADIOBUTTON,10,30,56,10 + CONTROL "Autocaulk+ (Detail Brushes)",IDC_AC_SUPER_RADIO,"Button", + BS_AUTORADIOBUTTON,10,45,106,10 +END + +IDD_TEXTURE_RESET_DIALOG DIALOG DISCARDABLE 0, 0, 272, 107 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Texture Reset" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,160,85,50,14 + PUSHBUTTON "Cancel",IDCANCEL,215,85,50,14 + EDITTEXT IDC_RESET_TEXTURE_EDIT,5,5,118,14,ES_AUTOHSCROLL + EDITTEXT IDC_SCL_VERT_EDIT,85,45,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_SCL_HOR_EDIT,85,65,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_ROTATION_EDIT,85,85,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_SHFT_VER_EDIT,225,45,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_SHFT_HOR_EDIT,225,65,40,14,ES_AUTOHSCROLL + RTEXT "Scale::Vertical",IDC_STATIC,5,45,75,15,SS_CENTERIMAGE + RTEXT "Scale::Horizontal",IDC_STATIC,5,65,75,15,SS_CENTERIMAGE + RTEXT "Rotation",IDC_STATIC,5,85,75,15,SS_CENTERIMAGE + RTEXT "Shift::Horizontal",IDC_STATIC,160,65,60,15, + SS_CENTERIMAGE + RTEXT "Shift::Vertical",IDC_STATIC,160,45,60,15,SS_CENTERIMAGE + LTEXT "Texture To Reset",IDC_STATIC,128,5,62,15,SS_CENTERIMAGE + CONTROL "Reset All Textures",IDC_ALLTEXTURES_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,195,5,75,15 + EDITTEXT IDC_RESET_NEW_TEXTURE_EDIT,5,25,118,14,ES_AUTOHSCROLL + LTEXT "New Texture Name",IDC_STATIC,128,25,62,15, + SS_CENTERIMAGE + CONTROL "Reset Texture Only",IDC_ONLYTEXTURE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,195,25,75,15 +END + +IDD_PATHPLOTTER_DIALOG DIALOG DISCARDABLE 0, 0, 172, 113 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Path Plotter" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Enable",IDYES,5,92,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,92,50,14 + PUSHBUTTON "Disable",IDNO,60,92,50,14 + EDITTEXT IDC_POINTCOUNT_EDIT,5,5,80,14,ES_AUTOHSCROLL + EDITTEXT IDC_MULTIPLIER_EDIT,5,25,80,14,ES_AUTOHSCROLL + EDITTEXT IDC_GRAVITY_EDIT,5,45,80,14,ES_AUTOHSCROLL + LTEXT "Number Of Points",IDC_STATIC,90,5,60,15,SS_CENTERIMAGE + CONTROL "No Dynamic Update",IDC_NOUPDATE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,65,80,10 + LTEXT "Multiplier",IDC_STATIC,90,25,60,15,SS_CENTERIMAGE + LTEXT "Gravity",IDC_STATIC,90,45,60,15,SS_CENTERIMAGE + CONTROL "Show Bounding Lines",IDC_SHOWEXTRA_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,79,85,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_STAIR_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 239 + TOPMARGIN, 7 + BOTTOMMARGIN, 111 + END + + IDD_POLYGON_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 264 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END + + IDD_DOOR_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 320 + TOPMARGIN, 7 + BOTTOMMARGIN, 112 + END + + IDD_INTERSECT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 238 + TOPMARGIN, 7 + BOTTOMMARGIN, 51 + END + + IDD_INTERSECT_INFO_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 25 + END + + IDD_BRUSHCHECKER_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 31 + END + + IDD_AUTOCAULK_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END + + IDD_AUTOCAULKSTART_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 230 + TOPMARGIN, 7 + BOTTOMMARGIN, 76 + END + + IDD_TEXTURE_RESET_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 265 + TOPMARGIN, 7 + BOTTOMMARGIN, 100 + END + + IDD_PATHPLOTTER_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 165 + TOPMARGIN, 7 + BOTTOMMARGIN, 106 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_DOOR_DIALOG DLGINIT +BEGIN + IDC_MAINTEX_COMBO, 0x403, 25, 0 +0x6162, 0x6573, 0x645f, 0x6f6f, 0x2f72, 0x6873, 0x6e69, 0x6d79, 0x7465, +0x6c61, 0x6f64, 0x726f, "\000" + IDC_MAINTEX_COMBO, 0x403, 33, 0 +0x6162, 0x6573, 0x645f, 0x6f6f, 0x2f72, 0x6873, 0x6e69, 0x6d79, 0x7465, +0x6c61, 0x6f64, 0x726f, 0x6f5f, 0x7475, 0x6973, 0x6564, "\000" + IDC_MAINTEX_COMBO, 0x403, 36, 0 +0x6162, 0x6573, 0x645f, 0x6f6f, 0x2f72, 0x6873, 0x6e69, 0x6d79, 0x7465, +0x6c61, 0x6f64, 0x726f, 0x6f5f, 0x7475, 0x6973, 0x6564, 0x6133, 0x0032, + + IDC_MAINTEX_COMBO, 0x403, 24, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x625f, 0x6572, 0x0064, + IDC_MAINTEX_COMBO, 0x403, 31, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x625f, 0x6572, 0x3264, 0x735f, 0x6968, 0x796e, "\000" + IDC_MAINTEX_COMBO, 0x403, 32, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x655f, 0x6c62, 0x6575, 0x5f32, 0x6873, 0x6e69, 0x0079, + IDC_MAINTEX_COMBO, 0x403, 33, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x695f, 0x6f5f, 0x6e72, 0x7461, 0x3565, 0x665f, 0x6e69, "\000" + IDC_MAINTEX_COMBO, 0x403, 21, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6a5f, "\000" + IDC_MAINTEX_COMBO, 0x403, 22, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6a5f, 0x0033, + IDC_MAINTEX_COMBO, 0x403, 22, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6a5f, 0x0034, + IDC_MAINTEX_COMBO, 0x403, 23, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6b5f, 0x6232, "\000" + IDC_TRIMTEX_COMBO, 0x403, 26, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x732f, 0x7075, 0x6f70, +0x7472, 0x7231, 0x7375, 0x0074, + IDC_TRIMTEX_COMBO, 0x403, 27, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x732f, 0x7075, 0x6f70, +0x7472, 0x7331, 0x6968, 0x796e, "\000" + IDC_TRIMTEX_COMBO, 0x403, 26, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x732f, 0x7075, 0x6f70, +0x7472, 0x7232, 0x7375, 0x0074, + IDC_TRIMTEX_COMBO, 0x403, 22, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x772f, 0x6c70, 0x7461, +0x5f31, 0x0031, + IDC_TRIMTEX_COMBO, 0x403, 22, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x702f, 0x616c, 0x6574, +0x5f32, 0x0035, + 0 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/bobtoolz/bobToolz_gtk.vcproj b/contrib/bobtoolz/bobToolz_gtk.vcproj new file mode 100644 index 00000000..08f32b5c --- /dev/null +++ b/contrib/bobtoolz/bobToolz_gtk.vcproj @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/bobtoolz/bobtoolz-gtk.rc b/contrib/bobtoolz/bobtoolz-gtk.rc new file mode 100644 index 00000000..d1ff0d2e --- /dev/null +++ b/contrib/bobtoolz/bobtoolz-gtk.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource-gtk.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource-gtk.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,1,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "by djbob :P and MarsMattel ~:)\0" + VALUE "CompanyName", "bobCo\0" + VALUE "FileDescription", "All your plugins are belong to us\0" + VALUE "FileVersion", "1, 1, 1, 0\0" + VALUE "InternalName", "bobToolz GTK\0" + VALUE "LegalCopyright", "Copyright © 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "bobToolz.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "bobCo bobToolz\0" + VALUE "ProductVersion", "2, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/bobtoolz/bsploader.cpp b/contrib/bobtoolz/bsploader.cpp new file mode 100644 index 00000000..5c2ee582 --- /dev/null +++ b/contrib/bobtoolz/bsploader.cpp @@ -0,0 +1,258 @@ +#include "StdAfx.h" +#include "./dialogs/dialogs-gtk.h" +#include "bsploader.h" +#include "../../libs/cmdlib.h" + +int numnodes; +int numplanes; +int numleafs; +int numleafsurfaces; +int numVisBytes; +int numDrawVerts; +int numDrawSurfaces; +int numbrushes; +int numbrushsides; +int numleafbrushes; + +byte *visBytes = NULL; +dnode_t *dnodes = NULL; +dplane_t *dplanes = NULL; +dleaf_t *dleafs = NULL; +qdrawVert_t *drawVerts = NULL; +dsurface_t *drawSurfaces = NULL; +int *dleafsurfaces = NULL; +dbrush_t *dbrushes = NULL; +dbrushside_t *dbrushsides = NULL; +int *dleafbrushes = NULL; + +#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I') +#define Q3_BSP_VERSION 46 +#define WOLF_BSP_VERSION 47 + +/* +================ +FileLength +================ +*/ +int FileLength (FILE *f) +{ + int pos; + int end; + + pos = ftell (f); + fseek (f, 0, SEEK_END); + end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; +} + +/* +============== +LoadFile +============== +*/ +qboolean LoadFile( const char *filename, byte **bufferptr) +{ + FILE *f; + int length; + byte *buffer; + + f = fopen(filename, "rb"); + if(!f) + return false; + + length = FileLength (f); + buffer = new byte[length+1]; + buffer[length] = 0; + fread(buffer, 1, length, f); + fclose (f); + + *bufferptr = buffer; + return true; +} + +/*int LittleLong (int l) +{ + return l; +} + +float LittleFloat (float l) +{ + return l; +}*/ + +/* +============= +SwapBlock + +If all values are 32 bits, this can be used to swap everything +============= +*/ +void SwapBlock( int *block, int sizeOfBlock ) { + int i; + + sizeOfBlock >>= 2; + for ( i = 0 ; i < sizeOfBlock ; i++ ) { + block[i] = LittleLong( block[i] ); + } +} + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile( void ) { + int i; + + // models +// SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) ); + + // shaders (don't swap the name) +// for ( i = 0 ; i < numShaders ; i++ ) { +// dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags ); +// dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags ); +// } + + // planes + SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) ); + + // nodes + SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) ); + + // leafs + SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) ); + + // leaffaces + SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) ); + + // leafbrushes + SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) ); + + // brushes + SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) ); + + // brushsides + SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) ); + + // vis + ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] ); + ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] ); + + // drawverts (don't swap colors ) + for ( i = 0 ; i < numDrawVerts ; i++ ) { + drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] ); + drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] ); + drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] ); + drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] ); + drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] ); + drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] ); + drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] ); + drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] ); + drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] ); + drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] ); + } + + // drawindexes +// SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) ); + + // drawsurfs + SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) ); + + // fogs +// for ( i = 0 ; i < numFogs ; i++ ) { +// dfogs[i].brushNum = LittleLong( dfogs[i].brushNum ); +// dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide ); +// } +} + +/* +============= +CopyLump +============= +*/ +int CopyLump( dheader_t *header, int lump, void **dest, int size ) { + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if(length == 0) + return 0; + + *dest = new byte[length]; + memcpy( *dest, (byte *)header + ofs, length ); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +qboolean LoadBSPFile( const char *filename ) { + dheader_t *header; + + // load the file header + if(!LoadFile (filename, (byte **)&header)) + return false; + + // swap the header + SwapBlock( (int *)header, sizeof(*header) ); + + if ( header->ident != BSP_IDENT ) { + DoMessageBox( "Cant find a valid IBSP file", "Error", MB_OK); + return false; + } + if ( (header->version != Q3_BSP_VERSION) && + (header->version != WOLF_BSP_VERSION) ) { + DoMessageBox( "File is incorrect version", "Error", MB_OK); + return false; + } + + numbrushsides = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushsides, sizeof(dbrushside_t) ); + numbrushes = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushes, sizeof(dbrush_t) ); + numplanes = CopyLump( header, LUMP_PLANES, (void**)&dplanes, sizeof(dplane_t) ); + numleafs = CopyLump( header, LUMP_LEAFS, (void**)&dleafs, sizeof(dleaf_t) ); + numnodes = CopyLump( header, LUMP_NODES, (void**)&dnodes, sizeof(dnode_t) ); + numDrawVerts = CopyLump( header, LUMP_DRAWVERTS, (void**)&drawVerts, sizeof(qdrawVert_t) ); + numDrawSurfaces = CopyLump( header, LUMP_SURFACES, (void**)&drawSurfaces, sizeof(dsurface_t) ); + numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, (void**)&dleafsurfaces, sizeof(int) ); + numVisBytes = CopyLump( header, LUMP_VISIBILITY, (void**)&visBytes, 1 ); + numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, (void**)&dleafbrushes, sizeof(int) ); + + delete header; // everything has been copied out + + // swap everything + SwapBSPFile(); + + return true; +} + +void FreeBSPData() +{ + if(visBytes) + delete visBytes; + if(dnodes) + delete dnodes; + if(dplanes) + delete dplanes; + if(dleafs) + delete dleafs; + if(drawVerts) + delete drawVerts; + if(drawSurfaces) + delete drawSurfaces; + if(dleafsurfaces) + delete dleafsurfaces; + if(dleafbrushes) + delete dleafbrushes; + if(dbrushes) + delete dbrushes; + if(dbrushsides) + delete dbrushsides; +} diff --git a/contrib/bobtoolz/bsploader.h b/contrib/bobtoolz/bsploader.h new file mode 100644 index 00000000..96f7c851 --- /dev/null +++ b/contrib/bobtoolz/bsploader.h @@ -0,0 +1,134 @@ +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define HEADER_LUMPS 17 + +typedef struct { + int fileofs, filelen; +} lump_t; + +typedef struct { + int ident; + int version; + + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct { + float normal[3]; + float dist; +} dplane_t; + +typedef struct { + int planeNum; + int children[2]; // negative numbers are -(leafs+1), not nodes + int mins[3]; // for frustom culling + int maxs[3]; +} dnode_t; + +typedef struct { + int cluster; // -1 = opaque cluster (do I still store these?) + int area; + + int mins[3]; // for frustum culling + int maxs[3]; + + int firstLeafSurface; + int numLeafSurfaces; + + int firstLeafBrush; + int numLeafBrushes; +} dleaf_t; + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; + byte color[4]; +} qdrawVert_t; + +typedef struct { + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + int lightmapNum; + int lightmapX, lightmapY; + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds + + int patchWidth; + int patchHeight; +} dsurface_t; + +typedef struct { + int planeNum; // positive plane side faces out of the leaf + int shaderNum; +} dbrushside_t; + +typedef struct { + int firstSide; + int numSides; + int shaderNum; // the shader that determines the contents flags +} dbrush_t; + +typedef enum { + MST_BAD, + MST_PLANAR, + MST_PATCH, + MST_TRIANGLE_SOUP, + MST_FLARE +} mapSurfaceType_t; + +#define MAX_MAP_VISIBILITY 0x200000 +#define MAX_MAP_NODES 0x20000 +#define MAX_MAP_PLANES 0x20000 +#define MAX_MAP_LEAFS 0x20000 + +extern int numVisBytes; +extern int numleafs; +extern int numplanes; +extern int numnodes; +extern int numDrawVerts; +extern int numDrawSurfaces; +extern int numleafsurfaces; +extern int numbrushes; +extern int numbrushsides; +extern int numleafbrushes; + +extern dnode_t *dnodes; +extern dplane_t *dplanes; +extern dleaf_t *dleafs; +extern byte *visBytes; +extern qdrawVert_t *drawVerts; +extern dsurface_t *drawSurfaces; +extern int *dleafsurfaces; +extern dbrush_t *dbrushes; +extern dbrushside_t *dbrushsides; +extern int *dleafbrushes; + +qboolean LoadBSPFile( const char *filename ); +void FreeBSPData(); diff --git a/contrib/bobtoolz/bt/bt-el1.txt b/contrib/bobtoolz/bt/bt-el1.txt new file mode 100644 index 00000000..ccac5e6e --- /dev/null +++ b/contrib/bobtoolz/bt/bt-el1.txt @@ -0,0 +1,17 @@ +common/areaportal +common/clip +common/clusterportal +common/cushion +common/donotenter +common/full_clip +common/hint +common/missileclip +common/nodraw +common/nodrawnonsolid +common/nodrop +common/noimpact +common/origin +common/trigger +common/weapclip +liquid +fog \ No newline at end of file diff --git a/contrib/bobtoolz/bt/bt-el2.txt b/contrib/bobtoolz/bt/bt-el2.txt new file mode 100644 index 00000000..e69de29b diff --git a/contrib/bobtoolz/bt/ctf-blue.txt b/contrib/bobtoolz/bt/ctf-blue.txt new file mode 100644 index 00000000..de5b0188 --- /dev/null +++ b/contrib/bobtoolz/bt/ctf-blue.txt @@ -0,0 +1,61 @@ +base_light/light1blue_2000 +base_light/light1blue_5000 +ctf/blue_telep +ctf/ctf_blueflag +ctf/ctf_tower_bluefin_shiny +gothic_door/door02_eblue2_shiny +gothic_light/ironcrossltblue_10000 +gothic_light/ironcrossltblue_2000 +gothic_light/ironcrossltblue_20000 +gothic_light/ironcrossltblue_3000 +gothic_light/ironcrossltblue_30000 +gothic_light/ironcrossltblue_4000 +gothic_light/ironcrossltblue_5000 +sfx/beam_blue +sfx/flameanim_blue +sfx/flameanim_blue_nolight +sfx/flameanim_blue_pj +sfx/mkc_fog_ctfblue +sfx/xbluefog +base_wall2/blue_metal +base_wall2/jumppad_blue_kc +base_wall2/blue_line +base_wall2/double_line_blue +base_wall2/blue_arrow_small +base_wall2/blue_circle +base_wall2/bluearrows +base_wall2/blue_solid +ctf2/blueteam01 +ctf2/blueteam02 +ctf2/xblueteam01 +ctf2/blue_banner02 +proto2/blueflag +proto2/blueob +proto2/marbledoor_blue +proto2/concrete_bluenfx +proto2/bluelight_on +proto2/bsbluelight_on +proto2/rsbluelight_off +proto2/bsbluelight_off +proto2/rsbluelight_on +proto2/bluetrim01 +proto2/blue_zot +proto2/blue_zot2 +proto2/bluea_dcl +proto2/concrete_blue +proto2/teamwerkz_blue1 +proto2/blueflare2 +proto2/blueflare +sfx2/flameanim_blue_lowlite +sfx2/blue_jumpad05 +sfx2/blue_launchpad +sfx2/blue_jumpad +sfx2/blue_jumpad2 +sfx2/blue_jumpad3 +sfx2/bluegoal2 +tim/blue_flagbase +team_icon/the fallen_blue +team_icon/intruders_blue +team_icon/crusaders_blue +team_icon/pagans_blue +team_icon/stroggs_blue \ No newline at end of file diff --git a/contrib/bobtoolz/bt/ctf-red.txt b/contrib/bobtoolz/bt/ctf-red.txt new file mode 100644 index 00000000..68c43dac --- /dev/null +++ b/contrib/bobtoolz/bt/ctf-red.txt @@ -0,0 +1,61 @@ +base_light/light1red_2000 +base_light/light1red_5000 +ctf/red_telep +ctf/ctf_redflag +ctf/ctf_tower_redfin_shiny +gothic_door/door02_bred2_shiny +gothic_light/ironcrossltred_10000 +gothic_light/ironcrossltred_2000 +gothic_light/ironcrossltred_20000 +gothic_light/ironcrossltred_3000 +gothic_light/ironcrossltred_30000 +gothic_light/ironcrossltred_4000 +gothic_light/ironcrossltred_5000 +sfx/beam_red +sfx/flameanim_red +sfx/flameanim_red_nolight +sfx/flameanim_red_pj +sfx/mkc_fog_ctfred +sfx/xredfog +base_wall2/red_metal +base_wall2/jumppad_red_kc +base_wall2/red_line +base_wall2/double_line_red +base_wall2/red_arrow_small +base_wall2/red_circle +base_wall2/redarrows +base_wall2/red_solid +ctf2/redteam01 +ctf2/redteam02 +ctf2/xredteam01x +ctf2/red_banner02 +proto2/redflag +proto2/redob +proto2/marbledoor_red +proto2/concrete_rednfx +proto2/redlight_on +proto2/bsredlight_on +proto2/rsredlight_off +proto2/bsredlight_off +proto2/rsredlight_on +proto2/redtrim01 +proto2/red_zot +proto2/red_zot2 +proto2/reda_dcl +proto2/concrete_red +proto2/teamwerkz_red1 +proto2/redflare2 +proto2/redflare +sfx2/flameanim_red_lowlite +sfx2/red_jumpad05 +sfx2/red_launchpad +sfx2/red_jumpad +sfx2/red_jumpad2 +sfx2/red_jumpad3 +sfx2/redgoal2 +tim/red_flagbase +team_icon/the fallen_red +team_icon/intruders_red +team_icon/crusaders_red +team_icon/pagans_red +team_icon/stroggs_red \ No newline at end of file diff --git a/contrib/bobtoolz/bt/door-tex-trim.txt b/contrib/bobtoolz/bt/door-tex-trim.txt new file mode 100644 index 00000000..5211a98c --- /dev/null +++ b/contrib/bobtoolz/bt/door-tex-trim.txt @@ -0,0 +1,5 @@ +base_support/support1rust +base_support/support1shiny +base_support/support2rust +base_support/wplat1_1 +base_support/plate2_5 \ No newline at end of file diff --git a/contrib/bobtoolz/bt/door-tex.txt b/contrib/bobtoolz/bt/door-tex.txt new file mode 100644 index 00000000..94b352f3 --- /dev/null +++ b/contrib/bobtoolz/bt/door-tex.txt @@ -0,0 +1,10 @@ +base_door/shinymetaldoor +base_door/shinymetaldoor_outside +gothic_door/door02_bred +gothic_door/door02_bred2_shiny +gothic_door/door02_eblue2_shiny +gothic_door/door02_i_ornate5_fin +gothic_door/door02_j +gothic_door/door02_j3 +gothic_door/door02_j4 +gothic_door/door02_k2b \ No newline at end of file diff --git a/contrib/bobtoolz/bt/tp_ent.txt b/contrib/bobtoolz/bt/tp_ent.txt new file mode 100644 index 00000000..09488da9 --- /dev/null +++ b/contrib/bobtoolz/bt/tp_ent.txt @@ -0,0 +1,14 @@ +{ + "entity" "misc_model" + + "offset" "-16" + + "model" "models/mapobjects/trees_sd/tree_a.md3" + "model" "models/mapobjects/trees_sd/tree_b.md3" + "model" "models/mapobjects/trees_sd/tree_c.md3" + "model" "models/mapobjects/trees_sd/tree_d.md3" + + "pitch" "-5" "5" + "yaw" "0" "360" + "scale" "1" "1.3" +} \ No newline at end of file diff --git a/contrib/bobtoolz/cportals.cpp b/contrib/bobtoolz/cportals.cpp new file mode 100644 index 00000000..d56c6b4c --- /dev/null +++ b/contrib/bobtoolz/cportals.cpp @@ -0,0 +1,340 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "CPortals.h" +#include "misc.h" + +#define LINE_BUF 1000 +#define MSG_PREFIX "bobToolz plugin: " + +// these classes are far less of a mess than my code was, +// thanq to G.DeWan 4 the prtview source on which it was based + +CBspPortal::CBspPortal() +{ + memset(this, 0, sizeof(CBspPortal)); +} + +CBspPortal::~CBspPortal() +{ + delete[] point; +} + +void ClampFloat(float* p) +{ + double i; + double frac = modf(*p, &i); + + if(!frac) + return; + + if(fabs(*p - ceil(*p)) < MAX_ROUND_ERROR) + *p = ceilf(*p); + + if(fabs(*p - floor(*p)) < MAX_ROUND_ERROR) + *p = floorf(*p); +} + +bool CBspPortal::Build(char *def, unsigned int pointCnt, bool bInverse) +{ + char *c = def; + unsigned int n; + + point_count = pointCnt; + + if(point_count < 3) + return FALSE; + + point = new CBspPoint[point_count]; + + for(n = 0; n < point_count; n++) + { + for(; *c != 0 && *c != '('; c++); + + if(*c == 0) + return FALSE; + + c++; + + int x; + if(bInverse) + x = point_count - n - 1; + else + x = n; + + sscanf(c, "%f %f %f", &point[x].p[0], &point[x].p[1], &point[x].p[2]); + + ClampFloat(&point[x].p[0]); + ClampFloat(&point[x].p[1]); + ClampFloat(&point[x].p[2]); + } + + return TRUE; +} + +CPortals::CPortals() +{ + memset(this, 0, sizeof(CPortals)); +} + +CPortals::~CPortals() +{ + Purge(); +} + +void CPortals::Purge() +{ + if(node) + delete[] node; + node = NULL; + node_count = 0; +} + +void CPortals::Load() +{ + char buf[LINE_BUF+1]; + + memset(buf, 0, LINE_BUF + 1); + + Purge(); + + Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); + + FILE *in; + + in = fopen(fn, "rt"); + + if(in == NULL) + { + Sys_Printf(" ERROR - could not open file.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + if(strncmp("PRT1", buf, 4) != 0) + { + fclose(in); + + Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &node_count); + + if(node_count > 0xFFFF) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int p_count; + sscanf(buf, "%u", &p_count); + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int p_count2; + sscanf(buf, "%u", &p_count2); + + node = new CBspNode[node_count]; + + unsigned int i; + for(i = 0; i < p_count; i++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int dummy, node1, node2; + sscanf(buf, "%u %u %u", &dummy, &node1, &node2); + + node[node1].portal_count++; + node[node2].portal_count++; + } + + for(i = 0; i < p_count2; i++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int dummy, node1; + sscanf(buf, "%u %u", &dummy, &node1); + + node[node1].portal_count++; + } + + for(i = 0; i < node_count; i++) + node[i].portal = new CBspPortal[node[i].portal_count]; + + fclose(in); + + in = fopen(fn, "rt"); + + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + + unsigned int n; + for(n = 0; n < p_count; n++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); + + return; + } + + unsigned int pCount, node1, node2; + sscanf(buf, "%u %u %u", &pCount, &node1, &node2); + + if(!node[node1].AddPortal(buf, pCount, FALSE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + + if(!node[node2].AddPortal(buf, pCount, TRUE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + } + + for(n = 0; n < p_count2; n++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); + + return; + } + + unsigned int pCount, node1; + sscanf(buf, "%u %u", &pCount, &node1); + + if(!node[node1].AddPortal(buf, pCount, FALSE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + } + + fclose(in); +} + +CBspNode::CBspNode() +{ + portal = NULL; + portal_count = 0; + portal_next = 0; +} + +CBspNode::~CBspNode() +{ + if(portal != NULL) + delete[] portal; +} + +bool CBspNode::AddPortal(char *def, unsigned int pointCnt, bool bInverse) +{ + return portal[portal_next++].Build(def, pointCnt, bInverse); +} diff --git a/contrib/bobtoolz/ctfToolz-GTK.cpp b/contrib/bobtoolz/ctfToolz-GTK.cpp new file mode 100644 index 00000000..e73a27d0 --- /dev/null +++ b/contrib/bobtoolz/ctfToolz-GTK.cpp @@ -0,0 +1,97 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" +#include "misc.h" + +#include "dialogs/dialogs-gtk.h" + +// Radiant function table +_QERFuncTable_1 g_FuncTable; +_QERAppBSPFrontendTable g_BSPTable; // for map name + +BOOL g_bBSPInitDone = FALSE; + +// plugin name +static const char *PLUGIN_NAME = "ctfToolz"; + +// commands in the menu +static const char *PLUGIN_COMMANDS = "About...,Colour Changer...,Swap Light Colours,Change Angles 180,Swap Spawn Points"; + +// globals +GtkWidget *g_pRadiantWnd=NULL; + +static const char *PLUGIN_ABOUT = "ctfToolz for GtkRadiant\n" + "by djbob\n" + "http://www.planetquake.com/toolz\n\n"; + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + +extern "C" LPCSTR WINAPI QERPlug_Init(HMODULE hApp, GtkWidget* pMainWidget) +{ + g_pRadiantWnd = pMainWidget; + memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); + g_FuncTable.m_fVersion = QER_PLUG_VERSION; + g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); + + return "ctfToolz for GTKradiant"; +} + +extern "C" LPCSTR WINAPI QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +extern "C" LPCSTR WINAPI QERPlug_GetCommandList() +{ + return (char*)PLUGIN_COMMANDS; +} + +extern "C" void WINAPI QERPlug_Dispatch (LPCSTR p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + LoadLists(); + + if (!g_bBSPInitDone) + { + g_BSPTable.m_nSize = sizeof(_QERAppBSPFrontendTable); + if ( g_FuncTable.m_pfnRequestInterface( QERAppBSPFrontendTable_GUID, static_cast(&g_BSPTable) ) ) + g_bBSPInitDone = TRUE; + else + { + Sys_ERROR("_QERAppBSPFrontendTable interface request failed\n"); + return; + } + } + + if(!strcmp(p, "About...")) + DoMessageBox(PLUGIN_ABOUT, "About", IDOK); + else if(!strcmp(p, "Colour Changer...")) + DoCTFColourChanger(); + else if(!strcmp(p, "Swap Light Colours")) + DoSwapLights(); + else if(!strcmp(p, "Change Angles 180")) + DoChangeAngles(); + else if(!strcmp(p, "Swap Spawn Points")) + DoSwapSpawns(); +} diff --git a/contrib/bobtoolz/ctfresource_gtk.h b/contrib/bobtoolz/ctfresource_gtk.h new file mode 100644 index 00000000..e0d51870 --- /dev/null +++ b/contrib/bobtoolz/ctfresource_gtk.h @@ -0,0 +1,34 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ctfresource_gtk.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/ctfresource_gtk.rc b/contrib/bobtoolz/ctfresource_gtk.rc new file mode 100644 index 00000000..c3e9d5d8 --- /dev/null +++ b/contrib/bobtoolz/ctfresource_gtk.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "ctfresource_gtk.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "ctfresource_gtk.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "bobCo\0" + VALUE "FileDescription", "All your plugins are belong to us\0" + VALUE "FileVersion", "1, 0, 0, 0\0" + VALUE "InternalName", "ctftoolz\0" + VALUE "LegalCopyright", "Copyright © 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "ctftoolz.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "bobCo ctftoolz\0" + VALUE "ProductVersion", "1, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/bobtoolz/ctftoolz.def b/contrib/bobtoolz/ctftoolz.def new file mode 100644 index 00000000..be5bab42 --- /dev/null +++ b/contrib/bobtoolz/ctftoolz.def @@ -0,0 +1,12 @@ +; plugin.def : Declares the module parameters for the DLL. + +LIBRARY "ctfToolz" +DESCRIPTION 'ctfToolz Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + QERPlug_Init @1 + QERPlug_GetName @2 + QERPlug_GetCommandList @3 + QERPlug_Dispatch @4 + QERPlug_GetFuncTable @5 diff --git a/contrib/bobtoolz/dialogs/AboutDialog.cpp b/contrib/bobtoolz/dialogs/AboutDialog.cpp new file mode 100644 index 00000000..250a231c --- /dev/null +++ b/contrib/bobtoolz/dialogs/AboutDialog.cpp @@ -0,0 +1,62 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AboutDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "AboutDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + + +CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAboutDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDialog) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) + //{{AFX_MSG_MAP(CAboutDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog message handlers + diff --git a/contrib/bobtoolz/dialogs/AboutDialog.h b/contrib/bobtoolz/dialogs/AboutDialog.h new file mode 100644 index 00000000..6467b4a6 --- /dev/null +++ b/contrib/bobtoolz/dialogs/AboutDialog.h @@ -0,0 +1,64 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +#define AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// AboutDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +class CAboutDialog : public CDialog +{ +// Construction +public: + CAboutDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutDialog) + enum { IDD = IDD_ABOUT }; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp b/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp new file mode 100644 index 00000000..ba5f109c --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp @@ -0,0 +1,63 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AutoCaulkDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "AutoCaulkDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog dialog + + +CAutoCaulkDialog::CAutoCaulkDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAutoCaulkDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAutoCaulkDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAutoCaulkDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAutoCaulkDialog) + DDX_Control(pDX, IDC_PROGRESS2, m_prog2); + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAutoCaulkDialog, CDialog) + //{{AFX_MSG_MAP(CAutoCaulkDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog message handlers diff --git a/contrib/bobtoolz/dialogs/AutoCaulkDialog.h b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h new file mode 100644 index 00000000..313a547b --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h @@ -0,0 +1,66 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AutoCaulkDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog dialog + +class CAutoCaulkDialog : public CDialog +{ +// Construction +public: + CAutoCaulkDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAutoCaulkDialog) + enum { IDD = IDD_AUTOCAULK_DIALOG }; + CProgressCtrl m_prog2; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAutoCaulkDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAutoCaulkDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp new file mode 100644 index 00000000..3eca76f8 --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp @@ -0,0 +1,66 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AutoCaulkStartDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "AutoCaulkStartDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog dialog + + +CAutoCaulkStartDialog::CAutoCaulkStartDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAutoCaulkStartDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAutoCaulkStartDialog) + m_bAllowDestruction = FALSE; + m_Warning1 = _T(""); + m_nMode = 0; + //}}AFX_DATA_INIT +} + + +void CAutoCaulkStartDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAutoCaulkStartDialog) + DDX_Check(pDX, IDC_KILLBRUSHES_CHECK, m_bAllowDestruction); + DDX_Text(pDX, IDC_WARNING1_STATIC, m_Warning1); + DDX_Radio(pDX, IDC_AC_NORMAL_RADIO, m_nMode); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAutoCaulkStartDialog, CDialog) + //{{AFX_MSG_MAP(CAutoCaulkStartDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog message handlers diff --git a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h new file mode 100644 index 00000000..753b068c --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h @@ -0,0 +1,71 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AutoCaulkStartDialog.h : header file +// + +#define MODE_AC_NORMAL 0 +#define MODE_AC_BUILD_MINI_PRT 1 +#define MODE_AC_SUPER 2 + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog dialog + +class CAutoCaulkStartDialog : public CDialog +{ +// Construction +public: + CAutoCaulkStartDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAutoCaulkStartDialog) + enum { IDD = IDD_AUTOCAULKSTART_DIALOG }; + BOOL m_bAllowDestruction; + CString m_Warning1; + int m_nMode; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAutoCaulkStartDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAutoCaulkStartDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/BrushCheckDialog.h b/contrib/bobtoolz/dialogs/BrushCheckDialog.h new file mode 100644 index 00000000..776c6137 --- /dev/null +++ b/contrib/bobtoolz/dialogs/BrushCheckDialog.h @@ -0,0 +1,65 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// BrushCheckDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog dialog + +class CBrushCheckDialog : public CDialog +{ +// Construction +public: + CBrushCheckDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CBrushCheckDialog) + enum { IDD = IDD_BRUSHCHECKER_DIALOG }; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CBrushCheckDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CBrushCheckDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/DoorDialog.cpp b/contrib/bobtoolz/dialogs/DoorDialog.cpp new file mode 100644 index 00000000..159d6e15 --- /dev/null +++ b/contrib/bobtoolz/dialogs/DoorDialog.cpp @@ -0,0 +1,92 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DoorDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "DoorDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog dialog + + +CDoorDialog::CDoorDialog(CWnd* pParent /*=NULL*/) + : CDialog(CDoorDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CDoorDialog) + m_fbTextureName = _T(""); + m_bSclMainHor = TRUE; + m_bSclMainVert = TRUE; + m_bSclTrimHor = TRUE; + m_bSclTrimVert = FALSE; + m_trimTextureName = _T(""); + m_trimTexSetBox = _T(""); + m_mainTexSetBox = _T(""); + m_doorDirection = -1; + //}}AFX_DATA_INIT +} + + +void CDoorDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CDoorDialog) + DDX_Text(pDX, IDC_FBTEXTURE_EDIT, m_fbTextureName); + DDX_Check(pDX, IDC_TEXSCALE1_CHECK, m_bSclMainHor); + DDX_Check(pDX, IDC_TEXSCALE2_CHECK, m_bSclMainVert); + DDX_Check(pDX, IDC_TEXSCALE3_CHECK, m_bSclTrimHor); + DDX_Check(pDX, IDC_TEXSCALE4_CHECK, m_bSclTrimVert); + DDX_Text(pDX, IDC_TRIMTEXTURE_EDIT, m_trimTextureName); + DDX_CBString(pDX, IDC_TRIMTEX_COMBO, m_trimTexSetBox); + DDX_CBString(pDX, IDC_MAINTEX_COMBO, m_mainTexSetBox); + DDX_Radio(pDX, IDC_DIR_NS_RADIO, m_doorDirection); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CDoorDialog, CDialog) + //{{AFX_MSG_MAP(CDoorDialog) + ON_BN_CLICKED(IDC_SET_MAINTEX_BTN, OnSetMaintexBtn) + ON_BN_CLICKED(IDC_SET_TRIMTEX_BTN, OnSetTrimtexBtn) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog message handlers + +void CDoorDialog::OnSetMaintexBtn() +{ + UpdateData(TRUE); + m_fbTextureName = m_mainTexSetBox; + UpdateData(FALSE); +} + +void CDoorDialog::OnSetTrimtexBtn() +{ + UpdateData(TRUE); + m_trimTextureName = m_trimTexSetBox; + UpdateData(FALSE); +} diff --git a/contrib/bobtoolz/dialogs/DoorDialog.h b/contrib/bobtoolz/dialogs/DoorDialog.h new file mode 100644 index 00000000..a40fd5b6 --- /dev/null +++ b/contrib/bobtoolz/dialogs/DoorDialog.h @@ -0,0 +1,74 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) +#define AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// DoorDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog dialog + +class CDoorDialog : public CDialog +{ +// Construction +public: + CDoorDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CDoorDialog) + enum { IDD = IDD_DOOR_DIALOG }; + CString m_fbTextureName; + BOOL m_bSclMainHor; + BOOL m_bSclMainVert; + BOOL m_bSclTrimHor; + BOOL m_bSclTrimVert; + CString m_trimTextureName; + CString m_trimTexSetBox; + CString m_mainTexSetBox; + int m_doorDirection; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CDoorDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CDoorDialog) + afx_msg void OnSetMaintexBtn(); + afx_msg void OnSetTrimtexBtn(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/IntersectDialog.cpp b/contrib/bobtoolz/dialogs/IntersectDialog.cpp new file mode 100644 index 00000000..8ffc0fb3 --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectDialog.cpp @@ -0,0 +1,65 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// IntersectDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "IntersectDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog dialog + + +CIntersectDialog::CIntersectDialog(CWnd* pParent /*=NULL*/) + : CDialog(CIntersectDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CIntersectDialog) + m_nBrushOptions = 1; + m_bUseDetail = FALSE; + m_bDuplicateOnly = FALSE; + //}}AFX_DATA_INIT +} + + +void CIntersectDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CIntersectDialog) + DDX_Radio(pDX, IDC_WHOLEMAP_RADIO, m_nBrushOptions); + DDX_Check(pDX, IDC_DETAIL_INCLUDE_CHECK, m_bUseDetail); + DDX_Check(pDX, IDC_DUPLICATEONLY_CHECK, m_bDuplicateOnly); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CIntersectDialog, CDialog) + //{{AFX_MSG_MAP(CIntersectDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog message handlers diff --git a/contrib/bobtoolz/dialogs/IntersectDialog.h b/contrib/bobtoolz/dialogs/IntersectDialog.h new file mode 100644 index 00000000..79a6e3cb --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectDialog.h @@ -0,0 +1,70 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) +#define AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IntersectDialog.h : header file +// + +#define BRUSH_OPT_WHOLE_MAP 0 +#define BRUSH_OPT_SELECTED 1 + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog dialog + +class CIntersectDialog : public CDialog +{ +// Construction +public: + CIntersectDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CIntersectDialog) + enum { IDD = IDD_INTERSECT_DIALOG }; + int m_nBrushOptions; + BOOL m_bUseDetail; + BOOL m_bDuplicateOnly; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CIntersectDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CIntersectDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp b/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp new file mode 100644 index 00000000..77a63985 --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp @@ -0,0 +1,61 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// IntersectInfoDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "IntersectInfoDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog dialog + + +CIntersectInfoDialog::CIntersectInfoDialog(CWnd* pParent /*=NULL*/) + : CDialog(CIntersectInfoDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CIntersectInfoDialog) + //}}AFX_DATA_INIT +} + + +void CIntersectInfoDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CIntersectInfoDialog) + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CIntersectInfoDialog, CDialog) + //{{AFX_MSG_MAP(CIntersectInfoDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog message handlers diff --git a/contrib/bobtoolz/dialogs/IntersectInfoDialog.h b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h new file mode 100644 index 00000000..72709ab3 --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h @@ -0,0 +1,65 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IntersectInfoDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog dialog + +class CIntersectInfoDialog : public CDialog +{ +// Construction +public: + CIntersectInfoDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CIntersectInfoDialog) + enum { IDD = IDD_INTERSECT_INFO_DIALOG }; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CIntersectInfoDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CIntersectInfoDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/PolygonDialog.cpp b/contrib/bobtoolz/dialogs/PolygonDialog.cpp new file mode 100644 index 00000000..e4342192 --- /dev/null +++ b/contrib/bobtoolz/dialogs/PolygonDialog.cpp @@ -0,0 +1,116 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PolygonDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "PolygonDialog.h" +#include "../shapes.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog dialog + + +CPolygonDialog::CPolygonDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPolygonDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPolygonDialog) + m_nSideCount = 3; + m_bInverse = FALSE; + m_bBorder = FALSE; + m_nBorderSize = 8; + m_bAlignTop = FALSE; + //}}AFX_DATA_INIT +} + +void CPolygonDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPolygonDialog) + DDX_Text(pDX, IDC_EDIT1, m_nSideCount); + DDV_MinMaxUInt(pDX, m_nSideCount, 3, MAX_POLYGON_FACES); + DDX_Check(pDX, IDC_INVERSE_CHK, m_bInverse); + DDX_Check(pDX, IDC_BORDER_CHK, m_bBorder); + DDX_Text(pDX, IDC_BORDER_EDIT, m_nBorderSize); + DDV_MinMaxUInt(pDX, m_nBorderSize, 1, 1024); + DDX_Check(pDX, IDC_ALIGN_CHK, m_bAlignTop); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPolygonDialog, CDialog) + //{{AFX_MSG_MAP(CPolygonDialog) + ON_BN_CLICKED(IDC_BORDER_CHK, OnBorderChkClicked) + ON_BN_CLICKED(IDC_INVERSE_CHK, OnInverseChkClickrd) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog message handlers + +BOOL CPolygonDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CPolygonDialog::EnableBordered(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_BORDER_CHK); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + +void CPolygonDialog::EnableBorderEdit(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_BORDER_EDIT); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + +void CPolygonDialog::OnBorderChkClicked() +{ + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); +} + +void CPolygonDialog::OnInverseChkClickrd() +{ + EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); +} + +BOOL CPolygonDialog::GetChkBool(int nID) +{ + CButton* btn = (CButton*)GetDlgItem(nID); + if(btn) + return btn->GetCheck(); + return FALSE; +} diff --git a/contrib/bobtoolz/dialogs/PolygonDialog.h b/contrib/bobtoolz/dialogs/PolygonDialog.h new file mode 100644 index 00000000..d556f500 --- /dev/null +++ b/contrib/bobtoolz/dialogs/PolygonDialog.h @@ -0,0 +1,74 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) +#define AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PolygonDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog dialog + +class CPolygonDialog : public CDialog +{ +// Construction +public: + BOOL GetChkBool(int nID); + void EnableBorderEdit(BOOL bEnable); + void EnableBordered(BOOL bEnable); + CPolygonDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPolygonDialog) + enum { IDD = IDD_POLYGON_DIALOG }; + UINT m_nSideCount; + BOOL m_bInverse; + BOOL m_bBorder; + UINT m_nBorderSize; + BOOL m_bAlignTop; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPolygonDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPolygonDialog) + virtual BOOL OnInitDialog(); + afx_msg void OnBorderChkClicked(); + afx_msg void OnInverseChkClickrd(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/StairDialog.cpp b/contrib/bobtoolz/dialogs/StairDialog.cpp new file mode 100644 index 00000000..c8e60bc2 --- /dev/null +++ b/contrib/bobtoolz/dialogs/StairDialog.cpp @@ -0,0 +1,105 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// StairDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "StairDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog dialog + + +CStairDialog::CStairDialog(CWnd* pParent /*=NULL*/) + : CDialog(CStairDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CStairDialog) + m_nStairHeight = 8; + m_StairDir = 0; + m_StairStyle = 0; + m_riserTexture = _T(""); + m_bDetail = TRUE; + //}}AFX_DATA_INIT +} + +void CStairDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CStairDialog) + DDX_Text(pDX, IDC_EDIT1, m_nStairHeight); + DDV_MinMaxUInt(pDX, m_nStairHeight, 1, 256); + DDX_Radio(pDX, IDC_DIR_N_RADIO, m_StairDir); + DDX_Radio(pDX, IDC_STYLE_ORIG_RADIO, m_StairStyle); + DDX_Text(pDX, IDC_RISER_EDIT, m_riserTexture); + DDV_MaxChars(pDX, m_riserTexture, 256); + DDX_Check(pDX, IDC_DETAIL_CHK, m_bDetail); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CStairDialog, CDialog) + //{{AFX_MSG_MAP(CStairDialog) + ON_BN_CLICKED(IDC_STYLE_BOB_RADIO, OnStyleBobClicked) + ON_BN_CLICKED(IDC_STYLE_ORIG_RADIO, OnStyleOrigClicked) + ON_BN_CLICKED(IDC_STYLE_CORNER_RADIO, OnStyleCornerClicked) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog message handlers + +void CStairDialog::OnStyleBobClicked() +{ + EnableDetail(TRUE); +} + +void CStairDialog::OnStyleOrigClicked() +{ + EnableDetail(FALSE); +} + +void CStairDialog::EnableDetail(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_DETAIL_CHK); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + + +BOOL CStairDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + EnableDetail(m_StairStyle == 1); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CStairDialog::OnStyleCornerClicked() +{ + EnableDetail(FALSE); +} diff --git a/contrib/bobtoolz/dialogs/StairDialog.h b/contrib/bobtoolz/dialogs/StairDialog.h new file mode 100644 index 00000000..c42959af --- /dev/null +++ b/contrib/bobtoolz/dialogs/StairDialog.h @@ -0,0 +1,74 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) +#define AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// StairDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog dialog + +class CStairDialog : public CDialog +{ +// Construction +public: + CStairDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CStairDialog) + enum { IDD = IDD_STAIR_DIALOG }; + UINT m_nStairHeight; + int m_StairDir; + int m_StairStyle; + CString m_riserTexture; + BOOL m_bDetail; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CStairDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CStairDialog) + afx_msg void OnStyleBobClicked(); + afx_msg void OnStyleOrigClicked(); + virtual BOOL OnInitDialog(); + afx_msg void OnStyleCornerClicked(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + void EnableDetail(BOOL bEnable); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/TextureResetDialog.cpp b/contrib/bobtoolz/dialogs/TextureResetDialog.cpp new file mode 100644 index 00000000..10c57f1b --- /dev/null +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.cpp @@ -0,0 +1,81 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// TextureResetDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "TextureResetDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog dialog + + +CTextureResetDialog::CTextureResetDialog(CWnd* pParent /*=NULL*/) + : CDialog(CTextureResetDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTextureResetDialog) + m_bAllTextures = FALSE; + m_TextureName = _T(""); + m_nRotation = 0; + m_fScaleHorizontal = 0.5f; + m_fScaleVertical = 0.5f; + m_nShiftHorizontal = 0; + m_nShiftVertical = 0; + m_bOnlyTexture = FALSE; + m_NewTextureName = _T(""); + //}}AFX_DATA_INIT +} + + +void CTextureResetDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTextureResetDialog) + DDX_Check(pDX, IDC_ALLTEXTURES_CHECK, m_bAllTextures); + DDX_Text(pDX, IDC_RESET_TEXTURE_EDIT, m_TextureName); + DDV_MaxChars(pDX, m_TextureName, 256); + DDX_Text(pDX, IDC_ROTATION_EDIT, m_nRotation); + DDV_MinMaxInt(pDX, m_nRotation, 0, 360); + DDX_Text(pDX, IDC_SCL_HOR_EDIT, m_fScaleHorizontal); + DDX_Text(pDX, IDC_SCL_VERT_EDIT, m_fScaleVertical); + DDX_Text(pDX, IDC_SHFT_HOR_EDIT, m_nShiftHorizontal); + DDX_Text(pDX, IDC_SHFT_VER_EDIT, m_nShiftVertical); + DDX_Check(pDX, IDC_ONLYTEXTURE_CHECK, m_bOnlyTexture); + DDX_Text(pDX, IDC_RESET_NEW_TEXTURE_EDIT, m_NewTextureName); + DDV_MaxChars(pDX, m_NewTextureName, 256); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTextureResetDialog, CDialog) + //{{AFX_MSG_MAP(CTextureResetDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog message handlers diff --git a/contrib/bobtoolz/dialogs/TextureResetDialog.h b/contrib/bobtoolz/dialogs/TextureResetDialog.h new file mode 100644 index 00000000..e0843505 --- /dev/null +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.h @@ -0,0 +1,73 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TextureResetDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog dialog + +class CTextureResetDialog : public CDialog +{ +// Construction +public: + CTextureResetDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CTextureResetDialog) + enum { IDD = IDD_TEXTURE_RESET_DIALOG }; + BOOL m_bAllTextures; + CString m_TextureName; + int m_nRotation; + float m_fScaleHorizontal; + float m_fScaleVertical; + int m_nShiftHorizontal; + int m_nShiftVertical; + BOOL m_bOnlyTexture; + CString m_NewTextureName; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTextureResetDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CTextureResetDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/brushcheckdialog.cpp b/contrib/bobtoolz/dialogs/brushcheckdialog.cpp new file mode 100644 index 00000000..5082d8a5 --- /dev/null +++ b/contrib/bobtoolz/dialogs/brushcheckdialog.cpp @@ -0,0 +1,61 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// BrushCheckDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "BrushCheckDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog dialog + + +CBrushCheckDialog::CBrushCheckDialog(CWnd* pParent /*=NULL*/) + : CDialog(CBrushCheckDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CBrushCheckDialog) + //}}AFX_DATA_INIT +} + + +void CBrushCheckDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CBrushCheckDialog) + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CBrushCheckDialog, CDialog) + //{{AFX_MSG_MAP(CBrushCheckDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog message handlers diff --git a/contrib/bobtoolz/dialogs/dialogs-gtk.cpp b/contrib/bobtoolz/dialogs/dialogs-gtk.cpp new file mode 100644 index 00000000..f59ff754 --- /dev/null +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.cpp @@ -0,0 +1,1894 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "../StdAfx.h" +#include "dialogs-gtk.h" +#include "../funchandlers.h" +#include "../lists.h" +#include "../misc.h" + +/*-------------------------------- + Callback Functions +---------------------------------*/ + +typedef struct { + GtkWidget *cbTexChange; + GtkWidget *editTexOld, *editTexNew; + + GtkWidget *cbScaleHor, *cbScaleVert; + GtkWidget *editScaleHor, *editScaleVert; + + GtkWidget *cbShiftHor, *cbShiftVert; + GtkWidget *editShiftHor, *editShiftVert; + + GtkWidget *cbRotation; + GtkWidget *editRotation; +}dlg_texReset_t; + +dlg_texReset_t dlgTexReset; + +void Update_TextureReseter(); + +static void dialog_button_callback_texreset_update (GtkWidget *widget, gpointer data) +{ + Update_TextureReseter(); +} + +void Update_TextureReseter() +{ + gboolean check; + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexNew), check); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexOld), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleHor), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleVert), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftHor), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftVert), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editRotation), check); +} + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void dialog_button_callback_settex (GtkWidget *widget, gpointer data) +{ + TwinWidget* tw = (TwinWidget*)data; + + GtkEntry* entry = GTK_ENTRY( tw->one ); + GtkCombo* combo = GTK_COMBO( tw->two ); + + const gchar* tex = gtk_entry_get_text(GTK_ENTRY( combo->entry )); + gtk_entry_set_text( entry, tex); +} + +/*-------------------------------- + Data validation Routines +---------------------------------*/ + +bool ValidateTextFloat(const char* pData, char* error_title, float* value) +{ + if(pData) + { + float testNum = (float)atof(pData); + + if((testNum == 0.0f) && strcmp(pData, "0")) + { + DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); + return FALSE; +} + +bool ValidateTextFloatRange(const char* pData, float min, float max, char* error_title, float* value) +{ + char error_buffer[256]; + sprintf(error_buffer, "Please Enter A Floating Point Number Between %.3f and %.3f", min, max); + + if(pData) + { + float testNum = (float)atof(pData); + + if((testNum < min) || (testNum > max)) + { + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; +} + +bool ValidateTextIntRange(const char* pData, int min, int max, char* error_title, int* value) +{ + char error_buffer[256]; + sprintf(error_buffer, "Please Enter An Integer Between %i and %i", min, max); + + if(pData) + { + int testNum = atoi(pData); + + if((testNum < min) || (testNum > max)) + { + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; +} + +bool ValidateTextInt(const char* pData, char* error_title, int* value) +{ + if(pData) + { + int testNum = atoi(pData); + + if((testNum == 0) && strcmp(pData, "0")) + { + DoMessageBox("Please Enter An Integer", error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox("Please Enter An Integer", error_title, MB_OK); + return FALSE; +} + +/*-------------------------------- + Modal Dialog Boxes +---------------------------------*/ + +/* + + Major clean up of variable names etc required, excluding Mars's ones, + which are nicely done :) + +*/ + +int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) +{ + GtkWidget *window, *w, *vbox, *hbox; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoIntersectBox (IntersectRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkWidget *radio1, *radio2; + GtkWidget *check1, *check2; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Intersect"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + radio1 = gtk_radio_button_new_with_label(NULL, "Use Whole Map"); + gtk_box_pack_start (GTK_BOX (vbox), radio1, FALSE, FALSE, 2); + gtk_widget_show (radio1); + + radio2 = gtk_radio_button_new_with_label(((GtkRadioButton*)radio1)->group, "Use Selected Brushes"); + gtk_box_pack_start (GTK_BOX (vbox), radio2, FALSE, FALSE, 2); + gtk_widget_show (radio2); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + check1 = gtk_check_button_new_with_label("Include Detail Brushes"); + gtk_box_pack_start (GTK_BOX (vbox), check1, FALSE, FALSE, 0); + gtk_widget_show (check1); + + check2 = gtk_check_button_new_with_label("Select Duplicate Brushes Only"); + gtk_box_pack_start (GTK_BOX (vbox), check2, FALSE, FALSE, 0); + gtk_widget_show (check2); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- ok/cancel buttons + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + if(gtk_toggle_button_get_active((GtkToggleButton*)radio1)) + rs->nBrushOptions = BRUSH_OPT_WHOLE_MAP; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radio2)) + rs->nBrushOptions = BRUSH_OPT_SELECTED; + + rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; + rs->bDuplicateOnly = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoPolygonBox (PolygonRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox, *vbox2, *hbox2; + + GtkWidget *check1, *check2, *check3; + GtkWidget *text1, *text2; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Polygon Builder"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + + vbox2 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); + gtk_widget_show (vbox2); + + // ---- vbox2 ---- + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + // ---- hbox2 ---- + + text1 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text1, "3"); + gtk_box_pack_start (GTK_BOX (hbox2), text1, FALSE, FALSE, 2); + gtk_widget_show (text1); + + w = gtk_label_new ("Number Of Sides"); + gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox2 ---- + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + // ---- hbox2 ---- + + text2 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text2, "8"); + gtk_box_pack_start (GTK_BOX (hbox2), text2, FALSE, FALSE, 2); + gtk_widget_show (text2); + + w = gtk_label_new ("Border Width"); + gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox2 ---- + + // ---- /vbox2 ---- + + + + vbox2 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); + gtk_widget_show (vbox2); + + // ---- vbox2 ---- + + check1 = gtk_check_button_new_with_label("Use Border"); + gtk_box_pack_start (GTK_BOX (vbox2), check1, FALSE, FALSE, 0); + gtk_widget_show (check1); + + + check2 = gtk_check_button_new_with_label("Inverse Polygon"); + gtk_box_pack_start (GTK_BOX (vbox2), check2, FALSE, FALSE, 0); + gtk_widget_show (check2); + + + check3 = gtk_check_button_new_with_label("Align Top Edge"); + gtk_box_pack_start (GTK_BOX (vbox2), check3, FALSE, FALSE, 0); + gtk_widget_show (check3); + + // ---- /vbox2 ---- + + // ---- /hbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDOK) + { + rs->bUseBorder = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; + rs->bInverse = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; + rs->bAlignTop = gtk_toggle_button_get_active((GtkToggleButton*)check3) ? true : false; + + if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text1), 3, 32, "Number Of Sides", &rs->nSides)) + dialogError = TRUE; + + if(rs->bUseBorder) + { + if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text2), 8, 256, "Border Width", &rs->nBorderWidth)) + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// mars +// for stair builder stuck as close as i could to the MFC version +// obviously feel free to change it at will :) +int DoBuildStairsBox(BuildStairsRS* rs) +{ + // i made widgets for just about everything ... i think that's what i need to do dunno tho + GtkWidget *window, *w, *vbox, *hbox; + GtkWidget *textStairHeight, *textRiserTex, *textMainTex; + GtkWidget *radioNorth, *radioSouth, *radioEast, *radioWest; // i'm guessing we can't just abuse 'w' for these if we're getting a value + GtkWidget *radioOldStyle, *radioBobStyle, *radioCornerStyle; + GtkWidget *checkUseDetail; + GSList *radioDirection, *radioStyle; + int ret, loop; + + loop = 1; + + char *text = "Please set a value in the boxes below and press 'OK' to build the stairs"; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title( GTK_WINDOW( window ), "Stair Builder" ); + + gtk_container_border_width( GTK_CONTAINER( window ), 10 ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // new vbox + vbox = gtk_vbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + gtk_widget_show( vbox ); + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( vbox ), hbox ); + gtk_widget_show( hbox ); + + // dunno if you want this text or not ... + w = gtk_label_new( text ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); // not entirely sure on all the parameters / what they do ... + gtk_widget_show( w ); + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ------------------------- // indenting == good way of keeping track of lines :) + + // new hbox + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textStairHeight = gtk_entry_new_with_max_length( 256 ); + gtk_box_pack_start( GTK_BOX( hbox ), textStairHeight, FALSE, FALSE, 1 ); + gtk_widget_show( textStairHeight ); + + w = gtk_label_new( "Stair Height" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // ------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Direction:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // radio buttons confuse me ... + // but this _looks_ right + + // djbob: actually it looks very nice :), slightly better than the way i did it + // edit: actually it doesn't work :P, you must pass the last radio item each time, ugh + + radioNorth = gtk_radio_button_new_with_label( NULL, "North" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioNorth, FALSE, FALSE, 3 ); + gtk_widget_show( radioNorth ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNorth ) ); + + radioSouth = gtk_radio_button_new_with_label( radioDirection, "South" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioSouth, FALSE, FALSE, 2 ); + gtk_widget_show( radioSouth ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioSouth ) ); + + radioEast = gtk_radio_button_new_with_label( radioDirection, "East" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioEast, FALSE, FALSE, 1 ); + gtk_widget_show( radioEast ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioEast ) ); + + radioWest = gtk_radio_button_new_with_label( radioDirection, "West" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioWest, FALSE, FALSE, 0 ); + gtk_widget_show( radioWest ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Style:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); + gtk_widget_show( w ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + radioOldStyle = gtk_radio_button_new_with_label( NULL, "Original" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioOldStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioOldStyle ); + + radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioOldStyle ) ); + + radioBobStyle = gtk_radio_button_new_with_label( radioStyle, "Bob's Style" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioBobStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioBobStyle ); + + radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioBobStyle ) ); + + radioCornerStyle = gtk_radio_button_new_with_label( radioStyle, "Corner Style" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioCornerStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioCornerStyle ); + + // err, the q3r has an if or something so you need bob style checked before this + // is "ungreyed out" but you'll need to do that, as i suck :) + + // djbob: er.... yeah um, im not at all sure how i'm gonna sort this + // djbob: think we need some button callback functions or smuffin + // FIXME: actually get around to doing what i suggested!!!! + + checkUseDetail = gtk_check_button_new_with_label( "Use Detail Brushes" ); + gtk_box_pack_start( GTK_BOX( hbox ), checkUseDetail, FALSE, FALSE, 0 ); + gtk_widget_show( checkUseDetail ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textMainTex = gtk_entry_new_with_max_length( 512 ); + gtk_entry_set_text(GTK_ENTRY(textMainTex), rs->mainTexture); + gtk_box_pack_start( GTK_BOX( hbox ), textMainTex, FALSE, FALSE, 0 ); + gtk_widget_show( textMainTex ); + + w = gtk_label_new( "Main Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textRiserTex = gtk_entry_new_with_max_length( 512 ); + gtk_box_pack_start( GTK_BOX( hbox ), textRiserTex, FALSE, FALSE, 0 ); + gtk_widget_show( textRiserTex ); + + w = gtk_label_new( "Riser Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // -------------------------- // + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "OK" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + + ret = IDCANCEL; + +// +djbob: need our "little" modal loop mars :P + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDOK) + { + rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)checkUseDetail) ? true : false; + + strcpy(rs->riserTexture, gtk_entry_get_text((GtkEntry*)textRiserTex)); + strcpy(rs->mainTexture, gtk_entry_get_text((GtkEntry*)textMainTex)); + + if(gtk_toggle_button_get_active((GtkToggleButton*)radioNorth)) + rs->direction = MOVE_NORTH; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioSouth)) + rs->direction = MOVE_SOUTH; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioEast)) + rs->direction = MOVE_EAST; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioWest)) + rs->direction = MOVE_WEST; + + if(!ValidateTextInt(gtk_entry_get_text((GtkEntry*)textStairHeight), "Stair Height", &rs->stairHeight)) + dialogError = TRUE; + + if(gtk_toggle_button_get_active((GtkToggleButton*)radioOldStyle)) + rs->style = STYLE_ORIGINAL; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioBobStyle)) + rs->style = STYLE_BOB; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioCornerStyle)) + rs->style = STYLE_CORNER; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +// -djbob + + // there we go, all done ... on my end at least, not bad for a night's work +} + +int DoDoorsBox(DoorRS* rs) +{ + GtkWidget *window, *hbox, *vbox, *w; + GtkWidget *textFrontBackTex, *textTrimTex; + GtkWidget *checkScaleMainH, *checkScaleMainV, *checkScaleTrimH, *checkScaleTrimV; + GtkWidget *comboMain, *comboTrim; + GtkWidget *buttonSetMain, *buttonSetTrim; + GtkWidget *radioNS, *radioEW; + GSList *radioOrientation; + TwinWidget tw1, tw2; + int ret, loop; + + loop = 1; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title( GTK_WINDOW( window ), "Door Builder" ); + + gtk_container_border_width( GTK_CONTAINER( window ), 10 ); + + g_object_set_data( G_OBJECT( window ), "loop", &loop ); + g_object_set_data( G_OBJECT( window ), "ret", &ret ); + + gtk_widget_realize (window); + + char buffer[256]; + GList *listMainTextures = NULL; + GList *listTrimTextures = NULL; + LoadGList(GetFilename(buffer, "plugins/bt/door-tex.txt"), &listMainTextures); + LoadGList(GetFilename(buffer, "plugins/bt/door-tex-trim.txt"), &listTrimTextures); + + vbox = gtk_vbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textFrontBackTex = gtk_entry_new_with_max_length( 512 ); + gtk_entry_set_text( GTK_ENTRY( textFrontBackTex ), rs->mainTexture); + gtk_box_pack_start( GTK_BOX( hbox ), textFrontBackTex, FALSE, FALSE, 0 ); + gtk_widget_show( textFrontBackTex ); + + w = gtk_label_new( "Door Front/Back Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ------------------------ // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textTrimTex = gtk_entry_new_with_max_length( 512 ); + gtk_box_pack_start( GTK_BOX( hbox ), textTrimTex, FALSE, FALSE, 0 ); + gtk_widget_show( textTrimTex ); + + w = gtk_label_new( "Door Trim Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // sp: horizontally ???? + // djbob: yes mars, u can spell :] + checkScaleMainH = gtk_check_button_new_with_label( "Scale Main Texture Horizontally" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainH ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainH, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleMainH ); + + checkScaleTrimH = gtk_check_button_new_with_label( "Scale Trim Texture Horizontally" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleTrimH ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimH, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleTrimH ); + + // ---------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + checkScaleMainV = gtk_check_button_new_with_label( "Scale Main Texture Vertically" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainV ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainV, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleMainV ); + + checkScaleTrimV = gtk_check_button_new_with_label( "Scale Trim Texture Vertically" ); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimV, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleTrimV ); + + // --------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // djbob: lists added + + comboMain = gtk_combo_new(); + gtk_box_pack_start( GTK_BOX( hbox ), comboMain, FALSE, FALSE, 0 ); + gtk_combo_set_popdown_strings( GTK_COMBO( comboMain ), listMainTextures ); + gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); + gtk_widget_show( comboMain ); + + tw1.one = textFrontBackTex; + tw1.two = comboMain; + + buttonSetMain = gtk_button_new_with_label( "Set As Main Texture" ); + gtk_signal_connect( GTK_OBJECT( buttonSetMain ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw1 ); + gtk_box_pack_start( GTK_BOX( hbox ), buttonSetMain, FALSE, FALSE, 0 ); + gtk_widget_show( buttonSetMain ); + + // ------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + comboTrim = gtk_combo_new(); + gtk_box_pack_start( GTK_BOX( hbox ), comboTrim, FALSE, FALSE, 0 ); + gtk_combo_set_popdown_strings( GTK_COMBO( comboTrim ), listTrimTextures ); + gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); + gtk_widget_show( comboTrim ); + + tw2.one = textTrimTex; + tw2.two = comboTrim; + + buttonSetTrim = gtk_button_new_with_label( "Set As Trim Texture" ); + gtk_signal_connect( GTK_OBJECT( buttonSetTrim ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw2 ); + gtk_box_pack_start( GTK_BOX( hbox ), buttonSetTrim, FALSE, FALSE, 0 ); + gtk_widget_show( buttonSetTrim ); + + // ------------------ // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Orientation" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // argh more radio buttons! + radioNS = gtk_radio_button_new_with_label( NULL, "North - South" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioNS, FALSE, FALSE, 0 ); + gtk_widget_show( radioNS ); + + radioOrientation = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNS ) ); + + radioEW = gtk_radio_button_new_with_label( radioOrientation, "East - West" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioEW, FALSE, FALSE, 0 ); + gtk_widget_show( radioEW ); + + // ----------------- // + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "OK" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + ret = IDCANCEL; + + // ----------------- // + +//+djbob + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + strcpy(rs->mainTexture, gtk_entry_get_text( GTK_ENTRY( textFrontBackTex ) )); + strcpy(rs->trimTexture, gtk_entry_get_text( GTK_ENTRY( textTrimTex ) )); + + rs->bScaleMainH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainH)) ? true : false; + rs->bScaleMainV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainV)) ? true : false; + rs->bScaleTrimH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimH)) ? true : false; + rs->bScaleTrimV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimV)) ? true : false; + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioNS))) + rs->nOrientation = DIRECTION_NS; + else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioEW))) + rs->nOrientation = DIRECTION_EW; + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +//-djbob +} + +int DoPathPlotterBox(PathPlotterRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox; + + GtkWidget *text1, *text2, *text3; + GtkWidget *check1, *check2; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text1 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text1, "25"); + gtk_box_pack_start (GTK_BOX (hbox), text1, FALSE, FALSE, 2); + gtk_widget_show (text1); + + w = gtk_label_new ("Number Of Points"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text2 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text2, "3"); + gtk_box_pack_start (GTK_BOX (hbox), text2, FALSE, FALSE, 2); + gtk_widget_show (text2); + + w = gtk_label_new ("Multipler"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + w = gtk_label_new ("Path Distance = dist(start -> apex) * multiplier"); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text3 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text3, "-800"); + gtk_box_pack_start (GTK_BOX (hbox), text3, FALSE, FALSE, 2); + gtk_widget_show (text3); + + w = gtk_label_new ("Gravity"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + check1 = gtk_check_button_new_with_label( "No Dynamic Update" ); + gtk_box_pack_start( GTK_BOX( vbox ), check1, FALSE, FALSE, 0 ); + gtk_widget_show( check1 ); + + check2 = gtk_check_button_new_with_label( "Show Bounding Lines" ); + gtk_box_pack_start( GTK_BOX( vbox ), check2, FALSE, FALSE, 0 ); + gtk_widget_show( check2 ); + + // ---- /vbox ---- + + + // ----------------- // + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Enable" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDYES ) ); + gtk_widget_show( w ); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label( "Disable" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDNO ) ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + + ret = IDCANCEL; + + // ----------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDYES) + { + if(!ValidateTextIntRange(gtk_entry_get_text(GTK_ENTRY(text1)), 1, 200, "Number Of Points", &rs->nPoints)) + dialogError = TRUE; + + if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text2)), 1.0f, 10.0f, "Multiplier", &rs->fMultiplier)) + dialogError = TRUE; + + if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text3)), -10000.0f, -1.0f, "Gravity", &rs->fGravity)) + dialogError = TRUE; + + rs->bNoUpdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check1)) ? true : false; + rs->bShowExtra = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check2)) ? true : false; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoCTFColourChangeBox () +{ + GtkWidget *window, *w, *vbox, *hbox; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "CTF Colour Changer"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + // ---- hbox ---- ok/cancel buttons + + w = gtk_button_new_with_label ("Red->Blue"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Blue->Red"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoResetTextureBox (ResetTextureRS* rs) +{ + Str texSelected; + + GtkWidget *window, *w, *vbox, *hbox, *frame, *table; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + texSelected = "Currently Selected Face: "; + if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() == 1) { + texSelected += GetCurrentTexture(); + } + + w = gtk_label_new (texSelected); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + frame = gtk_frame_new ("Reset Texture Names"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbTexChange = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbTexChange), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbTexChange); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbTexChange, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("Old Name: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editTexOld = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexOld), rs->textureName); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexOld, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editTexOld); + + w = gtk_label_new ("New Name: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editTexNew = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexNew), rs->textureName); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexNew, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editTexNew); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Scales"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbScaleHor = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbScaleHor); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleHor, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Horizontal Scale: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editScaleHor = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleHor), "0.5"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleHor, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editScaleHor); + + + dlgTexReset.cbScaleVert = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbScaleVert); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleVert, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Vertical Scale: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editScaleVert = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleVert), "0.5"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleVert, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editScaleVert); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Shift"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbShiftHor = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbShiftHor); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftHor, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Horizontal Shift: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editShiftHor = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftHor), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftHor, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editShiftHor); + + + dlgTexReset.cbShiftVert = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbShiftVert); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftVert, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Vertical Shift: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editShiftVert = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftVert), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftVert, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editShiftVert); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Rotation"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (1, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbRotation = gtk_check_button_new_with_label("Enabled"); + gtk_widget_show (dlgTexReset.cbRotation); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbRotation, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Rotation Value: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editRotation = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editRotation), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editRotation, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editRotation); + + // ---- /frame ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Use Selected Brushes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Use All Brushes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + Update_TextureReseter(); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret != IDCANCEL) + { + rs->bResetRotation = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); + if(rs->bResetRotation) + if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editRotation)), "Rotation", &rs->rotation)) + dialogError = TRUE; + + rs->bResetScale[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); + if(rs->bResetScale[0]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleHor)), "Horizontal Scale", &rs->fScale[0])) + dialogError = TRUE; + + rs->bResetScale[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); + if(rs->bResetScale[1]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleVert)), "Vertical Scale", &rs->fScale[1])) + dialogError = TRUE; + + rs->bResetShift[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); + if(rs->bResetShift[0]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftHor)), "Horizontal Shift", &rs->fShift[0])) + dialogError = TRUE; + + rs->bResetShift[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); + if(rs->bResetShift[1]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftVert)), "Vertical Shift", &rs->fShift[1])) + dialogError = TRUE; + + rs->bResetTextureName = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); + if(rs->bResetTextureName) + { + strcpy(rs->textureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexOld ))); + strcpy(rs->newTextureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexNew ))); + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoTrainThingBox (TrainThingRS* rs) +{ + Str texSelected; + + GtkWidget *window, *w, *vbox, *hbox, *frame, *table; + + GtkWidget *radiusX, *radiusY; + GtkWidget *angleStart, *angleEnd; + GtkWidget *heightStart, *heightEnd; + GtkWidget *numPoints; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Train Thing"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + gtk_object_set_data (GTK_OBJECT (window), "loop", &loop); + gtk_object_set_data (GTK_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- /hbox ---- + + frame = gtk_frame_new ("Radii"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("X: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + radiusX = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(radiusX), "100"); + gtk_table_attach (GTK_TABLE (table), radiusX, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (radiusX); + + + + w = gtk_label_new ("Y: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + radiusY = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(radiusY), "100"); + gtk_table_attach (GTK_TABLE (table), radiusY, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (radiusY); + + + + frame = gtk_frame_new ("Angles"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Start: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + angleStart = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(angleStart), "0"); + gtk_table_attach (GTK_TABLE (table), angleStart, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (angleStart); + + + + w = gtk_label_new ("End: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + angleEnd = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(angleEnd), "90"); + gtk_table_attach (GTK_TABLE (table), angleEnd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (angleEnd); + + + frame = gtk_frame_new ("Height"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Start: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + heightStart = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(heightStart), "0"); + gtk_table_attach (GTK_TABLE (table), heightStart, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (heightStart); + + + + w = gtk_label_new ("End: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + heightEnd = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(heightEnd), "0"); + gtk_table_attach (GTK_TABLE (table), heightEnd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (heightEnd); + + + + frame = gtk_frame_new ("Points"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Number: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + numPoints = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(numPoints), "0"); + gtk_table_attach (GTK_TABLE (table), numPoints, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (numPoints); + + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret != IDCANCEL) + { + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusX)), "Radius (X)", &rs->fRadiusX)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusY)), "Radius (Y)", &rs->fRadiusY)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleStart)), "Angle (Start)", &rs->fStartAngle)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleEnd)), "Angle (End)", &rs->fEndAngle)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightStart)), "Height (Start)", &rs->fStartHeight)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightEnd)), "Height (End)", &rs->fEndHeight)) + dialogError = TRUE; + + if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(numPoints)), "Num Points", &rs->iNumPoints)) + dialogError = TRUE; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} diff --git a/contrib/bobtoolz/dialogs/dialogs-gtk.h b/contrib/bobtoolz/dialogs/dialogs-gtk.h new file mode 100644 index 00000000..589b994e --- /dev/null +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.h @@ -0,0 +1,98 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct BuildStairsRS{ + char mainTexture[256]; + char riserTexture[256]; + int direction; + int style; + int stairHeight; + qboolean bUseDetail; +}; + +struct ResetTextureRS { + int bResetTextureName; + char textureName[256]; + char newTextureName[256]; + + int bResetScale[2]; + float fScale[2]; + + int bResetShift[2]; + float fShift[2]; + + int bResetRotation; + int rotation; +}; + +struct TrainThingRS { + float fRadiusX, fRadiusY; + float fStartAngle, fEndAngle; + int iNumPoints; + float fStartHeight, fEndHeight; +}; + +struct IntersectRS{ + int nBrushOptions; + qboolean bUseDetail; + qboolean bDuplicateOnly; +}; + +struct PolygonRS{ + qboolean bUseBorder; + qboolean bInverse; + qboolean bAlignTop; + int nSides; + int nBorderWidth; +}; + +struct DoorRS{ + char mainTexture[256]; + char trimTexture[256]; + qboolean bScaleMainH; + qboolean bScaleMainV; + qboolean bScaleTrimH; + qboolean bScaleTrimV; + int nOrientation; +}; + +struct PathPlotterRS{ + int nPoints; + float fMultiplier; + float fGravity; + qboolean bNoUpdate; + qboolean bShowExtra; +}; + +struct TwinWidget{ + GtkWidget* one; + GtkWidget* two; +}; + +int DoMessageBox(const char* lpText, const char* lpCaption, guint32 uType); +int DoIntersectBox(IntersectRS* rs); +int DoPolygonBox(PolygonRS* rs); +int DoResetTextureBox (ResetTextureRS* rs); +int DoBuildStairsBox(BuildStairsRS* rs); +int DoDoorsBox(DoorRS* rs); +int DoPathPlotterBox(PathPlotterRS* rs); +int DoCTFColourChangeBox(); +int DoTrainThingBox (TrainThingRS* rs); + +//GtkWidget* GetProgressWindow(char* title, GtkProgressBar* feedback); diff --git a/contrib/bobtoolz/dialogs/pathplotterdialog.cpp b/contrib/bobtoolz/dialogs/pathplotterdialog.cpp new file mode 100644 index 00000000..2a77f984 --- /dev/null +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.cpp @@ -0,0 +1,85 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PathPlotterDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "PathPlotterDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog dialog + + +CPathPlotterDialog::CPathPlotterDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPathPlotterDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPathPlotterDialog) + m_fGravity = -800.0f; + m_fMultiplier = 3.0f; + m_bNoUpdate = FALSE; + m_nPoints = 25; + m_bShowExtra = FALSE; + //}}AFX_DATA_INIT +} + + +void CPathPlotterDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPathPlotterDialog) + DDX_Text(pDX, IDC_GRAVITY_EDIT, m_fGravity); + DDV_MinMaxFloat(pDX, m_fGravity, -10000.f, -1.f); + DDX_Text(pDX, IDC_MULTIPLIER_EDIT, m_fMultiplier); + DDV_MinMaxFloat(pDX, m_fMultiplier, 1.f, 10.f); + DDX_Check(pDX, IDC_NOUPDATE_CHECK, m_bNoUpdate); + DDX_Text(pDX, IDC_POINTCOUNT_EDIT, m_nPoints); + DDV_MinMaxInt(pDX, m_nPoints, 1, 1000); + DDX_Check(pDX, IDC_SHOWEXTRA_CHECK, m_bShowExtra); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPathPlotterDialog, CDialog) + //{{AFX_MSG_MAP(CPathPlotterDialog) + ON_BN_CLICKED(IDYES, OnYes) + ON_BN_CLICKED(IDNO, OnNo) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog message handlers + +void CPathPlotterDialog::OnYes() +{ + if(UpdateData()) + EndModalLoop(IDYES); +} + +void CPathPlotterDialog::OnNo() +{ + EndModalLoop(IDNO); +} diff --git a/contrib/bobtoolz/dialogs/pathplotterdialog.h b/contrib/bobtoolz/dialogs/pathplotterdialog.h new file mode 100644 index 00000000..749e4da3 --- /dev/null +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.h @@ -0,0 +1,70 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PathPlotterDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog dialog + +class CPathPlotterDialog : public CDialog +{ +// Construction +public: + CPathPlotterDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPathPlotterDialog) + enum { IDD = IDD_PATHPLOTTER_DIALOG }; + float m_fGravity; + float m_fMultiplier; + BOOL m_bNoUpdate; + int m_nPoints; + BOOL m_bShowExtra; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPathPlotterDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPathPlotterDialog) + afx_msg void OnYes(); + afx_msg void OnNo(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/funchandlers-GTK.cpp b/contrib/bobtoolz/funchandlers-GTK.cpp new file mode 100644 index 00000000..57d06b18 --- /dev/null +++ b/contrib/bobtoolz/funchandlers-GTK.cpp @@ -0,0 +1,800 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "dialogs/dialogs-gtk.h" + +#include "DEntity.h" +#include "DShape.h" +#include "DPatch.h" + +#include "misc.h" +#include "shapes.h" +#include "lists.h" +#include "funchandlers.h" +#include "visfind.h" + +// for autocaulk +list exclusionList; // whole brush exclusion +list exclusionList_Face; // single face exclusion + +bool el1Loaded = FALSE; +bool el2Loaded = FALSE; +bool clrLst1Loaded = FALSE; +bool clrLst2Loaded = FALSE; + +DBobView* g_PathView = NULL; +DVisDrawer* g_VisView = NULL; +DTrainDrawer* g_TrainView = NULL; +DTreePlanter* g_TreePlanter = NULL; +// ------------- + +//========================// +// Helper Functions // +//========================// + +void LoadLists() +{ + char buffer[256]; + + if(!el1Loaded) + el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList); + if(!el2Loaded) + el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face); +} + + +//========================// +// Main Functions // +//========================// + +void DoIntersect() +{ + IntersectRS rs; + + if(DoIntersectBox(&rs) == IDCANCEL) + return; + + if(rs.nBrushOptions == BRUSH_OPT_SELECTED) + { + if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) + { + DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK); + return; + } + } + + DEntity world; + + switch(rs.nBrushOptions) + { + case BRUSH_OPT_SELECTED: + { + world.LoadSelectedBrushes(); + break; + } + case BRUSH_OPT_WHOLE_MAP: + { + world.LoadFromEntity(0, FALSE); + break; + } + } + + world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail); + + bool* pbSelectList; + if(rs.bDuplicateOnly) + pbSelectList = world.BuildDuplicateList(); + else + pbSelectList = world.BuildIntersectList(); + + world.SelectBrushes(pbSelectList); + + delete[] pbSelectList; +} + +void DoPolygonsTB() +{ + vec3_t vMin, vMax; + + // figure out vMin and vMax + g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL ); + + DoPolygons( vMin, vMax ); +} + +void DoPolygons(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + PolygonRS rs; + + // ask user for type, size, etc.... + if(DoPolygonBox(&rs) == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + DShape poly; + + if(rs.bInverse) + poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop); + else + { + if(rs.bUseBorder) + poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop); + else + poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop); + + } + + poly.Commit(); + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoFixBrushes() +{ + DMap world; + world.LoadAll(); + + int count = world.FixBrushes(TRUE); + + Sys_Printf("%i invalid/duplicate planes removed\n", count); +} + +void DoResetTextures() +{ + static ResetTextureRS rs; + + const char* texName; + if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1) + { + texName = NULL; + } + else + { + texName = GetCurrentTexture(); + strcpy(rs.textureName, GetCurrentTexture()); + } + + int ret; + if((ret = DoResetTextureBox(&rs)) == IDCANCEL) + return; + + if(rs.bResetTextureName) + texName = rs.textureName; + + if(ret == IDOK) + { + DEntity world; + world.LoadSelectedBrushes(); + world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, + rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE); + } + else + { + DMap world; + world.LoadAll(TRUE); + world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, + rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation); + } +} + +void DoBuildStairs(vec3_t vMin, vec3_t vMax) +{ + BuildStairsRS rs; + + strcpy(rs.mainTexture, GetCurrentTexture()); + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + // ask user for type, size, etc.... + if(DoBuildStairsBox(&rs) == IDOK) + { + // calc brush size + vec3_t size; + VectorSubtract(vMax, vMin, size); + + if(((int)size[2] % rs.stairHeight) != 0) + { + // stairs must fit evenly into brush + DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); + } + else + { + + // Remove Size Brush + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + + // Get Step Count + int numSteps = (int)size[2] / rs.stairHeight; + + if(rs.style == STYLE_CORNER) + { + BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture); + } + else + { + + // Get Step Dimensions + float stairHeight = (float)rs.stairHeight; + float stairWidth; + if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST)) + stairWidth = (size[0])/numSteps; + else + stairWidth = (size[1])/numSteps; + + + // Build Base For Stair (bob's style) + if(rs.style == STYLE_BOB) + Build_Wedge(rs.direction, vMin, vMax, TRUE); + + + // Set First Step Starting Position + vMax[2] = vMin[2] + stairHeight; + SetInitialStairPos(rs.direction, vMin, vMax, stairWidth); + + + // Build The Steps + for(int i = 0; i < numSteps; i++) + { + if(rs.style == STYLE_BOB) + Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail); + else if(rs.style == STYLE_ORIGINAL) + Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction); + + // get step into next position + MoveBlock(rs.direction, vMin, vMax, stairWidth); + vMax[2] += stairHeight; + if(rs.style == STYLE_BOB) + vMin[2] += stairHeight; // wedge bottom must be raised + } + } + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoBuildDoors(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DoorRS rs; + strcpy(rs.mainTexture, GetCurrentTexture()); + + if(DoDoorsBox(&rs) == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + BuildDoorsX2(vMin, vMax, + rs.bScaleMainH, rs.bScaleMainV, + rs.bScaleTrimH, rs.bScaleTrimV, + rs.mainTexture, rs.trimTexture, + rs.nOrientation); // shapes.cpp + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoPathPlotter() +{ + PathPlotterRS rs; + int ret = DoPathPlotterBox(&rs); + if(ret == IDCANCEL) + return; + if(ret == IDNO) + { + if(g_PathView) + delete g_PathView; + return; + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // should be our trigger brush + + DEntity world; + world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner)); + + DEPair* trigger_ep = world.FindEPairByKey("targetname"); + + if(trigger_ep) + { + if(!strcmp(world.m_Classname, "trigger_push")) + { + DEPair* target_ep = world.FindEPairByKey("target"); + if(target_ep) + { + entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL); + if(entTarget) + { + if(g_PathView) + delete g_PathView; + g_PathView = new DBobView; + + g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra); + } + else + DoMessageBox("trigger_push target could not be found.", "Error", MB_OK); + } + else + DoMessageBox("trigger_push has no target.", "Error", MB_OK); + } + else + DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK); + } + else + DoMessageBox("Entity must have a targetname", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoPitBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DShape pit; + + if(pit.BuildPit(vMin, vMax)) + { + pit.Commit(); + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + } + else + DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoMergePatches() +{ + patch_merge_t merge_info; + DPatch mrgPatches[2]; + int i; + + // ensure we have something selected + if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) + { + DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); + return; + } + + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + for (i = 0; i < 2; i++) + { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + if (!brush->pPatch) + { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("You must select ONLY patches", "Error", MB_OK); + return; + } + + mrgPatches[i].LoadFromBrush_t(brush); + } + + /* mrgPatches[0].Transpose(); + mrgPatches[0].RemoveFromRadiant(); + mrgPatches[0].BuildInRadiant();*/ + + merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]); + + if (merge_info.mergable) + { + Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2); + + Sys_Printf("Patches Mergable\n"); + DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]); + + /* mrgPatches[0].RemoveFromRadiant(); + mrgPatches[0].BuildInRadiant(); + + mrgPatches[1].RemoveFromRadiant(); + mrgPatches[1].BuildInRadiant(); + + + delete newPatch;*/ + + if (!newPatch) + { + } else + { + mrgPatches[0].RemoveFromRadiant(); + mrgPatches[1].RemoveFromRadiant(); + + newPatch->BuildInRadiant(); + delete newPatch; + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoSplitPatch() { + DPatch patch; + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) { + DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + + if( !brush->pPatch ) { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("You must select ONLY patches", "Error", MB_OK); + return; + } + + patch.LoadFromBrush_t(brush); + + list patchList = patch.Split( true, true ); + for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) { + (*patches).BuildInRadiant(); + } + + patch.RemoveFromRadiant(); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoVisAnalyse() +{ + char filename[1024]; + + if( g_FuncTable.m_pfnSelectedBrushCount() == 0 ) + { + if(g_VisView) + { + delete g_VisView; + return; + } + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + + DBrush orgBrush; + orgBrush.LoadFromBrush_t(brush, false); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + orgBrush.BuildBounds(); + vec3_t origin; + origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f; + origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f; + origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f; + + + char* rad_filename = g_FuncTable.m_pfnGetMapName(); + if(!rad_filename) + { + DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK); + return; + } + + strcpy(filename, rad_filename); + + char* ext = strrchr(filename, '.')+1; + strcpy(ext, "bsp");// rename the extension + + list *pointList = BuildTrace(filename, origin); + + if(!g_VisView) + { + g_VisView = new DVisDrawer; + g_VisView->Register(); + } + + g_VisView->SetList(pointList); +} + +void DoTrainPathPlot() { + if(g_TrainView) { + delete g_TrainView; + g_TrainView = NULL; + } + + g_TrainView = new DTrainDrawer(); +} + +void DoCaulkSelection( void ) { + DEntity world; + + float fScale[2] = { 0.5f, 0.5f }; + float fShift[2] = { 0.0f, 0.0f }; + + int bResetScale[2] = { false, false }; + int bResetShift[2] = { false, false }; + + world.LoadSelectedBrushes(); + world.LoadSelectedPatches(); + world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true ); +} + +void DoTreePlanter( void ) { + if(g_TreePlanter) { + delete g_TreePlanter; + g_TreePlanter = NULL; + return; + } + + g_TreePlanter = new DTreePlanter(); +} + +void DoDropEnts( void ) { + if(g_TreePlanter) { + g_TreePlanter->DropEntsToGround(); + } +} + +void DoMakeChain( void ) { + DTreePlanter pl; + pl.MakeChain(); +} + +typedef DPoint* pntTripple[3]; + +bool bFacesNoTop[6] = {true, true, true, true, true, false}; + +void DoFlipTerrain( void ) { + vec3_t vUp = { 0.f, 0.f, 1.f }; + int i; + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) { + DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t* brushes[2]; + for( i = 0; i < 2; i++ ) { + brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + } + + DBrush Brushes[2]; + DPlane* Planes[2]; + pntTripple Points[2]; + for( i = 0; i < 2; i++ ) { + Brushes[i].LoadFromBrush_t( brushes[i], false ); + if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("Error", "Error", MB_OK); + return; + } + } + + vec3_t mins1, mins2, maxs1, maxs2; + Brushes[0].GetBounds( mins1, maxs1 ); + Brushes[1].GetBounds( mins2, maxs2 ); + + entity_t* ents[2]; + for( i = 0; i < 2; i++ ) { + ents[i] = brushes[i]->owner; + Brushes[i].RemoveFromRadiant(); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + + + + int dontmatch[2] = { -1, -1 }; + bool found = false; + for( i = 0; i < 3; i++ ) { + for( int j = 0; j < 3 && !found; j++ ) { + if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) { + found = true; + break; + } + } + if(!found) { + dontmatch[0] = i; + break; + } + found = false; + } + if(dontmatch[0] == -1) { + DoMessageBox("Error", "Error", MB_OK); + return; + } + + for( i = 0; i < 3; i++ ) { + for( int j = 0; j < 3 && !found; j++ ) { + if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) { + found = true; + break; + } + } + if(!found) { + dontmatch[1] = i; + break; + } + found = false; + } + if(dontmatch[1] == -1) { + DoMessageBox("Error", "Error", MB_OK); + return; + } + + vec3_t plnpnts1[3]; + vec3_t plnpnts2[3]; + vec3_t plnpntsshr[3]; + + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] ); + for( i = 0; i < 3; i++ ) { + if( dontmatch[0] != i ) { + VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] ); + break; + } + } + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] ); + + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] ); + for( i = 0; i < 3; i++ ) { + if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) { + VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] ); + break; + } + } + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] ); + + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] ); + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] ); + if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) { + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] ); + } else { + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] ); + } + plnpntsshr[2][2] -= 16; + + for( i = 0; i < 3; i++ ) { + if( mins2[i] < mins1[i] ) { + mins1[i] = mins2[i]; + } + if( maxs2[i] > maxs1[i] ) { + maxs1[i] = maxs2[i]; + } + } + + DBrush* newBrushes[2]; + newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); + newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); + + vec3_t normal; + MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal ); + if( normal[2] >= 0 ) { + newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true ); + } else { + newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true ); + } + + MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal ); + if( normal[2] >= 0 ) { + newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true ); + } else { + newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true ); + } + + vec3_t vec; + MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal ); + + VectorSubtract( plnpnts1[2], plnpnts1[1], vec ); + if( DotProduct( vec, normal ) >= 0 ) { + newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); + } else { + newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); + } + + VectorSubtract( plnpnts2[2], plnpnts2[1], vec ); + if( DotProduct( vec, normal ) >= 0 ) { + newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); + } else { + newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); + } + + for( i = 0; i < 2; i++ ) { + newBrushes[i]->RemoveRedundantPlanes(); + newBrushes[i]->BuildInRadiant( false, NULL, ents[i] ); + delete newBrushes[i]; + } + +} diff --git a/contrib/bobtoolz/funchandlers-ctf-GTK.cpp b/contrib/bobtoolz/funchandlers-ctf-GTK.cpp new file mode 100644 index 00000000..e13b6400 --- /dev/null +++ b/contrib/bobtoolz/funchandlers-ctf-GTK.cpp @@ -0,0 +1,214 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "dialogs/dialogs-gtk.h" + +#include "DEntity.h" +#include "DMap.h" + +#include "misc.h" +#include "lists.h" +#include "funchandlers.h" + +// for ctf texture changer +list clrList_Blue; +list clrList_Red; + +BOOL clrLst1Loaded = FALSE; +BOOL clrLst2Loaded = FALSE; + +// ------------- + +//========================// +// Helper Functions // +//========================// + +void LoadLists() +{ + char buffer[256]; + + if(!clrLst1Loaded) + { + clrLst1Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-blue.txt"), &clrList_Blue); + LoadExclusionList(GetFilename(buffer, "plugins/bt/blue.txt"), &clrList_Blue); + } + if(!clrLst2Loaded) + { + clrLst2Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-red.txt"), &clrList_Red); + LoadExclusionList(GetFilename(buffer, "plugins/bt/red.txt"), &clrList_Red); + } +} + + +//========================// +// Main Functions // +//========================// + +void DoCTFColourChanger() +{ + if(!clrLst1Loaded || !clrLst2Loaded) + { + DoMessageBox("CTF texture lists not found, this function will terminate.", "Error", MB_OK); + return; + } + + int ret = DoCTFColourChangeBox(); + if(ret == IDCANCEL) + return; + + int cnt = Min(clrList_Blue.size(), clrList_Red.size()); + + list::const_iterator Texture_change; + list::const_iterator Texture_new; + + float fDummy[2]; + + int eCnt = g_FuncTable.m_pfnGetEntityCount(); + + DMap world; + world.LoadAll(TRUE); + + if(ret == IDYES) + { + Texture_change = clrList_Blue.begin(); + Texture_new = clrList_Red.begin(); + } + else + { + Texture_change = clrList_Red.begin(); + Texture_new = clrList_Blue.begin(); + } + + for(int i = 0; i < cnt; i++) + { + world.ResetTextures((*Texture_change).c_str(), fDummy, fDummy, 0, (*Texture_new).c_str(), TRUE); + + Texture_change++; + Texture_new++; + } +} + +void DoSwapLights() +{ +/* DMap world; + world.LoadAll(); + + for(list::const_iterator loopEnt = world.entityList.begin(); loopEnt != world.entityList.end(); loopEnt++) + { + DEntity* e = (*loopEnt); + DEPair* epLightColour = e->FindEPairByKey("_color"); + if(epLightColour) + { + float r, g, b; + sscanf(epLightColour->value, "%f %f %f", &r, &g, &b); + sprintf(epLightColour->value, "%f %f %f", b, g, r); + DMap::RebuildEntity(e); + } + }*/ + + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("_color", epList->key)) + { + float r, g, b; + sscanf(epList->value, "%f %f %f", &r, &g, &b); + sprintf(epList->value, "%f %f %f", b, g, r); + } + } + } +} + +void DoChangeAngles() +{ + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("angle", epList->key)) + { + float angle; + sscanf(epList->value, "%f", &angle); + angle += 180; + while(angle > 360) + angle -= 360; + + sprintf(epList->value, "%f", angle); + } + } + } +} + +void DoSwapSpawns() +{ + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("classname", epList->key)) + { + if(!strcmp(epList->value, "team_CTF_redplayer")) + sprintf(epList->value, "team_CTF_blueplayer"); + else if(!strcmp(epList->value, "team_CTF_blueplayer")) + sprintf(epList->value, "team_CTF_redplayer"); + + if(!strcmp(epList->value, "team_CTF_redspawn")) + sprintf(epList->value, "team_CTF_bluespawn"); + else if(!strcmp(epList->value, "team_CTF_bluespawn")) + sprintf(epList->value, "team_CTF_redspawn"); + + if(!strcmp(epList->value, "team_CTF_redflag")) + sprintf(epList->value, "team_CTF_blueflag"); + else if(!strcmp(epList->value, "team_CTF_blueflag")) + sprintf(epList->value, "team_CTF_redflag") + ; + if(!strcmp(epList->value, "team_redobelisk")) + sprintf(epList->value, "team_blueobelisk"); + else if(!strcmp(epList->value, "team_blueobelisk")) + sprintf(epList->value, "team_redobelisk"); + } + } + } +} + +/*void test() +{ + DMap world; + world.LoadAll(); + + for(list::const_iterator ents = world.entityList.begin(); ents != world.entityList.end(); ents++) + { + (*ents)->RemoveFromRadiant(); + } +}*/ diff --git a/contrib/bobtoolz/funchandlers.cpp b/contrib/bobtoolz/funchandlers.cpp new file mode 100644 index 00000000..3dcd819a --- /dev/null +++ b/contrib/bobtoolz/funchandlers.cpp @@ -0,0 +1,503 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" + +#include "IntersectDialog.h" +#include "PolygonDialog.h" +#include "StairDialog.h" +#include "DoorDialog.h" +#include "IntersectInfoDialog.h" +#include "BrushCheckDialog.h" +#include "AutoCaulkDialog.h" +#include "AutoCaulkStartDialog.h" +#include "TextureResetDialog.h" +#include "pathplotterdialog.h" + +#include "DEntity.h" +#include "shapes.h" +#include "lists.h" +#include "misc.h" +#include "DShape.h" + +// for autocaulk +list exclusionList; // whole brush exclusion +list exclusionList_Face; // single face exclusion + +BOOL el1Loaded; +BOOL el2Loaded; + +DBobView* g_PathView = NULL; +// ------------- + +/************************ + Global Variables +************************/ + +CPolygonDialog polygonDlg; +CIntersectDialog intrDlg; +CStairDialog stairDlg; +CDoorDialog doorDlg; +CAutoCaulkStartDialog autocaulkDlg; +CTextureResetDialog texRstDlg; +CPathPlotterDialog ppDlg; + +/************************ + --Main Functions-- +************************/ + +void LoadLists() +{ + char buffer[256]; + + if(!el1Loaded) + el1Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el1.txt"), &exclusionList); + if(!el2Loaded) + el2Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el2.txt"), &exclusionList); +} + +void PolygonBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + // ask user for type, size, etc.... + if(polygonDlg.DoModal() == IDOK) + { + DShape poly; + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + if(polygonDlg.m_bInverse) + poly.BuildInversePrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); + else + { + if(polygonDlg.m_bBorder) + poly.BuildBorderedPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_nBorderSize, polygonDlg.m_bAlignTop); + else + poly.BuildRegularPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); + } + + poly.Commit(); + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + + +void IntersectionFinder() +{ + if(intrDlg.DoModal() == IDCANCEL) + return; + + if(intrDlg.m_nBrushOptions == BRUSH_OPT_SELECTED) + { + // ensure we have enough brushes selected + if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) + { + MessageBox(NULL, "Invalid number of brushes selected, choose at least 2", "Error", MB_OK); + return; + } + } + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + DEntity world; + + switch(intrDlg.m_nBrushOptions) + { + case BRUSH_OPT_SELECTED: + { + world.LoadSelectedBrushes(&intrInfoDlg->m_prog1); + break; + } + case BRUSH_OPT_WHOLE_MAP: + { + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + break; + } + } + + world.RemoveNonCheckBrushes(&exclusionList, intrDlg.m_bUseDetail); + BOOL* pbSelectList; + if(intrDlg.m_bDuplicateOnly) + pbSelectList = world.BuildDuplicateList(); + else + pbSelectList = world.BuildIntersectList(); + + world.SelectBrushes(pbSelectList); + + intrInfoDlg->DestroyWindow(); + delete[] pbSelectList; +} + +void StairBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + // ask user for type, size, etc.... + if(stairDlg.DoModal() == IDOK) + { + + // calc brush size + vec3_t size; + _VectorSubtract(vMax, vMin, size); + + + if(((int)size[2] % stairDlg.m_nStairHeight) != 0) + { + // stairs must fit evenly into brush + MessageBox(NULL, "Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); + } + else + { + + // Remove Size Brush + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + + // Get Step Count, Direction of Stairs, Stair Style + int numSteps = (int)size[2] / stairDlg.m_nStairHeight; + int direction = stairDlg.m_StairDir; + int style = stairDlg.m_StairStyle; + + if(stairDlg.m_StairStyle == STYLE_CORNER) + { + BuildCornerStairs(vMin, vMax, numSteps, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture); + } + else + { + // Get Step Dimensions + float stairHeight = (float)stairDlg.m_nStairHeight; + float stairWidth; + if((direction == MOVE_EAST) || (direction == MOVE_WEST)) + stairWidth = (size[0])/numSteps; + else + stairWidth = (size[1])/numSteps; + + + // Build Base For Stair (bob's style) + if(style == STYLE_BOB) + Build_Wedge(direction, vMin, vMax, TRUE); + + + // Set First Step Starting Position + vMax[2] = vMin[2] + stairHeight; + SetInitialStairPos(direction, vMin, vMax, stairWidth); + + + // Build The Steps + for(int i = 0; i < numSteps; i++) + { + if(style == STYLE_BOB) + Build_StairStep_Wedge(direction, vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, stairDlg.m_bDetail); + else if(style == STYLE_ORIGINAL) + Build_StairStep(vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, direction); + + // get step into next position + MoveBlock(direction, vMin, vMax, stairWidth); + vMax[2] += stairHeight; + if(style == STYLE_BOB) + vMin[2] += stairHeight; // wedge bottom must be raised + } + } + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoorBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + + strcpy(doorDlg.m_fbTextureName.GetBuffer(256), g_FuncTable.m_pfnGetCurrentTexture()); + + if(doorDlg.DoModal() == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + BuildDoorsX2(vMin, vMax, + doorDlg.m_bSclMainHor, doorDlg.m_bSclMainVert, + doorDlg.m_bSclTrimHor, doorDlg.m_bSclTrimVert, + (LPCTSTR)doorDlg.m_fbTextureName, + (LPCTSTR)doorDlg.m_trimTextureName, + doorDlg.m_doorDirection); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void FixBrushes() +{ + DEntity world; + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + + intrInfoDlg->DestroyWindow(); + + CBrushCheckDialog* chkDlg = new CBrushCheckDialog(); + chkDlg->Create(IDD_BRUSHCHECKER_DIALOG); + + int count = world.FixBrushes(TRUE, &chkDlg->m_prog1); + + chkDlg->DestroyWindow(); + + Sys_Printf("%i invalid/duplicate planes removed\n", count); +} + +void AutoCaulk() +{ + if(!el1Loaded) + autocaulkDlg.m_Warning1 = "WARNING: Brush exclusion list not found\n, ALL BRUSHES WILL BE USED"; + + if(autocaulkDlg.DoModal() == IDCANCEL) + return; + + if(autocaulkDlg.m_nMode == MODE_AC_BUILD_MINI_PRT) + { + BuildMiniPrt(&exclusionList); + return; + } + + CAutoCaulkDialog* acDlg = new CAutoCaulkDialog; + acDlg->Create(IDD_AUTOCAULK_DIALOG); + + char filename[1204]; + + if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) + { + char* rad_filename = g_BSPTable.m_pfnGetMapName(); + if(!rad_filename) + { + MessageBox(NULL, "An Error Occurred While Trying To Get The Map Filename", "Error", MB_OK); + acDlg->DestroyWindow(); + return; + } + + strcpy(filename, rad_filename); + + char* ext = strrchr(filename, '.')+1; + strcpy(ext, "prt");// rename the extension + } + else + { + IEpair* pEp = g_EpairTable.m_pfnIEpairForProjectKeys(); + char *pn = pEp->ValueForKey("mapspath"); + pEp->DecRef(); + + strcpy( filename, pn ); + strcat( filename, "/ac_prt.prt" ); + } + + DEntity portals; + if(!portals.LoadFromPrt(filename, &acDlg->m_prog1)) + { + MessageBox(NULL, "Failed To Load Portal File", "Error", MB_OK); + acDlg->DestroyWindow(); + return; + } + // load portal file + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + DEntity world; + + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + intrInfoDlg->DestroyWindow(); + + if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) + world.RemoveNonCheckBrushes(&exclusionList, FALSE); + else + world.RemoveNonCheckBrushes(&exclusionList, TRUE); + + world.ResetChecks(&exclusionList_Face); + + int caulkedCount = 0; + int killCnt = world.AutoCaulk(&portals, autocaulkDlg.m_bAllowDestruction, &caulkedCount, &acDlg->m_prog2); + + if(autocaulkDlg.m_bAllowDestruction) + Sys_Printf("%i unrequired brush(es) killed\n", killCnt); + Sys_Printf("%i face(s) caulked\n", caulkedCount); + + acDlg->DestroyWindow(); +} + +void ResetTextures() +{ + texRstDlg.m_TextureName = GetCurrentTexture(); + texRstDlg.m_NewTextureName = GetCurrentTexture(); + + if(texRstDlg.DoModal() == IDCANCEL) + return; + + float fScale[2]; + float fShift[2]; + fScale[1] = texRstDlg.m_fScaleVertical; + fScale[0] = texRstDlg.m_fScaleHorizontal; + + fShift[1] = (float)texRstDlg.m_nShiftVertical; + fShift[0] = (float)texRstDlg.m_nShiftHorizontal; + + DEntity world; + world.LoadFromEntity(0, NULL); + + if(texRstDlg.m_bAllTextures) + world.ResetTextures(NULL, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); + else + world.ResetTextures(texRstDlg.m_TextureName, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); +} + +void PathPlotter() +{ + int ret = ppDlg.DoModal(); + if(ret == IDCANCEL) + return; + if(ret == IDNO) + { + if(g_PathView) + delete g_PathView; + + return; + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DEntity world; + world.LoadEPairList(*g_FuncTable.m_pfnGetEntityKeyValList(brush->owner)); + + DEPair* trigger_ep = world.FindEPairByKey("targetname"); + + if(trigger_ep) + { + if(!strcmp(world.m_Classname, "trigger_push")) + { + DEPair* target_ep = world.FindEPairByKey("target"); + if(target_ep) + { + entity_s* entTarget = FindEntityFromTargetname(target_ep->value); + if(entTarget) + { + if(g_PathView) + delete g_PathView; + g_PathView = new DBobView; + + g_PathView->Begin(trigger_ep->value, target_ep->value, ppDlg.m_fMultiplier, ppDlg.m_nPoints, ppDlg.m_fGravity, ppDlg.m_bNoUpdate, ppDlg.m_bShowExtra); + } + else + MessageBox(NULL, "trigger_push target could not be found.", "Error", MB_OK); + } + else + MessageBox(NULL, "trigger_push has no target.", "Error", MB_OK); + } + else + MessageBox(NULL, "You must select a 'trigger_push' entity.", "Error", MB_OK); + } + else + MessageBox(NULL, "Entity must have a targetname", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void PitBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DShape pit; + + if(pit.BuildPit(vMin, vMax)) + { + pit.Commit(); + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + } + else + MessageBox(NULL, "Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} diff --git a/contrib/bobtoolz/funchandlers.h b/contrib/bobtoolz/funchandlers.h new file mode 100644 index 00000000..d8c1e33c --- /dev/null +++ b/contrib/bobtoolz/funchandlers.h @@ -0,0 +1,72 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "DBobView.h" +#include "DVisDrawer.h" +#include "DTrainDrawer.h" +#include "DTreePlanter.h" + +extern DBobView* g_PathView; +extern DVisDrawer* g_VisView; +extern DTrainDrawer* g_TrainView; +extern DTreePlanter* g_TreePlanter; + +// intersect stuff +#define BRUSH_OPT_WHOLE_MAP 0 +#define BRUSH_OPT_SELECTED 1 + +// defines for stairs +#define MOVE_NORTH 0 +#define MOVE_SOUTH 1 +#define MOVE_EAST 2 +#define MOVE_WEST 3 + +#define STYLE_ORIGINAL 0 +#define STYLE_BOB 1 +#define STYLE_CORNER 2 + +// defines for doors +#define DIRECTION_NS 0 +#define DIRECTION_EW 1 + +// help +void LoadLists(); + + +// djbob +void DoIntersect( void ); +void DoPolygonsTB( void ); +void DoPolygons(vec3_t vMin, vec3_t vMax); +void DoFixBrushes( void ); +void DoResetTextures( void ); +void DoBuildStairs(vec3_t vMin, vec3_t vMax); +void DoBuildDoors(vec3_t vMin, vec3_t vMax); +void DoPathPlotter( void ); +void DoPitBuilder(vec3_t vMin, vec3_t vMax); +void DoCTFColourChanger( void ); +void DoMergePatches( void ); +void DoSplitPatch( void ); +void DoVisAnalyse( void ); +void DoTrainThing( void ); +void DoTrainPathPlot( void ); +void DoCaulkSelection( void ); +void DoTreePlanter( void ); +void DoDropEnts( void ); +void DoMakeChain( void ); +void DoFlipTerrain( void ); diff --git a/contrib/bobtoolz/interfaces/IScriptParser.h b/contrib/bobtoolz/interfaces/IScriptParser.h new file mode 100644 index 00000000..934a9671 --- /dev/null +++ b/contrib/bobtoolz/interfaces/IScriptParser.h @@ -0,0 +1,23 @@ +#ifndef _ISCRIPTPARSER_H_ +#define _ISCRIPTPARSER_H_ + +class IScriptParser { +public: + virtual ~IScriptParser() {}; + + virtual const char* GetToken ( bool ) = 0; + virtual char* GetBufferCopy ( void ) = 0; + virtual int GetTokenOffset ( void ) = 0; + + virtual void SkipBracedSection ( void ) = 0; + virtual void SkipRestOfLine ( void ) = 0; + virtual void UndoGetToken ( void ) = 0; + virtual void ResetParseSession ( void ) = 0; + + virtual void LoadScript ( const char* ) = 0; + virtual void SetScript ( char* ) = 0; + + virtual void AddBreakChar( char ) = 0; +}; + +#endif diff --git a/contrib/bobtoolz/lists.cpp b/contrib/bobtoolz/lists.cpp new file mode 100644 index 00000000..b4a97815 --- /dev/null +++ b/contrib/bobtoolz/lists.cpp @@ -0,0 +1,85 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "lists.h" +#include "misc.h" + +bool LoadExclusionList(char* filename, list* exclusionList) +{ + FILE* eFile = fopen(filename, "r"); + if(eFile) + { + char buffer[256]; + int cnt = 0; + while(!feof(eFile)) + { + memset(buffer, 0, 256); + fscanf(eFile, "%s\n", buffer); + + if(strlen(buffer) > 0) + exclusionList->push_back(buffer); + else + cnt++; + } + + fclose(eFile); + + return TRUE; + } + + Sys_ERROR("Failed To Load Exclusion List: %s\n", filename); + return FALSE; +} + +bool LoadGList(char* filename, GList** loadlist) +{ + FILE* eFile = fopen(filename, "r"); + if(eFile) + { + char buffer[256]; + int cnt = 0; + while(!feof(eFile)) + { + memset(buffer, 0, 256); + fscanf(eFile, "%s\n", buffer); + + if(strlen(buffer) > 0) + { + char* buffer2 = new char[strlen(buffer) + 1]; + strcpy(buffer2, buffer); + *loadlist = g_list_append(*loadlist, buffer2); + } + else + cnt++; + } + + fclose(eFile); + + return TRUE; + } + + Sys_ERROR("Failed To Load GList: %s\n", filename); + return FALSE; +} diff --git a/contrib/bobtoolz/lists.h b/contrib/bobtoolz/lists.h new file mode 100644 index 00000000..d71e7594 --- /dev/null +++ b/contrib/bobtoolz/lists.h @@ -0,0 +1,21 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +bool LoadExclusionList(char* filename, list* exclusionList); +bool LoadGList(char* filename, GList** loadlist); diff --git a/contrib/bobtoolz/misc.cpp b/contrib/bobtoolz/misc.cpp new file mode 100644 index 00000000..bebc2b24 --- /dev/null +++ b/contrib/bobtoolz/misc.cpp @@ -0,0 +1,424 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "DEntity.h" +#include "funchandlers.h" + +#ifdef __linux__ +#include +#include +#endif + +/*========================== + Global Vars +==========================*/ + +//HANDLE bsp_process; +char g_CurrentTexture[256] = ""; + +//============================================================= +//============================================================= + +void ReadCurrentTexture() +{ + const char* textureName = g_FuncTable.m_pfnGetCurrentTexture(); + strcpy(g_CurrentTexture, textureName); +} + +const char* GetCurrentTexture() +{ + ReadCurrentTexture(); + return g_CurrentTexture; +} + +epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value) +{ + epair_t* nextEPair = g_FuncTable.m_pfnAllocateEpair(key, value); + + if(lastItem != NULL) + lastItem->next = nextEPair; + + return nextEPair; +} + +void MoveBlock(int dir, vec3_t min, vec3_t max, float dist) +{ + switch(dir) + { + case MOVE_EAST: + { + min[0]+=dist; + max[0]+=dist; + break; + } + case MOVE_WEST: + { + min[0]-=dist; + max[0]-=dist; + break; + } + case MOVE_NORTH: + { + min[1]+=dist; + max[1]+=dist; + break; + } + case MOVE_SOUTH: + { + min[1]-=dist; + max[1]-=dist; + break; + } + } +} + +void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width) +{ + switch(dir) + { + case MOVE_EAST: + { + max[0] = min[0] + width; + break; + } + case MOVE_WEST: + { + min[0] = max[0] - width; + break; + } + case MOVE_NORTH: + { + max[1] = min[1] + width; + break; + } + case MOVE_SOUTH: + { + min[1] = max[1] - width; + break; + } + } +} + +char* TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; i%s", buf); +} + +/*void Sys_Printf (char *text, ...) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text,argptr); + va_end (argptr); + + g_FuncTable.m_pfnSysMsg ( buf ); +}*/ + +char* UnixToDosPath(char* path) +{ +#ifndef _WIN32 + return path; +#else + for(char* p = path; *p; p++) + { + if(*p == '/') + *p = '\\'; + } + return path; +#endif +} + +const char* ExtractFilename(const char* path) +{ + char* p = strrchr(path, '/'); + if(!p) + { + p = strrchr(path, '\\'); + + if(!p) + return path; + } + return ++p; +} + +extern char* PLUGIN_NAME; +/*char* GetGameFilename(char* buffer, const char* filename) +{ + strcpy(buffer, g_FuncTable.m_pfnGetGamePath()); + char* p = strrchr(buffer, '/'); + *++p = '\0'; + strcat(buffer, filename); + buffer = UnixToDosPath(buffer); + return buffer; +}*/ + +#if defined (__linux__) || defined (__APPLE__) +// the bCreateConsole parameter is ignored on linux .. +bool Q_Exec( const char *pCmd, bool bCreateConsole ) +{ + switch (fork()) + { + case -1: + return false; +// Error ("CreateProcess failed"); + break; + case 0: +#ifdef _DEBUG + printf("Running system...\n"); + printf("Command: %s\n", pCmd); +#endif + // NOTE: we could use that to detect when a step finishes. But then it + // would not work for remote compiling stuff. +// execlp (pCmd, pCmd, NULL); + system( pCmd ); + printf ("system() returned"); + _exit (0); + break; + } + return true; +} +#endif + +#ifdef _WIN32 +bool Q_Exec( const char *pCmd, bool bCreateConsole ) +{ + // G_DeWan: Don't know if this is needed for linux version + + PROCESS_INFORMATION pi; + STARTUPINFO si = {0}; // Initialize all members to zero + si.cb = sizeof(STARTUPINFO); // Set byte count + DWORD dwCreationFlags; + + if (bCreateConsole) + dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; + else + dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; + + for(; *pCmd == ' '; pCmd++); + + if(!CreateProcess(NULL, (char *)pCmd, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) + return false; + + return true; +} +#endif + +void StartBSP() +{ + char exename[256]; + GetFilename(exename, "q3map"); + UnixToDosPath(exename); // do we want this done in linux version? + + char mapname[256]; + const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); + + strcpy( mapname, pn ); + strcat( mapname, "/ac_prt.map" ); + UnixToDosPath(mapname); + + char command[1024]; + sprintf(command, "%s -nowater -fulldetail %s", exename, mapname); + + Q_Exec( command, TRUE ); +} + +void BuildMiniPrt(list* exclusionList) +{ + // yes, we could just use -fulldetail option, but, as SPOG said + // it'd be faster without all the hint, donotenter etc textures and + // doors, etc + + DEntity world; + + char buffer[128]; + const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); + + strcpy( buffer, pn ); + strcat( buffer, "/ac_prt.map" ); + FILE* pFile = fopen(buffer, "w"); + + // ahem, thx rr2 + if(!pFile) + return; + + int count = g_FuncTable.m_pfnGetEntityCount(); + for(int i = 0; i < count; i++) + { + entity_t* ent = (entity_t*)g_FuncTable.m_pfnGetEntityHandle(i); + + epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(ent); + + epair_t* ep = epl; + while(ep) + { + if(!strcmp(ep->key, "classname")) + { + if(!strcmp(ep->value, "worldspawn")) + { + world.LoadFromEntity(i, FALSE); + world.RemoveNonCheckBrushes(exclusionList, TRUE); + world.SaveToFile(pFile); + } + else if(strstr(ep->value, "info_")) + { + world.ClearBrushes(); + world.ClearEPairs(); + world.LoadEPairList(epl); + world.SaveToFile(pFile); + } + break; + } + + ep = ep->next; + } + } + + fclose(pFile); + + StartBSP(); +} + +entity_s* FindEntityFromTargetname(const char* targetname, int* entNum) +{ + DEntity world; + + int count = g_FuncTable.m_pfnGetEntityCount(); + for(int i = 0; i < count; i++) + { + world.ClearEPairs(); + + entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); + + world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); + + DEPair* tn = world.FindEPairByKey("targetname"); + if(tn) + { + if(!stricmp(tn->value, targetname)) { + if(entNum) { + *entNum = i; + } + return ent; + } + } + } + return NULL; +} + +void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture) +{ + faceData->m_bBPrimit = FALSE; + faceData->m_fRotate = 0; + faceData->m_fScale[0] = 0.5; + faceData->m_fScale[1] = 0.5; + faceData->m_fShift[0] = 0; + faceData->m_fShift[1] = 0; + faceData->m_nContents = 0; + faceData->m_nFlags = 0; + faceData->m_nValue = 0; + if(*texture) + strcpy(faceData->m_TextureName, texture); + else + strcpy(faceData->m_TextureName, "textures/common/caulk"); + VectorCopy(va, faceData->m_v1); + VectorCopy(vb, faceData->m_v2); + VectorCopy(vc, faceData->m_v3); +} + +float Determinant3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3) +{ + return a1*(b2*c3-b3*c2) - a2*(b1*c3-b3*c1) + a3*(b1*c2-b2*c1); +} + +bool GetEntityCentre(const char* entity, vec3_t centre) +{ + entity_s* ent = FindEntityFromTargetname(entity, NULL); + if(!ent) + return FALSE; + + int cnt = g_FuncTable.m_pfnAllocateEntityBrushHandles(ent); + if(cnt == 0) + { + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + return FALSE; + } + + brush_t* brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(0); + DBrush cBrush; + cBrush.LoadFromBrush_t(brush, FALSE); + + vec3_t min, max; + cBrush.GetBounds(min, max); + + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + return TRUE; +} + +vec_t Min(vec_t a, vec_t b) +{ + if(a < b) + return a; + return b; +} + +void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ) { + vec3_t v1, v2; + VectorSubtract(va, vb, v1); + VectorSubtract(vc, vb, v2); + CrossProduct(v1, v2, out); +} diff --git a/contrib/bobtoolz/misc.h b/contrib/bobtoolz/misc.h new file mode 100644 index 00000000..c02a99e9 --- /dev/null +++ b/contrib/bobtoolz/misc.h @@ -0,0 +1,48 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +vec_t Min(vec_t a, vec_t b); + +epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value); + +// reads current texture into global, returns pointer to it +const char* GetCurrentTexture(); + +void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture); + +void Sys_ERROR (char* text, ...); + +void BuildMiniPrt(list* exclusionList); + +void MoveBlock(int dir, vec3_t min, vec3_t max, float dist); +void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width); + +entity_s* FindEntityFromTargetname(const char* targetname, int* entNum); + +char* UnixToDosPath(char* path); + +char* GetFilename(char* buffer, const char* filename); +char* GetGameFilename(char* buffer, const char* filename); + +float Determinant3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3); + +bool GetEntityCentre(const char* entity, vec3_t centre); +void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ); diff --git a/contrib/bobtoolz/res/plugin.rc2 b/contrib/bobtoolz/res/plugin.rc2 new file mode 100644 index 00000000..2def5721 --- /dev/null +++ b/contrib/bobtoolz/res/plugin.rc2 @@ -0,0 +1,13 @@ +// +// SOUNDTEST.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/contrib/bobtoolz/resource-gtk.h b/contrib/bobtoolz/resource-gtk.h new file mode 100644 index 00000000..e4522dff --- /dev/null +++ b/contrib/bobtoolz/resource-gtk.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bobtoolz-gtk.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/resource.h b/contrib/bobtoolz/resource.h new file mode 100644 index 00000000..999d639b --- /dev/null +++ b/contrib/bobtoolz/resource.h @@ -0,0 +1,115 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bobToolz.rc +// +#define IDD_PATHPLOTTER_DIALOG 101 +#define IDD_ABOUT 129 +#define IDD_STAIR_DIALOG 130 +#define IDD_POLYGON_DIALOG 131 +#define IDB_BT_BITMAP 137 +#define IDI_ICON1 139 +#define IDD_POLYGON_BRD_DIALOG 141 +#define IDD_DOOR_DIALOG 141 +#define IDD_INTERSECT_DIALOG 143 +#define IDD_INTERSECT_INFO_DIALOG 144 +#define IDD_BRUSHCHECKER_DIALOG 146 +#define IDD_AUTOCAULK_DIALOG 147 +#define IDD_AUTOCAULKSTART_DIALOG 148 +#define IDD_TEXTURE_RESET_DIALOG 149 +#define IDC_EDIT1 1000 +#define IDC_DIR_N_RADIO 1001 +#define IDC_TRIMTEXTURE_EDIT 1001 +#define IDC_SCL_VERT_EDIT 1001 +#define IDC_DIR_S_RADIO 1002 +#define IDC_SCL_HOR_EDIT 1002 +#define IDC_POINTCOUNT_EDIT 1002 +#define IDC_DIR_E_RADIO 1003 +#define IDC_ROTATION_EDIT 1003 +#define IDC_MULTIPLIER_EDIT 1003 +#define IDC_DIR_W_RADIO 1004 +#define IDC_SHFT_VER_EDIT 1004 +#define IDC_GRAVITY_EDIT 1004 +#define IDC_STYLE_ORIG_RADIO 1005 +#define IDC_SHFT_HOR_EDIT 1005 +#define IDC_NOUPDATE_CHECK 1005 +#define IDC_STYLE_BOB_RADIO 1006 +#define IDC_SHOWEXTRA_CHECK 1006 +#define IDC_STYLE_CORNER_RADIO 1007 +#define IDC_RISER_EDIT 1011 +#define IDC_FLAT_EDIT 1012 +#define IDC_MAX_WALL_WIDTH 1013 +#define IDC_MIN_WALL_WIDTH 1014 +#define IDC_DETAIL_CHK 1014 +#define IDC_MAX_CLIFF_HEIGHT 1015 +#define IDC_INVERSE_CHK 1015 +#define IDC_MIN_CLIFF_HEIGHT 1016 +#define IDC_BORDER_CHK 1016 +#define IDC_ALIGN_CHK 1017 +#define IDC_BORDER_EDIT 1018 +#define IDC_MAX_CNR_SIZE 1019 +#define IDC_MIN_CNR_SIZE 1020 +#define IDC_FBTEXTURE_EDIT 1020 +#define IDC_GRID_SNAP 1021 +#define IDC_TEXSCALE1_CHECK 1021 +#define IDC_MAX_WALL_BREADTH 1022 +#define IDC_TEXSCALE2_CHECK 1022 +#define IDC_MIN_WALL_BREADTH 1023 +#define IDC_MAINTEX_COMBO 1023 +#define IDC_TEXSCALE3_CHECK 1024 +#define IDC_TEXSCALE4_CHECK 1025 +#define IDC_TRIMTEX_COMBO 1026 +#define IDC_SET_MAINTEX_BTN 1027 +#define IDC_SET_TRIMTEX_BTN 1028 +#define IDC_WHOLEMAP_CHECK 1030 +#define IDC_DETAIL_INCLUDE_CHECK 1031 +#define IDC_SKIPBOUNDS_CHECK 1032 +#define IDC_SKIPSIMPLE_CHECK 1033 +#define IDC_SKIPACCURATE_CHECK 1034 +#define IDC_PROGRESS1 1035 +#define IDC_INTR_PROG1 1035 +#define IDC_DIR_NS_RADIO 1036 +#define IDC_PROGRESS2 1036 +#define IDC_DIR_EW_RADIO 1037 +#define IDC_DIR_GROUP 1038 +#define IDC_WHOLEMAP_RADIO 1040 +#define IDC_SELECTED_RADIO 1041 +#define IDC_KILLBRUSHES_CHECK 1041 +#define IDC_WARNING1_STATIC 1042 +#define IDC_AC_NORMAL_RADIO 1043 +#define IDC_AC_BUILD_MINI_PRT_RADIO 1044 +#define IDC_AC_SUPER_RADIO 1045 +#define IDC_RESET_TEXTURE_EDIT 1046 +#define IDC_RESET_NEW_TEXTURE_EDIT 1047 +#define IDC_ONLYTEXTURE_CHECK 1048 +#define IDC_ALLTEXTURES_CHECK 1049 +#define IDC_DUPLICATEONLY_CHECK 1050 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/shapes.cpp b/contrib/bobtoolz/shapes.cpp new file mode 100644 index 00000000..d69023ee --- /dev/null +++ b/contrib/bobtoolz/shapes.cpp @@ -0,0 +1,666 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "StdAfx.h" + +#include "shapes.h" + +#include "DPlane.h" + +#include "misc.h" +#include "funchandlers.h" + +//#include "dialogs-gtk.h" + +/************************ + Cube Diagram +************************/ + +/* + + 7 ----- 5 + /| /| + / | / | + / | / | + 4 ----- 6 | + | 2|_|___|8 + | / | / + | / | / ----> WEST, definitely + |/ | / + 1|_____|/3 + +*/ + +/************************ + Global Variables +************************/ + +vec3_t g_Origin = {0.0f, 0.0f, 0.0f}; + +extern bool bFacesAll[]; + +/************************ + Helper Functions +************************/ + +float Deg2Rad(float angle) +{ + return (float)(angle*Q_PI/180); +} + +void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail) +{ + _QERFaceData faceData; + FillDefaultTexture(&faceData, va, vb, vc, texture); + if(detail) + faceData.m_nContents |= FACE_DETAIL; + + g_FuncTable.m_pfnAddFaceData(brush, &faceData); +} + +void AddFaceWithTextureScaled(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, + const char* texture, bool bVertScale, bool bHorScale, + float minX, float minY, float maxX, float maxY) +{ + g_ShadersTable.m_pfnShader_ForName(texture); // need to call frist to load? + + qtexture_t* pqtTexInfo; + + // TTimo: there used to be a call to pfnHasShader here + // this was not necessary. In Radiant everything is shader. + // If a texture doesn't have a shader script, a default shader object is used. + // The IShader object was leaking also + // collect texture info: sizes, etc + IShader* i = g_ShadersTable.m_pfnShader_ForName(texture); + pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly + + if(pqtTexInfo) + { + float scale[2] = {0.5f, 0.5f}; + float shift[2] = {0, 0}; + + if(bHorScale) + { + int texWidth = pqtTexInfo->width; + float width = maxX - minX; + + scale[0] = width/texWidth; + shift[0] = -(float)((int)maxX%(int)width)/scale[0]; + } + + if(bVertScale) + { + int texHeight = pqtTexInfo->height; + float height = maxY - minY; + + scale[1] = height/texHeight; + shift[1] = (float)((int)minY%(int)height)/scale[1]; + } + + _QERFaceData addFace; + FillDefaultTexture(&addFace, va, vb, vc, texture); + addFace.m_fScale[0] = scale[0]; + addFace.m_fScale[1] = scale[1]; + addFace.m_fShift[0] = shift[0]; + addFace.m_fShift[1] = shift[1]; + + g_FuncTable.m_pfnAddFaceData(brush, &addFace); + } + else + { + // shouldn't even get here, as default missing texture should be returned if + // texture doesn't exist, but just in case + AddFaceWithTexture(brush, va, vb, vc, texture, FALSE); + Sys_ERROR("BobToolz::Invalid Texture Name-> %s", texture); + } + // the IShader is not kept referenced, DecRef it + i->DecRef(); +} + +/************************ + --Main Functions-- +************************/ + +void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + vec3_t v1, v2, v3, v5, v6, v7, v8; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + VectorCopy(max, v8); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + v8[2] = min[2]; + + if(bUp) + { + + if(dir != MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); + + if(dir != MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + if(dir != MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); + + AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v5, "textures/common/caulk", FALSE); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v2, v6, v8, "textures/common/caulk", FALSE); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v6, v5, "textures/common/caulk", FALSE); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v3, v8, "textures/common/caulk", FALSE); + } + else + { + if(dir != MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); + + if(dir != MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_NORTH) + AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_SOUTH) + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + + AddFaceWithTexture(newBrush, v6, v5, v7, "textures/common/caulk", FALSE); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", FALSE); + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", FALSE); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", FALSE); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", FALSE); + } + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7, v8; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + VectorCopy(max, v8); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + v8[2] = min[2]; + //v8 needed this time, becoz of sloping faces (2-4-6-8) + + //---------------------------------- + + AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, detail); + + if(dir != MOVE_EAST) + { + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v5, v2, v7, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v5, v2, v7, "textures/common/caulk", detail); + } + + if(dir != MOVE_WEST) + { + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", detail); + } + + if(dir != MOVE_NORTH) + { + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", detail); + } + + if(dir != MOVE_SOUTH) + { + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", detail); + } + + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", detail); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", detail); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", detail); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", detail); + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +// internal use only, to get a box without finishing construction +brush_t* Build_Get_BoundingCube_Selective(vec3_t min, vec3_t max, char* texture, bool* useFaces) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(useFaces[0]) + AddFaceWithTexture(newBrush, v1, v2, v3, texture, FALSE); + if(useFaces[1]) + AddFaceWithTexture(newBrush, v1, v3, v6, texture, FALSE); + if(useFaces[2]) + AddFaceWithTexture(newBrush, v1, v7, v2, texture, FALSE); + + if(useFaces[3]) + AddFaceWithTexture(newBrush, v5, v6, v3, texture, FALSE); + if(useFaces[4]) + AddFaceWithTexture(newBrush, v5, v2, v7, texture, FALSE); + if(useFaces[5]) + AddFaceWithTexture(newBrush, v5, v7, v6, texture, FALSE); + + //---------------------------------- + + return newBrush; +} + +brush_t* Build_Get_BoundingCube(vec3_t min, vec3_t max, char* texture) +{ + return Build_Get_BoundingCube_Selective(min, max, texture, bFacesAll); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, FALSE); + // top gets current texture + + + if(direction == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + // west facing side, etc... + + + if(direction == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + if(direction == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", FALSE); + + if(direction == MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v2, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v7, v5, v2, "textures/common/caulk", FALSE); + + + AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); + // base is caulked + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); + // finish brush +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void BuildDoorsX2(vec3_t min, vec3_t max, + bool bSclMainHor, bool bSclMainVert, + bool bSclTrimHor, bool bSclTrimVert, + const char* mainTexture, const char* trimTexture, + int direction) +{ + int xy; + if(direction == 0) + xy = 0; + else + xy = 1; + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + float width = (max[xy] - min[xy])/2; + + if(direction == 0) + { + VectorCopy(v1, ve_1); + VectorCopy(v3, ve_2); + VectorCopy(v6, ve_3); + } + else + { + VectorCopy(v7, ve_1); + VectorCopy(v1, ve_2); + VectorCopy(v2, ve_3); + } + + ve_1[xy] += width; + ve_2[xy] += width; + ve_3[xy] += width; + + //---------------------------------- + + brush_t* newBrush1 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + brush_t* newBrush2 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + AddFaceWithTexture(newBrush1, v1, v2, v3, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush1, v5, v7, v6, "textures/common/caulk", FALSE); + + AddFaceWithTexture(newBrush2, v1, v2, v3, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v7, v6, "textures/common/caulk", FALSE); + + if(direction == 0) + { + AddFaceWithTexture(newBrush1, v1, v3, v6, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v2, v7, "textures/common/caulk", FALSE); + } + else + { + AddFaceWithTexture(newBrush1, v1, v7, v2, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v6, v3, "textures/common/caulk", FALSE); + } + + if(direction == 0) + { + AddFaceWithTextureScaled(newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, + min[0], min[2], max[0], max[2]); + AddFaceWithTextureScaled(newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, + max[0], min[2], min[0], max[2]); + + + AddFaceWithTextureScaled(newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, + min[0], min[2], max[0], max[2]); + AddFaceWithTextureScaled(newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, + max[0], min[2], min[0], max[2]); // flip max/min to reverse tex dir + + + + AddFaceWithTextureScaled(newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, + min[1], min[2], max[1], max[2]); + + AddFaceWithTextureScaled(newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, + max[1], min[2], min[1], max[2]); + } + else + { + AddFaceWithTextureScaled(newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, + min[1], min[2], max[1], max[2]); + AddFaceWithTextureScaled(newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, + max[1], min[2], min[1], max[2]); + + + AddFaceWithTextureScaled(newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, + min[1], min[2], max[1], max[2]); + AddFaceWithTextureScaled(newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, + max[1], min[2], min[1], max[2]); // flip max/min to reverse tex dir + + + AddFaceWithTextureScaled(newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, + min[0], min[2], max[0], max[2]); + + AddFaceWithTextureScaled(newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, + max[0], min[2], min[0], max[2]); + } + + //---------------------------------- + + + entity_t* pEDoor1 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + entity_t* pEDoor2 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + + epair_t* epDoor11 = GetNextChainItem(NULL, "classname", "func_door"); + epair_t* epDoor21 = GetNextChainItem(NULL, "classname", "func_door"); + + epair_t* epDoor12; + epair_t* epDoor22; + + if(direction == 0) + { + epDoor12 = GetNextChainItem(epDoor11, "angle", "180"); + epDoor22 = GetNextChainItem(epDoor21, "angle", "360"); + } + else + { + epDoor12 = GetNextChainItem(epDoor11, "angle", "270"); + epDoor22 = GetNextChainItem(epDoor21, "angle", "90"); + } + + srand((unsigned)time(NULL)); + + char teamname[256]; + sprintf(teamname, "t%i", rand()); + /*epair_t* epDoor13 = */ GetNextChainItem(epDoor12, "team", teamname); + /*epair_t* epDoor23 = */ GetNextChainItem(epDoor22, "team", teamname); + + g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush1, pEDoor1); + g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush2, pEDoor2); + + g_EntityTable.m_pfnSetEntityKeyValList(pEDoor1, epDoor11); + g_EntityTable.m_pfnSetEntityKeyValList(pEDoor2, epDoor21); + + g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor1); + g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor2); + +// ResetCurrentTexture(); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void MakeBevel(vec3_t vMin, vec3_t vMax) +{ + int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); + + pm->height = 3; + pm->width = 3; + + vec3_t x_3, y_3, z_3; + x_3[0] = vMin[0]; x_3[1] = vMin[0]; x_3[2] = vMax[0]; + y_3[0] = vMin[1]; y_3[1] = vMax[1]; y_3[2] = vMax[1]; + z_3[0] = vMin[2]; z_3[1] = (vMax[2] + vMin[2])/2; z_3[2] = vMax[2]; + +/* x_3[0] = 0; x_3[1] = 0; x_3[2] = 64; + y_3[0] = 0; y_3[1] = 64; y_3[2] = 64; + z_3[0] = 0; z_3[1] = 32; z_3[2] = 64;*/ + + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + pm->ctrl[i][j].xyz[0] = x_3[i]; + pm->ctrl[i][j].xyz[1] = y_3[i]; + pm->ctrl[i][j].xyz[2] = z_3[j]; + } + } + + + g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, "textures/common/caulk"); +} + +void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex) +{ + vec3_t* topPoints = new vec3_t[nSteps+1]; + vec3_t* botPoints = new vec3_t[nSteps+1]; + + bool bFacesUse[6] = {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE}; + + vec3_t centre; + VectorCopy(vMin, centre); + centre[0] = vMax[0]; + + int height = (int)(vMax[2] - vMin[2]) / nSteps; + + vec3_t vTop, vBot; + VectorCopy(vMax, vTop); + VectorCopy(vMin, vBot); + vTop[2] = vMin[2] + height; + + int i; + for(i = 0; i <= nSteps; i++) + { + VectorCopy(centre, topPoints[i]); + VectorCopy(centre, botPoints[i]); + + topPoints[i][2] = vMax[2]; + botPoints[i][2] = vMin[2]; + + topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) ); + topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) ); + + botPoints[i][0] = topPoints[i][0]; + botPoints[i][1] = topPoints[i][1]; + } + + vec3_t tp[3]; + for(int j = 0; j < 3; j++) + VectorCopy(topPoints[j], tp[j]); + + for(i = 0; i < nSteps; i++) + { + brush_t* brush = Build_Get_BoundingCube_Selective(vBot, vTop, "textures/common/caulk", bFacesUse); + + for(int j = 0; j < 3; j++) + tp[j][2] = vTop[2]; + + AddFaceWithTexture(brush, tp[2], tp[1], tp[0], mainTexture, FALSE); + + AddFaceWithTexture(brush, centre, botPoints[i+1], topPoints[i+1], "textures/common/caulk", FALSE); + AddFaceWithTexture(brush, centre, topPoints[i], botPoints[i], riserTex, FALSE); + + g_FuncTable.m_pfnCommitBrushHandle(brush); + + vTop[2] += height; + vBot[2] += height; + } + + delete[] topPoints; + delete[] botPoints; + + vMin[2] += height; + vMax[2] += height; + MakeBevel(vMin, vMax); +} diff --git a/contrib/bobtoolz/shapes.h b/contrib/bobtoolz/shapes.h new file mode 100644 index 00000000..e5fccd9c --- /dev/null +++ b/contrib/bobtoolz/shapes.h @@ -0,0 +1,49 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// TODO: implement all this stuff via DBrush class. started with DShape +// TODO: Auto Face Scaling, no need to pass parms, calculated via brush. + +// Q3MAP stuff +#define FACE_DETAIL 0x8000000 + +// defines for polygon stuff +#define MAX_POLYGON_FACES 128 + +// generic (detail added 12/01/01, for AC+) +void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail); + +// ------------- +// ---caulked--- +// ------------- +void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp); + +// -------------- +// ---textured--- +// -------------- +void BuildDoorsX2(vec3_t min, vec3_t max, bool bSclMainHor, bool bSclMainVert, bool bSclTrimHor, bool bSclTrimVert, const char* mainTexture, const char* trimTexture, int direction); +void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction); +void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail); +void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex); +// stairs stuff. + +//void Build_Prism_Border(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop = FALSE); //moved to DShape +//void Build_Prism_Ordinary(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape +//void Build_Prism_Efficient(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape +// polygon stuff. diff --git a/contrib/bobtoolz/txt/changelog.txt b/contrib/bobtoolz/txt/changelog.txt new file mode 100644 index 00000000..c7440a5e --- /dev/null +++ b/contrib/bobtoolz/txt/changelog.txt @@ -0,0 +1,96 @@ +BobToolz Changelog: +[=================] + +Changes in v1110 (GTK): +[=====================] + +djbob + +Added: +(16.05.01) + Impemented a little feature that highligths the q3map bug that is causing problems for autocaulk, (see readme) +(01.04.01) + Added DPatch class to implement patches, however radiant does not (currently) support adding patches to an entity via a plugin, so, its actually redundant atm, i was adding this to fix the patches being removed from entities probelm with dealing with entities outside of the worldspawn. + +Changes: +(02.04.01) + EPair keys and values can now be 128 characters long, not 64, happy now hydra? + Texture reseter works on patches now too. + +Removed: +(29.03.01) + Removed CTF colour changer, it is now in the ctftoolz. + +Fixed: +(02.04.01) + Worldspawn brushes are rebuilt per brush, rather than per entity in texture reseter. +(03.04.01) + Worldspawn brushes are rebuilt per brush, rather than per entity in brush cleanup. + +Changes in v1100 (GTK): +[=====================] + +djbob + +Added: +(24.03.01) + Added CTF colour changer for worldspawn+func_group. + +Changes: +(25.03.01) + Brought some functions over to using DMap class, allowing them to run on multiple entities, patches are still a no-no atm. + This includes: + + a) brush cleanup, will now fix problems on brushes that are not in the worldspawn, and rebuild the entitiy afterwards. + b) texture reseter will change textures on all brushes now, not just those in the worldspawn. + c) CTF colour changer will also work on brushes outside of the worldspawn entity. + +This introduces one prolem, patches in entities will no longer be part of the new entity, sorry for any trouble this causes, i will fix it soon hopefully. + +Fixes: +(25.03.01) + Fixed bug in DMap class that prevented it destroying brushes... thus enabling the class to work!!!! + +Changes in v1090 (GTK): +[=====================] + +djbob + +Added: +(22.03.01) + Added PitOMatic Function. + +Changes in v1080b (GTK): +[======================] + +djbob + +Fixes: + Removed some previously unnoticed porting introduced bugs. + +Added: + Polygon stuff now passes through my internal validation routines, no more phantom brushes will be made, or squiffy planes. + +Changes in v1080 (GTK): +[=====================] + +djbob + +Fixes: +(05.03.01) + Fixed line removed by rr2 in autocaulk. + Fixed Autocaulk not working with maps larger than the old grid. + +Added: +(04.03.01) + Added Changelog. + Added ability to align polygons so that top edge will be flat. (Request By Casey) +(05.03.01) + Added ability to change main texture for stairs. + +rr2do2 + +Changes: +(??.??.01) + Removed all traces of MFC from GTK version, the evil that it is ;] + diff --git a/contrib/bobtoolz/txt/readme.txt b/contrib/bobtoolz/txt/readme.txt new file mode 100644 index 00000000..d816b5b1 --- /dev/null +++ b/contrib/bobtoolz/txt/readme.txt @@ -0,0 +1,77 @@ +BobToolz GTK: v1100 +[=================] + +Date: +[===] +16.05.01 + +The multipurpose Quake3 Mappers Tool +[==================================] + +Author: djbob +Other work: q3terra, ctftoolz, EECA mod + +eMail: gbiggans@uglab.eee.strath.ac.uk (NO SPAM thank u very much :P) + +www: www.planetquake.com/toolz + www.planetquake.com/eeca + +IRC: #freepq irc.fdf.net + #qeradiant irc.telefragged.com + +Files Contained In This Package: +[==============================] + +Readme.txt --- This file. +Changelog.txt --- Version information. +bobToolz.dll --- The plugin itsself. +bt/*.txt --- A few text files required by the plugin. + + +What's a boy to do? +[=================] + +Put The plugin in your GTKRadiant plugins folder: +e.g. mine: c:\gamez\quake3\GTKRadiant\plugins + +Run Radiant, and select the toolz from the dropdown plugin menu. + +Help is available in the form of a manual on my site. + + + +For the new q3map bug highlighting feature, run autocaulk-build mini prt, then run autocaulk. +identify an area which has been caulked incorrectly, then reopen the map, select the q3map bug highlight option, and wait. +once the selected brushes appear, u have 2 choices, + +a) press i and remove all the original brushes, or +b) keep going with both sets (slower, but more useful) + +navigate to the problem region, you should find that the set of inverse brushes that has been built is missing a brush +at the problem area, i suppose the next problem is finding out why :] + +this function is mainly provided for other coders to show the problem, and is probably of little use to anyone else, +but u never know. + + +Coming Soon: +[==========] +Region area saving. perhaps, if i get the time to finish it. + + +Testing, Feedback & Ideas: +[========================] + + Akuma, Casey, Cartman2K, maverik, rayden, nephilim_goth and god knows who else. + Thx to you all. + +Thanx: +[====] + + ttimo, da man :] + spog, for his often baffling advice.... and questions.... + Thx to rr2do2, for his linux conversion, and removing the "evil" (his words :]) MFC code. + Thx to RKone, for improving my q3w sig. + Azr for giving me ops in #qeradiant, k3wl :] + Everyone at the Quake3World Forums, I think of you all as my little worshippers :P + id Software, of course. \ No newline at end of file diff --git a/contrib/bobtoolz/visfind.cpp b/contrib/bobtoolz/visfind.cpp new file mode 100644 index 00000000..28525ff9 --- /dev/null +++ b/contrib/bobtoolz/visfind.cpp @@ -0,0 +1,245 @@ +// Requries parts of the q3 tools source to compile +// Date: Oct 5, 2001 +// Written by: Brad Whitehead (whiteheb@gamerstv.net) + +#include "StdAfx.h" +#include "dialogs/dialogs-gtk.h" +#include "DWinding.h" +#include "bsploader.h" + +typedef struct { + int portalclusters; + int leafbytes; //leafbytes = ((portalclusters+63)&~63)>>3; +} vis_header; + +// added because int shift = 32; i = 0xFFFFFFFF >> shift; +// then i = 0xFFFFFFFF, when it should = 0 +const unsigned long bitmasks[33] = +{ + 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +}; + +int bsp_leafnumfororigin(vec3_t origin) +{ + dnode_t *node; + dplane_t *plane; + float d; + + // TODO: check if origin is in the map?? + + node = dnodes; + while (true) + { + plane = &dplanes[node->planeNum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if ( d >= 0 ) + if ( node->children[0] < 0 ) + return -(node->children[0]+1); + else + node = &dnodes[node->children[0]]; + else + if ( node->children[1] < 0 ) + return -(node->children[1]+1); + else + node = &dnodes[node->children[1]]; + } + return 0; +} + +int bsp_leafnumforcluster(int cluster) +{ + dleaf_t *l; + int i; + + for ( i = 0, l = dleafs; i < numleafs; i++, l++ ) + if ( l->cluster == cluster ) return(i); + return(0); +} + +// leaf1 = origin leaf +// leaf2 = leaf to test for +/*int bsp_InPVS(int cluster1, int cluster2) +{ + vis_header *vheader; + byte *visdata; + + vheader = (vis_header *) visBytes; + visdata = visBytes + VIS_HEADER_SIZE; + + return( *( visdata + ( cluster1 * vheader->leafbytes ) + (cluster2 / 8) ) & ( 1 << ( cluster2 % 8 ) ) ); +}*/ + +void bsp_setbitvectorlength( byte *v, int length_bits, int length_vector ) +{ + int i; + + i = length_bits/8; + + *(v+i) = (byte) bitmasks[length_bits % 8]; + + memset((v+i+1), 0, length_vector-i-1); +} + + +void bsp_bitvectorsubtract(byte *first, byte *second, byte *out, int length) +{ + + int i; + + for ( i = 0; i < length; i++ ) + *(out+i) = *(first+i) & ~(*(second+i)); +} + +int bsp_countclusters(byte *bitvector, int length) +{ + int i, j, c; + + c = 0; + for ( i = 0; i < length; i++ ) + for ( j = 0; j < 8; j++ ) + if ( (*(bitvector+i) & (1 << j)) ) c++; + return(c); +} + +int bsp_countclusters_mask(byte *bitvector, byte *maskvector, int length) +{ + int i, j, c; + + c = 0; + for ( i = 0; i < length; i++ ) + for ( j = 0; j < 8; j++ ) + if ( (*(bitvector+i) & (1 << j)) && (*(maskvector+i) & (1 << j)) ) c++; + return(c); +} + +void AddCluster(list *pointlist, dleaf_t *cl, qboolean* repeatlist, vec3_t clr) +{ + DWinding* w; + + int* leafsurf = &dleafsurfaces[cl->firstLeafSurface]; + for(int k = 0; k < cl->numLeafSurfaces; k++, leafsurf++) + { + if(repeatlist[*leafsurf]) + continue; + + dsurface_t* surf = &drawSurfaces[*leafsurf]; + if(surf->surfaceType != MST_PLANAR) + continue; + + qdrawVert_t* vert = &drawVerts[surf->firstVert]; + if(surf->firstVert + surf->numVerts > numDrawVerts) + DoMessageBox("Warning", "Warning", MB_OK); + + w = new DWinding(); + w->AllocWinding(surf->numVerts); + + for (int l = 0; l < surf->numVerts; l++, vert++) + { + (w->p[l])[0] = vert->xyz[0]; + (w->p[l])[1] = vert->xyz[1]; + (w->p[l])[2] = vert->xyz[2]; + + w->clr[0] = clr[0]; + w->clr[1] = clr[1]; + w->clr[2] = clr[2]; + } + pointlist->push_back(w); + + repeatlist[*leafsurf] = true; + } +} + +/* +============= +CreateTrace +============= +*/ +list *CreateTrace( dleaf_t *leaf, int c, vis_header *header, byte *visdata, byte *seen ) +{ + byte *vis; + int i, j, clusterNum; + list *pointlist = new list; + qboolean* repeatlist = new qboolean[numDrawSurfaces]; + dleaf_t *cl; + + vec3_t clrRnd[5] = { + {0.f, 0.f, 1.f}, + {0.f, 1.f, 1.f}, + {1.f, 0.f, 0.f}, + {1.f, 0.f, 1.f}, + {1.f, 1.f, 0.f}, + }; + + vec3_t clrGreen = {0.f, 1.f, 0.f}; + + memset(repeatlist, 0, sizeof(qboolean)*numDrawSurfaces); + + vis = visdata + ( c * header->leafbytes ); + + clusterNum = 0; + + AddCluster(pointlist, &(dleafs[bsp_leafnumforcluster( c )]), repeatlist, clrGreen); + + for ( i = 0; i < header->leafbytes; i++ ) + { + for ( j = 0; j < 8; j++ ) + { + cl = &(dleafs[bsp_leafnumforcluster( clusterNum )]); + + if ( ( *(vis + i) & (1 << j) ) && (*(seen+i) & (1 << j)) && (leaf->area == cl->area)) + AddCluster(pointlist, cl, repeatlist, clrRnd[rand()%5]); + clusterNum++; + } + } + + delete repeatlist; + + return pointlist; +} + +/* +============= +TraceCluster + +setup for CreateTrace +============= +*/ +list *TraceCluster (int leafnum) +{ + byte seen[(MAX_MAP_LEAFS/8) + 1]; + vis_header *vheader; + byte *visdata; + dleaf_t *leaf; + + vheader = (vis_header *) visBytes; + visdata = visBytes + sizeof(vis_header); + + memset(seen, 0xFF, sizeof(seen)); + bsp_setbitvectorlength(seen, vheader->portalclusters, sizeof(seen)); + + leaf = &(dleafs[leafnum]); + + return CreateTrace(leaf, leaf->cluster, vheader, visdata, seen); +} + +list* BuildTrace(char* filename, vec3_t v_origin) +{ + if(!LoadBSPFile(filename)) + return NULL; + + int leafnum = bsp_leafnumfororigin(v_origin); + + list *pointlist = TraceCluster(leafnum); + + FreeBSPData(); + + return pointlist; +} diff --git a/contrib/bobtoolz/visfind.h b/contrib/bobtoolz/visfind.h new file mode 100644 index 00000000..732f3b6c --- /dev/null +++ b/contrib/bobtoolz/visfind.h @@ -0,0 +1 @@ +list *BuildTrace(char* filename, vec3_t v_origin); diff --git a/contrib/camera/bitmaps/camera_insp.bmp b/contrib/camera/bitmaps/camera_insp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1286716ed0224332b47a73b0f14f4edccf1af436 GIT binary patch literal 320 zcmYjNTMmFA3>$1QCVprzTYcwi^#eI%vl_!gZfXJRal&*nkyCG9yRqiwH4+ z5(VpJsbGKogkuq<7LmkMe>{_0tBQadXxw1VQBz1EHle%lq3~oxBW@^M%rv|8;6925 awT?ZzU$oc$F*Rl**U#wOn>uTc9Kr{8e+#1k literal 0 HcmV?d00001 diff --git a/contrib/camera/camera.cpp b/contrib/camera/camera.cpp new file mode 100644 index 00000000..9ac94f44 --- /dev/null +++ b/contrib/camera/camera.cpp @@ -0,0 +1,292 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +// Render view +CRenderer *Renderer = NULL; + +// Interaction +CListener *Listener = NULL; + +// plugin name +static const char *PLUGIN_NAME = "Camera"; + +// commands in the menu +static const char *PLUGIN_COMMANDS = "About...,-,Load Camera...,-,Preview Camera,-,Camera Inspector...,-,New Spline Camera,New Interpolated Camera,New Fixed Camera"; + +// globals +GtkWidget *g_pRadiantWnd = NULL; +GtkWidget *g_pCameraInspectorWnd = NULL; +CCamera *firstCam = NULL; // double linked list +CCamera *firstFreeCam = NULL; // single linked list +CCamera *currentCam = NULL; // single item +bool g_bEditOn = false; +int g_iEditMode = 0; // 0: editting points 1: adding points +int g_iActiveTarget = -1; +int g_iPreviewRunning = 0; // 0: no preview 1: start preview 2: preview in progress + +static const char *PLUGIN_ABOUT = "Camera v1.0 for GtkRadiant\n" + "by Arnout van Meer (rr2do2@splashdamage.com)\n\n" + "This product contains software technology\n" + "from id Software, Inc. ('id Technology').\n" + "id Technology (c) 2001, 2002 id Software, Inc."; + + +#include "iplugin.h" + +const char* QERPlug_Init(void* hApp, void* pMainWidget) +{ + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + // initialize cams + for( int i = 0; i < MAX_CAMERAS; i++ ) { + if( i == 0 ) { + firstFreeCam = new CCamera( i ); + firstCam = firstFreeCam; + } else { + firstCam->SetNext( new CCamera( i ) ); + firstCam = firstCam->GetNext(); + } + } + firstCam = NULL; + + if( !Renderer ) + { + Renderer = new CRenderer; + } + + if( g_pCameraInspectorWnd == NULL ) + g_pCameraInspectorWnd = CreateCameraInspectorDialog(); + + InitIglToQgl(&g_QglTable); + + GetFileTypeRegistry()->addType("camera", filetype_t("Camera file", "*.camera")); + + return "Camera for GtkRadiant"; +} + +const char* QERPlug_GetName() +{ + return PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +void QERPlug_Dispatch (const char* p, float* vMin, float* vMax, bool bSingleBrush) +{ + if( !strcmp( p, "New Fixed Camera" ) ) + DoNewFixedCamera(); + else if( !strcmp( p, "New Interpolated Camera" ) ) + DoNewInterpolatedCamera(); + else if( !strcmp( p, "New Spline Camera" ) ) + DoNewSplineCamera(); + else if( !strcmp( p, "Camera Inspector..." ) ) + DoCameraInspector(); + else if( !strcmp( p, "Preview Camera" ) ) + DoPreviewCamera(); + else if( !strcmp( p, "Load Camera..." ) ) + DoLoadCamera(); + else if( !strcmp( p, "About..." ) ) + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, PLUGIN_ABOUT, "About", MB_OK, NULL ); +} + + +// toolbar + +#include "itoolbar.h" + +unsigned int ToolbarButtonCount() +{ + return 1; +} + +class CameraInspectorButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + return "camera_insp.bmp"; + } + virtual const char* getText() const + { + return "Inspector"; + } + virtual const char* getTooltip() const + { + return "Camera Inspector"; + } + virtual void activate() const + { + DoCameraInspector(); + } + virtual EType getType() const + { + return eButton; + } +}; + +CameraInspectorButton g_camerainspectorbutton; + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + return &g_camerainspectorbutton; +} + + +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERUITable g_UITable; +_QERCameraTable g_CameraTable; + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class CameraSynapseClient : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CameraSynapseClient() { } + virtual ~CameraSynapseClient() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +CameraSynapseClient g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "camera", sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "camera", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable), SYN_REQUIRE, &g_UITable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); + g_SynapseClient.AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable), SYN_REQUIRE, &g_CameraTable); + + return &g_SynapseClient; +} + +bool CameraSynapseClient::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CameraSynapseClient::GetInfo() +{ + return "Camera plugin v1.0 - Arnout van Meer - built " __DATE__ " " RADIANT_VERSION; +} + + + +// +// CCamera +// +CCamera *AllocCam() { + if( !firstFreeCam ) + return( NULL ); + + CCamera *cam = firstFreeCam; + firstFreeCam = firstFreeCam->GetNext(); + cam->Init(); + if( firstCam ) { + cam->SetNext( firstCam ); + firstCam->SetPrev( cam ); + } + firstCam = cam; + + return( cam ); +} + +void FreeCam( CCamera *cam ) { + if( cam->GetPrev() ) { + if( cam->GetNext() ) { + cam->GetPrev()->SetNext( cam->GetNext() ); + cam->GetNext()->SetPrev( cam->GetPrev() ); + } else { + cam->GetPrev()->SetNext( NULL ); + } + } else if( cam->GetNext() ) { + cam->GetNext()->SetPrev( NULL ); + firstCam = cam->GetNext(); + } else { + firstCam = NULL; + } + + cam->GetCam()->clear(); + cam->Init(); + + if( firstFreeCam ) { + cam->SetNext( firstFreeCam ); + } + firstFreeCam = cam; +} + +void SetCurrentCam( CCamera *cam ) { + currentCam = cam; +} + +CCamera *GetCurrentCam() { + return( currentCam ); +} diff --git a/contrib/camera/camera.def b/contrib/camera/camera.def new file mode 100644 index 00000000..509df54a --- /dev/null +++ b/contrib/camera/camera.def @@ -0,0 +1,8 @@ +; camera.def : Declares the module parameters for the DLL. + +LIBRARY "CAMERA" +DESCRIPTION 'CAMERA Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/camera/camera.h b/contrib/camera/camera.h new file mode 100644 index 00000000..d60783a9 --- /dev/null +++ b/contrib/camera/camera.h @@ -0,0 +1,162 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +#ifdef _WIN32 + #pragma warning(disable : 4267) +#else + typedef unsigned char byte; +#endif + +class CCamera; + +#include + +#include "str.h" + +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" + +#include "igl.h" +#include "iui.h" +#include "icamera.h" + +#include "misc.h" +#include "dialogs.h" +#include "funchandlers.h" +#include "renderer.h" +#include "listener.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERUITable g_UITable; +extern _QERCameraTable g_CameraTable; + +extern CRenderer *Renderer; +extern CListener *Listener; + +// splinelib +#define CAMERA_PLUGIN +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) + +extern void ( APIENTRY * qglBegin )(GLenum mode); +extern void ( APIENTRY * qglEnd )(void); +extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); + +extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ); + +#include "splines/splines.h" + +// this needs to match splines.cpp +#define MAX_CAMERAS 64 +extern idCameraDef camera[MAX_CAMERAS]; + +extern "C" qboolean loadCamera(int camNum, const char *name); + +// +// CCamera +// + +class CCamera { +public: + CCamera( int i ) { + cam = &camera[i]; + camnum = i; + Init(); + } + ~CCamera(); + + void Init() { + next = prev = NULL; + fileName[0] = '\0'; + hasbeensaved = 0; + } + + idCameraDef *GetCam() { + return( cam ); + } + int GetCamNum() { + return( camnum ); + } + + char *GetFileName() { + return( fileName ); + } + void SetFileName( const char *name, bool save ) { + strcpy( fileName, name ); + if( save ) + hasbeensaved = 1; + } + + CCamera *GetNext() { + return( next ); + } + + CCamera *GetPrev() { + return( prev ); + } + + void SetNext( CCamera *camera ) { + next = camera; + } + void SetPrev( CCamera *camera ) { + prev = camera; + } + + int HasBeenSaved() { + return( hasbeensaved ); + } + void HasBeenModified() { + if( hasbeensaved ) + hasbeensaved = 2; + } + +protected: + idCameraDef *cam; + int camnum; + CCamera *next, *prev; + char fileName[PATH_MAX]; + int hasbeensaved; // 0:never saved 1:saved 2:saved, but modified +}; + +CCamera *AllocCam(); +void FreeCam( CCamera *cam ); +void SetCurrentCam( CCamera *cam ); +CCamera *GetCurrentCam(); + +// globals +extern GtkWidget *g_pRadiantWnd; +extern GtkWidget *g_pCameraInspectorWnd; +extern CCamera *firstCam; +extern bool g_bEditOn; +extern int g_iEditMode; +extern int g_iActiveTarget; +extern int g_iPreviewRunning; +extern CCamera *g_pCurrentEditCam; + +#endif // _CAMERA_H_ diff --git a/contrib/camera/camera.vcproj b/contrib/camera/camera.vcproj new file mode 100644 index 00000000..5feead39 --- /dev/null +++ b/contrib/camera/camera.vcproj @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/camera/dialogs.cpp b/contrib/camera/dialogs.cpp new file mode 100644 index 00000000..2e8e5b0e --- /dev/null +++ b/contrib/camera/dialogs.cpp @@ -0,0 +1,1352 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +static GSList *g_pEditTypeRadio = NULL; +static GtkWidget *g_pEditModeEditRadioButton = NULL; +GtkWidget *g_pEditModeAddRadioButton = NULL; +static GtkWidget *g_pSecondsEntry = NULL; +static GtkWidget *g_pEventsList = NULL; +static GtkLabel *g_pCurrentTime = NULL; +static GtkLabel *g_pTotalTime = NULL; +static GtkAdjustment *g_pTimeLine = NULL; +static GtkWidget *g_pTrackCamera = NULL; +static GtkWidget *g_pCamName = NULL; +static char *g_cNull = '\0'; + +static gint ci_editmode_edit( GtkWidget *widget, gpointer data ) +{ + g_iEditMode = 0; + + return TRUE; +} + +static gint ci_editmode_add( GtkWidget *widget, gpointer data ) +{ + g_iEditMode = 1; + + return TRUE; +} + +/*static gint ci_delete_selected( GtkWidget *widget, gpointer data ) +{ + return TRUE; +} + +static gint ci_select_all( GtkWidget *widget, gpointer data ) +{ + return TRUE; +}*/ + +static gint ci_new( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame; //, *name; + GtkWidget *fixed, *interpolated, *spline; + int ret, loop = 1; + GSList *targetTypeRadio = NULL; +// char buf[128]; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "New Camera" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); + gtk_widget_show( fixed ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); + + interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); + gtk_widget_show( interpolated ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); + + spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); + gtk_widget_show( spline ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) + DoNewFixedCamera(); + else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) + DoNewInterpolatedCamera(); + else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) + DoNewSplineCamera(); + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_load( GtkWidget *widget, gpointer data ) +{ + DoLoadCamera(); + + return TRUE; +} + +static gint ci_save( GtkWidget *widget, gpointer data ) +{ + DoSaveCamera(); + + return TRUE; +} + +static gint ci_unload( GtkWidget *widget, gpointer data ) +{ + DoUnloadCamera(); + + return TRUE; +} + +static gint ci_apply( GtkWidget *widget, gpointer data ) +{ + if( GetCurrentCam() ) { + const char *str; + char buf[128]; + bool build = false; + + str = gtk_entry_get_text( GTK_ENTRY(g_pCamName) ); + + if( str ) { + GetCurrentCam()->GetCam()->setName( str ); + build = true; + } + + str = gtk_entry_get_text( GTK_ENTRY(g_pSecondsEntry) ); + + if( str ) { + GetCurrentCam()->GetCam()->setBaseTime( atof( str ) ); + build = true; + } + + if( build ) { + GetCurrentCam()->GetCam()->buildCamera(); + } + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; + + GetCurrentCam()->HasBeenModified(); + } + + return TRUE; +} + +static gint ci_preview( GtkWidget *widget, gpointer data ) +{ + if( GetCurrentCam() ) { + g_iPreviewRunning = 1; + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + + return TRUE; +} + +static gint ci_expose( GtkWidget *widget, gpointer data ) +{ + // start edit mode + DoStartEdit( GetCurrentCam() ); + + return FALSE; +} + +static gint ci_close( GtkWidget *widget, gpointer data ) +{ + gtk_widget_hide( g_pCameraInspectorWnd ); + + // exit edit mode + DoStopEdit(); + + return TRUE; +} + +static GtkWidget *g_pPathListCombo = NULL; +static GtkLabel *g_pPathType = NULL; + +static void RefreshPathListCombo( void ) +{ + if( !g_pPathListCombo ) + return; + + GList *combo_list = (GList*)NULL; + + if( GetCurrentCam() ) { + combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getPositionObj()->getName() ); + for( int i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { + combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ); + } + } else { + // add one empty string make gtk be quiet + combo_list = g_list_append( combo_list, (gpointer)g_cNull ); + } + + gtk_combo_set_popdown_strings( GTK_COMBO( g_pPathListCombo ), combo_list ); + g_list_free( combo_list ); +} + +static gint ci_pathlist_changed( GtkWidget *widget, gpointer data ) +{ + const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); + + if( !str || !GetCurrentCam() ) + return TRUE; + + int i; + for( i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { + if( !strcmp( str, GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ) ) + break; + } + + if( i >= 0 && i < GetCurrentCam()->GetCam()->numTargets() ) { + GetCurrentCam()->GetCam()->setActiveTarget( i ); + + g_iActiveTarget = i; + if( g_pPathType ) + gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->typeStr() ); + } else { + g_iActiveTarget = -1; + if( g_pPathType ) + gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); + } + + // start edit mode + if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) + DoStartEdit( GetCurrentCam() ); + + return TRUE; +} + +static void RefreshEventList( void ) +{ + int i; + char buf[128]; + + // Clear events list + gtk_clist_freeze( GTK_CLIST(g_pEventsList) ); + gtk_clist_clear( GTK_CLIST(g_pEventsList) ); + + if( GetCurrentCam() ) { + // Fill events list + for( i = 0; i < GetCurrentCam()->GetCam()->numEvents(); i++ ) { + char rowbuf[3][128], *row[3]; + // FIXME: sort by time? + sprintf( rowbuf[0], "%li", GetCurrentCam()->GetCam()->getEvent(i)->getTime() ); row[0] = rowbuf[0]; + strncpy( rowbuf[1], GetCurrentCam()->GetCam()->getEvent(i)->typeStr(), sizeof(rowbuf[0]) ); row[1] = rowbuf[1]; + strncpy( rowbuf[2], GetCurrentCam()->GetCam()->getEvent(i)->getParam(), sizeof(rowbuf[1]) ); row[2] = rowbuf[2]; + gtk_clist_append( GTK_CLIST(g_pEventsList), row ); + } + + // Total duration might have changed + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = ( GetCurrentCam()->GetCam()->getTotalTime() * 1000 ); + } + + gtk_clist_thaw( GTK_CLIST(g_pEventsList) ); +} + +static gint ci_rename( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *hbox, *name; + int ret, loop = 1; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Rename Path" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize ( window ); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + name = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), name, FALSE, FALSE, 0 ); + gtk_widget_show( name ); + + if( g_iActiveTarget < 0 ) + gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getPositionObj()->getName() ); + else + gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->getName() ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); + + if( str && str[0] ) { + // Update the path + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->setName( str ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->setName( str ); + + GetCurrentCam()->GetCam()->buildCamera(); + + // Rebuild the listbox + RefreshPathListCombo(); + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_add_target( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *name; + GtkWidget *fixed, *interpolated, *spline; + int ret, loop = 1; + GSList *targetTypeRadio = NULL; + char buf[128]; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Add Target" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + name = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), name, TRUE, TRUE, 0 ); + gtk_widget_show( name ); + + sprintf( buf, "target%i", GetCurrentCam()->GetCam()->numTargets() + 1 ); + gtk_entry_set_text( GTK_ENTRY(name), buf ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); + gtk_widget_show( fixed ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); + + interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); + gtk_widget_show( interpolated ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); + + spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); + gtk_widget_show( spline ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); + + if( str && str[0] ) { + int type; + GList *li; + + if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) + type = 0; + else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) + type = 1; + else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) + type = 2; + + // Add the target + GetCurrentCam()->GetCam()->addTarget( str, static_cast(type) ); + + // Rebuild the listbox + RefreshPathListCombo(); + + // Select the last item in the listbox + li = g_list_last( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list)->children ); + gtk_list_select_child( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list), GTK_WIDGET (li->data) ); + + // If this was the first one, refresh the event list + if( GetCurrentCam()->GetCam()->numTargets() == 1 ) { + RefreshEventList(); + } + + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static GtkWidget *g_pCamListCombo = NULL; +static GtkLabel *g_pCamType = NULL; + +void RefreshCamListCombo( void ) +{ + if( !g_pCamListCombo ) + return; + + GList *combo_list = (GList*)NULL; + CCamera *combo_cam = firstCam; + if( combo_cam ) { + while( combo_cam ) { + //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); + //if( combo_cam->HasBeenSaved() ) { + combo_list = g_list_append( combo_list, (void *)combo_cam->GetFileName() ); + /*} else { + char buf[128]; + sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); + combo_list = g_list_append( combo_list, (void *)buf ); + + //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); // FIXME: this requires camera.dll to create unique names for new cams + }*/ + combo_cam = combo_cam->GetNext(); + } + }else { + // add one empty string make gtk be quiet + combo_list = g_list_append( combo_list, (gpointer)g_cNull ); + } + gtk_combo_set_popdown_strings( GTK_COMBO( g_pCamListCombo ), combo_list ); + g_list_free( combo_list ); + + // select our current entry in the list + if( GetCurrentCam() ) { + // stop editing on the current cam + //GetCurrentCam()->GetCam()->stopEdit(); // FIXME: this crashed on creating new cameras, why is it here? + + GList *li = GTK_LIST( GTK_COMBO(g_pCamListCombo)->list)->children; + combo_cam = firstCam; + while( li && combo_cam ) { + if( combo_cam == GetCurrentCam() ) { + gtk_list_select_child( GTK_LIST( GTK_COMBO(g_pCamListCombo)->list ), GTK_WIDGET( li->data ) ); + break; + } + li = li->next; + combo_cam = combo_cam->GetNext(); + } + } + + RefreshPathListCombo(); +} + +static gint ci_camlist_changed( GtkWidget *widget, gpointer data ) +{ + const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); + + CCamera *combo_cam = firstCam; + while( str && combo_cam ) { + //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) + //if( combo_cam->HasBeenSaved() ) { + if( !strcmp( str, combo_cam->GetFileName() ) ) + break; + /*} else { + char buf[128]; + sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); + if( !strcmp( str, buf ) ) + //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) + break; + }*/ + + combo_cam = combo_cam->GetNext(); + } + + SetCurrentCam( combo_cam ); + + if( g_pCamType ) { + if( GetCurrentCam() ) { + // Fill in our widgets fields for this camera + char buf[128]; + + // Set Name + gtk_entry_set_text( GTK_ENTRY(g_pCamName), GetCurrentCam()->GetCam()->getName() ); + + // Set type + gtk_label_set_text( g_pCamType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); + + // Set duration + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; + } else { + // Set Name + gtk_entry_set_text( GTK_ENTRY(g_pCamName), "" ); + + // Set type + gtk_label_set_text( g_pCamType, "" ); + + // Set duration + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), "30.00" ); + + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, "30.00" ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = 30000; + } + + // Refresh event list + RefreshEventList(); + } + + RefreshPathListCombo(); + + // start edit mode + g_iActiveTarget = -1; + if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) + DoStartEdit( GetCurrentCam() ); + + return TRUE; +} + +enum camEventType { + EVENT_NA = 0x00, + EVENT_WAIT, // + EVENT_TARGETWAIT, // + EVENT_SPEED, // + EVENT_TARGET, // char(name) + EVENT_SNAPTARGET, // + EVENT_FOV, // int(time), int(targetfov) + EVENT_CMD, // + EVENT_TRIGGER, // + EVENT_STOP, // + EVENT_CAMERA, // + EVENT_FADEOUT, // int(time) + EVENT_FADEIN, // int(time) + EVENT_FEATHER, // + EVENT_COUNT +}; + +// { requires parameters, enabled } +const bool camEventFlags[][2] = { + { false, false }, + { false, true }, + { false, false }, + { false, false }, + { true, true }, + { false, false }, + { true, true }, + { false, false }, + { false, false }, + { false, true }, + { true, true }, + { true, true }, + { true, true }, + { false, true }, +}; + +const char *camEventStr[] = { + "n/a", + "Wait", + "Target wait", + "Speed", + "Change Target ", + "Snap Target", + "FOV ", + "Run Script", + "Trigger", + "Stop", + "Change to Camera (or ", + "Fade Out ", + "Fade In ", + "Feather" +}; + +static gint ci_add( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *parameters; + GtkWidget *eventWidget[EVENT_COUNT]; + int i, ret, loop = 1; + GSList *eventTypeRadio = NULL; +// char buf[128]; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Add Event" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + for( i = 1; i < EVENT_COUNT; i++ ) { + eventWidget[i] = gtk_radio_button_new_with_label( eventTypeRadio, camEventStr[i] ); + gtk_box_pack_start( GTK_BOX( vbox2 ), eventWidget[i], FALSE, FALSE, 3 ); + gtk_widget_show( eventWidget[i] ); + eventTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( eventWidget[i] ) ); + if( camEventFlags[i][1] == false ) + gtk_widget_set_sensitive (eventWidget[i], FALSE); + } + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Parameters:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + parameters = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), parameters, TRUE, TRUE, 0 ); + gtk_widget_show( parameters ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(parameters) ); + + if( !camEventFlags[i][0] || ( str && str[0] ) ) { + int type = 0; +// GList *li; + + for( type = 1; type < EVENT_COUNT; type++ ) { + if( gtk_toggle_button_get_active( (GtkToggleButton*)eventWidget[type] ) ) + break; + } + + // Add the event + GetCurrentCam()->GetCam()->addEvent( static_cast(type), str, (long)(g_pTimeLine->value) ); + + // Refresh event list + RefreshEventList(); + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_del( GtkWidget *widget, gpointer data ) +{ + // TODO: add support to splines lib + if( GetCurrentCam() && GTK_CLIST(g_pEventsList)->focus_row >= 0 ) { + GetCurrentCam()->GetCam()->removeEvent( GTK_CLIST(g_pEventsList)->focus_row ); + // Refresh event list + RefreshEventList(); + } + + return TRUE; +} + +static gint ci_timeline_changed( GtkAdjustment *adjustment ) +{ + char buf[128]; + + sprintf( buf, "%.2f", adjustment->value / 1000.f ); + gtk_label_set_text( g_pCurrentTime, buf ); + + // FIXME: this will never work completely perfect. Startcamera calls buildcamera, which sets all events to 'nottriggered'. + // So if you have a wait at the end of the path, this will go to nontriggered immediately when you go over it and the camera + // will have no idea where on the track it should be. + if( GetCurrentCam() && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(g_pTrackCamera) ) ) { + float fov; + vec3_t origin = { 0.0f, 0.0f, 0.0f }, dir = { 0.0f, 0.0f, 0.0f}, angles; + + GetCurrentCam()->GetCam()->startCamera( 0 ); + + GetCurrentCam()->GetCam()->getCameraInfo( (long)(adjustment->value), &origin[0], &dir[0], &fov ); + VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); + g_CameraTable.m_pfnSetCamera( origin, angles ); + } + + return TRUE; +} + +GtkWidget *CreateCameraInspectorDialog( void ) +{ + GtkWidget *window, *w, *vbox, *hbox, *table, *frame; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Camera Inspector" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( ci_close ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL ); + // gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pRadiantWnd ) ); + + // don't use show, as you don't want to have it displayed on startup ;-) + gtk_widget_realize( window ); + + // fill the window + + // the table + // -------------------------- // + + table = gtk_table_new( 3, 2, FALSE ); + gtk_widget_show( table ); + gtk_container_add( GTK_CONTAINER( window ), table ); + gtk_container_set_border_width( GTK_CONTAINER( table ), 5 ); + gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); + gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); + + // the properties column + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "File:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pCamListCombo = gtk_combo_new(); + gtk_box_pack_start (GTK_BOX( hbox ), g_pCamListCombo, TRUE, TRUE, 0); + gtk_widget_show( g_pCamListCombo ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pCamName = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), g_pCamName, FALSE, FALSE, 0 ); + gtk_widget_show( g_pCamName ); + + w = gtk_label_new( "Type: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pCamType = GTK_LABEL( w ); + + RefreshCamListCombo(); + + gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pCamListCombo)->entry ), FALSE ); + gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pCamListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_camlist_changed ), NULL ); + + // -------------------------- // + + frame = gtk_frame_new( "Path and Target editing" ); + gtk_widget_show( frame ); + gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Edit:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pPathListCombo = gtk_combo_new(); + gtk_box_pack_start (GTK_BOX( hbox ), g_pPathListCombo, TRUE, TRUE, 0); + gtk_widget_show( g_pPathListCombo ); + + RefreshPathListCombo(); + + gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pPathListCombo)->entry ), FALSE ); + gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pPathListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_pathlist_changed ), NULL ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pEditModeEditRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Edit Points" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeEditRadioButton, FALSE, FALSE, 3 ); + gtk_widget_show( g_pEditModeEditRadioButton ); + g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeEditRadioButton ) ); + + gtk_signal_connect( GTK_OBJECT( g_pEditModeEditRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_edit ), NULL ); + + g_pEditModeAddRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Add Points" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeAddRadioButton, FALSE, FALSE, 3 ); + gtk_widget_show( g_pEditModeAddRadioButton ); + g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeAddRadioButton ) ); + + gtk_signal_connect( GTK_OBJECT( g_pEditModeAddRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_add ), NULL ); + + // see if we should use a different default + if( g_iEditMode == 1 ) { + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + } + + w = gtk_label_new( "Type: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pPathType = GTK_LABEL( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Rename..." ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_rename ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Add Target..." ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add_target ), NULL ); + gtk_widget_show( w ); + + // not available in splines library + /*w = gtk_button_new_with_label( "Delete Selected" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_delete_selected ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Select All" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_select_all ), NULL ); + gtk_widget_show( w );*/ + + // -------------------------- // + + frame = gtk_frame_new( "Time" ); + gtk_widget_show( frame ); + gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Length (seconds):" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pSecondsEntry = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), g_pSecondsEntry, FALSE, FALSE, 0 ); + gtk_widget_show( g_pSecondsEntry ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Current Time: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "0.00" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pCurrentTime = GTK_LABEL( w ); + + w = gtk_label_new( " of " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "0.00" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pTotalTime = GTK_LABEL( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pTimeLine = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 30000, 100, 250, 0 ) ); + gtk_signal_connect( GTK_OBJECT(g_pTimeLine), "value_changed", GTK_SIGNAL_FUNC( ci_timeline_changed ), NULL ); + w = gtk_hscale_new( g_pTimeLine ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_widget_show( w ); + gtk_scale_set_draw_value( GTK_SCALE( w ), FALSE ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pTrackCamera = gtk_check_button_new_with_label( "Track Camera" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pTrackCamera, FALSE, FALSE, 0 ); + gtk_widget_show( g_pTrackCamera ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Events:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_scrolled_window_new( NULL, NULL ); + gtk_widget_set_usize( w, 0, 150 ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_widget_show( w ); + + g_pEventsList = gtk_clist_new( 3 ); + gtk_container_add( GTK_CONTAINER(w), g_pEventsList); + //gtk_signal_connect( GTK_OBJECT(g_pEventsList), "select_row", GTK_SIGNAL_FUNC (proplist_select_row), NULL); + gtk_clist_set_selection_mode( GTK_CLIST(g_pEventsList), GTK_SELECTION_BROWSE ); + gtk_clist_column_titles_hide( GTK_CLIST(g_pEventsList) ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 0, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 1, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 2, TRUE ); + gtk_widget_show( g_pEventsList ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 0 ); + gtk_widget_show( vbox ); + + w = gtk_button_new_with_label( "Add..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Del" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_del ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + /*/ + | + | + | + */ + + // the buttons column + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + w = gtk_button_new_with_label( "New..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_new ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Load..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_load ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + w = gtk_button_new_with_label( "Save..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_save ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Unload" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_unload ), NULL ); + gtk_widget_show( w ); + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Apply" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_apply ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Preview" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_preview ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Close" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_close ), NULL ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + // -------------------------- // + + return window; +} diff --git a/contrib/camera/dialogs.h b/contrib/camera/dialogs.h new file mode 100644 index 00000000..5ba86c5a --- /dev/null +++ b/contrib/camera/dialogs.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +struct TwinWidget { + GtkWidget* one; + GtkWidget* two; +}; + +void dialog_button_callback (GtkWidget *widget, gpointer data); +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data); +//void dialog_button_callback_settex (GtkWidget *widget, gpointer data); + +void RefreshCamListCombo( void ); +GtkWidget *CreateCameraInspectorDialog( void ); diff --git a/contrib/camera/dialogs_common.cpp b/contrib/camera/dialogs_common.cpp new file mode 100644 index 00000000..bebf5976 --- /dev/null +++ b/contrib/camera/dialogs_common.cpp @@ -0,0 +1,51 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} diff --git a/contrib/camera/funchandlers.cpp b/contrib/camera/funchandlers.cpp new file mode 100644 index 00000000..97e861eb --- /dev/null +++ b/contrib/camera/funchandlers.cpp @@ -0,0 +1,272 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +extern GtkWidget *g_pEditModeAddRadioButton; + +char* Q_realpath(const char *path, char *resolved_path, size_t size) +{ +#if defined (__linux__) || defined (__APPLE__) + return realpath(path, resolved_path); +#else + return _fullpath(resolved_path, path, size); +#endif +} + +static void DoNewCamera( idCameraPosition::positionType type ) +{ + CCamera *cam = AllocCam(); + + if( cam ) { + char buf[128]; + sprintf( buf, "camera%i", cam->GetCamNum() ); + + cam->GetCam()->startNewCamera( type ); + cam->GetCam()->setName( buf ); + cam->GetCam()->buildCamera(); + + sprintf( buf, "Unsaved Camera %i", cam->GetCamNum() ); + cam->SetFileName( buf, false ); + + SetCurrentCam( cam ); + RefreshCamListCombo(); + + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + + // Show the camera inspector + DoCameraInspector(); + + // Start edit mode (if not initiated by DoCameraInspector) + if( !g_bEditOn ) + DoStartEdit( GetCurrentCam() ); + } else { + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free cameras available.", "Create Camera Error", MB_OK, NULL ); + } +} + +void DoNewFixedCamera() +{ + DoNewCamera( idCameraPosition::FIXED ); +} + +void DoNewInterpolatedCamera() +{ + DoNewCamera( idCameraPosition::INTERPOLATED ); +} + +void DoNewSplineCamera() +{ + DoNewCamera( idCameraPosition::SPLINE ); +} + +void DoCameraInspector() +{ + gtk_widget_show( g_pCameraInspectorWnd ); +} + +void DoPreviewCamera() +{ + if( GetCurrentCam() ) { + g_iPreviewRunning = 1; + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} + +void DoLoadCamera() +{ + char basepath[PATH_MAX]; + + if( firstCam && firstCam->HasBeenSaved() ) + ExtractFilePath( firstCam->GetFileName(), basepath ); + else + strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); + + const gchar *filename = g_FuncTable.m_pfnFileDialog( (GtkWidget *)g_pRadiantWnd, TRUE, "Open Camera File", basepath, "camera"); + + if( filename ) + { + CCamera *cam = AllocCam(); + char fullpathtofile[PATH_MAX]; + + if( cam ) { + Q_realpath(filename, fullpathtofile, PATH_MAX); + + // see if this camera file was already loaded + CCamera *checkCam = firstCam->GetNext(); // not the first one as we just allocated it + while( checkCam ) { + if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { + char error[PATH_MAX+64]; + FreeCam( cam ); + sprintf( error, "Camera file \'%s\' is already loaded", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); + //g_free( filename ); + return; + } + checkCam = checkCam->GetNext(); + } + + if( loadCamera( cam->GetCamNum(), fullpathtofile ) ) { + cam->GetCam()->buildCamera(); + cam->SetFileName( filename, true ); + SetCurrentCam( cam ); + RefreshCamListCombo(); + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } else { + char error[PATH_MAX+64]; + FreeCam( cam ); + sprintf( error, "An error occured during the loading of \'%s\'", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); + } + + //g_free( filename ); + } else { + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free camera slots available", "Load error", MB_OK, NULL ); + } + } +} + +void DoSaveCamera() { + char basepath[PATH_MAX]; + + if( !GetCurrentCam() ) + return; + + if( GetCurrentCam()->GetFileName()[0] ) + ExtractFilePath( GetCurrentCam()->GetFileName(), basepath ); + else + strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); + + const gchar *filename = g_FuncTable.m_pfnFileDialog( (void *)g_pRadiantWnd, FALSE, "Save Camera File", basepath, "camera"); + + if( filename ) { + char fullpathtofile[PATH_MAX + 8]; + + Q_realpath(filename, fullpathtofile, PATH_MAX); + + // File dialog from windows (and maybe the gtk one from radiant) doesn't handle default extensions properly. + // Add extension and check again if file exists + if( strcmp( fullpathtofile + (strlen(fullpathtofile) - 7), ".camera" ) ) { + strcat( fullpathtofile, ".camera" ); + + if( FileExists( fullpathtofile ) ) { + if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "File already exists.\nOverwrite?", "Save Camera File", MB_YESNO, NULL ) == IDNO ) { + return; + } + } + } + + // see if this camera file was already loaded + CCamera *checkCam = firstCam; + while( checkCam ) { + if( checkCam == GetCurrentCam() ) { + checkCam = checkCam->GetNext(); + if( !checkCam ) // we only have one camera file opened so no need to check further + break; + } else if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { + char error[PATH_MAX+64]; + sprintf( error, "Camera file \'%s\' is currently loaded by GtkRadiant.\nPlease select a different filename.", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Save error", MB_OK, NULL ); + return; + } + checkCam = checkCam->GetNext(); + } + + // FIXME: check for existing directory + + GetCurrentCam()->GetCam()->save( fullpathtofile ); + GetCurrentCam()->SetFileName( fullpathtofile, true ); + RefreshCamListCombo(); + } +} + +void DoUnloadCamera() { + if( !GetCurrentCam() ) + return; + + if( !GetCurrentCam()->HasBeenSaved() ) { + char buf[PATH_MAX+64]; + sprintf( buf, "Do you want to save the changes for camera '%s'?", GetCurrentCam()->GetCam()->getName() ); + if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { + DoSaveCamera(); + } + } else if( GetCurrentCam()->HasBeenSaved() == 2 ) { + char buf[PATH_MAX+64]; + sprintf( buf, "Do you want to save the changes made to camera file '%s'?", GetCurrentCam()->GetFileName() ); + if( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { + DoSaveCamera(); + } + } + + if( g_pCurrentEditCam ) { + DoStopEdit(); + g_pCurrentEditCam = NULL; + } + + FreeCam( GetCurrentCam() ); + SetCurrentCam( NULL ); + RefreshCamListCombo(); +} + +CCamera *g_pCurrentEditCam = NULL; + +void DoStartEdit( CCamera *cam ) { + if( g_pCurrentEditCam ) { + DoStopEdit(); + g_pCurrentEditCam = NULL; + } + + if( cam ) { + g_bEditOn = true; + + if( !Listener ) + Listener = new CListener; + + cam->GetCam()->startEdit( g_iActiveTarget < 0 ? true : false ); + + g_pCurrentEditCam = cam; + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} + +void DoStopEdit( void ) { + g_bEditOn = false; + + if( Listener ) { + delete Listener; + Listener = NULL; + } + + if( g_pCurrentEditCam ) { + // stop editing on the current cam + g_pCurrentEditCam->GetCam()->stopEdit(); + g_pCurrentEditCam = NULL; + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} diff --git a/contrib/camera/funchandlers.h b/contrib/camera/funchandlers.h new file mode 100644 index 00000000..a9419062 --- /dev/null +++ b/contrib/camera/funchandlers.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +void DoNewFixedCamera(); +void DoNewInterpolatedCamera(); +void DoNewSplineCamera(); +void DoCameraInspector(); +void DoPreviewCamera(); +void DoLoadCamera(); +void DoSaveCamera(); +void DoUnloadCamera(); +void DoStartEdit( CCamera *cam ); +void DoStopEdit( void ); + diff --git a/contrib/camera/listener.cpp b/contrib/camera/listener.cpp new file mode 100644 index 00000000..c21e8715 --- /dev/null +++ b/contrib/camera/listener.cpp @@ -0,0 +1,234 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +CListener::CListener() +{ + refCount = 1; + + m_bHooked = FALSE; + + m_bLeftMBPressed = m_bRightMBPressed = m_bMiddleMBPressed = false; + + oldValid = false; + + Register(); +} + +CListener::~CListener() +{ + UnRegister(); +} + +void CListener::Register() +{ + g_UITable.m_pfnHookWindow( this ); + g_pXYWndWrapper = g_UITable.m_pfnGetXYWndWrapper(); + m_bHooked = TRUE; +} + +void CListener::UnRegister() +{ + if(m_bHooked) + { + g_UITable.m_pfnUnHookWindow( this ); + g_pXYWndWrapper= NULL; + m_bHooked = FALSE; + } +} + +bool CListener::OnMouseMove( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + if( m_bLeftMBPressed && oldValid && g_iEditMode == 0 ) { + vec3_t click, delta; + + g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, click ); + + switch( m_vt ) { + case XY: + VectorSet( delta, click[0] - old_x, click[1] - old_y, 0 ); + old_x = click[0]; old_y = click[1]; + break; + case XZ: + VectorSet( delta, click[0] - old_x, 0, click[2] - old_y ); + old_x = click[0]; old_y = click[2]; + break; + case YZ: + VectorSet( delta, 0, click[1] - old_x, click[2] - old_y ); + old_x = click[1]; old_y = click[2]; + break; + } + + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->updateSelection( delta[0], delta[1], delta[2] ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->updateSelection( delta[0], delta[1], delta[2] ); + + GetCurrentCam()->HasBeenModified(); + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + + return true; + } + + return false; +} + +bool CListener::OnLButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bLeftMBPressed = true; + oldValid = true; + + vec3_t org, delta; + + g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, org ); + + switch( m_vt ) { + case XY: + old_x = org[0]; old_y = org[1]; org[2] = 64*1024; + VectorSet( delta, 0, 0, -1 ); + break; + case XZ: + old_x = org[0]; old_y = org[2]; org[1] = 64*1024; + VectorSet( delta, 0, -1, 0 ); + break; + case YZ: + old_x = org[1]; old_y = org[2]; org[0] = 64*1024; + VectorSet( delta, -1, 0, 0 ); + break; + } + + if( g_iEditMode == 0 ) { + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); + } else if( g_iEditMode == 1 ) { + idVec3 *lastcoord; + idCameraPosition *camera; + + if( g_iActiveTarget < 0 ) { + camera = GetCurrentCam()->GetCam()->getPositionObj(); + } else { + camera = GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget); + } + + if( camera->numPoints() ) { + lastcoord = camera->getPoint( camera->numPoints() -1 ); + switch( m_vt ) { + case XY: + camera->addPoint( org[0], org[1], lastcoord->z ); + break; + case XZ: + camera->addPoint( org[0], lastcoord->y, org[2] ); + break; + case YZ: + camera->addPoint( lastcoord->x, org[1], org[2] ); + break; + } + } else { + switch( m_vt ) { + case XY: + camera->addPoint( org[0], org[1], 0 ); + break; + case XZ: + camera->addPoint( org[0], 0, org[2] ); + break; + case YZ: + camera->addPoint( 0, org[1], org[2] ); + break; + } + } + + GetCurrentCam()->HasBeenModified(); + } + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + + return true; + + //return false; +} + +bool CListener::OnLButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bLeftMBPressed = false; + oldValid = false; + + if( g_iEditMode == 0 ) { + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->deselectAll(); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->deselectAll(); + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + + return false; +} + +bool CListener::OnRButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bRightMBPressed = true; + + return false; +} + +bool CListener::OnRButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bRightMBPressed = false; + + return false; +} + +bool CListener::OnMButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bMiddleMBPressed = true; + + return false; +} + +bool CListener::OnMButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bMiddleMBPressed = false; + + return false; +} diff --git a/contrib/camera/listener.h b/contrib/camera/listener.h new file mode 100644 index 00000000..13e14b71 --- /dev/null +++ b/contrib/camera/listener.h @@ -0,0 +1,64 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +class CListener : public IWindowListener +{ +public: + bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnKeyPressed(char *s) { return false; } + bool Paint() { return true; } + void Close() { } + + void UnRegister(); + void Register(); + CListener(); + virtual ~CListener(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + void SetViewType( VIEWTYPE vt ) { if( m_vt != vt ) oldValid = false; m_vt = vt; } + +private: + IXYWndWrapper *g_pXYWndWrapper; + + bool m_bHooked; + int refCount; + VIEWTYPE m_vt; + + // mouse button status + bool m_bLeftMBPressed, m_bRightMBPressed, m_bMiddleMBPressed; + + // old mouse coordinates + bool oldValid; + gdouble old_x, old_y; +}; diff --git a/contrib/camera/misc.cpp b/contrib/camera/misc.cpp new file mode 100644 index 00000000..8f45d9b3 --- /dev/null +++ b/contrib/camera/misc.cpp @@ -0,0 +1,243 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +void Sys_ERROR( char* text, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text,argptr); + va_end (argptr); + + Sys_Printf("Camera::ERROR->%s", buf); +} + +char* UnixToDosPath( char* path ) +{ +#ifndef _WIN32 + return path; +#else + for(char* p = path; *p; p++) + { + if(*p == '/') + *p = '\\'; + } + return path; +#endif +} + +void ExtractFilePath( const char *path, char *dest ) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +const char* ExtractFilename( const char* path ) +{ + char* p = (char *)strrchr(path, '/'); + if(!p) + { + p = (char *)strrchr(path, '\\'); + + if(!p) + return path; + } + return ++p; +} + +int Q_stricmp (const char *s1, const char *s2) { + return stricmp( s1, s2 ); +} + +/* +============== +FileExists +============== +*/ +bool FileExists (const char *filename) +{ + FILE *f; + + f = fopen( filename, "r" ); + if( !f ) + return false; + fclose( f ); + return true; +} + +// +// command buffer +// empty wrappers, don't really use them here +// +void Cbuf_AddText( const char *text ) {}; +void Cbuf_Execute (void) {}; + +// +// Common +// + +void CDECL Com_Error( int level, const char *error, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,error); + vsprintf (buf, error,argptr); + va_end (argptr); + + Sys_Printf("Camera::ERROR->%s", buf); +} + +void CDECL Com_Printf( const char* msg, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,msg); + vsprintf (buf, msg,argptr); + va_end (argptr); + + Sys_Printf("Camera::%s", buf); +} + +void CDECL Com_DPrintf( const char* msg, ... ) +{ +#ifdef _DEBUG + va_list argptr; + char buf[32768]; + + va_start (argptr,msg); + vsprintf (buf, msg,argptr); + va_end (argptr); + + Sys_Printf("Camera::%s", buf); +#endif +} + +void *Com_Allocate( int bytes ) { + return( malloc( bytes ) ); +} + +void Com_Dealloc( void *ptr ) { + free( ptr ); +} + +// +// Filesystem +// + +#ifdef _WIN32 + #pragma warning(disable : 4311) + #pragma warning(disable : 4312) +#endif + +int FS_Read( void *buffer, int len, fileHandle_t f ) { + return fread( buffer, len, 1, (FILE *)f ); +} + +int FS_Write( const void *buffer, int len, fileHandle_t h ) { + return fwrite( buffer, len, 1, (FILE *)h ); +} + +int FS_ReadFile( const char *qpath, void **buffer ) { + fileHandle_t h; + byte* buf; + int len; + + buf = NULL; + + len = FS_FOpenFileRead( qpath, &h, qfalse ); + + if( h == 0 ) { + if ( buffer ) { + *buffer = NULL; + } + + return -1; + } + + buf = (byte *)Com_Allocate( len + 1 ); + + *buffer = buf; + + FS_Read (buf, len, h); + + buf[len] = 0; + FS_FCloseFile( h ); + + return len; +} + +void FS_FreeFile( void *buffer ) { + Com_Dealloc( buffer ); +} + +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) { + FILE *fh; + long len; + + fh = fopen( filename, "rb" ); + *file = *(fileHandle_t *)&fh; + + if( file ) + { + fseek (fh, 0, SEEK_END); + len = ftell (fh); + rewind (fh); + return len; + } + else + return -1; +} + +fileHandle_t FS_FOpenFileWrite( const char *filename ) { + FILE *fh; + fileHandle_t f; + + memset( &f, 0, sizeof(f) ); + + fh = fopen( filename, "wb" ); + + f = (fileHandle_t)fh; + return f; +} + +void FS_FCloseFile( fileHandle_t f ) { + fclose( (FILE *)f ); +} diff --git a/contrib/camera/misc.h b/contrib/camera/misc.h new file mode 100644 index 00000000..6c56dc73 --- /dev/null +++ b/contrib/camera/misc.h @@ -0,0 +1,91 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +void Sys_ERROR( char* text, ... ); +char* UnixToDosPath( char* path ); +void ExtractFilePath( const char *path, char *dest ); +const char* ExtractFilename( const char* path ); +bool FileExists (const char *filename); +int Q_stricmp (const char *s1, const char *s2); + +typedef int fileHandle_t; + +#define qfalse false +#define qtrue true + +extern "C" { +// command buffer +void Cbuf_AddText( const char *text ); +void Cbuf_Execute (void); + +// common +#ifndef CDECL +#ifdef _WIN32 + #define CDECL __cdecl +#else + #define CDECL +#endif +#endif + +void CDECL Com_Error( int level, const char *error, ... ); +void CDECL Com_Printf( const char *msg, ... ); +void CDECL Com_DPrintf( const char *msg, ... ); +void *Com_Allocate( int bytes ); +void Com_Dealloc( void *ptr ); + +// filesystem +int FS_Read( void *buffer, int len, fileHandle_t f ); +int FS_Write( const void *buffer, int len, fileHandle_t h ); +int FS_ReadFile( const char *qpath, void **buffer ); +void FS_FreeFile( void *buffer ); +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ); +fileHandle_t FS_FOpenFileWrite( const char *filename ); +void FS_FCloseFile( fileHandle_t f ); +} + +// vectors +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) + +#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) +#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) +#define CrossProduct(a,b,c) ((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]) + +#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3]) +#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) +#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s)) +#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s)) + +#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) +#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + +#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];} diff --git a/contrib/camera/renderer.cpp b/contrib/camera/renderer.cpp new file mode 100644 index 00000000..9f44a37d --- /dev/null +++ b/contrib/camera/renderer.cpp @@ -0,0 +1,183 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +CRenderer::CRenderer() { + + refCount = 1; + + m_bHooked = FALSE; + + Register(); + Initialize(); +} + +CRenderer::~CRenderer() { + if( m_bHooked ) + UnRegister(); +} + +void CRenderer::Register() { + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void CRenderer::UnRegister() { + if( g_QglTable.m_nSize ) { + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + } + m_bHooked = FALSE; +} + +void CRenderer::Initialize() { + +} + +void CRenderer::Draw2D( VIEWTYPE vt ) { + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + CCamera *cam = firstCam; + while( cam ) { + cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); + cam = cam->GetNext(); + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void CRenderer::Draw3D() { + // FIXME: really need a mainloop callback from the editor core + static long start; + static float cycle; + static long msecs; + static long current; + + if( g_iPreviewRunning ) { + if( g_iPreviewRunning == 1 ) { + start = g_FuncTable.m_pfnQGetTickCount(); + GetCurrentCam()->GetCam()->startCamera( start ); + cycle = GetCurrentCam()->GetCam()->getTotalTime(); + msecs = (long)(cycle * 1000); + current = start; + g_iPreviewRunning = 2; + } + + if( current < start + msecs ) { + float fov; + vec3_t origin = {0.0f, 0.0f, 0.0f}, dir = {0.0f, 0.0f, 0.0f}, angles; + + GetCurrentCam()->GetCam()->getCameraInfo( current, &origin[0], &dir[0], &fov ); + VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); + g_CameraTable.m_pfnSetCamera( origin, angles ); + current = g_FuncTable.m_pfnQGetTickCount(); + } else { + g_iPreviewRunning = 0; + GetCurrentCam()->GetCam()->setRunning( false ); + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + CCamera *cam = firstCam; + while( cam ) { + cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); + cam = cam->GetNext(); + } + + if( g_iPreviewRunning ) { + int x, y, width, height, i; + float degInRad; + + g_CameraTable.m_pfnGetCamWindowExtents( &x, &y, &width, &height ); + + // setup orthographic projection mode + g_QglTable.m_pfn_qglMatrixMode(GL_PROJECTION); + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglDisable( GL_DEPTH_TEST ); + g_QglTable.m_pfn_qglOrtho( 0, (float)width, 0, (float)height, -100, 100 ); + g_QglTable.m_pfn_qglMatrixMode( GL_MODELVIEW ); + + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglColor3f( 1.f, 1.f, 1.f ); + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + g_QglTable.m_pfn_qglVertex2f( 10, 10 ); + g_QglTable.m_pfn_qglVertex2f( 40, 10 ); + g_QglTable.m_pfn_qglVertex2f( 40, 25 ); + g_QglTable.m_pfn_qglVertex2f( 10, 25 ); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for( i = 0; i < 360; i += 60 ) { + degInRad = i * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + } + g_QglTable.m_pfn_qglEnd(); + + degInRad = (360-((current - start) % 360)) * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglBegin( GL_LINES ); + g_QglTable.m_pfn_qglVertex2f( 18, 18 ); + g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + g_QglTable.m_pfn_qglVertex2f( 32, 18 ); + g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for( i = 0; i < 360; i += 60 ) { + degInRad = i * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + } + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINES ); + g_QglTable.m_pfn_qglVertex2f( 40, 22 ); + g_QglTable.m_pfn_qglVertex2f( 52, 31 ); + g_QglTable.m_pfn_qglVertex2f( 40, 13 ); + g_QglTable.m_pfn_qglVertex2f( 52, 4 ); + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} diff --git a/contrib/camera/renderer.h b/contrib/camera/renderer.h new file mode 100644 index 00000000..c2ca93bd --- /dev/null +++ b/contrib/camera/renderer.h @@ -0,0 +1,46 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +class CRenderer : public IGL2DWindow, public IGL3DWindow { +public: + CRenderer(); + virtual ~CRenderer(); + +protected: + int refCount; + +public: + void Register(); + void UnRegister(); + void Initialize(); + void Draw2D( VIEWTYPE vt ); + void Draw3D(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + bool m_bHooked; +}; diff --git a/contrib/gtkgensurf/.cvsignore b/contrib/gtkgensurf/.cvsignore new file mode 100644 index 00000000..7320b210 --- /dev/null +++ b/contrib/gtkgensurf/.cvsignore @@ -0,0 +1,4 @@ +Debug +*.plg +*.BAK +*.d diff --git a/contrib/gtkgensurf/CHANGES b/contrib/gtkgensurf/CHANGES new file mode 100644 index 00000000..3d916c71 --- /dev/null +++ b/contrib/gtkgensurf/CHANGES @@ -0,0 +1,73 @@ +05/14/2001 + ^Fishman +=============== +bitmap.cpp +Added Hydra's snap to grid code. +=============== +dec.cpp +Modified to support the new max size for the maps(Q3 1.27). +=============== +face.cpp +Modified to support the new max size for the maps(Q3 1.27). +=============== +font.cpp +Changed the fonts color to green, part of the new theme. +=============== +gendlgs.cpp +Added a label and textbox for the snap to grid feature. +Added a checkbox for adding terrain key to func_group. +Added a checkbox for antialiased lines in the preview window. +Modified a textbox to support the new max size for the maps(Q3 1.27). +Modified the About dialog. +=============== +genmap.cpp +Modified to support the new max size for the maps(Q3 1.27). +Added code for adding terrain key to func_group. +=============== +gensurf.cpp +Added code to save the settings of the antialiasing checkbox status and the terrain key checkbox status. +Modified version number. +=============== +view.cpp +Modified code for the new Green/Black theme. +Added code to antialiase lines in the preview window + +12/18/2000 + MrHyde +=============== +bitmap.cpp +Corrected a substitution error that would prevent code from reading a selected bitmap on the first pass, and possibly leave the bitmap file open. +Checks to ensure that main window has been created before updating the preview (which might be done if a bitmap filename was saved to ini file). Previous failure to do this resulted in Radiant console error messages. +=============== +gendlgs.cpp +One tooltip was goofed up ("preview" instead of "main_preview"), resulting in "invalid cast from (NULL) pointer to GtkObject" in Radiant console. +Tooltips - oops. Use wave_radios[] rather than string constants. +Moved check for game type from SetDlgValues to GenSurfInit in gensurf.cpp. Since the game type presumably won't change while GenSurf is active this only needs to be checked once (and if it IS possible to change the game while GenSurf is active then quite a bit more needs to be changed). +Worked around strange bug in SetDlgValues. In release dll (not debug), the 2nd pass through the set_sensitive loop for game_radios crashed. Since the state of those radio buttons won't ever change during a single session, the state is only set once now. Sure would like to know what's going on there, though. +=============== +view.cpp +Elevation and azimuth labels are right-justified. + +TODO: +Check out Fix Points on Voodoo2 again. Previous attempt caused entire preview to be redrawn when moving mouse (GL_SCISSOR_TEST failed?) + +12/17/2000 + MrHyde +- tooltips +- reformatted the source to use spaces instead of tabs +- fixes to update mechanism in bitmap tab + +12/13/2000 + MrHyde +=============== +gendlgs.cpp +In ReadDlgValues, reads wavelength, amplitude, and roughness text boxes (previously ignored). +In create_main_dialog, set a "focus_out_event" for the above and added a "value_changed" for RandomSeed. +In main_go, added call to WriteIni +=============== +gensurf.cpp +Set gszIni to "plugins/gensurf.ini" to get past assert error +ported WriteIni +=============== +view.cpp +In DrawPreview, changed 2 occurrences of GL_LINE_LOOP to GL_LINE_STRIP for patches diff --git a/contrib/gtkgensurf/bitmap.cpp b/contrib/gtkgensurf/bitmap.cpp new file mode 100644 index 00000000..93dcd282 --- /dev/null +++ b/contrib/gtkgensurf/bitmap.cpp @@ -0,0 +1,434 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +void GenerateBitmapMapping () +{ + double value; + double C0, C1; + double x, y; + int i, j; + int O00,O01,O10,O11; + int r0, r1, c0, c1; + int color; + unsigned char *colors; + + if (!gbmp.colors) + return; + + colors = gbmp.colors; + + for (j=0; j<=NV; j++) + { + y = (double)(j*(gbmp.height-1))/(double)NV; + r0 = (int)floor(y); + r1 = (int)ceil(y); + for (i=0; i<=NH; i++) + { + x = (double)(i*(gbmp.width-1))/(double)NH; + c0 = (int)floor(x); + c1 = (int)ceil(x); + O00 = r0*gbmp.width + c0; + O01 = r0*gbmp.width + c1; + O10 = r1*gbmp.width + c0; + O11 = r1*gbmp.width + c1; + C0 = (double)colors[O00] + (double)(colors[O01]-colors[O00])*(x-(double)c0); + C1 = (double)colors[O10] + (double)(colors[O11]-colors[O10])*(x-(double)c0); + color = (int)(C0 + (C1-C0)*(y-r0)); + + value = CalculateSnapValue(gbmp.black_value + color*((gbmp.white_value-gbmp.black_value)/255.)); + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] = value; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] = value; + break; + default: + xyz[i][j].p[2] = value; + } + } + } +} + +static unsigned char* OpenBitmapFile () +{ + int bmWidth; + int bmHeight; + unsigned char bmPlanes; + unsigned char bmBitsPixel; + unsigned char m1,m2; + unsigned long sizeimage; + short res1,res2; + long filesize, pixoff; + long bmisize, compression; + long xscale, yscale; + long colors, impcol; + unsigned long m_bytesRead = 0; + unsigned char *image; + FILE *fp; + + fp = fopen (gbmp.name, "rb"); + if (fp == NULL) + return NULL; + + long rc; + rc = fread(&m1, 1, 1, fp); + m_bytesRead++; + if (rc == -1) + { + fclose(fp); + return NULL; + } + + rc = fread(&m2, 1, 1, fp); + m_bytesRead++; + if ((m1 != 'B') || (m2 != 'M')) + { + fclose(fp); + return NULL; + } + + rc = fread((long*)&(filesize),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(res1),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(res2),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(pixoff),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(bmisize),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long *)&(bmWidth),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(bmHeight),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(bmPlanes),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(compression),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(sizeimage),4,1,fp); m_bytesRead+=4; + if (rc != 1) {fclose(fp); return NULL; } + + rc = fread((long*)&(xscale),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(yscale),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(colors),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(impcol),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + if (bmBitsPixel != 8) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "This is not an 8-bit image. GenSurf can't use it.", + "Bitmap", MB_ICONEXCLAMATION); + fclose(fp); + return NULL; + } + + if (colors == 0) + colors = 1 << bmBitsPixel; + + if (bmBitsPixel != 24) + { + int i; + for (i = 0; i < colors; i++) + { + unsigned char r ,g, b, dummy; + + rc = fread(&b, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + fclose(fp); + return NULL; + } + + rc = fread(&g, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + fclose(fp); + return NULL; + } + + rc = fread(&r, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + fclose(fp); + return NULL; + } + + rc = fread(&dummy, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + fclose(fp); + return NULL; + } + } + } + + if ((long)m_bytesRead > pixoff) + { + fclose(fp); + return NULL; + } + + while ((long)m_bytesRead < pixoff) + { + char dummy; + fread(&dummy,1,1,fp); + m_bytesRead++; + } + + int w = bmWidth; + int h = bmHeight; + + // set the output params + image = (unsigned char*)malloc(w*h); + + if (image != NULL) + { + gbmp.width = w; + gbmp.height = h; + unsigned char* outbuf = image; + long row = 0; + long rowOffset = 0; + + if (compression == 0) // BI_RGB + { + for (row = 0; row < bmHeight; row++) + { + // which row are we working on? + rowOffset = (long unsigned)row*w; + + { + // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them + int bit_count = 0; + unsigned long mask = (1 << bmBitsPixel) - 1; + unsigned char inbyte = 0; + + for (int col=0;col> bit_count) & mask; + + // lookup the color from the colormap - stuff it in our buffer + // swap red and blue + *(outbuf + rowOffset + col) = pix; + } + + // read DWORD padding + while ((m_bytesRead-pixoff)&3) + { + char dummy; + if (fread(&dummy,1,1,fp)!=1) + { + free(image); + fclose(fp); + return NULL; + } + m_bytesRead++; + } + } + } + } + else // compression != 0 + { + int i, x = 0; + unsigned char c, c1 = 0, *pp; + row = 0; + pp = outbuf; + + if (bmBitsPixel == 8) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = c1; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + row*bmWidth; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x + row*bmWidth; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + c1 = getc(fp); + *pp = c1; pp++; + } + + if (c & 1) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + else if (bmBitsPixel == 4) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + bmHeight*bmWidth; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x + row*bmWidth; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + if ((i&1) == 0) + c1 = getc(fp); + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; + } + + if (((c&3) == 1) || ((c&3) == 2)) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + } + } + fclose(fp); + return image; +} + +bool OpenBitmap () +{ + if (gbmp.colors) + free (gbmp.colors); + + gbmp.colors = OpenBitmapFile (); + + if (!gbmp.colors) + { + char Text[256]; + + sprintf (Text, "Error opening %s", gbmp.name); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "Bitmap", MB_ICONEXCLAMATION); + strcpy (gbmp.name, ""); + } + + if (g_pWnd) + { + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), + strlen (gbmp.name) ? TRUE : FALSE); + + UpdatePreview (true); + } + + return (gbmp.colors != NULL); +} diff --git a/contrib/gtkgensurf/dec.cpp b/contrib/gtkgensurf/dec.cpp new file mode 100644 index 00000000..4dbedf8c --- /dev/null +++ b/contrib/gtkgensurf/dec.cpp @@ -0,0 +1,1328 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define SINGLE +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +#include +#include +#include +#include "gensurf.h" +#include "triangle.h" + +typedef struct +{ + float error; + int node; +} TRITABLE; + +double dh, dv; +int NVP1; + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) + +void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri) +{ + int compare(TRITABLE *, TRITABLE *); + int Bisect(NODE *, int, int, int); + void CalcAngles(NODE *, int *, float *); + void EdgeOnSide(int *, int *, int *); + int tricall(int, NODE *, int *, TRI **, TRI **, char *); + int CheckBorders(int *,int,NODE *,int *,TRI **); + + float biggesterror; + int i, j, N; + int j0, j1, j2; + int NumNodesToSave; + int NumNodesUsed; + NODE *Node; + TRI *Tri; + TRITABLE *TriTable; + + if(Decimate <= 0) return; + /* + ghCursorCurrent = LoadCursor(NULL,IDC_WAIT); + SetCursor(ghCursorCurrent); + */ + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + NVP1 = NV+1; + + NumNodes[0] = (NH+1)*(NVP1); + *pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE)); + Node = *pNode; + memset(Node,0,NumNodes[0]*sizeof(NODE)); + + // Copy [NH][NV] vertex array to our working node array + for(i=0,N=0; i<=NH; i++) + { + for(j=0; j<=NV; j++, N++) + { + Node[N].p[0] = (float)xyz[i][j].p[0]; + Node[N].p[1] = (float)xyz[i][j].p[1]; + Node[N].p[2] = (float)xyz[i][j].p[2]; + Node[N].fixed = xyz[i][j].fixed; + } + } + // Start things off with the corner values + Node[ 0].used = 1; + Node[NV].used = 1; + Node[NH*NVP1].used = 1; + Node[NH*NVP1+NV].used = 1; + NumNodesUsed = 4; + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + + // Which coordinates are we triangulating on? + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + j0 = 1; + j1 = 0; + j2 = 2; + break; + case PLANE_YZ0: + case PLANE_YZ1: + j0 = 0; + j1 = 1; + j2 = 2; + break; + default: + j0 = 2; + j1 = 0; + j2 = 1; + } + + // TriTable stores the largest error in a triangle and the node where that + // error occurs + TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE)); + NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed)); + + while(NumNodesUsed < NumNodesToSave) + { + for(i=0; i TriTable[Node[i].tri].error) + { + TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error)); + TriTable[Node[i].tri].node = i; + } + } + qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare ); + for(i=0; i 0.5*biggesterror; i++) + { + if(Node[TriTable[i].node].used) continue; // shouldn't happen + NumNodesUsed++; + Node[TriTable[i].node].used++; + } + free(Tri); + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + // Sliver-check along borders. Since borders are often linear, the errors + // along borders will often be zero, so no new points will be added. This + // tends to produce long, thin brushes. For all border triangles, check + // that minimum angle isn't less than SLIVER_ANGLE. If it is, add another + // vertex. + while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0) + { + } + Tri = *pTri; + } + } + free(TriTable); + // One last time (because we're pessimistic), check border triangles +// CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri); +// Tri = *pTri; + + // Check that all fixed points are exact. If not, add them to the mix. + // First check to see if we have any fixed points that aren't already used. + for(i=0, N=0; i 0.5) + { + NumNodesUsed++; + Node[i].used++; + free(Tri); + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + } + } + } + + // Swap node orders for surfaces facing down, north or west so that + // they are counterclockwise when facing the surface + + if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) ) + { + for(i=0; i= R) && (v[1] >= R) ) + { + edge[0] = 0; + border[0] = 1; + } + if( (v[1] >= R) && (v[2] >= R) ) + { + edge[0] = 1; + border[0] = 1; + } + if( (v[2] >= R) && (v[0] >= R) ) + { + edge[0] = 2; + border[0] = 1; + } + + if(border[0] >= 0) + { + k0 = edge[0]; + k1 = (k0+1) % 3; + N = Absolute(v[k0] - v[k1]); + Ndv = (float)(N*dv); + } + if( ((v[0] % NVP1) == 0) && ((v[1] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[0] - v[1])*dh)) return; + edge[0] = 0; + border[0] = 2; + return; + } + if( ((v[1] % NVP1) == 0) && ((v[2] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[1] - v[2])*dh)) return; + edge[0] = 1; + border[0] = 2; + return; + } + if( ((v[2] % NVP1) == 0) && ((v[0] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[2] - v[0])*dh)) return; + edge[0] = 2; + border[0] = 2; + return; + } + + if( ((v[0] % NVP1) == NV) && ((v[1] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[0] - v[1])*dh)) return; + edge[0] = 0; + border[0] = 3; + return; + } + if( ((v[1] % NVP1) == NV) && ((v[2] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[1] - v[2])*dh)) return; + edge[0] = 1; + border[0] = 3; + return; + } + if( ((v[2] % NVP1) == NV) && ((v[0] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[2] - v[0])*dh)) return; + edge[0] = 2; + border[0] = 3; + return; + } + return; +} + +void CalcAngles(NODE *node, int *v, float *angle) +{ + int i, j, k; + vec l; + vec x0, x1, x2, y0, y1, y2; + vec2 vv[3]; + vec dot; + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + i = 0; + j = 2; + break; + case PLANE_YZ0: + case PLANE_YZ1: + i = 1; + j = 2; + break; + default: + i = 0; + j = 1; + } + x0 = node[v[0]].p[i]; + x1 = node[v[1]].p[i]; + x2 = node[v[2]].p[i]; + y0 = node[v[0]].p[j]; + y1 = node[v[1]].p[j]; + y2 = node[v[2]].p[j]; + + vv[0][0] = x1-x0; + vv[0][1] = y1-y0; + vv[1][0] = x2-x1; + vv[1][1] = y2-y1; + vv[2][0] = x0-x2; + vv[2][1] = y0-y2; + + for(k=0; k<3; k++) + { + l = (vec)(sqrt( vv[k][0]*vv[k][0] + vv[k][1]*vv[k][1] )); + if(l > 0.) + { + vv[k][0] /= l; + vv[k][1] /= l; + } + } + + dot = -(vv[0][0]*vv[2][0] + vv[0][1]*vv[2][1]); + angle[0] = (float)(acos(dot)); + dot = -(vv[1][0]*vv[0][0] + vv[1][1]*vv[0][1]); + angle[1] = (float)(acos(dot)); + dot = -(vv[2][0]*vv[1][0] + vv[2][1]*vv[1][1]); + angle[2] = (float)(acos(dot)); +} +//================================================================= +int Bisect(NODE *node, int border, int j0, int j1) +{ + int k; + + switch(border) + { + case 0: + k = (j0+j1)/2; + break; + case 1: + k = (j0+j1)/2; + break; + case 2: + k = (int)((j0+j1)/(2*NVP1)) * NVP1; + break; + case 3: + k = (int)((j0+j1+2)/(2*NVP1)) * NVP1 - 1; + break; + } + return( ((k != j0) && (k != j1)) ? k : 0 ); +} +//================================================================= +int compare(TRITABLE *t1, TRITABLE *t2) +{ + if(t1->error > t2->error) return -1; + if(t1->error < t2->error) return 1; + return 0; +} + +void MakeBrushes(int NumTris, NODE *Node, TRI *Tri,bool surf, + int offset,char *texture0, char *texture1, char *texture2) +{ + extern double backface; + BRUSH brush; + int contents; + int i, j; + float Steep; + vec3_t PlaneNormal,SurfNormal; + bool CheckAngle; + vec3_t t[2]; + + // if texture2 is identical to texture0, there's no need to + // check surface angle + if(!g_strcasecmp(texture0,texture2) || !strlen(texture2)) + CheckAngle = FALSE; + else + { + CheckAngle = TRUE; + Steep = (float)cos((double)SlantAngle/57.2957795); + switch(Plane) + { + case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break; + case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break; + case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break; + case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + } + } + + contents = 0; + if(surf) + { + if(UseDetail) contents += CONTENTS_DETAIL; + if(UseLadder) contents += CONTENTS_LADDER; + } + + OpenFuncGroup(); + for(i=0; i= max(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; + if(Tri[k].min[j2] >= max(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; + if(Tri[k].max[j1] <= min(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; + if(Tri[k].max[j2] <= min(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; + + for(h0=0; h0<4 && OK; h0++) + { + h1 = (h0+1)%4; + for(t=0; t<3 && OK; t++) + { + s[t] = side(Node[q[h0]].p[j1],Node[q[h0]].p[j2], + Node[q[h1]].p[j1],Node[q[h1]].p[j2], + Node[Tri[k].v[t]].p[j1],Node[Tri[k].v[t]].p[j2]); + } + if((s[1] > 0 || s[2] > 0) && s[0] < 0) OK=0; + if((s[2] > 0 || s[0] > 0) && s[1] < 0) OK=0; + if((s[0] > 0 || s[1] > 0) && s[2] < 0) OK=0; + } + } + if(!OK) continue; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + // front + brush.face[0].v[0][0] = Node[q[2]].p[0]; + brush.face[0].v[0][1] = (float)front; + brush.face[0].v[0][2] = Node[q[2]].p[2]; + + brush.face[0].v[1][0] = Node[q[1]].p[0]; + brush.face[0].v[1][1] = (float)front; + brush.face[0].v[1][2] = Node[q[1]].p[2]; + + brush.face[0].v[2][0] = Node[q[0]].p[0]; + brush.face[0].v[2][1] = (float)front; + brush.face[0].v[2][2] = Node[q[0]].p[2]; + + // back + brush.face[1].v[0][0] = Node[q[0]].p[0]; + brush.face[1].v[0][1] = (float)backface; + brush.face[1].v[0][2] = Node[q[0]].p[2]; + + brush.face[1].v[1][0] = Node[q[1]].p[0]; + brush.face[1].v[1][1] = (float)backface; + brush.face[1].v[1][2] = Node[q[1]].p[2]; + + brush.face[1].v[2][0] = Node[q[2]].p[0]; + brush.face[1].v[2][1] = (float)backface; + brush.face[1].v[2][2] = Node[q[2]].p[2]; + + for(k0=0; k0= 0) + { + if(!Node[j].used) // Shouldn't be used, but... + { + NumNodesUsed[0]++; + Node[j].used++; + } + } + } + } + if(NumNodesUsed[0] > N) + { + free(*pTri); + tricall(NumNodes, Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + } + return (NumNodesUsed[0] - N); +} diff --git a/contrib/gtkgensurf/face.cpp b/contrib/gtkgensurf/face.cpp new file mode 100644 index 00000000..6c43c677 --- /dev/null +++ b/contrib/gtkgensurf/face.cpp @@ -0,0 +1,450 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "gensurf.h" + +#define MAX_FACES 128 // Maximum number of faces on a brush +#define MAX_POINTS_ON_WINDING 64 +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +vec3 vec3_origin = {0,0,0}; + +void PlaneFromPoints (float *p0, float *p1, float *p2, PLANE *plane) +{ + vec3 t1, t2; + vec length; + + VectorSubtract (p0, p1, t1); + VectorSubtract (p2, p1, t2); + plane->normal[0] = t1[1]*t2[2] - t1[2]*t2[1]; + plane->normal[1] = t1[2]*t2[0] - t1[0]*t2[2]; + plane->normal[2] = t1[0]*t2[1] - t1[1]*t2[0]; + + length = (vec)(sqrt(plane->normal[0]*plane->normal[0] + + plane->normal[1]*plane->normal[1] + + plane->normal[2]*plane->normal[2] )); + if (length == 0) + { + VectorClear(plane->normal); + } + else + { + plane->normal[0] /= length; + plane->normal[1] /= length; + plane->normal[2] /= length; + } + plane->dist = DotProduct (p0, plane->normal); +} + +void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3 v1, vec3 v2, vec3 cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +/* +============= +AllocWinding +============= +*/ +MY_WINDING *AllocWinding (int points) +{ + MY_WINDING *w; + int s; + + s = sizeof(vec)*3*points + sizeof(int); + w = (MY_WINDING*)malloc (s); + memset (w, 0, s); + return w; +} + +vec VectorNormalize (vec3 in, vec3 out) +{ + vec length, ilength; + + length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2])); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = (vec)1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +/* +================= +BaseWindingForPlane +================= +*/ +MY_WINDING *BaseWindingForPlane (vec3 normal, vec dist) +{ + int i, x; + vec max, v; + vec3 org, vright, vup; + MY_WINDING *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = (vec)(fabs(normal[i])); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) x = 2; + + VectorCopy(vec3_origin,vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 65536, vup); + VectorScale (vright, 65536, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +void FreeWinding (MY_WINDING *w) +{ + if (*(unsigned *)w == 0xdeaddead) +// Error ("FreeWinding: freed a freed winding"); + return; + *(unsigned *)w = 0xdeaddead; + + free (w); +} + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (MY_WINDING **inout, vec3 normal, vec dist, vec epsilon) +{ + MY_WINDING *in; + vec dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec dot; // VC 4.2 optimizer bug if not static + int i, j; + vec *p1, *p2; + vec3 mid; + MY_WINDING *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding(in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + +// if (f->numpoints > maxpts) +// Error ("ClipWinding: points exceeded estimate"); +// if (f->numpoints > MAX_POINTS_ON_WINDING) +// Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding(in); + *inout = f; +} + +void UseFaceBounds() +{ + LPVOID vp; + float Dot, BestDot; + float planepts[3][3]; + int BestFace; + int i, j; + int NumFaces; + vec3 SurfNormal; + vec3 vmin,vmax; + _QERFaceData *QERFaceData; + PLANE plane[MAX_FACES*2]; + PLANE pface; + MY_WINDING *w; + + switch(Plane) + { + case PLANE_XY1: + SurfNormal[0] = 0.0; + SurfNormal[1] = 0.0; + SurfNormal[2] =-1.0; + break; + case PLANE_XZ0: + SurfNormal[0] = 0.0; + SurfNormal[1] = 1.0; + SurfNormal[2] = 0.0; + break; + case PLANE_XZ1: + SurfNormal[0] = 0.0; + SurfNormal[1] =-1.0; + SurfNormal[2] = 0.0; + break; + case PLANE_YZ0: + SurfNormal[0] = 1.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 0.0; + break; + case PLANE_YZ1: + SurfNormal[0] =-1.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 0.0; + break; + default: + SurfNormal[0] = 0.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 1.0; + } + + i = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + vp = g_FuncTable.m_pfnGetSelectedBrushHandle(0); + NumFaces = g_FuncTable.m_pfnGetFaceCount(vp); + + BestFace = -1; + BestDot = 0.0; + + for(i=0; im_v1[0]; + planepts[0][1] = QERFaceData->m_v1[1]; + planepts[0][2] = QERFaceData->m_v1[2]; + planepts[1][0] = QERFaceData->m_v2[0]; + planepts[1][1] = QERFaceData->m_v2[1]; + planepts[1][2] = QERFaceData->m_v2[2]; + planepts[2][0] = QERFaceData->m_v3[0]; + planepts[2][1] = QERFaceData->m_v3[1]; + planepts[2][2] = QERFaceData->m_v3[2]; + + PlaneFromPoints (planepts[0], planepts[1], planepts[2], &plane[2*i]); + VectorSubtract (vec3_origin, plane[2*i].normal, plane[2*i+1].normal); + plane[2*i+1].dist = -plane[2*i].dist; + + Dot = DotProduct(plane[2*i].normal,SurfNormal); + if(Dot > BestDot) + { + BestDot = Dot; + BestFace = i; + if(strlen(QERFaceData->m_TextureName)) + strcpy(Texture[Game][0],QERFaceData->m_TextureName); + } + } + for(i=0; im_TextureName)) + { + if(strcmp(Texture[Game][0],QERFaceData->m_TextureName)) + strcpy(Texture[Game][1],QERFaceData->m_TextureName); + } + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + w = BaseWindingForPlane (plane[BestFace*2].normal, plane[BestFace*2].dist); + + for (i=0 ; ip[0][0]; + vmin[1] = vmax[1] = w->p[0][1]; + vmin[2] = vmax[2] = w->p[0][2]; + for(j=1; jnumpoints; j++) + { + vmin[0] = min(vmin[0],w->p[j][0]); + vmin[1] = min(vmin[1],w->p[j][1]); + vmin[2] = min(vmin[2],w->p[j][2]); + vmax[0] = max(vmax[0],w->p[j][0]); + vmax[1] = max(vmax[1],w->p[j][1]); + vmax[2] = max(vmax[2],w->p[j][2]); + } + + FreeWinding(w); + + VectorCopy(plane[BestFace*2].normal,pface.normal); + pface.dist = plane[BestFace*2].dist; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + if(pface.normal[1] == 0.) return; + Hll = vmin[0]; + Hur = vmax[0]; + Vll = vmin[2]; + Vur = vmax[2]; + Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vll)/pface.normal[1]; + Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vur)/pface.normal[1]; + Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vll)/pface.normal[1]; + Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vur)/pface.normal[1]; + break; + case PLANE_YZ0: + case PLANE_YZ1: + if(pface.normal[0] == 0.) return; + Hll = vmin[1]; + Hur = vmax[1]; + Vll = vmin[2]; + Vur = vmax[2]; + Z00 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vll)/pface.normal[0]; + Z01 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vur)/pface.normal[0]; + Z10 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vll)/pface.normal[0]; + Z11 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vur)/pface.normal[0]; + break; + default: + if(pface.normal[2] == 0.) return; + Hll = vmin[0]; + Hur = vmax[0]; + Vll = vmin[1]; + Vur = vmax[1]; + Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vll)/pface.normal[2]; + Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vur)/pface.normal[2]; + Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vll)/pface.normal[2]; + Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vur)/pface.normal[2]; + } +} diff --git a/contrib/gtkgensurf/font.cpp b/contrib/gtkgensurf/font.cpp new file mode 100644 index 00000000..bb3753f1 --- /dev/null +++ b/contrib/gtkgensurf/font.cpp @@ -0,0 +1,270 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// +// Texture Font +// +// Taken from LeoCAD (www.leocad.org) and used in GtkGenSurf +// with permission from the author. +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "gensurf.h" + +static const unsigned char data[2048] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 31, 255, 231, 159, 153, 63, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 207, 255, 231, 159, 153, 63, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 207, 255, 231, 255, 159, 63, 255, 255, 255, 255, + 7, 78, 252, 240, 145, 135, 3, 71, 38, 158, 153, 51, 19, 227, 196, 255, + 243, 140, 121, 230, 140, 51, 207, 51, 198, 156, 153, 57, 99, 204, 152, 255, + 255, 204, 51, 111, 158, 121, 206, 121, 230, 153, 153, 60, 115, 206, 60, 255, + 31, 204, 51, 127, 158, 121, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, + 199, 204, 51, 127, 158, 1, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, + 243, 204, 51, 127, 158, 249, 207, 121, 230, 153, 153, 60, 115, 206, 60, 255, + 243, 204, 51, 111, 158, 249, 207, 121, 230, 153, 153, 57, 115, 206, 60, 255, + 243, 140, 121, 230, 140, 115, 206, 51, 230, 153, 153, 51, 115, 206, 60, 255, + 7, 73, 252, 240, 145, 7, 207, 71, 230, 153, 153, 39, 115, 206, 60, 255, + 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 57, 255, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 131, 255, 255, 252, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 227, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 201, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 156, 255, + 15, 79, 252, 200, 196, 96, 32, 79, 62, 252, 15, 15, 159, 192, 156, 255, + 103, 142, 121, 198, 112, 206, 57, 79, 62, 60, 15, 15, 159, 207, 156, 255, + 243, 204, 51, 207, 120, 254, 57, 207, 156, 57, 103, 102, 206, 231, 156, 255, + 243, 204, 51, 207, 124, 252, 57, 207, 156, 25, 230, 112, 206, 231, 156, 255, + 243, 204, 51, 207, 252, 224, 57, 207, 156, 25, 230, 121, 206, 243, 156, 255, + 243, 204, 51, 207, 252, 199, 57, 207, 201, 211, 242, 240, 228, 249, 156, 255, + 243, 204, 51, 207, 252, 207, 57, 207, 201, 195, 112, 230, 228, 249, 156, 255, + 103, 142, 121, 198, 124, 206, 121, 198, 227, 231, 57, 207, 241, 252, 201, 255, + 15, 79, 252, 200, 252, 224, 227, 200, 227, 231, 57, 207, 241, 192, 227, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 252, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 159, 15, 30, 252, 57, 224, 225, 128, 131, 7, 255, 254, 128, 127, 240, 255, + 135, 231, 204, 249, 57, 255, 252, 159, 57, 115, 126, 252, 60, 63, 231, 255, + 159, 247, 236, 249, 56, 127, 254, 159, 57, 115, 126, 252, 124, 158, 207, 255, + 159, 255, 252, 249, 56, 127, 254, 207, 57, 115, 62, 249, 124, 158, 207, 255, + 159, 255, 252, 121, 56, 112, 254, 207, 57, 115, 62, 249, 60, 207, 255, 255, + 159, 127, 62, 60, 57, 103, 224, 231, 131, 115, 158, 243, 128, 207, 255, 255, + 159, 63, 255, 57, 249, 103, 206, 231, 57, 7, 158, 243, 60, 207, 255, 255, + 159, 159, 255, 153, 249, 103, 206, 231, 57, 127, 206, 231, 124, 206, 255, 255, + 159, 207, 255, 25, 240, 103, 206, 243, 57, 127, 14, 224, 124, 158, 207, 255, + 159, 231, 239, 249, 185, 103, 206, 243, 57, 127, 230, 207, 124, 158, 207, 255, + 159, 231, 207, 249, 57, 103, 206, 243, 57, 63, 231, 207, 60, 63, 231, 255, + 159, 7, 28, 252, 121, 240, 224, 243, 131, 135, 231, 207, 128, 127, 240, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 7, 126, 128, 3, 124, 240, 249, 156, 63, 231, 57, 255, 252, 57, 159, 255, + 231, 124, 254, 243, 63, 231, 249, 156, 63, 231, 60, 255, 252, 57, 159, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 63, 103, 62, 255, 248, 56, 158, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 63, 39, 63, 255, 248, 56, 156, 255, + 231, 115, 254, 243, 207, 255, 249, 156, 63, 135, 63, 255, 112, 56, 152, 255, + 231, 115, 192, 3, 206, 255, 1, 156, 63, 199, 63, 255, 112, 56, 153, 255, + 231, 115, 254, 243, 207, 193, 249, 156, 63, 135, 63, 255, 36, 57, 147, 255, + 231, 115, 254, 243, 207, 207, 249, 156, 63, 39, 63, 255, 36, 57, 131, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 57, 103, 62, 255, 140, 57, 135, 255, + 231, 121, 254, 243, 159, 199, 249, 156, 57, 231, 60, 255, 140, 57, 143, 255, + 231, 124, 254, 243, 63, 199, 249, 156, 147, 231, 57, 255, 220, 57, 159, 255, + 7, 126, 128, 243, 127, 208, 249, 156, 199, 231, 51, 192, 220, 57, 159, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 63, 252, 128, 63, 252, 128, 63, 28, 128, 249, 204, 79, 254, 39, 63, 255, + 159, 249, 60, 159, 249, 60, 159, 249, 249, 249, 204, 79, 158, 39, 63, 255, + 207, 243, 124, 206, 243, 124, 206, 243, 249, 249, 156, 103, 158, 103, 158, 255, + 207, 243, 124, 206, 243, 124, 206, 255, 249, 249, 156, 231, 156, 243, 204, 255, + 231, 231, 124, 230, 231, 124, 158, 255, 249, 249, 156, 231, 12, 243, 225, 255, + 231, 231, 60, 231, 231, 60, 63, 252, 249, 249, 60, 243, 12, 243, 243, 255, + 231, 231, 128, 231, 231, 128, 255, 249, 249, 249, 60, 243, 105, 249, 243, 255, + 231, 231, 252, 103, 230, 60, 255, 243, 249, 249, 124, 251, 97, 248, 225, 255, + 207, 243, 252, 207, 240, 124, 254, 243, 249, 249, 124, 248, 97, 248, 204, 255, + 207, 243, 252, 207, 241, 124, 206, 243, 249, 249, 124, 248, 243, 124, 158, 255, + 159, 249, 252, 159, 241, 124, 158, 249, 249, 115, 254, 252, 243, 60, 63, 255, + 63, 252, 252, 63, 228, 252, 60, 252, 249, 7, 255, 252, 243, 60, 63, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 243, 19, 192, 255, 252, 255, 255, 127, 14, 127, 248, 15, 252, 247, 227, 231, + 243, 243, 207, 255, 252, 255, 153, 127, 102, 62, 243, 227, 241, 193, 201, 243, + 231, 249, 231, 255, 252, 255, 60, 127, 242, 156, 231, 249, 231, 148, 201, 249, + 207, 252, 243, 255, 204, 124, 126, 126, 254, 156, 231, 57, 230, 148, 201, 252, + 207, 252, 243, 255, 204, 60, 255, 60, 255, 156, 231, 156, 204, 244, 99, 254, + 31, 254, 249, 255, 252, 159, 255, 57, 127, 158, 231, 204, 204, 244, 63, 255, + 31, 254, 252, 255, 252, 207, 255, 51, 63, 159, 231, 204, 204, 193, 159, 255, + 63, 127, 254, 255, 252, 159, 255, 57, 159, 207, 207, 204, 204, 151, 207, 248, + 63, 127, 254, 255, 252, 63, 255, 156, 159, 159, 231, 204, 228, 151, 103, 242, + 63, 63, 255, 255, 255, 127, 126, 158, 255, 159, 231, 25, 241, 148, 115, 242, + 63, 159, 127, 230, 204, 252, 60, 159, 159, 159, 231, 249, 255, 148, 121, 242, + 63, 31, 64, 230, 204, 252, 153, 159, 159, 159, 231, 227, 255, 193, 252, 248, + 255, 255, 63, 255, 231, 255, 255, 255, 255, 159, 231, 15, 252, 247, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 243, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 63, 254, 255, 195, 255, 255, 255, 255, 3, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 255, 153, 255, 255, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 255, 153, 255, 243, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 204, 60, 255, 243, 255, 255, 243, 252, 0, 255, 255, 255, 255, 255, + 63, 254, 204, 60, 255, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 63, 254, 225, 60, 255, 243, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 31, 126, 128, 60, 127, 128, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 159, 228, 225, 60, 193, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 207, 240, 204, 60, 255, 243, 255, 255, 243, 124, 128, 255, 255, 255, 255, 255, + 207, 249, 204, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 207, 240, 255, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 31, 242, 255, 60, 255, 255, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 255, 255, 255, 60, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 153, 255, 255, 255, 0, 242, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 153, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 195, 255, 255, 255, 255, 3, 252, 255, 255, 255, 255, 255, 255 +}; + +typedef struct +{ + unsigned char width; + float left, right, top, bottom; +} LC_TXFVERT; + +static LC_TXFVERT glyphs[93]; +static GLuint texture; + +void texfont_init () +{ + if (texture != 0) + return; + + int i, j, x, y; + float inv = 1.0f/128; + char *charlines[16] = { + "abcdefghijklmn", "opqrstuvwxyz0", "123456789ABC", "DEFGHIJKLMN", + "OPQRSTUVWX", "YZ,.!;:<>/?{}@$%", "&*()-+=_[] #" }; + unsigned char lefts[7][17] = { + { 1, 11, 21, 30, 40, 50, 56, 66, 76, 80, 84, 93, 97, 111, 121 }, + { 1, 11, 21, 31, 38, 47, 53, 63, 72, 86, 94, 103, 111, 120 }, + { 1, 10, 19, 28, 37, 46, 55, 64, 73, 82, 94, 106, 118, }, + { 1, 13, 24, 34, 47, 59, 64, 73, 84, 94, 108, 120 }, + { 1, 14, 25, 38, 50, 61, 71, 83, 94, 109, 120 }, + { 1, 12, 22, 26, 30, 35, 39, 43, 52, 61, 65, 75, 81, 87, 103, 112, 125 }, + { 3, 14, 23, 28, 33, 38, 47, 56, 65, 70, 75, 79, 88 } }; + // tops = 1 20 39 58 77 96 112 (+16) + memset(glyphs, 0, sizeof(glyphs)); + + // ASCII 32-125 + for (i = 32; i < 126; i++) + for (x = 0; x < 7; x++) + for (y = 0; charlines[x][y]; y++) + if (charlines[x][y] == i) + { + glyphs[i-32].width = lefts[x][y+1] - lefts[x][y]; + glyphs[i-32].left = (float)lefts[x][y]*inv; + glyphs[i-32].right = (float)(lefts[x][y+1])*inv; + + if (x != 6) + glyphs[i-32].top = (float)(1 + 19*x); + else + glyphs[i-32].top = 112; + glyphs[i-32].bottom = glyphs[i-32].top + 16; + glyphs[i-32].top *= inv; + glyphs[i-32].bottom *= inv; + } + + g_GLTable.m_pfn_qglGenTextures (1, &texture); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_S); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_T); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // g_GLTable.m_pfn_qglPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + unsigned char *buf = (unsigned char*)malloc (128*128); + memset (buf, 255, 128*128); + + for (i = 0; i < 2048; i++) + for (j = 0; j < 8; j++) + if ((data[i] & (1 << j)) != 0) + buf[i*8+j] = 0; + + g_GLTable.m_pfn_qglTexImage2D (GL_TEXTURE_2D, 0, GL_INTENSITY4, 128, 128, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, buf); + free (buf); +} + +void texfont_write (const char *text, float l, float t) +{ + if (texture == 0) + return; + + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); + g_GLTable.m_pfn_qglEnable (GL_TEXTURE_2D); + // g_GLTable.m_pfn_qglTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + g_GLTable.m_pfn_qglAlphaFunc (GL_GREATER, 0.0625); + g_GLTable.m_pfn_qglEnable (GL_ALPHA_TEST); + + g_GLTable.m_pfn_qglBegin (GL_QUADS); + for (const char* p = text; *p; p++) + { + if (*p < 32 || *p > 125) + continue; + if (glyphs[*p-32].width == 0) + continue; + + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].top); + g_GLTable.m_pfn_qglVertex2f (l, t); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].bottom); + g_GLTable.m_pfn_qglVertex2f (l, t-16); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].bottom); + g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t-16); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].top); + g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t); + l += glyphs[*p-32].width; + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglDisable (GL_ALPHA_TEST); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_2D); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); +} diff --git a/contrib/gtkgensurf/gendlgs.cpp b/contrib/gtkgensurf/gendlgs.cpp new file mode 100644 index 00000000..3faf2707 --- /dev/null +++ b/contrib/gtkgensurf/gendlgs.cpp @@ -0,0 +1,2364 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include "gensurf.h" + +#define GENERAL_TAB 0 +#define EXTENTS_TAB 1 +#define BITMAP_TAB 2 +#define FIXPOINTS_TAB 3 +#define TEXTURE_TAB 4 +//#define BUFF_SIZE 32768 + +#define ENABLE_WIDGET(name,enable) \ + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), (name))), (enable)) +#define CHECK_WIDGET(name,check) \ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), name)), check) + +static GtkWidget *game_radios[NUMGAMES]; +static GtkWidget *wave_radios[5]; +static GtkWidget *plane_radios[6]; +static guint current_tab; +static int OldPreview; +static int WasDetail; +static GtkTooltips *tooltips; +static int FirstPassComplete = 0; + +void About (GtkWidget *parent) +{ +/* + char *icon_xpm[] = { +"32 32 4 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #838183", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................", +"...............++...............", +".............++++++.............", +"............++@+++@+............", +"..........+++..++..+++..........", +"........++.+.++..++.+.@+........", +".......+..+..+.++.+..+..++......", +".....++..++.+..++..+.++..++.....", +"...++..++...+.+..+.++..++..++...", +"..++.+.++....++..++....++.+..+..", +".+.+..+..++....++....++..++.+.+.", +"..+++....+.++++++++++.+....+++..", +"....++.@@+++++.++.++++@++.++....", +"......+++++++......++@+++++.....", +".......+++.+.++..++.+..++.......", +".........++..+.++.+..++.........", +"...........++..++..++...........", +".............++..+.+............", +"..............+..+@.............", +"...............@@...............", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................" +}; +*/ + // leo: I'm too lazy to create a nice about box + // ^Fishman - I am lazy too :P. + g_FuncTable.m_pfnMessageBox (parent, "GtkGenSurf 1.05\n\n" + "Original version\n" + "David Hyde (rascal@vicksburg.com)\n\n" + "Porting\n" + "Leonardo Zide (leo@lokigames.com)\n\n" + "Enhancements\n" + "Pablo Zurita (pablo@qeradiant.com)\n" + "Hydra (hydra@hydras-world.com)", + "About GtkGenSurf", MB_OK); +} + +// ============================================================================= +// main dialog + +static void SetupControls () +{ + switch (current_tab) + { + case GENERAL_TAB: + break; + + case EXTENTS_TAB: + if (Game != QUAKE3) + { + gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); + ENABLE_WIDGET ("use_patches", FALSE); + } + else + { + gtk_widget_show (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); + ENABLE_WIDGET ("use_patches", TRUE); + } + + if (Game == QUAKE3 && UsePatches != 0) + { + ENABLE_WIDGET ("decimate", FALSE); + } + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "snap_text")), "Snap to grid:"); // ^Fishman - Snap to grid. + break; + + case BITMAP_TAB: + if (WaveType != WAVE_BITMAP) + { + ENABLE_WIDGET ("bmp_file", FALSE); + ENABLE_WIDGET ("bmp_file_browse", FALSE); + ENABLE_WIDGET ("bmp_black", FALSE); + ENABLE_WIDGET ("bmp_white", FALSE); + ENABLE_WIDGET ("bmp_text1", FALSE); + ENABLE_WIDGET ("bmp_text2", FALSE); + ENABLE_WIDGET ("bmp_text3", FALSE); + ENABLE_WIDGET ("bmp_reload", FALSE); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), + "These options are disabled unless \"From Bitmap\"\n" + "is selected as the Waveform on the General tab."); + } + else + { + ENABLE_WIDGET ("bmp_file", TRUE); + ENABLE_WIDGET ("bmp_file_browse", TRUE); + ENABLE_WIDGET ("bmp_black", TRUE); + ENABLE_WIDGET ("bmp_white", TRUE); + ENABLE_WIDGET ("bmp_text1", TRUE); + ENABLE_WIDGET ("bmp_text2", TRUE); + ENABLE_WIDGET ("bmp_text3", TRUE); + ENABLE_WIDGET ("bmp_reload", strlen(gbmp.name) != 0); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), + "GenSurf works only with 8-bit bitmaps. Color indices are\n" + "mapped to values for each vertex. Generally, gray scale\n" + "images are stored with black as color 0, white as color 255."); + } + break; + + case FIXPOINTS_TAB: + ENABLE_WIDGET ("fix_value", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_value_text", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_free", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_range", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_range_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_rate", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_rate_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + break; + + case TEXTURE_TAB: + ENABLE_WIDGET ("texture2", (UsePatches == 0)); + ENABLE_WIDGET ("texture3", (UsePatches == 0)); + ENABLE_WIDGET ("tex_slant", (UsePatches == 0)); + ENABLE_WIDGET ("detail", (UsePatches == 0)); + if (Game != QUAKE3 ) + { + ENABLE_WIDGET ("terrain_ent", FALSE); // ^Fishman - Adds terrain key to func_group. + ENABLE_WIDGET ("hint", (UsePatches == 0)); + } + break; + } + + switch (WaveType) + { + case WAVE_HCYLINDER: + case WAVE_VCYLINDER: + ENABLE_WIDGET ("amplitude", TRUE); + ENABLE_WIDGET ("wavelength", TRUE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + break; + case WAVE_BITMAP: + ENABLE_WIDGET ("amplitude", FALSE); + ENABLE_WIDGET ("wavelength", FALSE); + ENABLE_WIDGET ("z00", FALSE); + ENABLE_WIDGET ("z01", FALSE); + ENABLE_WIDGET ("z10", FALSE); + ENABLE_WIDGET ("z11", FALSE); + ENABLE_WIDGET ("linearborder", FALSE); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + break; + case WAVE_ROUGH_ONLY: + ENABLE_WIDGET ("amplitude", FALSE); + ENABLE_WIDGET ("wavelength", FALSE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + break; + default: + ENABLE_WIDGET ("amplitude", TRUE); + ENABLE_WIDGET ("wavelength", TRUE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + } + + switch (Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); + break; + case PLANE_YZ0: + case PLANE_YZ1: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); + break; + default: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Y:"); + break; + } +} + +// SetDlgValues fills in text boxes and initializes other input controls +static void SetDlgValues (int tab) +{ + char Text[256]; + char RForm[16] = "%.5g"; + int i; + + switch (tab) + { + case GENERAL_TAB: + // Hell if I know why, but in the release build the 2nd pass thru the + // set_sensitive loop for game_radios crashes. No need to do this more + // than once anyhow. + if (!FirstPassComplete) + { + for (i = 0; i < NUMGAMES; i++) + gtk_widget_set_sensitive (game_radios[i], (i == Game ? TRUE : FALSE)); + for (i = 0; i < 6; i++) + gtk_widget_set_sensitive (plane_radios[i], (i == Plane ? TRUE : FALSE)); + } + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (game_radios[Game]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plane_radios[Plane]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wave_radios[WaveType]), TRUE); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "random")), + RandomSeed); + sprintf (Text, RForm, WaveLength); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), Text); + sprintf (Text, RForm, Amplitude); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), Text); + sprintf (Text, RForm, Roughness); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), Text); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "main_antialiasing")), Antialiasing); + break; + + case EXTENTS_TAB: + sprintf (Text,RForm,Hll); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), Text); + sprintf (Text,RForm,Vll); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), Text); + sprintf (Text,RForm,Hur); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), Text); + sprintf (Text,RForm,Vur); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), Text); + sprintf (Text,RForm,Z00); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z00")), Text); + sprintf (Text,RForm,Z01); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z01")), Text); + sprintf (Text,RForm,Z10); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z10")), Text); + sprintf (Text,RForm,Z11); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z11")), Text); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "sp")), SP); // ^Fishman - Snap to grid. + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "linearborder")), FixBorders); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "use_patches")), UsePatches); + gtk_adjustment_set_value (GTK_ADJUSTMENT (g_object_get_data (G_OBJECT (g_pWnd), "decimate_adj")), + Decimate); + + if (Game == QUAKE3 && UsePatches) + { + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), FALSE); + + if (NH % 2) + { + NH++; + if (NH > MAX_ROWS) NH -= 2; + SetDlgValues (current_tab); + } + + if (NV % 2) + { + NV++; + if (NV > MAX_ROWS) NV -= 2; + SetDlgValues (current_tab); + } + if (NH % 2 ) NH++; + if (NH < 2 ) NH = 2; + if (NH > MAX_ROWS) NH = MAX_ROWS; + if (NV % 2 ) NV++; + if (NV < 2 ) NV = 2; + if (NV > MAX_ROWS) NV = MAX_ROWS; + + gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); + GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 2; + gtk_adjustment_changed (adj); + spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 2; + gtk_adjustment_changed (adj); + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), TRUE); + + gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); + GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 1; + gtk_adjustment_changed (adj); + spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 1; + gtk_adjustment_changed (adj); + } + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); + + break; + + case BITMAP_TAB: + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); + sprintf(Text,"%g",gbmp.black_value); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), Text); + sprintf(Text,"%g",gbmp.white_value); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), Text); + break; + + case FIXPOINTS_TAB: + break; + + case TEXTURE_TAB: + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), Texture[Game][0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), Texture[Game][1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), Texture[Game][2]); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "tex_slant")), + SlantAngle); + sprintf(Text,RForm,TexOffset[0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsetx")), Text); + sprintf(Text,RForm,TexOffset[1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsety")), Text); + sprintf(Text,RForm,TexScale[0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscalex")), Text); + sprintf(Text,RForm,TexScale[1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscaley")), Text); + CHECK_WIDGET ("detail", UseDetail); + + if (Game==QUAKE3) + { + ENABLE_WIDGET ("hint", FALSE); + AddHints=0; + } + else + ENABLE_WIDGET ("hint", TRUE); + CHECK_WIDGET ("hint", AddHints); + + /* + if (Game==SIN) + { + // ArghRad doesn't currently support SiN + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); + } + */ + + if(Game==QUAKE3) + { + /* + // ArghRad sun is inapplicable (so far) + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + // No ladders in Q3 + EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pk3 file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"PK3:"); + */ + } + +/*trix if(Game==HERETIC2) + { + // ArghRad doesn't currently support Heretic2 + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pak file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Pak:"); + } */ + /* + if(Game==HALFLIFE) + { + // A bunch of controls aren't applicable to HL + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use wad file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Wad:"); + SetDlgItemText(hwndDisplay,DLG_HINT,"Hint brushes"); + } + + if(Game==GENESIS3D) + { + // No Q2-type compilers support Genesis3D (including ArghRad) + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); + } + */ + break; + } + SetupControls (); +} + +static void ReadDlgValues (int tab) +{ + // char Text[256]; + // int i; + + switch (tab) + { + case GENERAL_TAB: + gpointer spin; + Roughness = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")))); + WaveLength = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")))); + Amplitude = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")))); + spin = g_object_get_data (G_OBJECT (g_pWnd), "random"); + RandomSeed = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)); + break; + + case EXTENTS_TAB: + SP = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "sp")))); + NH = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nh")))); + NV = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nv")))); + + if (Game == QUAKE3 && UsePatches != 0) + { + if (NH % 2 ) NH++; + if (NH < 2 ) NH = 2; + if (NH > MAX_ROWS) NH = MAX_ROWS; + if (NV % 2 ) NV++; + if (NV < 2 ) NV = 2; + if (NV > MAX_ROWS) NV = MAX_ROWS; + } + break; + +#if 0 + case BITMAP_TAB: + + if (WaveType == WAVE_BITMAP) + { + GetDlgItemText(hwnd,DLG_BMP_FILE,gbmp.name,sizeof(gbmp.name)); + CheckValidDIB(hwnd); + GetDlgItemText(hwnd,DLG_BMP_BLACK,Text,sizeof(Text)); + gbmp.black_value = atof(Text); + GetDlgItemText(hwnd,DLG_BMP_WHITE,Text,sizeof(Text)); + gbmp.white_value = atof(Text); + UpdatePreview(TRUE); + } + break; + + case FIXPOINTS_TAB: + GetDlgItemText(hwnd,DLG_FIX_VALUE,Text,sizeof(Text)); + temp.fixed_value = atoi(Text); + GetDlgItemText(hwnd,DLG_FIX_RANGE,Text,sizeof(Text)); + temp.range = atoi(Text); + GetDlgItemText(hwnd,DLG_FIX_RATE, Text,sizeof(Text)); + temp.rate = atof(Text); + for(k=0; k MAX_ROWS) + { + sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (NV < 1 || NV > MAX_ROWS) + { + sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (Hll >= Hur) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "The \"lower-left\" values must be less than " + "the corresponding \"upper-right\" values in " + "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (Vll >= Vur) + { + g_FuncTable.m_pfnMessageBox (g_pWnd,"The \"lower-left\" values must be less than " + "the corresponding \"upper-right\" values in " + "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (!strlen (Texture[Game][0])) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "You must supply a texture name.", "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + +/* if (Decimate>0 && GimpHints!=0) + { + MessageBox(hwnd,"You've elected to use a decimated grid and gimp's non-detail hint brushes. " + "This combination usually produces bizarre visual errors in the game, " + "so GenSurf has turned off the hint brush option.", + "GenSurf",MB_ICONEXCLAMATION); + GimpHints = 0; + } */ + + gtk_widget_hide (g_pWnd); + if (g_pWndPreview) + gtk_widget_hide (g_pWndPreview); + + GenerateMap(); + WriteIniFile(gszIni); +} + +// ============================================================================= +// general tab callbacks + +static void general_game (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + Game = GPOINTER_TO_INT (data); + UpdatePreview (TRUE); + } +} + +static void general_plane (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + Plane = GPOINTER_TO_INT (data); + SetupControls (); + UpdatePreview (TRUE); + } +} + +static void general_wave (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + WaveType = GPOINTER_TO_INT (data); + SetupControls (); + UpdatePreview (TRUE); + } +} + +static void general_random (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + if (RandomSeed != nPos) + { + RandomSeed = nPos; + UpdatePreview (true); + } +} + +// ============================================================================= +// extents tab callbacks + +static void extents_linearborder (GtkToggleButton *check, gpointer data) +{ + FixBorders = gtk_toggle_button_get_active (check); + UpdatePreview (true); +} + +static void extents_use_patches (GtkToggleButton *check, gpointer data) +{ + if (Game != QUAKE3) + return; + + UsePatches = gtk_toggle_button_get_active (check); + SetDlgValues (current_tab); + SetupControls (); + UpdatePreview (true); +} + +static void extents_nhnv_spin (GtkAdjustment *adj, int *data) +{ + int nPos = (int)adj->value; + + if (*data != nPos) + { + if (Game==QUAKE3 && UsePatches && (nPos % 2)) + { + if (*data < nPos) + *data += 2; + else + *data -= 2; + gtk_adjustment_set_value (adj, *data); + } + else + *data = nPos; + UpdatePreview (true); + } +} + +static void extents_decimate (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + Decimate = nPos; + UpdatePreview (true); +} + +// Hydra : snap to grid begin +/*static void extents_snaptogrid (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + SnapToGrid = nPos; + UpdatePreview (true); +}*/ + +// ^Fishman - Modified version of Hydra's snap to grid code. +static void extents_snaptogrid_spin (GtkAdjustment *adj, int *data) +{ + int nPos = (int)adj->value; + SnapToGrid = nPos; + UpdatePreview (true); +} + +// ============================================================================= +// bitmap tab callbacks + +static gint bitmap_file_entryfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) +{ + char filename[NAME_MAX]; + + strcpy (filename, gtk_entry_get_text (GTK_ENTRY(widget))); + if(strcmp (filename,gbmp.name)) + { + if (gbmp.colors) + { + free(gbmp.colors); + gbmp.colors=NULL; + } + strcpy (gbmp.name,filename); + if (strlen(gbmp.name) ) + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } + return FALSE; +} + +static void bitmap_browse (GtkWidget *widget, gpointer data) +{ + const char *filename; + char *ptr; + + filename = g_FuncTable.m_pfnFileDialog (g_pWnd, TRUE, "Bitmap File", gbmp.defpath); + + if (filename != NULL) + { + strcpy (gbmp.name, filename); + + ptr = strrchr (filename, G_DIR_SEPARATOR); + if (ptr != NULL) + { + *(ptr+1) = '\0'; + strcpy (gbmp.defpath, filename); + } + + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } +} + +static void bitmap_reload (GtkWidget *widget, gpointer data) +{ + strcpy (gbmp.name, gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")))); + if(strlen (gbmp.name) ) + { + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } + else + ENABLE_WIDGET ("go", FALSE ); +} + +// ============================================================================= +// fix points tab callbacks + +static gint fix_value_entryfocusout (GtkWidget* widget, GdkEventFocus *event, gpointer data) +{ + int i = atoi (gtk_entry_get_text (GTK_ENTRY(widget))), k; + char Text[32]; + + if (i < -65536 || i > 65536) + { + gdk_beep (); + g_FuncTable.m_pfnMessageBox (g_pWnd, "The value must be between -65536 and 65536, inclusive.", + "GenSurf", MB_OK | MB_ICONEXCLAMATION); + sprintf (Text, "%d", (int)xyz[Vertex[0].i][Vertex[0].j].fixed_value); + gtk_entry_set_text (GTK_ENTRY(widget), Text); + gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)), widget); + } + else if (i != xyz[Vertex[0].i][Vertex[0].j].fixed_value) + { + for(k=0; kvalue; + + if (xyz[Vertex[0].i][Vertex[0].j].fixed_value != i) + { + for(k=0; k(data)); + return FALSE; +} + +// ============================================================================= +// create tooltips + +void create_tooltips () +{ + tooltips = gtk_tooltips_new (); + + // Main + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "go")), + "Accept all input and generate a surface in Q3Radiant", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "open")), + "Open a previously saved GenSurf settings file.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "save")), + "Save all settings to a file.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "defaults")), + "Restore default values from DEFAULTS.SRF. If this file does not exist, GenSurf " + "initializes all input parameters to reasonable values. You can create your own " + "default surface by setting all parameters to your liking, then saving a settings " + "file as DEFAULTS.SRF with the Save As button.", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), + "View a wire-frame representation of the surface", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_antialiasing")), + "The lines in the preview window are antialiased for better quality", + ""); + + // General tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[0]), + "Builds a surface with alternating hills and valleys. Uses the general form Z=cos(X) " + "x sin(Y)", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[1]), + "Builds a surface with ridges parallel to the vertical axis.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[2]), + "Builds a surface with ridges parallel to the horizontal axis.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[3]), + "Builds a map from a bitmap image representing a contour plot. Click the \"Bitmap\" " + "tab to select the image. GenSurf only supports 256-color (8 bit) " + "bitmaps. GenSurf will work with any 256-color bitmap, but gray scale bitmaps are a bit " + "more intuitive.", + "" ); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[4]), + "Builds a random surface using the Plasma Cloud technique. Variance is controlled " + "by the Roughness input. To build a surface with completely random values not " + "dependent on neighboring vertices, use one of the other waveforms with 0 amplitude.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), + "Enter the wavelength (distance between crests). NOTE: Wavelengths equal to the grid " + "size or 2 times the grid size will result in 0 amplitudes. For best results, the " + "wavelength value should be at least 4 times the grid size (extents divided by the " + "number of divisions", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), + "Enter the height of hills/ridges.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), + "Enter the roughness value (noise) for the surface. For fractal surfaces, this value " + "is used as a variance in the fractal calculations.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "random")), + "Seed value for the pseudo-random number generator.", + ""); + // Extents tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), + "Minimum horizontal coordinate of the surface, i.e. X for a surface parallel to " + "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), + "Maximum horizontal coordinate of the surface, i.e. X for a surface parallel to " + "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), + "Minimum vertical coordinate of the surface, i.e. Y for a surface parallel to " + "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), + "Maximum vertical coordinate of the surface, i.e. Y for a surface parallel to " + "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nh")), + "Number of divisions in the horizontal direction. For best results, the extents " + "in a given direction should be evenly divisible by the number of divisions in " + "that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nv")), + "Number of divisions in the vertical direction. For best results, the extents " + "in a given direction should be evenly divisible by the number of divisions in " + "that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches")), + "Produce one or more curved patches in the shape of your selected surface rather " + "than producing solid brushes. Depending on the size of your surface (and the " + "user's graphic detail settings, which you cannot control), curved surfaces will " + "be represented in the game by a very large number of polygons. Read the warnings " + "concerning curved surfaces on the GenSurf web page before using this feature.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), + "Use the slider to control the number of vertices discarded by GenSurf. For many " + "surfaces, you can produce roughly the same shape surface with a high decimation " + "value. This will generally result in a map with lower polygon counts (and better " + "in-game performance). However, this feature should NOT be used for large terrain " + "surfaces in Q3", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z00")), + "Enter the height of the surface at the lower left corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z01")), + "Enter the height of the surface at the upper left corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z10")), + "Enter the height of the surface at the lower right corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z11")), + "Enter the height of the surface at the upper right corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "linearborder")), + "Restrict the edges of the surface to a straight line. This will help match up " + "brush edges if you drop this surface into another map.", + ""); + // Bitmap tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), + "Type the name of an 8-bit bitmap image file, or click Browse to select an image " + "from a list of those available on your system.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file_browse")), + "Select a bitmap image file from a list of those available on your system.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), + "Reload the selected bitmap file after making changes in an external image editor.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), + "Enter the value corresponding to color index 0 in the bitmap file. For gray scale " + "images, color 0 is normally black.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), + "Enter the value corresponding to color index 255 in the bitmap file. For gray scale " + "images, color 255 is normally white.", + ""); + // Fixpoints tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_value")), + "Enter a value for the selected vertex. This value will not be adjusted when applying " + "a waveform or roughness to the surface. Unlock this vertex (so that it will be " + "adjusted normally) by clicking \"Free\". This vertex will influence vertices within " + "the \"Range affected\" of this vertex.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_range")), + "Enter the range away from the selected vertex that other vertices will be affected. " + "Use 0 if you don't want other vertices to be influenced by the currently selected " + "one. Note: this box is disabled if you've chosen the fractal generator, as it uses " + "a completely different method for determining values.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_rate")), + "Enter a rate of change for the surface affected by the fixed value. 0 gives a smooth " + "sinusoidal curve, values less than 0 give progressively sharper spikes, and values " + "greater than 0 take on a square shape. Values less than -30 or greater than 30 are " + "set to -30 and 30, respectively. Note that this entry will have no effect unless " + "you also specify a \"range affected\".", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_free")), + "Click this to free (unlock the value of) the currently selected vertex.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_freeall")), + "Click this to free (unlock the values of) all vertices.", + ""); + // Texture tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), + "Enter the name of the texture or shader used for the surface faces.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), + "Enter the name of the texture or shader used for faces other than the surface. Under " + "normal circumstances this should be \"common/caulk\"", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), + "Enter the name of the texture or shader used for \"steep\" surface faces, where \"steep\" " + "is the angle specified below. If this entry is left blank or if the \"steep\" angle is 0, " + "all surface faces will use the texture specified by \"Surface\".", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "detail")), + "Check this box to use the detail content property on the generated brushes. Compile " + "times will be considerably shorter if the detail property is used, though the surface " + "will not block visibility at all. If you use the detail property, you should make sure " + "that \"common/caulk\" is used for the non-surface faces, or the polygon count will be " + "much higher than necessary.", + ""); +} + +// ============================================================================= +// create main dialog + +GtkWidget* create_main_dialog () +{ + GtkWidget *dlg, *vbox, *hbox, *hbox2, *button, *notebook, *frame, *table, *table2; + GtkWidget *check, *spin, *radio, *label, *entry, *scale; + GtkObject *adj; + GSList *group; + int i; + char *games[] = { "Quake 2", "Half-Life", "SiN", "Heretic 2", "Kingpin", "Genesis3D", "Quake 3 Arena" }; + char *waveforms[] = { "Alternating hill/valley", "Cylindrical left-to-right", "Cylindrical top-to-bottom", + "From bitmap", "Fractal" }; + char *orientations[] = { "Ground surface", "Ceiling", "Wall facing 0", "Wall facing 90", + "Wall facing 180","Wall facing 270" }; + + g_pWnd = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), gszCaption); + g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (main_close), NULL); + // g_signal_connect (G_OBJECT (dlg), "destroy", G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pRadiantWnd)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + notebook = gtk_notebook_new (); + gtk_widget_show (notebook); + gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0); + g_signal_connect (G_OBJECT (notebook), "switch_page", + G_CALLBACK (switch_page), NULL); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + g_object_set_data (G_OBJECT (dlg), "notebook", notebook); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("General"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label); + + frame = gtk_frame_new ("Game"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < NUMGAMES; i++) + { + radio = gtk_radio_button_new_with_label (group, games[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + game_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_game), GINT_TO_POINTER (i)); + } + + frame = gtk_frame_new ("Waveform"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < 5; i++) + { + radio = gtk_radio_button_new_with_label (group, waveforms[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + wave_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_wave), GINT_TO_POINTER (i)); + } + + frame = gtk_frame_new ("Orientation"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < 6; i++) + { + radio = gtk_radio_button_new_with_label (group, orientations[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + plane_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_plane), GINT_TO_POINTER (i)); + } + + table2 = gtk_table_new (4, 2, FALSE); + gtk_widget_show (table2); + gtk_table_set_row_spacings (GTK_TABLE (table2), 5); + gtk_table_set_col_spacings (GTK_TABLE (table2), 5); + gtk_table_attach (GTK_TABLE (table), table2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + label = gtk_label_new ("Wavelength:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Max. amplitude:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Roughness:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Random seed:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "wavelength", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &WaveLength); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "amplitude", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Amplitude); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "roughness", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Roughness); + + adj = gtk_adjustment_new (1, 1, 32767, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (general_random), NULL); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table2), spin, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "random", spin); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Extents"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + frame = gtk_frame_new ("Extents"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); + + table = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hmin_text", label); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hmax_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vmin_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vmax_text", label); + + label = gtk_label_new ("Lower-left"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Upper-right"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "hmin", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hll); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "hmax", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hur); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "vmin", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vll); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "vmax", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vur); + + frame = gtk_frame_new ("Divisions"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "nh_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "nv_text", label); + + adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NH); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "nh", spin); + + adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NV); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "nv", spin); + + check = gtk_check_button_new_with_label ("Use Bezier patches"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "use_patches", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_use_patches), NULL); + + // ^Fishman - Snap to grid, replaced scroll bar with a texbox. + label = gtk_label_new ("Snap to grid:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_object_set_data (GTK_OBJECT (dlg), "snap_text", label); + + adj = gtk_adjustment_new (8, 0, 256, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_snaptogrid_spin), &SP); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (vbox), spin, FALSE, TRUE, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "sp", spin); + // ^Fishman - End of Snap to grid code. + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 10); + + label = gtk_label_new ("Decimate:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (0, 0, 110, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_decimate), NULL); + g_object_set_data (G_OBJECT (dlg), "decimate_adj", adj); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (hbox2), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + g_object_set_data (G_OBJECT (dlg), "decimate", scale); + + frame = gtk_frame_new ("Corner values"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Upper-left:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Lower-left:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Upper-right:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Lower-right:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z01", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z01); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z00", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z00); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z11", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z11); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z10", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z10); + + check = gtk_check_button_new_with_label ("Linear borders"); + gtk_widget_show (check); + gtk_table_attach (GTK_TABLE (table), check, 0, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "linearborder", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_linearborder), NULL); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Bitmap"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + label = gtk_label_new (""); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_note", label); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Filename:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text1", label); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_file", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (bitmap_file_entryfocusout), NULL); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("Browse..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_file_browse", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_browse), NULL); + + button = gtk_button_new_with_label ("Reload"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_reload", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_reload), NULL); + + table = gtk_table_new (2, 2, TRUE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Map color 0 to:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text2", label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Map color 255 to:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text3", label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_black", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.black_value); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_white", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.white_value); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Fix Points"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + label = gtk_label_new ("Click on a vertex in the lower half of the preview window,\n" + "then use the arrow keys or text box to assign a value.\n" + "Use Ctrl+Click to select multiple vertices/toggle a\n" + "selection. Use Shift+Click to select a range of vertices.\n\n" + "Click \"Free\" to unlock a vertex. Vertices within \"Range\n" + "affected\" will be influenced by this vertex."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + + table = gtk_table_new (3, 3, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Value:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_value_text", label); + + label = gtk_label_new ("Range affected:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_range_text", label); + + label = gtk_label_new ("Rate of change:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_rate_text", label); + + adj = gtk_adjustment_new (0, -65536, 65536, 1, 16, 16); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (fix_value_changed), NULL); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_EXPAND), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_value", spin); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (fix_value_entryfocusout), NULL); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_range", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_range_entryfocusout), NULL); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_rate", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_rate_entryfocusout), NULL); + + button = gtk_button_new_with_label ("Free"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_free", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_free), NULL); + + button = gtk_button_new_with_label ("Free All"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_freeall", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_freeall), NULL); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Texture"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + // ^Fishman - Modified to add more labels and textboxes. + table = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Surface:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Other:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Steep:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture1", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (0)); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture2", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (1)); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture3", entry); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + label = gtk_label_new ("\"Steep\" angle:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (60, 0, 90, 1, 10, 10); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "tex_slant", spin); + + table = gtk_table_new (2, 4, TRUE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Offset "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Scale "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texoffsetx", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texoffsety", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texscalex", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texscaley", entry); + + + + check = gtk_check_button_new_with_label ("Use detail brushes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "detail", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_detail), NULL); + + check = gtk_check_button_new_with_label ("Detail hint brushes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "hint", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_hint), NULL); + + // ^Fishman - Add terrain key to func_group. + check = gtk_check_button_new_with_label ("Add terrain key"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "terrain_ent", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_terrainent), NULL); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "go", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_go), NULL); + + label = gtk_label_new ("Settings:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Open..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "open", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_open), NULL); + + button = gtk_button_new_with_label ("Save as..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "save", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_save), NULL); + + button = gtk_button_new_with_label ("Defaults"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "defaults", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_defaults), NULL); + + button = gtk_button_new_with_label ("About..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_about), NULL); + + check = gtk_check_button_new_with_label ("Preview"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_preview), NULL); + g_object_set_data (G_OBJECT (dlg), "main_preview", check); + + // ^Fishman - Antializing for the preview window. + check = gtk_check_button_new_with_label ("Antialised lines"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "main_antialiasing", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_antialiasing), NULL); + + for (i = 0; i < 5; i++) + SetDlgValues (i); + + CreateViewWindow (); + + create_tooltips(); + + FirstPassComplete = 1; + + return dlg; +} + + +#if 0 + +HWND hwndDisplay = (HWND)NULL; +HWND ghwndTab = (HWND)NULL; +int iTab=0; +RECT rcTab; +FILE *ftex; + +char GenSurfURL[40] = {"http://tarot.telefragged.com/gensurf"}; +char GenSurfBoard[40]={"http://tarot.telefragged.com/board"}; + +/* +* AboutDlgProc - processes messages for the about dialog. +*/ + +qboolean CALLBACK AboutDlgProc( HWND hwnd, unsigned msg, UINT wparam, LONG lparam ) +{ + char szText[256]; + DRAWITEMSTRUCT *dis; + HDC hdc; + HPEN hpen; + HWND hwndURL; + RECT rc; + SIZE size; + + lparam = lparam; /* turn off warning */ + + switch( msg ) { + case WM_INITDIALOG: + strcpy(szText,"About " ); + strcat(szText,gszCaption); + SetWindowText(hwnd,gszCaption); + SetDlgItemText(hwnd,DLG_ABOUT_APP,szText); + /* Application icon: */ + SendDlgItemMessage( hwnd, DLG_ABOUT_ICON, + STM_SETICON, (WPARAM)(HICON)LoadIcon(ghInst,"GENSURF"), + (LPARAM) NULL); + + hwndURL = GetDlgItem(hwnd,DLG_ABOUT_URL); + hdc = GetDC(hwndURL); + GetTextExtentPoint(hdc,GenSurfURL,strlen(GenSurfURL),&size); + ReleaseDC(hwndURL,hdc); + GetWindowRect(hwndURL,&rc); + SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, + SWP_NOMOVE | SWP_NOZORDER); + + hwndURL = GetDlgItem(hwnd,DLG_ABOUT_BOARD); + hdc = GetDC(hwndURL); + GetTextExtentPoint(hdc,GenSurfBoard,strlen(GenSurfBoard),&size); + ReleaseDC(hwndURL,hdc); + GetWindowRect(hwndURL,&rc); + SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, + SWP_NOMOVE | SWP_NOZORDER); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wparam)) + { + case DLG_ABOUT_URL: + HTTP(GenSurfURL); + break; + case DLG_ABOUT_BOARD: + HTTP(GenSurfBoard); + break; + case IDOK: + EndDialog(hwnd,1); + return TRUE; + } + break; + + case WM_DRAWITEM: + if(wparam == DLG_ABOUT_URL) + { + dis = (LPDRAWITEMSTRUCT)lparam; + SetTextColor(dis->hDC,RGB(0,0,255)); + TextOut(dis->hDC,0,0,GenSurfURL,strlen(GenSurfURL)); + GetWindowRect(dis->hwndItem,&rc); + GetTextExtentPoint(dis->hDC,GenSurfURL,strlen(GenSurfURL),&size); + hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); + SelectObject(dis->hDC,hpen); + MoveToEx(dis->hDC,0,size.cy,NULL); + LineTo(dis->hDC,size.cx,size.cy); + SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); + DeleteObject(hpen); + } + else if(wparam==DLG_ABOUT_BOARD) + { + dis = (LPDRAWITEMSTRUCT)lparam; + SetTextColor(dis->hDC,RGB(0,0,255)); + TextOut(dis->hDC,0,0,GenSurfBoard,strlen(GenSurfBoard)); + GetWindowRect(dis->hwndItem,&rc); + GetTextExtentPoint(dis->hDC,GenSurfBoard,strlen(GenSurfBoard),&size); + hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); + SelectObject(dis->hDC,hpen); + MoveToEx(dis->hDC,0,size.cy,NULL); + LineTo(dis->hDC,size.cx,size.cy); + SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); + DeleteObject(hpen); + } + break; + + case WM_CLOSE: + EndDialog(hwnd,1); + return TRUE; + + default: + return FALSE; + } + return FALSE; + +} /* AboutDlgProc */ + +void About() +{ + if( DialogBox( ghInst,"About", ghwnd_main, (DLGPROC)AboutDlgProc ) < 0) + { + char Text[256]; + sprintf(Text,"In About(), GetLastError()=0x%08x",GetLastError()); + MessageBox(ghwnd_main,Text,"GenSurf",MB_ICONEXCLAMATION); + } +} + +#endif diff --git a/contrib/gtkgensurf/gendlgs.h b/contrib/gtkgensurf/gendlgs.h new file mode 100644 index 00000000..c6df4866 --- /dev/null +++ b/contrib/gtkgensurf/gendlgs.h @@ -0,0 +1,151 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define DLG_PLANE_XY0 100 +#define DLG_PLANE_XY1 101 +#define DLG_PLANE_YZ0 102 +#define DLG_PLANE_XZ0 103 +#define DLG_PLANE_YZ1 104 +#define DLG_PLANE_XZ1 105 +#define DLG_WAVE_01 106 +#define DLG_WAVE_02 107 +#define DLG_WAVE_03 108 +#define DLG_WAVE_04 109 +#define DLG_WAVE_05 110 +#define DLG_WAVE_06 111 +#define DLG_LAMBDA 112 +#define DLG_LAMBDA_TEXT 113 +#define DLG_AMP 114 +#define DLG_AMP_TEXT 115 +#define DLG_ROUGH 116 +#define DLG_ROUGH_TEXT 117 +#define DLG_LINEARBORDER 118 +#define DLG_FILE 119 +#define DLG_FILE_BROWSE 120 +#define DLG_PREVIEW 121 +#define DLG_GO 122 +#define DLG_ABOUT 123 +#define DLG_NH_TEXT 124 +#define DLG_NH 125 +#define DLG_NH_SPIN 126 +#define DLG_NV_TEXT 127 +#define DLG_NV 128 +#define DLG_NV_SPIN 129 +#define DLG_HMIN_TEXT 130 +#define DLG_HMIN 131 +#define DLG_HMAX_TEXT 132 +#define DLG_HMAX 133 +#define DLG_VMIN_TEXT 134 +#define DLG_VMIN 135 +#define DLG_VMAX_TEXT 136 +#define DLG_VMAX 137 +#define DLG_Z00_TEXT 138 +#define DLG_Z00 139 +#define DLG_Z01_TEXT 140 +#define DLG_Z01 141 +#define DLG_Z10_TEXT 142 +#define DLG_Z10 143 +#define DLG_Z11_TEXT 144 +#define DLG_Z11 145 +#define DLG_TEXTURE 146 +#define DLG_SKYBOX 147 +#define DLG_AUTOOVERWRITE 148 +#define DLG_DETAIL 149 +#define DLG_ARGHRAD2 150 +#define DLG_ARGHRAD2_SPIN 151 +#define DLG_APPEND 152 +#define DLG_REFRESH 153 +#define DLG_TEXOFFSETX 154 +#define DLG_TEXOFFSETY 155 +#define DLG_TEXSCALEX 156 +#define DLG_TEXSCALEY 157 +#define DLG_FIXPOINTS 158 +#define DLG_TEXTURE_BROWSE 159 +#define DLG_AZIMUTH 162 +#define DLG_AZIMUTH_SPIN 163 +#define DLG_ELEVATION 164 +#define DLG_ELEVATION_SPIN 165 +#define DLG_RANDOMSEED 166 +#define DLG_RANDOMSEED_SPIN 167 +#define DLG_BITMAP 168 +#define DLG_SAVE 169 +#define DLG_OPEN 170 +#define DLG_TAB 171 +#define DLG_TEXTURE2 172 +#define DLG_TEXTURE2_BROWSE 173 +#define DLG_LADDER 174 +#define DLG_ARGHRAD2_TEXT 175 +#define DLG_FILE_TEXT 176 +#define DLG_DECIMATE 177 +#define DLG_DECIMATE_TEXT 178 +#define DLG_HIDEBACKFACES 179 +#define DLG_DEFAULTS 180 +#define DLG_ABOUT_APP 200 +#define DLG_ABOUT_ICON 201 +#define DLG_BMP_FILE 202 +#define DLG_BMP_FILE_BROWSE 203 +#define DLG_BMP_BLACK 204 +#define DLG_BMP_WHITE 205 +#define DLG_BMP_TEXT1 206 +#define DLG_BMP_TEXT2 207 +#define DLG_BMP_TEXT3 208 +#define DLG_BMP_NOTE 209 +#define DLG_BMP_RELOAD 210 +#define DLG_ABOUT_URL 211 +#define DLG_ABOUT_BOARD 212 +#define DLG_FIX_FREE 300 +#define DLG_FIX_FREEALL 301 +#define DLG_FIX_VALUE_TEXT 302 +#define DLG_FIX_VALUE 303 +#define DLG_FIX_VALUE_SPIN 304 +#define DLG_FIX_DONE 305 +#define DLG_FIX_RANGE_TEXT 306 +#define DLG_FIX_RANGE 307 +#define DLG_FIX_NOTE 308 +#define DLG_FIX_RATE_TEXT 309 +#define DLG_FIX_RATE 310 +#define DLG_USE_PATCHES 311 +#define DLG_DECIMATE_LABEL 312 +#define DLG_HINT 350 +#define DLG_GAME_00 400 +#define DLG_GAME_01 401 +#define DLG_GAME_02 402 +#define DLG_GAME_03 403 +#define DLG_GAME_04 404 +#define DLG_GAME_05 405 +#define DLG_GAME_06 406 +#define DLG_GAME_07 407 +#define DLG_GAME_08 408 +#define DLG_GAME_09 409 +#define DLG_TEX_USEPAK 420 +#define DLG_TEX_PAK_TEXT 421 +#define DLG_TEX_PAKFILE 422 +#define DLG_TEX_PAK_BROWSE 423 +#define DLG_TEX_LIST1 424 +#define DLG_TEX_LIST2 425 +#define DLG_TEX_LIST3 426 +#define DLG_TEXTURE3 427 +#define DLG_TEXTURE3_BROWSE 428 +#define DLG_TEX_SLANT_TEXT 429 +#define DLG_TEX_SLANT 430 +#define DLG_TEX_SLANT_SPIN 431 +#define DLG_EXCEL_FUNC 500 +#define DLG_EXCEL_FUNC_TEXT 501 +#define DLG_PREVIEW_ANTIALIASING 502 // ^Fishman - Antializing for the preview window. +#define DLG_SNAP_TO_GRID 503 // Hydra : snap to grid diff --git a/contrib/gtkgensurf/genmap.cpp b/contrib/gtkgensurf/genmap.cpp new file mode 100644 index 00000000..ace97b68 --- /dev/null +++ b/contrib/gtkgensurf/genmap.cpp @@ -0,0 +1,2056 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +double xmin,xmax,ymin,ymax,zmin,zmax; +double backface; +extern double dh, dv; +FILE *fmap; +XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; +int contents; +int surface[3]; +LPVOID h_func_group; +LPVOID terrainkey; // ^Fishman - Add terrain key to func_group. + +//============================================================= +// Hydra : snap-to-grid begin +double CalculateSnapValue(double value) +{ + long snapvalue; + + // simple uncomplicated snapping, rounding both UP and DOWN to the nearest + // grid unit. + if (SnapToGrid >0) + { + snapvalue = (int)value / SnapToGrid; + if ((long)value % SnapToGrid < (SnapToGrid / 2)) // Snap Downwards if less than halfway between to grid units + value = snapvalue * SnapToGrid; + else // Snap Upwards if more than halfway between to grid units + value = (snapvalue+1) * SnapToGrid; + } + return value; +} +// Hydra : snap-to-grid end + +//============================================================= +bool ValidSurface() +{ + if(WaveType == WAVE_BITMAP && !gbmp.colors) return FALSE; + if(NH < 1) return FALSE; + if(NH > MAX_ROWS) return FALSE; + if(NV < 1) return FALSE; + if(NV > MAX_ROWS) return FALSE; + if(Hll >= Hur) return FALSE; + if(Vll >= Vur) return FALSE; + return TRUE; +} + +//============================================================= +int MapPatches() +{ + int NH_remain; + int NV_remain; + int NH_patch; + int NV_patch; + int BrushNum = 0; + int i, j, k1, k2, k3; + int i0, j0, ii; + char szOops[128]; + patchMesh_t p; + + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + memset(&p,0,sizeof(patchMesh_t)); + + // Generate control points in pp array to give desired values currently + // in p array. + switch(Plane) + { + case PLANE_XY0: + case PLANE_XY1: + k1 = 0; + k2 = 1; + k3 = 2; + break; + case PLANE_XZ0: + case PLANE_XZ1: + k1 = 0; + k2 = 2; + k3 = 1; + break; + case PLANE_YZ0: + case PLANE_YZ1: + k1 = 1; + k2 = 2; + k3 = 0; + break; + } + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].pp[k1] = xyz[i][j].p[k1]; + xyz[i][j].pp[k2] = xyz[i][j].p[k2]; + } + } + for(i=0; i<=NH; i+=2) + { + for(j=0; j<=NV; j+=2) + xyz[i][j].pp[k3] = xyz[i][j].p[k3]; + } + for(i=1; i 1) + { + if(( (NH_remain-1) % 14) == 0) + NH_patch = 15; + else if(( (NH_remain-1) % 12) == 0) + NH_patch = 13; + else if(( (NH_remain-1) % 10) == 0) + NH_patch = 11; + else if(( (NH_remain-1) % 8) == 0) + NH_patch = 9; + else if(( (NH_remain-1) % 6) == 0) + NH_patch = 7; + else if(( (NH_remain-1) % 4) == 0) + NH_patch = 5; + else if(( (NH_remain-1) % 2) == 0) + NH_patch = 3; + else if(NH_remain > 16) + NH_patch = 7; + else if(NH_remain > 4) + NH_patch = 5; + else + NH_patch = 3; + while( NH_patch > 3 && (NH_patch-1)*dh > 512 ) + NH_patch -= 2; + NH_remain -= (NH_patch-1); + if(NH_remain < 0) + { + sprintf(szOops,"Oops... screwed up with NH=%d",NH); + g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); + } + NV_remain = NV+1; + j0 = 0; + while(NV_remain > 1) + { + if(( (NV_remain-1) % 14) == 0) + NV_patch = 15; + else if(( (NV_remain-1) % 12) == 0) + NV_patch = 13; + else if(( (NV_remain-1) % 10) == 0) + NV_patch = 11; + else if(( (NV_remain-1) % 8) == 0) + NV_patch = 9; + else if(( (NV_remain-1) % 6) == 0) + NV_patch = 7; + else if(( (NV_remain-1) % 4) == 0) + NV_patch = 5; + else if(( (NV_remain-1) % 2) == 0) + NV_patch = 3; + else if(NV_remain > 16) + NV_patch = 7; + else if(NV_remain > 4) + NV_patch = 5; + else + NV_patch = 3; + while( NV_patch > 3 && (NV_patch-1)*dh > 512 ) + NV_patch -= 2; + NV_remain -= (NV_patch-1); + if(NV_remain < 0) + { + sprintf(szOops,"Oops... screwed up with NV=%d",NV); + g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); + } + + p.width = NH_patch; + p.height = NV_patch; + p.type = PATCH_GENERIC; + for(i=0; i 0 && (Game != QUAKE3 || UsePatches==0) ) + { + MapOut(gNumNodes,gNumTris,gNode,gTri); + /* + ghCursorCurrent = ghCursorDefault; + SetCursor(ghCursorCurrent); + */ + return; + } + + contents = 0; + // HL doesn't have detail property + if((Game != HALFLIFE) && UseDetail) contents += CONTENTS_DETAIL; + // HL and Q3 don't have ladder property + if((Game != HALFLIFE && Game != QUAKE3) && UseLadder) contents += CONTENTS_LADDER; + // Genesis requires solid property to be set explicitly + if(Game == GENESIS3D) contents |= CONTENTS_SOLID; + // Heretic 2 uses different sounds (in surface props) for different texture types + if(Game == HERETIC2) + { + surface[0] = GetDefSurfaceProps(Texture[Game][0]); + surface[1] = GetDefSurfaceProps(Texture[Game][1]); + surface[2] = GetDefSurfaceProps(Texture[Game][2]); + } + else + { + surface[0] = 0; + surface[1] = 0; + surface[2] = 0; + } + if(Game!=QUAKE3 || UsePatches == 0) + MapBrushes(); + + /* + ghCursorCurrent = ghCursorDefault; + SetCursor(ghCursorCurrent); + */ +} + +//============================================================= +void GenerateXYZ() +{ + extern void MakeDecimatedMap(int *, int *, NODE **, TRI **); + double zl, zu; + double wh, wv; + int NHalfcycles; + double a,v,h,ha,va; + double delta, dr, rate; + double range, maxrange; + double r; + int i, j, k, N; + int i0, i1, j0, j1; + int ii, jj; + +// FILE *f; +// char CSV[64]; + + if(!ValidSurface()) return; + + srand(1); + srand(RandomSeed); + + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + + // H & V + for(i=0; i<=NH; i++) + { + for(j=0;j<=NV;j++) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[0] = Hll + i*dh; + xyz[i][j].p[2] = Vll + j*dv; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[1] = Hll + i*dh; + xyz[i][j].p[2] = Vll + j*dv; + break; + default: + xyz[i][j].p[0] = Hll + i*dh; + xyz[i][j].p[1] = Vll + j*dv; + } + } + } + + if(WaveType == WAVE_BITMAP) + GenerateBitmapMapping(); + /* + else if(WaveType == WAVE_FORMULA) + DoFormula(); + */ + else + { + // Initialize Z values using bilinear interpolation + for(i=0; i<=NH; i++) + { + zl = Z00 + i*(Z10 - Z00)/NH; + zu = Z01 + i*(Z11 - Z01)/NH; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(j=0; j<=NV; j++) + xyz[i][j].p[1] = zl + j*(zu-zl)/NV; + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(j=0; j<=NV; j++) + xyz[i][j].p[0] = zl + j*(zu-zl)/NV; + break; + default: + for(j=0; j<=NV; j++) + xyz[i][j].p[2] = zl + j*(zu-zl)/NV; + } + } + } + + switch(WaveType) + { + case WAVE_COS_SIN: + if(FixBorders) + { + NHalfcycles = (int)((Hur-Hll)/(WaveLength/2.)); + NHalfcycles = max(NHalfcycles,1); + wh = 2.*(Hur-Hll)/NHalfcycles; + NHalfcycles = (int)((Vur-Vll)/(WaveLength/2.)); + wv = 2.*(Vur-Vll)/NHalfcycles; + NHalfcycles = max(NHalfcycles,1); + i0 = 1; + i1 = NH-1; + j0 = 1; + j1 = NV-1; + } + else + { + wh = WaveLength; + wv = WaveLength; + i0 = 0; + i1 = NH; + j0 = 0; + j1 = NV; + } + + for(i=i0; i<=i1; i++) + { + h = Hll + i*dh; + ha = ((h-Hll)/wh)*2.*PI - PI/2.; + for(j=j0; j<=j1; j++) + { + v = Vll + j*dv; + va = ((v-Vll)/wv)*2.*PI; + a = Amplitude * cos( ha ) * sin( va ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_HCYLINDER: + for(i=0; i<=NH; i++) + { + h = Hll + i*dh; + ha = ((h-Hll)/WaveLength)*2.*PI - PI/2.; + for(j=0; j<=NV; j++) + { + a = Amplitude * cos( ha ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_VCYLINDER: + for(i=0; i<=NH; i++) + { + h = Hll + i*dh; + for(j=0; j<=NV; j++) + { + v = Vll + j*dv; + va = ((v-Vll)/WaveLength)*2.*PI; + a = Amplitude * sin( va ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_ROUGH_ONLY: + PlasmaCloud(); + break; + } + + if(WaveType != WAVE_ROUGH_ONLY) + { + // Fixed values + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] = xyz[i][j].fixed_value; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] = xyz[i][j].fixed_value; + break; + default: + xyz[i][j].p[2] = xyz[i][j].fixed_value; + } + + if(xyz[i][j].range > 0) + { + maxrange = pow(xyz[i][j].range,2); // so we don't have to do sqrt's + i0 = i - (int)( floor(xyz[i][j].range/dh - 0.5) + 1 ); + i1 = i + i - i0; + j0 = j - (int)( floor(xyz[i][j].range/dv - 0.5) + 1 ); + j1 = j + j - j0; + if(FixBorders) + { + i0 = max(i0,1); + i1 = min(i1,NH-1); + j0 = max(j0,1); + j1 = min(j1,NV-1); + } + else + { + i0 = max(i0,0); + i1 = min(i1,NH); + j0 = max(j0,0); + j1 = min(j1,NV); + } + for(ii=i0; ii<=i1; ii++) + { + for(jj=j0; jj<=j1; jj++) + { + if(ii==i && jj==j) continue; + range = pow( dh*(i-ii), 2) + pow( dv*(j-jj), 2); + if(range > maxrange) continue; + dr = sqrt(range/maxrange); + rate = max(-30.,min(xyz[i][j].rate,30.)); + if(rate < -1.) + { + delta = pow((1.-dr),-rate+1.); + } + else if(rate < 0.) + { + delta = (1+rate)*0.5*(cos(dr*PI)+1.0) - + rate*pow((1.-dr),2); + } + else if(rate == 0.) + { + delta = 0.5*(cos(dr*PI)+1.0); + } + else if(rate <= 1.) + { + delta = (1.-rate)*0.5*(cos(dr*PI)+1.0) + + rate*(1.-pow(dr,2)); + } + else + { + delta = 1.-pow(dr,rate+1); + } + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[ii][jj].p[1] += (xyz[i][j].p[1] - xyz[ii][jj].p[1])*delta; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[ii][jj].p[0] += (xyz[i][j].p[0] - xyz[ii][jj].p[0])*delta; + break; + default: + xyz[ii][jj].p[2] += (xyz[i][j].p[2] - xyz[ii][jj].p[2])*delta; + } + } + } + } + } + } + } + } + + if((Roughness > 0.) && (WaveType != WAVE_ROUGH_ONLY) ) + { + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(CanEdit(i,j) && !xyz[i][j].fixed) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + break; + default: + xyz[i][j].p[2] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + } + } + else + r = rand(); // We still get a random number, so that fixing points + // doesn't change the sequence. + + } + } + } + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + for(k=0; k<3; k++) + { + xyz[i][j].p[k] = Nearest(xyz[i][j].p[k],2.0); + } + } + } + + // Find minima and maxima + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xmin = Hll; + xmax = Hur; + zmin = Vll; + zmax = Vur; + ymin = xyz[0][0].p[1]; + ymax = ymin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + ymin = min(ymin,xyz[i][j].p[1]); + ymax = max(ymax,xyz[i][j].p[1]); + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + ymin = Hll; + ymax = Hur; + zmin = Vll; + zmax = Vur; + xmin = xyz[0][0].p[0]; + xmax = ymin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xmin = min(xmin,xyz[i][j].p[0]); + xmax = max(xmax,xyz[i][j].p[0]); + } + } + break; + break; + default: + xmin = Hll; + xmax = Hur; + ymin = Vll; + ymax = Vur; + zmin = xyz[0][0].p[2]; + zmax = zmin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + zmin = min(zmin,xyz[i][j].p[2]); + zmax = max(zmax,xyz[i][j].p[2]); + } + } + } + + xmin = Nearest(xmin,2.); + xmax = Nearest(xmax,2.); + ymin = Nearest(ymin,2.); + ymax = Nearest(ymax,2.); + zmin = Nearest(zmin,2.); + zmax = Nearest(zmax,2.); + + switch(Plane) + { + case PLANE_XY1: + backface = AtLeast(zmax+32.,32.); + break; + case PLANE_XZ0: + backface = NoMoreThan(ymin-32.,32.); + break; + case PLANE_XZ1: + backface = AtLeast(ymax+32.,32.); + break; + case PLANE_YZ0: + backface = NoMoreThan(xmin-32.,32.); + break; + case PLANE_YZ1: + backface = AtLeast(xmax+32.,32.); + break; + default: + backface = NoMoreThan(zmin-32.,32.); + } + + if(gNode) + { + free(gNode); + free(gTri); + gNode = (NODE *)NULL; + gTri = (TRI *)NULL; + } + if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) + { + MakeDecimatedMap(&gNumNodes,&gNumTris,&gNode,&gTri); + } + else + { + gNumNodes = (NH+1)*(NV+1); + gNumTris = NH*NV*2; + gNode = (NODE *) malloc(gNumNodes * sizeof(NODE)); + gTri = (TRI *) malloc(gNumTris * sizeof(TRI)); + + for(i=0,N=0; i<=NH; i++) + { + for(j=0; j<=NV; j++, N++) + { + gNode[N].used = 1; + gNode[N].p[0] = (float)xyz[i][j].p[0]; + gNode[N].p[1] = (float)xyz[i][j].p[1]; + gNode[N].p[2] = (float)xyz[i][j].p[2]; + } + } + + for(i=0; i 0) + { + for(i=0; i x) xx -= dx; + return xx; +} +//============================================================= +double AtLeast(double x, double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + if(xx < x) xx += dx; + return xx; +} +//============================================================= +double LessThan(double x,double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + if(xx >= x) xx -= dx; + return xx; +} +//============================================================= +double MoreThan(double x,double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + while(xx <= x) + xx += dx; + return xx; +} +//============================================================= +void SubdividePlasma(int i0,int j0,int i1,int j1) +{ + int i, j; + double z1, z2; + double r; // NOTE: This is used to keep the random number sequence the same + // when we fix a point. If we did NOT do this, then simply + // fixing a point at its current value would change the entire + // surface. + + i = (i0+i1)/2; + j = (j0+j1)/2; + if(i1 > i0+1) + { + if(!xyz[i][j0].done) + { + xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + + (xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2])*(double)(i-i0)/(double)(i1-i0) + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j0].done = 1; + } + else + r = rand(); + if((j1 > j0) && (!xyz[i][j1].done) ) + { + xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + + (xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2])*(double)(i-i0)/(double)(i1-i0) + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j1].done = 1; + } + else + r = rand(); + } + if(j1 > j0 + 1) + { + if(!xyz[i0][j].done) + { + xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + + (xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + + ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i0][j].done = 1; + } + else + r = rand(); + if((i1 > i0) && (!xyz[i1][j].done)) + { + xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + + (xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + + ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i1][j].done = 1; + } + else + r = rand(); + } + if((i1 > i0+1) && (j1 > j0+1)) + { + if(!xyz[i][j].done) + { + z1 = xyz[i0][j].pp[2] + + (xyz[i1][j].pp[2] - xyz[i0][j].pp[2])*(double)(i-i0)/(double)(i1-i0); + z2 = xyz[i][j0].pp[2] + + (xyz[i][j1].pp[2] - xyz[i][j0].pp[2])*(double)(j-j0)/(double)(j1-j0); + xyz[i][j].pp[2] = (z1+z2)/2. + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j].done = 1; + } + else + r = rand(); + } + if(i > i0+1 || j > j0+1) + SubdividePlasma(i0,j0,i,j); + if(i1 > i+1 || j > j0+1) + SubdividePlasma(i,j0,i1,j); + if(i > i0+1 || j1 > j0+1) + SubdividePlasma(i0,j,i,j1); + if(i1 > i+1 || j1 > j0+1) + SubdividePlasma(i,j,i1,j1); +} +//================================================================================== +void PlasmaCloud() +{ + int i, j; + /* use pp[2] values until done to avoid messing with a bunch of + switch statements */ + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(FixedPoint(i,j)) + xyz[i][j].done = 1; + else + xyz[i][j].done = 0; + } + } + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[1]; + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[0]; + } + } + break; + default: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[2]; + } + } + break; + } + SubdividePlasma(0,0,NH,NV); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[1] = xyz[i][j].pp[2]; + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[0] = xyz[i][j].pp[2]; + } + } + break; + default: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[2] = xyz[i][j].pp[2]; + } + } + break; + } +} +//=========================================================================== +bool FixedPoint(int i, int j) +{ + if(xyz[i][j].fixed) return TRUE; + return !CanEdit(i,j); +} +//=========================================================================== +bool CanEdit(int i, int j) +{ + if(FixBorders && ( (WaveType==WAVE_COS_SIN) || (WaveType==WAVE_ROUGH_ONLY) ) ) + { + if(i== 0) return FALSE; + if(i==NH) return FALSE; + if(j== 0) return FALSE; + if(j==NV) return FALSE; + } + if(i== 0 && j== 0) return FALSE; + if(i==NH && j== 0) return FALSE; + if(i== 0 && j==NV) return FALSE; + if(i==NH && j==NV) return FALSE; + return TRUE; +} +/*============================================================================ + TriangleFromPoint + Determines which triangle in the gTri array bounds the input point. Doesn't + do anything special with border points. +*/ +int TriangleFromPoint(double x, double y) +{ + int j, tri; + + if(!gTri) return -1; + + for(j=0, tri=-1; jp[0],2.); + v[0][1] = (vec)Nearest(xyz->p[1],2.); + v[0][2] = (vec)Nearest(xyz->p[2],2.); +} + +//============================================================= +void MakePatch(patchMesh_t *p) +{ + int ret; + char shadername[64+9]; + + ret = g_FuncTable.m_pfnCreatePatchHandle(); + // strcpy(shadername, "textures/"); + // strcpy(shadername+9, Texture[Game][0]); + strcpy(shadername, Texture[Game][0]); + g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername); + g_FuncTable.m_pfnReleasePatchHandles(); +} + +//============================================================= +void MakeBrush(BRUSH *brush) +{ + LPVOID vp; + int i; + _QERFaceData QERFaceData; + + if(g_FuncTable.m_pfnCreateBrushHandle==NULL) + { + g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0); + return; + } + vp=(g_FuncTable.m_pfnCreateBrushHandle)(); + if(!vp) return; + for(i=0; iNumFaces; i++) + { + if(!strncmp(brush->face[i].texture, "textures/", 9)) + strcpy(QERFaceData.m_TextureName,brush->face[i].texture); + else + { + strcpy(QERFaceData.m_TextureName,"textures/"); + strcpy(QERFaceData.m_TextureName+9,brush->face[i].texture); + } + QERFaceData.m_nContents = brush->face[i].Contents; + QERFaceData.m_nFlags = brush->face[i].Surface; + QERFaceData.m_nValue = brush->face[i].Value; + QERFaceData.m_fShift[0] = brush->face[i].Shift[0]; + QERFaceData.m_fShift[1] = brush->face[i].Shift[1]; + QERFaceData.m_fRotate = brush->face[i].Rotate; + QERFaceData.m_fScale[0] = brush->face[i].Scale[0]; + QERFaceData.m_fScale[1] = brush->face[i].Scale[1]; + QERFaceData.m_v1[0] = brush->face[i].v[0][0]; + QERFaceData.m_v1[1] = brush->face[i].v[0][1]; + QERFaceData.m_v1[2] = brush->face[i].v[0][2]; + QERFaceData.m_v2[0] = brush->face[i].v[1][0]; + QERFaceData.m_v2[1] = brush->face[i].v[1][1]; + QERFaceData.m_v2[2] = brush->face[i].v[1][2]; + QERFaceData.m_v3[0] = brush->face[i].v[2][0]; + QERFaceData.m_v3[1] = brush->face[i].v[2][1]; + QERFaceData.m_v3[2] = brush->face[i].v[2][2]; + QERFaceData.m_bBPrimit = false; + (g_FuncTable.m_pfnAddFaceData)(vp,&QERFaceData); + } + if(g_FuncTable.m_pfnCommitBrushHandle!=NULL) + { + if(h_func_group) + g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group); + else + g_FuncTable.m_pfnCommitBrushHandle(vp); + } +} +//============================================================= +void OpenFuncGroup() +{ + if (g_FuncTable.m_pfnAllocateEpair!=NULL) + { + epair_t *ep; + + h_func_group = g_FuncTable.m_pfnCreateEntityHandle(); + ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group"); + g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); + + if (AddTerrainKey) // ^Fishman - Add terrain key to func_group. + { + epair_t *ep2; + terrainkey = g_FuncTable.m_pfnCreateEntityHandle(); + ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1"); + ep->next = ep2; + g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); + } + } + else + h_func_group = NULL; +} +//============================================================= +void CloseFuncGroup() +{ + if (h_func_group) + g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group); + if (g_FuncTable.m_pfnSysUpdateWindows != NULL) + g_FuncTable.m_pfnSysUpdateWindows (W_ALL); +} diff --git a/contrib/gtkgensurf/gensurf.cpp b/contrib/gtkgensurf/gensurf.cpp new file mode 100644 index 00000000..b9ff7d47 --- /dev/null +++ b/contrib/gtkgensurf/gensurf.cpp @@ -0,0 +1,467 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +/* +#include +#include +#include +*/ +#include "gensurf.h" + +char gszAppDir[NAME_MAX]; +char gszCaption[64]; +char gszIni[NAME_MAX]; +char gszHelpFile[NAME_MAX]; +char gszMapFile[NAME_MAX]; +char gszVersion[64]; +double Amplitude; +double Roughness; +double TexOffset[2]; +double TexScale[2]; +double WaveLength; +double Hll, Hur, Vll, Vur; +double Z00, Z01, Z10, Z11; +ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; +int AddHints; +int ArghRad2; +int AutoOverwrite; +int Decimate=0; +int SnapToGrid=0; // 0, or the grid size to snap to. // Hydra : snap to grid +int FileAppend=0; +int FixBorders; +int HideBackFaces=0; +int NH, NV; +int NumVerticesSelected; +int Plane; +int Preview; +int RandomSeed=1; +int Skybox; +int UseDetail; +int UseLadder; +int VertexMode=0; +int WaveType; +int gNumNodes=0; +int gNumTris=0; +int vid_x, vid_y; +int view_x, view_y; +int view_cx, view_cy; +int UsePatches; +int SlantAngle; +int GimpHints; +int Antialiasing; // ^Fishman - Antializing for the preview window. +int AddTerrainKey; // ^Fishman - Add terrain key to func_group. +int SP; // ^Fishman - Snap to grid. + +GtkWidget *g_pWnd; // ghwnd; +GtkWidget *g_pRadiantWnd; // ghwnd_main; +/*HWND ghwndAngles; +*/GtkWidget *g_pWndPreview; +GtkWidget *g_pPreviewWidget; +MYBITMAP gbmp; +NODE *gNode=(NODE *)NULL; +TRI *gTri=(TRI *)NULL; + +int Game; +bounding_box PlayerBox[NUMGAMES] = { {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Quake2 + {{-16., 16.}, {-16., 16.}, {-36., 36.}}, // Half-Life + {{-16., 16.}, {-16., 16.}, {-32., 32.}}, // SiN + {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Heretic2 (guess) + {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // KingPin (guess) + {{-30., 30.}, {-30., 30.}, {-10.,160.}}, // Genesis3D (no idea) + {{-16., 16.}, {-16., 16.}, {-24., 32.}}}; // Quake3 (not sure) +//char gszOutputDir[NUMGAMES][NAME_MAX]; +//char gszTextureDir[NUMGAMES][NAME_MAX]; +char Texture[NUMGAMES][3][64]; +//char pakfile[NUMGAMES][NAME_MAX]; +//char lastpakfile[NUMGAMES][NAME_MAX]; +//int UsePak[NUMGAMES]; +//char GameDir[NUMGAMES][NAME_MAX]; + +char GameName[NUMGAMES][16] = {"Quake2", "Half-Life", "SiN", "Heretic2", "Kingpin", "Genesis3D", "Quake3" }; + + +bool GenSurfInit () +{ + strcpy (gszVersion, "1.05"); + strcpy (gszCaption, "GtkGenSurf"); + if (strlen (gszVersion)) + { + strcat (gszCaption, " v"); + strcat (gszCaption, gszVersion); + } + + strcpy (gszIni, g_FuncTable.m_pfnProfileGetDirectory ()); + strcat (gszIni, "gensurf.ini"); + +/*if (g_FuncTable.m_pfnReadProjectKey != NULL) + { + char *basepath; + + basepath = g_FuncTable.m_pfnReadProjectKey("basepath"); + if (basepath) + { + g_strdown (basepath); + if (strstr(basepath,"baseq3")) + Game = QUAKE3; + else if (strstr (basepath,"baseq2")) + Game = QUAKE2; + else // Gotta have a game, might as well be Quake3 + Game = QUAKE3; + } + else + Game = QUAKE3; + } + else */ + Game = QUAKE3; + + ReadIniFile (gszIni); + + if (g_pWnd == NULL) + g_pWnd = create_main_dialog (); + + return true; +} + +// Reads default values + +#define OPTS_SECTION "Options" + +void ReadIniFile (const char *file) +{ + char *Text; + float x1,x2,x3,x4; + int i; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Amplitude", ""); + if (strlen (Text)) + Amplitude = atof (Text); + else + Amplitude = 128; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Roughness", ""); + if (strlen (Text)) + Roughness = atof (Text); + else + Roughness = 16; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "WaveLength", ""); + if (strlen (Text)) + WaveLength = atof (Text); + else + WaveLength = 1024; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Extents", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); + Hll = x1; + Vll = x2; + Hur = x3; + Vur = x4; + } + else + { + Hll = -512; + Vll = -512; + Hur = 512; + Vur = 512; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "CornerValues", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); + Z00 = x1; + Z01 = x2; + Z10 = x3; + Z11 = x4; + } + else + { + Z00 = 0.; + Z01 = 0.; + Z10 = 0.; + Z11 = 0.; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "TextureOffset", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f",&x1,&x2); + TexOffset[0] = x1; + TexOffset[1] = x2; + } + else + { + TexOffset[0] = 0.; + TexOffset[1] = 0.; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION,"TextureScale",""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f",&x1,&x2); + TexScale[0] = x1; + TexScale[1] = x2; + if(TexScale[0] == 0.) TexScale[0] = 1.0; + if(TexScale[1] == 0.) TexScale[1] = 1.0; + } + else + { + TexScale[0] = 1.; + TexScale[1] = 1.; + } + + NH = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NH",8); + NH = max(1,min(NH,MAX_ROWS)); + NV = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NV",8); + NV = max(1,min(NV,MAX_ROWS)); + +// Decimate = GetPrivateProfileInt(OPTS_SECTION,"Decimate",0,file); +// Decimate = max(0,min(Decimate,100)); + + AddHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddHints",0); + ArghRad2 = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"ArghRad2",0); + AutoOverwrite = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AutoOverwrite",0); + FixBorders = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"FixBorders",1); + HideBackFaces = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"HideBackFaces",0); + Plane = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Plane",0); + Preview = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Preview", 0); + Antialiasing = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Antialiasing",0); // ^Fishman - Antializing for the preview window. + RandomSeed = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"RandomSeed",1); + Skybox = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Skybox",0); + UseDetail = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseDetail",0); + AddTerrainKey = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddTerrainKey",0); // ^Fishman - Add terrain key to func_group. + UseLadder = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseLadder",0); + WaveType = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"WaveType",0); + vid_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_x", 0); + vid_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_y", 0); + view_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_x",0); + view_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_y",0); + view_cx = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cx",0); + view_cy = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cy",0); + + UsePatches = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UsePatches",0); + + SlantAngle = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"SlantAngle",60); + GimpHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"GimpHints",0); + + for(i=0; i + +#include "qerplugin.h" +//#include "qertypes.h" + +#include "igl.h" +#include "iui_gtk.h" +#include "ientity.h" + +#include "gendlgs.h" + +#define PLUGIN +#define Q3RADIANT + +#if defined(__linux__) || defined(__APPLE__) +template +inline T min (T x, T y) { return (x < y) ? x : y; } +template +inline T max (T x, T y) { return (x > y) ? x : y; } + +typedef struct { long x, y; } POINT; +typedef struct { long left, top, right, bottom; } RECT; +#endif +inline bool PtInRect (RECT *rc, POINT pt) +{ + if (pt.x < rc->left) return false; + if (pt.x > rc->right) return false; + if (pt.y < rc->bottom) return false; + if (pt.y > rc->top) return false; + return true; +} + +#define NUMGAMES 7 + +#define CONTENTS_SOLID 0x00000001 +#define CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs +#define CONTENTS_LADDER 0x20000000 +#define SURF_HINT 0x100 // make a primary bsp splitter +#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes +#define HINT_OFFSET 96 + +#define PI 3.14159265358979224 +#define RadiansToDegrees(a) (floor(a*57.2957795 - 0.5)+1.) +#define DegreesToRadians(a) (a/57.2957795) + +#define BOGUS_RANGE 65536 +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define XYZVectorSubtract(a,b,c) {c[0]=(float)a[0]-(float)b[0];c[1]=(float)a[1]-(float)b[1];c[2]=(float)a[2]-(float)b[2];} +#define side(u1,v1,u2,v2,u3,v3) (v3-v1)*(u2-u1) - (u3-u1)*(v2-v1) + +#define QUAKE2 0 +#define HALFLIFE 1 +#define SIN 2 +#define HERETIC2 3 +#define KINGPIN 4 +#define GENESIS3D 5 +#define QUAKE3 6 + +#define MAX_FACES_PER_BRUSH 6 +#define SLIVER_ANGLE DegreesToRadians(20) +#define MAX_NODES (MAX_ROWS+1)*(MAX_ROWS+1) +#define MAX_TRIS (MAX_ROWS)*(MAX_ROWS) + +typedef float vec; +typedef vec vec3[3]; +typedef vec vec2[2]; + +typedef struct +{ + vec3 v[3]; + char texture[64]; + float Shift[2]; + float Rotate; + float Scale[2]; + int Contents; + int Surface; + int Value; +} FACE; + +typedef struct +{ + vec3 normal; + vec dist; +} PLANE; + +typedef struct +{ + int numpoints; + vec3 p[4]; // variable sized +} MY_WINDING; + +typedef struct +{ + int Number; + int NumFaces; + FACE face[MAX_FACES_PER_BRUSH]; +} BRUSH; + +typedef struct tagXYZ +{ + int fixed; + int done; + double p[3]; + double pp[3]; // these used only for general 3D projection (not isometric) + double fixed_value; + double range; + double rate; +} XYZ; + +// Q2 PAK file structures +typedef struct +{ + char id[4]; // Should be 'PACK' + int dstart; // Offest in the file to the directory + int dsize; // Size in bytes of the directory, same as num_items*64 +} pak_header_t; + +typedef struct +{ + char name[56]; // The name of the item, normal C string + int start; // Offset in .pak file to start of item + int size; // Size of item in bytes +} pak_item_t; + +// SiN .SIN structures +#define SINPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'S') +#define MAX_PAK_FILENAME_LENGTH 120 + +typedef struct +{ + char name[MAX_PAK_FILENAME_LENGTH]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +// Half-Life WAD file structures +typedef struct +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +typedef struct +{ + int signature; + short version; + short bitflag; + short compression_method; + short modfiletime; + short modfiledate; + int crc; + int compressed_size; + int uncompressed_size; + short filename_size; + short extra_size; +} zipheader_t; + +typedef struct +{ + double x[2]; + double y[2]; + double z[2]; +} bounding_box; + +typedef struct +{ + float p[3]; + int used; + int tri; + float error; + int fixed; +} NODE; + +typedef struct +{ + int v[3]; + int n[3]; // indices of neighboring triangles + PLANE plane; + int flag; + float min[3]; + float max[3]; +} TRI; + +//--------------- bitmap.c ----------------------------- +bool OpenBitmap (); +void GenerateBitmapMapping (); +//--------------- face.c ------------------------------- +void PlaneFromPoints (float *, float *, float *, PLANE *); +void CrossProduct (vec3 v1, vec3 v2, vec3 cross); +vec VectorNormalize (vec3 in, vec3 out); +//--------------- gendlg.c ----------------------------- +GtkWidget* create_main_dialog (); +void About (GtkWidget *parent); +//--------------- genmap.c ----------------------------- +double AtLeast(double,double); +bool CanEdit(int, int); +void CloseFuncGroup(); +bool FixedPoint(int,int); +void GenerateMap(); +void GenerateXYZ(); +double LessThan(double,double); +void MakeBrush(BRUSH *); +double MoreThan(double,double); +double Nearest(double,double); +double NoMoreThan(double,double); +void OpenFuncGroup(); +void PlasmaCloud(); +int PlayerStartZ(double,double); +void SubdividePlasma(int,int,int,int); +bool ValidSurface(); +void XYZtoV(XYZ *, vec3 *); +void MakePatch(patchMesh_t *); +double CalculateSnapValue(double value); + +//---------------- gensurf.c --------------------------- +bool GenSurfInit (); +void ReadIniFile (const char *); +void WriteIniFile (const char *); +void OpenSetup (GtkWidget*,int); +void SaveSetup (GtkWidget*); +//---------------- heretic.c --------------------------- +int GetDefSurfaceProps(char *); +//---------------- view.c ------------------------------ +void CreateViewWindow (); +void DrawGrid(RECT); +void DrawPreview(RECT); +void evaluate(); +void GetScaleFactor(RECT); +void project(XYZ *); +void Scale(RECT,XYZ,POINT *); +void ShowPreview (); +void UpdatePreview (bool); + +//---------------- plugin.c ----------------------------- +void UseFaceBounds(); + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_GLTable; +extern _QERUIGtkTable g_UIGtkTable; +extern _QEREntityTable g_EntityTable; +//#define MAX_ROWS 64 +#define MAX_ROWS 128 + +#define PLANE_XY0 0 +#define PLANE_XY1 1 +#define PLANE_YZ0 2 +#define PLANE_XZ0 3 +#define PLANE_YZ1 4 +#define PLANE_XZ1 5 + +#define WAVE_COS_SIN 0 +#define WAVE_HCYLINDER 1 +#define WAVE_VCYLINDER 2 +#define WAVE_BITMAP 3 +#define WAVE_ROUGH_ONLY 4 +#define WAVE_FORMULA 5 +#define WAVE_FIRST WAVE_COS_SIN +#define WAVE_LAST WAVE_FORMULA +#define DLG_WAVE_LAST DLG_WAVE_01+WAVE_LAST-WAVE_FIRST + +#define MSG_VERTEX_SELECTED WM_USER+1 + +typedef struct tagMYBITMAP +{ + char name[NAME_MAX]; + char defpath[NAME_MAX]; + double black_value; + double white_value; + int width, height; + unsigned char* colors; +} MYBITMAP; + +typedef struct tagELEMENT { + int i; + int j; +} ELEMENT; + +extern char gszAppDir[NAME_MAX]; +extern char gszCaption[64]; +extern char gszHelpFile[NAME_MAX]; +extern char gszIni[NAME_MAX]; +extern char gszMapFile[NAME_MAX]; +extern char gszVersion[64]; +extern double Amplitude; +extern double Roughness; +extern double TexOffset[2]; +extern double TexScale[2]; +extern double WaveLength; +extern double Hll, Hur, Vll, Vur; +extern double Z00, Z01, Z10, Z11; +extern double yaw, pitch, roll; +extern ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; +extern int AddHints; +extern int ArghRad2; +extern int AutoOverwrite; +extern int Decimate; +extern int FileAppend; +extern int FixBorders; +extern int HideBackFaces; +extern int NH, NV; +extern int NumVerticesSelected; +extern int Plane; +extern int Preview; +extern int RandomSeed; +extern int Skybox; +extern int UseDetail; +extern int UseLadder; +extern int VertexMode; +extern int vid_x, vid_y; +extern int WaveType; +extern int gNumNodes; +extern int gNumTris; +extern int view_x, view_y; +extern int view_cx, view_cy; +extern int UsePatches; +extern int SlantAngle; +extern int GimpHints; +extern int Antialiasing; // ^Fishman - Antializing for the preview window. +extern int AddTerrainKey; // ^Fishman - Add terrain key to func_group. +extern int SnapToGrid; // Hydra : snap to grid +extern int SP; // ^Fishman - Snap to grid. + +/*extern HCURSOR ghCursorCurrent; +extern HCURSOR ghCursorDefault; +extern HCURSOR ghCursorVertex; +extern HINSTANCE ghInst;*/ +extern GtkWidget *g_pRadiantWnd; +extern GtkWidget *g_pWnd; +/*extern HWND ghwndAngles; +extern HWND ghwndFix; +*/extern GtkWidget *g_pWndPreview; +extern GtkWidget *g_pPreviewWidget; +extern MYBITMAP gbmp; +extern NODE *gNode; +extern TRI *gTri; +extern XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; + +extern int Game; +extern bounding_box PlayerBox[NUMGAMES]; +//extern char gszOutputDir[NUMGAMES][NAME_MAX]; +extern char Texture[NUMGAMES][3][64]; +//extern char gszTextureDir[NUMGAMES][NAME_MAX]; +extern char GameName[NUMGAMES][16]; +//extern char pakfile[NUMGAMES][NAME_MAX]; +//extern char lastpakfile[NUMGAMES][NAME_MAX]; +//extern int UsePak[NUMGAMES]; +//extern char GameDir[NUMGAMES][NAME_MAX]; +//extern char ExcelFunc[1024]; + +#endif // _GENSURF_H_ diff --git a/contrib/gtkgensurf/gtkgensurf.vcproj b/contrib/gtkgensurf/gtkgensurf.vcproj new file mode 100644 index 00000000..eeadd58e --- /dev/null +++ b/contrib/gtkgensurf/gtkgensurf.vcproj @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/gtkgensurf/heretic.cpp b/contrib/gtkgensurf/heretic.cpp new file mode 100644 index 00000000..7c5bcc03 --- /dev/null +++ b/contrib/gtkgensurf/heretic.cpp @@ -0,0 +1,150 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +// Heretic 2 - specific routines + +typedef struct palette_s +{ + guint8 r,g,b; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define MIPLEVELS 16 + +typedef struct miptex_s +{ + int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + +//============================================================= +int GetDefSurfaceProps(char *Tex) +{ + return 0; // leo: only used for Heretic 2, fix later + /* + char path[NAME_MAX]; + char *p; + int flags; + miptex_t *mt; + FILE *f; + int length; + int pos; + + if(Game != HERETIC2) return 0; + if(!strlen(Tex)) return 0; + + mt = NULL; + flags = 0; + if(UsePak[Game]) + { + FILE *fpak; + pak_header_t pakheader; + pak_item_t pakitem; + int i; + int num; + int numitems; + + if (NULL != (fpak = fopen(pakfile[Game], "rb"))) + { + sprintf(path,"textures/%s.m8",Tex); + g_strdown(path); + num=fread(&pakheader,1,sizeof(pak_header_t),fpak); + if((size_t)num < sizeof(pak_header_t)) + { + fclose(fpak); + return 0; + } + if(strncmp(pakheader.id,"PACK",4)) + { + fclose(fpak); + return 0; + } + numitems = pakheader.dsize/sizeof(pak_item_t); + fseek(fpak,pakheader.dstart,SEEK_SET); + for(i=0; iflags; + free(mt); + } + } + } + fclose(fpak); + } + } + else + { + // Assume .map will be output to gamedir/maps, then back up + // to the gamedir and append /textures. Ugly but it should work + strcpy(path,gszMapFile); + g_strdown(path); + p = strstr(path,"maps"); + if(!p) return 0; + p[0] = '\0'; + strcat(path,"textures/"); + strcat(path,Tex); + strcat(path,".m8"); + f = fopen (path, "rb"); + if (!f) + flags = 0; + else + { + pos = ftell (f); + fseek (f, 0, SEEK_END); + length = ftell (f); + fseek (f, pos, SEEK_SET); + if((mt = (miptex_t*)malloc(length+1))==NULL) + flags = 0; + else + { + ((char *)mt)[length] = 0; + fread(mt, 1, length, f); + fclose (f); + flags = mt->flags; + free(mt); + } + } + } + return flags; + */ +} diff --git a/contrib/gtkgensurf/plugin.cpp b/contrib/gtkgensurf/plugin.cpp new file mode 100644 index 00000000..d7825cc2 --- /dev/null +++ b/contrib/gtkgensurf/plugin.cpp @@ -0,0 +1,227 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "gensurf.h" + +// Global plugin FuncTable +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_GLTable; +_QERUIGtkTable g_UIGtkTable; +_QEREntityTable g_EntityTable; +bool SingleBrushSelected; +bool g_bInitDone; + +#include "iplugin.h" + +const char* QERPlug_Init(void* hApp, void* pMainWidget) +{ + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + return "GenSurf for Q3Radiant"; +} + +const char* QERPlug_GetName () +{ + return "GtkGenSurf"; +} + +const char* QERPlug_GetCommandList () +{ + return "Wall facing 270...;Wall facing 180...;Wall facing 90...;Wall facing 0...;" + "Ceiling...;Ground surface...;-;About..."; +} + +// vMin/vMax provide the bounds of the selection, they are zero if there is no selection +// if there is a selection, bSingleBrush will be true if a single brush is selected +// if so, typical plugin behaviour (such as primitive creation) would use the bounds as +// a rule to create the primitive, then delete the selection +void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + bool Generate = false; + + if (!g_bInitDone) + { + if (GenSurfInit ()) + g_bInitDone = true; + } + + if (!strcmp (p, "Ground surface...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XY0; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[1]; + Hur = vMax[0]; + Vur = vMax[1]; + Z00 = Z01 = Z10 = Z11 = vMax[2]; + } + Generate = true; + } + else if (!strcmp (p, "Ceiling...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XY1; + if(SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[1]; + Hur = vMax[0]; + Vur = vMax[1]; + Z00 = Z01 = Z10 = Z11 = vMin[2]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 0...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_YZ0; + if (SingleBrushSelected) + { + Hll = vMin[1]; + Vll = vMin[2]; + Hur = vMax[1]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMax[0]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 90...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XZ0; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[2]; + Hur = vMax[0]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMax[1]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 180...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_YZ1; + if (SingleBrushSelected) + { + Hll = vMin[1]; + Vll = vMin[2]; + Hur = vMax[1]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMin[0]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 270...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XZ1; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[2]; + Hur = vMax[0]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMin[1]; + } + Generate = true; + } + else if (!strcmp(p,"About...")) + About (g_pRadiantWnd); + + if (Generate) + { + if (SingleBrushSelected) + UseFaceBounds (); + + gtk_widget_show (g_pWnd); + } +} + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class GenSurfSynapseClient : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + GenSurfSynapseClient() { } + virtual ~GenSurfSynapseClient() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +GenSurfSynapseClient g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "gtkgensurf", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable), SYN_REQUIRE, &g_UIGtkTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_GLTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(_QEREntityTable), SYN_REQUIRE, &g_EntityTable); + + return &g_SynapseClient; +} + +bool GenSurfSynapseClient::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* GenSurfSynapseClient::GetInfo() +{ + return "GtkGenSurf - built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/gtkgensurf/triangle.c b/contrib/gtkgensurf/triangle.c new file mode 100644 index 00000000..1462499f --- /dev/null +++ b/contrib/gtkgensurf/triangle.c @@ -0,0 +1,13236 @@ +#define ANSI_DECLARATORS +/*****************************************************************************/ +/* */ +/* 888888888 ,o, / 888 */ +/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */ +/* 888 888 888 88b 888 888 888 888 888 d888 88b */ +/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */ +/* 888 888 888 C888 888 888 888 / 888 q888 */ +/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */ +/* "8oo8D */ +/* */ +/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */ +/* (triangle.c) */ +/* */ +/* Version 1.3 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/* This program may be freely redistributed under the condition that the */ +/* copyright notices (including this entire header and the copyright */ +/* notice printed when the `-h' switch is selected) are not removed, and */ +/* no compensation is received. Private, research, and institutional */ +/* use is free. You may distribute modified versions of this code UNDER */ +/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */ +/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */ +/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */ +/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */ +/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */ +/* WITH THE AUTHOR. (If you are not directly supplying this code to a */ +/* customer, and you are instead telling them how they can obtain it for */ +/* free, then you are not required to make any arrangement with me.) */ +/* */ +/* Hypertext instructions for Triangle are available on the Web at */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.html */ +/* */ +/* Some of the references listed below are marked [*]. These are available */ +/* for downloading from the Web page */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.research.html */ +/* */ +/* A paper discussing some aspects of Triangle is available. See Jonathan */ +/* Richard Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator */ +/* and Delaunay Triangulator," First Workshop on Applied Computational */ +/* Geometry, ACM, May 1996. [*] */ +/* */ +/* Triangle was created as part of the Archimedes project in the School of */ +/* Computer Science at Carnegie Mellon University. Archimedes is a */ +/* system for compiling parallel finite element solvers. For further */ +/* information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */ +/* Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk, */ +/* and Shang-Hua Teng, "Automated Parallel Solution of Unstructured PDE */ +/* Problems." To appear in Communications of the ACM, we hope. */ +/* */ +/* The quality mesh generation algorithm is due to Jim Ruppert, "A */ +/* Delaunay Refinement Algorithm for Quality 2-Dimensional Mesh */ +/* Generation," Journal of Algorithms 18(3):548-585, May 1995. [*] */ +/* */ +/* My implementation of the divide-and-conquer and incremental Delaunay */ +/* triangulation algorithms follows closely the presentation of Guibas */ +/* and Stolfi, even though I use a triangle-based data structure instead */ +/* of their quad-edge data structure. (In fact, I originally implemented */ +/* Triangle using the quad-edge data structure, but switching to a */ +/* triangle-based data structure sped Triangle by a factor of two.) The */ +/* mesh manipulation primitives and the two aforementioned Delaunay */ +/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */ +/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */ +/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */ +/* 4(2):74-123, April 1985. */ +/* */ +/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */ +/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */ +/* Delaunay Triangulation," International Journal of Computer and */ +/* Information Science 9(3):219-242, 1980. The idea to improve the */ +/* divide-and-conquer algorithm by alternating between vertical and */ +/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */ +/* Conquer Algorithm for Constructing Delaunay Triangulations," */ +/* Algorithmica 2(2):137-151, 1987. */ +/* */ +/* The incremental insertion algorithm was first proposed by C. L. Lawson, */ +/* "Software for C1 Surface Interpolation," in Mathematical Software III, */ +/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */ +/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */ +/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */ +/* Preprocessing in Two- and Three-dimensional Delaunay Triangulations," */ +/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */ +/* ACM, May 1996. [*] If I were to randomize the order of point */ +/* insertion (I currently don't bother), their result combined with the */ +/* result of Leonidas J. Guibas, Donald E. Knuth, and Micha Sharir, */ +/* "Randomized Incremental Construction of Delaunay and Voronoi */ +/* Diagrams," Algorithmica 7(4):381-413, 1992, would yield an expected */ +/* O(n^{4/3}) bound on running time. */ +/* */ +/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */ +/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */ +/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */ +/* boundary of the triangulation are maintained in a splay tree for the */ +/* purpose of point location. Splay trees are described by Daniel */ +/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */ +/* Trees," Journal of the ACM 32(3):652-686, July 1985. */ +/* */ +/* The algorithms for exact computation of the signs of determinants are */ +/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */ +/* Point Arithmetic and Fast Robust Geometric Predicates," Technical */ +/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ +/* University, Pittsburgh, Pennsylvania, May 1996. [*] (Submitted to */ +/* Discrete & Computational Geometry.) An abbreviated version appears as */ +/* Jonathan Richard Shewchuk, "Robust Adaptive Floating-Point Geometric */ +/* Predicates," Proceedings of the Twelfth Annual Symposium on Computa- */ +/* tional Geometry, ACM, May 1996. [*] Many of the ideas for my exact */ +/* arithmetic routines originate with Douglas M. Priest, "Algorithms for */ +/* Arbitrary Precision Floating Point Arithmetic," Tenth Symposium on */ +/* Computer Arithmetic, 132-143, IEEE Computer Society Press, 1991. [*] */ +/* Many of the ideas for the correct evaluation of the signs of */ +/* determinants are taken from Steven Fortune and Christopher J. Van Wyk, */ +/* "Efficient Exact Arithmetic for Computational Geometry," Proceedings */ +/* of the Ninth Annual Symposium on Computational Geometry, ACM, */ +/* pp. 163-172, May 1993, and from Steven Fortune, "Numerical Stability */ +/* of Algorithms for 2D Delaunay Triangulations," International Journal */ +/* of Computational Geometry & Applications 5(1-2):193-213, March-June */ +/* 1995. */ +/* */ +/* For definitions of and results involving Delaunay triangulations, */ +/* constrained and conforming versions thereof, and other aspects of */ +/* triangular mesh generation, see the excellent survey by Marshall Bern */ +/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */ +/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */ +/* editors, World Scientific, Singapore, pp. 23-90, 1992. */ +/* */ +/* The time for incrementally adding PSLG (planar straight line graph) */ +/* segments to create a constrained Delaunay triangulation is probably */ +/* O(n^2) per segment in the worst case and O(n) per edge in the common */ +/* case, where n is the number of triangles that intersect the segment */ +/* before it is inserted. This doesn't count point location, which can */ +/* be much more expensive. (This note does not apply to conforming */ +/* Delaunay triangulations, for which a different method is used to */ +/* insert segments.) */ +/* */ +/* The time for adding segments to a conforming Delaunay triangulation is */ +/* not clear, but does not depend upon n alone. In some cases, very */ +/* small features (like a point lying next to a segment) can cause a */ +/* single segment to be split an arbitrary number of times. Of course, */ +/* floating-point precision is a practical barrier to how much this can */ +/* happen. */ +/* */ +/* The time for deleting a point from a Delaunay triangulation is O(n^2) in */ +/* the worst case and O(n) in the common case, where n is the degree of */ +/* the point being deleted. I could improve this to expected O(n) time */ +/* by "inserting" the neighboring vertices in random order, but n is */ +/* usually quite small, so it's not worth the bother. (The O(n) time */ +/* for random insertion follows from L. Paul Chew, "Building Voronoi */ +/* Diagrams for Convex Polygons in Linear Expected Time," Technical */ +/* Report PCS-TR90-147, Department of Mathematics and Computer Science, */ +/* Dartmouth College, 1990. */ +/* */ +/* Ruppert's Delaunay refinement algorithm typically generates triangles */ +/* at a linear rate (constant time per triangle) after the initial */ +/* triangulation is formed. There may be pathological cases where more */ +/* time is required, but these never arise in practice. */ +/* */ +/* The segment intersection formulae are straightforward. If you want to */ +/* see them derived, see Franklin Antonio. "Faster Line Segment */ +/* Intersection." In Graphics Gems III (David Kirk, editor), pp. 199- */ +/* 202. Academic Press, Boston, 1992. */ +/* */ +/* If you make any improvements to this code, please please please let me */ +/* know, so that I may obtain the improvements. Even if you don't change */ +/* the code, I'd still love to hear what it's being used for. */ +/* */ +/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */ +/* whatsoever. This code is provided "as-is". Use at your own risk. */ +/* */ +/*****************************************************************************/ + +/* For single precision (which will save some memory and reduce paging), */ +/* define the symbol SINGLE by using the -DSINGLE compiler switch or by */ +/* writing "#define SINGLE" below. */ +/* */ +/* For double precision (which will allow you to refine meshes to a smaller */ +/* edge length), leave SINGLE undefined. */ +/* */ +/* Double precision uses more memory, but improves the resolution of the */ +/* meshes you can generate with Triangle. It also reduces the likelihood */ +/* of a floating exception due to overflow. Finally, it is much faster */ +/* than single precision on 64-bit architectures like the DEC Alpha. I */ +/* recommend double precision unless you want to generate a mesh for which */ +/* you do not have enough memory. */ + +#define SINGLE + +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +/* If yours is not a Unix system, define the NO_TIMER compiler switch to */ +/* remove the Unix-specific timing code. */ + +#define NO_TIMER + +/* To insert lots of self-checks for internal errors, define the SELF_CHECK */ +/* symbol. This will slow down the program significantly. It is best to */ +/* define the symbol using the -DSELF_CHECK compiler switch, but you could */ +/* write "#define SELF_CHECK" below. If you are modifying this code, I */ +/* recommend you turn self-checks on. */ + +/* #define SELF_CHECK */ + +/* To compile Triangle as a callable object library (triangle.o), define the */ +/* TRILIBRARY symbol. Read the file triangle.h for details on how to call */ +/* the procedure triangulate() that results. */ + +#define TRILIBRARY + +/* It is possible to generate a smaller version of Triangle using one or */ +/* both of the following symbols. Define the REDUCED symbol to eliminate */ +/* all features that are primarily of research interest; specifically, the */ +/* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */ +/* all meshing algorithms above and beyond constrained Delaunay */ +/* triangulation; specifically, the -r, -q, -a, -S, and -s switches. */ +/* These reductions are most likely to be useful when generating an object */ +/* library (triangle.o) by defining the TRILIBRARY symbol. */ + +#define REDUCED +#define CDT_ONLY + +/* On some machines, the exact arithmetic routines might be defeated by the */ +/* use of internal extended precision floating-point registers. Sometimes */ +/* this problem can be fixed by defining certain values to be volatile, */ +/* thus forcing them to be stored to memory and rounded off. This isn't */ +/* a great solution, though, as it slows Triangle down. */ +/* */ +/* To try this out, write "#define INEXACT volatile" below. Normally, */ +/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +/* Maximum number of characters in a file name (including the null). */ + +#define FILENAMESIZE 512 + +/* Maximum number of characters in a line read from a file (including the */ +/* null). */ + +#define INPUTLINESIZE 512 + +/* For efficiency, a variety of data structures are allocated in bulk. The */ +/* following constants determine how many of each structure is allocated */ +/* at once. */ + +#define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */ +#define SHELLEPERBLOCK 508 /* Number of shell edges allocated at once. */ +#define POINTPERBLOCK 4092 /* Number of points allocated at once. */ +#define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */ +/* Number of encroached segments allocated at once. */ +#define BADSEGMENTPERBLOCK 252 +/* Number of skinny triangles allocated at once. */ +#define BADTRIPERBLOCK 4092 +/* Number of splay tree nodes allocated at once. */ +#define SPLAYNODEPERBLOCK 508 + +/* The point marker DEADPOINT is an arbitrary number chosen large enough to */ +/* (hopefully) not conflict with user boundary markers. Make sure that it */ +/* is small enough to fit into your machine's integer size. */ + +#define DEADPOINT -1073741824 + +/* The next line is used to outsmart some very stupid compilers. If your */ +/* compiler is smarter, feel free to replace the "int" with "void". */ +/* Not that it matters. */ + +#define VOID int + +/* Two constants for algorithms based on random sampling. Both constants */ +/* have been chosen empirically to optimize their respective algorithms. */ + +/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */ +/* how large a random sample of triangles to inspect. */ +#define SAMPLEFACTOR 11 +/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */ +/* of boundary edges should be maintained in the splay tree for point */ +/* location on the front. */ +#define SAMPLERATE 10 + +/* A number that speaks for itself, every kissable digit. */ + +#define PI 3.141592653589793238462643383279502884197169399375105820974944592308 + +/* Another fave. */ + +#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732 + +/* And here's one for those of you who are intimidated by math. */ + +#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333 + +#include +#include +#include +#ifndef NO_TIMER +#include +#endif /* NO_TIMER */ +#ifdef TRILIBRARY +#include "triangle.h" +#endif /* TRILIBRARY */ + +/* The following obscenity seems to be necessary to ensure that this program */ +/* will port to Dec Alphas running OSF/1, because their stdio.h file commits */ +/* the unpardonable sin of including stdlib.h. Hence, malloc(), free(), and */ +/* exit() may or may not already be defined at this point. I declare these */ +/* functions explicitly because some non-ANSI C compilers lack stdlib.h. */ + +#ifndef _STDLIB_H_ +extern void *malloc(); +extern void free(); +extern void exit(); +extern double strtod(); +extern long strtol(); +#endif /* _STDLIB_H_ */ + +/* A few forward declarations. */ + +void poolrestart(); +#ifndef TRILIBRARY +char *readline(); +char *findfield(); +#endif /* not TRILIBRARY */ + +/* Labels that signify whether a record consists primarily of pointers or of */ +/* floating-point words. Used to make decisions about data alignment. */ + +enum wordtype {POINTER, FLOATINGPOINT}; + +/* Labels that signify the result of point location. The result of a */ +/* search indicates that the point falls in the interior of a triangle, on */ +/* an edge, on a vertex, or outside the mesh. */ + +enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE}; + +/* Labels that signify the result of site insertion. The result indicates */ +/* that the point was inserted with complete success, was inserted but */ +/* encroaches on a segment, was not inserted because it lies on a segment, */ +/* or was not inserted because another point occupies the same location. */ + +enum insertsiteresult {SUCCESSFULPOINT, ENCROACHINGPOINT, VIOLATINGPOINT, + DUPLICATEPOINT}; + +/* Labels that signify the result of direction finding. The result */ +/* indicates that a segment connecting the two query points falls within */ +/* the direction triangle, along the left edge of the direction triangle, */ +/* or along the right edge of the direction triangle. */ + +enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR}; + +/* Labels that signify the result of the circumcenter computation routine. */ +/* The return value indicates which edge of the triangle is shortest. */ + +enum circumcenterresult {OPPOSITEORG, OPPOSITEDEST, OPPOSITEAPEX}; + +/*****************************************************************************/ +/* */ +/* The basic mesh data structures */ +/* */ +/* There are three: points, triangles, and shell edges (abbreviated */ +/* `shelle'). These three data structures, linked by pointers, comprise */ +/* the mesh. A point simply represents a point in space and its properties.*/ +/* A triangle is a triangle. A shell edge is a special data structure used */ +/* to represent impenetrable segments in the mesh (including the outer */ +/* boundary, boundaries of holes, and internal boundaries separating two */ +/* triangulated regions). Shell edges represent boundaries defined by the */ +/* user that triangles may not lie across. */ +/* */ +/* A triangle consists of a list of three vertices, a list of three */ +/* adjoining triangles, a list of three adjoining shell edges (when shell */ +/* edges are used), an arbitrary number of optional user-defined floating- */ +/* point attributes, and an optional area constraint. The latter is an */ +/* upper bound on the permissible area of each triangle in a region, used */ +/* for mesh refinement. */ +/* */ +/* For a triangle on a boundary of the mesh, some or all of the neighboring */ +/* triangles may not be present. For a triangle in the interior of the */ +/* mesh, often no neighboring shell edges are present. Such absent */ +/* triangles and shell edges are never represented by NULL pointers; they */ +/* are represented by two special records: `dummytri', the triangle that */ +/* fills "outer space", and `dummysh', the omnipresent shell edge. */ +/* `dummytri' and `dummysh' are used for several reasons; for instance, */ +/* they can be dereferenced and their contents examined without causing the */ +/* memory protection exception that would occur if NULL were dereferenced. */ +/* */ +/* However, it is important to understand that a triangle includes other */ +/* information as well. The pointers to adjoining vertices, triangles, and */ +/* shell edges are ordered in a way that indicates their geometric relation */ +/* to each other. Furthermore, each of these pointers contains orientation */ +/* information. Each pointer to an adjoining triangle indicates which face */ +/* of that triangle is contacted. Similarly, each pointer to an adjoining */ +/* shell edge indicates which side of that shell edge is contacted, and how */ +/* the shell edge is oriented relative to the triangle. */ +/* */ +/* Shell edges are found abutting edges of triangles; either sandwiched */ +/* between two triangles, or resting against one triangle on an exterior */ +/* boundary or hole boundary. */ +/* */ +/* A shell edge consists of a list of two vertices, a list of two */ +/* adjoining shell edges, and a list of two adjoining triangles. One of */ +/* the two adjoining triangles may not be present (though there should */ +/* always be one), and neighboring shell edges might not be present. */ +/* Shell edges also store a user-defined integer "boundary marker". */ +/* Typically, this integer is used to indicate what sort of boundary */ +/* conditions are to be applied at that location in a finite element */ +/* simulation. */ +/* */ +/* Like triangles, shell edges maintain information about the relative */ +/* orientation of neighboring objects. */ +/* */ +/* Points are relatively simple. A point is a list of floating point */ +/* numbers, starting with the x, and y coordinates, followed by an */ +/* arbitrary number of optional user-defined floating-point attributes, */ +/* followed by an integer boundary marker. During the segment insertion */ +/* phase, there is also a pointer from each point to a triangle that may */ +/* contain it. Each pointer is not always correct, but when one is, it */ +/* speeds up segment insertion. These pointers are assigned values once */ +/* at the beginning of the segment insertion phase, and are not used or */ +/* updated at any other time. Edge swapping during segment insertion will */ +/* render some of them incorrect. Hence, don't rely upon them for */ +/* anything. For the most part, points do not have any information about */ +/* what triangles or shell edges they are linked to. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Handles */ +/* */ +/* The oriented triangle (`triedge') and oriented shell edge (`edge') data */ +/* structures defined below do not themselves store any part of the mesh. */ +/* The mesh itself is made of `triangle's, `shelle's, and `point's. */ +/* */ +/* Oriented triangles and oriented shell edges will usually be referred to */ +/* as "handles". A handle is essentially a pointer into the mesh; it */ +/* allows you to "hold" one particular part of the mesh. Handles are used */ +/* to specify the regions in which one is traversing and modifying the mesh.*/ +/* A single `triangle' may be held by many handles, or none at all. (The */ +/* latter case is not a memory leak, because the triangle is still */ +/* connected to other triangles in the mesh.) */ +/* */ +/* A `triedge' is a handle that holds a triangle. It holds a specific side */ +/* of the triangle. An `edge' is a handle that holds a shell edge. It */ +/* holds either the left or right side of the edge. */ +/* */ +/* Navigation about the mesh is accomplished through a set of mesh */ +/* manipulation primitives, further below. Many of these primitives take */ +/* a handle and produce a new handle that holds the mesh near the first */ +/* handle. Other primitives take two handles and glue the corresponding */ +/* parts of the mesh together. The exact position of the handles is */ +/* important. For instance, when two triangles are glued together by the */ +/* bond() primitive, they are glued by the sides on which the handles lie. */ +/* */ +/* Because points have no information about which triangles they are */ +/* attached to, I commonly represent a point by use of a handle whose */ +/* origin is the point. A single handle can simultaneously represent a */ +/* triangle, an edge, and a point. */ +/* */ +/*****************************************************************************/ + +/* The triangle data structure. Each triangle contains three pointers to */ +/* adjoining triangles, plus three pointers to vertex points, plus three */ +/* pointers to shell edges (defined below; these pointers are usually */ +/* `dummysh'). It may or may not also contain user-defined attributes */ +/* and/or a floating-point "area constraint". It may also contain extra */ +/* pointers for nodes, when the user asks for high-order elements. */ +/* Because the size and structure of a `triangle' is not decided until */ +/* runtime, I haven't simply defined the type `triangle' to be a struct. */ + +typedef REAL **triangle; /* Really: typedef triangle *triangle */ + +/* An oriented triangle: includes a pointer to a triangle and orientation. */ +/* The orientation denotes an edge of the triangle. Hence, there are */ +/* three possible orientations. By convention, each edge is always */ +/* directed to point counterclockwise about the corresponding triangle. */ + +struct triedge { + triangle *tri; + int orient; /* Ranges from 0 to 2. */ +}; + +/* The shell data structure. Each shell edge contains two pointers to */ +/* adjoining shell edges, plus two pointers to vertex points, plus two */ +/* pointers to adjoining triangles, plus one shell marker. */ + +typedef REAL **shelle; /* Really: typedef shelle *shelle */ + +/* An oriented shell edge: includes a pointer to a shell edge and an */ +/* orientation. The orientation denotes a side of the edge. Hence, there */ +/* are two possible orientations. By convention, the edge is always */ +/* directed so that the "side" denoted is the right side of the edge. */ + +struct edge { + shelle *sh; + int shorient; /* Ranges from 0 to 1. */ +}; + +/* The point data structure. Each point is actually an array of REALs. */ +/* The number of REALs is unknown until runtime. An integer boundary */ +/* marker, and sometimes a pointer to a triangle, is appended after the */ +/* REALs. */ + +typedef REAL *point; + +/* A queue used to store encroached segments. Each segment's vertices are */ +/* stored so that one can check whether a segment is still the same. */ + +struct badsegment { + struct edge encsegment; /* An encroached segment. */ + point segorg, segdest; /* The two vertices. */ + struct badsegment *nextsegment; /* Pointer to next encroached segment. */ +}; + +/* A queue used to store bad triangles. The key is the square of the cosine */ +/* of the smallest angle of the triangle. Each triangle's vertices are */ +/* stored so that one can check whether a triangle is still the same. */ + +struct badface { + struct triedge badfacetri; /* A bad triangle. */ + REAL key; /* cos^2 of smallest (apical) angle. */ + point faceorg, facedest, faceapex; /* The three vertices. */ + struct badface *nextface; /* Pointer to next bad triangle. */ +}; + +/* A node in a heap used to store events for the sweepline Delaunay */ +/* algorithm. Nodes do not point directly to their parents or children in */ +/* the heap. Instead, each node knows its position in the heap, and can */ +/* look up its parent and children in a separate array. The `eventptr' */ +/* points either to a `point' or to a triangle (in encoded format, so that */ +/* an orientation is included). In the latter case, the origin of the */ +/* oriented triangle is the apex of a "circle event" of the sweepline */ +/* algorithm. To distinguish site events from circle events, all circle */ +/* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */ + +struct event { + REAL xkey, ykey; /* Coordinates of the event. */ + VOID *eventptr; /* Can be a point or the location of a circle event. */ + int heapposition; /* Marks this event's position in the heap. */ +}; + +/* A node in the splay tree. Each node holds an oriented ghost triangle */ +/* that represents a boundary edge of the growing triangulation. When a */ +/* circle event covers two boundary edges with a triangle, so that they */ +/* are no longer boundary edges, those edges are not immediately deleted */ +/* from the tree; rather, they are lazily deleted when they are next */ +/* encountered. (Since only a random sample of boundary edges are kept */ +/* in the tree, lazy deletion is faster.) `keydest' is used to verify */ +/* that a triangle is still the same as when it entered the splay tree; if */ +/* it has been rotated (due to a circle event), it no longer represents a */ +/* boundary edge and should be deleted. */ + +struct splaynode { + struct triedge keyedge; /* Lprev of an edge on the front. */ + point keydest; /* Used to verify that splay node is still live. */ + struct splaynode *lchild, *rchild; /* Children in splay tree. */ +}; + +/* A type used to allocate memory. firstblock is the first block of items. */ +/* nowblock is the block from which items are currently being allocated. */ +/* nextitem points to the next slab of free memory for an item. */ +/* deaditemstack is the head of a linked list (stack) of deallocated items */ +/* that can be recycled. unallocateditems is the number of items that */ +/* remain to be allocated from nowblock. */ +/* */ +/* Traversal is the process of walking through the entire list of items, and */ +/* is separate from allocation. Note that a traversal will visit items on */ +/* the "deaditemstack" stack as well as live items. pathblock points to */ +/* the block currently being traversed. pathitem points to the next item */ +/* to be traversed. pathitemsleft is the number of items that remain to */ +/* be traversed in pathblock. */ +/* */ +/* itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest */ +/* what sort of word the record is primarily made up of. alignbytes */ +/* determines how new records should be aligned in memory. itembytes and */ +/* itemwords are the length of a record in bytes (after rounding up) and */ +/* words. itemsperblock is the number of items allocated at once in a */ +/* single block. items is the number of currently allocated items. */ +/* maxitems is the maximum number of items that have been allocated at */ +/* once; it is the current number of items plus the number of records kept */ +/* on deaditemstack. */ + +struct memorypool { + VOID **firstblock, **nowblock; + VOID *nextitem; + VOID *deaditemstack; + VOID **pathblock; + VOID *pathitem; + enum wordtype itemwordtype; + int alignbytes; + int itembytes, itemwords; + int itemsperblock; + long items, maxitems; + int unallocateditems; + int pathitemsleft; +}; + +/* Variables used to allocate memory for triangles, shell edges, points, */ +/* viri (triangles being eaten), bad (encroached) segments, bad (skinny */ +/* or too large) triangles, and splay tree nodes. */ + +static struct memorypool triangles; +static struct memorypool shelles; +static struct memorypool points; +static struct memorypool viri; +static struct memorypool badsegments; +static struct memorypool badtriangles; +static struct memorypool splaynodes; + +/* Variables that maintain the bad triangle queues. The tails are pointers */ +/* to the pointers that have to be filled in to enqueue an item. */ + +static struct badface *queuefront[64]; +static struct badface **queuetail[64]; + +static REAL xmin, xmax, ymin, ymax; /* x and y bounds. */ +static REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */ +static int inpoints; /* Number of input points. */ +static int inelements; /* Number of input triangles. */ +static int insegments; /* Number of input segments. */ +static int holes; /* Number of input holes. */ +static int regions; /* Number of input regions. */ +static long edges; /* Number of output edges. */ +static int mesh_dim; /* Dimension (ought to be 2). */ +static int nextras; /* Number of attributes per point. */ +static int eextras; /* Number of attributes per triangle. */ +static long hullsize; /* Number of edges of convex hull. */ +static int triwords; /* Total words per triangle. */ +static int shwords; /* Total words per shell edge. */ +static int pointmarkindex; /* Index to find boundary marker of a point. */ +static int point2triindex; /* Index to find a triangle adjacent to a point. */ +static int highorderindex; /* Index to find extra nodes for high-order elements. */ +static int elemattribindex; /* Index to find attributes of a triangle. */ +static int areaboundindex; /* Index to find area bound of a triangle. */ +static int checksegments; /* Are there segments in the triangulation yet? */ +static int readnodefile; /* Has a .node file been read? */ +static long samples; /* Number of random samples for point location. */ +static unsigned long randomseed; /* Current random number seed. */ + +static REAL splitter; /* Used to split REAL factors for exact multiplication. */ +static REAL epsilon; /* Floating-point machine epsilon. */ +static REAL resulterrbound; +static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; +static REAL iccerrboundA, iccerrboundB, iccerrboundC; + +static long incirclecount; /* Number of incircle tests performed. */ +static long counterclockcount; /* Number of counterclockwise tests performed. */ +static long hyperbolacount; /* Number of right-of-hyperbola tests performed. */ +static long circumcentercount; /* Number of circumcenter calculations performed. */ +static long circletopcount; /* Number of circle top calculations performed. */ + +/* Switches for the triangulator. */ +/* poly: -p switch. refine: -r switch. */ +/* quality: -q switch. */ +/* minangle: minimum angle bound, specified after -q switch. */ +/* goodangle: cosine squared of minangle. */ +/* vararea: -a switch without number. */ +/* fixedarea: -a switch with number. */ +/* maxarea: maximum area bound, specified after -a switch. */ +/* regionattrib: -A switch. convex: -c switch. */ +/* firstnumber: inverse of -z switch. All items are numbered starting */ +/* from firstnumber. */ +/* edgesout: -e switch. voronoi: -v switch. */ +/* neighbors: -n switch. geomview: -g switch. */ +/* nobound: -B switch. nopolywritten: -P switch. */ +/* nonodewritten: -N switch. noelewritten: -E switch. */ +/* noiterationnum: -I switch. noholes: -O switch. */ +/* noexact: -X switch. */ +/* order: element order, specified after -o switch. */ +/* nobisect: count of how often -Y switch is selected. */ +/* steiner: maximum number of Steiner points, specified after -S switch. */ +/* steinerleft: number of Steiner points not yet used. */ +/* incremental: -i switch. sweepline: -F switch. */ +/* dwyer: inverse of -l switch. */ +/* splitseg: -s switch. */ +/* docheck: -C switch. */ +/* quiet: -Q switch. verbose: count of how often -V switch is selected. */ +/* useshelles: -p, -r, -q, or -c switch; determines whether shell edges */ +/* are used at all. */ +/* */ +/* Read the instructions to find out the meaning of these switches. */ + +static int poly, refine, quality, vararea, fixedarea, regionattrib, convex; +static int firstnumber; +static int edgesout, voronoi, neighbors, geomview; +static int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum; +static int noholes, noexact; +static int incremental, sweepline, dwyer; +static int splitseg; +static int docheck; +static int quiet, verbose; +static int useshelles; +static int order; +static int nobisect; +static int steiner, steinerleft; +static REAL minangle, goodangle; +static REAL maxarea; + +/* Variables for file names. */ + +#ifndef TRILIBRARY +char innodefilename[FILENAMESIZE]; +char inelefilename[FILENAMESIZE]; +char inpolyfilename[FILENAMESIZE]; +char areafilename[FILENAMESIZE]; +char outnodefilename[FILENAMESIZE]; +char outelefilename[FILENAMESIZE]; +char outpolyfilename[FILENAMESIZE]; +char edgefilename[FILENAMESIZE]; +char vnodefilename[FILENAMESIZE]; +char vedgefilename[FILENAMESIZE]; +char neighborfilename[FILENAMESIZE]; +char offfilename[FILENAMESIZE]; +#endif /* not TRILIBRARY */ + +/* Triangular bounding box points. */ + +static point infpoint1, infpoint2, infpoint3; + +/* Pointer to the `triangle' that occupies all of "outer space". */ + +static triangle *dummytri; +static triangle *dummytribase; /* Keep base address so we can free() it later. */ + +/* Pointer to the omnipresent shell edge. Referenced by any triangle or */ +/* shell edge that isn't really connected to a shell edge at that */ +/* location. */ + +static shelle *dummysh; +static shelle *dummyshbase; /* Keep base address so we can free() it later. */ + +/* Pointer to a recently visited triangle. Improves point location if */ +/* proximate points are inserted sequentially. */ + +static struct triedge recenttri; + +/*****************************************************************************/ +/* */ +/* Mesh manipulation primitives. Each triangle contains three pointers to */ +/* other triangles, with orientations. Each pointer points not to the */ +/* first byte of a triangle, but to one of the first three bytes of a */ +/* triangle. It is necessary to extract both the triangle itself and the */ +/* orientation. To save memory, I keep both pieces of information in one */ +/* pointer. To make this possible, I assume that all triangles are aligned */ +/* to four-byte boundaries. The `decode' routine below decodes a pointer, */ +/* extracting an orientation (in the range 0 to 2) and a pointer to the */ +/* beginning of a triangle. The `encode' routine compresses a pointer to a */ +/* triangle and an orientation into a single pointer. My assumptions that */ +/* triangles are four-byte-aligned and that the `unsigned long' type is */ +/* long enough to hold a pointer are two of the few kludges in this program.*/ +/* */ +/* Shell edges are manipulated similarly. A pointer to a shell edge */ +/* carries both an address and an orientation in the range 0 to 1. */ +/* */ +/* The other primitives take an oriented triangle or oriented shell edge, */ +/* and return an oriented triangle or oriented shell edge or point; or they */ +/* change the connections in the data structure. */ +/* */ +/*****************************************************************************/ + +/********* Mesh manipulation primitives begin here *********/ +/** **/ +/** **/ + +/* Fast lookup arrays to speed some of the mesh manipulation primitives. */ + +int plus1mod3[3] = {1, 2, 0}; +int minus1mod3[3] = {2, 0, 1}; + +/********* Primitives for triangles *********/ +/* */ +/* */ + +/* decode() converts a pointer to an oriented triangle. The orientation is */ +/* extracted from the two least significant bits of the pointer. */ + +#define decode(ptr, triedge) \ + (triedge).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \ + (triedge).tri = (triangle *) \ + ((unsigned long) (ptr) ^ (unsigned long) (triedge).orient) + +/* encode() compresses an oriented triangle into a single pointer. It */ +/* relies on the assumption that all triangles are aligned to four-byte */ +/* boundaries, so the two least significant bits of (triedge).tri are zero.*/ + +#define encode(triedge) \ + (triangle) ((unsigned long) (triedge).tri | (unsigned long) (triedge).orient) + +/* The following edge manipulation primitives are all described by Guibas */ +/* and Stolfi. However, they use an edge-based data structure, whereas I */ +/* am using a triangle-based data structure. */ + +/* sym() finds the abutting triangle, on the same edge. Note that the */ +/* edge direction is necessarily reversed, because triangle/edge handles */ +/* are always directed counterclockwise around the triangle. */ + +#define sym(triedge1, triedge2) \ + ptr = (triedge1).tri[(triedge1).orient]; \ + decode(ptr, triedge2); + +#define symself(triedge) \ + ptr = (triedge).tri[(triedge).orient]; \ + decode(ptr, triedge); + +/* lnext() finds the next edge (counterclockwise) of a triangle. */ + +#define lnext(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = plus1mod3[(triedge1).orient] + +#define lnextself(triedge) \ + (triedge).orient = plus1mod3[(triedge).orient] + +/* lprev() finds the previous edge (clockwise) of a triangle. */ + +#define lprev(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = minus1mod3[(triedge1).orient] + +#define lprevself(triedge) \ + (triedge).orient = minus1mod3[(triedge).orient] + +/* onext() spins counterclockwise around a point; that is, it finds the next */ +/* edge with the same origin in the counterclockwise direction. This edge */ +/* will be part of a different triangle. */ + +#define onext(triedge1, triedge2) \ + lprev(triedge1, triedge2); \ + symself(triedge2); + +#define onextself(triedge) \ + lprevself(triedge); \ + symself(triedge); + +/* oprev() spins clockwise around a point; that is, it finds the next edge */ +/* with the same origin in the clockwise direction. This edge will be */ +/* part of a different triangle. */ + +#define oprev(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lnextself(triedge2); + +#define oprevself(triedge) \ + symself(triedge); \ + lnextself(triedge); + +/* dnext() spins counterclockwise around a point; that is, it finds the next */ +/* edge with the same destination in the counterclockwise direction. This */ +/* edge will be part of a different triangle. */ + +#define dnext(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lprevself(triedge2); + +#define dnextself(triedge) \ + symself(triedge); \ + lprevself(triedge); + +/* dprev() spins clockwise around a point; that is, it finds the next edge */ +/* with the same destination in the clockwise direction. This edge will */ +/* be part of a different triangle. */ + +#define dprev(triedge1, triedge2) \ + lnext(triedge1, triedge2); \ + symself(triedge2); + +#define dprevself(triedge) \ + lnextself(triedge); \ + symself(triedge); + +/* rnext() moves one edge counterclockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rnext(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lnextself(triedge2); \ + symself(triedge2); + +#define rnextself(triedge) \ + symself(triedge); \ + lnextself(triedge); \ + symself(triedge); + +/* rnext() moves one edge clockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rprev(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lprevself(triedge2); \ + symself(triedge2); + +#define rprevself(triedge) \ + symself(triedge); \ + lprevself(triedge); \ + symself(triedge); + +/* These primitives determine or set the origin, destination, or apex of a */ +/* triangle. */ + +#define org(triedge, pointptr) \ + pointptr = (point) (triedge).tri[plus1mod3[(triedge).orient] + 3] + +#define dest(triedge, pointptr) \ + pointptr = (point) (triedge).tri[minus1mod3[(triedge).orient] + 3] + +#define apex(triedge, pointptr) \ + pointptr = (point) (triedge).tri[(triedge).orient + 3] + +#define setorg(triedge, pointptr) \ + (triedge).tri[plus1mod3[(triedge).orient] + 3] = (triangle) pointptr + +#define setdest(triedge, pointptr) \ + (triedge).tri[minus1mod3[(triedge).orient] + 3] = (triangle) pointptr + +#define setapex(triedge, pointptr) \ + (triedge).tri[(triedge).orient + 3] = (triangle) pointptr + +#define setvertices2null(triedge) \ + (triedge).tri[3] = (triangle) NULL; \ + (triedge).tri[4] = (triangle) NULL; \ + (triedge).tri[5] = (triangle) NULL; + +/* Bond two triangles together. */ + +#define bond(triedge1, triedge2) \ + (triedge1).tri[(triedge1).orient] = encode(triedge2); \ + (triedge2).tri[(triedge2).orient] = encode(triedge1) + +/* Dissolve a bond (from one side). Note that the other triangle will still */ +/* think it's connected to this triangle. Usually, however, the other */ +/* triangle is being deleted entirely, or bonded to another triangle, so */ +/* it doesn't matter. */ + +#define dissolve(triedge) \ + (triedge).tri[(triedge).orient] = (triangle) dummytri + +/* Copy a triangle/edge handle. */ + +#define triedgecopy(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = (triedge1).orient + +/* Test for equality of triangle/edge handles. */ + +#define triedgeequal(triedge1, triedge2) \ + (((triedge1).tri == (triedge2).tri) && \ + ((triedge1).orient == (triedge2).orient)) + +/* Primitives to infect or cure a triangle with the virus. These rely on */ +/* the assumption that all shell edges are aligned to four-byte boundaries.*/ + +#define infect(triedge) \ + (triedge).tri[6] = (triangle) \ + ((unsigned long) (triedge).tri[6] | (unsigned long) 2l) + +#define uninfect(triedge) \ + (triedge).tri[6] = (triangle) \ + ((unsigned long) (triedge).tri[6] & ~ (unsigned long) 2l) + +/* Test a triangle for viral infection. */ + +#define infected(triedge) \ + (((unsigned long) (triedge).tri[6] & (unsigned long) 2l) != 0) + +/* Check or set a triangle's attributes. */ + +#define elemattribute(triedge, attnum) \ + ((REAL *) (triedge).tri)[elemattribindex + (attnum)] + +#define setelemattribute(triedge, attnum, value) \ + ((REAL *) (triedge).tri)[elemattribindex + (attnum)] = (REAL)value + +/* Check or set a triangle's maximum area bound. */ + +#define areabound(triedge) ((REAL *) (triedge).tri)[areaboundindex] + +#define setareabound(triedge, value) \ + ((REAL *) (triedge).tri)[areaboundindex] = (REAL)value + +/********* Primitives for shell edges *********/ +/* */ +/* */ + +/* sdecode() converts a pointer to an oriented shell edge. The orientation */ +/* is extracted from the least significant bit of the pointer. The two */ +/* least significant bits (one for orientation, one for viral infection) */ +/* are masked out to produce the real pointer. */ + +#define sdecode(sptr, edge) \ + (edge).shorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \ + (edge).sh = (shelle *) \ + ((unsigned long) (sptr) & ~ (unsigned long) 3l) + +/* sencode() compresses an oriented shell edge into a single pointer. It */ +/* relies on the assumption that all shell edges are aligned to two-byte */ +/* boundaries, so the least significant bit of (edge).sh is zero. */ + +#define sencode(edge) \ + (shelle) ((unsigned long) (edge).sh | (unsigned long) (edge).shorient) + +/* ssym() toggles the orientation of a shell edge. */ + +#define ssym(edge1, edge2) \ + (edge2).sh = (edge1).sh; \ + (edge2).shorient = 1 - (edge1).shorient + +#define ssymself(edge) \ + (edge).shorient = 1 - (edge).shorient + +/* spivot() finds the other shell edge (from the same segment) that shares */ +/* the same origin. */ + +#define spivot(edge1, edge2) \ + sptr = (edge1).sh[(edge1).shorient]; \ + sdecode(sptr, edge2) + +#define spivotself(edge) \ + sptr = (edge).sh[(edge).shorient]; \ + sdecode(sptr, edge) + +/* snext() finds the next shell edge (from the same segment) in sequence; */ +/* one whose origin is the input shell edge's destination. */ + +#define snext(edge1, edge2) \ + sptr = (edge1).sh[1 - (edge1).shorient]; \ + sdecode(sptr, edge2) + +#define snextself(edge) \ + sptr = (edge).sh[1 - (edge).shorient]; \ + sdecode(sptr, edge) + +/* These primitives determine or set the origin or destination of a shell */ +/* edge. */ + +#define sorg(edge, pointptr) \ + pointptr = (point) (edge).sh[2 + (edge).shorient] + +#define sdest(edge, pointptr) \ + pointptr = (point) (edge).sh[3 - (edge).shorient] + +#define setsorg(edge, pointptr) \ + (edge).sh[2 + (edge).shorient] = (shelle) pointptr + +#define setsdest(edge, pointptr) \ + (edge).sh[3 - (edge).shorient] = (shelle) pointptr + +/* These primitives read or set a shell marker. Shell markers are used to */ +/* hold user boundary information. */ + +#define mark(edge) (* (int *) ((edge).sh + 6)) + +#define setmark(edge, value) \ + * (int *) ((edge).sh + 6) = value + +/* Bond two shell edges together. */ + +#define sbond(edge1, edge2) \ + (edge1).sh[(edge1).shorient] = sencode(edge2); \ + (edge2).sh[(edge2).shorient] = sencode(edge1) + +/* Dissolve a shell edge bond (from one side). Note that the other shell */ +/* edge will still think it's connected to this shell edge. */ + +#define sdissolve(edge) \ + (edge).sh[(edge).shorient] = (shelle) dummysh + +/* Copy a shell edge. */ + +#define shellecopy(edge1, edge2) \ + (edge2).sh = (edge1).sh; \ + (edge2).shorient = (edge1).shorient + +/* Test for equality of shell edges. */ + +#define shelleequal(edge1, edge2) \ + (((edge1).sh == (edge2).sh) && \ + ((edge1).shorient == (edge2).shorient)) + +/********* Primitives for interacting triangles and shell edges *********/ +/* */ +/* */ + +/* tspivot() finds a shell edge abutting a triangle. */ + +#define tspivot(triedge, edge) \ + sptr = (shelle) (triedge).tri[6 + (triedge).orient]; \ + sdecode(sptr, edge) + +/* stpivot() finds a triangle abutting a shell edge. It requires that the */ +/* variable `ptr' of type `triangle' be defined. */ + +#define stpivot(edge, triedge) \ + ptr = (triangle) (edge).sh[4 + (edge).shorient]; \ + decode(ptr, triedge) + +/* Bond a triangle to a shell edge. */ + +#define tsbond(triedge, edge) \ + (triedge).tri[6 + (triedge).orient] = (triangle) sencode(edge); \ + (edge).sh[4 + (edge).shorient] = (shelle) encode(triedge) + +/* Dissolve a bond (from the triangle side). */ + +#define tsdissolve(triedge) \ + (triedge).tri[6 + (triedge).orient] = (triangle) dummysh + +/* Dissolve a bond (from the shell edge side). */ + +#define stdissolve(edge) \ + (edge).sh[4 + (edge).shorient] = (shelle) dummytri + +/********* Primitives for points *********/ +/* */ +/* */ + +#define pointmark(pt) ((int *) (pt))[pointmarkindex] + +#define setpointmark(pt, value) \ + ((int *) (pt))[pointmarkindex] = value + +#define point2tri(pt) ((triangle *) (pt))[point2triindex] + +#define setpoint2tri(pt, value) \ + ((triangle *) (pt))[point2triindex] = value + +/** **/ +/** **/ +/********* Mesh manipulation primitives end here *********/ + +/********* User interaction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* syntax() Print list of command line switches. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void syntax() +{ +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + + printf(" -p Triangulates a Planar Straight Line Graph (.poly file).\n"); +#ifndef CDT_ONLY + printf(" -r Refines a previously generated mesh.\n"); + printf( + " -q Quality mesh generation. A minimum angle may be specified.\n"); + printf(" -a Applies a maximum triangle area constraint.\n"); +#endif /* not CDT_ONLY */ + printf( + " -A Applies attributes to identify elements in certain regions.\n"); + printf(" -c Encloses the convex hull with segments.\n"); + printf(" -e Generates an edge list.\n"); + printf(" -v Generates a Voronoi diagram.\n"); + printf(" -n Generates a list of triangle neighbors.\n"); + printf(" -g Generates an .off file for Geomview.\n"); + printf(" -B Suppresses output of boundary information.\n"); + printf(" -P Suppresses output of .poly file.\n"); + printf(" -N Suppresses output of .node file.\n"); + printf(" -E Suppresses output of .ele file.\n"); + printf(" -I Suppresses mesh iteration numbers.\n"); + printf(" -O Ignores holes in .poly file.\n"); + printf(" -X Suppresses use of exact arithmetic.\n"); + printf(" -z Numbers all items starting from zero (rather than one).\n"); + printf(" -o2 Generates second-order subparametric elements.\n"); +#ifndef CDT_ONLY + printf(" -Y Suppresses boundary segment splitting.\n"); + printf(" -S Specifies maximum number of added Steiner points.\n"); +#endif /* not CDT_ONLY */ +#ifndef REDUCED + printf(" -i Uses incremental method, rather than divide-and-conquer.\n"); + printf(" -F Uses Fortune's sweepline algorithm, rather than d-and-c.\n"); +#endif /* not REDUCED */ + printf(" -l Uses vertical cuts only, rather than alternating cuts.\n"); +#ifndef REDUCED +#ifndef CDT_ONLY + printf( + " -s Force segments into mesh by splitting (instead of using CDT).\n"); +#endif /* not CDT_ONLY */ + printf(" -C Check consistency of final mesh.\n"); +#endif /* not REDUCED */ + printf(" -Q Quiet: No terminal output except errors.\n"); + printf(" -V Verbose: Detailed information on what I'm doing.\n"); + printf(" -h Help: Detailed instructions for Triangle.\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* info() Print out complete instructions. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void info() +{ + printf("Triangle\n"); + printf( +"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n"); + printf("Version 1.3\n\n"); + printf( +"Copyright 1996 Jonathan Richard Shewchuk (bugs/comments to jrs@cs.cmu.edu)\n" +); + printf("School of Computer Science / Carnegie Mellon University\n"); + printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania 15213-3891\n"); + printf( +"Created as part of the Archimedes project (tools for parallel FEM).\n"); + printf( +"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n"); + printf("There is no warranty whatsoever. Use at your own risk.\n"); +#ifdef SINGLE + printf("This executable is compiled for single precision arithmetic.\n\n\n"); +#else /* not SINGLE */ + printf("This executable is compiled for double precision arithmetic.\n\n\n"); +#endif /* not SINGLE */ + printf( +"Triangle generates exact Delaunay triangulations, constrained Delaunay\n"); + printf( +"triangulations, and quality conforming Delaunay triangulations. The latter\n" +); + printf( +"can be generated with no small angles, and are thus suitable for finite\n"); + printf( +"element analysis. If no command line switches are specified, your .node\n"); + printf( +"input file will be read, and the Delaunay triangulation will be returned in\n" +); + printf(".node and .ele output files. The command syntax is:\n\n"); +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n\n"); +#else /* not REDUCED */ + printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + printf( +"Underscores indicate that numbers may optionally follow certain switches;\n"); + printf( +"do not leave any space between a switch and its numeric parameter.\n"); + printf( +"input_file must be a file with extension .node, or extension .poly if the\n"); + printf( +"-p switch is used. If -r is used, you must supply .node and .ele files,\n"); + printf( +"and possibly a .poly file and .area file as well. The formats of these\n"); + printf("files are described below.\n\n"); + printf("Command Line Switches:\n\n"); + printf( +" -p Reads a Planar Straight Line Graph (.poly file), which can specify\n" +); + printf( +" points, segments, holes, and regional attributes and area\n"); + printf( +" constraints. Will generate a constrained Delaunay triangulation\n"); + printf( +" fitting the input; or, if -s, -q, or -a is used, a conforming\n"); + printf( +" Delaunay triangulation. If -p is not used, Triangle reads a .node\n" +); + printf(" file by default.\n"); + printf( +" -r Refines a previously generated mesh. The mesh is read from a .node\n" +); + printf( +" file and an .ele file. If -p is also used, a .poly file is read\n"); + printf( +" and used to constrain edges in the mesh. Further details on\n"); + printf(" refinement are given below.\n"); + printf( +" -q Quality mesh generation by Jim Ruppert's Delaunay refinement\n"); + printf( +" algorithm. Adds points to the mesh to ensure that no angles\n"); + printf( +" smaller than 20 degrees occur. An alternative minimum angle may be\n" +); + printf( +" specified after the `q'. If the minimum angle is 20.7 degrees or\n"); + printf( +" smaller, the triangulation algorithm is theoretically guaranteed to\n" +); + printf( +" terminate (assuming infinite precision arithmetic - Triangle may\n"); + printf( +" fail to terminate if you run out of precision). In practice, the\n"); + printf( +" algorithm often succeeds for minimum angles up to 33.8 degrees.\n"); + printf( +" For highly refined meshes, however, it may be necessary to reduce\n"); + printf( +" the minimum angle to well below 20 to avoid problems associated\n"); + printf( +" with insufficient floating-point precision. The specified angle\n"); + printf(" may include a decimal point.\n"); + printf( +" -a Imposes a maximum triangle area. If a number follows the `a', no\n"); + printf( +" triangle will be generated whose area is larger than that number.\n"); + printf( +" If no number is specified, an .area file (if -r is used) or .poly\n"); + printf( +" file (if -r is not used) specifies a number of maximum area\n"); + printf( +" constraints. An .area file contains a separate area constraint for\n" +); + printf( +" each triangle, and is useful for refining a finite element mesh\n"); + printf( +" based on a posteriori error estimates. A .poly file can optionally\n" +); + printf( +" contain an area constraint for each segment-bounded region, thereby\n" +); + printf( +" enforcing triangle densities in a first triangulation. You can\n"); + printf( +" impose both a fixed area constraint and a varying area constraint\n"); + printf( +" by invoking the -a switch twice, once with and once without a\n"); + printf( +" number following. Each area specified may include a decimal point.\n" +); + printf( +" -A Assigns an additional attribute to each triangle that identifies\n"); + printf( +" what segment-bounded region each triangle belongs to. Attributes\n"); + printf( +" are assigned to regions by the .poly file. If a region is not\n"); + printf( +" explicitly marked by the .poly file, triangles in that region are\n"); + printf( +" assigned an attribute of zero. The -A switch has an effect only\n"); + printf(" when the -p switch is used and the -r switch is not.\n"); + printf( +" -c Creates segments on the convex hull of the triangulation. If you\n"); + printf( +" are triangulating a point set, this switch causes a .poly file to\n"); + printf( +" be written, containing all edges in the convex hull. (By default,\n" +); + printf( +" a .poly file is written only if a .poly file is read.) If you are\n" +); + printf( +" triangulating a PSLG, this switch specifies that the interior of\n"); + printf( +" the convex hull of the PSLG should be triangulated. If you do not\n" +); + printf( +" use this switch when triangulating a PSLG, it is assumed that you\n"); + printf( +" have identified the region to be triangulated by surrounding it\n"); + printf( +" with segments of the input PSLG. Beware: if you are not careful,\n" +); + printf( +" this switch can cause the introduction of an extremely thin angle\n"); + printf( +" between a PSLG segment and a convex hull segment, which can cause\n"); + printf( +" overrefinement or failure if Triangle runs out of precision. If\n"); + printf( +" you are refining a mesh, the -c switch works differently; it\n"); + printf( +" generates the set of boundary edges of the mesh, rather than the\n"); + printf(" convex hull.\n"); + printf( +" -e Outputs (to an .edge file) a list of edges of the triangulation.\n"); + printf( +" -v Outputs the Voronoi diagram associated with the triangulation.\n"); + printf(" Does not attempt to detect degeneracies.\n"); + printf( +" -n Outputs (to a .neigh file) a list of triangles neighboring each\n"); + printf(" triangle.\n"); + printf( +" -g Outputs the mesh to an Object File Format (.off) file, suitable for\n" +); + printf(" viewing with the Geometry Center's Geomview package.\n"); + printf( +" -B No boundary markers in the output .node, .poly, and .edge output\n"); + printf( +" files. See the detailed discussion of boundary markers below.\n"); + printf( +" -P No output .poly file. Saves disk space, but you lose the ability\n"); + printf( +" to impose segment constraints on later refinements of the mesh.\n"); + printf(" -N No output .node file.\n"); + printf(" -E No output .ele file.\n"); + printf( +" -I No iteration numbers. Suppresses the output of .node and .poly\n"); + printf( +" files, so your input files won't be overwritten. (If your input is\n" +); + printf( +" a .poly file only, a .node file will be written.) Cannot be used\n"); + printf( +" with the -r switch, because that would overwrite your input .ele\n"); + printf( +" file. Shouldn't be used with the -s, -q, or -a switch if you are\n"); + printf( +" using a .node file for input, because no .node file will be\n"); + printf(" written, so there will be no record of any added points.\n"); + printf(" -O No holes. Ignores the holes in the .poly file.\n"); + printf( +" -X No exact arithmetic. Normally, Triangle uses exact floating-point\n" +); + printf( +" arithmetic for certain tests if it thinks the inexact tests are not\n" +); + printf( +" accurate enough. Exact arithmetic ensures the robustness of the\n"); + printf( +" triangulation algorithms, despite floating-point roundoff error.\n"); + printf( +" Disabling exact arithmetic with the -X switch will cause a small\n"); + printf( +" improvement in speed and create the possibility (albeit small) that\n" +); + printf( +" Triangle will fail to produce a valid mesh. Not recommended.\n"); + printf( +" -z Numbers all items starting from zero (rather than one). Note that\n" +); + printf( +" this switch is normally overrided by the value used to number the\n"); + printf( +" first point of the input .node or .poly file. However, this switch\n" +); + printf(" is useful when calling Triangle from another program.\n"); + printf( +" -o2 Generates second-order subparametric elements with six nodes each.\n" +); + printf( +" -Y No new points on the boundary. This switch is useful when the mesh\n" +); + printf( +" boundary must be preserved so that it conforms to some adjacent\n"); + printf( +" mesh. Be forewarned that you will probably sacrifice some of the\n"); + printf( +" quality of the mesh; Triangle will try, but the resulting mesh may\n" +); + printf( +" contain triangles of poor aspect ratio. Works well if all the\n"); + printf( +" boundary points are closely spaced. Specify this switch twice\n"); + printf( +" (`-YY') to prevent all segment splitting, including internal\n"); + printf(" boundaries.\n"); + printf( +" -S Specifies the maximum number of Steiner points (points that are not\n" +); + printf( +" in the input, but are added to meet the constraints of minimum\n"); + printf( +" angle and maximum area). The default is to allow an unlimited\n"); + printf( +" number. If you specify this switch with no number after it,\n"); + printf( +" the limit is set to zero. Triangle always adds points at segment\n"); + printf( +" intersections, even if it needs to use more points than the limit\n"); + printf( +" you set. When Triangle inserts segments by splitting (-s), it\n"); + printf( +" always adds enough points to ensure that all the segments appear in\n" +); + printf( +" the triangulation, again ignoring the limit. Be forewarned that\n"); + printf( +" the -S switch may result in a conforming triangulation that is not\n" +); + printf( +" truly Delaunay, because Triangle may be forced to stop adding\n"); + printf( +" points when the mesh is in a state where a segment is non-Delaunay\n" +); + printf( +" and needs to be split. If so, Triangle will print a warning.\n"); + printf( +" -i Uses an incremental rather than divide-and-conquer algorithm to\n"); + printf( +" form a Delaunay triangulation. Try it if the divide-and-conquer\n"); + printf(" algorithm fails.\n"); + printf( +" -F Uses Steven Fortune's sweepline algorithm to form a Delaunay\n"); + printf( +" triangulation. Warning: does not use exact arithmetic for all\n"); + printf(" calculations. An exact result is not guaranteed.\n"); + printf( +" -l Uses only vertical cuts in the divide-and-conquer algorithm. By\n"); + printf( +" default, Triangle uses alternating vertical and horizontal cuts,\n"); + printf( +" which usually improve the speed except with point sets that are\n"); + printf( +" small or short and wide. This switch is primarily of theoretical\n"); + printf(" interest.\n"); + printf( +" -s Specifies that segments should be forced into the triangulation by\n" +); + printf( +" recursively splitting them at their midpoints, rather than by\n"); + printf( +" generating a constrained Delaunay triangulation. Segment splitting\n" +); + printf( +" is true to Ruppert's original algorithm, but can create needlessly\n" +); + printf(" small triangles near external small features.\n"); + printf( +" -C Check the consistency of the final mesh. Uses exact arithmetic for\n" +); + printf( +" checking, even if the -X switch is used. Useful if you suspect\n"); + printf(" Triangle is buggy.\n"); + printf( +" -Q Quiet: Suppresses all explanation of what Triangle is doing, unless\n" +); + printf(" an error occurs.\n"); + printf( +" -V Verbose: Gives detailed information about what Triangle is doing.\n"); + printf( +" Add more `V's for increasing amount of detail. `-V' gives\n"); + printf( +" information on algorithmic progress and more detailed statistics.\n"); + printf( +" `-VV' gives point-by-point details, and will print so much that\n"); + printf( +" Triangle will run much more slowly. `-VVV' gives information only\n" +); + printf(" a debugger could love.\n"); + printf(" -h Help: Displays these instructions.\n"); + printf("\n"); + printf("Definitions:\n"); + printf("\n"); + printf( +" A Delaunay triangulation of a point set is a triangulation whose vertices\n" +); + printf( +" are the point set, having the property that no point in the point set\n"); + printf( +" falls in the interior of the circumcircle (circle that passes through all\n" +); + printf(" three vertices) of any triangle in the triangulation.\n\n"); + printf( +" A Voronoi diagram of a point set is a subdivision of the plane into\n"); + printf( +" polygonal regions (some of which may be infinite), where each region is\n"); + printf( +" the set of points in the plane that are closer to some input point than\n"); + printf( +" to any other input point. (The Voronoi diagram is the geometric dual of\n" +); + printf(" the Delaunay triangulation.)\n\n"); + printf( +" A Planar Straight Line Graph (PSLG) is a collection of points and\n"); + printf( +" segments. Segments are simply edges, whose endpoints are points in the\n"); + printf( +" PSLG. The file format for PSLGs (.poly files) is described below.\n"); + printf("\n"); + printf( +" A constrained Delaunay triangulation of a PSLG is similar to a Delaunay\n"); + printf( +" triangulation, but each PSLG segment is present as a single edge in the\n"); + printf( +" triangulation. (A constrained Delaunay triangulation is not truly a\n"); + printf(" Delaunay triangulation.)\n\n"); + printf( +" A conforming Delaunay triangulation of a PSLG is a true Delaunay\n"); + printf( +" triangulation in which each PSLG segment may have been subdivided into\n"); + printf( +" several edges by the insertion of additional points. These inserted\n"); + printf( +" points are necessary to allow the segments to exist in the mesh while\n"); + printf(" maintaining the Delaunay property.\n\n"); + printf("File Formats:\n\n"); + printf( +" All files may contain comments prefixed by the character '#'. Points,\n"); + printf( +" triangles, edges, holes, and maximum area constraints must be numbered\n"); + printf( +" consecutively, starting from either 1 or 0. Whichever you choose, all\n"); + printf( +" input files must be consistent; if the nodes are numbered from 1, so must\n" +); + printf( +" be all other objects. Triangle automatically detects your choice while\n"); + printf( +" reading the .node (or .poly) file. (When calling Triangle from another\n"); + printf( +" program, use the -z switch if you wish to number objects from zero.)\n"); + printf(" Examples of these file formats are given below.\n\n"); + printf(" .node files:\n"); + printf( +" First line: <# of points> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Remaining lines: [attributes] [boundary marker]\n"); + printf("\n"); + printf( +" The attributes, which are typically floating-point values of physical\n"); + printf( +" quantities (such as mass or conductivity) associated with the nodes of\n" +); + printf( +" a finite element mesh, are copied unchanged to the output mesh. If -s,\n" +); + printf( +" -q, or -a is selected, each new Steiner point added to the mesh will\n"); + printf(" have attributes assigned to it by linear interpolation.\n\n"); + printf( +" If the fourth entry of the first line is `1', the last column of the\n"); + printf( +" remainder of the file is assumed to contain boundary markers. Boundary\n" +); + printf( +" markers are used to identify boundary points and points resting on PSLG\n" +); + printf( +" segments; a complete description appears in a section below. The .node\n" +); + printf( +" file produced by Triangle will contain boundary markers in the last\n"); + printf(" column unless they are suppressed by the -B switch.\n\n"); + printf(" .ele files:\n"); + printf( +" First line: <# of triangles> <# of attributes>\n"); + printf( +" Remaining lines: ... [attributes]\n" +); + printf("\n"); + printf( +" Points are indices into the corresponding .node file. The first three\n" +); + printf( +" points are the corners, and are listed in counterclockwise order around\n" +); + printf( +" each triangle. (The remaining points, if any, depend on the type of\n"); + printf( +" finite element used.) The attributes are just like those of .node\n"); + printf( +" files. Because there is no simple mapping from input to output\n"); + printf( +" triangles, an attempt is made to interpolate attributes, which may\n"); + printf( +" result in a good deal of diffusion of attributes among nearby triangles\n" +); + printf( +" as the triangulation is refined. Diffusion does not occur across\n"); + printf( +" segments, so attributes used to identify segment-bounded regions remain\n" +); + printf( +" intact. In output .ele files, all triangles have three points each\n"); + printf( +" unless the -o2 switch is used, in which case they have six, and the\n"); + printf( +" fourth, fifth, and sixth points lie on the midpoints of the edges\n"); + printf(" opposite the first, second, and third corners.\n\n"); + printf(" .poly files:\n"); + printf( +" First line: <# of points> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Following lines: [attributes] [boundary marker]\n"); + printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: [boundary marker]\n"); + printf(" One line: <# of holes>\n"); + printf(" Following lines: \n"); + printf( +" Optional line: <# of regional attributes and/or area constraints>\n"); + printf( +" Optional following lines: \n"); + printf("\n"); + printf( +" A .poly file represents a PSLG, as well as some additional information.\n" +); + printf( +" The first section lists all the points, and is identical to the format\n" +); + printf( +" of .node files. <# of points> may be set to zero to indicate that the\n" +); + printf( +" points are listed in a separate .node file; .poly files produced by\n"); + printf( +" Triangle always have this format. This has the advantage that a point\n" +); + printf( +" set may easily be triangulated with or without segments. (The same\n"); + printf( +" effect can be achieved, albeit using more disk space, by making a copy\n" +); + printf( +" of the .poly file with the extension .node; all sections of the file\n"); + printf(" but the first are ignored.)\n\n"); + printf( +" The second section lists the segments. Segments are edges whose\n"); + printf( +" presence in the triangulation is enforced. Each segment is specified\n"); + printf( +" by listing the indices of its two endpoints. This means that you must\n" +); + printf( +" include its endpoints in the point list. If -s, -q, and -a are not\n"); + printf( +" selected, Triangle will produce a constrained Delaunay triangulation,\n"); + printf( +" in which each segment appears as a single edge in the triangulation.\n"); + printf( +" If -q or -a is selected, Triangle will produce a conforming Delaunay\n"); + printf( +" triangulation, in which segments may be subdivided into smaller edges.\n" +); + printf(" Each segment, like each point, may have a boundary marker.\n\n"); + printf( +" The third section lists holes (and concavities, if -c is selected) in\n"); + printf( +" the triangulation. Holes are specified by identifying a point inside\n"); + printf( +" each hole. After the triangulation is formed, Triangle creates holes\n"); + printf( +" by eating triangles, spreading out from each hole point until its\n"); + printf( +" progress is blocked by PSLG segments; you must be careful to enclose\n"); + printf( +" each hole in segments, or your whole triangulation may be eaten away.\n"); + printf( +" If the two triangles abutting a segment are eaten, the segment itself\n"); + printf( +" is also eaten. Do not place a hole directly on a segment; if you do,\n"); + printf(" Triangle will choose one side of the segment arbitrarily.\n\n"); + printf( +" The optional fourth section lists regional attributes (to be assigned\n"); + printf( +" to all triangles in a region) and regional constraints on the maximum\n"); + printf( +" triangle area. Triangle will read this section only if the -A switch\n"); + printf( +" is used or the -a switch is used without a number following it, and the\n" +); + printf( +" -r switch is not used. Regional attributes and area constraints are\n"); + printf( +" propagated in the same manner as holes; you specify a point for each\n"); + printf( +" attribute and/or constraint, and the attribute and/or constraint will\n"); + printf( +" affect the whole region (bounded by segments) containing the point. If\n" +); + printf( +" two values are written on a line after the x and y coordinate, the\n"); + printf( +" former is assumed to be a regional attribute (but will only be applied\n" +); + printf( +" if the -A switch is selected), and the latter is assumed to be a\n"); + printf( +" regional area constraint (but will only be applied if the -a switch is\n" +); + printf( +" selected). You may also specify just one value after the coordinates,\n" +); + printf( +" which can serve as both an attribute and an area constraint, depending\n" +); + printf( +" on the choice of switches. If you are using the -A and -a switches\n"); + printf( +" simultaneously and wish to assign an attribute to some region without\n"); + printf(" imposing an area constraint, use a negative maximum area.\n\n"); + printf( +" When a triangulation is created from a .poly file, you must either\n"); + printf( +" enclose the entire region to be triangulated in PSLG segments, or\n"); + printf( +" use the -c switch, which encloses the convex hull of the input point\n"); + printf( +" set. If you do not use the -c switch, Triangle will eat all triangles\n" +); + printf( +" on the outer boundary that are not protected by segments; if you are\n"); + printf( +" not careful, your whole triangulation may be eaten away. If you do\n"); + printf( +" use the -c switch, you can still produce concavities by appropriate\n"); + printf(" placement of holes just inside the convex hull.\n\n"); + printf( +" An ideal PSLG has no intersecting segments, nor any points that lie\n"); + printf( +" upon segments (except, of course, the endpoints of each segment.) You\n" +); + printf( +" aren't required to make your .poly files ideal, but you should be aware\n" +); + printf( +" of what can go wrong. Segment intersections are relatively safe -\n"); + printf( +" Triangle will calculate the intersection points for you and add them to\n" +); + printf( +" the triangulation - as long as your machine's floating-point precision\n" +); + printf( +" doesn't become a problem. You are tempting the fates if you have three\n" +); + printf( +" segments that cross at the same location, and expect Triangle to figure\n" +); + printf( +" out where the intersection point is. Thanks to floating-point roundoff\n" +); + printf( +" error, Triangle will probably decide that the three segments intersect\n" +); + printf( +" at three different points, and you will find a minuscule triangle in\n"); + printf( +" your output - unless Triangle tries to refine the tiny triangle, uses\n"); + printf( +" up the last bit of machine precision, and fails to terminate at all.\n"); + printf( +" You're better off putting the intersection point in the input files,\n"); + printf( +" and manually breaking up each segment into two. Similarly, if you\n"); + printf( +" place a point at the middle of a segment, and hope that Triangle will\n"); + printf( +" break up the segment at that point, you might get lucky. On the other\n" +); + printf( +" hand, Triangle might decide that the point doesn't lie precisely on the\n" +); + printf( +" line, and you'll have a needle-sharp triangle in your output - or a lot\n" +); + printf(" of tiny triangles if you're generating a quality mesh.\n\n"); + printf( +" When Triangle reads a .poly file, it also writes a .poly file, which\n"); + printf( +" includes all edges that are part of input segments. If the -c switch\n"); + printf( +" is used, the output .poly file will also include all of the edges on\n"); + printf( +" the convex hull. Hence, the output .poly file is useful for finding\n"); + printf( +" edges associated with input segments and setting boundary conditions in\n" +); + printf( +" finite element simulations. More importantly, you will need it if you\n" +); + printf( +" plan to refine the output mesh, and don't want segments to be missing\n"); + printf(" in later triangulations.\n\n"); + printf(" .area files:\n"); + printf(" First line: <# of triangles>\n"); + printf(" Following lines: \n\n"); + printf( +" An .area file associates with each triangle a maximum area that is used\n" +); + printf( +" for mesh refinement. As with other file formats, every triangle must\n"); + printf( +" be represented, and they must be numbered consecutively. A triangle\n"); + printf( +" may be left unconstrained by assigning it a negative maximum area.\n"); + printf("\n"); + printf(" .edge files:\n"); + printf(" First line: <# of edges> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: [boundary marker]\n"); + printf("\n"); + printf( +" Endpoints are indices into the corresponding .node file. Triangle can\n" +); + printf( +" produce .edge files (use the -e switch), but cannot read them. The\n"); + printf( +" optional column of boundary markers is suppressed by the -B switch.\n"); + printf("\n"); + printf( +" In Voronoi diagrams, one also finds a special kind of edge that is an\n"); + printf( +" infinite ray with only one endpoint. For these edges, a different\n"); + printf(" format is used:\n\n"); + printf(" -1 \n\n"); + printf( +" The `direction' is a floating-point vector that indicates the direction\n" +); + printf(" of the infinite ray.\n\n"); + printf(" .neigh files:\n"); + printf( +" First line: <# of triangles> <# of neighbors per triangle (always 3)>\n" +); + printf( +" Following lines: \n"); + printf("\n"); + printf( +" Neighbors are indices into the corresponding .ele file. An index of -1\n" +); + printf( +" indicates a mesh boundary, and therefore no neighbor. Triangle can\n"); + printf( +" produce .neigh files (use the -n switch), but cannot read them.\n"); + printf("\n"); + printf( +" The first neighbor of triangle i is opposite the first corner of\n"); + printf(" triangle i, and so on.\n\n"); + printf("Boundary Markers:\n\n"); + printf( +" Boundary markers are tags used mainly to identify which output points and\n" +); + printf( +" edges are associated with which PSLG segment, and to identify which\n"); + printf( +" points and edges occur on a boundary of the triangulation. A common use\n" +); + printf( +" is to determine where boundary conditions should be applied to a finite\n"); + printf( +" element mesh. You can prevent boundary markers from being written into\n"); + printf(" files produced by Triangle by using the -B switch.\n\n"); + printf( +" The boundary marker associated with each segment in an output .poly file\n" +); + printf(" or edge in an output .edge file is chosen as follows:\n"); + printf( +" - If an output edge is part or all of a PSLG segment with a nonzero\n"); + printf( +" boundary marker, then the edge is assigned the same marker.\n"); + printf( +" - Otherwise, if the edge occurs on a boundary of the triangulation\n"); + printf( +" (including boundaries of holes), then the edge is assigned the marker\n" +); + printf(" one (1).\n"); + printf(" - Otherwise, the edge is assigned the marker zero (0).\n"); + printf( +" The boundary marker associated with each point in an output .node file is\n" +); + printf(" chosen as follows:\n"); + printf( +" - If a point is assigned a nonzero boundary marker in the input file,\n"); + printf( +" then it is assigned the same marker in the output .node file.\n"); + printf( +" - Otherwise, if the point lies on a PSLG segment (including the\n"); + printf( +" segment's endpoints) with a nonzero boundary marker, then the point\n"); + printf( +" is assigned the same marker. If the point lies on several such\n"); + printf(" segments, one of the markers is chosen arbitrarily.\n"); + printf( +" - Otherwise, if the point occurs on a boundary of the triangulation,\n"); + printf(" then the point is assigned the marker one (1).\n"); + printf(" - Otherwise, the point is assigned the marker zero (0).\n"); + printf("\n"); + printf( +" If you want Triangle to determine for you which points and edges are on\n"); + printf( +" the boundary, assign them the boundary marker zero (or use no markers at\n" +); + printf( +" all) in your input files. Alternatively, you can mark some of them and\n"); + printf(" leave others marked zero, allowing Triangle to label them.\n\n"); + printf("Triangulation Iteration Numbers:\n\n"); + printf( +" Because Triangle can read and refine its own triangulations, input\n"); + printf( +" and output files have iteration numbers. For instance, Triangle might\n"); + printf( +" read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n"); + printf( +" triangulation, and output the files mesh.4.node, mesh.4.ele, and\n"); + printf(" mesh.4.poly. Files with no iteration number are treated as if\n"); + printf( +" their iteration number is zero; hence, Triangle might read the file\n"); + printf( +" points.node, triangulate it, and produce the files points.1.node and\n"); + printf(" points.1.ele.\n\n"); + printf( +" Iteration numbers allow you to create a sequence of successively finer\n"); + printf( +" meshes suitable for multigrid methods. They also allow you to produce a\n" +); + printf( +" sequence of meshes using error estimate-driven mesh refinement.\n"); + printf("\n"); + printf( +" If you're not using refinement or quality meshing, and you don't like\n"); + printf( +" iteration numbers, use the -I switch to disable them. This switch will\n"); + printf( +" also disable output of .node and .poly files to prevent your input files\n" +); + printf( +" from being overwritten. (If the input is a .poly file that contains its\n" +); + printf(" own points, a .node file will be written.)\n\n"); + printf("Examples of How to Use Triangle:\n\n"); + printf( +" `triangle dots' will read points from dots.node, and write their Delaunay\n" +); + printf( +" triangulation to dots.1.node and dots.1.ele. (dots.1.node will be\n"); + printf( +" identical to dots.node.) `triangle -I dots' writes the triangulation to\n" +); + printf( +" dots.ele instead. (No additional .node file is needed, so none is\n"); + printf(" written.)\n\n"); + printf( +" `triangle -pe object.1' will read a PSLG from object.1.poly (and possibly\n" +); + printf( +" object.1.node, if the points are omitted from object.1.poly) and write\n"); + printf(" their constrained Delaunay triangulation to object.2.node and\n"); + printf( +" object.2.ele. The segments will be copied to object.2.poly, and all\n"); + printf(" edges will be written to object.2.edge.\n\n"); + printf( +" `triangle -pq31.5a.1 object' will read a PSLG from object.poly (and\n"); + printf( +" possibly object.node), generate a mesh whose angles are all greater than\n" +); + printf( +" 31.5 degrees and whose triangles all have area smaller than 0.1, and\n"); + printf( +" write the mesh to object.1.node and object.1.ele. Each segment may have\n" +); + printf( +" been broken up into multiple edges; the resulting constrained edges are\n"); + printf(" written to object.1.poly.\n\n"); + printf( +" Here is a sample file `box.poly' describing a square with a square hole:\n" +); + printf("\n"); + printf( +" # A box with eight points in 2D, no attributes, one boundary marker.\n"); + printf(" 8 2 0 1\n"); + printf(" # Outer box has these vertices:\n"); + printf(" 1 0 0 0\n"); + printf(" 2 0 3 0\n"); + printf(" 3 3 0 0\n"); + printf(" 4 3 3 33 # A special marker for this point.\n"); + printf(" # Inner square has these vertices:\n"); + printf(" 5 1 1 0\n"); + printf(" 6 1 2 0\n"); + printf(" 7 2 1 0\n"); + printf(" 8 2 2 0\n"); + printf(" # Five segments with boundary markers.\n"); + printf(" 5 1\n"); + printf(" 1 1 2 5 # Left side of outer box.\n"); + printf(" 2 5 7 0 # Segments 2 through 5 enclose the hole.\n"); + printf(" 3 7 8 0\n"); + printf(" 4 8 6 10\n"); + printf(" 5 6 5 0\n"); + printf(" # One hole in the middle of the inner square.\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n\n"); + printf( +" Note that some segments are missing from the outer square, so one must\n"); + printf( +" use the `-c' switch. After `triangle -pqc box.poly', here is the output\n" +); + printf( +" file `box.1.node', with twelve points. The last four points were added\n"); + printf( +" to meet the angle constraint. Points 1, 2, and 9 have markers from\n"); + printf( +" segment 1. Points 6 and 8 have markers from segment 4. All the other\n"); + printf( +" points but 4 have been marked to indicate that they lie on a boundary.\n"); + printf("\n"); + printf(" 12 2 0 1\n"); + printf(" 1 0 0 5\n"); + printf(" 2 0 3 5\n"); + printf(" 3 3 0 1\n"); + printf(" 4 3 3 33\n"); + printf(" 5 1 1 1\n"); + printf(" 6 1 2 10\n"); + printf(" 7 2 1 1\n"); + printf(" 8 2 2 10\n"); + printf(" 9 0 1.5 5\n"); + printf(" 10 1.5 0 1\n"); + printf(" 11 3 1.5 1\n"); + printf(" 12 1.5 3 1\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf(" Here is the output file `box.1.ele', with twelve triangles.\n\n"); + printf(" 12 3 0\n"); + printf(" 1 5 6 9\n"); + printf(" 2 10 3 7\n"); + printf(" 3 6 8 12\n"); + printf(" 4 9 1 5\n"); + printf(" 5 6 2 9\n"); + printf(" 6 7 3 11\n"); + printf(" 7 11 4 8\n"); + printf(" 8 7 5 10\n"); + printf(" 9 12 2 6\n"); + printf(" 10 8 7 11\n"); + printf(" 11 5 1 10\n"); + printf(" 12 8 4 12\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf( +" Here is the output file `box.1.poly'. Note that segments have been added\n" +); + printf( +" to represent the convex hull, and some segments have been split by newly\n" +); + printf( +" added points. Note also that <# of points> is set to zero to indicate\n"); + printf(" that the points should be read from the .node file.\n\n"); + printf(" 0 2 0 1\n"); + printf(" 12 1\n"); + printf(" 1 1 9 5\n"); + printf(" 2 5 7 1\n"); + printf(" 3 8 7 1\n"); + printf(" 4 6 8 10\n"); + printf(" 5 5 6 1\n"); + printf(" 6 3 10 1\n"); + printf(" 7 4 11 1\n"); + printf(" 8 2 12 1\n"); + printf(" 9 9 2 5\n"); + printf(" 10 10 1 1\n"); + printf(" 11 11 3 1\n"); + printf(" 12 12 4 1\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf("Refinement and Area Constraints:\n\n"); + printf( +" The -r switch causes a mesh (.node and .ele files) to be read and\n"); + printf( +" refined. If the -p switch is also used, a .poly file is read and used to\n" +); + printf( +" specify edges that are constrained and cannot be eliminated (although\n"); + printf( +" they can be divided into smaller edges) by the refinement process.\n"); + printf("\n"); + printf( +" When you refine a mesh, you generally want to impose tighter quality\n"); + printf( +" constraints. One way to accomplish this is to use -q with a larger\n"); + printf( +" angle, or -a followed by a smaller area than you used to generate the\n"); + printf( +" mesh you are refining. Another way to do this is to create an .area\n"); + printf( +" file, which specifies a maximum area for each triangle, and use the -a\n"); + printf( +" switch (without a number following). Each triangle's area constraint is\n" +); + printf( +" applied to that triangle. Area constraints tend to diffuse as the mesh\n"); + printf( +" is refined, so if there are large variations in area constraint between\n"); + printf(" adjacent triangles, you may not get the results you want.\n\n"); + printf( +" If you are refining a mesh composed of linear (three-node) elements, the\n" +); + printf( +" output mesh will contain all the nodes present in the input mesh, in the\n" +); + printf( +" same order, with new nodes added at the end of the .node file. However,\n" +); + printf( +" there is no guarantee that each output element is contained in a single\n"); + printf( +" input element. Often, output elements will overlap two input elements,\n"); + printf( +" and input edges are not present in the output mesh. Hence, a sequence of\n" +); + printf( +" refined meshes will form a hierarchy of nodes, but not a hierarchy of\n"); + printf( +" elements. If you a refining a mesh of higher-order elements, the\n"); + printf( +" hierarchical property applies only to the nodes at the corners of an\n"); + printf(" element; other nodes may not be present in the refined mesh.\n\n"); + printf( +" It is important to understand that maximum area constraints in .poly\n"); + printf( +" files are handled differently from those in .area files. A maximum area\n" +); + printf( +" in a .poly file applies to the whole (segment-bounded) region in which a\n" +); + printf( +" point falls, whereas a maximum area in an .area file applies to only one\n" +); + printf( +" triangle. Area constraints in .poly files are used only when a mesh is\n"); + printf( +" first generated, whereas area constraints in .area files are used only to\n" +); + printf( +" refine an existing mesh, and are typically based on a posteriori error\n"); + printf( +" estimates resulting from a finite element simulation on that mesh.\n"); + printf("\n"); + printf( +" `triangle -rq25 object.1' will read object.1.node and object.1.ele, then\n" +); + printf( +" refine the triangulation to enforce a 25 degree minimum angle, and then\n"); + printf( +" write the refined triangulation to object.2.node and object.2.ele.\n"); + printf("\n"); + printf( +" `triangle -rpaa6.2 z.3' will read z.3.node, z.3.ele, z.3.poly, and\n"); + printf( +" z.3.area. After reconstructing the mesh and its segments, Triangle will\n" +); + printf( +" refine the mesh so that no triangle has area greater than 6.2, and\n"); + printf( +" furthermore the triangles satisfy the maximum area constraints in\n"); + printf( +" z.3.area. The output is written to z.4.node, z.4.ele, and z.4.poly.\n"); + printf("\n"); + printf( +" The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n"); + printf( +" x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n"); + printf(" suitable for multigrid.\n\n"); + printf("Convex Hulls and Mesh Boundaries:\n\n"); + printf( +" If the input is a point set (rather than a PSLG), Triangle produces its\n"); + printf( +" convex hull as a by-product in the output .poly file if you use the -c\n"); + printf( +" switch. There are faster algorithms for finding a two-dimensional convex\n" +); + printf( +" hull than triangulation, of course, but this one comes for free. If the\n" +); + printf( +" input is an unconstrained mesh (you are using the -r switch but not the\n"); + printf( +" -p switch), Triangle produces a list of its boundary edges (including\n"); + printf(" hole boundaries) as a by-product if you use the -c switch.\n\n"); + printf("Voronoi Diagrams:\n\n"); + printf( +" The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n"); + printf( +" .v.edge. For example, `triangle -v points' will read points.node,\n"); + printf( +" produce its Delaunay triangulation in points.1.node and points.1.ele,\n"); + printf( +" and produce its Voronoi diagram in points.1.v.node and points.1.v.edge.\n"); + printf( +" The .v.node file contains a list of all Voronoi vertices, and the .v.edge\n" +); + printf( +" file contains a list of all Voronoi edges, some of which may be infinite\n" +); + printf( +" rays. (The choice of filenames makes it easy to run the set of Voronoi\n"); + printf(" vertices through Triangle, if so desired.)\n\n"); + printf( +" This implementation does not use exact arithmetic to compute the Voronoi\n" +); + printf( +" vertices, and does not check whether neighboring vertices are identical.\n" +); + printf( +" Be forewarned that if the Delaunay triangulation is degenerate or\n"); + printf( +" near-degenerate, the Voronoi diagram may have duplicate points, crossing\n" +); + printf( +" edges, or infinite rays whose direction vector is zero. Also, if you\n"); + printf( +" generate a constrained (as opposed to conforming) Delaunay triangulation,\n" +); + printf( +" or if the triangulation has holes, the corresponding Voronoi diagram is\n"); + printf(" likely to have crossing edges and unlikely to make sense.\n\n"); + printf("Mesh Topology:\n\n"); + printf( +" You may wish to know which triangles are adjacent to a certain Delaunay\n"); + printf( +" edge in an .edge file, which Voronoi regions are adjacent to a certain\n"); + printf( +" Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to\n" +); + printf( +" each other. All of this information can be found by cross-referencing\n"); + printf( +" output files with the recollection that the Delaunay triangulation and\n"); + printf(" the Voronoi diagrams are planar duals.\n\n"); + printf( +" Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n"); + printf( +" the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n"); + printf( +" wise from the Voronoi edge. Triangle j of an .ele file is the dual of\n"); + printf( +" vertex j of the corresponding .v.node file; and Voronoi region k is the\n"); + printf(" dual of point k of the corresponding .node file.\n\n"); + printf( +" Hence, to find the triangles adjacent to a Delaunay edge, look at the\n"); + printf( +" vertices of the corresponding Voronoi edge; their dual triangles are on\n"); + printf( +" the left and right of the Delaunay edge, respectively. To find the\n"); + printf( +" Voronoi regions adjacent to a Voronoi edge, look at the endpoints of the\n" +); + printf( +" corresponding Delaunay edge; their dual regions are on the right and left\n" +); + printf( +" of the Voronoi edge, respectively. To find which Voronoi regions are\n"); + printf(" adjacent to each other, just read the list of Delaunay edges.\n"); + printf("\n"); + printf("Statistics:\n"); + printf("\n"); + printf( +" After generating a mesh, Triangle prints a count of the number of points,\n" +); + printf( +" triangles, edges, boundary edges, and segments in the output mesh. If\n"); + printf( +" you've forgotten the statistics for an existing mesh, the -rNEP switches\n" +); + printf( +" (or -rpNEP if you've got a .poly file for the existing mesh) will\n"); + printf(" regenerate these statistics without writing any output.\n\n"); + printf( +" The -V switch produces extended statistics, including a rough estimate\n"); + printf( +" of memory use and a histogram of triangle aspect ratios and angles in the\n" +); + printf(" mesh.\n\n"); + printf("Exact Arithmetic:\n\n"); + printf( +" Triangle uses adaptive exact arithmetic to perform what computational\n"); + printf( +" geometers call the `orientation' and `incircle' tests. If the floating-\n" +); + printf( +" point arithmetic of your machine conforms to the IEEE 754 standard (as\n"); + printf( +" most workstations do), and does not use extended precision internal\n"); + printf( +" registers, then your output is guaranteed to be an absolutely true\n"); + printf(" Delaunay or conforming Delaunay triangulation, roundoff error\n"); + printf( +" notwithstanding. The word `adaptive' implies that these arithmetic\n"); + printf( +" routines compute the result only to the precision necessary to guarantee\n" +); + printf( +" correctness, so they are usually nearly as fast as their approximate\n"); + printf( +" counterparts. The exact tests can be disabled with the -X switch. On\n"); + printf( +" most inputs, this switch will reduce the computation time by about eight\n" +); + printf( +" percent - it's not worth the risk. There are rare difficult inputs\n"); + printf( +" (having many collinear and cocircular points), however, for which the\n"); + printf( +" difference could be a factor of two. These are precisely the inputs most\n" +); + printf(" likely to cause errors if you use the -X switch.\n\n"); + printf( +" Unfortunately, these routines don't solve every numerical problem. Exact\n" +); + printf( +" arithmetic is not used to compute the positions of points, because the\n"); + printf( +" bit complexity of point coordinates would grow without bound. Hence,\n"); + printf( +" segment intersections aren't computed exactly; in very unusual cases,\n"); + printf( +" roundoff error in computing an intersection point might actually lead to\n" +); + printf( +" an inverted triangle and an invalid triangulation. (This is one reason\n"); + printf( +" to compute your own intersection points in your .poly files.) Similarly,\n" +); + printf( +" exact arithmetic is not used to compute the vertices of the Voronoi\n"); + printf(" diagram.\n\n"); + printf( +" Underflow and overflow can also cause difficulties; the exact arithmetic\n" +); + printf( +" routines do not ameliorate out-of-bounds exponents, which can arise\n"); + printf( +" during the orientation and incircle tests. As a rule of thumb, you\n"); + printf( +" should ensure that your input values are within a range such that their\n"); + printf( +" third powers can be taken without underflow or overflow. Underflow can\n"); + printf( +" silently prevent the tests from being performed exactly, while overflow\n"); + printf(" will typically cause a floating exception.\n\n"); + printf("Calling Triangle from Another Program:\n\n"); + printf(" Read the file triangle.h for details.\n\n"); + printf("Troubleshooting:\n\n"); + printf(" Please read this section before mailing me bugs.\n\n"); + printf(" `My output mesh has no triangles!'\n\n"); + printf( +" If you're using a PSLG, you've probably failed to specify a proper set\n" +); + printf( +" of bounding segments, or forgotten to use the -c switch. Or you may\n"); + printf( +" have placed a hole badly. To test these possibilities, try again with\n" +); + printf( +" the -c and -O switches. Alternatively, all your input points may be\n"); + printf( +" collinear, in which case you can hardly expect to triangulate them.\n"); + printf("\n"); + printf(" `Triangle doesn't terminate, or just crashes.'\n"); + printf("\n"); + printf( +" Bad things can happen when triangles get so small that the distance\n"); + printf( +" between their vertices isn't much larger than the precision of your\n"); + printf( +" machine's arithmetic. If you've compiled Triangle for single-precision\n" +); + printf( +" arithmetic, you might do better by recompiling it for double-precision.\n" +); + printf( +" Then again, you might just have to settle for more lenient constraints\n" +); + printf( +" on the minimum angle and the maximum area than you had planned.\n"); + printf("\n"); + printf( +" You can minimize precision problems by ensuring that the origin lies\n"); + printf( +" inside your point set, or even inside the densest part of your\n"); + printf( +" mesh. On the other hand, if you're triangulating an object whose x\n"); + printf( +" coordinates all fall between 6247133 and 6247134, you're not leaving\n"); + printf(" much floating-point precision for Triangle to work with.\n\n"); + printf( +" Precision problems can occur covertly if the input PSLG contains two\n"); + printf( +" segments that meet (or intersect) at a very small angle, or if such an\n" +); + printf( +" angle is introduced by the -c switch, which may occur if a point lies\n"); + printf( +" ever-so-slightly inside the convex hull, and is connected by a PSLG\n"); + printf( +" segment to a point on the convex hull. If you don't realize that a\n"); + printf( +" small angle is being formed, you might never discover why Triangle is\n"); + printf( +" crashing. To check for this possibility, use the -S switch (with an\n"); + printf( +" appropriate limit on the number of Steiner points, found by trial-and-\n" +); + printf( +" error) to stop Triangle early, and view the output .poly file with\n"); + printf( +" Show Me (described below). Look carefully for small angles between\n"); + printf( +" segments; zoom in closely, as such segments might look like a single\n"); + printf(" segment from a distance.\n\n"); + printf( +" If some of the input values are too large, Triangle may suffer a\n"); + printf( +" floating exception due to overflow when attempting to perform an\n"); + printf( +" orientation or incircle test. (Read the section on exact arithmetic\n"); + printf( +" above.) Again, I recommend compiling Triangle for double (rather\n"); + printf(" than single) precision arithmetic.\n\n"); + printf( +" `The numbering of the output points doesn't match the input points.'\n"); + printf("\n"); + printf( +" You may have eaten some of your input points with a hole, or by placing\n" +); + printf(" them outside the area enclosed by segments.\n\n"); + printf( +" `Triangle executes without incident, but when I look at the resulting\n"); + printf( +" mesh, it has overlapping triangles or other geometric inconsistencies.'\n"); + printf("\n"); + printf( +" If you select the -X switch, Triangle's divide-and-conquer Delaunay\n"); + printf( +" triangulation algorithm occasionally makes mistakes due to floating-\n"); + printf( +" point roundoff error. Although these errors are rare, don't use the -X\n" +); + printf(" switch. If you still have problems, please report the bug.\n"); + printf("\n"); + printf( +" Strange things can happen if you've taken liberties with your PSLG. Do\n"); + printf( +" you have a point lying in the middle of a segment? Triangle sometimes\n"); + printf( +" copes poorly with that sort of thing. Do you want to lay out a collinear\n" +); + printf( +" row of evenly spaced, segment-connected points? Have you simply defined\n" +); + printf( +" one long segment connecting the leftmost point to the rightmost point,\n"); + printf( +" and a bunch of points lying along it? This method occasionally works,\n"); + printf( +" especially with horizontal and vertical lines, but often it doesn't, and\n" +); + printf( +" you'll have to connect each adjacent pair of points with a separate\n"); + printf(" segment. If you don't like it, tough.\n\n"); + printf( +" Furthermore, if you have segments that intersect other than at their\n"); + printf( +" endpoints, try not to let the intersections fall extremely close to PSLG\n" +); + printf(" points or each other.\n\n"); + printf( +" If you have problems refining a triangulation not produced by Triangle:\n"); + printf( +" Are you sure the triangulation is geometrically valid? Is it formatted\n"); + printf( +" correctly for Triangle? Are the triangles all listed so the first three\n" +); + printf(" points are their corners in counterclockwise order?\n\n"); + printf("Show Me:\n\n"); + printf( +" Triangle comes with a separate program named `Show Me', whose primary\n"); + printf( +" purpose is to draw meshes on your screen or in PostScript. Its secondary\n" +); + printf( +" purpose is to check the validity of your input files, and do so more\n"); + printf( +" thoroughly than Triangle does. Show Me requires that you have the X\n"); + printf( +" Windows system. If you didn't receive Show Me with Triangle, complain to\n" +); + printf(" whomever you obtained Triangle from, then send me mail.\n\n"); + printf("Triangle on the Web:\n\n"); + printf( +" To see an illustrated, updated version of these instructions, check out\n"); + printf("\n"); + printf(" http://www.cs.cmu.edu/~quake/triangle.html\n"); + printf("\n"); + printf("A Brief Plea:\n"); + printf("\n"); + printf( +" If you use Triangle, and especially if you use it to accomplish real\n"); + printf( +" work, I would like very much to hear from you. A short letter or email\n"); + printf( +" (to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to\n"); + printf( +" me. The more people I know are using this program, the more easily I can\n" +); + printf( +" justify spending time on improvements and on the three-dimensional\n"); + printf( +" successor to Triangle, which in turn will benefit you. Also, I can put\n"); + printf( +" you on a list to receive email whenever a new version of Triangle is\n"); + printf(" available.\n\n"); + printf( +" If you use a mesh generated by Triangle in a publication, please include\n" +); + printf(" an acknowledgment as well.\n\n"); + printf("Research credit:\n\n"); + printf( +" Of course, I can take credit for only a fraction of the ideas that made\n"); + printf( +" this mesh generator possible. Triangle owes its existence to the efforts\n" +); + printf( +" of many fine computational geometers and other researchers, including\n"); + printf( +" Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David\n"); + printf( +" Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, C. L.\n"); + printf( +" Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,\n"); + printf( +" Isaac Saias, Bruce J. Schachter, Micha Sharir, Jorge Stolfi, Christopher\n" +); + printf( +" J. Van Wyk, David F. Watson, and Binhai Zhu. See the comments at the\n"); + printf(" beginning of the source code for references.\n\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* internalerror() Ask the user to send me the defective product. Exit. */ +/* */ +/*****************************************************************************/ + +void internalerror() +{ + printf(" Please report this bug to jrs@cs.cmu.edu\n"); + printf(" Include the message above, your input data set, and the exact\n"); + printf(" command line you used to run Triangle.\n"); + exit(1); +} + +/*****************************************************************************/ +/* */ +/* parsecommandline() Read the command line, identify switches, and set */ +/* up options and file names. */ +/* */ +/* The effects of this routine are felt entirely through global variables. */ +/* */ +/*****************************************************************************/ + +void parsecommandline(argc, argv) +int argc; +char **argv; +{ +#ifdef TRILIBRARY +#define STARTINDEX 0 +#else /* not TRILIBRARY */ +#define STARTINDEX 1 + int increment; + int meshnumber; +#endif /* not TRILIBRARY */ + int i, j; +#ifndef CDT_ONLY + int k; + char workstring[FILENAMESIZE]; +#endif + + poly = refine = quality = vararea = fixedarea = regionattrib = convex = 0; + firstnumber = 1; + edgesout = voronoi = neighbors = geomview = 0; + nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0; + noholes = noexact = 0; + incremental = sweepline = 0; + dwyer = 1; + splitseg = 0; + docheck = 0; + nobisect = 0; + steiner = -1; + order = 1; + minangle = 0.0; + maxarea = -1.0; + quiet = verbose = 0; +#ifndef TRILIBRARY + innodefilename[0] = '\0'; +#endif /* not TRILIBRARY */ + + for (i = STARTINDEX; i < argc; i++) { +#ifndef TRILIBRARY + if (argv[i][0] == '-') { +#endif /* not TRILIBRARY */ + for (j = STARTINDEX; argv[i][j] != '\0'; j++) { + if (argv[i][j] == 'p') { + poly = 1; + } +#ifndef CDT_ONLY + if (argv[i][j] == 'r') { + refine = 1; + } + if (argv[i][j] == 'q') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + minangle = (REAL) strtod(workstring, (char **) NULL); + } else { + minangle = 20.0; + } + } + if (argv[i][j] == 'a') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + fixedarea = 1; + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + maxarea = (REAL) strtod(workstring, (char **) NULL); + if (maxarea <= 0.0) { + printf("Error: Maximum area must be greater than zero.\n"); + exit(1); + } + } else { + vararea = 1; + } + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'A') { + regionattrib = 1; + } + if (argv[i][j] == 'c') { + convex = 1; + } + if (argv[i][j] == 'z') { + firstnumber = 0; + } + if (argv[i][j] == 'e') { + edgesout = 1; + } + if (argv[i][j] == 'v') { + voronoi = 1; + } + if (argv[i][j] == 'n') { + neighbors = 1; + } + if (argv[i][j] == 'g') { + geomview = 1; + } + if (argv[i][j] == 'B') { + nobound = 1; + } + if (argv[i][j] == 'P') { + nopolywritten = 1; + } + if (argv[i][j] == 'N') { + nonodewritten = 1; + } + if (argv[i][j] == 'E') { + noelewritten = 1; + } +#ifndef TRILIBRARY + if (argv[i][j] == 'I') { + noiterationnum = 1; + } +#endif /* not TRILIBRARY */ + if (argv[i][j] == 'O') { + noholes = 1; + } + if (argv[i][j] == 'X') { + noexact = 1; + } + if (argv[i][j] == 'o') { + if (argv[i][j + 1] == '2') { + j++; + order = 2; + } + } +#ifndef CDT_ONLY + if (argv[i][j] == 'Y') { + nobisect++; + } + if (argv[i][j] == 'S') { + steiner = 0; + while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + j++; + steiner = steiner * 10 + (int) (argv[i][j] - '0'); + } + } +#endif /* not CDT_ONLY */ +#ifndef REDUCED + if (argv[i][j] == 'i') { + incremental = 1; + } + if (argv[i][j] == 'F') { + sweepline = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'l') { + dwyer = 0; + } +#ifndef REDUCED +#ifndef CDT_ONLY + if (argv[i][j] == 's') { + splitseg = 1; + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'C') { + docheck = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'Q') { + quiet = 1; + } + if (argv[i][j] == 'V') { + verbose++; + } +#ifndef TRILIBRARY + if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || + (argv[i][j] == '?')) { + info(); + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + } else { + strncpy(innodefilename, argv[i], FILENAMESIZE - 1); + innodefilename[FILENAMESIZE - 1] = '\0'; + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + if (innodefilename[0] == '\0') { + syntax(); + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".node")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".poly")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + poly = 1; + } +#ifndef CDT_ONLY + if (!strcmp(&innodefilename[strlen(innodefilename) - 4], ".ele")) { + innodefilename[strlen(innodefilename) - 4] = '\0'; + refine = 1; + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".area")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + refine = 1; + quality = 1; + vararea = 1; + } +#endif /* not CDT_ONLY */ +#endif /* not TRILIBRARY */ + steinerleft = steiner; + useshelles = poly || refine || quality || convex; + goodangle = (REAL)cos(minangle * PI / 180.0); + goodangle *= goodangle; + if (refine && noiterationnum) { + printf( + "Error: You cannot use the -I switch when refining a triangulation.\n"); + exit(1); + } + /* Be careful not to allocate space for element area constraints that */ + /* will never be assigned any value (other than the default -1.0). */ + if (!refine && !poly) { + vararea = 0; + } + /* Be careful not to add an extra attribute to each element unless the */ + /* input supports it (PSLG in, but not refining a preexisting mesh). */ + if (refine || !poly) { + regionattrib = 0; + } + +#ifndef TRILIBRARY + strcpy(inpolyfilename, innodefilename); + strcpy(inelefilename, innodefilename); + strcpy(areafilename, innodefilename); + increment = 0; + strcpy(workstring, innodefilename); + j = 1; + while (workstring[j] != '\0') { + if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { + increment = j + 1; + } + j++; + } + meshnumber = 0; + if (increment > 0) { + j = increment; + do { + if ((workstring[j] >= '0') && (workstring[j] <= '9')) { + meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); + } else { + increment = 0; + } + j++; + } while (workstring[j] != '\0'); + } + if (noiterationnum) { + strcpy(outnodefilename, innodefilename); + strcpy(outelefilename, innodefilename); + strcpy(edgefilename, innodefilename); + strcpy(vnodefilename, innodefilename); + strcpy(vedgefilename, innodefilename); + strcpy(neighborfilename, innodefilename); + strcpy(offfilename, innodefilename); + strcat(outnodefilename, ".node"); + strcat(outelefilename, ".ele"); + strcat(edgefilename, ".edge"); + strcat(vnodefilename, ".v.node"); + strcat(vedgefilename, ".v.edge"); + strcat(neighborfilename, ".neigh"); + strcat(offfilename, ".off"); + } else if (increment == 0) { + strcpy(outnodefilename, innodefilename); + strcpy(outpolyfilename, innodefilename); + strcpy(outelefilename, innodefilename); + strcpy(edgefilename, innodefilename); + strcpy(vnodefilename, innodefilename); + strcpy(vedgefilename, innodefilename); + strcpy(neighborfilename, innodefilename); + strcpy(offfilename, innodefilename); + strcat(outnodefilename, ".1.node"); + strcat(outpolyfilename, ".1.poly"); + strcat(outelefilename, ".1.ele"); + strcat(edgefilename, ".1.edge"); + strcat(vnodefilename, ".1.v.node"); + strcat(vedgefilename, ".1.v.edge"); + strcat(neighborfilename, ".1.neigh"); + strcat(offfilename, ".1.off"); + } else { + workstring[increment] = '%'; + workstring[increment + 1] = 'd'; + workstring[increment + 2] = '\0'; + sprintf(outnodefilename, workstring, meshnumber + 1); + strcpy(outpolyfilename, outnodefilename); + strcpy(outelefilename, outnodefilename); + strcpy(edgefilename, outnodefilename); + strcpy(vnodefilename, outnodefilename); + strcpy(vedgefilename, outnodefilename); + strcpy(neighborfilename, outnodefilename); + strcpy(offfilename, outnodefilename); + strcat(outnodefilename, ".node"); + strcat(outpolyfilename, ".poly"); + strcat(outelefilename, ".ele"); + strcat(edgefilename, ".edge"); + strcat(vnodefilename, ".v.node"); + strcat(vedgefilename, ".v.edge"); + strcat(neighborfilename, ".neigh"); + strcat(offfilename, ".off"); + } + strcat(innodefilename, ".node"); + strcat(inpolyfilename, ".poly"); + strcat(inelefilename, ".ele"); + strcat(areafilename, ".area"); +#endif /* not TRILIBRARY */ +} + +/** **/ +/** **/ +/********* User interaction routines begin here *********/ + +/********* Debugging routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* printtriangle() Print out the details of a triangle/edge handle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about a */ +/* triangle/edge handle in digestible form. It's also used when the */ +/* highest level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +void printtriangle(t) +struct triedge *t; +{ + struct triedge printtri; + struct edge printsh; + point printpoint; + + printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, + t->orient); + decode(t->tri[0], printtri); + if (printtri.tri == dummytri) { + printf(" [0] = Outer space\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[1], printtri); + if (printtri.tri == dummytri) { + printf(" [1] = Outer space\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[2], printtri); + if (printtri.tri == dummytri) { + printf(" [2] = Outer space\n"); + } else { + printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + org(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 1) % 3 + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + dest(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 2) % 3 + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + apex(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Apex [%d] = NULL\n", t->orient + 3); + else + printf(" Apex [%d] = x%lx (%.12g, %.12g)\n", + t->orient + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + if (useshelles) { + sdecode(t->tri[6], printsh); + if (printsh.sh != dummysh) { + printf(" [6] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(t->tri[7], printsh); + if (printsh.sh != dummysh) { + printf(" [7] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(t->tri[8], printsh); + if (printsh.sh != dummysh) { + printf(" [8] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + } + if (vararea) { + printf(" Area constraint: %.4g\n", areabound(*t)); + } +} + +/*****************************************************************************/ +/* */ +/* printshelle() Print out the details of a shell edge handle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about a */ +/* shell edge handle in digestible form. It's also used when the highest */ +/* level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +void printshelle(s) +struct edge *s; +{ + struct edge printsh; + struct triedge printtri; + point printpoint; + + printf("shell edge x%lx with orientation %d and mark %d:\n", + (unsigned long) s->sh, s->shorient, mark(*s)); + sdecode(s->sh[0], printsh); + if (printsh.sh == dummysh) { + printf(" [0] = No shell\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(s->sh[1], printsh); + if (printsh.sh == dummysh) { + printf(" [1] = No shell\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sorg(*s, printpoint); + if (printpoint == (point) NULL) + printf(" Origin[%d] = NULL\n", 2 + s->shorient); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + 2 + s->shorient, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + sdest(*s, printpoint); + if (printpoint == (point) NULL) + printf(" Dest [%d] = NULL\n", 3 - s->shorient); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + 3 - s->shorient, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + decode(s->sh[4], printtri); + if (printtri.tri == dummytri) { + printf(" [4] = Outer space\n"); + } else { + printf(" [4] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(s->sh[5], printtri); + if (printtri.tri == dummytri) { + printf(" [5] = Outer space\n"); + } else { + printf(" [5] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } +} + +/** **/ +/** **/ +/********* Debugging routines end here *********/ + +/********* Memory management routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* poolinit() Initialize a pool of memory for allocation of items. */ +/* */ +/* This routine initializes the machinery for allocating items. A `pool' */ +/* is created whose records have size at least `bytecount'. Items will be */ +/* allocated in `itemcount'-item blocks. Each item is assumed to be a */ +/* collection of words, and either pointers or floating-point values are */ +/* assumed to be the "primary" word type. (The "primary" word type is used */ +/* to determine alignment of items.) If `alignment' isn't zero, all items */ +/* will be `alignment'-byte aligned in memory. `alignment' must be either */ +/* a multiple or a factor of the primary word size; powers of two are safe. */ +/* `alignment' is normally used to create a few unused bits at the bottom */ +/* of each item's pointer, in which information may be stored. */ +/* */ +/* Don't change this routine unless you understand it. */ +/* */ +/*****************************************************************************/ + +void poolinit(pool, bytecount, itemcount, wtype, alignment) +struct memorypool *pool; +int bytecount; +int itemcount; +enum wordtype wtype; +int alignment; +{ + int wordsize; + + /* Initialize values in the pool. */ + pool->itemwordtype = wtype; + wordsize = (pool->itemwordtype == POINTER) ? sizeof(VOID *) : sizeof(REAL); + /* Find the proper alignment, which must be at least as large as: */ + /* - The parameter `alignment'. */ + /* - The primary word type, to avoid unaligned accesses. */ + /* - sizeof(VOID *), so the stack of dead items can be maintained */ + /* without unaligned accesses. */ + if (alignment > wordsize) { + pool->alignbytes = alignment; + } else { + pool->alignbytes = wordsize; + } + if (sizeof(VOID *) > pool->alignbytes) { + pool->alignbytes = sizeof(VOID *); + } + pool->itemwords = ((bytecount + pool->alignbytes - 1) / pool->alignbytes) + * (pool->alignbytes / wordsize); + pool->itembytes = pool->itemwords * wordsize; + pool->itemsperblock = itemcount; + + /* Allocate a block of items. Space for `itemsperblock' items and one */ + /* pointer (to point to the next block) are allocated, as well as space */ + /* to ensure alignment of the items. */ + pool->firstblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes + + sizeof(VOID *) + pool->alignbytes); + if (pool->firstblock == (VOID **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Set the next block pointer to NULL. */ + *(pool->firstblock) = (VOID *) NULL; + poolrestart(pool); +} + +/*****************************************************************************/ +/* */ +/* poolrestart() Deallocate all items in a pool. */ +/* */ +/* The pool is returned to its starting state, except that no memory is */ +/* freed to the operating system. Rather, the previously allocated blocks */ +/* are ready to be reused. */ +/* */ +/*****************************************************************************/ + +void poolrestart(pool) +struct memorypool *pool; +{ + unsigned long alignptr; + + pool->items = 0; + pool->maxitems = 0; + + /* Set the currently active block. */ + pool->nowblock = pool->firstblock; + /* Find the first item in the pool. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + /* The stack of deallocated items is empty. */ + pool->deaditemstack = (VOID *) NULL; +} + +/*****************************************************************************/ +/* */ +/* pooldeinit() Free to the operating system all memory taken by a pool. */ +/* */ +/*****************************************************************************/ + +void pooldeinit(pool) +struct memorypool *pool; +{ + while (pool->firstblock != (VOID **) NULL) { + pool->nowblock = (VOID **) *(pool->firstblock); + free(pool->firstblock); + pool->firstblock = pool->nowblock; + } +} + +/*****************************************************************************/ +/* */ +/* poolalloc() Allocate space for an item. */ +/* */ +/*****************************************************************************/ + +VOID *poolalloc(pool) +struct memorypool *pool; +{ + VOID *newitem; + VOID **newblock; + unsigned long alignptr; + + /* First check the linked list of dead items. If the list is not */ + /* empty, allocate an item from the list rather than a fresh one. */ + if (pool->deaditemstack != (VOID *) NULL) { + newitem = pool->deaditemstack; /* Take first item in list. */ + pool->deaditemstack = * (VOID **) pool->deaditemstack; + } else { + /* Check if there are any free items left in the current block. */ + if (pool->unallocateditems == 0) { + /* Check if another block must be allocated. */ + if (*(pool->nowblock) == (VOID *) NULL) { + /* Allocate a new block of items, pointed to by the previous block. */ + newblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes + + sizeof(VOID *) + pool->alignbytes); + if (newblock == (VOID **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *(pool->nowblock) = (VOID *) newblock; + /* The next block pointer is NULL. */ + *newblock = (VOID *) NULL; + } + /* Move to the new block. */ + pool->nowblock = (VOID **) *(pool->nowblock); + /* Find the first item in the block. */ + /* Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + } + /* Allocate a new item. */ + newitem = pool->nextitem; + /* Advance `nextitem' pointer to next free item in block. */ + if (pool->itemwordtype == POINTER) { + pool->nextitem = (VOID *) ((VOID **) pool->nextitem + pool->itemwords); + } else { + pool->nextitem = (VOID *) ((REAL *) pool->nextitem + pool->itemwords); + } + pool->unallocateditems--; + pool->maxitems++; + } + pool->items++; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* pooldealloc() Deallocate space for an item. */ +/* */ +/* The deallocated space is stored in a queue for later reuse. */ +/* */ +/*****************************************************************************/ + +void pooldealloc(pool, dyingitem) +struct memorypool *pool; +VOID *dyingitem; +{ + /* Push freshly killed item onto stack. */ + *((VOID **) dyingitem) = pool->deaditemstack; + pool->deaditemstack = dyingitem; + pool->items--; +} + +/*****************************************************************************/ +/* */ +/* traversalinit() Prepare to traverse the entire list of items. */ +/* */ +/* This routine is used in conjunction with traverse(). */ +/* */ +/*****************************************************************************/ + +void traversalinit(pool) +struct memorypool *pool; +{ + unsigned long alignptr; + + /* Begin the traversal in the first block. */ + pool->pathblock = pool->firstblock; + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; +} + +/*****************************************************************************/ +/* */ +/* traverse() Find the next item in the list. */ +/* */ +/* This routine is used in conjunction with traversalinit(). Be forewarned */ +/* that this routine successively returns all items in the list, including */ +/* deallocated ones on the deaditemqueue. It's up to you to figure out */ +/* which ones are actually dead. Why? I don't want to allocate extra */ +/* space just to demarcate dead items. It can usually be done more */ +/* space-efficiently by a routine that knows something about the structure */ +/* of the item. */ +/* */ +/*****************************************************************************/ + +VOID *traverse(pool) +struct memorypool *pool; +{ + VOID *newitem; + unsigned long alignptr; + + /* Stop upon exhausting the list of items. */ + if (pool->pathitem == pool->nextitem) { + return (VOID *) NULL; + } + /* Check whether any untraversed items remain in the current block. */ + if (pool->pathitemsleft == 0) { + /* Find the next block. */ + pool->pathblock = (VOID **) *(pool->pathblock); + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; + } + newitem = pool->pathitem; + /* Find the next item in the block. */ + if (pool->itemwordtype == POINTER) { + pool->pathitem = (VOID *) ((VOID **) pool->pathitem + pool->itemwords); + } else { + pool->pathitem = (VOID *) ((REAL *) pool->pathitem + pool->itemwords); + } + pool->pathitemsleft--; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* dummyinit() Initialize the triangle that fills "outer space" and the */ +/* omnipresent shell edge. */ +/* */ +/* The triangle that fills "outer space", called `dummytri', is pointed to */ +/* by every triangle and shell edge on a boundary (be it outer or inner) of */ +/* the triangulation. Also, `dummytri' points to one of the triangles on */ +/* the convex hull (until the holes and concavities are carved), making it */ +/* possible to find a starting triangle for point location. */ +/* */ +/* The omnipresent shell edge, `dummysh', is pointed to by every triangle */ +/* or shell edge that doesn't have a full complement of real shell edges */ +/* to point to. */ +/* */ +/*****************************************************************************/ + +void dummyinit(trianglewords, shellewords) +int trianglewords; +int shellewords; +{ + unsigned long alignptr; + + /* `triwords' and `shwords' are used by the mesh manipulation primitives */ + /* to extract orientations of triangles and shell edges from pointers. */ + triwords = trianglewords; /* Initialize `triwords' once and for all. */ + shwords = shellewords; /* Initialize `shwords' once and for all. */ + + /* Set up `dummytri', the `triangle' that occupies "outer space". */ + dummytribase = (triangle *) malloc(triwords * sizeof(triangle) + + triangles.alignbytes); + if (dummytribase == (triangle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) dummytribase; + dummytri = (triangle *) + (alignptr + (unsigned long) triangles.alignbytes + - (alignptr % (unsigned long) triangles.alignbytes)); + /* Initialize the three adjoining triangles to be "outer space". These */ + /* will eventually be changed by various bonding operations, but their */ + /* values don't really matter, as long as they can legally be */ + /* dereferenced. */ + dummytri[0] = (triangle) dummytri; + dummytri[1] = (triangle) dummytri; + dummytri[2] = (triangle) dummytri; + /* Three NULL vertex points. */ + dummytri[3] = (triangle) NULL; + dummytri[4] = (triangle) NULL; + dummytri[5] = (triangle) NULL; + + if (useshelles) { + /* Set up `dummysh', the omnipresent "shell edge" pointed to by any */ + /* triangle side or shell edge end that isn't attached to a real shell */ + /* edge. */ + dummyshbase = (shelle *) malloc(shwords * sizeof(shelle) + + shelles.alignbytes); + if (dummyshbase == (shelle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Align `dummysh' on a `shelles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) dummyshbase; + dummysh = (shelle *) + (alignptr + (unsigned long) shelles.alignbytes + - (alignptr % (unsigned long) shelles.alignbytes)); + /* Initialize the two adjoining shell edges to be the omnipresent shell */ + /* edge. These will eventually be changed by various bonding */ + /* operations, but their values don't really matter, as long as they */ + /* can legally be dereferenced. */ + dummysh[0] = (shelle) dummysh; + dummysh[1] = (shelle) dummysh; + /* Two NULL vertex points. */ + dummysh[2] = (shelle) NULL; + dummysh[3] = (shelle) NULL; + /* Initialize the two adjoining triangles to be "outer space". */ + dummysh[4] = (shelle) dummytri; + dummysh[5] = (shelle) dummytri; + /* Set the boundary marker to zero. */ + * (int *) (dummysh + 6) = 0; + + /* Initialize the three adjoining shell edges of `dummytri' to be */ + /* the omnipresent shell edge. */ + dummytri[6] = (triangle) dummysh; + dummytri[7] = (triangle) dummysh; + dummytri[8] = (triangle) dummysh; + } +} + +/*****************************************************************************/ +/* */ +/* initializepointpool() Calculate the size of the point data structure */ +/* and initialize its memory pool. */ +/* */ +/* This routine also computes the `pointmarkindex' and `point2triindex' */ +/* indices used to find values within each point. */ +/* */ +/*****************************************************************************/ + +void initializepointpool() +{ + int pointsize; + + /* The index within each point at which the boundary marker is found. */ + /* Ensure the point marker is aligned to a sizeof(int)-byte address. */ + pointmarkindex = ((mesh_dim + nextras) * sizeof(REAL) + sizeof(int) - 1) + / sizeof(int); + pointsize = (pointmarkindex + 1) * sizeof(int); + if (poly) { + /* The index within each point at which a triangle pointer is found. */ + /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */ + point2triindex = (pointsize + sizeof(triangle) - 1) / sizeof(triangle); + pointsize = (point2triindex + 1) * sizeof(triangle); + } + /* Initialize the pool of points. */ + poolinit(&points, pointsize, POINTPERBLOCK, + (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0); +} + +/*****************************************************************************/ +/* */ +/* initializetrisegpools() Calculate the sizes of the triangle and shell */ +/* edge data structures and initialize their */ +/* memory pools. */ +/* */ +/* This routine also computes the `highorderindex', `elemattribindex', and */ +/* `areaboundindex' indices used to find values within each triangle. */ +/* */ +/*****************************************************************************/ + +void initializetrisegpools() +{ + int trisize; + + /* The index within each triangle at which the extra nodes (above three) */ + /* associated with high order elements are found. There are three */ + /* pointers to other triangles, three pointers to corners, and possibly */ + /* three pointers to shell edges before the extra nodes. */ + highorderindex = 6 + (useshelles * 3); + /* The number of bytes occupied by a triangle. */ + trisize = ((order + 1) * (order + 2) / 2 + (highorderindex - 3)) * + sizeof(triangle); + /* The index within each triangle at which its attributes are found, */ + /* where the index is measured in REALs. */ + elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL); + /* The index within each triangle at which the maximum area constraint */ + /* is found, where the index is measured in REALs. Note that if the */ + /* `regionattrib' flag is set, an additional attribute will be added. */ + areaboundindex = elemattribindex + eextras + regionattrib; + /* If triangle attributes or an area bound are needed, increase the number */ + /* of bytes occupied by a triangle. */ + if (vararea) { + trisize = (areaboundindex + 1) * sizeof(REAL); + } else if (eextras + regionattrib > 0) { + trisize = areaboundindex * sizeof(REAL); + } + /* If a Voronoi diagram or triangle neighbor graph is requested, make */ + /* sure there's room to store an integer index in each triangle. This */ + /* integer index can occupy the same space as the shell edges or */ + /* attributes or area constraint or extra nodes. */ + if ((voronoi || neighbors) && + (trisize < 6 * sizeof(triangle) + sizeof(int))) { + trisize = 6 * sizeof(triangle) + sizeof(int); + } + /* Having determined the memory size of a triangle, initialize the pool. */ + poolinit(&triangles, trisize, TRIPERBLOCK, POINTER, 4); + + if (useshelles) { + /* Initialize the pool of shell edges. */ + poolinit(&shelles, 6 * sizeof(triangle) + sizeof(int), SHELLEPERBLOCK, + POINTER, 4); + + /* Initialize the "outer space" triangle and omnipresent shell edge. */ + dummyinit(triangles.itemwords, shelles.itemwords); + } else { + /* Initialize the "outer space" triangle. */ + dummyinit(triangles.itemwords, 0); + } +} + +/*****************************************************************************/ +/* */ +/* triangledealloc() Deallocate space for a triangle, marking it dead. */ +/* */ +/*****************************************************************************/ + +void triangledealloc(dyingtriangle) +triangle *dyingtriangle; +{ + /* Set triangle's vertices to NULL. This makes it possible to */ + /* detect dead triangles when traversing the list of all triangles. */ + dyingtriangle[3] = (triangle) NULL; + dyingtriangle[4] = (triangle) NULL; + dyingtriangle[5] = (triangle) NULL; + pooldealloc(&triangles, (VOID *) dyingtriangle); +} + +/*****************************************************************************/ +/* */ +/* triangletraverse() Traverse the triangles, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +triangle *triangletraverse() +{ + triangle *newtriangle; + + do { + newtriangle = (triangle *) traverse(&triangles); + if (newtriangle == (triangle *) NULL) { + return (triangle *) NULL; + } + } while (newtriangle[3] == (triangle) NULL); /* Skip dead ones. */ + return newtriangle; +} + +/*****************************************************************************/ +/* */ +/* shelledealloc() Deallocate space for a shell edge, marking it dead. */ +/* */ +/*****************************************************************************/ + +void shelledealloc(dyingshelle) +shelle *dyingshelle; +{ + /* Set shell edge's vertices to NULL. This makes it possible to */ + /* detect dead shells when traversing the list of all shells. */ + dyingshelle[2] = (shelle) NULL; + dyingshelle[3] = (shelle) NULL; + pooldealloc(&shelles, (VOID *) dyingshelle); +} + +/*****************************************************************************/ +/* */ +/* shelletraverse() Traverse the shell edges, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +shelle *shelletraverse() +{ + shelle *newshelle; + + do { + newshelle = (shelle *) traverse(&shelles); + if (newshelle == (shelle *) NULL) { + return (shelle *) NULL; + } + } while (newshelle[2] == (shelle) NULL); /* Skip dead ones. */ + return newshelle; +} + +/*****************************************************************************/ +/* */ +/* pointdealloc() Deallocate space for a point, marking it dead. */ +/* */ +/*****************************************************************************/ + +void pointdealloc(dyingpoint) +point dyingpoint; +{ + /* Mark the point as dead. This makes it possible to detect dead points */ + /* when traversing the list of all points. */ + setpointmark(dyingpoint, DEADPOINT); + pooldealloc(&points, (VOID *) dyingpoint); +} + +/*****************************************************************************/ +/* */ +/* pointtraverse() Traverse the points, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +point pointtraverse() +{ + point newpoint; + + do { + newpoint = (point) traverse(&points); + if (newpoint == (point) NULL) { + return (point) NULL; + } + } while (pointmark(newpoint) == DEADPOINT); /* Skip dead ones. */ + return newpoint; +} + +/*****************************************************************************/ +/* */ +/* badsegmentdealloc() Deallocate space for a bad segment, marking it */ +/* dead. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void badsegmentdealloc(dyingseg) +struct edge *dyingseg; +{ + /* Set segment's orientation to -1. This makes it possible to */ + /* detect dead segments when traversing the list of all segments. */ + dyingseg->shorient = -1; + pooldealloc(&badsegments, (VOID *) dyingseg); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* badsegmenttraverse() Traverse the bad segments, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +struct edge *badsegmenttraverse() +{ + struct edge *newseg; + + do { + newseg = (struct edge *) traverse(&badsegments); + if (newseg == (struct edge *) NULL) { + return (struct edge *) NULL; + } + } while (newseg->shorient == -1); /* Skip dead ones. */ + return newseg; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* getpoint() Get a specific point, by number, from the list. */ +/* */ +/* The first point is number 'firstnumber'. */ +/* */ +/* Note that this takes O(n) time (with a small constant, if POINTPERBLOCK */ +/* is large). I don't care to take the trouble to make it work in constant */ +/* time. */ +/* */ +/*****************************************************************************/ + +point getpoint(number) +int number; +{ + VOID **getblock; + point foundpoint; + unsigned long alignptr; + int current; + + getblock = points.firstblock; + current = firstnumber; + /* Find the right block. */ + while (current + points.itemsperblock <= number) { + getblock = (VOID **) *getblock; + current += points.itemsperblock; + } + /* Now find the right point. */ + alignptr = (unsigned long) (getblock + 1); + foundpoint = (point) (alignptr + (unsigned long) points.alignbytes + - (alignptr % (unsigned long) points.alignbytes)); + while (current < number) { + foundpoint += points.itemwords; + current++; + } + return foundpoint; +} + +/*****************************************************************************/ +/* */ +/* triangledeinit() Free all remaining allocated memory. */ +/* */ +/*****************************************************************************/ + +void triangledeinit() +{ + pooldeinit(&triangles); + free(dummytribase); + if (useshelles) { + pooldeinit(&shelles); + free(dummyshbase); + } + pooldeinit(&points); +#ifndef CDT_ONLY + if (quality) { + pooldeinit(&badsegments); + if ((minangle > 0.0) || vararea || fixedarea) { + pooldeinit(&badtriangles); + } + } +#endif /* not CDT_ONLY */ +} + +/** **/ +/** **/ +/********* Memory management routines end here *********/ + +/********* Constructors begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* maketriangle() Create a new triangle with orientation zero. */ +/* */ +/*****************************************************************************/ + +void maketriangle(newtriedge) +struct triedge *newtriedge; +{ + int i; + + newtriedge->tri = (triangle *) poolalloc(&triangles); + /* Initialize the three adjoining triangles to be "outer space". */ + newtriedge->tri[0] = (triangle) dummytri; + newtriedge->tri[1] = (triangle) dummytri; + newtriedge->tri[2] = (triangle) dummytri; + /* Three NULL vertex points. */ + newtriedge->tri[3] = (triangle) NULL; + newtriedge->tri[4] = (triangle) NULL; + newtriedge->tri[5] = (triangle) NULL; + /* Initialize the three adjoining shell edges to be the omnipresent */ + /* shell edge. */ + if (useshelles) { + newtriedge->tri[6] = (triangle) dummysh; + newtriedge->tri[7] = (triangle) dummysh; + newtriedge->tri[8] = (triangle) dummysh; + } + for (i = 0; i < eextras; i++) { + setelemattribute(*newtriedge, i, 0.0); + } + if (vararea) { + setareabound(*newtriedge, -1.0); + } + + newtriedge->orient = 0; +} + +/*****************************************************************************/ +/* */ +/* makeshelle() Create a new shell edge with orientation zero. */ +/* */ +/*****************************************************************************/ + +void makeshelle(newedge) +struct edge *newedge; +{ + newedge->sh = (shelle *) poolalloc(&shelles); + /* Initialize the two adjoining shell edges to be the omnipresent */ + /* shell edge. */ + newedge->sh[0] = (shelle) dummysh; + newedge->sh[1] = (shelle) dummysh; + /* Two NULL vertex points. */ + newedge->sh[2] = (shelle) NULL; + newedge->sh[3] = (shelle) NULL; + /* Initialize the two adjoining triangles to be "outer space". */ + newedge->sh[4] = (shelle) dummytri; + newedge->sh[5] = (shelle) dummytri; + /* Set the boundary marker to zero. */ + setmark(*newedge, 0); + + newedge->shorient = 0; +} + +/** **/ +/** **/ +/********* Constructors end here *********/ + +/********* Determinant evaluation routines begin here *********/ +/** **/ +/** **/ + +/* The adaptive exact arithmetic geometric predicates implemented herein are */ +/* described in detail in my Technical Report CMU-CS-96-140. The complete */ +/* reference is given in the header. */ + +/* Which of the following two methods of finding the absolute values is */ +/* fastest is compiler-dependent. A few compilers can inline and optimize */ +/* the fabs() call; but most will incur the overhead of a function call, */ +/* which is disastrously slow. A faster way on IEEE machines might be to */ +/* mask the appropriate bit, but that's difficult to do in C. */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that */ +/* performs an approximate operation, and a "tail" that computes the */ +/* roundoff error of that operation. */ +/* */ +/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ +/* Split(), and Two_Product() are all implemented as described in the */ +/* reference. Each of these macros requires certain variables to be */ +/* defined in the calling routine. The variables `bvirt', `c', `abig', */ +/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ +/* they store the result of an operation that may incur roundoff error. */ +/* The input parameter `x' (or the highest numbered `x_' parameter) must */ +/* also be declared `INEXACT'. */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (REAL) (x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (REAL) (a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (REAL) (splitter * a); \ + abig = (REAL) (c - a); \ + ahi = (REAL)(c - abig); \ + alo = (REAL)(a - ahi) + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (REAL) (a * b); \ + Two_Product_Tail(a, b, x, y) + +/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Square() can be done more quickly than Two_Product(). */ + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (REAL) (a * a); \ + Square_Tail(a, x, y) + +/* Macros for summing expansions of various fixed lengths. These are all */ +/* unrolled versions of Expansion_Sum(). */ + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b , _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b , _i, x0); \ + Two_Sum( a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +/*****************************************************************************/ +/* */ +/* exactinit() Initialize the variables used for exact arithmetic. */ +/* */ +/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ +/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ +/* error. It is used for floating-point error analysis. */ +/* */ +/* `splitter' is used to split floating-point numbers into two half- */ +/* length significands for exact multiplication. */ +/* */ +/* I imagine that a highly optimizing compiler might be too smart for its */ +/* own good, and somehow cause this routine to fail, if it pretends that */ +/* floating-point arithmetic is too much like real arithmetic. */ +/* */ +/* Don't change this routine unless you fully understand it. */ +/* */ +/*****************************************************************************/ + +void exactinit() +{ + REAL half; + REAL check, lastcheck; + int every_other; + + every_other = 1; + half = 0.5; + epsilon = 1.0; + splitter = 1.0; + check = 1.0; + /* Repeatedly divide `epsilon' by two until it is too small to add to */ + /* one without causing roundoff. (Also check if the sum is equal to */ + /* the previous sum, for machines that round up instead of using exact */ + /* rounding. Not that these routines will work on such machines anyway. */ + do { + lastcheck = check; + epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = (REAL)(1.0 + epsilon); + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + if (verbose > 1) { + printf("Floating point roundoff is of magnitude %.17g\n", epsilon); + printf("Floating point splitter is %.17g\n", splitter); + } + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (REAL)((3.0 + 8.0 * epsilon) * epsilon); + ccwerrboundA = (REAL)((3.0 + 16.0 * epsilon) * epsilon); + ccwerrboundB = (REAL)((2.0 + 12.0 * epsilon) * epsilon); + ccwerrboundC = (REAL)((9.0 + 64.0 * epsilon) * epsilon * epsilon); + iccerrboundA = (REAL)((10.0 + 96.0 * epsilon) * epsilon); + iccerrboundB = (REAL)((4.0 + 48.0 * epsilon) * epsilon); + iccerrboundC = (REAL)((44.0 + 576.0 * epsilon) * epsilon * epsilon); +} + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See my Robust Predicates paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +int fast_expansion_sum_zeroelim(elen, e, flen, f, h) /* h cannot be e or f. */ +int elen; +REAL *e; +int flen; +REAL *f; +REAL *h; +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL hh; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ +/* eliminating zero components from the */ +/* output expansion. */ +/* */ +/* Sets h = be. See my Robust Predicates paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int scale_expansion_zeroelim(elen, e, b, h) /* e and h cannot be the same. */ +int elen; +REAL *e; +REAL b; +REAL *h; +{ + INEXACT REAL Q, sum; + REAL hh; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* estimate() Produce a one-word estimate of an expansion's value. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL estimate(elen, e) +int elen; +REAL *e; +{ + REAL Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/*****************************************************************************/ +/* */ +/* counterclockwise() Return a positive value if the points pa, pb, and */ +/* pc occur in counterclockwise order; a negative */ +/* value if they occur in clockwise order; and zero */ +/* if they are collinear. The result is also a rough */ +/* approximation of twice the signed area of the */ +/* triangle defined by the three points. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are collinear or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL counterclockwiseadapt(pa, pb, pc, detsum) +point pa; +point pb; +point pc; +REAL detsum; +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail, bcxtail, bcytail; + INEXACT REAL detleft, detright; + REAL detlefttail, detrighttail; + REAL det, errbound; + REAL B[4], C1[8], C2[12], D[16]; + INEXACT REAL B3; + int C1length, C2length, Dlength; + REAL u[4]; + INEXACT REAL u3; + INEXACT REAL s1, t1; + REAL s0, t0; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + acx = (REAL) (pa[0] - pc[0]); + bcx = (REAL) (pb[0] - pc[0]); + acy = (REAL) (pa[1] - pc[1]); + bcy = (REAL) (pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, + B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = (REAL)(ccwerrboundB * detsum); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) + && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = (REAL)(ccwerrboundC * detsum + resulterrbound * Absolute(det)); + det += (acx * bcytail + bcy * acxtail) + - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return(D[Dlength - 1]); +} + +REAL counterclockwise(pa, pb, pc) +point pa; +point pb; +point pc; +{ + REAL detleft, detright, det; + REAL detsum, errbound; + + counterclockcount++; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (noexact) { + return det; + } + + if (detleft > 0.0) { + if (detright <= 0.0) { + return det; + } else { + detsum = detleft + detright; + } + } else if (detleft < 0.0) { + if (detright >= 0.0) { + return det; + } else { + detsum = -detleft - detright; + } + } else { + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return counterclockwiseadapt(pa, pb, pc, detsum); +} + +/*****************************************************************************/ +/* */ +/* incircle() Return a positive value if the point pd lies inside the */ +/* circle passing through pa, pb, and pc; a negative value if */ +/* it lies outside; and zero if the four points are cocircular.*/ +/* The points pa, pb, and pc must be in counterclockwise */ +/* order, or the sign of the result will be reversed. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are cocircular or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL incircleadapt(pa, pb, pc, pd, permanent) +point pa; +point pb; +point pc; +point pd; +REAL permanent; +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + REAL abdet[64]; + int ablen; + REAL fin1[1152], fin2[1152]; + REAL *finnow, *finother, *finswap; + int finlength; + + REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + REAL aa[4], bb[4], cc[4]; + INEXACT REAL aa3, bb3, cc3; + INEXACT REAL ti1, tj1; + REAL ti0, tj0; + REAL u[4], v[4]; + INEXACT REAL u3, v3; + REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; + REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + REAL axtbctt[8], aytbctt[8], bxtcatt[8]; + REAL bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + REAL abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + REAL abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT REAL abtt3, bctt3, catt3; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = (REAL)(iccerrboundB * permanent); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = (REAL)(iccerrboundC * permanent + resulterrbound * Absolute(det)); + det += (REAL)(((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx))); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, + temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, + temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, + temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, + temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, + temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, + temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, + temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, + temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, + temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, + temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, + temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, + temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, + temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, + temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, + temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, + temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, + temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, + temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +REAL incircle(pa, pb, pc, pd) +point pa; +point pb; +point pc; +point pd; +{ + REAL adx, bdx, cdx, ady, bdy, cdy; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL alift, blift, clift; + REAL det; + REAL permanent, errbound; + + incirclecount++; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + + blift * (cdxady - adxcdy) + + clift * (adxbdy - bdxady); + + if (noexact) { + return det; + } + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return incircleadapt(pa, pb, pc, pd, permanent); +} + +/** **/ +/** **/ +/********* Determinant evaluation routines end here *********/ + +/*****************************************************************************/ +/* */ +/* triangleinit() Initialize some variables. */ +/* */ +/*****************************************************************************/ + +void triangleinit() +{ + points.maxitems = triangles.maxitems = shelles.maxitems = viri.maxitems = + badsegments.maxitems = badtriangles.maxitems = splaynodes.maxitems = 0l; + points.itembytes = triangles.itembytes = shelles.itembytes = viri.itembytes = + badsegments.itembytes = badtriangles.itembytes = splaynodes.itembytes = 0; + recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */ + samples = 1; /* Point location should take at least one sample. */ + checksegments = 0; /* There are no segments in the triangulation yet. */ + incirclecount = counterclockcount = hyperbolacount = 0; + circumcentercount = circletopcount = 0; + randomseed = 1; + + exactinit(); /* Initialize exact arithmetic constants. */ +} + +/*****************************************************************************/ +/* */ +/* randomnation() Generate a random number between 0 and `choices' - 1. */ +/* */ +/* This is a simple linear congruential random number generator. Hence, it */ +/* is a bad random number generator, but good enough for most randomized */ +/* geometric algorithms. */ +/* */ +/*****************************************************************************/ + +unsigned long randomnation(choices) +unsigned int choices; +{ + randomseed = (randomseed * 1366l + 150889l) % 714025l; + return randomseed / (714025l / choices + 1); +} + +/********* Mesh quality testing routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* checkmesh() Test the mesh for topological consistency. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void checkmesh() +{ + struct triedge triangleloop; + struct triedge oppotri, oppooppotri; + point triorg, tridest, triapex; + point oppoorg, oppodest; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = noexact; + noexact = 0; + if (!quiet) { + printf(" Checking consistency of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + if (triangleloop.orient == 0) { /* Only test for inversion once. */ + /* Test if the triangle is flat or inverted. */ + apex(triangleloop, triapex); + if (counterclockwise(triorg, tridest, triapex) <= 0.0) { + printf(" !! !! Inverted "); + printtriangle(&triangleloop); + horrors++; + } + } + /* Find the neighboring triangle on this edge. */ + sym(triangleloop, oppotri); + if (oppotri.tri != dummytri) { + /* Check that the triangle's neighbor knows it's a neighbor. */ + sym(oppotri, oppooppotri); + if ((triangleloop.tri != oppooppotri.tri) + || (triangleloop.orient != oppooppotri.orient)) { + printf(" !! !! Asymmetric triangle-triangle bond:\n"); + if (triangleloop.tri == oppooppotri.tri) { + printf(" (Right triangle, wrong orientation)\n"); + } + printf(" First "); + printtriangle(&triangleloop); + printf(" Second (nonreciprocating) "); + printtriangle(&oppotri); + horrors++; + } + /* Check that both triangles agree on the identities */ + /* of their shared vertices. */ + org(oppotri, oppoorg); + dest(oppotri, oppodest); + if ((triorg != oppodest) || (tridest != oppoorg)) { + printf(" !! !! Mismatched edge coordinates between two triangles:\n" + ); + printf(" First mismatched "); + printtriangle(&triangleloop); + printf(" Second mismatched "); + printtriangle(&oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(); + } + if (horrors == 0) { + if (!quiet) { + printf(" In my studied opinion, the mesh appears to be consistent.\n"); + } + } else if (horrors == 1) { + printf(" !! !! !! !! Precisely one festering wound discovered.\n"); + } else { + printf(" !! !! !! !! %d abominations witnessed.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* checkdelaunay() Ensure that the mesh is (constrained) Delaunay. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void checkdelaunay() +{ + struct triedge triangleloop; + struct triedge oppotri; + struct edge opposhelle; + point triorg, tridest, triapex; + point oppoapex; + int shouldbedelaunay; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = noexact; + noexact = 0; + if (!quiet) { + printf(" Checking Delaunay property of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + apex(triangleloop, triapex); + sym(triangleloop, oppotri); + apex(oppotri, oppoapex); + /* Only test that the edge is locally Delaunay if there is an */ + /* adjoining triangle whose pointer is larger (to ensure that */ + /* each pair isn't tested twice). */ + shouldbedelaunay = (oppotri.tri != dummytri) + && (triapex != (point) NULL) && (oppoapex != (point) NULL) + && (triangleloop.tri < oppotri.tri); + if (checksegments && shouldbedelaunay) { + /* If a shell edge separates the triangles, then the edge is */ + /* constrained, so no local Delaunay test should be done. */ + tspivot(triangleloop, opposhelle); + if (opposhelle.sh != dummysh){ + shouldbedelaunay = 0; + } + } + if (shouldbedelaunay) { + if (incircle(triorg, tridest, triapex, oppoapex) > 0.0) { + printf(" !! !! Non-Delaunay pair of triangles:\n"); + printf(" First non-Delaunay "); + printtriangle(&triangleloop); + printf(" Second non-Delaunay "); + printtriangle(&oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(); + } + if (horrors == 0) { + if (!quiet) { + printf( + " By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n"); + } + } else if (horrors == 1) { + printf( + " !! !! !! !! Precisely one terrifying transgression identified.\n"); + } else { + printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* enqueuebadtri() Add a bad triangle to the end of a queue. */ +/* */ +/* The queue is actually a set of 64 queues. I use multiple queues to give */ +/* priority to smaller angles. I originally implemented a heap, but the */ +/* queues are (to my surprise) much faster. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void enqueuebadtri(instri, angle, insapex, insorg, insdest) +struct triedge *instri; +REAL angle; +point insapex; +point insorg; +point insdest; +{ + struct badface *newface; + int queuenumber; + + if (verbose > 2) { + printf(" Queueing bad triangle:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", insorg[0], + insorg[1], insdest[0], insdest[1], insapex[0], insapex[1]); + } + /* Allocate space for the bad triangle. */ + newface = (struct badface *) poolalloc(&badtriangles); + triedgecopy(*instri, newface->badfacetri); + newface->key = angle; + newface->faceapex = insapex; + newface->faceorg = insorg; + newface->facedest = insdest; + newface->nextface = (struct badface *) NULL; + /* Determine the appropriate queue to put the bad triangle into. */ + if (angle > 0.6) { + queuenumber = (int) (160.0 * (angle - 0.6)); + if (queuenumber > 63) { + queuenumber = 63; + } + } else { + /* It's not a bad angle; put the triangle in the lowest-priority queue. */ + queuenumber = 0; + } + /* Add the triangle to the end of a queue. */ + *queuetail[queuenumber] = newface; + /* Maintain a pointer to the NULL pointer at the end of the queue. */ + queuetail[queuenumber] = &newface->nextface; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* dequeuebadtri() Remove a triangle from the front of the queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +struct badface *dequeuebadtri() +{ + struct badface *result; + int queuenumber; + + /* Look for a nonempty queue. */ + for (queuenumber = 63; queuenumber >= 0; queuenumber--) { + result = queuefront[queuenumber]; + if (result != (struct badface *) NULL) { + /* Remove the triangle from the queue. */ + queuefront[queuenumber] = result->nextface; + /* Maintain a pointer to the NULL pointer at the end of the queue. */ + if (queuefront[queuenumber] == (struct badface *) NULL) { + queuetail[queuenumber] = &queuefront[queuenumber]; + } + return result; + } + } + return (struct badface *) NULL; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* checkedge4encroach() Check a segment to see if it is encroached; add */ +/* it to the list if it is. */ +/* */ +/* An encroached segment is an unflippable edge that has a point in its */ +/* diametral circle (that is, it faces an angle greater than 90 degrees). */ +/* This definition is due to Ruppert. */ +/* */ +/* Returns a nonzero value if the edge is encroached. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +int checkedge4encroach(testedge) +struct edge *testedge; +{ + struct triedge neighbortri; + struct edge testsym; + struct edge *badedge; + int addtolist; + int sides; + point eorg, edest, eapex; + triangle ptr; /* Temporary variable used by stpivot(). */ + + addtolist = 0; + sides = 0; + + sorg(*testedge, eorg); + sdest(*testedge, edest); + /* Check one neighbor of the shell edge. */ + stpivot(*testedge, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != dummytri) { + sides++; + /* Find a vertex opposite this edge. */ + apex(neighbortri, eapex); + /* Check whether the vertex is inside the diametral circle of the */ + /* shell edge. Pythagoras' Theorem is used to check whether the */ + /* angle at the vertex is greater than 90 degrees. */ + if (eapex[0] * (eorg[0] + edest[0]) + eapex[1] * (eorg[1] + edest[1]) > + eapex[0] * eapex[0] + eorg[0] * edest[0] + + eapex[1] * eapex[1] + eorg[1] * edest[1]) { + addtolist = 1; + } + } + /* Check the other neighbor of the shell edge. */ + ssym(*testedge, testsym); + stpivot(testsym, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != dummytri) { + sides++; + /* Find the other vertex opposite this edge. */ + apex(neighbortri, eapex); + /* Check whether the vertex is inside the diametral circle of the */ + /* shell edge. Pythagoras' Theorem is used to check whether the */ + /* angle at the vertex is greater than 90 degrees. */ + if (eapex[0] * (eorg[0] + edest[0]) + + eapex[1] * (eorg[1] + edest[1]) > + eapex[0] * eapex[0] + eorg[0] * edest[0] + + eapex[1] * eapex[1] + eorg[1] * edest[1]) { + addtolist += 2; + } + } + + if (addtolist && (!nobisect || ((nobisect == 1) && (sides == 2)))) { + if (verbose > 2) { + printf(" Queueing encroached segment (%.12g, %.12g) (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1]); + } + /* Add the shell edge to the list of encroached segments. */ + /* Be sure to get the orientation right. */ + badedge = (struct edge *) poolalloc(&badsegments); + if (addtolist == 1) { + shellecopy(*testedge, *badedge); + } else { + shellecopy(testsym, *badedge); + } + } + return addtolist; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* testtriangle() Test a face for quality measures. */ +/* */ +/* Tests a triangle to see if it satisfies the minimum angle condition and */ +/* the maximum area condition. Triangles that aren't up to spec are added */ +/* to the bad triangle queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void testtriangle(testtri) +struct triedge *testtri; +{ + struct triedge sametesttri; + struct edge edge1, edge2; + point torg, tdest, tapex; + point anglevertex; + REAL dxod, dyod, dxda, dyda, dxao, dyao; + REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2; + REAL apexlen, orglen, destlen; + REAL angle; + REAL area; + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*testtri, torg); + dest(*testtri, tdest); + apex(*testtri, tapex); + dxod = torg[0] - tdest[0]; + dyod = torg[1] - tdest[1]; + dxda = tdest[0] - tapex[0]; + dyda = tdest[1] - tapex[1]; + dxao = tapex[0] - torg[0]; + dyao = tapex[1] - torg[1]; + dxod2 = dxod * dxod; + dyod2 = dyod * dyod; + dxda2 = dxda * dxda; + dyda2 = dyda * dyda; + dxao2 = dxao * dxao; + dyao2 = dyao * dyao; + /* Find the lengths of the triangle's three edges. */ + apexlen = dxod2 + dyod2; + orglen = dxda2 + dyda2; + destlen = dxao2 + dyao2; + if ((apexlen < orglen) && (apexlen < destlen)) { + /* The edge opposite the apex is shortest. */ + /* Find the square of the cosine of the angle at the apex. */ + angle = dxda * dxao + dyda * dyao; + angle = angle * angle / (orglen * destlen); + anglevertex = tapex; + lnext(*testtri, sametesttri); + tspivot(sametesttri, edge1); + lnextself(sametesttri); + tspivot(sametesttri, edge2); + } else if (orglen < destlen) { + /* The edge opposite the origin is shortest. */ + /* Find the square of the cosine of the angle at the origin. */ + angle = dxod * dxao + dyod * dyao; + angle = angle * angle / (apexlen * destlen); + anglevertex = torg; + tspivot(*testtri, edge1); + lprev(*testtri, sametesttri); + tspivot(sametesttri, edge2); + } else { + /* The edge opposite the destination is shortest. */ + /* Find the square of the cosine of the angle at the destination. */ + angle = dxod * dxda + dyod * dyda; + angle = angle * angle / (apexlen * orglen); + anglevertex = tdest; + tspivot(*testtri, edge1); + lnext(*testtri, sametesttri); + tspivot(sametesttri, edge2); + } + /* Check if both edges that form the angle are segments. */ + if ((edge1.sh != dummysh) && (edge2.sh != dummysh)) { + /* The angle is a segment intersection. */ + if ((angle > 0.9924) && !quiet) { /* Roughly 5 degrees. */ + if (angle > 1.0) { + /* Beware of a floating exception in acos(). */ + angle = 1.0; + } + /* Find the actual angle in degrees, for printing. */ + angle = acos(sqrt(angle)) * (180.0 / PI); + printf( + "Warning: Small angle (%.4g degrees) between segments at point\n", + angle); + printf(" (%.12g, %.12g)\n", anglevertex[0], anglevertex[1]); + } + /* Don't add this bad triangle to the list; there's nothing that */ + /* can be done about a small angle between two segments. */ + angle = 0.0; + } + /* Check whether the angle is smaller than permitted. */ + if (angle > goodangle) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + return; + } + if (vararea || fixedarea) { + /* Check whether the area is larger than permitted. */ + area = 0.5 * (dxod * dyda - dyod * dxda); + if (fixedarea && (area > maxarea)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + } else if (vararea) { + /* Nonpositive area constraints are treated as unconstrained. */ + if ((area > areabound(*testtri)) && (areabound(*testtri) > 0.0)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + } + } + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality testing routines end here *********/ + +/********* Point location routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* makepointmap() Construct a mapping from points to triangles to improve */ +/* the speed of point location for segment insertion. */ +/* */ +/* Traverses all the triangles, and provides each corner of each triangle */ +/* with a pointer to that triangle. Of course, pointers will be */ +/* overwritten by other pointers because (almost) each point is a corner */ +/* of several triangles, but in the end every point will point to some */ +/* triangle that contains it. */ +/* */ +/*****************************************************************************/ + +void makepointmap() +{ + struct triedge triangleloop; + point triorg; + + if (verbose) { + printf(" Constructing mapping from points to triangles.\n"); + } + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three points of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + setpoint2tri(triorg, encode(triangleloop)); + } + triangleloop.tri = triangletraverse(); + } +} + +/*****************************************************************************/ +/* */ +/* preciselocate() Find a triangle or edge containing a given point. */ +/* */ +/* Begins its search from `searchtri'. It is important that `searchtri' */ +/* be a handle with the property that `searchpoint' is strictly to the left */ +/* of the edge denoted by `searchtri', or is collinear with that edge and */ +/* does not intersect that edge. (In particular, `searchpoint' should not */ +/* be the origin or destination of that edge.) */ +/* */ +/* These conditions are imposed because preciselocate() is normally used in */ +/* one of two situations: */ +/* */ +/* (1) To try to find the location to insert a new point. Normally, we */ +/* know an edge that the point is strictly to the left of. In the */ +/* incremental Delaunay algorithm, that edge is a bounding box edge. */ +/* In Ruppert's Delaunay refinement algorithm for quality meshing, */ +/* that edge is the shortest edge of the triangle whose circumcenter */ +/* is being inserted. */ +/* */ +/* (2) To try to find an existing point. In this case, any edge on the */ +/* convex hull is a good starting edge. The possibility that the */ +/* vertex one seeks is an endpoint of the starting edge must be */ +/* screened out before preciselocate() is called. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* This implementation differs from that given by Guibas and Stolfi. It */ +/* walks from triangle to triangle, crossing an edge only if `searchpoint' */ +/* is on the other side of the line containing that edge. After entering */ +/* a triangle, there are two edges by which one can leave that triangle. */ +/* If both edges are valid (`searchpoint' is on the other side of both */ +/* edges), one of the two is chosen by drawing a line perpendicular to */ +/* the entry edge (whose endpoints are `forg' and `fdest') passing through */ +/* `fapex'. Depending on which side of this perpendicular `searchpoint' */ +/* falls on, an exit edge is chosen. */ +/* */ +/* This implementation is empirically faster than the Guibas and Stolfi */ +/* point location routine (which I originally used), which tends to spiral */ +/* in toward its target. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* However, it can still be used to find the circumcenter of a triangle, as */ +/* long as the search is begun from the triangle in question. */ +/* */ +/*****************************************************************************/ + +enum locateresult preciselocate(searchpoint, searchtri) +point searchpoint; +struct triedge *searchtri; +{ + struct triedge backtracktri; + point forg, fdest, fapex; + point swappoint; + REAL orgorient, destorient; + int moveleft; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 2) { + printf(" Searching for point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Where are we? */ + org(*searchtri, forg); + dest(*searchtri, fdest); + apex(*searchtri, fapex); + while (1) { + if (verbose > 2) { + printf(" At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]); + } + /* Check whether the apex is the point we seek. */ + if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) { + lprevself(*searchtri); + return ONVERTEX; + } + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's destination? */ + destorient = counterclockwise(forg, fapex, searchpoint); + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's origin? */ + orgorient = counterclockwise(fapex, fdest, searchpoint); + if (destorient > 0.0) { + if (orgorient > 0.0) { + /* Move left if the inner product of (fapex - searchpoint) and */ + /* (fdest - forg) is positive. This is equivalent to drawing */ + /* a line perpendicular to the line (forg, fdest) passing */ + /* through `fapex', and determining which side of this line */ + /* `searchpoint' falls on. */ + moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) + + (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0; + } else { + moveleft = 1; + } + } else { + if (orgorient > 0.0) { + moveleft = 0; + } else { + /* The point we seek must be on the boundary of or inside this */ + /* triangle. */ + if (destorient == 0.0) { + lprevself(*searchtri); + return ONEDGE; + } + if (orgorient == 0.0) { + lnextself(*searchtri); + return ONEDGE; + } + return INTRIANGLE; + } + } + + /* Move to another triangle. Leave a trace `backtracktri' in case */ + /* floating-point roundoff or some such bogey causes us to walk */ + /* off a boundary of the triangulation. We can just bounce off */ + /* the boundary as if it were an elastic band. */ + if (moveleft) { + lprev(*searchtri, backtracktri); + fdest = fapex; + } else { + lnext(*searchtri, backtracktri); + forg = fapex; + } + sym(backtracktri, *searchtri); + + /* Check for walking off the edge. */ + if (searchtri->tri == dummytri) { + /* Turn around. */ + triedgecopy(backtracktri, *searchtri); + swappoint = forg; + forg = fdest; + fdest = swappoint; + apex(*searchtri, fapex); + /* Check if the point really is beyond the triangulation boundary. */ + destorient = counterclockwise(forg, fapex, searchpoint); + orgorient = counterclockwise(fapex, fdest, searchpoint); + if ((orgorient < 0.0) && (destorient < 0.0)) { + return OUTSIDE; + } + } else { + apex(*searchtri, fapex); + } + } +} + +/*****************************************************************************/ +/* */ +/* locate() Find a triangle or edge containing a given point. */ +/* */ +/* Searching begins from one of: the input `searchtri', a recently */ +/* encountered triangle `recenttri', or from a triangle chosen from a */ +/* random sample. The choice is made by determining which triangle's */ +/* origin is closest to the point we are searcing for. Normally, */ +/* `searchtri' should be a handle on the convex hull of the triangulation. */ +/* */ +/* Details on the random sampling method can be found in the Mucke, Saias, */ +/* and Zhu paper cited in the header of this code. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* */ +/*****************************************************************************/ + +enum locateresult locate(searchpoint, searchtri) +point searchpoint; +struct triedge *searchtri; +{ + VOID **sampleblock; + triangle *firsttri; + struct triedge sampletri; + point torg, tdest; + unsigned long alignptr; + REAL searchdist, dist; + REAL ahead; + long sampleblocks, samplesperblock, samplenum; + long triblocks; + long i, j; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 2) { + printf(" Randomly sampling for a triangle near point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Record the distance from the suggested starting triangle to the */ + /* point we seek. */ + org(*searchtri, torg); + searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (verbose > 2) { + printf(" Boundary triangle has origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + + /* If a recently encountered triangle has been recorded and has not been */ + /* deallocated, test it as a good starting point. */ + if (recenttri.tri != (triangle *) NULL) { + if (recenttri.tri[3] != (triangle) NULL) { + org(recenttri, torg); + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + triedgecopy(recenttri, *searchtri); + return ONVERTEX; + } + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + triedgecopy(recenttri, *searchtri); + searchdist = dist; + if (verbose > 2) { + printf(" Choosing recent triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + + /* The number of random samples taken is proportional to the cube root of */ + /* the number of triangles in the mesh. The next bit of code assumes */ + /* that the number of triangles increases monotonically. */ + while (SAMPLEFACTOR * samples * samples * samples < triangles.items) { + samples++; + } + triblocks = (triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK; + samplesperblock = 1 + (samples / triblocks); + sampleblocks = samples / samplesperblock; + sampleblock = triangles.firstblock; + sampletri.orient = 0; + for (i = 0; i < sampleblocks; i++) { + alignptr = (unsigned long) (sampleblock + 1); + firsttri = (triangle *) (alignptr + (unsigned long) triangles.alignbytes + - (alignptr % (unsigned long) triangles.alignbytes)); + for (j = 0; j < samplesperblock; j++) { + if (i == triblocks - 1) { + samplenum = randomnation((int) + (triangles.maxitems - (i * TRIPERBLOCK))); + } else { + samplenum = randomnation(TRIPERBLOCK); + } + sampletri.tri = (triangle *) + (firsttri + (samplenum * triangles.itemwords)); + if (sampletri.tri[3] != (triangle) NULL) { + org(sampletri, torg); + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + triedgecopy(sampletri, *searchtri); + searchdist = dist; + if (verbose > 2) { + printf(" Choosing triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + sampleblock = (VOID **) *sampleblock; + } + /* Where are we? */ + org(*searchtri, torg); + dest(*searchtri, tdest); + /* Check the starting triangle's vertices. */ + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + return ONVERTEX; + } + if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) { + lnextself(*searchtri); + return ONVERTEX; + } + /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */ + ahead = counterclockwise(torg, tdest, searchpoint); + if (ahead < 0.0) { + /* Turn around so that `searchpoint' is to the left of the */ + /* edge specified by `searchtri'. */ + symself(*searchtri); + } else if (ahead == 0.0) { + /* Check if `searchpoint' is between `torg' and `tdest'. */ + if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0])) + && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) { + return ONEDGE; + } + } + return preciselocate(searchpoint, searchtri); +} + +/** **/ +/** **/ +/********* Point location routines end here *********/ + +/********* Mesh transformation routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* insertshelle() Create a new shell edge and insert it between two */ +/* triangles. */ +/* */ +/* The new shell edge is inserted at the edge described by the handle */ +/* `tri'. Its vertices are properly initialized. The marker `shellemark' */ +/* is applied to the shell edge and, if appropriate, its vertices. */ +/* */ +/*****************************************************************************/ + +void insertshelle(tri, shellemark) +struct triedge *tri; /* Edge at which to insert the new shell edge. */ +int shellemark; /* Marker for the new shell edge. */ +{ + struct triedge oppotri; + struct edge newshelle; + point triorg, tridest; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Mark points if possible. */ + org(*tri, triorg); + dest(*tri, tridest); + if (pointmark(triorg) == 0) { + setpointmark(triorg, shellemark); + } + if (pointmark(tridest) == 0) { + setpointmark(tridest, shellemark); + } + /* Check if there's already a shell edge here. */ + tspivot(*tri, newshelle); + if (newshelle.sh == dummysh) { + /* Make new shell edge and initialize its vertices. */ + makeshelle(&newshelle); + setsorg(newshelle, tridest); + setsdest(newshelle, triorg); + /* Bond new shell edge to the two triangles it is sandwiched between. */ + /* Note that the facing triangle `oppotri' might be equal to */ + /* `dummytri' (outer space), but the new shell edge is bonded to it */ + /* all the same. */ + tsbond(*tri, newshelle); + sym(*tri, oppotri); + ssymself(newshelle); + tsbond(oppotri, newshelle); + setmark(newshelle, shellemark); + if (verbose > 2) { + printf(" Inserting new "); + printshelle(&newshelle); + } + } else { + if (mark(newshelle) == 0) { + setmark(newshelle, shellemark); + } + } +} + +/*****************************************************************************/ +/* */ +/* Terminology */ +/* */ +/* A "local transformation" replaces a small set of triangles with another */ +/* set of triangles. This may or may not involve inserting or deleting a */ +/* point. */ +/* */ +/* The term "casing" is used to describe the set of triangles that are */ +/* attached to the triangles being transformed, but are not transformed */ +/* themselves. Think of the casing as a fixed hollow structure inside */ +/* which all the action happens. A "casing" is only defined relative to */ +/* a single transformation; each occurrence of a transformation will */ +/* involve a different casing. */ +/* */ +/* A "shell" is similar to a "casing". The term "shell" describes the set */ +/* of shell edges (if any) that are attached to the triangles being */ +/* transformed. However, I sometimes use "shell" to refer to a single */ +/* shell edge, so don't get confused. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* flip() Transform two triangles to two different triangles by flipping */ +/* an edge within a quadrilateral. */ +/* */ +/* Imagine the original triangles, abc and bad, oriented so that the */ +/* shared edge ab lies in a horizontal plane, with the point b on the left */ +/* and the point a on the right. The point c lies below the edge, and the */ +/* point d lies above the edge. The `flipedge' handle holds the edge ab */ +/* of triangle abc, and is directed left, from vertex a to vertex b. */ +/* */ +/* The triangles abc and bad are deleted and replaced by the triangles cdb */ +/* and dca. The triangles that represent abc and bad are NOT deallocated; */ +/* they are reused for dca and cdb, respectively. Hence, any handles that */ +/* may have held the original triangles are still valid, although not */ +/* directed as they were before. */ +/* */ +/* Upon completion of this routine, the `flipedge' handle holds the edge */ +/* dc of triangle dca, and is directed down, from vertex d to vertex c. */ +/* (Hence, the two triangles have rotated counterclockwise.) */ +/* */ +/* WARNING: This transformation is geometrically valid only if the */ +/* quadrilateral adbc is convex. Furthermore, this transformation is */ +/* valid only if there is not a shell edge between the triangles abc and */ +/* bad. This routine does not check either of these preconditions, and */ +/* it is the responsibility of the calling routine to ensure that they are */ +/* met. If they are not, the streets shall be filled with wailing and */ +/* gnashing of teeth. */ +/* */ +/*****************************************************************************/ + +void flip(flipedge) +struct triedge *flipedge; /* Handle for the triangle abc. */ +{ + struct triedge botleft, botright; + struct triedge topleft, topright; + struct triedge top; + struct triedge botlcasing, botrcasing; + struct triedge toplcasing, toprcasing; + struct edge botlshelle, botrshelle; + struct edge toplshelle, toprshelle; + point leftpoint, rightpoint, botpoint; + point farpoint; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Identify the vertices of the quadrilateral. */ + org(*flipedge, rightpoint); + dest(*flipedge, leftpoint); + apex(*flipedge, botpoint); + sym(*flipedge, top); +#ifdef SELF_CHECK + if (top.tri == dummytri) { + printf("Internal error in flip(): Attempt to flip on boundary.\n"); + lnextself(*flipedge); + return; + } + if (checksegments) { + tspivot(*flipedge, toplshelle); + if (toplshelle.sh != dummysh) { + printf("Internal error in flip(): Attempt to flip a segment.\n"); + lnextself(*flipedge); + return; + } + } +#endif /* SELF_CHECK */ + apex(top, farpoint); + + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(*flipedge, botleft); + sym(botleft, botlcasing); + lprev(*flipedge, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + + if (checksegments) { + /* Check for shell edges and rebond them to the quadrilateral. */ + tspivot(topleft, toplshelle); + tspivot(botleft, botlshelle); + tspivot(botright, botrshelle); + tspivot(topright, toprshelle); + if (toplshelle.sh == dummysh) { + tsdissolve(topright); + } else { + tsbond(topright, toplshelle); + } + if (botlshelle.sh == dummysh) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlshelle); + } + if (botrshelle.sh == dummysh) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrshelle); + } + if (toprshelle.sh == dummysh) { + tsdissolve(botright); + } else { + tsbond(botright, toprshelle); + } + } + + /* New point assignments for the rotated quadrilateral. */ + setorg(*flipedge, farpoint); + setdest(*flipedge, botpoint); + setapex(*flipedge, rightpoint); + setorg(top, botpoint); + setdest(top, farpoint); + setapex(top, leftpoint); + if (verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(&topleft); + printf(" and right "); + printtriangle(flipedge); + } +} + +/*****************************************************************************/ +/* */ +/* insertsite() Insert a vertex into a Delaunay triangulation, */ +/* performing flips as necessary to maintain the Delaunay */ +/* property. */ +/* */ +/* The point `insertpoint' is located. If `searchtri.tri' is not NULL, */ +/* the search for the containing triangle begins from `searchtri'. If */ +/* `searchtri.tri' is NULL, a full point location procedure is called. */ +/* If `insertpoint' is found inside a triangle, the triangle is split into */ +/* three; if `insertpoint' lies on an edge, the edge is split in two, */ +/* thereby splitting the two adjacent triangles into four. Edge flips are */ +/* used to restore the Delaunay property. If `insertpoint' lies on an */ +/* existing vertex, no action is taken, and the value DUPLICATEPOINT is */ +/* returned. On return, `searchtri' is set to a handle whose origin is the */ +/* existing vertex. */ +/* */ +/* Normally, the parameter `splitedge' is set to NULL, implying that no */ +/* segment should be split. In this case, if `insertpoint' is found to */ +/* lie on a segment, no action is taken, and the value VIOLATINGPOINT is */ +/* returned. On return, `searchtri' is set to a handle whose primary edge */ +/* is the violated segment. */ +/* */ +/* If the calling routine wishes to split a segment by inserting a point in */ +/* it, the parameter `splitedge' should be that segment. In this case, */ +/* `searchtri' MUST be the triangle handle reached by pivoting from that */ +/* segment; no point location is done. */ +/* */ +/* `segmentflaws' and `triflaws' are flags that indicate whether or not */ +/* there should be checks for the creation of encroached segments or bad */ +/* quality faces. If a newly inserted point encroaches upon segments, */ +/* these segments are added to the list of segments to be split if */ +/* `segmentflaws' is set. If bad triangles are created, these are added */ +/* to the queue if `triflaws' is set. */ +/* */ +/* If a duplicate point or violated segment does not prevent the point */ +/* from being inserted, the return value will be ENCROACHINGPOINT if the */ +/* point encroaches upon a segment (and checking is enabled), or */ +/* SUCCESSFULPOINT otherwise. In either case, `searchtri' is set to a */ +/* handle whose origin is the newly inserted vertex. */ +/* */ +/* insertsite() does not use flip() for reasons of speed; some */ +/* information can be reused from edge flip to edge flip, like the */ +/* locations of shell edges. */ +/* */ +/*****************************************************************************/ + +enum insertsiteresult insertsite(insertpoint, searchtri, splitedge, + segmentflaws, triflaws) +point insertpoint; +struct triedge *searchtri; +struct edge *splitedge; +int segmentflaws; +int triflaws; +{ + struct triedge horiz; + struct triedge top; + struct triedge botleft, botright; + struct triedge topleft, topright; + struct triedge newbotleft, newbotright; + struct triedge newtopright; + struct triedge botlcasing, botrcasing; + struct triedge toplcasing, toprcasing; + struct triedge testtri; + struct edge botlshelle, botrshelle; + struct edge toplshelle, toprshelle; + struct edge brokenshelle; + struct edge checkshelle; + struct edge rightedge; + struct edge newedge; + struct edge *encroached; + point first; + point leftpoint, rightpoint, botpoint, toppoint, farpoint; + REAL attrib; + REAL area; + enum insertsiteresult success; + enum locateresult intersect; + int doflip; + int mirrorflag; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by spivot() and tspivot(). */ + + if (verbose > 1) { + printf(" Inserting (%.12g, %.12g).\n", insertpoint[0], insertpoint[1]); + } + if (splitedge == (struct edge *) NULL) { + /* Find the location of the point to be inserted. Check if a good */ + /* starting triangle has already been provided by the caller. */ + if (searchtri->tri == (triangle *) NULL) { + /* Find a boundary triangle. */ + horiz.tri = dummytri; + horiz.orient = 0; + symself(horiz); + /* Search for a triangle containing `insertpoint'. */ + intersect = locate(insertpoint, &horiz); + } else { + /* Start searching from the triangle provided by the caller. */ + triedgecopy(*searchtri, horiz); + intersect = preciselocate(insertpoint, &horiz); + } + } else { + /* The calling routine provides the edge in which the point is inserted. */ + triedgecopy(*searchtri, horiz); + intersect = ONEDGE; + } + if (intersect == ONVERTEX) { + /* There's already a vertex there. Return in `searchtri' a triangle */ + /* whose origin is the existing vertex. */ + triedgecopy(horiz, *searchtri); + triedgecopy(horiz, recenttri); + return DUPLICATEPOINT; + } + if ((intersect == ONEDGE) || (intersect == OUTSIDE)) { + /* The vertex falls on an edge or boundary. */ + if (checksegments && (splitedge == (struct edge *) NULL)) { + /* Check whether the vertex falls on a shell edge. */ + tspivot(horiz, brokenshelle); + if (brokenshelle.sh != dummysh) { + /* The vertex falls on a shell edge. */ + if (segmentflaws) { + if (nobisect == 0) { + /* Add the shell edge to the list of encroached segments. */ + encroached = (struct edge *) poolalloc(&badsegments); + shellecopy(brokenshelle, *encroached); + } else if ((nobisect == 1) && (intersect == ONEDGE)) { + /* This segment may be split only if it is an internal boundary. */ + sym(horiz, testtri); + if (testtri.tri != dummytri) { + /* Add the shell edge to the list of encroached segments. */ + encroached = (struct edge *) poolalloc(&badsegments); + shellecopy(brokenshelle, *encroached); + } + } + } + /* Return a handle whose primary edge contains the point, */ + /* which has not been inserted. */ + triedgecopy(horiz, *searchtri); + triedgecopy(horiz, recenttri); + return VIOLATINGPOINT; + } + } + /* Insert the point on an edge, dividing one triangle into two (if */ + /* the edge lies on a boundary) or two triangles into four. */ + lprev(horiz, botright); + sym(botright, botrcasing); + sym(horiz, topright); + /* Is there a second triangle? (Or does this edge lie on a boundary?) */ + mirrorflag = topright.tri != dummytri; + if (mirrorflag) { + lnextself(topright); + sym(topright, toprcasing); + maketriangle(&newtopright); + } else { + /* Splitting the boundary edge increases the number of boundary edges. */ + hullsize++; + } + maketriangle(&newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightpoint); + dest(horiz, leftpoint); + apex(horiz, botpoint); + setorg(newbotright, botpoint); + setdest(newbotright, rightpoint); + setapex(newbotright, insertpoint); + setorg(horiz, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of a new triangle. */ + setelemattribute(newbotright, i, elemattribute(botright, i)); + } + if (vararea) { + /* Set the area constraint of a new triangle. */ + setareabound(newbotright, areabound(botright)); + } + if (mirrorflag) { + dest(topright, toppoint); + setorg(newtopright, rightpoint); + setdest(newtopright, toppoint); + setapex(newtopright, insertpoint); + setorg(topright, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of another new triangle. */ + setelemattribute(newtopright, i, elemattribute(topright, i)); + } + if (vararea) { + /* Set the area constraint of another new triangle. */ + setareabound(newtopright, areabound(topright)); + } + } + + /* There may be shell edges that need to be bonded */ + /* to the new triangle(s). */ + if (checksegments) { + tspivot(botright, botrshelle); + if (botrshelle.sh != dummysh) { + tsdissolve(botright); + tsbond(newbotright, botrshelle); + } + if (mirrorflag) { + tspivot(topright, toprshelle); + if (toprshelle.sh != dummysh) { + tsdissolve(topright); + tsbond(newtopright, toprshelle); + } + } + } + + /* Bond the new triangle(s) to the surrounding triangles. */ + bond(newbotright, botrcasing); + lprevself(newbotright); + bond(newbotright, botright); + lprevself(newbotright); + if (mirrorflag) { + bond(newtopright, toprcasing); + lnextself(newtopright); + bond(newtopright, topright); + lnextself(newtopright); + bond(newtopright, newbotright); + } + + if (splitedge != (struct edge *) NULL) { + /* Split the shell edge into two. */ + setsdest(*splitedge, insertpoint); + ssymself(*splitedge); + spivot(*splitedge, rightedge); + insertshelle(&newbotright, mark(*splitedge)); + tspivot(newbotright, newedge); + sbond(*splitedge, newedge); + ssymself(newedge); + sbond(newedge, rightedge); + ssymself(*splitedge); + } + +#ifdef SELF_CHECK + if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge point insertion (bottom).\n"); + } + if (mirrorflag) { + if (counterclockwise(leftpoint, rightpoint, toppoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge point insertion (top).\n"); + } + if (counterclockwise(rightpoint, toppoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (top right).\n" + ); + } + if (counterclockwise(toppoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (top left).\n" + ); + } + } + if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (bottom left).\n" + ); + } + if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf( + " Clockwise triangle after edge point insertion (bottom right).\n"); + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Updating bottom left "); + printtriangle(&botright); + if (mirrorflag) { + printf(" Updating top left "); + printtriangle(&topright); + printf(" Creating top right "); + printtriangle(&newtopright); + } + printf(" Creating bottom right "); + printtriangle(&newbotright); + } + + /* Position `horiz' on the first edge to check for */ + /* the Delaunay property. */ + lnextself(horiz); + } else { + /* Insert the point in a triangle, splitting it into three. */ + lnext(horiz, botleft); + lprev(horiz, botright); + sym(botleft, botlcasing); + sym(botright, botrcasing); + maketriangle(&newbotleft); + maketriangle(&newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightpoint); + dest(horiz, leftpoint); + apex(horiz, botpoint); + setorg(newbotleft, leftpoint); + setdest(newbotleft, botpoint); + setapex(newbotleft, insertpoint); + setorg(newbotright, botpoint); + setdest(newbotright, rightpoint); + setapex(newbotright, insertpoint); + setapex(horiz, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of the new triangles. */ + attrib = elemattribute(horiz, i); + setelemattribute(newbotleft, i, attrib); + setelemattribute(newbotright, i, attrib); + } + if (vararea) { + /* Set the area constraint of the new triangles. */ + area = areabound(horiz); + setareabound(newbotleft, area); + setareabound(newbotright, area); + } + + /* There may be shell edges that need to be bonded */ + /* to the new triangles. */ + if (checksegments) { + tspivot(botleft, botlshelle); + if (botlshelle.sh != dummysh) { + tsdissolve(botleft); + tsbond(newbotleft, botlshelle); + } + tspivot(botright, botrshelle); + if (botrshelle.sh != dummysh) { + tsdissolve(botright); + tsbond(newbotright, botrshelle); + } + } + + /* Bond the new triangles to the surrounding triangles. */ + bond(newbotleft, botlcasing); + bond(newbotright, botrcasing); + lnextself(newbotleft); + lprevself(newbotright); + bond(newbotleft, newbotright); + lnextself(newbotleft); + bond(botleft, newbotleft); + lprevself(newbotright); + bond(botright, newbotright); + +#ifdef SELF_CHECK + if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to point insertion.\n"); + } + if (counterclockwise(rightpoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (top).\n"); + } + if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (left).\n"); + } + if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (right).\n"); + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Updating top "); + printtriangle(&horiz); + printf(" Creating left "); + printtriangle(&newbotleft); + printf(" Creating right "); + printtriangle(&newbotright); + } + } + + /* The insertion is successful by default, unless an encroached */ + /* edge is found. */ + success = SUCCESSFULPOINT; + /* Circle around the newly inserted vertex, checking each edge opposite */ + /* it for the Delaunay property. Non-Delaunay edges are flipped. */ + /* `horiz' is always the edge being checked. `first' marks where to */ + /* stop circling. */ + org(horiz, first); + rightpoint = first; + dest(horiz, leftpoint); + /* Circle until finished. */ + while (1) { + /* By default, the edge will be flipped. */ + doflip = 1; + if (checksegments) { + /* Check for a segment, which cannot be flipped. */ + tspivot(horiz, checkshelle); + if (checkshelle.sh != dummysh) { + /* The edge is a segment and cannot be flipped. */ + doflip = 0; +#ifndef CDT_ONLY + if (segmentflaws) { + /* Does the new point encroach upon this segment? */ + if (checkedge4encroach(&checkshelle)) { + success = ENCROACHINGPOINT; + } + } +#endif /* not CDT_ONLY */ + } + } + if (doflip) { + /* Check if the edge is a boundary edge. */ + sym(horiz, top); + if (top.tri == dummytri) { + /* The edge is a boundary edge and cannot be flipped. */ + doflip = 0; + } else { + /* Find the point on the other side of the edge. */ + apex(top, farpoint); + /* In the incremental Delaunay triangulation algorithm, any of */ + /* `leftpoint', `rightpoint', and `farpoint' could be vertices */ + /* of the triangular bounding box. These vertices must be */ + /* treated as if they are infinitely distant, even though their */ + /* "coordinates" are not. */ + if ((leftpoint == infpoint1) || (leftpoint == infpoint2) + || (leftpoint == infpoint3)) { + /* `leftpoint' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farpoint' might be */ + /* infinite as well, but trust me, this same condition */ + /* should be applied. */ + doflip = counterclockwise(insertpoint, rightpoint, farpoint) > 0.0; + } else if ((rightpoint == infpoint1) || (rightpoint == infpoint2) + || (rightpoint == infpoint3)) { + /* `rightpoint' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farpoint' might be */ + /* infinite as well, but trust me, this same condition */ + /* should be applied. */ + doflip = counterclockwise(farpoint, leftpoint, insertpoint) > 0.0; + } else if ((farpoint == infpoint1) || (farpoint == infpoint2) + || (farpoint == infpoint3)) { + /* `farpoint' is infinitely distant and cannot be inside */ + /* the circumcircle of the triangle `horiz'. */ + doflip = 0; + } else { + /* Test whether the edge is locally Delaunay. */ + doflip = incircle(leftpoint, insertpoint, rightpoint, farpoint) + > 0.0; + } + if (doflip) { + /* We made it! Flip the edge `horiz' by rotating its containing */ + /* quadrilateral (the two triangles adjacent to `horiz'). */ + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(horiz, botleft); + sym(botleft, botlcasing); + lprev(horiz, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + if (checksegments) { + /* Check for shell edges and rebond them to the quadrilateral. */ + tspivot(topleft, toplshelle); + tspivot(botleft, botlshelle); + tspivot(botright, botrshelle); + tspivot(topright, toprshelle); + if (toplshelle.sh == dummysh) { + tsdissolve(topright); + } else { + tsbond(topright, toplshelle); + } + if (botlshelle.sh == dummysh) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlshelle); + } + if (botrshelle.sh == dummysh) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrshelle); + } + if (toprshelle.sh == dummysh) { + tsdissolve(botright); + } else { + tsbond(botright, toprshelle); + } + } + /* New point assignments for the rotated quadrilateral. */ + setorg(horiz, farpoint); + setdest(horiz, insertpoint); + setapex(horiz, rightpoint); + setorg(top, insertpoint); + setdest(top, farpoint); + setapex(top, leftpoint); + for (i = 0; i < eextras; i++) { + /* Take the average of the two triangles' attributes. */ + attrib = (REAL)(0.5 * (elemattribute(top, i) + elemattribute(horiz, i))); + setelemattribute(top, i, attrib); + setelemattribute(horiz, i, attrib); + } + if (vararea) { + if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) { + area = -1.0; + } else { + /* Take the average of the two triangles' area constraints. */ + /* This prevents small area constraints from migrating a */ + /* long, long way from their original location due to flips. */ + area = (REAL)(0.5 * (areabound(top) + areabound(horiz))); + } + setareabound(top, area); + setareabound(horiz, area); + } +#ifdef SELF_CHECK + if (insertpoint != (point) NULL) { + if (counterclockwise(leftpoint, insertpoint, rightpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge flip (bottom).\n"); + } + /* The following test has been removed because constrainededge() */ + /* sometimes generates inverted triangles that insertsite() */ + /* removes. */ +/* + if (counterclockwise(rightpoint, farpoint, leftpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge flip (top).\n"); + } +*/ + if (counterclockwise(farpoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge flip (left).\n"); + } + if (counterclockwise(insertpoint, rightpoint, farpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge flip (right).\n"); + } + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(&topleft); + printf(" and right "); + printtriangle(&horiz); + } + /* On the next iterations, consider the two edges that were */ + /* exposed (this is, are now visible to the newly inserted */ + /* point) by the edge flip. */ + lprevself(horiz); + leftpoint = farpoint; + } + } + } + if (!doflip) { + /* The handle `horiz' is accepted as locally Delaunay. */ +#ifndef CDT_ONLY + if (triflaws) { + /* Check the triangle `horiz' for quality. */ + testtriangle(&horiz); + } +#endif /* not CDT_ONLY */ + /* Look for the next edge around the newly inserted point. */ + lnextself(horiz); + sym(horiz, testtri); + /* Check for finishing a complete revolution about the new point, or */ + /* falling off the edge of the triangulation. The latter will */ + /* happen when a point is inserted at a boundary. */ + if ((leftpoint == first) || (testtri.tri == dummytri)) { + /* We're done. Return a triangle whose origin is the new point. */ + lnext(horiz, *searchtri); + lnext(horiz, recenttri); + return success; + } + /* Finish finding the next edge around the newly inserted point. */ + lnext(testtri, horiz); + rightpoint = leftpoint; + dest(horiz, leftpoint); + } + } +} + +/*****************************************************************************/ +/* */ +/* triangulatepolygon() Find the Delaunay triangulation of a polygon that */ +/* has a certain "nice" shape. This includes the */ +/* polygons that result from deletion of a point or */ +/* insertion of a segment. */ +/* */ +/* This is a conceptually difficult routine. The starting assumption is */ +/* that we have a polygon with n sides. n - 1 of these sides are currently */ +/* represented as edges in the mesh. One side, called the "base", need not */ +/* be. */ +/* */ +/* Inside the polygon is a structure I call a "fan", consisting of n - 1 */ +/* triangles that share a common origin. For each of these triangles, the */ +/* edge opposite the origin is one of the sides of the polygon. The */ +/* primary edge of each triangle is the edge directed from the origin to */ +/* the destination; note that this is not the same edge that is a side of */ +/* the polygon. `firstedge' is the primary edge of the first triangle. */ +/* From there, the triangles follow in counterclockwise order about the */ +/* polygon, until `lastedge', the primary edge of the last triangle. */ +/* `firstedge' and `lastedge' are probably connected to other triangles */ +/* beyond the extremes of the fan, but their identity is not important, as */ +/* long as the fan remains connected to them. */ +/* */ +/* Imagine the polygon oriented so that its base is at the bottom. This */ +/* puts `firstedge' on the far right, and `lastedge' on the far left. */ +/* The right vertex of the base is the destination of `firstedge', and the */ +/* left vertex of the base is the apex of `lastedge'. */ +/* */ +/* The challenge now is to find the right sequence of edge flips to */ +/* transform the fan into a Delaunay triangulation of the polygon. Each */ +/* edge flip effectively removes one triangle from the fan, committing it */ +/* to the polygon. The resulting polygon has one fewer edge. If `doflip' */ +/* is set, the final flip will be performed, resulting in a fan of one */ +/* (useless?) triangle. If `doflip' is not set, the final flip is not */ +/* performed, resulting in a fan of two triangles, and an unfinished */ +/* triangular polygon that is not yet filled out with a single triangle. */ +/* On completion of the routine, `lastedge' is the last remaining triangle, */ +/* or the leftmost of the last two. */ +/* */ +/* Although the flips are performed in the order described above, the */ +/* decisions about what flips to perform are made in precisely the reverse */ +/* order. The recursive triangulatepolygon() procedure makes a decision, */ +/* uses up to two recursive calls to triangulate the "subproblems" */ +/* (polygons with fewer edges), and then performs an edge flip. */ +/* */ +/* The "decision" it makes is which vertex of the polygon should be */ +/* connected to the base. This decision is made by testing every possible */ +/* vertex. Once the best vertex is found, the two edges that connect this */ +/* vertex to the base become the bases for two smaller polygons. These */ +/* are triangulated recursively. Unfortunately, this approach can take */ +/* O(n^2) time not only in the worst case, but in many common cases. It's */ +/* rarely a big deal for point deletion, where n is rarely larger than ten, */ +/* but it could be a big deal for segment insertion, especially if there's */ +/* a lot of long segments that each cut many triangles. I ought to code */ +/* a faster algorithm some time. */ +/* */ +/* The `edgecount' parameter is the number of sides of the polygon, */ +/* including its base. `triflaws' is a flag that determines whether the */ +/* new triangles should be tested for quality, and enqueued if they are */ +/* bad. */ +/* */ +/*****************************************************************************/ + +void triangulatepolygon(firstedge, lastedge, edgecount, doflip, triflaws) +struct triedge *firstedge; +struct triedge *lastedge; +int edgecount; +int doflip; +int triflaws; +{ + struct triedge testtri; + struct triedge besttri; + struct triedge tempedge; + point leftbasepoint, rightbasepoint; + point testpoint; + point bestpoint; + int bestnumber; + int i; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + /* Identify the base vertices. */ + apex(*lastedge, leftbasepoint); + dest(*firstedge, rightbasepoint); + if (verbose > 2) { + printf(" Triangulating interior polygon at edge\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", leftbasepoint[0], + leftbasepoint[1], rightbasepoint[0], rightbasepoint[1]); + } + /* Find the best vertex to connect the base to. */ + onext(*firstedge, besttri); + dest(besttri, bestpoint); + triedgecopy(besttri, testtri); + bestnumber = 1; + for (i = 2; i <= edgecount - 2; i++) { + onextself(testtri); + dest(testtri, testpoint); + /* Is this a better vertex? */ + if (incircle(leftbasepoint, rightbasepoint, bestpoint, testpoint) > 0.0) { + triedgecopy(testtri, besttri); + bestpoint = testpoint; + bestnumber = i; + } + } + if (verbose > 2) { + printf(" Connecting edge to (%.12g, %.12g)\n", bestpoint[0], + bestpoint[1]); + } + if (bestnumber > 1) { + /* Recursively triangulate the smaller polygon on the right. */ + oprev(besttri, tempedge); + triangulatepolygon(firstedge, &tempedge, bestnumber + 1, 1, triflaws); + } + if (bestnumber < edgecount - 2) { + /* Recursively triangulate the smaller polygon on the left. */ + sym(besttri, tempedge); + triangulatepolygon(&besttri, lastedge, edgecount - bestnumber, 1, + triflaws); + /* Find `besttri' again; it may have been lost to edge flips. */ + sym(tempedge, besttri); + } + if (doflip) { + /* Do one final edge flip. */ + flip(&besttri); +#ifndef CDT_ONLY + if (triflaws) { + /* Check the quality of the newly committed triangle. */ + sym(besttri, testtri); + testtriangle(&testtri); + } +#endif /* not CDT_ONLY */ + } + /* Return the base triangle. */ + triedgecopy(besttri, *lastedge); +} + +/*****************************************************************************/ +/* */ +/* deletesite() Delete a vertex from a Delaunay triangulation, ensuring */ +/* that the triangulation remains Delaunay. */ +/* */ +/* The origin of `deltri' is deleted. The union of the triangles adjacent */ +/* to this point is a polygon, for which the Delaunay triangulation is */ +/* found. Two triangles are removed from the mesh. */ +/* */ +/* Only interior points that do not lie on segments (shell edges) or */ +/* boundaries may be deleted. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void deletesite(deltri) +struct triedge *deltri; +{ + struct triedge countingtri; + struct triedge firstedge, lastedge; + struct triedge deltriright; + struct triedge lefttri, righttri; + struct triedge leftcasing, rightcasing; + struct edge leftshelle, rightshelle; + point delpoint; + point neworg; + int edgecount; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*deltri, delpoint); + if (verbose > 1) { + printf(" Deleting (%.12g, %.12g).\n", delpoint[0], delpoint[1]); + } + pointdealloc(delpoint); + + /* Count the degree of the point being deleted. */ + onext(*deltri, countingtri); + edgecount = 1; + while (!triedgeequal(*deltri, countingtri)) { +#ifdef SELF_CHECK + if (countingtri.tri == dummytri) { + printf("Internal error in deletesite():\n"); + printf(" Attempt to delete boundary point.\n"); + internalerror(); + } +#endif /* SELF_CHECK */ + edgecount++; + onextself(countingtri); + } + +#ifdef SELF_CHECK + if (edgecount < 3) { + printf("Internal error in deletesite():\n Point has degree %d.\n", + edgecount); + internalerror(); + } +#endif /* SELF_CHECK */ + if (edgecount > 3) { + /* Triangulate the polygon defined by the union of all triangles */ + /* adjacent to the point being deleted. Check the quality of */ + /* the resulting triangles. */ + onext(*deltri, firstedge); + oprev(*deltri, lastedge); + triangulatepolygon(&firstedge, &lastedge, edgecount, 0, !nobisect); + } + /* Splice out two triangles. */ + lprev(*deltri, deltriright); + dnext(*deltri, lefttri); + sym(lefttri, leftcasing); + oprev(deltriright, righttri); + sym(righttri, rightcasing); + bond(*deltri, leftcasing); + bond(deltriright, rightcasing); + tspivot(lefttri, leftshelle); + if (leftshelle.sh != dummysh) { + tsbond(*deltri, leftshelle); + } + tspivot(righttri, rightshelle); + if (rightshelle.sh != dummysh) { + tsbond(deltriright, rightshelle); + } + + /* Set the new origin of `deltri' and check its quality. */ + org(lefttri, neworg); + setorg(*deltri, neworg); + if (!nobisect) { + testtriangle(deltri); + } + + /* Delete the two spliced-out triangles. */ + triangledealloc(lefttri.tri); + triangledealloc(righttri.tri); +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh transformation routines end here *********/ + +/********* Divide-and-conquer Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* The divide-and-conquer bounding box */ +/* */ +/* I originally implemented the divide-and-conquer and incremental Delaunay */ +/* triangulations using the edge-based data structure presented by Guibas */ +/* and Stolfi. Switching to a triangle-based data structure doubled the */ +/* speed. However, I had to think of a few extra tricks to maintain the */ +/* elegance of the original algorithms. */ +/* */ +/* The "bounding box" used by my variant of the divide-and-conquer */ +/* algorithm uses one triangle for each edge of the convex hull of the */ +/* triangulation. These bounding triangles all share a common apical */ +/* vertex, which is represented by NULL and which represents nothing. */ +/* The bounding triangles are linked in a circular fan about this NULL */ +/* vertex, and the edges on the convex hull of the triangulation appear */ +/* opposite the NULL vertex. You might find it easiest to imagine that */ +/* the NULL vertex is a point in 3D space behind the center of the */ +/* triangulation, and that the bounding triangles form a sort of cone. */ +/* */ +/* This bounding box makes it easy to represent degenerate cases. For */ +/* instance, the triangulation of two vertices is a single edge. This edge */ +/* is represented by two bounding box triangles, one on each "side" of the */ +/* edge. These triangles are also linked together in a fan about the NULL */ +/* vertex. */ +/* */ +/* The bounding box also makes it easy to traverse the convex hull, as the */ +/* divide-and-conquer algorithm needs to do. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* pointsort() Sort an array of points by x-coordinate, using the */ +/* y-coordinate as a secondary key. */ +/* */ +/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */ +/* the usual quicksort mistakes. */ +/* */ +/*****************************************************************************/ + +void pointsort(sortarray, arraysize) +point *sortarray; +int arraysize; +{ + int left, right; + int pivot; + REAL pivotx, pivoty; + point temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][0] > sortarray[1][0]) || + ((sortarray[0][0] == sortarray[1][0]) && + (sortarray[0][1] > sortarray[1][1]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation(arraysize); + pivotx = sortarray[pivot][0]; + pivoty = sortarray[pivot][1]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a point whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][0] < pivotx) || + ((sortarray[left][0] == pivotx) && + (sortarray[left][1] < pivoty)))); + /* Search for a point whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][0] > pivotx) || + ((sortarray[right][0] == pivotx) && + (sortarray[right][1] > pivoty)))); + if (left < right) { + /* Swap the left and right points. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + if (left > 1) { + /* Recursively sort the left subset. */ + pointsort(sortarray, left); + } + if (right < arraysize - 2) { + /* Recursively sort the right subset. */ + pointsort(&sortarray[right + 1], arraysize - right - 1); + } +} + +/*****************************************************************************/ +/* */ +/* pointmedian() An order statistic algorithm, almost. Shuffles an array */ +/* of points so that the first `median' points occur */ +/* lexicographically before the remaining points. */ +/* */ +/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */ +/* if axis == 1. Very similar to the pointsort() procedure, but runs in */ +/* randomized linear time. */ +/* */ +/*****************************************************************************/ + +void pointmedian(sortarray, arraysize, median, axis) +point *sortarray; +int arraysize; +int median; +int axis; +{ + int left, right; + int pivot; + REAL pivot1, pivot2; + point temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][axis] > sortarray[1][axis]) || + ((sortarray[0][axis] == sortarray[1][axis]) && + (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation(arraysize); + pivot1 = sortarray[pivot][axis]; + pivot2 = sortarray[pivot][1 - axis]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a point whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][axis] < pivot1) || + ((sortarray[left][axis] == pivot1) && + (sortarray[left][1 - axis] < pivot2)))); + /* Search for a point whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][axis] > pivot1) || + ((sortarray[right][axis] == pivot1) && + (sortarray[right][1 - axis] > pivot2)))); + if (left < right) { + /* Swap the left and right points. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + /* Unlike in pointsort(), at most one of the following */ + /* conditionals is true. */ + if (left > median) { + /* Recursively shuffle the left subset. */ + pointmedian(sortarray, left, median, axis); + } + if (right < median - 1) { + /* Recursively shuffle the right subset. */ + pointmedian(&sortarray[right + 1], arraysize - right - 1, + median - right - 1, axis); + } +} + +/*****************************************************************************/ +/* */ +/* alternateaxes() Sorts the points as appropriate for the divide-and- */ +/* conquer algorithm with alternating cuts. */ +/* */ +/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */ +/* For the base case, subsets containing only two or three points are */ +/* always sorted by x-coordinate. */ +/* */ +/*****************************************************************************/ + +void alternateaxes(sortarray, arraysize, axis) +point *sortarray; +int arraysize; +int axis; +{ + int divider; + + divider = arraysize >> 1; + if (arraysize <= 3) { + /* Recursive base case: subsets of two or three points will be */ + /* handled specially, and should always be sorted by x-coordinate. */ + axis = 0; + } + /* Partition with a horizontal or vertical cut. */ + pointmedian(sortarray, arraysize, divider, axis); + /* Recursively partition the subsets with a cross cut. */ + if (arraysize - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1 - axis); + } + alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis); + } +} + +/*****************************************************************************/ +/* */ +/* mergehulls() Merge two adjacent Delaunay triangulations into a */ +/* single Delaunay triangulation. */ +/* */ +/* This is similar to the algorithm given by Guibas and Stolfi, but uses */ +/* a triangle-based, rather than edge-based, data structure. */ +/* */ +/* The algorithm walks up the gap between the two triangulations, knitting */ +/* them together. As they are merged, some of their bounding triangles */ +/* are converted into real triangles of the triangulation. The procedure */ +/* pulls each hull's bounding triangles apart, then knits them together */ +/* like the teeth of two gears. The Delaunay property determines, at each */ +/* step, whether the next "tooth" is a bounding triangle of the left hull */ +/* or the right. When a bounding triangle becomes real, its apex is */ +/* changed from NULL to a real point. */ +/* */ +/* Only two new triangles need to be allocated. These become new bounding */ +/* triangles at the top and bottom of the seam. They are used to connect */ +/* the remaining bounding triangles (those that have not been converted */ +/* into real triangles) into a single fan. */ +/* */ +/* On entry, `farleft' and `innerleft' are bounding triangles of the left */ +/* triangulation. The origin of `farleft' is the leftmost vertex, and */ +/* the destination of `innerleft' is the rightmost vertex of the */ +/* triangulation. Similarly, `innerright' and `farright' are bounding */ +/* triangles of the right triangulation. The origin of `innerright' and */ +/* destination of `farright' are the leftmost and rightmost vertices. */ +/* */ +/* On completion, the origin of `farleft' is the leftmost vertex of the */ +/* merged triangulation, and the destination of `farright' is the rightmost */ +/* vertex. */ +/* */ +/*****************************************************************************/ + +void mergehulls(farleft, innerleft, innerright, farright, axis) +struct triedge *farleft; +struct triedge *innerleft; +struct triedge *innerright; +struct triedge *farright; +int axis; +{ + struct triedge leftcand, rightcand; + struct triedge baseedge; + struct triedge nextedge; + struct triedge sidecasing, topcasing, outercasing; + struct triedge checkedge; + point innerleftdest; + point innerrightorg; + point innerleftapex, innerrightapex; + point farleftpt, farrightpt; + point farleftapex, farrightapex; + point lowerleft, lowerright; + point upperleft, upperright; + point nextapex; + point checkvertex; + int changemade; + int badedge; + int leftfinished, rightfinished; + triangle ptr; /* Temporary variable used by sym(). */ + + dest(*innerleft, innerleftdest); + apex(*innerleft, innerleftapex); + org(*innerright, innerrightorg); + apex(*innerright, innerrightapex); + /* Special treatment for horizontal cuts. */ + if (dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + /* The pointers to the extremal points are shifted to point to the */ + /* topmost and bottommost point of each hull, rather than the */ + /* leftmost and rightmost points. */ + while (farleftapex[1] < farleftpt[1]) { + lnextself(*farleft); + symself(*farleft); + farleftpt = farleftapex; + apex(*farleft, farleftapex); + } + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > innerleftdest[1]) { + lnext(checkedge, *innerleft); + innerleftapex = innerleftdest; + innerleftdest = checkvertex; + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + } + while (innerrightapex[1] < innerrightorg[1]) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + } + sym(*farright, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > farrightpt[1]) { + lnext(checkedge, *farright); + farrightapex = farrightpt; + farrightpt = checkvertex; + sym(*farright, checkedge); + apex(checkedge, checkvertex); + } + } + /* Find a line tangent to and below both hulls. */ + do { + changemade = 0; + /* Make innerleftdest the "bottommost" point of the left hull. */ + if (counterclockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) { + lprevself(*innerleft); + symself(*innerleft); + innerleftdest = innerleftapex; + apex(*innerleft, innerleftapex); + changemade = 1; + } + /* Make innerrightorg the "bottommost" point of the right hull. */ + if (counterclockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + changemade = 1; + } + } while (changemade); + /* Find the two candidates to be the next "gear tooth". */ + sym(*innerleft, leftcand); + sym(*innerright, rightcand); + /* Create the bottom new bounding triangle. */ + maketriangle(&baseedge); + /* Connect it to the bounding boxes of the left and right triangulations. */ + bond(baseedge, *innerleft); + lnextself(baseedge); + bond(baseedge, *innerright); + lnextself(baseedge); + setorg(baseedge, innerrightorg); + setdest(baseedge, innerleftdest); + /* Apex is intentionally left NULL. */ + if (verbose > 2) { + printf(" Creating base bounding "); + printtriangle(&baseedge); + } + /* Fix the extreme triangles if necessary. */ + org(*farleft, farleftpt); + if (innerleftdest == farleftpt) { + lnext(baseedge, *farleft); + } + dest(*farright, farrightpt); + if (innerrightorg == farrightpt) { + lprev(baseedge, *farright); + } + /* The vertices of the current knitting edge. */ + lowerleft = innerleftdest; + lowerright = innerrightorg; + /* The candidate vertices for knitting. */ + apex(leftcand, upperleft); + apex(rightcand, upperright); + /* Walk up the gap between the two triangulations, knitting them together. */ + while (1) { + /* Have we reached the top? (This isn't quite the right question, */ + /* because even though the left triangulation might seem finished now, */ + /* moving up on the right triangulation might reveal a new point of */ + /* the left triangulation. And vice-versa.) */ + leftfinished = counterclockwise(upperleft, lowerleft, lowerright) <= 0.0; + rightfinished = counterclockwise(upperright, lowerleft, lowerright) <= 0.0; + if (leftfinished && rightfinished) { + /* Create the top new bounding triangle. */ + maketriangle(&nextedge); + setorg(nextedge, lowerleft); + setdest(nextedge, lowerright); + /* Apex is intentionally left NULL. */ + /* Connect it to the bounding boxes of the two triangulations. */ + bond(nextedge, baseedge); + lnextself(nextedge); + bond(nextedge, rightcand); + lnextself(nextedge); + bond(nextedge, leftcand); + if (verbose > 2) { + printf(" Creating top bounding "); + printtriangle(&baseedge); + } + /* Special treatment for horizontal cuts. */ + if (dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + /* The pointers to the extremal points are restored to the leftmost */ + /* and rightmost points (rather than topmost and bottommost). */ + while (checkvertex[0] < farleftpt[0]) { + lprev(checkedge, *farleft); + farleftapex = farleftpt; + farleftpt = checkvertex; + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + } + while (farrightapex[0] > farrightpt[0]) { + lprevself(*farright); + symself(*farright); + farrightpt = farrightapex; + apex(*farright, farrightapex); + } + } + return; + } + /* Consider eliminating edges from the left triangulation. */ + if (!leftfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lprev(leftcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperleft, nextapex) > 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* left triangulation will have one more boundary triangle. */ + lnextself(nextedge); + sym(nextedge, topcasing); + lnextself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(leftcand, sidecasing); + lnextself(leftcand); + sym(leftcand, outercasing); + lprevself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(leftcand, lowerleft); + setdest(leftcand, NULL); + setapex(leftcand, nextapex); + setorg(nextedge, NULL); + setdest(nextedge, upperleft); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperleft = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + triedgecopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperleft, nextapex) + > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + /* Consider eliminating edges from the right triangulation. */ + if (!rightfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lnext(rightcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperright, nextapex) > 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* right triangulation will have one more boundary triangle. */ + lprevself(nextedge); + sym(nextedge, topcasing); + lprevself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(rightcand, sidecasing); + lprevself(rightcand); + sym(rightcand, outercasing); + lnextself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(rightcand, NULL); + setdest(rightcand, lowerright); + setapex(rightcand, nextapex); + setorg(nextedge, upperright); + setdest(nextedge, NULL); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperright = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + triedgecopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperright, nextapex) + > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + if (leftfinished || (!rightfinished && + (incircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) { + /* Knit the triangulations, adding an edge from `lowerleft' */ + /* to `upperright'. */ + bond(baseedge, rightcand); + lprev(rightcand, baseedge); + setdest(baseedge, lowerleft); + lowerright = upperright; + sym(baseedge, rightcand); + apex(rightcand, upperright); + } else { + /* Knit the triangulations, adding an edge from `upperleft' */ + /* to `lowerright'. */ + bond(baseedge, leftcand); + lnext(leftcand, baseedge); + setorg(baseedge, lowerright); + lowerleft = upperleft; + sym(baseedge, leftcand); + apex(leftcand, upperleft); + } + if (verbose > 2) { + printf(" Connecting "); + printtriangle(&baseedge); + } + } +} + +/*****************************************************************************/ +/* */ +/* divconqrecurse() Recursively form a Delaunay triangulation by the */ +/* divide-and-conquer method. */ +/* */ +/* Recursively breaks down the problem into smaller pieces, which are */ +/* knitted together by mergehulls(). The base cases (problems of two or */ +/* three points) are handled specially here. */ +/* */ +/* On completion, `farleft' and `farright' are bounding triangles such that */ +/* the origin of `farleft' is the leftmost vertex (breaking ties by */ +/* choosing the highest leftmost vertex), and the destination of */ +/* `farright' is the rightmost vertex (breaking ties by choosing the */ +/* lowest rightmost vertex). */ +/* */ +/*****************************************************************************/ + +void divconqrecurse(sortarray, vertices, axis, farleft, farright) +point *sortarray; +int vertices; +int axis; +struct triedge *farleft; +struct triedge *farright; +{ + struct triedge midtri, tri1, tri2, tri3; + struct triedge innerleft, innerright; + REAL area; + int divider; + + if (verbose > 2) { + printf(" Triangulating %d points.\n", vertices); + } + if (vertices == 2) { + /* The triangulation of two vertices is an edge. An edge is */ + /* represented by two bounding triangles. */ + maketriangle(farleft); + setorg(*farleft, sortarray[0]); + setdest(*farleft, sortarray[1]); + /* The apex is intentionally left NULL. */ + maketriangle(farright); + setorg(*farright, sortarray[1]); + setdest(*farright, sortarray[0]); + /* The apex is intentionally left NULL. */ + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + if (verbose > 2) { + printf(" Creating "); + printtriangle(farleft); + printf(" Creating "); + printtriangle(farright); + } + /* Ensure that the origin of `farleft' is sortarray[0]. */ + lprev(*farright, *farleft); + return; + } else if (vertices == 3) { + /* The triangulation of three vertices is either a triangle (with */ + /* three bounding triangles) or two edges (with four bounding */ + /* triangles). In either case, four triangles are created. */ + maketriangle(&midtri); + maketriangle(&tri1); + maketriangle(&tri2); + maketriangle(&tri3); + area = counterclockwise(sortarray[0], sortarray[1], sortarray[2]); + if (area == 0.0) { + /* Three collinear points; the triangulation is two edges. */ + setorg(midtri, sortarray[0]); + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri1, sortarray[0]); + setorg(tri2, sortarray[2]); + setdest(tri2, sortarray[1]); + setorg(tri3, sortarray[1]); + setdest(tri3, sortarray[2]); + /* All apices are intentionally left NULL. */ + bond(midtri, tri1); + bond(tri2, tri3); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri3); + bond(tri1, tri2); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri1); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + triedgecopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + triedgecopy(tri2, *farright); + } else { + /* The three points are not collinear; the triangulation is one */ + /* triangle, namely `midtri'. */ + setorg(midtri, sortarray[0]); + setdest(tri1, sortarray[0]); + setorg(tri3, sortarray[0]); + /* Apices of tri1, tri2, and tri3 are left NULL. */ + if (area > 0.0) { + /* The vertices are in counterclockwise order. */ + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri2, sortarray[1]); + setapex(midtri, sortarray[2]); + setorg(tri2, sortarray[2]); + setdest(tri3, sortarray[2]); + } else { + /* The vertices are in clockwise order. */ + setdest(midtri, sortarray[2]); + setorg(tri1, sortarray[2]); + setdest(tri2, sortarray[2]); + setapex(midtri, sortarray[1]); + setorg(tri2, sortarray[1]); + setdest(tri3, sortarray[1]); + } + /* The topology does not depend on how the vertices are ordered. */ + bond(midtri, tri1); + lnextself(midtri); + bond(midtri, tri2); + lnextself(midtri); + bond(midtri, tri3); + lprevself(tri1); + lnextself(tri2); + bond(tri1, tri2); + lprevself(tri1); + lprevself(tri3); + bond(tri1, tri3); + lnextself(tri2); + lprevself(tri3); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + triedgecopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + if (area > 0.0) { + triedgecopy(tri2, *farright); + } else { + lnext(*farleft, *farright); + } + } + if (verbose > 2) { + printf(" Creating "); + printtriangle(&midtri); + printf(" Creating "); + printtriangle(&tri1); + printf(" Creating "); + printtriangle(&tri2); + printf(" Creating "); + printtriangle(&tri3); + } + return; + } else { + /* Split the vertices in half. */ + divider = vertices >> 1; + /* Recursively triangulate each half. */ + divconqrecurse(sortarray, divider, 1 - axis, farleft, &innerleft); + divconqrecurse(&sortarray[divider], vertices - divider, 1 - axis, + &innerright, farright); + if (verbose > 1) { + printf(" Joining triangulations with %d and %d vertices.\n", divider, + vertices - divider); + } + /* Merge the two triangulations into one. */ + mergehulls(farleft, &innerleft, &innerright, farright, axis); + } +} + +long removeghosts(startghost) +struct triedge *startghost; +{ + struct triedge searchedge; + struct triedge dissolveedge; + struct triedge deadtri; + point markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose) { + printf(" Removing ghost triangles.\n"); + } + /* Find an edge on the convex hull to start point location from. */ + lprev(*startghost, searchedge); + symself(searchedge); + dummytri[0] = encode(searchedge); + /* Remove the bounding box and count the convex hull edges. */ + triedgecopy(*startghost, dissolveedge); + hullsize = 0; + do { + hullsize++; + lnext(dissolveedge, deadtri); + lprevself(dissolveedge); + symself(dissolveedge); + /* If no PSLG is involved, set the boundary markers of all the points */ + /* on the convex hull. If a PSLG is used, this step is done later. */ + if (!poly) { + /* Watch out for the case where all the input points are collinear. */ + if (dissolveedge.tri != dummytri) { + org(dissolveedge, markorg); + if (pointmark(markorg) == 0) { + setpointmark(markorg, 1); + } + } + } + /* Remove a bounding triangle from a convex hull triangle. */ + dissolve(dissolveedge); + /* Find the next bounding triangle. */ + sym(deadtri, dissolveedge); + /* Delete the bounding triangle. */ + triangledealloc(deadtri.tri); + } while (!triedgeequal(dissolveedge, *startghost)); + return hullsize; +} + +/*****************************************************************************/ +/* */ +/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */ +/* conquer method. */ +/* */ +/* Sorts the points, calls a recursive procedure to triangulate them, and */ +/* removes the bounding box, setting boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +long divconqdelaunay() +{ + point *sortarray; + struct triedge hullleft, hullright; + int divider; + int i, j; + + /* Allocate an array of pointers to points for sorting. */ + sortarray = (point *) malloc(inpoints * sizeof(point)); + if (sortarray == (point *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + traversalinit(&points); + for (i = 0; i < inpoints; i++) { + sortarray[i] = pointtraverse(); + } + if (verbose) { + printf(" Sorting points.\n"); + } + /* Sort the points. */ + pointsort(sortarray, inpoints); + /* Discard duplicate points, which can really mess up the algorithm. */ + i = 0; + for (j = 1; j < inpoints; j++) { + if ((sortarray[i][0] == sortarray[j][0]) + && (sortarray[i][1] == sortarray[j][1])) { + if (!quiet) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + sortarray[j][0], sortarray[j][1]); + } +/* Commented out - would eliminate point from output .node file, but causes + a failure if some segment has this point as an endpoint. + setpointmark(sortarray[j], DEADPOINT); +*/ + } else { + i++; + sortarray[i] = sortarray[j]; + } + } + i++; + if (dwyer) { + /* Re-sort the array of points to accommodate alternating cuts. */ + divider = i >> 1; + if (i - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1); + } + alternateaxes(&sortarray[divider], i - divider, 1); + } + } + if (verbose) { + printf(" Forming triangulation.\n"); + } + /* Form the Delaunay triangulation. */ + divconqrecurse(sortarray, i, 0, &hullleft, &hullright); + free(sortarray); + + return removeghosts(&hullleft); +} + +/** **/ +/** **/ +/********* Divide-and-conquer Delaunay triangulation ends here *********/ + +/********* Incremental Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* boundingbox() Form an "infinite" bounding triangle to insert points */ +/* into. */ +/* */ +/* The points at "infinity" are assigned finite coordinates, which are used */ +/* by the point location routines, but (mostly) ignored by the Delaunay */ +/* edge flip routines. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void boundingbox() +{ + struct triedge inftri; /* Handle for the triangular bounding box. */ + REAL width; + + if (verbose) { + printf(" Creating triangular bounding box.\n"); + } + /* Find the width (or height, whichever is larger) of the triangulation. */ + width = xmax - xmin; + if (ymax - ymin > width) { + width = ymax - ymin; + } + if (width == 0.0) { + width = 1.0; + } + /* Create the vertices of the bounding box. */ + infpoint1 = (point) malloc(points.itembytes); + infpoint2 = (point) malloc(points.itembytes); + infpoint3 = (point) malloc(points.itembytes); + if ((infpoint1 == (point) NULL) || (infpoint2 == (point) NULL) + || (infpoint3 == (point) NULL)) { + printf("Error: Out of memory.\n"); + exit(1); + } + infpoint1[0] = xmin - 50.0 * width; + infpoint1[1] = ymin - 40.0 * width; + infpoint2[0] = xmax + 50.0 * width; + infpoint2[1] = ymin - 40.0 * width; + infpoint3[0] = 0.5 * (xmin + xmax); + infpoint3[1] = ymax + 60.0 * width; + + /* Create the bounding box. */ + maketriangle(&inftri); + setorg(inftri, infpoint1); + setdest(inftri, infpoint2); + setapex(inftri, infpoint3); + /* Link dummytri to the bounding box so we can always find an */ + /* edge to begin searching (point location) from. */ + dummytri[0] = (triangle) inftri.tri; + if (verbose > 2) { + printf(" Creating "); + printtriangle(&inftri); + } +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* removebox() Remove the "infinite" bounding triangle, setting boundary */ +/* markers as appropriate. */ +/* */ +/* The triangular bounding box has three boundary triangles (one for each */ +/* side of the bounding box), and a bunch of triangles fanning out from */ +/* the three bounding box vertices (one triangle for each edge of the */ +/* convex hull of the inner mesh). This routine removes these triangles. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +long removebox() +{ + struct triedge deadtri; + struct triedge searchedge; + struct triedge checkedge; + struct triedge nextedge, finaledge, dissolveedge; + point markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose) { + printf(" Removing triangular bounding box.\n"); + } + /* Find a boundary triangle. */ + nextedge.tri = dummytri; + nextedge.orient = 0; + symself(nextedge); + /* Mark a place to stop. */ + lprev(nextedge, finaledge); + lnextself(nextedge); + symself(nextedge); + /* Find a triangle (on the boundary of the point set) that isn't */ + /* a bounding box triangle. */ + lprev(nextedge, searchedge); + symself(searchedge); + /* Check whether nextedge is another boundary triangle */ + /* adjacent to the first one. */ + lnext(nextedge, checkedge); + symself(checkedge); + if (checkedge.tri == dummytri) { + /* Go on to the next triangle. There are only three boundary */ + /* triangles, and this next triangle cannot be the third one, */ + /* so it's safe to stop here. */ + lprevself(searchedge); + symself(searchedge); + } + /* Find a new boundary edge to search from, as the current search */ + /* edge lies on a bounding box triangle and will be deleted. */ + dummytri[0] = encode(searchedge); + hullsize = -2l; + while (!triedgeequal(nextedge, finaledge)) { + hullsize++; + lprev(nextedge, dissolveedge); + symself(dissolveedge); + /* If not using a PSLG, the vertices should be marked now. */ + /* (If using a PSLG, markhull() will do the job.) */ + if (!poly) { + /* Be careful! One must check for the case where all the input */ + /* points are collinear, and thus all the triangles are part of */ + /* the bounding box. Otherwise, the setpointmark() call below */ + /* will cause a bad pointer reference. */ + if (dissolveedge.tri != dummytri) { + org(dissolveedge, markorg); + if (pointmark(markorg) == 0) { + setpointmark(markorg, 1); + } + } + } + /* Disconnect the bounding box triangle from the mesh triangle. */ + dissolve(dissolveedge); + lnext(nextedge, deadtri); + sym(deadtri, nextedge); + /* Get rid of the bounding box triangle. */ + triangledealloc(deadtri.tri); + /* Do we need to turn the corner? */ + if (nextedge.tri == dummytri) { + /* Turn the corner. */ + triedgecopy(dissolveedge, nextedge); + } + } + triangledealloc(finaledge.tri); + + free(infpoint1); /* Deallocate the bounding box vertices. */ + free(infpoint2); + free(infpoint3); + + return hullsize; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* incrementaldelaunay() Form a Delaunay triangulation by incrementally */ +/* adding vertices. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +long incrementaldelaunay() +{ + struct triedge starttri; + point pointloop; + int i; + + /* Create a triangular bounding box. */ + boundingbox(); + if (verbose) { + printf(" Incrementally inserting points.\n"); + } + traversalinit(&points); + pointloop = pointtraverse(); + i = 1; + while (pointloop != (point) NULL) { + /* Find a boundary triangle to search from. */ + starttri.tri = (triangle *) NULL; + if (insertsite(pointloop, &starttri, (struct edge *) NULL, 0, 0) == + DUPLICATEPOINT) { + if (!quiet) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + pointloop[0], pointloop[1]); + } +/* Commented out - would eliminate point from output .node file. + setpointmark(pointloop, DEADPOINT); +*/ + } + pointloop = pointtraverse(); + i++; + } + /* Remove the bounding box. */ + return removebox(); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Incremental Delaunay triangulation ends here *********/ + +/********* Sweepline Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +#ifndef REDUCED + +void eventheapinsert(heap, heapsize, newevent) +struct event **heap; +int heapsize; +struct event *newevent; +{ + REAL eventx, eventy; + int eventnum; + int parent; + int notdone; + + eventx = newevent->xkey; + eventy = newevent->ykey; + eventnum = heapsize; + notdone = eventnum > 0; + while (notdone) { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } + heap[eventnum] = newevent; + newevent->heapposition = eventnum; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void eventheapify(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +{ + struct event *thisevent; + REAL eventx, eventy; + int leftchild, rightchild; + int smallest; + int notdone; + + thisevent = heap[eventnum]; + eventx = thisevent->xkey; + eventy = thisevent->ykey; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + while (notdone) { + if ((heap[leftchild]->ykey < eventy) || + ((heap[leftchild]->ykey == eventy) + && (heap[leftchild]->xkey < eventx))) { + smallest = leftchild; + } else { + smallest = eventnum; + } + rightchild = leftchild + 1; + if (rightchild < heapsize) { + if ((heap[rightchild]->ykey < heap[smallest]->ykey) || + ((heap[rightchild]->ykey == heap[smallest]->ykey) + && (heap[rightchild]->xkey < heap[smallest]->xkey))) { + smallest = rightchild; + } + } + if (smallest == eventnum) { + notdone = 0; + } else { + heap[eventnum] = heap[smallest]; + heap[eventnum]->heapposition = eventnum; + heap[smallest] = thisevent; + thisevent->heapposition = smallest; + + eventnum = smallest; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void eventheapdelete(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +{ + struct event *moveevent; + REAL eventx, eventy; + int parent; + int notdone; + + moveevent = heap[heapsize - 1]; + if (eventnum > 0) { + eventx = moveevent->xkey; + eventy = moveevent->ykey; + do { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } while (notdone); + } + heap[eventnum] = moveevent; + moveevent->heapposition = eventnum; + eventheapify(heap, heapsize - 1, eventnum); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void createeventheap(eventheap, events, freeevents) +struct event ***eventheap; +struct event **events; +struct event **freeevents; +{ + point thispoint; + int maxevents; + int i; + + maxevents = (3 * inpoints) / 2; + *eventheap = (struct event **) malloc(maxevents * sizeof(struct event *)); + if (*eventheap == (struct event **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *events = (struct event *) malloc(maxevents * sizeof(struct event)); + if (*events == (struct event *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + traversalinit(&points); + for (i = 0; i < inpoints; i++) { + thispoint = pointtraverse(); + (*events)[i].eventptr = (VOID *) thispoint; + (*events)[i].xkey = thispoint[0]; + (*events)[i].ykey = thispoint[1]; + eventheapinsert(*eventheap, i, *events + i); + } + *freeevents = (struct event *) NULL; + for (i = maxevents - 1; i >= inpoints; i--) { + (*events)[i].eventptr = (VOID *) *freeevents; + *freeevents = *events + i; + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +int rightofhyperbola(fronttri, newsite) +struct triedge *fronttri; +point newsite; +{ + point leftpoint, rightpoint; + REAL dxa, dya, dxb, dyb; + + hyperbolacount++; + + dest(*fronttri, leftpoint); + apex(*fronttri, rightpoint); + if ((leftpoint[1] < rightpoint[1]) + || ((leftpoint[1] == rightpoint[1]) && (leftpoint[0] < rightpoint[0]))) { + if (newsite[0] >= rightpoint[0]) { + return 1; + } + } else { + if (newsite[0] <= leftpoint[0]) { + return 0; + } + } + dxa = leftpoint[0] - newsite[0]; + dya = leftpoint[1] - newsite[1]; + dxb = rightpoint[0] - newsite[0]; + dyb = rightpoint[1] - newsite[1]; + return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +REAL circletop(pa, pb, pc, ccwabc) +point pa; +point pb; +point pc; +REAL ccwabc; +{ + REAL xac, yac, xbc, ybc, xab, yab; + REAL aclen2, bclen2, ablen2; + + circletopcount++; + + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + xab = pa[0] - pb[0]; + yab = pa[1] - pb[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + ablen2 = xab * xab + yab * yab; + return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2)) + / (2.0 * ccwabc); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void check4deadevent(checktri, freeevents, eventheap, heapsize) +struct triedge *checktri; +struct event **freeevents; +struct event **eventheap; +int *heapsize; +{ + struct event *deadevent; + point eventpoint; + int eventnum; + + org(*checktri, eventpoint); + if (eventpoint != (point) NULL) { + deadevent = (struct event *) eventpoint; + eventnum = deadevent->heapposition; + deadevent->eventptr = (VOID *) *freeevents; + *freeevents = deadevent; + eventheapdelete(eventheap, *heapsize, eventnum); + (*heapsize)--; + setorg(*checktri, NULL); + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *splay(splaytree, searchpoint, searchtri) +struct splaynode *splaytree; +point searchpoint; +struct triedge *searchtri; +{ + struct splaynode *child, *grandchild; + struct splaynode *lefttree, *righttree; + struct splaynode *leftright; + point checkpoint; + int rightofroot, rightofchild; + + if (splaytree == (struct splaynode *) NULL) { + return (struct splaynode *) NULL; + } + dest(splaytree->keyedge, checkpoint); + if (checkpoint == splaytree->keydest) { + rightofroot = rightofhyperbola(&splaytree->keyedge, searchpoint); + if (rightofroot) { + triedgecopy(splaytree->keyedge, *searchtri); + child = splaytree->rchild; + } else { + child = splaytree->lchild; + } + if (child == (struct splaynode *) NULL) { + return splaytree; + } + dest(child->keyedge, checkpoint); + if (checkpoint != child->keydest) { + child = splay(child, searchpoint, searchtri); + if (child == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = (struct splaynode *) NULL; + } else { + splaytree->lchild = (struct splaynode *) NULL; + } + return splaytree; + } + } + rightofchild = rightofhyperbola(&child->keyedge, searchpoint); + if (rightofchild) { + triedgecopy(child->keyedge, *searchtri); + grandchild = splay(child->rchild, searchpoint, searchtri); + child->rchild = grandchild; + } else { + grandchild = splay(child->lchild, searchpoint, searchtri); + child->lchild = grandchild; + } + if (grandchild == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + return child; + } + if (rightofchild) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = grandchild->rchild; + grandchild->rchild = splaytree; + } + child->rchild = grandchild->lchild; + grandchild->lchild = child; + } else { + if (rightofroot) { + splaytree->rchild = grandchild->lchild; + grandchild->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + child->lchild = grandchild->rchild; + grandchild->rchild = child; + } + return grandchild; + } else { + lefttree = splay(splaytree->lchild, searchpoint, searchtri); + righttree = splay(splaytree->rchild, searchpoint, searchtri); + + pooldealloc(&splaynodes, (VOID *) splaytree); + if (lefttree == (struct splaynode *) NULL) { + return righttree; + } else if (righttree == (struct splaynode *) NULL) { + return lefttree; + } else if (lefttree->rchild == (struct splaynode *) NULL) { + lefttree->rchild = righttree->lchild; + righttree->lchild = lefttree; + return righttree; + } else if (righttree->lchild == (struct splaynode *) NULL) { + righttree->lchild = lefttree->rchild; + lefttree->rchild = righttree; + return lefttree; + } else { +/* printf("Holy Toledo!!!\n"); */ + leftright = lefttree->rchild; + while (leftright->rchild != (struct splaynode *) NULL) { + leftright = leftright->rchild; + } + leftright->rchild = righttree; + return lefttree; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *splayinsert(splayroot, newkey, searchpoint) +struct splaynode *splayroot; +struct triedge *newkey; +point searchpoint; +{ + struct splaynode *newsplaynode; + + newsplaynode = (struct splaynode *) poolalloc(&splaynodes); + triedgecopy(*newkey, newsplaynode->keyedge); + dest(*newkey, newsplaynode->keydest); + if (splayroot == (struct splaynode *) NULL) { + newsplaynode->lchild = (struct splaynode *) NULL; + newsplaynode->rchild = (struct splaynode *) NULL; + } else if (rightofhyperbola(&splayroot->keyedge, searchpoint)) { + newsplaynode->lchild = splayroot; + newsplaynode->rchild = splayroot->rchild; + splayroot->rchild = (struct splaynode *) NULL; + } else { + newsplaynode->lchild = splayroot->lchild; + newsplaynode->rchild = splayroot; + splayroot->lchild = (struct splaynode *) NULL; + } + return newsplaynode; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *circletopinsert(splayroot, newkey, pa, pb, pc, topy) +struct splaynode *splayroot; +struct triedge *newkey; +point pa; +point pb; +point pc; +REAL topy; +{ + REAL ccwabc; + REAL xac, yac, xbc, ybc; + REAL aclen2, bclen2; + REAL searchpoint[2]; + struct triedge dummytri; + + ccwabc = counterclockwise(pa, pb, pc); + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc); + searchpoint[1] = topy; + return splayinsert(splay(splayroot, (point) searchpoint, &dummytri), newkey, + (point) searchpoint); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *frontlocate(splayroot, bottommost, searchpoint, searchtri, + farright) +struct splaynode *splayroot; +struct triedge *bottommost; +point searchpoint; +struct triedge *searchtri; +int *farright; +{ + int farrightflag; + triangle ptr; /* Temporary variable used by onext(). */ + + triedgecopy(*bottommost, *searchtri); + splayroot = splay(splayroot, searchpoint, searchtri); + + farrightflag = 0; + while (!farrightflag && rightofhyperbola(searchtri, searchpoint)) { + onextself(*searchtri); + farrightflag = triedgeequal(*searchtri, *bottommost); + } + *farright = farrightflag; + return splayroot; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +long sweeplinedelaunay() +{ + struct event **eventheap; + struct event *events; + struct event *freeevents; + struct event *nextevent; + struct event *newevent; + struct splaynode *splayroot; + struct triedge bottommost; + struct triedge searchtri; + struct triedge fliptri; + struct triedge lefttri, righttri, farlefttri, farrighttri; + struct triedge inserttri; + point firstpoint, secondpoint; + point nextpoint, lastpoint; + point connectpoint; + point leftpoint, midpoint, rightpoint; + REAL lefttest, righttest; + int heapsize; + int check4events, farrightflag; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + poolinit(&splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK, POINTER, + 0); + splayroot = (struct splaynode *) NULL; + + if (verbose) { + printf(" Placing points in event heap.\n"); + } + createeventheap(&eventheap, &events, &freeevents); + heapsize = inpoints; + + if (verbose) { + printf(" Forming triangulation.\n"); + } + maketriangle(&lefttri); + maketriangle(&righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + firstpoint = (point) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + do { + if (heapsize == 0) { + printf("Error: Input points are all identical.\n"); + exit(1); + } + secondpoint = (point) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + if ((firstpoint[0] == secondpoint[0]) + && (firstpoint[1] == secondpoint[1])) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + secondpoint[0], secondpoint[1]); +/* Commented out - would eliminate point from output .node file. + setpointmark(secondpoint, DEADPOINT); +*/ + } + } while ((firstpoint[0] == secondpoint[0]) + && (firstpoint[1] == secondpoint[1])); + setorg(lefttri, firstpoint); + setdest(lefttri, secondpoint); + setorg(righttri, secondpoint); + setdest(righttri, firstpoint); + lprev(lefttri, bottommost); + lastpoint = secondpoint; + while (heapsize > 0) { + nextevent = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + check4events = 1; + if (nextevent->xkey < xmin) { + decode(nextevent->eventptr, fliptri); + oprev(fliptri, farlefttri); + check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize); + onext(fliptri, farrighttri); + check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize); + + if (triedgeequal(farlefttri, bottommost)) { + lprev(fliptri, bottommost); + } + flip(&fliptri); + setapex(fliptri, NULL); + lprev(fliptri, lefttri); + lnext(fliptri, righttri); + sym(lefttri, farlefttri); + + if (randomnation(SAMPLERATE) == 0) { + symself(fliptri); + dest(fliptri, leftpoint); + apex(fliptri, midpoint); + org(fliptri, rightpoint); + splayroot = circletopinsert(splayroot, &lefttri, leftpoint, midpoint, + rightpoint, nextevent->ykey); + } + } else { + nextpoint = (point) nextevent->eventptr; + if ((nextpoint[0] == lastpoint[0]) && (nextpoint[1] == lastpoint[1])) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + nextpoint[0], nextpoint[1]); +/* Commented out - would eliminate point from output .node file. + setpointmark(nextpoint, DEADPOINT); +*/ + check4events = 0; + } else { + lastpoint = nextpoint; + + splayroot = frontlocate(splayroot, &bottommost, nextpoint, &searchtri, + &farrightflag); +/* + triedgecopy(bottommost, searchtri); + farrightflag = 0; + while (!farrightflag && rightofhyperbola(&searchtri, nextpoint)) { + onextself(searchtri); + farrightflag = triedgeequal(searchtri, bottommost); + } +*/ + + check4deadevent(&searchtri, &freeevents, eventheap, &heapsize); + + triedgecopy(searchtri, farrighttri); + sym(searchtri, farlefttri); + maketriangle(&lefttri); + maketriangle(&righttri); + dest(farrighttri, connectpoint); + setorg(lefttri, connectpoint); + setdest(lefttri, nextpoint); + setorg(righttri, nextpoint); + setdest(righttri, connectpoint); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, farlefttri); + bond(righttri, farrighttri); + if (!farrightflag && triedgeequal(farrighttri, bottommost)) { + triedgecopy(lefttri, bottommost); + } + + if (randomnation(SAMPLERATE) == 0) { + splayroot = splayinsert(splayroot, &lefttri, nextpoint); + } else if (randomnation(SAMPLERATE) == 0) { + lnext(righttri, inserttri); + splayroot = splayinsert(splayroot, &inserttri, nextpoint); + } + } + } + nextevent->eventptr = (VOID *) freeevents; + freeevents = nextevent; + + if (check4events) { + apex(farlefttri, leftpoint); + dest(lefttri, midpoint); + apex(lefttri, rightpoint); + lefttest = counterclockwise(leftpoint, midpoint, rightpoint); + if (lefttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = xminextreme; + newevent->ykey = circletop(leftpoint, midpoint, rightpoint, + lefttest); + newevent->eventptr = (VOID *) encode(lefttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(lefttri, newevent); + } + apex(righttri, leftpoint); + org(righttri, midpoint); + apex(farrighttri, rightpoint); + righttest = counterclockwise(leftpoint, midpoint, rightpoint); + if (righttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = xminextreme; + newevent->ykey = circletop(leftpoint, midpoint, rightpoint, + righttest); + newevent->eventptr = (VOID *) encode(farrighttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(farrighttri, newevent); + } + } + } + + pooldeinit(&splaynodes); + lprevself(bottommost); + return removeghosts(&bottommost); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Sweepline Delaunay triangulation ends here *********/ + +/********* General mesh construction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* delaunay() Form a Delaunay triangulation. */ +/* */ +/*****************************************************************************/ + +long delaunay() +{ + eextras = 0; + initializetrisegpools(); + +#ifdef REDUCED + if (!quiet) { + printf( + "Constructing Delaunay triangulation by divide-and-conquer method.\n"); + } + return divconqdelaunay(); +#else /* not REDUCED */ + if (!quiet) { + printf("Constructing Delaunay triangulation "); + if (incremental) { + printf("by incremental method.\n"); + } else if (sweepline) { + printf("by sweepline method.\n"); + } else { + printf("by divide-and-conquer method.\n"); + } + } + if (incremental) { + return incrementaldelaunay(); + } else if (sweepline) { + return sweeplinedelaunay(); + } else { + return divconqdelaunay(); + } +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* reconstruct() Reconstruct a triangulation from its .ele (and possibly */ +/* .poly) file. Used when the -r switch is used. */ +/* */ +/* Reads an .ele file and reconstructs the original mesh. If the -p switch */ +/* is used, this procedure will also read a .poly file and reconstruct the */ +/* shell edges of the original mesh. If the -a switch is used, this */ +/* procedure will also read an .area file and set a maximum area constraint */ +/* on each triangle. */ +/* */ +/* Points that are not corners of triangles, such as nodes on edges of */ +/* subparametric elements, are discarded. */ +/* */ +/* This routine finds the adjacencies between triangles (and shell edges) */ +/* by forming one stack of triangles for each vertex. Each triangle is on */ +/* three different stacks simultaneously. Each triangle's shell edge */ +/* pointers are used to link the items in each stack. This memory-saving */ +/* feature makes the code harder to read. The most important thing to keep */ +/* in mind is that each triangle is removed from a stack precisely when */ +/* the corresponding pointer is adjusted to refer to a shell edge rather */ +/* than the next triangle of the stack. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef TRILIBRARY + +int reconstruct(trianglelist, triangleattriblist, trianglearealist, elements, + corners, attribs, segmentlist, segmentmarkerlist, + numberofsegments) +int *trianglelist; +REAL *triangleattriblist; +REAL *trianglearealist; +int elements; +int corners; +int attribs; +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; + +#else /* not TRILIBRARY */ + +long reconstruct(elefilename, areafilename, polyfilename, polyfile) +char *elefilename; +char *areafilename; +char *polyfilename; +FILE *polyfile; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int pointindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *elefile; + FILE *areafile; + char inputline[INPUTLINESIZE]; + char *stringptr; + int areaelements; +#endif /* not TRILIBRARY */ + struct triedge triangleloop; + struct triedge triangleleft; + struct triedge checktri; + struct triedge checkleft; + struct triedge checkneighbor; + struct edge shelleloop; + triangle *vertexarray; + triangle *prevlink; + triangle nexttri; + point tdest, tapex; + point checkdest, checkapex; + point shorg; + point killpoint; + REAL area; + int corner[3]; + int end[2]; + int killpointindex; + int incorners; + int segmentmarkers; + int boundmarker; + int aroundpoint; + long hullsize; + int notfound; + int elementnumber, segmentnumber; + int i, j; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + inelements = elements; + incorners = corners; + if (incorners < 3) { + printf("Error: Triangles must have at least 3 points.\n"); + exit(1); + } + eextras = attribs; +#else /* not TRILIBRARY */ + /* Read the triangles from an .ele file. */ + if (!quiet) { + printf("Opening %s.\n", elefilename); + } + elefile = fopen(elefilename, "r"); + if (elefile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", elefilename); + exit(1); + } + /* Read number of triangles, number of points per triangle, and */ + /* number of triangle attributes from .ele file. */ + stringptr = readline(inputline, elefile, elefilename); + inelements = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + incorners = 3; + } else { + incorners = (int) strtol (stringptr, &stringptr, 0); + if (incorners < 3) { + printf("Error: Triangles in %s must have at least 3 points.\n", + elefilename); + exit(1); + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + eextras = 0; + } else { + eextras = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + initializetrisegpools(); + + /* Create the triangles. */ + for (elementnumber = 1; elementnumber <= inelements; elementnumber++) { + maketriangle(&triangleloop); + /* Mark the triangle as living. */ + triangleloop.tri[3] = (triangle) triangleloop.tri; + } + + if (poly) { +#ifdef TRILIBRARY + insegments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; +#else /* not TRILIBRARY */ + /* Read number of segments and number of segment */ + /* boundary markers from .poly file. */ + stringptr = readline(inputline, polyfile, inpolyfilename); + insegments = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + /* Create the shell edges. */ + for (segmentnumber = 1; segmentnumber <= insegments; segmentnumber++) { + makeshelle(&shelleloop); + /* Mark the shell edge as living. */ + shelleloop.sh[2] = (shelle) shelleloop.sh; + } + } + +#ifdef TRILIBRARY + pointindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (vararea) { + /* Open an .area file, check for consistency with the .ele file. */ + if (!quiet) { + printf("Opening %s.\n", areafilename); + } + areafile = fopen(areafilename, "r"); + if (areafile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", areafilename); + exit(1); + } + stringptr = readline(inputline, areafile, areafilename); + areaelements = (int) strtol (stringptr, &stringptr, 0); + if (areaelements != inelements) { + printf("Error: %s and %s disagree on number of triangles.\n", + elefilename, areafilename); + exit(1); + } + } +#endif /* not TRILIBRARY */ + + if (!quiet) { + printf("Reconstructing mesh.\n"); + } + /* Allocate a temporary array that maps each point to some adjacent */ + /* triangle. I took care to allocate all the permanent memory for */ + /* triangles and shell edges first. */ + vertexarray = (triangle *) malloc(points.items * sizeof(triangle)); + if (vertexarray == (triangle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Each point is initially unrepresented. */ + for (i = 0; i < points.items; i++) { + vertexarray[i] = (triangle) dummytri; + } + + if (verbose) { + printf(" Assembling triangles.\n"); + } + /* Read the triangles from the .ele file, and link */ + /* together those that share an edge. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { +#ifdef TRILIBRARY + /* Copy the triangle's three corners. */ + for (j = 0; j < 3; j++) { + corner[j] = trianglelist[pointindex++]; + if ((corner[j] < firstnumber) || (corner[j] >= firstnumber + inpoints)) { + printf("Error: Triangle %d has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } +#else /* not TRILIBRARY */ + /* Read triangle number and the triangle's three corners. */ + stringptr = readline(inputline, elefile, elefilename); + for (j = 0; j < 3; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Triangle %d is missing point %d in %s.\n", + elementnumber, j + 1, elefilename); + exit(1); + } else { + corner[j] = (int) strtol (stringptr, &stringptr, 0); + if ((corner[j] < firstnumber) || + (corner[j] >= firstnumber + inpoints)) { + printf("Error: Triangle %d has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } + } +#endif /* not TRILIBRARY */ + + /* Find out about (and throw away) extra nodes. */ + for (j = 3; j < incorners; j++) { +#ifdef TRILIBRARY + killpointindex = trianglelist[pointindex++]; +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr != '\0') { + killpointindex = (int) strtol (stringptr, &stringptr, 0); +#endif /* not TRILIBRARY */ + if ((killpointindex >= firstnumber) && + (killpointindex < firstnumber + inpoints)) { + /* Delete the non-corner point if it's not already deleted. */ + killpoint = getpoint(killpointindex); + if (pointmark(killpoint) != DEADPOINT) { + pointdealloc(killpoint); + } + } +#ifndef TRILIBRARY + } +#endif /* not TRILIBRARY */ + } + + /* Read the triangle's attributes. */ + for (j = 0; j < eextras; j++) { +#ifdef TRILIBRARY + setelemattribute(triangleloop, j, triangleattriblist[attribindex++]); +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setelemattribute(triangleloop, j, 0); + } else { + setelemattribute(triangleloop, j, + (REAL) strtod (stringptr, &stringptr)); + } +#endif /* not TRILIBRARY */ + } + + if (vararea) { +#ifdef TRILIBRARY + area = trianglearealist[elementnumber - firstnumber]; +#else /* not TRILIBRARY */ + /* Read an area constraint from the .area file. */ + stringptr = readline(inputline, areafile, areafilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + area = -1.0; /* No constraint on this triangle. */ + } else { + area = (REAL) strtod(stringptr, &stringptr); + } +#endif /* not TRILIBRARY */ + setareabound(triangleloop, area); + } + + /* Set the triangle's vertices. */ + triangleloop.orient = 0; + setorg(triangleloop, getpoint(corner[0])); + setdest(triangleloop, getpoint(corner[1])); + setapex(triangleloop, getpoint(corner[2])); + /* Try linking the triangle to others that share these vertices. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + /* Take the number for the origin of triangleloop. */ + aroundpoint = corner[triangleloop.orient]; + /* Look for other triangles having this vertex. */ + nexttri = vertexarray[aroundpoint - firstnumber]; + /* Link the current triangle to the next one in the stack. */ + triangleloop.tri[6 + triangleloop.orient] = nexttri; + /* Push the current triangle onto the stack. */ + vertexarray[aroundpoint - firstnumber] = encode(triangleloop); + decode(nexttri, checktri); + if (checktri.tri != dummytri) { + dest(triangleloop, tdest); + apex(triangleloop, tapex); + /* Look for other triangles that share an edge. */ + do { + dest(checktri, checkdest); + apex(checktri, checkapex); + if (tapex == checkdest) { + /* The two triangles share an edge; bond them together. */ + lprev(triangleloop, triangleleft); + bond(triangleleft, checktri); + } + if (tdest == checkapex) { + /* The two triangles share an edge; bond them together. */ + lprev(checktri, checkleft); + bond(triangleloop, checkleft); + } + /* Find the next triangle in the stack. */ + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } while (checktri.tri != dummytri); + } + } + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifdef TRILIBRARY + pointindex = 0; +#else /* not TRILIBRARY */ + fclose(elefile); + if (vararea) { + fclose(areafile); + } +#endif /* not TRILIBRARY */ + + hullsize = 0; /* Prepare to count the boundary edges. */ + if (poly) { + if (verbose) { + printf(" Marking segments in triangulation.\n"); + } + /* Read the segments from the .poly file, and link them */ + /* to their neighboring triangles. */ + boundmarker = 0; + traversalinit(&shelles); + shelleloop.sh = shelletraverse(); + segmentnumber = firstnumber; + while (shelleloop.sh != (shelle *) NULL) { +#ifdef TRILIBRARY + end[0] = segmentlist[pointindex++]; + end[1] = segmentlist[pointindex++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[segmentnumber - firstnumber]; + } +#else /* not TRILIBRARY */ + /* Read the endpoints of each segment, and possibly a boundary marker. */ + stringptr = readline(inputline, polyfile, inpolyfilename); + /* Skip the first (segment number) field. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", segmentnumber, + polyfilename); + exit(1); + } else { + end[0] = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", + segmentnumber, polyfilename); + exit(1); + } else { + end[1] = (int) strtol (stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol (stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + for (j = 0; j < 2; j++) { + if ((end[j] < firstnumber) || (end[j] >= firstnumber + inpoints)) { + printf("Error: Segment %d has an invalid vertex index.\n", + segmentnumber); + exit(1); + } + } + + /* set the shell edge's vertices. */ + shelleloop.shorient = 0; + setsorg(shelleloop, getpoint(end[0])); + setsdest(shelleloop, getpoint(end[1])); + setmark(shelleloop, boundmarker); + /* Try linking the shell edge to triangles that share these vertices. */ + for (shelleloop.shorient = 0; shelleloop.shorient < 2; + shelleloop.shorient++) { + /* Take the number for the destination of shelleloop. */ + aroundpoint = end[1 - shelleloop.shorient]; + /* Look for triangles having this vertex. */ + prevlink = &vertexarray[aroundpoint - firstnumber]; + nexttri = vertexarray[aroundpoint - firstnumber]; + decode(nexttri, checktri); + sorg(shelleloop, shorg); + notfound = 1; + /* Look for triangles having this edge. Note that I'm only */ + /* comparing each triangle's destination with the shell edge; */ + /* each triangle's apex is handled through a different vertex. */ + /* Because each triangle appears on three vertices' lists, each */ + /* occurrence of a triangle on a list can (and does) represent */ + /* an edge. In this way, most edges are represented twice, and */ + /* every triangle-segment bond is represented once. */ + while (notfound && (checktri.tri != dummytri)) { + dest(checktri, checkdest); + if (shorg == checkdest) { + /* We have a match. Remove this triangle from the list. */ + *prevlink = checktri.tri[6 + checktri.orient]; + /* Bond the shell edge to the triangle. */ + tsbond(checktri, shelleloop); + /* Check if this is a boundary edge. */ + sym(checktri, checkneighbor); + if (checkneighbor.tri == dummytri) { + /* The next line doesn't insert a shell edge (because there's */ + /* already one there), but it sets the boundary markers of */ + /* the existing shell edge and its vertices. */ + insertshelle(&checktri, 1); + hullsize++; + } + notfound = 0; + } + /* Find the next triangle in the stack. */ + prevlink = &checktri.tri[6 + checktri.orient]; + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } + } + shelleloop.sh = shelletraverse(); + segmentnumber++; + } + } + + /* Mark the remaining edges as not being attached to any shell edge. */ + /* Also, count the (yet uncounted) boundary edges. */ + for (i = 0; i < points.items; i++) { + /* Search the stack of triangles adjacent to a point. */ + nexttri = vertexarray[i]; + decode(nexttri, checktri); + while (checktri.tri != dummytri) { + /* Find the next triangle in the stack before this */ + /* information gets overwritten. */ + nexttri = checktri.tri[6 + checktri.orient]; + /* No adjacent shell edge. (This overwrites the stack info.) */ + tsdissolve(checktri); + sym(checktri, checkneighbor); + if (checkneighbor.tri == dummytri) { + insertshelle(&checktri, 1); + hullsize++; + } + decode(nexttri, checktri); + } + } + + free(vertexarray); + return hullsize; +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* General mesh construction routines end here *********/ + +/********* Segment (shell edge) insertion begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* finddirection() Find the first triangle on the path from one point */ +/* to another. */ +/* */ +/* Finds the triangle that intersects a line segment drawn from the */ +/* origin of `searchtri' to the point `endpoint', and returns the result */ +/* in `searchtri'. The origin of `searchtri' does not change, even though */ +/* the triangle returned may differ from the one passed in. This routine */ +/* is used to find the direction to move in to get from one point to */ +/* another. */ +/* */ +/* The return value notes whether the destination or apex of the found */ +/* triangle is collinear with the two points in question. */ +/* */ +/*****************************************************************************/ + +enum finddirectionresult finddirection(searchtri, endpoint) +struct triedge *searchtri; +point endpoint; +{ + struct triedge checktri; + point startpoint; + point leftpoint, rightpoint; + REAL leftccw, rightccw; + int leftflag, rightflag; + triangle ptr; /* Temporary variable used by onext() and oprev(). */ + + org(*searchtri, startpoint); + dest(*searchtri, rightpoint); + apex(*searchtri, leftpoint); + /* Is `endpoint' to the left? */ + leftccw = counterclockwise(endpoint, startpoint, leftpoint); + leftflag = leftccw > 0.0; + /* Is `endpoint' to the right? */ + rightccw = counterclockwise(startpoint, endpoint, rightpoint); + rightflag = rightccw > 0.0; + if (leftflag && rightflag) { + /* `searchtri' faces directly away from `endpoint'. We could go */ + /* left or right. Ask whether it's a triangle or a boundary */ + /* on the left. */ + onext(*searchtri, checktri); + if (checktri.tri == dummytri) { + leftflag = 0; + } else { + rightflag = 0; + } + } + while (leftflag) { + /* Turn left until satisfied. */ + onextself(*searchtri); + if (searchtri->tri == dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], + startpoint[1]); + printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); + internalerror(); + } + apex(*searchtri, leftpoint); + rightccw = leftccw; + leftccw = counterclockwise(endpoint, startpoint, leftpoint); + leftflag = leftccw > 0.0; + } + while (rightflag) { + /* Turn right until satisfied. */ + oprevself(*searchtri); + if (searchtri->tri == dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], + startpoint[1]); + printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); + internalerror(); + } + dest(*searchtri, rightpoint); + leftccw = rightccw; + rightccw = counterclockwise(startpoint, endpoint, rightpoint); + rightflag = rightccw > 0.0; + } + if (leftccw == 0.0) { + return LEFTCOLLINEAR; + } else if (rightccw == 0.0) { + return RIGHTCOLLINEAR; + } else { + return WITHIN; + } +} + +/*****************************************************************************/ +/* */ +/* segmentintersection() Find the intersection of an existing segment */ +/* and a segment that is being inserted. Insert */ +/* a point at the intersection, splitting an */ +/* existing shell edge. */ +/* */ +/* The segment being inserted connects the apex of splittri to endpoint2. */ +/* splitshelle is the shell edge being split, and MUST be opposite */ +/* splittri. Hence, the edge being split connects the origin and */ +/* destination of splittri. */ +/* */ +/* On completion, splittri is a handle having the newly inserted */ +/* intersection point as its origin, and endpoint1 as its destination. */ +/* */ +/*****************************************************************************/ + +void segmentintersection(splittri, splitshelle, endpoint2) +struct triedge *splittri; +struct edge *splitshelle; +point endpoint2; +{ + point endpoint1; + point torg, tdest; + point leftpoint, rightpoint; + point newpoint; + enum insertsiteresult success; + enum finddirectionresult collinear; + REAL ex, ey; + REAL tx, ty; + REAL etx, ety; + REAL split, denom; + int i; + triangle ptr; /* Temporary variable used by onext(). */ + + /* Find the other three segment endpoints. */ + apex(*splittri, endpoint1); + org(*splittri, torg); + dest(*splittri, tdest); + /* Segment intersection formulae; see the Antonio reference. */ + tx = tdest[0] - torg[0]; + ty = tdest[1] - torg[1]; + ex = endpoint2[0] - endpoint1[0]; + ey = endpoint2[1] - endpoint1[1]; + etx = torg[0] - endpoint2[0]; + ety = torg[1] - endpoint2[1]; + denom = ty * ex - tx * ey; + if (denom == 0.0) { + printf("Internal error in segmentintersection():"); + printf(" Attempt to find intersection of parallel segments.\n"); + internalerror(); + } + split = (ey * etx - ex * ety) / denom; + /* Create the new point. */ + newpoint = (point) poolalloc(&points); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = torg[i] + split * (tdest[i] - torg[i]); + } + setpointmark(newpoint, mark(*splitshelle)); + if (verbose > 1) { + printf( + " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + torg[0], torg[1], tdest[0], tdest[1], newpoint[0], newpoint[1]); + } + /* Insert the intersection point. This should always succeed. */ + success = insertsite(newpoint, splittri, splitshelle, 0, 0); + if (success != SUCCESSFULPOINT) { + printf("Internal error in segmentintersection():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (steinerleft > 0) { + steinerleft--; + } + /* Inserting the point may have caused edge flips. We wish to rediscover */ + /* the edge connecting endpoint1 to the new intersection point. */ + collinear = finddirection(splittri, endpoint1); + dest(*splittri, rightpoint); + apex(*splittri, leftpoint); + if ((leftpoint[0] == endpoint1[0]) && (leftpoint[1] == endpoint1[1])) { + onextself(*splittri); + } else if ((rightpoint[0] != endpoint1[0]) || + (rightpoint[1] != endpoint1[1])) { + printf("Internal error in segmentintersection():\n"); + printf(" Topological inconsistency after splitting a segment.\n"); + internalerror(); + } + /* `splittri' should have destination endpoint1. */ +} + +/*****************************************************************************/ +/* */ +/* scoutsegment() Scout the first triangle on the path from one endpoint */ +/* to another, and check for completion (reaching the */ +/* second endpoint), a collinear point, and the */ +/* intersection of two segments. */ +/* */ +/* Returns one if the entire segment is successfully inserted, and zero if */ +/* the job must be finished by conformingedge() or constrainededge(). */ +/* */ +/* If the first triangle on the path has the second endpoint as its */ +/* destination or apex, a shell edge is inserted and the job is done. */ +/* */ +/* If the first triangle on the path has a destination or apex that lies on */ +/* the segment, a shell edge is inserted connecting the first endpoint to */ +/* the collinear point, and the search is continued from the collinear */ +/* point. */ +/* */ +/* If the first triangle on the path has a shell edge opposite its origin, */ +/* then there is a segment that intersects the segment being inserted. */ +/* Their intersection point is inserted, splitting the shell edge. */ +/* */ +/* Otherwise, return zero. */ +/* */ +/*****************************************************************************/ + +int scoutsegment(searchtri, endpoint2, newmark) +struct triedge *searchtri; +point endpoint2; +int newmark; +{ + struct triedge crosstri; + struct edge crossedge; + point leftpoint, rightpoint; + point endpoint1; + enum finddirectionresult collinear; + shelle sptr; /* Temporary variable used by tspivot(). */ + + collinear = finddirection(searchtri, endpoint2); + dest(*searchtri, rightpoint); + apex(*searchtri, leftpoint); + if (((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) || + ((rightpoint[0] == endpoint2[0]) && (rightpoint[1] == endpoint2[1]))) { + /* The segment is already an edge in the mesh. */ + if ((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) { + lprevself(*searchtri); + } + /* Insert a shell edge, if there isn't already one there. */ + insertshelle(searchtri, newmark); + return 1; + } else if (collinear == LEFTCOLLINEAR) { + /* We've collided with a point between the segment's endpoints. */ + /* Make the collinear point be the triangle's origin. */ + lprevself(*searchtri); + insertshelle(searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } else if (collinear == RIGHTCOLLINEAR) { + /* We've collided with a point between the segment's endpoints. */ + insertshelle(searchtri, newmark); + /* Make the collinear point be the triangle's origin. */ + lnextself(*searchtri); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } else { + lnext(*searchtri, crosstri); + tspivot(crosstri, crossedge); + /* Check for a crossing segment. */ + if (crossedge.sh == dummysh) { + return 0; + } else { + org(*searchtri, endpoint1); + /* Insert a point at the intersection. */ + segmentintersection(&crosstri, &crossedge, endpoint2); + triedgecopy(crosstri, *searchtri); + insertshelle(searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* conformingedge() Force a segment into a conforming Delaunay */ +/* triangulation by inserting a point at its midpoint, */ +/* and recursively forcing in the two half-segments if */ +/* necessary. */ +/* */ +/* Generates a sequence of edges connecting `endpoint1' to `endpoint2'. */ +/* `newmark' is the boundary marker of the segment, assigned to each new */ +/* splitting point and shell edge. */ +/* */ +/* Note that conformingedge() does not always maintain the conforming */ +/* Delaunay property. Once inserted, segments are locked into place; */ +/* points inserted later (to force other segments in) may render these */ +/* fixed segments non-Delaunay. The conforming Delaunay property will be */ +/* restored by enforcequality() by splitting encroached segments. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED +#ifndef CDT_ONLY + +void conformingedge(endpoint1, endpoint2, newmark) +point endpoint1; +point endpoint2; +int newmark; +{ + struct triedge searchtri1, searchtri2; + struct edge brokenshelle; + point newpoint; + point midpoint1, midpoint2; + enum insertsiteresult success; + int result1, result2; + int i; + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose > 2) { + printf("Forcing segment into triangulation by recursive splitting:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1], + endpoint2[0], endpoint2[1]); + } + /* Create a new point to insert in the middle of the segment. */ + newpoint = (point) poolalloc(&points); + /* Interpolate coordinates and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]); + } + setpointmark(newpoint, newmark); + /* Find a boundary triangle to search from. */ + searchtri1.tri = (triangle *) NULL; + /* Attempt to insert the new point. */ + success = insertsite(newpoint, &searchtri1, (struct edge *) NULL, 0, 0); + if (success == DUPLICATEPOINT) { + if (verbose > 2) { + printf(" Segment intersects existing point (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + } + /* Use the point that's already there. */ + pointdealloc(newpoint); + org(searchtri1, newpoint); + } else { + if (success == VIOLATINGPOINT) { + if (verbose > 2) { + printf(" Two segments intersect at (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + } + /* By fluke, we've landed right on another segment. Split it. */ + tspivot(searchtri1, brokenshelle); + success = insertsite(newpoint, &searchtri1, &brokenshelle, 0, 0); + if (success != SUCCESSFULPOINT) { + printf("Internal error in conformingedge():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + } + /* The point has been inserted successfully. */ + if (steinerleft > 0) { + steinerleft--; + } + } + triedgecopy(searchtri1, searchtri2); + result1 = scoutsegment(&searchtri1, endpoint1, newmark); + result2 = scoutsegment(&searchtri2, endpoint2, newmark); + if (!result1) { + /* The origin of searchtri1 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri1, midpoint1); + conformingedge(midpoint1, endpoint1, newmark); + } + if (!result2) { + /* The origin of searchtri2 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri2, midpoint2); + conformingedge(midpoint2, endpoint2, newmark); + } +} + +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */ +/* recursively from an existing point. Pay special */ +/* attention to stacking inverted triangles. */ +/* */ +/* This is a support routine for inserting segments into a constrained */ +/* Delaunay triangulation. */ +/* */ +/* The origin of fixuptri is treated as if it has just been inserted, and */ +/* the local Delaunay condition needs to be enforced. It is only enforced */ +/* in one sector, however, that being the angular range defined by */ +/* fixuptri. */ +/* */ +/* This routine also needs to make decisions regarding the "stacking" of */ +/* triangles. (Read the description of constrainededge() below before */ +/* reading on here, so you understand the algorithm.) If the position of */ +/* the new point (the origin of fixuptri) indicates that the vertex before */ +/* it on the polygon is a reflex vertex, then "stack" the triangle by */ +/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */ +/* triangles are identified.) */ +/* */ +/* Otherwise, check whether the vertex before that was a reflex vertex. */ +/* If so, perform an edge flip, thereby eliminating an inverted triangle */ +/* (popping it off the stack). The edge flip may result in the creation */ +/* of a new inverted triangle, depending on whether or not the new vertex */ +/* is visible to the vertex three edges behind on the polygon. */ +/* */ +/* If neither of the two vertices behind the new vertex are reflex */ +/* vertices, fixuptri and fartri, the triangle opposite it, are not */ +/* inverted; hence, ensure that the edge between them is locally Delaunay. */ +/* */ +/* `leftside' indicates whether or not fixuptri is to the left of the */ +/* segment being inserted. (Imagine that the segment is pointing up from */ +/* endpoint1 to endpoint2.) */ +/* */ +/*****************************************************************************/ + +void delaunayfixup(fixuptri, leftside) +struct triedge *fixuptri; +int leftside; +{ + struct triedge neartri; + struct triedge fartri; + struct edge faredge; + point nearpoint, leftpoint, rightpoint, farpoint; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + lnext(*fixuptri, neartri); + sym(neartri, fartri); + /* Check if the edge opposite the origin of fixuptri can be flipped. */ + if (fartri.tri == dummytri) { + return; + } + tspivot(neartri, faredge); + if (faredge.sh != dummysh) { + return; + } + /* Find all the relevant vertices. */ + apex(neartri, nearpoint); + org(neartri, leftpoint); + dest(neartri, rightpoint); + apex(fartri, farpoint); + /* Check whether the previous polygon vertex is a reflex vertex. */ + if (leftside) { + if (counterclockwise(nearpoint, leftpoint, farpoint) <= 0.0) { + /* leftpoint is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } else { + if (counterclockwise(farpoint, rightpoint, nearpoint) <= 0.0) { + /* rightpoint is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } + if (counterclockwise(rightpoint, leftpoint, farpoint) > 0.0) { + /* fartri is not an inverted triangle, and farpoint is not a reflex */ + /* vertex. As there are no reflex vertices, fixuptri isn't an */ + /* inverted triangle, either. Hence, test the edge between the */ + /* triangles to ensure it is locally Delaunay. */ + if (incircle(leftpoint, farpoint, rightpoint, nearpoint) <= 0.0) { + return; + } + /* Not locally Delaunay; go on to an edge flip. */ + } /* else fartri is inverted; remove it from the stack by flipping. */ + flip(&neartri); + lprevself(*fixuptri); /* Restore the origin of fixuptri after the flip. */ + /* Recursively process the two triangles that result from the flip. */ + delaunayfixup(fixuptri, leftside); + delaunayfixup(&fartri, leftside); +} + +/*****************************************************************************/ +/* */ +/* constrainededge() Force a segment into a constrained Delaunay */ +/* triangulation by deleting the triangles it */ +/* intersects, and triangulating the polygons that */ +/* form on each side of it. */ +/* */ +/* Generates a single edge connecting `endpoint1' to `endpoint2'. The */ +/* triangle `starttri' has `endpoint1' as its origin. `newmark' is the */ +/* boundary marker of the segment. */ +/* */ +/* To insert a segment, every triangle whose interior intersects the */ +/* segment is deleted. The union of these deleted triangles is a polygon */ +/* (which is not necessarily monotone, but is close enough), which is */ +/* divided into two polygons by the new segment. This routine's task is */ +/* to generate the Delaunay triangulation of these two polygons. */ +/* */ +/* You might think of this routine's behavior as a two-step process. The */ +/* first step is to walk from endpoint1 to endpoint2, flipping each edge */ +/* encountered. This step creates a fan of edges connected to endpoint1, */ +/* including the desired edge to endpoint2. The second step enforces the */ +/* Delaunay condition on each side of the segment in an incremental manner: */ +/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */ +/* independently on each side of the segment), each vertex is "enforced" */ +/* as if it had just been inserted, but affecting only the previous */ +/* vertices. The result is the same as if the vertices had been inserted */ +/* in the order they appear on the polygon, so the result is Delaunay. */ +/* */ +/* In truth, constrainededge() interleaves these two steps. The procedure */ +/* walks from endpoint1 to endpoint2, and each time an edge is encountered */ +/* and flipped, the newly exposed vertex (at the far end of the flipped */ +/* edge) is "enforced" upon the previously flipped edges, usually affecting */ +/* only one side of the polygon (depending upon which side of the segment */ +/* the vertex falls on). */ +/* */ +/* The algorithm is complicated by the need to handle polygons that are not */ +/* convex. Although the polygon is not necessarily monotone, it can be */ +/* triangulated in a manner similar to the stack-based algorithms for */ +/* monotone polygons. For each reflex vertex (local concavity) of the */ +/* polygon, there will be an inverted triangle formed by one of the edge */ +/* flips. (An inverted triangle is one with negative area - that is, its */ +/* vertices are arranged in clockwise order - and is best thought of as a */ +/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */ +/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */ +/* later. */ +/* */ +/* A reflex vertex is popped from the stack when a vertex is inserted that */ +/* is visible to the reflex vertex. (However, if the vertex behind the */ +/* reflex vertex is not visible to the reflex vertex, a new inverted */ +/* triangle will take its place on the stack.) These details are handled */ +/* by the delaunayfixup() routine above. */ +/* */ +/*****************************************************************************/ + +void constrainededge(starttri, endpoint2, newmark) +struct triedge *starttri; +point endpoint2; +int newmark; +{ + struct triedge fixuptri, fixuptri2; + struct edge fixupedge; + point endpoint1; + point farpoint; + REAL area; + int collision; + int done; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*starttri, endpoint1); + lnext(*starttri, fixuptri); + flip(&fixuptri); + /* `collision' indicates whether we have found a point directly */ + /* between endpoint1 and endpoint2. */ + collision = 0; + done = 0; + do { + org(fixuptri, farpoint); + /* `farpoint' is the extreme point of the polygon we are "digging" */ + /* to get from endpoint1 to endpoint2. */ + if ((farpoint[0] == endpoint2[0]) && (farpoint[1] == endpoint2[1])) { + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around endpoint2. */ + delaunayfixup(&fixuptri, 0); + delaunayfixup(&fixuptri2, 1); + done = 1; + } else { + /* Check whether farpoint is to the left or right of the segment */ + /* being inserted, to decide which edge of fixuptri to dig */ + /* through next. */ + area = counterclockwise(endpoint1, endpoint2, farpoint); + if (area == 0.0) { + /* We've collided with a point between endpoint1 and endpoint2. */ + collision = 1; + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farpoint. */ + delaunayfixup(&fixuptri, 0); + delaunayfixup(&fixuptri2, 1); + done = 1; + } else { + if (area > 0.0) { /* farpoint is to the left of the segment. */ + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farpoint, on the */ + /* left side of the segment only. */ + delaunayfixup(&fixuptri2, 1); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + lprevself(fixuptri); + } else { /* farpoint is to the right of the segment. */ + delaunayfixup(&fixuptri, 0); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + oprevself(fixuptri); + } + /* Check for two intersecting segments. */ + tspivot(fixuptri, fixupedge); + if (fixupedge.sh == dummysh) { + flip(&fixuptri); /* May create an inverted triangle on the left. */ + } else { + /* We've collided with a segment between endpoint1 and endpoint2. */ + collision = 1; + /* Insert a point at the intersection. */ + segmentintersection(&fixuptri, &fixupedge, endpoint2); + done = 1; + } + } + } + } while (!done); + /* Insert a shell edge to make the segment permanent. */ + insertshelle(&fixuptri, newmark); + /* If there was a collision with an interceding vertex, install another */ + /* segment connecting that vertex with endpoint2. */ + if (collision) { + /* Insert the remainder of the segment. */ + if (!scoutsegment(&fixuptri, endpoint2, newmark)) { + constrainededge(&fixuptri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* insertsegment() Insert a PSLG segment into a triangulation. */ +/* */ +/*****************************************************************************/ + +void insertsegment(endpoint1, endpoint2, newmark) +point endpoint1; +point endpoint2; +int newmark; +{ + struct triedge searchtri1, searchtri2; + triangle encodedtri; + point checkpoint; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 1) { + printf(" Connecting (%.12g, %.12g) to (%.12g, %.12g).\n", + endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]); + } + + /* Find a triangle whose origin is the segment's first endpoint. */ + checkpoint = (point) NULL; + encodedtri = point2tri(endpoint1); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri1); + org(searchtri1, checkpoint); + } + if (checkpoint != endpoint1) { + /* Find a boundary triangle to search from. */ + searchtri1.tri = dummytri; + searchtri1.orient = 0; + symself(searchtri1); + /* Search for the segment's first endpoint by point location. */ + if (locate(endpoint1, &searchtri1) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG point\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint1[0], endpoint1[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + triedgecopy(searchtri1, recenttri); + /* Scout the beginnings of a path from the first endpoint */ + /* toward the second. */ + if (scoutsegment(&searchtri1, endpoint2, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The first endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri1, endpoint1); + + /* Find a triangle whose origin is the segment's second endpoint. */ + checkpoint = (point) NULL; + encodedtri = point2tri(endpoint2); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri2); + org(searchtri2, checkpoint); + } + if (checkpoint != endpoint2) { + /* Find a boundary triangle to search from. */ + searchtri2.tri = dummytri; + searchtri2.orient = 0; + symself(searchtri2); + /* Search for the segment's second endpoint by point location. */ + if (locate(endpoint2, &searchtri2) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG point\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint2[0], endpoint2[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + triedgecopy(searchtri2, recenttri); + /* Scout the beginnings of a path from the second endpoint */ + /* toward the first. */ + if (scoutsegment(&searchtri2, endpoint1, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The second endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri2, endpoint2); + +#ifndef REDUCED +#ifndef CDT_ONLY + if (splitseg) { + /* Insert vertices to force the segment into the triangulation. */ + conformingedge(endpoint1, endpoint2, newmark); + } else { +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + /* Insert the segment directly into the triangulation. */ + constrainededge(&searchtri1, endpoint2, newmark); +#ifndef REDUCED +#ifndef CDT_ONLY + } +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* markhull() Cover the convex hull of a triangulation with shell edges. */ +/* */ +/*****************************************************************************/ + +void markhull() +{ + struct triedge hulltri; + struct triedge nexttri; + struct triedge starttri; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + + /* Find a triangle handle on the hull. */ + hulltri.tri = dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + triedgecopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Create a shell edge if there isn't already one here. */ + insertshelle(&hulltri, 1); + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != dummytri) { + triedgecopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!triedgeequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* formskeleton() Create the shell edges of a triangulation, including */ +/* PSLG edges and edges on the convex hull. */ +/* */ +/* The PSLG edges are read from a .poly file. The return value is the */ +/* number of segments in the file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +int formskeleton(segmentlist, segmentmarkerlist, numberofsegments) +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; + +#else /* not TRILIBRARY */ + +int formskeleton(polyfile, polyfilename) +FILE *polyfile; +char *polyfilename; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + char polyfilename[6]; + int index; +#else /* not TRILIBRARY */ + char inputline[INPUTLINESIZE]; + char *stringptr; +#endif /* not TRILIBRARY */ + point endpoint1, endpoint2; + int segments; + int segmentmarkers; + int end1, end2; + int boundmarker; + int i; + + if (poly) { + if (!quiet) { + printf("Inserting segments into Delaunay triangulation.\n"); + } +#ifdef TRILIBRARY + strcpy(polyfilename, "input"); + segments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; + index = 0; +#else /* not TRILIBRARY */ + /* Read the segments from a .poly file. */ + /* Read number of segments and number of boundary markers. */ + stringptr = readline(inputline, polyfile, polyfilename); + segments = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + /* If segments are to be inserted, compute a mapping */ + /* from points to triangles. */ + if (segments > 0) { + if (verbose) { + printf(" Inserting PSLG segments.\n"); + } + makepointmap(); + } + + boundmarker = 0; + /* Read and insert the segments. */ + for (i = 1; i <= segments; i++) { +#ifdef TRILIBRARY + end1 = segmentlist[index++]; + end2 = segmentlist[index++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[i - 1]; + } +#else /* not TRILIBRARY */ + stringptr = readline(inputline, polyfile, inpolyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", i, + polyfilename); + exit(1); + } else { + end1 = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", i, + polyfilename); + exit(1); + } else { + end2 = (int) strtol (stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol (stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) { + if (!quiet) { + printf("Warning: Invalid first endpoint of segment %d in %s.\n", i, + polyfilename); + } + } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) { + if (!quiet) { + printf("Warning: Invalid second endpoint of segment %d in %s.\n", i, + polyfilename); + } + } else { + endpoint1 = getpoint(end1); + endpoint2 = getpoint(end2); + if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) { + if (!quiet) { + printf("Warning: Endpoints of segment %d are coincident in %s.\n", + i, polyfilename); + } + } else { + insertsegment(endpoint1, endpoint2, boundmarker); + } + } + } + } else { + segments = 0; + } + if (convex || !poly) { + /* Enclose the convex hull with shell edges. */ + if (verbose) { + printf(" Enclosing convex hull with segments.\n"); + } + markhull(); + } + return segments; +} + +/** **/ +/** **/ +/********* Segment (shell edge) insertion ends here *********/ + +/********* Carving out holes and concavities begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* infecthull() Virally infect all of the triangles of the convex hull */ +/* that are not protected by shell edges. Where there are */ +/* shell edges, set boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +void infecthull() +{ + struct triedge hulltri; + struct triedge nexttri; + struct triedge starttri; + struct edge hulledge; + triangle **deadtri; + point horg, hdest; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose) { + printf(" Marking concavities (external triangles) for elimination.\n"); + } + /* Find a triangle handle on the hull. */ + hulltri.tri = dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + triedgecopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Ignore triangles that are already infected. */ + if (!infected(hulltri)) { + /* Is the triangle protected by a shell edge? */ + tspivot(hulltri, hulledge); + if (hulledge.sh == dummysh) { + /* The triangle is not protected; infect it. */ + infect(hulltri); + deadtri = (triangle **) poolalloc(&viri); + *deadtri = hulltri.tri; + } else { + /* The triangle is protected; set boundary markers if appropriate. */ + if (mark(hulledge) == 0) { + setmark(hulledge, 1); + org(hulltri, horg); + dest(hulltri, hdest); + if (pointmark(horg) == 0) { + setpointmark(horg, 1); + } + if (pointmark(hdest) == 0) { + setpointmark(hdest, 1); + } + } + } + } + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != dummytri) { + triedgecopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!triedgeequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* plague() Spread the virus from all infected triangles to any neighbors */ +/* not protected by shell edges. Delete all infected triangles. */ +/* */ +/* This is the procedure that actually creates holes and concavities. */ +/* */ +/* This procedure operates in two phases. The first phase identifies all */ +/* the triangles that will die, and marks them as infected. They are */ +/* marked to ensure that each triangle is added to the virus pool only */ +/* once, so the procedure will terminate. */ +/* */ +/* The second phase actually eliminates the infected triangles. It also */ +/* eliminates orphaned points. */ +/* */ +/*****************************************************************************/ + +void plague() +{ + struct triedge testtri; + struct triedge neighbor; + triangle **virusloop; + triangle **deadtri; + struct edge neighborshelle; + point testpoint; + point norg, ndest; + point deadorg, deaddest, deadapex; + int killorg; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the virus to */ + /* their neighbors, then to their neighbors' neighbors. */ + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its shell */ + /* edges, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent shell edges. */ + uninfect(testtri); + if (verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its points. */ + testtri.orient = 0; + org(testtri, deadorg); + dest(testtri, deaddest); + apex(testtri, deadapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a shell between the triangle and its neighbor. */ + tspivot(testtri, neighborshelle); + /* Check if the neighbor is nonexistent or already infected. */ + if ((neighbor.tri == dummytri) || infected(neighbor)) { + if (neighborshelle.sh != dummysh) { + /* There is a shell edge separating the triangle from its */ + /* neighbor, but both triangles are dying, so the shell */ + /* edge dies too. */ + shelledealloc(neighborshelle.sh); + if (neighbor.tri != dummytri) { + /* Make sure the shell edge doesn't get deallocated again */ + /* later when the infected neighbor is visited. */ + uninfect(neighbor); + tsdissolve(neighbor); + infect(neighbor); + } + } + } else { /* The neighbor exists and is not infected. */ + if (neighborshelle.sh == dummysh) { + /* There is no shell edge protecting the neighbor, so */ + /* the neighbor becomes infected. */ + if (verbose > 2) { + org(neighbor, deadorg); + dest(neighbor, deaddest); + apex(neighbor, deadapex); + printf( + " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + deadtri = (triangle **) poolalloc(&viri); + *deadtri = neighbor.tri; + } else { /* The neighbor is protected by a shell edge. */ + /* Remove this triangle from the shell edge. */ + stdissolve(neighborshelle); + /* The shell edge becomes a boundary. Set markers accordingly. */ + if (mark(neighborshelle) == 0) { + setmark(neighborshelle, 1); + } + org(neighbor, norg); + dest(neighbor, ndest); + if (pointmark(norg) == 0) { + setpointmark(norg, 1); + } + if (pointmark(ndest) == 0) { + setpointmark(ndest, 1); + } + } + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&viri); + } + + if (verbose) { + printf(" Deleting marked triangles.\n"); + } + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + + /* Check each of the three corners of the triangle for elimination. */ + /* This is done by walking around each point, checking if it is */ + /* still connected to at least one live triangle. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + org(testtri, testpoint); + /* Check if the point has already been tested. */ + if (testpoint != (point) NULL) { + killorg = 1; + /* Mark the corner of the triangle as having been tested. */ + setorg(testtri, NULL); + /* Walk counterclockwise about the point. */ + onext(testtri, neighbor); + /* Stop upon reaching a boundary or the starting triangle. */ + while ((neighbor.tri != dummytri) + && (!triedgeequal(neighbor, testtri))) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The point survives. */ + killorg = 0; + } + /* Walk counterclockwise about the point. */ + onextself(neighbor); + } + /* If we reached a boundary, we must walk clockwise as well. */ + if (neighbor.tri == dummytri) { + /* Walk clockwise about the point. */ + oprev(testtri, neighbor); + /* Stop upon reaching a boundary. */ + while (neighbor.tri != dummytri) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The point survives. */ + killorg = 0; + } + /* Walk clockwise about the point. */ + oprevself(neighbor); + } + } + if (killorg) { + if (verbose > 1) { + printf(" Deleting point (%.12g, %.12g)\n", + testpoint[0], testpoint[1]); + } + pointdealloc(testpoint); + } + } + } + + /* Record changes in the number of boundary edges, and disconnect */ + /* dead triangles from their neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + sym(testtri, neighbor); + if (neighbor.tri == dummytri) { + /* There is no neighboring triangle on this edge, so this edge */ + /* is a boundary edge. This triangle is being deleted, so this */ + /* boundary edge is deleted. */ + hullsize--; + } else { + /* Disconnect the triangle from its neighbor. */ + dissolve(neighbor); + /* There is a neighboring triangle on this edge, so this edge */ + /* becomes a boundary edge when this triangle is deleted. */ + hullsize++; + } + } + /* Return the dead triangle to the pool of triangles. */ + triangledealloc(testtri.tri); + virusloop = (triangle **) traverse(&viri); + } + /* Empty the virus pool. */ + poolrestart(&viri); +} + +/*****************************************************************************/ +/* */ +/* regionplague() Spread regional attributes and/or area constraints */ +/* (from a .poly file) throughout the mesh. */ +/* */ +/* This procedure operates in two phases. The first phase spreads an */ +/* attribute and/or an area constraint through a (segment-bounded) region. */ +/* The triangles are marked to ensure that each triangle is added to the */ +/* virus pool only once, so the procedure will terminate. */ +/* */ +/* The second phase uninfects all infected triangles, returning them to */ +/* normal. */ +/* */ +/*****************************************************************************/ + +void regionplague(attribute, area) +REAL attribute; +REAL area; +{ + struct triedge testtri; + struct triedge neighbor; + triangle **virusloop; + triangle **regiontri; + struct edge neighborshelle; + point regionorg, regiondest, regionapex; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose > 1) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the attribute */ + /* and/or area constraint to their neighbors, then to their neighbors' */ + /* neighbors. */ + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its shell */ + /* edges, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent shell edges. */ + uninfect(testtri); + if (regionattrib) { + /* Set an attribute. */ + setelemattribute(testtri, eextras, attribute); + } + if (vararea) { + /* Set an area constraint. */ + setareabound(testtri, area); + } + if (verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its points. */ + testtri.orient = 0; + org(testtri, regionorg); + dest(testtri, regiondest); + apex(testtri, regionapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a shell between the triangle and its neighbor. */ + tspivot(testtri, neighborshelle); + /* Make sure the neighbor exists, is not already infected, and */ + /* isn't protected by a shell edge. */ + if ((neighbor.tri != dummytri) && !infected(neighbor) + && (neighborshelle.sh == dummysh)) { + if (verbose > 2) { + org(neighbor, regionorg); + dest(neighbor, regiondest); + apex(neighbor, regionapex); + printf(" Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Infect the neighbor. */ + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + regiontri = (triangle **) poolalloc(&viri); + *regiontri = neighbor.tri; + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&viri); + } + + /* Uninfect all triangles. */ + if (verbose > 1) { + printf(" Unmarking marked triangles.\n"); + } + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + uninfect(testtri); + virusloop = (triangle **) traverse(&viri); + } + /* Empty the virus pool. */ + poolrestart(&viri); +} + +/*****************************************************************************/ +/* */ +/* carveholes() Find the holes and infect them. Find the area */ +/* constraints and infect them. Infect the convex hull. */ +/* Spread the infection and kill triangles. Spread the */ +/* area constraints. */ +/* */ +/* This routine mainly calls other routines to carry out all these */ +/* functions. */ +/* */ +/*****************************************************************************/ + +void carveholes(holelist, holes, regionlist, regions) +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +{ + struct triedge searchtri; + struct triedge triangleloop; + struct triedge *regiontris; + triangle **holetri; + triangle **regiontri; + point searchorg, searchdest; + enum locateresult intersect; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + + if (!(quiet || (noholes && convex))) { + printf("Removing unwanted triangles.\n"); + if (verbose && (holes > 0)) { + printf(" Marking holes for elimination.\n"); + } + } + + if (regions > 0) { + /* Allocate storage for the triangles in which region points fall. */ + regiontris = (struct triedge *) malloc(regions * sizeof(struct triedge)); + if (regiontris == (struct triedge *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + + if (((holes > 0) && !noholes) || !convex || (regions > 0)) { + /* Initialize a pool of viri to be used for holes, concavities, */ + /* regional attributes, and/or regional area constraints. */ + poolinit(&viri, sizeof(triangle *), VIRUSPERBLOCK, POINTER, 0); + } + + if (!convex) { + /* Mark as infected any unprotected triangles on the boundary. */ + /* This is one way by which concavities are created. */ + infecthull(); + } + + if ((holes > 0) && !noholes) { + /* Infect each triangle in which a hole lies. */ + for (i = 0; i < 2 * holes; i += 2) { + /* Ignore holes that aren't within the bounds of the mesh. */ + if ((holelist[i] >= xmin) && (holelist[i] <= xmax) + && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the hole is to the left of this boundary edge; */ + /* otherwise, locate() will falsely report that the hole */ + /* falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(searchorg, searchdest, &holelist[i]) > 0.0) { + /* Find a triangle that contains the hole. */ + intersect = locate(&holelist[i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Infect the triangle. This is done by marking the triangle */ + /* as infect and including the triangle in the virus pool. */ + infect(searchtri); + holetri = (triangle **) poolalloc(&viri); + *holetri = searchtri.tri; + } + } + } + } + } + + /* Now, we have to find all the regions BEFORE we carve the holes, because */ + /* locate() won't work when the triangulation is no longer convex. */ + /* (Incidentally, this is the reason why regional attributes and area */ + /* constraints can't be used when refining a preexisting mesh, which */ + /* might not be convex; they can only be used with a freshly */ + /* triangulated PSLG.) */ + if (regions > 0) { + /* Find the starting triangle for each region. */ + for (i = 0; i < regions; i++) { + regiontris[i].tri = dummytri; + /* Ignore region points that aren't within the bounds of the mesh. */ + if ((regionlist[4 * i] >= xmin) && (regionlist[4 * i] <= xmax) && + (regionlist[4 * i + 1] >= ymin) && (regionlist[4 * i + 1] <= ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the region point is to the left of this boundary */ + /* edge; otherwise, locate() will falsely report that the */ + /* region point falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(searchorg, searchdest, ®ionlist[4 * i]) > + 0.0) { + /* Find a triangle that contains the region point. */ + intersect = locate(®ionlist[4 * i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Record the triangle for processing after the */ + /* holes have been carved. */ + triedgecopy(searchtri, regiontris[i]); + } + } + } + } + } + + if (viri.items > 0) { + /* Carve the holes and concavities. */ + plague(); + } + /* The virus pool should be empty now. */ + + if (regions > 0) { + if (!quiet) { + if (regionattrib) { + if (vararea) { + printf("Spreading regional attributes and area constraints.\n"); + } else { + printf("Spreading regional attributes.\n"); + } + } else { + printf("Spreading regional area constraints.\n"); + } + } + if (regionattrib && !refine) { + /* Assign every triangle a regional attribute of zero. */ + traversalinit(&triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + setelemattribute(triangleloop, eextras, 0.0); + triangleloop.tri = triangletraverse(); + } + } + for (i = 0; i < regions; i++) { + if (regiontris[i].tri != dummytri) { + /* Make sure the triangle under consideration still exists. */ + /* It may have been eaten by the virus. */ + if (regiontris[i].tri[3] != (triangle) NULL) { + /* Put one triangle in the virus pool. */ + infect(regiontris[i]); + regiontri = (triangle **) poolalloc(&viri); + *regiontri = regiontris[i].tri; + /* Apply one region's attribute and/or area constraint. */ + regionplague(regionlist[4 * i + 2], regionlist[4 * i + 3]); + /* The virus pool should be empty now. */ + } + } + } + if (regionattrib && !refine) { + /* Note the fact that each triangle has an additional attribute. */ + eextras++; + } + } + + /* Free up memory. */ + if (((holes > 0) && !noholes) || !convex || (regions > 0)) { + pooldeinit(&viri); + } + if (regions > 0) { + free(regiontris); + } +} + +/** **/ +/** **/ +/********* Carving out holes and concavities ends here *********/ + +/********* Mesh quality maintenance begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* tallyencs() Traverse the entire list of shell edges, check each edge */ +/* to see if it is encroached. If so, add it to the list. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void tallyencs() +{ + struct edge edgeloop; + int dummy; + + traversalinit(&shelles); + edgeloop.shorient = 0; + edgeloop.sh = shelletraverse(); + while (edgeloop.sh != (shelle *) NULL) { + /* If the segment is encroached, add it to the list. */ + dummy = checkedge4encroach(&edgeloop); + edgeloop.sh = shelletraverse(); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* precisionerror() Print an error message for precision problems. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void precisionerror() +{ + printf("Try increasing the area criterion and/or reducing the minimum\n"); + printf(" allowable angle so that tiny triangles are not created.\n"); +#ifdef SINGLE + printf("Alternatively, try recompiling me with double precision\n"); + printf(" arithmetic (by removing \"#define SINGLE\" from the\n"); + printf(" source file or \"-DSINGLE\" from the makefile).\n"); +#endif /* SINGLE */ +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* repairencs() Find and repair all the encroached segments. */ +/* */ +/* Encroached segments are repaired by splitting them by inserting a point */ +/* at or near their centers. */ +/* */ +/* `flaws' is a flag that specifies whether one should take note of new */ +/* encroached segments and bad triangles that result from inserting points */ +/* to repair existing encroached segments. */ +/* */ +/* When a segment is split, the two resulting subsegments are always */ +/* tested to see if they are encroached upon, regardless of the value */ +/* of `flaws'. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void repairencs(flaws) +int flaws; +{ + struct triedge enctri; + struct triedge testtri; + struct edge *encloop; + struct edge testsh; + point eorg, edest; + point newpoint; + enum insertsiteresult success; + REAL segmentlength, nearestpoweroftwo; + REAL split; + int acuteorg, acutedest; + int dummy; + int i; + triangle ptr; /* Temporary variable used by stpivot(). */ + shelle sptr; /* Temporary variable used by snext(). */ + + while ((badsegments.items > 0) && (steinerleft != 0)) { + traversalinit(&badsegments); + encloop = badsegmenttraverse(); + while ((encloop != (struct edge *) NULL) && (steinerleft != 0)) { + /* To decide where to split a segment, we need to know if the */ + /* segment shares an endpoint with an adjacent segment. */ + /* The concern is that, if we simply split every encroached */ + /* segment in its center, two adjacent segments with a small */ + /* angle between them might lead to an infinite loop; each */ + /* point added to split one segment will encroach upon the */ + /* other segment, which must then be split with a point that */ + /* will encroach upon the first segment, and so on forever. */ + /* To avoid this, imagine a set of concentric circles, whose */ + /* radii are powers of two, about each segment endpoint. */ + /* These concentric circles determine where the segment is */ + /* split. (If both endpoints are shared with adjacent */ + /* segments, split the segment in the middle, and apply the */ + /* concentric shells for later splittings.) */ + + /* Is the origin shared with another segment? */ + stpivot(*encloop, enctri); + lnext(enctri, testtri); + tspivot(testtri, testsh); + acuteorg = testsh.sh != dummysh; + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = testsh.sh != dummysh; + /* Now, check the other side of the segment, if there's a triangle */ + /* there. */ + sym(enctri, testtri); + if (testtri.tri != dummytri) { + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = acutedest || (testsh.sh != dummysh); + /* Is the origin shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acuteorg = acuteorg || (testsh.sh != dummysh); + } + + sorg(*encloop, eorg); + sdest(*encloop, edest); + /* Use the concentric circles if exactly one endpoint is shared */ + /* with another adjacent segment. */ + if (acuteorg ^ acutedest) { + segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0]) + + (edest[1] - eorg[1]) * (edest[1] - eorg[1])); + /* Find the power of two nearest the segment's length. */ + nearestpoweroftwo = 1.0; + while (segmentlength > SQUAREROOTTWO * nearestpoweroftwo) { + nearestpoweroftwo *= 2.0; + } + while (segmentlength < (0.5 * SQUAREROOTTWO) * nearestpoweroftwo) { + nearestpoweroftwo *= 0.5; + } + /* Where do we split the segment? */ + split = 0.5 * nearestpoweroftwo / segmentlength; + if (acutedest) { + split = 1.0 - split; + } + } else { + /* If we're not worried about adjacent segments, split */ + /* this segment in the middle. */ + split = 0.5; + } + + /* Create the new point. */ + newpoint = (point) poolalloc(&points); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = (1.0 - split) * eorg[i] + split * edest[i]; + } + setpointmark(newpoint, mark(*encloop)); + if (verbose > 1) { + printf( + " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1], newpoint[0], newpoint[1]); + } + /* Check whether the new point lies on an endpoint. */ + if (((newpoint[0] == eorg[0]) && (newpoint[1] == eorg[1])) + || ((newpoint[0] == edest[0]) && (newpoint[1] == edest[1]))) { + printf("Error: Ran out of precision at (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + printf("I attempted to split a segment to a smaller size than can\n"); + printf(" be accommodated by the finite precision of floating point\n" + ); + printf(" arithmetic.\n"); + precisionerror(); + exit(1); + } + /* Insert the splitting point. This should always succeed. */ + success = insertsite(newpoint, &enctri, encloop, flaws, flaws); + if ((success != SUCCESSFULPOINT) && (success != ENCROACHINGPOINT)) { + printf("Internal error in repairencs():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (steinerleft > 0) { + steinerleft--; + } + /* Check the two new subsegments to see if they're encroached. */ + dummy = checkedge4encroach(encloop); + snextself(*encloop); + dummy = checkedge4encroach(encloop); + + badsegmentdealloc(encloop); + encloop = badsegmenttraverse(); + } + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* tallyfaces() Test every triangle in the mesh for quality measures. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void tallyfaces() +{ + struct triedge triangleloop; + + if (verbose) { + printf(" Making a list of bad triangles.\n"); + } + traversalinit(&triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* If the triangle is bad, enqueue it. */ + testtriangle(&triangleloop); + triangleloop.tri = triangletraverse(); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* findcircumcenter() Find the circumcenter of a triangle. */ +/* */ +/* The result is returned both in terms of x-y coordinates and xi-eta */ +/* coordinates. The xi-eta coordinate system is defined in terms of the */ +/* triangle: the origin of the triangle is the origin of the coordinate */ +/* system; the destination of the triangle is one unit along the xi axis; */ +/* and the apex of the triangle is one unit along the eta axis. */ +/* */ +/* The return value indicates which edge of the triangle is shortest. */ +/* */ +/*****************************************************************************/ + +enum circumcenterresult findcircumcenter(torg, tdest, tapex, circumcenter, + xi, eta) +point torg; +point tdest; +point tapex; +point circumcenter; +REAL *xi; +REAL *eta; +{ + REAL xdo, ydo, xao, yao, xad, yad; + REAL dodist, aodist, addist; + REAL denominator; + REAL dx, dy; + + circumcentercount++; + + /* Compute the circumcenter of the triangle. */ + xdo = tdest[0] - torg[0]; + ydo = tdest[1] - torg[1]; + xao = tapex[0] - torg[0]; + yao = tapex[1] - torg[1]; + dodist = xdo * xdo + ydo * ydo; + aodist = xao * xao + yao * yao; + if (noexact) { + denominator = (REAL)(0.5 / (xdo * yao - xao * ydo)); + } else { + /* Use the counterclockwise() routine to ensure a positive (and */ + /* reasonably accurate) result, avoiding any possibility of */ + /* division by zero. */ + denominator = (REAL)(0.5 / counterclockwise(tdest, tapex, torg)); + /* Don't count the above as an orientation test. */ + counterclockcount--; + } + circumcenter[0] = torg[0] - (ydo * aodist - yao * dodist) * denominator; + circumcenter[1] = torg[1] + (xdo * aodist - xao * dodist) * denominator; + + /* To interpolate point attributes for the new point inserted at */ + /* the circumcenter, define a coordinate system with a xi-axis, */ + /* directed from the triangle's origin to its destination, and */ + /* an eta-axis, directed from its origin to its apex. */ + /* Calculate the xi and eta coordinates of the circumcenter. */ + dx = circumcenter[0] - torg[0]; + dy = circumcenter[1] - torg[1]; + *xi = (REAL)((dx * yao - xao * dy) * (2.0 * denominator)); + *eta = (REAL)((xdo * dy - dx * ydo) * (2.0 * denominator)); + + xad = tapex[0] - tdest[0]; + yad = tapex[1] - tdest[1]; + addist = xad * xad + yad * yad; + if ((addist < dodist) && (addist < aodist)) { + return OPPOSITEORG; + } else if (dodist < aodist) { + return OPPOSITEAPEX; + } else { + return OPPOSITEDEST; + } +} + +/*****************************************************************************/ +/* */ +/* splittriangle() Inserts a point at the circumcenter of a triangle. */ +/* Deletes the newly inserted point if it encroaches upon */ +/* a segment. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void splittriangle(badtri) +struct badface *badtri; +{ + point borg, bdest, bapex; + point newpoint; + REAL xi, eta; + enum insertsiteresult success; + enum circumcenterresult shortedge; + int errorflag; + int i; + + org(badtri->badfacetri, borg); + dest(badtri->badfacetri, bdest); + apex(badtri->badfacetri, bapex); + /* Make sure that this triangle is still the same triangle it was */ + /* when it was tested and determined to be of bad quality. */ + /* Subsequent transformations may have made it a different triangle. */ + if ((borg == badtri->faceorg) && (bdest == badtri->facedest) && + (bapex == badtri->faceapex)) { + if (verbose > 1) { + printf(" Splitting this triangle at its circumcenter:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0], + borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + errorflag = 0; + /* Create a new point at the triangle's circumcenter. */ + newpoint = (point) poolalloc(&points); + shortedge = findcircumcenter(borg, bdest, bapex, newpoint, &xi, &eta); + /* Check whether the new point lies on a triangle vertex. */ + if (((newpoint[0] == borg[0]) && (newpoint[1] == borg[1])) + || ((newpoint[0] == bdest[0]) && (newpoint[1] == bdest[1])) + || ((newpoint[0] == bapex[0]) && (newpoint[1] == bapex[1]))) { + if (!quiet) { + printf("Warning: New point (%.12g, %.12g) falls on existing vertex.\n" + , newpoint[0], newpoint[1]); + errorflag = 1; + } + pointdealloc(newpoint); + } else { + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + newpoint[i] = borg[i] + xi * (bdest[i] - borg[i]) + + eta * (bapex[i] - borg[i]); + } + /* The new point must be in the interior, and have a marker of zero. */ + setpointmark(newpoint, 0); + /* Ensure that the handle `badtri->badfacetri' represents the shortest */ + /* edge of the triangle. This ensures that the circumcenter must */ + /* fall to the left of this edge, so point location will work. */ + if (shortedge == OPPOSITEORG) { + lnextself(badtri->badfacetri); + } else if (shortedge == OPPOSITEDEST) { + lprevself(badtri->badfacetri); + } + /* Insert the circumcenter, searching from the edge of the triangle, */ + /* and maintain the Delaunay property of the triangulation. */ + success = insertsite(newpoint, &(badtri->badfacetri), + (struct edge *) NULL, 1, 1); + if (success == SUCCESSFULPOINT) { + if (steinerleft > 0) { + steinerleft--; + } + } else if (success == ENCROACHINGPOINT) { + /* If the newly inserted point encroaches upon a segment, delete it. */ + deletesite(&(badtri->badfacetri)); + } else if (success == VIOLATINGPOINT) { + /* Failed to insert the new point, but some segment was */ + /* marked as being encroached. */ + pointdealloc(newpoint); + } else { /* success == DUPLICATEPOINT */ + /* Failed to insert the new point because a vertex is already there. */ + if (!quiet) { + printf( + "Warning: New point (%.12g, %.12g) falls on existing vertex.\n" + , newpoint[0], newpoint[1]); + errorflag = 1; + } + pointdealloc(newpoint); + } + } + if (errorflag) { + if (verbose) { + printf(" The new point is at the circumcenter of triangle\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + printf("This probably means that I am trying to refine triangles\n"); + printf(" to a smaller size than can be accommodated by the finite\n"); + printf(" precision of floating point arithmetic. (You can be\n"); + printf(" sure of this if I fail to terminate.)\n"); + precisionerror(); + } + } + /* Return the bad triangle to the pool. */ + pooldealloc(&badtriangles, (VOID *) badtri); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* enforcequality() Remove all the encroached edges and bad triangles */ +/* from the triangulation. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void enforcequality() +{ + int i; + + if (!quiet) { + printf("Adding Steiner points to enforce quality.\n"); + } + /* Initialize the pool of encroached segments. */ + poolinit(&badsegments, sizeof(struct edge), BADSEGMENTPERBLOCK, POINTER, 0); + if (verbose) { + printf(" Looking for encroached segments.\n"); + } + /* Test all segments to see if they're encroached. */ + tallyencs(); + if (verbose && (badsegments.items > 0)) { + printf(" Splitting encroached segments.\n"); + } + /* Note that steinerleft == -1 if an unlimited number */ + /* of Steiner points is allowed. */ + while ((badsegments.items > 0) && (steinerleft != 0)) { + /* Fix the segments without noting newly encroached segments or */ + /* bad triangles. The reason we don't want to note newly */ + /* encroached segments is because some encroached segments are */ + /* likely to be noted multiple times, and would then be blindly */ + /* split multiple times. I should fix that some time. */ + repairencs(0); + /* Now, find all the segments that became encroached while adding */ + /* points to split encroached segments. */ + tallyencs(); + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay. */ + + /* Next, we worry about enforcing triangle quality. */ + if ((minangle > 0.0) || vararea || fixedarea) { + /* Initialize the pool of bad triangles. */ + poolinit(&badtriangles, sizeof(struct badface), BADTRIPERBLOCK, POINTER, + 0); + /* Initialize the queues of bad triangles. */ + for (i = 0; i < 64; i++) { + queuefront[i] = (struct badface *) NULL; + queuetail[i] = &queuefront[i]; + } + /* Test all triangles to see if they're bad. */ + tallyfaces(); + if (verbose) { + printf(" Splitting bad triangles.\n"); + } + while ((badtriangles.items > 0) && (steinerleft != 0)) { + /* Fix one bad triangle by inserting a point at its circumcenter. */ + splittriangle(dequeuebadtri()); + /* Fix any encroached segments that may have resulted. Record */ + /* any new bad triangles or encroached segments that result. */ + if (badsegments.items > 0) { + repairencs(1); + } + } + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay and have no */ + /* low-quality triangles. */ + + /* Might we have run out of Steiner points too soon? */ + if (!quiet && (badsegments.items > 0) && (steinerleft == 0)) { + printf("\nWarning: I ran out of Steiner points, but the mesh has\n"); + if (badsegments.items == 1) { + printf(" an encroached segment, and therefore might not be truly\n"); + } else { + printf(" %ld encroached segments, and therefore might not be truly\n", + badsegments.items); + } + printf(" Delaunay. If the Delaunay property is important to you,\n"); + printf(" try increasing the number of Steiner points (controlled by\n"); + printf(" the -S switch) slightly and try again.\n\n"); + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality maintenance ends here *********/ + +/*****************************************************************************/ +/* */ +/* highorder() Create extra nodes for quadratic subparametric elements. */ +/* */ +/*****************************************************************************/ + +void highorder() +{ + struct triedge triangleloop, trisym; + struct edge checkmark; + point newpoint; + point torg, tdest; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (!quiet) { + printf("Adding vertices for second-order triangles.\n"); + } + /* The following line ensures that dead items in the pool of nodes */ + /* cannot be allocated for the extra nodes associated with high */ + /* order elements. This ensures that the primary nodes (at the */ + /* corners of elements) will occur earlier in the output files, and */ + /* have lower indices, than the extra nodes. */ + points.deaditemstack = (VOID *) NULL; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + org(triangleloop, torg); + dest(triangleloop, tdest); + /* Create a new node in the middle of the edge. Interpolate */ + /* its attributes. */ + newpoint = (point) poolalloc(&points); + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = (REAL)(0.5 * (torg[i] + tdest[i])); + } + /* Set the new node's marker to zero or one, depending on */ + /* whether it lies on a boundary. */ + setpointmark(newpoint, trisym.tri == dummytri); + if (useshelles) { + tspivot(triangleloop, checkmark); + /* If this edge is a segment, transfer the marker to the new node. */ + if (checkmark.sh != dummysh) { + setpointmark(newpoint, mark(checkmark)); + } + } + if (verbose > 1) { + printf(" Creating (%.12g, %.12g).\n", newpoint[0], newpoint[1]); + } + /* Record the new node in the (one or two) adjacent elements. */ + triangleloop.tri[highorderindex + triangleloop.orient] = + (triangle) newpoint; + if (trisym.tri != dummytri) { + trisym.tri[highorderindex + trisym.orient] = (triangle) newpoint; + } + } + } + triangleloop.tri = triangletraverse(); + } +} + +/********* File I/O routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* readline() Read a nonempty line from a file. */ +/* */ +/* A line is considered "nonempty" if it contains something that looks like */ +/* a number. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +char *readline(string, infile, infilename) +char *string; +FILE *infile; +char *infilename; +{ + char *result; + + /* Search for something that looks like a number. */ + do { + result = fgets(string, INPUTLINESIZE, infile); + if (result == (char *) NULL) { + printf(" Error: Unexpected end of file in %s.\n", infilename); + exit(1); + } + /* Skip anything that doesn't look like a number, a comment, */ + /* or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* If it's a comment or end of line, read another line and try again. */ + } while ((*result == '#') || (*result == '\0')); + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* findfield() Find the next field of a string. */ +/* */ +/* Jumps past the current field by searching for whitespace, then jumps */ +/* past the whitespace to find the next field. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +char *findfield(string) +char *string; +{ + char *result; + + result = string; + /* Skip the current field. Stop upon reaching whitespace. */ + while ((*result != '\0') && (*result != '#') + && (*result != ' ') && (*result != '\t')) { + result++; + } + /* Now skip the whitespace and anything else that doesn't look like a */ + /* number, a comment, or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* Check for a comment (prefixed with `#'). */ + if (*result == '#') { + *result = '\0'; + } + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readnodes() Read the points from a file, which may be a .node or .poly */ +/* file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void readnodes(nodefilename, polyfilename, polyfile) +char *nodefilename; +char *polyfilename; +FILE **polyfile; +{ + FILE *infile; + point pointloop; + char inputline[INPUTLINESIZE]; + char *stringptr; + char *infilename; + REAL x, y; + int firstnode; + int nodemarkers; + int currentmarker; + int i, j; + + if (poly) { + /* Read the points from a .poly file. */ + if (!quiet) { + printf("Opening %s.\n", polyfilename); + } + *polyfile = fopen(polyfilename, "r"); + if (*polyfile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", polyfilename); + exit(1); + } + /* Read number of points, number of dimensions, number of point */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, *polyfile, polyfilename); + inpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + mesh_dim = 2; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nextras = 0; + } else { + nextras = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol (stringptr, &stringptr, 0); + } + if (inpoints > 0) { + infile = *polyfile; + infilename = polyfilename; + readnodefile = 0; + } else { + /* If the .poly file claims there are zero points, that means that */ + /* the points should be read from a separate .node file. */ + readnodefile = 1; + infilename = innodefilename; + } + } else { + readnodefile = 1; + infilename = innodefilename; + *polyfile = (FILE *) NULL; + } + + if (readnodefile) { + /* Read the points from a .node file. */ + if (!quiet) { + printf("Opening %s.\n", innodefilename); + } + infile = fopen(innodefilename, "r"); + if (infile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", innodefilename); + exit(1); + } + /* Read number of points, number of dimensions, number of point */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, infile, innodefilename); + inpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + mesh_dim = 2; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nextras = 0; + } else { + nextras = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol (stringptr, &stringptr, 0); + } + } + + if (inpoints < 3) { + printf("Error: Input must have at least three input points.\n"); + exit(1); + } + if (mesh_dim != 2) { + printf("Error: Triangle only works with two-dimensional meshes.\n"); + exit(1); + } + + initializepointpool(); + + /* Read the points. */ + for (i = 0; i < inpoints; i++) { + pointloop = (point) poolalloc(&points); + stringptr = readline(inputline, infile, infilename); + if (i == 0) { + firstnode = (int) strtol (stringptr, &stringptr, 0); + if ((firstnode == 0) || (firstnode == 1)) { + firstnumber = firstnode; + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no x coordinate.\n", firstnumber + i); + exit(1); + } + x = (REAL) strtod(stringptr, &stringptr); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no y coordinate.\n", firstnumber + i); + exit(1); + } + y = (REAL) strtod(stringptr, &stringptr); + pointloop[0] = x; + pointloop[1] = y; + /* Read the point attributes. */ + for (j = 2; j < 2 + nextras; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + pointloop[j] = 0.0; + } else { + pointloop[j] = (REAL) strtod(stringptr, &stringptr); + } + } + if (nodemarkers) { + /* Read a point marker. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setpointmark(pointloop, 0); + } else { + currentmarker = (int) strtol (stringptr, &stringptr, 0); + setpointmark(pointloop, currentmarker); + } + } else { + /* If no markers are specified in the file, they default to zero. */ + setpointmark(pointloop, 0); + } + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + } + } + if (readnodefile) { + fclose(infile); + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + xminextreme = 10 * xmin - 9 * xmax; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* transfernodes() Read the points from memory. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void transfernodes(pointlist, pointattriblist, pointmarkerlist, numberofpoints, + numberofpointattribs) +REAL *pointlist; +REAL *pointattriblist; +int *pointmarkerlist; +int numberofpoints; +int numberofpointattribs; +{ + point pointloop; + REAL x, y; + int i, j; + int coordindex; + int attribindex; + + inpoints = numberofpoints; + mesh_dim = 2; + nextras = numberofpointattribs; + readnodefile = 0; + if (inpoints < 3) { + printf("Error: Input must have at least three input points.\n"); + exit(1); + } + + initializepointpool(); + + /* Read the points. */ + coordindex = 0; + attribindex = 0; + for (i = 0; i < inpoints; i++) { + pointloop = (point) poolalloc(&points); + /* Read the point coordinates. */ + x = pointloop[0] = pointlist[coordindex++]; + y = pointloop[1] = pointlist[coordindex++]; + /* Read the point attributes. */ + for (j = 0; j < numberofpointattribs; j++) { + pointloop[2 + j] = pointattriblist[attribindex++]; + } + if (pointmarkerlist != (int *) NULL) { + /* Read a point marker. */ + setpointmark(pointloop, pointmarkerlist[i]); + } else { + /* If no markers are specified, they default to zero. */ + setpointmark(pointloop, 0); + } + x = pointloop[0]; + y = pointloop[1]; + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + } + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + xminextreme = 10 * xmin - 9 * xmax; +} + +#endif /* TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readholes() Read the holes, and possibly regional attributes and area */ +/* constraints, from a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void readholes(polyfile, polyfilename, hlist, holes, rlist, regions) +FILE *polyfile; +char *polyfilename; +REAL **hlist; +int *holes; +REAL **rlist; +int *regions; +{ + REAL *holelist; + REAL *regionlist; + char inputline[INPUTLINESIZE]; + char *stringptr; + int index; + int i; + + /* Read the holes. */ + stringptr = readline(inputline, polyfile, polyfilename); + *holes = (int) strtol (stringptr, &stringptr, 0); + if (*holes > 0) { + holelist = (REAL *) malloc(2 * *holes * sizeof(REAL)); + *hlist = holelist; + if (holelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + for (i = 0; i < 2 * *holes; i += 2) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no x coordinate.\n", + firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no y coordinate.\n", + firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); + } + } + } else { + *hlist = (REAL *) NULL; + } + +#ifndef CDT_ONLY + if ((regionattrib || vararea) && !refine) { + /* Read the area constraints. */ + stringptr = readline(inputline, polyfile, polyfilename); + *regions = (int) strtol (stringptr, &stringptr, 0); + if (*regions > 0) { + regionlist = (REAL *) malloc(4 * *regions * sizeof(REAL)); + *rlist = regionlist; + if (regionlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + index = 0; + for (i = 0; i < *regions; i++) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no x coordinate.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no y coordinate.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf( + "Error: Region %d has no region attribute or area constraint.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + regionlist[index] = regionlist[index - 1]; + } else { + regionlist[index] = (REAL) strtod(stringptr, &stringptr); + } + index++; + } + } + } else { + /* Set `*regions' to zero to avoid an accidental free() later. */ + *regions = 0; + *rlist = (REAL *) NULL; + } +#endif /* not CDT_ONLY */ + + fclose(polyfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* finishfile() Write the command line to the output file so the user */ +/* can remember how the file was generated. Close the file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void finishfile(outfile, argc, argv) +FILE *outfile; +int argc; +char **argv; +{ + int i; + + fprintf(outfile, "# Generated by"); + for (i = 0; i < argc; i++) { + fprintf(outfile, " "); + fputs(argv[i], outfile); + } + fprintf(outfile, "\n"); + fclose(outfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* writenodes() Number the points and write them to a .node file. */ +/* */ +/* To save memory, the point numbers are written over the shell markers */ +/* after the points are written to a file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writenodes(pointlist, pointattriblist, pointmarkerlist) +REAL **pointlist; +REAL **pointattriblist; +int **pointmarkerlist; + +#else /* not TRILIBRARY */ + +void writenodes(nodefilename, argc, argv) +char *nodefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *pmlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + point pointloop; + int pointnumber; + int i; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing points.\n"); + } + /* Allocate memory for output points if necessary. */ + if (*pointlist == (REAL *) NULL) { + *pointlist = (REAL *) malloc(points.items * 2 * sizeof(REAL)); + if (*pointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output point attributes if necessary. */ + if ((nextras > 0) && (*pointattriblist == (REAL *) NULL)) { + *pointattriblist = (REAL *) malloc(points.items * nextras * sizeof(REAL)); + if (*pointattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output point markers if necessary. */ + if (!nobound && (*pointmarkerlist == (int *) NULL)) { + *pointmarkerlist = (int *) malloc(points.items * sizeof(int)); + if (*pointmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + plist = *pointlist; + palist = *pointattriblist; + pmlist = *pointmarkerlist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", nodefilename); + } + outfile = fopen(nodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", nodefilename); + exit(1); + } + /* Number of points, number of dimensions, number of point attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d %d %d\n", points.items, mesh_dim, nextras, + 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&points); + pointloop = pointtraverse(); + pointnumber = firstnumber; + while (pointloop != (point) NULL) { +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = pointloop[0]; + plist[coordindex++] = pointloop[1]; + /* Point attributes. */ + for (i = 0; i < nextras; i++) { + palist[attribindex++] = pointloop[2 + i]; + } + if (!nobound) { + /* Copy the boundary marker. */ + pmlist[pointnumber - firstnumber] = pointmark(pointloop); + } +#else /* not TRILIBRARY */ + /* Point number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", pointnumber, pointloop[0], + pointloop[1]); + for (i = 0; i < nextras; i++) { + /* Write an attribute. */ + fprintf(outfile, " %.17g", pointloop[i + 2]); + } + if (nobound) { + fprintf(outfile, "\n"); + } else { + /* Write the boundary marker. */ + fprintf(outfile, " %d\n", pointmark(pointloop)); + } +#endif /* not TRILIBRARY */ + + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* numbernodes() Number the points. */ +/* */ +/* Each point is assigned a marker equal to its number. */ +/* */ +/* Used when writenodes() is not called because no .node file is written. */ +/* */ +/*****************************************************************************/ + +void numbernodes() +{ + point pointloop; + int pointnumber; + + traversalinit(&points); + pointloop = pointtraverse(); + pointnumber = firstnumber; + while (pointloop != (point) NULL) { + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } +} + +/*****************************************************************************/ +/* */ +/* writeelements() Write the triangles to an .ele file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writeelements(trianglelist, triangleattriblist) +int **trianglelist; +REAL **triangleattriblist; + +#else /* not TRILIBRARY */ + +void writeelements(elefilename, argc, argv) +char *elefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *tlist; + REAL *talist; + int pointindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop; + point p1, p2, p3; + point mid1, mid2, mid3; + int elementnumber; + int i; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing triangles.\n"); + } + /* Allocate memory for output triangles if necessary. */ + if (*trianglelist == (int *) NULL) { + *trianglelist = (int *) malloc(triangles.items * + ((order + 1) * (order + 2) / 2) * sizeof(int)); + if (*trianglelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output triangle attributes if necessary. */ + if ((eextras > 0) && (*triangleattriblist == (REAL *) NULL)) { + *triangleattriblist = (REAL *) malloc(triangles.items * eextras * + sizeof(REAL)); + if (*triangleattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + tlist = *trianglelist; + talist = *triangleattriblist; + pointindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", elefilename); + } + outfile = fopen(elefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", elefilename); + exit(1); + } + /* Number of triangles, points per triangle, attributes per triangle. */ + fprintf(outfile, "%ld %d %d\n", triangles.items, + (order + 1) * (order + 2) / 2, eextras); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + if (order == 1) { +#ifdef TRILIBRARY + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for three points. */ + fprintf(outfile, "%4d %4d %4d %4d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3)); +#endif /* not TRILIBRARY */ + } else { + mid1 = (point) triangleloop.tri[highorderindex + 1]; + mid2 = (point) triangleloop.tri[highorderindex + 2]; + mid3 = (point) triangleloop.tri[highorderindex]; +#ifdef TRILIBRARY + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); + tlist[pointindex++] = pointmark(mid1); + tlist[pointindex++] = pointmark(mid2); + tlist[pointindex++] = pointmark(mid3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for six points. */ + fprintf(outfile, "%4d %4d %4d %4d %4d %4d %4d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3), pointmark(mid1), + pointmark(mid2), pointmark(mid3)); +#endif /* not TRILIBRARY */ + } + +#ifdef TRILIBRARY + for (i = 0; i < eextras; i++) { + talist[attribindex++] = elemattribute(triangleloop, i); + } +#else /* not TRILIBRARY */ + for (i = 0; i < eextras; i++) { + fprintf(outfile, " %.17g", elemattribute(triangleloop, i)); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writepoly() Write the segments and holes to a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writepoly(segmentlist, segmentmarkerlist) +int **segmentlist; +int **segmentmarkerlist; + +#else /* not TRILIBRARY */ + +void writepoly(polyfilename, holelist, holes, regionlist, regions, argc, argv) +char *polyfilename; +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *slist; + int *smlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; + int i; +#endif /* not TRILIBRARY */ + struct edge shelleloop; + point endpoint1, endpoint2; + int shellenumber; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing segments.\n"); + } + /* Allocate memory for output segments if necessary. */ + if (*segmentlist == (int *) NULL) { + *segmentlist = (int *) malloc(shelles.items * 2 * sizeof(int)); + if (*segmentlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output segment markers if necessary. */ + if (!nobound && (*segmentmarkerlist == (int *) NULL)) { + *segmentmarkerlist = (int *) malloc(shelles.items * sizeof(int)); + if (*segmentmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + slist = *segmentlist; + smlist = *segmentmarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", polyfilename); + } + outfile = fopen(polyfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", polyfilename); + exit(1); + } + /* The zero indicates that the points are in a separate .node file. */ + /* Followed by number of dimensions, number of point attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%d %d %d %d\n", 0, mesh_dim, nextras, 1 - nobound); + /* Number of segments, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", shelles.items, 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&shelles); + shelleloop.sh = shelletraverse(); + shelleloop.shorient = 0; + shellenumber = firstnumber; + while (shelleloop.sh != (shelle *) NULL) { + sorg(shelleloop, endpoint1); + sdest(shelleloop, endpoint2); +#ifdef TRILIBRARY + /* Copy indices of the segment's two endpoints. */ + slist[index++] = pointmark(endpoint1); + slist[index++] = pointmark(endpoint2); + if (!nobound) { + /* Copy the boundary marker. */ + smlist[shellenumber - firstnumber] = mark(shelleloop); + } +#else /* not TRILIBRARY */ + /* Segment number, indices of its two endpoints, and possibly a marker. */ + if (nobound) { + fprintf(outfile, "%4d %4d %4d\n", shellenumber, + pointmark(endpoint1), pointmark(endpoint2)); + } else { + fprintf(outfile, "%4d %4d %4d %4d\n", shellenumber, + pointmark(endpoint1), pointmark(endpoint2), mark(shelleloop)); + } +#endif /* not TRILIBRARY */ + + shelleloop.sh = shelletraverse(); + shellenumber++; + } + +#ifndef TRILIBRARY +#ifndef CDT_ONLY + fprintf(outfile, "%d\n", holes); + if (holes > 0) { + for (i = 0; i < holes; i++) { + /* Hole number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g\n", firstnumber + i, + holelist[2 * i], holelist[2 * i + 1]); + } + } + if (regions > 0) { + fprintf(outfile, "%d\n", regions); + for (i = 0; i < regions; i++) { + /* Region number, x and y coordinates, attribute, maximum area. */ + fprintf(outfile, "%4d %.17g %.17g %.17g %.17g\n", firstnumber + i, + regionlist[4 * i], regionlist[4 * i + 1], + regionlist[4 * i + 2], regionlist[4 * i + 3]); + } + } +#endif /* not CDT_ONLY */ + + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeedges() Write the edges to a .edge file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writeedges(edgelist, edgemarkerlist) +int **edgelist; +int **edgemarkerlist; + +#else /* not TRILIBRARY */ + +void writeedges(edgefilename, argc, argv) +char *edgefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *elist; + int *emlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + struct edge checkmark; + point p1, p2; + int edgenumber; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing edges.\n"); + } + /* Allocate memory for edges if necessary. */ + if (*edgelist == (int *) NULL) { + *edgelist = (int *) malloc(edges * 2 * sizeof(int)); + if (*edgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for edge markers if necessary. */ + if (!nobound && (*edgemarkerlist == (int *) NULL)) { + *edgemarkerlist = (int *) malloc(edges * sizeof(int)); + if (*edgemarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + elist = *edgelist; + emlist = *edgemarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", edgefilename); + } + outfile = fopen(edgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", edgefilename); + exit(1); + } + /* Number of edges, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", edges, 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + edgenumber = firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + org(triangleloop, p1); + dest(triangleloop, p2); +#ifdef TRILIBRARY + elist[index++] = pointmark(p1); + elist[index++] = pointmark(p2); +#endif /* TRILIBRARY */ + if (nobound) { +#ifndef TRILIBRARY + /* Edge number, indices of two endpoints. */ + fprintf(outfile, "%4d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2)); +#endif /* not TRILIBRARY */ + } else { + /* Edge number, indices of two endpoints, and a boundary marker. */ + /* If there's no shell edge, the boundary marker is zero. */ + if (useshelles) { + tspivot(triangleloop, checkmark); + if (checkmark.sh == dummysh) { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = 0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), 0); +#endif /* not TRILIBRARY */ + } else { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = mark(checkmark); +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), mark(checkmark)); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = trisym.tri == dummytri; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), trisym.tri == dummytri); +#endif /* not TRILIBRARY */ + } + } + edgenumber++; + } + } + triangleloop.tri = triangletraverse(); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */ +/* file. */ +/* */ +/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */ +/* Hence, the Voronoi vertices are listed by traversing the Delaunay */ +/* triangles, and the Voronoi edges are listed by traversing the Delaunay */ +/* edges. */ +/* */ +/* WARNING: In order to assign numbers to the Voronoi vertices, this */ +/* procedure messes up the shell edges or the extra nodes of every */ +/* element. Hence, you should call this procedure last. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writevoronoi(vpointlist, vpointattriblist, vpointmarkerlist, vedgelist, + vedgemarkerlist, vnormlist) +REAL **vpointlist; +REAL **vpointattriblist; +int **vpointmarkerlist; +int **vedgelist; +int **vedgemarkerlist; +REAL **vnormlist; + +#else /* not TRILIBRARY */ + +void writevoronoi(vnodefilename, vedgefilename, argc, argv) +char *vnodefilename; +char *vedgefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *elist; + REAL *normlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + point torg, tdest, tapex; + REAL circumcenter[2]; + REAL xi, eta; + int vnodenumber, vedgenumber; + int p1, p2; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing Voronoi vertices.\n"); + } + /* Allocate memory for Voronoi vertices if necessary. */ + if (*vpointlist == (REAL *) NULL) { + *vpointlist = (REAL *) malloc(triangles.items * 2 * sizeof(REAL)); + if (*vpointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for Voronoi vertex attributes if necessary. */ + if (*vpointattriblist == (REAL *) NULL) { + *vpointattriblist = (REAL *) malloc(triangles.items * nextras * + sizeof(REAL)); + if (*vpointattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + *vpointmarkerlist = (int *) NULL; + plist = *vpointlist; + palist = *vpointattriblist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", vnodefilename); + } + outfile = fopen(vnodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vnodefilename); + exit(1); + } + /* Number of triangles, two dimensions, number of point attributes, */ + /* zero markers. */ + fprintf(outfile, "%ld %d %d %d\n", triangles.items, 2, nextras, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + vnodenumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, torg); + dest(triangleloop, tdest); + apex(triangleloop, tapex); + findcircumcenter(torg, tdest, tapex, circumcenter, &xi, &eta); +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = circumcenter[0]; + plist[coordindex++] = circumcenter[1]; + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i]); + } +#else /* not TRILIBRARY */ + /* Voronoi vertex number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", vnodenumber, circumcenter[0], + circumcenter[1]); + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + fprintf(outfile, " %.17g", torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i])); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + * (int *) (triangleloop.tri + 6) = vnodenumber; + triangleloop.tri = triangletraverse(); + vnodenumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing Voronoi edges.\n"); + } + /* Allocate memory for output Voronoi edges if necessary. */ + if (*vedgelist == (int *) NULL) { + *vedgelist = (int *) malloc(edges * 2 * sizeof(int)); + if (*vedgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + *vedgemarkerlist = (int *) NULL; + /* Allocate memory for output Voronoi norms if necessary. */ + if (*vnormlist == (REAL *) NULL) { + *vnormlist = (REAL *) malloc(edges * 2 * sizeof(REAL)); + if (*vnormlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + elist = *vedgelist; + normlist = *vnormlist; + coordindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", vedgefilename); + } + outfile = fopen(vedgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vedgefilename); + exit(1); + } + /* Number of edges, zero boundary markers. */ + fprintf(outfile, "%ld %d\n", edges, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + vedgenumber = firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + /* Find the number of this triangle (and Voronoi vertex). */ + p1 = * (int *) (triangleloop.tri + 6); + if (trisym.tri == dummytri) { + org(triangleloop, torg); + dest(triangleloop, tdest); +#ifdef TRILIBRARY + /* Copy an infinite ray. Index of one endpoint, and -1. */ + elist[coordindex] = p1; + normlist[coordindex++] = tdest[1] - torg[1]; + elist[coordindex] = -1; + normlist[coordindex++] = torg[0] - tdest[0]; +#else /* not TRILIBRARY */ + /* Write an infinite ray. Edge number, index of one endpoint, -1, */ + /* and x and y coordinates of a vector representing the */ + /* direction of the ray. */ + fprintf(outfile, "%4d %d %d %.17g %.17g\n", vedgenumber, + p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]); +#endif /* not TRILIBRARY */ + } else { + /* Find the number of the adjacent triangle (and Voronoi vertex). */ + p2 = * (int *) (trisym.tri + 6); + /* Finite edge. Write indices of two endpoints. */ +#ifdef TRILIBRARY + elist[coordindex] = p1; + normlist[coordindex++] = 0.0; + elist[coordindex] = p2; + normlist[coordindex++] = 0.0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d\n", vedgenumber, p1, p2); +#endif /* not TRILIBRARY */ + } + vedgenumber++; + } + } + triangleloop.tri = triangletraverse(); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +#ifdef TRILIBRARY + +void writeneighbors(neighborlist) +int **neighborlist; + +#else /* not TRILIBRARY */ + +void writeneighbors(neighborfilename, argc, argv) +char *neighborfilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *nlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + int elementnumber; + int neighbor1, neighbor2, neighbor3; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing neighbors.\n"); + } + /* Allocate memory for neighbors if necessary. */ + if (*neighborlist == (int *) NULL) { + *neighborlist = (int *) malloc(triangles.items * 3 * sizeof(int)); + if (*neighborlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + nlist = *neighborlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", neighborfilename); + } + outfile = fopen(neighborfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", neighborfilename); + exit(1); + } + /* Number of triangles, three edges per triangle. */ + fprintf(outfile, "%ld %d\n", triangles.items, 3); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + * (int *) (triangleloop.tri + 6) = elementnumber; + triangleloop.tri = triangletraverse(); + elementnumber++; + } + * (int *) (dummytri + 6) = -1; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + triangleloop.orient = 1; + sym(triangleloop, trisym); + neighbor1 = * (int *) (trisym.tri + 6); + triangleloop.orient = 2; + sym(triangleloop, trisym); + neighbor2 = * (int *) (trisym.tri + 6); + triangleloop.orient = 0; + sym(triangleloop, trisym); + neighbor3 = * (int *) (trisym.tri + 6); +#ifdef TRILIBRARY + nlist[index++] = neighbor1; + nlist[index++] = neighbor2; + nlist[index++] = neighbor3; +#else /* not TRILIBRARY */ + /* Triangle number, neighboring triangle numbers. */ + fprintf(outfile, "%4d %d %d %d\n", elementnumber, + neighbor1, neighbor2, neighbor3); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeoff() Write the triangulation to an .off file. */ +/* */ +/* OFF stands for the Object File Format, a format used by the Geometry */ +/* Center's Geomview package. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void writeoff(offfilename, argc, argv) +char *offfilename; +int argc; +char **argv; +{ + FILE *outfile; + struct triedge triangleloop; + point pointloop; + point p1, p2, p3; + + if (!quiet) { + printf("Writing %s.\n", offfilename); + } + outfile = fopen(offfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", offfilename); + exit(1); + } + /* Number of points, triangles, and edges. */ + fprintf(outfile, "OFF\n%ld %ld %ld\n", points.items, triangles.items, + edges); + + /* Write the points. */ + traversalinit(&points); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + /* The "0.0" is here because the OFF format uses 3D coordinates. */ + fprintf(outfile, " %.17g %.17g %.17g\n", pointloop[0], + pointloop[1], 0.0); + pointloop = pointtraverse(); + } + + /* Write the triangles. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + /* The "3" means a three-vertex polygon. */ + fprintf(outfile, " 3 %4d %4d %4d\n", pointmark(p1) - 1, + pointmark(p2) - 1, pointmark(p3) - 1); + triangleloop.tri = triangletraverse(); + } + finishfile(outfile, argc, argv); +} + +#endif /* not TRILIBRARY */ + +/** **/ +/** **/ +/********* File I/O routines end here *********/ + +/*****************************************************************************/ +/* */ +/* quality_statistics() Print statistics about the quality of the mesh. */ +/* */ +/*****************************************************************************/ + +void quality_statistics() +{ + struct triedge triangleloop; + point p[3]; + REAL cossquaretable[8]; + REAL ratiotable[16]; + REAL dx[3], dy[3]; + REAL edgelength[3]; + REAL dotproduct; + REAL cossquare; + REAL triarea; + REAL shortest, longest; + REAL trilongest2; + REAL smallestarea, biggestarea; + REAL triminaltitude2; + REAL minaltitude; + REAL triaspect2; + REAL worstaspect; + REAL smallestangle, biggestangle; + REAL radconst, degconst; + int angletable[18]; + int aspecttable[16]; + int aspectindex; + int tendegree; + int acutebiggest; + int i, ii, j, k; + + printf("Mesh quality statistics:\n\n"); + radconst = (REAL)(PI / 18.0); + degconst = (REAL)(180.0 / PI); + for (i = 0; i < 8; i++) { + cossquaretable[i] = (REAL)(cos(radconst * (REAL) (i + 1))); + cossquaretable[i] = cossquaretable[i] * cossquaretable[i]; + } + for (i = 0; i < 18; i++) { + angletable[i] = 0; + } + + ratiotable[0] = 1.5; ratiotable[1] = 2.0; + ratiotable[2] = 2.5; ratiotable[3] = 3.0; + ratiotable[4] = 4.0; ratiotable[5] = 6.0; + ratiotable[6] = 10.0; ratiotable[7] = 15.0; + ratiotable[8] = 25.0; ratiotable[9] = 50.0; + ratiotable[10] = 100.0; ratiotable[11] = 300.0; + ratiotable[12] = 1000.0; ratiotable[13] = 10000.0; + ratiotable[14] = 100000.0; ratiotable[15] = 0.0; + for (i = 0; i < 16; i++) { + aspecttable[i] = 0; + } + + worstaspect = 0.0; + minaltitude = xmax - xmin + ymax - ymin; + minaltitude = minaltitude * minaltitude; + shortest = minaltitude; + longest = 0.0; + smallestarea = minaltitude; + biggestarea = 0.0; + worstaspect = 0.0; + smallestangle = 0.0; + biggestangle = 2.0; + acutebiggest = 1; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p[0]); + dest(triangleloop, p[1]); + apex(triangleloop, p[2]); + trilongest2 = 0.0; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dx[i] = p[j][0] - p[k][0]; + dy[i] = p[j][1] - p[k][1]; + edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; + if (edgelength[i] > trilongest2) { + trilongest2 = edgelength[i]; + } + if (edgelength[i] > longest) { + longest = edgelength[i]; + } + if (edgelength[i] < shortest) { + shortest = edgelength[i]; + } + } + + triarea = counterclockwise(p[0], p[1], p[2]); + if (triarea < smallestarea) { + smallestarea = triarea; + } + if (triarea > biggestarea) { + biggestarea = triarea; + } + triminaltitude2 = triarea * triarea / trilongest2; + if (triminaltitude2 < minaltitude) { + minaltitude = triminaltitude2; + } + triaspect2 = trilongest2 / triminaltitude2; + if (triaspect2 > worstaspect) { + worstaspect = triaspect2; + } + aspectindex = 0; + while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) + && (aspectindex < 15)) { + aspectindex++; + } + aspecttable[aspectindex]++; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; + cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); + tendegree = 8; + for (ii = 7; ii >= 0; ii--) { + if (cossquare > cossquaretable[ii]) { + tendegree = ii; + } + } + if (dotproduct <= 0.0) { + angletable[tendegree]++; + if (cossquare > smallestangle) { + smallestangle = cossquare; + } + if (acutebiggest && (cossquare < biggestangle)) { + biggestangle = cossquare; + } + } else { + angletable[17 - tendegree]++; + if (acutebiggest || (cossquare > biggestangle)) { + biggestangle = cossquare; + acutebiggest = 0; + } + } + } + triangleloop.tri = triangletraverse(); + } + + shortest = (REAL)sqrt(shortest); + longest = (REAL)sqrt(longest); + minaltitude = (REAL)sqrt(minaltitude); + worstaspect = (REAL)sqrt(worstaspect); + smallestarea *= 2.0; + biggestarea *= 2.0; + if (smallestangle >= 1.0) { + smallestangle = 0.0; + } else { + smallestangle = (REAL)(degconst * acos(sqrt(smallestangle))); + } + if (biggestangle >= 1.0) { + biggestangle = 180.0; + } else { + if (acutebiggest) { + biggestangle = (REAL)(degconst * acos(sqrt(biggestangle))); + } else { + biggestangle = (REAL)(180.0 - degconst * acos(sqrt(biggestangle))); + } + } + + printf(" Smallest area: %16.5g | Largest area: %16.5g\n", + smallestarea, biggestarea); + printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", + shortest, longest); + printf(" Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", + minaltitude, worstaspect); + printf(" Aspect ratio histogram:\n"); + printf(" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], + aspecttable[8]); + for (i = 1; i < 7; i++) { + printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[i - 1], ratiotable[i], aspecttable[i], + ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]); + } + printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", + ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], + aspecttable[15]); + printf( +" (Triangle aspect ratio is longest edge divided by shortest altitude)\n\n"); + printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", + smallestangle, biggestangle); + printf(" Angle histogram:\n"); + for (i = 0; i < 9; i++) { + printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", + i * 10, i * 10 + 10, angletable[i], + i * 10 + 90, i * 10 + 100, angletable[i + 9]); + } + printf("\n"); +} + +/*****************************************************************************/ +/* */ +/* statistics() Print all sorts of cool facts. */ +/* */ +/*****************************************************************************/ + +void statistics() +{ + printf("\nStatistics:\n\n"); + printf(" Input points: %d\n", inpoints); + if (refine) { + printf(" Input triangles: %d\n", inelements); + } + if (poly) { + printf(" Input segments: %d\n", insegments); + if (!refine) { + printf(" Input holes: %d\n", holes); + } + } + + printf("\n Mesh points: %ld\n", points.items); + printf(" Mesh triangles: %ld\n", triangles.items); + printf(" Mesh edges: %ld\n", edges); + if (poly || refine) { + printf(" Mesh boundary edges: %ld\n", hullsize); + printf(" Mesh segments: %ld\n\n", shelles.items); + } else { + printf(" Mesh convex hull edges: %ld\n\n", hullsize); + } + if (verbose) { + quality_statistics(); + printf("Memory allocation statistics:\n\n"); + printf(" Maximum number of points: %ld\n", points.maxitems); + printf(" Maximum number of triangles: %ld\n", triangles.maxitems); + if (shelles.maxitems > 0) { + printf(" Maximum number of segments: %ld\n", shelles.maxitems); + } + if (viri.maxitems > 0) { + printf(" Maximum number of viri: %ld\n", viri.maxitems); + } + if (badsegments.maxitems > 0) { + printf(" Maximum number of encroached segments: %ld\n", + badsegments.maxitems); + } + if (badtriangles.maxitems > 0) { + printf(" Maximum number of bad triangles: %ld\n", + badtriangles.maxitems); + } + if (splaynodes.maxitems > 0) { + printf(" Maximum number of splay tree nodes: %ld\n", + splaynodes.maxitems); + } + printf(" Approximate heap memory use (bytes): %ld\n\n", + points.maxitems * points.itembytes + + triangles.maxitems * triangles.itembytes + + shelles.maxitems * shelles.itembytes + + viri.maxitems * viri.itembytes + + badsegments.maxitems * badsegments.itembytes + + badtriangles.maxitems * badtriangles.itembytes + + splaynodes.maxitems * splaynodes.itembytes); + + printf("Algorithmic statistics:\n\n"); + printf(" Number of incircle tests: %ld\n", incirclecount); + printf(" Number of orientation tests: %ld\n", counterclockcount); + if (hyperbolacount > 0) { + printf(" Number of right-of-hyperbola tests: %ld\n", + hyperbolacount); + } + if (circumcentercount > 0) { + printf(" Number of circumcenter computations: %ld\n", + circumcentercount); + } + if (circletopcount > 0) { + printf(" Number of circle top computations: %ld\n", + circletopcount); + } + printf("\n"); + } +} + +/*****************************************************************************/ +/* */ +/* main() or triangulate() Gosh, do everything. */ +/* */ +/* The sequence is roughly as follows. Many of these steps can be skipped, */ +/* depending on the command line switches. */ +/* */ +/* - Initialize constants and parse the command line. */ +/* - Read the points from a file and either */ +/* - triangulate them (no -r), or */ +/* - read an old mesh from files and reconstruct it (-r). */ +/* - Insert the PSLG segments (-p), and possibly segments on the convex */ +/* hull (-c). */ +/* - Read the holes (-p), regional attributes (-pA), and regional area */ +/* constraints (-pa). Carve the holes and concavities, and spread the */ +/* regional attributes and area constraints. */ +/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */ +/* Also enforce the conforming Delaunay property (-q and -a). */ +/* - Compute the number of edges in the resulting mesh. */ +/* - Promote the mesh's linear triangles to higher order elements (-o). */ +/* - Write the output files and print the statistics. */ +/* - Check the consistency and Delaunay property of the mesh (-C). */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void triangulate(triswitches, in, out, vorout) +char *triswitches; +struct triangulateio *in; +struct triangulateio *out; +struct triangulateio *vorout; + +#else /* not TRILIBRARY */ + +int main(argc, argv) +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ + REAL *holearray; /* Array of holes. */ + REAL *regionarray; /* Array of regional attributes and area constraints. */ +#ifndef TRILIBRARY + FILE *polyfile; +#endif /* not TRILIBRARY */ +#ifndef NO_TIMER + /* Variables for timing the performance of Triangle. The types are */ + /* defined in sys/time.h. */ + struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6; + struct timezone tz; +#endif /* NO_TIMER */ + +#ifndef NO_TIMER + gettimeofday(&tv0, &tz); +#endif /* NO_TIMER */ + + triangleinit(); +#ifdef TRILIBRARY + parsecommandline(1, &triswitches); +#else /* not TRILIBRARY */ + parsecommandline(argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + transfernodes(in->pointlist, in->pointattributelist, in->pointmarkerlist, + in->numberofpoints, in->numberofpointattributes); +#else /* not TRILIBRARY */ + readnodes(innodefilename, inpolyfilename, &polyfile); +#endif /* not TRILIBRARY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv1, &tz); + } +#endif /* NO_TIMER */ + +#ifdef CDT_ONLY + hullsize = delaunay(); /* Triangulate the points. */ +#else /* not CDT_ONLY */ + if (refine) { + /* Read and reconstruct a mesh. */ +#ifdef TRILIBRARY + hullsize = reconstruct(in->trianglelist, in->triangleattributelist, + in->trianglearealist, in->numberoftriangles, + in->numberofcorners, in->numberoftriangleattributes, + in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + hullsize = reconstruct(inelefilename, areafilename, inpolyfilename, + polyfile); +#endif /* not TRILIBRARY */ + } else { + hullsize = delaunay(); /* Triangulate the points. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv2, &tz); + if (refine) { + printf("Mesh reconstruction"); + } else { + printf("Delaunay"); + } + printf(" milliseconds: %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec) + + (tv2.tv_usec - tv1.tv_usec) / 1000l); + } +#endif /* NO_TIMER */ + + /* Ensure that no point can be mistaken for a triangular bounding */ + /* box point in insertsite(). */ + infpoint1 = (point) NULL; + infpoint2 = (point) NULL; + infpoint3 = (point) NULL; + + if (useshelles) { + checksegments = 1; /* Segments will be introduced next. */ + if (!refine) { + /* Insert PSLG segments and/or convex hull segments. */ +#ifdef TRILIBRARY + insegments = formskeleton(in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + insegments = formskeleton(polyfile, inpolyfilename); +#endif /* not TRILIBRARY */ + } + } + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv3, &tz); + if (useshelles && !refine) { + printf("Segment milliseconds: %ld\n", + 1000l * (tv3.tv_sec - tv2.tv_sec) + + (tv3.tv_usec - tv2.tv_usec) / 1000l); + } + } +#endif /* NO_TIMER */ + + if (poly) { +#ifdef TRILIBRARY + holearray = in->holelist; + holes = in->numberofholes; + regionarray = in->regionlist; + regions = in->numberofregions; +#else /* not TRILIBRARY */ + readholes(polyfile, inpolyfilename, &holearray, &holes, + ®ionarray, ®ions); +#endif /* not TRILIBRARY */ + if (!refine) { + /* Carve out holes and concavities. */ + carveholes(holearray, holes, regionarray, regions); + } + } else { + /* Without a PSLG, there can be no holes or regional attributes */ + /* or area constraints. The following are set to zero to avoid */ + /* an accidental free() later. */ + holes = 0; + regions = 0; + } + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv4, &tz); + if (poly && !refine) { + printf("Hole milliseconds: %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec) + + (tv4.tv_usec - tv3.tv_usec) / 1000l); + } + } +#endif /* NO_TIMER */ + +#ifndef CDT_ONLY + if (quality) { + enforcequality(); /* Enforce angle and area constraints. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv5, &tz); +#ifndef CDT_ONLY + if (quality) { + printf("Quality milliseconds: %ld\n", + 1000l * (tv5.tv_sec - tv4.tv_sec) + + (tv5.tv_usec - tv4.tv_usec) / 1000l); + } +#endif /* not CDT_ONLY */ + } +#endif /* NO_TIMER */ + + /* Compute the number of edges. */ + edges = (3l * triangles.items + hullsize) / 2l; + + if (order > 1) { + highorder(); /* Promote elements to higher polynomial order. */ + } + if (!quiet) { + printf("\n"); + } + +#ifdef TRILIBRARY + out->numberofpoints = points.items; + out->numberofpointattributes = nextras; + out->numberoftriangles = triangles.items; + out->numberofcorners = (order + 1) * (order + 2) / 2; + out->numberoftriangleattributes = eextras; + out->numberofedges = edges; + if (useshelles) { + out->numberofsegments = shelles.items; + } else { + out->numberofsegments = hullsize; + } + if (vorout != (struct triangulateio *) NULL) { + vorout->numberofpoints = triangles.items; + vorout->numberofpointattributes = nextras; + vorout->numberofedges = edges; + } +#endif /* TRILIBRARY */ + /* If not using iteration numbers, don't write a .node file if one was */ + /* read, because the original one would be overwritten! */ + if (nonodewritten || (noiterationnum && readnodefile)) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing points.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .node file.\n"); +#endif /* not TRILIBRARY */ + } + numbernodes(); /* We must remember to number the points. */ + } else { +#ifdef TRILIBRARY + writenodes(&out->pointlist, &out->pointattributelist, + &out->pointmarkerlist); +#else /* not TRILIBRARY */ + writenodes(outnodefilename, argc, argv); /* Numbers the points too. */ +#endif /* TRILIBRARY */ + } + if (noelewritten) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing triangles.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing an .ele file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writeelements(&out->trianglelist, &out->triangleattributelist); +#else /* not TRILIBRARY */ + writeelements(outelefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + /* The -c switch (convex switch) causes a PSLG to be written */ + /* even if none was read. */ + if (poly || convex) { + /* If not using iteration numbers, don't overwrite the .poly file. */ + if (nopolywritten || noiterationnum) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing segments.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .poly file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writepoly(&out->segmentlist, &out->segmentmarkerlist); + out->numberofholes = holes; + out->numberofregions = regions; + if (poly) { + out->holelist = in->holelist; + out->regionlist = in->regionlist; + } else { + out->holelist = (REAL *) NULL; + out->regionlist = (REAL *) NULL; + } +#else /* not TRILIBRARY */ + writepoly(outpolyfilename, holearray, holes, regionarray, regions, + argc, argv); +#endif /* not TRILIBRARY */ + } + } +#ifndef TRILIBRARY +#ifndef CDT_ONLY + if (regions > 0) { + free(regionarray); + } +#endif /* not CDT_ONLY */ + if (holes > 0) { + free(holearray); + } + if (geomview) { + writeoff(offfilename, argc, argv); + } +#endif /* not TRILIBRARY */ + if (edgesout) { +#ifdef TRILIBRARY + writeedges(&out->edgelist, &out->edgemarkerlist); +#else /* not TRILIBRARY */ + writeedges(edgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (voronoi) { +#ifdef TRILIBRARY + writevoronoi(&vorout->pointlist, &vorout->pointattributelist, + &vorout->pointmarkerlist, &vorout->edgelist, + &vorout->edgemarkerlist, &vorout->normlist); +#else /* not TRILIBRARY */ + writevoronoi(vnodefilename, vedgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (neighbors) { +#ifdef TRILIBRARY + writeneighbors(&out->neighborlist); +#else /* not TRILIBRARY */ + writeneighbors(neighborfilename, argc, argv); +#endif /* not TRILIBRARY */ + } + + if (!quiet) { +#ifndef NO_TIMER + gettimeofday(&tv6, &tz); + printf("\nOutput milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv5.tv_sec) + + (tv6.tv_usec - tv5.tv_usec) / 1000l); + printf("Total running milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv0.tv_sec) + + (tv6.tv_usec - tv0.tv_usec) / 1000l); +#endif /* NO_TIMER */ + + statistics(); + } + +#ifndef REDUCED + if (docheck) { + checkmesh(); + checkdelaunay(); + } +#endif /* not REDUCED */ + + triangledeinit(); +#ifndef TRILIBRARY + return 0; +#endif /* not TRILIBRARY */ +} diff --git a/contrib/gtkgensurf/triangle.h b/contrib/gtkgensurf/triangle.h new file mode 100644 index 00000000..70cd6596 --- /dev/null +++ b/contrib/gtkgensurf/triangle.h @@ -0,0 +1,288 @@ +/*****************************************************************************/ +/* */ +/* (triangle.h) */ +/* */ +/* Include file for programs that call Triangle. */ +/* */ +/* Accompanies Triangle Version 1.3 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* How to call Triangle from another program */ +/* */ +/* */ +/* If you haven't read Triangle's instructions (run "triangle -h" to read */ +/* them), you won't understand what follows. */ +/* */ +/* Triangle must be compiled into an object file (triangle.o) with the */ +/* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */ +/* switch). The makefile included with Triangle will do this for you if */ +/* you run "make trilibrary". The resulting object file can be called via */ +/* the procedure triangulate(). */ +/* */ +/* If the size of the object file is important to you, you may wish to */ +/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ +/* of all features that are primarily of research interest. Specifically, */ +/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ +/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ +/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ +/* eliminates Triangle's -r, -q, -a, -S, and -s switches. */ +/* */ +/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ +/* made in the makefile or in triangle.c itself. Putting these definitions */ +/* in this file will not create the desired effect. */ +/* */ +/* */ +/* The calling convention for triangulate() follows. */ +/* */ +/* void triangulate(triswitches, in, out, vorout) */ +/* char *triswitches; */ +/* struct triangulateio *in; */ +/* struct triangulateio *out; */ +/* struct triangulateio *vorout; */ +/* */ +/* `triswitches' is a string containing the command line switches you wish */ +/* to invoke. No initial dash is required. Some suggestions: */ +/* */ +/* - You'll probably find it convenient to use the `z' switch so that */ +/* points (and other items) are numbered from zero. This simplifies */ +/* indexing, because the first item of any type always starts at index */ +/* [0] of the corresponding array, whether that item's number is zero or */ +/* one. */ +/* - You'll probably want to use the `Q' (quiet) switch in your final code, */ +/* but you can take advantage of Triangle's printed output (including the */ +/* `V' switch) while debugging. */ +/* - If you are not using the `q' or `a' switches, then the output points */ +/* will be identical to the input points, except possibly for the */ +/* boundary markers. If you don't need the boundary markers, you should */ +/* use the `N' (no nodes output) switch to save memory. (If you do need */ +/* boundary markers, but need to save memory, a good nasty trick is to */ +/* set out->pointlist equal to in->pointlist before calling triangulate(),*/ +/* so that Triangle overwrites the input points with identical copies.) */ +/* - The `I' (no iteration numbers) and `g' (.off file output) switches */ +/* have no effect when Triangle is compiled with TRILIBRARY defined. */ +/* */ +/* `in', `out', and `vorout' are descriptions of the input, the output, */ +/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ +/* `vorout' may be NULL. `in' and `out' may never be NULL. */ +/* */ +/* Certain fields of the input and output structures must be initialized, */ +/* as described below. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* The `triangulateio' structure. */ +/* */ +/* Used to pass data into and out of the triangulate() procedure. */ +/* */ +/* */ +/* Arrays are used to store points, triangles, markers, and so forth. In */ +/* all cases, the first item in any array is stored starting at index [0]. */ +/* However, that item is item number `1' unless the `z' switch is used, in */ +/* which case it is item number `0'. Hence, you may find it easier to */ +/* index points (and triangles in the neighbor list) if you use the `z' */ +/* switch. Unless, of course, you're calling Triangle from a Fortran */ +/* program. */ +/* */ +/* Description of fields (except the `numberof' fields, which are obvious): */ +/* */ +/* `pointlist': An array of point coordinates. The first point's x */ +/* coordinate is at index [0] and its y coordinate at index [1], followed */ +/* by the coordinates of the remaining points. Each point occupies two */ +/* REALs. */ +/* `pointattributelist': An array of point attributes. Each point's */ +/* attributes occupy `numberofpointattributes' REALs. */ +/* `pointmarkerlist': An array of point markers; one int per point. */ +/* */ +/* `trianglelist': An array of triangle corners. The first triangle's */ +/* first corner is at index [0], followed by its other two corners in */ +/* counterclockwise order, followed by any other nodes if the triangle */ +/* represents a nonlinear element. Each triangle occupies */ +/* `numberofcorners' ints. */ +/* `triangleattributelist': An array of triangle attributes. Each */ +/* triangle's attributes occupy `numberoftriangleattributes' REALs. */ +/* `trianglearealist': An array of triangle area constraints; one REAL per */ +/* triangle. Input only. */ +/* `neighborlist': An array of triangle neighbors; three ints per */ +/* triangle. Output only. */ +/* */ +/* `segmentlist': An array of segment endpoints. The first segment's */ +/* endpoints are at indices [0] and [1], followed by the remaining */ +/* segments. Two ints per segment. */ +/* `segmentmarkerlist': An array of segment markers; one int per segment. */ +/* */ +/* `holelist': An array of holes. The first hole's x and y coordinates */ +/* are at indices [0] and [1], followed by the remaining holes. Two */ +/* REALs per hole. Input only, although the pointer is copied to the */ +/* output structure for your convenience. */ +/* */ +/* `regionlist': An array of regional attributes and area constraints. */ +/* The first constraint's x and y coordinates are at indices [0] and [1], */ +/* followed by the regional attribute and index [2], followed by the */ +/* maximum area at index [3], followed by the remaining area constraints. */ +/* Four REALs per area constraint. Note that each regional attribute is */ +/* used only if you select the `A' switch, and each area constraint is */ +/* used only if you select the `a' switch (with no number following), but */ +/* omitting one of these switches does not change the memory layout. */ +/* Input only, although the pointer is copied to the output structure for */ +/* your convenience. */ +/* */ +/* `edgelist': An array of edge endpoints. The first edge's endpoints are */ +/* at indices [0] and [1], followed by the remaining edges. Two ints per */ +/* edge. Output only. */ +/* `edgemarkerlist': An array of edge markers; one int per edge. Output */ +/* only. */ +/* `normlist': An array of normal vectors, used for infinite rays in */ +/* Voronoi diagrams. The first normal vector's x and y magnitudes are */ +/* at indices [0] and [1], followed by the remaining vectors. For each */ +/* finite edge in a Voronoi diagram, the normal vector written is the */ +/* zero vector. Two REALs per edge. Output only. */ +/* */ +/* */ +/* Any input fields that Triangle will examine must be initialized. */ +/* Furthermore, for each output array that Triangle will write to, you */ +/* must either provide space by setting the appropriate pointer to point */ +/* to the space you want the data written to, or you must initialize the */ +/* pointer to NULL, which tells Triangle to allocate space for the results. */ +/* The latter option is preferable, because Triangle always knows exactly */ +/* how much space to allocate. The former option is provided mainly for */ +/* people who need to call Triangle from Fortran code, though it also makes */ +/* possible some nasty space-saving tricks, like writing the output to the */ +/* same arrays as the input. */ +/* */ +/* Triangle will not free() any input or output arrays, including those it */ +/* allocates itself; that's up to you. */ +/* */ +/* Here's a guide to help you decide which fields you must initialize */ +/* before you call triangulate(). */ +/* */ +/* `in': */ +/* */ +/* - `pointlist' must always point to a list of points; `numberofpoints' */ +/* and `numberofpointattributes' must be properly set. */ +/* `pointmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. If */ +/* `numberofpointattributes' is not zero, `pointattributelist' must */ +/* point to a list of point attributes. */ +/* - If the `r' switch is used, `trianglelist' must point to a list of */ +/* triangles, and `numberoftriangles', `numberofcorners', and */ +/* `numberoftriangleattributes' must be properly set. If */ +/* `numberoftriangleattributes' is not zero, `triangleattributelist' */ +/* must point to a list of triangle attributes. If the `a' switch is */ +/* used (with no number following), `trianglearealist' must point to a */ +/* list of triangle area constraints. `neighborlist' may be ignored. */ +/* - If the `p' switch is used, `segmentlist' must point to a list of */ +/* segments, `numberofsegments' must be properly set, and */ +/* `segmentmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. */ +/* - If the `p' switch is used without the `r' switch, then */ +/* `numberofholes' and `numberofregions' must be properly set. If */ +/* `numberofholes' is not zero, `holelist' must point to a list of */ +/* holes. If `numberofregions' is not zero, `regionlist' must point to */ +/* a list of region constraints. */ +/* - If the `p' switch is used, `holelist', `numberofholes', */ +/* `regionlist', and `numberofregions' is copied to `out'. (You can */ +/* nonetheless get away with not initializing them if the `r' switch is */ +/* used.) */ +/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ +/* ignored. */ +/* */ +/* `out': */ +/* */ +/* - `pointlist' must be initialized (NULL or pointing to memory) unless */ +/* the `N' switch is used. `pointmarkerlist' must be initialized */ +/* unless the `N' or `B' switch is used. If `N' is not used and */ +/* `in->numberofpointattributes' is not zero, `pointattributelist' must */ +/* be initialized. */ +/* - `trianglelist' must be initialized unless the `E' switch is used. */ +/* `neighborlist' must be initialized if the `n' switch is used. If */ +/* the `E' switch is not used and (`in->numberofelementattributes' is */ +/* not zero or the `A' switch is used), `elementattributelist' must be */ +/* initialized. `trianglearealist' may be ignored. */ +/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ +/* and the `P' switch is not used. `segmentmarkerlist' must also be */ +/* initialized under these circumstances unless the `B' switch is used. */ +/* - `edgelist' must be initialized if the `e' switch is used. */ +/* `edgemarkerlist' must be initialized if the `e' switch is used and */ +/* the `B' switch is not. */ +/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ +/* */ +/* `vorout' (only needed if `v' switch is used): */ +/* */ +/* - `pointlist' must be initialized. If `in->numberofpointattributes' */ +/* is not zero, `pointattributelist' must be initialized. */ +/* `pointmarkerlist' may be ignored. */ +/* - `edgelist' and `normlist' must both be initialized. */ +/* `edgemarkerlist' may be ignored. */ +/* - Everything else may be ignored. */ +/* */ +/* After a call to triangulate(), the valid fields of `out' and `vorout' */ +/* will depend, in an obvious way, on the choice of switches used. Note */ +/* that when the `p' switch is used, the pointers `holelist' and */ +/* `regionlist' are copied from `in' to `out', but no new space is */ +/* allocated; be careful that you don't free() the same array twice. On */ +/* the other hand, Triangle will never copy the `pointlist' pointer (or any */ +/* others); new space is allocated for `out->pointlist', or if the `N' */ +/* switch is used, `out->pointlist' remains uninitialized. */ +/* */ +/* All of the meaningful `numberof' fields will be properly set; for */ +/* instance, `numberofedges' will represent the number of edges in the */ +/* triangulation whether or not the edges were written. If segments are */ +/* not used, `numberofsegments' will indicate the number of boundary edges. */ +/* */ +/*****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct triangulateio { + REAL *pointlist; /* In / out */ + REAL *pointattributelist; /* In / out */ + int *pointmarkerlist; /* In / out */ + int numberofpoints; /* In / out */ + int numberofpointattributes; /* In / out */ + + int *trianglelist; /* In / out */ + REAL *triangleattributelist; /* In / out */ + REAL *trianglearealist; /* In only */ + int *neighborlist; /* Out only */ + int numberoftriangles; /* In / out */ + int numberofcorners; /* In / out */ + int numberoftriangleattributes; /* In / out */ + + int *segmentlist; /* In / out */ + int *segmentmarkerlist; /* In / out */ + int numberofsegments; /* In / out */ + + REAL *holelist; /* In / pointer to array copied out */ + int numberofholes; /* In / copied out */ + + REAL *regionlist; /* In / pointer to array copied out */ + int numberofregions; /* In / copied out */ + + int *edgelist; /* Out only */ + int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ + REAL *normlist; /* Used only with Voronoi diagram; out only */ + int numberofedges; /* Out only */ +}; + +void triangulate(char *, struct triangulateio *, struct triangulateio *, + struct triangulateio *); + +#ifdef __cplusplus +} +#endif diff --git a/contrib/gtkgensurf/view.cpp b/contrib/gtkgensurf/view.cpp new file mode 100644 index 00000000..ff4b1572 --- /dev/null +++ b/contrib/gtkgensurf/view.cpp @@ -0,0 +1,1287 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +#undef ISOMETRIC + +extern double backface; +extern double dh, dv; +extern double xmin,xmax,ymin,ymax,zmin,zmax; + +double SF, SFG; // Graphics scale factors +double XLo, XHi, YLo, YHi, ZLo, ZHi; +double yaw,roll; +double elevation,azimuth; +int cxChar = 10, cyChar = 16; +int X0, Y0; +int X0G, Y0G; + +static RECT rcCoord; // where X= Y= is drawn +static RECT rcGrid; // rectangle within rcLower that forms the border of the grid, plus + // a 3 pixel slop. +static RECT rcLower; // lower half of window, where plan view is drawn +static RECT rcUpper; // upper half or entire window, where isometric projection is drawn + +void vertex_selected (); +void texfont_init (); +void texfont_write (const char *text, float l, float t); + +#define PEN_GRID { \ + g_GLTable.m_pfn_qglLineWidth (1); \ + g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } + +#define PEN_RED { \ + g_GLTable.m_pfn_qglLineWidth (2); \ + g_GLTable.m_pfn_qglColor3f (1, 0, 0); \ + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } + +#define PEN_DASH { \ + g_GLTable.m_pfn_qglLineWidth (1); \ + g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ + g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \ + g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); } + +#define DRAW_QUAD(rc,r,g,b) { \ + g_GLTable.m_pfn_qglBegin (GL_QUADS); \ + g_GLTable.m_pfn_qglColor3f (0,1,0); \ + g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.bottom); \ + g_GLTable.m_pfn_qglVertex2f (rc.right, rc.bottom); \ + g_GLTable.m_pfn_qglVertex2f (rc.right, rc.top+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.top+1); \ + g_GLTable.m_pfn_qglColor3f (r,g,b); \ + g_GLTable.m_pfn_qglVertex2f (rc.left, rc.bottom+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.bottom+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.top); \ + g_GLTable.m_pfn_qglVertex2f (rc.left, rc.top); \ + g_GLTable.m_pfn_qglEnd (); } + + +#ifndef ISOMETRIC +double D=65536.; +double ct[3],st[3]; +double Hhi, Hlo, Vhi, Vlo; +#endif + +#define SUBDIVS 6 + + +void ShowPreview () +{ + if (Preview) + { + if (g_pWndPreview == NULL) + CreateViewWindow (); + gtk_widget_show (g_pWndPreview); + + UpdatePreview (true); + } + else + gtk_widget_hide (g_pWndPreview); +} + +static void draw_preview () +{ + int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height; + + g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1); + g_GLTable.m_pfn_qglViewport (0, 0, width, height); + g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION); + g_GLTable.m_pfn_qglLoadIdentity (); + g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1); + g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + // ^Fishman - Antializing for the preview window. + if (Antialiasing) + { + g_GLTable.m_pfn_qglEnable(GL_BLEND); + g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + else + { + g_GLTable.m_pfn_qglDisable(GL_BLEND); + g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + } + + texfont_init (); + + if (!ValidSurface ()) + return; + + rcUpper.left = 0; + rcUpper.right = width; + rcUpper.bottom = 0; + rcUpper.top = height; + rcLower.left = 0; + rcLower.right = width; + rcLower.bottom = 0; + rcLower.top = height; + + if (VertexMode) + { + rcUpper.bottom = rcUpper.top/2; + DrawPreview (rcUpper); + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (rcUpper.left, rcUpper.bottom); + g_GLTable.m_pfn_qglVertex2f (rcUpper.right, rcUpper.bottom); + g_GLTable.m_pfn_qglEnd (); + rcLower.top = rcUpper.bottom-1; + DrawGrid (rcLower); + rcCoord.left = rcLower.left; + rcCoord.right = rcLower.right; + rcCoord.bottom = rcLower.bottom; + rcCoord.top = rcLower.top; + rcCoord.top = rcCoord.bottom+cyChar; + rcCoord.right = rcCoord.left + 15*cxChar; + rcGrid.left = X0G - 3; + rcGrid.bottom = Y0G - 3; + rcGrid.right = X0G + (int)(SFG*(Hur-Hll)) + 3; + rcGrid.top = Y0G + (int)(SFG*(Vur-Vll)) + 3; + } + else + DrawPreview (rcUpper); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) + { + g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); + return TRUE; + } + + draw_preview (); + + g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); + g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); + + return TRUE; +} + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; + bool Selected; + double x,y; + int i, j, k, ks; + int i0, i1, j0, j1; + + if ((!VertexMode) || (event->button != 1)) + return; + + if (!PtInRect (&rcGrid,pt)) + { + gdk_beep (); + return; + } + + x = Hll + (pt.x-X0G)/SFG; + y = Vur - (pt.y-Y0G)/SFG; + i = (int)(floor( (x-Hll)/dh - 0.5) + 1); + j = (int)(floor( (y-Vll)/dv - 0.5) + 1); + if (i < 0 || i > NH || j < 0 || j > NV) + { + gdk_beep (); + return; + } + + if(!CanEdit(i,j)) + { + gdk_beep (); + return; + } + + // Control key pressed - add this point, or remove it if already selected + if ((event->state & GDK_CONTROL_MASK) != 0) + { + Selected = FALSE; + if (NumVerticesSelected) + { + for (k=0; kstate & GDK_SHIFT_MASK) != 0) + { + if (NumVerticesSelected) + { + NumVerticesSelected = 1; + i0 = min(Vertex[0].i, i); + i1 = max(Vertex[0].i, i); + j0 = min(Vertex[0].j, j); + j1 = max(Vertex[0].j, j); + for(i=i0; i<=i1; i++) + { + for(j=j0; j<=j1; j++) + { + if(i==0 && j==0 ) continue; + if(i==NH && j==0 ) continue; + if(i==0 && j==NV) continue; + if(i==NH && j==NV) continue; + if(i != Vertex[0].i || j != Vertex[0].j) + { + Vertex[NumVerticesSelected].i = i; + Vertex[NumVerticesSelected].j = j; + NumVerticesSelected++; + } + } + } + } + else + { + Vertex[0].i = i; + Vertex[0].j = j; + NumVerticesSelected = 1; + } + } + else + { + Vertex[0].i = i; + Vertex[0].j = j; + NumVerticesSelected = 1; + } + + vertex_selected (); +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; + + if (!VertexMode) + return; + + if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) + { + g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); + return; + } + + g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST); + g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left, + rcCoord.top-rcCoord.bottom); + g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT); + + if (PtInRect(&rcGrid,pt)) + { + GdkCursor *cursor = gdk_cursor_new (GDK_CROSS); + gdk_window_set_cursor (g_pWndPreview->window, cursor); + gdk_cursor_unref (cursor); + + char Text[32]; + int x, y; + + x = (int)(Hll + (pt.x-X0G)/SFG); + y = (int)(Vur - (pt.y-Y0G)/SFG); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + sprintf(Text," x=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + break; + case PLANE_YZ0: + case PLANE_YZ1: + sprintf(Text," y=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + break; + default: + sprintf(Text," x=%d, y=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + } + + texfont_write (Text, rcCoord.left, rcCoord.top); + } + else + { + gdk_window_set_cursor (g_pWndPreview->window, NULL); + } + + g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); + g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); + g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST); +} + +static gint preview_close (GtkWidget *widget, gpointer data) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE); + return TRUE; +} + +static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data) +{ + *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360)); + UpdatePreview (false); +} + +static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) +{ + preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast(data)); + return FALSE; +} + +static void preview_spin (GtkAdjustment *adj, double *data) +{ + *data = DegreesToRadians (adj->value); + UpdatePreview (false); +} + +void CreateViewWindow () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame; + GtkObject *adj; + +#ifndef ISOMETRIC + elevation = PI/6.; + azimuth = PI/6.; +#endif + + g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd)); + gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + +#ifndef ISOMETRIC + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); + + label = gtk_label_new ("Elevation"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation); + + adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); + gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + + label = gtk_label_new ("Azimuth"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth); +#endif + + frame = gtk_frame_new (NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL); + + gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), NULL); + + gtk_widget_show (g_pPreviewWidget); + gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget); + + if (Preview) + gtk_widget_show (g_pWndPreview); + + UpdatePreview (true); +} + +//============================================================= +/* DrawPreview */ +void DrawPreview (RECT rc) +{ +#define COSXA 0.8660254037844 +#define SINXA 0.5 +#define COSYA 0.8660254037844 +#define SINYA 0.5 + + double L; + double x,y; + int i, j; + POINT pt[8]; + XYZ v[8]; + char axis[3][2] = {"X","Y","Z"}; + +#ifndef ISOMETRIC + evaluate(); +#endif + + XLo = xmin; + XHi = xmax; + YLo = ymin; + YHi = ymax; + ZLo = zmin; + ZHi = zmax; + switch (Plane) + { + case PLANE_XY1: + ZHi = backface; + break; + case PLANE_XZ0: + YLo = backface; + break; + case PLANE_XZ1: + YHi = backface; + break; + case PLANE_YZ0: + XLo = backface; + break; + case PLANE_YZ1: + XHi = backface; + break; + default: + ZLo = backface; + } + + + + GetScaleFactor(rc); + //PEN_GRID + g_GLTable.m_pfn_qglLineWidth (1); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); + + if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) + { + XYZ *vv; + + vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ)); + for(i=0; i 2) + x = Hll + dh * (int)(NH/2 + 1); + else + x = Hll + dh * (int)(NH/2); + if(NV > 2) + y = Vll + dv * (int)(NV/2 + 1); + else + y = Vll + dv * (int)(NV/2); + } + else + { + if(NH > 1) + x = Hll + dh * (int)(NH/2); + else + x = Hll + dh/2; + if(NV > 1) + y = Vll + dv * (int)(NV/2); + else + y = Vll + dv/2; + } +// x = (Hll+Hur)/2.; +// y = (Vll+Vur)/2.; + v[0].p[0] = x + PlayerBox[Game].x[0]; + v[0].p[1] = y + PlayerBox[Game].y[0]; + v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist + } + v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0]; + v[1].p[1] = v[0].p[1]; + v[1].p[2] = v[0].p[2]; + v[2].p[0] = v[1].p[0]; + v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0]; + v[2].p[2] = v[0].p[2]; + v[3].p[0] = v[0].p[0]; + v[3].p[1] = v[2].p[1]; + v[3].p[2] = v[0].p[2]; + VectorCopy(v[0].p,v[4].p); + VectorCopy(v[1].p,v[5].p); + VectorCopy(v[2].p,v[6].p); + VectorCopy(v[3].p,v[7].p); + v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + for(i=0; i<=7; i++) + { +#ifndef ISOMETRIC + project(&v[i]); +#endif + Scale(rc,v[i],&pt[i]); + } + g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); + g_GLTable.m_pfn_qglVertex2f (pt[3].x, pt[3].y); + for(i=0; i<=3; i++) + g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); + g_GLTable.m_pfn_qglEnd (); + g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); + g_GLTable.m_pfn_qglVertex2f (pt[7].x, pt[7].y); + for(i=4; i<=7; i++) + g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); + g_GLTable.m_pfn_qglEnd (); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=3; i++) + { + g_GLTable.m_pfn_qglVertex2f (pt[i].x,pt[i].y); + g_GLTable.m_pfn_qglVertex2f (pt[i+4].x,pt[i+4].y); + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglLineWidth (1); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); +} +//============================================================= +void DrawGrid(RECT rc) +{ + int i, j, k; + double h,w,x,y; + POINT pt[2]; + RECT rcBox; + + w = (double)(rc.right-rc.left+1) - cxChar; + h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar; + + SFG = w/(Hur-Hll); + SFG = min(SFG, h/(Vur-Vll)); + + // Center drawing + X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2; + Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2; + + g_GLTable.m_pfn_qglLineWidth (2); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); + + pt[0].y = Y0G; + pt[1].y = Y0G + (int)(SFG*(Vur-Vll)); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=NH; i++) + { + x = Hll + i * dh; + pt[0].x = X0G + (int)(SFG*(x-Hll)); + g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[0].y); + g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[1].y); + } + g_GLTable.m_pfn_qglEnd (); + pt[0].x = X0G; + pt[1].x = X0G + (int)(SFG*(Hur-Hll)); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=NV; i++) + { + y = Vll + i * dv; + pt[0].y = Y0G + (int)(SFG*(Vur-y)); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[0].y); + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglLineWidth (1); + + // Draw axes + pt[0].x = rc.right - cyChar - cxChar - cyChar/2; + pt[0].y = rc.bottom + cyChar/2; + pt[1].x = pt[0].x + cyChar; + pt[1].y = pt[0].y; + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); + g_GLTable.m_pfn_qglEnd (); + switch(Plane) + { + case PLANE_YZ0: + case PLANE_YZ1: + texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2); + break; + default: + texfont_write ("X", pt[1].x, pt[1].y+cyChar/2); + } + pt[1].x = pt[0].x; + pt[1].y = pt[0].y + cyChar; + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); + g_GLTable.m_pfn_qglEnd (); + switch(Plane) + { + case PLANE_XY0: + case PLANE_XY1: + texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar); + break; + default: + texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar); + } + + // Denote fixed points with a 5x5 red rectangle + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + { + x = Hll + i*dh; + y = Vll + j*dv; + rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2; + rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2; + rcBox.right = rcBox.left + 5; + rcBox.bottom = rcBox.top - 5; + + DRAW_QUAD (rcBox, 1,0,0); + } + } + } + + // Denote currently selected point with a 5x5 green rectangle + if (NumVerticesSelected) + { + for(k=0; kp[0]; + y = v->p[1]; + z = v->p[2]; + + // yaw + xa = ct[0]*x - st[0]*z; + za = st[0]*x + ct[0]*z; + + // roll + x = ct[1]*xa + st[1]*y; + ya = ct[1]*y - st[1]*xa; + + // azimuth + z = ct[2]*za - st[2]*ya; + y = ct[2]*ya + st[2]*za; + + // horizontal and vertical projections: +// v->pp[0] = D*x/z; +// v->pp[1] = D*y/z; + v->pp[0] = -y; + v->pp[1] = x; + v->pp[2] = z; + + // NOTE: if perspective transformation is desired, + // set "persp" to the range from the surface, + // then: + // v->projected_h = -v->projected_h * persp/(v->projected_z-persp); + // v->projected_v = -v->projected_v * persp/(v->projected_z-persp); +} +/*=======================================================================*/ +void evaluate() +{ + int i, j; + XYZ v[4]; + + if(elevation > PI) elevation -= 2.*PI; + roll = elevation * sin(azimuth); + yaw = 1.5*PI + elevation*cos(azimuth); + + // Find angles from midpoint to viewpoint: + st[0] = sin(yaw); + st[1] = sin(roll); + st[2] = sin(azimuth); + ct[0] = cos(yaw); + ct[1] = cos(roll); + ct[2] = cos(azimuth); + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + project(&xyz[i][j]); + } + } + + Hhi = xyz[0][0].pp[0]; + Hlo = Hhi; + Vhi = xyz[0][0].pp[1]; + Vlo = Vhi; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + Hlo = min(Hlo,xyz[i][j].pp[0]); + Hhi = max(Hhi,xyz[i][j].pp[0]); + Vlo = min(Vlo,xyz[i][j].pp[1]); + Vhi = max(Vhi,xyz[i][j].pp[1]); + } + } + + // Include backface in min-max + VectorCopy(xyz[ 0][ 0].p,v[0].p); + VectorCopy(xyz[NH][ 0].p,v[1].p); + VectorCopy(xyz[NH][NV].p,v[2].p); + VectorCopy(xyz[ 0][NV].p,v[3].p); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + v[0].p[1] = backface; + v[1].p[1] = v[0].p[1]; + v[2].p[1] = v[0].p[1]; + v[3].p[1] = v[0].p[1]; + break; + case PLANE_YZ0: + case PLANE_YZ1: + v[0].p[0] = backface; + v[1].p[0] = v[0].p[0]; + v[2].p[0] = v[0].p[0]; + v[3].p[0] = v[0].p[0]; + break; + default: + v[0].p[2] = backface; + v[1].p[2] = v[0].p[2]; + v[2].p[2] = v[0].p[2]; + v[3].p[2] = v[0].p[2]; + } + for(i=0; i<=3; i++) + { + project(&v[i]); + Hlo = min(Hlo,v[i].pp[0]); + Hhi = max(Hhi,v[i].pp[0]); + Vlo = min(Vlo,v[i].pp[1]); + Vhi = max(Vhi,v[i].pp[1]); + } + +} +#endif diff --git a/contrib/hydratoolz/hydratoolz.def b/contrib/hydratoolz/hydratoolz.def new file mode 100644 index 00000000..c7ce9f33 --- /dev/null +++ b/contrib/hydratoolz/hydratoolz.def @@ -0,0 +1,8 @@ +; fgd.def : Declares the module parameters for the DLL. + +LIBRARY "HydraToolz" +DESCRIPTION 'HydraToolz Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/hydratoolz/hydratoolz.vcproj b/contrib/hydratoolz/hydratoolz.vcproj new file mode 100644 index 00000000..106ae05b --- /dev/null +++ b/contrib/hydratoolz/hydratoolz.vcproj @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/hydratoolz/plugin.cpp b/contrib/hydratoolz/plugin.cpp new file mode 100644 index 00000000..9e05e6d1 --- /dev/null +++ b/contrib/hydratoolz/plugin.cpp @@ -0,0 +1,412 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "plugin.h" +#include "version.h" + +/*! \file plugin.cpp + \brief HydraToolz! + + HydraToolz by Dominic Clifton - Hydra (Hydra@Hydras-World.com) + + Overview + ======== + + This plugin allows the user to rebuild the "wad" key pair in the worldspawn + so that it has a list of all the .wad files in use. + + Version History + =============== + + v0.1 - 28/May/2002 + - Initial version. + + v1.0 - 10/March/2003 + - Added more console output + - Removed some old test code + - Tweaked dialog box. + - Fixed up for Radiant 1.3.5 + + + ToDo + ==== + + Nothing... + +*/ + +// ============================================================================= +// Globals + +_QERFuncTable_1 g_FuncTable; +_QERFileSystemTable g_FileSystemTable; +_QEREntityTable g_EntityTable; + + +// ============================================================================= +// Ripped from cmdlib.cpp + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +// End of rip from cmdlib.cpp + +// ============================================================================= +// Actual Plugin Code + +// get the wad name from the shader name (or an actual wadname) and add to a list of wad names making +// sure we don't add duplicates. + +GSList *AddToWadList(GSList *wadlist, const char *shadername, const char *wad) +{ + char tmpstr[QER_MAX_NAMELEN]; + char *wadname; + if (!shadername && !wad) return wadlist; + + if (shadername) + { + if (strcmp(shadername,"color") == 0) + return wadlist; + ExtractFilePath(shadername,tmpstr); + // Sys_Printf("checking: %s\n",shadername); + + int l = strlen(tmpstr) - 1; + + if (tmpstr[l] == '/' || tmpstr[l] == '\\') + tmpstr[l] = 0; + else + { + Sys_Printf("HydraToolz: WARNING: Unknown wad file for shader %s\n",shadername); + return wadlist; + } + + ExtractFileName(tmpstr,tmpstr); + + wadname = (char *)malloc(strlen(tmpstr) + 5); + sprintf(wadname,"%s.wad",tmpstr); + } + else + { + wadname=strdup(wad); + } + + for (GSList *l = wadlist; l != NULL ; l = l->next) + { + if (!stricmp((char *)l->data,wadname)) + { + free( wadname ); + return wadlist; + } + } + + Sys_Printf("HydraToolz: Adding Wad File to WAD list: %s (reason: ",wadname); + if (shadername) + Sys_Printf("see shader \"%s\")\n", shadername); + else + Sys_Printf("already in WAD key. )\n"); + return ( g_slist_append (wadlist, wadname ) ); +} + +void UpdateWadKeyPair( void ) +{ + int i,nb; + + char wads[2048]; // change to CString usage ? + *wads = 0; + char *p1,*p2; + entity_t *pEntity; + epair_t *pEpair; + GSList *wadlist = NULL; + face_t *f; + brush_t *b; + char cleanwadname[QER_MAX_NAMELEN]; + char *actualwad; + + + pEntity = (entity_t *)g_FuncTable.m_pfnGetEntityHandle(0); // get the worldspawn ent + + Sys_Printf("HydraToolz: Searching for in-use wad files...\n"); + for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) + { + if (stricmp(pEpair->key,"wad") == 0) + { + strcpy(wads,pEpair->value); + ConvertDOSToUnixName(wads,wads); + + Sys_Printf("HydraToolz: Current wad key is \"%s\"!\n",wads); + + // ok, we got the list of ; delimited wads, now split it into a GSList that contains + // just the wad names themselves. + + p1 = wads; + + do + { + p2 = strchr(p1,';'); + if (p2) + *p2 = 0; // swap the ; with a null terminator + + if (strchr(p1,'/') || strchr(p1,'\\')) + { + ExtractFileName(p1,cleanwadname); + wadlist = AddToWadList (wadlist, NULL, cleanwadname); + } + else + { + wadlist = AddToWadList (wadlist, NULL, p1); + } + if (p2) + p1 = p2+1; // point back to the remainder of the string + else + p1 = NULL; // make it so we exit the loop. + + } while (p1); + + // ok, now we have a list of wads in GSList. + // now we need to add any new wadfiles (with their paths) to this list + // so scan all brushes and see what wads are in use + // FIXME: scan brushes only in the region ? + + break; // we don't need to process any more key/pairs. + } + } + + if (!*wads) + Sys_Printf("HydraToolz: No \"wad\" keypair wound in worldspawn\n"); + + + nb = g_FuncTable.m_pfnAllocateActiveBrushHandles(); + for( i = 0; i < nb; i++ ) + { + b = (brush_t *)g_FuncTable.m_pfnGetActiveBrushHandle(i); + if (b->patchBrush) // patches in halflife ? + { + wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); + } + } + } + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + nb = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + for( i = 0; i < nb; i++ ) + { + b = (brush_t *)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + if (b->patchBrush) // patches in halflife ? + { + wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); + } + } + } + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + Sys_Printf("HydraToolz: Rebuilding worldspawn's \"wad\" key-pair...\n"); + // Now we have a complete list of wadnames (without paths) so we just have to turn this + // back to a ; delimited list. + + *wads = 0; + while (wadlist) + { + // skip wad files if they start with "common-" + if (strnicmp((char *)wadlist->data,"common-",7) == 0) + { + Sys_Printf("HydraToolz: Skipping radiant/user-supplied wad file %s\n",(char *)wadlist->data); + } + else + { + if (wads[0]) + strcat(wads,";"); + + actualwad = vfsGetFullPath((char *)wadlist->data); + + if (actualwad) + { + strcat(wads, actualwad); + } + else + { + Sys_Printf("HydraToolz: WARNING: could not locate wad file %s\n",(char *)wadlist->data); + strcat(wads, (char *)wadlist->data); + } + } + + free (wadlist->data); + wadlist = g_slist_remove (wadlist, wadlist->data); + } + + // store the wad list back in the worldspawn. + if (*wads) + { + //free(pEpair->value); + //pEpair->value = strdup(wads); + SetKeyValue(pEntity, "wad", wads); + Sys_Printf("HydraToolz: Setting worldspawn \"wad\" key value to \"%s\"\n",wads); + + } + + Sys_Printf("HydraToolz: Finished rebuilding wad keypair!\n"); + +} + +// ============================================================================= +// PLUGIN INTERFACE STUFF + +// plugin name +const char *PLUGIN_NAME = "HydraToolz"; + +// commands in the menu +const char *PLUGIN_COMMANDS = "About...;Create/Update WAD keypair"; + +const char *PLUGIN_ABOUT = "HydraToolz v1.0 for GTKRadiant\n\n" + "By Hydra!"; + +extern "C" void* WINAPI QERPlug_GetFuncTable () +{ + return &g_FuncTable; +} + +const char* QERPlug_Init (void* hApp, void *pWidget) +{ + return "HydraToolz for GTKRadiant"; // do we need this ? hmmm +} + +const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + if(!strcmp(p, "Create/Update WAD keypair")) + UpdateWadKeyPair(); + else if(!strcmp(p, "About...")) + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientHydraToolz g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "HydraToolz", sizeof(_QERPluginTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + return &g_SynapseClient; +} + +bool CSynapseClientHydraToolz::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable); + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +const char* CSynapseClientHydraToolz::GetInfo() +{ + return "HydraToolz plugin built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/hydratoolz/plugin.h b/contrib/hydratoolz/plugin.h new file mode 100644 index 00000000..493fa839 --- /dev/null +++ b/contrib/hydratoolz/plugin.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +//#include +//#include +#include +#include + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ishaders.h" +#define USE_VFSTABLE_DEFINE +#include "ifilesystem.h" +#define USE_ENTITYTABLE_DEFINE +#include "ientity.h" + +class CSynapseClientHydraToolz : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientHydraToolz() { } + virtual ~CSynapseClientHydraToolz() { } +}; + +#endif // _PLUGIN_H_ diff --git a/contrib/prtview/.cvsignore b/contrib/prtview/.cvsignore new file mode 100644 index 00000000..66d25b10 --- /dev/null +++ b/contrib/prtview/.cvsignore @@ -0,0 +1,8 @@ +Debug +Release +*.d +*.plg +*.BAK +*.mak +*.ncb +*.opt diff --git a/contrib/prtview/AboutDialog.cpp b/contrib/prtview/AboutDialog.cpp new file mode 100644 index 00000000..b82a7a49 --- /dev/null +++ b/contrib/prtview/AboutDialog.cpp @@ -0,0 +1,139 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AboutDialog.cpp : implementation file +// + +#include "stdafx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +void DoAboutDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *button, *label; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); + + label = gtk_label_new ("Version 1.000\n\n" + "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" + "Written by Geoffrey DeWan\ngdewan@prairienet.org\n\n" + "Built against GtkRadiant " RADIANT_VERSION "\n" + __DATE__ + ); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +#else // GTK_PLUGIN + +CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAboutDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDialog) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) + //{{AFX_MSG_MAP(CAboutDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +#endif // GTK_PLUGIN + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog message handlers diff --git a/contrib/prtview/AboutDialog.h b/contrib/prtview/AboutDialog.h new file mode 100644 index 00000000..73dbad78 --- /dev/null +++ b/contrib/prtview/AboutDialog.h @@ -0,0 +1,72 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) +#define AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// AboutDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +#ifdef GTK_PLUGIN +void DoAboutDlg (); + +#else // GTK_PLUGIN + +class CAboutDialog : public CDialog +{ +// Construction +public: + CAboutDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutDialog) + enum { IDD = IDD_ABOUT }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/ConfigDialog.cpp b/contrib/prtview/ConfigDialog.cpp new file mode 100644 index 00000000..ced949bb --- /dev/null +++ b/contrib/prtview/ConfigDialog.cpp @@ -0,0 +1,925 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// ConfigDialog.cpp : implementation file +// + +#include "stdafx.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog dialog + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +// ============================================================================= +// Color selection dialog + +static int DoColor (COLORREF *c) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = ((double)GetRValue (*c)) / 255.0; + clr[1] = ((double)GetGValue (*c)) / 255.0; + clr[2] = ((double)GetBValue (*c)) / 255.0; + + dlg = gtk_color_selection_dialog_new ("Choose Color"); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + gtk_widget_show(dlg); + gtk_grab_add(dlg); + + while (loop) + gtk_main_iteration (); + + gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); + } + + return ret; +} + +static void Set2DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DTransText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void SetClipText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void OnScroll2d (GtkAdjustment *adj, gpointer data) +{ + portals.width_2d = adj->value; + Set2DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnScroll3d (GtkAdjustment *adj, gpointer data) +{ + portals.width_3d = adj->value; + Set3DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollTrans (GtkAdjustment *adj, gpointer data) +{ + portals.trans_3d = adj->value; + Set3DTransText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollClip (GtkAdjustment *adj, gpointer data) +{ + portals.clip_range = adj->value; + SetClipText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnAntiAlias2d (GtkWidget *widget, gpointer data) +{ + portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnConfig2d (GtkWidget *widget, gpointer data) +{ + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnColor2d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_2d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +static void OnConfig3d (GtkWidget *widget, gpointer data) +{ + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +static void OnAntiAlias3d (GtkWidget *widget, gpointer data) +{ + portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnColor3d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_3d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnColorFog (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_fog) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnFog (GtkWidget *widget, gpointer data) +{ + portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) +{ + portals.zbuffer = GPOINTER_TO_INT (data); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnPoly (GtkWidget *widget, gpointer data) +{ + portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnLines (GtkWidget *widget, gpointer data) +{ + portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnClip (GtkWidget *widget, gpointer data) +{ + portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void DoConfigDialog () +{ + GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; + GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; + GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; + GtkWidget *transslider, *translabel, *clipslider, *cliplabel; + GtkWidget *show2check, *show3check, *portalcheck; + int loop = 1, ret = IDCANCEL; + GtkObject *adj; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + frame = gtk_frame_new ("3D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); + + adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); + lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw3slider); + gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); + + lw3label = gtk_label_new (""); + gtk_widget_show (lw3label); + gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); + + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); + + button = gtk_button_new_with_label ("Depth Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); + + aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa3check); + gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); + + depthcheck = gtk_check_button_new_with_label ("Depth Cue"); + gtk_widget_show (depthcheck); + gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); + + linescheck = gtk_check_button_new_with_label ("Lines"); + gtk_widget_show (linescheck); + gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); + + polyscheck = gtk_check_button_new_with_label ("Polygons"); + gtk_widget_show (polyscheck); + gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); + + zlist = gtk_option_menu_new (); + gtk_widget_show (zlist); + gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); + + menu = gtk_menu_new (); + gtk_widget_show (menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Off"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); + gtk_menu_append (GTK_MENU (menu), item); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); + transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (transslider); + gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); + + translabel = gtk_label_new (""); + gtk_widget_show (translabel); + gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); + + adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); + clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (clipslider); + gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); + + cliplabel = gtk_label_new (""); + gtk_widget_show (cliplabel); + gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show3check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show3check); + gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); + + portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); + gtk_widget_show (portalcheck); + gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); + + frame = gtk_frame_new ("2D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); + lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw2slider); + gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); + + lw2label = gtk_label_new (""); + gtk_widget_show (lw2label); + gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); + gtk_widget_set_usize (button, 60, -2); + + aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa2check); + gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show2check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show2check); + gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + // initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); + Set2DText (lw2label); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); + gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); + + Set3DText (lw3label); + Set3DTransText (translabel); + SetClipText (cliplabel); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +#else // GTK_PLUGIN + +CConfigDialog::CConfigDialog(CWnd* pParent /*=NULL*/) + : CDialog(CConfigDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CConfigDialog) + //}}AFX_DATA_INIT +} + + +void CConfigDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CConfigDialog) + DDX_Control(pDX, IDC_CLIP, m_clip_ctrl); + DDX_Control(pDX, IDC_CUBIC, m_cubic_ctrl); + DDX_Control(pDX, IDC_SCROLL_CUBIC, m_scroll_cubic_ctrl); + DDX_Control(pDX, IDC_LINES, m_line_ctrl); + DDX_Control(pDX, IDC_SCROLL_3D_TRANS, m_scroll_3d_trans_ctrl); + DDX_Control(pDX, IDC_3D_TRANS, m_3d_trans_ctrl); + DDX_Control(pDX, IDC_POLY, m_poly_ctrl); + DDX_Control(pDX, IDC_FOG, m_fog_ctrl); + DDX_Control(pDX, IDC_ZBUFFER, m_z_ctrl); + DDX_Control(pDX, IDC_SCROLL_3D_WIDTH, m_scroll_3d_width_ctrl); + DDX_Control(pDX, IDC_ANTI_ALIAS_3D, m_aa_3d_ctrl); + DDX_Control(pDX, IDC_3D_WIDTH, m_3d_width_ctrl); + DDX_Control(pDX, IDC_ANTI_ALIAS_2D, m_aa_2d_ctrl); + DDX_Control(pDX, IDC_SCROLL_2D_WIDTH, m_scroll_2d_width_ctrl); + DDX_Control(pDX, IDC_2D_WIDTH, m_2d_width_ctrl); + DDX_Control(pDX, IDC_CONFIG_3D, m_3d_ctrl); + DDX_Control(pDX, IDC_CONFIG_2D, m_2d_ctrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CConfigDialog, CDialog) + //{{AFX_MSG_MAP(CConfigDialog) + ON_WM_HSCROLL() + ON_BN_CLICKED(IDC_ANTI_ALIAS_2D, OnAntiAlias2d) + ON_BN_CLICKED(IDC_CONFIG_2D, OnConfig2d) + ON_BN_CLICKED(IDC_CONFIG_3D, OnConfig3d) + ON_BN_CLICKED(IDC_COLOR_2D, OnColor2d) + ON_BN_CLICKED(IDC_ANTI_ALIAS_3D, OnAntiAlias3d) + ON_BN_CLICKED(IDC_COLOR_3D, OnColor3d) + ON_BN_CLICKED(IDC_COLOR_FOG, OnColorFog) + ON_BN_CLICKED(IDC_FOG, OnFog) + ON_CBN_SELCHANGE(IDC_ZBUFFER, OnSelchangeZbuffer) + ON_BN_CLICKED(IDC_POLY, OnPoly) + ON_BN_CLICKED(IDC_LINES, OnLines) + ON_BN_CLICKED(IDC_CLIP, OnClip) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog message handlers + +void CConfigDialog::Set2DText() +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + m_2d_width_ctrl.SetWindowText(s); +} + +void CConfigDialog::Set3DText() +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + m_3d_width_ctrl.SetWindowText(s); +} + +void CConfigDialog::Set3DTransText() +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + m_3d_trans_ctrl.SetWindowText(s); +} + +void CConfigDialog::SetClipText() +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + m_cubic_ctrl.SetWindowText(s); +} + +qboolean CConfigDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_2d_ctrl.SetCheck(portals.show_2d); + m_aa_2d_ctrl.SetCheck(portals.aa_2d); + Set2DText(); + + m_scroll_2d_width_ctrl.SetScrollRange(2, 40, FALSE); + m_scroll_2d_width_ctrl.SetScrollPos((int)portals.width_2d, TRUE); + + m_3d_ctrl.SetCheck(portals.show_3d); + m_fog_ctrl.SetCheck(portals.fog); + m_poly_ctrl.SetCheck(portals.polygons); + m_line_ctrl.SetCheck(portals.lines); + m_aa_3d_ctrl.SetCheck(portals.aa_3d); + m_z_ctrl.SetCurSel(portals.zbuffer); + m_clip_ctrl.SetCheck(portals.clip); + + Set3DText(); + Set3DTransText(); + SetClipText(); + + m_scroll_3d_width_ctrl.SetScrollRange(2, 40, FALSE); + m_scroll_3d_width_ctrl.SetScrollPos((int)portals.width_3d, TRUE); + m_scroll_3d_trans_ctrl.SetScrollRange(0, 100, FALSE); + m_scroll_3d_trans_ctrl.SetScrollPos((int)portals.trans_3d, TRUE); + m_scroll_cubic_ctrl.SetScrollRange(1, 128, FALSE); + m_scroll_cubic_ctrl.SetScrollPos((int)portals.clip_range, TRUE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CConfigDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + float *adj; + float scr_min, scr_max, scr_big; + + if(nSBCode == SB_THUMBPOSITION) + { + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + return; + } + + if(pScrollBar == &m_scroll_2d_width_ctrl) + { + scr_min = 2.0f; + scr_max = 40.0f; + scr_big = 4.0f; + + adj = &portals.width_2d; + } + else if(pScrollBar == &m_scroll_3d_width_ctrl) + { + scr_min = 2.0f; + scr_max = 40.0f; + scr_big = 4.0f; + + adj = &portals.width_3d; + } + else if(pScrollBar == &m_scroll_3d_trans_ctrl) + { + scr_min = 0.0f; + scr_max = 100.0f; + scr_big = 10.0f; + + adj = &portals.trans_3d; + } + else if(pScrollBar == &m_scroll_cubic_ctrl) + { + scr_min = 1.0f; + scr_max = 128.0f; + scr_big = 8.0f; + + adj = &portals.clip_range; + } + else + { + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + return; + } + + switch(nSBCode) + { + case SB_LEFT: + *adj = scr_min; + pScrollBar->SetScrollPos((int)scr_min, TRUE); + break; + case SB_RIGHT: + *adj = scr_max; + pScrollBar->SetScrollPos((int)scr_max, TRUE); + break; + case SB_LINELEFT: + *adj -= 1.0f; + + if(*adj < scr_min) + *adj = scr_min; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_LINERIGHT: + *adj += 1.0f; + + if(*adj > scr_max) + *adj = scr_max; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_PAGELEFT: + *adj -= scr_big; + + if(*adj < scr_min) + *adj = scr_min; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_PAGERIGHT: + *adj += scr_big; + + if(*adj > scr_max) + *adj = scr_max; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_THUMBTRACK: + *adj = (float)nPos; + + break; + case SB_ENDSCROLL: + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + default: + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + } + + if(pScrollBar == &m_scroll_2d_width_ctrl) + { + Set2DText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } + else if(pScrollBar == &m_scroll_3d_width_ctrl) + { + Set3DText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } + else if(pScrollBar == &m_scroll_3d_trans_ctrl) + { + Set3DTransText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } + else if(pScrollBar == &m_scroll_cubic_ctrl) + { + SetClipText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnAntiAlias2d() +{ + portals.aa_2d = m_aa_2d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +void CConfigDialog::OnConfig2d() +{ + portals.show_2d = m_2d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +void CConfigDialog::OnColor2d() +{ + CColorDialog dlg(portals.color_2d, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_2d = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +void CConfigDialog::OnConfig3d() +{ + portals.show_3d = m_3d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +void CConfigDialog::OnAntiAlias3d() +{ + portals.aa_3d = m_aa_3d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnColor3d() +{ + CColorDialog dlg(portals.color_3d, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_3d = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnColorFog() +{ + CColorDialog dlg(portals.color_fog, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_fog = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnFog() +{ + portals.fog = m_fog_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnSelchangeZbuffer() +{ + portals.zbuffer = m_z_ctrl.GetCurSel(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnPoly() +{ + portals.polygons = m_poly_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnLines() +{ + portals.lines = m_line_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnClip() +{ + portals.clip = m_clip_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +#endif // GTK_PLUGIN diff --git a/contrib/prtview/ConfigDialog.h b/contrib/prtview/ConfigDialog.h new file mode 100644 index 00000000..7ca84920 --- /dev/null +++ b/contrib/prtview/ConfigDialog.h @@ -0,0 +1,107 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) +#define AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// ConfigDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog dialog + +#ifdef GTK_PLUGIN + +void DoConfigDialog (); + +#else + +class CConfigDialog : public CDialog +{ +// Construction +public: + CConfigDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CConfigDialog) + enum { IDD = IDD_CONFIG }; + CButton m_clip_ctrl; + CStatic m_cubic_ctrl; + CScrollBar m_scroll_cubic_ctrl; + CButton m_line_ctrl; + CScrollBar m_scroll_3d_trans_ctrl; + CStatic m_3d_trans_ctrl; + CButton m_poly_ctrl; + CButton m_fog_ctrl; + CComboBox m_z_ctrl; + CScrollBar m_scroll_3d_width_ctrl; + CButton m_aa_3d_ctrl; + CStatic m_3d_width_ctrl; + CButton m_aa_2d_ctrl; + CScrollBar m_scroll_2d_width_ctrl; + CStatic m_2d_width_ctrl; + CButton m_3d_ctrl; + CButton m_2d_ctrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CConfigDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + void Set2DText(); + void Set3DText(); + void Set3DTransText(); + void SetClipText(); + + // Generated message map functions + //{{AFX_MSG(CConfigDialog) + virtual qboolean OnInitDialog(); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnAntiAlias2d(); + afx_msg void OnConfig2d(); + afx_msg void OnConfig3d(); + afx_msg void OnColor2d(); + afx_msg void OnAntiAlias3d(); + afx_msg void OnColor3d(); + afx_msg void OnColorFog(); + afx_msg void OnFog(); + afx_msg void OnSelchangeZbuffer(); + afx_msg void OnPoly(); + afx_msg void OnLines(); + afx_msg void OnClip(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/LoadPortalFileDialog.cpp b/contrib/prtview/LoadPortalFileDialog.cpp new file mode 100644 index 00000000..ed7d9de1 --- /dev/null +++ b/contrib/prtview/LoadPortalFileDialog.cpp @@ -0,0 +1,288 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// LoadPortalFileDialog.cpp : implementation file +// + +#include "stdafx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + char **filename; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); + + *loop = 0; + if ((int)data == IDOK) + *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); +} + +static void change_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget* file_sel; + char* filename = NULL; + int loop = 1; + + file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + if (filename != NULL) + { + strcpy (portals.fn, filename); + gtk_entry_set_text (GTK_ENTRY (data), filename); + g_free (filename); + } +} + +int DoLoadPortalFileDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + check3d = gtk_check_button_new_with_label ("Show 3D"); + gtk_widget_show (check3d); + gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); + + check2d = gtk_check_button_new_with_label ("Show 2D"); + gtk_widget_show (check2d); + gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + char *fn = g_FuncTable.m_pfnGetMapName(); + strcpy (portals.fn, fn); + fn = strrchr (portals.fn, '.'); + if (fn != NULL) + { + *fn = '\0'; + strcat (portals.fn, ".prt"); + } + + gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + portals.Purge(); + + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)) ? true : false; + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)) ? true : false; + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +#else // GTK_PLUGIN + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog dialog + +CLoadPortalFileDialog::CLoadPortalFileDialog(CWnd* pParent /*=NULL*/) + : CDialog(CLoadPortalFileDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoadPortalFileDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CLoadPortalFileDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoadPortalFileDialog) + DDX_Control(pDX, IDC_LOAD_3D, m_3d_ctrl); + DDX_Control(pDX, IDC_LOAD_2D, m_2d_ctrl); + DDX_Control(pDX, IDC_LOAD_FILE_NAME, m_fn_ctrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoadPortalFileDialog, CDialog) + //{{AFX_MSG_MAP(CLoadPortalFileDialog) + ON_BN_CLICKED(IDC_LOAD_OTHER, OnLoadOther) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog message handlers + +qboolean CLoadPortalFileDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + char fn_drive[_MAX_DRIVE]; + char fn_dir[_MAX_DIR]; + char fn_name[_MAX_FNAME]; + char fn_ext[_MAX_EXT]; + + char *fn = g_IBSPTable.m_pfnGetMapName(); + + _fullpath(portals.fn, fn, _MAX_PATH); + _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); + + strcpy(portals.fn, fn_drive); + strcat(portals.fn, fn_dir); + strcat(portals.fn, fn_name); + strcat(portals.fn, ".prt"); + + m_fn_ctrl.SetWindowText(portals.fn); + + m_2d_ctrl.SetCheck(portals.show_2d); + m_3d_ctrl.SetCheck(portals.show_3d); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CLoadPortalFileDialog::OnOK() +{ + portals.Purge(); + + portals.show_3d = m_3d_ctrl.GetCheck(); + portals.show_2d = m_2d_ctrl.GetCheck(); + + CDialog::OnOK(); +} + +void CLoadPortalFileDialog::OnLoadOther() +{ + CFileDialog dlg(TRUE, "prt", portals.fn, OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_FILEMUSTEXIST, + "Portal files (*.prt)|*.prt|All Files (*.*)|*.*||", NULL); + + dlg.m_ofn.lpstrTitle = "Locate portal file"; + + if(IDOK == dlg.DoModal()) + { + _fullpath(portals.fn, dlg.GetPathName().GetBuffer(1), _MAX_PATH); + m_fn_ctrl.SetWindowText(portals.fn); + } +} + +#endif // GTK_PLUGIN diff --git a/contrib/prtview/LoadPortalFileDialog.h b/contrib/prtview/LoadPortalFileDialog.h new file mode 100644 index 00000000..c11c01ea --- /dev/null +++ b/contrib/prtview/LoadPortalFileDialog.h @@ -0,0 +1,77 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) +#define AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// LoadPortalFileDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog dialog + +#ifdef GTK_PLUGIN + +int DoLoadPortalFileDialog (); + +#else + +class CLoadPortalFileDialog : public CDialog +{ +// Construction +public: + CLoadPortalFileDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoadPortalFileDialog) + enum { IDD = IDD_LOAD }; + CButton m_3d_ctrl; + CButton m_2d_ctrl; + CStatic m_fn_ctrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoadPortalFileDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoadPortalFileDialog) + virtual qboolean OnInitDialog(); + virtual void OnOK(); + afx_msg void OnLoadOther(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/PrtView.aps b/contrib/prtview/PrtView.aps new file mode 100644 index 0000000000000000000000000000000000000000..d86f060791a3bb3c138bcadf57243ffbdec5f624 GIT binary patch literal 21916 zcmd5^36vv8dH&bC;3M9cm;?w(h;W>+`@pukCCx~jZuK$KSxGHRt(l!=L2tY>yPmL~ zS!QSP5hw9Q-h+^ngq(m0U~?E^bKh4u41@p)1js=EbNIILg@M52`~Rv|Rkt*onD_Et zG*2U`zOVlJ>;CJn>LMa4;k~)3-uRk()$r>~yk}{in)uw@+@|qUcjzy4L7&Kf>i!GX zE?nLpFYTY%cwTRDX=QPBWB-A*)s6L)^Yl<_UJbV2B$Nee1t9Yjr z(q8qed|kGW%UW7KxU#xj8hX**VJ8{(yRA4)!``qL_LD)+5Bob$ z`IQ1EX@$pw)1K$=IlhE$FX@K8bio#bbXE?Qo~Y7V+Qs^0It+tWYj^3g%StwwdcB!p z*ct4Wh(Joi`M6VYcb?MnIx_=rCM-3cQgVPESzkPK;bQ5)+S2my$l{^pU5;CGIok5- z(#k=Oo|PvG)2d(hj8f^Gb4sggt7o-W4y>;oT|2l@np-(~Z1Hf(fAW({%S$U8%S)xK zI*;0tbj_?EfDHYDsQ$*{>eAx+5_Gxn$lB`i>IO#=HBd9>qIydB+}wQBsEwA%w3~Cc zbM4MipN9A!QV-u^O3>nl((WRB=hypp-2G!BZsS=ymtcC9`XFwIs#WO#d|ZQoZIHJ? z>$F0vbciB+9;RhTUZsPy2F_)|DWi>*seyNu&c}bE$KkyVt$vLz#NRUb8*~(5B`f?0 zEh799=(;EzK?qk4jfqO`p zoa-aV7nj;0x&Ts$W{}GPw8}6p#e<^tE`;p{;*Qea1->mWg(S}DGD>L?-=8NXiMBzf zf|uxYxQ00AS=sR~E_v3EOC{6yY>YxJ{1MXRbQoQs7l6&VZPGFPI*imf9@hoqYxsQ( z^{|nvtA|?$WvPR_ykbq*^`P|Yqb!$^HrMmvoPL4mKZo%3QLatP*d>DyE}Y;HaR{p$+w^W*A==%&j#O!bZT$XH6`p_Q+pME<8%cM`SHe@b|B z8$BxDxIM0*?z!x@by@Zm^eEK+PviII=H;l*Jsc>n69hkzPDDz-26S`tO4K7u$l7j+ zOo{EJotVv7`Ud{E&y}F(CHOysUu#J7AkbwA;hr@wTJ1y|<+gQ^{5lt<&8=-kDslNeQht0*<~~BpTZ8;1Xmz%v#l7PsW^6lNS&0ZH zq0FvBPf_K?<6^$V6puNN5zg%xKbhmBA95WWLVoPmcE~%C9*cV2Nw;clAKW#RM+svL zw=w(0d>{O0fPc#v-yP#ajdzTAeCF09D`XmZ$yX7Gd)pv#H$dGzbsM7Ap1XQCOG zBrdnnt0azH-dP)ctRRovwgdIUy?3k8P>n)7g7f%vOzPW=t^d0=`x&}>Vw*jY6UK}4 z@eutP^yM6LIhqlfalC|g8vQK&5uHN!ZQtCyT7^qF@Ym~r^?=`FRIqpHuGhB1@d zz=OcJcGpmroL_!%9r5RR=reDopP>hY(XQ^v7N3p^MTZRuP~3^F<=( zdHBY2O$jWX!F+zMdFqaPdCO*v?_$CQ2)2TanI^x$8_5W-^gZ1e)qBsbKUNae_NNn z(s<~#Vy~~2uft%|3AB=)4s2kik-&Y;K@^F8PMJCK z#A?tlsK8d-2|1oyreDm-^ast@XTYIfQotz0r6=f+R@`Muh0ueBUbjE&gnLu7qM!3x z1Jrh2xsU{!~4n4`n`wQ(biw=~qzRH?)<}6{m z@`-fO%Br|dVC`?4>ksF`UO!Gc!?+VAn0Qa8ZBmG-mm;gX&T@8R?nf++>oi4q9P5?DygNRH%bR z*(m00*y^^EAkT2=&kbWFdlf@SIS|~4ZKum!lO4Cfb#}Br@Ju9NfRrWQM`VLDYEUw(g>ZhPk(2yc5eXTy}r^1 zR>_S;tQ9(v6<}`}$KaYo;b2;Q>o`_Xm`iUP$Epge(A&qcn!>8|j&W>CVKsW^I5w@Y zDSFp9R#(_Gy?Y#kbDHx|r}vCw$hCkCdhY~KmyAd6n*i#fY0~>AfVymatVc)nr0N3Y ztqUih4^9Ae>4fy537{^Xh(4SLTV7Vf5q(6UFo@Hk-wHh$e;inCA1j2zXi+T&hTF$2 z4DC$H#C7QtRxm7nE-9FBH<{1~G)O;ep(~nH)Avhb zs2Bx;R_V(&+UI>aQNB{6uL#1!wOW{Qgld_-J_-)^YI4<~Z%8PQ{yZm!dqqgqrJGGS zSE|@J5L2OV8eq`ZbAVH=(zhg>4RE&PS)dYCqi>I5sE{eTMM8ow@?hOr+-bU15Lpah z8c_vRE7Khk%tPhS1Uq!61V>4)4NEaX(vrYbneGvQcOv6XAC^>BS+H{Hz7ZyUf?J== z2QJnF_vbO>CM$9m)5`+|be8LR7=y*>x|j$b%ro>xW{icB5UTXO5dngmW+-+s@H~`F zlS4fxpug(LtpdG&JO;xC;aQ7iSD^gnI6)gX6(~>J^jtrZ&Z(%l6@cR?raT2#>4Y(O zUy`(A$#(@)<@Sje>egiI>~^&a1>sp zlTElcNE55e)uGKP2JN>os%14)MYiR8dV6z3E%nio4(to8 z^GsuEpjaPkBiVG&Kr4Bi4RA-}Dr%sC{JafhZKHuk{dfl8GO$*=XJp#-;Yr|C6$`;) zkDhD;?L^sN5t4mM4&ZE$V!3oy4&&}tZ5zhqX~U!b6v5Bq z*a*%Nz?fFqK$W{TmU{g?E!`d>)Oy8$ZLA_@_RUK?(%t&u-C&9%bP=|@tQiXFg=2d z1iw!LyL!;=CcP91gnRw4o5Ir~;$Vn`hB-R!Q6RY#8B#lJqqvK5Dl}s#155}-LX~C> zq07d8(qWZE4a}W;44QPX^pZh0Dr5d^86=%g4B}GTAR>`5wQ5Af3UzE)mHT<~s(h(V9VfX_ON_MMn%MmZ+7x#xy0mO)POrs%gP@mk)XU6oG zWd8pgqd`{~hR&Rx2GFasym@q`VGTOHa0dC71qKpn(p5z;mxNDO8yu$%)%KN2OXWDA z7v>pF>~CR6<6Q&A2EW8a(Z46C&T6d+YTxlFk%0oNNO&~;vN#F=nsqFV3f&e z`lBLf_bYbD{Be*lWJ&eqXRi(ciW1(o3fnS>mSXuMJOG=0i0R zOLCZhUtw@vR2UMlRP88dWaQKxdZppOC_-~ZRrh5ebm}f$V^H0iWrB7v1-~kTlmUkk z#7?|Qf1BZ$Jx0R>OuabL(rfhUNfb3gs4Ps;YYasXX(N{?)Ssr;8r-B}Q|ff>Bnmn| z%z0%)JM{)#H;Kfi1!~!5di1(UOyebhR!w@n;mm~aJlF=V%9&4ZFdR6QCvgILqv7b> zqjmaTPc^%GNY@*J$-WxXRXP#9X^esiJ(l51D45T0FqEt>2?xWRqBwM;q3DE!!G2~% zap^424f^omj1y9Ir<2E|9VU$t+*To1*s=I6bU5*c~rcgc{GiX?kyg zg-rl6u6T8NUjgSl^}~?;peU3Ey}y9ZqTYwG*t(AA(FY1}AGq?xA$F5KSb#AL?is;8 zeW(EQs5ct)FsyyJfQLz>^a|-C2J(8C%SZLxEYn8|m|f3Jhdx$-dC*HbIBLLIZo2gG z0*=;|M5B^#R_GH2f((a7LX~bR5KyR@PZKHB=#%5P57&rT&Q5cRJ~fW_{n@b1dv6dh zO`pyP{bAzsAquY*4mxq#A9k^CEPkQL@yqlX!_z)3?VOBUc#HqZpn6Lj?OmAyE*!@H zY+%Utu_tH2E`7nk>^-uu3Vkudy2Ji?t!%WHA(*q^V#xouJVm*VcnpG_JkO0RD^M3R zz`y6oVY`cmGW?`9Xyb5$@`ylah5jSYi{h|_<}5`wY{zhFrM^tMZoNuh&2!^cE1ZF? z!h4TO#~S@-o+3v8x)@Y?$vn0=aiYeDuRxKf=xcd0oDRAxV(@0SnBq;-*T;Ah#MS8= zd73F7ySciUG;YolxxA5fnxx8ZbL$>`Gfzo^rat(jMp30%lfIRw@%e;_lY(3K>Dzg3 zzk@C6SqzwCvy590=sS5bkNlXcWI@!C(-Ek=kZ#Gdbi>KBBDyutLRMkCd1y6ypms5p z+?MB{e202{Jg#2Dq1*FxDV{kO)pp(hTc)bw8ZOlgHx@8Xa0qI^_IF6=T`? z-8@N`N`UPstiP<*faT}Cd8$6G!i^e^#7X&R(0%zRs{7@pQ5UPx`}3@3lI&@Fy*&jN zoYJ^S4;+t;B`myox`=#wFyr=zDoYv(==&McMRS3*+nIrz9P1ubAJ*RcaHvMDD_l$; zn|W@4BMnUq-=Ywv59~pxQw~a$_BwGc^~r$9#U!#V&q8fsh(!-kt~?jB$RqO%%n_W5 z9PHvDvRS1Q^9(iK4LUh5riR@e&Zen3coDe)_7Vypj}6*$=LXnQD8M}bbHfj1 z+W``=xlo|MAf3&3jsP1C1roY#6Gt+YkIN0P;ZPvtn?*21rxyr%As`DADf?iW9$nzD zkhqN@8IG;2s|0oW*^Gu^4zoiu*^4uNWqP~`R^B{>I`j)BR6Galh7ivP@54Qz2nvPW z18~CdR@^U-5m3b%tx#zU)xKA^T%{+Tz*|w+9&O>2O2T`%*dBA}ObMQk_cif+q6)<6 z!z@s5lz>^KU&{iqF&g)IVnc9^o@5eDy(W*ed=yckW!jaY0q;e!H!En(P^CPLq@QLm z$!CVZyKf`nBxaY4Y@cyd`1lP$?R4sO7^77>*PyE8Ww(p58hI9`w>cS@qNV}FJD2Ui zGdfMaLD{VuY8jz7+IZ%*S4-e&IzNMBY%t>3QlNC83Qm?(XgQCHdIDAHUebnhu{J%)3G8pKg;eTU=F>Yh_QhL#HEXh$V@N9@DHp) z7ZEPv z2&hiKRfKRvdN$4Q2K{ys4`7_AT*5#4JCo2Xr*M&8J_*;kg@5#lA}opX2*rwHPxs0q zfm1iRhHvz$NerEHctx)+z^Xm6OZ0^X=`XvC}9{&x+?F=PgV1Jj`wSwQTk z><>q{OD{IzdVoc6g?`Tjt3zH0twAE5*lcbJU zD_TUaE7DN9Y7pi+Lce@{k)R$dLFvhw496_#4Mj>b?L=7(qHn%&0uFx`j@XG7=$zM2 zV2pB%uKA`3_$)>j>EudCjow@&!RsZf7$a$l{;o(Wh?%AvwqzJNb-K~8;6ff?3r(rf zptl&LnaIHrl%q#)HNi1F2+BJeI!$_;0hn)tKE2(5YMwDV1oRFABCB{H0)vn2_+-we z&MISV<8kM?Te(nQUojx=H8(QZkLL4{! zu;Fk)4@c2G`p7txkKLrdHxylhMu1NrorvaT1oW{nmYOND2LmFU7Nn0GlIrqe4GsDD zGjNAKF&XC*(7;`~$>4l)W5|mE!EjpU(*=wt035oiU&jhIf3R@Wek^`}E6sZkpQ3N{}U$XHao{M=~xVf+|?1@J|#3sg< zZ3;}xBvQTAOm<$CzA}M?xz6I$=wEFP+zPxDW3wXZ;qXyYZF+^+$M`p!C!{1DdGkVS zVf?#I(1J2AZHO(5|FCfu;I+7T7e=*+ZH%wloB#`0Ka7)+Yazr=#(&xjOA5}t^iws5 zU_;|;HVe8aw=6O?qjqyc&!?~39D7THcWS?3gChZUiG*}>fs>V-s>O)DY2#>XyvM{G zr6oLA-?9lRw*|LR2uIepZ5H|k9OT>_%uZAYKh}3_5@!Z37b#s)25zidYy$6wN!iJH zLsPzRX5CukL6E6tc(HD?33|f|^7t%If11Ii3Rm+C-?DYgYG&Gkq`YYjP`e6ZPDE}8!mKYb#%1QW5;fGh9_(`>7L_| zRhE7FuFdI$VUQ_VOgo@^ZK_IJ>J|klF3hkQ(tS1ud&9@kFQWU8Ll*t8&-8%J$#lzA zuadE|2Jn( z^b-!f6rXGVq&&rLKiAIplJM))9X>r35A5-cFMP|#e%x`eg#R5YpA%7)K$K??2+Zgf{Sf3A{D%=Wwq`1JB`d%n09EfBUw%a}etwU92_x z|DexB(0nzg&&zOmME)LvPmR?VHxul#v-J(>H~nP6=B5;Z zx|3ma6~cX@-{|N4@>5yn(EdUBXy(-+S;q`OV)Rl5gy%>*MMiPEGDQ_{8YK;8yN0Tk<=p+xr~hNk+@4Jqn~$c3HsWI@5)arBdCmf zG=+w|erwItr3yb%6uENY$Lc#@t*|N81b+&yA&{-DnE}q|tBhxT!-b{J52$ei z`$?Gn4Phyyv)a zv@X^?n|vSU)A8Oq9lpsXe+L}j!FUTqZFL7D-yt`POHZ=751&YG29Fx!Y zd)n)@huEdN|$bF#7AaQ+)q>G_=i literal 0 HcmV?d00001 diff --git a/contrib/prtview/PrtView.def b/contrib/prtview/PrtView.def new file mode 100644 index 00000000..4b693944 --- /dev/null +++ b/contrib/prtview/PrtView.def @@ -0,0 +1,8 @@ +; PrtView.def : Declares the module parameters for the DLL. + +LIBRARY "PrtView" +; DESCRIPTION 'PrtView Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/prtview/PrtView.rc b/contrib/prtview/PrtView.rc new file mode 100644 index 00000000..d876753a --- /dev/null +++ b/contrib/prtview/PrtView.rc @@ -0,0 +1,264 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif\r\n" + "#include ""res\\PrtView.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "Q3Radiant Portal Viewer\0" + VALUE "FileVersion", "1.000\0" + VALUE "InternalName", "PrtView\0" + VALUE "LegalCopyright", "GNU Copyleft (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "PrtView.DLL\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Q3Radiant Portal Viewer\0" + VALUE "ProductVersion", "1.000\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 186, 52 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Portal Viewer" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,16,50,14 + LTEXT "Version 1.000\r\rWritten by Geoffrey DeWan\rgdewan@prairienet.org", + IDC_STATIC,7,7,116,38 +END + +IDD_LOAD DIALOGEX 0, 0, 224, 69 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Load .prt" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,167,48,50,14 + PUSHBUTTON "Change",IDC_LOAD_OTHER,167,22,50,14 + CONTROL "Show 3D",IDC_LOAD_3D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,23,52,13 + CONTROL "Show 2D",IDC_LOAD_2D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,67,23,61,13 + PUSHBUTTON "Cancel",IDCANCEL,113,48,50,14 + LTEXT "",IDC_LOAD_FILE_NAME,7,7,209,12,SS_CENTERIMAGE, + WS_EX_CLIENTEDGE +END + +IDD_CONFIG DIALOG DISCARDABLE 0, 0, 262, 260 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Portal Viewer Configuration" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,205,239,50,14 + GROUPBOX "3D View",IDC_STATIC,7,7,248,149 + SCROLLBAR IDC_SCROLL_3D_WIDTH,15,20,144,10 + LTEXT "-",IDC_3D_WIDTH,167,20,82,10,SS_CENTERIMAGE + PUSHBUTTON "Color",IDC_COLOR_3D,15,41,50,14 + CONTROL "Anti-Alias (May not work on some video cards)", + IDC_ANTI_ALIAS_3D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 81,38,174,17 + PUSHBUTTON "Depth Color",IDC_COLOR_FOG,15,60,50,14 + CONTROL "Depth Cue",IDC_FOG,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,81,61,57,13 + CONTROL "Lines",IDC_LINES,"Button",BS_AUTO3STATE | WS_TABSTOP, + 140,61,49,13 + CONTROL "Polygons",IDC_POLY,"Button",BS_AUTO3STATE | WS_TABSTOP, + 206,61,49,13 + COMBOBOX IDC_ZBUFFER,15,85,231,109,CBS_DROPDOWNLIST | WS_TABSTOP + SCROLLBAR IDC_SCROLL_3D_TRANS,15,105,128,10 + LTEXT "-",IDC_3D_TRANS,152,105,95,10,SS_CENTERIMAGE + CONTROL "Show",IDC_CONFIG_3D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,137,52,13 + GROUPBOX "2D View",IDC_STATIC,7,158,248,72 + SCROLLBAR IDC_SCROLL_2D_WIDTH,15,172,144,10 + LTEXT "-",IDC_2D_WIDTH,166,172,82,10,SS_CENTERIMAGE + PUSHBUTTON "Color",IDC_COLOR_2D,15,190,50,14 + CONTROL "Anti-Alias (May not work on some video cards)", + IDC_ANTI_ALIAS_2D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 81,193,174,13 + CONTROL "Show",IDC_CONFIG_2D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,212,61,13 + SCROLLBAR IDC_SCROLL_CUBIC,15,122,128,10 + LTEXT "-",IDC_CUBIC,152,122,95,10,SS_CENTERIMAGE + CONTROL "Portal cubic clipper",IDC_CLIP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,147,137,52,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END + + IDD_LOAD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 217 + TOPMARGIN, 7 + BOTTOMMARGIN, 62 + END + + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 255 + VERTGUIDE, 15 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + HORZGUIDE, 21 + HORZGUIDE, 31 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_CONFIG DLGINIT +BEGIN + IDC_ZBUFFER, 0x403, 62, 0 +0x2d5a, 0x7542, 0x6666, 0x7265, 0x5420, 0x7365, 0x2074, 0x6e61, 0x2064, +0x7257, 0x7469, 0x2065, 0x7228, 0x6365, 0x6d6f, 0x656d, 0x646e, 0x6620, +0x726f, 0x7320, 0x6c6f, 0x6469, 0x2020, 0x726f, 0x6e20, 0x206f, 0x6f70, +0x796c, 0x6f67, 0x736e, 0x0029, + IDC_ZBUFFER, 0x403, 56, 0 +0x2d5a, 0x7542, 0x6666, 0x7265, 0x5420, 0x7365, 0x2074, 0x6e4f, 0x796c, +0x2820, 0x6572, 0x6f63, 0x6d6d, 0x6e65, 0x2064, 0x6f66, 0x2072, 0x7274, +0x6e61, 0x7073, 0x7261, 0x6e65, 0x2074, 0x6f70, 0x796c, 0x6f67, 0x736e, +0x0029, + IDC_ZBUFFER, 0x403, 13, 0 +0x2d5a, 0x7542, 0x6666, 0x7265, 0x4f20, 0x6666, "\000" + 0 +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif +#include "res\PrtView.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/prtview/PrtView.txt b/contrib/prtview/PrtView.txt new file mode 100644 index 00000000..fba9508d --- /dev/null +++ b/contrib/prtview/PrtView.txt @@ -0,0 +1,12 @@ +Put PrtView.dll in the Q3Radiant plugins directory. + +This program is pretty self explanitary, but point needs to +be mentioned. In the configuration menu for 3D view options, +the lines and polygons flags are tri-state. In the third state, +the lines or polygons will only be drawn if the have the +hint flag set. Older version of q3map will not set this flag +and the hint shader may have to be modified to set it. As of +this writing, I do not know all the details. + +Geoffrey DeWan +gdewan@prairienet.org \ No newline at end of file diff --git a/contrib/prtview/PrtView.vcproj b/contrib/prtview/PrtView.vcproj new file mode 100644 index 00000000..bfb7567d --- /dev/null +++ b/contrib/prtview/PrtView.vcproj @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/prtview/gtkdlgs.cpp b/contrib/prtview/gtkdlgs.cpp new file mode 100644 index 00000000..d19dd39b --- /dev/null +++ b/contrib/prtview/gtkdlgs.cpp @@ -0,0 +1,732 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// +// PrtView dialogs done with GTK+ +// + +#include +#include "stdafx.h" + +// ============================================================================= +// Static functions + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + char **filename; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); + + *loop = 0; + if ((int)data == IDOK) + *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); +} + +static void change_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget* file_sel; + char* filename = NULL; + int loop = 1; + + file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + if (filename != NULL) + { + strcpy (portals.fn, filename); + gtk_entry_set_text (GTK_ENTRY (data), filename); + g_free (filename); + } +} + +// ============================================================================= +// LoadPortalFile dialog + +int DoLoadPortalFileDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + check3d = gtk_check_button_new_with_label ("Show 3D"); + gtk_widget_show (check3d); + gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); + + check2d = gtk_check_button_new_with_label ("Show 2D"); + gtk_widget_show (check2d); + gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + char *fn = g_IBSPTable.m_pfnGetMapName(); + strcpy (portals.fn, fn); + fn = strrchr (portals.fn, '.'); + if (fn != NULL) + { + *fn = '\0'; + strcat (portals.fn, ".prt"); + } + + gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + portals.Purge(); + + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)); + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// About dialog + +void DoAboutDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *button, *label; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); + + label = gtk_label_new ("Version 1.000\n\n" + "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" + "Written by Geoffrey DeWan\ngdewan@prairienet.org"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Config dialog + +static int DoColor (COLORREF *c) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = ((double)GetRValue (*c)) / 255.0; + clr[1] = ((double)GetGValue (*c)) / 255.0; + clr[2] = ((double)GetBValue (*c)) / 255.0; + + dlg = gtk_color_selection_dialog_new ("Choose Color"); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + gtk_widget_show(dlg); + gtk_grab_add(dlg); + + while (loop) + gtk_main_iteration (); + + gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); + } + + return ret; +} + +static void Set2DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DTransText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void SetClipText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void OnScroll2d (GtkAdjustment *adj, gpointer data) +{ + portals.width_2d = adj->value; + Set2DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnScroll3d (GtkAdjustment *adj, gpointer data) +{ + portals.width_3d = adj->value; + Set3DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollTrans (GtkAdjustment *adj, gpointer data) +{ + portals.trans_3d = adj->value; + Set3DTransText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollClip (GtkAdjustment *adj, gpointer data) +{ + portals.clip_range = adj->value; + SetClipText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnAntiAlias2d (GtkWidget *widget, gpointer data) +{ + portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnConfig2d (GtkWidget *widget, gpointer data) +{ + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnColor2d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_2d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +static void OnConfig3d (GtkWidget *widget, gpointer data) +{ + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +static void OnAntiAlias3d (GtkWidget *widget, gpointer data) +{ + portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnColor3d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_3d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnColorFog (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_fog) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnFog (GtkWidget *widget, gpointer data) +{ + portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) +{ + portals.zbuffer = GPOINTER_TO_INT (data); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnPoly (GtkWidget *widget, gpointer data) +{ + portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnLines (GtkWidget *widget, gpointer data) +{ + portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnClip (GtkWidget *widget, gpointer data) +{ + portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void DoConfigDialog () +{ + GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; + GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; + GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; + GtkWidget *transslider, *translabel, *clipslider, *cliplabel; + GtkWidget *show2check, *show3check, *portalcheck; + int loop = 1, ret = IDCANCEL; + GtkObject *adj; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + frame = gtk_frame_new ("3D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); + + adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); + lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw3slider); + gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); + + lw3label = gtk_label_new (""); + gtk_widget_show (lw3label); + gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); + + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); + + button = gtk_button_new_with_label ("Depth Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); + + aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa3check); + gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); + + depthcheck = gtk_check_button_new_with_label ("Depth Cue"); + gtk_widget_show (depthcheck); + gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); + + linescheck = gtk_check_button_new_with_label ("Lines"); + gtk_widget_show (linescheck); + gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); + + polyscheck = gtk_check_button_new_with_label ("Polygons"); + gtk_widget_show (polyscheck); + gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); + + zlist = gtk_option_menu_new (); + gtk_widget_show (zlist); + gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); + + menu = gtk_menu_new (); + gtk_widget_show (menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Off"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); + gtk_menu_append (GTK_MENU (menu), item); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); + transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (transslider); + gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); + + translabel = gtk_label_new (""); + gtk_widget_show (translabel); + gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); + + adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); + clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (clipslider); + gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); + + cliplabel = gtk_label_new (""); + gtk_widget_show (cliplabel); + gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show3check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show3check); + gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); + + portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); + gtk_widget_show (portalcheck); + gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); + + frame = gtk_frame_new ("2D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); + lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw2slider); + gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); + + lw2label = gtk_label_new (""); + gtk_widget_show (lw2label); + gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); + gtk_widget_set_usize (button, 60, -2); + + aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa2check); + gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show2check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show2check); + gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + // initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); + Set2DText (lw2label); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); + gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); + + Set3DText (lw3label); + Set3DTransText (translabel); + SetClipText (cliplabel); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} diff --git a/contrib/prtview/gtkdlgs.h b/contrib/prtview/gtkdlgs.h new file mode 100644 index 00000000..afa3ea74 --- /dev/null +++ b/contrib/prtview/gtkdlgs.h @@ -0,0 +1,27 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _GTKDLGS_H_ +#define _GTKDLGS_H_ + +int DoLoadPortalFileDialog (); +void DoAboutDlg (); +void DoConfigDialog (); + +#endif // _GTKDLGS_H_ diff --git a/contrib/prtview/portals.cpp b/contrib/prtview/portals.cpp new file mode 100644 index 00000000..378bb85d --- /dev/null +++ b/contrib/prtview/portals.cpp @@ -0,0 +1,802 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "stdafx.h" +#include +#include +#ifndef __APPLE__ +#include +#endif +#include + +#define LINE_BUF 1000 + +CPortals portals; +CPortalsRender render; + +int compare( const void *arg1, const void *arg2 ) +{ + + if(portals.portal[*((int *)arg1)].dist > portals.portal[*((int *)arg2)].dist) + return -1; + else if(portals.portal[*((int *)arg1)].dist < portals.portal[*((int *)arg2)].dist) + return 1; + + return 0; +} + + +CBspPortal::CBspPortal() +{ + memset(this, 0, sizeof(CBspPortal)); +} + +CBspPortal::~CBspPortal() +{ + delete[] point; + delete[] inner_point; +} + +qboolean CBspPortal::Build(char *def) +{ + char *c = def; + unsigned int n; + int dummy1, dummy2; + int res_cnt, i; + + if(portals.hint_flags) + { + res_cnt = sscanf(def, "%u %d %d %d", &point_count, &dummy1, &dummy2, (int *)&hint); + } + else + { + sscanf(def, "%u", &point_count); + hint = FALSE; + } + + if(point_count < 3 || (portals.hint_flags && res_cnt < 4)) + return FALSE; + + point = new CBspPoint[point_count]; + inner_point = new CBspPoint[point_count]; + + for(n = 0; n < point_count; n++) + { + for(; *c != 0 && *c != '('; c++); + + if(*c == 0) + return FALSE; + + c++; + + sscanf(c, "%f %f %f", point[n].p, point[n].p+1, point[n].p+2); + + center.p[0] += point[n].p[0]; + center.p[1] += point[n].p[1]; + center.p[2] += point[n].p[2]; + + if(n == 0) + { + for(i = 0; i < 3; i++) + { + min[i] = point[n].p[i]; + max[i] = point[n].p[i]; + } + } + else + { + for(i = 0; i < 3; i++) + { + if(min[i] > point[n].p[i]) + min[i] = point[n].p[i]; + if(max[i] < point[n].p[i]) + max[i] = point[n].p[i]; + } + } + } + + center.p[0] /= (float)point_count; + center.p[1] /= (float)point_count; + center.p[2] /= (float)point_count; + + for(n = 0; n < point_count; n++) + { + inner_point[n].p[0] = (0.01f * center.p[0]) + (0.99f * point[n].p[0]); + inner_point[n].p[1] = (0.01f * center.p[1]) + (0.99f * point[n].p[1]); + inner_point[n].p[2] = (0.01f * center.p[2]) + (0.99f * point[n].p[2]); + } + + fp_color_random[0] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[1] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[2] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[3] = 1.0f; + + return TRUE; +} + +CPortals::CPortals() +{ + memset(this, 0, sizeof(CPortals)); +} + +CPortals::~CPortals() +{ + Purge(); +} + +void CPortals::Purge() +{ + delete[] portal; + delete[] portal_sort; + portal = NULL; + portal_sort = NULL; + portal_count = 0; + + /* + delete[] node; + node = NULL; + node_count = 0; + */ +} + +void CPortals::Load() +{ + char buf[LINE_BUF+1]; + + memset(buf, 0, LINE_BUF + 1); + + Purge(); + + Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); + + FILE *in; + + in = fopen(fn, "rt"); + + if(in == NULL) + { + Sys_Printf(" ERROR - could not open file.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + if(strncmp("PRT1", buf, 4) != 0) + { + fclose(in); + + Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &node_count); +/* + if(node_count > 0xFFFF) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); + + return; + } + */ + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &portal_count); + + if(portal_count > 0xFFFF) + { + fclose(in); + + portal_count = 0; + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of portals, aborting.\n"); + + return; + } + + if(portal_count < 0) + { + fclose(in); + + portal_count = 0; + node_count = 0; + + Sys_Printf(" ERROR - number of portals equals 0, aborting.\n"); + + return; + } + +// node = new CBspNode[node_count]; + portal = new CBspPortal[portal_count]; + portal_sort = new int[portal_count]; + + unsigned int n; + qboolean first = TRUE; + unsigned test_vals_1, test_vals_2; + + hint_flags = FALSE; + + for(n = 0; n < portal_count; ) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, portal_count); + + return; + } + + if(!portal[n].Build(buf)) + { + if(first && sscanf(buf, "%d %d", &test_vals_1, &test_vals_2) == 1) // skip additional counts of later data, not needed + { + // We can count on hint flags being in the file + hint_flags = TRUE; + continue; + } + + first = FALSE; + + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, portal_count); + + return; + } + + n++; + } + + fclose(in); + + Sys_Printf(" %u portals read in.\n", node_count, portal_count); +} + +void CPortals::FixColors() +{ + fp_color_2d[0] = (float)GetRValue(color_2d) / 255.0f; + fp_color_2d[1] = (float)GetGValue(color_2d) / 255.0f; + fp_color_2d[2] = (float)GetBValue(color_2d) / 255.0f; + fp_color_2d[3] = 1.0f; + + fp_color_3d[0] = (float)GetRValue(color_3d) / 255.0f; + fp_color_3d[1] = (float)GetGValue(color_3d) / 255.0f; + fp_color_3d[2] = (float)GetBValue(color_3d) / 255.0f; + fp_color_3d[3] = 1.0f; + + fp_color_fog[0] = 0.0f;//(float)GetRValue(color_fog) / 255.0f; + fp_color_fog[1] = 0.0f;//(float)GetGValue(color_fog) / 255.0f; + fp_color_fog[2] = 0.0f;//(float)GetBValue(color_fog) / 255.0f; + fp_color_fog[3] = 1.0f; +} + +CPortalsRender::CPortalsRender() +{ + refCount = 1; +} + +CPortalsRender::~CPortalsRender() +{ +} + +void CPortalsRender::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); +} + +void CPortalsRender::Draw2D( VIEWTYPE vt ) +{ + if(!portals.show_2d || portals.portal_count < 1) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + if(portals.aa_2d) + { + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + else + { + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(portals.width_2d * 0.5f); + + g_QglTable.m_pfn_qglColor4fv(portals.fp_color_2d); + + unsigned int n, p; + + for(n = 0; n < portals.portal_count; n++) + { + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +/* + * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in + * Input: m - the 4x4 matrix + * in - the 4x1 vector + * Output: out - the resulting 4x1 vector. + */ +static void transform_point( GLdouble out[4], const GLdouble m[16], + const GLdouble in[4] ) +{ +#define M(row,col) m[col*4+row] + out[0] = M(0,0) * in[0] + M(0,1) * in[1] + M(0,2) * in[2] + M(0,3) * in[3]; + out[1] = M(1,0) * in[0] + M(1,1) * in[1] + M(1,2) * in[2] + M(1,3) * in[3]; + out[2] = M(2,0) * in[0] + M(2,1) * in[1] + M(2,2) * in[2] + M(2,3) * in[3]; + out[3] = M(3,0) * in[0] + M(3,1) * in[1] + M(3,2) * in[2] + M(3,3) * in[3]; +#undef M +} + +#include + + +/* + * Perform a 4x4 matrix multiplication (product = a x b). + * Input: a, b - matrices to multiply + * Output: product - product of a and b + */ +static void matmul( GLdouble *product, const GLdouble *a, const GLdouble *b ) +{ + /* This matmul was contributed by Thomas Malik */ + GLdouble temp[16]; + GLint i; + +#define A(row,col) a[(col<<2)+row] +#define B(row,col) b[(col<<2)+row] +#define T(row,col) temp[(col<<2)+row] + + /* i-te Zeile */ + for (i = 0; i < 4; i++) + { + T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0); + T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1); + T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2); + T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3); + } + +#undef A +#undef B +#undef T + memcpy ( product, temp, 16*sizeof(GLdouble) ); +} + + + +/* + * Compute inverse of 4x4 transformation matrix. + * Code contributed by Jacques Leroy jle@star.be + * Return GL_TRUE for success, GL_FALSE for failure (singular matrix) + */ +static GLboolean invert_matrix( const GLdouble *m, GLdouble *out ) +{ +/* NB. OpenGL Matrices are COLUMN major. */ +#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } +#define MAT(m,r,c) (m)[(c)*4+(r)] + + GLdouble wtmp[4][8]; + GLdouble m0, m1, m2, m3, s; + GLdouble *r0, *r1, *r2, *r3; + + r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; + + r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1), + r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3), + r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, + + r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1), + r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3), + r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, + + r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1), + r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3), + r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, + + r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1), + r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3), + r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; + + /* choose pivot - or die */ + if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2); + if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1); + if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0); + if (0.0 == r0[0]) return GL_FALSE; + + /* eliminate first variable */ + m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; + s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; + s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; + s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r0[5]; + if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r0[6]; + if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r0[7]; + if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2); + if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1); + if (0.0 == r1[1]) return GL_FALSE; + + /* eliminate second variable */ + m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1]; + r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; + s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2); + if (0.0 == r2[2]) return GL_FALSE; + + /* eliminate third variable */ + m3 = r3[2]/r2[2]; + r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], + r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], + r3[7] -= m3 * r2[7]; + + /* last check */ + if (0.0 == r3[3]) return GL_FALSE; + + s = 1.0/r3[3]; /* now back substitute row 3 */ + r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; + + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0/r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), + r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, + r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, + r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; + + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0/r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, + r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; + + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0/r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); + + MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5], + MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7], + MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5], + MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7], + MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5], + MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7], + MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5], + MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7]; + + return GL_TRUE; + +#undef MAT +#undef SWAP_ROWS +} + +GLint UnProject(GLdouble winx,GLdouble winy,GLdouble winz, + const GLdouble model[16],const GLdouble proj[16], + const GLint viewport[4], + GLdouble *objx,GLdouble *objy,GLdouble *objz) +{ + /* matrice de transformation */ + GLdouble m[16], A[16]; + GLdouble in[4],out[4]; + + /* transformation coordonnees normalisees entre -1 et 1 */ + in[0]=(winx-viewport[0])*2/viewport[2] - 1.0; + in[1]=(winy-viewport[1])*2/viewport[3] - 1.0; + in[2]=2*winz - 1.0; + in[3]=1.0; + + /* calcul transformation inverse */ + matmul(A,proj,model); + invert_matrix(A,m); + + /* d'ou les coordonnees objets */ + transform_point(out,m,in); + if (out[3]==0.0) + return GL_FALSE; + *objx=out[0]/out[3]; + *objy=out[1]/out[3]; + *objz=out[2]/out[3]; + return GL_TRUE; +} + +void CPortalsRender::Draw3D() +{ + if(!portals.show_3d || portals.portal_count < 1) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + double cam[3]; + double proj_m[16]; + double model_m[16]; + float min_check[3]; + float max_check[3]; + float trans = (100.0f - portals.trans_3d) / 100.0f; + int view[4]; + + g_QglTable.m_pfn_qglGetDoublev(GL_PROJECTION_MATRIX, proj_m); + g_QglTable.m_pfn_qglGetDoublev(GL_MODELVIEW_MATRIX, model_m); + g_QglTable.m_pfn_qglGetIntegerv(GL_VIEWPORT, view); + + UnProject(0.5 * (double)view[2], 0.5 * (double)view[3], 0.0, model_m, proj_m, view, cam, cam+1, cam+2); + + min_check[0] = (float)cam[0] + (portals.clip_range * 64.0f); + min_check[1] = (float)cam[1] + (portals.clip_range * 64.0f); + min_check[2] = (float)cam[2] + (portals.clip_range * 64.0f); + max_check[0] = (float)cam[0] - (portals.clip_range * 64.0f); + max_check[1] = (float)cam[1] - (portals.clip_range * 64.0f); + max_check[2] = (float)cam[2] - (portals.clip_range * 64.0f); + + g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); + + g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglEnable(GL_POLYGON_SMOOTH); + + if(portals.aa_3d) + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + else + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + if(portals.fog) + { + g_QglTable.m_pfn_qglEnable(GL_FOG); + + g_QglTable.m_pfn_qglFogi(GL_FOG_MODE, GL_EXP); + g_QglTable.m_pfn_qglFogf(GL_FOG_DENSITY, 0.001f); + g_QglTable.m_pfn_qglFogf(GL_FOG_START, 10.0f); + g_QglTable.m_pfn_qglFogf(GL_FOG_END, 10000.0f); + g_QglTable.m_pfn_qglFogi(GL_FOG_INDEX, 0); + g_QglTable.m_pfn_qglFogfv(GL_FOG_COLOR, portals.fp_color_fog); + } + else + { + g_QglTable.m_pfn_qglDisable(GL_FOG); + } + + switch(portals.zbuffer) + { + case 1: + g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); + g_QglTable.m_pfn_qglDepthMask(GL_FALSE); + break; + case 2: + g_QglTable.m_pfn_qglDisable(GL_DEPTH_TEST); + break; + default: + g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); + g_QglTable.m_pfn_qglDepthMask(GL_TRUE); + } + + g_QglTable.m_pfn_qglLineWidth(portals.width_3d * 0.5f); + + unsigned int n, p; + + if(portals.polygons) + { + if(portals.zbuffer != 0) + { + float d; + + for(n = 0; n < portals.portal_count; n++) + { + d = (float)cam[0] - portals.portal[n].center.p[0]; + portals.portal[n].dist = d * d; + + d = (float)cam[1] - portals.portal[n].center.p[1]; + portals.portal[n].dist += d * d; + + d = (float)cam[2] - portals.portal[n].center.p[2]; + portals.portal[n].dist += d * d; + + portals.portal_sort[n] = n; + } + + qsort(portals.portal_sort, portals.portal_count, 4, compare); + + for(n = 0; n < portals.portal_count; n++) + { + if(portals.polygons == 2 && !portals.portal[portals.portal_sort[n]].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[portals.portal_sort[n]].min[0]) + continue; + else if(min_check[1] < portals.portal[portals.portal_sort[n]].min[1]) + continue; + else if(min_check[2] < portals.portal[portals.portal_sort[n]].min[2]) + continue; + else if(max_check[0] > portals.portal[portals.portal_sort[n]].max[0]) + continue; + else if(max_check[1] > portals.portal[portals.portal_sort[n]].max[1]) + continue; + else if(max_check[2] > portals.portal[portals.portal_sort[n]].max[2]) + continue; + } + + g_QglTable.m_pfn_qglColor4f(portals.portal[portals.portal_sort[n]].fp_color_random[0], portals.portal[portals.portal_sort[n]].fp_color_random[1], + portals.portal[portals.portal_sort[n]].fp_color_random[2], trans); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + + for(p = 0; p < portals.portal[portals.portal_sort[n]].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[portals.portal_sort[n]].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + else + { + for(n = 0; n < portals.portal_count; n++) + { + if(portals.polygons == 2 && !portals.portal[n].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[n].min[0]) + continue; + else if(min_check[1] < portals.portal[n].min[1]) + continue; + else if(min_check[2] < portals.portal[n].min[2]) + continue; + else if(max_check[0] > portals.portal[n].max[0]) + continue; + else if(max_check[1] > portals.portal[n].max[1]) + continue; + else if(max_check[2] > portals.portal[n].max[2]) + continue; + } + + g_QglTable.m_pfn_qglColor4f(portals.portal[n].fp_color_random[0], portals.portal[n].fp_color_random[1], + portals.portal[n].fp_color_random[2], trans); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + } + + if(portals.lines) + { + g_QglTable.m_pfn_qglColor4fv(portals.fp_color_3d); + + for(n = 0; n < portals.portal_count; n++) + { + if(portals.lines == 2 && !portals.portal[n].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[n].min[0]) + continue; + else if(min_check[1] < portals.portal[n].min[1]) + continue; + else if(min_check[2] < portals.portal[n].min[2]) + continue; + else if(max_check[0] > portals.portal[n].max[0]) + continue; + else if(max_check[1] > portals.portal[n].max[1]) + continue; + else if(max_check[2] > portals.portal[n].max[2]) + continue; + } + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].inner_point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + diff --git a/contrib/prtview/portals.h b/contrib/prtview/portals.h new file mode 100644 index 00000000..33bac1ec --- /dev/null +++ b/contrib/prtview/portals.h @@ -0,0 +1,125 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _PORTALS_H_ +#define _PORTALS_H_ + +class CBspPoint { +public: + float p[3]; +}; + +class CBspPortal { +public: + CBspPortal(); + ~CBspPortal(); + +protected: + +public: + CBspPoint center; + unsigned point_count; + CBspPoint *point; + CBspPoint *inner_point; + float fp_color_random[4]; + float min[3]; + float max[3]; + float dist; + qboolean hint; + + qboolean Build(char *def); +}; + +class CPortals { +public: + + CPortals(); + ~CPortals(); + +protected: + + +public: + + void Load(); // use filename in fn + void Purge(); + + void FixColors(); + + char fn[_MAX_PATH]; + + int zbuffer; + int polygons; + int lines; + qboolean show_3d; + qboolean aa_3d; + qboolean fog; + COLORREF color_3d; + float width_3d; // in 8'ths + float fp_color_3d[4]; + COLORREF color_fog; + float fp_color_fog[4]; + float trans_3d; + float clip_range; + qboolean clip; + + qboolean show_2d; + qboolean aa_2d; + COLORREF color_2d; + float width_2d; // in 8'ths + float fp_color_2d[4]; + + CBspPortal *portal; + int *portal_sort; + qboolean hint_flags; +// CBspNode *node; + + unsigned int node_count; + unsigned int portal_count; +}; + +class CPortalsRender : public IGL2DWindow, public IGL3DWindow { +public: + + CPortalsRender(); + virtual ~CPortalsRender(); + +protected: + + int refCount; +#ifdef _WIN32 + CRITICAL_SECTION protect; +#endif + +public: + + // IGL2DWindow IGL3DWindow interface + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); + void Draw3D(); + void Register(); +}; + +// void Sys_Printf (char *text, ...); + +extern CPortals portals; +extern CPortalsRender render; + +#endif // _PORTALS_H_ diff --git a/contrib/prtview/prtview.cpp b/contrib/prtview/prtview.cpp new file mode 100644 index 00000000..3e1ba2db --- /dev/null +++ b/contrib/prtview/prtview.cpp @@ -0,0 +1,543 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PrtView.cpp : Defines the initialization routines for the DLL. +// + +#include "stdafx.h" +#include +#include + +#define Q3R_CMD_SPLITTER "-" +#define Q3R_CMD_ABOUT "About Portal Viewer" +#define Q3R_CMD_LOAD "Load .prt file" +#define Q3R_CMD_RELEASE "Unload .prt file" +#define Q3R_CMD_SHOW_3D "Toggle portals (3D)" +#define Q3R_CMD_SHOW_2D "Toggle portals (2D)" +#define Q3R_CMD_OPTIONS "Configure Portal Viewer" + +static char INIfn[NAME_MAX]; + +///////////////////////////////////////////////////////////////////////////// +// CPrtViewApp construction + +#define RENDER_2D "Render2D" +#define WIDTH_2D "Width2D" +#define AA_2D "AntiAlias2D" +#define COLOR_2D "Color2D" + +#define RENDER_3D "Render3D" +#define WIDTH_3D "Width3D" +#define AA_3D "AntiAlias3D" +#define COLOR_3D "Color3D" +#define COLOR_FOG "ColorFog" +#define FOG "Fog" +#define ZBUFFER "ZBuffer" +#define POLYGON "Polygons" +#define LINE "Lines" +#define TRANS_3D "Transparency" +#define CLIP_RANGE "ClipRange" +#define CLIP "Clip" + +void InitInstance () +{ +#ifdef _WIN32 + char fn[_MAX_PATH]; + char fn_drive[_MAX_DRIVE]; + char fn_dir[_MAX_DIR]; + char fn_name[_MAX_FNAME]; + char fn_ext[_MAX_EXT]; + + GetModuleFileName(GetModuleHandle("PrtView.dll"), fn, _MAX_PATH); + + _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); + + strcpy(INIfn, fn_drive); + strcat(INIfn, fn_dir); + strcat(INIfn, fn_name); + strcat(INIfn, ".ini"); +#else // if def __linux__ + strcpy (INIfn, g_get_home_dir ()); + strcat (INIfn, "/.radiant/"); + strcat (INIfn, RADIANT_VERSION); + strcat (INIfn, "/prtview.ini"); +#endif + + portals.show_2d = INIGetInt(RENDER_2D, FALSE) ? true : false; + portals.aa_2d = INIGetInt(AA_2D, FALSE) ? true : false; + portals.width_2d = (float)INIGetInt(WIDTH_2D, 10); + portals.color_2d = (COLORREF)INIGetInt(COLOR_2D, RGB(0, 0, 255)) & 0xFFFFFF; + + if (portals.width_2d > 40.0f) + portals.width_2d = 40.0f; + else if (portals.width_2d < 2.0f) + portals.width_2d = 2.0f; + + portals.show_3d = INIGetInt(RENDER_3D, TRUE) ? true : false; + + portals.zbuffer = INIGetInt(ZBUFFER, 1); + portals.fog = INIGetInt(FOG, FALSE) ? true : false; + portals.polygons = INIGetInt(POLYGON, TRUE); + portals.lines = INIGetInt(LINE, TRUE); + portals.aa_3d = INIGetInt(AA_3D, FALSE) ? true : false; + portals.width_3d = (float)INIGetInt(WIDTH_3D, 4); + portals.color_3d = (COLORREF)INIGetInt(COLOR_3D, RGB(255, 255, 0)) & 0xFFFFFF; + portals.color_fog = (COLORREF)INIGetInt(COLOR_FOG, RGB(127, 127, 127)) & 0xFFFFFF; + portals.trans_3d = (float)INIGetInt(TRANS_3D, 50); + portals.clip = INIGetInt(CLIP, FALSE) ? true : false; + portals.clip_range = (float)INIGetInt(CLIP_RANGE, 16); + + if (portals.clip_range < 1) + portals.clip_range = 1; + else if (portals.clip_range > 128) + portals.clip_range = 128; + + if (portals.zbuffer < 0) + portals.zbuffer = 0; + else if (portals.zbuffer > 2) + portals.zbuffer = 0; + + if (portals.width_3d > 40.0f) + portals.width_3d = 40.0f; + else if (portals.width_3d < 2.0f) + portals.width_3d = 2.0f; + + if (portals.trans_3d > 100.0f) + portals.trans_3d = 100.0f; + else if (portals.trans_3d < 0.0f) + portals.trans_3d = 0.0f; + + SaveConfig(); + + portals.FixColors(); +} + +void SaveConfig () +{ + INISetInt(RENDER_2D, portals.show_2d, "Draw in 2D windows"); + INISetInt(WIDTH_2D, (int)portals.width_2d, "Width of lines in 2D windows (in units of 1/2)"); + INISetInt(COLOR_2D, (int)portals.color_2d, "Color of lines in 2D windows"); + INISetInt(AA_2D, portals.aa_2d, "Draw lines in 2D window anti-aliased"); + + INISetInt(ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window"); + INISetInt(FOG, portals.fog, "Use depth cueing in 3D window"); + INISetInt(POLYGON, portals.polygons, "Render using polygons polygons in 3D window"); + INISetInt(LINE, portals.polygons, "Render using lines in 3D window"); + INISetInt(RENDER_3D, portals.show_3d, "Draw in 3D windows"); + INISetInt(WIDTH_3D, (int)portals.width_3d, "Width of lines in 3D window (in units of 1/2)"); + INISetInt(COLOR_3D, (int)portals.color_3d, "Color of lines/polygons in 3D window"); + INISetInt(COLOR_FOG, (int)portals.color_fog, "Color of distant lines/polygons in 3D window"); + INISetInt(AA_3D, portals.aa_3d, "Draw lines in 3D window anti-aliased"); + INISetInt(TRANS_3D, (int)portals.trans_3d, "Transparency in 3d view (0 = solid, 100 = invisible)"); + INISetInt(CLIP, portals.clip, "Cubic clipper active for portal viewer"); + INISetInt(CLIP_RANGE, (int)portals.clip_range, "Portal viewer cubic clip distance (in units of 64)"); +} + +// Radiant function table +// use to access what Radiant provides +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; + +#define CONFIG_SECTION "Configuration" + +#if defined(__linux__) || defined(__APPLE__) + +static bool read_var (const char *filename, const char *section, const char *key, char *value) +{ + char line[1024], *ptr; + FILE *rc; + + rc = fopen (filename, "rt"); + + if (rc == NULL) + return false; + + while (fgets (line, 1024, rc) != 0) + { + // First we find the section + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + while (fgets (line, 1024, rc) != 0) + { + ptr = strchr (line, '='); + + if (ptr == NULL) + { + // reached the end of the section + fclose (rc); + return false; + } + *ptr = '\0'; + + if (strcmp (line, key) == 0) + { + strcpy (value, ptr+1); + fclose (rc); + + while (value[strlen (value)-1] == 10 || + value[strlen (value)-1] == 13 || + value[strlen (value)-1] == 32) + value[strlen (value)-1] = 0; + return true; + } + } + } + } + + fclose (rc); + return false; +} + +static bool save_var (const char *filename, const char *section, const char *key, const char *value) +{ + char line[1024], *ptr; + FILE *old_rc = NULL, *rc; + bool found; + + rc = fopen (filename, "rb"); + + if (rc != NULL) + { + guint32 len; + void *buf; + + char *tmpname = g_strdup_printf ("%s.tmp", filename); + old_rc = fopen (tmpname, "w+b"); + g_free (tmpname); + + fseek (rc, 0, SEEK_END); + len = ftell (rc); + rewind (rc); + buf = g_malloc (len); + fread (buf, len, 1, rc); + fwrite (buf, len, 1, old_rc); + g_free (buf); + fclose (rc); + rewind (old_rc); + } + + rc = fopen (filename, "wb"); + + if (rc == NULL) + return false; + + // First we need to find the section + found = false; + if (old_rc != NULL) + while (fgets (line, 1024, old_rc) != NULL) + { + fputs (line, rc); + + if (line[0] == '[') + { + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + found = true; + break; + } + } + } + + if (!found) + { + fputs ("\n", rc); + fprintf (rc, "[%s]\n", section); + } + + fprintf (rc, "%s=%s\n", key, value); + + if (old_rc != NULL) + { + while (fgets (line, 1024, old_rc) != NULL) + { + ptr = strchr (line, '='); + + if (ptr != NULL) + { + *ptr = '\0'; + + if (strcmp (line, key) == 0) + break; + + *ptr = '='; + fputs (line, rc); + } + else + { + fputs (line, rc); + break; + } + } + + while (fgets (line, 1024, old_rc) != NULL) + fputs (line, rc); + + fclose (old_rc); + + char *tmpname = g_strdup_printf ("%s.tmp", filename); + remove (tmpname); + g_free (tmpname); + } + + fclose (rc); + + return true; +} + +#endif + +int INIGetInt(char *key, int def) +{ +#if defined(__linux__) || defined(__APPLE__) + char value[1024]; + + if (read_var (INIfn, CONFIG_SECTION, key, value)) + return atoi (value); + else + return def; +#else + return GetPrivateProfileInt(CONFIG_SECTION, key, def, INIfn); +#endif +} + +void INISetInt(char *key, int val, char *comment /* = NULL */) +{ + char s[1000]; + + if(comment) + sprintf(s, "%d ; %s", val, comment); + else + sprintf(s, "%d", val); +#if defined(__linux__) || defined(__APPLE__) + save_var (INIfn, CONFIG_SECTION, key, s); +#else + WritePrivateProfileString(CONFIG_SECTION, key, s, INIfn); +#endif +} + + +// plugin name +static const char *PLUGIN_NAME = "Portal Viewer"; +// commands in the menu +static const char *PLUGIN_COMMANDS = + Q3R_CMD_ABOUT ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_OPTIONS ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_SHOW_2D ";" + Q3R_CMD_SHOW_3D ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_RELEASE ";" + Q3R_CMD_LOAD; + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + + +//extern "C" LPCSTR WINAPI QERPlug_Init (HMODULE hApp, GtkWidget* hwndMain) +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + // Setup defaults & load config + InitInstance(); + + return "Portal Viewer for Q3Radiant"; +} + +extern "C" const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList() +{ + return (char*)PLUGIN_COMMANDS; +} + +/* +void Sys_Printf (char *text, ...) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text, argptr); + va_end (argptr); + + g_FuncTable.m_pfnSysMsg (buf); +} +*/ + +bool interfaces_started = false; + +static void CheckInterfaces() +{ + if (interfaces_started) + return; + + render.Register(); + + interfaces_started = true; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p); + + if (!strcmp(p,Q3R_CMD_ABOUT)) + { + DoAboutDlg (); + } + else if (!strcmp(p,Q3R_CMD_LOAD)) + { + CheckInterfaces(); + + if (interfaces_started) + { + if (DoLoadPortalFileDialog () == IDOK) + { + portals.Load(); + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + } + else + { + Sys_Printf(MSG_PREFIX "Portal file load aborted.\n", portals.fn); + } + } + } + else if (!strcmp(p,Q3R_CMD_RELEASE)) + { + portals.Purge(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + + Sys_Printf(MSG_PREFIX "Portals unloaded.\n"); + } + else if (!strcmp(p,Q3R_CMD_SHOW_2D)) + { + portals.show_2d = !portals.show_2d; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + SaveConfig(); + + if(portals.show_2d) + Sys_Printf(MSG_PREFIX "Portals will be rendered in 2D view.\n"); + else + Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 2D view.\n"); + } + else if (!strcmp(p,Q3R_CMD_SHOW_3D)) + { + portals.show_3d = !portals.show_3d; + SaveConfig(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + + if (portals.show_3d) + Sys_Printf(MSG_PREFIX "Portals will be rendered in 3D view.\n"); + else + Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 3D view.\n"); + } + else if (!strcmp(p,Q3R_CMD_OPTIONS)) + { + DoConfigDialog (); + SaveConfig(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + } +} + + + +// ============================================================================= +// SYNAPSE + +class CSynapseClientPrtView : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientPrtView() { } + virtual ~CSynapseClientPrtView() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientPrtView g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, PRTVIEW_MINOR, sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable); + + return &g_SynapseClient; +} + +bool CSynapseClientPrtView::RequestAPI(APIDescriptor_t *pAPI) +{ + if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) ) + { + if( !strcmp(pAPI->minor_name, PRTVIEW_MINOR) ) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientPrtView::GetInfo() +{ + return "PrtView module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/prtview/prtview.h b/contrib/prtview/prtview.h new file mode 100644 index 00000000..e478f7d9 --- /dev/null +++ b/contrib/prtview/prtview.h @@ -0,0 +1,29 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PrtView.h : main header file for the PRTVIEW DLL +// + +#if !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) +#define AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_ + +void InitInstance (); +void SaveConfig (); + +#endif // !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/res/PrtView.rc2 b/contrib/prtview/res/PrtView.rc2 new file mode 100644 index 00000000..0422bb19 --- /dev/null +++ b/contrib/prtview/res/PrtView.rc2 @@ -0,0 +1,13 @@ +// +// PRTVIEW.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/contrib/prtview/resource.h b/contrib/prtview/resource.h new file mode 100644 index 00000000..afa9db6e --- /dev/null +++ b/contrib/prtview/resource.h @@ -0,0 +1,42 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by PrtView.rc +// +#define IDD_ABOUT 129 +#define IDD_LOAD 130 +#define IDD_CONFIG 131 +#define IDC_LOAD_2D 1000 +#define IDC_LOAD_3D 1001 +#define IDC_LOAD_FILE_NAME 1002 +#define IDC_LOAD_OTHER 1003 +#define IDC_CONFIG_3D 1004 +#define IDC_CONFIG_2D 1005 +#define IDC_SCROLL_2D_WIDTH 1006 +#define IDC_2D_WIDTH 1007 +#define IDC_ANTI_ALIAS_2D 1008 +#define IDC_COLOR_2D 1009 +#define IDC_ZBUFFER 1010 +#define IDC_SCROLL_3D_WIDTH 1011 +#define IDC_3D_WIDTH 1012 +#define IDC_ANTI_ALIAS_3D 1013 +#define IDC_COLOR_3D 1014 +#define IDC_COLOR_FOG 1015 +#define IDC_FOG 1016 +#define IDC_SCROLL_3D_TRANS 1017 +#define IDC_POLY 1018 +#define IDC_3D_TRANS 1019 +#define IDC_LINES 1020 +#define IDC_SCROLL_CUBIC 1021 +#define IDC_CUBIC 1022 +#define IDC_CLIP 1023 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/prtview/stdafx.cpp b/contrib/prtview/stdafx.cpp new file mode 100644 index 00000000..6bee6d29 --- /dev/null +++ b/contrib/prtview/stdafx.cpp @@ -0,0 +1,25 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// stdafx.cpp : source file that includes just the standard includes +// PrtView.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + diff --git a/contrib/prtview/stdafx.h b/contrib/prtview/stdafx.h new file mode 100644 index 00000000..b4afbc8e --- /dev/null +++ b/contrib/prtview/stdafx.h @@ -0,0 +1,79 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __PRTVIEW_AFX_H__ +#define __PRTVIEW_AFX_H__ + +#include + +#if defined(__linux__) || defined(__APPLE__) +#include + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +typedef guint32 COLORREF; +typedef void* LPVOID; +typedef char* LPCSTR; +typedef void* HMODULE; +typedef int BOOL; + +#define RGB(r, g, b) ((guint32)(((guint8) (r) | ((guint16) (g) << 8))|(((guint32) (guint8) (b)) << 16))) +#define GetRValue(rgb) ((guint8)(rgb)) +#define GetGValue(rgb) ((guint8)(((guint16)(rgb)) >> 8)) +#define GetBValue(rgb) ((guint8)((rgb)>>16)) + +#define _MAX_PATH PATH_MAX + +#define IDOK 1 +#define IDCANCEL 2 + +#endif // __linux__ + +#include "synapse.h" + +// plugin +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ibspfrontend.h" +#include "igl.h" +#include "version.h" + +// PrtView +#include "gtkdlgs.h" +#include "prtview.h" +#include "portals.h" + +#define MSG_PREFIX "Portal Viewer plugin: " +#define PRTVIEW_MINOR "prtview" + +#define UPDATE_2D (W_XY | W_XZ | W_YZ) +#define UPDATE_3D (W_CAMERA) +#define UPDATE_ALL (UPDATE_2D | UPDATE_3D) + +int INIGetInt(char *key, int def); +void INISetInt(char *key, int val, char *comment = NULL); + +extern bool interfaces_started; + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; + +#endif diff --git a/docs/developer/.cvsignore b/docs/developer/.cvsignore new file mode 100644 index 00000000..cc43c10e --- /dev/null +++ b/docs/developer/.cvsignore @@ -0,0 +1 @@ +*.BAK diff --git a/docs/developer/CHANGES b/docs/developer/CHANGES new file mode 100644 index 00000000..20d07a9b --- /dev/null +++ b/docs/developer/CHANGES @@ -0,0 +1,5616 @@ +This is the changelog for developers, != changelog for the end user +that we distribute with the binaries. (see changelog) + +05/19/2004 +TTimo +- testing CIA setup + +04/09/2004 +TTimo +- update the OSX setup / .info generation code + +04/08/2004 +TTimo +- fix for scons 0.95 +- re-enable Python >= 2.1 version check +- OSX 10.3: remove obsolete dlsym_auto_underscore (bug #920) +- OSX: disable q2 tools build (broken thread code) + +-- 1.4.0 + +SCDS_reyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=963 + fix to multiple monitor support (ABI compatibility with NT4) + +-- 1.4.0-rc2 + +14/12/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=955 + fix setup to install VC7 runtime + +-- 1.4.0-rc1 + +10/12/2003 +TTimo +- created stable branch, branches/1.4 on all SVN modules +- removed outdated .dsp/.dsw (.net 2002 required now) + +-- branches/1.4 + +06/12/2003 +SCDS_ReyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=930 + shortcuts to change texture window scale + +02/12/2003 +SCDS_ReyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913 + fix for single monitor window positioning save +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=924 + fixes to CenterXYView shortcut, correctly bound to Shift+Control+Tab now +TTimo +- add a 'q3map2' command line to win32_install.py, factorize and remove win32_install_q3map2.py + +-- linux 1.3.14 test build 1 + +29/11/2003 +TTimo +- heretic2 has no q2map. linux setup tries to install and breaks + removed faulty setup line +- cleaned more Linux setup fuckage caused by q2/her2 + a tip: rm -rf build install before building and testing a new setup + +28/11/2003 +ydnar +- full SCC purge of the vs.net project files (for real this time) +- added seperate Q3Map2 build targets +- added seperate Q3Map2 post-build Python script +- _skybox entity support +- _skybox and _decal in entities.def (Q3) + +-- win32 1.3.14 test build 1 + +28/11/2003 +djbob +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=899 + bobtoolz update (icon functionality is in menu too) +djbob & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=842 + migration of the win32 build system to vs.net/VC7 + new libxml and libpng packages are required: + http://zerowing.idsoftware.com/libxml/ + http://zerowing.idsoftware.com/libpng/ + updated win32_install.py for new names and paths +TTimo +- assraped the vcproj with sed to remove Scc entries +SCDS_ReyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88 + 2D background image plugin +TTimo +- putting together win32 setup updates for 1.3.14 + msvcr70.dll goes in core directory + bkgrnd2d plugin content + changed file paths (libxml/libpng) + .xlink for new JA content + +27/11/2003 +TTimo +- using a central scons.signatures file for checksums +- version bump to 1.3.14 +- a libxml-related build bug in qe3.cpp on Debian sid +- it looks like Sid no longer has inflate_mask exported from /usr/lib/libz.so + switched the mask to be defined in our source + this may be a problem on other distros, and on holy box (Woody) +SCDS_ReyalP +- bug 921 and 922, Z floating window fixes +- bug 926, hullcaulk, hintskip, subtlehint +EvilTypeGuy +- bug 505 - select all faces with a given texture + +19/11/2003 +ydnar +- clipper tool plane points default to 1st selected patch mesh + +17/11/2003 +TTimo +- upgraded server to subversion 0.33 + +-- released 1.3.13 + +10/11/2003 +SCDS_reyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=917 + floating windows startup crash + +09/11/2003 +TTimo +- fix M4_GAME_ET ( OSX setup ) +AstroCreep +- cleaned up JA shader scripts + +01/11/2003 +ydnar +- Merged ASE submaterial/subobject code from BirdDawg +- Made Q2/Heretic2 tools not use precompiled headers to eliminate Win32 compilation errors +- Added glColor4ubv() support to the GL function table +- Changed PicoModel rendering to use glColor4ubv() instead of 4 divides and pass-by-value glColor4f() +- Fixed bug 900 by setting alpha to 255 explicitly in image module, rather than 3 input components, + which was borking Q3Map2 jpeg loading, and thus compiles + +24/10/2003 +TTimo +- bump to 1.3.13 +Anders +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=826 +new osx patch, fixes strip bug in setup. merging setup patches to a single file +SCDS_reyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 +Some jpegs get garbaged alpha channel + +22/10/2003 +-- merge https://zerowing.idsoftware.com:666/radiant/GtkRadiant/branches/Release-1.3.12/ + 19/10/2003 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=826 + scons BUILD=info to generate a tarball and it's .info + + 18/10/2003 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=888 + patch for 16 bit RGBA support in glwidget + + -- released 1.3.12 Linux + + 14/10/2003 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=879 + fixed hellish dlclose issue only occuring with holy builds + + -- released 1.3.12 win32 +-- end merge +Arnout +- added epsilon testing to hashtable compares to eliminate almost-identical vertices +- pico surfaces now use the normals from LWO vertices + +21/10/2003 +Arnout +- added hashtable for faster vertex matching during LWO surface generation +- model rendering now uses DrawElements and will use vertex colours in wireframe/flats shade mode + +20/10/2003 +Arnout +- added LWO support to picomodel. + shader names are derived from surface name + only geometry from layer 0 is used +- added support for 'vertical flipped' TGAs + +19/10/2003 +Arnout +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=893 + fixed starton primary monitor + fixed mouse pointer setting on win32 to properly translate gdk's offset coordinate system in windows' one + +-- released 1.3.12 win32 + +11/10/2003 +Spog +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=865 + fix texture subsets +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=889 + misc update, missing JA system textures +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=824 + fixed .pref file trashing +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=881 + BSP monitoring disabled by default in Q2 + +09/10/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=883 + more JA pack: shaders and mapextras.pk3 textures +- fix Q2 win32_install.py to put the tools at the right spot +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=878 + correctly support PNG images with an alpha channel +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=885 + fix console to refresh during a texture directory load +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=739 + fix weird Shift + Control + Z causing a Redo in non-floating window mode + +07/10/2003 +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=872 + Q2 tools, added -fs_basepath. Need corresponding setup and .proj updates +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=875 + fixed broken surface properties in Q2 surface plugin +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=872 + more fixes, build paths in scons, take out INSTALL config on command line (not functional + not need) + added Q2 tools back to Linux setup +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + using "*" as the shaders minor in surface plugin +- updated makeself copy to the latest from icculus.org cvs +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=574 + sprite plugins, tweak to make it functional for all games +- updated Q2 tools .dsp +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=876 + more Jedi Academy setup work and content + moving imagepng.dll module to the core, as now both Sof2 and JA need it + sample maps reorg, new siege_hoth_sample.map +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=874 + a lot more models - using a dynamic File Group in IS to cope with that +- Q2 IS setup fix, was not properly putting stuff in baseq2/ + IS setup: tweak to Q2 tools stuff + +06/10/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=872 + Q2 setup needs to be cleaned up and unified between win32 and Linux + using INSTALL_Q2 and TOOLS_Q2 in SCons script to install the Q2 tools + fixed the setup build dependencies to reference the Q2 tools targets + moved the Q2 specific modules imagewad and vfspak to q2/modules + +05/10/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=871 + updating the gtk2 version to 2.2.4 + adding an SVN module with the Gtk2 developer package: checkout gtk2-win32 + updating IS to the new files + sed'ing the .dsp to replace src-gtk2 by gtk2-win32 +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=609 + Q2 tools: comment out dupe strupr on win32 + update IS setup to missing Q2 stuff ( vfspak and tools ) +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=866 + Fixed Camera inspector window not refreshing. Was a missing top level gtk_widget_show call + +03/10/2003 +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=609 + quake2 tools build scripts + Linux setup updates - Q2 game pack in Linux setup +TTimo +- scan through all URL links in game.xlink to update them +- added JA links (Raven and MapCenter forums) + +30/09/2003 +TTimo +- update all synapse.config, win32 .dsw and install_win32.py for new surface module +- Jedi Academy and Quake II game packs in IS setups +- hardcoded hacks in editor core for JA, copied over from JKII +- bug #867, disable sleep by default +- q3map2 bug fix + +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=862 + Q2's 'no patch' stuff + +29/09/2003 +TTimo +- OSX: fixup setup.xml.in + +-- merge bug856 back into trunk +16/09/2003 +Nurail +- new patch + win32 stuff for surface module +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=804 + refactored the XML synapse.config handling: + better detection of invalid XML file + less code, factorized to CSynapseClient::ConfigXML +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=828 + fixing bobtoolz 'shaders' major loading issues + added '*' minor. to be used with lots of caution. only if the given major will have a single API such as 'shaders' + also, map module was missing a VFS entry in non-HL configs. that's bad karma, using a minor "*" instead + NOTE: on a lot of modules we could be using a '*' entry instead of having lines in synapse.config +- took out obsolete md3model + +15/09/2003 +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=856 + quake2 surface module + +07/09/2003 +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=856 + a surface inspector module to customize per-game API + removing DO_SURFACEPLUGIN define (enabled implicitely) + removing bSurfacePropertiesPlugin (true implicitely) + remove SI_SetActiveInRadiant, it's always on by default + why was USE_UNDOTABLE_DEFINE taken out? - put back in + removed DBG_PLUGIN define and related code, that stuff is from way back and no longer relevant + cleanup QERApp_FreeShaders in shader module from DO_SURFACEPLUGIN stuff + the WINAPI stuff in interfaces is not needed, that's an old remnant. Cleaned up +-- end merge bug856 back into trunk + +19/09/2003 +Justin Blur +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=785 + fix ~/.radiant permission bug +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=849 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=851 + win32 updates for the new modules and install_win32.py + +16/09/2003 +Nurail & Hydra +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=848 + q2 map format minor + +08/09/2003 +Tr3B +- imagepng.so / PNG format support in Linux + NOTE: atm no official supported Linux game by GtkR uses this + +07/09/2003 +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=851 + imagewal.so module / wal image format +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=840 + md2 support in picomodel + +06/09/2003 +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=848 + renaming mapq3.so to map.so + added hooks for Q2 map format load/save to single map module (minor mapq2) +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=849 + vfspak port to synapse and updates + +04/09/2003 +SPoG +- Fixed crash in RunBsp caused by passing an invalid pointer to printf. +- Changed console to wrap long lines instead of using horizontal scrollbar. + +30/08/2003 +Anders & TTimo +- OSX setup, new patch to make scons SETUP=1 produce a .run +- don't put bspc Linux binary in the setup + +26/08/2003 +Anders +- more scons OSX, start on setup stuff + +25/08/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=855 + make 'move into worldspawn' work again +Anders Gudmundson & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=826 + OSX scons build system + +24/08/2003 +ydnar +- Removed "test.cpp" from radiant.dsp (merge artifact?) +- Added ddslib to radiant.dsw +- Correctly set lib deps for q3map2.dsp for ddslib +- [bug 852] Increased buffers from 260 bytes on Win32 to 4096 bytes + +TTimo +- bump to ver 1.3.12 +- EnsurePythonVersion broke in 0.91 (commented out) + +David Hogue +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=844 + q3data Linux. q3data can read .ase and turn them into .md3 + +23/08/2003 +ydnar +- Added ddslib to repository, based on nvidia sample code, cleaned up a bit + straight C, loads DXT1, DXT3 and DXT5 format DDS textures. + +22/08/2003 +TTimo +- https://zerowing.idsoftware.com:666/viewsvn/ +- Arnout's commit email script - try #2 + the commit script doesn't handle viewsvn root remaps (radiant instead of radiant.svn) + adding a prefix to the report + +04/08/2003 +TTimo +- conversion from CVS to Subversion: +repository convert completed (with revml) +module repositories glued together in a single one +hooking email commit scripts and backup scripts +- Python >= 2.1 required instead of 2.2 + +-- tagged as head-cvs2svn + +01/08/2003 +SPoG +- Changed gl widget to request maximum available depth buffer precision. +- Changed all uses of deprecated GtkCList and GtkCTree to use GtkTreeView/Model. +- Fixed directory handle leakage in synapse module search. +- Fixed dir_dialog always returning NULL for Textures -> Load Directory. + +23/07/2003 +SPoG +- Ported focus_out_event handlers in gensurf to gtk2 signals system. +- Fixed failure to load models for entities other than misc_model. +- Fixed crash in model module shutdown caused by mismatched resource capture/release. + +22/07/2003 +TTimo +- fix q3map2 .dsp for correct glib-2.0 includes (common/vfs.c) +- camera plugin installs to core now (RTCW and ET) +- fixups to the merged setup stuff +- patched cvsreport to provide explicit diff for some files #2 +- fix to work with scons 0.90 / added LIBPREFIX ('lib') where needed + https://sourceforge.net/tracker/?func=detail&atid=398971&aid=766975&group_id=30337 +SPoG +- Fixed crash in cmdlib ExtractFileBase when source filename is an empty string. + +20/07/2003 +TTimo +- SCons scripts for the ported plugins: bobtoolz, camera, prtview, gensurf +- ET Linux setup script + new plugins +- q3map2.x86 is installed and wrapped through a q3map2 script (libstdc++ LD_LIBRARY_PATH) +- update ChangeLog and credits +- put back the GTKRAD_DIR in .fgl + +19/07/2003 +SPoG +- Tagged trunk before merge as bug537-merge-3. +- Tagged branch port_gtk2_20030307 as gtk2-merge-final. +- Merged changes since tag bug537-merge-2 into trunk. +- Removed gtk dependency from plugin toolbar interface. +- Ported prtview, bobtoolz and gensurf to gtk2. + +18/07/2003 +Anders Gud +- OSX build fix + +16/07/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=814 + merging ET support code into to trunk +- cvsreport 0.3.0 - http://www.nongnu.org/cvsreport/ + rolling out this ver since old cvsreport setup broke +- fixup to build on Linux (including fixing plugin builds) + +-- release-1_3_8-ET + +02/07/2003 +TTimo +- new setup build, with patches and updates from SD +- local fixing of bobtoolz dependency against libcmd, and itoolbar.h gtk header bustage + +19/06/2003 +TTimo +- missing plugins. add them to .dsw for default build, add them to IS setup: + camera, gensurf, bobtoolz, prtview +- fixup bobtoolz code for VC6. for(int i=0 causing duplicate definition errors +- removed pk3man from IS (we no longer distribute/maintain it) + TODO: cvs remove the IS files for it +- re-enabled plugins in build by default, disabled curry and textool + TODO: following error when bring up About box of bobtoolz: + BobToolz::ERROR->Failed To Load Exclusion List: C:\Program Files\GtkRadiant-ET-1.3\plugins\bobtoolz.dllbt\bt-el2.txt + +18/06/2003 +TTimo +- add ET game pack. from Arnout's full dump of editor source + game pack data + trunk tagged at ET-tag for this +- Dlg_SdAskCorePath: + szDir = "C:\\Program Files\\GtkRadiant-ET-1.<>"; + +09/06/2003 +ydnar +- Added Q3Map2 keys/entities to Quake 3 entities.def +- Removed obsolete vlight keys from Quake 3 entities.def +- Added MD5 functionality to mathlib, from: + http://sourceforge.net/projects/libmd5-rfc/ + +------- merged changes since tag bug537-merge-2 from branch port_gtk2_20030307 to trunk + +TTimo +- try checkin on branch see if cvsreport 0.3.0 will verbose it + +08/07/2003 +SPoG +- Fixed recent-files list for file names containing underscores. + +07/07/2003 +SPoG +- Fixed crash and file-type bugs in gtk file-dialog. +TTimo +- converted the setup code from perl to python +- added copy over of libgcc_s and libstdc++, and LD_LIBRARY_PATH in the wrapper script + +06/07/2003 +SPoG +- Changed console popup menu to include cut/copy/paste as well as clear. + +05/07/2003 +SPoG +- Fixed the way surface-inspector dialog responds to escape key. + +04/07/2003 +TTimo +- linux building / SCons + 0.90 is broken, use 0.14 for now. added version check + adding scons SETUP=1 option to spawn setup build + enable back vfswad in scons + TODO: grab Conscript-setup, convert it to python in build_setup function + +02/07/2003 +TTimo +- building a win32 setup, using -gtk2 suffix (game packs in Radiant-1.3-gtk2 and core in GtkRadiant-1.3-gtk2) +SPoG +- Ported vfswad to gtk2. +- Fixed memory leak in vfspk3 directory search. +- Added vfswad to win32_install.py. + +09/06/2003 +TTimo +- tagging setup/ as gtk2_setup_rollback + rolling back trunk setup code to the branch to build an experimental release +- merge trunk to branch: +-- tagged HEAD with bug537-merge-2 +-- merge HEAD between bug537 and bug537-merge-2 into the branch -- + 31/05/2003 + TTimo + - grab back vfswad code that I forgot in bug 800 rollback + - add prtview back to the project, fix it to build (#817) + + 27/05/2003 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=817 + prtview fixes, upgrade to synapse + + -- release-1_3_8 +-- end merge HEAD between bug537 and bug537-merge-2 into the branch -- +- freshly merged in vfswad is broken +- freshly merged in prtview is broken +- q3radiant.dsp -> GtkRadiant.dsp, outputs GtkRadiant.exe +- removed vc5 dsps +SPoG +- Updated win32 setup stuff to use gtk2 dlls. +- Modified setup.pl to run correctly (tested on cygwin perl 5.6). + +08/06/2003 +TTimo +- Linux: + check gcc 3.x, better ldd check + add gcc version to about message + kill old cons stuff +- added q3map2.x86 scons build +- header conflict libs/cmdlib.h tools/quake3/common/cmdlib.h + grepped through q3map2 source to change #include "cmdlib.h" to common/cmdlib.h +- killed more cons files remnants +SPoG +- Improved error reporting for win32 setup system. +- Fixed errors reported when running setup scripts. +- Fixed scale of xor selection rectangle in XY window. + +07/06/2003 +SPoG +- Fixed X Window System error when entering freelook on *nix. + +06/06/2003 +SPoG +- Fixed copy/paste on *nix. +- Changed copy/paste on *nix to use GtkClipboard api. +- Changed copy/paste on win32 to be non-window-specific. +- Further cleaned up MainFrame::Create. +- Changed freelook to use gdk_window_get_origin instead of gdk_window_get_root_origin to place the cursor. + +05/06/2003 +SPoG +- Fixed grey statusbar in 4-way-split mode. +- Redirected gtk messages before creating main window. +- Removed unused XYFriend hack from camwindow. + +04/06/2003 +TTimo +- win32_install.py settings loaded/saved from site.conf + +02/06/2003 +TTimo +- fixed python running with no output. Make sure VC6 finds native Python before any cygwin Python + look at the Directories settings in Tools > Options to either kill the c:\cygwin\bin path, or have Python path first +- renamed dupe files to avoid header collision and general confusion between entity and model +- added win32_install.py to perform post-build install (need to load the configuration paths from a non-cvs stored site.conf file) + +01/06/2003 +TTimo +- bind gen.dsp to makeversion.py +- added a run_python.bat to check for python presence and execute + +27/05/2003 +TTimo +- write makeversion.py module - hook it up to SCons build - cleaner, easier to use +- comment out vfswad build lines. source is still not in tree (bug 800 aftermath I think) + +18/05/2003 +SPoG +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=537 + Changed Sys_FPrintf_VA to immediately process console events during map load. + Changed startup to create main window after QE_Init(). + Fixed loading last map on startup. + Fixed crash on exit. + Fixed colour dialog. +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=537 + have to delay merging back to trunk. + have a behaviour problem between debug and release builds. + while debug is fine, release is screwed (see bug item) + +-- tagged HEAD with bug537 +-- merge HEAD between merge-gtk2-20030413 and bug537 into the branch ----- + 11/05/2003 + Dan Olofson & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=812 + workaround for ATI drivers bug (polygon backfaces) + use Preferences > 2D Display/rendering > ATI cards with broken drivers + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=806 + updated synapse.config for SoF2 png + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=805 + dir_dialog is broken - is only used in prefab path prompt + + -- release-1_3_7 + + 14/04/2003 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=801 + moved "ignoring sprite for entity.." to be a _DEBUG only thing + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=802 + fixed models not drawing on win32. was a setup bug + - OSX setup build updates - added dependency against libpng3-shlibs + - added openurl.sh to open urls on *nix (with setup updates) + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=803 + RTCW - default_project.proj in setup + + 13/04/2003 + Michael Schlueter & EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=684 + imagepng building under Linux + Riant & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=797 + fixed texture compression support + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=799 + regen project file from template on version upgrade + updated all default_project.proj to have "version" "1" + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=798 + missing modules/bitmaps/model_reload_entity.bmp from Linux setup +-- end merge HEAD between merge-gtk2-20030413 and bug537 into the branch ----- + +17/05/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=537 + http://www.qeradiant.com/wikifaq/index.php?Gtk2%20build%20notes + went through the new dll dependencies, listed required files preparing for a single zip package + updated all the project files to rely on src-gtk2/ + +13/04/2003 +SPoG +- Tagged HEAD with 'merge-gtk2-20030413' and merged HEAD --> port_gtk2_20030307. + +12/04/2003 +SPoG +- Added gtk-2.x libraries to win32 setup. +- Changed win32 setup to use 'dynamic' file-groups, making it possible to add files without + modifying installshield scripts. +- Modified win32/setup.pl to copy setup data to dynamic file-group directories. + +30/03/2003 +TTimo +- added scons scripts. the scons engine is included in the tree. you just need to have python + have ldd -r safe check on .so + TODO: + - make sure it's gcc3 + - check OSX + - add q3map2 build + +29/03/2003 +TTimo +- tracked and fixed the startup bomb on Debian sid: + `pkg-config gtk+-2.0 --libs` + -Wl,--export-dynamic -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0 + http://www.gnu.org/manual/ld-2.9.1/html_chapter/ld_2.html#SEC3 + --export-dynamic + When creating a dynamically linked executable, add all symbols to the dynamic symbol table. + The dynamic symbol table is the set of symbols which are visible from dynamic objects at run time. + If you do not use this option, the dynamic symbol table will normally contain only those symbols + which are referenced by some dynamic object mentioned in the link. If you use dlopen to load + a dynamic object which needs to refer back to the symbols defined by the program, rather than + some other dynamic object, then you will probably need to use this option when linking the program + itself. + this causes symbol confusion, shaders.so's g_ShaderTable suddenly resolves to the core's g_ShaderTable + one is a 'shaders' API, the other an 'appshaders' .. everything gets badly mixed up + added a check in the cons script, using `pkg-config gtk+-2.0 --libs-only-L` `pkg-config gtk+-2.0 --libs-only-l` + (same for gtkglext) + +28/03/2003 +TTimo +- propagate jpeg compile fix from bug750 branch +- use PKG_CONFIG_PATH when building radiant/ (alternate gtkglext-1.0) +- on OSX, you need gtk+2-dev package, and pkgconfig, atk1 + build gtkglext from source http://gtkglext.sourceforge.net + +17/03/2003 +TTimo +- updated the build system to glib2/gtk2/gtkglext + atm it compiles and starts on my dev box (Debian Sid) + but doesn't reach end of initialization, hangs on + q = (qtexture_t*)g_hash_table_lookup (g_ShadersTable.m_pfnQTexmap (), stdName); + in shaders.cpp QERApp_Try_Texture_ForName + need to have the gtk2 dev packages, and libgtkglext1-dev + +12/03/2003 +SPoG +- Replaced alpha-blended area-selection rect with XOR rect. +- Fixed YX/XZ/YZ toggle in floating windows layout. +- Cleaned up xor rectangle code. + +11/03/2003 +SPoG +- Fixed console scroll-to-last-text-inserted. +- Fixed console error/warning colours. +- Refactored or removed WIN32-specific gtk-related stuff. +- Removed win32 SetCapture/ReleaseCapture on GLWindow. +- Removed win32 gtk_main_iteration calls in glwindow mousemoved. +- Cleaned up start-on-primary-monitor stuff. +- Changed main window to use standard save/load window position/size. +- Replaced deprecated gtk_widget_set_uposition with gtk_window_move. +- Removed win32/X gl functions from igl. +- TODO: replace/remove deprecated gtk_widget_usize. + +10/03/2003 +SPoG +- Changed fonts in win32 rc file to 8pt tahoma. +- Fixed flat-grey gui in Regular layout mode. +- Changed main-window save/restore maximized to use gtk API. +- Fixed button_press_event handling on console/entity/entitylist windows. + +09/03/2003 +SPoG +- Fixed crash on shutdown after changing floating-z-window preference. +- Removed win32_realize_floating hack. +- Refactored MainFrame::Create to make it more readable. +- Fixed key_press_event handlers for entity/surface/patch dialogs. +- Fixed delete_event handlers for dialogs derived from Dialog class. + +08/03/2003 +SPoG +- Fixed viewport for entity window comment text. +- Fixed x-shrinking for entity window comment text. +- Fixed menu underscore shortcut hack in MRU list. +- Changed groupdialog to connect switch_page signal after creating all pages. +- Changed gl widget to use gtkglext/pango to create fonts. +- Cleaned up gtkglext glwidget implementation. +- Reduced border size on toolbar widgets. +- Replaced font with font_name in win32 rc file. +- Added viewports for all scrolled text boxes. +- Fixed entities/textures/console window title update when page is changed. +- Fixed floating windows not being transient to main window (don't want them on taskbar). + +07/03/2003 +SPoG +- Created a new branch for the port to gtk 2.x. +- Fixed menu underscore shortcuts to use gtk_label_new_with_mnemonic. +- Fixed global keyboard shortcuts by using mainframe_keypress. +- Fixed use of deprecated gtk_color_selection_get_color. +- Removed use of deprecated gtk_paned_set_gutter_size. +- Replaced deprecated gtk_widget_draw with gtk_widget_queue_draw. +- Replaced deprecated gtk_object_get/set_data with g_object_get/set_data. +- Replaced deprecated gdk functions with 2.x equivalents. + + +----- branch port_gtk2_20030307 ------ + + +13/04/2003 +Michael Schlueter & EvilTypeGuy +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=684 + imagepng building under Linux +Riant & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=797 + broken texture compression support + +12/04/2003 +TTimo +- push version to 1.3.7-dev +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=794 + add a synapse.config chunk for image module + also added check for correct dynamic APIs initializations (bug 796) + misc stability fixes to synapse +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=796 + "map" "maphl" not checking for "VFS" "wad" presence + added a safe check. don't have an HL setup to test on though +LordHavoc +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=790 + misc crash fixes related to vfsLoadFullPathFile returning -1 on not found +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=89 + work on Q1 support + added a new module 'Q1Pack' wit the synapse.config for Q1 + applied the patch (#415) - with some modifications. Removed unused TGA stuff from imagehl. +Riant +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=781 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=795 + 1.3 SoF2/JK2 setup missing synapse.config + several fixes to the SoF2/JK2 support + BSP menu, q3map2 + monitored compiling + fixed TEMPLATEapppath expansion + Q3 default_project.proj + +10/04/2003 +** who ? ** (ETG?) +- Compilation warning fixes including: + lack of newline at end of files + non-virtual destructor for virtual function class + addition of header #includes to solve "implicit declaration" cases + corrected bogus #endif declarations + added declaration of WinPrint for l_net_berkley.c +- Added _GNU_SOURCE define for q3map2 threads.c for non-WIN32 platforms + (usage of mutex_setattr_settype is a posix *extension*) + +29/03/2003 +TTimo +- merging bug750 branch back into trunk. Have Linux and OSX setup live together +- added setup.sh.in config.sh.in / stuff flagged as OSX-only - setup.sh only tries to run setup.gtk +- the .deb building on Linux was experimental, we don't plan to use it. took it out (.deb is for OSX/fink setup build) +- setup.xml.in with a bunch of OSX updates +- propagated back the GtkR setup patch to lokisetup ML +-- bug750 branch ------------------------------- + 18/03/2003 + X-Man & TTimo + - corrected setup.gtk bugs (don't strip, detect arch correctly) + - fixed arch detection in postinstall.sh + - updated setup.sh to do the right thing and point to help + - rebuilding a rev 3 + + 17/03/2003 + TTimo + - setup.sh sources fink's init.sh stuff + - abort if not root + - fake xsu to have correct abort (run it as root directly) + - rebuilt .deb + + 10/03/2003 + TTimo + - building a fink .deb to wrap the setup: when run as root, ./cons -- setup + now produces a .deb which wraps the graphical installer + - updated setup.gtk and related source patch to new loki_setup source + - handy script to use when putting together a list of dependencies: + otool -L radiant.ppc > otool.txt + cat otool.txt | sed -e 's/^\([^ ]*\) .*/\1/' | while read i ; do dpkg -S $i ; done 2>/dev/null + + 05/03/2003 + TTimo + - making ./cons -- setup builds a .deb + the idea is to use a .deb for dependencies against fink, and trigger our custom setup once the .deb is installed + no dependencies atm, need to rebuild on OSX and write in the whole set of deps + - happy place, happy place .. the code to build a .deb for debian and a .deb + for fink won't be compatible. fink lacks -fakeroot support, some stuff needs + to run as root. Disabled for now + - hacked to fix libjpeg build, need to -Ilibs/jpeg6 before system paths + (would need a CPP_BASEPATH in the build system) +-- end bug750 branch ----------------------------- + +13/03/2003 +Hydra +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + cleanup in hydratoolz plugin +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=776 + more post build step cleanup +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=648 + enginepath in setup +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=574 + sprites loader verbosity + +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=775 + - updating 1.3 setup against 1.2 tree + - zlib and libpng12 in Program DLL Files + - changelog.q3map2.txt to Program Misc Files + - merged RTCW GOTY edition prompt from 1.2 setup + - merge SoF2 setup prompt code from 1.2 setup + - made sure merged SoF2 .game has enginepath + - remove the media update items (we start from scratch on 1.3) + - bitmaps in Program Executable Files + file0=<>\GtkRadiant\plugins\model\bitmaps\picomodel.bmp + file1=<>\GtkRadiant\plugins\model\bitmaps\model_reload_entity.bmp + - added dependencies of q3data.exe installed in STVEF Executable Files (libxml2 etc.) + - removed libxml2 / iconv / glib where not needed + +11/03/2003 +Hydra TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=776 + sanitize post build step +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=574 + updates for spritemodel stuff. cleaned up the patch a bit + +Hydra +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=777 + improve visibility of selected models +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + hydratoolz update + +28/02/2003 +TTimo +- building an experimental 1.3 full setup on win32 + includes all games (Q3 RTCW JKII EF SOF2 HL) + several updates to .dsp's to get everything building in release + setup updates: + took out all plugins (they have not been ported) + took out q3map references (we only distribute q3map2 in 1.3) + add q3map2 to Program Executable Files + using GtkRadiant-1.<> for core path + usign Radiant-1.<> for game packs + adding synapse.config: HL / Q3 / RTCW (HL untested) - others don't have one yet + +17/02/2003 +TTimo +- tweaking ./cons -- setup on OSX, look for gcc 3.x by default + -- creating branch bug750 for OSX setup work + - long term, we want a single setup file working for both Linux and OSX + but initial OSX setup work is easier if we just do a standalone OSX setup + though since it breaks Linux setup for a bit, putting this on a branch + - compiled a ppc setup.gtk from loki_setup + - updated Conscript-setup and related stuff to be OSX / ppc compliant + +16/02/2003 +TTimo +- fixed symlink bug in Linux setup stuff + +15/02/2003 +TTimo +- added CreateDirectoryPath to cmdlib, shuffled some utility code around. + QE_SaveProject correctly creates the paths + +10/02/2003 +TTimo +- Finalize Linux x86 setup. + Updated loki_setup patch with SETUP_COMPONENT_PATH env var for postinstall.sh, rebuilt a glibc 2.1 x86 image for setup.gtk + Finished ./cons -- setup code up to final setup generation + +31/01/2003 +SPoG +- bug #752 - Construct fix for ppc, patch applied. + +26/01/2003 +TTimo +- bug #750 - revamp of the setup stuff on Linux + (under way, see bug for progress - feel free to help!) +- reworked the cons scripts, setup is hooked in to cons now + also, added gcc version select on command line, using Cons_gcc.pm utility + +22/01/2003 +TTimo +- merged merge-1_2_10-post back to trunk + +=============================================================== +-- merging release-1_2_9 -> merge-post-1_2_10 into trunk + trunk before merge is tagged pre-merge-1_2_10 +=============================================================== + +22/01/2003 +TTimo +- finished up the TODO items, turned into bug items or dropped them. branch is ready to move back in to trunk + +18/01/2003 +TTimo +- fixed ID_SELECTION_MERGE + +17/01/2003 +TTimo +- fixups + FlushReloadSelectedToolbarButton -> CFlushReloadSelected + incorrect naming: RadiantToolbarModuleManager -> CRadiantToolbarModuleManager + ToolbarButton -> IToolbarButton, and C* implementations + http://www.qeradiant.com/wikifaq/admin.php?Code%20Conventions + +14/01/2003 +ydnar +- Minor Cons fix for OS X (bug 729) + +13/01/2003 +ydnar +- GtkRadiant now builds on OS X, Linux, and Win32 out of the same tree +- OSX build uses gtkfileselect-linux now, as the Darwin version was broken/old + fixme: change this to use OS X open dialog box or something? +- Minor fixes to a few files to fix gcc warnings +- Model module now builds on OS X and Linux, using Synapse properly +- PicoModel change to invert T coordinate on ASE models +- Q3Map2 change to export ASE models with T coordinate flipped +- Misc Q3Map2 changes + +09/01/2003 +ydnar +- Updated Construct with Darwin/OS X ld flags for 4MB stack size +- Misc Q3Map2 updates (2.3.35-dev) + +05/01/2003 +ydnar +- "angles" key now properly ordered, to work with current mathlib + (also changed in Q3Map2) + +31/12/2002 +ydnar +- PicoModel: Minor fix to MDC loader (naming/define) +- Q3Map2: 2.3.34-pre-1 updates +- MapXML dsp unix->dos newlines + +29/12/2002 +SPoG +- Merged q3map2-texturing prefs key. +- Merged vfs check for gamemode project key. + +27/12/2002 +TTimo +- fix GetTickCount stuff +- added q3map2 cons script +- fixed Linux build + +23/12/2002 +SPoG +- Added model cache API, moved model cache implementation from entity module to core. +- Added file-type registry API, replaced core file-type manager with registry. +- Changed model module to register supported file types with core registry. +- Removed or #ifdef'd non-functional code from model module. +- Added support for misc_gamemodel and model_static to entity module. +- Cleaned up entity module's on-epair-changed API. +- Moved light-entity-specific code to a seperate file in entity module. +- Cleaned up file dialog interface - specify file-type-lists with a string. + +22/12/2002 +SPoG +- Ported camera plugin to synapse, adding support for camera and ui APIs. + +20/12/2002 +SPoG +- Fixed default prefs setting for selected-brushes-camera, gridmajor-alt and gridminor-alt. +- Merged CEntityEclassModel::Draw in entity module. +- Ported imagepng module to synapse. +- Fixed warning for CamDragMultiSelect preference bool used as int. + +19/12/2002 +SPoG +- Fixed white-textures bug caused by texture compression preferences. +- Ported light-radius rendering to 1.3 entity module. + +18/12/2002 +SPoG +- Merged win32 project files, with the exception of camera plugin. +- Ported model module to synapse API. +- Redesigned toolbar API to remove gtk-dependency from toolbar plugins. +- Refactored window-position preference save/load. + +17/12/2002 +TTimo +- kick doxygen generation for branch merge-1_2_10-post + +15/12/2002 +TTimo +- having the linux version compile and start again. took out numerous elements while merging, built a list of TODO stuff + the main thing to do being to bring the win32 build back up too, then to go through TODO list and fix stuff + until the win32 version runs too, I check this in to a seperate branch merge-1_2_10-post +- There is quite a massive update in mainframe.cpp switch case for all events. + Looks like it's just a reordering of stuff, but it looks bad in the diffs. +- added m_MapReg pattern + +- At some point, I'm thinking that forcing correct TAB/SPACE conversion on the server end would be a good thing to have. + Nazisticly forcing the formatting sounds like the only viable solution. + + 11/12/2002 + RR2DO2 + - #418, mdc load and display (RTCW) + - #597, CenterCamera shortcut + Use Ctrl+Shift+TAB to center the views onto the current camera location + - #714, bitmap loading fixes and speedups + - #715, fixed Alt+Shift cycle/drill select to work with brush-based entities + EvilTypeGuy + - #718, fix compilation warnings + Riant + - #707, fixed HM mode in STV:EF + + 10/12/2002 + EvilTypeGuy + - Fix gcc3 compilation warning + EvilTypeGuy and X-Man + - Fix OpenURL so browser launching works on XDarwin (Mac) systems. + + 8/12/2002 + RR2DO2 + - #710, AssignSound pattern + - #711, SoF2 model_static drawing + - #713, sync 2d and 3d rendering of models + - #238, apply 0..1 T range when Fitting a patch (instead of 0..-1 previously) + - #633, Add ability to change default color in 3D window Misc > Colors > Camera background + ydnar + - Q3Map 2.3.33 (see changes.q3map2.txt) + - Quake 3 + TA common.shader updates (q3map_terrain, hint) + + 3/12/2002 + TTimo + - merging Stable-1_2-Apple into Stable-1_2 + - why INSTALL.TXT? re-used INSTALL, updated to point to wiki + - why the -machinedump test against i386-redhat-linux? removed + - using $is_darwin flag instead of $gcc_machine tests in the build scripts: + gotta leave some room for a Linux ppc build, and darwin x86 + exporting it for use in sub scripts + - the addition of ccache support broke some Apple SConstruct patches to $ENV{PATH}, fixing + merged version is compiling fine on Debian Sid + checking in on a branch, need to validate win32 build and OSX build before applying in Stable-1_2 + + -- release-1_2_11 + + 30/11/2002 + TTimo + - added seaw0lf to credits + - ydnar's changelog.q3map2, added to global.xlink and Linux setup + - 1.2.11 version tag + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=699 + updated IS setup for q3map_terrain keyword + also fixed details in STVEF media + Arnout + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=569 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=698 + fixed drill select, Ctrl bug in vertex mode, and updated changelog.txt + + 29/11/2002 + TTimo + - 1.2.11-rc1 + - update changelog credits links for release + - update linux setup, putting EULA and new README instructions + + 28/11/2002 + ydnar + - Removed redundant 'p' from "developers" + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=637 - fixed + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=694 - fixed + - Updated to Q3Map 2.3.32 + - Added epsilon to texture plane choose code to eliminate numerical + inconsistencies on brush faces slanted at 45 degree angles (bug 637) + - Fixed bug in lightmap export after lighting when map contains 0 BSP lightmaps + - Adjusted some light tracing constants to fix certain brush/patch seam shadows + - Tinkered with skylight code again + - Fixed bug where lightgrid would be black if level was compiled with -nogrid + - Fixed -approx code to work in floating-point space, using _minlight + - Fixed bug where vertex light code was using invalid pvs data to create + light list for surface, leading to incorrect vertex lighting + - Fixed related bug in anti-light-leak code that was causing brush faces to go + black (bug 694) + - New: _minlight sets _minvertexlight and (new) _mingridlight automatically + - New: _mingridlight key to set minimum grid lighting + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=637 + added preference setting in Preferences > BSP monitoring + added an item on the wiki + + 27/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=662 + picomodel-based model.dll module (new model.dll, removed md3module.dll) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=664 + media/setup updates for q3map2 support + added modified quakev3.qe4, bumped internal version to 4 for all games + SOF2 and JKII were forcing BSP monitoring off because of sof2map, now only printing a warning + added -rename to SOF2 BSP phase + Q3 & RTCW new templates are working + haven't tested the STVEF & SOF2 versions + updated IS setup scripts to make sure quakev3.qe4 is updated in nightly release + (not needed on Linux, we will be doing a full release) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=662 + updated win32 setup to provide right model.dll stuff + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=621 + typo was causing memory error + + RR2DO2 & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=662 + more model fixes, fixed the Linux build to build model.so + added search path to modules/ for bitmaps + model reload, patch and bitmap + + 26/11/2002 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=569 + area select - Alt+Shift for area select (complete tall) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=621 + broken undo creating ghost undo entities (and trashes memory) + partly fixes the issue, it's a memory error still + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=659 + updates to RTCW camera plugin - works in 4 view mode + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=663 + more fixes to plugin API + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=638 + libpng in the core DLLs instead of SoF2 (for q3map2 dependencies) + putting q3map2 binary with the Core Binaries + + 25/11/2002 + TTimo + - added ccache support to cons build system - http://ccache.samba.org/ + + 21/11/2002 + ydnar + - minor bugfix to PicoModel ASE material loader + - Q3Map2 updated to 2.3.31 (Splash Damage) + - Stitching the edges of lightmaps on patches that wrap around (cyls and cones) + so the seam is no longer visible + - The -patchmeta switch works better now, the patches are still stored in the + BSP for collision, but are pre-tesselated into nonplanar meta surfaces for + more efficient rendering + - Better, more uniform lightmap sample position finding on patch meshes + - Moved q3map_tcMod and q3map_alphaMod processing to the final phase + - New: q3map_skylight AMOUNT ITERATIONS to replace surfacelight on sky surfaces + for much faster and more uniform sky illumination + - Fixed bug in PicoModel ASE material parsing code + - Fixed a few seam/lightmap precision/projection errors + - Increased MAX_SHADER FILES to 1024 and fixed overrun error when more than that + number of shaders was listed in shaderlist.txt + - Increased a few compiler maximums for larger maps + - New: -np N switch on BSP phase, works like -shadeangle, in that it forces all + planar shaders to be nonplanar with the shading angle specified + - New: -nohint switch on BSP phase, omits hint brushes from compile for testing + - New: -debugaxis switch on light mode. Colors lightmaps based on their lightmap + axis (which direction the lightmap was projected on) + - New: -debugorigin switch on light mode. Colors lightmaps based on the luxel + origin relative to the raw lightmap's bounding box + - New: -debugcluster switch on light mode. Colors lightmaps based on the pvs + cluster the luxel falls into + - New: -convert switch to convert BSP to ASE file (experimental) + - New: q3map_lightmapmergable directive to allow terrain to be mapped onto a + single lightmap page for seamless terrain shadows + + 18/11/2002 + TTimo + - fixed pk3man build system to work with new cons layout + - fixing linux setup system to work with new cons layout + Linux 1.2.11 will be a full setup, much easier that way + - update makeself to the latest (and best) version + - add q3map2 to Linux setup. goes in core (g_strAppPath) + NOTE: has a dynamic dependency to libpng + - pk3man still has issues with the zlib code that's been thrown in it + unresolved which I don't have time to look at + since we plan to drop pk3man in 1.3, dropping it now is just as good + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=644 + detect GOTY install from registry and use it as default path + + 13/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + reworked to have the UI in game settings dialog + (this is strictly win32 thing, if that broke Linux build, then fix the typos) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=630 + mouse AngleSpeed setting was getting clobbered. fixed and upped the max values + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 + applied a fix, rolls back the values when the compression formats are not supported + fix ain't very clean, if we have to deal with extensions some more, we need to deal with the settings persistance better + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=624 + updated the setup code for town_*.shader (both in full setup and update) + updated files in WolfPack + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 + using a QE4_VERSION define, added a message if there's a project template with wrong version + + 12/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=671 + guard junk.txt path between " " + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=663 + fix to CommitBrushHandleToEntity stuff + + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=660 + previously you could select patch control points when patch selected + vertex edit (V) in 2D view. Works in camera view now + + 12/11/2002 + TTimo + - nudging zerowing to trigger Stable-1_2-Apple doxygen generation + http://zerowing.idsoftware.com/doxygen/ + + 11/11/2002 + TTimo + - http://ttimo.net/web/anjuta + modified the .prj to work with the cons patches (linked dirs) + still way experimental + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=651 + fixing linking for radiant.x86 + + 10/11/2002 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=669 + patch inspector bug - fixed + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=663 + fucked up change in the plugin API caused breakage of several plugins + still have to fix bobtoolz http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=665 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=661 + Undolevels not set properly + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=660 + drag selection to the camwindow for patches in controlpoint edit mode + (not sure about the actual shortcuts, Ctrl+Alt on my current Linux setup) + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=657 + mark map modified on editing entity keys + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=651 + added the correct link and ldflags statements to have static linking everywhere + didn't check gcc 3 build, check correct static on Debian Sid and holy box + has a $staticstdcxx in Construct to toggle On/Off if needed + + 09/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=651 + reworking the cons building. support for gcc2 and gcc3 + cons -- gcc= + read gcc version and configure accordingly + changed _NO_STLPORT to Q_NO_STLPORT + independant BASE_CFLAGS and BASE_CXXFLAGS + correcting usage of CC/CXX for c/cpp source and linking + fixed missing -lz in vfspk3.so + changed the way we build curry.so, works from the GtkRadiant tree now + (NOTE: gcc 3.2 build of curry.so spews quite a few warnings) + tweaked the way we do -fno-rtti -fno-exception + + 04/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=638 + .qe4 version 4, udpated q3's .qe4 template, update setup to put q3map2 in the right place + bumped version to 1.2.11-test for test setups + + 03/11/2002 + ydnar + - fixed bug in jpeg loading code (4 components instead of 3 for RGB images, mh) + - updated PicoModel to 0.8.8 and Q3Map2 sundry fixes (2.3.29): + - Merged with latest CVS, fixed minor issues with matrix order + - Fixed minor Sys_FPrintf/Sys_Printf substitution typo in Q3Map2 + - Expanded debug colors to 12 for debugging surface meshes + - PicoModel: fixed ASE loader to support > 1 texture coordinate per-vertex, + so more models supported correctly, also loading vertex normals + - PicoModel: md3 shader names are now cleaned. Suffixes (such as .tga or .jpg) + are stripped, and \ path separators are changed to / + - New: Add :q3map to the end of any shader name, and it will be interpreted as + the named shader minus :q3map. Example: + textures/shaderlab/concrete:q3map -> textures/shaderlab/concrete + One potential use is the -approx feature to collapse lightmapped surfaces + into vertexlit surfaces, saving lightmap space/memory + - New: q3map_clipModel -- does what you think it does, sort of. This code ix + really experimental, and should *only* be used on large models such as terrain + (not small decorative models). This code will be evolving. Note: the shader's + surfaceparms are inherited by the magic clip brush, so if you have nonsolid + in your model's shader that uses q3map_clipModel, then the brush will also + be nonsolid + + 03/11/2002 + TTimo + - cleaning up some cons stuff, checking that the setup building process is still good on Linux + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=622 + updated Linux setup to put the bitmap + + 02/11/2002 + ydnar + - PicoModel: replaced stricmp with _pico_stricmp + + 02/11/2002 + ydnar + - PicoModel: added obj.c and ms3d.c, removed wfobj.c + + 02/11/2002 + ydnar - seaw0lf + - Updated Q3Map2 to 2.3.29 sources + 2.3.29 + - Merged with latest CVS, fixed minor issues with matrix order + 2.3.28 + - Bug 654 (http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=654): + Fixed problem where brush faces, drawsurfaces, and surfaceparms weren't living + together in perfect harmony (terrain surfaceparms now inherited by brushes) + - Nodraw fog works now, albeit when you're underneath, surfaces above don't get + fogged properly. Could be good for foggy water where you want the above-water + portions to only be occluded by the water surface + - Bug 656 (http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=656): + Number of lightgrid points displayed (byte size is currently out of proportion + due to internal storage format) when Q3Map is called with the -info switch + - Fixed wack surface merging bug where code would attempt to merge triangles not + adjacent to the current set, causing bad lightmap projections on nonplanar + surfaces + - Fixed tiny 1-character bug in 2d lightmap texture allocator where adjacent + luxels were being checked for occlusion rather than the actual source luxel + 2.3.27 + - Fixed minor bug in scriplib bugfix where the last character in a file wasn't + being read. + - Fixed bug where 0-area or bogus triangles were causing crash in MapRawLightmap + if they used a shader with a normalmap (thanks ShadowSpawn) + - Fixed bug where lightmaps were getting hosed levelwide on a prerelease version + of 2.3.27 + - Fixed bug where lightmaps were getting knackered on models and certain patches + - Merged latest PicoModel version from seaw0lf, adding support for ASE and WF OBJ + models (preliminary) + - Increased MAX_MAP_PLANES to 0x40000 (~256k) + 2.3.26 + - Now using GtkRadiant's libpng and zlib config (linked as DLLs) + - Fixed bug in script parser where repeat calls to GetToken() were causing + memory corruption + - Fixed SOF2 -rename bug + - When using -game sof2 or -game jk2, the -flares argument is implied + - Added -noflares argument to disable the above behavior + - Added support for flares on entities. Use one of the following keys: + "_flare" "1" -- use default flare (different for each game) + "_flareshader" "path/to/flareshader" -- use a specific flare shader + Note: This only matters in SOF2/JK2 now. Make a light targetted (a spotlight) + to get it to aim the correct direction, otherwise it defaults to pointing + downward. You cannot have omnidirectional flares + - Lightgrid size is automatically increased to accomodate large maps. The + MAX_MAP_LIGHTGRID error will never happen again + - Update PicoModel to 0.8.7 sources + - ASE support + - Alias|Wavefront OBJ support + - .remap shader remapping suport + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=655 + handle grayscale jpegs gracefully + - mathlib: fixed VectorClear(), got rid of braces + - scriplib: fixed double-free memory corruption bug + - radiant: added new color scheme to emulate Lightwave/Maya/3DS Max + + 02/11/2002 + TTimo + - too many issues with build system reading system's libjpeg.h instead of libs/libjpeg.h + renamed libs/libjpeg.h to libs/radiant_libjpeg.h, updated sources + + 29/10/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + running from a network share - saving prefs per-user + + 27/10/2002 + TTimo + - merged in some more m4x4 code for q3map2 + - fixed unresolved code in picomodel (strlwr / strnicmp) + - reworked the tools building to build both q3map and q3map2 without trouble + + 25/10/2002 + ydnar + - q3map2 and picomodel source, initial checkin to Stable-1_2 branch (does not compile yet, tweaking to be done) + + 23/10/2002 + TTimo + - camera.dll goes into $(RTCWRADIANTDIR)/plugins instead of $(RTCWRADIANTDIR)/modules + fixed up camera compile (exports) + added camera bitmap (plugin toolbar) + + 21/10/2002 + TTimo + - quickfix to the build (typo) + - changed dynamic linking on Linux to look for libGL.so.1 by default + fixes "all textures are blank" Linux bug with NVidia cards + (you still have to have a working NVidia GL installation though, xlibmesa-dev on Debian screws things up) + - checked in modified q3 .qe4 with q3map2 menu (see bug #638) + + 09/10/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=622 + reworked the plugin toolbar to rely on interface instead of straight exports + cleaned up the botclip monsterclip Brush_Draw filtering, added proper selection filtering (Brush_Ray) + merged bug-622 back into Stable-1_2, bug-622 branch is dead now + + 06/09/2002 + James Monroe - RR2DO2 - TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=619 + light globes, applying patch by RR2DO2 built from the initial light globe code + - note to self: indent -kr -nut -st -ts2 -i2 + + RR2DO2 - TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=622 + massive patch update from SD's GtkRadiant + - camera plugin: new bitmap + fixed Linux install path for camera plugin to wolf/plugins + - fixed various warnings in camera build gcc / Linux + - fixed pref crash if plugin toolbar disabled + - fixed Gtk-WARNING on bad cast in AddPlugInToolbarItem + - renamed the new select to 'Use paint-select in camera view:' in prefs + (camera paint-select, should be our default name for this) + + NEW: you can 'paint select' in the camera view: 'camera paint-select' + press shift and move the mouse over the camera view to paint over brushes you want to select + configurable in prefs to enable / use Shift key, or use 'classic mode' ctrl+alt + + NEW: light radius drawing + Added in-editor light envelope drawing. Outer circle is max envelope, + inner fullbright radius. Optional classic mode emulates the similar drawing + from Rituals and Ravens tools (not q3map correct, easier for the level designer + to understand/legacy). + + NOTE: 'angles' is q3map2 only + NOTE: could manipulate angles directly from the views (2d and 3d with some handles) + + NOTE TO SELF: + hey guys .. just a quick question if you don't mind .. I'm trying to track a Gtk-WARNING .. is there a way to make those apps cause a break to track them easily ? + just run your app with --g-fatal-warnings + + TODO: add new bitmap to win32 & linux setups + TODO: don't use exports for the plugin toolbar, use entry functions + do something like CPlugIn::InitBSPFrontendPlugin + TODO: botclip is broken with the new Brush_Ray code + + initial ChangeLog for the patch: + + 28-09-2002 + Arnout + + Added 'angles' support for models (misc_model/misc_gamemodel). + + Prevented pivot drawing of model from scaling and rotating. + + Cleaned up the dropdown boxes in the preferences a bit (all use + tables now, so not multiline). + + Added 'Classic Key Setup' option to camera paint select configuration, this + drag-selects with ctrl+alt instead of shift. + + Changed XYWnd::PositionView to position on the center of the + selection, not on the mins. + + 27-09-2002 + Arnout + + Added in-editor light envelope drawing. Outer circle is max envelope, + inner fullbright radius. Optional classic mode emulates the similar drawing + from Rituals and Ravens tools (not q3map correct, easier for the level designer + to understand/legacy). + + 26-09-2002 + Arnout + + Upped MAX_TEXTUREDIRS to 256 (from 128). + + 25-09-2002 + Arnout + + Fixed patches not being drawn in XY window with colour of parent + entity. + + Made paste to camera snap destination spot snap to grid. + + 18-09-2002 + Arnout + + Changed Select_Reselect to be much faster. + + 12-09-2002 + Arnout + + Fixed curve point drag-selection area not showing properly in XY + views. + + Fixed size info breaking over 9999.9 units. + + Fixed AllocateSelectedPatchHandles not setting patchesmode to + ESelectedPatches. + + Changed the horizontal and vertical tc shift spin control to have a + limit of 8192. + + Moved SPoG's implementation of redisperse cols to a seperate function + and reinstated the old code. + + Added 'Paste to Camera', shortcut Alt+V, which pastes the contents of + the clipboard to the current camera origin. + + Added centerview functionality to 4 window mode. Ctrl+tab will focus + on the selection, or if non existant, on the camera. + + 11-09-2002 + Arnout + + Made sure settings set in savedinfo.bin get initialized to their + proper defaults. + + Added botclip filter (filters *botclip* and *monsterclip*). + + 10-09-2002 + Arnout + + Removed .reg from normal map saving, can only save as region + using 'Save region'. + + Added outline style cycling (j) cycle between z buffered outlines and + selected colour rendering. + + Added colour dialog to pick the colour of selected surfaces in the + camwindow. + + Third coordinate for clip points now gets set to the center of the + selection. + + Changed arbitrary rotation dialog to accept negative angles as well. + + Changed texture alignment dialog to accept values up to 2 decimal + points. + + Fixed entity inspector to say 'Textures:' in the window title. + NOTE: still broke in floating window mode + + Changed entity inspector so that tab doesn't clear the epair value + field anymore, so it retains the value while jumping to it. + + Disabling camera paint-select now returns selection behaviour for groups to + the old behaviour as well (shift+click selects whole group). + + Changed load_plugin_bitmap to load bitmaps from g_strAppPath if + g_strGameToolsPath fails. + + Added plugin toolbar and api. + + Fixed m_pfnCommitBrushHandleToEntity, wasn't creating brushes + properly (well, not at all really). + + Older changes: + Arnout + + Added misc_gamemodel drawing. + + Ported camera paint-select over from 1.3. + + Fixed statusbar display of text (removed a bunch of \n's). + + Added area selection in 3d view for patches. + + 30/09/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 + quickfix crash bug + + 27/09/2002 + TTimo + - more CORERADIANTDIR cleanup (q3data) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=602 + added cascading to the entity submenu (doesn't cascade the main menu, only the sub ones, NPC_* for instance) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 + with clip and caulk filtered out, won't be selected anymore in camera view (i.e. selecting invisible faces) + added SF_CAMERA to the flags in the selection process + cleanup up various ugly syntaxes in the selection code: + don't ever do if (flags == SF_SINGLEFACE) on a bitmask and assert that the other flags will always be NULL + don't do arithmetic on bitmasks: + if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) + return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST); + is WRONG + using flags & ~SF_ENTITIES_FIRST is the appropriate way + + 23/09/2002 + Riant + - new IS scripts to go with recent media updates + Riant & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=615 + reworked the fix to use "caulk_shader" in .game + updated IS .rul script to generate special values for Sof2 and JKII + + 21/09/2002 + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=595 + more texture compression, dialog and settings + Michael Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=592 + fixes to the Linux build system, exclusive q3 or wolf working now + + 22/08/2002 + EvilTypeGuy + - Fix @*$&)@)$$ memory leak of my own doing, yes it's really been in there this long. + This should help memory usage drastically, especially when flushing & reloading + the same sets of textures, GtkRadiant's memory usage no longer becomes heinous. + + 14/08/2002 + EvilTypeGuy + - Fix build on some linux boxen by including qertypes.h for proper boolean type declaration + + -- release-1_2_10 + + 16/08/2002 + TTimo + - STVEF media update finalized (some .def) + - 1_2 Core Update for shader manual update + - in JKII, typo with nar_shader? replaced by nar_shaddar, with proper support in update too + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=530 + Q3/TA media update with cleaned up shaders + - validated the update content by a diff between 1.2.9 + 1.2.10-update and 1.2.10 full + - added a DO_NIGHTLY_BOOL to setup.rul AND a warning during setup about update content for games that are not installed + - built 1.2.10-sof2, SoF2 full install + + 15/08/2002 + Michael Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=590 + added the option to build a Linux setup with the debug binaries + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=530 + cleaned up shaders, done nightly setup update on Linux + updated Linux nightly for 1.2 to use /usr/local/games/GtkRadiant-1.2 as default base + - using version 1.2.10-update. Full Sof2 setup will be 1.2.10-sof2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=426 + don't straffe when using Ctrl+Shift(+Alt) + - camera.so RTCW plugin in Linux setup + - quickfix to non-initialized var in camera code + - awfull piece of work that had been completely left out, nightly elements for JK2 and STVEF + added JKII media update and STVEF media update (for the DIR_GAME elements) + JKII nightly is finalized + + 14/08/2002 + TTimo + - fixed a missing file + - Linux build quickfix + - fixed silly rendering bug + - added pref to force texture compression off (hey why would you do that??) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=466 + fixed MAX_POINTS_ON_WINDING overflow in q3map (and relevant code to handle in radiant) + + 13/08/2002 + TTimo + - cleared up notexture (dead code) + - cleaned up QERApp_LoadTextureRGBA gamma table init + - having a shot at 1.3 texture compression + sees the extension, binds the texture with the currect setting + but rendering is fucked .. someone explain? + + 08/7/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=586 + search and destroy Q3Radiant -> Radiant + + 07/7/2002 + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526 + wolf_entities.def update + + riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=548 + STV:EF updates + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=541 + SOF2 updates + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=584 + JKII updates + + 06/7/2002 + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=541 + Sof2 patches and IS setup + TTimo + - game pack prompt asking about STVEF, fixed + - mp_examples was leaked and non lighted, fixed + - imagepng.dll goes into Sof2 install / modules, and not in DIR_CORE + - libpng12.dll needs installed only with Sof2 pack (added 'SOF2 Pogram DLL') + default texture scale is 0.125 + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=582 + nomipmap -> nomipmaps in shader manual + - removed libs/pak, this was still being linked in to Radiant, but not used at all + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=580 + .PK3 are recognized along .pk3 files (strcmp ->strcasecmp) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=386 + added the RTCW camera plugin to IS setup + + Michael Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=581 + GL warning fix + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=567 + GL font display fixes (mostly Linux) + applied the changes with some tweaking + + 31/6/2002 + TTimo + - compiling the camera plugin on Linux: + move the GUID and other misc compatibility definitions to include/misc_def.h + GetTickCount being used in camera.so, this is from radiant/missing.cpp (unresolved) + -> use QGetTickCount instead (in main function table) + + 30/6/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=530 + cleaned the .shader from 'light 1' statements + updated the IS script for the updated .shader + + 17/6/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=541 + Sof2 support, PNG format + wrote imagepng module, dynamic dependencies to zlib and libpng + changes in the core: + some hardcoded to "sof2.game" for png interface loading and extensions + in GetTextureExtension, killed outdated support for texture plugins + if ! "sof2.game", png is not loaded, support disabled + http://zerowing.idsoftware.com/libpng/ + correctly configured for VC build (post build steps and dependencies) + is required on win32 to build imagepng + - added m_pfnGetGameFileName to the main function table (was needed for png stuff) + - cleaned up the QERApp_LoadTextureRGBA path + using (unsigned char* pPixels, int nWidth, int nHeight) + cleaning up internal access path + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=386 + camera plugin for RTCW + TTimo: wrote the .dsp, post build steps etc. + IMPORTANT: you need to have RTCWRADIANTDIR env variable pointing to the RTCW Radiant files + (default C:\Program Files\Return To Castle Wolfenstein\Radiant) + + + 12/6/2002 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=299 + MP/SP pk3 filtering in VFS + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=386 + .camera support: splines library, camera plugin + TTimo: portability fixups, cons build, guarding pragma, __cdecl BOOL + virtual functions but non-virtual destructor + declaration with no type + int idCameraFOV::start - control reaches end of non-void, making it void + enumeration not handled in switch + no _MAX_PATH, the portable one is PATH_MAX + implicit declaration of int _fullpath + for(int i = 0; .. + struct _IO_FILE has no member named '_bufsiz' + stricmp -> Q_stricmp + attempt at implementation in .h file (InitIglToQgl) + camera stuff still vastly broken (particularly on Linux), need to check in because of new fixes incoming + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=17 + quick fix to spawnflags getting corrupted when multiple entities selected + (doesn't completely solve the problems we have with spawnflags yet though) + +=============================================================== +END -- merging release-1_2_9 -> merge-post-1_2_10 into trunk - END +=============================================================== + +12/12/2002 + Hydra + - #197, HL support update + +11/12/2002 + TTimo + - added cmdlib dependency to mapq3.so (fixes unresolved) + +25/10/2002 + Hydra + - vfsGetFullPath() can now (optionally) search PK3/WAD files + - Half-life map loading is now un-borked (my original patch worked + but some conditional code in the patch was incorrectly applied. + That, coupled with the missing vfsFileExists and vfsFindFile replacements) + - A patch to imagehl/lbmlib.cpp/LoadIDSP() was missed out, causing all sprite + models to be reverse-rendered (due to an inverted alphamask) + - Renamed HydraToolz to HydraToolz-HL as it's half-life specific + changed project files and renamed all appropriate files and directories + (for the merge, just delete contrib/hydratoolz and apply the diff) + + - Comments on previous notes: + + - TODO: need to rationalize where the modules are placed and identify HL specific modules + (this affects the build system / post build step too) + imagehl and spritemodel are halflife specific and can be placed in + either $coreradiantdir/modules or $hlradiantdir/modules + I've updated the .dsp files so that they are copied to $coreradiantdir/modules + spritemodel can actually be used for other engines, not just HL so it makes sense + to keep it in $coreradiantdir/modules + hydratoolz is a half-life specific plugin and must go in $hlradiantdir/modules as it + is NOT to be used for any other engines. I've also updated the "about text" to + reflect this. + +14/08/2002 + EvilTypeGuy + - fix build process for textool plugin on some Linux boxen by including qertypes.h + +11/06/2002 + TTimo + - spritemodels in build system + - applying HL setup patch (att 270, bug 197) + - the templating went one filename seperator too far, causing all *.fgl to be modified .. + fixed so that we only have the relevant changes + - modules added to main Executable Files, TODO for later will need to identify what is HL specific + - .game generation: don't want enginename yet, gamename is ok + - updated HL .game generation for eclass_singleload and no_patch + - update hydratoolz location in setup + - update maphl in synapse.config + +07/06/2002 + TTimo + - realized that \func doesn't work in doxygen, should be \fn (updated everywhere) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + applying the HL patch (see original list of changes below) + - ugly eclass API changes + eclassfgd/plugin.cpp.rej, eclass API changes involved, a bunch of .rej + SupportsMultiple tries to send configuration information from the eclass format file module to the eclass manager + dropping it, using a proper configuration node instead (eclass_singleload) + - added "no_patch" prop to disable patch support + the patch toolbar prompts are only present in prefs if there is patch support + otherwise everything is force-disabled + - PFN_VFSFINDFILE PFN_VFSFILEEXISTS: + one of the problems we have is that the 'manager' code and file format code are in the same module + (i.e. vfspk3 / vfswad: two formats, but the manager part is pretty much the same) + vfsFindFile(relative filename): + this worked by searching through the list of loaded pk3/wad files for the file + then trying to search through the search directories + - wasn't properly documented about what it does / how is the search performed + - not consistent with existing code, duplicate of vfsGetFullPath for the most part + can't be added to the VFS API as-is, it would confuse the interface + - usage of vfsFindFile in the code doesn't justify the way it proceeds for search + foxing it, replacing by calls to vfsGetFullPath + vfsFileExists(relative filename): + returns wether a file exist, can be flagged to search in pk3/wad or straight filesystem + - this is a duplicate / particular case of vfsGetFileCount + foxing it too, we need to extend and update vfsGetFileCount instead + - mapq3: the changes completely fucked q3 map parsing + need reorganization. same module provides parsing for all .map based formats + we use wrappers around the actual calls and globals in the module to select formats + MAPVERSION_Q2 and MAPVERSION_Q1 don't need to be there yet, they are not supported + MAPVERSION_HL means WC >= 2.2 + (when introduced, MAPVERSION_Q2 would be Q2 or qer+hl plugin (same)) + MAPVERSION_HL uses "maphl" minor name (instead of mapq2) + cleaned up the Q3 read/write code that got broken + cleaned up various commenting/hack that deal with Q2!=HL format .. we'll see about Q2 when we actually do it + bad cut and paste from cmdlib code, using actual dependency to cmdlib instead (see below for some cmdlib updates) + - took out all SafeRead SafeWrite code from cmdlib, removed annoying cmdlib dependency to Error function + all file access go through VFS module, the cmdlib 07/06/2002 15:47file code was way old + - radiant/points.cpp pointfile code changes (that's used only for non-monitored compiling now) + - applied patch 267 (hydratoolz fixes) + - commented out some bworldcraft flagged stuff in mapq3/parse.cpp + - updated the .dsw .dsp to compile and copy HL stuff + - TODO: need to rationalize where the modules are placed and identify HL specific modules + - TODO: seems to be a synapse crash when unloading plugins (hydratools) + (looks like I didn't look at the plugin unload code yet actually) + - TODO: make sure HL setup puts eclass_singleload="1" and no_patch="1" + - TODO: WATCHBSP_KEY and TEXTURE_KEY hardcoded for HL need cleanup + - TODO: imagehl duplicates some image functionality + imagehl is supposed to be only for HL-specific image formats + it 'adds' the required formats to the stuff that image makes available for everyone already + - TODO: HL doesn't have a BSP menu! + - TODO: rename mapq3/ into map/, the map module handles all .map formats + - TODO: it's likely that we only need a vfs/ module instead of vfspk3/ and vfspak/ + think about it, see if we really act on this (or do we need to abstract the manager and some file format modules) + - TODO: HL synapse.config needs to use maphl + - TODO: wtf is enginename="quake2" in hl.game + - TODO: I don't have a sample HL map to play with, so I didn't test the changes against + +05/06/2002 + TTimo + - fixups to make 1.3 start (Q3 mode) + - turned off C++ exception support in the modules/plugins, as we don't use it + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 + exit properly if missing chunks in synapse.config, don't crash + + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=558 + fix for version check in release build + + ====================================================================================== + -- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + HL support patch + ====================================================================================== + 04/6/2002 + Hydra + - Patched in some CVS changes and fixed a little issue with the + new entity file loader code. + + 28/5/2002 + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=544 + Selected Entity Bounding Box obscured by brushes fix. + - Moved the "wad" keypair creation code from the Map module into + a new plugin called HydraToolz, this means that wad keypair is + done manually by the user, as in fact it should be. (as the + order of the wads is actually important). + - Fixed a problem with the wads in the wad list being re-ordered. + + 27/5/2002 + Hydra + - Created an inital implementation of a sprite model plugin. + According to the powers that be, it seems creating a model + plugin is hackish. + It works ok, but there is no way to attach models (sprites if you will) + to non-fixedsize entities (like func_bombtarget) + Also, I can't get the alpha map stuff right so I had to invert the alpha + mask in the spr loader so that 0xff = not drawn pixel. + + 17/5/2002 + Hydra + - "Wad" keypairs are now used when loading a map and speeds up map loading + significantly. This sorts out quite a few issues that could otherwise occur. + - Map loader now uses textures from wads listed in the the "wad" keypair first. + - Added a texture name mapping cache system to the .map loader + this significantly improves load times of maps that don't store texture + names along with paths (e.g. "mytexture" not "mytextures/mytexture".) + - Added vfsFileExists() to the vfs table (for above) and added it to + vfspk3 and vfswad + - Map loading and saving times are printed to the console. + - Wad file names from the "wad" key pair are logged to the console when + a map is loaded + - The user is informed if the textures loaded were not found in the + wad files in the "wad" keypair. + - The user is informed if the textures was not found in any wad file at all + (Q2/HL only, the shader module still gives you similar information for other + games when a shader activation fails) + + + 8/5/2002 + Hydra + - Added basic support in mapq3 for reading maps saved by Worldcraft 2.2+ + in .map format (It uses [ ]'s round some of the texture co-ordinates) + TODO: do we need to be able to save a map in this format too ? + - Added support for loading ZHLT style point files (*.lin) + - Added wad filename information when loading textures. + (This helps take the ambiguity out of which wad files textures come from, + so that we can correctly setup the worldspawn "wads" e-pair manually.) + Note: This will be removed when the "wads" worldspawn key is built by radiant. + - added vfsFindFile() to vfs table. + - VFSWAD: vfsLoadFile() no longer ignores paths when loading textures + (this was by design, but the design has changed for the better) + - When loading a Quake2 map file, vfsFindFile() is used to find the actual path of + the shader/texture being loaded. + This fixes all the weird issues that crop up when we were able to use non + wad-relative texture names () and wad-relative(/). + (such as having an image loaded twice in memory.) + We also now get the correct shader name in the suface inspector too. + Note: not sure if this code should stay in the map parser, or wether it should + be moved to where shaders are first initialised. + Note: maybe this needs to be when a halflife map is loaded, not specifically a + quake2 map file. + - added EClass_SupportsMultiple to the EClass loader API. + Note: this is poop. FGD files can be additive but radiant makes it so they can't be. + This function would not be needed if the eclass loader itself took care of the init, + rather then the manager taking care of the init. Also note that if the loader were + to take care of the init then FGD files *CAN* be additive, as it's not down to the + format of the FGD files. However, it'll do for the moment because all the supplied + FGD files that come with halflife and it's mods are meant to be used one at a time. + - removed support for having an additional (not external) eclass loader. + Just ifdef'd for now, grep for USEADDITIONALECLASSLOADER. + We never mix entity definition formats and synapse.config allows us to just have the + right one and also there is no mechanism for setting g_bHaveEClassExt anymore. + - Texture subset on by default for halflife. + - default texture scale is now set to 1 instead of 0.5 for halflife. + (needs to be 1 for q1/q2 too) + - patch toolbar disabled by default for halflife and it's also disabled + in the preferences so it can't be turned back on) + (needs to be 1 for q1/q2 too) + - bsp monitoring disabled by default for halflife + - When you drop a light entity the epair "_light" is used instead of "light" (halflife specific) + - removed -fs_game additions to the map compiler commands; ZHLT doesn't support it. + - saving of contents/flags/values in q2 format maps disabled (ZHLT doesn't like em !#?!) + TODO: re-enable for Q2 (but not halflife) format maps when we can + can figure out what game/engine combo we're using from within a module + - configured mapq3 to have dynamic VFS API too + - Added halflife shaderlist.txt parsing back in, it's actually useful + afterall (for editor shaders). + ====================================================================================== + -- end HL support patch + ====================================================================================== + +01/06/2002 + TTimo + - merging 1.2.7 -> 1.2.9 changes into 1.3, merge notes: + - the win32 .dsp are a bit different, using the $(CORERADIANTDIR) post build commands now + - merged in the JKII/STVEF hardcoded chunks, should probably check that everything is still fine on that end + was setting the "dir" epair in project files intead of "gamename" like all other games? + (which should really be "fs_game" anyway, I wonder who decided to call it "gamename") + - rebuilt a setup. we have a problem with RADIANT_MAJOR RADIANT_MINOR it seems + TODO: setup needs to use GtkRadiant-1. as basename in start menu, and base for installation + C:\Program Files\GtkRadiant-1.3 and C:\quake3\Radiant-1.3 etc. for the game packs + TODO: add HL setup chunks! + +=============================================================== +-- merging release-1_2_7 -> release-1_2_9 into 1.3 +=============================================================== +28/5/2002 + TTimo + - final fixes for Linux 1.2.9 setup + +27/5/2002 + TTimo + - bug 521, q3 entities.def trigger_hurt fix + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=542 + default texture scale is configured in .game + defaults to 0.5 (q3/wolf) if nothing specified, under the prop "default_scale" + removed the item from the prefs dialog too + updated the nightly setup to put the proper param in JKII .game + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=509 + changing texture window scale changes selected brushes texture + re-selecting the previous texture can be done, but is a bit tedious to write + made sure we deselect before re-init of the tex window view + - fixed linux setup code bug. won't be any update, only a full release on linux + +26/5/2002 + TTimo + - parallel cons working at last! was a problem with the targets list ('Default' command) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=515 + using the eclass extents for the box if model can't be found + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=435 + changed the submenu cascading params to avoid the overlap (we fit less stuff now obviously) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540 + that sigchld handler is only used on Linux to report the run times + since we are rewriting the whole BSP code stuff, we can drop this for now + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=538 + removed that prompt and display + - we build radiant.x86 in cons scripts, updated the setup code + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526 + updated the setup script to install new wolf_entities.def + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=302 + added q3map2 URL to global.xlink, updated Linux setup + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=465 + printing q3map version info through the net stream + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=539 + fixed various media, some related code, and Linux setup + - fixed watchbsp.cpp "jk2.game", was breaking game spawn for wolf (needed else if) + + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=504 + fixed bobtoolz vis viewer to work with RTCW (BSP version) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526 + update of the Wolf entities file + +25/5/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=164 + corruption on exit, tried to look some more. Cleaned up some source, need looking at Gtk code closer + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536 + cleaned up SHADER_NOT_FOUND SHADER_NOTEX internals some more + added a clean error exit in case this happens, fixed a crash that would happen anyway (Patch_LODMatchAll) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 + cleanup/sanitize of the pattern filtering code, it was ugly. did some doxygen documentation + fixed part of the print XY code, more broken stuff showed up, dropping it + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + region compiling was indeed fucked, spog b0rkage + fixed so that it works again + denying compile with camera out of the region + reworked SelectBrush to deal with regioning and select the right brushes + +24/5/2002 + TTimo + - Linux build fix + +23/5/2002 + Riant & TTimo + - STVEF patch and setup scripts + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 + moved error handling code to it's own file radiant/error.cpp + compiled with UNICODE define (that's why I had to isolate), and process the error string + so that Gtk can print it (that's only relevant to win32) + +22/5/2002 + TTimo + - quickfix, cleanup of the console verbosity + +11/5/2002 + TTimo + - final IS script updates for JKII game pack, version 1.2.8-jk2 + - fixed a bad karma #ifdef _DEBUG chunk in Texture_NextPos (causing crash of release build) + - added web url support in .xlink files (strstr on http://) + +10/5/2002 + TTimo + - cleaned the build step copy from $(QUAKE3RADIANTDIR) to $(CORERADIANTDIR) + - system shaders auto-load: display 'system' in the prefs + - force BSP monitoring off in jk2 mode + - cleaned up web update check, added HL (3) and Jedi Knight II (number 4) (on the web database too) + - updated IS setup script for mapextras.pk3 + Riant + - system shaders auto-load in prefs + Raven + - mapextras.pk3 as replacement for system.pk3 (system editor textures) + +8/5/2002 + Riant + - game pack and patches for JKII support + TTimo + - .game additions to specify .shader path (shaderlist and shader scripts) + NOTE: if we ever use q3map for JKII compiles, that would need to be propagated + - reworked the shaderlist to list all the included shaders + - built a system.pk3 pack for textures/system/ and textures/radiant/ (misses a few pieces still) + - MP / SP mapping mode toggle, SP ignores mp_*.def MP ignores sp_*.def + - fs_basepath does not get added during BSP command expansion for JKII mode + - more verbose on script location and junk.txt location when monitored compile is disabled + (the BSP compilation WANTS to be rewritten, it's getting VERY URGENT) + - JKII game back IS setup lands + +7/5/2002 + TTimo + - using radiant.x86 as Linux target (instead of radiant, didn't fit with the setup procedure) + - bumped version tag + - TODO: bug #453 code needs backported from 1.3 + +6/5/2002 + TTimo + - fixed typo in plugins/mapq3/write.cpp Map_Write + g_count_entities = 0; instead of g_count_brushes + - more fixes which showed up while merging this with 1.3 + +-- release-1_2_7 ----------- tagged and Stable-1_2 merging into trunk + +02/5/2002 + Gef + - added filtering on unselect for newly created brushes/entities (bugzilla: #374) + SPoG + - added undo for pasted/cloned brushes + +============================================================ +-- end release-1_2_7 -> release-1_2_9 merge +============================================================ + +15/05/2002 + TTimo + - rewrote the ref count code cleanly, added some elements to design and todo + - wrote the core shutdown code of synapse, 1.3 exits cleanly without crashing (well, in most cases it seems) + +10/05/2002 + TTimo + - began writing proper unloading and shutdown of synapse (see libs/synapse/docs/unload.txt) + design doc started, non active modules are unloaded after startup + need win32 implementation of ReleaseSO + - quickfix on win32 (ReleaseSO) + +07/05/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=512 + - cleaned up strHomeMaps and strFSBasePath stuff + prompts for maps, models, sounds etc are fs_game-dependant + + =========================================================================== + -- merging Stable-1_2 between Stable-1_2-tag and release_1_2_7 into trunk + merge ChangeLog + ============================================================================= + 07/05/2002 + - using RADIANT_MAJOR_VERSION and RADIANT_MINOR_VERSION for the version info, this was conflicting with synapse + + - m_strHomeMaps + http://zerowing.idsoftware.com/viewcvs/viewcvs.cgi/GtkRadiant/include/qertypes.h.diff?r1=1.27&r2=1.28&only_with_tag=MAIN + http://zerowing.idsoftware.com/archives/gtkradiant/2002-February/002170.html + posted on the ML, bringing it back in from 1.2 + + setup scripts: + easily merged, as the 1.3 scripts have not been touched mostly + + qe3.cpp conflict: + 1.2 tweaks stuff in the QE_*Project* functions + 1.3 has them mostly commented out + applying manually where relevant + the project settings stuff is very different, and the changes can't be applied as is + given the fixes I had to do in 1.2, I'd expect the current 1.3 version to be fairly broken + a complete kill and rewrite of the prefs/project stuff might be our option anyway + http://zerowing.idsoftware.com/archives/gtkradiant/2002-May/003038.html + qe3.cpp QE_InitVFS conflict: + 1.3 has some changes when creating the files in a new userprefix (ex. ~/.q3a/baseq3/scripts /maps /maps/prefabs etc.) + merged by hand, probably needs to be checked + qe3.cpp OpenDialog SaveAsDialog conflict: + commented out in 1.3, getting rid of it completely + + preferences.cpp conflict: + 1.2 adds CUSTOMSHADEREDITOR_KEY pref + 1.3 uses a completely different syntax for prefs + preferences.cpp conflict: + prefab path pref changes conflict with 1.3 pref syntax + applying changes manually to 1.3 codebase + + pmesh.cpp conflict: + 1.2 adds pref to group / not group patch thickening + 1.3 changes the way we manipulate entities around that code + merged manually, would be worth checking that the thicken pref works + + pluginmanager.cpp conflicts: synapse completely changes that part + on relevant 1.2 thing is the removal of pfnRadiant_Free + + map.cpp Map_ImportEntities conflict + 1.3 has bug 453 map conversion promt that was not backported to 1.2 (caused merge to conflict a bit) + usin 1.3 code and checking 1.2 changes manually + + using radiant.x86 as Linux target (instead of radiant, didn't fit with the setup procedure) + + 06/05/2002 + not merging in .dsw .dsp + an eclass.cpp fixed moved to eclass_def.cpp + mainframe.cpp is always a bitch to merge, sent several mail comments to list about conflicts that arose + MainFrame::OnFileSaveas needed some updates that were not in the diff (correct default prompt) + (same for MainFrame::OnFileSaveregion) + MainFrame::OnFileNewproject conflicts a bit, changes have been made in 1.2 and 1.3 + changes in 1.2 seem more crucial, using the 1.2 version, and patched the 1.3 manually over it + (might need to be checked, bug #506) + + TODO: need to check for parasite g_free that I added back from the file dialog + + propagated ChangeLog from Stable-1_2 + ============================================================================= + 02/5/2002 + Gef + - added filtering on unselect for newly created brushes/entities (bugzilla: #374) + SPoG + - added undo for pasted/cloned brushes + TTimo + - shift+left click to open shader editor no longer selects the texture on the way + (this was unstable, pCurrentShader could become NULL somehow) + - editpad bindings were completely broken + attempts to make it work again failed + taking it out + changed the prefs, on win32 you select between internal shader editor or win32 .shader binding + we have lost the ability to jump to a given line, if someone has a good solution for line jumping, let me know + - one more fix to the MAJOR / MINOR safe checks stuff + - bug #500: oooogly, I removed a line which I should not have :) + + 01/5/2002 + TTimo + - "Save selected.." load/save in fs_game sensitive directory too + - removed a bunch of unused/broken project settings items + removed most of them actually .. project settings are .. ahem + - added an optional 'go to url' button in gtk_MessageBox + + 30/4/2002 + Gef + - fixed lod drawing of selected patches when patches are filtered + + 29/4/2002 + TTimo + - bugzilla #467 + make patch inspector deny space textures + make mapq3 write code drop space textures + - bugzilla #132 + removed remotebasepath and texturepath + rewrote the Textures > Load Directory (which was kinda relying on texturepath) + - bugzilla #355 + uploading editpad zip to qeradiant.com misc/ in files section, replacing the win32 message about editpad + added editpad quote in qer.com totd + - fixing the map load/save dialogs to work correctly with mod settings on win32 (was done on Linux and still broken on win32) + + + 26/4/2002 + Gef + - fixed patches losing their shader if outside region when calling flush/reload + (bugzilla: #492) + - blocked textures with spaces from loading in Texture_ShowDirectory with a warning + (bugzilla: #467) + - fixed a dud shader (liquids.shader -> textures/liquids/ripplewater2_back) didn't have + the textures/liquids prefix + + 25/4/2002 + Gef + - fixed a broken image link in the shader manual (bugzilla: #486) + - changed prtview to use ~/.radiant//prtview.ini instead of + ~/.q3a/radiant/prtview.ini on linux + - fixed prtview loading/saving config (bugzilla: #424) + TTimo + - removed QERApp_RadiantFree from the function table + we can malloc and free across modules configured correctly for the CRT (Common Runtime DLLs) + cleaned up related broken malloc / free strategy in the plugins (vfsLoadFile uglyness) + - added main build date and version to curry / pk3man / prtview + + 23/4/2002 + SmallPileOfGibs + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=229 + flush and reload was affecting texturing of selected brushes + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=489 + File > Check for update menu item, jumps to the website and checks for update + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 + win32 part, RADIANT_MAJOR RADIANT_MINOR written out by setup + - more stuff on File > New Project and common mod setup issues (not finished yet) + + 22/4/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 + reworking a bit the installer stuff + wrote the version checking + needs testing on win32 (RADIANT_MAJOR and RADIANT_MINOR are required in the install now) + + 21/4/2002 + TTimo + - trying more seriously to get a new nightly out + updating the ChangeLog for current 1.2.7 from this file + cleanups, browsing through the bugs to close/update/fix + - http://zerowing.idsoftware.com/bugzilla/showattachment.cgi?attach_id=197 + I kinda fixed that myself already, going through the diff and applying the missing stuff + creating the prefabs/ dir in QE_InitVFS + - added a line about the games dialog / auto-select at startup in the dialog frame + + 15/4/2002 + TTimo + - cleaning some old commented out map load code + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=477 + on Linux: + - strHomeMaps was init without taking care of m_strFSGame + - SaveAsDialog was not using strHomeMaps + NOTE: should strHomeMaps be spcific to Linux, or we will do better if we unify + need similar checks on win32 + + 13/4/2002 + TTimo + - kicking the source to generate new doxygen on zerowing + + 09/4/2002 + Gef + - setting the sel_mode accordingly when (i)nverting selection, verts were being drawn when + they shouldn't have been + + 05/4/2002 + Gef + - fix File/New Project for mods so it doesn't fail if the dir exists (bugzilla: #459) + - add Linux-isms for New Projects & read/write permissions... + note: for a total conversion, basepath needs to be manually set + - prevent opening multiple internal shader editor dialogs + - added preference for using a custom shader editor + - set horizontal scrollbar to be automatic instead of never for entity keyval list (bugzilla: #4) + - added a call to Select_Reselect() in XYWnd->OnViewEntity() to make sure its modifying the + current selection (bugzilla: #436) + - fixed entity dialog passing events through to main window (bugzilla: #454) return values + were backwards + - patching in the .pfb extension adding stuff (bugzilla: #259) + - fixed thickened patches not being grouped (bugzilla: #226). this was supposed to be happening + anyway, the entity create code was called before the patches were selected + + 02/4/2002 + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=457 + add entity #X and brush #X comments back to saved .map files + + 24/3/2002 + Hydra & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444 + only show empty alpha channel warning if the tga texture is actually 32 bit + (24 bit would always have empty alpha, the warning was useless in this case) + + 19/3/2002 + Gef + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=217 + - Set show value to true for angle and movement velocity sliders in preferences + - Increased the maximum value of angle velocity from 6 to 100 + + 18/3/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=419 + fixed File->Save with region active acts the same as File->SaveRegion for ents + + + end merge + ============================================================================= + +16/4/2002 + SPoG + - fixed MDC_XYZ_SCALE value + +12/4/2002 + SPoG + - fixed win32 compile error - vc6 being nitpicky + - fixed refcount init on CSynapseAPIManager + - cleaned up md3model win32 project file + +9/4/2002 + Gef + - added nudging for selected brush and patch vertices (bugzilla: #240) + - added selected brush vertex highlighting + - sorted all the ID_'s in HandleCommand alphabetically to make it easier to track things down + - setting the sel_mode accordingly when (i)nverting selection, verts were being drawn when + they shouldn't have been + +5/4/2002 + EvilTypeGuy & djbob + - patched in djbob's grid minor/major color settings for gridsize < 1 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=24 + +1/4/2002 + TTimo + - configured md3model to have dynamic VFS API too + - cleaned up texwindow.cpp texture extension loop + - updated current HL media with hl's synapse.config + http://zerowing.idsoftware.com/stuff/HL-media-0401.zip + - checking in new synapse.config for Q3/RTCW + - fixed win32 project files, removed hltoggle.h + - bumped version to 1.3.3 + +31/3/2002 + TTimo + - XML runtime configuration of synapse + uses a synapse.config in the gametools path, we can add a line in the .game to specify the file later on + - various cleanups and removal of dead code + - Linux build system: sanitized CFLAGS, libxml, STLPort and glib include path all in the toplevel Construct file + - removed the 'cons -- halflife' option, the binaries are unified again + - cleaned up image loading + + +29/3/2002 + TTimo + - patching in Hydra's code for Half-Life, builds and runs on Linux, need to quickfix on win32 now + - build system on Linux: some things are still hardcoded into the core, you need a different core + for Q3/RTCW or HL for now. do ./cons -- halflife to build HL mode (build trees are seperate) + - there is no media / install procedure yet, but a zip with what you may need for install is available: + http://zerowing.idsoftware.com/stuff/HL-media-0329.zip + - cvs added all the new files + - patched various things from the patches, don't have a precise list + cleaned up the interface requests, isolated HL specific between TMP_HALFLIFE defines + removed 'tga' from imagehl, two modules providing the same API has unexpected results + + TODO: the image loading is the main problem right now. We should not have any place that scans the + extensions, this is done internally to the image load manager? texwindow.cpp does enumeration of the + minors too .. but that may be legal in this case. + + TODO: synapse config at runtime through XML (rather big piece) + + - fixing build on win32 + bad coding practices: 'for (GSList *choicelst = ..' + added a quick hack include/hltoggle.h for easy switch q3/rtcw or hl compile + (remaining hardcoded stuff is temporary) + + +28/3/2002 + Gef + - added linux pthreads support to tools + - removed old terrain.c and lightv.c from q3map2 Conscript + +27/3/2002 + Gef + - updated cons for q3map 2 + - minor q3map2 fixes for linux compile errors/warnings + - minor warning fix in map.cpp + SPoG + - changed entity_addtolist to add entities to end of list instead of beginning + - added eclass_forname to eclassmanager interface + - fixed setting eclass before model-update for entities loaded from map + - fixed setting bounding box for models after model-update + ydnar - q3map2 + - fixed crash on -connect and other gremlins related to argument processing + - removed flag that prevented Castle's maps from compiling + + +27/3/2002 + + Hydra + + Important Changes: + + - Added VFSWAD modules for extracting textures from WAD files. + - Added ImageHL for loading textures contained in WAD files + - Updated shaders source code so that you can produce ShadersHL.dll + (single minor using #ifdefs) + - MapQ3 source updated so that it can load and save q2 format maps + provides a multiple minors. + - Added EClassFGD for loading FGD definition files + (I documented this code quite well, if you're interested...) + - Added support for iconsprite() settings in the FGD loader, we set + eclass_t->skinpath with the name of the sprite + TODO: write a sprite model plugin. + + Fixes: + + - Fixed incorrect line numbers being reported when script files had // comments in them + - Removed EClass_Create from the EClass manager _EClassManagerTable + - Replaced all occurences of "textures/radiant/notex" in shaders.cpp with a define. + - Fixed a crash in shaders.cpp when there was no default texture. + - Fixed a possible issue with g_bCancel_Map_LoadFile + - Added a crash fix for uninitialised patchMesh_t->pSymbiot + + Core Changes Required for HalfLife Support: + + - Set MAX_FLAGS to 16 to support Halflife's extra spawnflags, adjusted + entity inspector to display the new spawnflags, updated FGD loader + to load them correctly (previously it only loaded the ones with values <8) + (Done without breaking the old Q2 code that was commented out) + - Added GetTokenExtra to the _ScripLibTable + - Kludged texwindow.cpp to allow loading extension other than "tga" and "jpg" + TODO: ttimo, we need something in synapse to help with this. + - Plugin manager requests different API's depending on .game file used. + TODO: this needs to be done on a PER GAME basis, not PER .GAME FILE. + - Shaderlist.txt is not parsed on startup if hl.game is used. + TODO: this needs to be done on a PER ENGINE basis, not PER GAME. + + Cosmetic Changes: + + - Changed MAPQ3's minor_name from "map" to "mapq3" (also adds "mapq2" as a minor) + - Changed XMAP's minor_name from "xmap" to "mapxml" + - Changed VFS's minor_name from "quake3" to "pk3", more inline with VFSWAD now. + - Changed file/Load to file/Import on the menus + - When a shader (Q3/HL) is not found a message is displayed in the console + (only once for each shader that is not found). This is so the user can + quickly get a list of missing textures/shaders. + +26/3/2002 + ydnar + - initial q3map 2.0 source import + new tools/quake3/q3map2 directory + common/qfiles.h and common/surfaceflags.h modified + affects q3map 1.x too, bumped MAX_MAP_BRUSHSIDES to 0x40000 + will need to write the build scripts and compile on Linux too + SPoG + - Re-added dialog prompting user to convert/change-mode/abort when map BP mode + conflicts with project settings + - large entity/models update + +++ include/ientity.h 25 Mar 2002 11:37:54 -0000 + entity module + - interface cleanup + - common #defines for easy transition + +++ include/igl.h 25 Mar 2002 11:37:55 -0000 + opengl module + - Vertex Arrays support + +++ include/imodel.h 25 Mar 2002 11:37:57 -0000 + model module + - interface cleanup + +++ libs/mathlib.h 25 Mar 2002 11:37:59 -0000 + vector macros - cleanup + m4x4 + - documentation of matrix layout + - interface for utility functions for axis-angle and quaternion rotations + - interface for new utilities for specifically transforming points/normals + aabb + - interface for faster aabb-ray test without finding intersection point + - interface for utility to calculate an aabb to contain a transformed aabb + +++ libs/mathlib/bbox.c 25 Mar 2002 11:38:01 -0000 + - cleanup of use of qboolean + - implementation of fast aabb-ray-test + - implementation of aabb-for-transformed-aabb + +++ libs/mathlib/m4x4.c 25 Mar 2002 11:38:02 -0000 + - implementation of utility for rotation matrix from axis-angle/quaternion + - cleanup of implementation of matrix multiplication functions (optimise for in-order array traversal) + - implementation of new utilities for specifically transforming points/normals + +++ libs/mathlib/ray.c 25 Mar 2002 11:38:02 -0000 + - replace use of m4x4_transform_vec3 with new point/normal specific utils + +++ plugins/mapq3/plugin.cpp 25 Mar 2002 11:38:06 -0000 + - rename g_EntityTable using #define in ientity.h + +++ plugins/mapq3/plugin.h 25 Mar 2002 11:38:06 -0000 + - rename g_EntityTable using #define in ientity.h + +++ plugins/mapxml/xmlparse.cpp 25 Mar 2002 11:38:06 -0000 + - buffer-safe dtd path construction (without using string class, in case of unknown bugs) + +++ plugins/md3model/Conscript 25 Mar 2002 11:38:06 -0000 + - remove entity-module files from md3model conscript + +++ plugins/md3model/md3model.cpp 25 Mar 2002 11:38:07 -0000 + - implementation of generic quake-style-model class CModel + - implementation of CModel-derived md3/mdc classes + +++ plugins/md3model/md3model.dsp 25 Mar 2002 11:38:08 -0000 + - remove entity-module files from md3model dsp + +++ plugins/md3model/md3model.h 25 Mar 2002 11:38:08 -0000 + - interface for generic quake-style-model class CModel + - interface for CModel-derived md3/mdc classes + +++ plugins/md3model/md3surface.cpp 25 Mar 2002 11:38:09 -0000 + - implementation of generic quake-style-model class CSurface + - implementation of CSurface-derived md3/md2/mdl/mdc classes + +++ plugins/md3model/md3surface.h 25 Mar 2002 11:38:09 -0000 + - interface for generic quake-style-model class CSurface + - interface for CSurface-derived md3/md2/mdl/mdc classes + +++ plugins/md3model/plugin.cpp 25 Mar 2002 11:38:10 -0000 + - provide support to synapse for loading md3/mdc/mdl/md2 models, and mdl images + +++ plugins/md3model/plugin.h 25 Mar 2002 11:38:10 -0000 + - interface for loading md3/mdc/mdl/md2 models, and mdl images + +++ radiant/brush.cpp 25 Mar 2002 11:38:18 -0000 + - #ifdef remove Group/Brush-Patch-Epair related stuff + - const correctness for ValueForKey interface const change + - add bounding-box update for models in Brush_Build + - remove old brush parsing/writing stuff + - remove old eclass-model loading/displaying stuff + - enable vertex arrays on light drawing + - moved brush is-selected? utility to brush.cpp + +++ radiant/brush.h 25 Mar 2002 11:38:18 -0000 + - comment out interface for old brush parse/write stuff + - comment out interface for brush epair stuff + +++ radiant/brush_primit.cpp 25 Mar 2002 11:38:20 -0000 + - remove old brush-primitives parsing/writing stuff + +++ radiant/camwindow.cpp 25 Mar 2002 11:38:23 -0000 + - moved brush-bbox update for models to brush.cpp:Brush_Build + - bugfix for material colour setting when drawing models + +++ radiant/eclass.cpp 25 Mar 2002 11:38:24 -0000 + - removed old eclass-model checking/loading stuff + - added const checking for Eclass_ForName interface + +++ radiant/entity.cpp 25 Mar 2002 11:38:26 -0000 + - REMOVE THIS FILE + +++ radiant/entity.h 25 Mar 2002 11:38:26 -0000 + - REMOVE THIS FILE + +++ radiant/groupdialog.cpp 25 Mar 2002 11:38:29 -0000 + - change entity creation to not use Entity_Create (function was removed) + - commented groups stuff + +++ radiant/gtkdlgs.cpp 25 Mar 2002 11:38:36 -0000 + - const correctness for ValueForKey + +++ radiant/gtkmisc.cpp 25 Mar 2002 11:38:39 -0000 + - added filetype patterns for mdc/mdl/md2 + +++ radiant/main.cpp 25 Mar 2002 11:38:41 -0000 + - const correctness fixes + +++ radiant/mainframe.cpp 25 Mar 2002 11:38:59 -0000 + - change selection -> merge entity and selection -> separate from entity to go through mainframe class + - implementation of mainframe functions for selection -> merge entity and selection -> separate from entity + - made entity grouping and detail/structural settings undoable + - commented out old groups stuff + +++ radiant/mainframe.h 25 Mar 2002 11:39:01 -0000 + - interface for mainframe functions for selection -> merge entity and selection -> separate from entity + +++ radiant/map.cpp 25 Mar 2002 11:39:04 -0000 + - const correctness fixes + +++ radiant/pluginmanager.cpp 25 Mar 2002 11:39:08 -0000 + - removed model table + - stopped requesting model table from synapse + - request undo table from synapse + - commented out support for IEpairs stuff - NOTE: to be integrated with entity module + - fill interface table for opengl vertex array support + - fill interface table for undo + +++ radiant/pmesh.cpp 25 Mar 2002 11:39:18 -0000 + - cleanup patch cap and patch thicken to create entities using entity module interface (without Entity_Create) + - removed old patch parse/write stuff + - #ifdef'd out patch epair/groups stuff + +++ radiant/qe3.cpp 25 Mar 2002 11:39:21 -0000 + - const fixes + - buffer-safe dtd path construction (without using string class, in case of unknown bugs) + +++ radiant/qe3.h 25 Mar 2002 11:39:24 -0000 + - don't include entity.h, include ientity.h and forward-declare entity-table instead + - include imodel.h but don't forward declare model-table + - include iundo.h and forward-declare undo table + - comment out interface to old patch parse/write stuff + - comment out interface to old brush parse/write stuff + - comment out iepairs header include.. NOTE: to be integrated with entity module/interface + - include eclass interface (we don't have an eclass.h) + - declare interface for CreateEntityFromName (generic useful func) + - declare target/targetname utils interface (we don't have a targetname.h) + +++ radiant/select.cpp 25 Mar 2002 11:39:27 -0000 + - cleanup implementation of entity selection-grouping/ungrouping utlities + +++ radiant/select.h 25 Mar 2002 11:39:27 -0000 + - cleanup interface for entity selection-grouping/ungrouping utlities + +++ radiant/undo.cpp 25 Mar 2002 11:39:29 -0000 + - removed workaround for wierd entity_clone behaviour (changed in entity module) + - avoid using Entity_FreeEpairs (not exposed by entity module) + +++ radiant/xywindow.cpp 25 Mar 2002 11:39:35 -0000 + - const fixes + - cleanup implementation of CreateEntityFromName to be a usful generic utiliy function + - enable vertex arrays in XY_Draw + - enable undo for right-click dropping entities in XY window + TTimo + - various fixes to make the above compile on Linux, checkin to cvs + - fixing some win32 build stuff + + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=434 + fixed setSpecialLoad in .def code + +19/3/2002 + Gef + - Modified the fix for LoadImage to be more consistent with other code + - Applied Hydra's fix for empty alpha channel warnings & cleaned up indentations (tabs) in lbmlib.cpp + also added output of the tga type when a tga file fails to load + - Reverted my over complex fix (read; mess) for strtok_r to use strtok instead of manual tokenising + +17/3/2002 + Gef + - Fixed LoadImage API list not being incremented while trying to find image minors, result was + infinite loop when loading images that weren't of the first type (tga) + - Fixed cloning giving dtd errors. mapxml/xmlparse.cpp:ParseXMLStream() was using + g_FuncTable.m_pfnGetQERPath() as the dtds path... disabled validation until spog can check + that my fix is the right solution + - Added simple formatting to xmap file output so that each node has a new line for readability + +13/3/2002 + TTimo + - introduced API List managers + we deal with two types of APIManager now, the ones that matching all minors for a given major + and the ones that require a fixed list of minors + - converted the image loaders to go through a API list manager + - fixed various things in synapse (introduced more bugs?) + - fixed plugins, realized it was still broken + +12/3/2002 + Hydra & TTimo + - EClass_Create in the EClass manager _EClassManagerTable + - removed InitFromText from _EClassTable + +8/3/2002 + TTimo + - some commented out code cleanups + - added eclassfgd/ fgd.so module skeleton + loaded up in radiant core as an optional entity format + added eclass manager code to deal with the new format if present + this still loads .def, the actual .fgd code needs to be written now + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=433 + added a g_strDTDPath global + disabled DTD validation, broken on win32 + - Str copy constructor (const Str &) working correctly with a __strDup + +7/3/2002 + TTimo + - added verbosity in file accesses for CXMLPropertyBag + - more fixes to project lookup + - dropping dtds/ prefix, this is installation dependent + - removed ipluginentities.h, the plugin entities stuff was disabled long time ago already + - cleaned up some old commented out stuff + - proof of concept synapse builtin module: new class CSynapseClientBuiltin allows to have + modules builtin to the application (i.e. statically linked) + adding + include/ieclass.h (eclass loader API) + radiant/eclass_def.cpp (.def class loader, builtin) + radiant/eclass_def.h (.def loade, API public to the core) + + NOTE: radiant/eclass_def.cpp needs to be added to the win32 projects + - quickfix to project file loading ("/scripts/") + - introduced an EClass manager, hooked up the .def builtin module through it + (not yet possible to push new entity format modules, but .def reading is already fully synapsed) + +6/3/2002 + Gef + - Fixed a segfault when getting mUserPathPrefix in CGameDescription::CGameDescription() + - added preferences check for fixing target/name collisions + - fixed a logical error on my part, where setting g_qeglobals.m_strHomeGame in + CGameDescription constructor results in a value from the last file parsed. Moved it + to a more appropriate location, where it gets a value from the selected .game file. + SPoG + - changed g_strGameToolsPath to g_strAppPath in GetQERPath API + - fixed mapq3.dtd + - enabled DTD validation of xmap files + - added mapq3.dtd to setup scripts (not tested) + TTimo + - added OnActivated() to synapse clients, override to put some init code + - fixing default project path lookup and user project increment (again) + - fix to linux setup, no trailing slash in basegame items + (wolf.game and q3.game) + - removed old plugin/modules code, leaving only the synapse implementation + recoded image loading and Map_Import/Map_Export + still some temporary solutions and cleanup work to be done + removed plugin.cpp from the tree / build system + +5/3/2002 + SPoG + - TODO: add default project for wolf to WolfPack CVS module + - changed xml project file load to search for DTD "dtds/project.dtd" under radiant path + - fixed crash in mapq3 on trying to read uninitialised token ptr + - changed .map to be default map format for now + - changed runbsp to not hardcode -fs_basepath + - added -fs_basepath to quake3 default project + - added project.dtd to setup scripts and swapped quakev2.qe4 for default_project.proj (not tested) + +4/3/2002 + TTimo + - merged synapse2 branch back into trunk, checked Linux and win32 builds ok + - updated the .dsp to work with new libxml2 2.4.16 + - fixed broken enginepath guessing, and broken project path rotation / saving + +28/2/2002 + Gef + - Added extra checks for target/targetname collisions + - Find Brush dialog title correction (bugzilla #393) + +26/2/2002 + Gef + - Added Entity_Connect() to entity.cpp to avoid duplicating code + - Fixed target/targetname collisions - entities being cross-linked when copied + Bugzilla #385 : http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=385 + +16/2/2002 + Gef + - cleaned up the kyro gl_point workaround stuff + - taught ClipPoint's (clips & path points) how to draw themselves + +8/2/2002 + Gef + - Added mapxml.so to linux setup + - strip debug symbols option in setup + - removed g_qeglobals.m_strHomeMaps, writing it to project instead + fixes a bunch of re-broken path issues. Also uses fs_game now. + - Minor grid colour in QER Black & Green theme + - Save window's pos/size for all view types in MainFrame::OnDestroy + +--------------------------- on branch synapse2 +4/3/2002 + - modules don't show up in plugins menu, added a dump in console before entering interactive mode + - added compile time def for synapse verbosity + +3/3/2002 + - finished converting all the modules to synapse, disabled old ResolveInterface call + +24/2/2002 + - hooked TexTool into Radiant plugin menu through synapse + - added iplugin.h which I had forgotten earlier + - ported synapse code to compile and run on win32 + +19/2/2002 + - SYN_REQUIRE_ANY / multiple API manager code + can load multiple interfaces based on a matching pattern + converted TexTool to load that way + +18/2/2002 + - added iplugin.h with basic interface for plugins + +13/2/2002 + - synapse on modules currently disabled, + the basics of the code are working fine, need to look at multiple interfaces matches before going further + - started converting shaders, requires conversion of a lot more others + - image converted to synapse + - no longer using GUID in synapse, all done through *_MAJOR strings + HOWTO: convert a module to synapse: + configure it to link against synapse static lib + (+include path to STLPort required) + add #include "synapse.h" to the plugin header + declare the : public CSynapseClient in plugin header + implement it (listing provides and requires, implement the request code) + +12/2/2002 + - vfspk3 converted to synapse + +11/2/2002 + TODO: get rid of all WINAPI crap + - debugged the API dependencies solver to actually work + - added newer cons at the head of the tree + +10/2/2002 + TTimo + - added the basic code for solving API dependencies and requesting the various tables + - more diagnostic printing code fixes + - version checkings + - some more design work (libs/synapse/doc) + +9/2/2002 + TTimo + - some changes to the files layout, cleanup of the diagnostics printing + (stuff's mostly broken right now) + - reworked the complete Sys_Printf stuff to rely on va_list implementation + - include/isynapse.h declared useless and foxed without mercy + - added include/irefcount.h + +8/2/2002 + TTimo + - adding an experimental Anjuta project file to play around with + +7/2/2002 + TTimo + - various fixes to build on linux, listed a bunch of current issues + - fixing terrademo.map to remove broken mapobj~1 -> mapobjects + -- synapse2 branch -- + - propagate the code from old synapse branch to a new branch out of 1.3 tree + (builds and runs on linux, that's about it for now) + +--------------------------- end branch synapse2 + +7/2/2002 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=354 + moved all the preferences code to XML + +6/2/2002 + SPoG + - checked all paths conform to: unix dir separators + trailing separator + - changed file dialogs for load/save of maps to default to "mapspath" + - removed OpenDialog and SaveAsDialog, use file_dialog instead + - removed FileSystem paths stored in QEGlobals_t.. replaced by CGameDescription + - removed dependence on EnginePath from preferences, replaced by CGameDescription + - removed hardcoded g_get_home_dir calls for file dialogs + - added validation of project settings entry paths before they are set + +5/2/2002 + EvilTypeGuy + - moved filters.cpp related function declarations to filters.h + and added #include "filters.h" to brush.cpp, csg.cpp, main.cpp, + mainframe.cpp, map.cpp, select.cpp as not all files include + qe3.h and qe3.h is a rather monolithic header this seems to be + a cleaner solution per SPoG's suggestion...Fixes compilation. + + Gef + - contrib/plugins BOOL cleanup (uses qboolean now) fixes X header conflict + - cons update for mapxml + - SaveAsDialog() changed to match path's used in OpenDialog() + - removed radiant/xy.h - moved contents to qe3.h (FilterBrush declaration) + +4/2/2002 + SPoG + - changed QE_LoadProject and QE_SaveProject to load/save xml project file format + - changed request dialog for project files to loop until a valid file is found + - fixed memleaks in CGameDescription constructor for xmlGetProp + - added converting gametoolspath unix format when parsed from game file + + - fixed m4x4 lib to use column-major order (more compatible with opengl) + - added divergence parameter to ray-point intersection test + (now easier to select distant points in perspective views) + - cleaned up modelview/projection matrix manipulations in 2d/3d view + - cleaned up map modules / interface source files a bit + + - added ability to specify map module version when importing/exporting map + - cleaned up file dialog code, returned filename is static and in unix format + - save-as dialogs force a file extension depending on filetype selected + - added filetype manager to support registering custom file types + - fixed loading and cleaning engine path from radiant.ini correctly + +3/2/2002 + EvilTypeGuy + - fixed win32 compilation (userpathprefix is Linux specific) + + ETG & Powzer + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=308 + added preference to allow 'paint drag-select' brushes/faces in 3d camera view + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=389 + added preference to strafe camera foward/back in 3d view while freelook is active + + ETG & RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=388 + patch adds ability to strafe up/down/left right while freelook is active + +1/2/2002 + TTimo + - bumped to 1.3.1-nightly + +-- 1.2 stable branch branched here + + Gef & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=372 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=376 + appplied the patch, corrected the mapspath expansion stuff + TTimo + - linux nightly setup code + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=384 + hacked a corrective action in the nightly setup + + SPoG + - fixed creating region brushes that fill the entire grid for Save Region + +31/1/2002 + + Micheal Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=375 + syntax fix to q3map path_init.c + + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + patch 185 == 186 + tweaking to config stuff in linux setup + patch 187 + Ensures the games directory exists before trying to create a file there + patch 177 + Adds *.cf files & uses them. I think I have all the files in the right places now... maybe + (some additional fixes on top by me) + + ETG + quick fix to shader prefs load + +29/1/2002 + + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=345 + more detachable menus fixes + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=334 + fixes 'load shaders at startup' preference + + SPoG + - fixed misc_model "modelscale" and "modelscale_vec" support + + TTimo + - upgraded setup scripts to support nightly build + - last minute fix to the modelscale and modelscale_vec code (md3 module) + + ydnar + q3map 1.2.4-y2 + + New features: + - -nopatchfix argument. This disables lightmap patch fixes and makes a map suitable for lighting with -vlight. + - Degenerate patches are treated like broken brushes. They are ignored, warned about, and selected in Radiant if you ran with the -connect option (or from the BSP menu). This was what was causing the "0 valued axis" error some people were experiencing. + + New entity keys: + - "_lightmapscale" key for brush entities (worldspawn, func_*). This lets a mapper scale the lightmap samplesize per-entity. For large constructions, 2.0 or 3.0 is a fine value, and keeps BSP size down and compile times low. For those areas you want to have high-detail shadows, make a func_group and use a value of 0.25 or so. It will scale the samplesize value for the surface's shader (default 16) or the -samplesize argument. + - "modelscale" and "modelscale_vec" keys for misc_models (1.0 = default). This was for proper RTCW support and is available for Quake 3 maps as well. Lets you scale up map models in the world, getting around the MD3 size limitation. The next build of GtkRadiant has SPoG's code to support this in-editor so you can see what effect a scale has. + - Flare surfaces are now supressed from the BSP. They serve no purpose other than add to the vert & surfacecount in a BSP. These surfaces were created silently when a shader has "light 1" or "q3map_flareshader X." Use the new -flares switch when BSPing your map to have them emitted. + + Changes: + - GtkRadiant 1.2.4-nightly version increment. + - Full WolfSDK style lighting enabled with -game wolf, including lightJuniors. This includes linear lights by default (no angle attenuation) and support for the additional RTCW "fade" and "angle" keys, and spawnflag changes, including q3map_nondynamic on light entities. This may require maps being constructed for RTCW with the current toolset to change their light entities. Sorry. :) Note, Wolf-style lighting only works with -light, and not -vlight. + - Vertex light stitching now uses a near-ambient light check for dark vertexes as opposed to lower-than-average fixups. This preserves some shadow detail better while getting the buried verts lit properly. Comments encouraged. + - Surfaces' samplesize are now stored in the BSP. This change makes BSPs generated from this version incompatible with all other q3maps. The upside is that -samplesize N is no longer necessary on the -light or -vlight stage. This feature is necessary to support the "_lightmapscale" key. + - Additional PVS optimizations in lighting. + + Fixes: + - Will compile for RTCW properly (1.2.1-y12 didn't). + - No more sparklies where fog meets brush faces. They're split properly now. + - Crash bug in vlight fixed. + - Vertex light fixups/stitching is considerably faster. + - Vertex light fixups ONLY stitch faces with lightmaps. For pointlight surfaces you're on your own. + - Better snapping logic when merging nearly-coincident vertexes on complex brush windings. + - Bug where the .prt file had some bogus or nearly-borked portals. They're cleaned up like everything else now. + - A few stupid bugs in path initialization. Should work better. Also includes TTimo's fixes to my code so it would work properly on Linux. + - RR2DO2's PCX loading patch for alphamaps. This bug was manifesting itself in the form of offset or incorrect samples being used on terrain entities. + - A ton of other minor little fixes here and there. + +28/1/2002 + + TTimo + - win32 fixes + - 1.2.4-nightly + + djbob + - EClass_ForName fix if malformed name + +---- 1.2.3 linux released + + TTimo + - fixed BSP version depending on game mode in q3map + (home dir guessing is still fucked, have to fix before release) + - fixed q3map init_path.c home path bug on init + + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=369 + more fixes to texture paths in gensurf + +27/1/2002 + TTimo + - switching to v3 project file, forcing reload of template if non-v3 + need to distribute quakev3.qe4 in setups now (done for linux setup, will have to in win32) + - renamed Main to main in q3map init paths + - fixes the ~/. inits and init order in q3map + - added m_pfnPathForPluginName to the main function table, returns the directory a plugin is running from + used in bobtoolz / curry / pk3man to find various files + see also todo: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=368 + - some fixes to textures loading paths in curry + - linux setup copying correct content for curry (pk3 in wolf media) and bobtoolz (bt/ in plugins/) + - building 1.2.2 setups + + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=362 + gensurf fix + + djbob + - bobtoolz update + + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=361 + fixes a bug with the texture menu loading, now we see the non-shaderlist directories too + +26/1/2002 + Gef - Michael Schlueter - TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + applied several patches (to setup code and to the setup scripts) + modified makesdk.pl to update with more content + added an "enginepath" attribute to the game file, reworked the handling in editor + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=347 + took out the refresh command from the plugin menu + - more linux fixes: + bringing all the plugins to compile again on linux + polishing the setup code (all the right files in the right places) + - for linux release, bumping ver to 1.2.2 + win32 will have a 1.2.3-nightly after that + - added correct init of ~/.q3a or ~/.wolf + *nix systems have a 'prefix' attribute in the .game file to specify + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=359 + identified the mod compiling problems + applying back the old fs_basepath fs_game code to the BSP generation + + ydnar- TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=351 + cleaner path init code + it doesn't init for ~/.q3a and ~/.wolf paths yet + +25/1/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=352 + using the wrong matrix stack for XY_Draw caused stack overflow error + - texture_mode was set to an invalid enum in wireframe/flatshade mode + - changed plugin API to expect gamedir-relative texturenames + - fixed gensurf to create faces/patches with gamedir-relative textures + +24/1/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=322 + added modelscale key check to misc_model entity in md3/entity module + added angle key check to eclassmodel class in md3/entity module + fixed bugs in BP writing and reading in map module + TTimo (commited as SPoG) + - fixing permissions on cvsreport and doxygen stuff, upgraded dot + +23/1/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=336 + plugin API bugfix - fixes textures on stuff created by plugins + +---- 1.2.1 was released here + +22/1/2002 + Gef + - linux build fixes + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=325 + wrong file packaged in setup + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=327 + fix to PCX loading + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=298 + cut & paste bugfix + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=332 + update origin key on entities + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=333 + made fixedsize entities not scalable + +21/1/2002 + TTimo + - scanning in g_strAppPath/modules/ and plugins/ prior to g_strGameToolsPath + using the main path to put general plugins and modules + - fixed bobtoolz bug, init of epairs table was relying on wrong params + - fixed curry to compile again on 1.2 + - fixed pk3man to compile again on 1.2 + - updated IS setup: + installing the plugins with the core + installing the common modules in the core + - Compiling manual, more IS stuff, .xlink etc. + + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=315 + patches for improved multimonitor support (with some associated pref items) + + ydnar + - more q3map: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=324 + - radiosity fixes (proper handling of ambient light) + - polygonoffset fixes + - lightmaps on patches work better (normal calcs adjusted, planar patches are + box projected like brush sides) + - double vfs init in bsp stage removed (this needs to be tested on Linux) + - lighting is faster again + - a couple crash bugs resolved + - other tasty nibbles + +20/1/2002 + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=313 + detachable menus set as preference (in layout) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=255 + path prompt + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=307 + patch dialog names + ETG & RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=306 + fix 'Natural' texturing crash + ETG & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 + found out the problem, Wolf SP spawn works now + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 + fixed more problems with model loading vfsExtractRelativePath + prolly broke the linux build, just a matter of putting a bunch of #idfdef + - fixed an additionnal .pid lock situation, cleaning the global prefs on game .pid lock + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=301 + fixed md3 tris test selection bug + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=219 + fixed bobtoolz for 1.2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=318 + filter structural + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=305 + filter in viewmenu for lightgrid brushes (ydnar's q3map) + fixes image lib loading bugs + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=298 + copy/clone deselects the copied stuff + added a pref to deselect or not, and to nudge pasted stuff or not + +19/1/2002 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=311 + IEpair wrapper to access project entity from plugins + RR2DO2 + - missing IncRef in CShaderArray::AddSingle + TTimo + - game.xlink files in gametools path, is scanned to build items in the Help menu + (and the associated code) + +18/1/2002 + Gef / Michael Schlueter / TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + patches 133 and 138 applied, new setup code + +14/1/2002 + TTimo + - adding djbob write access for bobtoolz + +13/1/2002 + ydnar + - q3map code updates 1.2.1-y8 + new lightgrid surface flag feature + lightgrid shader and editor image for Wolf and Q3/TA: in the common .pk3 and in all common.shader + cvs remove setup/data/baseq3/common-q3r.pk3 (unused, we use common-spog.pk3) + TTimo + - updating setup to use mapq3 module instead of map (both Wolf and Q3 game packs) + (also checked the lightgrid option) + - fixed setup.pl bug for template gen from WorkDir/ + - correct spawning between SP and MP mapping mode + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + .pid check, console logging and prefs cleanup + Wolfen + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=294 + checked in updates to the manual links page and setup instructions + (i.e. new prefs dialog) + +12/1/2002 + Gef & Michael Schlueter + - bugs #295 and #279, new patches applied + EvilTypeGuy & djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=220 + patch selection crash + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=260 + Dense and Very Dense Cylinders have wrong number of rows + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=292 + latching patch toolbar settings + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 + win32 long/short pathname bugs reappearing, switching back to short paths for project settings + - removed obsolete radiant/vfs.cpp radiant/vfs.h + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 + using new .qe4 for Wolf, fixed stuff editor side (long path names and engine spawn) + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/showattachment.cgi?attach_id=118 + realloc bug in terrain + +11/1/2002 + SPoG + - unpatched bug #239, unintended duplication of brushes, patch #96 + Note: bug #239 now unresolved + EvilTypeGuy + - bug #295 fixes for compile under Linux + +10/1/2002 + SPoG + - fixed CEntityEclassModel referencing eclass after eclass has been deleted + SPoG - map-module branch + - new map module, provides current functionality, using new map interface + - cleaned up merging/creating of entity array used by map module + - implemented MemStream::printf(const char,...) - can't print strings larger than 1024 currently + - changed copy/paste to use the map module, via abstraction of FileStream/MemStream as DataStream + - fixed Save Region and Save Selected + - new xml map module "mapxml" + - cleaned up map.cpp + +6/1/2002 + TTimo + - removed m_bPak from pref dialogs (it was dead code) + +5/1/2002 + RR2DO2 + - q3map terrain blending fix for >5 layers + EvilTypeGuy + - fs_homepath patch on linux + Gef + - bug #279, linux setup, patch #102 + - bug #239, unintended duplication of brushes, patch #96 + TTimo + - added Wolf specific project settings dialog: + correct fs_game selection and combo names + added multiplayer / single player mapping mode selection + +4/1/2002 + TTimo + - adding -game wolf switch to q3map (-game quake3 works too, but it's the default anyway) + using different bsp version and different fs_basegame on wolf + - updated the setup/win32/setup.pl script to generate from a config file instead of hardcoded + (added corresponding q3.cf wolf.cf and all.cf config files) + - added a default Start Menu shortcut name (RR2DO2 special) + - diffing against Id's internal SOS source and merging in new stuff: + - bumped MAX_SURFACE_INFO to 4096 in shaders.c + - new terrain code (Jim Dose) + ParseTerrain() addition in terrain.c + Creates a mapDrawSurface_t from the terrain text + - VL_SurfaceRadiosity and VL_SurfaceRadiosity + MrElusive's vlight radiosity code + - speedups to vis.c and visflow.c (MrElusive) + +3/1/2002 + TTimo + - merge gameselect branch back into trunk + the IS setup scripts have been updated for the new paths layout + developement environment needs to be updated to copy binaries to the right places for debug + it is recommended to run a 1.2.1 setup on win32 prior to compile and install debug bins + - updated the setup to be more templated for inclusion/non inclusion of game packs on demand + + - propagating recent fixes to Alpha into the trunk + based on diffing between Merge-1_1_1 and Merge-1_1_2: + ===================================================================== + 13/11/2001 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=244 + reverted again the shader manual and tcMod docs + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=214 + patched aselib.c, was calling strstr badly (relative path extraction) + + 12/11/2001 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=241 + applied patch, will release in next nightly + + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=254 + patch for safe_malloc + + TTimo + - fixing STLPort config checks and XML config (CHAR -> xmlChar) + - added safe_malloc_info and safe_malloc in the common/ dir + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=179 + added XML stream version checking between Radiant and q3map + ======================================================================== + also, manual merge of docs/manual and setup media + this merge work is related to bug #280 too: + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=280 + + ydnar + - new q3map, radiosity and bug fixes, code merged in with the trunk version + (TODO: add more detailed changes log) + + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=274 + broken auto caulking fix + + EvilTypeGyu & LordHavoc + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=207 + (two new files, project settings updated) + +2/1/2002 + TTimo - branch gameselect + - copying over the linux setup binaries (setup, uninstall, setup.gtk) + from Alpha branch. Those have the ability to prompt destination path + per component. + Gef - branch gameselect + - patch 101 for bug 279 + .game files generation by the setup, makesdk.sh and postinstall.sh fixups + +1/1/2002 + Gef - branch gameselect + - linux source fix http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + (we use PATH_MAX as the cross platform define instead of MAX_PATH which only works on win32) + + TTimo - branch gameselect + - cleanup and homogeneisation of the paths for prefs storage + m_global_rc_path: + win32: g_strAppPath + linux: ~/.radiant// + m_rc_path: + win32: g_strGameToolsPath + linux: ~/.radiant// + so that global.pref goes in ~/.radiant//global.pref + and radiant.ini ~/.radiant///radiant.ini + +27/12/2001 + TTimo - branch gameselect + - global prefs file (global.pref), XML based in core directory + stores game selection setting + stores autoload setting + - dropping 'gameid' from .game file, gonna use a 'gamefile' in global prefs instead + (and the .game file name .. thks Gef) + - TODO: radiant.log stuff in global prefs? + +21/12/2001 + TTimo - branch gameselect + - more Wolf setup tweaking for an experimental build release: + quakev2.qe4 project template file + using a 'gameid' attribute in the game file to select hardcoded features in the editor binary + 'basegame' node for lookup of the default project file + 'engine' node for engine path + - added experimental Wolf game pack to IS + - added setup/win32/HOWTO with extensive information about the procedure to + add new game packs + - reading the 'name' attribute in the game node for game selection dialog + - TODO: pid files to make safe startup? + The .pid stuff should be happening after game selection, since it covers game-specific + preference settings. + - TODO: console logging pref should be a global pref, goes with game autoload? + +17/12/2001 + TTimo - branch gameselect + - updating the setup script for experimental 1.2.0 setup: + + merged some of the docs back into trunk (Radiant manual, some TA docs) + will need to perform a complete diffing between Alpha and trunk about docs/manual at some point + merged bitmaps from Alpha too + + added the Q3 modules (image, map, md3model, shaders, vfspk3) to Q3 game pack in setup + + generating per-game config file q3.game in OnMoved (IS setup) + will need equivalent with linux setup of course + + various other generic fixes to the setup code + + - multiple games support, list of changes, and TODO: + NOTE: this is on a 'gameselect' branch for now + Doxygen documentation should be at http://zerowing.idsoftware.com/doxygen + for this branch too. + + The installation procedure has changed. The win32 installer is partly ready, linux installer + will need to be modified too. The editor binary and the Gtk DLLs are installed in a common + location, i.e. 'C:\Program Files\GtkRadiant' typically. The game specific binaries and modules + go in the same location as usual, for instance 'C:\Program Files\Quake III Arena\GtkRadiant\' + (and also 'C:\Program Files\Quake III Arena\GtkRadiant\modules' 'C:\<..>\plugins') + + The environment variables used by the build system (VC6 project files) have been adapted: + $(QUAKE3RADIANTDIR) is still used + $(CORERADIANTDIR) is used for the main editor location + + When editor starts, it looks for games/*.game under g_strAppPath and prompts the user for a game + Once game is selected, parameters are used for regular startup. + You need to write your own q3.game for now, it will be generated by the setup procedure + my C:\Program Files\GtkRadiant\games\q3.game looks like that: + + + + + + given that, the editor does a complete startup, and the basics are here for multiple games + + - precise changes: + + g_strToolsPath renamed to g_strGameToolsPath + most of former g_strAppPath uses g_strGameToolsPath + the name change was also meant for homogeneity with DIR_GAMETOOLS_* variables we use in the setups + g_strAppPath still used, points to the main installation path + + added the game selection code in CPrefsDlg::Init + using several classes and a dialog box, parsing XML files + + - TODO: + + the console 'Radiant.log' doesn't catch the game selection stuff as it is now + initialize it to the main install, without the game setting + (console logging is a debugging tool anyway, no reason it should go to the proper game folder + each time) + + the 'preferences reset/cleanup' code is probably broken, specially when used with the .pid checking + since we check for .pid even before we know where the GameTools path is + + on linux, we need to sanitize the ~/.q3a dir usage. Switch to ~/.radiant, use the version tag + to maintain things independant, and use the game name to isolate per-game settings? + ~/.radiant/1.2.0-nightly/quake3/radiant.ini (.pid, .log) + ~/.radiant/1.2.0-nightly/wolf/.. + + also, when looking for those files (.ini mostly), win32 stores them in a main installation, and + linux has them in ~/.radiant/.. (which is the read/write area). This should be homogenized? + Maybe by adding a 'Main' to the readonly path and a new variable with 'RW', pointing to 'Main' on + win32 and to ~/.radiant on linux + +11/12/2001 + TTimo + - replaced setup/win32/setup.sh by setup/win32/setup.pl + same functionality level + abiliy to generate back a template from a work version + - major rework on the IS scripts, basics of multiple games support installer + clean seperation between editor core and game pack + design doc and analysis of custom setup generation, setup script UI requierements + see setup/win32/TODO for more details + +10/12/2001 + TTimo + - new generation of InstallShield setup + using a template/ directory instead of a .zip file + requires rewrite of the processing script + allows easier maintenance of the IS script + +23/11/2001 + TTimo + - yet another update to cvsreport script, + catch the branch and forward the info to user commands too + able to build doxygen for several branches selectively now: + http://zerowing.idsoftware.com/doxygen + +22/11/2001 + TTimo + - new cvsreport script, should send explicit diff of the CHANGES file now + +03/12/2001 + TTimo - md3-module branch + - validated the fixes and the build on linux, ready to merge in trunk + SPoG - md3-module branch + - changed function naming conventions in mathlib for m4x4, ray, bbox, to be consistent + - fixed bug in m4x4_invert + +29/11/2001 + TTimo - md3-module branch + - flagged all new mathlib functions that need a name change or an argument order change + also added various \todo to point out inconsistencies + +28/11/2001 + TTimo - md3-module branch + - updated linux build + - fixed CEntityMiscModel and CEntityEclassModel destructors + (any destructor should be virtual) + +27/11/2001 + Spog - md3-module branch + - stopped texturewindow showing shaders without the "textures/" path + - made md3 module functionally identical to current radiant md3 code + +22/11/2001 + TTimo - md3-module branch + - fixes to the core for linux build + - model.so module builds on linux + - added plugins/md3model/doc/md3-design.txt + - several doxy-friendly \todo chunks about the module model + + Spog - md3-module branch + - fixed aabb_add_aabb() algorithm wasn't very reliable + - added VectorMid, VectorNegative and CrossProduct macros to mathlib + - added bbox_intersect_plane() + +21/11/2001 + Spog & TTimo - md3-module branch + - initial code from Spog following a preparatory design work + merging in as new 'md3-module' branch + geomlib code merged into mathlib + some reorganisation of the source layout and cleanup (more stuff in imodel.h, less in qertypes.h) + + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=261 + fix applied + +20/23/11/2001 + TTimo + - yet another update to cvsreport script, + catch the branch and forward the info to user commands too + able to build doxygen for several branches selectively now: + http://zerowing.idsoftware.com/doxygen + +22/11/2001 + TTimo + - new cvsreport script, should send explicit diff of the CHANGES file now + +11/2001 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=253 + additional fixes + TTimo + - renamed tools/quake3/common/threads.h to qthreads.h + avoids a collision with system headers + +19/11/2001 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=251 + Fixed "Move into worldspawn" deleting entities with only one brush + Fixed Brush_Move using texture lock on fixedsize entity brushes + Fixed Textures > Texture Lock > Rotations toggle checkbox + +16/11/2001 + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=247 + applied patch 77, using a notebook layout for preferences dialog + also patched in some preferences saving that had been forgotten + (such as invert mouse in freelook) + + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=253 + patch 84 + additional modifs, bug still open + +15/11/2001 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 + rewritten rendering pipeline for cam window - fixes some hacks, improves speed, + makes rendering modes more consistent with each other + +07/11/2001 + TTimo + - more IMAP interface, adding a blind data void *pData to entity_t + more info about it and why it's done is in map.cpp, should be a small base for next additions to the editor + +31/10/2001 + TTimo + - using IDataStream in map module, moved back some of the module code into the trunk + +30/10/2001 + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=245 + applied patch 76 + + TTimo + - renaming istream.h to idatastream.h, this had nasty conflicts with OS includes + already had to IStream -> IDataStream some time ago anyway + +27/10/2001 + TTimo + - updated cvsreport, testing new ver + - added a static version of texdef (no memory alloc on the texture name) + unused for now, was just experimental + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=245 + applied patch 75 + +26/01/2001 + TTimo + - various updates: + new GtkSDK precompiled binaries + updated libxml2 package (to 2.4.3) + updated STLPort (to 4.5) + now compiling with STLPort and threading (since we are using threading throughout the app) + - exposing the data stream API to the modules, renamed some stuff on the way + need to update the map module to use it now + - cleanup on qtexture_t definition + guarding and disabling chunks of the surface plugin code behind DO_SURFACEPLUGIN + (see earlier patch on plugin entities) + +25/01/2001 + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=202 + applied patch commenting out plugin entities code + might come back in 1.2 under another implementation + the code is still there, only commented out for now + +17/01/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=93 + checking in doxygen content, setting up generation on zerowing + auto generation on zerowing upon a commit: + http://zerowing.idsoftware.com/doxygen + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=231 + checked in the patch + - switching to a new cvs commit script + +14/10/2001 + TTimo + - libs/mathlib library + unifies mathlib code squattered all over the tree + mainly a merge of tools math code and radiant/mathlib.cpp + C implementation, using an extern "C" construct for use from C++ + need to check on linux, win32 builds ok + extracted qboolean code into libs/bytebool.h on the way + +11/10/2001 + TTimo + merged TmpMerge-1_1_1 branch back in the trunk, the update process from Alpha 1.1.1 is done + + TTimo - branch TmpMerge-1_1_1 + looking through all remaining .rej files and applying the failed patches accordingly + bobtoolz is broken, but it's not due to the merge + the plugin API is different and some things need updated + (disabled bobtoolz build in contrib/Construct for now) + same for gensurf + same for prtview + same for textool + setup: replaced the existing stuff with 1.1.1 code + fixed various things for win32 build, checked correct CRT lib config + +10/10/2001 + TTimo - branch TmpMerge-1_1_1 + building modules, going through all the .rej + merging radiant/missing.h and modules/shaders/missing.h into a single one, moving to libs/ + exposing BuildShaderList PreloadShaders in _QERAppShadersTable + have to review all the remaining .rej to finalize the merge now + +04/10/2001 + TTimo - branch TmpMerge-1_1_1 + using this branch as temporary location for merge process + copied over new binary files. mostly .dsp (prolly broken) + and setup/linux/setup.data stuff + +25/08/2001 + TTimo + map module successfully loaded and saved q3dm1, the saved file was then loaded back into 1.1-TA without problems + rebuilt and checked on win32 + merged IMap back in trunk, fixed some memory conflicts on win32 + Took me a lot more time than I would have liked to, but there's a script tied to the CVS server now, which will post on this list a diff of the docs/developer/CHANGES file whenever it gets updated. This will probably be very handy for me since I'll only have to put update information in the CHANGES file instead of having to post on the list too. + The script is likely to be a bit laggy, or miss some features (for instance I'd like to extract the branch name .. anyone know how I can get the branch name (Alpha/IMap/HEAD) from the version number? + PS: I can email this script to anyone who would like to have a look + +22/08/2001 + TTimo + did more work on map module, one big chunk of work left: the core should broadcast interface requests to plugins + when it doesn't know how to do it by itself.. + Gef + new doxygen patch, generates output from core (libs/ include/ and radiant/) + +21/08/2001 + TTimo + removed Makefile, use cons damnit! + +18/08/2001 + Gef + automated documentation via doxygen, new scripts and content + +18/08/2001 + EvilTypeGuy + patch for CHAR to xmlChar conversion (xml2 consistency) + +09/08/2001 + TTimo + the map module starts to look like something, cleaned up the interface stuff + started moving the actual code out in the module and removing it from the core + lots of issues raised on the way, some structures to export, and the macro scheme to access API functions more easily + it compiles right now, but won't run because it's missing a lot of things .. the process simply happens to be "under way" + +04/08/2001 + TTimo + patched more path code, to look for stuff in "bitmaps/" and "modules/" instead of "tools/bitmaps" and "tools/modules" + modified the Construct files accordingly + merged in radiant/ishaders.cpp diff into plugins/shaders/shaders.cpp (PreloadShaders) + merged in radiant/lbmlib.cpp diff into plugins/images/lbmlib.cpp (Sys_FPrintf) + checked the .rej and patched a few remaining things + NOTE + the diffs are space/tab sensisitive, and we used the "beautify source" a bunch of times, so it's a bit fucked now + next time, generate the diffs not space sensitive.. + TODO + map loading is fucked, "textures/" prefix issue? + +27/07/2001 + TTimo + merging recent changes from Alpha branch into the Trunk + this could not be done with a regular cvs merge because we already did a cvs merge of Alpha into trunk some time ago + manually built a diff between the current Alpha (now tagged Merge-1_1-TA_1-nightly) + and the Alpha we had right after the former cvs merge: -r Alpha -D 2000-05-28 + binary files ignored in the diff, only going for source stuff + built with diff -Nru Reference/ Current/ + then patch -p1 < patchfile + next, started rebuilding: + big manual updates were in vfs.cpp and texwindow.cpp + cleaned up some VFS stuff .. it had an absurd QERAppFileSystem / QERPlugFileSystem scheme + TODO: + the ISSetup has not been copied over from Alpha + OK check the Construct files + OK radiant/ishaders.cpp no longer exists .. apply the patch on the shader module + OK radiant/lbmlib.cpp no longer exists .. in the image code? + OK look at the *.rej files + +03/10/2001 + TTimo + - adding a pref to select patches by BBox, fixes + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=212 + +02/10/2001 + TTimo + - reverting Spog patch 67 to bug #209, starting from scratch + applied again, with HasModel returning NULL safe checks + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=211 + fixed overlays drawing (XY and Cam) + +01/10/2001 + TTimo + - building and distributing q3data (.ase -> .md3 conversion utility) + updated q3data to show main GtkRadiant version information and build date + - generating a new GUID per-setup + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=206 + Gef + - updated credits.html and links.htm, look much better + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=200 + - update Z-checker view on camera up and down + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=199 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=209 + Fixed QERApp_ReloadShaders.. PreloadShaders needs a BuildShaderList call + Fixed Flush & Reload Shaders for md3 models + +25/09/2001 + Gef / djbob + - several patches to the key handling code, for linux specific issues and sticky keys + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=191 + TTimo + - fixing q3map bug, not processing the argv correctly + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=192 + - fixed ToggleCubicClip shortcut Ctrl+\ (win32 Gtk source patch) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=15 + +18/09/2001 + RR2DO2 + - discreet movement for camera (prefs setting) + fixes texture window bug + latching view layout changes until restart + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + djbob + - added back "view > show > show angles" in view filters + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=188 + +15/09/2001 + G_Dewan + - fixed problems with q3map when not using -connect + SPoG + - fixed q3map texture projection for brushes belonging to entities with local origin + - added SafeOpenRead() check, terminating map->bsp stage if .map file cannot be read + +13/09/2001 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=181 + fixing key handling bug (key pressed with repetition was not properly catched) + TTimo + - added new Radiant manual elements (GtkRad section) to the win32 full setup + - reverting version to nightly, going back to nightly / RC delayed + - patched linux setup, now prompting for component path only if at least + one of the options is checked. Still need to handle Cancel in dialog though. + +12/09/2001 + TTimo + - more fixes to linux script, copy plugins right now + +10/09/2001 + TTimo + - patched contrib plugins, using seperate build scheme + - fixed textool issues, compiles again + +09/09/2001 + TTimo + - sub-menu cascading + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=178 + - udpated the Q3Radiant manual with some new GtkRadiant stuff + - updated the FAQ with 1.1.1 known issues + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=174 + applied all the patches + +07/09/2001 + SPoG + - fixed qer_editorimages outside "textures/" being ignored + - stopped q3map_lightimage being used to set shader image dimensions + - changed bsp menu to remove "bsp_", changed menu text in default .qe4 + - fixed patch LOD update - now always occurs on both cam/xy draw + + djbob + - dynamic DEpair class strings in bobtoolz + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=171 + - decrease VESF verbosity + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=169 + + TTimo + - fixed Gtk keyboard bug Ctrl + [ and ] + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=15 + +06/09/2001 + TTimo + - merged FullSetup branch into the trunk, we have basic functionality + for a full linux setup (components prompting for path) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=158 + + Gef + - CapDialog source cleanup patch (got rid of the namespace) + + RR2DO2 + - more camera fixes, wheel mouse and texture drag drop + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + - additionnal patch to optimize camera refreshes + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + + djbob + - remember last key/pair in entity dialog for easy "apply again" + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=18 + - re-enabled texture name edit on PI + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=18 + +04/09/2001 + djbob + - left pane on status bar + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=166 + + RR2DO2 + - cam window cursor fix + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + + TTimo (FullSetup branch) + patched setupdb and setup to allow for path prompt in install + modified the setup script scheme to go towards a solution similar to what + we do under win32 (build a full and nightly build) + the binaries in setup.data/ (setup and setup.gtk) still need to be updated + with proper binaries built from setup and setupdb cvs source + +03/09/2001 + TTimo + - wheel mouse in texture window on win32 (with a pref setting for increment) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=160 + - not saving prefs while exit on sleep + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=157 + - fixed select all of type (changed behaviour to something that makes more sense?) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=79 + + Gef + - final tweaks to wheel mouse scrolling (locks texwin scrolling and scrollbar update) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=160 + - prevent multiple color selection dialog for light entity + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=165 + + djbob & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=137 + window positions + applied patch to store SI and PI positions + storing entity info and map info positions + reworked the overall position load/save scheme + added an enum for the view style, makes things more readable + +02/09/2001 + TTimo + - added/cleanup ToggleFreeMode to camwindow.cpp .. stopped working on cam stuff since RR2DO2 has another patch in preparation + Gef + - patched Conscript to accept 'cons -- release' on the command line to performa a release build + djbob + - added patch splitting to bobtoolz + - fix to patch control points bug in camera + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=159 + - handling of NWUV errors in q3map + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=147 + RR2DO2 + - new patch for camera control + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + +01/09/2001 + SPoG + - Fixed .wal texture support, searches for .wal extension if .tga and .jpg fail + NOTE: requires a "pics/colormap.pcx" file to obtain a palette from + - Added variable default texture scale in preferences (ini key: TextureDefaultScale) + +01/09/2001 + djbob + - fixed surface inspector "fit" bug + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=161 + - single face deselection on a selected brush + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=153 + +31/08/2001 + TTimo + - Moved *.def files to scripts/ in win32 setup + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=116 + - Applied patch for background position on widgets (win32) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=108 + - Checked C runtime lib configs + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=135 + - updating docs (add to CVS, update setups etc.) + added TA teams manual to the full setup + uploaded on web site + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=97 + - changed versioning to 1.1.1-nightly, next release will be 1.1.1 + (the -TA part was removed, since we now support ALL mods) + - removed AFX_MANAGE_STATE calls, this is old MFC related code for win32 + - moved texdef_t::name to private, added const char * GetName() + (doesn't fix explosion on exit for win32 debug builds though) + - fixed DoTextEdit / EditPad b0rkage (due to recent Q_Exec changes) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=134 + - added targetShaderName documentation to shader manual + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=102 + - added "notta" and "notq3a" documentation to the TA Mapping manual + - fixed entities.def on shootable doors and buttons + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=101 + + djbob + - added MAX_POINT_ON_WINDING error handling + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=129 + - bobtoolz update + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=123 + + RR2DO2 + - noclip-type camera movement + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + +30/08/2001 + TTimo + - Fixed CHANGES commit script bug + - Fixed -onlyents bug in q3map / origin brushes + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=92 + - added mouse wheel to the texture window + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=81 + SPoG + - Fixed texture rotation not updating correctly on patches + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=136 + - Fixed long delay on toggling cubic clip by removing call to Map_BuildBrushData() + - Added note in entities.def for default worldspawn _color value + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=105 + - Added IncRef and DecRef to Patch_FindReplaceTexture() + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=95 + - Fixed misc_model updating on changing model key or with invalid model + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=138 + +30/08/2001 + SPoG + - Added negative vertical scale on SET and FIT in patch/surface inspector + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=65 + +27/08/2001 + Gef + - running makeversion.sh from Conscript + - a bunch of patches to cleanup compile warnings on linux + - added VectorSnap on float grid + - IWindowListener modified to pass float values for X Y in click messages + TTimo + - fixed crash when adding a misc_model if Gtk dialog is on + djbob + - md3 filtering for misc_model dialog + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=76 + +26/08/2001 + Gef + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=152 + Kyro II GL drivers bug + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=150 + using a scrolling textbox for GL extensions in the about list + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=150 + func_group toggle in cap dialog + + TTimo + fixed running BSP commands on linux + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=133 + VFS init on linux + +around 15/08/2001 + TTimo + quakecon fixes: switched to long filenames in project and misc_model dialogs, + removed all occurences of win32 conversion to old 8.3 filenames + NOTE: this might raise some bugs and issues, but it's the way to go for the future, + already fixes more issues than it creates + +03/08/2001 + djbob + fixed Radiant hijacks win32 copy/paste + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=36 + +--- merged Alpha into Trunk, see Merge-1_1-TA-nightly tag + +25/07/2001 + TTimo + fixed project dialog to behave right + proper .def scanning + fixed shader loading with VFS and mod stuff + added a local to texwindow.cpp GSList *l_shaderfiles + holds the names of the active .shader files + modified q3map to read "fs_basepath" and "fs_game" + TODO: + .def files in the media need to move to /scripts/ + rename entities-TA.def to entities-ta.def + +24/07/2001 + TTimo + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=116 + updated cmdlib's Q_Exec to be more widely used through Radiant (during watchbsp.cpp cleanup) + patching in MarsMattel's code for mod support, and started fixing: + added m_strFSBasePath m_strFSMain m_strFSGame to g_qeglobals to match Q3's filesystem + reworked the project file dialog + changed the way we load and initialize eclass and shaders to work with mod code + updated VFS initialisation code, cleaner and better console output + the "game" key in the project file is no longer relevant, only "dir" is + (if "dir" is not present, then no mod support, vanilla Q3) + changed the loading of the .def files to scan in scripts/, you might need to move your entites.def to use + TODO: + cleanup .. (search where "basepath" is used for instance) + using fs_game when calling q3map + fixing project dialog to behave right + shader loading using VFS functions (seems to work again but I'm not sure) + win32 ver. might be slightly broken + .def scanning, don't scan ALL .def + +23/07/2001 + TTimo + added version and build info to the log file + current timestamp + +22/07/2001 + SPoG + fixed selection of misc_model when viewed as a bounding box + +20/07/2001 + TTimo + cons script for q3map building + added general GtkRadiant versioning (version.h) to q3map + nightly setup on linux: + using the right install path (with GtkRadiant's version name) + cleaned up options to only the stuff relevant to nightly + fixed Radiant and core binaries path in setup + added some template processing of setup.xml (similar to what is being done on win32) + +19/07/2001 + TTimo + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=112 + applied ^Fishman's path + inclusion of version.h and aboutmsg.h moved to qe3.h + changed base path location process (in most cases it will prompt) + fixed the path construction to initialize according to the new layout + +16/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=115 + fixed wake up crash on linux + +12/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=117 + fixed + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=120 + fixed installer bug on win98, was a problem with cygwin config + +11/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=64 + cleanup and fixed + +06/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=100 + can't locate the "textures: in use" problem, has been fixed already? + now selecting the right entity in the list, had to go around an inifinite recursion problem + (i.e. selection message in the entity class list causes UpdateSel recursion) + +04/07/2001 + TTimo + - added botclip to missionpack/common.shader + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=114 + +01/07/2001 + TTimo + - backported cons scripts to Alpha branch. Type 'cons' at the head to build + regular makefiles should soon be outdated.. + +30/06/2001 + TTimo + - updated the IS script (Gtk changes and and BACK problem) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=68 + - bunch of fixed to make it build on win32 against new STLPort + http://zerowing.idsoftware.com/STLPort/ + using an STLPort configured locally in GtkRadiant (with stl_config.h, new file) + +29/06/2001 + TTimo + - fixed GDI leak affecting text widgets, specially the console and the entity inspector + +18/06/2001 + TTimo + - more win32 project file cleanup, removing libs/libxml2 from the tree + - importing back "gtkr_list.h" from 1.2, made Alpha branch STLport compliant too + http://www.qeradiant.com/faq/fom-serve/cache/174.html + +30/05/2001 + TTimo + - added libxml2 as an external dependency. libxml2 should be installed as a seperate + directory on win32. dynamic linking now instead of static previously. + - cleaned up q3map win32 project file, removed opengl dependency + (the drawflag command line is inoperant now .. I don't think it was used anyway?) + +26/07/2001 + TTimo + - checking in Gef's doxygen files + +14/06/2001 + TTimo + - added .dsp for map module on win32 + - fixed several issues with module loading, stability of the debug and release builds + http://www.qeradiant.com/faq/index.cgi?file=197 + +12/06/2001 + TTimo + - got rid of of SysMsg thing, using SysPrintf and SysFPrintf now + - got rid of InfoMsg functions (can't remember what it was) + - changed the m_pfnError in the plugin API to match Radiant's (void)(char *, ...) + - changed Warning to Sys_Warning, as #define to Sys_FPrintf(SYS_WRN, + +11/06/2001 + TTimo + - new map module, in plugins/map, required for execution (linux Makefiles written, win32 needs to be) + this is using the imap.h interface + - added Sys_ functions to the main table (Sys_BeginWait Sys_EndWait) + - got rid of AFX_MANAGE_STATE macros .. those are crappy MFC remnants + - reverted Spog's changes to the console logging switches to their original behaviour + - removed m_fVersion from the func table .. we use the size of the table to do the checks + XMLmap merge from 31/11/2000: + - started moving the map loading code into a module + +08/06/2001 + TTimo + - updates to the plugin loading code, verbose a bit more, and more interesting information + +05/06/2001 + TTimo + - some fixes to vfspk3 string code, using the proper str implementation + http://www.qeradiant.com/faq/index.cgi?file=175 + - added and tweaked various cons build files, Radiant 1.2 core and required Q3 modules are building now + - fixes to image module + +04/06/2001 + TTimo + - started using cons for the linux (*NIX) build system + see http://www.dsmit.com/cons/ + + SPoG + - Fixed drawing too much coordinate text in XY window + - Changed grid line drawing in XY window to be more consistent + - Fixed clipper-tool-uses-caulk to only apply common/caulk to solid opaque brushes + (shaders.dll now parses some new surfaceparms) + - Changed shader parsing to pass over layer information in shaders, + rather than parsing and ignoring it all + - Changed misc_model selection to ignore back-facing triangles + - Added axes to show the grid origin in XY window + - Changed misc_model rendering and selection to minimise the number of extra + transformation calculations + - Fixed texture directory listing to allocate and free memory correctly using vfs + - Added qglDeleteTextures() to plugin GL API - fixes crash + - Fixed image.dll to correctly allocate and free memory for jpgs + - Moved modules to /modules from /plugins, updated win32 project files. + (linux/mac makefiles will need to be updated) + - Changed console logging toggle in main() to automatically disable logging after any successful startup + - Changed console logging to only activate when a Release build finds a .pid file + - Changed "found .pid" and "logging console output" messageboxes to give a clearer message + - Added vfsFreeFile - which is kinda redundant if we use g_free and g_malloc for everything + +31/05/2001 + TTimo + - cleanup of the win32 project file and C++ options.\ + Turned off exception handling, changed some code generation options and fixed + some threaded/non-threaded linking problems + - STL in GtkRadiant or a plugin must now use STLPort + a custom configured version of STLPort is available at http://zerowing.idsoftware.com/STLPort + still need to write some guidelines about it + bascially, we are using STL: iostreams disabled, no namespace, no threading, no exceptions + +30/05/2001 + TTimo + - removed libxml2 from tree, use a seperate libxml2/ directory next to GtkRadiant/ for win32 + libxml2 will be distributed seperately as an archive based on official release (same as win32 Gtk SDK) + (check on zerowing for the latest archive) + libxml2 is now used as dynamic shared object on win32, makes sense since many module will rely on it + - cleaned q3map, removed GL dependencies + - updated Debug and Release builds on win32, it compiles and runs now + +28/05/2001 + Spog + - moved vfsExtractRelativePath and vfsGetFullPath to vfs.cpp in vfspk3, + added vfsExtractRelativePath and vfsGetFullPath to IFileSystem. Copied BuildShortPathName() from qe3.cpp to vfs.cpp as a Temp fix. + - Changed Error() calls in bmp.cpp as a Temp fix, they relied on definition of Error in qe3.cpp. Should probably use Error() from cmdlib instead. + - Fixed unresolved external in jpgload.obj - merged bufsize argument into jpeg_stdio_src from Alpha branch... assuming Alpha is the newer version. + - Changed GtkWidget* to void* in image.cpp.. this could be cleaned up more.. i only did enough to make it compile. + - Added jpeg.cpp to msvc project for image.dll.. changed declaraction of LoadJPG() in image.cpp to an extern... is this correct? + - TODO: update vfs.cpp, vfspak.cpp and vfs.h in plugins/vfspak + - fixed unresolved external load_pixmap() - merged load_pixmap declaration from Alpha branch into gtkmisc.cpp + - moved vfsBasePromptPath() to qe3.cpp as a Temp fix - not currently required in vfs module, but it will be in future. + - two calls to free() in texwindow.cpp freeing memory allocated by vfs module, causing debug assert errors - changed them to g_free() + - TODO: Delete vfs.cpp and vfs.h from /radiant + TTimo + - additional fixes after Spog's merge (linux version), removed messaging.cpp messaging.h (name changed to ui.h ui.cpp) + updated linux makefile accordingly + - merge of Alpha version into trunk (massive amount of changes and merges, not detailed) + +25/05/2001 + TTimo (Alpha branch) + - merged the recent MacOS branch back into Alpha + this makes a potential source codebase for a MacOS release + +24/05/2001 + TTimo (Alpha branch) + - patching Spog's recent changes to fix linux build + using DBL_MAX and FLT_MAX from for float and double max + +23/05/2001 + TTimo (Alpha branch) + - testing Spog's write access + + SPoG (Alpha branch) + - Added variable LOD for PatchMeshes based on curvature + - Added LOD-matching to eliminate gaps between patches with mismatched LOD + - Fixed texture shift/scale on LOD'd PatchMeshes + - Added opengl lighting (three infinite light sources) + - Added dynamically calculating vertex normals for PatchMeshes, for gl lighting + - Added decoding/transforming md3 vertex normals for gl lighting + - Changed camera drawing routine to minimise gl state changes + - Removed Patch_InsertDelete() - not functional + - Added CV lattice to selected patches + - Added Per-polygon patch selection + - Added Per-polygon misc_model selection + - Changed default "patch subdivisions" to 4 + - Rewrote camwindow drawing to only change opengl state within the camwnd's member functions + fixes all rendering modes to be more consistent, speeds up rendering + +--------- GtkRadiant 1.1-TA win32 and linux release ---------- + +13/05/2001 + + Spog (patched in TTimo) (Alpha branch) + - Fixed "Fix entity-target/targetname collisions" to use next available tN if tN, else use next available name_N + - Changed patch point selection to pick already-selected points in preference over non-selected + - Changed RemoveCols and RemoveRows to not extrapolate unless a col/row is selected + +11/05/2001 + TTimo (Alpha branch) + - final fix pass to the generated version and about message tags + - improved texture adjustment code (shift+arrows shortcuts) + + texture adjustment commands now affect the texture relatively to their current orientation + they will move along their texture axis, and not along world axis + the texture adjustment commands are now interpreted to be more intuitive: + Radiant will match the up/down/right/left translation messages to the face that is affected + depending on the way the camera is looking at the face, the right move commands will be used + + changes start in Select_ShiftTexture, using new ShiftTextureRelative_Camera + + ShiftTextureRelative_Camera uses several new functions: + + // get the two relative texture axes for the current texturing + BrushPrimit_GetRelativeAxes(f, vecS, vecT); + + MatchViewAxes does the matching between up/down/left/right commands and world directions: + // vec defines a direction in geometric space and P an origin point + // the user is interacting from the camera view + // (for example with texture adjustment shortcuts) + // and intuitively if he hits left / right / up / down + // what happens in geometric space should match the left/right/up/down move in camera space + // axis = 0: vec is along left/right + // axis = 1: vec is along up/down + // sgn = +1: same directions + // sgn = -1: opposite directions + // Implementation: + // typical use case is giving a face center and a normalized vector + // 1) compute start and endpoint, project them in camera view, get the direction + // depending on the situation, we might bump into precision issues with that + // 2) possible to compute the projected direction independently? + // this solution would be better but right now I don't see how to do it.. + void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn) + + // shift a texture (texture adjustments) along it's current texture axes + // x and y are geometric values, which we must compute as ST increments + // this depends on the texture size and the pixel/texel ratio + void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y) + + those functions are using various new utility functions: + + // GL matrix product + void GLMatMul(vec_t M[4][4], vec_t A[4], vec_t B[4]); + + // project a 3D point onto the camera space + // we use the GL viewing matrixes + // this is the implementation of a glu function (I realized that afterwards): gluProject + void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2]) + + - UI abstraction layer (interfaces for Gtk MFC and Q3 UI) + +09/05/2001 + Maj (Alpha branch) + - new splash screen + + Spog (patched in by TTimo) (Alpha branch) + + patcing in changes: + - moving void VectorSnap(vec3_t point, int snap); to mathlib + - NOTE: STL dependency removed .. leaving this comment + this will rely on M$ implementation of STL on win32 and the libstdc++ for linux + it should work fine for basic stuff + but M$ implementation doesn't follow the standards when it comes to advanced stuff + it is probably better to leave the STL header in local files and not go towards including it directly from qe3.h + + Spog's Changelog: + + rushing this a bit.. make sure you check it doesn't remove anything you + changed. This only contains changes within /radiant .. i'm pretty sure I didn't + change anything else, but i'll check again. Patch below. + + Fixed ctrl+G SnapToGrid, now never creates degenerate face-planes + Fixed setting an origin for multiple brushes to use origin point of fixedsize + entities + Fixed mirroring and rotation of fixedsize entities including misc_model + Fixed undo/redo on multiple entities to link brushes to entities correctly + Fixed "view > entities as.." menu to display correct default setting + Fixed "view > entities as.." toolbar button to show menu + Changed selection-area of edge/vertex control handles to stay constant when + zoomed + Fixed undo on ctrl+G SnapToGrid + Fixed Selection Invert to set bSelected correctly on patches + Fixed XY-window Z selection origin to be g_MaxWorldCoord + Changed RotateIcon to draw same size at all zoom levels + + Fixed origin drift on saving misc_model with null md3Class + Fixed creation of cap for 'Bevel' type patches + Fixed inverted cap being created for 'Endcap' type patches + Fixed inverting patches on mirror operations + Added snap-selected-to-grid affects only the patch points selected + Cleaned up Select_ApplyMatrix and Select_SnapToGrid + Added drawing of brush planepts in debug build + Fixed texture quality slider adjustment + Removed redundant menu items curve > cap > inverted bevel/inverted endcap + Fixed texture scrolling not working when scrollbar is disabled + Fixed textures with odd dimensions being skewed with texture quality less than + max + Changed Patch Inspector Horizontal/Vertical increment to use pixel values + (default 8) + Changed Patch Inspector Horizontal increment to subtract from S values but not + T values + Changed Patch Inspector Stretch spinner to do something useful + Changed Patch Inspector Stretch default amount to 0.5 + Changed Arbitrary Rotation dialog to reset rotation spinner values to 0 on Apply + !! stops output in console window !! - Added sending q3map output + to /temp/junk.txt to bsp commands, in win32 only + Fixed Patch_Naturalize to calculate T values backwards, correcting texture + vertical flip + Changed patch row/column Insert/Remove to interpolate/extrapolate from existing + curves + Fixed point selection on patches when new points are added + Fixed redundant edge/vertex handles being created for patch brushes and + fixedsize brushes + Fixed refusal to activate brush vertex-drag mode if any patches are selected + Partly fixed Undo picking up patch point drags when no points are selected + Fixed behaviour of vertex selection on patches + Fixed patch point colours in textured mode in cam window + Changed patch point selection to update selection pool on each selection click + +06/05/2001 + TTimo (Alpha branch) + - more setup script changes, will rely on version information + various other fixes in the script file + +02/05/2001 + TTimo (Alpha branch) + - added makeversion.sh to the root, will generate version and date files before compilation + version.h and date.h + - cleanup and fixes to the linux setup scripts + + Spog (CVS add and config by TTimo) (Alpha branch) + - win32 setup script, run setup/setup.sh from cygwin to create a working directory for the setup + +01/05/2001 + TTimo (Alpha branch) + - fixes to linux version from previous set of patches + +19/04/2001 + Hydra (patched in TTimo) (Alpha branch) + http://fenris.lokigames.com/show_bug.cgi?id=3458 : + - *.pfb filter + + SpoG (patched in TTimo) (Alpha branch) + - updated setup data: entities.def common.shader(Q3) and common-spog.pk3 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=25 : + - Patches: Curve > matrix > redisperse > rows/columns + I changed this function to treat a patch as multiple 3by3 sections when doing + redispersal of control points. The effect is that green patch points are never + moved. I also removed the call to Patch_Naturalize, so the texture coordinates + are not changed (user can hit ctrl+n to naturalize afterwards if desired). + - rewrote the patch_captexture function to be more reliable + - Fixed YZ view drawing and selection being mirrored on plane X=0 + - Fixed X and Z rotation direction to be clockwise as shown on the toolbar button + icons + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8 : + - Fixed: Removed orientation-switching hack to fix 2pt-clip orientation problems, + originally stemming from ass-backwards representation of grid axes. Fixed + clipper to generate 3rd clip point correctly for each axis instead. + - Fixed: Stopped clipper-caulker from NOT applying caulk if the first face of a + brush was "common/caulk". + + TTimo (Alpha branch) + - removed some unused code in the Gtk file dialog, hopefully stabilizing it + +02/04/2001 + TTimo (Alpha branch) + - changed the regular/BP conversion prompt + +01/04/2001 + Spog (patched in by TTimo) (Alpha branch) + - Fixed view > show coordinates now affects Z window + - Fixed minimum/maximum world coordinates now -65536/65536 + - Fixed view > show blocks now only draws vertical lines if not XY view + - Added variable blocksize (gtkr only displays 1024 < blocksize < 65536) + - Changed XY/Z window grid drawing to use floats internally + - Fixed broken XY window grid drawing for higher zoom levels + - Changed camera and Z-checker icons to stay the same size when zoom level changes + +24/03/2001 + Spog (patched in by TTimo) (Alpha branch) + - added filters.cpp to the VC6 Makefile. Linux build needs updating + - Changed Filter system to use brush-flags updated only on actions that affect filtering + - Changed Filter system to allow further extension and future customisation + - Changed show/hide to use brush filter flags + - Changed Find/Replace textures to only rebuild brushes that changed. + - Changed View > Filter menu shortcuts and behaviour + - Fixed various minor spelling errors + + TTimo (Alpha branch) + - Fixed the 'Clean' command in preferences, used to remove only Radiant.ini and not SavedInfo.bin + +06/03/2001 + TTimo (Alpha branch) + - better parse error information: added the line number of the error in (hopefully) all cases + +30/02/2001 + TTimo (Alpha branch) + - texture locking in BP mode for axis flipping and axis rotation (toolbar buttons) (Id bugfix request) + - fixed undo in BP mode + - MatchToken error message in q3map improved with the script name + +27/02/2001 + TTimo (Alpha branch) + - switched linux makefiles to xml2-config instead of xml-config + latest version of libxml2 is using xml2-config instead of xml-config now + +26/02/2001 + TTimo (Alpha branch) + - fixed a loki_initpath misbehaviour, was overriding the path to the binary with RADIANT_DATA if defined + +21/02/2001 + - Added setup data and a script to build linux setups to the cvs + TTimo (Alpha branch) + - various printf -> Sys_Printf + - added vslick/ directory for Visual Slickedit 6.0 on win32 <- THIS IDE RULES + +20/02/2001 + - Removed "Show Paths" option, already in the filter menu + +19/02/2001 + - Fixed the Enter key handling on the surface inspector (suggested by Spog) + - Fixed skewed textures with lower texture quality + - Changed the order the include directories are searched under Linux + +15/02/2001 + - Moved the Show Cluster Portals option to the Filter menu + - Fixed the rotate and scale toolbar buttons being incorrectly checked + - Fixed arbitrary rotation bug (#3073) + +14/02/2001 + - Fixed CreateFont memory leak on glwidget + +12/02/2001 + TTimo (Alpha branch) + - fixed save as prefab stuff (right dialog name and overwrite prompt) + +10/02/2001 + TTimo (Alpha branch) + - was crashing on win32 boxes where HOME env var was not defined (loading bookmarks) + +09/02/2001 + TTimo (Alpha branch) + - change some code in the file dialog to use g_malloc g_free instead of new + for win32 file dialog and malloc for Gtk file dialog. (all of this trying to get rid of + some of the crashes) + +07/02/2001 + - Fixed Load command initial path + - Fixed some toolbar buttons not being correctly initialized + +-----------? + +06/02/2001 + (Alpha branch) + - Fixed pk3man file dialog errors + - New RC uploaded + - Changed conflicting shortcuts: FilterModels = Shift+M, FilterTriggers = Ctrl+Shift+T + TTimo (Alpha branch) + - fix to hide/show, still selecting hidden brushes + +05/02/2001 + (Alpha branch) + - Fixed compile errors (use stat, not _stat) + - Removed --nofonts option + +04/02/2001 + TTimo (Alpha branch) + - fenris #2866, added a pref to turn on/off name conflicts resolution, rewrote the whole algorithm + - fenris #2823, fixed patch and brush dragging in 0.25 0.5 grids (it's an ugly hack btw) + - fixed the black squares at end of line in Gtk text boxes + RR2DO2 (Alpha branch) + - fix to the "entitypath" fixup in QE_CheckProject. might not compile on linux yet (use of _stat?) + +03/02/2001 + TTimo (Alpha branch) + - fenris #2867, limiting the amount of "spawnflags" "0" appearing in entities. This bug has work left to do, + there are some oddities in the entity inspector behavior described. + +02/02/2001 + (Alpha branch) + - Fixed sleep mode not restoring windows correctly + - Fixed some minimize/restore issues on floating views mode + TTimo (Alpha branch) + - fixed more gtkfilesel stuff. pattern filtering works for both Gtk dialogs + and win32 native. Also checked on linux that it compiles. Renamed gtkfilesel.h + to gtkfilesel-linux.h for consistency. + +31/01/2001 + (Alpha branch) + - New file selection widget with filtering, masks and all other shit we need + TTimo (Alpha branch) + - changed some gtkfilesel API and fixed some bugs on pattern filtering, need to reboot on linux and fix some more + +30/01/2001 + (Alpha branch) + - Added an option to keep the Z and XY views on the same window in floating views mode + - Did some cleanup + TTimo (Alpha branch) + - removed the 3 layers in terrain entities limitation, increase version tag to patchlevel 3 + sent for testing to AstroCreep, bug is still there + - fixed one more thing with RC file (get it in the right dir) + - worked on file dialog and pattern filtering, still issues left + +29/01/2001 + Jonas (patched in by TTimo) (Alpha branch) + - Using RC file to tweak the font size on win32, looks much nicer now! + - Fixed fenris #2773: esc key behaviour when group window has focus / dependant on view modes + +28/01/2001 + TTimo (Alpha branch) + - Finished fenris #2810 (Snap T to grid), it was a bitch + - Fixed fenris #2769: raise the brush max size (it was already big, now it's just not sane) + - Fixed fenris #2965: eclass (entities) loading code broken, needs to be checked on linux build before closing + +27/01/2001 + TTimo (Alpha branch) + - Fixed vertex edit prefs broken + - more fixes in Gtk libs + - Fixed clipping + brush primitives bug (#2644) + - Fixed clip caulk related issues (#2912) + - Added Snap T to grid back (#2810) <- still need to test and validate it, I'm too tired tonight + +25/01/2001 + TTimo (Alpha branch) + - New Gtk file selection dialog seems stabilized, built a Gtk SDK for the new Gtk libs. + +24/01/2001 + (Alpha branch) + - Fixed elapsed time displayed by q3map + - Fixed Radiant loading some TGA files upside down + TTimo (Alpha branch) + - more work done on the file selector. Added a win32 pref to select between regular win32 file dialog and Gtk one. + The advanced file selector is still not stabilized on win32. I am thinking about letting go and sticking to the regular one. + +23/01/2001 + (Alpha branch) + - Fixed q3map not finding md3 files under missionpack/ + - Prompt to save changes when choosing a recent file + - Fixed window title when choosing File/Load Map + - Don't show hidden brushes in the Z window + +22/01/2001 + (Alpha branch) + - More File Dialog fixes + +21/01/2001 + TTimo (Alpha branch) + - version first version of the advanced file selector on win32 + seems to work nicely, but crashes when you actually load something .. needs debugging! + + leo (Alpha branch) + - Set correct initial directory for the File/Load command + +17/01/2001 + (Alpha branch) + - Fixed q3map is crash if a .shader file is referenced in shaderlist and not found + + TTimo (Alpha branch) + - fixed some license headers on gtkfilesel.c, started looking into porting gtkfilesel.c to win32 + +16/01/2001 + raistlin + - the tree is opened whoooo! + + TTimo (Alpha branch) + - replaced the old Id header by the newer version (BIG update, to trunk and Alpha) + - switched str.h to BSP + - added LGPL license to the sample dll + +15/01/2001 + (Alpha branch) + - Added camera window toggle option to all views mode + + TTimo + for trunk and Alpha: + - renamed TOOL_SOURCE_EULA to LICENSE_ID + - renamed CONTRIBUTOR to CONTRIBUTOR_AGREEMENT + - added CONTRIBUTORS and LICENSE + +14/01/2001 + (Alpha branch) + - plugin SDK is back in setup/ moved the sample dll to be in plugins/, need to rewrite the SDK scripts + - built a lightweight plugin SDK with cygwin makefile for the sample plugin + +12/01/2001 + (Alpha branch) + - Set map modified flag when deleting a brush + - Minimize all windows when the main window is minimized in floating views mode + +11/01/2001 + (Alpha branch) + - Cleaned up the View/Show submenu + - Fixed texture menu splitting + - Fixed major grid lines on 128 and 256 grids + - Load only a single .def file if specified in the project settings + - Fixed q3map Makefile + + TTimo + (Alpha branch) + - Removed plugins/shaders from Alpha branch + - got rid of common2/ and code, moved qfiles.h and surfaceflags.h into common/ + - put the licensing headers in all source files (forgot some? byte me) + +10/01/2001 + leo (Alpha branch) + - Added new filter system based on FAKK2 Radiant + + TTimo + - fixed whatever could be fixed to make it compile with the new directory layout + (Alpha branch) + - project files update + +09/01/2001 + (Alpha branch) + - Added undo for patch redisperse rows and patch redisperse cols commands + - Fixed Show Z Outline menu item + +30/11/2000 + TTimo + - removed content flags and value from qtexture_t, these have moved to the IShader + (NOTE: qtexture_t != texdef_t, texdef_t still using flags value and content) + + - Rewrote the linux plugins Makefiles + +29/11/2000 + - Improved the way modules are loaded + - Added new parameter to QERPlug_RequestInterface + - finished VC6 project files conversion for new directory structure + - fixed shader blending on terrain maps bug + +08/01/2001 + - Updated Makefiles for the new directory structure + - Fixed View/Show/Entities menu not being checked correctly + - Fixed "Invert Selection" command selecting hidden brushes + - Fixed "Select All of Type" command not working correctly after the Enitity Window is closed + - Fixed grid being drawn even when it's the same color of the background + - Fixed "Toggle Size Paint" not turning off + +05/01/2001 + - Fixed autosave interval being calculated wrong + - Fixed autosave path under Linux + - Fixed q3map crash when trying to load missing pcx files + - Fixed q3map not finding .bmp files for the terrain alpha map + +04/01/2001 + - Fixed GL stack underflow when loading a misc_model + +03/01/2001 + - Fixed patches remaining half-selected after "Region set selected" (#2748) + - Fixed Surface Inspector spin buttons rate (#2776) + - Fixed some shortcuts not appearing on menu items (#2786) + + +================================================================================ + 1.1-TA beta +================================================================================ + +02/01/2001 + - Fixed memory problem if a file without extension is entered in the file save dialog. + - Fixed double slashes "//" on filenames when saving a map + - Fixed pk3man plugin not finding the toolbar bitmaps + - Fixed double clicks being considered 2 mouse clicks + + RR2DO2 (applied by TTimo) + - Clusterportal filtering ('View > Show > Show clusterportal' toggle) + +01/01/2001 + TTimo + - updated Web/ with new stuff, web site ready for release + - fixed a crash with multiple edge dragging on win32 (was caused by compiler optimizations, + this one was a major pain) + +31/12/2000 + - fixed the file open/save dialogs initial directory + + RR2DO2 (applied by TTimo) + - bug fix in the terrain loading speedup + + TTimo + - tried to lookup the Z window minimum width problem, added #define DBG_WINDOWPOS code to investigate + +30/12/2000 + RR2DO2 (applied by TTimo) + - fix to CSG Merge in the menu drop down (menu was there, command not hooked) + - some message formatting fixes + + TTimo + - rudimentary pattern matching in file selection, affects the plugin API too + - fixed silly bug in the "clipper uses caulk" code + - major speedup to the loading code on terrain entities + (in mpterra2, from 113s to 4s for the main terrain entity) + - patched back the file open/save dialogs initial directory to override in TA mode + - fixed Patch output crash in the plugin API + - fixed BP conversion in the brush output of the plugin API + + minkey (applied by TTimo) + - fix to the m_pfnLoadFile code to use VFS + +29/12/2000 + - Remember main window position in floating views mode + - Fixed wake up when running the engine in floating views mode under win32 + + TTimo + - various fixes and debug hooks for PJ bug reports + +28/12/2000 + - Fixed VFS initialization order + - Removed texture menu splitting option from preferences (now it's automatic) + + TTimo + - built an initial setup, updated the changelog file for 1.1-TA-beta + +27/12/2000 + - Fixed Q3Map output window being too wide on some errors + - Added VFS to q3map + + TTimo + - replace a printf in q3map by Sys_Printf (!), which is what should actually be used + - added a set of functions to vfs to help with file dialogs, building relative files etc. + - reworked the file dialogs so they default in the right location (open/save as/md3 loading/sound loading) + - fixed shader editor to work with the right path + +26/12/2000 + TTimo + - put the converted HTML manuals (Radiant, shaders and model) in the tree (and the win32 setup) + - added the new Terrain and Team Arena mapping manuals (added to the setups too) + + leo + - Copy and paste across different instances of Radiant + - Fixed wait cursor when copying + - Print engine command line to the console + - Fix glib warnings when running the engine + - Fixed shader files being loaded twice + - Texture menu now automatically breaks when it reaches the maximum screen height + +24/12/2000 + - Fixed q3map to compile with the new LoadJPGBuf parameter + + TTimo + - added TA paths to the BSP commands and running engine + - fixed a bug if running with monitoring disabled (generating the .bat was borked) + - changed the -moddir implementation to a global switch in q3map (same as -connect) + - moddirparam as a global variable in cmdlib, added a TA_HACK in there + - changed the SetQDirFromPath to stick to "baseq3/" when using -moddir + TODO: check standalone files + +23/12/2000 + TTimo + - fixed some sleep/wake code (crashes and wakeup problems on models) + - vfsInitDirectory for TA directory (needs to be checked on linux) + - changed my mind on entities.def, if TA is enabled, load entities-TA.def on top of regular entities.def + + mickey (applied by TTimo) + - some memory overrun fixes + +22/12/2000 + - Fixed plugin Makefiles to not use private/ + + RR2DO2 (applied by leo) + - Fixed SetTallBrush undo + - Added bug report link to help menu + +21/12/2000 + - Daily Linux compilation fixes + - Fixed q3map to read .pk3 files from the directory set by -moddir + - Fixed vfs not listing all files correctly + - Fixed libjpeg crashing on some jpeg files + - Load .def files depending on the current game + +20/12/2000 + - Applied Mickey's patch to fix win32 window position save/load. + - removed missing _msize call + + TTimo + - cleaned up more g_malloc g_free problems, cleaned a INPUT_BUF_SIZE problem in jpeglib + +19/12/2000 + - More manual updates + - Fixed bugs comparing file extensions + - Added VFS to the Alpha branch + + TTimo + - moved game selection to the project settings + - got leo's vfs fixes, started changing the memory allocation scheme to glib + - moved 'free' calls to g_free with a #define in cmdlib, Radiant seems to run nicely again + - removed calls to _msize .. those were causing heap debug assertion failures + - upped more stuff + +18/12/2000 + - Added popup menus with the list of active textures to the find texture dialog + - Fixed some menu checkbuttons + - Changed max number of shader files parsed by q3map to 128 + - Updated manual images + +17/12/2000 + - Fixed bug with the texture window scrollbar range + + Mickey (patched in by TTimo) + - fix to the floating windows mode, don't send windows to the desktop when raising something else (#2659) + + TTimo + - finalized the merge and move into worldspawn commands by adding the undo stuff + - fixed the clamping problems when flipping or mirroring patches + - added 0.5 and 0.25 grids + - added undo to Select_CompleteTall Select_PartialTall and Select_Inside + - added on-the-fly conversion between regular brush coordinates and brush primitives texturing in the plugin API + +15/12/2000 + - Fixed crash on Shift-A (Select all of type) + - Save the state of the toolbar buttons + - Remember the state of the Show Patch Bounding Box button + - Double clicking on an entity on the Entity View tree selects the entity + - Sort the list columns of the map info dialog + - Fixed a bug that would allow multiple Entity View dialogs + + Mickey (patched in by TTimo) + - saving position and size of the entity window between runs and during usage + + TTimo + - two new commands in the drop down menu: + "move into worldspawn" will move selected brushes to worldspawn and eventually delete entities which end up with no brushes + "merge brushes" will merge brushes into an entity (from worldspawn or from another entity) + - added cleaned HTML version of the editor manual in the tree + +14/12/2000 + - When pressing a letter key in the entity window list, scroll to the entity starting with the key pressed + - Fixed backspace not working on the texture subset entry + - Added version check when loading savedinfo.bin + + TTimo + - started implementing Select_Merge and Select_Seperate for workflow improvement on terrain maps + +13/12/2000 + - Finished GtkGenSurf + + RR2DO2 (merged in by TTimo) + - patch to q3map, added option -custinfoparams for custom surface flags (still need documentation) + + TTimo + - zoom out and grid drawing taylored to the world size + +12/12/2000 + TTimo + - quick win32 update to gensurf + - fixed #2610 (MAX_NETMESSAGE) .. needed a consistent rewrite of the way we parse the stream + +11/12/2000 + - Fixed linux compiler errors from recent changes + Not fixed today but I forgot to add those to the Alpha changelog + - Fixed multiple Map Info dialogs bug + - Fixed texture window not scrolling to the top when a new directory is loaded + - Fixed GL Windows grab pointer bug + - Fixed crash after map compilation if the map leaked + - Fixed q3map crash if MAX_SHADER_FILES is reached + +28/11/2000 + - Fixed sleep mode restoring hidden windows (win32) + - Fixed find/replace textures dialog layout and keep it always on top of the main window + - Replaced malloc/free calls with g_malloc/g_free to avoid the win32 limitation + +27/11/2000 + - Removed glu.h dependencies + - Added new file selection dialog + - Removed g_PrefsDlg.m_bDisableAlphaChannel (always FALSE) + - Added shortcuts for sleep and simple patch mesh + - Fixed crash after sleep mode (no GL context current) + +24/11/2000 + - Rewrote the jpeg functions of the image plugin + - Replaced some MFC classes with glib + - More shader plugin fixes + - Fixed bug with select all entities command + + TTimo + - fixed q3map to handle the new LoadJPGBuff length parameter + +22/11/2000 + - Fixed crash in Error() if there's no current GL context + - Fixes to the shaders plugin + + TTimo + - created VC6 project file for image module + - modified the m_pfnError in qerplugin.h to use (char *, ...) construct + +21/11/2000 + - Ensured that the plugins are loaded in the correct order + - Added Sys_FPrintf and Sys_Printf to the plugin interfaces + - Some VC++ fixes + + TTimo + - more fixes to the world size + - modified moduleentry_t so it compiles on win32. need to update the code in all modules probably + - other minor fixes and updates to get everything building on win32 + +20/11/2000 + - Moved image loading code to a plugin + - Fixed some bugs in the shader plugin + - Now using glGenTextures to set texture ids + +19/11/2000 + TTimo + - shader code removed from Radiant core, relies on shader module + - added ctrl-alt-LBUTTON = multiple brush select without selecting whole entities (from TA update) + - added an XML testing proggy in DevDocs/ + +18/11/2000 + TTimo + - shader module is compiling + - reworked the way we deal with required interfaces, + automated the interface request process and added code to check the required modules have been found + +17/11/2000 + - Q1 VFS plugin + - Changes to the VFS API to detect the format supported by a plugin + - Added checks to PluginManager to load the correct VFS plugin + + TTimo + - made a mess with XML MAX_NETMESSAGE error, still not fixed + - merged q3map 1.0r (TA update from Id) into the tree - important files modified: surfaceflags.h qfiles.h + +08/12/2000 + TTimo (shit I'm 24 now) + - added gtk gensurf, VC6 project files are up to date, linux Makefile not checked + - fix some WINAPI stuff on above code + - add idata.h for raw access to editor data + - new _QERAppShaderTable for shader module -> editor functions + - added new entries in various tables (GL, parser etc.) + - shader module is well under way + +16/11/2000 + - Added a color selection dialog function to the plugin API + - Added profile read/write functions to the plugin API + + TTimo + - MAX_NETMESSAGE bug: patched q3map so it sends in several messages if the problem occurs + still need to update Radiant to recognize XML nodes split into several messages (using an input buffer) + - added a test map for MAX_NETMESSAGE: sput.map + - project file for vfspk3and win32 patching + +15/11/2000 + - More plugin cleanup + - Added IsEqualGUID() to qerplugin.h + + TTimo + - merged Alpha back in (didn't try to merge this CHANGES file) + - backported some stuff from the trunk to here, the Sys_Printf, gtk_MessageBox and profile stuff + - created VC project file for gtk-based gensurf plugin + +14/11/2000 + - Fixed DumpUnreferencedShaders() + + TTimo + - added QE_CheckProjectEntity to check paths are following the right conventions + +13/11/2000 + - Fixed bugs in the vfs plugin + - Added support to vfs plugins in Radiant + + TTimo + - updated project file to libxml2-2.2.8, use libxml2 as the directory name for whatever version.. + NOTE: libxml2-2.2.8 needs some patching to compile right.. + +12/11/2000 + TTimo + - all Radiant functions that might be exported in interfaces need to use the WINAPI calling convention + modified the GTK functions code accordingly + - started writing the shaders module + +10/11/2000 + - Added new GTK functions to the plugin API + - Added 'parent' parameter to MessageBox, file_dialog and dir_dialog + - Fixed Help commands (Linux) + +09/11/2000 + - Fixed bug in the Z wnd code + - Fixed copy text from the console (win32) + + TTimo + - moved the libxml library out of the tree, updated the VC6 project files accordingly + +08/11/2000 + - ZWnd always on top (view #2, win32) + + TTimo + - added Escape key to hide the entity inspector + - S and Shift+S now act as toggles on the inspectors + +07/11/2000 + - Added ungroup command to right click menu + - Fixed message box accelerator bug + - Fixed GL error on win32 startup + + TTimo + - additions to the BSP interface + - fixed DestroyCursor error + - clipper caulks faces (and prefs checkbox) + +06/11/2000 + - Cleaned PrtView and TexTool plugins + - Fixed bug in texture menu names (#2506) + - Added splitters to Entity dialog + + TTimo + - started clipper caulk implementation + - fix to the pointfile not drawing in 2D views + - MAX_BUILD_SIDES in q3map debug stream + +05/11/2000 + - Merged Alpha branch with the trunk + + TTimo + - more plugin interface for Q3Build, and plugin SDK additions + - merged q3map Realloc back into Alpha branch + +04/11/2000 + - Fixed crash during startup if Zwnd was hidden in views #2 and #3 + - Fixed ToggleConsole command + - Fixed ToggleEntity and ToggleTexture commands in view #2 + - Fixed plugin Makefiles + - Removed -rdynamic from Radiant link options (crashes pk3man plugin) + +03/11/2000 + TTimo + - directory reorganisation for the plugin SDK, added an interface/ directory + +02/11/2000 + - Save ZWnd state in views #2 and #3 + - Entity dlg always on top (linux) + - Fixed shortcuts.ini parsing bug + - Fixed editpad crash if editpad not present (win32) + - Fixed bugs in the internal shader editor + - Fixed widget_show if window moved after gtk_widget_set_uposition + +================================================================================ + 1.1 beta +================================================================================ + +31/10/2000 + - Continue loading if glXGetProcAddressARB is not present (Utah-GLX fix) + - Fix BSP commands not working if a map is not in "mapspath" (linux) + +30/10/2000 + - fixed the Region commands, "Region > Set brush" is working + Region uses the camera as spawn point. + - Fixed view/show menu initialization + - Fixed warning when starting view #2 + - Fixed z wnd in view #3 + - Fixed win32 sleep mode crashes on views #2 and #3 + - Added "Restart" message when changing texture quality in the preferences + - Cleanup: removed radbsp.cpp (unused) and unzip.cpp (already in pak.a) + +29/10/2000 + - Fixed SIGCHLD handler + - Built 1.1b setups + +28/10/2000 + - Fixed q3map bug visbytes > MAX_MAP_VISIBILITY + - Fixed clipper display bug + + TTimo + - updated quakev2.qe4 with -vlight options + - added checks in q3map to prevent crashing on allocating a winding too big + will stop with an error now. + - added the corresponding editor support for debug messages if MAX_POINTS_ON_WINDING is exceeded + + G_Dewan + - improved q3map, reducing minimal memory footprint by about 45Mb + +27/10/2000 + - Fixed crash in BSP debug window + - Reorganized the preferences dialog + - Fixed q3map Makefile + - Fixed +/- bug in win32 (Gtk patch) + - Fixed Alt shortcuts bug in win32 (Gtk patch) + - Fixed q3map crash when visbytes > MAX_MAP_VISIBILITY + + TTimo + - improved snapshots behaviour, doesn't snapshot non-modified maps + +26/10/2000 + - Fixed patch inspector not showing after it has been closed + - Added 'Reset' button to entity dialog + +25/10/2000 + - Fixed more grid issues + - Fixed load window position bug (saved pos greater than screen resolution) + - Fixed selection nudge bug + - Improved entity windows layout + - Fixed GL font not being recreated when exiting sleep mode + + TTimo + - cleaned m_nTextureTweak and m_bSnapTToGrid + - improved the CycleCapTexturePatch command, now cycles across the 3 planes only + and works on multiple patches at once + +24/10/2000 + - Added an overwrite prompt when saving files + - Fixed 128 and 256 grid display + - Commented-out grouping code (not functional yet) + +23/10/2000 + - Fixed q3map to load jpgs under Linux + - Fixed wake-up crash when floating windows were closed (#2423) + +21/10/2000 + - More q3map and radiant Makefile fixes + - Remember size/position of the entities dialog + +20/10/2000 + - Redirect Gdk warnings + - Draw border around active XY wnd + - Moved some scripts to the Makefile + - Added shift+rclick to zoom in/out + - Removed minimize/maximize buttons for z wnd in floating mode under win32 + + TTimo + - Two new entries in View > Show: Show Outline and Show Axes + Show Outline turns on/off colored outline of the current view + Show Axes turns on/off display of a small axis base in the 2D view + - fix q3map Makefile to use external libxml2 source + + G_DEWAN + - Fix to bogus noshader error message in q3map + +19/10/2000 + - Added new console functions that support colors + - Revised linux makefile for debug/release builds + - Redirect Gtk warnings to the console + + TTimo + - reorganized the entity inspector window, layout depends on the number of flags to get + more space in the comment window. + +18/10/2000 + - Fixed add/remove bsp items in project settings dialog + - Did some cleanup (removed #define WIN32_CONSOLE) + - Fixed console not working in view #3 + - Fixed warning when exiting in views #2 #3 + + TTimo + - fix to entity inspector comment window for the eclass_t on win32 (removed the white squares) + +17/10/2000 + - Fixed texwindow not scrolling when last texture is large + - Added LOD for patches + - Fixed prefab path & user ini in preferences dialog + +13/10/2000 + TTimo (XML branch) + - basic architecture for XML feedback is functional + see radiant/feedback.cpp radiant/watchbsp.cpp q3tools/common2/inout.c + merging back in alpha + +04/10/2000 + TTimo (XML branch) + - sax interface is in Radiant, need to add a state machine and proper processing + +04/10/2000 + TTimo (XML branch) + - experimental use of SAX interface to parse the stream on the server side, see q3tools/q3map/NetTest + +03/10/2000 + TTimo (XML branch) + - adding libxml2 in the repository, based on libxml2-2.2.4 with project files and stuff to build on win32 + +31/09/2000 + TTimo (XML branch) + - new common2/ dir, output system rewritten through Sys_Printf + - experimental use of libxml + +28/09/2000 + TTimo (Inspector branch) + - shift+arrows matches the increments from the surface inspector + - button 'Match Grid' in the SI to set the increment according to current grid + +25/09/2000 + TTimo (Inspector branch) + - fixed crappy bug in SavedInfo.bin upgrade (when the struct sizes don't match) + - surface inspector has inc step dialog boxes (+saved in prefs) + - face selection is always on (was something weird from the prefs) + - undo works better with the surface inspector + +25/09/2000 + - Added ARB_Multitexture support + +21/09/2000 + - Fixed preferences dialog warning + - Added new grid sizes + +20/09/2000 + - Fixed small bugs reported from Fenris + +17/09/2000 + TTimo + - fixed a bug with template project loading / path to the engine safecheck (a weird hidden one) + G_Dewan & TTimo + - fixes to the process spawning (Q_Exec in cmdlib) + appropriate warning and error messages + Fishman + - antialiased drawing in 2D views + +14/09/2000 + TTimo + - radiant.log commandlist.txt and radiant.pid are create in g_strAppPath on win32 and g_strTempPath on linux + - moved the splash screen after the .pid code + - I suspect a bug in the .pid removal, added a check and message box + - help works again on win32, spawning Word with the Q3Rad_Manual.doc (temporary solution of course) + - surface inspector: removed all Q2 related stuff, fixed horizontal shift, reorganized the widgets layout + hooked the widgets to apply the changes on the fly (the inspectors need a good chunk of work) + - fixed a radiant.pid bug + - added icon to MSVC6 project (with some help) + + G_Dewan + - fix to BSP menu order getting mixed up + - fix to the file dialog + +11/09/2000 + - Added splash screen + +25/08/2000 TTimo + - launch sleep mode before running game + - fixed Map_Snapshot bug + - going to sleep works on view n2, raising is still screwed (contexts) + +24/08/2000 TTimo + - fixed some sleep mode stuff + - fixed map snapshot bug + +21/08/2000 + - fixed stuff to build on linux + - Merged in q3map 1.0p + +18/08/2000 + - Removed "High Color Textures" option (always on) + - Removed "Status Point Size" option + +17/08/2000 + - Fixed win32 console issues + +16/08/2000 + - added g_strTempPath + - restore maximized window state + - fixed logo.bmp + +15/08/2000 TTimo + - fixed keyboard shortcuts + - fixed engine path in prefs (must use the file dialog to change) + - fixed a bug related to engine path and project templates + +15/08/2000 + - Removed QE4 update model option (always on) + - Removed Buggy ICD option (always off) + - Reorganized the preferences dialog to take a bit less space + +14/08/2000 TTimo + - using profile.cpp code to read shortcut keys files + - moved DevDocs/changelog.txt to data/changelog.txt + (data/ should be used for user-side stuff and DevDocs/ for developpers) + - added data/quickstart.txt with a beginning of info about the main differences + between Q3Radiant 202 and GtkRadiant. to be used as a doc later. + +13/08/2000 TTimo + - added DevDocs/WIN32SETUP and DevDocs/changelog.txt + changelog.txt is end user changes + WIN32SETUP the TODO list for install specific stuff + - wrapped a first version of the win32 installers (full and patch) + +11/08/2000 TTimo + - quickfix to put undo/redo back in + - added DevDocs/WIN32SETUP, describes what I'm up to with the setup of win32 version + +10/08/2000 TTimo + - added back the window position saving code that was in earlier tree + NOTE: would have rather have it done in prefs than hooked in mainframe_delete and MainFrame::Create + (would have been cleaner IMO) + NOTE: IT'S STILL BROKEN .. I ADDED THE CODE BUT I MUST BE MISSING SOMETHING + NOTE: it doesn't remember the maximized state. It should. + +08/08/2000 TTimo + - fixed win32 build for GLWidget code, added WINAPI calling convention on all exported stuff + - fixed TexTool to compile under win32 + +07/08/2000 TTimo + - fixed some crash with the new jpeg lib + - fixed console logging behaviour (was always turned on at startup) + - added console logging checkbutton in prefs + +07/08/2000 + - Merged the GLWidget branch + - Merged 202 patches + - Fixed "clean" button in the preferences dialog + - Added pid startup detection + - Updated plugin interface with GLWidget functions + - Updated TexTool plugin + +04/08/2000 + - Added "errno" string to the Error() message box + - More 202 patches + +03/08/2000 + - Merged changes from MFC Radiant 202 + - Fixed the win32 GLWidget stuff + +02/08/2000 + - new OpenGL widget to keep all platform specific code in only one file + +01/08/2000 + - Added code to restore the windows when coming out of sleep mode + - Rewrote the TexTool plugin + +31/07/2000 TTimo + - added vc6 projects for PrtView + - tested PrtView and Radiant against latest binary release of Gtk (works great) + + Leo: + - Updated VC5 projects + - Fixed plugin loading under win32 + - Updated PrtView to compile under win32 + - Radiant is now iconified when going in sleep mode + +30/07/2000 TTimo + - prefs dialog for BSP monitoring + - Added data/ directory with entities.def and quakev2.qe4 + - stabilized syntax of v2 project file, same project file for both platforms + - added DevDocs/WIN32BETA with a list of stuff to do before going on public beta on win32 + - added DevDocs/d2u .. handy script to remove linefeeds from DOS files + - added radiant/radiant.proj, project file for source navigator (SN rules) + + Leo: + - Fixed the logfile crash when ~/.q3a/radiant doesn't exist (fenris #1953) + +28/07/2000 TTimo + - Fix to the win32 console to use window's default font + - Added File > Sleep for experimentation + NOTE: we need to keep Radiant minimized when going into sleep mode + +28/07/2000 + - Finished the win32 console replacement + - Fixed bug 1952 (map loading segfault) + - Added a Makefile to the libs dir + +26/07/2000 + - Added PrtView plugin + - Added qvm target to source/Makefile + - Another release candidate sent to QA + +18/07/2000 + - Fixed the slow updates issue in the win32 version + - Added 3 new variables to fix the paths issue + +17/07/2000 + - Fixed the plugin search directory (broken with the changes to g_strAppPath) + +14/07/2000 + - Increased the timer speed in MainFrame::RoutineProcessing + - Added code to release and recreate the contexts to the win32 version + - Fixed the mouse capture under win32 + +13/07/2000 + - Fixed the new path and bsp problems + - Sent new version to QA for testing/release + +12/07/2000 + - Added "tools/" back to g_strAppPath under linux + +11/07/2000 + - Added code to release and the recreate the GL contexts (linux) + +10/07/2000 + - Changed directory structure + +09/07/2000 + - Added CS_OWNDC for win32 with a GDK hack + +07/07/2000 + - Fixed "white textures" bug (gluBuild2DMipmaps bug) + +03/07/2000 +TTimo: - main.cpp l386, removed tools/ appending to g_strAppPath, g_strAppPath is expected to point to the app.. (hope it doesn't break anything) + +02/07/2000 + - Added precompiled headers for faster win32 builds + +01/07/2000 + - Finally got q3asm/lcc working + +26/06/2000 + - 201 patches + - Added screenshot option + - Added an error message if X is running in 8 bits + +23/06/2000 + - Updated with build 200 source + +13/06/2000 + - Remove --noshare option + - Added --nofonts option to workaround a bug using glXUseXFonts in XFree 4.0 + +04/06/2000 + - Fixed bug with the Ctrl-X accelerator for the File/Exit menu + +02/06/2000 + - Converting the TexTool plugin + +30/05/2000 + - Changes to the plugin loading code + +28/05/2000 + - Files with an underscore character are now correctly parsed in the MRU menu + +25/05/2000 + - Fixed _exit bugs + - Fixed bug in CMapStringToString::SetAt + - Fixed copy/paste/clone bug + +24/05/2000 + - Finished applying the 199 patches + - Fixed a bug in CShaderArray::SortShaders() that was calling the wrong version of InsertAt() + - Added numbers to the MRU menu items + +23/05/2000 + - Fixed the floating point bug in gluBuild2DMipmaps + - Fixed the time display after a bsp command is executed + - Applied several patches from the 199 version + - The console is now visible by default + +21/05/2000 + - Added a replacement for gluBuild2DMipmaps + +20/05/2000 + - Fixed the repeating textures bug when playing a map, "brush_primit" must be set to "1". + - Fixed the bug about no current GL context when exiting in computers with 3dfx cards. + - Textures in the directory pointed by "texturepath" are now loaded correctly in Radiant. + - Fixed bug in q3map where it would require a shaderlist.txt file in ~/.q3a/baseq3/scripts. + +19/05/2000 + - Fixed a bug in the multiple directories hack in libs/pakstuff.cc + - Finished the filter in the texture window + - The wait cursor is now correctly set in the XY window + - Added replacements for gluPerspective and gluLookAt + - Textures can now be stored in 2 places: + * The path pointed by "texturepath" (defaults to ~/.q3a/baseq3/textures, + but can be changed in the project settings) + * The base texture path (/baseq3/textures) + - Radiant and the q3map tool now looks for shaders in ~/.q3a/baseq3/shaderlist.txt + and /baseq3/scripts/shaderlist.txt + +18/05/2000 + - Plugin menu fixes + - Created a simple text editor to edit the shaders (instead of calling an external program) + - Copy and paste now work + - Fixed some bugs with the MRU menu + - Some menu items are now enabled/disabled correctly in MainFrame::RoutineProcessing () + - Added a new command line option (--cdpath) to set the CD-ROM path + - Fixed some bugs in the entity window, now it's possible to add/edit/remove properties + - New directory paths: + * maps now default to ~/.q3a/baseq3/maps + * autosave files are saved in ~/.q3a/baseq3/maps + * .pk3 files can be in ~/.q3a/baseq3, /baseq3 and in the CD-ROM + +17/05/2000 + - Fixed bug deselecting a brush after the surface dialog is open + - hide cursor when right-dragging XYWnd + - files saved to /tmp are now saved in ~/.q3a/radiant + - Disabled undo + - Fixed a bug in FillTextureMenu + - User can now correctly change the accelerators at run-time + - Accelerators are read from ~/.q3a/radiant/radiant.ini + +16/05/2000 + - Finished the patch inspector + - Finished the texture toolbar + - more small bug fixes + +11/05/2000 + - Finished the GroupDlg stuff + - Added support to read pak files from the Quake3 CD-ROM + - moved /tmp/paklog.txt to ~/.q3a/radiant/paklog + - added functions to replace GetKeyState and SetCursorPos + - fixed the command key handlers for the mainwindow diff --git a/docs/developer/DRAFT b/docs/developer/DRAFT new file mode 100644 index 00000000..2ba0f75d --- /dev/null +++ b/docs/developer/DRAFT @@ -0,0 +1,130 @@ +usefull global variables in Radiant: +g_strAppPath has the path to the binary + +----------------------------------------------------------------------- +using prefs / ini settings: +are stored in Radiant.ini and *.bin files +win32: +looks in the current directory for a Radiant.ini file +if found, will use it and set the ini directory to the proper location +if not found: +the registry has a path to the default directory? +under key HKEY_CURRENT_USER/Software/GtkRadiant/PrimaryEditorPath +(DefaultEditorPath cause that gets used for +if the key doesn't exist create in current directory and set the key +NOTE: need some registry version info, when we find in another dir than ours, + check version and prompt to use existing settings or our own? + +storing version information: +each build publicly released should have a version string +- use it in the about box +- store it in the Radiant.ini file +- use it in the registry GtkRadiant/ +do we need major and minor? minor could be used for versions that don't break .ini compatibility + (well I'm lazy .. won't do) + +linux: +look in the current directory (check write permission!) +if found, use it +if not found: +look in ~/.q3a/radiant + +----------------------------------------------------------------------- +icons: +look for bitmaps/ under g_strAppPath +win32: +if not found, use DefaultEditorPath registry key and try to locate there +linux: +we also need a DefaultEditorPath kind of thing? +somewhere in ~/.q3a/radiant? + +----------------------------------------------------------------------- +project file: +Radiant.ini must have full path to the project file +if no project file path: +win32: +we have to locate BASEPATH one way or the other. we have code that will look for the +main directory and go down into baseq3/scripts. If that fails we prompt the user. +it would be good to store BASEPATH in the .ini as well! +linux: +store path to Radiant installation somewhere in ~/.q3a/radiant +if not found try some defaults and prompt the user + +NOTE: on linux radiant is in /usr/local/games/quake3/ instead of some +quake3/tools directory. This makes looking for the basepath easier. + +g_PrefsDlg.m_strLastProject points to the project to be loaded +if radiant cannot find it at startup it will try to guess and/or ask the user +once the project file is loaded you can deduce a lot of things.. +but project file parsing has some prerequisites: __QERPATH / __QERHOMEPATH ?? +need to unify between win32 and linux! +PrefsDlg has a bunch of defaults, but it must not try to guess + __QERPATH and __QERHOMEPATH until there has been an ini load (or a lack of) +the involved members are: +m_strQuake2 <- points to the engine path, renamed to m_strBasePath m_strEngine +m_strPAKFile <- built from m_strBasePath, removed (not used?) +and: need to add more, like map compilers directory m_strToolsPath + +project file syntax: +linux version is using __QERPATH / __QERHOMEPATH +win32 has __Q2PATH __QERPATH +and the overall syntax is different! + +big problem is user customization, it performs expansion and saves with static +paths. but we'd like to keep the original one with generic naming. (cause if the +config fucks up and user reinstalls he'll still get broken project settings) +so: we try to load quake.qe4 project, expand it, and save as user.qe4 +(on linux, user.qe4 goes in ~/.q3a/baseq3/scripts) + +TODO: how is "New project" supposed to work? would copy the current project.. +TODO: get rid of m_bLoadLast .. we require having a project loaded for use? +TODO: store path to the tools in prefs? (see usage for project file expansion?) + -> so you can use q3map in a given dir etc? + +unifying project file syntaxes: + +get rid of BuildShortPathName things! + +----------------------------------------------------------------- +some common operations and portable code: +document XP use of stat, checking for directory / file existence + +how to have code that reads well across XP: +don't use TABS, have them emulated to 2 spaces + +----------------------------------------------------------------- +project files: +unless we rewrite a whole bunch of it from scratch there's no much +hope for evolution of the project files. Nevertheless, introduced +a new "version" key that describes the version of the project file. +version 2 adds a # keyword for q3map global options +NOTE: and it's a compatibility nightmare, we can't call this one +quake.qe4 or default.qe4 cause it will break backward compatibility + +----------------------------------------------------------------- +monitoring BSP process: +we monitor through network connections +we need to stop the process if an error occurs during one of the three steps +and launch quake3 when all is done +we don't want to CreateProcess and watch cause for rsh mode it will return immediately +a BSP process is decomposed in several steps and we expect a connection at each step +- later we can add custom steps that don't net connect and then we just spawn and +watch them +- we could add a name to the step to identify them, for now we'll just assume +the first connection that we get is the one of the process we spawned +when we loose the connection we wait one sec and spawn the next one... +- we don't use batch file, just produce the command lines for each steps, the batch file +will be produced only if we don't monitor the process (we can add an option to output +the BAT file anyway) + +what stuff goes in prefs? "Monitor BSP process" + +detecting when the socket closes? +using select() one can detect if a socket has closed or if there's some input +NOTE: when launching a new BSP process we may still be connected. Need to ask the user +about overridding and closing current connection. + +in prefs, boolean flag for process monitoring .. g_PrefsDlg.m_bWatchBSP + +when running in monitored mode, the BSP watcher is in charge of spawning and watching +the processes (and more later when it will be parsing the output). diff --git a/docs/developer/HEAP b/docs/developer/HEAP new file mode 100644 index 00000000..11c9e0fa --- /dev/null +++ b/docs/developer/HEAP @@ -0,0 +1,33 @@ +find and xargs: + I need to remember that grep trick + 'find -type f | xargs grep -n whatever' is handy.. + find -type f -name '*.[ch]' is even better at times. + +stdout / stderr redirections: +make -f makefile.cygwin 2> err.log +make -f makefile.cygwin >& full.log + +escape shell expansion: +find gtk-20001023 -name "*.zip" -exec unzip {} \; +find and -exec: +find //c/Donwload/Gtk-20001226 -name '*src*zip' -exec unzip {} \; +find //c/Donwload/Gtk-20001226 -name '*dev*zip' -exec unzip {} \; + +simple encryption for /etc/passwd entries: +perl -e 'print crypt("password","hk");' + +debian and /etc/init.d +update-rc.d + +silly hint on sed and regexp: +cat bspfile.c | sed -e 's/\([^_]\)malloc/\1safe_malloc/' | grep malloc + +*poke 10* +bleh +bleh +bleh +bleh +bleh +bleh +bleh +bleh diff --git a/docs/developer/Inspector/Inspectors.argo b/docs/developer/Inspector/Inspectors.argo new file mode 100644 index 00000000..0512d60e --- /dev/null +++ b/docs/developer/Inspector/Inspectors.argo @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/developer/Inspector/Inspectors.xmi b/docs/developer/Inspector/Inspectors.xmi new file mode 100644 index 00000000..0d6c906a --- /dev/null +++ b/docs/developer/Inspector/Inspectors.xmi @@ -0,0 +1,247 @@ + + + + + + + + + Surface inspectors + + + + + + + SurfaceDlg + + + + + + + + + + + + + + Toggle + + + + + + + + + + + + + + + + + + + + + + + activeInspectors + + + + + Java + 0 + + + + + + + + + + + + + Dialog + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + + + + ISurfaceDlg + + + + + + + + + + + + + + + + CQ3BrushDlg + + + + + + + + + + + + + + + + + + + + + + + + + + CQ3PatchDlg + + + + + + + + + + + + + + + + + + + + + + + + + + COtherGameDlg + + + + + + + + + + + + + + + + + + + + + + + + + + Undo / Redo code + + + + + + + + + + Messaging API + + + + + + + + + + int + + + + + + + + + + + list + + + + + + + + + + + + + diff --git a/docs/developer/Inspector/Inspectors_classdiagram1.pgml b/docs/developer/Inspector/Inspectors_classdiagram1.pgml new file mode 100644 index 00000000..6ef4a8d0 --- /dev/null +++ b/docs/developer/Inspector/Inspectors_classdiagram1.pgml @@ -0,0 +1,571 @@ + + + + + + + + + SurfaceDlg + public int newAttr = 0 + void Toggle() + + + + + + + Dialog + + + + Toggle hide/shows SurfaceDlg +replace DoSurface and ByeByeSurfaceDialog + + + + + + ISurfaceDlg + + + + Available in the plugin API +defined in ISurfacePlugin.h + + + + + + CQ3BrushDlg + + + + + + + + + CQ3PatchDlg + + + + These two hardcoded in Radiant + + + + + + COtherGameDlg + + + + Implemented in a plugin + + + + + + Undo / Redo code + + + + + + + + Messaging API + + + Selection / Deselection messages + Store a snapshot of something for later use + List of the SurfaceDlg objects we currently need +Updated on the way when we get messages + + + sourcePortFig="Fig0" + destPortFig="Fig1" + sourceFigNode="Fig0" + destFigNode="Fig1" + + + + + + + + + sourcePortFig="Fig6" + destPortFig="Fig4" + sourceFigNode="Fig6" + destFigNode="Fig4" + + + + + + + + + sourcePortFig="Fig8" + destPortFig="Fig4" + sourceFigNode="Fig8" + destFigNode="Fig4" + + + + + + + + + sourcePortFig="Fig11.0" + destPortFig="Fig4.0" + sourceFigNode="Fig11" + destFigNode="Fig4" + + + + + + + diff --git a/docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml b/docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml new file mode 100644 index 00000000..95c7614e --- /dev/null +++ b/docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml @@ -0,0 +1,6 @@ + + + + diff --git a/docs/developer/Inspector/Inspectors_usecasediagram1.pgml b/docs/developer/Inspector/Inspectors_usecasediagram1.pgml new file mode 100644 index 00000000..a6182ca9 --- /dev/null +++ b/docs/developer/Inspector/Inspectors_usecasediagram1.pgml @@ -0,0 +1,6 @@ + + + + diff --git a/docs/developer/Inspector/classdiagram1.gif b/docs/developer/Inspector/classdiagram1.gif new file mode 100644 index 0000000000000000000000000000000000000000..bf468e2f9968b65200f9d443e661c7f5f6748989 GIT binary patch literal 6693 zcmV+=8rtPYNk%w1VSED20r3C;@9*yb00960{{R60A^8LW00000EC2ui0DJ<>0RRI2 zgpaAq?GK}zwAzca-n{z{hT=$;=82~2%C_zc$MQ_q_KoNI&iDQg3<`(DqVb4KDwoWr z^9hZX0@SMYip^@b+^*Lv4U5O*@-QGstJmzd`wfrF=kb8~j?e4&A2j_B7$`Vr$7gtm zn0V(m*y#B9R;V~hS!wyh2&uUlD0%q_8Y())S!!B0nyR|W`jB}FYwFobTWdRs#`wCn z%a&;BTmuO+CP;VbD5m2#(I!orC&@wxy8MUH}AEt zeEa(S+qJG>3vlxqK5Q*4;>CF94t{)~FyqOT5x%XAIjUpGk0odRe0MMC(VRAO7VMd{ zYR!sQyY6&4_T|^K^|r2!+l^4bynBCBOhsNc8yd4gQ4hFK^xn=&1qS zeCrjc-g|5mxE_J(A&6ar>_rD5fd{%b9fb!bh~0w{Mo6KB8EWVuh8;q9p@9!Z*r7Au z?dO_!FyjvR)#qnTk+c_x(^J_#h6YPPvzlwwA?qJcU(m?nrW8pkDR zG6w3BmtVFyrs!JKFU)Wk?e>cpys}6`FH8AOb#TTtTnuq(|7zw>KH;9z4!Ihi ztZK*ae#~vbq@oNnzA8^9al{-?6LZea&CFQM{g$h9&=lOvbC+Q?jI>`uFFgX$MGNAy zzCbfg^}|oI6}7ulSIxBnPG4Op17Fj&b=Oso4K_Str(L$$OrxDP&TE6+w%bC(9k*^Q z7hSjAI^&(UTUK}6x8E@X9yl|5^IW*$C?lTupMyjG+_>W!L!Nln+g5J*!I%fG`LdjM zZtmxKhaT$aq^D|n+^7?(`s!Y`&i3Ln$1Zz-w9{?7%DCs=-0oMu9_a7D%O?EO#B*u< z@uwxvckhHdZ#eXfOHVoVep`P#_CITHH}}5xmvs4Ff$z5X)6YFT`ev)2J^RYL-!=T- z%O5@cXGgx)@>w>oKeO0RYThGY0N=(xwfJvF06d^m2B@_HM$mzGOQ6Z{cRdOQ4T77K zU|X4otX4n6;6MZ;T@d=lH)jO3sb}#3KXs2uD78u8iKvfi48uM?!kckcvYj z{rp%$M)Jau?t|oiBsob+YR{7638Vvh;Ym#fPm!Al<={*y%IA?1RW_1aDs#t4@SqX_ z)R^TfQL{>6v=U>t>|89BV@m*FrI)1p<#B=;7GgTjn8@J)GL>1EG)i-tS8*mZuh|)F zYLhO{+@?1X(amp)QxD-Br#Z_|&U30$3h7*@JDbqXcghn9@tmhU&v4It9;2T6>}PQN z3D8yWGoZ$xra=cP1B4Q^7R-cND*hC@&{j0GIHG`PL{M)mknL&mX^d@Q6hN4LUO&SZR*LR9?zL|lCJt4_37 zrVM*IO*ckStN;xuH&sbkMFz5->Xc+XGuSXwHk#M;EUN$B2};pCR5wWDp^szU#& zR*fDutt`Xj7`OV5d5$&Bu$;?IFS*%P-c5QfE8TQ`_zk??wus>4?OCyC4%_iIV-7sv z?1YlNZCRI_VU6i!NAkGgh7X?1E$A=H!Bc-Qw}#vEZ~3g*u1a2YwS~*V3YQ5)<;K;a zrH$rd{dwG-R+F|Lon?j>yI7!Rw6T*krjWa;;@@8PwNDt;mO7$6eP~W|UF*5-(9s#{Y?gNt#-YYkqN}8-te0BsJAP86fKKWj)tx?9*E!U4 zFl&fdZw3dz{v0lSr-rak9+-XjpJI_B@&Uid0eM6$^7zl&pgG4ttVqm{M)@| z)c^=D(X?YP8qIK;fAm{oHiru0A*PML)y6f$i+J@X8E=zS;u05gSN5|TKtg*!I%S=GOaEe?}*h1o&^oNyUKg{GbSb+PdE%>RHkL z_WqJj`~Z$5kf(MJDqA>uAg3$7!W~?wYhXxZ6lZy7=t|2MgNQdl#D`#kwkcZ1b6wUWA%ZDlHgt`m zBxRDKKh=&bV{)2ai zB$W4gHRx>>s0tIfGHy6rj2MShmu8(ub(4r6r*?yWM|XjjZ+d5oc1MVk5_qx4hLVPG zR0M}(h;fzoD~{G}u|iV9$ZEmZgQ~c1>H=^) z7YnqvjZ|Zb1E`2^2#yBEgO%})NnwMqFptKCKu!pR^CN^V*cPPtP(Rp$rz2e`N00?M zOazFJ0l8d{g;D^ykNLxpmynJLhKdOnk(Dr!{!)>`c#%!zki%Fz9f^@2XBWz{CJM(Ly}P#Ih)avP)L&r`H;I6lQOx6;Zu`2>5D)936zJpJwwSq zIC+#pR6R<0lPKAg&cc#VISsw%S7I>?B#1RqIhA+pN zpr?i;2Z@(yk1z;~YXh1&1(z1n5)9~)u27DDhj)1>hl99ftte(2CW||_nXDO8hPj)q z@e6P{S@&gM`zM@tNu2b!cZBJ1a2IHP_MDX{n2xA8|wh1r>hsgTQYUy)!vX=w_<5_-l6c^(HWSU4;b`iQS$ zdDlpJmuGBid7#yqj}Qr&YayO-V~$i7mI&IDIP{$+YAbmYn2F&yL}?rHNk=cLma0{w zRtY+&xueq=qVc(osc4it>W_uzqXLPaLCT{mDxwL>J5B1OIt8UfI-)*_qd}UasppwC zI(#LHgW3_8Wr~~5NsZygdG5Gv$;WxeGLyQArBWJ%I$D`Wh?#eqgkM%~wTFc>aukNpf$Jp(WC#@VBH3=?cyH zhq_pxwdsgkrf481XyQhyhBly_T8O9GcLItdpK5_DI+k_%NsneJklL4@Hh1f3sk$PG zUl*gV31FfIcEH-6mZ)>-fvcq$sv$Y5&pL$7 zglB4^1X8dSRg?Qfj2-ii@z@?nR+XMfu~llN@L8zwfUqNbSsSaXA_+butFl*svMuYf zFAK9VE3-38vo&k8H;c15tFt@HvpwsxKMS-${wuUYOSDC6v`34yNvpI=%d}1Fv`-7Q zQ7g4mOSM&NwO5O^S*x{M%e7tWwOV9#X1am8IrlXhztQ|h;i2)Jipt%mxyg^LL-MKZ)-U3vwgSsIm!O9Zd? zfc5En!D&{AOSqJ~xJ}lb^kr3zI}R+i4_p}(FY0eMHg@Qyrs+1B;mB|xvbRxdxs8ir z9QamprkFJPFNS!hy*OZgD!Y)Ns)Ogbh6}p)_h2KlV!Rugmev|U2Zpk`tgSkF57)0{ zC~TPuVttn&wF|Yk%b42Nn5Nsi4ppN5$LV*iIG{{&hpE<|TF0p1t8U2~xJdO?8iRmaQGV>!%=D5rx?oGtjcMs$J)MsI;_kZ ztg0r#KoCo)o4UO^a?8k}$mn_3sIRj5u8$gxma3NpBEC=Cx19U1#p|$0Il^z0wn~$? zuQ8*OD!@Nn4~JW%`iR7OB)B?kq)mJSIlROqD#cT*#F9IMSDeI8T*X?-#VO;(TKuD7 zjKyQzg56QXm&k1~+Q$3#uCY6YVQR)=%&RXVymE}EIkvEkm~X>7ZFL+2RBRlE_HlsL zZDj^`UMPlWNS>v4$fFj)g53TBgbZt?%Bo=3b$vO%s=BQ>hn~iYY?M66S$xT#$cl3E za^RXN3{0uP60IN{b(2iW1c%1_RVnHztgJb|MYpf3tSOP`Bsc7|mRx14Ik3p6!kOoB z8#;Nv2B9*HuM#@SwLEL4+@e{MqPc0!wtUBAJR?Qy!`-|yx4f$sM9fWV%#jhqX++L^ z_Ra6CJJ>AGz_HHt92@Q27x-)__sq|b;m`j(7y&KN(L~P$J z&=D;_3Qf^eLC_b?6dA42M8VM=EfXIN(l8;?BmEI2ZPFcq(kZ8#V}^d+zd)ImK4wnWrMoin*G)J3V(9EH?d`P4d8&6Vsj zRxs7tMavBlRmesKSrP`Xk+rce1pEbqBZQQhkTJ>Pt%WVkt^xDeJ+tU46&kfyXP+6FO-Px@Sn7|Fx zt=IzvQNZop{_I4;ax30oP2Tj>-RCX0L2y^^4d2`#-%McM^xEBZfZz$PR11F84esEM1>t0n-xFTR`<(|8j^TZv;pD{O9j*Z%CB7jp z;)GEI#C+i=?g1$U)GN;78Q|iUVB#_U7V#~SHE!d=bOhq9<1C(3>+RD*F2PGhLb>x7%_ZPjGi@uwi>iMC4yX%{56<7ADzJKlN7m>bYrR(IC?1%O2 z&hCMud%7A3z1SD+!EO!WWtSF#1-M&N5N5(}-85#|dlkXzblDH}wGpM8?Q!YXmQGjR z9#_tbVn#K7j_K5dQSa0)m(#bHm)n54?#+%%?Z273q)Y7jUVr?))g?9U>0a&no_^3< z!Sg;e|4#A4&c9?$@Vo1~0)pKF zxxiWT5AX8a{OIV;>;r%72Z$0T-|OZM^QwNGUe#A|#_~IXoi{(?OmFIR*7R#tx>G;( zDoXM$G3zAL^-Vu#77tWif5Lt)OAt@T7r;yz-|y%CKM+sogCt9#p6Pc_VPF40S{ad? z?&#E_=?lf@T!H6>uSVyA_*wDyga5^Ach`oFSAZ}1r10sB?)cygla?R&Dn`k+7hw|~xwYx z^?t!&@dc|jH@TMbnY~LF*KK+1J+|NRdA%e)_xoJ_1nI!~1`j{#_7)i%9fu4N2Nn4w zEk`JWA}{AMA3s4uMFBQB+dLmiP0vsRS1nsdWoK!xUSVBt4`Ve{b*Ff1g@=hLe1Fk$ zk^O>`mIa%OrKhEjpLwDYtgoF4xjU)D#m5u2zh$xy%+F!cjoI1U{>kU*$JXIfXV0HOhZa4WbZOJ4QKweDnssZ}uVKfQJ)3rI z+qZG&*1el|Z{NRx2Nyn^cyZ&$ktbKaoH@+L&!I<`J~-n3bnDk4H(#zc?$zquy=za- z9lThb<>iVWkA7E2@@3VpXAjN&e7EtDzqeoU`+iLLkJHaT0p4OnKzIrSkhBB$OK=Yc z&v8(}&>);o!aOSE=E4a*^I(7vK^#Di4^Z+} zQ2-oc(2)clH{_5r4|gn*#}Z{Y@<$|>gyBUcl}s^_`l5u9hbXI@ABI%izFV)W}W8eDuye#e5XhQ9u4Yw9`{T#k12?7cDbYMMovo((e$J z71l!4BvsH`6*V(gUp);~*j^Ex^-|w5Ew#}}gDtk#Qhyzm%u@?}b)rHgAZ;z!cS!sc_vs_hqEtk-4r&X0x9L2SEQ+|y-PvC=1 zrI+4)uf^Blh5dauUSuOBS5kLH6&TJy6OD1%NLw{@(2zyWGgnE^OgTh&3!&6yW(RdS z=9xW4QDrl2t~usqmt}ckx-vx1=dn&?XG=o=`+2vZ%Nx3jKHR(}Y7?dw!D*$pVj8@w vkI)(!uCXo(yRpeG+b;LaPTRV$*>2nIw-DiuTkg5(uG{Xr@y^?V0ssIzQ@%@6 literal 0 HcmV?d00001 diff --git a/docs/developer/Inspector/collaborationdiagram1.pgml b/docs/developer/Inspector/collaborationdiagram1.pgml new file mode 100644 index 00000000..95c7614e --- /dev/null +++ b/docs/developer/Inspector/collaborationdiagram1.pgml @@ -0,0 +1,6 @@ + + + + diff --git a/docs/developer/Inspector/inspector.txt b/docs/developer/Inspector/inspector.txt new file mode 100644 index 00000000..acf80040 --- /dev/null +++ b/docs/developer/Inspector/inspector.txt @@ -0,0 +1,266 @@ +OK. Again I would have liked to get a design document before it being done. Main functionalities we +need in the inspector: + +- Unifiy the inspector under a single dialog box, called with 'S' + +- Depending on what is currently selected, display several frames in the inspector: +only brushes -> surface inspector +only patches -> patch inspector +brushes & patches -> both +and later when brush primitives are mixed with regular brushes + plugin entities, raise whatever +additional inspector stuff we need + +- The camera view must update realtime when we change some parameters. + +- Get rid of the Apply button, use the Undo code to store settings when surface inspector is +raised. If user hits Cancel, call the undo stuff. + +- Use the message broadcasting stuff to keep the inspectors up to date when the user changes the +current selection. Be careful to keep the undo stuff in sync with the select / deselect operations. + +- Use a 3-state scheme to display the params in the widgets. If two faces are selected that don't +have the same shift increment, just grey out the shift box. + +Messaging: +- a good chunk of the work is moving the selection/creation stuff to the messaging API + we no longer use UpdateSurfaceDialog, we post messages instead .. + the surface inspector has hooked one of it's listeners into the corresponding message + we may need to reorganize the messages, maybe introduce a hierarchy? + or pass a void * param with messages? + +- we don't post messages like "update surface inspector", we post messages that say "this and that +have changed", then the surface inspector reacts if it needs to. +Do we need marshalling in the messages? Very likely .. maybe using Gtk signal stuff would be interesting? + +-> the messaging stuff is a big chunk of work and our surface inspector changes are not totally +dependent on it. Better leave that for l8r + +the inspector works by states and transitions? Or we post messages to it? +Use case: +the user raises the inspector .. if we are up we'll ignore, if we are hidden we'll +go through the whole process (initialise, look at what is selected, display) +then we enter an active state (listening for select / deselects and applying stuff) + +all in all it seems to be too big a change for next release. will see later probably. +Trying a few more days with it, see what happens. after all the interface is fairly restricted +so there's a good chance our changes are fairly stable in the end. But rebuilding the whole interface +part might be too much ... +We need something state based? AND a set of messages .. +but first, need to write the initialisation loop +build the dialog, get the current surface information and display + +Undoing the changes on the selected stuff: +at any point in time, one can get a snapshot of selected stuff and use it to store the surface +properties settings for later on. But what happens if the user modifies the selected brush, pushing +it in the undo stack? Then we would cancel the changes? (and just backup to the state right after +the modif) +We could has the 'Apply' button used for that .. grey it out when the current state is the one in +the backup. This happens whenever we hit 'Apply' or change something in the selection. +The selection has several items: entities, brushes and selected faces (possibly later generic plugin entities) +Current undo stuff is aimed at entities and brushes. +NOTE: you can't have selected faces and brushes/entities at the same time, that's a good point to +keep that seperated to deal with undo and storage +On what side should the implemetation be ? undo.cpp select.cpp or surfacedialog.cpp ? +We are going to do it with the messaging API anyway.. +And hook in the undo stuff, to reset the snapshot each time something gets pushed in the undo? + +We have advanced stuff on the Inspector branch, doing basics on Alpha branch. +Start writing the watch code in surfacedialog.cpp, see if we need some merging with Undo stuff l8r +We need to track for the patch inspector as well.. + +basic code for CSurfaceUndo written. need to add hooks for the snapshot stuff and undo stuff. and a +debug flag to monitor the life cycle of the object. + +some use cases: +- select a brush +- bring up surface inspector +- check we had the debug messages from CSurfaceUndo (initialise, activate, snapshot) +- edit the surface settings +- check the views are updating correctly +- hit Ok +- check we had a deactivate message +OK + +- select a brush +- bring up surface inspector +- check we had the debug messages from CSurfaceUndo (initialise, activate, snapshot) +- edit the surface settings +- check the views are updating correctly +- hit cancel / escape +- check we have a undo and deactivate from CSurfaceUndo +OK + +- select a brush +- bring up the surface inspector +- edit the surface settings +- hit apply +- edit them again +- hit cancel / escape +- check you get back to the apply state +OK + +- make two brushes +- select a brush +- bring up surface inspector +- change settings +- select an additional brush +- check the surface inspector, new snapshot +- hit cancel +- check brushes remained in the same state +- use standard Undo +- check the first brush got back to it's initial settings +OK + +- select a brush +- bring up surface inspector +- change settings +- select an additional brush +- check the surface inspector, new snapshot +- change more settings +- hit cancel +- check the first brush returned to intermediate state, and second to initial state (i.e. last snapshot) +OK + +g_surfaceUndo acts as a layer on top of the core Undo code when the surface inspector is activated. +We need it because the surface inspector can edit faces which are not handled by the undo? +(or does the current code push the whole brush when editing a face?) + +not sure of the utility of the g_surfaceDialog hooks here .. +default undo usage in the sruface inspector sends way too many undo messages. +with the new scheme we store in undo only when select/deselect or user hits apply +that way the 'Cancel' and later Ctrl+Z calls make sense +but is it worth implementing a new class to achieve that?? .. yes because we intend a later cleanup +of this part. (ahem is this reason good enough..) +this part is actually much closer from the undo code than I had expected.. +'Cancel' call being an Undo call.. + +going to Inspector3: +don't create a new class, simply use the Undo more intelligently? +i.e. don't create undo stuff when editing the brush +-> we add a flag to turn off the default undo behaviour and force Undo storage when we want +we could also store the undo Id we are interested in and call undo several times to get it back + +NOTE: what happens if the user hits undo when the surface inspector is up? +-> we'll have to take his request into account? +err .. performing which undo? The texture positioning or something else? +seems the snapshot approach would still make sense then? + +more use cases, see with Undo calls and select/deselect events +NOTE: this whole thing is probably a single call to select_settexture that needs to be turned on/off +instead of working at the undo level. but we would like to move to messaging so maybe it still makes sense +the undo call is in Select_SetTexture (which does not have that many callers, I was expecting more) + +the question about having the undo code keep working when surface inspector is around is still raised. +but it makes it a lot harder, gotta have a real inspector mode in the undo? +dunno, think about it again later + +two operations are mixed in a single one and should not be: +reading the map to get the current data we'll manipulate +feed it in the dialog box widgets +WARNING: when putting stuff in the widgets, it raises a shitload of update messages and therefor completely +fucks up our OnOK OnApply OnCancel scheme (specially OnApply!) + +NOTE: we want to switch between Surface inspector for brushes only and Patch inspector for patches only +there's some crappy code in the surface inspector that we need to get rid of +but need to check about that before with Spog or others + +Forcing the way into using the surface inspector is SCREWED? +Doesn't seem to work the way we want to. Always get parasite Undo messages and stuff. +We could use a seperate stack for Undo with the surface inspector? +Just store the surface properties in a seperate stack? +When user hits cancel you go back and apply whatever you had? +Doesn't seem like a clean way either. + +Now dealing with both regular surface inspector and patch inspector: +we have some stuff that needs to be on/off with the two inspectors +what about catching the messages and issuing new snapshots? +the main surface inspector is doing it? +no! +so what, we have several states? +FUCKED UP + +INSPECTOR 5 ---------------------------------------------------------------- +restarted from scratch, made much more simple changes. +trying another trick for undo (!) +just let the undo work as usual, but call undo ourselves in SetTexMods if we have create the last do +requires proper initialization/deinitialisation.. in SetTexMods and GetTexMods.. + +getting rid of patch manipulation code in the regular surface inspector. The buttons will +still work, but manip will require the patch inspector. (seems the patch inspector doesn't have that +much success anyway) + +TODO: +OK get rid of patch stuff +OK get rid of the texture toolbar? (it's broken right now) + (and doesn't have anything usefull..) +OK (Partial) OnCancel? we need to cancel the texdef as well + store an undo texdef each time we grab new texdef stuff + this works in reverse than the Undo code? When we do the initial + problem is, in some cases the settings that show up are not in sync with what's in the inspector?? + (we can't avoid that because if a brush is selected there's no single setting) + prolly get it out as is and let Spog or others send feedback about what it's supposed to do.. + for now: store stuff in the cancel texdef when we initialize an undo loop + revert to that if OnCancel is used +OK message when spinning over a patch? +DUPLICATE (.. see below ..) check the increments we store in the SI are used when shift + arrows etc. + no it doesn't work .. the shifting on keyboard shortcuts is done with m_nTextureTweak + seems m_nTextureTweak is nowhere available in the prefs (and it's not in MFC builds either) + some cleanup to be done around that it seems +OK (.. merged with below, maybe some special cases left ..) texture widget (catch the Enter key to force-call an OnApply) +OK (.. see above ..) catch Enter key at dialog level to call OnDone +NO (.. it's clean, but thats too many lines of code ..) move the code that blokes updates to use gtk_signal_handler_block_by_func and gtk_signal_handler_block_by_func +OK shift + arrow must match the SI settings, +OK (FIXME .. not using the right scale (using the scale step instead! + add a button in SI to 'Match grid') +POSTPONED (.. m_nTextureTweak is used in the nudge commands .. + .. and nudge shortcuts are broken right now ..) get rid of m_nTextureTweak ++ SI and PI always on top! + ++ known issues: "Match Grid" is broken in BP mode + +now on the patch inspector (nightmare!): +OK (.. put it as readonly .. don't bother ..) texture name widget is screwed? +OK the spinners scheme doesn't work, the stuff in the dialog is the inc step and we just need arrows +OK get rid of the 'Type' dialog box +POSTPONED (.. can't do undo on PI without proper Undo module ..) add proper Done Apply Cancel with Undo +NO (.. too much work for something that sucks ..) make the changes reflect in the views when manipulating the entries +OK (.. using %g ..) cut down on the number of digits! +OK increment steps to be stored in the registry + +putting the Cancel stuff in the surface inspector: only based on the Undo code, no cancel settings to store +because we don't have actual storage of a current texdef (we only send alterations) BTW we should do that for +brushes as well +the patch inspector works by increments, Patch_SetTextureInfo to incrementally modify the patch. +we can still do some undo by having a texdef storing the changes and working together with the undo +if the undo is recognized, it means our current texdef increment is valid +no, we can't represent the combination of several increments scale and rotate in a single texdef.. +get rid of the undo code for now .. only Apply and Done left + +it seems it's still vastly broken when you select something. or is it on linux only? +need a LOT of testing and figuring it out!! +selecting a brush breaks totally.. (the texture screws up it seems) +does it attempt to change the texture of the selected object?? +also: it seems you can multiple select a same brush?? + +the UNDO code of the SURFACE INSPECTOR IS STILL BROKEN ???? +(ok I'm really screwed, time to sleep) +-> can't reproduce now?? maybe it's linux specific problem, I can't tell + +FOUND A WAY TO REPRODUCE THE CRASH: ++ select brush ++ hit "Fit" ++ hit the shift spinners two times +OR: ++ select single face on brush ++ manually edit scale values +-> maybe we have a problem with current texture? (NO) +it's some kind of infinite loop? we call UpdateSurfaceInspector from Select_Brush and bang! +no, it's a texdef from a face that got deleted +prolly that hooking the undo code in there screws up the selected faces stuff +if you undo a selected face operation, you end up with the whole brush selected. +but that does not necessarily explain why you remove the face at Undo_Start +ho well .. removed the undo buffering when selected faces and everything's better +would need to re-establish the right face selection after undo, might solve the problem +(actually you'd still need to have the settings point to the right object) + +From PJ about the 'Match Grid' stuff: textures are moved in pixels, not units. +We must rely on the current texture scale AND gridsize to compute the shift increment diff --git a/docs/developer/RegExp/Go b/docs/developer/RegExp/Go new file mode 100644 index 00000000..9c6a3ce7 --- /dev/null +++ b/docs/developer/RegExp/Go @@ -0,0 +1,92 @@ +./replace.pl bsp.c 255 +./replace.pl facebsp.c 240 +./replace.pl facebsp.c 251 +./replace.pl facebsp.c 260 +./replace.pl fog.c 83 +./replace.pl fog.c 439 +./replace.pl fog.c 529 +./replace.pl fog.c 530 +./replace.pl fog.c 531 +./replace.pl fog.c 532 +./replace.pl leakfile.c 34 +./replace.pl leakfile.c 75 +light.c:212: qprintf ("--- CountLightmaps ---\n"); +light.c:228: qprintf( "%5i drawSurfaces\n", numDrawSurfaces ); +light.c:229: qprintf( "%5i lightmaps\n", count ); +light.c:252: qprintf ("--- CreateSurfaceLights ---\n"); +light.c:1730: qprintf( "%5i gridPoints\n", numGridPoints ); +light.c:1786: qprintf ("--- CreateLights ---\n"); +light.c:1788: qprintf ("%i point lights\n", numPointLights); +light.c:1789: qprintf ("%i area lights\n", numAreaLights); +light.c:1792: qprintf ("--- TraceGrid ---\n"); +light.c:1794: qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1], +light.c:1798: qprintf ("--- TraceLtm ---\n"); +light.c:1800: qprintf( "%5i visible samples\n", c_visible ); +light.c:1801: qprintf( "%5i occluded samples\n", c_occluded ); +lightmaps.c:312: qprintf ("--- AllocateLightmaps ---\n"); +lightmaps.c:347: qprintf( "%5i unique shaders\n", numSortShaders ); +lightmaps.c:369: qprintf( "%7i exact lightmap texels\n", c_exactLightmap ); +lightmaps.c:370: qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT ); +lightv.c:4769: qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]); +lightv.c:4771: qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]); +map.c:294: qprintf ("Entity %i, Brush %i: mixed face contents\n" +map.c:1138: qprintf ("--- LoadMapFile ---\n"); +map.c:1163: qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) ); +map.c:1164: qprintf ("%5i detail brushes\n", c_detail ); +map.c:1165: qprintf ("%5i patches\n", numMapPatches); +map.c:1166: qprintf ("%5i boxbevels\n", c_boxbevels); +map.c:1167: qprintf ("%5i edgebevels\n", c_edgebevels); +map.c:1168: qprintf ("%5i entities\n", num_entities); +map.c:1169: qprintf ("%5i planes\n", nummapplanes); +map.c:1170: qprintf ("%5i areaportals\n", c_areaportals); +map.c:1171: qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], +misc_model.c:411: qprintf("----- AddTriangleModels -----\n"); +misc_model.c:446: qprintf( "%5i triangle models\n", c_triangleModels ); +misc_model.c:447: qprintf( "%5i triangle surfaces\n", c_triangleSurfaces ); +misc_model.c:448: qprintf( "%5i triangle vertexes\n", c_triangleVertexes ); +misc_model.c:449: qprintf( "%5i triangle indexes\n", c_triangleIndexes ); +patch.c:176: qprintf( "----- PatchMapDrawSurfs -----\n" ); +patch.c:262: qprintf( "%5i patches\n", patchCount ); +patch.c:263: qprintf( "%5i patch LOD groups\n", groupCount ); +portals.c:500: qprintf( "----- MakeTreePortals -----\n"); +portals.c:503: qprintf("%6d tiny portals\n", c_tinyportals); +portals.c:589: qprintf ("--- FloodEntities ---\n"); +portals.c:608: qprintf("%5i flooded leafs\n", c_floodedleafs ); +portals.c:612: qprintf ("no entities in open -- no filling\n"); +portals.c:616: qprintf ("entity reached from outside -- no filling\n"); +portals.c:762: qprintf ("--- FloodAreas ---\n"); +portals.c:768: qprintf ("%5i areas\n", c_areas); +portals.c:813: qprintf ("--- FillOutside ---\n"); +portals.c:815: qprintf ("%5i solid leafs\n", c_solid); +portals.c:816: qprintf ("%5i leafs filled\n", c_outside); +portals.c:817: qprintf ("%5i inside leafs\n", c_inside); +prtfile.c:213: qprintf ("--- NumberClusters ---\n"); +prtfile.c:218: qprintf ("%5i visclusters\n", num_visclusters); +prtfile.c:219: qprintf ("%5i visportals\n", num_visportals); +prtfile.c:220: qprintf ("%5i solidfaces\n", num_solidfaces); +prtfile.c:232: qprintf ("--- WritePortalFile ---\n"); +shaders.c:301:// qprintf( "shaderFile: %s\n", filename ); +shaders.c:600: qprintf( "%5i shaderInfo\n", numShaderInfo); +surface.c:176: qprintf( "----- MergeSides -----\n"); +surface.c:182: qprintf( "%5i siderefs\n", numSideRefs ); +surface.c:266: qprintf( "----- SubdivideDrawSurfs -----\n"); +surface.c:365: qprintf( "----- ClipSidesIntoTree -----\n"); +surface.c:1013: qprintf( "----- FilterDrawsurfsIntoTree -----\n"); +surface.c:1045: qprintf( "%5i emited drawsurfs\n", c_surfs ); +surface.c:1046: qprintf( "%5i references\n", c_refs ); +surface.c:1047: qprintf( "%5i stripfaces\n", c_stripSurfaces ); +surface.c:1048: qprintf( "%5i fanfaces\n", c_fanSurfaces ); +tjunction.c:476: qprintf("----- FixTJunctions -----\n"); +tjunction.c:508: qprintf( "%6i axial edge lines\n", axialEdgeLines ); +tjunction.c:509: qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines ); +tjunction.c:510: qprintf( "%6i degenerate edges\n", c_degenerateEdges ); +tjunction.c:525: qprintf( "%6i verts added for tjunctions\n", c_addedVerts ); +tjunction.c:526: qprintf( "%6i total verts\n", c_totalVerts ); +tjunction.c:527: qprintf( "%6i naturally ordered\n", c_natural ); +tjunction.c:528: qprintf( "%6i rotated orders\n", c_rotate ); +tjunction.c:529: qprintf( "%6i can't order\n", c_cant ); +vis.c:223: qprintf ("cluster %4i : %4i visible\n", leafnum, numvis); +visflow.c:642: qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", +visflow.c:774: qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", +visflow.c:1037: qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", +writebsp.c:388: qprintf ("--- EndModel ---\n"); diff --git a/docs/developer/RegExp/Go.cleaned b/docs/developer/RegExp/Go.cleaned new file mode 100644 index 00000000..be03c468 --- /dev/null +++ b/docs/developer/RegExp/Go.cleaned @@ -0,0 +1,92 @@ +./replace.pl bsp.c 255 +./replace.pl facebsp.c 240 +./replace.pl facebsp.c 251 +./replace.pl facebsp.c 260 +./replace.pl fog.c 83 +./replace.pl fog.c 439 +./replace.pl fog.c 529 +./replace.pl fog.c 530 +./replace.pl fog.c 531 +./replace.pl fog.c 532 +./replace.pl leakfile.c 34 +./replace.pl leakfile.c 75 +./replace.pl light.c 212 +./replace.pl light.c 228 +./replace.pl light.c 229 +./replace.pl light.c 252 +./replace.pl light.c 1730 +./replace.pl light.c 1786 +./replace.pl light.c 1788 +./replace.pl light.c 1789 +./replace.pl light.c 1792 +./replace.pl light.c 1794 +./replace.pl light.c 1798 +./replace.pl light.c 1800 +./replace.pl light.c 1801 +./replace.pl lightmaps.c 312 +./replace.pl lightmaps.c 347 +./replace.pl lightmaps.c 369 +./replace.pl lightmaps.c 370 +./replace.pl lightv.c 4769 +./replace.pl lightv.c 4771 +./replace.pl map.c 294 +./replace.pl map.c 1138 +./replace.pl map.c 1163 +./replace.pl map.c 1164 +./replace.pl map.c 1165 +./replace.pl map.c 1166 +./replace.pl map.c 1167 +./replace.pl map.c 1168 +./replace.pl map.c 1169 +./replace.pl map.c 1170 +./replace.pl map.c 1171 +./replace.pl misc_model.c 411 +./replace.pl misc_model.c 446 +./replace.pl misc_model.c 447 +./replace.pl misc_model.c 448 +./replace.pl misc_model.c 449 +./replace.pl patch.c 176 +./replace.pl patch.c 262 +./replace.pl patch.c 263 +./replace.pl portals.c 500 +./replace.pl portals.c 503 +./replace.pl portals.c 589 +./replace.pl portals.c 608 +./replace.pl portals.c 612 +./replace.pl portals.c 616 +./replace.pl portals.c 762 +./replace.pl portals.c 768 +./replace.pl portals.c 813 +./replace.pl portals.c 815 +./replace.pl portals.c 816 +./replace.pl portals.c 817 +./replace.pl prtfile.c 213 +./replace.pl prtfile.c 218 +./replace.pl prtfile.c 219 +./replace.pl prtfile.c 220 +./replace.pl prtfile.c 232 +./replace.pl shaders.c 301 +./replace.pl shaders.c 600 +./replace.pl surface.c 176 +./replace.pl surface.c 182 +./replace.pl surface.c 266 +./replace.pl surface.c 365 +./replace.pl surface.c 1013 +./replace.pl surface.c 1045 +./replace.pl surface.c 1046 +./replace.pl surface.c 1047 +./replace.pl surface.c 1048 +./replace.pl tjunction.c 476 +./replace.pl tjunction.c 508 +./replace.pl tjunction.c 509 +./replace.pl tjunction.c 510 +./replace.pl tjunction.c 525 +./replace.pl tjunction.c 526 +./replace.pl tjunction.c 527 +./replace.pl tjunction.c 528 +./replace.pl tjunction.c 529 +./replace.pl vis.c 223 +./replace.pl visflow.c 642 +./replace.pl visflow.c 774 +./replace.pl visflow.c 1037 +./replace.pl writebsp.c 388 diff --git a/docs/developer/RegExp/pattern b/docs/developer/RegExp/pattern new file mode 100644 index 00000000..843bb113 --- /dev/null +++ b/docs/developer/RegExp/pattern @@ -0,0 +1,4 @@ +#s/.*:/.\/replace.pl &/ +#s/\(.*\):\([0-9]*\):\(.*\):/.\/replace.pl \1 \2/ +#s/\(.*\):\([0-9]*\):/.\/replace.pl \1 \2 / +s/\(.*\):\([0-9]*\):\(.*\)/.\/replace.pl \1 \2 / \ No newline at end of file diff --git a/docs/developer/RegExp/replace.pl b/docs/developer/RegExp/replace.pl new file mode 100644 index 00000000..86bbb389 --- /dev/null +++ b/docs/developer/RegExp/replace.pl @@ -0,0 +1,17 @@ +#!perl +rename("$ARGV[0]", "$ARGV[0].old"); +open(FILE, "$ARGV[0].old"); +open(OFILE, ">$ARGV[0]"); +while() +{ +if($. != $ARGV[1]) +{ +print OFILE; +next; +} +s/Sys_Printf \(/Sys_FPrintf \(SYS_VRB,/; +s/Sys_Printf\(/Sys_FPrintf \(SYS_VRB,/; +print OFILE; +} +close(OFILE); +close(FILE); \ No newline at end of file diff --git a/docs/developer/RegExp/tstscrpt.pl b/docs/developer/RegExp/tstscrpt.pl new file mode 100644 index 00000000..84e646d3 --- /dev/null +++ b/docs/developer/RegExp/tstscrpt.pl @@ -0,0 +1,17 @@ +#!perl +rename("brush.c", "brush.c.old"); +open(FILE, "brush.c.old"); +open(OFILE, ">brush.c"); +while() +{ +if($. != 150) +{ +print OFILE; +next; +} +s/Sys_Printf \(/Sys_FPrintf \(SYS_VRB,/; +s/Sys_Printf\(/Sys_FPrintf \(SYS_VRB,/; +print OFILE; +} +close(OFILE); +close(FILE); \ No newline at end of file diff --git a/docs/developer/TESTERS b/docs/developer/TESTERS new file mode 100644 index 00000000..6b3e5c1c --- /dev/null +++ b/docs/developer/TESTERS @@ -0,0 +1,19 @@ +a few basic contacts for people willing to test GtkRadiant: + ++ everyone on the RadiantBinaries mailing list + ++ ----------------------- + |UL|FeNiX: (5:20 PM) when will you be letting loose a new beta for this "completely" new radiant? + |UL|FeNiX: (5:20 PM) I would love the honor to help you alpha and or beta test anything....... + |UL|FeNiX: (5:20 PM) you could consider me your win2K tester...... +Tim: (5:21 PM) well .. within a few days I hope .. it will need lots of testing +but I want something that is basically usable before we can go forward +yeah, w2k testing is much needed +what's your email? + + |UL|FeNiX: (5:21 PM) kingfenix1@home.com +Tim: (5:21 PM) k + ++ GL slowdowns tests -------------------------------------------- +mac (from Q3W forum) +gangstapoodle@hotmail.com diff --git a/docs/developer/TODO b/docs/developer/TODO new file mode 100644 index 00000000..fbfbb5f1 --- /dev/null +++ b/docs/developer/TODO @@ -0,0 +1,123 @@ +Things that need to be done in Q3Radiant Linux: + +- copy and paste to other instances + +Bugs: + +- The surface inspector is not updated if you close it, + select another brush and open it again. (Win32 too) + +Win32 version BUGS/TODO list: + +- write an XP version of _stat / FileExists in cmdlib +- put the sleep thing in a proper place, bind it in the keyboard shortcuts +- console output bugs: properly format the output, fix "console not scrolling but keeps + overwriting lines" + we no longer need to convert to CR/LF to output in the console. removed that. + interesting piece about the text widget here: + http://www.gtk.org/tutorial/gtk_tut-14.html + added freeze and thaw calls in Sys_BeginWait Sys_EndWait + need to call Sys_BeginWait Sys_EndWait in all appropriate places (Map_LoadFile) + need to limit size of the console, and scroll down on output + wrote a test program that reproduces the bug with scrolling +- write a coding directions document (what and where to put stuff) + qe3.h, globals, map data storage structures + see DevDocs/draft, need to do something along those lines +- remember maximized state (not only the size) + and various window position settings +- get rid of the SGIOpenGL flag, (make it default?) + actually, remove all the prefs crap that's not relevant +- widgets too big? + at least the menus, or the dialog boxes as well? +- get rid of Texture_LoadTGATexture (or rename it) + (do l8r) +- sleep mode +- proper about box +- have basic default position and size for the windows in the four views +- plugin API +- have plugin links accessed from plugins menu +- make sure the registry cleaning works +- version information! +- custom shortcut keys file! + shortcut.ini ? +- problem with strPrefab + +- fix user.qe4 thing, don't overwrite. And tell the user about it. Actually allow him to + select another location / name for the project file. + +- command map: changing the file to command.ini? put it in the same dir as radiant.ini + (get rid of user path + +- logging console: add the checkbox +- add the radiant.pid detection!! (this is from 200 -> 201) +- remember window position on the desktop and maximized state +- fix browsing for a directory, the win32 dialog to browse for a dir is fucked +- check creating a new project on linux, I rewrote it and tested on win +- cleanup the q3map code, remove the dirty __TTIMOBUILD stuff + +- changes to the jpeg library for the MFC version, must make their way to Gtk + (proper error handling) + +- saving window pos in MainFrame::OnDestroy crashes in 4-view mode (Sagnor) +- 4-view: [00:31] oh and the "o" for the console doens't work + +FIXED: -------- +- Printing: Saving screenshot instead +- icon in KDE has "name=quake3": Fixed in the latest setup (thanks Stephane) +- add precompiled headers to speedup building + done. basically added stdafx.h, the VC5 project needs to be updated + stdafx.cpp: generate precompiled header with stdafx.h + all other files: automatic use of precompiled headers... + (maybe later add more headers to stdafx) +- context switch problems + seem to have disappeared since I fixed a bug in Str + no it's definitely back! + fix by Leo, hacked into gdk.dll for CS_OWNDC window class style +- use proper texture when not found instead of white + Leo fixed, bug in the custom gluBuild2DMipmaps +- use registry + for window positions <- Leo did + have proper default positions! +- bitmap loading broken (can't get anything to load up) + ok Leo fixed +- renaming some files .. linux_dlgs.cpp to dlgs.cpp etc. let's be neutral! + done that .. removed linux_*, renamed qgl_linux.c to qgl.c + (Makefile and VC5 project need updating) +- prefs stuff? big open/close loop on radiant.ini? + fixed radiant.ini growing huge on win32 (doesn't seem to affect the linux version) + will have to check with a profiler if that's so bad +- fixed m_strQuake2 (change name and have proper defaults) + it's the path to the engine we've all been waiting for! +- fixed the new project step +- fixed paklog crashes if /tmp/paklog.txt and the dir tmp doesn't exist on win32 + (ask windows for the temp directory? .. I would put in radiant current dir .. on win32) + also check on a machine that doesn't define a HOME env var! +- can't reproduce: crash in gluBuild2DMipmaps? seems very random. was not able to reproduce + it for sure. First time happened on base_trim/pewter. + happens on image[k++] = *ubptr++; (l1038) +- merge 201 in, use the console logging stuff to debug project settings things + +DISCUSSION LOG ABOUT GL SPEED: +[19:17] Then why not use your own main, calling g_main_iteration at even intervals? :) +[19:17] shuoldn't be too hard. I hve plenty of code like that +[19:18] *** Joins: Centove (gregm@coco.comstar.net) +[19:18] while(1) { while(g_main_iteration(0)) /* do nothing, process until done */; [do own stuff]; pause(); } or so +[19:18] I see .. well actually my main problem is that the GL view is dead slow +[19:19] at first we though it was because of all the stuff between windows and the handlers +[19:19] but the problem seems somwhere else +[19:20] can you profile the code? +[19:21] we'll try .. but actually I don't know for sure where the perfomance hit happens +[19:21] might be because it doesn't process the mouse messages quickly enough, or because the refresh messages are sent once every g_main_interaction +[19:22] but compared to the MFC version, it feels sluggish +[19:22] yoda: fwiw, it looks like Lance mispaired two sets of speakers when he packed up the Utah offices. If you have no complaints, I'll put my mismatched pair back and take a known pair, which should leave you even. 'k? +[19:22] I believe that g_main can block +[19:23] block? what do you mean? +[19:23] g_main_iteration(1) blocks if there are no events to process +[19:23] might not be at all what's wrong here though. :) +[19:23] you mean it sleeps until more events happen? +[19:23] yeahj +[19:24] well that would not be a problem .. the problem is I'd like to emit paint messages faster when the user interacts with the GL window +[19:24] I don't know g_main works, but I would assume it uses g_main_iteration(1) +[19:24] ok, well thanks for the insight .. we'll keep looking anyway +[19:24] hmm. Your own main look might do the trick, possibly. Dunno. :) + diff --git a/docs/developer/TstMaps/Desktop_pb_leaf.map b/docs/developer/TstMaps/Desktop_pb_leaf.map new file mode 100644 index 00000000..da1a4a4b --- /dev/null +++ b/docs/developer/TstMaps/Desktop_pb_leaf.map @@ -0,0 +1,9221 @@ +{ +"classname" "worldspawn" +"music" "sounds/world/desktop/intro.wav sounds/world/desktop/loop.wav" +// brush 0 +{ +( 1391 438 1580 ) ( 1263 438 1580 ) ( 1263 426 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 469 1595 ) ( 1259 481 1595 ) ( 1387 481 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 364 1593 ) ( 1387 364 1593 ) ( 1387 364 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 380 1593 ) ( 1423 392 1593 ) ( 1423 392 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 527 1595 ) ( 1227 527 1595 ) ( 1227 527 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 376 1593 ) ( 1259 364 1593 ) ( 1259 364 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 1391 977 1579 ) ( 1263 977 1579 ) ( 1263 965 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 1008 1594 ) ( 1259 1020 1594 ) ( 1387 1020 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 903 1592 ) ( 1387 903 1592 ) ( 1387 903 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 919 1592 ) ( 1423 931 1592 ) ( 1423 931 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 1066 1594 ) ( 1227 1066 1594 ) ( 1227 1066 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 915 1592 ) ( 1259 903 1592 ) ( 1259 903 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( 1919 793 1579 ) ( 1791 793 1579 ) ( 1791 781 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 824 1594 ) ( 1787 836 1594 ) ( 1915 836 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 719 1592 ) ( 1915 719 1592 ) ( 1915 719 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1951 735 1592 ) ( 1951 747 1592 ) ( 1951 747 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1883 882 1594 ) ( 1755 882 1594 ) ( 1755 882 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 731 1592 ) ( 1787 719 1592 ) ( 1787 719 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 1919 -807 1579 ) ( 1791 -807 1579 ) ( 1791 -819 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 -776 1594 ) ( 1787 -764 1594 ) ( 1915 -764 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 -881 1592 ) ( 1915 -881 1592 ) ( 1915 -881 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1951 -865 1592 ) ( 1951 -853 1592 ) ( 1951 -853 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1883 -718 1594 ) ( 1755 -718 1594 ) ( 1755 -718 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 -869 1592 ) ( 1787 -881 1592 ) ( 1787 -881 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 855 -983 1579 ) ( 727 -983 1579 ) ( 727 -995 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 723 -952 1594 ) ( 723 -940 1594 ) ( 851 -940 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 723 -1057 1592 ) ( 851 -1057 1592 ) ( 851 -1057 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 887 -1041 1592 ) ( 887 -1029 1592 ) ( 887 -1029 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 819 -894 1594 ) ( 691 -894 1594 ) ( 691 -894 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 723 -1045 1592 ) ( 723 -1057 1592 ) ( 723 -1057 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 1391 -623 1579 ) ( 1263 -623 1579 ) ( 1263 -635 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -592 1594 ) ( 1259 -580 1594 ) ( 1387 -580 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -697 1592 ) ( 1387 -697 1592 ) ( 1387 -697 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 -681 1592 ) ( 1423 -669 1592 ) ( 1423 -669 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 -534 1594 ) ( 1227 -534 1594 ) ( 1227 -534 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -685 1592 ) ( 1259 -697 1592 ) ( 1259 -697 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 1391 -1162 1580 ) ( 1263 -1162 1580 ) ( 1263 -1174 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -1131 1595 ) ( 1259 -1119 1595 ) ( 1387 -1119 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -1236 1593 ) ( 1387 -1236 1593 ) ( 1387 -1236 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 -1220 1593 ) ( 1423 -1208 1593 ) ( 1423 -1208 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 -1073 1595 ) ( 1227 -1073 1595 ) ( 1227 -1073 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -1224 1593 ) ( 1259 -1236 1593 ) ( 1259 -1236 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( 311 -642 1580 ) ( 183 -642 1580 ) ( 183 -654 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -611 1595 ) ( 179 -599 1595 ) ( 307 -599 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -716 1593 ) ( 307 -716 1593 ) ( 307 -716 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 -700 1593 ) ( 343 -688 1593 ) ( 343 -688 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 -553 1595 ) ( 147 -553 1595 ) ( 147 -553 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -704 1593 ) ( 179 -716 1593 ) ( 179 -716 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( 311 -103 1579 ) ( 183 -103 1579 ) ( 183 -115 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -72 1594 ) ( 179 -60 1594 ) ( 307 -60 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -177 1592 ) ( 307 -177 1592 ) ( 307 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 -161 1592 ) ( 343 -149 1592 ) ( 343 -149 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 -14 1594 ) ( 147 -14 1594 ) ( 147 -14 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -165 1592 ) ( 179 -177 1592 ) ( 179 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( -225 -463 1579 ) ( -353 -463 1579 ) ( -353 -475 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 -432 1594 ) ( -357 -420 1594 ) ( -229 -420 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 -537 1592 ) ( -229 -537 1592 ) ( -229 -537 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -193 -521 1592 ) ( -193 -509 1592 ) ( -193 -509 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -261 -374 1594 ) ( -389 -374 1594 ) ( -389 -374 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 -525 1592 ) ( -357 -537 1592 ) ( -357 -537 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( 839 -287 1579 ) ( 711 -287 1579 ) ( 711 -299 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 -256 1594 ) ( 707 -244 1594 ) ( 835 -244 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 -361 1592 ) ( 835 -361 1592 ) ( 835 -361 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 871 -345 1592 ) ( 871 -333 1592 ) ( 871 -333 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 803 -198 1594 ) ( 675 -198 1594 ) ( 675 -198 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 -349 1592 ) ( 707 -361 1592 ) ( 707 -361 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( -585 -103 1579 ) ( -713 -103 1579 ) ( -713 -115 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 -72 1594 ) ( -717 -60 1594 ) ( -589 -60 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 -177 1592 ) ( -589 -177 1592 ) ( -589 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -553 -161 1592 ) ( -553 -149 1592 ) ( -553 -149 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -621 -14 1594 ) ( -749 -14 1594 ) ( -749 -14 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 -165 1592 ) ( -717 -177 1592 ) ( -717 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( -1649 -279 1579 ) ( -1777 -279 1579 ) ( -1777 -291 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 -248 1594 ) ( -1781 -236 1594 ) ( -1653 -236 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 -353 1592 ) ( -1653 -353 1592 ) ( -1653 -353 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1617 -337 1592 ) ( -1617 -325 1592 ) ( -1617 -325 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1685 -190 1594 ) ( -1813 -190 1594 ) ( -1813 -190 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 -341 1592 ) ( -1781 -353 1592 ) ( -1781 -353 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( -1113 81 1579 ) ( -1241 81 1579 ) ( -1241 69 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 112 1594 ) ( -1245 124 1594 ) ( -1117 124 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 7 1592 ) ( -1117 7 1592 ) ( -1117 7 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 23 1592 ) ( -1081 35 1592 ) ( -1081 35 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 170 1594 ) ( -1277 170 1594 ) ( -1277 170 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 19 1592 ) ( -1245 7 1592 ) ( -1245 7 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 14 +{ +( -1113 -458 1580 ) ( -1241 -458 1580 ) ( -1241 -470 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 -427 1595 ) ( -1245 -415 1595 ) ( -1117 -415 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 -532 1593 ) ( -1117 -532 1593 ) ( -1117 -532 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 -516 1593 ) ( -1081 -504 1593 ) ( -1081 -504 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 -369 1595 ) ( -1277 -369 1595 ) ( -1277 -369 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 -520 1593 ) ( -1245 -532 1593 ) ( -1245 -532 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 15 +{ +( -1113 630 1580 ) ( -1241 630 1580 ) ( -1241 618 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 661 1595 ) ( -1245 673 1595 ) ( -1117 673 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 556 1593 ) ( -1117 556 1593 ) ( -1117 556 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 572 1593 ) ( -1081 584 1593 ) ( -1081 584 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 719 1595 ) ( -1277 719 1595 ) ( -1277 719 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 568 1593 ) ( -1245 556 1593 ) ( -1245 556 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 16 +{ +( -1113 1169 1579 ) ( -1241 1169 1579 ) ( -1241 1157 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1200 1594 ) ( -1245 1212 1594 ) ( -1117 1212 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1095 1592 ) ( -1117 1095 1592 ) ( -1117 1095 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 1111 1592 ) ( -1081 1123 1592 ) ( -1081 1123 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 1258 1594 ) ( -1277 1258 1594 ) ( -1277 1258 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1107 1592 ) ( -1245 1095 1592 ) ( -1245 1095 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 17 +{ +( -1649 809 1579 ) ( -1777 809 1579 ) ( -1777 797 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 840 1594 ) ( -1781 852 1594 ) ( -1653 852 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 735 1592 ) ( -1653 735 1592 ) ( -1653 735 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1617 751 1592 ) ( -1617 763 1592 ) ( -1617 763 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1685 898 1594 ) ( -1813 898 1594 ) ( -1813 898 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 747 1592 ) ( -1781 735 1592 ) ( -1781 735 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 18 +{ +( -585 985 1579 ) ( -713 985 1579 ) ( -713 973 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 1016 1594 ) ( -717 1028 1594 ) ( -589 1028 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 911 1592 ) ( -589 911 1592 ) ( -589 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -553 927 1592 ) ( -553 939 1592 ) ( -553 939 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -621 1074 1594 ) ( -749 1074 1594 ) ( -749 1074 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 923 1592 ) ( -717 911 1592 ) ( -717 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 19 +{ +( 839 801 1579 ) ( 711 801 1579 ) ( 711 789 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 832 1594 ) ( 707 844 1594 ) ( 835 844 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 727 1592 ) ( 835 727 1592 ) ( 835 727 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 871 743 1592 ) ( 871 755 1592 ) ( 871 755 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 803 890 1594 ) ( 675 890 1594 ) ( 675 890 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 739 1592 ) ( 707 727 1592 ) ( 707 727 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 20 +{ +( -225 625 1579 ) ( -353 625 1579 ) ( -353 613 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 656 1594 ) ( -357 668 1594 ) ( -229 668 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 551 1592 ) ( -229 551 1592 ) ( -229 551 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -193 567 1592 ) ( -193 579 1592 ) ( -193 579 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -261 714 1594 ) ( -389 714 1594 ) ( -389 714 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 563 1592 ) ( -357 551 1592 ) ( -357 551 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 21 +{ +( 311 985 1579 ) ( 183 985 1579 ) ( 183 973 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1016 1594 ) ( 179 1028 1594 ) ( 307 1028 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 911 1592 ) ( 307 911 1592 ) ( 307 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 927 1592 ) ( 343 939 1592 ) ( 343 939 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 1074 1594 ) ( 147 1074 1594 ) ( 147 1074 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 923 1592 ) ( 179 911 1592 ) ( 179 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 22 +{ +( 311 446 1580 ) ( 183 446 1580 ) ( 183 434 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 477 1595 ) ( 179 489 1595 ) ( 307 489 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 372 1593 ) ( 307 372 1593 ) ( 307 372 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 388 1593 ) ( 343 400 1593 ) ( 343 400 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 535 1595 ) ( 147 535 1595 ) ( 147 535 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 384 1593 ) ( 179 372 1593 ) ( 179 372 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 23 +{ +( 847 1326 1580 ) ( 719 1326 1580 ) ( 719 1314 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1357 1595 ) ( 715 1369 1595 ) ( 843 1369 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1252 1593 ) ( 843 1252 1593 ) ( 843 1252 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 879 1268 1593 ) ( 879 1280 1593 ) ( 879 1280 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 811 1415 1595 ) ( 683 1415 1595 ) ( 683 1415 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1264 1593 ) ( 715 1252 1593 ) ( 715 1252 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 24 +{ +( 847 1865 1579 ) ( 719 1865 1579 ) ( 719 1853 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1896 1594 ) ( 715 1908 1594 ) ( 843 1908 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1791 1592 ) ( 843 1791 1592 ) ( 843 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 879 1807 1592 ) ( 879 1819 1592 ) ( 879 1819 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 811 1954 1594 ) ( 683 1954 1594 ) ( 683 1954 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1803 1592 ) ( 715 1791 1592 ) ( 715 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 25 +{ +( 311 1505 1579 ) ( 183 1505 1579 ) ( 183 1493 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1536 1594 ) ( 179 1548 1594 ) ( 307 1548 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1431 1592 ) ( 307 1431 1592 ) ( 307 1431 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 1447 1592 ) ( 343 1459 1592 ) ( 343 1459 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 1594 1594 ) ( 147 1594 1594 ) ( 147 1594 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1443 1592 ) ( 179 1431 1592 ) ( 179 1431 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 26 +{ +( 1375 1681 1579 ) ( 1247 1681 1579 ) ( 1247 1669 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1243 1712 1594 ) ( 1243 1724 1594 ) ( 1371 1724 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1243 1607 1592 ) ( 1371 1607 1592 ) ( 1371 1607 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1407 1623 1592 ) ( 1407 1635 1592 ) ( 1407 1635 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1339 1770 1594 ) ( 1211 1770 1594 ) ( 1211 1770 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1243 1619 1592 ) ( 1243 1607 1592 ) ( 1243 1607 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 27 +{ +( -49 1865 1579 ) ( -177 1865 1579 ) ( -177 1853 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -181 1896 1594 ) ( -181 1908 1594 ) ( -53 1908 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -181 1791 1592 ) ( -53 1791 1592 ) ( -53 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -17 1807 1592 ) ( -17 1819 1592 ) ( -17 1819 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -85 1954 1594 ) ( -213 1954 1594 ) ( -213 1954 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -181 1803 1592 ) ( -181 1791 1592 ) ( -181 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 28 +{ +( -1113 1689 1579 ) ( -1241 1689 1579 ) ( -1241 1677 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1720 1594 ) ( -1245 1732 1594 ) ( -1117 1732 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1615 1592 ) ( -1117 1615 1592 ) ( -1117 1615 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 1631 1592 ) ( -1081 1643 1592 ) ( -1081 1643 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 1778 1594 ) ( -1277 1778 1594 ) ( -1277 1778 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1627 1592 ) ( -1245 1615 1592 ) ( -1245 1615 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 29 +{ +( -577 2049 1579 ) ( -705 2049 1579 ) ( -705 2037 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 2080 1594 ) ( -709 2092 1594 ) ( -581 2092 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1975 1592 ) ( -581 1975 1592 ) ( -581 1975 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -545 1991 1592 ) ( -545 2003 1592 ) ( -545 2003 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -613 2138 1594 ) ( -741 2138 1594 ) ( -741 2138 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1987 1592 ) ( -709 1975 1592 ) ( -709 1975 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 30 +{ +( -577 1510 1580 ) ( -705 1510 1580 ) ( -705 1498 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1541 1595 ) ( -709 1553 1595 ) ( -581 1553 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1436 1593 ) ( -581 1436 1593 ) ( -581 1436 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -545 1452 1593 ) ( -545 1464 1593 ) ( -545 1464 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -613 1599 1595 ) ( -741 1599 1595 ) ( -741 1599 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1448 1593 ) ( -709 1436 1593 ) ( -709 1436 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 31 +{ +( -392 667 -457 ) ( -412 643 -453 ) ( -382 623 -416 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -422 689 -474 ) ( -441 665 -470 ) ( -402 632 -468 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -449 714 -460 ) ( -470 690 -456 ) ( -443 662 -492 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -459 728 -424 ) ( -478 704 -420 ) ( -481 698 -472 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -445 723 -387 ) ( -465 699 -383 ) ( -496 718 -421 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -416 701 -371 ) ( -436 677 -367 ) ( -476 710 -369 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -388 676 -384 ) ( -409 651 -381 ) ( -435 680 -345 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -378 661 -420 ) ( -399 637 -416 ) ( -396 643 -365 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -458 719 -475 ) ( -384 658 -472 ) ( -379 670 -369 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -450 585 -356 ) ( -456 573 -459 ) ( -530 635 -462 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 32 + { + patchDef2 + { + desktop/deskwood + ( 3 3 0 0 0 ) +( +( ( -360 160 -136 -2.812500 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ( 368 928 -136 2.875000 -7.250000 ) ) +( ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ) +( ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ) +) + } + } +// brush 33 + { + patchDef2 + { + desktop/deskwood + ( 3 3 0 0 0 ) +( +( ( 368 928 -168 2.875000 -7.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ( -360 160 -168 -2.812500 -1.250000 ) ) +( ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ) +( ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ) +) + } + } +// brush 34 +{ +( 8192 8192 -136 ) ( 8192 -8192 -136 ) ( -8192 -8192 -136 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -168 ) ( 8192 8192 -168 ) ( -8192 -8192 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 160 8192 ) ( -8192 160 8192 ) ( -8192 160 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1360 8192 ) ( 8192 -1360 8192 ) ( -8192 -1360 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 368 -8192 8192 ) ( 368 8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -1912 8192 8192 ) ( -1912 -8192 8192 ) ( -1912 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 35 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -448 676 -828 -7 -10.562500 ) ( -472 676 -828 -7.375000 -10.562500 ) ( -472 652 -828 -7.375000 -10.187500 ) ) +( ( -424 676 -828 -6.625000 -10.562500 ) ( -448 652 -828 -7 -10.187500 ) ( -472 628 -828 -7.375000 -9.812500 ) ) +( ( -424 652 -828 -6.625000 -10.187500 ) ( -424 628 -828 -6.625000 -9.812500 ) ( -448 628 -828 -7 -9.812500 ) ) +) + } + } +// brush 36 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -472 652 -660 -7.375000 -10.187500 ) ( -472 676 -660 -7.375000 -10.562500 ) ( -448 676 -660 -7 -10.562500 ) ) +( ( -472 628 -660 -7.375000 -9.812500 ) ( -448 652 -660 -7 -10.187500 ) ( -424 676 -660 -6.625000 -10.562500 ) ) +( ( -448 628 -660 -7 -9.812500 ) ( -424 628 -660 -6.625000 -9.812500 ) ( -424 652 -660 -6.625000 -10.187500 ) ) +) + } + } +// brush 37 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -448 688 -1120 -7 -10.750000 ) ( -484 688 -1120 -7.562500 -10.750000 ) ( -484 652 -1120 -7.562500 -10.187500 ) ) +( ( -412 688 -1120 -6.437500 -10.750000 ) ( -448 652 -1120 -7 -10.187500 ) ( -484 616 -1120 -7.562500 -9.625000 ) ) +( ( -412 652 -1120 -6.437500 -10.187500 ) ( -412 616 -1120 -6.437500 -9.625000 ) ( -448 616 -1120 -7 -9.625000 ) ) +) + } + } +// brush 38 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -484 652 -828 -7.562500 -10.187500 ) ( -484 688 -828 -7.562500 -10.750000 ) ( -448 688 -828 -7 -10.750000 ) ) +( ( -484 616 -828 -7.562500 -9.625000 ) ( -448 652 -828 -7 -10.187500 ) ( -412 688 -828 -6.437500 -10.750000 ) ) +( ( -448 616 -828 -7 -9.625000 ) ( -412 616 -828 -6.437500 -9.625000 ) ( -412 652 -828 -6.437500 -10.187500 ) ) +) + } + } +// brush 39 +{ +( -197 857 -1176 ) ( -197 857 -1120 ) ( -186 868 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -208 852 -1176 ) ( -208 852 -1120 ) ( -192 852 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -219 857 -1176 ) ( -219 857 -1120 ) ( -208 846 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -224 868 -1176 ) ( -224 868 -1120 ) ( -224 852 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -219 879 -1176 ) ( -219 879 -1120 ) ( -230 868 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -208 884 -1176 ) ( -208 884 -1120 ) ( -224 884 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -197 879 -1176 ) ( -197 879 -1120 ) ( -208 890 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -192 868 -1176 ) ( -192 868 -1120 ) ( -192 884 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -224 852 -1188 ) ( -192 852 -1188 ) ( -192 884 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -192 884 -1132 ) ( -192 852 -1132 ) ( -224 852 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 40 +{ +( -437 963 -1176 ) ( -437 963 -1120 ) ( -426 974 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 958 -1176 ) ( -448 958 -1120 ) ( -432 958 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 963 -1176 ) ( -459 963 -1120 ) ( -448 952 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 974 -1176 ) ( -464 974 -1120 ) ( -464 958 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 985 -1176 ) ( -459 985 -1120 ) ( -470 974 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 990 -1176 ) ( -448 990 -1120 ) ( -464 990 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -437 985 -1176 ) ( -437 985 -1120 ) ( -448 996 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 974 -1176 ) ( -432 974 -1120 ) ( -432 990 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 958 -1188 ) ( -432 958 -1188 ) ( -432 990 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 990 -1132 ) ( -432 958 -1132 ) ( -464 958 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 41 +{ +( -719 803 -1176 ) ( -719 803 -1120 ) ( -708 814 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -730 798 -1176 ) ( -730 798 -1120 ) ( -714 798 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -741 803 -1176 ) ( -741 803 -1120 ) ( -730 792 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -746 814 -1176 ) ( -746 814 -1120 ) ( -746 798 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -741 825 -1176 ) ( -741 825 -1120 ) ( -752 814 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -730 830 -1176 ) ( -730 830 -1120 ) ( -746 830 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -719 825 -1176 ) ( -719 825 -1120 ) ( -730 836 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -714 814 -1176 ) ( -714 814 -1120 ) ( -714 830 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -746 798 -1188 ) ( -714 798 -1188 ) ( -714 830 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -714 830 -1132 ) ( -714 798 -1132 ) ( -746 798 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 42 +{ +( -677 425 -1176 ) ( -677 425 -1120 ) ( -666 436 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -688 420 -1176 ) ( -688 420 -1120 ) ( -672 420 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -699 425 -1176 ) ( -699 425 -1120 ) ( -688 414 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -704 436 -1176 ) ( -704 436 -1120 ) ( -704 420 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -699 447 -1176 ) ( -699 447 -1120 ) ( -710 436 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -688 452 -1176 ) ( -688 452 -1120 ) ( -704 452 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -677 447 -1176 ) ( -677 447 -1120 ) ( -688 458 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -672 436 -1176 ) ( -672 436 -1120 ) ( -672 452 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -704 420 -1188 ) ( -672 420 -1188 ) ( -672 452 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -672 452 -1132 ) ( -672 420 -1132 ) ( -704 420 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 43 +{ +( -437 317 -1176 ) ( -437 317 -1120 ) ( -426 328 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 312 -1176 ) ( -448 312 -1120 ) ( -432 312 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 317 -1176 ) ( -459 317 -1120 ) ( -448 306 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 328 -1176 ) ( -464 328 -1120 ) ( -464 312 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 339 -1176 ) ( -459 339 -1120 ) ( -470 328 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 344 -1176 ) ( -448 344 -1120 ) ( -464 344 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -437 339 -1176 ) ( -437 339 -1120 ) ( -448 350 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 328 -1176 ) ( -432 328 -1120 ) ( -432 344 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 312 -1188 ) ( -432 312 -1188 ) ( -432 344 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 344 -1132 ) ( -432 312 -1132 ) ( -464 312 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 44 +{ +( -153 469 -1176 ) ( -153 469 -1120 ) ( -142 480 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -164 464 -1176 ) ( -164 464 -1120 ) ( -148 464 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -175 469 -1176 ) ( -175 469 -1120 ) ( -164 458 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -180 480 -1176 ) ( -180 480 -1120 ) ( -180 464 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -175 491 -1176 ) ( -175 491 -1120 ) ( -186 480 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -164 496 -1176 ) ( -164 496 -1120 ) ( -180 496 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -153 491 -1176 ) ( -153 491 -1120 ) ( -164 502 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -148 480 -1176 ) ( -148 480 -1120 ) ( -148 496 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -180 464 -1188 ) ( -148 464 -1188 ) ( -148 496 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -148 496 -1132 ) ( -148 464 -1132 ) ( -180 464 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 45 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 544 -688 480 ) ( 544 8 480 ) ( 544 -688 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 46 +{ +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 480 ) ( 944 -688 480 ) ( 944 8 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 47 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 48 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 49 +{ +( 744 8192 8192 ) ( 744 -8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8212 -354 8192 ) ( -8159 -996 8192 ) ( -8159 -996 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 50 +{ +( 744 8192 8192 ) ( 744 -8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8212 -354 8192 ) ( -8159 -996 8192 ) ( -8159 -996 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 51 +{ +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8202 560 8192 ) ( -7964 -2102 8192 ) ( -7964 -2102 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 480 ) ( 944 -688 480 ) ( 944 8 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 52 +{ +( 914 8192 8192 ) ( 914 -8192 8192 ) ( 914 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8202 560 8192 ) ( -7964 -2102 8192 ) ( -7964 -2102 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 53 +{ +( 914 8192 8192 ) ( 914 -8192 8192 ) ( 914 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8202 560 8192 ) ( -7964 -2102 8192 ) ( -7964 -2102 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 54 +{ +( 744 -8192 8192 ) ( 744 8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8161 -937 8192 ) ( -8209 -295 8192 ) ( -8209 -295 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 55 +{ +( 744 -8192 8192 ) ( 744 8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8161 -937 8192 ) ( -8209 -295 8192 ) ( -8209 -295 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 56 +{ +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8019 -1863 8192 ) ( -8146 798 8192 ) ( -8146 798 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 544 -688 480 ) ( 544 8 480 ) ( 544 -688 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 57 +{ +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8019 -1863 8192 ) ( -8146 798 8192 ) ( -8146 798 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 58 +{ +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8019 -1863 8192 ) ( -8146 798 8192 ) ( -8146 798 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 59 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 1304 -1208 0 0 ) ( 536 1304 -1144 0 2.625000 ) ( 536 1304 -1080 0 5.250000 ) ) +( ( 536 1264 -1208 1.250000 0 ) ( 536 1264 -1144 1.250000 2.625000 ) ( 536 1264 -1080 1.250000 5.250000 ) ) +( ( 576 1264 -1208 2.500000 0 ) ( 576 1264 -1144 2.500000 2.625000 ) ( 576 1264 -1080 2.500000 5.250000 ) ) +( ( 616 1264 -1208 3.750000 0 ) ( 616 1264 -1144 3.750000 2.625000 ) ( 616 1264 -1080 3.750000 5.250000 ) ) +( ( 616 1304 -1208 5 0 ) ( 616 1304 -1144 5 2.625000 ) ( 616 1304 -1080 5 5.250000 ) ) +( ( 616 1344 -1208 6.250000 0 ) ( 616 1344 -1144 6.250000 2.625000 ) ( 616 1344 -1080 6.250000 5.250000 ) ) +( ( 576 1344 -1208 7.500000 0 ) ( 576 1344 -1144 7.500000 2.625000 ) ( 576 1344 -1080 7.500000 5.250000 ) ) +( ( 536 1344 -1208 8.750000 0 ) ( 536 1344 -1144 8.750000 2.625000 ) ( 536 1344 -1080 8.750000 5.250000 ) ) +( ( 536 1304 -1208 10 0 ) ( 536 1304 -1144 10 2.625000 ) ( 536 1304 -1080 10 5.250000 ) ) +) + } + } +// brush 60 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 904 -1208 0 0 ) ( 536 904 -1144 0 2.625000 ) ( 536 904 -1080 0 5.250000 ) ) +( ( 536 864 -1208 1.250000 0 ) ( 536 864 -1144 1.250000 2.625000 ) ( 536 864 -1080 1.250000 5.250000 ) ) +( ( 576 864 -1208 2.500000 0 ) ( 576 864 -1144 2.500000 2.625000 ) ( 576 864 -1080 2.500000 5.250000 ) ) +( ( 616 864 -1208 3.750000 0 ) ( 616 864 -1144 3.750000 2.625000 ) ( 616 864 -1080 3.750000 5.250000 ) ) +( ( 616 904 -1208 5 0 ) ( 616 904 -1144 5 2.625000 ) ( 616 904 -1080 5 5.250000 ) ) +( ( 616 944 -1208 6.250000 0 ) ( 616 944 -1144 6.250000 2.625000 ) ( 616 944 -1080 6.250000 5.250000 ) ) +( ( 576 944 -1208 7.500000 0 ) ( 576 944 -1144 7.500000 2.625000 ) ( 576 944 -1080 7.500000 5.250000 ) ) +( ( 536 944 -1208 8.750000 0 ) ( 536 944 -1144 8.750000 2.625000 ) ( 536 944 -1080 8.750000 5.250000 ) ) +( ( 536 904 -1208 10 0 ) ( 536 904 -1144 10 2.625000 ) ( 536 904 -1080 10 5.250000 ) ) +) + } + } +// brush 61 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 904 -1208 0 0 ) ( 1824 904 -1144 0 2.625000 ) ( 1824 904 -1080 0 5.250000 ) ) +( ( 1824 864 -1208 1.250000 0 ) ( 1824 864 -1144 1.250000 2.625000 ) ( 1824 864 -1080 1.250000 5.250000 ) ) +( ( 1864 864 -1208 2.500000 0 ) ( 1864 864 -1144 2.500000 2.625000 ) ( 1864 864 -1080 2.500000 5.250000 ) ) +( ( 1904 864 -1208 3.750000 0 ) ( 1904 864 -1144 3.750000 2.625000 ) ( 1904 864 -1080 3.750000 5.250000 ) ) +( ( 1904 904 -1208 5 0 ) ( 1904 904 -1144 5 2.625000 ) ( 1904 904 -1080 5 5.250000 ) ) +( ( 1904 944 -1208 6.250000 0 ) ( 1904 944 -1144 6.250000 2.625000 ) ( 1904 944 -1080 6.250000 5.250000 ) ) +( ( 1864 944 -1208 7.500000 0 ) ( 1864 944 -1144 7.500000 2.625000 ) ( 1864 944 -1080 7.500000 5.250000 ) ) +( ( 1824 944 -1208 8.750000 0 ) ( 1824 944 -1144 8.750000 2.625000 ) ( 1824 944 -1080 8.750000 5.250000 ) ) +( ( 1824 904 -1208 10 0 ) ( 1824 904 -1144 10 2.625000 ) ( 1824 904 -1080 10 5.250000 ) ) +) + } + } +// brush 62 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 1304 -1208 0 0 ) ( 1824 1304 -1144 0 2.625000 ) ( 1824 1304 -1080 0 5.250000 ) ) +( ( 1824 1264 -1208 1.250000 0 ) ( 1824 1264 -1144 1.250000 2.625000 ) ( 1824 1264 -1080 1.250000 5.250000 ) ) +( ( 1864 1264 -1208 2.500000 0 ) ( 1864 1264 -1144 2.500000 2.625000 ) ( 1864 1264 -1080 2.500000 5.250000 ) ) +( ( 1904 1264 -1208 3.750000 0 ) ( 1904 1264 -1144 3.750000 2.625000 ) ( 1904 1264 -1080 3.750000 5.250000 ) ) +( ( 1904 1304 -1208 5 0 ) ( 1904 1304 -1144 5 2.625000 ) ( 1904 1304 -1080 5 5.250000 ) ) +( ( 1904 1344 -1208 6.250000 0 ) ( 1904 1344 -1144 6.250000 2.625000 ) ( 1904 1344 -1080 6.250000 5.250000 ) ) +( ( 1864 1344 -1208 7.500000 0 ) ( 1864 1344 -1144 7.500000 2.625000 ) ( 1864 1344 -1080 7.500000 5.250000 ) ) +( ( 1824 1344 -1208 8.750000 0 ) ( 1824 1344 -1144 8.750000 2.625000 ) ( 1824 1344 -1080 8.750000 5.250000 ) ) +( ( 1824 1304 -1208 10 0 ) ( 1824 1304 -1144 10 2.625000 ) ( 1824 1304 -1080 10 5.250000 ) ) +) + } + } +// brush 63 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 1304 -336 0 0 ) ( 1824 1304 -252 0 2.625000 ) ( 1824 1304 -168 0 5.250000 ) ) +( ( 1824 1264 -336 1.250000 0 ) ( 1824 1264 -252 1.250000 2.625000 ) ( 1824 1264 -168 1.250000 5.250000 ) ) +( ( 1864 1264 -336 2.500000 0 ) ( 1864 1264 -252 2.500000 2.625000 ) ( 1864 1264 -168 2.500000 5.250000 ) ) +( ( 1904 1264 -336 3.750000 0 ) ( 1904 1264 -252 3.750000 2.625000 ) ( 1904 1264 -168 3.750000 5.250000 ) ) +( ( 1904 1304 -336 5 0 ) ( 1904 1304 -252 5 2.625000 ) ( 1904 1304 -168 5 5.250000 ) ) +( ( 1904 1344 -336 6.250000 0 ) ( 1904 1344 -252 6.250000 2.625000 ) ( 1904 1344 -168 6.250000 5.250000 ) ) +( ( 1864 1344 -336 7.500000 0 ) ( 1864 1344 -252 7.500000 2.625000 ) ( 1864 1344 -168 7.500000 5.250000 ) ) +( ( 1824 1344 -336 8.750000 0 ) ( 1824 1344 -252 8.750000 2.625000 ) ( 1824 1344 -168 8.750000 5.250000 ) ) +( ( 1824 1304 -336 10 0 ) ( 1824 1304 -252 10 2.625000 ) ( 1824 1304 -168 10 5.250000 ) ) +) + } + } +// brush 64 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 904 -336 0 0 ) ( 1824 904 -252 0 2.625000 ) ( 1824 904 -168 0 5.250000 ) ) +( ( 1824 864 -336 1.250000 0 ) ( 1824 864 -252 1.250000 2.625000 ) ( 1824 864 -168 1.250000 5.250000 ) ) +( ( 1864 864 -336 2.500000 0 ) ( 1864 864 -252 2.500000 2.625000 ) ( 1864 864 -168 2.500000 5.250000 ) ) +( ( 1904 864 -336 3.750000 0 ) ( 1904 864 -252 3.750000 2.625000 ) ( 1904 864 -168 3.750000 5.250000 ) ) +( ( 1904 904 -336 5 0 ) ( 1904 904 -252 5 2.625000 ) ( 1904 904 -168 5 5.250000 ) ) +( ( 1904 944 -336 6.250000 0 ) ( 1904 944 -252 6.250000 2.625000 ) ( 1904 944 -168 6.250000 5.250000 ) ) +( ( 1864 944 -336 7.500000 0 ) ( 1864 944 -252 7.500000 2.625000 ) ( 1864 944 -168 7.500000 5.250000 ) ) +( ( 1824 944 -336 8.750000 0 ) ( 1824 944 -252 8.750000 2.625000 ) ( 1824 944 -168 8.750000 5.250000 ) ) +( ( 1824 904 -336 10 0 ) ( 1824 904 -252 10 2.625000 ) ( 1824 904 -168 10 5.250000 ) ) +) + } + } +// brush 65 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 904 -336 0 0 ) ( 536 904 -252 0 2.625000 ) ( 536 904 -168 0 5.250000 ) ) +( ( 536 864 -336 1.250000 0 ) ( 536 864 -252 1.250000 2.625000 ) ( 536 864 -168 1.250000 5.250000 ) ) +( ( 576 864 -336 2.500000 0 ) ( 576 864 -252 2.500000 2.625000 ) ( 576 864 -168 2.500000 5.250000 ) ) +( ( 616 864 -336 3.750000 0 ) ( 616 864 -252 3.750000 2.625000 ) ( 616 864 -168 3.750000 5.250000 ) ) +( ( 616 904 -336 5 0 ) ( 616 904 -252 5 2.625000 ) ( 616 904 -168 5 5.250000 ) ) +( ( 616 944 -336 6.250000 0 ) ( 616 944 -252 6.250000 2.625000 ) ( 616 944 -168 6.250000 5.250000 ) ) +( ( 576 944 -336 7.500000 0 ) ( 576 944 -252 7.500000 2.625000 ) ( 576 944 -168 7.500000 5.250000 ) ) +( ( 536 944 -336 8.750000 0 ) ( 536 944 -252 8.750000 2.625000 ) ( 536 944 -168 8.750000 5.250000 ) ) +( ( 536 904 -336 10 0 ) ( 536 904 -252 10 2.625000 ) ( 536 904 -168 10 5.250000 ) ) +) + } + } +// brush 66 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 1304 -336 0 0 ) ( 536 1304 -252 0 2.625000 ) ( 536 1304 -168 0 5.250000 ) ) +( ( 536 1264 -336 1.250000 0 ) ( 536 1264 -252 1.250000 2.625000 ) ( 536 1264 -168 1.250000 5.250000 ) ) +( ( 576 1264 -336 2.500000 0 ) ( 576 1264 -252 2.500000 2.625000 ) ( 576 1264 -168 2.500000 5.250000 ) ) +( ( 616 1264 -336 3.750000 0 ) ( 616 1264 -252 3.750000 2.625000 ) ( 616 1264 -168 3.750000 5.250000 ) ) +( ( 616 1304 -336 5 0 ) ( 616 1304 -252 5 2.625000 ) ( 616 1304 -168 5 5.250000 ) ) +( ( 616 1344 -336 6.250000 0 ) ( 616 1344 -252 6.250000 2.625000 ) ( 616 1344 -168 6.250000 5.250000 ) ) +( ( 576 1344 -336 7.500000 0 ) ( 576 1344 -252 7.500000 2.625000 ) ( 576 1344 -168 7.500000 5.250000 ) ) +( ( 536 1344 -336 8.750000 0 ) ( 536 1344 -252 8.750000 2.625000 ) ( 536 1344 -168 8.750000 5.250000 ) ) +( ( 536 1304 -336 10 0 ) ( 536 1304 -252 10 2.625000 ) ( 536 1304 -168 10 5.250000 ) ) +) + } + } +// brush 67 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -512 -168 0 32.500000 ) ( 1784 -512 -656 0 16.250000 ) ( 1784 -512 -1144 0 0 ) ) +( ( 1832 -512 -168 1.500000 32.500000 ) ( 1832 -512 -656 1.500000 16.250000 ) ( 1832 -512 -1144 1.500000 0 ) ) +( ( 1832 -744 -168 8.750000 32.500000 ) ( 1832 -744 -656 8.750000 16.250000 ) ( 1832 -744 -1144 8.750000 0 ) ) +) + } + } +// brush 68 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -976 -168 0 32.500000 ) ( 1784 -976 -656 0 16.250000 ) ( 1784 -976 -1144 0 0 ) ) +( ( 1736 -976 -168 1.500000 32.500000 ) ( 1736 -976 -656 1.500000 16.250000 ) ( 1736 -976 -1144 1.500000 0 ) ) +( ( 1736 -744 -168 8.750000 32.500000 ) ( 1736 -744 -656 8.750000 16.250000 ) ( 1736 -744 -1144 8.750000 0 ) ) +) + } + } +// brush 69 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -976 -1144 0 0 ) ( 1784 -976 -656 0 16.250000 ) ( 1784 -976 -168 0 32.500000 ) ) +( ( 1832 -976 -1144 1.500000 0 ) ( 1832 -976 -656 1.500000 16.250000 ) ( 1832 -976 -168 1.500000 32.500000 ) ) +( ( 1832 -744 -1144 8.750000 0 ) ( 1832 -744 -656 8.750000 16.250000 ) ( 1832 -744 -168 8.750000 32.500000 ) ) +) + } + } +// brush 70 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -512 -1144 0 0 ) ( 1784 -512 -656 0 16.250000 ) ( 1784 -512 -167.999969 0 32.500000 ) ) +( ( 1736 -512 -1144 1.500000 0 ) ( 1736 -512 -656 1.500000 16.250000 ) ( 1736 -512 -167.999969 1.500000 32.500000 ) ) +( ( 1736 -744 -1144 8.750000 0 ) ( 1736 -744 -656 8.750000 16.250000 ) ( 1736 -744 -167.999969 8.750000 32.500000 ) ) +) + } + } +// brush 71 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -1008 -1144 0 0 ) ( -1640 -1008 -656 0 16.250000 ) ( -1640 -1008 -168 0 32.500000 ) ) +( ( -1592 -1008 -1144 1.500000 0 ) ( -1592 -1008 -656 1.500000 16.250000 ) ( -1592 -1008 -168 1.500000 32.500000 ) ) +( ( -1592 -776 -1144 8.750000 0 ) ( -1592 -776 -656 8.750000 16.250000 ) ( -1592 -776 -168 8.750000 32.500000 ) ) +) + } + } +// brush 72 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -1008 -168 0 32.500000 ) ( -1640 -1008 -656 0 16.250000 ) ( -1640 -1008 -1144 0 0 ) ) +( ( -1688 -1008 -168 1.500000 32.500000 ) ( -1688 -1008 -656 1.500000 16.250000 ) ( -1688 -1008 -1144 1.500000 0 ) ) +( ( -1688 -776 -168 8.750000 32.500000 ) ( -1688 -776 -656 8.750000 16.250000 ) ( -1688 -776 -1144 8.750000 0 ) ) +) + } + } +// brush 73 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -544 -1144 0 0 ) ( -1640 -544 -656 0 16.250000 ) ( -1640 -544 -168 0 32.500000 ) ) +( ( -1688 -544 -1144 1.500000 0 ) ( -1688 -544 -656 1.500000 16.250000 ) ( -1688 -544 -168 1.500000 32.500000 ) ) +( ( -1688 -776 -1144 8.750000 0 ) ( -1688 -776 -656 8.750000 16.250000 ) ( -1688 -776 -168 8.750000 32.500000 ) ) +) + } + } +// brush 74 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -544 -168 0 32.500000 ) ( -1640 -544 -656 0 16.250000 ) ( -1640 -544 -1144 0 0 ) ) +( ( -1592 -544 -168 1.500000 32.500000 ) ( -1592 -544 -656 1.500000 16.250000 ) ( -1592 -544 -1144 1.500000 0 ) ) +( ( -1592 -776 -168 8.750000 32.500000 ) ( -1592 -776 -656 8.750000 16.250000 ) ( -1592 -776 -1144 8.750000 0 ) ) +) + } + } +// brush 75 +{ +( -34 -176 -136 ) ( -34 -176 0 ) ( 4 -138 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -70 -190 -136 ) ( -70 -190 0 ) ( -16 -190 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -104 -174 -136 ) ( -104 -174 0 ) ( -66 -212 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -118 -138 -136 ) ( -118 -138 0 ) ( -118 -192 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -102 -104 -136 ) ( -102 -104 0 ) ( -140 -142 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -92 -136 ) ( -66 -92 0 ) ( -120 -92 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -40 -104 -136 ) ( -40 -104 0 ) ( -78 -66 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -22 -140 -136 ) ( -22 -140 0 ) ( -22 -86 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -120 -192 -136 ) ( -16 -192 -136 ) ( -16 -84 -136 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -18 -84 -8 ) ( -18 -192 -8 ) ( -122 -192 -8 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 76 + { + patchDef2 + { + common/clip + ( 9 3 0 0 0 ) +( +( ( -122 -140 0 0 8.500000 ) ( -122 -140 -68 0 4.250000 ) ( -122 -140 -136 0 0 ) ) +( ( -122 -194 0 3.750000 8.500000 ) ( -122 -194 -68 3.750000 4.250000 ) ( -122 -194 -136 3.750000 0 ) ) +( ( -70 -194 0 7.500000 8.500000 ) ( -70 -194 -68 7.500000 4.250000 ) ( -70 -194 -136 7.500000 0 ) ) +( ( -17.999998 -194 0 11.250000 8.500000 ) ( -17.999998 -194 -68 11.250000 4.250000 ) ( -17.999998 -194 -136 11.250000 0 ) ) +( ( -17.999998 -140 0 15 8.500000 ) ( -17.999998 -140 -68 15 4.250000 ) ( -17.999998 -140 -136 15 0 ) ) +( ( -17.999998 -86 0 18.750000 8.500000 ) ( -17.999998 -86 -68 18.750000 4.250000 ) ( -17.999998 -86 -136 18.750000 0 ) ) +( ( -70 -86 0 22.500000 8.500000 ) ( -70 -86 -68 22.500000 4.250000 ) ( -70 -86 -136 22.500000 0 ) ) +( ( -122 -86 0 26.250000 8.500000 ) ( -122 -86 -68 26.250000 4.250000 ) ( -122 -86 -136 26.250000 0 ) ) +( ( -122 -140 0 30 8.500000 ) ( -122 -140 -68 30 4.250000 ) ( -122 -140 -136 30 0 ) ) +) + } + } +// brush 77 + { + patchDef2 + { + common/clip + ( 9 3 0 0 0 ) +( +( ( -130 -141 -136 0 0 ) ( -130 -141 -68 0 4.250000 ) ( -130 -141 0 0 8.500000 ) ) +( ( -130 -200 -136 3.750000 0 ) ( -130 -200 -68 3.750000 4.250000 ) ( -130 -200 0 3.750000 8.500000 ) ) +( ( -70 -200 -136 7.500000 0 ) ( -70 -200 -68 7.500000 4.250000 ) ( -70 -200 0 7.500000 8.500000 ) ) +( ( -10 -200 -136 11.250000 0 ) ( -10 -200 -68 11.250000 4.250000 ) ( -10 -200 0 11.250000 8.500000 ) ) +( ( -10 -141 -136 15 0 ) ( -10 -141 -68 15 4.250000 ) ( -10 -141 0 15 8.500000 ) ) +( ( -10 -82 -136 18.750000 0 ) ( -10 -82 -68 18.750000 4.250000 ) ( -10 -82 0 18.750000 8.500000 ) ) +( ( -70 -82 -136 22.500000 0 ) ( -70 -82 -68 22.500000 4.250000 ) ( -70 -82 0 22.500000 8.500000 ) ) +( ( -130 -82 -136 26.250000 0 ) ( -130 -82 -68 26.250000 4.250000 ) ( -130 -82 0 26.250000 8.500000 ) ) +( ( -130 -141 -136 30 0 ) ( -130 -141 -68 30 4.250000 ) ( -130 -141 0 30 8.500000 ) ) +) + } + } +// brush 78 +{ +( -8192 -256 7850 ) ( 8192 -256 7850 ) ( -8192 -256 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 7850 ) ( -8192 -216 7850 ) ( -8192 -216 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -134 ) ( 8192 -8192 -134 ) ( -8192 -8192 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 749 -8161 7850 ) ( -272 8190 7850 ) ( -272 8190 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 583 8171 7850 ) ( -438 -8180 7850 ) ( -438 -8180 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 79 +{ +( 232 -198 -10 ) ( 40 -198 -10 ) ( 40 -230 -10 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 142 ) ( 232 -216 142 ) ( 232 -216 -146 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 232 -202 120 ) ( 40 -202 120 ) ( 40 -202 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 254 -240 150 ) ( 254 -240 -138 ) ( 256 -272 150 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 252 -236 -154 ) ( 252 -236 134 ) ( 254 -268 134 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 80 +{ +( 232 -200 -10 ) ( 40 -200 -10 ) ( 40 -232 -10 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -230 206 ) ( 40 -198 206 ) ( 232 -198 206 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 144 ) ( 232 -216 144 ) ( 232 -216 -144 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 232 -202 120 ) ( 40 -202 120 ) ( 40 -202 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 310 ) ( 58 -230 310 ) ( 60 -198 22 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 60 -232 328 ) ( 62 -200 328 ) ( 62 -200 40 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 81 +{ +( 230 -200 -10 ) ( 38 -200 -10 ) ( 38 -232 -10 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 234 -200 122 ) ( 42 -200 122 ) ( 42 -200 -166 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 328 ) ( 58 -230 328 ) ( 60 -198 40 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 40 -202 120 ) ( 232 -202 120 ) ( 40 -202 -168 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 82 +{ +( 40 -232 208 ) ( 40 -200 208 ) ( 232 -200 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 144 ) ( 232 -216 144 ) ( 232 -216 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -200 152 ) ( 48 -200 152 ) ( 48 -200 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 328 ) ( 58 -230 328 ) ( 60 -198 40 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -200 206 ) ( 40 -232 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 83 +{ +( 240 -200 -12 ) ( 48 -200 -12 ) ( 48 -232 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 92 ) ( 232 -216 92 ) ( 232 -216 -196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -200 100 ) ( 48 -200 100 ) ( 48 -200 -188 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 276 ) ( 58 -230 276 ) ( 60 -198 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 100 ) ( 254 -238 -188 ) ( 256 -270 100 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 48 -200 -10 ) ( 240 -200 -10 ) ( 48 -232 -10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 84 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 64 -288 206 ) ( 64 -256 206 ) ( 256 -256 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 253 -265 -80 ) ( 255 -233 -80 ) ( 255 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 85 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 64 -288 206 ) ( 64 -256 206 ) ( 256 -256 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 59 -273 152 ) ( 57 -241 152 ) ( 57 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 86 +{ +( 64 -288 208 ) ( 64 -256 208 ) ( 256 -256 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 64 -256 206 ) ( 64 -288 206 ) ( 256 -256 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 87 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -256 -134 ) ( 264 -256 -134 ) ( 72 -288 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 88 +{ +( 240 -200 -136 ) ( 48 -200 -136 ) ( 48 -232 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -256 144 ) ( 232 -256 144 ) ( 232 -256 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -216 152 ) ( 48 -216 152 ) ( 48 -216 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 252 -238 -136 ) ( 252 -238 152 ) ( 254 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 89 +{ +( 240 -200 -136 ) ( 48 -200 -136 ) ( 48 -232 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -256 144 ) ( 232 -256 144 ) ( 232 -256 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -216 150 ) ( 48 -216 150 ) ( 48 -216 -138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 152 ) ( 58 -230 152 ) ( 60 -198 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -230 150 ) ( 62 -198 150 ) ( 62 -198 -138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 90 +{ +( 240 -200 -136 ) ( 48 -200 -136 ) ( 48 -232 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 18 ) ( 40 -200 18 ) ( 232 -200 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 242 -216 110 ) ( 50 -216 110 ) ( 50 -216 -178 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 128 ) ( 58 -230 128 ) ( 60 -198 -160 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 128 ) ( 254 -238 -160 ) ( 256 -270 128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 48 -218 128 ) ( 240 -218 128 ) ( 48 -218 -160 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 91 +{ +( 40 -232 208 ) ( 40 -200 208 ) ( 232 -200 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -256 144 ) ( 232 -256 144 ) ( 232 -256 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -216 152 ) ( 48 -216 152 ) ( 48 -216 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 152 ) ( 58 -230 152 ) ( 60 -198 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -200 206 ) ( 40 -232 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 92 +{ +( 192 -520 -130 ) ( 192 -176 -130 ) ( 168 -176 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 168 -184 -57 ) ( 192 -184 -57 ) ( 192 -528 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 176 -168 -22 ) ( 176 -512 -22 ) ( 176 -512 -126 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 168 -479 -29 ) ( 192 -479 -29 ) ( 192 -479 -133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 178 -520 -26 ) ( 178 -176 -26 ) ( 178 -176 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 184 -437 -28 ) ( 160 -437 -28 ) ( 160 -437 -132 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 93 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -478 144 ) ( 72 -478 144 ) ( 264 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -126 -464 -130 ) ( 218 -464 -130 ) ( -126 -488 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 94 +{ +( 66 -288 208 ) ( 66 -256 208 ) ( 258 -256 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 74 -480 144 ) ( 266 -480 144 ) ( 266 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 57 -241 152 ) ( 59 -273 152 ) ( 57 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 256 -233 -80 ) ( 254 -265 -80 ) ( 256 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 263 -478 144 ) ( 71 -478 144 ) ( 263 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -116 -464 -57 ) ( -116 -488 -57 ) ( 228 -464 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 95 +{ +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -478 144 ) ( 72 -478 144 ) ( 264 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 218 -464 -130 ) ( -126 -464 -130 ) ( -126 -488 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -118 -488 -57 ) ( -118 -464 -57 ) ( 226 -464 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 177 -464 -25 ) ( 177 -488 -25 ) ( 177 -464 -129 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 96 +{ +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -478 144 ) ( 72 -478 144 ) ( 264 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 218 -464 -130 ) ( -126 -464 -130 ) ( -126 -488 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -118 -488 -57 ) ( -118 -464 -57 ) ( 226 -464 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -496 -28 ) ( 135 -472 -28 ) ( 135 -496 -132 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 97 +{ +( -432 648 -1148 ) ( -464 648 -1148 ) ( -464 368 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 796 -1101 ) ( -464 796 -1101 ) ( -464 519 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 312 -1124 ) ( -432 312 -1124 ) ( -432 312 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 652 -1077 ) ( -432 652 -1077 ) ( -464 375 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 648 -1124 ) ( -464 368 -1124 ) ( -464 368 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 648 -1124 ) ( -464 648 -1124 ) ( -464 648 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 368 -1124 ) ( -432 648 -1124 ) ( -432 648 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 368 -1092 ) ( -464 648 -1092 ) ( -432 648 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 98 +{ +( -464 656 -1148 ) ( -432 656 -1148 ) ( -432 936 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 508 -1101 ) ( -432 508 -1101 ) ( -432 785 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 992 -1124 ) ( -464 992 -1124 ) ( -464 992 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 652 -1077 ) ( -464 652 -1077 ) ( -432 929 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 656 -1124 ) ( -432 936 -1124 ) ( -432 936 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 656 -1124 ) ( -432 656 -1124 ) ( -432 656 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 936 -1124 ) ( -464 656 -1124 ) ( -464 656 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 936 -1092 ) ( -432 656 -1092 ) ( -464 656 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 99 +{ +( -456 666 -1148 ) ( -434 643 -1148 ) ( -226 830 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -566 568 -1101 ) ( -544 543 -1101 ) ( -338 729 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -184 867 -1124 ) ( -206 892 -1124 ) ( -206 892 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -438 640 -1077 ) ( -458 664 -1077 ) ( -232 826 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -434 643 -1124 ) ( -226 830 -1124 ) ( -226 830 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -456 666 -1124 ) ( -434 643 -1124 ) ( -434 643 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -248 854 -1124 ) ( -456 666 -1124 ) ( -456 666 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -226 830 -1092 ) ( -434 643 -1092 ) ( -456 666 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 100 +{ +( -440 638 -1148 ) ( -462 661 -1148 ) ( -670 474 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -330 736 -1101 ) ( -352 761 -1101 ) ( -558 575 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -712 437 -1124 ) ( -690 412 -1124 ) ( -690 412 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -458 664 -1077 ) ( -438 640 -1077 ) ( -664 478 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -462 661 -1124 ) ( -670 474 -1124 ) ( -670 474 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -440 638 -1124 ) ( -462 661 -1124 ) ( -462 661 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -648 450 -1124 ) ( -440 638 -1124 ) ( -440 638 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -670 474 -1092 ) ( -462 661 -1092 ) ( -440 638 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 101 +{ +( -459 640 -1148 ) ( -444 668 -1148 ) ( -686 808 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -331 566 -1101 ) ( -315 594 -1101 ) ( -556 733 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -734 836 -1124 ) ( -751 808 -1124 ) ( -751 808 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -440 666 -1077 ) ( -456 638 -1077 ) ( -680 804 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -444 668 -1124 ) ( -686 808 -1124 ) ( -686 808 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 640 -1124 ) ( -444 668 -1124 ) ( -444 668 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -702 780 -1124 ) ( -459 640 -1124 ) ( -459 640 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -686 808 -1092 ) ( -444 668 -1092 ) ( -459 640 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 102 +{ +( -437 664 -1148 ) ( -452 636 -1148 ) ( -210 496 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -565 738 -1101 ) ( -581 710 -1101 ) ( -340 571 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -162 468 -1124 ) ( -145 496 -1124 ) ( -145 496 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -456 638 -1077 ) ( -440 666 -1077 ) ( -216 500 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -452 636 -1124 ) ( -210 496 -1124 ) ( -210 496 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -437 664 -1124 ) ( -452 636 -1124 ) ( -452 636 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -194 524 -1124 ) ( -437 664 -1124 ) ( -437 664 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -210 496 -1092 ) ( -452 636 -1092 ) ( -437 664 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 103 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -168 464 -1208 0 0 ) ( -176 464 -1208 0 0.062500 ) ( -184 464 -1208 0 0.125000 ) ) +( ( -168 436 -1208 0.218750 0 ) ( -176 436 -1208 0.218750 0.062500 ) ( -184 436 -1208 0.218750 0.125000 ) ) +( ( -168 436 -1180 0.437500 0 ) ( -176 436 -1180 0.437500 0.062500 ) ( -184 436 -1180 0.437500 0.125000 ) ) +( ( -168 436 -1152 0.656250 0 ) ( -176 436 -1152 0.656250 0.062500 ) ( -184 436 -1152 0.656250 0.125000 ) ) +( ( -168 464 -1152 0.875000 0 ) ( -176 464 -1152 0.875000 0.062500 ) ( -184 464 -1152 0.875000 0.125000 ) ) +( ( -168 492 -1152 1.093750 0 ) ( -176 492 -1152 1.093750 0.062500 ) ( -184 492 -1152 1.093750 0.125000 ) ) +( ( -168 492 -1180 1.312500 0 ) ( -176 492 -1180 1.312500 0.062500 ) ( -184 492 -1180 1.312500 0.125000 ) ) +( ( -168 492 -1208 1.531250 0 ) ( -176 492 -1208 1.531250 0.062500 ) ( -184 492 -1208 1.531250 0.125000 ) ) +( ( -168 464 -1208 1.750000 0 ) ( -176 464 -1208 1.750000 0.062500 ) ( -184 464 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 104 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -168 492 -1180 -8.031250 -18 ) ( -168 492 -1208 -8.250000 -18 ) ( -168 464 -1208 -8.250000 -17.781250 ) ) +( ( -168 492 -1152 -7.812500 -18 ) ( -168 464 -1180 -8.031250 -17.781250 ) ( -168 436 -1208 -8.250000 -17.562500 ) ) +( ( -168 464 -1152 -7.812500 -17.781250 ) ( -168 436 -1152 -7.812500 -17.562500 ) ( -168 436 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 105 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -184 464 -1208 -8.250000 -17.781250 ) ( -184 492 -1208 -8.250000 -18 ) ( -184 492 -1180 -8.031250 -18 ) ) +( ( -184 436 -1208 -8.250000 -17.562500 ) ( -184 464 -1180 -8.031250 -17.781250 ) ( -184 492 -1152 -7.812500 -18 ) ) +( ( -184 436 -1180 -8.031250 -17.562500 ) ( -184 436 -1152 -7.812500 -17.562500 ) ( -184 464 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 106 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -144 464 -1208 0 0 ) ( -152 464 -1208 0 0.062500 ) ( -160 464 -1208 0 0.125000 ) ) +( ( -144 436 -1208 0.218750 0 ) ( -152 436 -1208 0.218750 0.062500 ) ( -160 436 -1208 0.218750 0.125000 ) ) +( ( -144 436 -1180 0.437500 0 ) ( -152 436 -1180 0.437500 0.062500 ) ( -160 436 -1180 0.437500 0.125000 ) ) +( ( -144 436 -1152 0.656250 0 ) ( -152 436 -1152 0.656250 0.062500 ) ( -160 436 -1152 0.656250 0.125000 ) ) +( ( -144 464 -1152 0.875000 0 ) ( -152 464 -1152 0.875000 0.062500 ) ( -160 464 -1152 0.875000 0.125000 ) ) +( ( -144 492 -1152 1.093750 0 ) ( -152 492 -1152 1.093750 0.062500 ) ( -160 492 -1152 1.093750 0.125000 ) ) +( ( -144 492 -1180 1.312500 0 ) ( -152 492 -1180 1.312500 0.062500 ) ( -160 492 -1180 1.312500 0.125000 ) ) +( ( -144 492 -1208 1.531250 0 ) ( -152 492 -1208 1.531250 0.062500 ) ( -160 492 -1208 1.531250 0.125000 ) ) +( ( -144 464 -1208 1.750000 0 ) ( -152 464 -1208 1.750000 0.062500 ) ( -160 464 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 107 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -144 492 -1180 -8.031250 -18 ) ( -144 492 -1208 -8.250000 -18 ) ( -144 464 -1208 -8.250000 -17.781250 ) ) +( ( -144 492 -1152 -7.812500 -18 ) ( -144 464 -1180 -8.031250 -17.781250 ) ( -144 436 -1208 -8.250000 -17.562500 ) ) +( ( -144 464 -1152 -7.812500 -17.781250 ) ( -144 436 -1152 -7.812500 -17.562500 ) ( -144 436 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 108 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -160 464 -1208 -8.250000 -17.781250 ) ( -160 492 -1208 -8.250000 -18 ) ( -160 492 -1180 -8.031250 -18 ) ) +( ( -160 436 -1208 -8.250000 -17.562500 ) ( -160 464 -1180 -8.031250 -17.781250 ) ( -160 492 -1152 -7.812500 -18 ) ) +( ( -160 436 -1180 -8.031250 -17.562500 ) ( -160 436 -1152 -7.812500 -17.562500 ) ( -160 464 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 109 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -196 852 -1208 -8.250000 -17.781250 ) ( -196 880 -1208 -8.250000 -18 ) ( -196 880 -1180 -8.031250 -18 ) ) +( ( -196 824 -1208 -8.250000 -17.562500 ) ( -196 852 -1180 -8.031250 -17.781250 ) ( -196 880 -1152 -7.812500 -18 ) ) +( ( -196 824 -1180 -8.031250 -17.562500 ) ( -196 824 -1152 -7.812500 -17.562500 ) ( -196 852 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 110 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -180 880 -1180 -8.031250 -18 ) ( -180 880 -1208 -8.250000 -18 ) ( -180 852 -1208 -8.250000 -17.781250 ) ) +( ( -180 880 -1152 -7.812500 -18 ) ( -180 852 -1180 -8.031250 -17.781250 ) ( -180 824 -1208 -8.250000 -17.562500 ) ) +( ( -180 852 -1152 -7.812500 -17.781250 ) ( -180 824 -1152 -7.812500 -17.562500 ) ( -180 824 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 111 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -180 852 -1208 0 0 ) ( -188 852 -1208 0 0.062500 ) ( -196 852 -1208 0 0.125000 ) ) +( ( -180 824 -1208 0.218750 0 ) ( -188 824 -1208 0.218750 0.062500 ) ( -196 824 -1208 0.218750 0.125000 ) ) +( ( -180 824 -1180 0.437500 0 ) ( -188 824 -1180 0.437500 0.062500 ) ( -196 824 -1180 0.437500 0.125000 ) ) +( ( -180 824 -1152 0.656250 0 ) ( -188 824 -1152 0.656250 0.062500 ) ( -196 824 -1152 0.656250 0.125000 ) ) +( ( -180 852 -1152 0.875000 0 ) ( -188 852 -1152 0.875000 0.062500 ) ( -196 852 -1152 0.875000 0.125000 ) ) +( ( -180 880 -1152 1.093750 0 ) ( -188 880 -1152 1.093750 0.062500 ) ( -196 880 -1152 1.093750 0.125000 ) ) +( ( -180 880 -1180 1.312500 0 ) ( -188 880 -1180 1.312500 0.062500 ) ( -196 880 -1180 1.312500 0.125000 ) ) +( ( -180 880 -1208 1.531250 0 ) ( -188 880 -1208 1.531250 0.062500 ) ( -196 880 -1208 1.531250 0.125000 ) ) +( ( -180 852 -1208 1.750000 0 ) ( -188 852 -1208 1.750000 0.062500 ) ( -196 852 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 112 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -220 852 -1208 -8.250000 -17.781250 ) ( -220 880 -1208 -8.250000 -18 ) ( -220 880 -1180 -8.031250 -18 ) ) +( ( -220 824 -1208 -8.250000 -17.562500 ) ( -220 852 -1180 -8.031250 -17.781250 ) ( -220 880 -1152 -7.812500 -18 ) ) +( ( -220 824 -1180 -8.031250 -17.562500 ) ( -220 824 -1152 -7.812500 -17.562500 ) ( -220 852 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 113 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -204 880 -1180 -8.031250 -18 ) ( -204 880 -1208 -8.250000 -18 ) ( -204 852 -1208 -8.250000 -17.781250 ) ) +( ( -204 880 -1152 -7.812500 -18 ) ( -204 852 -1180 -8.031250 -17.781250 ) ( -204 824 -1208 -8.250000 -17.562500 ) ) +( ( -204 852 -1152 -7.812500 -17.781250 ) ( -204 824 -1152 -7.812500 -17.562500 ) ( -204 824 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 114 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -204 852 -1208 0 0 ) ( -212 852 -1208 0 0.062500 ) ( -220 852 -1208 0 0.125000 ) ) +( ( -204 824 -1208 0.218750 0 ) ( -212 824 -1208 0.218750 0.062500 ) ( -220 824 -1208 0.218750 0.125000 ) ) +( ( -204 824 -1180 0.437500 0 ) ( -212 824 -1180 0.437500 0.062500 ) ( -220 824 -1180 0.437500 0.125000 ) ) +( ( -204 824 -1152 0.656250 0 ) ( -212 824 -1152 0.656250 0.062500 ) ( -220 824 -1152 0.656250 0.125000 ) ) +( ( -204 852 -1152 0.875000 0 ) ( -212 852 -1152 0.875000 0.062500 ) ( -220 852 -1152 0.875000 0.125000 ) ) +( ( -204 880 -1152 1.093750 0 ) ( -212 880 -1152 1.093750 0.062500 ) ( -220 880 -1152 1.093750 0.125000 ) ) +( ( -204 880 -1180 1.312500 0 ) ( -212 880 -1180 1.312500 0.062500 ) ( -220 880 -1180 1.312500 0.125000 ) ) +( ( -204 880 -1208 1.531250 0 ) ( -212 880 -1208 1.531250 0.062500 ) ( -220 880 -1208 1.531250 0.125000 ) ) +( ( -204 852 -1208 1.750000 0 ) ( -212 852 -1208 1.750000 0.062500 ) ( -220 852 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 115 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -736 796 -1208 0 0 ) ( -744 796 -1208 0 0.062500 ) ( -752 796 -1208 0 0.125000 ) ) +( ( -736 768 -1208 0.218750 0 ) ( -744 768 -1208 0.218750 0.062500 ) ( -752 768 -1208 0.218750 0.125000 ) ) +( ( -736 768 -1180 0.437500 0 ) ( -744 768 -1180 0.437500 0.062500 ) ( -752 768 -1180 0.437500 0.125000 ) ) +( ( -736 768 -1152 0.656250 0 ) ( -744 768 -1152 0.656250 0.062500 ) ( -752 768 -1152 0.656250 0.125000 ) ) +( ( -736 796 -1152 0.875000 0 ) ( -744 796 -1152 0.875000 0.062500 ) ( -752 796 -1152 0.875000 0.125000 ) ) +( ( -736 824 -1152 1.093750 0 ) ( -744 824 -1152 1.093750 0.062500 ) ( -752 824 -1152 1.093750 0.125000 ) ) +( ( -736 824 -1180 1.312500 0 ) ( -744 824 -1180 1.312500 0.062500 ) ( -752 824 -1180 1.312500 0.125000 ) ) +( ( -736 824 -1208 1.531250 0 ) ( -744 824 -1208 1.531250 0.062500 ) ( -752 824 -1208 1.531250 0.125000 ) ) +( ( -736 796 -1208 1.750000 0 ) ( -744 796 -1208 1.750000 0.062500 ) ( -752 796 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 116 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -736 824 -1180 -8.031250 -18 ) ( -736 824 -1208 -8.250000 -18 ) ( -736 796 -1208 -8.250000 -17.781250 ) ) +( ( -736 824 -1152 -7.812500 -18 ) ( -736 796 -1180 -8.031250 -17.781250 ) ( -736 768 -1208 -8.250000 -17.562500 ) ) +( ( -736 796 -1152 -7.812500 -17.781250 ) ( -736 768 -1152 -7.812500 -17.562500 ) ( -736 768 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 117 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -752 796 -1208 -8.250000 -17.781250 ) ( -752 824 -1208 -8.250000 -18 ) ( -752 824 -1180 -8.031250 -18 ) ) +( ( -752 768 -1208 -8.250000 -17.562500 ) ( -752 796 -1180 -8.031250 -17.781250 ) ( -752 824 -1152 -7.812500 -18 ) ) +( ( -752 768 -1180 -8.031250 -17.562500 ) ( -752 768 -1152 -7.812500 -17.562500 ) ( -752 796 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 118 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -712 796 -1208 0 0 ) ( -720 796 -1208 0 0.062500 ) ( -728 796 -1208 0 0.125000 ) ) +( ( -712 768 -1208 0.218750 0 ) ( -720 768 -1208 0.218750 0.062500 ) ( -728 768 -1208 0.218750 0.125000 ) ) +( ( -712 768 -1180 0.437500 0 ) ( -720 768 -1180 0.437500 0.062500 ) ( -728 768 -1180 0.437500 0.125000 ) ) +( ( -712 768 -1152 0.656250 0 ) ( -720 768 -1152 0.656250 0.062500 ) ( -728 768 -1152 0.656250 0.125000 ) ) +( ( -712 796 -1152 0.875000 0 ) ( -720 796 -1152 0.875000 0.062500 ) ( -728 796 -1152 0.875000 0.125000 ) ) +( ( -712 824 -1152 1.093750 0 ) ( -720 824 -1152 1.093750 0.062500 ) ( -728 824 -1152 1.093750 0.125000 ) ) +( ( -712 824 -1180 1.312500 0 ) ( -720 824 -1180 1.312500 0.062500 ) ( -728 824 -1180 1.312500 0.125000 ) ) +( ( -712 824 -1208 1.531250 0 ) ( -720 824 -1208 1.531250 0.062500 ) ( -728 824 -1208 1.531250 0.125000 ) ) +( ( -712 796 -1208 1.750000 0 ) ( -720 796 -1208 1.750000 0.062500 ) ( -728 796 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 119 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -712 824 -1180 -8.031250 -18 ) ( -712 824 -1208 -8.250000 -18 ) ( -712 796 -1208 -8.250000 -17.781250 ) ) +( ( -712 824 -1152 -7.812500 -18 ) ( -712 796 -1180 -8.031250 -17.781250 ) ( -712 768 -1208 -8.250000 -17.562500 ) ) +( ( -712 796 -1152 -7.812500 -17.781250 ) ( -712 768 -1152 -7.812500 -17.562500 ) ( -712 768 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 120 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -728 796 -1208 -8.250000 -17.781250 ) ( -728 824 -1208 -8.250000 -18 ) ( -728 824 -1180 -8.031250 -18 ) ) +( ( -728 768 -1208 -8.250000 -17.562500 ) ( -728 796 -1180 -8.031250 -17.781250 ) ( -728 824 -1152 -7.812500 -18 ) ) +( ( -728 768 -1180 -8.031250 -17.562500 ) ( -728 768 -1152 -7.812500 -17.562500 ) ( -728 796 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 121 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -692 408 -1208 -8.250000 -17.781250 ) ( -692 436 -1208 -8.250000 -18 ) ( -692 436 -1180 -8.031250 -18 ) ) +( ( -692 380 -1208 -8.250000 -17.562500 ) ( -692 408 -1180 -8.031250 -17.781250 ) ( -692 436 -1152 -7.812500 -18 ) ) +( ( -692 380 -1180 -8.031250 -17.562500 ) ( -692 380 -1152 -7.812500 -17.562500 ) ( -692 408 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 122 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -676 436 -1180 -8.031250 -18 ) ( -676 436 -1208 -8.250000 -18 ) ( -676 408 -1208 -8.250000 -17.781250 ) ) +( ( -676 436 -1152 -7.812500 -18 ) ( -676 408 -1180 -8.031250 -17.781250 ) ( -676 380 -1208 -8.250000 -17.562500 ) ) +( ( -676 408 -1152 -7.812500 -17.781250 ) ( -676 380 -1152 -7.812500 -17.562500 ) ( -676 380 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 123 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -676 408 -1208 0 0 ) ( -684 408 -1208 0 0.062500 ) ( -692 408 -1208 0 0.125000 ) ) +( ( -676 380 -1208 0.218750 0 ) ( -684 380 -1208 0.218750 0.062500 ) ( -692 380 -1208 0.218750 0.125000 ) ) +( ( -676 380 -1180 0.437500 0 ) ( -684 380 -1180 0.437500 0.062500 ) ( -692 380 -1180 0.437500 0.125000 ) ) +( ( -676 380 -1152 0.656250 0 ) ( -684 380 -1152 0.656250 0.062500 ) ( -692 380 -1152 0.656250 0.125000 ) ) +( ( -676 408 -1152 0.875000 0 ) ( -684 408 -1152 0.875000 0.062500 ) ( -692 408 -1152 0.875000 0.125000 ) ) +( ( -676 436 -1152 1.093750 0 ) ( -684 436 -1152 1.093750 0.062500 ) ( -692 436 -1152 1.093750 0.125000 ) ) +( ( -676 436 -1180 1.312500 0 ) ( -684 436 -1180 1.312500 0.062500 ) ( -692 436 -1180 1.312500 0.125000 ) ) +( ( -676 436 -1208 1.531250 0 ) ( -684 436 -1208 1.531250 0.062500 ) ( -692 436 -1208 1.531250 0.125000 ) ) +( ( -676 408 -1208 1.750000 0 ) ( -684 408 -1208 1.750000 0.062500 ) ( -692 408 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 124 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -716 408 -1208 -8.250000 -17.781250 ) ( -716 436 -1208 -8.250000 -18 ) ( -716 436 -1180 -8.031250 -18 ) ) +( ( -716 380 -1208 -8.250000 -17.562500 ) ( -716 408 -1180 -8.031250 -17.781250 ) ( -716 436 -1152 -7.812500 -18 ) ) +( ( -716 380 -1180 -8.031250 -17.562500 ) ( -716 380 -1152 -7.812500 -17.562500 ) ( -716 408 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 125 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -700 436 -1180 -8.031250 -18 ) ( -700 436 -1208 -8.250000 -18 ) ( -700 408 -1208 -8.250000 -17.781250 ) ) +( ( -700 436 -1152 -7.812500 -18 ) ( -700 408 -1180 -8.031250 -17.781250 ) ( -700 380 -1208 -8.250000 -17.562500 ) ) +( ( -700 408 -1152 -7.812500 -17.781250 ) ( -700 380 -1152 -7.812500 -17.562500 ) ( -700 380 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 126 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -700 408 -1208 0 0 ) ( -708 408 -1208 0 0.062500 ) ( -716 408 -1208 0 0.125000 ) ) +( ( -700 380 -1208 0.218750 0 ) ( -708 380 -1208 0.218750 0.062500 ) ( -716 380 -1208 0.218750 0.125000 ) ) +( ( -700 380 -1180 0.437500 0 ) ( -708 380 -1180 0.437500 0.062500 ) ( -716 380 -1180 0.437500 0.125000 ) ) +( ( -700 380 -1152 0.656250 0 ) ( -708 380 -1152 0.656250 0.062500 ) ( -716 380 -1152 0.656250 0.125000 ) ) +( ( -700 408 -1152 0.875000 0 ) ( -708 408 -1152 0.875000 0.062500 ) ( -716 408 -1152 0.875000 0.125000 ) ) +( ( -700 436 -1152 1.093750 0 ) ( -708 436 -1152 1.093750 0.062500 ) ( -716 436 -1152 1.093750 0.125000 ) ) +( ( -700 436 -1180 1.312500 0 ) ( -708 436 -1180 1.312500 0.062500 ) ( -716 436 -1180 1.312500 0.125000 ) ) +( ( -700 436 -1208 1.531250 0 ) ( -708 436 -1208 1.531250 0.062500 ) ( -716 436 -1208 1.531250 0.125000 ) ) +( ( -700 408 -1208 1.750000 0 ) ( -708 408 -1208 1.750000 0.062500 ) ( -716 408 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 127 +{ +( -112 896 -556 ) ( -800 896 -556 ) ( -800 336 -556 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -792 336 -492 ) ( -792 896 -492 ) ( -104 896 -492 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -808 456 -548 ) ( -120 456 -548 ) ( -120 456 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -128 336 -548 ) ( -128 896 -548 ) ( -128 896 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -112 848 -548 ) ( -800 848 -548 ) ( -800 848 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -784 896 -548 ) ( -784 336 -548 ) ( -784 336 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 128 +{ +( -48 960 -556 ) ( -736 960 -556 ) ( -736 400 -556 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -728 400 -492 ) ( -728 960 -492 ) ( -40 960 -492 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -736 848 -548 ) ( -48 848 -548 ) ( -48 848 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -192 400 -548 ) ( -192 960 -548 ) ( -192 960 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -48 912 -548 ) ( -736 912 -548 ) ( -736 912 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -720 960 -548 ) ( -720 400 -548 ) ( -720 400 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 129 +{ +( -864 344 -556 ) ( -176 344 -556 ) ( -176 904 -556 ) desktop/blackdrawer 0 0 -180 0.500000 0.500000 0 0 0 +( -184 904 -492 ) ( -184 344 -492 ) ( -872 344 -492 ) desktop/blackdrawer 0 0 -180 0.500000 0.500000 0 0 0 +( -176 456 -548 ) ( -864 456 -548 ) ( -864 456 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +( -712 904 -548 ) ( -712 344 -548 ) ( -712 344 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +( -856 392 -548 ) ( -168 392 -548 ) ( -168 392 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +( -184 344 -548 ) ( -184 904 -548 ) ( -184 904 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 130 +{ +( -864 344 -492 ) ( -176 344 -492 ) ( -176 904 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -184 904 -460 ) ( -184 344 -460 ) ( -872 344 -460 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -176 456 -452 ) ( -864 456 -452 ) ( -864 456 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -712 904 -452 ) ( -712 344 -452 ) ( -712 344 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -856 392 -452 ) ( -168 392 -452 ) ( -168 392 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -184 344 -452 ) ( -184 904 -452 ) ( -184 904 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 131 +{ +( -48 960 -492 ) ( -736 960 -492 ) ( -736 400 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -728 400 -460 ) ( -728 960 -460 ) ( -40 960 -460 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -736 848 -452 ) ( -48 848 -452 ) ( -48 848 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -192 400 -452 ) ( -192 960 -452 ) ( -192 960 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -48 912 -452 ) ( -736 912 -452 ) ( -736 912 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -720 960 -452 ) ( -720 400 -452 ) ( -720 400 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 132 +{ +( -112 896 -492 ) ( -800 896 -492 ) ( -800 336 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -792 336 -460 ) ( -792 896 -460 ) ( -104 896 -460 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -808 456 -452 ) ( -120 456 -452 ) ( -120 456 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -128 336 -452 ) ( -128 896 -452 ) ( -128 896 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -112 848 -452 ) ( -800 848 -452 ) ( -800 848 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -784 896 -452 ) ( -784 336 -452 ) ( -784 336 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 133 +{ +( -800 976 -428 ) ( -112 976 -428 ) ( -112 976 132 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -120 912 132 ) ( -120 912 -428 ) ( -808 912 -428 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -96 968 -252 ) ( -784 968 -252 ) ( -784 1008 -252 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -784 968 132 ) ( -784 968 -428 ) ( -784 1008 -428 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +( -800 968 -380 ) ( -112 968 -380 ) ( -112 1008 -380 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -128 968 -428 ) ( -128 968 132 ) ( -128 1008 132 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 134 +{ +( -864 976 -492 ) ( -176 976 -492 ) ( -176 976 68 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -184 912 68 ) ( -184 912 -492 ) ( -872 912 -492 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -176 968 -380 ) ( -864 968 -380 ) ( -864 1008 -380 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -720 968 68 ) ( -720 968 -492 ) ( -720 1008 -492 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +( -864 968 -444 ) ( -176 968 -444 ) ( -176 1008 -444 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -192 968 -492 ) ( -192 968 68 ) ( -192 1008 68 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 135 +{ +( -800 912 -428 ) ( -112 912 -428 ) ( -112 912 132 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -120 880 132 ) ( -120 880 -428 ) ( -808 880 -428 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -88 872 -252 ) ( -776 872 -252 ) ( -776 912 -252 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -784 872 132 ) ( -784 872 -428 ) ( -784 912 -428 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +( -800 872 -380 ) ( -112 872 -380 ) ( -112 912 -380 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -128 872 -428 ) ( -128 872 132 ) ( -128 912 132 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 136 +{ +( -88 912 124 ) ( -776 912 124 ) ( -776 912 -436 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -768 880 -436 ) ( -768 880 124 ) ( -80 880 124 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -768 872 -252 ) ( -80 872 -252 ) ( -80 912 -252 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -296 872 -436 ) ( -296 872 124 ) ( -296 912 124 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +( -100 872 222 ) ( -788 872 222 ) ( -788 912 222 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -616 872 116 ) ( -616 872 -444 ) ( -616 912 -444 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 137 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 880 -380 -11.875000 -34.250000 ) ( -160 880 -380 -11.875000 -34.750000 ) ( -160 880 -380 -11.875000 -34.750000 ) ) +( ( -192 880 -444 -10.875000 -34.250000 ) ( -160 880 -412 -11.375000 -34.750000 ) ( -128 880 -380 -11.875000 -35.250000 ) ) +( ( -192 880 -444 -10.875000 -34.250000 ) ( -128 880 -444 -10.875000 -35.250000 ) ( -128 880 -380 -11.875000 -35.250000 ) ) +) + } + } +// brush 138 +{ +( -864 912 -492 ) ( -176 912 -492 ) ( -176 912 68 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -184 880 68 ) ( -184 880 -492 ) ( -872 880 -492 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -176 872 -380 ) ( -864 872 -380 ) ( -864 912 -380 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -720 872 68 ) ( -720 872 -492 ) ( -720 912 -492 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +( -864 872 -444 ) ( -176 872 -444 ) ( -176 912 -444 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -192 872 -492 ) ( -192 872 68 ) ( -192 912 68 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 139 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -160 944 -380 0 0 ) ( -160 960 -380 0 0.750000 ) ( -160 976 -380 0 1.500000 ) ) +( ( -128 944 -380 0.500000 0 ) ( -128 960 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 944 -380 0.500000 0 ) ( -128 960 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 944 -444 1.500000 0 ) ( -128 960 -444 1.500000 0.750000 ) ( -128 976 -444 1.500000 1.500000 ) ) +( ( -192 944 -444 2.500000 0 ) ( -192 960 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 944 -444 2.500000 0 ) ( -192 960 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 944 -380 3.500000 0 ) ( -192 960 -380 3.500000 0.750000 ) ( -192 976 -380 3.500000 1.500000 ) ) +( ( -160 944 -380 4 0 ) ( -160 960 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +( ( -160 944 -380 4 0 ) ( -160 960 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +) + } + } +// brush 140 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -720 944 -412 0 0 ) ( -720 960 -412 0 0.750000 ) ( -720 976 -412 0 1.500000 ) ) +( ( -720 944 -444 0.500000 0 ) ( -720 960 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -720 944 -444 0.500000 0 ) ( -720 960 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -784 944 -444 1.500000 0 ) ( -784 960 -444 1.500000 0.750000 ) ( -784 976 -444 1.500000 1.500000 ) ) +( ( -784 944 -380 2.500000 0 ) ( -784 960 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -784 944 -380 2.500000 0 ) ( -784 960 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -720 944 -380 3.500000 0 ) ( -720 960 -380 3.500000 0.750000 ) ( -720 976 -380 3.500000 1.500000 ) ) +( ( -720 944 -412 4 0 ) ( -720 960 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +( ( -720 944 -412 4 0 ) ( -720 960 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +) + } + } +// brush 141 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -720 880 -380 -11.875000 -34.250000 ) ( -720 880 -412 -11.875000 -34.750000 ) ( -720 880 -412 -11.875000 -34.750000 ) ) +( ( -784 880 -380 -10.875000 -34.250000 ) ( -752 880 -412 -11.375000 -34.750000 ) ( -720 880 -444 -11.875000 -35.250000 ) ) +( ( -784 880 -380 -10.875000 -34.250000 ) ( -784 880 -444 -10.875000 -35.250000 ) ( -720 880 -444 -11.875000 -35.250000 ) ) +) + } + } +// brush 142 +{ +( -88 976 124 ) ( -776 976 124 ) ( -776 976 -436 ) desktop/blackdrawer 0 80 0 0.500000 -0.500000 0 0 0 +( -768 912 -436 ) ( -768 912 124 ) ( -80 912 124 ) desktop/blackdrawer 0 80 0 0.500000 -0.500000 0 0 0 +( -776 968 -252 ) ( -88 968 -252 ) ( -88 1008 -252 ) desktop/blackdrawer 0 16 0 0.500000 0.500000 0 0 0 +( -296 968 -436 ) ( -296 968 124 ) ( -296 1008 124 ) desktop/blackdrawer -80 16 -90 0.500000 0.500000 0 0 0 +( -90 968 222 ) ( -778 968 222 ) ( -778 1008 222 ) desktop/blackdrawer 0 16 0 0.500000 0.500000 0 0 0 +( -616 968 124 ) ( -616 968 -436 ) ( -616 1008 -436 ) desktop/blackdrawer -80 16 -90 0.500000 0.500000 0 0 0 +} +// brush 143 +{ +( -416 976 -510 ) ( -480 976 -510 ) ( -480 928 -510 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -480 928 -444 ) ( -480 976 -444 ) ( -416 976 -444 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -480 924 -444 ) ( -416 924 -444 ) ( -416 924 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -416 928 -444 ) ( -416 976 -444 ) ( -416 976 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -416 959 -444 ) ( -480 959 -444 ) ( -480 959 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -480 976 -444 ) ( -480 928 -444 ) ( -480 928 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 144 +{ +( -416 907 -557 ) ( -480 907 -557 ) ( -480 875 -521 ) desktop/blackdrawer 0 40 0 0.500000 -0.372040 0 0 0 +( -480 905 -527 ) ( -416 905 -527 ) ( -416 839 -586 ) desktop/blackdrawer 0 79 0 0.500000 0.371704 0 0 0 +( -416 917 -483 ) ( -416 949 -519 ) ( -416 883 -578 ) desktop/blackdrawer -61 -27 -47 0.500113 0.499524 0 0 0 +( -416 949 -519 ) ( -480 949 -519 ) ( -480 883 -578 ) desktop/blackdrawer 0 50 0 0.500000 0.371338 0 0 0 +( -480 949 -519 ) ( -480 917 -483 ) ( -480 851 -542 ) desktop/blackdrawer -61 -27 -47 0.500113 0.499524 0 0 0 +( -480 976 -510 ) ( -416 976 -510 ) ( -480 928 -510 ) desktop/blackdrawer -61 -27 -47 0.500113 0.499524 0 0 0 +} +// brush 145 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 400 -8192 8192 ) ( 400 8192 8192 ) ( 400 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 146 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1456 8192 ) ( 8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 147 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 148 +{ +( 1984 8192 8192 ) ( 1984 -8192 8192 ) ( 1984 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 149 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 736 8192 ) ( -8192 736 8192 ) ( -8192 736 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 150 +{ +( -2168 8192 8192 ) ( -2168 -8192 8192 ) ( -2168 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -2160 -8192 8192 ) ( -2160 8192 8192 ) ( -2160 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 151 +{ +( -2160 8192 8192 ) ( -2160 -8192 8192 ) ( -2160 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 2120 -8192 8192 ) ( 2120 8192 8192 ) ( 2120 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 2648 8192 ) ( 8192 2648 8192 ) ( -8192 2648 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 152 +{ +( 2120 8192 8192 ) ( 2120 -8192 8192 ) ( 2120 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 2128 -8192 8192 ) ( 2128 8192 8192 ) ( 2128 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 153 +{ +( -2168 8192 8192 ) ( -2168 -8192 8192 ) ( -2168 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 2128 -8192 8192 ) ( 2128 8192 8192 ) ( 2128 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1432 8192 ) ( 8192 -1432 8192 ) ( -8192 -1432 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1424 8192 ) ( -8192 -1424 8192 ) ( -8192 -1424 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 154 +{ +( -2168 8192 8192 ) ( -2168 -8192 8192 ) ( -2168 8192 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 2128 -8192 8192 ) ( 2128 8192 8192 ) ( 2128 8192 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1208 ) ( 8192 -8192 -1208 ) ( -8192 -8192 -1208 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 155 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 749 -8161 8192 ) ( -272 8190 8192 ) ( -272 8190 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 583 8171 8192 ) ( -438 -8180 8192 ) ( -438 -8180 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 156 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 8 ) ( 8192 -8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 157 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 158 +{ +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 -7808 2544 ) ( 8191 8090 -1409 ) ( -8192 8087 -1423 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1911 7973 8192 ) ( 2572 -7785 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1196 -8176 8192 ) ( 3288 7581 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7809 2539 ) ( 8192 8088 -1418 ) ( -8192 8088 -1418 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 159 +{ +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1196 -8176 8192 ) ( 3288 7581 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1911 7973 8192 ) ( 2572 -7785 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 7925 2075 ) ( 8191 -7985 -1832 ) ( -8192 -7980 -1851 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1912 7973 8192 ) ( 2573 -7784 8192 ) ( 2573 -7784 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 160 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/myscreen 0 32 0 -0.031250 2.250000 0 0 0 +( 1104 -8192 8192 ) ( 1104 8192 8192 ) ( 1104 8192 -8192 ) desktop/myscreen 0 32 0 -0.031250 2.250000 0 0 0 +( -8192 -144 8192 ) ( 8192 -144 8192 ) ( -8192 -144 -8192 ) desktop/myscreen 136 32 0 -2.812500 2.250000 0 0 0 +( 8192 -136 8192 ) ( -8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/myscreen 136 32 0 -2.812500 2.250000 0 0 0 +( 8192 -8192 72 ) ( 8192 8192 72 ) ( -8192 -8192 72 ) desktop/myscreen 136 0 0 -2.812500 0.031250 0 0 0 +( 8192 8192 648 ) ( 8192 -8192 648 ) ( -8192 -8192 648 ) desktop/myscreen 136 0 0 -2.812500 0.031250 0 0 0 +} +// brush 161 +{ +( 352 8192 8192 ) ( 352 -8192 8192 ) ( 352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1136 -8192 8192 ) ( 1136 8192 8192 ) ( 1136 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -166 8192 ) ( -8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 162 +{ +( 464 8192 8192 ) ( 464 -8192 8192 ) ( 464 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 984 -8192 8192 ) ( 984 8192 8192 ) ( 984 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -144 8192 ) ( -8192 -144 8192 ) ( -8192 -144 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -120 ) ( 8192 -8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 163 +{ +( 416 8192 8192 ) ( 416 -8192 8192 ) ( 416 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1224 -8192 8192 ) ( 1224 8192 8192 ) ( 1224 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 24 8192 ) ( 8192 24 8192 ) ( -8192 24 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 360 8192 ) ( -8192 360 8192 ) ( -8192 360 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -112 ) ( 8192 -8192 -112 ) ( -8192 -8192 -112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 164 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Keybesc 113 -17 180 0.095893 0.101763 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1505 8191 8136 ) ( 1505 -8191 8136 ) ( 823 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 165 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F1 84 -5 180 0.190898 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 421 -8191 8255 ) ( 421 8191 8255 ) ( 1781 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1433 8191 8139 ) ( 1433 -8191 8139 ) ( 751 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 166 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F2 2 -5 180 0.188531 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 389 -8191 8252 ) ( 389 8191 8252 ) ( 1750 8191 -8074 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1401 8191 8140 ) ( 1401 -8191 8140 ) ( 719 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 167 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F3 41 -5 180 0.189517 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 357 -8191 8250 ) ( 357 8191 8250 ) ( 1718 8191 -8077 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1369 8191 8142 ) ( 1369 -8191 8142 ) ( 687 -8191 -8227 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 168 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F4 -34 -5 180 0.190813 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 325 -8191 8247 ) ( 325 8191 8247 ) ( 1686 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1337 8191 8143 ) ( 1337 -8191 8143 ) ( 655 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 169 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/F5 60 58 0 -0.234493 0.226945 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F5 24 3 180 0.188937 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 278 -8191 8243 ) ( 278 8191 8243 ) ( 1638 8191 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1289 8191 8145 ) ( 1289 -8191 8145 ) ( 607 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 170 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F6 40 -5 180 0.186584 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 246 -8191 8240 ) ( 246 8191 8240 ) ( 1607 8191 -8086 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1257 8191 8146 ) ( 1257 -8191 8146 ) ( 575 -8191 -8223 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 171 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F7 -27 -5 180 0.187561 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 214 -8191 8238 ) ( 214 8191 8238 ) ( 1575 8191 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1225 8191 8148 ) ( 1225 -8191 8148 ) ( 543 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 172 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F8 31 -13 180 0.188858 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 182 -8191 8235 ) ( 182 8191 8235 ) ( 1543 8191 -8091 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1193 8191 8149 ) ( 1193 -8191 8149 ) ( 511 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 173 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F9 74 -5 180 0.186992 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -8191 8231 ) ( 135 8191 8231 ) ( 1495 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1145 8191 8151 ) ( 1145 -8191 8151 ) ( 463 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 174 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F10 90 -5 180 0.184310 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 103 -8191 8229 ) ( 103 8191 8229 ) ( 1464 8191 -8098 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1113 8191 8152 ) ( 1113 -8191 8152 ) ( 431 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 175 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F11 56 -5 180 0.189489 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 71 -8191 8226 ) ( 71 8191 8226 ) ( 1432 8191 -8101 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1082 8191 8154 ) ( 1082 -8191 8154 ) ( 399 -8191 -8215 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 176 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 39 -8191 8223 ) ( 39 8191 8223 ) ( 1400 8191 -8103 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 8191 8155 ) ( 1050 -8191 8155 ) ( 368 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 177 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 178 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 179 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 180 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Kplus 74 59 180 0.187958 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 111 -8191 8229 ) ( 111 8191 8229 ) ( 1471 8191 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1121 8191 8152 ) ( 1121 -8191 8152 ) ( 439 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 181 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Kminus 138 59 180 0.186671 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 143 -8191 8232 ) ( 143 8191 8232 ) ( 1503 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 8191 8151 ) ( 1153 -8191 8151 ) ( 471 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 182 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K0 -11 59 180 0.189511 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 174 -8191 8234 ) ( 174 8191 8234 ) ( 1535 8191 -8092 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1185 8191 8149 ) ( 1185 -8191 8149 ) ( 503 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 183 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K9 62 59 180 0.187882 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 206 -8191 8237 ) ( 206 8191 8237 ) ( 1567 8191 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1217 8191 8148 ) ( 1217 -8191 8148 ) ( 535 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 184 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K8 19 59 180 0.186586 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 238 -8191 8240 ) ( 238 8191 8240 ) ( 1599 8191 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1249 8191 8147 ) ( 1249 -8191 8147 ) ( 567 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 185 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K7 112 59 180 0.189598 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 270 -8191 8242 ) ( 270 8191 8242 ) ( 1630 8191 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1281 8191 8145 ) ( 1281 -8191 8145 ) ( 599 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 186 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K6 77 59 180 0.187970 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 302 -8191 8245 ) ( 302 8191 8245 ) ( 1662 8191 -8081 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1313 8191 8144 ) ( 1313 -8191 8144 ) ( 631 -8191 -8225 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 187 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K5 45 59 180 0.190493 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 333 -8191 8248 ) ( 333 8191 8248 ) ( 1694 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1345 8191 8143 ) ( 1345 -8191 8143 ) ( 663 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 188 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K4 -9 59 180 0.189508 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 365 -8191 8250 ) ( 365 8191 8250 ) ( 1726 8191 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1377 8191 8141 ) ( 1377 -8191 8141 ) ( 695 -8191 -8228 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 189 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K3 73 59 180 0.191880 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 397 -8191 8253 ) ( 397 8191 8253 ) ( 1757 8191 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1409 8191 8140 ) ( 1409 -8191 8140 ) ( 727 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 190 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K2 146 59 180 0.190578 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 429 -8191 8256 ) ( 429 8191 8256 ) ( 1789 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1441 8191 8139 ) ( 1441 -8191 8139 ) ( 759 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 191 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K1 93 59 180 0.193414 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 460 -8191 8258 ) ( 460 8191 8258 ) ( 1821 8191 -8068 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1473 8191 8137 ) ( 1473 -8191 8137 ) ( 791 -8191 -8232 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 192 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Topleftkey 52 59 180 0.191785 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1505 8191 8136 ) ( 1505 -8191 8136 ) ( 823 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 193 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 79 -8191 8227 ) ( 79 8191 8227 ) ( 1440 8191 -8100 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 194 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Q 110 123 180 0.293417 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 452 -8191 8258 ) ( 452 8191 8258 ) ( 1813 8191 -8069 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1465 8191 8138 ) ( 1465 -8191 8138 ) ( 783 -8191 -8231 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 195 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/W 164 115 180 0.290898 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 421 -8191 8255 ) ( 421 8191 8255 ) ( 1781 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1433 8191 8139 ) ( 1433 -8191 8139 ) ( 751 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 196 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/E 82 115 180 0.288531 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 389 -8191 8252 ) ( 389 8191 8252 ) ( 1750 8191 -8074 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1401 8191 8140 ) ( 1401 -8191 8140 ) ( 719 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 197 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/R 81 115 180 0.289517 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 357 -8191 8250 ) ( 357 8191 8250 ) ( 1718 8191 -8077 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1369 8191 8142 ) ( 1369 -8191 8142 ) ( 687 -8191 -8227 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 198 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/T 78 115 180 0.290813 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 325 -8191 8247 ) ( 325 8191 8247 ) ( 1686 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1337 8191 8143 ) ( 1337 -8191 8143 ) ( 655 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 199 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Y 125 115 180 0.288615 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 294 -8191 8244 ) ( 294 8191 8244 ) ( 1654 8191 -8082 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1305 8191 8144 ) ( 1305 -8191 8144 ) ( 623 -8191 -8225 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 200 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/U 130 115 180 0.289599 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 262 -8191 8242 ) ( 262 8191 8242 ) ( 1622 8191 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1273 8191 8146 ) ( 1273 -8191 8146 ) ( 591 -8191 -8223 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 201 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 230 -8191 8239 ) ( 230 8191 8239 ) ( 1591 8191 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1241 8191 8147 ) ( 1241 -8191 8147 ) ( 559 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 202 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 198 -8191 8236 ) ( 198 8191 8236 ) ( 1559 8191 -8090 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1209 8191 8148 ) ( 1209 -8191 8148 ) ( 527 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 203 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 166 -8191 8234 ) ( 166 8191 8234 ) ( 1527 8191 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1177 8191 8150 ) ( 1177 -8191 8150 ) ( 495 -8191 -8219 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 204 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -8191 8231 ) ( 135 8191 8231 ) ( 1495 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1145 8191 8151 ) ( 1145 -8191 8151 ) ( 463 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 205 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 103 -8191 8229 ) ( 103 8191 8229 ) ( 1464 8191 -8098 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1113 8191 8152 ) ( 1113 -8191 8152 ) ( 431 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 206 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 95 -8191 8228 ) ( 95 8191 8228 ) ( 1456 8191 -8099 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 8191 8153 ) ( 1106 -8191 8153 ) ( 423 -8191 -8216 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 207 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 127 -8191 8230 ) ( 127 8191 8230 ) ( 1487 8191 -8096 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1137 8191 8151 ) ( 1137 -8191 8151 ) ( 455 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 208 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 159 -8191 8233 ) ( 159 8191 8233 ) ( 1519 8191 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1169 8191 8150 ) ( 1169 -8191 8150 ) ( 487 -8191 -8219 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 209 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 190 -8191 8236 ) ( 190 8191 8236 ) ( 1551 8191 -8091 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1201 8191 8149 ) ( 1201 -8191 8149 ) ( 519 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 210 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 222 -8191 8238 ) ( 222 8191 8238 ) ( 1583 8191 -8088 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1233 8191 8147 ) ( 1233 -8191 8147 ) ( 551 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 211 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -8191 8241 ) ( 254 8191 8241 ) ( 1614 8191 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1265 8191 8146 ) ( 1265 -8191 8146 ) ( 583 -8191 -8223 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 212 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 286 -8191 8244 ) ( 286 8191 8244 ) ( 1646 8191 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1297 8191 8145 ) ( 1297 -8191 8145 ) ( 615 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 213 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 317 -8191 8246 ) ( 317 8191 8246 ) ( 1678 8191 -8080 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1329 8191 8143 ) ( 1329 -8191 8143 ) ( 647 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 214 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 349 -8191 8249 ) ( 349 8191 8249 ) ( 1710 8191 -8077 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1361 8191 8142 ) ( 1361 -8191 8142 ) ( 679 -8191 -8227 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 215 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 381 -8191 8252 ) ( 381 8191 8252 ) ( 1742 8191 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1393 8191 8141 ) ( 1393 -8191 8141 ) ( 711 -8191 -8228 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 216 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 413 -8191 8254 ) ( 413 8191 8254 ) ( 1773 8191 -8072 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1425 8191 8139 ) ( 1425 -8191 8139 ) ( 743 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 217 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 445 -8191 8257 ) ( 445 8191 8257 ) ( 1805 8191 -8069 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1457 8191 8138 ) ( 1457 -8191 8138 ) ( 775 -8191 -8231 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 218 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1497 8191 8136 ) ( 1497 -8191 8136 ) ( 815 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 219 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1497 8191 8136 ) ( 1497 -8191 8136 ) ( 815 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 220 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 460 -8191 8258 ) ( 460 8191 8258 ) ( 1821 8191 -8068 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1473 8191 8137 ) ( 1473 -8191 8137 ) ( 791 -8191 -8232 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 221 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 429 -8191 8256 ) ( 429 8191 8256 ) ( 1789 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1441 8191 8139 ) ( 1441 -8191 8139 ) ( 759 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 222 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 397 -8191 8253 ) ( 397 8191 8253 ) ( 1757 8191 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1409 8191 8140 ) ( 1409 -8191 8140 ) ( 727 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 223 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 365 -8191 8250 ) ( 365 8191 8250 ) ( 1726 8191 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1377 8191 8141 ) ( 1377 -8191 8141 ) ( 695 -8191 -8228 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 224 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 333 -8191 8248 ) ( 333 8191 8248 ) ( 1694 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1345 8191 8143 ) ( 1345 -8191 8143 ) ( 663 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 225 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 302 -8191 8245 ) ( 302 8191 8245 ) ( 1662 8191 -8081 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1313 8191 8144 ) ( 1313 -8191 8144 ) ( 631 -8191 -8225 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 226 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 270 -8191 8242 ) ( 270 8191 8242 ) ( 1630 8191 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1281 8191 8145 ) ( 1281 -8191 8145 ) ( 599 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 227 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 238 -8191 8240 ) ( 238 8191 8240 ) ( 1599 8191 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1249 8191 8147 ) ( 1249 -8191 8147 ) ( 567 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 228 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 206 -8191 8237 ) ( 206 8191 8237 ) ( 1567 8191 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1217 8191 8148 ) ( 1217 -8191 8148 ) ( 535 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 229 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 174 -8191 8234 ) ( 174 8191 8234 ) ( 1535 8191 -8092 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1185 8191 8149 ) ( 1185 -8191 8149 ) ( 503 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 230 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 143 -8191 8232 ) ( 143 8191 8232 ) ( 1503 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 8191 8151 ) ( 1153 -8191 8151 ) ( 471 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 231 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 111 -8191 8229 ) ( 111 8191 8229 ) ( 1471 8191 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1121 8191 8152 ) ( 1121 -8191 8152 ) ( 439 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 232 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1505 8191 8136 ) ( 1505 -8191 8136 ) ( 823 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 233 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 71 -8191 8226 ) ( 71 8191 8226 ) ( 1432 8191 -8101 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 234 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 750 8161 ) ( 8192 750 8161 ) ( 8192 -271 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 63 -8191 8225 ) ( 63 8191 8225 ) ( 1424 8191 -8101 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 235 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 79 -8191 8227 ) ( 79 8191 8227 ) ( 1440 8191 -8100 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 236 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 237 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 238 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 239 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 240 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 241 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 242 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 243 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 244 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 245 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 246 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1360 8192 ) ( 8192 -1360 8192 ) ( -8192 -1360 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1512 8192 ) ( -8192 1512 8192 ) ( -8192 1512 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -168 ) ( 8192 8192 -168 ) ( -8192 -8192 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -136 ) ( 8192 -8192 -136 ) ( -8192 -8192 -136 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 247 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1489 8191 8137 ) ( 1489 -8191 8137 ) ( 807 -8191 -8232 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 248 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 445 -8191 8257 ) ( 445 8191 8257 ) ( 1805 8191 -8069 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1449 8191 8138 ) ( 1449 -8191 8138 ) ( 767 -8191 -8231 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 249 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 405 -8191 8254 ) ( 405 8191 8254 ) ( 1765 8191 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1409 8191 8140 ) ( 1409 -8191 8140 ) ( 727 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 250 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -8191 8225 ) ( 55 8191 8225 ) ( 1416 8191 -8102 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 8191 8155 ) ( 1050 -8191 8155 ) ( 368 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 251 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 95 -8191 8228 ) ( 95 8191 8228 ) ( 1456 8191 -8099 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1098 8191 8153 ) ( 1098 -8191 8153 ) ( 415 -8191 -8216 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 252 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -8191 8231 ) ( 135 8191 8231 ) ( 1495 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1137 8191 8151 ) ( 1137 -8191 8151 ) ( 455 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 253 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 174 -8191 8234 ) ( 174 8191 8234 ) ( 1535 8191 -8092 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1177 8191 8150 ) ( 1177 -8191 8150 ) ( 495 -8191 -8219 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 254 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 365 -8191 8250 ) ( 365 8191 8250 ) ( 1726 8191 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1217 8191 8148 ) ( 1217 -8191 8148 ) ( 535 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 255 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -272 8190 ) ( -8192 -272 8190 ) ( -8192 749 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 256 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -272 8190 ) ( -8192 -272 8190 ) ( -8192 749 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 257 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -272 8190 ) ( -8192 -272 8190 ) ( -8192 749 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 258 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 259 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 260 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 261 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 262 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 263 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 264 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 265 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 266 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 766 8160 ) ( 8192 766 8160 ) ( 8192 -255 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 267 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 766 8160 ) ( 8192 766 8160 ) ( 8192 -255 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 268 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 766 8160 ) ( 8192 766 8160 ) ( 8192 -255 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 269 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -214 -8191 8202 ) ( -214 8191 8202 ) ( 1146 8191 -8124 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 794 8191 8166 ) ( 794 -8191 8166 ) ( 112 -8191 -8203 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 270 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -214 -8191 8202 ) ( -214 8191 8202 ) ( 1146 8191 -8124 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 794 8191 8166 ) ( 794 -8191 8166 ) ( 112 -8191 -8203 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 271 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -214 -8191 8202 ) ( -214 8191 8202 ) ( 1146 8191 -8124 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 794 8191 8166 ) ( 794 -8191 8166 ) ( 112 -8191 -8203 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 272 +{ +( 540 8192 8192 ) ( 540 -8192 8192 ) ( 540 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1136 -8192 8192 ) ( 1136 8192 8192 ) ( 1136 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -166 8192 ) ( 8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1275 8093 ) ( -8192 -1275 8093 ) ( -8192 988 -8133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 273 +{ +( 828 8192 8192 ) ( 828 -8192 8192 ) ( 828 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 854 -8192 8192 ) ( 854 8192 8192 ) ( 854 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 274 +{ +( 884 8192 8192 ) ( 884 -8192 8192 ) ( 884 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 910 -8192 8192 ) ( 910 8192 8192 ) ( 910 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 275 +{ +( 856 8192 8192 ) ( 856 -8192 8192 ) ( 856 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 882 -8192 8192 ) ( 882 8192 8192 ) ( 882 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 276 +{ +( 912 8192 8192 ) ( 912 -8192 8192 ) ( 912 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 -8192 8192 ) ( 938 8192 8192 ) ( 938 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 277 +{ +( 940 8192 8192 ) ( 940 -8192 8192 ) ( 940 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 966 -8192 8192 ) ( 966 8192 8192 ) ( 966 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 278 +{ +( 968 8192 8192 ) ( 968 -8192 8192 ) ( 968 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 992 -8192 8192 ) ( 992 8192 8192 ) ( 992 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 279 +{ +( 740 8192 8192 ) ( 740 -8192 8192 ) ( 740 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 764 -8192 8192 ) ( 764 8192 8192 ) ( 764 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 280 +{ +( 712 8192 8192 ) ( 712 -8192 8192 ) ( 712 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 738 -8192 8192 ) ( 738 8192 8192 ) ( 738 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 281 +{ +( 634 8192 8192 ) ( 634 -8192 8192 ) ( 634 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 660 -8192 8192 ) ( 660 8192 8192 ) ( 660 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 282 +{ +( 606 8192 8192 ) ( 606 -8192 8192 ) ( 606 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 632 -8192 8192 ) ( 632 8192 8192 ) ( 632 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 283 +{ +( 352 8192 8192 ) ( 352 -8192 8192 ) ( 352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 464 -8192 8192 ) ( 464 8192 8192 ) ( 464 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -166 8192 ) ( 8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1275 8093 ) ( -8192 -1275 8093 ) ( -8192 988 -8133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 284 +{ +( 465 8192 8192 ) ( 465 -8192 8192 ) ( 465 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 539 -8192 8192 ) ( 539 8192 8192 ) ( 539 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -166 8192 ) ( 8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1275 8093 ) ( -8192 -1275 8093 ) ( -8192 988 -8133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 285 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 680 8192 ) ( 8192 680 8192 ) ( -8192 680 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1512 8192 ) ( -8192 1512 8192 ) ( -8192 1512 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -360 ) ( 8192 8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -336 ) ( 8192 -8192 -336 ) ( -8192 -8192 -336 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 286 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 688 8192 ) ( 8192 688 8192 ) ( -8192 688 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1504 8192 ) ( -8192 1504 8192 ) ( -8192 1504 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1080 ) ( 8192 8192 -1080 ) ( -8192 -8192 -1080 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1048 ) ( 8192 -8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 287 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1472 8192 ) ( 8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1504 8192 ) ( -8192 1504 8192 ) ( -8192 1504 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 288 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 688 8192 ) ( 8192 688 8192 ) ( -8192 688 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 720 8192 ) ( -8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 289 +{ +( 2056 8192 8192 ) ( 2056 -8192 8192 ) ( 2056 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 290 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 384 -8192 8192 ) ( 384 8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -634 ) ( 8192 -8192 -634 ) ( -8192 -8192 -634 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 291 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -918 8192 ) ( -8192 -918 8192 ) ( -8192 -918 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 7 ) ( 8192 8192 7 ) ( -8192 -8192 7 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 607 -8245 8192 ) ( 1629 8106 8192 ) ( 1629 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -145 8198 8192 ) ( 876 -8153 8192 ) ( 876 -8153 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 292 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 598 ) ( 8192 8192 598 ) ( -8192 -8192 598 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 609 -8246 8192 ) ( 1631 8106 8192 ) ( 1631 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -142 8199 8192 ) ( 879 -8152 8192 ) ( 879 -8152 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 293 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 8 ) ( 8192 8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -147 8198 8192 ) ( 874 -8153 8192 ) ( 874 -8153 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 881 -8152 8192 ) ( -140 8199 8192 ) ( -140 8199 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 294 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 8 ) ( 8192 8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 613 -8246 8192 ) ( 1635 8105 8192 ) ( 1635 8105 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1629 8106 8192 ) ( 607 -8245 8192 ) ( 1629 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 295 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 6 ) ( 8192 8192 6 ) ( -8192 -8192 6 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 8 ) ( 8192 -8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 609 -8246 8192 ) ( 1631 8106 8192 ) ( 1631 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -140 8199 8192 ) ( 881 -8152 8192 ) ( -140 8199 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 296 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 297 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -224 8192 ) ( -8192 -224 8192 ) ( -8192 -224 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 298 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 276 8193 ) ( 8192 276 8193 ) ( 8192 -890 -8149 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7995 -1789 ) ( 8192 -8044 1551 ) ( -8192 -8044 1551 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 815 8155 ) ( -8192 815 8155 ) ( -8192 -1350 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8172 577 ) ( 8192 8155 -783 ) ( -8192 8155 -783 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 299 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 276 8193 ) ( 8192 276 8193 ) ( 8192 -890 -8149 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7995 -1789 ) ( 8192 -8044 1551 ) ( -8192 -8044 1551 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 815 8155 ) ( -8192 815 8155 ) ( -8192 -1350 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8172 577 ) ( 8192 8155 -783 ) ( -8192 8155 -783 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 300 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 642 8194 ) ( 8194 -136 8194 ) ( 8139 -1301 -8147 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7995 -1789 ) ( 8192 -8044 1551 ) ( -8192 -8044 1551 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 815 8155 ) ( -8192 815 8155 ) ( -8192 -1350 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8172 577 ) ( 8192 8155 -783 ) ( -8192 8155 -783 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 301 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8213 345 8169 ) ( 8156 1027 8169 ) ( 8240 -1001 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8162 ) ( -8192 767 8162 ) ( -8192 -1397 -8078 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 584 ) ( 8192 8155 -776 ) ( -8192 8155 -776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 667 8172 ) ( 8191 667 8172 ) ( 8191 -1364 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -52 ) ( 8192 -8192 -52 ) ( -8192 -8192 -52 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 302 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 667 8172 ) ( 8191 667 8172 ) ( 8191 -1364 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8162 ) ( -8192 767 8162 ) ( -8192 -1397 -8078 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 584 ) ( 8192 8155 -776 ) ( -8192 8155 -776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 303 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 667 8172 ) ( 8191 667 8172 ) ( 8191 -1364 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8162 ) ( -8192 767 8162 ) ( -8192 -1397 -8078 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 584 ) ( 8192 8155 -776 ) ( -8192 8155 -776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 304 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 719 8168 ) ( -8192 719 8168 ) ( -8192 -1445 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 591 ) ( 8192 8156 -769 ) ( -8192 8156 -769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 305 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 719 8168 ) ( -8192 719 8168 ) ( -8192 -1445 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 591 ) ( 8192 8156 -769 ) ( -8192 8156 -769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 306 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 719 8168 ) ( -8192 719 8168 ) ( -8192 -1445 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 591 ) ( 8192 8156 -769 ) ( -8192 8156 -769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 307 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 572 8184 ) ( 8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 672 8174 ) ( -8192 672 8174 ) ( -8192 -1493 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7799 2512 ) ( 8192 7675 -2870 ) ( -8192 7675 -2870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 308 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 572 8184 ) ( 8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 672 8174 ) ( -8192 672 8174 ) ( -8192 -1493 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7799 2512 ) ( 8192 7675 -2870 ) ( -8192 7675 -2870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 309 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 572 8184 ) ( 8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 672 8174 ) ( -8192 672 8174 ) ( -8192 -1493 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7799 2512 ) ( 8192 7675 -2870 ) ( -8192 7675 -2870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 310 +{ +( -392 8192 8192 ) ( -392 -8192 8192 ) ( -392 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -320 -8192 8192 ) ( -320 8192 8192 ) ( -320 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8191 445 8200 ) ( 8191 445 8200 ) ( 8191 -1586 -8057 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7972 -1889 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8191 1800 7993 ) ( -8191 1800 7993 ) ( -8191 -2172 -7900 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 311 +{ +( -285 8192 8192 ) ( -285 -8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -199 -8192 8192 ) ( -199 8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 909 8145 ) ( 8191 909 8145 ) ( 8191 -1407 -8074 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7939 -2020 ) ( 8192 -7998 1774 ) ( -8192 -7998 1774 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1230 8101 ) ( -8192 1230 8101 ) ( -8192 -1593 -8037 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8047 1537 ) ( 8192 7987 -1824 ) ( -8192 7987 -1824 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 312 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -199 -8192 8192 ) ( -199 8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -405 8203 ) ( 8192 -405 8203 ) ( 8192 -795 -8175 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8182 402 ) ( 8192 -8184 -353 ) ( -8192 -8184 -353 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 396 8199 ) ( -8192 396 8199 ) ( -8192 -1453 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 313 +{ +( 14 8192 8192 ) ( 14 -8192 8192 ) ( 14 8192 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 174 -8192 8192 ) ( 174 8192 8192 ) ( 174 8192 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( -8192 -80 8192 ) ( 8192 -80 8192 ) ( -8192 -80 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 8192 80 8192 ) ( -8192 80 8192 ) ( -8192 80 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 8192 8192 -132 ) ( 8192 -8192 -132 ) ( -8192 -8192 -132 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +} +// brush 314 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2572 -7785 8192 ) ( -1911 7973 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 315 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2572 -7785 8192 ) ( -1911 7973 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 316 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 317 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 318 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -528 8192 ) ( 8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -136 8192 ) ( -8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 319 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 320 +{ +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3288 7581 8192 ) ( -1196 -8176 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 321 +{ +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3288 7581 8192 ) ( -1196 -8176 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 322 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 564 8185 ) ( 8191 564 8185 ) ( 8191 -1467 -8072 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 572 8184 ) ( -8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 908 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 323 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 592 8181 ) ( 8191 592 8181 ) ( 8191 -1439 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 933 ) ( -8192 -8139 933 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 600 8180 ) ( -8191 600 8180 ) ( -8191 -1431 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 909 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 324 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 628 8177 ) ( -8191 628 8177 ) ( -8191 -1404 -8080 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 903 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 325 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 648 8174 ) ( 8191 648 8174 ) ( 8191 -1384 -8082 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 928 ) ( -8192 -8139 928 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 656 8173 ) ( -8191 656 8173 ) ( -8191 -1376 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 904 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 326 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 675 8171 ) ( 8191 675 8171 ) ( 8191 -1356 -8086 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 683 8170 ) ( -8191 683 8170 ) ( -8191 -1348 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 898 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 327 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 703 8167 ) ( 8191 703 8167 ) ( 8191 -1328 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 923 ) ( -8192 -8140 923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 711 8166 ) ( -8191 711 8166 ) ( -8191 -1320 -8090 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 899 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 328 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 731 8164 ) ( 8191 731 8164 ) ( 8191 -1300 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1114 ) ( 8192 -8141 917 ) ( -8192 -8141 917 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 739 8163 ) ( -8191 739 8163 ) ( -8191 -1292 -8094 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8144 893 ) ( 8192 8113 -1138 ) ( -8192 8113 -1138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 329 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 755 8161 ) ( 8191 755 8161 ) ( 8191 -1276 -8096 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1113 ) ( 8192 -8140 918 ) ( -8192 -8140 918 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 763 8160 ) ( -8191 763 8160 ) ( -8191 -1268 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 894 ) ( 8192 8113 -1137 ) ( -8192 8113 -1137 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 330 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 755 8161 ) ( 8191 755 8161 ) ( 8191 -1276 -8096 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1113 ) ( 8192 -8140 918 ) ( -8192 -8140 918 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 763 8160 ) ( -8191 763 8160 ) ( -8191 -1268 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 894 ) ( 8192 8113 -1137 ) ( -8192 8113 -1137 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 331 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 731 8164 ) ( 8191 731 8164 ) ( 8191 -1300 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1114 ) ( 8192 -8141 917 ) ( -8192 -8141 917 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 739 8163 ) ( -8191 739 8163 ) ( -8191 -1292 -8094 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8144 893 ) ( 8192 8113 -1138 ) ( -8192 8113 -1138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 332 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 703 8167 ) ( 8191 703 8167 ) ( 8191 -1328 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 923 ) ( -8192 -8140 923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 711 8166 ) ( -8191 711 8166 ) ( -8191 -1320 -8090 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 899 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 333 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 675 8171 ) ( 8191 675 8171 ) ( 8191 -1356 -8086 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 683 8170 ) ( -8191 683 8170 ) ( -8191 -1348 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 898 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 334 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 648 8174 ) ( 8191 648 8174 ) ( 8191 -1384 -8082 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 928 ) ( -8192 -8139 928 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 656 8173 ) ( -8191 656 8173 ) ( -8191 -1376 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 904 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 335 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 628 8177 ) ( -8191 628 8177 ) ( -8191 -1404 -8080 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 903 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 336 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 592 8181 ) ( 8191 592 8181 ) ( 8191 -1439 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 933 ) ( -8192 -8139 933 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 600 8180 ) ( -8191 600 8180 ) ( -8191 -1431 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 909 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 337 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 564 8185 ) ( 8191 564 8185 ) ( 8191 -1467 -8072 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 572 8184 ) ( -8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 908 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 338 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -392 -8192 8192 ) ( -392 8192 8192 ) ( -392 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 445 8200 ) ( 8191 445 8200 ) ( 8191 -1586 -8057 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 1800 7993 ) ( -8191 1800 7993 ) ( -8191 -2172 -7900 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 339 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -320 -8192 8192 ) ( -320 8192 8192 ) ( -320 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 1800 7993 ) ( 8191 1800 7993 ) ( -8191 -2172 -7900 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 340 +{ +( -320 8192 8192 ) ( -320 -8192 8192 ) ( -320 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -296 -8192 8192 ) ( -296 8192 8192 ) ( -296 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 445 8200 ) ( 8191 445 8200 ) ( 8191 -1586 -8057 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 341 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -296 -8192 8192 ) ( -296 8192 8192 ) ( -296 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 445 8200 ) ( -8191 445 8200 ) ( 8191 -1586 -8057 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 342 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -296 -8192 8192 ) ( -296 8192 8192 ) ( -296 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -126 ) ( 8192 8192 -126 ) ( -8192 -8192 -126 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7967 -1909 ) ( 8192 -8032 1617 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8036 1599 ) ( 8192 7957 -1954 ) ( -8192 7957 -1954 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 343 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -288 -8192 8192 ) ( -288 8192 8192 ) ( -288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -517 8192 ) ( -8192 -517 8192 ) ( -8192 -517 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8031 1622 ) ( 8192 7965 -1917 ) ( -8191 7963 -1929 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 344 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -517 8192 ) ( 8192 -517 8192 ) ( -8192 -517 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 345 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -38 ) ( 8192 -8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1469 8062 ) ( -8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8057 -1481 ) ( 8192 -8098 1239 ) ( -8192 -8098 1239 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1616 ) ( 8192 7964 -1923 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 346 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -288 -8192 8192 ) ( -288 8192 8192 ) ( -288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7964 -1923 ) ( 8192 -8032 1616 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 347 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -126 ) ( 8192 8192 -126 ) ( -8192 -8192 -126 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -38 ) ( 8192 -8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8036 1599 ) ( 8192 7957 -1954 ) ( -8192 7957 -1954 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7964 -1923 ) ( 8192 -8032 1616 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 348 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1616 ) ( 8192 7964 -1923 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 349 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -38 ) ( 8192 -8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 588 8182 ) ( -8191 588 8182 ) ( -8191 -1443 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8098 1239 ) ( 8192 8057 -1481 ) ( -8192 -8098 1239 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 350 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7965 -1917 ) ( 8192 -8031 1622 ) ( -8191 7963 -1929 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 351 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8031 1622 ) ( 8192 7965 -1917 ) ( -8191 7963 -1929 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1469 8062 ) ( 8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 352 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1469 8062 ) ( -8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8098 1239 ) ( 8192 8057 -1481 ) ( -8192 -8098 1239 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 739 8163 ) ( 8191 739 8163 ) ( -8191 -1292 -8094 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 353 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1469 8062 ) ( 8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1616 ) ( 8192 7964 -1923 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 354 +{ +( -629 8192 8192 ) ( -629 -8192 8192 ) ( -629 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -220 -8192 8192 ) ( -220 8192 8192 ) ( -220 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -599 8192 ) ( 8192 -599 8192 ) ( -8192 -599 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -263 8192 ) ( -8192 -263 8192 ) ( -8192 -263 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7957 -1954 ) ( 8192 -8036 1599 ) ( -8192 7957 -1954 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 355 +{ +( 1487 -8192 8192 ) ( 1487 8192 8192 ) ( 1487 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -130 ) ( 8192 8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -57 ) ( 8192 -8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 356 +{ +( 1529 8192 8192 ) ( 1529 -8192 8192 ) ( 1529 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -130 ) ( 8192 8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -57 ) ( 8192 -8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 357 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -57 ) ( 8192 8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1105 -8277 8192 ) ( 2127 8075 8192 ) ( 2127 8075 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 877 8262 8192 ) ( 1899 -8089 8192 ) ( 1899 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 358 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -130 ) ( 8192 -8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 359 +{ +( 1528 8192 8192 ) ( 1528 -8192 8192 ) ( 1528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1530 -8192 8192 ) ( 1530 8192 8192 ) ( 1530 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -479 8192 ) ( 8192 -479 8192 ) ( -8192 -479 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -437 8192 ) ( -8192 -437 8192 ) ( -8192 -437 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -130 ) ( 8192 8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -57 ) ( 8192 -8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 360 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 361 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 909 -8264 8192 ) ( 1931 8087 8192 ) ( 1931 8087 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 362 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1071 8274 8192 ) ( 2093 -8077 8192 ) ( 2093 -8077 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 363 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -134 ) ( 8192 -8192 -134 ) ( -8192 -8192 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 364 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 365 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1899 -8089 8192 ) ( 877 8262 8192 ) ( 1899 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 366 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2126 8075 8192 ) ( 1104 -8277 8192 ) ( 1104 -8277 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 367 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -12 ) ( 8192 8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -10 ) ( 8192 -8192 -10 ) ( -8192 -8192 -10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 368 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 369 +{ +( -8192 -202 8192 ) ( 8192 -202 8192 ) ( -8192 -202 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -10 ) ( 8192 8192 -10 ) ( -8192 -8192 -10 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 370 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -202 8192 ) ( -8192 -202 8192 ) ( -8192 -202 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -10 ) ( 8192 8192 -10 ) ( -8192 -8192 -10 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 909 -8264 8192 ) ( 1931 8087 8192 ) ( 1931 8087 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 371 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -202 8192 ) ( -8192 -202 8192 ) ( -8192 -202 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -10 ) ( 8192 8192 -10 ) ( -8192 -8192 -10 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 1072 8274 8192 ) ( 2094 -8077 8192 ) ( 2094 -8077 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 372 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -134 ) ( 8192 -8192 -134 ) ( -8192 -8192 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 373 +{ +( 32 8192 8192 ) ( 32 -8192 8192 ) ( 32 8192 -8192 ) desktop/border 0 0 0 0.500000 0.200000 0 0 0 +( 248 -8192 8192 ) ( 248 8192 8192 ) ( 248 8192 -8192 ) desktop/jspbookside 44 -114 90 1.700000 1.200000 0 0 0 +( -8192 448 8192 ) ( 8192 448 8192 ) ( -8192 448 -8192 ) desktop/border 0 0 0 0.500000 0.200000 0 0 0 +( 8192 752 8192 ) ( -8192 752 8192 ) ( -8192 752 -8192 ) desktop/border 0 0 0 1.300000 0.200000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1120 ) ( 8192 -8192 -1120 ) ( -8192 -8192 -1120 ) desktop/jspbookcover 5 135 180 1.056250 1.187500 0 0 0 +} +// brush 374 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1000 8192 ) ( 8192 1000 8192 ) ( -8192 1000 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1008 8192 ) ( -8192 1008 8192 ) ( -8192 1008 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -578 ) ( 8192 8192 -578 ) ( -8192 -8192 -578 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 375 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1104 8192 ) ( 8192 1104 8192 ) ( -8192 1104 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1112 8192 ) ( -8192 1112 8192 ) ( -8192 1112 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -578 ) ( 8192 8192 -578 ) ( -8192 -8192 -578 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 376 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1008 8192 ) ( 8192 1008 8192 ) ( -8192 1008 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1104 8192 ) ( -8192 1104 8192 ) ( -8192 1104 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -578 ) ( 8192 8192 -578 ) ( -8192 -8192 -578 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -570 ) ( 8192 -8192 -570 ) ( -8192 -8192 -570 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 377 +{ +( 60 8192 8192 ) ( 60 -8192 8192 ) ( 60 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 106 -8192 8192 ) ( 106 8192 8192 ) ( 106 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -118 ) ( 8192 -8192 -118 ) ( -8192 -8192 -118 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 378 +{ +( 60 8192 8192 ) ( 60 -8192 8192 ) ( 60 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 106 -8192 8192 ) ( 106 8192 8192 ) ( 106 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -128 ) ( 8192 8192 -128 ) ( -8192 -8192 -128 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -126 ) ( 8192 -8192 -126 ) ( -8192 -8192 -126 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 379 +{ +( 106 8192 8192 ) ( 106 -8192 8192 ) ( 106 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 132 -8192 8192 ) ( 132 8192 8192 ) ( 132 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -110 ) ( 8192 8192 -110 ) ( -8192 -8192 -110 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -108 ) ( 8192 -8192 -108 ) ( -8192 -8192 -108 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 380 +{ +( 132 8192 8192 ) ( 132 -8192 8192 ) ( 132 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 158 -8192 8192 ) ( 158 8192 8192 ) ( 158 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -104 ) ( 8192 8192 -104 ) ( -8192 -8192 -104 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -102 ) ( 8192 -8192 -102 ) ( -8192 -8192 -102 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 381 +{ +( 158 8192 8192 ) ( 158 -8192 8192 ) ( 158 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 184 -8192 8192 ) ( 184 8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -96 ) ( 8192 8192 -96 ) ( -8192 -8192 -96 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -94 ) ( 8192 -8192 -94 ) ( -8192 -8192 -94 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 382 +{ +( 184 8192 8192 ) ( 184 -8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 210 -8192 8192 ) ( 210 8192 8192 ) ( 210 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -88 ) ( 8192 8192 -88 ) ( -8192 -8192 -88 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -86 ) ( 8192 -8192 -86 ) ( -8192 -8192 -86 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 383 +{ +( 210 8192 8192 ) ( 210 -8192 8192 ) ( 210 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 236 -8192 8192 ) ( 236 8192 8192 ) ( 236 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -80 ) ( 8192 8192 -80 ) ( -8192 -8192 -80 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -78 ) ( 8192 -8192 -78 ) ( -8192 -8192 -78 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 384 +{ +( 184 8192 8192 ) ( 184 -8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 210 -8192 8192 ) ( 210 8192 8192 ) ( 210 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -72 ) ( 8192 8192 -72 ) ( -8192 -8192 -72 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -70 ) ( 8192 -8192 -70 ) ( -8192 -8192 -70 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 385 +{ +( 158 8192 8192 ) ( 158 -8192 8192 ) ( 158 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 184 -8192 8192 ) ( 184 8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -64 ) ( 8192 8192 -64 ) ( -8192 -8192 -64 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -62 ) ( 8192 -8192 -62 ) ( -8192 -8192 -62 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 386 +{ +( 130 8192 8192 ) ( 130 -8192 8192 ) ( 130 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 156 -8192 8192 ) ( 156 8192 8192 ) ( 156 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -54 ) ( 8192 -8192 -54 ) ( -8192 -8192 -54 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 387 +{ +( 104 8192 8192 ) ( 104 -8192 8192 ) ( 104 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 130 -8192 8192 ) ( 130 8192 8192 ) ( 130 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -50 ) ( 8192 8192 -50 ) ( -8192 -8192 -50 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -48 ) ( 8192 -8192 -48 ) ( -8192 -8192 -48 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 388 +{ +( 78 8192 8192 ) ( 78 -8192 8192 ) ( 78 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 104 -8192 8192 ) ( 104 8192 8192 ) ( 104 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -40 ) ( 8192 -8192 -40 ) ( -8192 -8192 -40 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 389 +{ +( 212 8192 8192 ) ( 212 -8192 8192 ) ( 212 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 238 -8192 8192 ) ( 238 8192 8192 ) ( 238 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -292 8192 ) ( 8192 -292 8192 ) ( -8192 -292 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 8 ) ( 8192 8192 8 ) ( -8192 -8192 8 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 390 +{ +( 186 8192 8192 ) ( 186 -8192 8192 ) ( 186 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 212 -8192 8192 ) ( 212 8192 8192 ) ( 212 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 2 ) ( 8192 -8192 2 ) ( -8192 -8192 2 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 391 +{ +( 160 8192 8192 ) ( 160 -8192 8192 ) ( 160 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 186 -8192 8192 ) ( 186 8192 8192 ) ( 186 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -8 ) ( 8192 8192 -8 ) ( -8192 -8192 -8 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -6 ) ( 8192 -8192 -6 ) ( -8192 -8192 -6 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 392 +{ +( 134 8192 8192 ) ( 134 -8192 8192 ) ( 134 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 160 -8192 8192 ) ( 160 8192 8192 ) ( 160 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -16 ) ( 8192 8192 -16 ) ( -8192 -8192 -16 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -14 ) ( 8192 -8192 -14 ) ( -8192 -8192 -14 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 393 +{ +( 108 8192 8192 ) ( 108 -8192 8192 ) ( 108 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 134 -8192 8192 ) ( 134 8192 8192 ) ( 134 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -22 ) ( 8192 8192 -22 ) ( -8192 -8192 -22 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -20 ) ( 8192 -8192 -20 ) ( -8192 -8192 -20 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 394 +{ +( 62 8192 8192 ) ( 62 -8192 8192 ) ( 62 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 108 -8192 8192 ) ( 108 8192 8192 ) ( 108 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -32 ) ( 8192 8192 -32 ) ( -8192 -8192 -32 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 395 +{ +( 1481 8192 8192 ) ( 1481 -8192 8192 ) ( 1481 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 1520 -8192 8192 ) ( 1520 8192 8192 ) ( 1520 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 691 8192 ) ( 8192 691 8192 ) ( -8192 691 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8192 ) ( -8192 767 8192 ) ( -8192 767 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -132 ) ( 8192 8192 -132 ) ( -8192 -8192 -132 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -87 ) ( 8192 -8192 -87 ) ( -8192 -8192 -87 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7505 -3290 ) ( 8192 -7319 3686 ) ( -8192 -7319 3686 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 396 +{ +( -74 8192 8192 ) ( -74 -8192 8192 ) ( -74 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -8192 8192 ) ( -66 8192 8192 ) ( -66 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -241 8192 ) ( 8192 -241 8192 ) ( -8192 -241 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -195 8192 ) ( -8192 -195 8192 ) ( -8192 -195 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -116 ) ( 8192 8192 -116 ) ( -8192 -8192 -116 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -104 ) ( 8192 -8192 -104 ) ( -8192 -8192 -104 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 397 +{ +( -74 8192 8192 ) ( -74 -8192 8192 ) ( -74 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -8192 8192 ) ( -66 8192 8192 ) ( -66 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -245 8192 ) ( 8192 -245 8192 ) ( -8192 -245 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -197 8192 ) ( -8192 -197 8192 ) ( -8192 -197 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -34 ) ( 8192 8192 -34 ) ( -8192 -8192 -34 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -14 ) ( 8192 -8192 -14 ) ( -8192 -8192 -14 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 398 +{ +( -74 8192 8192 ) ( -74 -8192 8192 ) ( -74 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -8192 8192 ) ( -66 8192 8192 ) ( -66 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -247 8192 ) ( 8192 -247 8192 ) ( -8192 -247 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -233 8192 ) ( -8192 -233 8192 ) ( -8192 -233 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -104 ) ( 8192 8192 -104 ) ( -8192 -8192 -104 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -34 ) ( 8192 -8192 -34 ) ( -8192 -8192 -34 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 399 +{ +( -8192 -218 8192 ) ( 8192 -218 8192 ) ( -8192 -218 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -10 ) ( 8192 -8192 -10 ) ( -8192 -8192 -10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 400 +{ +( -1592 8192 8192 ) ( -1592 -8192 8192 ) ( -1592 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1736 -8192 8192 ) ( 1736 8192 8192 ) ( 1736 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -776 8192 ) ( 8192 -776 8192 ) ( -8192 -776 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -704 8192 ) ( -8192 -704 8192 ) ( -8192 -704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -224 ) ( 8192 8192 -224 ) ( -8192 -8192 -224 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -168 ) ( 8192 -8192 -168 ) ( -8192 -8192 -168 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 401 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1206 ) ( 8192 -8192 -1206 ) ( -8192 -8192 -1206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 402 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -658 ) ( 8192 8192 -658 ) ( -8192 -8192 -658 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 403 +{ +( -1290 8192 8192 ) ( -1290 -8192 8192 ) ( -1290 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 404 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1534 -8192 8192 ) ( -1534 8192 8192 ) ( -1534 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 405 +{ +( -8192 156 8192 ) ( 8192 156 8192 ) ( -8192 156 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6771 -4673 8192 ) ( 5779 5856 8192 ) ( 5779 5856 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2373 -7898 8192 ) ( 492 8232 8192 ) ( 492 8232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5772 5864 8192 ) ( -6778 -4665 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 406 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2373 -7898 8192 ) ( 492 8232 8192 ) ( 492 8232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3572 -7397 8192 ) ( -4636 6781 8192 ) ( -4636 6781 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 483 8234 8192 ) ( -2382 -7897 8192 ) ( -2382 -7897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 407 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3572 -7397 8192 ) ( -4636 6781 8192 ) ( -4636 6781 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7722 -2733 8192 ) ( -7665 2890 8192 ) ( -7665 2890 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4645 6776 8192 ) ( 3563 -7402 8192 ) ( 3563 -7402 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2382 -7897 8192 ) ( 483 8234 8192 ) ( -2382 -7897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 408 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7722 -2733 8192 ) ( -7665 2890 8192 ) ( -7665 2890 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7413 3581 8192 ) ( -7975 -2043 8192 ) ( -7975 -2043 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7670 2877 8192 ) ( 7718 -2746 8192 ) ( 7718 -2746 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3563 -7402 8192 ) ( -4645 6776 8192 ) ( 3563 -7402 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 409 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7413 3581 8192 ) ( -7975 -2043 8192 ) ( -7975 -2043 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3032 7710 8192 ) ( -5176 -6468 8192 ) ( -5176 -6468 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7969 -2058 8192 ) ( 7418 3566 8192 ) ( 7418 3566 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7718 -2746 8192 ) ( -7670 2877 8192 ) ( 7718 -2746 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 410 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3032 7710 8192 ) ( -5176 -6468 8192 ) ( -5176 -6468 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2568 7863 8192 ) ( 296 -8267 8192 ) ( 296 -8267 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5166 -6474 8192 ) ( 3042 7704 8192 ) ( 3042 7704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7418 3566 8192 ) ( -7969 -2058 8192 ) ( 7418 3566 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 411 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2568 7863 8192 ) ( 296 -8267 8192 ) ( 296 -8267 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6664 4801 8192 ) ( 5886 -5728 8192 ) ( 5886 -5728 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 308 -8265 8192 ) ( -2557 7866 8192 ) ( -2557 7866 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3042 7704 8192 ) ( -5166 -6474 8192 ) ( 3042 7704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 412 +{ +( -8192 156 8192 ) ( 8192 156 8192 ) ( -8192 156 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6664 4801 8192 ) ( 5886 -5728 8192 ) ( 5886 -5728 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5895 -5718 8192 ) ( -6656 4811 8192 ) ( -6656 4811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2557 7866 8192 ) ( 308 -8265 8192 ) ( -2557 7866 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 413 +{ +( -8192 156 8192 ) ( 8192 156 8192 ) ( -8192 156 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 166 8192 ) ( -8192 166 8192 ) ( -8192 166 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6656 4811 8192 ) ( 5895 -5718 8192 ) ( -6656 4811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 414 +{ +( -8192 166 8192 ) ( 8192 166 8192 ) ( -8192 166 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1192 ) ( 8192 -8192 -1192 ) ( -8192 -8192 -1192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -2557 7866 8192 ) ( 308 -8265 8192 ) ( -2557 7866 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6656 4811 8192 ) ( 5895 -5718 8192 ) ( -6656 4811 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3563 -7402 8192 ) ( -4645 6776 8192 ) ( 3563 -7402 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3042 7704 8192 ) ( -5166 -6474 8192 ) ( 3042 7704 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7418 3566 8192 ) ( -7969 -2058 8192 ) ( 7418 3566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -2382 -7897 8192 ) ( 483 8234 8192 ) ( -2382 -7897 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7718 -2746 8192 ) ( -7670 2877 8192 ) ( 7718 -2746 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 415 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -814 ) ( 8192 8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -770 ) ( 8192 -8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 416 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1372 -8192 8192 ) ( -1372 8192 8192 ) ( -1372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -750 ) ( 8192 8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -730 ) ( 8192 -8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 417 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -814 ) ( 8192 -8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 418 +{ +( -1316 8192 8192 ) ( -1316 -8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -814 ) ( 8192 8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -770 ) ( 8192 -8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 419 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1508 -8192 8192 ) ( -1508 8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -814 ) ( 8192 8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -770 ) ( 8192 -8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 420 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -770 ) ( 8192 8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -750 ) ( 8192 -8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 421 +{ +( -1372 8192 8192 ) ( -1372 -8192 8192 ) ( -1372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -750 ) ( 8192 8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -730 ) ( 8192 -8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 422 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1460 -8192 8192 ) ( -1460 8192 8192 ) ( -1460 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -750 ) ( 8192 8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -730 ) ( 8192 -8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 423 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -730 ) ( 8192 8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -718 ) ( 8192 -8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 424 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -674 ) ( 8192 8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 425 +{ +( -1316 8192 8192 ) ( -1316 -8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -718 ) ( 8192 8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -674 ) ( 8192 -8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 426 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1508 -8192 8192 ) ( -1508 8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -718 ) ( 8192 8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -674 ) ( 8192 -8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 427 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -718 ) ( 8192 8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -702 ) ( 8192 -8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 428 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -682 ) ( 8192 8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -674 ) ( 8192 -8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 429 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -654 8192 ) ( -8192 -654 8192 ) ( -8192 -654 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 430 +{ +( -1348 8192 8192 ) ( -1348 -8192 8192 ) ( -1348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -654 8192 ) ( 8192 -654 8192 ) ( -8192 -654 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 431 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1476 -8192 8192 ) ( -1476 8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -654 8192 ) ( 8192 -654 8192 ) ( -8192 -654 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 432 +{ +( -1496 8192 8192 ) ( -1496 -8192 8192 ) ( -1496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -508 8192 ) ( 8192 -508 8192 ) ( -8192 -508 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -500 8192 ) ( -8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -712 ) ( 8192 8192 -712 ) ( -8192 -8192 -712 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -704 ) ( 8192 -8192 -704 ) ( -8192 -8192 -704 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 433 +{ +( -1534 8192 8192 ) ( -1534 -8192 8192 ) ( -1534 8192 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( -1290 -8192 8192 ) ( -1290 8192 8192 ) ( -1290 8192 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -1206 ) ( 8192 8192 -1206 ) ( -8192 -8192 -1206 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -734 ) ( 8192 -8192 -734 ) ( -8192 -8192 -734 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 434 +{ +( -1534 8192 8192 ) ( -1534 -8192 8192 ) ( -1534 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1290 -8192 8192 ) ( -1290 8192 8192 ) ( -1290 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -666 ) ( 8192 8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -658 ) ( 8192 -8192 -658 ) ( -8192 -8192 -658 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 435 +{ +( -1316 8192 8192 ) ( -1316 -8192 8192 ) ( -1316 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1290 -8192 8192 ) ( -1290 8192 8192 ) ( -1290 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 436 +{ +( -1534 8192 8192 ) ( -1534 -8192 8192 ) ( -1534 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1516 -8192 8192 ) ( -1516 8192 8192 ) ( -1516 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 437 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -732 ) ( 8192 -8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 438 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -992 8192 ) ( 8192 -992 8192 ) ( -8192 -992 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -668 ) ( 8192 8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 439 +{ +( -1318 8192 8192 ) ( -1318 -8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 440 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -822 8192 ) ( 8192 -822 8192 ) ( -8192 -822 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 441 +{ +( -1516 8192 8192 ) ( -1516 -8192 8192 ) ( -1516 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1514 -8192 8192 ) ( -1514 8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 442 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1322 -8192 8192 ) ( -1322 8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -672 ) ( 8192 -8192 -672 ) ( -8192 -8192 -672 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 443 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1460 -8192 8192 ) ( -1460 8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 444 +{ +( -1322 8192 8192 ) ( -1322 -8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 445 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1322 -8192 8192 ) ( -1322 8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -672 ) ( 8192 8192 -672 ) ( -8192 -8192 -672 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 446 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1322 -8192 8192 ) ( -1322 8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -728 ) ( 8192 -8192 -728 ) ( -8192 -8192 -728 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 447 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -866 8192 ) ( 8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -538 8192 ) ( -8192 -538 8192 ) ( -8192 -538 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -886 ) ( 8192 8192 -886 ) ( -8192 -8192 -886 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -830 ) ( 8192 -8192 -830 ) ( -8192 -8192 -830 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 448 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -866 8192 ) ( 8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -538 8192 ) ( -8192 -538 8192 ) ( -8192 -538 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1190 ) ( 8192 8192 -1190 ) ( -8192 -8192 -1190 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1106 ) ( 8192 -8192 -1106 ) ( -8192 -8192 -1106 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 449 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -866 8192 ) ( -8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1190 ) ( 8192 8192 -1190 ) ( -8192 -8192 -1190 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -970 ) ( 8192 -8192 -970 ) ( -8192 -8192 -970 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 450 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -866 8192 ) ( 8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -538 8192 ) ( -8192 -538 8192 ) ( -8192 -538 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1106 ) ( 8192 8192 -1106 ) ( -8192 -8192 -1106 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -886 ) ( 8192 -8192 -886 ) ( -8192 -8192 -886 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 451 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -738 8192 ) ( -8192 -738 8192 ) ( -8192 -738 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1160 ) ( 8192 8192 -1160 ) ( -8192 -8192 -1160 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1158 ) ( 8192 -8192 -1158 ) ( -8192 -8192 -1158 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 452 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1162 ) ( 8192 8192 -1162 ) ( -8192 -8192 -1162 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 453 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 454 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 455 +{ +( -1498 8192 8192 ) ( -1498 -8192 8192 ) ( -1498 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1474 -8192 8192 ) ( -1474 8192 8192 ) ( -1474 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 456 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 457 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 458 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 459 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 460 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 461 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 462 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 463 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 464 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 465 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1066 ) ( 8192 8192 -1066 ) ( -8192 -8192 -1066 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1056 ) ( 8192 -8192 -1056 ) ( -8192 -8192 -1056 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 466 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -714 8192 ) ( -8192 -714 8192 ) ( -8192 -714 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1064 ) ( 8192 8192 -1064 ) ( -8192 -8192 -1064 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1062 ) ( 8192 -8192 -1062 ) ( -8192 -8192 -1062 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 467 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -738 8192 ) ( -8192 -738 8192 ) ( -8192 -738 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1008 ) ( 8192 8192 -1008 ) ( -8192 -8192 -1008 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1006 ) ( 8192 -8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 468 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1010 ) ( 8192 8192 -1010 ) ( -8192 -8192 -1010 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1000 ) ( 8192 -8192 -1000 ) ( -8192 -8192 -1000 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 469 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 470 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 471 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 472 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 473 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 474 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 475 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 476 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 477 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 478 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 479 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 480 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 481 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1038 ) ( 8192 8192 -1038 ) ( -8192 -8192 -1038 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1028 ) ( 8192 -8192 -1028 ) ( -8192 -8192 -1028 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 482 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -770 8192 ) ( -8192 -770 8192 ) ( -8192 -770 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1036 ) ( 8192 8192 -1036 ) ( -8192 -8192 -1036 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1034 ) ( 8192 -8192 -1034 ) ( -8192 -8192 -1034 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 483 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -778 8192 ) ( -8192 -778 8192 ) ( -8192 -778 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1084 ) ( 8192 8192 -1084 ) ( -8192 -8192 -1084 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1082 ) ( 8192 -8192 -1082 ) ( -8192 -8192 -1082 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 484 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1086 ) ( 8192 8192 -1086 ) ( -8192 -8192 -1086 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1076 ) ( 8192 -8192 -1076 ) ( -8192 -8192 -1076 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 485 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1090 ) ( 8192 8192 -1090 ) ( -8192 -8192 -1090 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1088 ) ( 8192 -8192 -1088 ) ( -8192 -8192 -1088 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 486 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 487 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 488 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 489 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 490 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 491 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -850 8192 ) ( 8192 -850 8192 ) ( -8192 -850 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -828 8192 ) ( -8192 -828 8192 ) ( -8192 -828 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -994 ) ( 8192 8192 -994 ) ( -8192 -8192 -994 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -970 ) ( 8192 -8192 -970 ) ( -8192 -8192 -970 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 492 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -812 8192 ) ( 8192 -812 8192 ) ( -8192 -812 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -790 8192 ) ( -8192 -790 8192 ) ( -8192 -790 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -938 ) ( 8192 8192 -938 ) ( -8192 -8192 -938 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -914 ) ( 8192 -8192 -914 ) ( -8192 -8192 -914 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 493 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -738 8192 ) ( 8192 -738 8192 ) ( -8192 -738 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -716 8192 ) ( -8192 -716 8192 ) ( -8192 -716 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1036 ) ( 8192 -8192 -1036 ) ( -8192 -8192 -1036 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 494 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -698 8192 ) ( 8192 -698 8192 ) ( -8192 -698 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -676 8192 ) ( -8192 -676 8192 ) ( -8192 -676 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1028 ) ( 8192 8192 -1028 ) ( -8192 -8192 -1028 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1016 ) ( 8192 -8192 -1016 ) ( -8192 -8192 -1016 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 495 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -682 8192 ) ( 8192 -682 8192 ) ( -8192 -682 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -660 8192 ) ( -8192 -660 8192 ) ( -8192 -660 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1144 ) ( 8192 8192 -1144 ) ( -8192 -8192 -1144 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1132 ) ( 8192 -8192 -1132 ) ( -8192 -8192 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 496 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -708 8192 ) ( 8192 -708 8192 ) ( -8192 -708 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -686 8192 ) ( -8192 -686 8192 ) ( -8192 -686 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -934 ) ( 8192 8192 -934 ) ( -8192 -8192 -934 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -910 ) ( 8192 -8192 -910 ) ( -8192 -8192 -910 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 497 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -810 8192 ) ( 8192 -810 8192 ) ( -8192 -810 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -788 8192 ) ( -8192 -788 8192 ) ( -8192 -788 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -878 ) ( 8192 8192 -878 ) ( -8192 -8192 -878 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -854 ) ( 8192 -8192 -854 ) ( -8192 -8192 -854 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 498 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -628 8192 ) ( 8192 -628 8192 ) ( -8192 -628 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -606 8192 ) ( -8192 -606 8192 ) ( -8192 -606 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1114 ) ( 8192 8192 -1114 ) ( -8192 -8192 -1114 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1090 ) ( 8192 -8192 -1090 ) ( -8192 -8192 -1090 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 499 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -574 8192 ) ( 8192 -574 8192 ) ( -8192 -574 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -552 8192 ) ( -8192 -552 8192 ) ( -8192 -552 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1074 ) ( 8192 8192 -1074 ) ( -8192 -8192 -1074 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1050 ) ( 8192 -8192 -1050 ) ( -8192 -8192 -1050 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 500 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -582 8192 ) ( 8192 -582 8192 ) ( -8192 -582 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -560 8192 ) ( -8192 -560 8192 ) ( -8192 -560 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -976 ) ( 8192 8192 -976 ) ( -8192 -8192 -976 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -952 ) ( 8192 -8192 -952 ) ( -8192 -8192 -952 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 501 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -652 8192 ) ( 8192 -652 8192 ) ( -8192 -652 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -630 8192 ) ( -8192 -630 8192 ) ( -8192 -630 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -976 ) ( 8192 8192 -976 ) ( -8192 -8192 -976 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -952 ) ( 8192 -8192 -952 ) ( -8192 -8192 -952 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 502 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -636 8192 ) ( 8192 -636 8192 ) ( -8192 -636 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -614 8192 ) ( -8192 -614 8192 ) ( -8192 -614 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -906 ) ( 8192 8192 -906 ) ( -8192 -8192 -906 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -882 ) ( 8192 -8192 -882 ) ( -8192 -8192 -882 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 503 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -906 ) ( 8192 8192 -906 ) ( -8192 -8192 -906 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -882 ) ( 8192 -8192 -882 ) ( -8192 -8192 -882 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 504 +{ +( -1465 8192 8192 ) ( -1465 -8192 8192 ) ( -1465 8192 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( -1463 -8192 8192 ) ( -1463 8192 8192 ) ( -1463 8192 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +} +// brush 505 +{ +( -1474 8192 8192 ) ( -1474 -8192 8192 ) ( -1474 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -1472 -8192 8192 ) ( -1472 8192 8192 ) ( -1472 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 506 +{ +( -1471 8192 8192 ) ( -1471 -8192 8192 ) ( -1471 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -1469 -8192 8192 ) ( -1469 8192 8192 ) ( -1469 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 507 +{ +( -1468 8192 8192 ) ( -1468 -8192 8192 ) ( -1468 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 508 +{ +( 7816 -8577 1027 ) ( 7816 6228 -5986 ) ( -8278 7539 -3218 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( 7830 6164 -6034 ) ( 7830 -8545 1181 ) ( -8278 -7229 3863 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( -6407 5892 7694 ) ( 8692 -465 7694 ) ( 5804 -7324 -6902 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( 8788 -238 7575 ) ( -6311 6119 7575 ) ( -9254 -868 -6948 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( -4087 -7174 8192 ) ( 2167 7968 8192 ) ( 2167 7968 -8192 ) desktop/yellowwire 0 0 150 0.500000 0.500000 0 0 0 +( 2156 7972 8192 ) ( -4096 -7171 8192 ) ( -4096 -7171 -8192 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +} +// brush 509 +{ +( 92 8192 8192 ) ( 92 -8192 8192 ) ( 92 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 222 -8192 8192 ) ( 222 8192 8192 ) ( 222 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -428 8192 ) ( 8192 -428 8192 ) ( -8192 -428 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -292 8192 ) ( -8192 -292 8192 ) ( -8192 -292 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 16 ) ( 8192 8192 16 ) ( -8192 -8192 16 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 510 +{ +( 130 8192 8192 ) ( 130 -8192 8192 ) ( 130 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 136 -8192 8192 ) ( 136 8192 8192 ) ( 136 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 18 ) ( 8192 8192 18 ) ( -8192 -8192 18 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 112 ) ( 8192 -8192 112 ) ( -8192 -8192 112 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 511 +{ +( 182 8192 8192 ) ( 182 -8192 8192 ) ( 182 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 188 -8192 8192 ) ( 188 8192 8192 ) ( 188 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 18 ) ( 8192 8192 18 ) ( -8192 -8192 18 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 112 ) ( 8192 -8192 112 ) ( -8192 -8192 112 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 512 +{ +( 136 8192 8192 ) ( 136 -8192 8192 ) ( 136 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 182 -8192 8192 ) ( 182 8192 8192 ) ( 182 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 106 ) ( 8192 8192 106 ) ( -8192 -8192 106 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 112 ) ( 8192 -8192 112 ) ( -8192 -8192 112 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 513 +{ +( -1422 8192 8192 ) ( -1422 -8192 8192 ) ( -1422 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -926 ) ( 8192 -8192 -926 ) ( -8192 -8192 -926 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 514 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1422 -8192 8192 ) ( -1422 8192 8192 ) ( -1422 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -930 ) ( 8192 8192 -930 ) ( -8192 -8192 -930 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -926 ) ( 8192 -8192 -926 ) ( -8192 -8192 -926 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 515 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -930 ) ( 8192 -8192 -930 ) ( -8192 -8192 -930 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 516 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -658 8192 ) ( 8192 -658 8192 ) ( -8192 -658 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -636 8192 ) ( -8192 -636 8192 ) ( -8192 -636 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1124 ) ( 8192 8192 -1124 ) ( -8192 -8192 -1124 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1112 ) ( 8192 -8192 -1112 ) ( -8192 -8192 -1112 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 517 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -706 8192 ) ( 8192 -706 8192 ) ( -8192 -706 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -684 8192 ) ( -8192 -684 8192 ) ( -8192 -684 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1164 ) ( 8192 8192 -1164 ) ( -8192 -8192 -1164 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 518 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -730 8192 ) ( 8192 -730 8192 ) ( -8192 -730 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -708 8192 ) ( -8192 -708 8192 ) ( -8192 -708 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1184 ) ( 8192 8192 -1184 ) ( -8192 -8192 -1184 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1172 ) ( 8192 -8192 -1172 ) ( -8192 -8192 -1172 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 519 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -580 8192 ) ( -8192 -580 8192 ) ( -8192 -580 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1084 ) ( 8192 8192 -1084 ) ( -8192 -8192 -1084 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1072 ) ( 8192 -8192 -1072 ) ( -8192 -8192 -1072 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 520 +{ +( 1600 8192 8192 ) ( 1600 -8192 8192 ) ( 1600 8192 -8192 ) desktop/border 0 0 0 0.250000 0.250000 0 0 0 +( 1904 -8192 8192 ) ( 1904 8192 8192 ) ( 1904 8192 -8192 ) desktop/border 0 45 0 -27 0.880000 0 0 0 +( -8192 232 8192 ) ( 8192 232 8192 ) ( -8192 232 -8192 ) desktop/border 2 45 0 0.050000 0.250000 0 0 0 +( 8192 448 8192 ) ( -8192 448 8192 ) ( -8192 448 -8192 ) desktop/jspbookside -72 -56 270 -1.600000 1.100000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -48 ) ( 8192 -8192 -48 ) ( -8192 -8192 -48 ) desktop/jspbookcover -72 53 270 1.100000 1.200000 0 0 0 +} +// brush 521 +{ +( 436 8192 8192 ) ( 436 -8192 8192 ) ( 436 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 844 -8192 8192 ) ( 844 8192 8192 ) ( 844 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 2844 8192 ) ( 8192 2844 8192 ) ( -8192 2844 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 3216 8192 ) ( -8192 3216 8192 ) ( -8192 3216 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 1588 ) ( 8192 8192 1588 ) ( -8192 -8192 1588 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 1592 ) ( 8192 -8192 1592 ) ( -8192 -8192 1592 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 522 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1348 -8192 8192 ) ( -1348 8192 8192 ) ( -1348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -380 8192 ) ( 8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 523 +{ +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -404 8192 ) ( 8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -380 8192 ) ( -8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 524 +{ +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6690 4895 8192 ) ( 4895 -6690 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 525 +{ +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5347 6238 8192 ) ( -6238 -5347 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 526 +{ +( -1363 8192 8192 ) ( -1363 -8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6238 -5347 8192 ) ( 5347 6238 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 527 +{ +( -1363 8192 8192 ) ( -1363 -8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1348 -8192 8192 ) ( -1348 8192 8192 ) ( -1348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 528 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6690 4895 8192 ) ( 4895 -6690 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 529 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -380 8192 ) ( -8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6306 -5279 8192 ) ( 5279 6306 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 530 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1459 -8192 8192 ) ( -1459 8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -380 8192 ) ( -8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 531 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1459 -8192 8192 ) ( -1459 8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 532 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6306 -5279 8192 ) ( 5279 6306 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 533 +{ +( -1443 8192 8192 ) ( -1443 -8192 8192 ) ( -1443 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6294 -5291 8192 ) ( 5291 6294 8192 ) ( 5291 6294 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 534 +{ +( -8192 -420 8192 ) ( 8192 -420 8192 ) ( -8192 -420 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5291 6294 8192 ) ( -6294 -5291 8192 ) ( 5291 6294 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 535 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1443 -8192 8192 ) ( -1443 8192 8192 ) ( -1443 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6748 4837 8192 ) ( 4837 -6748 8192 ) ( 4837 -6748 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 536 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -488 8192 ) ( 8192 -488 8192 ) ( -8192 -488 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4837 -6748 8192 ) ( -6748 4837 8192 ) ( 4837 -6748 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 537 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4827 -6758 8192 ) ( -6758 4827 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 538 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -500 8192 ) ( -8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6238 -5347 8192 ) ( 5347 6238 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 539 +{ +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -488 8192 ) ( -8192 -488 8192 ) ( -8192 -488 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6246 -5339 8192 ) ( 5339 6246 8192 ) ( 5339 6246 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 540 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -500 8192 ) ( -8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 541 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4827 -6758 8192 ) ( -6758 4827 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 542 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6238 -5347 8192 ) ( 5347 6238 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5339 6246 8192 ) ( -6246 -5339 8192 ) ( 5339 6246 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 543 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5347 6238 8192 ) ( -6238 -5347 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 544 +{ +( -1375 8192 8192 ) ( -1375 -8192 8192 ) ( -1375 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4885 -6700 8192 ) ( -6700 4885 8192 ) ( -6700 4885 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6246 -5339 8192 ) ( 5339 6246 8192 ) ( 5339 6246 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 545 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -420 8192 ) ( -8192 -420 8192 ) ( -8192 -420 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6700 4885 8192 ) ( 4885 -6700 8192 ) ( -6700 4885 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 546 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -404 8192 ) ( 8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 547 +{ +( -2160 8192 8192 ) ( -2160 -8192 8192 ) ( -2160 8192 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 2120 -8192 8192 ) ( 2120 8192 8192 ) ( 2120 8192 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 8192 2648 8192 ) ( -8192 2648 8192 ) ( -8192 2648 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 8192 -8192 1596 ) ( 8192 8192 1596 ) ( -8192 -8192 1596 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +} +// brush 548 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -251 8192 ) ( 8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -209 8192 ) ( -8192 -209 8192 ) ( -8192 -209 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -93 ) ( 8192 8192 -93 ) ( -8192 -8192 -93 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -51 ) ( 8192 -8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5699 5885 ) ( -8192 5699 5885 ) ( -8192 -5817 -5768 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5976 5606 ) ( 8192 5677 -5909 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2255 ) ( 8192 -7936 2033 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5975 5607 ) ( -8192 -5975 5607 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 549 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -399 8192 ) ( 8192 -399 8192 ) ( -8192 -399 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -251 8192 ) ( -8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -51 ) ( 8192 8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -11 ) ( 8192 -8192 -11 ) ( -8192 -8192 -11 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5976 5606 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7936 2033 ) ( 8192 7876 -2255 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1775 8006 ) ( 8192 1775 8006 ) ( 8192 -2513 -7806 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2254 ) ( 8192 -7936 2034 ) ( -8192 -7936 2034 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 550 +{ +( 1436 8192 8192 ) ( 1436 -8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1580 -8192 8192 ) ( 1580 8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -215 8192 ) ( -8192 -215 8192 ) ( -8192 -215 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 551 +{ +( 1412 8192 8192 ) ( 1412 -8192 8192 ) ( 1412 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1604 -8192 8192 ) ( 1604 8192 8192 ) ( 1604 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -215 8192 ) ( -8192 -215 8192 ) ( -8192 -215 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 552 +{ +( 1412 8192 8192 ) ( 1412 -8192 8192 ) ( 1412 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1604 -8192 8192 ) ( 1604 8192 8192 ) ( 1604 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -201 8192 ) ( 8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 553 +{ +( 1436 8192 8192 ) ( 1436 -8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1580 -8192 8192 ) ( 1580 8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -201 8192 ) ( 8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 554 +{ +( 1412 8192 8192 ) ( 1412 -8192 8192 ) ( 1412 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1436 -8192 8192 ) ( 1436 8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 8192 -4244 ) ( 7056 -8192 -4244 ) ( -6050 -8192 5586 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5824 8192 5871 ) ( 5824 -8192 5871 ) ( -4005 -8192 -7235 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 555 +{ +( 1436 8192 8192 ) ( 1436 -8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1508 -8192 8192 ) ( 1508 8192 8192 ) ( 1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 8191 -590 ) ( 8171 -8191 -590 ) ( -8156 -8191 770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 556 +{ +( 1508 8192 8192 ) ( 1508 -8192 8192 ) ( 1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1580 -8192 8192 ) ( 1580 8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8176 8191 520 ) ( 8176 -8191 520 ) ( -8150 -8191 -839 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 557 +{ +( 1580 8192 8192 ) ( 1580 -8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1604 -8192 8192 ) ( 1604 8192 8192 ) ( 1604 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 8192 4138 ) ( 7136 -8192 4138 ) ( -5970 -8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3894 -8192 7319 ) ( -3894 8192 7319 ) ( 5936 8192 -5787 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 558 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -129 8192 ) ( 8192 -129 8192 ) ( -8192 -129 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 559 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -535 8192 ) ( -8192 -535 8192 ) ( -8192 -535 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 560 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 -8192 8192 ) ( 1153 8192 8192 ) ( 1153 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 692 ) ( 8192 8192 692 ) ( -8192 -8192 692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 561 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4869 8192 6715 ) ( -4869 -8192 6715 ) ( 6715 -8192 -4869 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 562 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 689 ) ( 8192 -8192 689 ) ( -8192 -8192 689 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 563 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 -8192 8192 ) ( 1153 8192 8192 ) ( 1153 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 692 ) ( 8192 -8192 692 ) ( -8192 -8192 692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 564 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -129 8192 ) ( 8192 -129 8192 ) ( -8192 -129 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 565 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -535 8192 ) ( -8192 -535 8192 ) ( -8192 -535 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 566 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 332 -8192 8192 ) ( 332 8192 8192 ) ( 332 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 689 ) ( 8192 -8192 689 ) ( -8192 -8192 689 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 567 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5613 -8192 5971 ) ( 5613 8192 5971 ) ( -5971 8192 -5613 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 568 +{ +( 335 8192 8192 ) ( 335 -8192 8192 ) ( 335 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 569 +{ +( 332 8192 8192 ) ( 332 -8192 8192 ) ( 332 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 689 ) ( 8192 -8192 689 ) ( -8192 -8192 689 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 570 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -468 8192 ) ( 8192 -468 8192 ) ( -8192 -468 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8192 ) ( -8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -24 ) ( 8192 8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1677 ) ( 8192 7979 -1855 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 571 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -495 8192 ) ( 8192 -495 8192 ) ( -8192 -495 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -288 8192 ) ( -8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 14 ) ( 8192 -8192 14 ) ( -8192 -8192 14 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1681 ) ( 8192 7975 -1872 ) ( -8192 7975 -1872 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7979 -1855 ) ( 8192 -8018 1677 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 572 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -495 8192 ) ( 8192 -495 8192 ) ( -8192 -495 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -288 8192 ) ( -8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 14 ) ( 8192 -8192 14 ) ( -8192 -8192 14 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7979 -1855 ) ( 8192 -8018 1677 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1681 ) ( 8192 7975 -1872 ) ( -8192 7975 -1872 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 573 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -468 8192 ) ( 8192 -468 8192 ) ( -8192 -468 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8192 ) ( -8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -24 ) ( 8192 8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1677 ) ( 8192 7979 -1855 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 574 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -312 8192 ) ( 8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -288 8192 ) ( -8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -24 ) ( 8192 -8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 3384 7464 ) ( -8192 3384 7464 ) ( -8192 -3820 -7250 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7427 3458 ) ( 8192 7287 -3745 ) ( -8192 7287 -3745 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 575 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -390 8192 ) ( 8192 -390 8192 ) ( -8192 -390 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8192 ) ( -8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -24 ) ( 8192 8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -5 ) ( 8192 -8192 -5 ) ( -8192 -8192 -5 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7977 1866 ) ( 8192 7929 -2059 ) ( -8192 7929 -2059 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 576 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -468 8192 ) ( 8192 -468 8192 ) ( -8192 -468 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -390 8192 ) ( -8192 -390 8192 ) ( -8192 -390 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -5 ) ( 8192 8192 -5 ) ( -8192 -8192 -5 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 14 ) ( 8192 -8192 14 ) ( -8192 -8192 14 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8056 1488 ) ( 8192 8025 -1646 ) ( -8192 8025 -1646 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 577 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 578 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 579 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 580 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 581 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 582 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 583 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 584 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 585 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3772 -7377 8192 ) ( -1408 8165 8192 ) ( -1408 8165 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 586 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1290 8192 ) ( -8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7559 -3227 8192 ) ( -7984 1953 8192 ) ( -7984 1953 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 587 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1290 8192 ) ( -8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8340 882 8192 ) ( -7202 -4298 8192 ) ( -7202 -4298 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 588 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4619 7095 8192 ) ( -561 -8448 8192 ) ( -561 -8448 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 589 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1309 8198 8192 ) ( 3871 -7344 8192 ) ( 3871 -7344 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 590 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1206 8192 ) ( 8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7951 2051 8192 ) ( 7592 -3129 8192 ) ( 7592 -3129 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 591 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1206 8192 ) ( 8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7235 -4199 8192 ) ( 8307 981 8192 ) ( 8307 981 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 592 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -659 -8415 8192 ) ( 4521 7128 8192 ) ( 4521 7128 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 593 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 594 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 595 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 596 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 597 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 598 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 599 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 600 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 601 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4077 -7276 8192 ) ( -1103 8267 8192 ) ( -1103 8267 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 602 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -274 8192 ) ( -8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7863 -2313 8192 ) ( -7679 2867 8192 ) ( -7679 2867 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 603 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -274 8192 ) ( -8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8036 1797 8192 ) ( -7507 -3383 8192 ) ( -7507 -3383 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 604 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4315 7196 8192 ) ( -865 -8346 8192 ) ( -865 -8346 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 605 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1005 8300 8192 ) ( 4175 -7243 8192 ) ( 4175 -7243 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 606 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -190 8192 ) ( 8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7646 2966 8192 ) ( 7896 -2214 8192 ) ( 7896 -2214 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 607 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -190 8192 ) ( 8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7540 -3285 8192 ) ( 8003 1895 8192 ) ( 8003 1895 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 608 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -964 -8313 8192 ) ( 4216 7229 8192 ) ( 4216 7229 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 609 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 610 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 611 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 612 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 613 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 614 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 615 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 616 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 617 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 681 -8408 8192 ) ( -4499 7135 8192 ) ( -4499 7135 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 618 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1322 8192 ) ( -8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7207 -4283 8192 ) ( -8336 897 8192 ) ( -8336 897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 619 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1322 8192 ) ( -8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8008 1881 8192 ) ( -7535 -3299 8192 ) ( -7535 -3299 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 620 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1547 8119 8192 ) ( -3633 -7424 8192 ) ( -3633 -7424 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 621 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4401 7168 8192 ) ( 779 -8375 8192 ) ( 779 -8375 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 622 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1238 8192 ) ( 8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8303 995 8192 ) ( 7240 -4185 8192 ) ( 7240 -4185 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 623 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1238 8192 ) ( 8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7568 -3201 8192 ) ( 7975 1979 8192 ) ( 7975 1979 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 624 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3731 -7391 8192 ) ( 1449 8152 8192 ) ( 1449 8152 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 625 +{ +( 565 8192 8192 ) ( 565 -8192 8192 ) ( 565 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 922 -8192 8192 ) ( 922 8192 8192 ) ( 922 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -648 8192 ) ( 8192 -648 8192 ) ( -8192 -648 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 626 +{ +( 438 8192 8192 ) ( 438 -8192 8192 ) ( 438 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 -8192 8192 ) ( 1050 8192 8192 ) ( 1050 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 627 +{ +( 361 8192 8192 ) ( 361 -8192 8192 ) ( 361 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1126 -8192 8192 ) ( 1126 8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 628 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 629 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 630 +{ +( 361 8192 8192 ) ( 361 -8192 8192 ) ( 361 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1126 -8192 8192 ) ( 1126 8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 631 +{ +( 438 8192 8192 ) ( 438 -8192 8192 ) ( 438 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 -8192 8192 ) ( 1050 8192 8192 ) ( 1050 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 632 +{ +( 565 8192 8192 ) ( 565 -8192 8192 ) ( 565 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 922 -8192 8192 ) ( 922 8192 8192 ) ( 922 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -648 8192 ) ( 8192 -648 8192 ) ( -8192 -648 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 633 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 369 -8200 8192 ) ( 369 8184 8192 ) ( 369 8184 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3835 -7243 8192 ) ( -3727 7290 8192 ) ( -3727 7290 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7557 3222 8192 ) ( -6975 -4341 8192 ) ( -6975 -4341 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 634 +{ +( 361 8192 8192 ) ( 361 -8192 8192 ) ( 361 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 446 -8192 8192 ) ( 446 8192 8192 ) ( 446 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7299 -3754 8192 ) ( -7599 3062 8192 ) ( -7599 3062 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 635 +{ +( 1042 8192 8192 ) ( 1042 -8192 8192 ) ( 1042 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1126 -8192 8192 ) ( 1126 8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7857 2499 8192 ) ( -7041 -4317 8192 ) ( -7041 -4317 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 636 +{ +( 1126 8192 8192 ) ( 1126 -8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4906 6681 8192 ) ( -2656 -7852 8192 ) ( -2656 -7852 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7292 -3731 8192 ) ( -7240 3831 8192 ) ( -7240 3831 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 637 +{ +( 311 8192 8192 ) ( 311 -8192 8192 ) ( 311 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 368 -8192 8192 ) ( 368 8192 8192 ) ( 368 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 160 8192 ) ( 8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 160 8192 ) ( -8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -168 ) ( 8192 8192 -168 ) ( -8192 -8192 -168 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -167 ) ( 8192 -8192 -167 ) ( -8192 -8192 -167 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8193 0 8192 ) ( -8186 334 8192 ) ( 8193 0 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8164 682 8192 ) ( -8183 -405 8192 ) ( 8164 682 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 638 +{ +( 311 8192 8192 ) ( 311 -8192 8192 ) ( 311 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 368 -8192 8192 ) ( 368 8192 8192 ) ( 368 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 160 8192 ) ( 8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 160 8192 ) ( -8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -137 ) ( 8192 8192 -137 ) ( -8192 -8192 -137 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -136 ) ( 8192 -8192 -136 ) ( -8192 -8192 -136 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8164 682 8192 ) ( -8183 -405 8192 ) ( 8164 682 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8193 0 8192 ) ( -8186 334 8192 ) ( 8193 0 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 639 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 640 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 641 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 642 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 643 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 644 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 645 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 646 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 647 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 985 -8306 8192 ) ( -4195 7236 8192 ) ( -4195 7236 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 648 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -306 8192 ) ( -8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7511 -3369 8192 ) ( -8031 1811 8192 ) ( -8031 1811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 649 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -306 8192 ) ( -8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7703 2795 8192 ) ( -7839 -2385 8192 ) ( -7839 -2385 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 650 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1243 8220 8192 ) ( -3937 -7322 8192 ) ( -3937 -7322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 651 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4096 7269 8192 ) ( 1084 -8273 8192 ) ( 1084 -8273 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 652 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -222 8192 ) ( 8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7998 1910 8192 ) ( 7544 -3270 8192 ) ( 7544 -3270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 653 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -222 8192 ) ( 8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7872 -2286 8192 ) ( 7670 2894 8192 ) ( 7670 2894 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 654 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4036 -7289 8192 ) ( 1144 8253 8192 ) ( 1144 8253 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 655 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -464 -8192 8192 ) ( -464 8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -519 8192 ) ( -8192 -519 8192 ) ( -8192 -519 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -31 ) ( 8192 8192 -31 ) ( -8192 -8192 -31 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8017 8336 -668 ) ( 8017 -7398 3899 ) ( -7987 -8374 536 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3687 7832 7699 ) ( -7708 -3938 7699 ) ( -3666 -7852 -7688 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6091 5486 8217 ) ( 5657 -5932 8217 ) ( 5094 -6512 -8146 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7945 7305 -4218 ) ( 7945 -8428 349 ) ( -8060 8281 -855 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8017 -7398 3898 ) ( 8017 8335 -669 ) ( -7987 7359 -4032 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8179 447 ) ( 8192 8172 -574 ) ( -8192 8172 -574 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8172 -8192 -570 ) ( 8172 8192 -570 ) ( -8179 8192 451 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5820 5765 8192 ) ( -5765 -5820 8192 ) ( -5765 -5820 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7243 8191 3831 ) ( 7243 -8191 3831 ) ( -7411 -8191 -3495 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6467 5078 8192 ) ( 5484 -6127 8192 ) ( 5484 -6127 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7818 -2451 ) ( 8192 -7915 2116 ) ( -8192 -7915 2116 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 656 +{ +( -464 8192 8192 ) ( -464 -8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -519 8192 ) ( -8192 -519 8192 ) ( -8192 -519 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -31 ) ( 8192 8192 -31 ) ( -8192 -8192 -31 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7945 7305 -4217 ) ( 7945 -8428 350 ) ( -8060 -7452 3713 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6107 -5469 8185 ) ( 5641 5949 8185 ) ( 6204 5369 -8178 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7286 -4347 7914 ) ( -4110 7423 7914 ) ( -8152 3509 -7473 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8017 8335 -669 ) ( 8017 -7398 3898 ) ( -7987 7359 -4032 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7945 -8428 349 ) ( 7945 7305 -4218 ) ( -8060 8281 -855 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7225 8192 -3866 ) ( 7225 -8192 -3866 ) ( -7428 -8192 3460 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5918 -5664 8192 ) ( 6033 5541 8192 ) ( 6033 5541 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8179 447 ) ( 8192 8172 -574 ) ( -8192 8172 -574 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8176 -8192 509 ) ( 8176 8192 509 ) ( -8175 8192 -512 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5301 -6284 8192 ) ( -6284 5301 8192 ) ( -6284 5301 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7818 -2451 ) ( 8192 -7915 2116 ) ( -8192 -7915 2116 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 657 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -512 -8192 8192 ) ( -512 8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -518 8192 ) ( -8192 -518 8192 ) ( -8192 -518 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -32 ) ( 8192 8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8052 8269 -1003 ) ( 8052 -7369 3883 ) ( -8020 -8316 851 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3302 8014 7685 ) ( -7550 -4258 7685 ) ( -3371 -7953 -7719 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5904 5679 8225 ) ( 5732 -5853 8225 ) ( 4855 -6738 -8111 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7982 7263 -4222 ) ( 7982 -8374 664 ) ( -8091 8210 -1190 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8052 -7369 3882 ) ( 8052 8268 -1004 ) ( -8020 7321 -4036 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8146 865 ) ( 8192 8125 -1048 ) ( -8192 8125 -1048 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8116 -8192 -1110 ) ( 8116 8192 -1110 ) ( -8140 8192 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5601 5977 8192 ) ( -5627 -5953 8192 ) ( -5627 -5953 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7233 8192 3850 ) ( 7233 -8192 3850 ) ( -7420 -8192 -3476 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6490 5054 8192 ) ( 5462 -6151 8192 ) ( 5462 -6151 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7763 -2620 ) ( 8192 -7874 2266 ) ( -8192 -7874 2266 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 658 +{ +( -512 8192 8192 ) ( -512 -8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -518 8192 ) ( -8192 -518 8192 ) ( -8192 -518 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -32 ) ( 8192 8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7982 7263 -4221 ) ( 7982 -8374 665 ) ( -8090 -7427 3697 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6236 -5344 8170 ) ( 5400 6188 8170 ) ( 6276 5304 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7042 -4707 7931 ) ( -3810 7565 7931 ) ( -7989 3870 -7473 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8052 8268 -1004 ) ( 8052 -7369 3882 ) ( -8020 7321 -4036 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7982 -8374 664 ) ( 7982 7263 -4222 ) ( -8091 8210 -1190 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7215 8192 -3885 ) ( 7215 -8192 -3885 ) ( -7438 -8192 3441 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5941 -5640 8192 ) ( 6011 5565 8192 ) ( 6011 5565 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8146 865 ) ( 8192 8125 -1048 ) ( -8192 8125 -1048 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8124 -8191 1047 ) ( 8124 8191 1047 ) ( -8132 8191 -984 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5084 -6464 8192 ) ( -6144 5466 8192 ) ( -6144 5466 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7763 -2620 ) ( 8192 -7874 2266 ) ( -8192 -7874 2266 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 659 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -512 -8192 8192 ) ( -512 8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7999 7247 -4215 ) ( 7999 -8344 814 ) ( -8102 -7415 3695 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5264 6321 8157 ) ( -6321 -5264 8157 ) ( -5301 -6284 -8162 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4012 7466 7924 ) ( 7192 -4485 7924 ) ( 3096 -8325 -7466 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8067 -7358 3872 ) ( 8067 8234 -1157 ) ( -8034 7304 -4039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7999 -8345 813 ) ( 7999 7247 -4216 ) ( -8102 8177 -1334 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7207 -8192 -3901 ) ( 7207 8192 -3901 ) ( -7446 8192 3425 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5976 5602 8192 ) ( -5976 -5602 8192 ) ( -5976 -5602 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8124 8191 1047 ) ( 8124 -8191 1047 ) ( -8132 8191 -984 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6304 5281 8192 ) ( 5281 -6304 8192 ) ( 5281 -6304 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 660 +{ +( -512 8192 8192 ) ( -512 -8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8067 8234 -1156 ) ( 8067 -7358 3872 ) ( -8034 -8287 991 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7673 -4034 7684 ) ( 3531 7917 7684 ) ( 7627 4077 -7707 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5813 -5772 8221 ) ( -5772 5813 8221 ) ( -6792 4793 -8098 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7999 -8345 813 ) ( 7999 7247 -4216 ) ( -8102 8177 -1334 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8067 -7358 3872 ) ( 8067 8234 -1157 ) ( -8034 7304 -4039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8116 8192 -1110 ) ( 8116 -8192 -1110 ) ( -8140 8192 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5793 -5792 8192 ) ( 5792 5793 8192 ) ( 5792 5793 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7241 -8192 3834 ) ( 7241 8192 3834 ) ( -7412 8192 -3492 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5497 -6113 8192 ) ( -6455 5091 8192 ) ( -6455 5091 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 661 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -464 -8192 8192 ) ( -464 8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8001 7250 -4207 ) ( 8001 -8342 822 ) ( -8100 -7412 3704 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5287 6297 8160 ) ( -6297 -5287 8160 ) ( -5277 -6307 -8159 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -3990 7488 7913 ) ( 7215 -4464 7913 ) ( 3119 -8304 -7478 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8069 -7361 3863 ) ( 8069 8231 -1166 ) ( -8032 7301 -4047 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8001 -8342 821 ) ( 8001 7250 -4208 ) ( -8100 8179 -1326 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7217 -8192 -3882 ) ( 7217 8192 -3882 ) ( -7436 8192 3444 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5998 5578 8192 ) ( -5953 -5626 8192 ) ( -5953 -5626 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8125 8192 1041 ) ( 8125 -8192 1041 ) ( -8131 -8192 -990 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6280 5305 8192 ) ( 5305 -6280 8192 ) ( 5305 -6280 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 662 +{ +( -464 8192 8192 ) ( -464 -8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8068 8231 -1165 ) ( 8068 -7361 3864 ) ( -8032 -8290 983 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7651 -4055 7695 ) ( 3554 7896 7695 ) ( 7650 4056 -7696 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5836 -5748 8218 ) ( -5748 5836 8218 ) ( -6768 4816 -8101 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8001 -8342 821 ) ( 8001 7250 -4208 ) ( -8100 8179 -1326 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8069 -7361 3863 ) ( 8069 8231 -1166 ) ( -8032 7301 -4047 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8117 8192 -1104 ) ( 8117 -8192 -1104 ) ( -8139 -8192 927 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5769 -5816 8192 ) ( 5816 5769 8192 ) ( 5816 5769 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7251 -8192 3815 ) ( 7251 8192 3815 ) ( -7403 8192 -3511 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5519 -6089 8192 ) ( -6432 5115 8192 ) ( -6432 5115 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 663 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -595 8192 ) ( 8192 -595 8192 ) ( -8192 -595 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -580 8192 ) ( -8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7612 3032 ) ( 8192 -7734 -2705 ) ( -8192 -7734 -2705 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 664 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7734 -2705 ) ( 8192 7612 3032 ) ( -8192 -7734 -2705 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 665 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -592 8192 ) ( 8192 -592 8192 ) ( -8192 -592 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -542 8192 ) ( -8192 -542 8192 ) ( -8192 -542 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8078 -1365 ) ( 8192 -8114 1130 ) ( -8192 -8114 1130 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 666 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -392 8192 ) ( -8192 -392 8192 ) ( -8192 -392 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8114 1130 ) ( 8192 8078 -1365 ) ( -8192 -8114 1130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 667 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -592 8192 ) ( 8192 -592 8192 ) ( -8192 -592 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -542 8192 ) ( -8192 -542 8192 ) ( -8192 -542 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8078 -1365 ) ( 8192 -8114 1130 ) ( -8192 -8114 1130 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 668 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -392 8192 ) ( -8192 -392 8192 ) ( -8192 -392 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8114 1130 ) ( 8192 8078 -1365 ) ( -8192 -8114 1130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 669 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -595 8192 ) ( 8192 -595 8192 ) ( -8192 -595 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -580 8192 ) ( -8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7612 3032 ) ( 8192 -7734 -2705 ) ( -8192 -7734 -2705 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 670 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7734 -2705 ) ( 8192 7612 3032 ) ( -8192 -7734 -2705 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 671 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -3 ) ( 8192 8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -3398 7475 ) ( 8192 -3398 7475 ) ( 8192 2339 -7870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7745 -2675 ) ( 8192 7600 3063 ) ( -8192 7600 3063 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 672 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -544 8192 ) ( 8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -392 8192 ) ( -8192 -392 8192 ) ( -8192 -392 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -5 ) ( 8192 8192 -5 ) ( -8192 -8192 -5 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 865 8155 ) ( -8191 865 8155 ) ( -8191 -1629 -8037 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8106 1182 ) ( 8192 8086 -1312 ) ( -8192 8086 -1312 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 673 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -229 8192 ) ( 8192 -229 8192 ) ( -8192 -229 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -219 8192 ) ( -8192 -219 8192 ) ( -8192 -219 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -102 ) ( 8192 -8192 -102 ) ( -8192 -8192 -102 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5662 -5924 ) ( 8192 -5991 5591 ) ( -8192 -5991 5591 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 674 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -243 8192 ) ( 8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -201 8192 ) ( -8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -112 ) ( 8192 8192 -112 ) ( -8192 -8192 -112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -43 ) ( 8192 -8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5991 5591 ) ( 8192 5662 -5924 ) ( -8192 -5991 5591 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 675 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -266 8192 ) ( 8192 -266 8192 ) ( -8192 -266 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -225 8192 ) ( -8192 -225 8192 ) ( -8192 -225 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -92 ) ( 8192 -8192 -92 ) ( -8192 -8192 -92 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7864 -2297 ) ( 8192 -7947 1990 ) ( -8192 -7947 1990 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 676 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -391 8192 ) ( 8192 -391 8192 ) ( -8192 -391 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -229 8192 ) ( -8192 -229 8192 ) ( -8192 -229 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -102 ) ( 8192 8192 -102 ) ( -8192 -8192 -102 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -3 ) ( 8192 -8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7947 1990 ) ( 8192 7864 -2297 ) ( -8192 -7947 1990 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 677 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -266 8192 ) ( 8192 -266 8192 ) ( -8192 -266 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -225 8192 ) ( -8192 -225 8192 ) ( -8192 -225 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -92 ) ( 8192 -8192 -92 ) ( -8192 -8192 -92 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7864 -2297 ) ( 8192 -7947 1990 ) ( -8192 -7947 1990 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 678 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -391 8192 ) ( 8192 -391 8192 ) ( -8192 -391 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -229 8192 ) ( -8192 -229 8192 ) ( -8192 -229 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -102 ) ( 8192 8192 -102 ) ( -8192 -8192 -102 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -3 ) ( 8192 -8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7947 1990 ) ( 8192 7864 -2297 ) ( -8192 -7947 1990 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 679 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -229 8192 ) ( 8192 -229 8192 ) ( -8192 -229 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -219 8192 ) ( -8192 -219 8192 ) ( -8192 -219 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -102 ) ( 8192 -8192 -102 ) ( -8192 -8192 -102 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5662 -5924 ) ( 8192 -5991 5591 ) ( -8192 -5991 5591 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 680 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -243 8192 ) ( 8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -201 8192 ) ( -8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -112 ) ( 8192 8192 -112 ) ( -8192 -8192 -112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -43 ) ( 8192 -8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5991 5591 ) ( 8192 5662 -5924 ) ( -8192 -5991 5591 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 681 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -243 8192 ) ( 8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -201 8192 ) ( -8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -85 ) ( 8192 8192 -85 ) ( -8192 -8192 -85 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -43 ) ( 8192 -8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5699 5885 ) ( -8192 5699 5885 ) ( -8192 -5817 -5768 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5969 5614 ) ( 8192 5684 -5902 ) ( -8192 5684 -5902 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 682 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -391 8192 ) ( 8192 -391 8192 ) ( -8192 -391 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -243 8192 ) ( -8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -43 ) ( 8192 8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -3 ) ( 8192 -8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7934 2041 ) ( 8192 7878 -2246 ) ( -8192 7878 -2246 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1780 8004 ) ( 8192 1780 8004 ) ( 8192 -2507 -7807 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 683 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 684 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 685 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 686 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 687 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 688 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 689 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 690 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 691 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 2 ) ( 8192 8192 2 ) ( -8192 -8192 2 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2464 7833 ) ( 8192 -2464 7833 ) ( 8192 1359 -8098 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2047 ) ( 8192 -7998 -1776 ) ( -8192 -7998 -1776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7998 -1777 ) ( 8192 7933 2046 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 692 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -528 8192 ) ( 8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -6 ) ( 8192 8192 -6 ) ( -8192 -8192 -6 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8104 -1198 ) ( 8192 -8120 1085 ) ( -8192 -8120 1085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 773 8163 ) ( -8192 773 8163 ) ( -8192 -1509 -8060 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8120 1084 ) ( 8192 8103 -1199 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 693 +{ +( 600 8192 8192 ) ( 600 -8192 8192 ) ( 600 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 630 -8192 8192 ) ( 630 8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -442 8192 ) ( 8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -352 8192 ) ( -8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2156 7916 8192 ) ( 3024 -7626 8192 ) ( 3024 -7626 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3025 -7626 8192 ) ( -2155 7916 8192 ) ( -2155 7916 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3236 7556 8192 ) ( -1944 -7986 8192 ) ( -1944 -7986 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7841 2381 8192 ) ( 7702 -2799 8192 ) ( 7702 -2799 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 694 +{ +( 630 8192 8192 ) ( 630 -8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 720 -8192 8192 ) ( 720 8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -472 8192 ) ( 8192 -472 8192 ) ( -8192 -472 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -442 8192 ) ( -8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7841 2381 8192 ) ( 7702 -2799 8192 ) ( 7702 -2799 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7702 -2798 8192 ) ( -7840 2382 8192 ) ( -7840 2382 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2156 7916 8192 ) ( 3024 -7626 8192 ) ( 3024 -7626 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7558 -3231 8192 ) ( 7985 1949 8192 ) ( 7985 1949 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 695 +{ +( 720 8192 8192 ) ( 720 -8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 810 -8192 8192 ) ( 810 8192 8192 ) ( 810 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -472 8192 ) ( 8192 -472 8192 ) ( -8192 -472 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -442 8192 ) ( -8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7558 -3231 8192 ) ( 7985 1949 8192 ) ( 7985 1949 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7984 1950 8192 ) ( -7558 -3230 8192 ) ( -7558 -3230 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7841 2381 8192 ) ( 7702 -2799 8192 ) ( 7702 -2799 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -8058 8192 ) ( 3452 7484 8192 ) ( 3452 7484 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 696 +{ +( 810 8192 8192 ) ( 810 -8192 8192 ) ( 810 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 840 -8192 8192 ) ( 840 8192 8192 ) ( 840 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -442 8192 ) ( 8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -352 8192 ) ( -8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -8058 8192 ) ( 3452 7484 8192 ) ( 3452 7484 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3451 7484 8192 ) ( -1729 -8058 8192 ) ( -1729 -8058 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7558 -3231 8192 ) ( 7985 1949 8192 ) ( 7985 1949 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3240 -7554 8192 ) ( -1940 7988 8192 ) ( -1940 7988 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 697 +{ +( 808 8192 8192 ) ( 808 -8192 8192 ) ( 808 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 840 -8192 8192 ) ( 840 8192 8192 ) ( 840 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -352 8192 ) ( 8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -262 8192 ) ( -8192 -262 8192 ) ( -8192 -262 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3240 -7554 8192 ) ( -1940 7988 8192 ) ( -1940 7988 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1943 7988 8192 ) ( 3237 -7555 8192 ) ( 3237 -7555 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -8058 8192 ) ( 3452 7484 8192 ) ( 3452 7484 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7774 -2583 8192 ) ( -7769 2597 8192 ) ( -7769 2597 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 698 +{ +( 720 8192 8192 ) ( 720 -8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 810 -8192 8192 ) ( 810 8192 8192 ) ( 810 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8190 -264 8192 ) ( 8194 -264 8192 ) ( -8190 -264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7774 -2583 8192 ) ( -7769 2597 8192 ) ( -7769 2597 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7767 2594 8192 ) ( 7775 -2586 8192 ) ( 7775 -2586 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3240 -7554 8192 ) ( -1940 7988 8192 ) ( -1940 7988 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7913 2165 8192 ) ( -7630 -3015 8192 ) ( -7630 -3015 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 699 +{ +( 630 8192 8192 ) ( 630 -8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 720 -8192 8192 ) ( 720 8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8196 -264 8192 ) ( 8188 -264 8192 ) ( -8196 -264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7913 2165 8192 ) ( -7630 -3015 8192 ) ( -7630 -3015 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7633 -3018 8192 ) ( 7909 2162 8192 ) ( 7909 2162 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7774 -2583 8192 ) ( -7769 2597 8192 ) ( -7769 2597 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3236 7556 8192 ) ( -1944 -7986 8192 ) ( -1944 -7986 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 700 +{ +( 600 8192 8192 ) ( 600 -8192 8192 ) ( 600 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 630 -8192 8192 ) ( 630 8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -352 8192 ) ( 8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -262 8192 ) ( -8192 -262 8192 ) ( -8192 -262 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3236 7556 8192 ) ( -1944 -7986 8192 ) ( -1944 -7986 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1943 -7987 8192 ) ( 3237 7556 8192 ) ( 3237 7556 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7913 2165 8192 ) ( -7630 -3015 8192 ) ( -7630 -3015 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2156 7916 8192 ) ( 3024 -7626 8192 ) ( 3024 -7626 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 701 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 702 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 703 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 704 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 705 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 706 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 707 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 708 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 709 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -233 8192 ) ( -8192 -233 8192 ) ( -8192 -233 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -100 ) ( 8192 -8192 -100 ) ( -8192 -8192 -100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7862 -2306 ) ( 8192 -7950 1981 ) ( -8192 -7950 1981 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 710 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -399 8192 ) ( 8192 -399 8192 ) ( -8192 -399 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -237 8192 ) ( -8192 -237 8192 ) ( -8192 -237 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -110 ) ( 8192 8192 -110 ) ( -8192 -8192 -110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -11 ) ( 8192 -8192 -11 ) ( -8192 -8192 -11 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7950 1981 ) ( 8192 7862 -2306 ) ( -8192 -7950 1981 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2255 ) ( 8192 -7936 2033 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 711 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -237 8192 ) ( 8192 -237 8192 ) ( -8192 -237 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -227 8192 ) ( -8192 -227 8192 ) ( -8192 -227 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -110 ) ( 8192 -8192 -110 ) ( -8192 -8192 -110 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5654 -5932 ) ( 8192 -5999 5583 ) ( -8192 -5999 5583 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 712 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -251 8192 ) ( 8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -209 8192 ) ( -8192 -209 8192 ) ( -8192 -209 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -51 ) ( 8192 -8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5999 5583 ) ( 8192 5654 -5932 ) ( -8192 -5999 5583 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5976 5606 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 713 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -237 8192 ) ( 8192 -237 8192 ) ( -8192 -237 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -227 8192 ) ( -8192 -227 8192 ) ( -8192 -227 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -110 ) ( 8192 -8192 -110 ) ( -8192 -8192 -110 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5654 -5932 ) ( 8192 -5999 5583 ) ( -8192 -5999 5583 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 714 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -251 8192 ) ( 8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -209 8192 ) ( -8192 -209 8192 ) ( -8192 -209 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -51 ) ( 8192 -8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5999 5583 ) ( 8192 5654 -5932 ) ( -8192 -5999 5583 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5976 5606 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 715 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -233 8192 ) ( -8192 -233 8192 ) ( -8192 -233 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -100 ) ( 8192 -8192 -100 ) ( -8192 -8192 -100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7862 -2306 ) ( 8192 -7950 1981 ) ( -8192 -7950 1981 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 716 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -399 8192 ) ( 8192 -399 8192 ) ( -8192 -399 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -237 8192 ) ( -8192 -237 8192 ) ( -8192 -237 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -110 ) ( 8192 8192 -110 ) ( -8192 -8192 -110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -11 ) ( 8192 -8192 -11 ) ( -8192 -8192 -11 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7950 1981 ) ( 8192 7862 -2306 ) ( -8192 -7950 1981 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2255 ) ( 8192 -7936 2033 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "path_corner" +"targetname" "topUC" +"origin" "-1467 -676 -203" +} +// entity 2 +{ +"classname" "trigger_push" +"target" "topUC" +// brush 0 +{ +( -402 656 -455 ) ( -423 632 -450 ) ( -392 612 -413 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -432 677 -471 ) ( -453 654 -466 ) ( -412 621 -464 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -459 703 -457 ) ( -480 679 -453 ) ( -453 651 -488 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -469 717 -421 ) ( -489 693 -416 ) ( -492 686 -469 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -455 712 -383 ) ( -476 688 -380 ) ( -506 707 -417 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -426 690 -367 ) ( -447 666 -363 ) ( -487 699 -365 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -399 665 -381 ) ( -419 640 -377 ) ( -445 669 -342 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -389 650 -416 ) ( -410 626 -413 ) ( -407 632 -361 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -539 644 -453 ) ( -466 582 -449 ) ( -460 595 -346 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -462 574 -352 ) ( -467 562 -455 ) ( -540 623 -459 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 3 +{ +"classname" "weapon_railgun" +"origin" "-320 944 240" +} +// entity 4 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/deskwood + ( 3 3 0 0 0 ) +( +( ( -360 160 -136 0 0.250000 ) ( -360 160 -152 0 0.125000 ) ( -360 160 -168 0 0 ) ) +( ( 368 160 -136 5.687500 0.250000 ) ( 368 160 -152 5.687500 0.125000 ) ( 368 160 -168 5.687500 0 ) ) +( ( 368 928 -136 11.687500 0.250000 ) ( 368 928 -152 11.687500 0.125000 ) ( 368 928 -168 11.687500 0 ) ) +) + } + } +} +// entity 5 +{ +"origin" "-520 744 -400" +"classname" "item_health_mega" +} +// entity 6 +{ +"origin" "-1416 -288 -648" +"classname" "item_quad" +"spawnflags" "1" +} +// entity 7 +{ +"origin" "-72 -144 -104" +"classname" "weapon_rocketlauncher" +} +// entity 8 +{ +"origin" "1508 -360 234" +"classname" "info_player_deathmatch" +} +// entity 9 +{ +"origin" "576 1152 -320" +"classname" "item_health_large" +} +// entity 10 +{ +"origin" "656 1304 -320" +"classname" "item_armor_body" +} +// entity 11 +{ +"origin" "648 904 -320" +"classname" "weapon_shotgun" +} +// entity 12 +{ +"origin" "1864 1120 -320" +"classname" "weapon_railgun" +} +// entity 13 +{ +"origin" "160 -304 80" +"light" "10000" +"classname" "light" +} +// entity 14 +{ +"classname" "light" +"light" "10000" +"origin" "-1064 312 -1160" +} +// entity 15 +{ +"classname" "weapon_bfg" +"origin" "-1064 304 -1152" +} +// entity 16 +{ +"dmg" "300" +"classname" "trigger_hurt" +// brush 0 +{ +( -8192 166 8192 ) ( 8192 166 8192 ) ( -8192 166 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1192 ) ( 8192 8192 -1192 ) ( -8192 -8192 -1192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1176 ) ( 8192 -8192 -1176 ) ( -8192 -8192 -1176 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2557 7866 8192 ) ( 308 -8265 8192 ) ( -2557 7866 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6656 4811 8192 ) ( 5895 -5718 8192 ) ( -6656 4811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3563 -7402 8192 ) ( -4645 6776 8192 ) ( 3563 -7402 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3042 7704 8192 ) ( -5166 -6474 8192 ) ( 3042 7704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7418 3566 8192 ) ( -7969 -2058 8192 ) ( 7418 3566 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2382 -7897 8192 ) ( 483 8234 8192 ) ( -2382 -7897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7718 -2746 8192 ) ( -7670 2877 8192 ) ( 7718 -2746 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 17 +{ +"classname" "info_player_deathmatch" +"origin" "-1464 -824 -976" +} +// entity 18 +{ +"light" "10000" +"origin" "-1416 -736 -792" +"classname" "light" +} +// entity 19 +{ +"origin" "-1462 -874 -982" +"classname" "item_armor_combat" +} +// entity 20 +{ +"origin" "-1462 -920 -982" +"classname" "weapon_grenadelauncher" +} +// entity 21 +{ +"origin" "160 -228 222" +"targetname" "bilbo" +"classname" "target_teleporter" +} +// entity 22 +{ +"target" "bilbo" +"classname" "trigger_teleport" +// brush 0 +{ +( -1498 8192 8192 ) ( -1498 -8192 8192 ) ( -1498 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1422 -8192 8192 ) ( -1422 8192 8192 ) ( -1422 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -930 ) ( 8192 -8192 -930 ) ( -8192 -8192 -930 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 23 +{ +"classname" "target_teleporter" +"targetname" "central" +"origin" "-1458 -910 -1142" +} +// entity 24 +{ +"classname" "trigger_teleport" +"target" "central" +// brush 0 +{ +( 136 8192 8192 ) ( 136 -8192 8192 ) ( 136 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 182 -8192 8192 ) ( 182 8192 8192 ) ( 182 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 18 ) ( 8192 8192 18 ) ( -8192 -8192 18 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 106 ) ( 8192 -8192 106 ) ( -8192 -8192 106 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 25 +{ +"origin" "-1264 -240 -544" +"light" "10000" +"classname" "light" +} +// entity 26 +{ +"origin" "1984 1000 368" +"classname" "ammo_rockets" +} +// entity 27 +{ +"origin" "1984 1432 368" +"classname" "weapon_rocketlauncher" +} +// entity 28 +{ +"origin" "1624 1288 368" +"classname" "item_armor_shard" +} +// entity 29 +{ +"origin" "1376 1192 368" +"classname" "item_health" +} +// entity 30 +{ +"origin" "792 -312 720" +"classname" "item_health_large" +} +// entity 31 +{ +"classname" "func_train" +"target" "drawerclosed" +"spawnflags" "1" +"origin" "376 1096 -496" +// brush 0 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 400 -8192 8192 ) ( 400 8192 8192 ) ( 400 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 736 8192 ) ( -8192 736 8192 ) ( -8192 736 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -608 ) ( 8192 8192 -608 ) ( -8192 -8192 -608 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -592 ) ( 8192 -8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1456 8192 ) ( 8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 1984 8192 8192 ) ( 1984 -8192 8192 ) ( 1984 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8281 207 8192 ) ( -7975 2240 8192 ) ( -7975 2240 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1199 8105 8192 ) ( -832 -8151 8192 ) ( -832 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8102 1688 8192 ) ( 8249 666 8192 ) ( 8249 666 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -843 -8150 8192 ) ( 1220 8102 8192 ) ( 1220 8102 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8247 -866 8192 ) ( -7583 3354 8192 ) ( -7583 3354 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 3191 7547 8192 ) ( -3531 -7393 8192 ) ( -3531 -7393 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -7594 3315 8192 ) ( 8236 -906 8192 ) ( 8236 -906 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -3517 -7400 8192 ) ( 3206 7540 8192 ) ( 3206 7540 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( -8192 1131 8192 ) ( 8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 768 8159 8192 ) ( -253 -8192 8192 ) ( -253 -8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8249 667 8192 ) ( -8102 1689 8192 ) ( -8102 1689 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -255 -8192 8192 ) ( 782 8158 8192 ) ( 782 8158 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( 330 8192 8192 ) ( 330 -8192 8192 ) ( 330 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1083 8192 ) ( 8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1131 8192 ) ( -8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( 8192 1083 8192 ) ( -8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -115 8200 8192 ) ( 906 -8151 8192 ) ( 906 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8240 516 8192 ) ( 8111 1538 8192 ) ( 8111 1538 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 921 -8149 8192 ) ( -116 8201 8192 ) ( -116 8201 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8248 -60 8192 ) ( 8009 1972 8192 ) ( 8009 1972 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -560 8185 8192 ) ( 1471 -8071 8192 ) ( 1471 -8071 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8111 1538 8192 ) ( -8240 516 8192 ) ( -8240 516 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1495 -8067 8192 ) ( -568 8185 8192 ) ( -568 8185 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2563 -7803 8192 ) ( -1410 8091 8192 ) ( -1410 8091 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -5807 5861 8192 ) ( 7029 -4319 8192 ) ( 7029 -4319 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 6637 4844 8192 ) ( -7315 -3742 8192 ) ( -7315 -3742 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8134 -1287 8192 ) ( 7695 2933 8192 ) ( 7695 2933 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -2703 7766 8192 ) ( 4020 -7174 8192 ) ( 4020 -7174 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 7685 2973 8192 ) ( -8145 -1248 8192 ) ( -8145 -1248 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 4034 -7167 8192 ) ( -2688 7773 8192 ) ( -2688 7773 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 384 -8192 8192 ) ( 384 8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -632 ) ( 8192 8192 -632 ) ( -8192 -8192 -632 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 14 +{ +( 360 8192 8192 ) ( 360 -8192 8192 ) ( 360 -8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 392 -8192 8192 ) ( 392 8192 8192 ) ( 392 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1080 8192 ) ( 8192 1080 8192 ) ( 8192 1080 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1112 8192 ) ( -8192 1112 8192 ) ( -8192 1112 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -512 ) ( 8192 8192 -512 ) ( -8192 8192 -512 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -480 ) ( 8192 -8192 -480 ) ( -8192 -8192 -480 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 32 +{ +"origin" "-70 -144 -136" +"model" "models/mapobjects/mug/mug.md3" +"classname" "misc_model" +} +// entity 33 +{ +"classname" "trigger_push" +"target" "pathtoscreen2" +// brush 0 +{ +( 56 8192 8192 ) ( 56 -8192 8192 ) ( 56 8192 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 140 -8192 8192 ) ( 140 8192 8192 ) ( 140 8192 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( -8192 32 8192 ) ( 8192 32 8192 ) ( -8192 32 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 8192 70 8192 ) ( -8192 70 8192 ) ( -8192 70 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -132 ) ( 8192 8192 -132 ) ( -8192 -8192 -132 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -130 ) ( 8192 -8192 -130 ) ( -8192 -8192 -130 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 34 +{ +"origin" "1504 952 664" +"targetname" "stapleremoverpath" +"classname" "path_corner" +} +// entity 35 +{ +"target" "stapleremoverpath" +"name" "stapleremover" +"classname" "trigger_push" +// brush 0 +{ +( 1481 8192 8192 ) ( 1481 -8192 8192 ) ( 1481 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1520 -8192 8192 ) ( 1520 8192 8192 ) ( 1520 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 700 8192 ) ( 8192 700 8192 ) ( -8192 700 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 724 8192 ) ( -8192 724 8192 ) ( -8192 724 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -103 ) ( 8192 8192 -103 ) ( -8192 -8192 -103 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -87 ) ( 8192 -8192 -87 ) ( -8192 -8192 -87 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7506 -3288 ) ( 8192 -7318 3687 ) ( -8192 -7318 3687 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 36 +{ +"target" "" +"targetname" "pathtoscreen" +"origin" "144 696 -18" +"classname" "path_corner" +} +// entity 37 +{ +"target" "pathtoscreen" +"classname" "trigger_push" +// brush 0 +{ +( 96 8192 8192 ) ( 96 -8192 8192 ) ( 96 8192 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 192 -8192 8192 ) ( 192 8192 8192 ) ( 192 8192 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( -8192 672 8192 ) ( 8192 672 8192 ) ( -8192 672 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 728 8192 ) ( -8192 728 8192 ) ( -8192 728 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1120 ) ( 8192 8192 -1120 ) ( -8192 -8192 -1120 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1112 ) ( 8192 -8192 -1112 ) ( -8192 -8192 -1112 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 38 +{ +"origin" "1501 728 -132" +"model" "/models/mapobjects/steprem/steprem.md3" +"classname" "misc_model" +} +// entity 39 +{ +"origin" "1248 944 -496" +"classname" "light" +"light" "10000" +} +// entity 40 +{ +"classname" "misc_model" +"model" "/models/mapobjects/bilbo/bilbo.md3" +"origin" "160 -228 234" +} +// entity 41 +{ +"target" "toptarget" +"name" "backtotop" +"classname" "trigger_teleport" +// brush 0 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1008 8192 ) ( 8192 1008 8192 ) ( -8192 1008 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1104 8192 ) ( -8192 1104 8192 ) ( -8192 1104 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -570 ) ( 8192 8192 -570 ) ( -8192 -8192 -570 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 42 +{ +"targetname" "toptarget" +"classname" "target_teleporter" +"origin" "-460 932 230" +} +// entity 43 +{ +"classname" "path_corner" +"targetname" "draweropen" +"target" "drawerclosed" +"origin" "104 1096 -496" +} +// entity 44 +{ +"classname" "light" +"light" "10000" +"origin" "84 512 -828" +} +// entity 45 +{ +"classname" "light" +"light" "10000" +"origin" "154 -312 8" +} +// entity 46 +{ +"origin" "106 88 -298" +"radius" "5000" +"classname" "light" +"light" "10000" +} +// entity 47 +{ +"origin" "-160 80 -104" +"classname" "info_player_deathmatch" +} +// entity 48 +{ +"origin" "384 1096 -496" +"target" "draweropen" +"targetname" "drawerclosed" +"classname" "path_corner" +} +// entity 49 +{ +"origin" "1506 -312 8" +"light" "10000" +"classname" "light" +} +// entity 50 +{ +"classname" "path_corner" +"origin" "352 -144 896" +"targetname" "pathtoscreen2" +} +// entity 51 +{ +"classname" "item_health" +"origin" "1416 1192 368" +} +// entity 52 +{ +"origin" "1456 1192 368" +"classname" "item_health" +} +// entity 53 +{ +"classname" "item_health" +"origin" "1496 1192 368" +} +// entity 54 +{ +"origin" "1536 1192 368" +"classname" "item_health" +} +// entity 55 +{ +"classname" "item_health" +"origin" "1576 1192 368" +} +// entity 56 +{ +"origin" "1624 1192 368" +"classname" "item_health" +} +// entity 57 +{ +"classname" "item_armor_shard" +"origin" "1576 1288 368" +} +// entity 58 +{ +"origin" "1536 1288 368" +"classname" "item_armor_shard" +} +// entity 59 +{ +"classname" "item_armor_shard" +"origin" "1496 1288 368" +} +// entity 60 +{ +"origin" "1456 1288 368" +"classname" "item_armor_shard" +} +// entity 61 +{ +"classname" "item_armor_shard" +"origin" "1416 1288 368" +} +// entity 62 +{ +"origin" "1376 1288 368" +"classname" "item_armor_shard" +} +// entity 63 +{ +"classname" "item_armor_shard" +"origin" "1376 1240 368" +} +// entity 64 +{ +"classname" "ammo_rockets" +"origin" "1984 1040 368" +} +// entity 65 +{ +"spawnflags" "1" +"target" "t1" +"classname" "func_train" +// brush 0 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8281 207 8192 ) ( -7975 2240 8192 ) ( -7975 2240 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1199 8105 8192 ) ( -832 -8151 8192 ) ( -832 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8102 1688 8192 ) ( 8249 666 8192 ) ( 8249 666 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -843 -8150 8192 ) ( 1220 8102 8192 ) ( 1220 8102 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8247 -866 8192 ) ( -7583 3354 8192 ) ( -7583 3354 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 3191 7547 8192 ) ( -3531 -7393 8192 ) ( -3531 -7393 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -7594 3315 8192 ) ( 8236 -906 8192 ) ( 8236 -906 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -3517 -7400 8192 ) ( 3206 7540 8192 ) ( 3206 7540 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( -8192 1131 8192 ) ( 8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 768 8159 8192 ) ( -253 -8192 8192 ) ( -253 -8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8249 667 8192 ) ( -8102 1689 8192 ) ( -8102 1689 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -255 -8192 8192 ) ( 782 8158 8192 ) ( 782 8158 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 330 8192 8192 ) ( 330 -8192 8192 ) ( 330 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1083 8192 ) ( 8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1131 8192 ) ( -8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 8192 1083 8192 ) ( -8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -115 8200 8192 ) ( 906 -8151 8192 ) ( 906 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8240 516 8192 ) ( 8111 1538 8192 ) ( 8111 1538 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 921 -8149 8192 ) ( -116 8201 8192 ) ( -116 8201 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8248 -60 8192 ) ( 8009 1972 8192 ) ( 8009 1972 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -560 8185 8192 ) ( 1471 -8071 8192 ) ( 1471 -8071 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8111 1538 8192 ) ( -8240 516 8192 ) ( -8240 516 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1495 -8067 8192 ) ( -568 8185 8192 ) ( -568 8185 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2563 -7803 8192 ) ( -1410 8091 8192 ) ( -1410 8091 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -5807 5861 8192 ) ( 7029 -4319 8192 ) ( 7029 -4319 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 6637 4844 8192 ) ( -7315 -3742 8192 ) ( -7315 -3742 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8134 -1287 8192 ) ( 7695 2933 8192 ) ( 7695 2933 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -2703 7766 8192 ) ( 4020 -7174 8192 ) ( 4020 -7174 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 7685 2973 8192 ) ( -8145 -1248 8192 ) ( -8145 -1248 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 4034 -7167 8192 ) ( -2688 7773 8192 ) ( -2688 7773 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 66 +{ +"classname" "light" +"light" "10000" +"origin" "-1392 -240 -984" +} +// entity 67 +{ +"light" "10000" +"classname" "light" +"origin" "-1416 -744 -928" +} +// entity 68 +{ +"classname" "item_health_large" +"origin" "576 1120 -320" +} +// entity 69 +{ +"origin" "576 1088 -320" +"classname" "item_health_large" +} +// entity 70 +{ +"classname" "item_health_large" +"origin" "576 1056 -320" +} +// entity 71 +{ +"classname" "info_player_deathmatch" +"origin" "878 -360 728" +} +// entity 72 +{ +"origin" "1974 1288 130" +"classname" "info_player_deathmatch" +} +// entity 73 +{ +"origin" "160 -296 232" +"classname" "info_player_deathmatch" +} +// entity 74 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -160 912 -380 0 0 ) ( -160 944 -380 0 0.750000 ) ( -160 976 -380 0 1.500000 ) ) +( ( -128 912 -380 0.500000 0 ) ( -128 944 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 912 -380 0.500000 0 ) ( -128 944 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 912 -444 1.500000 0 ) ( -128 944 -444 1.500000 0.750000 ) ( -128 976 -444 1.500000 1.500000 ) ) +( ( -192 912 -444 2.500000 0 ) ( -192 944 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 912 -444 2.500000 0 ) ( -192 944 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 912 -380 3.500000 0 ) ( -192 944 -380 3.500000 0.750000 ) ( -192 976 -380 3.500000 1.500000 ) ) +( ( -160 912 -380 4 0 ) ( -160 944 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +( ( -160 912 -380 4 0 ) ( -160 944 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 912 -380 -11.875000 5 ) ( -160 912 -380 -11.375000 5 ) ( -160 912 -380 -11.375000 5 ) ) +( ( -192 912 -444 -11.875000 6 ) ( -160 912 -412 -11.375000 5.500000 ) ( -128 912 -380 -10.875000 5 ) ) +( ( -192 912 -444 -11.875000 6 ) ( -128 912 -444 -10.875000 6 ) ( -128 912 -380 -10.875000 5 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -160 976 -380 -11.375000 5 ) ( -160 976 -380 -11.375000 5 ) ( -192 976 -380 -11.875000 5 ) ) +( ( -128 976 -380 -10.875000 5 ) ( -160 976 -412 -11.375000 5.500000 ) ( -192 976 -444 -11.875000 6 ) ) +( ( -128 976 -380 -10.875000 5 ) ( -128 976 -444 -10.875000 6 ) ( -192 976 -444 -11.875000 6 ) ) +) + } + } +} +// entity 75 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -720 912 -412 0 0 ) ( -720 944 -412 0 0.750000 ) ( -720 976 -412 0 1.500000 ) ) +( ( -720 912 -444 0.500000 0 ) ( -720 944 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -720 912 -444 0.500000 0 ) ( -720 944 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -784 912 -444 1.500000 0 ) ( -784 944 -444 1.500000 0.750000 ) ( -784 976 -444 1.500000 1.500000 ) ) +( ( -784 912 -380 2.500000 0 ) ( -784 944 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -784 912 -380 2.500000 0 ) ( -784 944 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -720 912 -380 3.500000 0 ) ( -720 944 -380 3.500000 0.750000 ) ( -720 976 -380 3.500000 1.500000 ) ) +( ( -720 912 -412 4 0 ) ( -720 944 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +( ( -720 912 -412 4 0 ) ( -720 944 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -720 912 -380 -20.125000 5 ) ( -720 912 -412 -20.125000 5.500000 ) ( -720 912 -412 -20.125000 5.500000 ) ) +( ( -784 912 -380 -21.125000 5 ) ( -752 912 -412 -20.625000 5.500000 ) ( -720 912 -444 -20.125000 6 ) ) +( ( -784 912 -380 -21.125000 5 ) ( -784 912 -444 -21.125000 6 ) ( -720 912 -444 -20.125000 6 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -720 976 -412 -20.125000 5.500000 ) ( -720 976 -412 -20.125000 5.500000 ) ( -720 976 -380 -20.125000 5 ) ) +( ( -720 976 -444 -20.125000 6 ) ( -752 976 -412 -20.625000 5.500000 ) ( -784 976 -380 -21.125000 5 ) ) +( ( -720 976 -444 -20.125000 6 ) ( -784 976 -444 -21.125000 6 ) ( -784 976 -380 -21.125000 5 ) ) +) + } + } +} +// entity 76 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -700 912 -251.999908 0 0 ) ( -700 944 -251.999908 0 0.750000 ) ( -700 976 -251.999908 0 1.500000 ) ) +( ( -784 912 -251.999908 0.500000 0 ) ( -784 944 -251.999908 0.500000 0.750000 ) ( -784 976 -251.999908 0.500000 1.500000 ) ) +( ( -784 912 -251.999908 0.500000 0 ) ( -784 944 -251.999908 0.500000 0.750000 ) ( -784 976 -251.999908 0.500000 1.500000 ) ) +( ( -784 912 222.000031 1.500000 0 ) ( -784 944 222.000031 1.500000 0.750000 ) ( -784 976 222.000031 1.500000 1.500000 ) ) +( ( -616 912 222.000031 2.500000 0 ) ( -616 944 222.000031 2.500000 0.750000 ) ( -616 976 222.000031 2.500000 1.500000 ) ) +( ( -616 912 222.000031 2.500000 0 ) ( -616 944 222.000031 2.500000 0.750000 ) ( -616 976 222.000031 2.500000 1.500000 ) ) +( ( -616 912 -251.999908 3.500000 0 ) ( -616 944 -251.999908 3.500000 0.750000 ) ( -616 976 -251.999908 3.500000 1.500000 ) ) +( ( -700 912 -251.999908 4 0 ) ( -700 944 -251.999908 4 0.750000 ) ( -700 976 -251.999908 4 1.500000 ) ) +( ( -700 912 -251.999908 4 0 ) ( -700 944 -251.999908 4 0.750000 ) ( -700 976 -251.999908 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -616 912 -251.999908 -18.500000 1.749999 ) ( -700 912 -251.999908 -19.812500 1.749999 ) ( -700 912 -251.999908 -19.812500 1.749999 ) ) +( ( -616 912 222.000031 -18.500000 -3.375000 ) ( -700 912 -16.445034 -19.812500 -0.796876 ) ( -784 912 -251.999908 -21.125000 1.749999 ) ) +( ( -616 912 222.000031 -18.500000 -3.375000 ) ( -784 912 222.000031 -21.125000 -3.375000 ) ( -784 912 -251.999908 -21.125000 1.749999 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -700 976 -251.999908 -19.812500 1.749999 ) ( -700 976 -251.999908 -19.812500 1.749999 ) ( -616 976 -251.999908 -18.500000 1.749999 ) ) +( ( -784 976 -251.999908 -21.125000 1.749999 ) ( -700 976 -16.445034 -19.812500 -0.796876 ) ( -616 976 222.000031 -18.500000 -3.375000 ) ) +( ( -784 976 -251.999908 -21.125000 1.749999 ) ( -784 976 222.000031 -21.125000 -3.375000 ) ( -616 976 222.000031 -18.500000 -3.375000 ) ) +) + } + } +} +// entity 77 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -700 880 -251.999939 0 0 ) ( -700 896 -251.999939 0 0.750000 ) ( -700 912 -251.999939 0 1.500000 ) ) +( ( -784 880 -251.999939 0.500000 0 ) ( -784 896 -251.999939 0.500000 0.750000 ) ( -784 912 -251.999939 0.500000 1.500000 ) ) +( ( -784 880 -251.999939 0.500000 0 ) ( -784 896 -251.999939 0.500000 0.750000 ) ( -784 912 -251.999939 0.500000 1.500000 ) ) +( ( -784 880 222.000061 1.500000 0 ) ( -784 896 222.000061 1.500000 0.750000 ) ( -784 912 222.000061 1.500000 1.500000 ) ) +( ( -616 880 222.000061 2.500000 0 ) ( -616 896 222.000061 2.500000 0.750000 ) ( -616 912 222.000061 2.500000 1.500000 ) ) +( ( -616 880 222.000061 2.500000 0 ) ( -616 896 222.000061 2.500000 0.750000 ) ( -616 912 222.000061 2.500000 1.500000 ) ) +( ( -616 880 -251.999939 3.500000 0 ) ( -616 896 -251.999939 3.500000 0.750000 ) ( -616 912 -251.999939 3.500000 1.500000 ) ) +( ( -700 880 -251.999939 4 0 ) ( -700 896 -251.999939 4 0.750000 ) ( -700 912 -251.999939 4 1.500000 ) ) +( ( -700 880 -251.999939 4 0 ) ( -700 896 -251.999939 4 0.750000 ) ( -700 912 -251.999939 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -616 880 -251.999939 -18.500000 1.749999 ) ( -700 880 -251.999939 -19.812500 1.749999 ) ( -700 880 -251.999939 -19.812500 1.749999 ) ) +( ( -616 880 222.000061 -18.500000 -3.375000 ) ( -700 880 -16.445053 -19.812500 -0.796876 ) ( -784 880 -251.999939 -21.125000 1.749999 ) ) +( ( -616 880 222.000061 -18.500000 -3.375000 ) ( -784 880 222.000061 -21.125000 -3.375000 ) ( -784 880 -251.999939 -21.125000 1.749999 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -700 912 -251.999939 -19.812500 1.749999 ) ( -700 912 -251.999939 -19.812500 1.749999 ) ( -616 912 -251.999939 -18.500000 1.749999 ) ) +( ( -784 912 -251.999939 -21.125000 1.749999 ) ( -700 912 -16.445053 -19.812500 -0.796876 ) ( -616 912 222.000061 -18.500000 -3.375000 ) ) +( ( -784 912 -251.999939 -21.125000 1.749999 ) ( -784 912 222.000061 -21.125000 -3.375000 ) ( -616 912 222.000061 -18.500000 -3.375000 ) ) +) + } + } +} +// entity 78 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -464 652 -660 0 0 ) ( -464 652 -608 0 0.781250 ) ( -464 652 -556 0 1.562500 ) ) +( ( -464 640 -660 0.218750 0 ) ( -464 640 -608 0.218750 0.781250 ) ( -464 640 -556 0.218750 1.562500 ) ) +( ( -448 640 -660 0.468750 0 ) ( -448 640 -608 0.468750 0.781250 ) ( -448 640 -556 0.468750 1.562500 ) ) +( ( -432 640 -660 0.718750 0 ) ( -432 640 -608 0.718750 0.781250 ) ( -432 640 -556 0.718750 1.562500 ) ) +( ( -432 652 -660 0.937500 0 ) ( -432 652 -608 0.937500 0.781250 ) ( -432 652 -556 0.937500 1.562500 ) ) +( ( -432 664 -660 1.156250 0 ) ( -432 664 -608 1.156250 0.781250 ) ( -432 664 -556 1.156250 1.562500 ) ) +( ( -448 664 -660 1.406250 0 ) ( -448 664 -608 1.406250 0.781250 ) ( -448 664 -556 1.406250 1.562500 ) ) +( ( -464 664 -660 1.656250 0 ) ( -464 664 -608 1.656250 0.781250 ) ( -464 664 -556 1.656250 1.562500 ) ) +( ( -464 652 -660 1.875000 0 ) ( -464 652 -608 1.875000 0.781250 ) ( -464 652 -556 1.875000 1.562500 ) ) +) + } + } +} +// entity 79 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -472 652 -828 0 0 ) ( -472 652 -744 0 0.781250 ) ( -472 652 -660 0 1.562500 ) ) +( ( -472 628 -828 0.218750 0 ) ( -472 628 -744 0.218750 0.781250 ) ( -472 628 -660 0.218750 1.562500 ) ) +( ( -448 628 -828 0.468750 0 ) ( -448 628 -744 0.468750 0.781250 ) ( -448 628 -660 0.468750 1.562500 ) ) +( ( -424 628 -828 0.718750 0 ) ( -424 628 -744 0.718750 0.781250 ) ( -424 628 -660 0.718750 1.562500 ) ) +( ( -424 652 -828 0.937500 0 ) ( -424 652 -744 0.937500 0.781250 ) ( -424 652 -660 0.937500 1.562500 ) ) +( ( -424 676 -828 1.156250 0 ) ( -424 676 -744 1.156250 0.781250 ) ( -424 676 -660 1.156250 1.562500 ) ) +( ( -448 676 -828 1.406250 0 ) ( -448 676 -744 1.406250 0.781250 ) ( -448 676 -660 1.406250 1.562500 ) ) +( ( -472 676 -828 1.656250 0 ) ( -472 676 -744 1.656250 0.781250 ) ( -472 676 -660 1.656250 1.562500 ) ) +( ( -472 652 -828 1.875000 0 ) ( -472 652 -744 1.875000 0.781250 ) ( -472 652 -660 1.875000 1.562500 ) ) +) + } + } +} +// entity 80 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -484 652 -1120 0 0 ) ( -484 652 -974 0 0.781250 ) ( -484 652 -828 0 1.562500 ) ) +( ( -484 616 -1120 0.218750 0 ) ( -484 616 -974 0.218750 0.781250 ) ( -484 616 -828 0.218750 1.562500 ) ) +( ( -448 616 -1120 0.468750 0 ) ( -448 616 -974 0.468750 0.781250 ) ( -448 616 -828 0.468750 1.562500 ) ) +( ( -412 616 -1120 0.718750 0 ) ( -412 616 -974 0.718750 0.781250 ) ( -412 616 -828 0.718750 1.562500 ) ) +( ( -412 652 -1120 0.937500 0 ) ( -412 652 -974 0.937500 0.781250 ) ( -412 652 -828 0.937500 1.562500 ) ) +( ( -412 688 -1120 1.156250 0 ) ( -412 688 -974 1.156250 0.781250 ) ( -412 688 -828 1.156250 1.562500 ) ) +( ( -448 688 -1120 1.406250 0 ) ( -448 688 -974 1.406250 0.781250 ) ( -448 688 -828 1.406250 1.562500 ) ) +( ( -484 688 -1120 1.656250 0 ) ( -484 688 -974 1.656250 0.781250 ) ( -484 688 -828 1.656250 1.562500 ) ) +( ( -484 652 -1120 1.875000 0 ) ( -484 652 -974 1.875000 0.781250 ) ( -484 652 -828 1.875000 1.562500 ) ) +) + } + } +} +// entity 81 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -452 996 -1208 0 0 ) ( -460 996 -1208 0 0.062500 ) ( -468 996 -1208 0 0.125000 ) ) +( ( -452 968 -1208 0.218750 0 ) ( -460 968 -1208 0.218750 0.062500 ) ( -468 968 -1208 0.218750 0.125000 ) ) +( ( -452 968 -1180 0.437500 0 ) ( -460 968 -1180 0.437500 0.062500 ) ( -468 968 -1180 0.437500 0.125000 ) ) +( ( -452 968 -1152 0.656250 0 ) ( -460 968 -1152 0.656250 0.062500 ) ( -468 968 -1152 0.656250 0.125000 ) ) +( ( -452 996 -1152 0.875000 0 ) ( -460 996 -1152 0.875000 0.062500 ) ( -468 996 -1152 0.875000 0.125000 ) ) +( ( -452 1024 -1152 1.093750 0 ) ( -460 1024 -1152 1.093750 0.062500 ) ( -468 1024 -1152 1.093750 0.125000 ) ) +( ( -452 1024 -1180 1.312500 0 ) ( -460 1024 -1180 1.312500 0.062500 ) ( -468 1024 -1180 1.312500 0.125000 ) ) +( ( -452 1024 -1208 1.531250 0 ) ( -460 1024 -1208 1.531250 0.062500 ) ( -468 1024 -1208 1.531250 0.125000 ) ) +( ( -452 996 -1208 1.750000 0 ) ( -460 996 -1208 1.750000 0.062500 ) ( -468 996 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -452 1024 -1180 -8.031250 -18 ) ( -452 1024 -1208 -8.250000 -18 ) ( -452 996 -1208 -8.250000 -17.781250 ) ) +( ( -452 1024 -1152 -7.812500 -18 ) ( -452 996 -1180 -8.031250 -17.781250 ) ( -452 968 -1208 -8.250000 -17.562500 ) ) +( ( -452 996 -1152 -7.812500 -17.781250 ) ( -452 968 -1152 -7.812500 -17.562500 ) ( -452 968 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -468 996 -1208 -8.250000 -17.781250 ) ( -468 1024 -1208 -8.250000 -18 ) ( -468 1024 -1180 -8.031250 -18 ) ) +( ( -468 968 -1208 -8.250000 -17.562500 ) ( -468 996 -1180 -8.031250 -17.781250 ) ( -468 1024 -1152 -7.812500 -18 ) ) +( ( -468 968 -1180 -8.031250 -17.562500 ) ( -468 968 -1152 -7.812500 -17.562500 ) ( -468 996 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 82 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -428 996 -1208 0 0 ) ( -436 996 -1208 0 0.062500 ) ( -444 996 -1208 0 0.125000 ) ) +( ( -428 968 -1208 0.218750 0 ) ( -436 968 -1208 0.218750 0.062500 ) ( -444 968 -1208 0.218750 0.125000 ) ) +( ( -428 968 -1180 0.437500 0 ) ( -436 968 -1180 0.437500 0.062500 ) ( -444 968 -1180 0.437500 0.125000 ) ) +( ( -428 968 -1152 0.656250 0 ) ( -436 968 -1152 0.656250 0.062500 ) ( -444 968 -1152 0.656250 0.125000 ) ) +( ( -428 996 -1152 0.875000 0 ) ( -436 996 -1152 0.875000 0.062500 ) ( -444 996 -1152 0.875000 0.125000 ) ) +( ( -428 1024 -1152 1.093750 0 ) ( -436 1024 -1152 1.093750 0.062500 ) ( -444 1024 -1152 1.093750 0.125000 ) ) +( ( -428 1024 -1180 1.312500 0 ) ( -436 1024 -1180 1.312500 0.062500 ) ( -444 1024 -1180 1.312500 0.125000 ) ) +( ( -428 1024 -1208 1.531250 0 ) ( -436 1024 -1208 1.531250 0.062500 ) ( -444 1024 -1208 1.531250 0.125000 ) ) +( ( -428 996 -1208 1.750000 0 ) ( -436 996 -1208 1.750000 0.062500 ) ( -444 996 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -428 1024 -1180 -8.031250 -18 ) ( -428 1024 -1208 -8.250000 -18 ) ( -428 996 -1208 -8.250000 -17.781250 ) ) +( ( -428 1024 -1152 -7.812500 -18 ) ( -428 996 -1180 -8.031250 -17.781250 ) ( -428 968 -1208 -8.250000 -17.562500 ) ) +( ( -428 996 -1152 -7.812500 -17.781250 ) ( -428 968 -1152 -7.812500 -17.562500 ) ( -428 968 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -444 996 -1208 -8.250000 -17.781250 ) ( -444 1024 -1208 -8.250000 -18 ) ( -444 1024 -1180 -8.031250 -18 ) ) +( ( -444 968 -1208 -8.250000 -17.562500 ) ( -444 996 -1180 -8.031250 -17.781250 ) ( -444 1024 -1152 -7.812500 -18 ) ) +( ( -444 968 -1180 -8.031250 -17.562500 ) ( -444 968 -1152 -7.812500 -17.562500 ) ( -444 996 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 83 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -452 304 -1208 0 0 ) ( -460 304 -1208 0 0.062500 ) ( -468 304 -1208 0 0.125000 ) ) +( ( -452 276 -1208 0.218750 0 ) ( -460 276 -1208 0.218750 0.062500 ) ( -468 276 -1208 0.218750 0.125000 ) ) +( ( -452 276 -1180 0.437500 0 ) ( -460 276 -1180 0.437500 0.062500 ) ( -468 276 -1180 0.437500 0.125000 ) ) +( ( -452 276 -1152 0.656250 0 ) ( -460 276 -1152 0.656250 0.062500 ) ( -468 276 -1152 0.656250 0.125000 ) ) +( ( -452 304 -1152 0.875000 0 ) ( -460 304 -1152 0.875000 0.062500 ) ( -468 304 -1152 0.875000 0.125000 ) ) +( ( -452 332 -1152 1.093750 0 ) ( -460 332 -1152 1.093750 0.062500 ) ( -468 332 -1152 1.093750 0.125000 ) ) +( ( -452 332 -1180 1.312500 0 ) ( -460 332 -1180 1.312500 0.062500 ) ( -468 332 -1180 1.312500 0.125000 ) ) +( ( -452 332 -1208 1.531250 0 ) ( -460 332 -1208 1.531250 0.062500 ) ( -468 332 -1208 1.531250 0.125000 ) ) +( ( -452 304 -1208 1.750000 0 ) ( -460 304 -1208 1.750000 0.062500 ) ( -468 304 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -452 332 -1180 -8.031250 -18 ) ( -452 332 -1208 -8.250000 -18 ) ( -452 304 -1208 -8.250000 -17.781250 ) ) +( ( -452 332 -1152 -7.812500 -18 ) ( -452 304 -1180 -8.031250 -17.781250 ) ( -452 276 -1208 -8.250000 -17.562500 ) ) +( ( -452 304 -1152 -7.812500 -17.781250 ) ( -452 276 -1152 -7.812500 -17.562500 ) ( -452 276 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -468 304 -1208 -8.250000 -17.781250 ) ( -468 332 -1208 -8.250000 -18 ) ( -468 332 -1180 -8.031250 -18 ) ) +( ( -468 276 -1208 -8.250000 -17.562500 ) ( -468 304 -1180 -8.031250 -17.781250 ) ( -468 332 -1152 -7.812500 -18 ) ) +( ( -468 276 -1180 -8.031250 -17.562500 ) ( -468 276 -1152 -7.812500 -17.562500 ) ( -468 304 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 84 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -428 304 -1208 0 0 ) ( -436 304 -1208 0 0.062500 ) ( -444 304 -1208 0 0.125000 ) ) +( ( -428 276 -1208 0.218750 0 ) ( -436 276 -1208 0.218750 0.062500 ) ( -444 276 -1208 0.218750 0.125000 ) ) +( ( -428 276 -1180 0.437500 0 ) ( -436 276 -1180 0.437500 0.062500 ) ( -444 276 -1180 0.437500 0.125000 ) ) +( ( -428 276 -1152 0.656250 0 ) ( -436 276 -1152 0.656250 0.062500 ) ( -444 276 -1152 0.656250 0.125000 ) ) +( ( -428 304 -1152 0.875000 0 ) ( -436 304 -1152 0.875000 0.062500 ) ( -444 304 -1152 0.875000 0.125000 ) ) +( ( -428 332 -1152 1.093750 0 ) ( -436 332 -1152 1.093750 0.062500 ) ( -444 332 -1152 1.093750 0.125000 ) ) +( ( -428 332 -1180 1.312500 0 ) ( -436 332 -1180 1.312500 0.062500 ) ( -444 332 -1180 1.312500 0.125000 ) ) +( ( -428 332 -1208 1.531250 0 ) ( -436 332 -1208 1.531250 0.062500 ) ( -444 332 -1208 1.531250 0.125000 ) ) +( ( -428 304 -1208 1.750000 0 ) ( -436 304 -1208 1.750000 0.062500 ) ( -444 304 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -428 332 -1180 -8.031250 -18 ) ( -428 332 -1208 -8.250000 -18 ) ( -428 304 -1208 -8.250000 -17.781250 ) ) +( ( -428 332 -1152 -7.812500 -18 ) ( -428 304 -1180 -8.031250 -17.781250 ) ( -428 276 -1208 -8.250000 -17.562500 ) ) +( ( -428 304 -1152 -7.812500 -17.781250 ) ( -428 276 -1152 -7.812500 -17.562500 ) ( -428 276 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -444 304 -1208 -8.250000 -17.781250 ) ( -444 332 -1208 -8.250000 -18 ) ( -444 332 -1180 -8.031250 -18 ) ) +( ( -444 276 -1208 -8.250000 -17.562500 ) ( -444 304 -1180 -8.031250 -17.781250 ) ( -444 332 -1152 -7.812500 -18 ) ) +( ( -444 276 -1180 -8.031250 -17.562500 ) ( -444 276 -1152 -7.812500 -17.562500 ) ( -444 304 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 85 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -752 848 -492 0 0 ) ( -752 848 -524 0 0.750000 ) ( -752 848 -556 0 1.500000 ) ) +( ( -784 848 -492 0.500000 0 ) ( -784 848 -524 0.500000 0.750000 ) ( -784 848 -556 0.500000 1.500000 ) ) +( ( -784 848 -492 0.500000 0 ) ( -784 848 -524 0.500000 0.750000 ) ( -784 848 -556 0.500000 1.500000 ) ) +( ( -784 912 -492 1.500000 0 ) ( -784 912 -524 1.500000 0.750000 ) ( -784 912 -556 1.500000 1.500000 ) ) +( ( -720 912 -492 2.500000 0 ) ( -720 912 -524 2.500000 0.750000 ) ( -720 912 -556 2.500000 1.500000 ) ) +( ( -720 912 -492 2.500000 0 ) ( -720 912 -524 2.500000 0.750000 ) ( -720 912 -556 2.500000 1.500000 ) ) +( ( -720 848 -492 3.500000 0 ) ( -720 848 -524 3.500000 0.750000 ) ( -720 848 -556 3.500000 1.500000 ) ) +( ( -752 848 -492 4 0 ) ( -752 848 -524 4 0.750000 ) ( -752 848 -556 4 1.500000 ) ) +( ( -752 848 -492 4 0 ) ( -752 848 -524 4 0.750000 ) ( -752 848 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -720 848 -492 -11.875000 -34.250000 ) ( -752 848 -492 -11.875000 -34.750000 ) ( -752 848 -492 -11.875000 -34.750000 ) ) +( ( -720 912 -492 -10.875000 -34.250000 ) ( -752 880 -492 -11.375000 -34.750000 ) ( -784 848 -492 -11.875000 -35.250000 ) ) +( ( -720 912 -492 -10.875000 -34.250000 ) ( -784 912 -492 -10.875000 -35.250000 ) ( -784 848 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -752 848 -556 -11.875000 -34.750000 ) ( -752 848 -556 -11.875000 -34.750000 ) ( -720 848 -556 -11.875000 -34.250000 ) ) +( ( -784 848 -556 -11.875000 -35.250000 ) ( -752 880 -556 -11.375000 -34.750000 ) ( -720 912 -556 -10.875000 -34.250000 ) ) +( ( -784 848 -556 -11.875000 -35.250000 ) ( -784 912 -556 -10.875000 -35.250000 ) ( -720 912 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 86 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -752 848 -460 0 0 ) ( -752 848 -476 0 0.750000 ) ( -752 848 -492 0 1.500000 ) ) +( ( -784 848 -460 0.500000 0 ) ( -784 848 -476 0.500000 0.750000 ) ( -784 848 -492 0.500000 1.500000 ) ) +( ( -784 848 -460 0.500000 0 ) ( -784 848 -476 0.500000 0.750000 ) ( -784 848 -492 0.500000 1.500000 ) ) +( ( -784 912 -460 1.500000 0 ) ( -784 912 -476 1.500000 0.750000 ) ( -784 912 -492 1.500000 1.500000 ) ) +( ( -720 912 -460 2.500000 0 ) ( -720 912 -476 2.500000 0.750000 ) ( -720 912 -492 2.500000 1.500000 ) ) +( ( -720 912 -460 2.500000 0 ) ( -720 912 -476 2.500000 0.750000 ) ( -720 912 -492 2.500000 1.500000 ) ) +( ( -720 848 -460 3.500000 0 ) ( -720 848 -476 3.500000 0.750000 ) ( -720 848 -492 3.500000 1.500000 ) ) +( ( -752 848 -460 4 0 ) ( -752 848 -476 4 0.750000 ) ( -752 848 -492 4 1.500000 ) ) +( ( -752 848 -460 4 0 ) ( -752 848 -476 4 0.750000 ) ( -752 848 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -720 848 -460 -11.875000 -34.250000 ) ( -752 848 -460 -11.875000 -34.750000 ) ( -752 848 -460 -11.875000 -34.750000 ) ) +( ( -720 912 -460 -10.875000 -34.250000 ) ( -752 880 -460 -11.375000 -34.750000 ) ( -784 848 -460 -11.875000 -35.250000 ) ) +( ( -720 912 -460 -10.875000 -34.250000 ) ( -784 912 -460 -10.875000 -35.250000 ) ( -784 848 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -752 848 -492 -11.875000 -34.750000 ) ( -752 848 -492 -11.875000 -34.750000 ) ( -720 848 -492 -11.875000 -34.250000 ) ) +( ( -784 848 -492 -11.875000 -35.250000 ) ( -752 880 -492 -11.375000 -34.750000 ) ( -720 912 -492 -10.875000 -34.250000 ) ) +( ( -784 848 -492 -11.875000 -35.250000 ) ( -784 912 -492 -10.875000 -35.250000 ) ( -720 912 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 87 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -192 880 -460 0 0 ) ( -192 880 -476 0 0.750000 ) ( -192 880 -492 0 1.500000 ) ) +( ( -192 912 -460 0.500000 0 ) ( -192 912 -476 0.500000 0.750000 ) ( -192 912 -492 0.500000 1.500000 ) ) +( ( -192 912 -460 0.500000 0 ) ( -192 912 -476 0.500000 0.750000 ) ( -192 912 -492 0.500000 1.500000 ) ) +( ( -128 912 -460 1.500000 0 ) ( -128 912 -476 1.500000 0.750000 ) ( -128 912 -492 1.500000 1.500000 ) ) +( ( -128 848 -460 2.500000 0 ) ( -128 848 -476 2.500000 0.750000 ) ( -128 848 -492 2.500000 1.500000 ) ) +( ( -128 848 -460 2.500000 0 ) ( -128 848 -476 2.500000 0.750000 ) ( -128 848 -492 2.500000 1.500000 ) ) +( ( -192 848 -460 3.500000 0 ) ( -192 848 -476 3.500000 0.750000 ) ( -192 848 -492 3.500000 1.500000 ) ) +( ( -192 880 -460 4 0 ) ( -192 880 -476 4 0.750000 ) ( -192 880 -492 4 1.500000 ) ) +( ( -192 880 -460 4 0 ) ( -192 880 -476 4 0.750000 ) ( -192 880 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 848 -460 -11.875000 -34.250000 ) ( -192 880 -460 -11.875000 -34.750000 ) ( -192 880 -460 -11.875000 -34.750000 ) ) +( ( -128 848 -460 -10.875000 -34.250000 ) ( -160 880 -460 -11.375000 -34.750000 ) ( -192 912 -460 -11.875000 -35.250000 ) ) +( ( -128 848 -460 -10.875000 -34.250000 ) ( -128 912 -460 -10.875000 -35.250000 ) ( -192 912 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 880 -492 -11.875000 -34.750000 ) ( -192 880 -492 -11.875000 -34.750000 ) ( -192 848 -492 -11.875000 -34.250000 ) ) +( ( -192 912 -492 -11.875000 -35.250000 ) ( -160 880 -492 -11.375000 -34.750000 ) ( -128 848 -492 -10.875000 -34.250000 ) ) +( ( -192 912 -492 -11.875000 -35.250000 ) ( -128 912 -492 -10.875000 -35.250000 ) ( -128 848 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 88 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -160 456 -460 0 0 ) ( -160 456 -476 0 0.750000 ) ( -160 456 -492 0 1.500000 ) ) +( ( -128 456 -460 0.500000 0 ) ( -128 456 -476 0.500000 0.750000 ) ( -128 456 -492 0.500000 1.500000 ) ) +( ( -128 456 -460 0.500000 0 ) ( -128 456 -476 0.500000 0.750000 ) ( -128 456 -492 0.500000 1.500000 ) ) +( ( -128 392 -460 1.500000 0 ) ( -128 392 -476 1.500000 0.750000 ) ( -128 392 -492 1.500000 1.500000 ) ) +( ( -192 392 -460 2.500000 0 ) ( -192 392 -476 2.500000 0.750000 ) ( -192 392 -492 2.500000 1.500000 ) ) +( ( -192 392 -460 2.500000 0 ) ( -192 392 -476 2.500000 0.750000 ) ( -192 392 -492 2.500000 1.500000 ) ) +( ( -192 456 -460 3.500000 0 ) ( -192 456 -476 3.500000 0.750000 ) ( -192 456 -492 3.500000 1.500000 ) ) +( ( -160 456 -460 4 0 ) ( -160 456 -476 4 0.750000 ) ( -160 456 -492 4 1.500000 ) ) +( ( -160 456 -460 4 0 ) ( -160 456 -476 4 0.750000 ) ( -160 456 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 456 -460 -11.875000 -34.250000 ) ( -160 456 -460 -11.875000 -34.750000 ) ( -160 456 -460 -11.875000 -34.750000 ) ) +( ( -192 392 -460 -10.875000 -34.250000 ) ( -160 424 -460 -11.375000 -34.750000 ) ( -128 456 -460 -11.875000 -35.250000 ) ) +( ( -192 392 -460 -10.875000 -34.250000 ) ( -128 392 -460 -10.875000 -35.250000 ) ( -128 456 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -160 456 -492 -11.875000 -34.750000 ) ( -160 456 -492 -11.875000 -34.750000 ) ( -192 456 -492 -11.875000 -34.250000 ) ) +( ( -128 456 -492 -11.875000 -35.250000 ) ( -160 424 -492 -11.375000 -34.750000 ) ( -192 392 -492 -10.875000 -34.250000 ) ) +( ( -128 456 -492 -11.875000 -35.250000 ) ( -128 392 -492 -10.875000 -35.250000 ) ( -192 392 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 89 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -712 424 -460 0 0 ) ( -712 424 -476 0 0.750000 ) ( -712 424 -492 0 1.500000 ) ) +( ( -712 392 -460 0.500000 0 ) ( -712 392 -476 0.500000 0.750000 ) ( -712 392 -492 0.500000 1.500000 ) ) +( ( -712 392 -460 0.500000 0 ) ( -712 392 -476 0.500000 0.750000 ) ( -712 392 -492 0.500000 1.500000 ) ) +( ( -784 392 -460 1.500000 0 ) ( -784 392 -476 1.500000 0.750000 ) ( -784 392 -492 1.500000 1.500000 ) ) +( ( -784 456 -460 2.500000 0 ) ( -784 456 -476 2.500000 0.750000 ) ( -784 456 -492 2.500000 1.500000 ) ) +( ( -784 456 -460 2.500000 0 ) ( -784 456 -476 2.500000 0.750000 ) ( -784 456 -492 2.500000 1.500000 ) ) +( ( -712 456 -460 3.500000 0 ) ( -712 456 -476 3.500000 0.750000 ) ( -712 456 -492 3.500000 1.500000 ) ) +( ( -712 424 -460 4 0 ) ( -712 424 -476 4 0.750000 ) ( -712 424 -492 4 1.500000 ) ) +( ( -712 424 -460 4 0 ) ( -712 424 -476 4 0.750000 ) ( -712 424 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -712 456 -460 -11.875000 -34.250000 ) ( -712 424 -460 -11.875000 -34.750000 ) ( -712 424 -460 -11.875000 -34.750000 ) ) +( ( -784 456 -460 -10.875000 -34.250000 ) ( -748 424 -460 -11.375000 -34.750000 ) ( -712 392 -460 -11.875000 -35.250000 ) ) +( ( -784 456 -460 -10.875000 -34.250000 ) ( -784 392 -460 -10.875000 -35.250000 ) ( -712 392 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -712 424 -492 -11.875000 -34.750000 ) ( -712 424 -492 -11.875000 -34.750000 ) ( -712 456 -492 -11.875000 -34.250000 ) ) +( ( -712 392 -492 -11.875000 -35.250000 ) ( -748 424 -492 -11.375000 -34.750000 ) ( -784 456 -492 -10.875000 -34.250000 ) ) +( ( -712 392 -492 -11.875000 -35.250000 ) ( -784 392 -492 -10.875000 -35.250000 ) ( -784 456 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 90 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -192 880 -492 0 0 ) ( -192 880 -524 0 0.750000 ) ( -192 880 -556 0 1.500000 ) ) +( ( -192 912 -492 0.500000 0 ) ( -192 912 -524 0.500000 0.750000 ) ( -192 912 -556 0.500000 1.500000 ) ) +( ( -192 912 -492 0.500000 0 ) ( -192 912 -524 0.500000 0.750000 ) ( -192 912 -556 0.500000 1.500000 ) ) +( ( -128 912 -492 1.500000 0 ) ( -128 912 -524 1.500000 0.750000 ) ( -128 912 -556 1.500000 1.500000 ) ) +( ( -128 848 -492 2.500000 0 ) ( -128 848 -524 2.500000 0.750000 ) ( -128 848 -556 2.500000 1.500000 ) ) +( ( -128 848 -492 2.500000 0 ) ( -128 848 -524 2.500000 0.750000 ) ( -128 848 -556 2.500000 1.500000 ) ) +( ( -192 848 -492 3.500000 0 ) ( -192 848 -524 3.500000 0.750000 ) ( -192 848 -556 3.500000 1.500000 ) ) +( ( -192 880 -492 4 0 ) ( -192 880 -524 4 0.750000 ) ( -192 880 -556 4 1.500000 ) ) +( ( -192 880 -492 4 0 ) ( -192 880 -524 4 0.750000 ) ( -192 880 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 848 -492 -11.875000 -34.250000 ) ( -192 880 -492 -11.875000 -34.750000 ) ( -192 880 -492 -11.875000 -34.750000 ) ) +( ( -128 848 -492 -10.875000 -34.250000 ) ( -160 880 -492 -11.375000 -34.750000 ) ( -192 912 -492 -11.875000 -35.250000 ) ) +( ( -128 848 -492 -10.875000 -34.250000 ) ( -128 912 -492 -10.875000 -35.250000 ) ( -192 912 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 880 -556 -11.875000 -34.750000 ) ( -192 880 -556 -11.875000 -34.750000 ) ( -192 848 -556 -11.875000 -34.250000 ) ) +( ( -192 912 -556 -11.875000 -35.250000 ) ( -160 880 -556 -11.375000 -34.750000 ) ( -128 848 -556 -10.875000 -34.250000 ) ) +( ( -192 912 -556 -11.875000 -35.250000 ) ( -128 912 -556 -10.875000 -35.250000 ) ( -128 848 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 91 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -160 456 -492 0 0 ) ( -160 456 -524 0 0.750000 ) ( -160 456 -556 0 1.500000 ) ) +( ( -128 456 -492 0.500000 0 ) ( -128 456 -524 0.500000 0.750000 ) ( -128 456 -556 0.500000 1.500000 ) ) +( ( -128 456 -492 0.500000 0 ) ( -128 456 -524 0.500000 0.750000 ) ( -128 456 -556 0.500000 1.500000 ) ) +( ( -128 392 -492 1.500000 0 ) ( -128 392 -524 1.500000 0.750000 ) ( -128 392 -556 1.500000 1.500000 ) ) +( ( -192 392 -492 2.500000 0 ) ( -192 392 -524 2.500000 0.750000 ) ( -192 392 -556 2.500000 1.500000 ) ) +( ( -192 392 -492 2.500000 0 ) ( -192 392 -524 2.500000 0.750000 ) ( -192 392 -556 2.500000 1.500000 ) ) +( ( -192 456 -492 3.500000 0 ) ( -192 456 -524 3.500000 0.750000 ) ( -192 456 -556 3.500000 1.500000 ) ) +( ( -160 456 -492 4 0 ) ( -160 456 -524 4 0.750000 ) ( -160 456 -556 4 1.500000 ) ) +( ( -160 456 -492 4 0 ) ( -160 456 -524 4 0.750000 ) ( -160 456 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 456 -492 -11.875000 -34.250000 ) ( -160 456 -492 -11.875000 -34.750000 ) ( -160 456 -492 -11.875000 -34.750000 ) ) +( ( -192 392 -492 -10.875000 -34.250000 ) ( -160 424 -492 -11.375000 -34.750000 ) ( -128 456 -492 -11.875000 -35.250000 ) ) +( ( -192 392 -492 -10.875000 -34.250000 ) ( -128 392 -492 -10.875000 -35.250000 ) ( -128 456 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -160 456 -556 -11.875000 -34.750000 ) ( -160 456 -556 -11.875000 -34.750000 ) ( -192 456 -556 -11.875000 -34.250000 ) ) +( ( -128 456 -556 -11.875000 -35.250000 ) ( -160 424 -556 -11.375000 -34.750000 ) ( -192 392 -556 -10.875000 -34.250000 ) ) +( ( -128 456 -556 -11.875000 -35.250000 ) ( -128 392 -556 -10.875000 -35.250000 ) ( -192 392 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 92 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -712 424 -492 0 0 ) ( -712 424 -524 0 0.750000 ) ( -712 424 -556 0 1.500000 ) ) +( ( -712 392 -492 0.500000 0 ) ( -712 392 -524 0.500000 0.750000 ) ( -712 392 -556 0.500000 1.500000 ) ) +( ( -712 392 -492 0.500000 0 ) ( -712 392 -524 0.500000 0.750000 ) ( -712 392 -556 0.500000 1.500000 ) ) +( ( -784 392 -492 1.500000 0 ) ( -784 392 -524 1.500000 0.750000 ) ( -784 392 -556 1.500000 1.500000 ) ) +( ( -784 456 -492 2.500000 0 ) ( -784 456 -524 2.500000 0.750000 ) ( -784 456 -556 2.500000 1.500000 ) ) +( ( -784 456 -492 2.500000 0 ) ( -784 456 -524 2.500000 0.750000 ) ( -784 456 -556 2.500000 1.500000 ) ) +( ( -712 456 -492 3.500000 0 ) ( -712 456 -524 3.500000 0.750000 ) ( -712 456 -556 3.500000 1.500000 ) ) +( ( -712 424 -492 4 0 ) ( -712 424 -524 4 0.750000 ) ( -712 424 -556 4 1.500000 ) ) +( ( -712 424 -492 4 0 ) ( -712 424 -524 4 0.750000 ) ( -712 424 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -712 456 -492 -11.875000 -34.250000 ) ( -712 424 -492 -11.875000 -34.750000 ) ( -712 424 -492 -11.875000 -34.750000 ) ) +( ( -784 456 -492 -10.875000 -34.250000 ) ( -748 424 -492 -11.375000 -34.750000 ) ( -712 392 -492 -11.875000 -35.250000 ) ) +( ( -784 456 -492 -10.875000 -34.250000 ) ( -784 392 -492 -10.875000 -35.250000 ) ( -712 392 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -712 424 -556 -11.875000 -34.750000 ) ( -712 424 -556 -11.875000 -34.750000 ) ( -712 456 -556 -11.875000 -34.250000 ) ) +( ( -712 392 -556 -11.875000 -35.250000 ) ( -748 424 -556 -11.375000 -34.750000 ) ( -784 456 -556 -10.875000 -34.250000 ) ) +( ( -712 392 -556 -11.875000 -35.250000 ) ( -784 392 -556 -10.875000 -35.250000 ) ( -784 456 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 93 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -212 976 -252 0 1.500000 ) ( -212 944 -252 0 0.750000 ) ( -212 912 -252 0 0 ) ) +( ( -128 976 -252 0.500000 1.500000 ) ( -128 944 -252 0.500000 0.750000 ) ( -128 912 -252 0.500000 0 ) ) +( ( -128 976 -252 0.500000 1.500000 ) ( -128 944 -252 0.500000 0.750000 ) ( -128 912 -252 0.500000 0 ) ) +( ( -128 976 222.000061 1.500000 1.500000 ) ( -128 944 222.000061 1.500000 0.750000 ) ( -128 912 222.000061 1.500000 0 ) ) +( ( -296 976 222.000061 2.500000 1.500000 ) ( -296 944 222.000061 2.500000 0.750000 ) ( -296 912 222.000061 2.500000 0 ) ) +( ( -296 976 222.000061 2.500000 1.500000 ) ( -296 944 222.000061 2.500000 0.750000 ) ( -296 912 222.000061 2.500000 0 ) ) +( ( -296 976 -252 3.500000 1.500000 ) ( -296 944 -252 3.500000 0.750000 ) ( -296 912 -252 3.500000 0 ) ) +( ( -212 976 -252 4 1.500000 ) ( -212 944 -252 4 0.750000 ) ( -212 912 -252 4 0 ) ) +( ( -212 976 -252 4 1.500000 ) ( -212 944 -252 4 0.750000 ) ( -212 912 -252 4 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -212 912 -252 -19.812500 1.749999 ) ( -212 912 -252 -19.812500 1.749999 ) ( -296 912 -252 -18.500000 1.749999 ) ) +( ( -128 912 -252 -21.125000 1.749999 ) ( -212 912 -16.445087 -19.812500 -0.796876 ) ( -296 912 222.000061 -18.500000 -3.375000 ) ) +( ( -128 912 -252 -21.125000 1.749999 ) ( -128 912 222.000061 -21.125000 -3.375000 ) ( -296 912 222.000061 -18.500000 -3.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -296 976 -252 -18.500000 1.749999 ) ( -212 976 -252 -19.812500 1.749999 ) ( -212 976 -252 -19.812500 1.749999 ) ) +( ( -296 976 222.000061 -18.500000 -3.375000 ) ( -212 976 -16.445087 -19.812500 -0.796876 ) ( -128 976 -252 -21.125000 1.749999 ) ) +( ( -296 976 222.000061 -18.500000 -3.375000 ) ( -128 976 222.000061 -21.125000 -3.375000 ) ( -128 976 -252 -21.125000 1.749999 ) ) +) + } + } +} +// entity 94 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -212 912 -252 0 1.500000 ) ( -212 896 -252 0 0.750000 ) ( -212 880 -252 0 0 ) ) +( ( -128 912 -252 0.500000 1.500000 ) ( -128 896 -252 0.500000 0.750000 ) ( -128 880 -252 0.500000 0 ) ) +( ( -128 912 -252 0.500000 1.500000 ) ( -128 896 -252 0.500000 0.750000 ) ( -128 880 -252 0.500000 0 ) ) +( ( -128 912 222.000061 1.500000 1.500000 ) ( -128 896 222.000061 1.500000 0.750000 ) ( -128 880 222.000061 1.500000 0 ) ) +( ( -296 912 222.000061 2.500000 1.500000 ) ( -296 896 222.000061 2.500000 0.750000 ) ( -296 880 222.000061 2.500000 0 ) ) +( ( -296 912 222.000061 2.500000 1.500000 ) ( -296 896 222.000061 2.500000 0.750000 ) ( -296 880 222.000061 2.500000 0 ) ) +( ( -296 912 -252 3.500000 1.500000 ) ( -296 896 -252 3.500000 0.750000 ) ( -296 880 -252 3.500000 0 ) ) +( ( -212 912 -252 4 1.500000 ) ( -212 896 -252 4 0.750000 ) ( -212 880 -252 4 0 ) ) +( ( -212 912 -252 4 1.500000 ) ( -212 896 -252 4 0.750000 ) ( -212 880 -252 4 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -212 880 -252 -19.812500 1.749999 ) ( -212 880 -252 -19.812500 1.749999 ) ( -296 880 -252 -18.500000 1.749999 ) ) +( ( -128 880 -252 -21.125000 1.749999 ) ( -212 880 -16.445107 -19.812500 -0.796876 ) ( -296 880 222.000061 -18.500000 -3.375000 ) ) +( ( -128 880 -252 -21.125000 1.749999 ) ( -128 880 222.000061 -21.125000 -3.375000 ) ( -296 880 222.000061 -18.500000 -3.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -296 912 -252 -18.500000 1.749999 ) ( -212 912 -252 -19.812500 1.749999 ) ( -212 912 -252 -19.812500 1.749999 ) ) +( ( -296 912 222.000061 -18.500000 -3.375000 ) ( -212 912 -16.445107 -19.812500 -0.796876 ) ( -128 912 -252 -21.125000 1.749999 ) ) +( ( -296 912 222.000061 -18.500000 -3.375000 ) ( -128 912 222.000061 -21.125000 -3.375000 ) ( -128 912 -252 -21.125000 1.749999 ) ) +) + } + } +} +// entity 95 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/plastic + ( 5 3 0 0 0 ) +( +( ( 60 -200 -12 0 0.937500 ) ( 60 -208 -12 0 0.468750 ) ( 60 -216 -12 0 0 ) ) +( ( 60 -200 -36 0.500000 0.937500 ) ( 60 -208 -36 0.500000 0.468750 ) ( 60 -216 -36 0.500000 0 ) ) +( ( 156 -200 -36 2 0.937500 ) ( 156 -208 -36 2 0.468750 ) ( 156 -216 -36 2 0 ) ) +( ( 252 -200 -36 3.500000 0.937500 ) ( 252 -208 -36 3.500000 0.468750 ) ( 252 -216 -36 3.500000 0 ) ) +( ( 252 -200 -12 4 0.937500 ) ( 252 -208 -12 4 0.468750 ) ( 252 -216 -12 4 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/plastic + ( 3 3 0 0 0 ) +( +( ( 60 -200 -12 1.875000 0.375000 ) ( 60 -200 -36 1.875000 1.125000 ) ( 156 -200 -36 4.875000 1.125000 ) ) +( ( 156 -200 -12 4.875000 0.375000 ) ( 156 -200 -36 4.875000 1.125000 ) ( 156 -200 -36 4.875000 1.125000 ) ) +( ( 252 -200 -12 7.875000 0.375000 ) ( 252 -200 -36 7.875000 1.125000 ) ( 156 -200 -36 4.875000 1.125000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/plastic + ( 3 3 0 0 0 ) +( +( ( 156 -216 -36 4.875000 1.125000 ) ( 60 -216 -36 1.875000 1.125000 ) ( 60 -216 -12 1.875000 0.375000 ) ) +( ( 156 -216 -36 4.875000 1.125000 ) ( 156 -216 -36 4.875000 1.125000 ) ( 156 -216 -12 4.875000 0.375000 ) ) +( ( 156 -216 -36 4.875000 1.125000 ) ( 252 -216 -36 7.875000 1.125000 ) ( 252 -216 -12 7.875000 0.375000 ) ) +) + } + } +} +// entity 96 +{ +"classname" "light" +"light" "500" +"origin" "-54 -312 8" +} diff --git a/docs/developer/TstMaps/komap1.map b/docs/developer/TstMaps/komap1.map new file mode 100644 index 00000000..a6065489 --- /dev/null +++ b/docs/developer/TstMaps/komap1.map @@ -0,0 +1,3452 @@ +{ +"classname" "worldspawn" +// brush 0 + { + patchDef2 + { + ko/flamegray1 + ( 9 3 0 0 0 ) +( +( ( -136 189 352 0 0 ) ( -136 189 372 0 0.156250 ) ( -136 189 392 0 0.312500 ) ) +( ( -136 165 352 0.375000 0 ) ( -136 165 372 0.375000 0.156250 ) ( -136 165 392 0.375000 0.312500 ) ) +( ( -112 165 352 0.750000 0 ) ( -112 165 372 0.750000 0.156250 ) ( -112 165 392 0.750000 0.312500 ) ) +( ( -88 165 352 1.125000 0 ) ( -88 165 372 1.125000 0.156250 ) ( -88 165 392 1.125000 0.312500 ) ) +( ( -88 189 352 1.500000 0 ) ( -88 189 372 1.500000 0.156250 ) ( -88 189 392 1.500000 0.312500 ) ) +( ( -88 213 352 1.875000 0 ) ( -88 213 372 1.875000 0.156250 ) ( -88 213 392 1.875000 0.312500 ) ) +( ( -112 213 352 2.250000 0 ) ( -112 213 372 2.250000 0.156250 ) ( -112 213 392 2.250000 0.312500 ) ) +( ( -136 213 352 2.625000 0 ) ( -136 213 372 2.625000 0.156250 ) ( -136 213 392 2.625000 0.312500 ) ) +( ( -136 189 352 3 0 ) ( -136 189 372 3 0.156250 ) ( -136 189 392 3 0.312500 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + cqjbko/kolamp + ( 9 3 0 0 0 ) +( +( ( -143 189 366 0 0 ) ( -143 189 343 0 0.179688 ) ( -112 189 346.285706 0 0.423232 ) ) +( ( -143 158 366 0.242188 0 ) ( -143 158 343 0.242188 0.179688 ) ( -112 189 346.285706 0.242188 0.423232 ) ) +( ( -112 158 366 0.484375 0 ) ( -112 158 343 0.484375 0.179688 ) ( -112 189 346.285706 0.484375 0.423232 ) ) +( ( -81 158 366 0.726563 0 ) ( -81 158 343 0.726563 0.179688 ) ( -112 189 346.285706 0.726563 0.423232 ) ) +( ( -81 189 366 0.968750 0 ) ( -81 189 343 0.968750 0.179688 ) ( -112 189 346.285706 0.968750 0.423232 ) ) +( ( -81 220 366 1.210938 0 ) ( -81 220 343 1.210938 0.179688 ) ( -112 189 346.285706 1.210938 0.423232 ) ) +( ( -112 220 366 1.453125 0 ) ( -112 220 343 1.453125 0.179688 ) ( -112 189 346.285706 1.453125 0.423232 ) ) +( ( -143 220 366 1.695313 0 ) ( -143 220 343 1.695313 0.179688 ) ( -112 189 346.285706 1.695313 0.423232 ) ) +( ( -143 189 366 1.937500 0 ) ( -143 189 343 1.937500 0.179688 ) ( -112 189 346.285706 1.937500 0.423232 ) ) +) + } + } +// brush 2 +{ +( -111 188 347 ) ( -111 190 347 ) ( -113 190 347 ) gothic_trim/pitted_rust3 -24 32 0 0.500000 -0.500000 134217728 0 0 +( -113 190 573 ) ( -111 190 573 ) ( -111 188 573 ) gothic_trim/pitted_rust3 -24 32 0 0.500000 -0.500000 134217728 0 0 +( -115 190 398 ) ( -115 188 398 ) ( -115 188 394 ) gothic_trim/pitted_rust3 32 -224 0 0.500000 -0.500000 134217728 0 0 +( -113 186 398 ) ( -111 186 398 ) ( -111 186 394 ) gothic_trim/pitted_rust3 -24 -224 0 0.500000 -0.500000 134217728 0 0 +( -109 188 398 ) ( -109 190 398 ) ( -109 190 394 ) gothic_trim/pitted_rust3 32 -224 0 0.500000 -0.500000 134217728 0 0 +( -111 192 398 ) ( -113 192 398 ) ( -113 192 394 ) gothic_trim/pitted_rust3 -24 -224 0 0.500000 -0.500000 134217728 0 0 +} +// brush 3 +{ +( -1344 480 0 ) ( -1376 480 0 ) ( -1376 352 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1376 352 776 ) ( -1376 480 776 ) ( -1344 480 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1360 -480 784 ) ( -1328 -480 784 ) ( -1328 -480 768 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1344 352 784 ) ( -1344 480 784 ) ( -1344 480 768 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -1344 480 784 ) ( -1376 480 784 ) ( -1376 480 768 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1376 480 784 ) ( -1376 352 784 ) ( -1376 352 768 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 -64 576 0 0 ) ( -1232 -64 576 0 0.500000 ) ( -1200 -64 576 0 1 ) ) +( ( -1264 -64 584 0.125000 0 ) ( -1232 -64 584 0.125000 0.500000 ) ( -1200 -64 584 0.125000 1 ) ) +( ( -1264 -64 592 0.250000 0 ) ( -1232 -64 592 0.250000 0.500000 ) ( -1200 -64 592 0.250000 1 ) ) +) + } + } +// brush 5 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 48 592 0 0 ) ( -1232 48 592 0 0.500000 ) ( -1200 48 592 0 1 ) ) +( ( -1264 56 592 0.125000 0 ) ( -1232 56 592 0.125000 0.500000 ) ( -1200 56 592 0.125000 1 ) ) +( ( -1264 64 592 0.250000 0 ) ( -1232 64 592 0.250000 0.500000 ) ( -1200 64 592 0.250000 1 ) ) +) + } + } +// brush 6 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 64 592 0 0 ) ( -1232 64 592 0 0.500000 ) ( -1200 64 592 0 1 ) ) +( ( -1264 63.720482 636.732056 0.698952 0 ) ( -1232 63.720482 636.732056 0.698952 0.500000 ) ( -1200 63.720482 636.732056 0.698952 1 ) ) +( ( -1264 48.007172 677.478271 1.381312 0 ) ( -1232 48.007172 677.478271 1.381312 0.500000 ) ( -1200 48.007172 677.478271 1.381312 1 ) ) +( ( -1264 34.606335 714.944580 2.003044 0 ) ( -1232 34.606335 714.944580 2.003044 0.500000 ) ( -1200 34.606335 714.944580 2.003044 1 ) ) +( ( -1264 11.439175 739.186829 2.526983 0 ) ( -1232 11.439175 739.186829 2.526983 0.500000 ) ( -1200 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 7 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 48 592 0 0 ) ( -1232 48 592 0 0.500000 ) ( -1264 48 592 0 1 ) ) +( ( -1200 48 633.754395 0.652412 0 ) ( -1232 48 633.754395 0.652412 0.500000 ) ( -1264 48 633.754395 0.652412 1 ) ) +( ( -1200 33 671.929871 1.293298 0 ) ( -1232 33 671.929871 1.293298 0.500000 ) ( -1264 33 671.929871 1.293298 1 ) ) +( ( -1200 21 706.526306 1.865462 0 ) ( -1232 21 706.526306 1.865462 0.500000 ) ( -1264 21 706.526306 1.865462 1 ) ) +( ( -1200 0 728 2.334763 0 ) ( -1232 0 728 2.334763 0.500000 ) ( -1264 0 728 2.334763 1 ) ) +) + } + } +// brush 8 +{ +( -1120 64 576 ) ( -2656 64 576 ) ( -2656 56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2656 56 592 ) ( -2656 64 592 ) ( -1120 64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2656 48 592 ) ( -1120 48 592 ) ( -1120 48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1200 56 592 ) ( -1200 64 592 ) ( -1200 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -288 64 592 ) ( -1824 64 592 ) ( -1824 64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1264 64 592 ) ( -1264 56 592 ) ( -1264 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( -1344 -64 576 ) ( 192 -64 576 ) ( 192 -56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 192 -56 592 ) ( 192 -64 592 ) ( -1344 -64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 192 -48 592 ) ( -1344 -48 592 ) ( -1344 -48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1264 -56 592 ) ( -1264 -64 592 ) ( -1264 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -2176 -64 592 ) ( -640 -64 592 ) ( -640 -64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1200 -64 592 ) ( -1200 -56 592 ) ( -1200 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 -48 592 0 0 ) ( -1232 -48 592 0 0.500000 ) ( -1264 -48 592 0 1 ) ) +( ( -1200 -56 592 0.125000 0 ) ( -1232 -56 592 0.125000 0.500000 ) ( -1264 -56 592 0.125000 1 ) ) +( ( -1200 -64 592 0.250000 0 ) ( -1232 -64 592 0.250000 0.500000 ) ( -1264 -64 592 0.250000 1 ) ) +) + } + } +// brush 11 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 0 728 0 0 ) ( -1232 0 728 0 0.500000 ) ( -1264 0 728 0 1 ) ) +( ( -1200 5.719587 733.593384 0.125000 0 ) ( -1232 5.719587 733.593384 0.125000 0.500000 ) ( -1264 5.719587 733.593384 0.125000 1 ) ) +( ( -1200 11.439175 739.186829 0.250000 0 ) ( -1232 11.439175 739.186829 0.250000 0.500000 ) ( -1264 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 12 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 -64 592 0 0 ) ( -1232 -64 592 0 0.500000 ) ( -1264 -64 592 0 1 ) ) +( ( -1200 -64 637 0.703125 0 ) ( -1232 -64 637 0.703125 0.500000 ) ( -1264 -64 637 0.703125 1 ) ) +( ( -1200 -48 677 1.376271 0 ) ( -1232 -48 677 1.376271 0.500000 ) ( -1264 -48 677 1.376271 1 ) ) +( ( -1200 -35 715 2.003805 0 ) ( -1232 -35 715 2.003805 0.500000 ) ( -1264 -35 715 2.003805 1 ) ) +( ( -1200 -11 739 2.534135 0 ) ( -1232 -11 739 2.534135 0.500000 ) ( -1264 -11 739 2.534135 1 ) ) +) + } + } +// brush 13 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 0 728 0 0 ) ( -1232 0 728 0 0.500000 ) ( -1200 0 728 0 1 ) ) +( ( -1264 -6 734 0.132583 0 ) ( -1232 -6 734 0.132583 0.500000 ) ( -1200 -6 734 0.132583 1 ) ) +( ( -1264 -11 739 0.243068 0 ) ( -1232 -11 739 0.243068 0.500000 ) ( -1200 -11 739 0.243068 1 ) ) +) + } + } +// brush 14 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 -48 592 0 0 ) ( -1200 -56 592 0 0.125000 ) ( -1200 -64 592 0 0.250000 ) ) +( ( -1200 -48 634 0.656250 0 ) ( -1200 -56 635 0.656250 0.125000 ) ( -1200 -64 637 0.656250 0.250000 ) ) +( ( -1200 -33 672 1.294584 0 ) ( -1200 -41 675 1.294584 0.125000 ) ( -1200 -48 677 1.294584 0.250000 ) ) +( ( -1200 -21 707 1.872709 0 ) ( -1200 -28 711 1.872709 0.125000 ) ( -1200 -35 715 1.872709 0.250000 ) ) +( ( -1200 0 728 2.336748 0 ) ( -1200 0 735 2.336748 0.125000 ) ( -1200 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 15 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 -64 592 0 0 ) ( -1264 -56 592 0 0.125000 ) ( -1264 -48 592 0 0.250000 ) ) +( ( -1264 -64 637 0.703125 0 ) ( -1264 -56 635 0.703125 0.125000 ) ( -1264 -48 634 0.703125 0.250000 ) ) +( ( -1264 -48 677 1.376271 0 ) ( -1264 -41 675 1.376271 0.125000 ) ( -1264 -33 672 1.376271 0.250000 ) ) +( ( -1264 -35 715 2.003805 0 ) ( -1264 -28 711 2.003805 0.125000 ) ( -1264 -21 707 2.003805 0.250000 ) ) +( ( -1264 0 744 2.714012 0 ) ( -1264 0 735 2.714012 0.125000 ) ( -1264 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 16 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 48 592 0 0 ) ( -1264 56 592 0 0.125000 ) ( -1264 64 592 0 0.250000 ) ) +( ( -1264 48 634 0.656250 0 ) ( -1264 56 635 0.656250 0.125000 ) ( -1264 64 637 0.656250 0.250000 ) ) +( ( -1264 33 672 1.294584 0 ) ( -1264 41 675 1.294584 0.125000 ) ( -1264 48 677 1.294584 0.250000 ) ) +( ( -1264 21 707 1.872709 0 ) ( -1264 28 711 1.872709 0.125000 ) ( -1264 35 715 1.872709 0.250000 ) ) +( ( -1264 0 728 2.336748 0 ) ( -1264 0 735 2.336748 0.125000 ) ( -1264 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 17 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 64 592 0 0 ) ( -1200 56 592 0 0.125000 ) ( -1200 48 592 0 0.250000 ) ) +( ( -1200 64 637 0.703125 0 ) ( -1200 56 635 0.703125 0.125000 ) ( -1200 48 634 0.703125 0.250000 ) ) +( ( -1200 48 677 1.376271 0 ) ( -1200 41 675 1.376271 0.125000 ) ( -1200 33 672 1.376271 0.250000 ) ) +( ( -1200 35 715 2.003805 0 ) ( -1200 28 711 2.003805 0.125000 ) ( -1200 21 707 2.003805 0.250000 ) ) +( ( -1200 0 744 2.714012 0 ) ( -1200 0 735 2.714012 0.125000 ) ( -1200 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 18 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 64 592 0 0 ) ( -976 56 592 0 0.125000 ) ( -976 48 592 0 0.250000 ) ) +( ( -976 64 637 0.703125 0 ) ( -976 56 635 0.703125 0.125000 ) ( -976 48 634 0.703125 0.250000 ) ) +( ( -976 48 677 1.376271 0 ) ( -976 41 675 1.376271 0.125000 ) ( -976 33 672 1.376271 0.250000 ) ) +( ( -976 35 715 2.003805 0 ) ( -976 28 711 2.003805 0.125000 ) ( -976 21 707 2.003805 0.250000 ) ) +( ( -976 0 744 2.714012 0 ) ( -976 0 735 2.714012 0.125000 ) ( -976 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 19 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 48 592 0 0 ) ( -1040 56 592 0 0.125000 ) ( -1040 64 592 0 0.250000 ) ) +( ( -1040 48 634 0.656250 0 ) ( -1040 56 635 0.656250 0.125000 ) ( -1040 64 637 0.656250 0.250000 ) ) +( ( -1040 33 672 1.294584 0 ) ( -1040 41 675 1.294584 0.125000 ) ( -1040 48 677 1.294584 0.250000 ) ) +( ( -1040 21 707 1.872709 0 ) ( -1040 28 711 1.872709 0.125000 ) ( -1040 35 715 1.872709 0.250000 ) ) +( ( -1040 0 728 2.336748 0 ) ( -1040 0 735 2.336748 0.125000 ) ( -1040 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 20 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 -64 592 0 0 ) ( -1040 -56 592 0 0.125000 ) ( -1040 -48 592 0 0.250000 ) ) +( ( -1040 -64 637 0.703125 0 ) ( -1040 -56 635 0.703125 0.125000 ) ( -1040 -48 634 0.703125 0.250000 ) ) +( ( -1040 -48 677 1.376271 0 ) ( -1040 -41 675 1.376271 0.125000 ) ( -1040 -33 672 1.376271 0.250000 ) ) +( ( -1040 -35 715 2.003805 0 ) ( -1040 -28 711 2.003805 0.125000 ) ( -1040 -21 707 2.003805 0.250000 ) ) +( ( -1040 0 744 2.714012 0 ) ( -1040 0 735 2.714012 0.125000 ) ( -1040 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 21 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 -48 592 0 0 ) ( -976 -56 592 0 0.125000 ) ( -976 -64 592 0 0.250000 ) ) +( ( -976 -48 634 0.656250 0 ) ( -976 -56 635 0.656250 0.125000 ) ( -976 -64 637 0.656250 0.250000 ) ) +( ( -976 -33 672 1.294584 0 ) ( -976 -41 675 1.294584 0.125000 ) ( -976 -48 677 1.294584 0.250000 ) ) +( ( -976 -21 707 1.872709 0 ) ( -976 -28 711 1.872709 0.125000 ) ( -976 -35 715 1.872709 0.250000 ) ) +( ( -976 0 728 2.336748 0 ) ( -976 0 735 2.336748 0.125000 ) ( -976 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 22 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 0 728 0 0 ) ( -1008 0 728 0 0.500000 ) ( -976 0 728 0 1 ) ) +( ( -1040 -6 734 0.132583 0 ) ( -1008 -6 734 0.132583 0.500000 ) ( -976 -6 734 0.132583 1 ) ) +( ( -1040 -11 739 0.243068 0 ) ( -1008 -11 739 0.243068 0.500000 ) ( -976 -11 739 0.243068 1 ) ) +) + } + } +// brush 23 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 -64 592 0 0 ) ( -1008 -64 592 0 0.500000 ) ( -1040 -64 592 0 1 ) ) +( ( -976 -64 637 0.703125 0 ) ( -1008 -64 637 0.703125 0.500000 ) ( -1040 -64 637 0.703125 1 ) ) +( ( -976 -48 677 1.376271 0 ) ( -1008 -48 677 1.376271 0.500000 ) ( -1040 -48 677 1.376271 1 ) ) +( ( -976 -35 715 2.003805 0 ) ( -1008 -35 715 2.003805 0.500000 ) ( -1040 -35 715 2.003805 1 ) ) +( ( -976 -11 739 2.534135 0 ) ( -1008 -11 739 2.534135 0.500000 ) ( -1040 -11 739 2.534135 1 ) ) +) + } + } +// brush 24 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 0 728 0 0 ) ( -1008 0 728 0 0.500000 ) ( -1040 0 728 0 1 ) ) +( ( -976 5.719587 733.593384 0.125000 0 ) ( -1008 5.719587 733.593384 0.125000 0.500000 ) ( -1040 5.719587 733.593384 0.125000 1 ) ) +( ( -976 11.439175 739.186829 0.250000 0 ) ( -1008 11.439175 739.186829 0.250000 0.500000 ) ( -1040 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 25 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 -48 592 0 0 ) ( -1008 -48 592 0 0.500000 ) ( -1040 -48 592 0 1 ) ) +( ( -976 -56 592 0.125000 0 ) ( -1008 -56 592 0.125000 0.500000 ) ( -1040 -56 592 0.125000 1 ) ) +( ( -976 -64 592 0.250000 0 ) ( -1008 -64 592 0.250000 0.500000 ) ( -1040 -64 592 0.250000 1 ) ) +) + } + } +// brush 26 +{ +( -1120 -64 576 ) ( 416 -64 576 ) ( 416 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 416 -56 592 ) ( 416 -64 592 ) ( -1120 -64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 416 -48 592 ) ( -1120 -48 592 ) ( -1120 -48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1040 -56 592 ) ( -1040 -64 592 ) ( -1040 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1952 -64 592 ) ( -416 -64 592 ) ( -416 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -976 -64 592 ) ( -976 -56 592 ) ( -976 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 27 +{ +( -896 64 576 ) ( -2432 64 576 ) ( -2432 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -2432 56 592 ) ( -2432 64 592 ) ( -896 64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -2432 48 592 ) ( -896 48 592 ) ( -896 48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -976 56 592 ) ( -976 64 592 ) ( -976 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -64 64 592 ) ( -1600 64 592 ) ( -1600 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1040 64 592 ) ( -1040 56 592 ) ( -1040 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 28 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 48 592 0 0 ) ( -1008 48 592 0 0.500000 ) ( -1040 48 592 0 1 ) ) +( ( -976 48 633.754395 0.652412 0 ) ( -1008 48 633.754395 0.652412 0.500000 ) ( -1040 48 633.754395 0.652412 1 ) ) +( ( -976 33 671.929871 1.293298 0 ) ( -1008 33 671.929871 1.293298 0.500000 ) ( -1040 33 671.929871 1.293298 1 ) ) +( ( -976 21 706.526306 1.865462 0 ) ( -1008 21 706.526306 1.865462 0.500000 ) ( -1040 21 706.526306 1.865462 1 ) ) +( ( -976 0 728 2.334763 0 ) ( -1008 0 728 2.334763 0.500000 ) ( -1040 0 728 2.334763 1 ) ) +) + } + } +// brush 29 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 64 592 0 0 ) ( -1008 64 592 0 0.500000 ) ( -976 64 592 0 1 ) ) +( ( -1040 63.720482 636.732056 0.698952 0 ) ( -1008 63.720482 636.732056 0.698952 0.500000 ) ( -976 63.720482 636.732056 0.698952 1 ) ) +( ( -1040 48.007172 677.478271 1.381312 0 ) ( -1008 48.007172 677.478271 1.381312 0.500000 ) ( -976 48.007172 677.478271 1.381312 1 ) ) +( ( -1040 34.606335 714.944580 2.003044 0 ) ( -1008 34.606335 714.944580 2.003044 0.500000 ) ( -976 34.606335 714.944580 2.003044 1 ) ) +( ( -1040 11.439175 739.186829 2.526983 0 ) ( -1008 11.439175 739.186829 2.526983 0.500000 ) ( -976 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 30 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 48 592 0 0 ) ( -1008 48 592 0 0.500000 ) ( -976 48 592 0 1 ) ) +( ( -1040 56 592 0.125000 0 ) ( -1008 56 592 0.125000 0.500000 ) ( -976 56 592 0.125000 1 ) ) +( ( -1040 64 592 0.250000 0 ) ( -1008 64 592 0.250000 0.500000 ) ( -976 64 592 0.250000 1 ) ) +) + } + } +// brush 31 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 -64 576 0 0 ) ( -1008 -64 576 0 0.500000 ) ( -976 -64 576 0 1 ) ) +( ( -1040 -64 584 0.125000 0 ) ( -1008 -64 584 0.125000 0.500000 ) ( -976 -64 584 0.125000 1 ) ) +( ( -1040 -64 592 0.250000 0 ) ( -1008 -64 592 0.250000 0.500000 ) ( -976 -64 592 0.250000 1 ) ) +) + } + } +// brush 32 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 -64 576 0 0 ) ( -784 -64 576 0 0.500000 ) ( -752 -64 576 0 1 ) ) +( ( -816 -64 584 0.125000 0 ) ( -784 -64 584 0.125000 0.500000 ) ( -752 -64 584 0.125000 1 ) ) +( ( -816 -64 592 0.250000 0 ) ( -784 -64 592 0.250000 0.500000 ) ( -752 -64 592 0.250000 1 ) ) +) + } + } +// brush 33 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 48 592 0 0 ) ( -784 48 592 0 0.500000 ) ( -752 48 592 0 1 ) ) +( ( -816 56 592 0.125000 0 ) ( -784 56 592 0.125000 0.500000 ) ( -752 56 592 0.125000 1 ) ) +( ( -816 64 592 0.250000 0 ) ( -784 64 592 0.250000 0.500000 ) ( -752 64 592 0.250000 1 ) ) +) + } + } +// brush 34 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 64 592 0 0 ) ( -784 64 592 0 0.500000 ) ( -752 64 592 0 1 ) ) +( ( -816 63.720482 636.732056 0.698952 0 ) ( -784 63.720482 636.732056 0.698952 0.500000 ) ( -752 63.720482 636.732056 0.698952 1 ) ) +( ( -816 48.007172 677.478271 1.381312 0 ) ( -784 48.007172 677.478271 1.381312 0.500000 ) ( -752 48.007172 677.478271 1.381312 1 ) ) +( ( -816 34.606335 714.944580 2.003044 0 ) ( -784 34.606335 714.944580 2.003044 0.500000 ) ( -752 34.606335 714.944580 2.003044 1 ) ) +( ( -816 11.439175 739.186829 2.526983 0 ) ( -784 11.439175 739.186829 2.526983 0.500000 ) ( -752 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 35 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 48 592 0 0 ) ( -784 48 592 0 0.500000 ) ( -816 48 592 0 1 ) ) +( ( -752 48 633.754395 0.652412 0 ) ( -784 48 633.754395 0.652412 0.500000 ) ( -816 48 633.754395 0.652412 1 ) ) +( ( -752 33 671.929871 1.293298 0 ) ( -784 33 671.929871 1.293298 0.500000 ) ( -816 33 671.929871 1.293298 1 ) ) +( ( -752 21 706.526306 1.865462 0 ) ( -784 21 706.526306 1.865462 0.500000 ) ( -816 21 706.526306 1.865462 1 ) ) +( ( -752 0 728 2.334763 0 ) ( -784 0 728 2.334763 0.500000 ) ( -816 0 728 2.334763 1 ) ) +) + } + } +// brush 36 +{ +( -672 64 576 ) ( -2208 64 576 ) ( -2208 56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2208 56 592 ) ( -2208 64 592 ) ( -672 64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2208 48 592 ) ( -672 48 592 ) ( -672 48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -752 56 592 ) ( -752 64 592 ) ( -752 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 160 64 592 ) ( -1376 64 592 ) ( -1376 64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -816 64 592 ) ( -816 56 592 ) ( -816 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 37 +{ +( -896 -64 576 ) ( 640 -64 576 ) ( 640 -56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 640 -56 592 ) ( 640 -64 592 ) ( -896 -64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 640 -48 592 ) ( -896 -48 592 ) ( -896 -48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -816 -56 592 ) ( -816 -64 592 ) ( -816 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -64 592 ) ( -192 -64 592 ) ( -192 -64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -752 -64 592 ) ( -752 -56 592 ) ( -752 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 38 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 -48 592 0 0 ) ( -784 -48 592 0 0.500000 ) ( -816 -48 592 0 1 ) ) +( ( -752 -56 592 0.125000 0 ) ( -784 -56 592 0.125000 0.500000 ) ( -816 -56 592 0.125000 1 ) ) +( ( -752 -64 592 0.250000 0 ) ( -784 -64 592 0.250000 0.500000 ) ( -816 -64 592 0.250000 1 ) ) +) + } + } +// brush 39 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 0 728 0 0 ) ( -784 0 728 0 0.500000 ) ( -816 0 728 0 1 ) ) +( ( -752 5.719587 733.593384 0.125000 0 ) ( -784 5.719587 733.593384 0.125000 0.500000 ) ( -816 5.719587 733.593384 0.125000 1 ) ) +( ( -752 11.439175 739.186829 0.250000 0 ) ( -784 11.439175 739.186829 0.250000 0.500000 ) ( -816 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 40 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 -64 592 0 0 ) ( -784 -64 592 0 0.500000 ) ( -816 -64 592 0 1 ) ) +( ( -752 -64 637 0.703125 0 ) ( -784 -64 637 0.703125 0.500000 ) ( -816 -64 637 0.703125 1 ) ) +( ( -752 -48 677 1.376271 0 ) ( -784 -48 677 1.376271 0.500000 ) ( -816 -48 677 1.376271 1 ) ) +( ( -752 -35 715 2.003805 0 ) ( -784 -35 715 2.003805 0.500000 ) ( -816 -35 715 2.003805 1 ) ) +( ( -752 -11 739 2.534135 0 ) ( -784 -11 739 2.534135 0.500000 ) ( -816 -11 739 2.534135 1 ) ) +) + } + } +// brush 41 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 0 728 0 0 ) ( -784 0 728 0 0.500000 ) ( -752 0 728 0 1 ) ) +( ( -816 -6 734 0.132583 0 ) ( -784 -6 734 0.132583 0.500000 ) ( -752 -6 734 0.132583 1 ) ) +( ( -816 -11 739 0.243068 0 ) ( -784 -11 739 0.243068 0.500000 ) ( -752 -11 739 0.243068 1 ) ) +) + } + } +// brush 42 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 -48 592 0 0 ) ( -752 -56 592 0 0.125000 ) ( -752 -64 592 0 0.250000 ) ) +( ( -752 -48 634 0.656250 0 ) ( -752 -56 635 0.656250 0.125000 ) ( -752 -64 637 0.656250 0.250000 ) ) +( ( -752 -33 672 1.294584 0 ) ( -752 -41 675 1.294584 0.125000 ) ( -752 -48 677 1.294584 0.250000 ) ) +( ( -752 -21 707 1.872709 0 ) ( -752 -28 711 1.872709 0.125000 ) ( -752 -35 715 1.872709 0.250000 ) ) +( ( -752 0 728 2.336748 0 ) ( -752 0 735 2.336748 0.125000 ) ( -752 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 43 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 -64 592 0 0 ) ( -816 -56 592 0 0.125000 ) ( -816 -48 592 0 0.250000 ) ) +( ( -816 -64 637 0.703125 0 ) ( -816 -56 635 0.703125 0.125000 ) ( -816 -48 634 0.703125 0.250000 ) ) +( ( -816 -48 677 1.376271 0 ) ( -816 -41 675 1.376271 0.125000 ) ( -816 -33 672 1.376271 0.250000 ) ) +( ( -816 -35 715 2.003805 0 ) ( -816 -28 711 2.003805 0.125000 ) ( -816 -21 707 2.003805 0.250000 ) ) +( ( -816 0 744 2.714012 0 ) ( -816 0 735 2.714012 0.125000 ) ( -816 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 44 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 48 592 0 0 ) ( -816 56 592 0 0.125000 ) ( -816 64 592 0 0.250000 ) ) +( ( -816 48 634 0.656250 0 ) ( -816 56 635 0.656250 0.125000 ) ( -816 64 637 0.656250 0.250000 ) ) +( ( -816 33 672 1.294584 0 ) ( -816 41 675 1.294584 0.125000 ) ( -816 48 677 1.294584 0.250000 ) ) +( ( -816 21 707 1.872709 0 ) ( -816 28 711 1.872709 0.125000 ) ( -816 35 715 1.872709 0.250000 ) ) +( ( -816 0 728 2.336748 0 ) ( -816 0 735 2.336748 0.125000 ) ( -816 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 45 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 64 592 0 0 ) ( -752 56 592 0 0.125000 ) ( -752 48 592 0 0.250000 ) ) +( ( -752 64 637 0.703125 0 ) ( -752 56 635 0.703125 0.125000 ) ( -752 48 634 0.703125 0.250000 ) ) +( ( -752 48 677 1.376271 0 ) ( -752 41 675 1.376271 0.125000 ) ( -752 33 672 1.376271 0.250000 ) ) +( ( -752 35 715 2.003805 0 ) ( -752 28 711 2.003805 0.125000 ) ( -752 21 707 2.003805 0.250000 ) ) +( ( -752 0 744 2.714012 0 ) ( -752 0 735 2.714012 0.125000 ) ( -752 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 46 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 64 592 0 0 ) ( -528 56 592 0 0.125000 ) ( -528 48 592 0 0.250000 ) ) +( ( -528 64 637 0.703125 0 ) ( -528 56 635 0.703125 0.125000 ) ( -528 48 634 0.703125 0.250000 ) ) +( ( -528 48 677 1.376271 0 ) ( -528 41 675 1.376271 0.125000 ) ( -528 33 672 1.376271 0.250000 ) ) +( ( -528 35 715 2.003805 0 ) ( -528 28 711 2.003805 0.125000 ) ( -528 21 707 2.003805 0.250000 ) ) +( ( -528 0 744 2.714012 0 ) ( -528 0 735 2.714012 0.125000 ) ( -528 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 47 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 48 592 0 0 ) ( -592 56 592 0 0.125000 ) ( -592 64 592 0 0.250000 ) ) +( ( -592 48 634 0.656250 0 ) ( -592 56 635 0.656250 0.125000 ) ( -592 64 637 0.656250 0.250000 ) ) +( ( -592 33 672 1.294584 0 ) ( -592 41 675 1.294584 0.125000 ) ( -592 48 677 1.294584 0.250000 ) ) +( ( -592 21 707 1.872709 0 ) ( -592 28 711 1.872709 0.125000 ) ( -592 35 715 1.872709 0.250000 ) ) +( ( -592 0 728 2.336748 0 ) ( -592 0 735 2.336748 0.125000 ) ( -592 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 48 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 -64 592 0 0 ) ( -592 -56 592 0 0.125000 ) ( -592 -48 592 0 0.250000 ) ) +( ( -592 -64 637 0.703125 0 ) ( -592 -56 635 0.703125 0.125000 ) ( -592 -48 634 0.703125 0.250000 ) ) +( ( -592 -48 677 1.376271 0 ) ( -592 -41 675 1.376271 0.125000 ) ( -592 -33 672 1.376271 0.250000 ) ) +( ( -592 -35 715 2.003805 0 ) ( -592 -28 711 2.003805 0.125000 ) ( -592 -21 707 2.003805 0.250000 ) ) +( ( -592 0 744 2.714012 0 ) ( -592 0 735 2.714012 0.125000 ) ( -592 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 49 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 -48 592 0 0 ) ( -528 -56 592 0 0.125000 ) ( -528 -64 592 0 0.250000 ) ) +( ( -528 -48 634 0.656250 0 ) ( -528 -56 635 0.656250 0.125000 ) ( -528 -64 637 0.656250 0.250000 ) ) +( ( -528 -33 672 1.294584 0 ) ( -528 -41 675 1.294584 0.125000 ) ( -528 -48 677 1.294584 0.250000 ) ) +( ( -528 -21 707 1.872709 0 ) ( -528 -28 711 1.872709 0.125000 ) ( -528 -35 715 1.872709 0.250000 ) ) +( ( -528 0 728 2.336748 0 ) ( -528 0 735 2.336748 0.125000 ) ( -528 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 50 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 0 728 0 0 ) ( -560 0 728 0 0.500000 ) ( -528 0 728 0 1 ) ) +( ( -592 -6 734 0.132583 0 ) ( -560 -6 734 0.132583 0.500000 ) ( -528 -6 734 0.132583 1 ) ) +( ( -592 -11 739 0.243068 0 ) ( -560 -11 739 0.243068 0.500000 ) ( -528 -11 739 0.243068 1 ) ) +) + } + } +// brush 51 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 -64 592 0 0 ) ( -560 -64 592 0 0.500000 ) ( -592 -64 592 0 1 ) ) +( ( -528 -64 637 0.703125 0 ) ( -560 -64 637 0.703125 0.500000 ) ( -592 -64 637 0.703125 1 ) ) +( ( -528 -48 677 1.376271 0 ) ( -560 -48 677 1.376271 0.500000 ) ( -592 -48 677 1.376271 1 ) ) +( ( -528 -35 715 2.003805 0 ) ( -560 -35 715 2.003805 0.500000 ) ( -592 -35 715 2.003805 1 ) ) +( ( -528 -11 739 2.534135 0 ) ( -560 -11 739 2.534135 0.500000 ) ( -592 -11 739 2.534135 1 ) ) +) + } + } +// brush 52 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 0 728 0 0 ) ( -560 0 728 0 0.500000 ) ( -592 0 728 0 1 ) ) +( ( -528 5.719587 733.593384 0.125000 0 ) ( -560 5.719587 733.593384 0.125000 0.500000 ) ( -592 5.719587 733.593384 0.125000 1 ) ) +( ( -528 11.439175 739.186829 0.250000 0 ) ( -560 11.439175 739.186829 0.250000 0.500000 ) ( -592 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 53 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 -48 592 0 0 ) ( -560 -48 592 0 0.500000 ) ( -592 -48 592 0 1 ) ) +( ( -528 -56 592 0.125000 0 ) ( -560 -56 592 0.125000 0.500000 ) ( -592 -56 592 0.125000 1 ) ) +( ( -528 -64 592 0.250000 0 ) ( -560 -64 592 0.250000 0.500000 ) ( -592 -64 592 0.250000 1 ) ) +) + } + } +// brush 54 +{ +( -672 -64 576 ) ( 864 -64 576 ) ( 864 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 864 -56 592 ) ( 864 -64 592 ) ( -672 -64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 864 -48 592 ) ( -672 -48 592 ) ( -672 -48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -592 -56 592 ) ( -592 -64 592 ) ( -592 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -64 592 ) ( 32 -64 592 ) ( 32 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -528 -64 592 ) ( -528 -56 592 ) ( -528 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 55 +{ +( -448 64 576 ) ( -1984 64 576 ) ( -1984 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1984 56 592 ) ( -1984 64 592 ) ( -448 64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1984 48 592 ) ( -448 48 592 ) ( -448 48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -528 56 592 ) ( -528 64 592 ) ( -528 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 384 64 592 ) ( -1152 64 592 ) ( -1152 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -592 64 592 ) ( -592 56 592 ) ( -592 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 56 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 48 592 0 0 ) ( -560 48 592 0 0.500000 ) ( -592 48 592 0 1 ) ) +( ( -528 48 633.754395 0.652412 0 ) ( -560 48 633.754395 0.652412 0.500000 ) ( -592 48 633.754395 0.652412 1 ) ) +( ( -528 33 671.929871 1.293298 0 ) ( -560 33 671.929871 1.293298 0.500000 ) ( -592 33 671.929871 1.293298 1 ) ) +( ( -528 21 706.526306 1.865462 0 ) ( -560 21 706.526306 1.865462 0.500000 ) ( -592 21 706.526306 1.865462 1 ) ) +( ( -528 0 728 2.334763 0 ) ( -560 0 728 2.334763 0.500000 ) ( -592 0 728 2.334763 1 ) ) +) + } + } +// brush 57 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 64 592 0 0 ) ( -560 64 592 0 0.500000 ) ( -528 64 592 0 1 ) ) +( ( -592 63.720482 636.732056 0.698952 0 ) ( -560 63.720482 636.732056 0.698952 0.500000 ) ( -528 63.720482 636.732056 0.698952 1 ) ) +( ( -592 48.007172 677.478271 1.381312 0 ) ( -560 48.007172 677.478271 1.381312 0.500000 ) ( -528 48.007172 677.478271 1.381312 1 ) ) +( ( -592 34.606335 714.944580 2.003044 0 ) ( -560 34.606335 714.944580 2.003044 0.500000 ) ( -528 34.606335 714.944580 2.003044 1 ) ) +( ( -592 11.439175 739.186829 2.526983 0 ) ( -560 11.439175 739.186829 2.526983 0.500000 ) ( -528 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 58 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 48 592 0 0 ) ( -560 48 592 0 0.500000 ) ( -528 48 592 0 1 ) ) +( ( -592 56 592 0.125000 0 ) ( -560 56 592 0.125000 0.500000 ) ( -528 56 592 0.125000 1 ) ) +( ( -592 64 592 0.250000 0 ) ( -560 64 592 0.250000 0.500000 ) ( -528 64 592 0.250000 1 ) ) +) + } + } +// brush 59 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 -64 576 0 0 ) ( -560 -64 576 0 0.500000 ) ( -528 -64 576 0 1 ) ) +( ( -592 -64 584 0.125000 0 ) ( -560 -64 584 0.125000 0.500000 ) ( -528 -64 584 0.125000 1 ) ) +( ( -592 -64 592 0.250000 0 ) ( -560 -64 592 0.250000 0.500000 ) ( -528 -64 592 0.250000 1 ) ) +) + } + } +// brush 60 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 -64 576 0 0 ) ( -336 -64 576 0 0.500000 ) ( -304 -64 576 0 1 ) ) +( ( -368 -64 584 0.125000 0 ) ( -336 -64 584 0.125000 0.500000 ) ( -304 -64 584 0.125000 1 ) ) +( ( -368 -64 592 0.250000 0 ) ( -336 -64 592 0.250000 0.500000 ) ( -304 -64 592 0.250000 1 ) ) +) + } + } +// brush 61 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 48 592 0 0 ) ( -336 48 592 0 0.500000 ) ( -304 48 592 0 1 ) ) +( ( -368 56 592 0.125000 0 ) ( -336 56 592 0.125000 0.500000 ) ( -304 56 592 0.125000 1 ) ) +( ( -368 64 592 0.250000 0 ) ( -336 64 592 0.250000 0.500000 ) ( -304 64 592 0.250000 1 ) ) +) + } + } +// brush 62 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 64 592 0 0 ) ( -336 64 592 0 0.500000 ) ( -304 64 592 0 1 ) ) +( ( -368 63.720482 636.732056 0.698952 0 ) ( -336 63.720482 636.732056 0.698952 0.500000 ) ( -304 63.720482 636.732056 0.698952 1 ) ) +( ( -368 48.007172 677.478271 1.381312 0 ) ( -336 48.007172 677.478271 1.381312 0.500000 ) ( -304 48.007172 677.478271 1.381312 1 ) ) +( ( -368 34.606335 714.944580 2.003044 0 ) ( -336 34.606335 714.944580 2.003044 0.500000 ) ( -304 34.606335 714.944580 2.003044 1 ) ) +( ( -368 11.439175 739.186829 2.526983 0 ) ( -336 11.439175 739.186829 2.526983 0.500000 ) ( -304 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 63 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 48 592 0 0 ) ( -336 48 592 0 0.500000 ) ( -368 48 592 0 1 ) ) +( ( -304 48 633.754395 0.652412 0 ) ( -336 48 633.754395 0.652412 0.500000 ) ( -368 48 633.754395 0.652412 1 ) ) +( ( -304 33 671.929871 1.293298 0 ) ( -336 33 671.929871 1.293298 0.500000 ) ( -368 33 671.929871 1.293298 1 ) ) +( ( -304 21 706.526306 1.865462 0 ) ( -336 21 706.526306 1.865462 0.500000 ) ( -368 21 706.526306 1.865462 1 ) ) +( ( -304 0 728 2.334763 0 ) ( -336 0 728 2.334763 0.500000 ) ( -368 0 728 2.334763 1 ) ) +) + } + } +// brush 64 +{ +( -224 64 576 ) ( -1760 64 576 ) ( -1760 56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1760 56 592 ) ( -1760 64 592 ) ( -224 64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1760 48 592 ) ( -224 48 592 ) ( -224 48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -304 56 592 ) ( -304 64 592 ) ( -304 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 608 64 592 ) ( -928 64 592 ) ( -928 64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -368 64 592 ) ( -368 56 592 ) ( -368 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 65 +{ +( -448 -64 576 ) ( 1088 -64 576 ) ( 1088 -56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 1088 -56 592 ) ( 1088 -64 592 ) ( -448 -64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 1088 -48 592 ) ( -448 -48 592 ) ( -448 -48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -368 -56 592 ) ( -368 -64 592 ) ( -368 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1280 -64 592 ) ( 256 -64 592 ) ( 256 -64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -304 -64 592 ) ( -304 -56 592 ) ( -304 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 66 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 -48 592 0 0 ) ( -336 -48 592 0 0.500000 ) ( -368 -48 592 0 1 ) ) +( ( -304 -56 592 0.125000 0 ) ( -336 -56 592 0.125000 0.500000 ) ( -368 -56 592 0.125000 1 ) ) +( ( -304 -64 592 0.250000 0 ) ( -336 -64 592 0.250000 0.500000 ) ( -368 -64 592 0.250000 1 ) ) +) + } + } +// brush 67 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 0 728 0 0 ) ( -336 0 728 0 0.500000 ) ( -368 0 728 0 1 ) ) +( ( -304 5.719587 733.593384 0.125000 0 ) ( -336 5.719587 733.593384 0.125000 0.500000 ) ( -368 5.719587 733.593384 0.125000 1 ) ) +( ( -304 11.439175 739.186829 0.250000 0 ) ( -336 11.439175 739.186829 0.250000 0.500000 ) ( -368 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 68 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 -64 592 0 0 ) ( -336 -64 592 0 0.500000 ) ( -368 -64 592 0 1 ) ) +( ( -304 -64 637 0.703125 0 ) ( -336 -64 637 0.703125 0.500000 ) ( -368 -64 637 0.703125 1 ) ) +( ( -304 -48 677 1.376271 0 ) ( -336 -48 677 1.376271 0.500000 ) ( -368 -48 677 1.376271 1 ) ) +( ( -304 -35 715 2.003805 0 ) ( -336 -35 715 2.003805 0.500000 ) ( -368 -35 715 2.003805 1 ) ) +( ( -304 -11 739 2.534135 0 ) ( -336 -11 739 2.534135 0.500000 ) ( -368 -11 739 2.534135 1 ) ) +) + } + } +// brush 69 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 0 728 0 0 ) ( -336 0 728 0 0.500000 ) ( -304 0 728 0 1 ) ) +( ( -368 -6 734 0.132583 0 ) ( -336 -6 734 0.132583 0.500000 ) ( -304 -6 734 0.132583 1 ) ) +( ( -368 -11 739 0.243068 0 ) ( -336 -11 739 0.243068 0.500000 ) ( -304 -11 739 0.243068 1 ) ) +) + } + } +// brush 70 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 -48 592 0 0 ) ( -304 -56 592 0 0.125000 ) ( -304 -64 592 0 0.250000 ) ) +( ( -304 -48 634 0.656250 0 ) ( -304 -56 635 0.656250 0.125000 ) ( -304 -64 637 0.656250 0.250000 ) ) +( ( -304 -33 672 1.294584 0 ) ( -304 -41 675 1.294584 0.125000 ) ( -304 -48 677 1.294584 0.250000 ) ) +( ( -304 -21 707 1.872709 0 ) ( -304 -28 711 1.872709 0.125000 ) ( -304 -35 715 1.872709 0.250000 ) ) +( ( -304 0 728 2.336748 0 ) ( -304 0 735 2.336748 0.125000 ) ( -304 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 71 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 -64 592 0 0 ) ( -368 -56 592 0 0.125000 ) ( -368 -48 592 0 0.250000 ) ) +( ( -368 -64 637 0.703125 0 ) ( -368 -56 635 0.703125 0.125000 ) ( -368 -48 634 0.703125 0.250000 ) ) +( ( -368 -48 677 1.376271 0 ) ( -368 -41 675 1.376271 0.125000 ) ( -368 -33 672 1.376271 0.250000 ) ) +( ( -368 -35 715 2.003805 0 ) ( -368 -28 711 2.003805 0.125000 ) ( -368 -21 707 2.003805 0.250000 ) ) +( ( -368 0 744 2.714012 0 ) ( -368 0 735 2.714012 0.125000 ) ( -368 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 72 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 48 592 0 0 ) ( -368 56 592 0 0.125000 ) ( -368 64 592 0 0.250000 ) ) +( ( -368 48 634 0.656250 0 ) ( -368 56 635 0.656250 0.125000 ) ( -368 64 637 0.656250 0.250000 ) ) +( ( -368 33 672 1.294584 0 ) ( -368 41 675 1.294584 0.125000 ) ( -368 48 677 1.294584 0.250000 ) ) +( ( -368 21 707 1.872709 0 ) ( -368 28 711 1.872709 0.125000 ) ( -368 35 715 1.872709 0.250000 ) ) +( ( -368 0 728 2.336748 0 ) ( -368 0 735 2.336748 0.125000 ) ( -368 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 73 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 64 592 0 0 ) ( -304 56 592 0 0.125000 ) ( -304 48 592 0 0.250000 ) ) +( ( -304 64 637 0.703125 0 ) ( -304 56 635 0.703125 0.125000 ) ( -304 48 634 0.703125 0.250000 ) ) +( ( -304 48 677 1.376271 0 ) ( -304 41 675 1.376271 0.125000 ) ( -304 33 672 1.376271 0.250000 ) ) +( ( -304 35 715 2.003805 0 ) ( -304 28 711 2.003805 0.125000 ) ( -304 21 707 2.003805 0.250000 ) ) +( ( -304 0 744 2.714012 0 ) ( -304 0 735 2.714012 0.125000 ) ( -304 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 74 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 64 592 0 0 ) ( -80 56 592 0 0.125000 ) ( -80 48 592 0 0.250000 ) ) +( ( -80 64 637 0.703125 0 ) ( -80 56 635 0.703125 0.125000 ) ( -80 48 634 0.703125 0.250000 ) ) +( ( -80 48 677 1.376271 0 ) ( -80 41 675 1.376271 0.125000 ) ( -80 33 672 1.376271 0.250000 ) ) +( ( -80 35 715 2.003805 0 ) ( -80 28 711 2.003805 0.125000 ) ( -80 21 707 2.003805 0.250000 ) ) +( ( -80 0 744 2.714012 0 ) ( -80 0 735 2.714012 0.125000 ) ( -80 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 75 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 48 592 0 0 ) ( -144 56 592 0 0.125000 ) ( -144 64 592 0 0.250000 ) ) +( ( -144 48 634 0.656250 0 ) ( -144 56 635 0.656250 0.125000 ) ( -144 64 637 0.656250 0.250000 ) ) +( ( -144 33 672 1.294584 0 ) ( -144 41 675 1.294584 0.125000 ) ( -144 48 677 1.294584 0.250000 ) ) +( ( -144 21 707 1.872709 0 ) ( -144 28 711 1.872709 0.125000 ) ( -144 35 715 1.872709 0.250000 ) ) +( ( -144 0 728 2.336748 0 ) ( -144 0 735 2.336748 0.125000 ) ( -144 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 76 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 -64 592 0 0 ) ( -144 -56 592 0 0.125000 ) ( -144 -48 592 0 0.250000 ) ) +( ( -144 -64 637 0.703125 0 ) ( -144 -56 635 0.703125 0.125000 ) ( -144 -48 634 0.703125 0.250000 ) ) +( ( -144 -48 677 1.376271 0 ) ( -144 -41 675 1.376271 0.125000 ) ( -144 -33 672 1.376271 0.250000 ) ) +( ( -144 -35 715 2.003805 0 ) ( -144 -28 711 2.003805 0.125000 ) ( -144 -21 707 2.003805 0.250000 ) ) +( ( -144 0 744 2.714012 0 ) ( -144 0 735 2.714012 0.125000 ) ( -144 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 77 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 -48 592 0 0 ) ( -80 -56 592 0 0.125000 ) ( -80 -64 592 0 0.250000 ) ) +( ( -80 -48 634 0.656250 0 ) ( -80 -56 635 0.656250 0.125000 ) ( -80 -64 637 0.656250 0.250000 ) ) +( ( -80 -33 672 1.294584 0 ) ( -80 -41 675 1.294584 0.125000 ) ( -80 -48 677 1.294584 0.250000 ) ) +( ( -80 -21 707 1.872709 0 ) ( -80 -28 711 1.872709 0.125000 ) ( -80 -35 715 1.872709 0.250000 ) ) +( ( -80 0 728 2.336748 0 ) ( -80 0 735 2.336748 0.125000 ) ( -80 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 78 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 0 728 0 0 ) ( -112 0 728 0 0.500000 ) ( -80 0 728 0 1 ) ) +( ( -144 -6 734 0.132583 0 ) ( -112 -6 734 0.132583 0.500000 ) ( -80 -6 734 0.132583 1 ) ) +( ( -144 -11 739 0.243068 0 ) ( -112 -11 739 0.243068 0.500000 ) ( -80 -11 739 0.243068 1 ) ) +) + } + } +// brush 79 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 -64 592 0 0 ) ( -112 -64 592 0 0.500000 ) ( -144 -64 592 0 1 ) ) +( ( -80 -64 637 0.703125 0 ) ( -112 -64 637 0.703125 0.500000 ) ( -144 -64 637 0.703125 1 ) ) +( ( -80 -48 677 1.376271 0 ) ( -112 -48 677 1.376271 0.500000 ) ( -144 -48 677 1.376271 1 ) ) +( ( -80 -35 715 2.003805 0 ) ( -112 -35 715 2.003805 0.500000 ) ( -144 -35 715 2.003805 1 ) ) +( ( -80 -11 739 2.534135 0 ) ( -112 -11 739 2.534135 0.500000 ) ( -144 -11 739 2.534135 1 ) ) +) + } + } +// brush 80 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 0 728 0 0 ) ( -111.999992 0 728 0 0.500000 ) ( -144 0 728 0 1 ) ) +( ( -80 5.719587 733.593384 0.125000 0 ) ( -111.999992 5.719587 733.593384 0.125000 0.500000 ) ( -144 5.719587 733.593384 0.125000 1 ) ) +( ( -80 11.439175 739.186829 0.250000 0 ) ( -111.999992 11.439175 739.186829 0.250000 0.500000 ) ( -144 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 81 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 -48 592 0 0 ) ( -112 -48 592 0 0.500000 ) ( -144 -48 592 0 1 ) ) +( ( -80 -56 592 0.125000 0 ) ( -112 -56 592 0.125000 0.500000 ) ( -144 -56 592 0.125000 1 ) ) +( ( -80 -64 592 0.250000 0 ) ( -112 -64 592 0.250000 0.500000 ) ( -144 -64 592 0.250000 1 ) ) +) + } + } +// brush 82 +{ +( -224 -64 576 ) ( 1312 -64 576 ) ( 1312 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 1312 -56 592 ) ( 1312 -64 592 ) ( -224 -64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 1312 -48 592 ) ( -224 -48 592 ) ( -224 -48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -144 -56 592 ) ( -144 -64 592 ) ( -144 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1056 -64 592 ) ( 480 -64 592 ) ( 480 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -80 -64 592 ) ( -80 -56 592 ) ( -80 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 83 +{ +( 0 64 576 ) ( -1536 64 576 ) ( -1536 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1536 56 592 ) ( -1536 64 592 ) ( 0 64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1536 48 592 ) ( 0 48 592 ) ( 0 48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -80 56 592 ) ( -80 64 592 ) ( -80 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 832 64 592 ) ( -704 64 592 ) ( -704 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -144 64 592 ) ( -144 56 592 ) ( -144 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 84 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 48 592 0 0 ) ( -111.999992 48 592 0 0.500000 ) ( -144 48 592 0 1 ) ) +( ( -80 48 633.754395 0.652412 0 ) ( -111.999992 48 633.754395 0.652412 0.500000 ) ( -144 48 633.754395 0.652412 1 ) ) +( ( -80 33 671.929871 1.293298 0 ) ( -111.999992 33 671.929871 1.293298 0.500000 ) ( -144 33 671.929871 1.293298 1 ) ) +( ( -80 21 706.526306 1.865462 0 ) ( -111.999992 21 706.526306 1.865462 0.500000 ) ( -144 21 706.526306 1.865462 1 ) ) +( ( -80 0 728 2.334763 0 ) ( -111.999992 0 728 2.334763 0.500000 ) ( -144 0 728 2.334763 1 ) ) +) + } + } +// brush 85 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 64 592 0 0 ) ( -111.999992 64 592 0 0.500000 ) ( -80 64 592 0 1 ) ) +( ( -144 63.720482 636.732056 0.698952 0 ) ( -111.999992 63.720482 636.732056 0.698952 0.500000 ) ( -80 63.720482 636.732056 0.698952 1 ) ) +( ( -144 48.007172 677.478271 1.381312 0 ) ( -111.999992 48.007172 677.478271 1.381312 0.500000 ) ( -80 48.007172 677.478271 1.381312 1 ) ) +( ( -144 34.606335 714.944580 2.003044 0 ) ( -111.999992 34.606335 714.944580 2.003044 0.500000 ) ( -80 34.606335 714.944580 2.003044 1 ) ) +( ( -144 11.439175 739.186829 2.526983 0 ) ( -111.999992 11.439175 739.186829 2.526983 0.500000 ) ( -80 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 86 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 48 592 0 0 ) ( -111.999992 48 592 0 0.500000 ) ( -80 48 592 0 1 ) ) +( ( -144 56 592 0.125000 0 ) ( -111.999992 56 592 0.125000 0.500000 ) ( -80 56 592 0.125000 1 ) ) +( ( -144 64 592 0.250000 0 ) ( -111.999992 64 592 0.250000 0.500000 ) ( -80 64 592 0.250000 1 ) ) +) + } + } +// brush 87 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 -64 576 0 0 ) ( -112 -64 576 0 0.500000 ) ( -80 -64 576 0 1 ) ) +( ( -144 -64 584 0.125000 0 ) ( -112 -64 584 0.125000 0.500000 ) ( -80 -64 584 0.125000 1 ) ) +( ( -144 -64 592 0.250000 0 ) ( -112 -64 592 0.250000 0.500000 ) ( -80 -64 592 0.250000 1 ) ) +) + } + } +// brush 88 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 5 3 0 0 0 ) +( +( ( -32.000008 64 592 0 0 ) ( -687.999939 64 592 0 5.875000 ) ( -1344 64 592 0 11.750000 ) ) +( ( -32.000008 64 638.666687 0.364583 0 ) ( -687.999939 64 638.666687 0.364583 5.875000 ) ( -1344 64 638.666687 0.364583 11.750000 ) ) +( ( -32.000008 44 681.333374 0.732721 0 ) ( -687.999939 44 681.333374 0.732721 5.875000 ) ( -1344 44 681.333374 0.732721 11.750000 ) ) +( ( -32.000008 28 720 1.059645 0 ) ( -687.999939 28 720 1.059645 5.875000 ) ( -1344 28 720 1.059645 11.750000 ) ) +( ( -32.000008 0 744 1.347756 0 ) ( -687.999939 0 744 1.347756 5.875000 ) ( -1344 0 744 1.347756 11.750000 ) ) +) + } + } +// brush 89 +{ +( 256 -464 256 ) ( 256 -448 256 ) ( 176 -448 256 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 176 -448 776 ) ( 256 -448 776 ) ( 256 -464 776 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( -1344 -448 1024 ) ( -1344 -464 1024 ) ( -1344 -464 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( -720 -464 1024 ) ( -640 -464 1024 ) ( -640 -464 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -496 1024 ) ( 0 -480 1024 ) ( 0 -480 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( 448 -448 1024 ) ( 368 -448 1024 ) ( 368 -448 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 90 +{ +( 256 448 256 ) ( 256 464 256 ) ( 176 464 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 176 464 776 ) ( 256 464 776 ) ( 256 448 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1344 464 1024 ) ( -1344 448 1024 ) ( -1344 448 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -528 448 1024 ) ( -448 448 1024 ) ( -448 448 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 416 1024 ) ( 0 432 1024 ) ( 0 432 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 256 464 1024 ) ( 176 464 1024 ) ( 176 464 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 91 +{ +( -1168 -448 256 ) ( -1168 -80 256 ) ( -1168 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1280 -448 256 ) ( -1168 -448 256 ) ( -1168 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -1296 -80 256 ) ( -1296 -448 256 ) ( -1296 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1168 -432 224 ) ( -1280 -432 224 ) ( -1280 -432 192 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1168 -80 256 ) ( -1168 -448 256 ) ( -1280 -448 256 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -1280 -448 224 ) ( -1168 -448 224 ) ( -1168 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +} +// brush 92 +{ +( -1240 -480 216 ) ( -1240 -552 216 ) ( -1240 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -992 -428 216 ) ( -664 -428 216 ) ( -664 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1256 -500 216 ) ( -1256 -428 216 ) ( -1256 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -688 -432 216 ) ( -1016 -432 216 ) ( -1016 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -640 -496 224 ) ( -640 -424 224 ) ( -968 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1248 -428 258 ) ( -1240 -428 232 ) ( -1240 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1248 -428 258 ) ( -1256 -432 232 ) ( -1256 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 93 +{ +( -1240 -428 220 ) ( -1240 -438 220 ) ( -1240 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1256 -428 220 ) ( -1240 -428 220 ) ( -1240 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1256 -438 220 ) ( -1256 -428 220 ) ( -1256 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1240 -448 220 ) ( -1256 -448 220 ) ( -1256 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1240 -438 220 ) ( -1240 -428 220 ) ( -1256 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1256 -428 224 ) ( -1240 -428 224 ) ( -1240 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 94 +{ +( -1208 -480 216 ) ( -1208 -552 216 ) ( -1208 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -960 -428 216 ) ( -632 -428 216 ) ( -632 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1224 -500 216 ) ( -1224 -428 216 ) ( -1224 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -656 -432 216 ) ( -984 -432 216 ) ( -984 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -608 -496 224 ) ( -608 -424 224 ) ( -936 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1216 -428 258 ) ( -1208 -428 232 ) ( -1208 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1216 -428 258 ) ( -1224 -432 232 ) ( -1224 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 95 +{ +( -1208 -428 220 ) ( -1208 -438 220 ) ( -1208 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1224 -428 220 ) ( -1208 -428 220 ) ( -1208 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1224 -438 220 ) ( -1224 -428 220 ) ( -1224 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1208 -448 220 ) ( -1224 -448 220 ) ( -1224 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1208 -438 220 ) ( -1208 -428 220 ) ( -1224 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1224 -428 224 ) ( -1208 -428 224 ) ( -1208 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 96 +{ +( -1272 -480 216 ) ( -1272 -552 216 ) ( -1272 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1024 -428 216 ) ( -696 -428 216 ) ( -696 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1288 -500 216 ) ( -1288 -428 216 ) ( -1288 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -720 -432 216 ) ( -1048 -432 216 ) ( -1048 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -672 -496 224 ) ( -672 -424 224 ) ( -1000 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1280 -428 258 ) ( -1272 -428 232 ) ( -1272 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1280 -428 258 ) ( -1288 -432 232 ) ( -1288 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 97 +{ +( -1272 -428 220 ) ( -1272 -438 220 ) ( -1272 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1288 -428 220 ) ( -1272 -428 220 ) ( -1272 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1288 -438 220 ) ( -1288 -428 220 ) ( -1288 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1272 -448 220 ) ( -1288 -448 220 ) ( -1288 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1272 -438 220 ) ( -1272 -428 220 ) ( -1288 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1288 -428 224 ) ( -1272 -428 224 ) ( -1272 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 98 +{ +( -1176 -480 216 ) ( -1176 -552 216 ) ( -1176 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -928 -428 216 ) ( -600 -428 216 ) ( -600 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1192 -500 216 ) ( -1192 -428 216 ) ( -1192 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -624 -432 216 ) ( -952 -432 216 ) ( -952 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -576 -496 224 ) ( -576 -424 224 ) ( -904 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1184 -428 258 ) ( -1176 -428 232 ) ( -1176 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1184 -428 258 ) ( -1192 -432 232 ) ( -1192 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 99 +{ +( -1176 -428 220 ) ( -1176 -438 220 ) ( -1176 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1192 -428 220 ) ( -1176 -428 220 ) ( -1176 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1192 -438 220 ) ( -1192 -428 220 ) ( -1192 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1176 -448 220 ) ( -1192 -448 220 ) ( -1192 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1176 -438 220 ) ( -1176 -428 220 ) ( -1192 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1192 -428 224 ) ( -1176 -428 224 ) ( -1176 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 100 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 -448 256 0 0 ) ( -1264 -440 256 0 0.125000 ) ( -1264 -432 256 0 0.250000 ) ) +( ( -1264 -448 592 5.250000 0 ) ( -1264 -440 584 5.250000 0.125000 ) ( -1264 -440 584 5.250000 0.250000 ) ) +( ( -1264 -64 592 11.250000 0 ) ( -1264 -64 584 11.250000 0.125000 ) ( -1264 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 101 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 -432 256 0 0 ) ( -1200 -440 256 0 0.125000 ) ( -1200 -448 256 0 0.250000 ) ) +( ( -1200 -440 584 5.126524 0 ) ( -1200 -440 584 5.126524 0.125000 ) ( -1200 -448 592 5.126524 0.250000 ) ) +( ( -1200 -64 576 11.002853 0 ) ( -1200 -64 584 11.002853 0.125000 ) ( -1200 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 102 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 -448 256 0 0 ) ( -1232 -448 256 0 0.500000 ) ( -1264 -448 256 0 1 ) ) +( ( -1200 -448 592 5.250000 0 ) ( -1232 -448 592 5.250000 0.500000 ) ( -1264 -448 592 5.250000 1 ) ) +( ( -1200 -64 592 11.250000 0 ) ( -1232 -64 592 11.250000 0.500000 ) ( -1264 -64 592 11.250000 1 ) ) +) + } + } +// brush 103 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 -448 256 0 0 ) ( -1008 -448 256 0 0.500000 ) ( -1040 -448 256 0 1 ) ) +( ( -976 -448 592 5.250000 0 ) ( -1008 -448 592 5.250000 0.500000 ) ( -1040 -448 592 5.250000 1 ) ) +( ( -976 -64 592 11.250000 0 ) ( -1008 -64 592 11.250000 0.500000 ) ( -1040 -64 592 11.250000 1 ) ) +) + } + } +// brush 104 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 -432 256 0 0 ) ( -976 -440 256 0 0.125000 ) ( -976 -448 256 0 0.250000 ) ) +( ( -976 -440 584 5.126524 0 ) ( -976 -440 584 5.126524 0.125000 ) ( -976 -448 592 5.126524 0.250000 ) ) +( ( -976 -64 576 11.002853 0 ) ( -976 -64 584 11.002853 0.125000 ) ( -976 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 105 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 -448 256 0 0 ) ( -1040 -440 256 0 0.125000 ) ( -1040 -432 256 0 0.250000 ) ) +( ( -1040 -448 592 5.250000 0 ) ( -1040 -440 584 5.250000 0.125000 ) ( -1040 -440 584 5.250000 0.250000 ) ) +( ( -1040 -64 592 11.250000 0 ) ( -1040 -64 584 11.250000 0.125000 ) ( -1040 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 106 +{ +( -968 -428 224 ) ( -952 -428 224 ) ( -952 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -952 -438 220 ) ( -952 -428 220 ) ( -968 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -952 -448 220 ) ( -968 -448 220 ) ( -968 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -968 -438 220 ) ( -968 -428 220 ) ( -968 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -968 -428 220 ) ( -952 -428 220 ) ( -952 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -952 -428 220 ) ( -952 -438 220 ) ( -952 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 107 +{ +( -960 -428 258 ) ( -968 -432 232 ) ( -968 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -960 -428 258 ) ( -952 -428 232 ) ( -952 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -352 -496 224 ) ( -352 -424 224 ) ( -680 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -400 -432 216 ) ( -728 -432 216 ) ( -728 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -968 -500 216 ) ( -968 -428 216 ) ( -968 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -704 -428 216 ) ( -376 -428 216 ) ( -376 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -952 -480 216 ) ( -952 -552 216 ) ( -952 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 108 +{ +( -1064 -428 224 ) ( -1048 -428 224 ) ( -1048 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1048 -438 220 ) ( -1048 -428 220 ) ( -1064 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1048 -448 220 ) ( -1064 -448 220 ) ( -1064 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1064 -438 220 ) ( -1064 -428 220 ) ( -1064 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1064 -428 220 ) ( -1048 -428 220 ) ( -1048 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1048 -428 220 ) ( -1048 -438 220 ) ( -1048 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 109 +{ +( -1056 -428 258 ) ( -1064 -432 232 ) ( -1064 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1056 -428 258 ) ( -1048 -428 232 ) ( -1048 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -448 -496 224 ) ( -448 -424 224 ) ( -776 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -496 -432 216 ) ( -824 -432 216 ) ( -824 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1064 -500 216 ) ( -1064 -428 216 ) ( -1064 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -800 -428 216 ) ( -472 -428 216 ) ( -472 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1048 -480 216 ) ( -1048 -552 216 ) ( -1048 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 110 +{ +( -1000 -428 224 ) ( -984 -428 224 ) ( -984 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -984 -438 220 ) ( -984 -428 220 ) ( -1000 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -984 -448 220 ) ( -1000 -448 220 ) ( -1000 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1000 -438 220 ) ( -1000 -428 220 ) ( -1000 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1000 -428 220 ) ( -984 -428 220 ) ( -984 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -984 -428 220 ) ( -984 -438 220 ) ( -984 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 111 +{ +( -992 -428 258 ) ( -1000 -432 232 ) ( -1000 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -992 -428 258 ) ( -984 -428 232 ) ( -984 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -384 -496 224 ) ( -384 -424 224 ) ( -712 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -432 -432 216 ) ( -760 -432 216 ) ( -760 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1000 -500 216 ) ( -1000 -428 216 ) ( -1000 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -736 -428 216 ) ( -408 -428 216 ) ( -408 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -984 -480 216 ) ( -984 -552 216 ) ( -984 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 112 +{ +( -1032 -428 224 ) ( -1016 -428 224 ) ( -1016 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1016 -438 220 ) ( -1016 -428 220 ) ( -1032 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1016 -448 220 ) ( -1032 -448 220 ) ( -1032 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1032 -438 220 ) ( -1032 -428 220 ) ( -1032 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1032 -428 220 ) ( -1016 -428 220 ) ( -1016 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1016 -428 220 ) ( -1016 -438 220 ) ( -1016 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 113 +{ +( -1024 -428 258 ) ( -1032 -432 232 ) ( -1032 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1024 -428 258 ) ( -1016 -428 232 ) ( -1016 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -416 -496 224 ) ( -416 -424 224 ) ( -744 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -464 -432 216 ) ( -792 -432 216 ) ( -792 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1032 -500 216 ) ( -1032 -428 216 ) ( -1032 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -768 -428 216 ) ( -440 -428 216 ) ( -440 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1016 -480 216 ) ( -1016 -552 216 ) ( -1016 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 114 +{ +( -1056 -448 224 ) ( -944 -448 224 ) ( -944 -80 224 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -944 -80 256 ) ( -944 -448 256 ) ( -1056 -448 256 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -944 -432 224 ) ( -1056 -432 224 ) ( -1056 -432 192 ) base_trim/spidertrim -64 0 -180 0.500000 -0.500000 0 0 0 +( -1072 -80 256 ) ( -1072 -448 256 ) ( -1072 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1056 -448 256 ) ( -944 -448 256 ) ( -944 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -944 -448 256 ) ( -944 -80 256 ) ( -944 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 115 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 -432 256 0 0 ) ( -1008 -432 256 0 0.250000 ) ( -976 -432 256 0 0.500001 ) ) +( ( -1040 -440 584 5.000002 0 ) ( -1008 -440 584 5.000002 0.250000 ) ( -976 -440 584 5.000002 0.500001 ) ) +( ( -1040 -64 576 10.750113 0 ) ( -1008 -64 576 10.750113 0.250000 ) ( -976 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 116 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 -432 256 0 0 ) ( -784 -432 256 0 0.250000 ) ( -752 -432 256 0 0.500001 ) ) +( ( -816 -440 584 5.000002 0 ) ( -784 -440 584 5.000002 0.250000 ) ( -752 -440 584 5.000002 0.500001 ) ) +( ( -816 -64 576 10.750113 0 ) ( -784 -64 576 10.750113 0.250000 ) ( -752 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 117 +{ +( -832 -448 224 ) ( -720 -448 224 ) ( -720 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -720 -80 256 ) ( -720 -448 256 ) ( -832 -448 256 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -720 -432 224 ) ( -832 -432 224 ) ( -832 -432 192 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -848 -80 256 ) ( -848 -448 256 ) ( -848 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -832 -448 256 ) ( -720 -448 256 ) ( -720 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -720 -448 256 ) ( -720 -80 256 ) ( -720 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 118 +{ +( -800 -428 258 ) ( -808 -432 232 ) ( -808 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -800 -428 258 ) ( -792 -428 232 ) ( -792 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -192 -496 224 ) ( -192 -424 224 ) ( -520 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -240 -432 216 ) ( -568 -432 216 ) ( -568 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -808 -500 216 ) ( -808 -428 216 ) ( -808 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -544 -428 216 ) ( -216 -428 216 ) ( -216 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -792 -480 216 ) ( -792 -552 216 ) ( -792 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 119 +{ +( -808 -428 224 ) ( -792 -428 224 ) ( -792 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -792 -438 220 ) ( -792 -428 220 ) ( -808 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -792 -448 220 ) ( -808 -448 220 ) ( -808 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -808 -438 220 ) ( -808 -428 220 ) ( -808 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -808 -428 220 ) ( -792 -428 220 ) ( -792 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -792 -428 220 ) ( -792 -438 220 ) ( -792 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 120 +{ +( -768 -428 258 ) ( -776 -432 232 ) ( -776 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -768 -428 258 ) ( -760 -428 232 ) ( -760 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -160 -496 224 ) ( -160 -424 224 ) ( -488 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -208 -432 216 ) ( -536 -432 216 ) ( -536 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -776 -500 216 ) ( -776 -428 216 ) ( -776 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -512 -428 216 ) ( -184 -428 216 ) ( -184 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -760 -480 216 ) ( -760 -552 216 ) ( -760 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 121 +{ +( -776 -428 224 ) ( -760 -428 224 ) ( -760 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -760 -438 220 ) ( -760 -428 220 ) ( -776 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -760 -448 220 ) ( -776 -448 220 ) ( -776 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -776 -438 220 ) ( -776 -428 220 ) ( -776 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -776 -428 220 ) ( -760 -428 220 ) ( -760 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -760 -428 220 ) ( -760 -438 220 ) ( -760 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 122 +{ +( -832 -428 258 ) ( -840 -432 232 ) ( -840 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -832 -428 258 ) ( -824 -428 232 ) ( -824 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -224 -496 224 ) ( -224 -424 224 ) ( -552 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -272 -432 216 ) ( -600 -432 216 ) ( -600 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -840 -500 216 ) ( -840 -428 216 ) ( -840 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -576 -428 216 ) ( -248 -428 216 ) ( -248 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -824 -480 216 ) ( -824 -552 216 ) ( -824 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 123 +{ +( -840 -428 224 ) ( -824 -428 224 ) ( -824 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -824 -438 220 ) ( -824 -428 220 ) ( -840 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -824 -448 220 ) ( -840 -448 220 ) ( -840 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -840 -438 220 ) ( -840 -428 220 ) ( -840 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -840 -428 220 ) ( -824 -428 220 ) ( -824 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -824 -428 220 ) ( -824 -438 220 ) ( -824 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 124 +{ +( -736 -428 258 ) ( -744 -432 232 ) ( -744 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -736 -428 258 ) ( -728 -428 232 ) ( -728 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -128 -496 224 ) ( -128 -424 224 ) ( -456 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -176 -432 216 ) ( -504 -432 216 ) ( -504 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -744 -500 216 ) ( -744 -428 216 ) ( -744 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -480 -428 216 ) ( -152 -428 216 ) ( -152 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -728 -480 216 ) ( -728 -552 216 ) ( -728 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 125 +{ +( -744 -428 224 ) ( -728 -428 224 ) ( -728 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -728 -438 220 ) ( -728 -428 220 ) ( -744 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -728 -448 220 ) ( -744 -448 220 ) ( -744 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -744 -438 220 ) ( -744 -428 220 ) ( -744 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -744 -428 220 ) ( -728 -428 220 ) ( -728 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -728 -428 220 ) ( -728 -438 220 ) ( -728 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 126 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 -448 256 0 0 ) ( -816 -440 256 0 0.125000 ) ( -816 -432 256 0 0.250000 ) ) +( ( -816 -448 592 5.250000 0 ) ( -816 -440 584 5.250000 0.125000 ) ( -816 -440 584 5.250000 0.250000 ) ) +( ( -816 -64 592 11.250000 0 ) ( -816 -64 584 11.250000 0.125000 ) ( -816 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 127 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 -432 256 0 0 ) ( -752 -440 256 0 0.125000 ) ( -752 -448 256 0 0.250000 ) ) +( ( -752 -440 584 5.126524 0 ) ( -752 -440 584 5.126524 0.125000 ) ( -752 -448 592 5.126524 0.250000 ) ) +( ( -752 -64 576 11.002853 0 ) ( -752 -64 584 11.002853 0.125000 ) ( -752 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 128 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 -448 256 0 0 ) ( -784 -448 256 0 0.500000 ) ( -816 -448 256 0 1 ) ) +( ( -752 -448 592 5.250000 0 ) ( -784 -448 592 5.250000 0.500000 ) ( -816 -448 592 5.250000 1 ) ) +( ( -752 -64 592 11.250000 0 ) ( -784 -64 592 11.250000 0.500000 ) ( -816 -64 592 11.250000 1 ) ) +) + } + } +// brush 129 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 -448 256 0 0 ) ( -560 -448 256 0 0.500000 ) ( -592 -448 256 0 1 ) ) +( ( -528 -448 592 5.250000 0 ) ( -560 -448 592 5.250000 0.500000 ) ( -592 -448 592 5.250000 1 ) ) +( ( -528 -64 592 11.250000 0 ) ( -560 -64 592 11.250000 0.500000 ) ( -592 -64 592 11.250000 1 ) ) +) + } + } +// brush 130 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 -432 256 0 0 ) ( -528 -440 256 0 0.125000 ) ( -528 -448 256 0 0.250000 ) ) +( ( -528 -440 584 5.126524 0 ) ( -528 -440 584 5.126524 0.125000 ) ( -528 -448 592 5.126524 0.250000 ) ) +( ( -528 -64 576 11.002853 0 ) ( -528 -64 584 11.002853 0.125000 ) ( -528 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 131 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 -448 256 0 0 ) ( -592 -440 256 0 0.125000 ) ( -592 -432 256 0 0.250000 ) ) +( ( -592 -448 592 5.250000 0 ) ( -592 -440 584 5.250000 0.125000 ) ( -592 -440 584 5.250000 0.250000 ) ) +( ( -592 -64 592 11.250000 0 ) ( -592 -64 584 11.250000 0.125000 ) ( -592 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 132 +{ +( -520 -428 224 ) ( -504 -428 224 ) ( -504 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -504 -438 220 ) ( -504 -428 220 ) ( -520 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -504 -448 220 ) ( -520 -448 220 ) ( -520 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -520 -438 220 ) ( -520 -428 220 ) ( -520 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -520 -428 220 ) ( -504 -428 220 ) ( -504 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -504 -428 220 ) ( -504 -438 220 ) ( -504 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 133 +{ +( -512 -428 258 ) ( -520 -432 232 ) ( -520 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -512 -428 258 ) ( -504 -428 232 ) ( -504 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 96 -496 224 ) ( 96 -424 224 ) ( -232 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 48 -432 216 ) ( -280 -432 216 ) ( -280 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -520 -500 216 ) ( -520 -428 216 ) ( -520 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -256 -428 216 ) ( 72 -428 216 ) ( 72 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -504 -480 216 ) ( -504 -552 216 ) ( -504 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 134 +{ +( -616 -428 224 ) ( -600 -428 224 ) ( -600 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -600 -438 220 ) ( -600 -428 220 ) ( -616 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -600 -448 220 ) ( -616 -448 220 ) ( -616 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -616 -438 220 ) ( -616 -428 220 ) ( -616 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -616 -428 220 ) ( -600 -428 220 ) ( -600 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -600 -428 220 ) ( -600 -438 220 ) ( -600 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 135 +{ +( -608 -428 258 ) ( -616 -432 232 ) ( -616 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -608 -428 258 ) ( -600 -428 232 ) ( -600 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 0 -496 224 ) ( 0 -424 224 ) ( -328 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -48 -432 216 ) ( -376 -432 216 ) ( -376 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -616 -500 216 ) ( -616 -428 216 ) ( -616 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -352 -428 216 ) ( -24 -428 216 ) ( -24 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -600 -480 216 ) ( -600 -552 216 ) ( -600 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 136 +{ +( -552 -428 224 ) ( -536 -428 224 ) ( -536 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -536 -438 220 ) ( -536 -428 220 ) ( -552 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -536 -448 220 ) ( -552 -448 220 ) ( -552 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -552 -438 220 ) ( -552 -428 220 ) ( -552 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -552 -428 220 ) ( -536 -428 220 ) ( -536 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -536 -428 220 ) ( -536 -438 220 ) ( -536 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 137 +{ +( -544 -428 258 ) ( -552 -432 232 ) ( -552 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -544 -428 258 ) ( -536 -428 232 ) ( -536 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 64 -496 224 ) ( 64 -424 224 ) ( -264 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 16 -432 216 ) ( -312 -432 216 ) ( -312 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -552 -500 216 ) ( -552 -428 216 ) ( -552 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -288 -428 216 ) ( 40 -428 216 ) ( 40 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -536 -480 216 ) ( -536 -552 216 ) ( -536 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 138 +{ +( -584 -428 224 ) ( -568 -428 224 ) ( -568 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -568 -438 220 ) ( -568 -428 220 ) ( -584 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -568 -448 220 ) ( -584 -448 220 ) ( -584 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -584 -438 220 ) ( -584 -428 220 ) ( -584 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -584 -428 220 ) ( -568 -428 220 ) ( -568 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -568 -428 220 ) ( -568 -438 220 ) ( -568 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 139 +{ +( -576 -428 258 ) ( -584 -432 232 ) ( -584 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -576 -428 258 ) ( -568 -428 232 ) ( -568 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 32 -496 224 ) ( 32 -424 224 ) ( -296 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -16 -432 216 ) ( -344 -432 216 ) ( -344 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -584 -500 216 ) ( -584 -428 216 ) ( -584 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -320 -428 216 ) ( 8 -428 216 ) ( 8 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -568 -480 216 ) ( -568 -552 216 ) ( -568 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 140 +{ +( -608 -448 224 ) ( -496 -448 224 ) ( -496 -80 224 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -496 -80 256 ) ( -496 -448 256 ) ( -608 -448 256 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -496 -432 224 ) ( -608 -432 224 ) ( -608 -432 192 ) base_trim/spidertrim -64 0 -180 0.500000 -0.500000 0 0 0 +( -624 -80 256 ) ( -624 -448 256 ) ( -624 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -608 -448 256 ) ( -496 -448 256 ) ( -496 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -496 -448 256 ) ( -496 -80 256 ) ( -496 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 141 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 -432 256 0 0 ) ( -560 -432 256 0 0.250000 ) ( -528 -432 256 0 0.500001 ) ) +( ( -592 -440 584 5.000002 0 ) ( -560 -440 584 5.000002 0.250000 ) ( -528 -440 584 5.000002 0.500001 ) ) +( ( -592 -64 576 10.750113 0 ) ( -560 -64 576 10.750113 0.250000 ) ( -528 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 142 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 -432 256 0 0 ) ( -336 -432 256 0 0.250000 ) ( -304 -432 256 0 0.500001 ) ) +( ( -368 -440 584 5.000002 0 ) ( -336 -440 584 5.000002 0.250000 ) ( -304 -440 584 5.000002 0.500001 ) ) +( ( -368 -64 576 10.750113 0 ) ( -336 -64 576 10.750113 0.250000 ) ( -304 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 143 +{ +( -384 -448 224 ) ( -272 -448 224 ) ( -272 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -272 -80 256 ) ( -272 -448 256 ) ( -384 -448 256 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -272 -432 224 ) ( -384 -432 224 ) ( -384 -432 192 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -400 -80 256 ) ( -400 -448 256 ) ( -400 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -384 -448 256 ) ( -272 -448 256 ) ( -272 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -272 -448 256 ) ( -272 -80 256 ) ( -272 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 144 +{ +( -352 -428 258 ) ( -360 -432 232 ) ( -360 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -352 -428 258 ) ( -344 -428 232 ) ( -344 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 256 -496 224 ) ( 256 -424 224 ) ( -72 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 208 -432 216 ) ( -120 -432 216 ) ( -120 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -360 -500 216 ) ( -360 -428 216 ) ( -360 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -96 -428 216 ) ( 232 -428 216 ) ( 232 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -344 -480 216 ) ( -344 -552 216 ) ( -344 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 145 +{ +( -360 -428 224 ) ( -344 -428 224 ) ( -344 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -344 -438 220 ) ( -344 -428 220 ) ( -360 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -344 -448 220 ) ( -360 -448 220 ) ( -360 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -360 -438 220 ) ( -360 -428 220 ) ( -360 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -360 -428 220 ) ( -344 -428 220 ) ( -344 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -344 -428 220 ) ( -344 -438 220 ) ( -344 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 146 +{ +( -320 -428 258 ) ( -328 -432 232 ) ( -328 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -320 -428 258 ) ( -312 -428 232 ) ( -312 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 288 -496 224 ) ( 288 -424 224 ) ( -40 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 240 -432 216 ) ( -88 -432 216 ) ( -88 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -328 -500 216 ) ( -328 -428 216 ) ( -328 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -64 -428 216 ) ( 264 -428 216 ) ( 264 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -312 -480 216 ) ( -312 -552 216 ) ( -312 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 147 +{ +( -328 -428 224 ) ( -312 -428 224 ) ( -312 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -312 -438 220 ) ( -312 -428 220 ) ( -328 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -312 -448 220 ) ( -328 -448 220 ) ( -328 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -328 -438 220 ) ( -328 -428 220 ) ( -328 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -328 -428 220 ) ( -312 -428 220 ) ( -312 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -312 -428 220 ) ( -312 -438 220 ) ( -312 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 148 +{ +( -384 -428 258 ) ( -392 -432 232 ) ( -392 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -384 -428 258 ) ( -376 -428 232 ) ( -376 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 224 -496 224 ) ( 224 -424 224 ) ( -104 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 176 -432 216 ) ( -152 -432 216 ) ( -152 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -392 -500 216 ) ( -392 -428 216 ) ( -392 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -128 -428 216 ) ( 200 -428 216 ) ( 200 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -376 -480 216 ) ( -376 -552 216 ) ( -376 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 149 +{ +( -392 -428 224 ) ( -376 -428 224 ) ( -376 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -376 -438 220 ) ( -376 -428 220 ) ( -392 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -376 -448 220 ) ( -392 -448 220 ) ( -392 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -392 -438 220 ) ( -392 -428 220 ) ( -392 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -392 -428 220 ) ( -376 -428 220 ) ( -376 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -376 -428 220 ) ( -376 -438 220 ) ( -376 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 150 +{ +( -288 -428 258 ) ( -296 -432 232 ) ( -296 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -288 -428 258 ) ( -280 -428 232 ) ( -280 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 320 -496 224 ) ( 320 -424 224 ) ( -8 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 272 -432 216 ) ( -56 -432 216 ) ( -56 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -296 -500 216 ) ( -296 -428 216 ) ( -296 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -32 -428 216 ) ( 296 -428 216 ) ( 296 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -280 -480 216 ) ( -280 -552 216 ) ( -280 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 151 +{ +( -296 -428 224 ) ( -280 -428 224 ) ( -280 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -280 -438 220 ) ( -280 -428 220 ) ( -296 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -280 -448 220 ) ( -296 -448 220 ) ( -296 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -296 -438 220 ) ( -296 -428 220 ) ( -296 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -296 -428 220 ) ( -280 -428 220 ) ( -280 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -280 -428 220 ) ( -280 -438 220 ) ( -280 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 152 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 -448 256 0 0 ) ( -368 -440 256 0 0.125000 ) ( -368 -432 256 0 0.250000 ) ) +( ( -368 -448 592 5.250000 0 ) ( -368 -440 584 5.250000 0.125000 ) ( -368 -440 584 5.250000 0.250000 ) ) +( ( -368 -64 592 11.250000 0 ) ( -368 -64 584 11.250000 0.125000 ) ( -368 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 153 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 -432 256 0 0 ) ( -304 -440 256 0 0.125000 ) ( -304 -448 256 0 0.250000 ) ) +( ( -304 -440 584 5.126524 0 ) ( -304 -440 584 5.126524 0.125000 ) ( -304 -448 592 5.126524 0.250000 ) ) +( ( -304 -64 576 11.002853 0 ) ( -304 -64 584 11.002853 0.125000 ) ( -304 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 154 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 -448 256 0 0 ) ( -336 -448 256 0 0.500000 ) ( -368 -448 256 0 1 ) ) +( ( -304 -448 592 5.250000 0 ) ( -336 -448 592 5.250000 0.500000 ) ( -368 -448 592 5.250000 1 ) ) +( ( -304 -64 592 11.250000 0 ) ( -336 -64 592 11.250000 0.500000 ) ( -368 -64 592 11.250000 1 ) ) +) + } + } +// brush 155 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 -448 256 0 0 ) ( -112 -448 256 0 0.500000 ) ( -144 -448 256 0 1 ) ) +( ( -80 -448 592 5.250000 0 ) ( -112 -448 592 5.250000 0.500000 ) ( -144 -448 592 5.250000 1 ) ) +( ( -80 -64 592 11.250000 0 ) ( -112 -64 592 11.250000 0.500000 ) ( -144 -64 592 11.250000 1 ) ) +) + } + } +// brush 156 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 -432 256 0 0 ) ( -80 -440 256 0 0.125000 ) ( -80 -448 256 0 0.250000 ) ) +( ( -80 -440 584 5.126524 0 ) ( -80 -440 584 5.126524 0.125000 ) ( -80 -448 592 5.126524 0.250000 ) ) +( ( -80 -64 576 11.002853 0 ) ( -80 -64 584 11.002853 0.125000 ) ( -80 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 157 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 -448 256 0 0 ) ( -144 -440 256 0 0.125000 ) ( -144 -432 256 0 0.250000 ) ) +( ( -144 -448 592 5.250000 0 ) ( -144 -440 584 5.250000 0.125000 ) ( -144 -440 584 5.250000 0.250000 ) ) +( ( -144 -64 592 11.250000 0 ) ( -144 -64 584 11.250000 0.125000 ) ( -144 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 158 +{ +( -72 -428 224 ) ( -56 -428 224 ) ( -56 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -56 -438 220 ) ( -56 -428 220 ) ( -72 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -56 -448 220 ) ( -72 -448 220 ) ( -72 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -72 -438 220 ) ( -72 -428 220 ) ( -72 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -72 -428 220 ) ( -56 -428 220 ) ( -56 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -56 -428 220 ) ( -56 -438 220 ) ( -56 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 159 +{ +( -64 -428 258 ) ( -72 -432 232 ) ( -72 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -64 -428 258 ) ( -56 -428 232 ) ( -56 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 544 -496 224 ) ( 544 -424 224 ) ( 216 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 496 -432 216 ) ( 168 -432 216 ) ( 168 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -72 -500 216 ) ( -72 -428 216 ) ( -72 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 192 -428 216 ) ( 520 -428 216 ) ( 520 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -56 -480 216 ) ( -56 -552 216 ) ( -56 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 160 +{ +( -168 -428 224 ) ( -152 -428 224 ) ( -152 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -152 -438 220 ) ( -152 -428 220 ) ( -168 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -152 -448 220 ) ( -168 -448 220 ) ( -168 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -168 -438 220 ) ( -168 -428 220 ) ( -168 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -168 -428 220 ) ( -152 -428 220 ) ( -152 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -152 -428 220 ) ( -152 -438 220 ) ( -152 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 161 +{ +( -160 -428 258 ) ( -168 -432 232 ) ( -168 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -160 -428 258 ) ( -152 -428 232 ) ( -152 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 448 -496 224 ) ( 448 -424 224 ) ( 120 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 400 -432 216 ) ( 72 -432 216 ) ( 72 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -168 -500 216 ) ( -168 -428 216 ) ( -168 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 96 -428 216 ) ( 424 -428 216 ) ( 424 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -152 -480 216 ) ( -152 -552 216 ) ( -152 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 162 +{ +( -104 -428 224 ) ( -88 -428 224 ) ( -88 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -88 -438 220 ) ( -88 -428 220 ) ( -104 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -88 -448 220 ) ( -104 -448 220 ) ( -104 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -104 -438 220 ) ( -104 -428 220 ) ( -104 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -104 -428 220 ) ( -88 -428 220 ) ( -88 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -88 -428 220 ) ( -88 -438 220 ) ( -88 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 163 +{ +( -96 -428 258 ) ( -104 -432 232 ) ( -104 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -96 -428 258 ) ( -88 -428 232 ) ( -88 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 512 -496 224 ) ( 512 -424 224 ) ( 184 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 464 -432 216 ) ( 136 -432 216 ) ( 136 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -104 -500 216 ) ( -104 -428 216 ) ( -104 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 160 -428 216 ) ( 488 -428 216 ) ( 488 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -88 -480 216 ) ( -88 -552 216 ) ( -88 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 164 +{ +( -136 -428 224 ) ( -120 -428 224 ) ( -120 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -120 -438 220 ) ( -120 -428 220 ) ( -136 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -120 -448 220 ) ( -136 -448 220 ) ( -136 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -136 -438 220 ) ( -136 -428 220 ) ( -136 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -136 -428 220 ) ( -120 -428 220 ) ( -120 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -120 -428 220 ) ( -120 -438 220 ) ( -120 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 165 +{ +( -128 -428 258 ) ( -136 -432 232 ) ( -136 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -128 -428 258 ) ( -120 -428 232 ) ( -120 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 480 -496 224 ) ( 480 -424 224 ) ( 152 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 432 -432 216 ) ( 104 -432 216 ) ( 104 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -136 -500 216 ) ( -136 -428 216 ) ( -136 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 128 -428 216 ) ( 456 -428 216 ) ( 456 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -120 -480 216 ) ( -120 -552 216 ) ( -120 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 166 +{ +( -160 -448 224 ) ( -48 -448 224 ) ( -48 -80 224 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -48 -80 256 ) ( -48 -448 256 ) ( -160 -448 256 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -48 -432 224 ) ( -160 -432 224 ) ( -160 -432 192 ) base_trim/spidertrim -64 0 -180 0.500000 -0.500000 0 0 0 +( -176 -80 256 ) ( -176 -448 256 ) ( -176 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -160 -448 256 ) ( -48 -448 256 ) ( -48 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -48 -448 256 ) ( -48 -80 256 ) ( -48 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 167 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 -432 256 0 0 ) ( -112 -432 256 0 0.250000 ) ( -80 -432 256 0 0.500001 ) ) +( ( -144 -440 584 5.000002 0 ) ( -112 -440 584 5.000002 0.250000 ) ( -80 -440 584 5.000002 0.500001 ) ) +( ( -144 -64 576 10.750113 0 ) ( -112 -64 576 10.750113 0.250000 ) ( -80 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 168 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 432 256 0 0 ) ( -1232 432 256 0 0.250000 ) ( -1264 432 256 0 0.500001 ) ) +( ( -1200 440 584 5.000002 0 ) ( -1232 440 584 5.000002 0.250000 ) ( -1264 440 584 5.000002 0.500001 ) ) +( ( -1200 64 576 10.750113 0 ) ( -1232 64 576 10.750113 0.250000 ) ( -1264 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 169 +{ +( -1184 448 224 ) ( -1296 448 224 ) ( -1296 80 224 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1296 80 256 ) ( -1296 448 256 ) ( -1184 448 256 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1296 432 224 ) ( -1184 432 224 ) ( -1184 432 192 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1168 80 256 ) ( -1168 448 256 ) ( -1168 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1184 448 256 ) ( -1296 448 256 ) ( -1296 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1296 448 256 ) ( -1296 80 256 ) ( -1296 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 170 +{ +( -1216 428 258 ) ( -1208 432 232 ) ( -1208 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1216 428 258 ) ( -1224 428 232 ) ( -1224 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1824 496 224 ) ( -1824 424 224 ) ( -1496 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1776 432 216 ) ( -1448 432 216 ) ( -1448 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1208 500 216 ) ( -1208 428 216 ) ( -1208 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1472 428 216 ) ( -1800 428 216 ) ( -1800 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1224 480 216 ) ( -1224 552 216 ) ( -1224 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 171 +{ +( -1208 428 224 ) ( -1224 428 224 ) ( -1224 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1224 438 220 ) ( -1224 428 220 ) ( -1208 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1224 448 220 ) ( -1208 448 220 ) ( -1208 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1208 438 220 ) ( -1208 428 220 ) ( -1208 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1208 428 220 ) ( -1224 428 220 ) ( -1224 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1224 428 220 ) ( -1224 438 220 ) ( -1224 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 172 +{ +( -1248 428 258 ) ( -1240 432 232 ) ( -1240 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1248 428 258 ) ( -1256 428 232 ) ( -1256 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1856 496 224 ) ( -1856 424 224 ) ( -1528 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1808 432 216 ) ( -1480 432 216 ) ( -1480 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1240 500 216 ) ( -1240 428 216 ) ( -1240 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1504 428 216 ) ( -1832 428 216 ) ( -1832 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 480 216 ) ( -1256 552 216 ) ( -1256 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 173 +{ +( -1240 428 224 ) ( -1256 428 224 ) ( -1256 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 438 220 ) ( -1256 428 220 ) ( -1240 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 448 220 ) ( -1240 448 220 ) ( -1240 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1240 438 220 ) ( -1240 428 220 ) ( -1240 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1240 428 220 ) ( -1256 428 220 ) ( -1256 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 428 220 ) ( -1256 438 220 ) ( -1256 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 174 +{ +( -1184 428 258 ) ( -1176 432 232 ) ( -1176 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1184 428 258 ) ( -1192 428 232 ) ( -1192 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1792 496 224 ) ( -1792 424 224 ) ( -1464 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1744 432 216 ) ( -1416 432 216 ) ( -1416 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1176 500 216 ) ( -1176 428 216 ) ( -1176 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1440 428 216 ) ( -1768 428 216 ) ( -1768 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1192 480 216 ) ( -1192 552 216 ) ( -1192 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 175 +{ +( -1176 428 224 ) ( -1192 428 224 ) ( -1192 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1192 438 220 ) ( -1192 428 220 ) ( -1176 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1192 448 220 ) ( -1176 448 220 ) ( -1176 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1176 438 220 ) ( -1176 428 220 ) ( -1176 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1176 428 220 ) ( -1192 428 220 ) ( -1192 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1192 428 220 ) ( -1192 438 220 ) ( -1192 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 176 +{ +( -1280 428 258 ) ( -1272 432 232 ) ( -1272 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1280 428 258 ) ( -1288 428 232 ) ( -1288 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1888 496 224 ) ( -1888 424 224 ) ( -1560 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1840 432 216 ) ( -1512 432 216 ) ( -1512 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1272 500 216 ) ( -1272 428 216 ) ( -1272 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1536 428 216 ) ( -1864 428 216 ) ( -1864 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1288 480 216 ) ( -1288 552 216 ) ( -1288 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 177 +{ +( -1272 428 224 ) ( -1288 428 224 ) ( -1288 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1288 438 220 ) ( -1288 428 220 ) ( -1272 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1288 448 220 ) ( -1272 448 220 ) ( -1272 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1272 438 220 ) ( -1272 428 220 ) ( -1272 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1272 428 220 ) ( -1288 428 220 ) ( -1288 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1288 428 220 ) ( -1288 438 220 ) ( -1288 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 178 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 448 256 0 0 ) ( -1200 440 256 0 0.125000 ) ( -1200 432 256 0 0.250000 ) ) +( ( -1200 448 592 5.250000 0 ) ( -1200 440 584 5.250000 0.125000 ) ( -1200 440 584 5.250000 0.250000 ) ) +( ( -1200 64 592 11.250000 0 ) ( -1200 64 584 11.250000 0.125000 ) ( -1200 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 179 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 432 256 0 0 ) ( -1264 440 256 0 0.125000 ) ( -1264 448 256 0 0.250000 ) ) +( ( -1264 440 584 5.126524 0 ) ( -1264 440 584 5.126524 0.125000 ) ( -1264 448 592 5.126524 0.250000 ) ) +( ( -1264 64 576 11.002853 0 ) ( -1264 64 584 11.002853 0.125000 ) ( -1264 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 180 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 448 256 0 0 ) ( -1232 448 256 0 0.500000 ) ( -1200 448 256 0 1 ) ) +( ( -1264 448 592 5.250000 0 ) ( -1232 448 592 5.250000 0.500000 ) ( -1200 448 592 5.250000 1 ) ) +( ( -1264 64 592 11.250000 0 ) ( -1232 64 592 11.250000 0.500000 ) ( -1200 64 592 11.250000 1 ) ) +) + } + } +// brush 181 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 448 256 0 0 ) ( -1008 448 256 0 0.500000 ) ( -976 448 256 0 1 ) ) +( ( -1040 448 592 5.250000 0 ) ( -1008 448 592 5.250000 0.500000 ) ( -976 448 592 5.250000 1 ) ) +( ( -1040 64 592 11.250000 0 ) ( -1008 64 592 11.250000 0.500000 ) ( -976 64 592 11.250000 1 ) ) +) + } + } +// brush 182 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 432 256 0 0 ) ( -1040 440 256 0 0.125000 ) ( -1040 448 256 0 0.250000 ) ) +( ( -1040 440 584 5.126524 0 ) ( -1040 440 584 5.126524 0.125000 ) ( -1040 448 592 5.126524 0.250000 ) ) +( ( -1040 64 576 11.002853 0 ) ( -1040 64 584 11.002853 0.125000 ) ( -1040 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 183 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 448 256 0 0 ) ( -976 440 256 0 0.125000 ) ( -976 432 256 0 0.250000 ) ) +( ( -976 448 592 5.250000 0 ) ( -976 440 584 5.250000 0.125000 ) ( -976 440 584 5.250000 0.250000 ) ) +( ( -976 64 592 11.250000 0 ) ( -976 64 584 11.250000 0.125000 ) ( -976 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 184 +{ +( -1048 428 224 ) ( -1064 428 224 ) ( -1064 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 438 220 ) ( -1064 428 220 ) ( -1048 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 448 220 ) ( -1048 448 220 ) ( -1048 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1048 438 220 ) ( -1048 428 220 ) ( -1048 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1048 428 220 ) ( -1064 428 220 ) ( -1064 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 428 220 ) ( -1064 438 220 ) ( -1064 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 185 +{ +( -1056 428 258 ) ( -1048 432 232 ) ( -1048 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1056 428 258 ) ( -1064 428 232 ) ( -1064 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1664 496 224 ) ( -1664 424 224 ) ( -1336 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1616 432 216 ) ( -1288 432 216 ) ( -1288 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1048 500 216 ) ( -1048 428 216 ) ( -1048 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1312 428 216 ) ( -1640 428 216 ) ( -1640 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 480 216 ) ( -1064 552 216 ) ( -1064 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 186 +{ +( -952 428 224 ) ( -968 428 224 ) ( -968 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 438 220 ) ( -968 428 220 ) ( -952 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 448 220 ) ( -952 448 220 ) ( -952 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -952 438 220 ) ( -952 428 220 ) ( -952 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -952 428 220 ) ( -968 428 220 ) ( -968 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 428 220 ) ( -968 438 220 ) ( -968 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 187 +{ +( -960 428 258 ) ( -952 432 232 ) ( -952 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -960 428 258 ) ( -968 428 232 ) ( -968 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1568 496 224 ) ( -1568 424 224 ) ( -1240 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1520 432 216 ) ( -1192 432 216 ) ( -1192 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -952 500 216 ) ( -952 428 216 ) ( -952 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1216 428 216 ) ( -1544 428 216 ) ( -1544 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 480 216 ) ( -968 552 216 ) ( -968 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 188 +{ +( -1016 428 224 ) ( -1032 428 224 ) ( -1032 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1032 438 220 ) ( -1032 428 220 ) ( -1016 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1032 448 220 ) ( -1016 448 220 ) ( -1016 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1016 438 220 ) ( -1016 428 220 ) ( -1016 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1016 428 220 ) ( -1032 428 220 ) ( -1032 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1032 428 220 ) ( -1032 438 220 ) ( -1032 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 189 +{ +( -1024 428 258 ) ( -1016 432 232 ) ( -1016 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1024 428 258 ) ( -1032 428 232 ) ( -1032 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1632 496 224 ) ( -1632 424 224 ) ( -1304 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1584 432 216 ) ( -1256 432 216 ) ( -1256 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1016 500 216 ) ( -1016 428 216 ) ( -1016 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1280 428 216 ) ( -1608 428 216 ) ( -1608 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1032 480 216 ) ( -1032 552 216 ) ( -1032 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 190 +{ +( -984 428 224 ) ( -1000 428 224 ) ( -1000 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 438 220 ) ( -1000 428 220 ) ( -984 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 448 220 ) ( -984 448 220 ) ( -984 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -984 438 220 ) ( -984 428 220 ) ( -984 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -984 428 220 ) ( -1000 428 220 ) ( -1000 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 428 220 ) ( -1000 438 220 ) ( -1000 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 191 +{ +( -992 428 258 ) ( -984 432 232 ) ( -984 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -992 428 258 ) ( -1000 428 232 ) ( -1000 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1600 496 224 ) ( -1600 424 224 ) ( -1272 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1552 432 216 ) ( -1224 432 216 ) ( -1224 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -984 500 216 ) ( -984 428 216 ) ( -984 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1248 428 216 ) ( -1576 428 216 ) ( -1576 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 480 216 ) ( -1000 552 216 ) ( -1000 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 192 +{ +( -960 448 224 ) ( -1072 448 224 ) ( -1072 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1072 80 256 ) ( -1072 448 256 ) ( -960 448 256 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1072 432 224 ) ( -960 432 224 ) ( -960 432 192 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -944 80 256 ) ( -944 448 256 ) ( -944 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -960 448 256 ) ( -1072 448 256 ) ( -1072 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1072 448 256 ) ( -1072 80 256 ) ( -1072 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 193 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 432 256 0 0 ) ( -1008 432 256 0 0.250000 ) ( -1040 432 256 0 0.500001 ) ) +( ( -976 440 584 5.000002 0 ) ( -1008 440 584 5.000002 0.250000 ) ( -1040 440 584 5.000002 0.500001 ) ) +( ( -976 64 576 10.750113 0 ) ( -1008 64 576 10.750113 0.250000 ) ( -1040 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 194 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 432 256 0 0 ) ( -784 432 256 0 0.250000 ) ( -816 432 256 0 0.500001 ) ) +( ( -752 440 584 5.000002 0 ) ( -784 440 584 5.000002 0.250000 ) ( -816 440 584 5.000002 0.500001 ) ) +( ( -752 64 576 10.750113 0 ) ( -784 64 576 10.750113 0.250000 ) ( -816 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 195 +{ +( -736 448 224 ) ( -848 448 224 ) ( -848 80 224 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -848 80 256 ) ( -848 448 256 ) ( -736 448 256 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -848 432 224 ) ( -736 432 224 ) ( -736 432 192 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -720 80 256 ) ( -720 448 256 ) ( -720 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -736 448 256 ) ( -848 448 256 ) ( -848 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -848 448 256 ) ( -848 80 256 ) ( -848 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 196 +{ +( -768 428 258 ) ( -760 432 232 ) ( -760 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -768 428 258 ) ( -776 428 232 ) ( -776 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1376 496 224 ) ( -1376 424 224 ) ( -1048 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1328 432 216 ) ( -1000 432 216 ) ( -1000 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -760 500 216 ) ( -760 428 216 ) ( -760 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1024 428 216 ) ( -1352 428 216 ) ( -1352 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -776 480 216 ) ( -776 552 216 ) ( -776 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 197 +{ +( -760 428 224 ) ( -776 428 224 ) ( -776 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -776 438 220 ) ( -776 428 220 ) ( -760 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -776 448 220 ) ( -760 448 220 ) ( -760 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -760 438 220 ) ( -760 428 220 ) ( -760 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -760 428 220 ) ( -776 428 220 ) ( -776 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -776 428 220 ) ( -776 438 220 ) ( -776 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 198 +{ +( -800 428 258 ) ( -792 432 232 ) ( -792 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -800 428 258 ) ( -808 428 232 ) ( -808 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1408 496 224 ) ( -1408 424 224 ) ( -1080 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1360 432 216 ) ( -1032 432 216 ) ( -1032 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -792 500 216 ) ( -792 428 216 ) ( -792 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1056 428 216 ) ( -1384 428 216 ) ( -1384 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 480 216 ) ( -808 552 216 ) ( -808 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 199 +{ +( -792 428 224 ) ( -808 428 224 ) ( -808 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 438 220 ) ( -808 428 220 ) ( -792 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 448 220 ) ( -792 448 220 ) ( -792 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -792 438 220 ) ( -792 428 220 ) ( -792 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -792 428 220 ) ( -808 428 220 ) ( -808 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 428 220 ) ( -808 438 220 ) ( -808 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 200 +{ +( -736 428 258 ) ( -728 432 232 ) ( -728 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -736 428 258 ) ( -744 428 232 ) ( -744 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1344 496 224 ) ( -1344 424 224 ) ( -1016 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1296 432 216 ) ( -968 432 216 ) ( -968 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -728 500 216 ) ( -728 428 216 ) ( -728 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -992 428 216 ) ( -1320 428 216 ) ( -1320 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -744 480 216 ) ( -744 552 216 ) ( -744 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 201 +{ +( -728 428 224 ) ( -744 428 224 ) ( -744 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -744 438 220 ) ( -744 428 220 ) ( -728 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -744 448 220 ) ( -728 448 220 ) ( -728 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -728 438 220 ) ( -728 428 220 ) ( -728 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -728 428 220 ) ( -744 428 220 ) ( -744 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -744 428 220 ) ( -744 438 220 ) ( -744 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 202 +{ +( -832 428 258 ) ( -824 432 232 ) ( -824 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -832 428 258 ) ( -840 428 232 ) ( -840 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1440 496 224 ) ( -1440 424 224 ) ( -1112 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1392 432 216 ) ( -1064 432 216 ) ( -1064 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -824 500 216 ) ( -824 428 216 ) ( -824 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1088 428 216 ) ( -1416 428 216 ) ( -1416 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -840 480 216 ) ( -840 552 216 ) ( -840 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 203 +{ +( -824 428 224 ) ( -840 428 224 ) ( -840 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -840 438 220 ) ( -840 428 220 ) ( -824 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -840 448 220 ) ( -824 448 220 ) ( -824 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -824 438 220 ) ( -824 428 220 ) ( -824 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -824 428 220 ) ( -840 428 220 ) ( -840 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -840 428 220 ) ( -840 438 220 ) ( -840 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 204 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 448 256 0 0 ) ( -752 440 256 0 0.125000 ) ( -752 432 256 0 0.250000 ) ) +( ( -752 448 592 5.250000 0 ) ( -752 440 584 5.250000 0.125000 ) ( -752 440 584 5.250000 0.250000 ) ) +( ( -752 64 592 11.250000 0 ) ( -752 64 584 11.250000 0.125000 ) ( -752 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 205 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 432 256 0 0 ) ( -816 440 256 0 0.125000 ) ( -816 448 256 0 0.250000 ) ) +( ( -816 440 584 5.126524 0 ) ( -816 440 584 5.126524 0.125000 ) ( -816 448 592 5.126524 0.250000 ) ) +( ( -816 64 576 11.002853 0 ) ( -816 64 584 11.002853 0.125000 ) ( -816 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 206 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 448 256 0 0 ) ( -784 448 256 0 0.500000 ) ( -752 448 256 0 1 ) ) +( ( -816 448 592 5.250000 0 ) ( -784 448 592 5.250000 0.500000 ) ( -752 448 592 5.250000 1 ) ) +( ( -816 64 592 11.250000 0 ) ( -784 64 592 11.250000 0.500000 ) ( -752 64 592 11.250000 1 ) ) +) + } + } +// brush 207 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 448 256 0 0 ) ( -560 448 256 0 0.500000 ) ( -528 448 256 0 1 ) ) +( ( -592 448 592 5.250000 0 ) ( -560 448 592 5.250000 0.500000 ) ( -528 448 592 5.250000 1 ) ) +( ( -592 64 592 11.250000 0 ) ( -560 64 592 11.250000 0.500000 ) ( -528 64 592 11.250000 1 ) ) +) + } + } +// brush 208 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 432 256 0 0 ) ( -592 440 256 0 0.125000 ) ( -592 448 256 0 0.250000 ) ) +( ( -592 440 584 5.126524 0 ) ( -592 440 584 5.126524 0.125000 ) ( -592 448 592 5.126524 0.250000 ) ) +( ( -592 64 576 11.002853 0 ) ( -592 64 584 11.002853 0.125000 ) ( -592 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 209 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 448 256 0 0 ) ( -528 440 256 0 0.125000 ) ( -528 432 256 0 0.250000 ) ) +( ( -528 448 592 5.250000 0 ) ( -528 440 584 5.250000 0.125000 ) ( -528 440 584 5.250000 0.250000 ) ) +( ( -528 64 592 11.250000 0 ) ( -528 64 584 11.250000 0.125000 ) ( -528 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 210 +{ +( -600 428 224 ) ( -616 428 224 ) ( -616 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 438 220 ) ( -616 428 220 ) ( -600 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 448 220 ) ( -600 448 220 ) ( -600 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -600 438 220 ) ( -600 428 220 ) ( -600 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -600 428 220 ) ( -616 428 220 ) ( -616 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 428 220 ) ( -616 438 220 ) ( -616 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 211 +{ +( -608 428 258 ) ( -600 432 232 ) ( -600 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -608 428 258 ) ( -616 428 232 ) ( -616 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1216 496 224 ) ( -1216 424 224 ) ( -888 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1168 432 216 ) ( -840 432 216 ) ( -840 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -600 500 216 ) ( -600 428 216 ) ( -600 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -864 428 216 ) ( -1192 428 216 ) ( -1192 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 480 216 ) ( -616 552 216 ) ( -616 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 212 +{ +( -504 428 224 ) ( -520 428 224 ) ( -520 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 438 220 ) ( -520 428 220 ) ( -504 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 448 220 ) ( -504 448 220 ) ( -504 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -504 438 220 ) ( -504 428 220 ) ( -504 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -504 428 220 ) ( -520 428 220 ) ( -520 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 428 220 ) ( -520 438 220 ) ( -520 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 213 +{ +( -512 428 258 ) ( -504 432 232 ) ( -504 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -512 428 258 ) ( -520 428 232 ) ( -520 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1120 496 224 ) ( -1120 424 224 ) ( -792 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1072 432 216 ) ( -744 432 216 ) ( -744 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -504 500 216 ) ( -504 428 216 ) ( -504 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -768 428 216 ) ( -1096 428 216 ) ( -1096 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 480 216 ) ( -520 552 216 ) ( -520 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 214 +{ +( -568 428 224 ) ( -584 428 224 ) ( -584 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -584 438 220 ) ( -584 428 220 ) ( -568 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -584 448 220 ) ( -568 448 220 ) ( -568 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -568 438 220 ) ( -568 428 220 ) ( -568 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -568 428 220 ) ( -584 428 220 ) ( -584 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -584 428 220 ) ( -584 438 220 ) ( -584 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 215 +{ +( -576 428 258 ) ( -568 432 232 ) ( -568 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -576 428 258 ) ( -584 428 232 ) ( -584 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1184 496 224 ) ( -1184 424 224 ) ( -856 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1136 432 216 ) ( -808 432 216 ) ( -808 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -568 500 216 ) ( -568 428 216 ) ( -568 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -832 428 216 ) ( -1160 428 216 ) ( -1160 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -584 480 216 ) ( -584 552 216 ) ( -584 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 216 +{ +( -536 428 224 ) ( -552 428 224 ) ( -552 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 438 220 ) ( -552 428 220 ) ( -536 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 448 220 ) ( -536 448 220 ) ( -536 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -536 438 220 ) ( -536 428 220 ) ( -536 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -536 428 220 ) ( -552 428 220 ) ( -552 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 428 220 ) ( -552 438 220 ) ( -552 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 217 +{ +( -544 428 258 ) ( -536 432 232 ) ( -536 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -544 428 258 ) ( -552 428 232 ) ( -552 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1152 496 224 ) ( -1152 424 224 ) ( -824 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1104 432 216 ) ( -776 432 216 ) ( -776 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -536 500 216 ) ( -536 428 216 ) ( -536 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -800 428 216 ) ( -1128 428 216 ) ( -1128 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 480 216 ) ( -552 552 216 ) ( -552 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 218 +{ +( -512 448 224 ) ( -624 448 224 ) ( -624 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -624 80 256 ) ( -624 448 256 ) ( -512 448 256 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -624 432 224 ) ( -512 432 224 ) ( -512 432 192 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -496 80 256 ) ( -496 448 256 ) ( -496 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -512 448 256 ) ( -624 448 256 ) ( -624 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -624 448 256 ) ( -624 80 256 ) ( -624 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 219 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 432 256 0 0 ) ( -560 432 256 0 0.250000 ) ( -592 432 256 0 0.500001 ) ) +( ( -528 440 584 5.000002 0 ) ( -560 440 584 5.000002 0.250000 ) ( -592 440 584 5.000002 0.500001 ) ) +( ( -528 64 576 10.750113 0 ) ( -560 64 576 10.750113 0.250000 ) ( -592 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 220 +{ +( -1376 480 784 ) ( -1376 -472 784 ) ( -1376 -472 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 480 784 ) ( -672 480 784 ) ( -672 480 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -472 784 ) ( 24 480 784 ) ( 24 480 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -672 -480 784 ) ( 24 -480 784 ) ( 24 -480 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -672 -472 784 ) ( -672 480 784 ) ( 24 480 784 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 480 776 ) ( -672 480 776 ) ( -672 -472 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 221 +{ +( -896 -464 768 ) ( -816 -464 768 ) ( -816 -464 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1344 -416 768 ) ( -1344 -432 768 ) ( -1344 -432 64 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -1520 -448 768 ) ( -1600 -448 768 ) ( -1600 -448 64 ) gothic_block/killblock -128 0 0 0.500000 0.500000 0 0 0 +( 0 -464 768 ) ( 0 -448 768 ) ( 0 -448 64 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -816 -464 256 ) ( -896 -464 256 ) ( -896 -448 256 ) common/caulk 0 -63 -90 0.500000 0.500000 0 0 0 +( -896 -448 0 ) ( -896 -464 0 ) ( -816 -464 0 ) common/caulk 0 -63 -90 0.500000 0.500000 0 0 0 +} +// brush 222 +{ +( -1344 448 0 ) ( -1344 -448 0 ) ( -1344 -448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( -688 448 0 ) ( -1344 448 0 ) ( -1344 448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( 16 -448 0 ) ( 16 448 0 ) ( 16 448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( -1344 -448 0 ) ( -688 -448 0 ) ( -688 -448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( -640 -448 0 ) ( -640 448 0 ) ( 16 448 0 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( 16 448 -16 ) ( -640 448 -16 ) ( -640 -448 -16 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 223 +{ +( 256 448 0 ) ( 256 464 0 ) ( 176 464 0 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( 176 464 256 ) ( 256 464 256 ) ( 256 448 256 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( -1344 464 768 ) ( -1344 448 768 ) ( -1344 448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -528 448 768 ) ( -448 448 768 ) ( -448 448 64 ) gothic_block/killblock 128 0 -180 0.500000 -0.500000 0 0 0 +( 0 416 768 ) ( 0 432 768 ) ( 0 432 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 256 464 768 ) ( 176 464 768 ) ( 176 464 64 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 224 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 432 256 0 0 ) ( -336 432 256 0 0.250000 ) ( -368 432 256 0 0.500001 ) ) +( ( -304 440 584 5.000002 0 ) ( -336 440 584 5.000002 0.250000 ) ( -368 440 584 5.000002 0.500001 ) ) +( ( -304 64 576 10.750113 0 ) ( -336 64 576 10.750113 0.250000 ) ( -368 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 225 +{ +( -288 448 224 ) ( -400 448 224 ) ( -400 80 224 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -400 80 256 ) ( -400 448 256 ) ( -288 448 256 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -400 432 224 ) ( -288 432 224 ) ( -288 432 192 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -272 80 256 ) ( -272 448 256 ) ( -272 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -288 448 256 ) ( -400 448 256 ) ( -400 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -400 448 256 ) ( -400 80 256 ) ( -400 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 226 +{ +( -320 428 258 ) ( -312 432 232 ) ( -312 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -320 428 258 ) ( -328 428 232 ) ( -328 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -928 496 224 ) ( -928 424 224 ) ( -600 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -880 432 216 ) ( -552 432 216 ) ( -552 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -312 500 216 ) ( -312 428 216 ) ( -312 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -576 428 216 ) ( -904 428 216 ) ( -904 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -328 480 216 ) ( -328 552 216 ) ( -328 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 227 +{ +( -312 428 224 ) ( -328 428 224 ) ( -328 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -328 438 220 ) ( -328 428 220 ) ( -312 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -328 448 220 ) ( -312 448 220 ) ( -312 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -312 438 220 ) ( -312 428 220 ) ( -312 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -312 428 220 ) ( -328 428 220 ) ( -328 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -328 428 220 ) ( -328 438 220 ) ( -328 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 228 +{ +( -352 428 258 ) ( -344 432 232 ) ( -344 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -352 428 258 ) ( -360 428 232 ) ( -360 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -960 496 224 ) ( -960 424 224 ) ( -632 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -912 432 216 ) ( -584 432 216 ) ( -584 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -344 500 216 ) ( -344 428 216 ) ( -344 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -608 428 216 ) ( -936 428 216 ) ( -936 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 480 216 ) ( -360 552 216 ) ( -360 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 229 +{ +( -344 428 224 ) ( -360 428 224 ) ( -360 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 438 220 ) ( -360 428 220 ) ( -344 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 448 220 ) ( -344 448 220 ) ( -344 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -344 438 220 ) ( -344 428 220 ) ( -344 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -344 428 220 ) ( -360 428 220 ) ( -360 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 428 220 ) ( -360 438 220 ) ( -360 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 230 +{ +( -288 428 258 ) ( -280 432 232 ) ( -280 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -288 428 258 ) ( -296 428 232 ) ( -296 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -896 496 224 ) ( -896 424 224 ) ( -568 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -848 432 216 ) ( -520 432 216 ) ( -520 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -280 500 216 ) ( -280 428 216 ) ( -280 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -544 428 216 ) ( -872 428 216 ) ( -872 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -296 480 216 ) ( -296 552 216 ) ( -296 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 231 +{ +( -280 428 224 ) ( -296 428 224 ) ( -296 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -296 438 220 ) ( -296 428 220 ) ( -280 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -296 448 220 ) ( -280 448 220 ) ( -280 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -280 438 220 ) ( -280 428 220 ) ( -280 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -280 428 220 ) ( -296 428 220 ) ( -296 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -296 428 220 ) ( -296 438 220 ) ( -296 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 232 +{ +( -384 428 258 ) ( -376 432 232 ) ( -376 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -384 428 258 ) ( -392 428 232 ) ( -392 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -992 496 224 ) ( -992 424 224 ) ( -664 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -944 432 216 ) ( -616 432 216 ) ( -616 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -376 500 216 ) ( -376 428 216 ) ( -376 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -640 428 216 ) ( -968 428 216 ) ( -968 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -392 480 216 ) ( -392 552 216 ) ( -392 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 233 +{ +( -376 428 224 ) ( -392 428 224 ) ( -392 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -392 438 220 ) ( -392 428 220 ) ( -376 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -392 448 220 ) ( -376 448 220 ) ( -376 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -376 438 220 ) ( -376 428 220 ) ( -376 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -376 428 220 ) ( -392 428 220 ) ( -392 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -392 428 220 ) ( -392 438 220 ) ( -392 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 234 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 448 256 0 0 ) ( -304 440 256 0 0.125000 ) ( -304 432 256 0 0.250000 ) ) +( ( -304 448 592 5.250000 0 ) ( -304 440 584 5.250000 0.125000 ) ( -304 440 584 5.250000 0.250000 ) ) +( ( -304 64 592 11.250000 0 ) ( -304 64 584 11.250000 0.125000 ) ( -304 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 235 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 432 256 0 0 ) ( -368 440 256 0 0.125000 ) ( -368 448 256 0 0.250000 ) ) +( ( -368 440 584 5.126524 0 ) ( -368 440 584 5.126524 0.125000 ) ( -368 448 592 5.126524 0.250000 ) ) +( ( -368 64 576 11.002853 0 ) ( -368 64 584 11.002853 0.125000 ) ( -368 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 236 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 448 256 0 0 ) ( -336 448 256 0 0.500000 ) ( -304 448 256 0 1 ) ) +( ( -368 448 592 5.250000 0 ) ( -336 448 592 5.250000 0.500000 ) ( -304 448 592 5.250000 1 ) ) +( ( -368 64 592 11.250000 0 ) ( -336 64 592 11.250000 0.500000 ) ( -304 64 592 11.250000 1 ) ) +) + } + } +// brush 237 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 448 256 0 0 ) ( -112 448 256 0 0.500000 ) ( -80 448 256 0 1 ) ) +( ( -144 448 592 5.250000 0 ) ( -112 448 592 5.250000 0.500000 ) ( -80 448 592 5.250000 1 ) ) +( ( -144 64 592 11.250000 0 ) ( -112 64 592 11.250000 0.500000 ) ( -80 64 592 11.250000 1 ) ) +) + } + } +// brush 238 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 432 256 0 0 ) ( -144 440 256 0 0.125000 ) ( -144 448 256 0 0.250000 ) ) +( ( -144 440 584 5.126524 0 ) ( -144 440 584 5.126524 0.125000 ) ( -144 448 592 5.126524 0.250000 ) ) +( ( -144 64 576 11.002853 0 ) ( -144 64 584 11.002853 0.125000 ) ( -144 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 239 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 448 256 0 0 ) ( -80 440 256 0 0.125000 ) ( -80 432 256 0 0.250000 ) ) +( ( -80 448 592 5.250000 0 ) ( -80 440 584 5.250000 0.125000 ) ( -80 440 584 5.250000 0.250000 ) ) +( ( -80 64 592 11.250000 0 ) ( -80 64 584 11.250000 0.125000 ) ( -80 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 240 +{ +( -168 428 220 ) ( -168 438 220 ) ( -168 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 428 220 ) ( -168 428 220 ) ( -168 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 438 220 ) ( -152 428 220 ) ( -152 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -168 448 220 ) ( -152 448 220 ) ( -152 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -168 438 220 ) ( -168 428 220 ) ( -152 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 428 224 ) ( -168 428 224 ) ( -168 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 241 +{ +( -168 480 216 ) ( -168 552 216 ) ( -168 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -416 428 216 ) ( -744 428 216 ) ( -744 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 500 216 ) ( -152 428 216 ) ( -152 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -720 432 216 ) ( -392 432 216 ) ( -392 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -768 496 224 ) ( -768 424 224 ) ( -440 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -160 428 258 ) ( -168 428 232 ) ( -168 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -160 428 258 ) ( -152 432 232 ) ( -152 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 242 +{ +( -72 428 220 ) ( -72 438 220 ) ( -72 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 428 220 ) ( -72 428 220 ) ( -72 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 438 220 ) ( -56 428 220 ) ( -56 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -72 448 220 ) ( -56 448 220 ) ( -56 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -72 438 220 ) ( -72 428 220 ) ( -56 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 428 224 ) ( -72 428 224 ) ( -72 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 243 +{ +( -72 480 216 ) ( -72 552 216 ) ( -72 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -320 428 216 ) ( -648 428 216 ) ( -648 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 500 216 ) ( -56 428 216 ) ( -56 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -624 432 216 ) ( -296 432 216 ) ( -296 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -672 496 224 ) ( -672 424 224 ) ( -344 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -64 428 258 ) ( -72 428 232 ) ( -72 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -64 428 258 ) ( -56 432 232 ) ( -56 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 244 +{ +( -136 428 220 ) ( -136 438 220 ) ( -136 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -120 428 220 ) ( -136 428 220 ) ( -136 428 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -120 438 220 ) ( -120 428 220 ) ( -120 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -136 448 220 ) ( -120 448 220 ) ( -120 448 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -136 438 220 ) ( -136 428 220 ) ( -120 428 220 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -120 428 224 ) ( -136 428 224 ) ( -136 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 245 +{ +( -136 480 216 ) ( -136 552 216 ) ( -136 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -384 428 216 ) ( -712 428 216 ) ( -712 428 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -120 500 216 ) ( -120 428 216 ) ( -120 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -688 432 216 ) ( -360 432 216 ) ( -360 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -736 496 224 ) ( -736 424 224 ) ( -408 424 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -128 428 258 ) ( -136 428 232 ) ( -136 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -128 428 258 ) ( -120 432 232 ) ( -120 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 246 +{ +( -104 428 220 ) ( -104 438 220 ) ( -104 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 428 220 ) ( -104 428 220 ) ( -104 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 438 220 ) ( -88 428 220 ) ( -88 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -104 448 220 ) ( -88 448 220 ) ( -88 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -104 438 220 ) ( -104 428 220 ) ( -88 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 428 224 ) ( -104 428 224 ) ( -104 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 247 +{ +( -104 480 216 ) ( -104 552 216 ) ( -104 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -352 428 216 ) ( -680 428 216 ) ( -680 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 500 216 ) ( -88 428 216 ) ( -88 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -656 432 216 ) ( -328 432 216 ) ( -328 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -704 496 224 ) ( -704 424 224 ) ( -376 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -96 428 258 ) ( -104 428 232 ) ( -104 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -96 428 258 ) ( -88 432 232 ) ( -88 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 248 +{ +( -176 448 256 ) ( -176 80 256 ) ( -176 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -64 448 256 ) ( -176 448 256 ) ( -176 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -48 80 256 ) ( -48 448 256 ) ( -48 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -176 432 224 ) ( -64 432 224 ) ( -64 432 192 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -176 80 256 ) ( -176 448 256 ) ( -64 448 256 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -64 448 224 ) ( -176 448 224 ) ( -176 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 249 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 3 3 0 0 0 ) +( +( ( -0.000038 448 256 0 0 ) ( -672.000061 448 256 0 6 ) ( -1344 448 256 0 12 ) ) +( ( -0.000038 448 592 2.625000 0 ) ( -672.000061 448 592 2.625000 6 ) ( -1344 448 592 2.625000 12 ) ) +( ( -0.000038 64 592 5.625000 0 ) ( -672.000061 64 592 5.625000 6 ) ( -1344 64 592 5.625000 12 ) ) +) + } + } +// brush 250 +{ +( 40 192 336 ) ( 24 192 336 ) ( 24 144 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 144 464 ) ( 24 192 464 ) ( 40 192 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 144 464 ) ( 32 144 464 ) ( 32 144 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 144 464 ) ( 40 192 464 ) ( 40 192 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 192 464 ) ( 16 192 464 ) ( 16 192 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 192 464 ) ( 16 144 464 ) ( 16 144 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 251 +{ +( 40 368 336 ) ( 24 368 336 ) ( 24 320 336 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 24 320 464 ) ( 24 368 464 ) ( 40 368 464 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 16 320 464 ) ( 32 320 464 ) ( 32 320 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 320 464 ) ( 40 368 464 ) ( 40 368 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( 40 368 464 ) ( 24 368 464 ) ( 24 368 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 368 464 ) ( 16 320 464 ) ( 16 320 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +} +// brush 252 +{ +( 40 320 432 ) ( 24 320 432 ) ( 24 304 432 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 24 304 464 ) ( 24 320 464 ) ( 40 320 464 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 192 464 ) ( 32 192 464 ) ( 32 192 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 40 304 464 ) ( 40 320 464 ) ( 40 320 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 320 464 ) ( 16 320 464 ) ( 16 320 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 320 464 ) ( 16 304 464 ) ( 16 304 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 253 +{ +( 40 -192 432 ) ( 24 -192 432 ) ( 24 -208 432 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 24 -208 464 ) ( 24 -192 464 ) ( 40 -192 464 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 -320 464 ) ( 32 -320 464 ) ( 32 -320 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 40 -208 464 ) ( 40 -192 464 ) ( 40 -192 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -192 464 ) ( 16 -192 464 ) ( 16 -192 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 -192 464 ) ( 16 -208 464 ) ( 16 -208 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 254 +{ +( 40 -144 336 ) ( 24 -144 336 ) ( 24 -192 336 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 24 -192 464 ) ( 24 -144 464 ) ( 40 -144 464 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 16 -192 464 ) ( 32 -192 464 ) ( 32 -192 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 -192 464 ) ( 40 -144 464 ) ( 40 -144 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( 40 -144 464 ) ( 24 -144 464 ) ( 24 -144 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -144 464 ) ( 16 -192 464 ) ( 16 -192 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +} +// brush 255 +{ +( 40 -320 336 ) ( 24 -320 336 ) ( 24 -368 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -368 464 ) ( 24 -320 464 ) ( 40 -320 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -368 464 ) ( 40 -368 464 ) ( 40 -368 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 -368 464 ) ( 40 -320 464 ) ( 40 -320 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -320 464 ) ( 16 -320 464 ) ( 16 -320 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -320 464 ) ( 16 -368 464 ) ( 16 -368 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 256 +{ +( 16 384 64 ) ( 0 384 64 ) ( 0 352 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 352 776 ) ( 0 384 776 ) ( 16 384 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 352 768 ) ( 16 352 768 ) ( 16 352 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 704 768 ) ( 16 736 768 ) ( 16 736 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 384 768 ) ( 0 352 768 ) ( 0 352 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 448 400 ) ( -624 448 400 ) ( 16 448 80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 257 +{ +( 0 64 776 ) ( 0 96 776 ) ( 16 96 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 416 768 ) ( 16 448 768 ) ( 16 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 768 ) ( 0 64 768 ) ( 0 64 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 352 384 ) ( -624 352 384 ) ( -624 352 64 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 160 400 ) ( 16 160 400 ) ( 16 160 80 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 384 464 ) ( -624 160 464 ) ( 16 384 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 258 +{ +( 16 96 64 ) ( 0 96 64 ) ( 0 64 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 416 768 ) ( 16 448 768 ) ( 16 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 768 ) ( 0 64 768 ) ( 0 64 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 352 384 ) ( -624 352 384 ) ( -624 352 64 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 160 400 ) ( 16 160 400 ) ( 16 160 80 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 384 176 ) ( 16 384 176 ) ( -624 160 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 259 +{ +( 16 320 176 ) ( -16 320 176 ) ( -16 192 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 192 208 ) ( -16 320 208 ) ( 16 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 160 208 ) ( 16 160 208 ) ( 16 160 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 192 208 ) ( 24 320 208 ) ( 24 320 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 352 208 ) ( -16 352 208 ) ( -16 352 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 320 208 ) ( -16 192 208 ) ( -16 192 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 260 +{ +( 56 320 208 ) ( 24 320 208 ) ( 24 192 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 192 432 ) ( 24 320 432 ) ( 56 320 432 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 192 432 ) ( 56 192 432 ) ( 56 192 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 192 432 ) ( 40 320 432 ) ( 40 320 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 56 320 432 ) ( 24 320 432 ) ( 24 320 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 320 432 ) ( 24 192 432 ) ( 24 192 256 ) skies/hellsky2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 261 +{ +( 32 352 208 ) ( -32 352 208 ) ( -32 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 320 304 ) ( -32 352 304 ) ( 32 352 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 320 304 ) ( 32 320 304 ) ( 32 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 320 304 ) ( 24 352 304 ) ( 24 352 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 352 304 ) ( -32 352 304 ) ( -32 352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 352 304 ) ( -16 320 304 ) ( -16 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 262 +{ +( 16 368 304 ) ( -16 368 304 ) ( -16 304 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 304 336 ) ( -16 368 336 ) ( 16 368 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 304 336 ) ( 16 304 336 ) ( 16 304 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 304 336 ) ( 40 368 336 ) ( 40 368 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 368 336 ) ( -16 368 336 ) ( -16 368 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 368 336 ) ( -32 304 336 ) ( -32 304 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 263 +{ +( 16 208 304 ) ( -16 208 304 ) ( -16 144 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 144 336 ) ( -16 208 336 ) ( 16 208 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 144 336 ) ( 16 144 336 ) ( 16 144 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 144 336 ) ( 40 208 336 ) ( 40 208 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 208 336 ) ( -16 208 336 ) ( -16 208 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 208 336 ) ( -32 144 336 ) ( -32 144 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 264 +{ +( 32 192 208 ) ( -32 192 208 ) ( -32 160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 160 304 ) ( -32 192 304 ) ( 32 192 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 160 304 ) ( 32 160 304 ) ( 32 160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 160 304 ) ( 24 192 304 ) ( 24 192 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 192 304 ) ( -32 192 304 ) ( -32 192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 192 304 ) ( -16 160 304 ) ( -16 160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 265 +{ +( 0 256 464 ) ( 0 160 336 ) ( 16 208 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 256 464 ) ( 0 160 464 ) ( 0 160 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 160 464 ) ( 16 256 464 ) ( 16 256 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 160 464 ) ( 16 160 464 ) ( 16 160 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 160 464 ) ( -16 256 464 ) ( 16 256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 266 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( -16 256 432 0 0 ) ( -16 208 400 0 0.450694 ) ( -16 192 336 0 0.966082 ) ) +( ( 4 256 432 0.156250 0 ) ( 4 208 400 0.156250 0.450694 ) ( 4 192 336 0.156250 0.966082 ) ) +( ( 24 256 432 0.312500 0 ) ( 24 208 400 0.312500 0.450694 ) ( 24 192 336 0.312500 0.966082 ) ) +( ( 24 256 448 0.437500 0 ) ( 24 197 411 0.437500 0.450694 ) ( 24 176 336 0.437500 0.966082 ) ) +( ( 24 256 464 0.562500 0 ) ( 24 185 423 0.562500 0.450694 ) ( 24 160 336 0.562500 0.966082 ) ) +( ( 4 256 464 0.718750 0 ) ( 4 185 423 0.718750 0.450694 ) ( 4 160 336 0.718750 0.966082 ) ) +( ( -16 256 464 0.875000 0 ) ( -16 185 423 0.875000 0.450694 ) ( -16 160 336 0.875000 0.966082 ) ) +( ( -16 256 448 1 0 ) ( -16 197 411 1 0.450694 ) ( -16 176 336 1 0.966082 ) ) +( ( -16 256 432 1.125000 0 ) ( -16 208 400 1.125000 0.450694 ) ( -16 192 336 1.125000 0.966082 ) ) +) + } + } +// brush 267 +{ +( 16 256 464 ) ( 16 352 336 ) ( 0 304 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 256 464 ) ( 16 352 464 ) ( 16 352 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 352 464 ) ( 0 256 464 ) ( 0 256 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 32 352 464 ) ( 0 352 464 ) ( 0 352 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 352 464 ) ( 32 256 464 ) ( 0 256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 268 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( 24 256 432 0 0 ) ( 24 304 400 0 0.450694 ) ( 24 320 336 0 0.966082 ) ) +( ( 4 256 432 0.156250 0 ) ( 4 304 400 0.156250 0.450694 ) ( 4 320 336 0.156250 0.966082 ) ) +( ( -16 256 432 0.312500 0 ) ( -16 304 400 0.312500 0.450694 ) ( -16 320 336 0.312500 0.966082 ) ) +( ( -16 256 448 0.437500 0 ) ( -16 315 411 0.437500 0.450694 ) ( -16 336 336 0.437500 0.966082 ) ) +( ( -16 256 464 0.562500 0 ) ( -16 327 423 0.562500 0.450694 ) ( -16 352 336 0.562500 0.966082 ) ) +( ( 4 256 464 0.718750 0 ) ( 4 327 423 0.718750 0.450694 ) ( 4 352 336 0.718750 0.966082 ) ) +( ( 24 256 464 0.875000 0 ) ( 24 327 423 0.875000 0.450694 ) ( 24 352 336 0.875000 0.966082 ) ) +( ( 24 256 448 1 0 ) ( 24 315 411 1 0.450694 ) ( 24 336 336 1 0.966082 ) ) +( ( 24 256 432 1.125000 0 ) ( 24 304 400 1.125000 0.450694 ) ( 24 320 336 1.125000 0.966082 ) ) +) + } + } +// brush 269 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( 24 -256 432 0 0 ) ( 24 -208 400 0 0.450694 ) ( 24 -192 336 0 0.966082 ) ) +( ( 4 -256 432 0.156250 0 ) ( 4 -208 400 0.156250 0.450694 ) ( 4 -192 336 0.156250 0.966082 ) ) +( ( -16 -256 432 0.312500 0 ) ( -16 -208 400 0.312500 0.450694 ) ( -16 -192 336 0.312500 0.966082 ) ) +( ( -16 -256 448 0.437500 0 ) ( -16 -197 411 0.437500 0.450694 ) ( -16 -176 336 0.437500 0.966082 ) ) +( ( -16 -256 464 0.562500 0 ) ( -16 -185 423 0.562500 0.450694 ) ( -16 -160 336 0.562500 0.966082 ) ) +( ( 4 -256 464 0.718750 0 ) ( 4 -185 423 0.718750 0.450694 ) ( 4 -160 336 0.718750 0.966082 ) ) +( ( 24 -256 464 0.875000 0 ) ( 24 -185 423 0.875000 0.450694 ) ( 24 -160 336 0.875000 0.966082 ) ) +( ( 24 -256 448 1 0 ) ( 24 -197 411 1 0.450694 ) ( 24 -176 336 1 0.966082 ) ) +( ( 24 -256 432 1.125000 0 ) ( 24 -208 400 1.125000 0.450694 ) ( 24 -192 336 1.125000 0.966082 ) ) +) + } + } +// brush 270 +{ +( 16 -256 464 ) ( 16 -160 336 ) ( 0 -208 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -256 464 ) ( 16 -160 464 ) ( 16 -160 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -160 464 ) ( 0 -256 464 ) ( 0 -256 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 32 -160 464 ) ( 0 -160 464 ) ( 0 -160 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -160 464 ) ( 32 -256 464 ) ( 0 -256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 271 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( -16 -256 432 0 0 ) ( -16 -304 400 0 0.450694 ) ( -16 -320 336 0 0.966082 ) ) +( ( 4 -256 432 0.156250 0 ) ( 4 -304 400 0.156250 0.450694 ) ( 4 -320 336 0.156250 0.966082 ) ) +( ( 24 -256 432 0.312500 0 ) ( 24 -304 400 0.312500 0.450694 ) ( 24 -320 336 0.312500 0.966082 ) ) +( ( 24 -256 448 0.437500 0 ) ( 24 -315 411 0.437500 0.450694 ) ( 24 -336 336 0.437500 0.966082 ) ) +( ( 24 -256 464 0.562500 0 ) ( 24 -327 423 0.562500 0.450694 ) ( 24 -352 336 0.562500 0.966082 ) ) +( ( 4 -256 464 0.718750 0 ) ( 4 -327 423 0.718750 0.450694 ) ( 4 -352 336 0.718750 0.966082 ) ) +( ( -16 -256 464 0.875000 0 ) ( -16 -327 423 0.875000 0.450694 ) ( -16 -352 336 0.875000 0.966082 ) ) +( ( -16 -256 448 1 0 ) ( -16 -315 411 1 0.450694 ) ( -16 -336 336 1 0.966082 ) ) +( ( -16 -256 432 1.125000 0 ) ( -16 -304 400 1.125000 0.450694 ) ( -16 -320 336 1.125000 0.966082 ) ) +) + } + } +// brush 272 +{ +( 0 -256 464 ) ( 0 -352 336 ) ( 16 -304 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -256 464 ) ( 0 -352 464 ) ( 0 -352 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -352 464 ) ( 16 -256 464 ) ( 16 -256 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 -352 464 ) ( 16 -352 464 ) ( 16 -352 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 -352 464 ) ( -16 -256 464 ) ( 16 -256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 273 +{ +( 32 -320 208 ) ( -32 -320 208 ) ( -32 -352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -352 304 ) ( -32 -320 304 ) ( 32 -320 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 -352 304 ) ( 32 -352 304 ) ( 32 -352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 -352 304 ) ( 24 -320 304 ) ( 24 -320 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -320 304 ) ( -32 -320 304 ) ( -32 -320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -320 304 ) ( -16 -352 304 ) ( -16 -352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 274 +{ +( 16 -304 304 ) ( -16 -304 304 ) ( -16 -368 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -368 336 ) ( -16 -304 336 ) ( 16 -304 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -368 336 ) ( 16 -368 336 ) ( 16 -368 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 -368 336 ) ( 40 -304 336 ) ( 40 -304 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -304 336 ) ( -16 -304 336 ) ( -16 -304 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -304 336 ) ( -32 -368 336 ) ( -32 -368 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 275 +{ +( 16 -144 304 ) ( -16 -144 304 ) ( -16 -208 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -208 336 ) ( -16 -144 336 ) ( 16 -144 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -208 336 ) ( 16 -208 336 ) ( 16 -208 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 -208 336 ) ( 40 -144 336 ) ( 40 -144 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -144 336 ) ( -16 -144 336 ) ( -16 -144 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -144 336 ) ( -32 -208 336 ) ( -32 -208 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 276 +{ +( 32 -160 208 ) ( -32 -160 208 ) ( -32 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -192 304 ) ( -32 -160 304 ) ( 32 -160 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 -192 304 ) ( 32 -192 304 ) ( 32 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 -192 304 ) ( 24 -160 304 ) ( 24 -160 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -160 304 ) ( -32 -160 304 ) ( -32 -160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -160 304 ) ( -16 -192 304 ) ( -16 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 277 +{ +( 56 -192 208 ) ( 24 -192 208 ) ( 24 -320 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -320 432 ) ( 24 -192 432 ) ( 56 -192 432 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -320 432 ) ( 56 -320 432 ) ( 56 -320 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 -320 432 ) ( 40 -192 432 ) ( 40 -192 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 56 -192 432 ) ( 24 -192 432 ) ( 24 -192 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -192 432 ) ( 24 -320 432 ) ( 24 -320 256 ) skies/hellsky2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 278 +{ +( 16 -192 176 ) ( -16 -192 176 ) ( -16 -320 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -320 208 ) ( -16 -192 208 ) ( 16 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -352 208 ) ( 16 -352 208 ) ( 16 -352 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 -320 208 ) ( 24 -192 208 ) ( 24 -192 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -160 208 ) ( -16 -160 208 ) ( -16 -160 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -192 208 ) ( -16 -320 208 ) ( -16 -320 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 279 +{ +( 16 -416 64 ) ( 0 -416 64 ) ( 0 -448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -160 384 ) ( -624 -160 384 ) ( -624 -160 64 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -352 400 ) ( 16 -352 400 ) ( 16 -352 80 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -128 176 ) ( 16 -128 176 ) ( -624 -352 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 280 +{ +( 0 -448 776 ) ( 0 -416 776 ) ( 16 -416 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -160 384 ) ( -624 -160 384 ) ( -624 -160 64 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -352 400 ) ( 16 -352 400 ) ( 16 -352 80 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -128 464 ) ( -624 -352 464 ) ( 16 -128 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 281 +{ +( 16 -416 64 ) ( 0 -416 64 ) ( 0 -448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -448 776 ) ( 0 -416 776 ) ( 16 -416 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -448 768 ) ( 16 -448 768 ) ( 16 -448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -352 400 ) ( -624 -352 400 ) ( 16 -352 80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 282 +{ +( 16 -416 64 ) ( 0 -416 64 ) ( 0 -448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -448 776 ) ( 0 -416 776 ) ( 16 -416 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -64 768 ) ( 0 -64 768 ) ( 0 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -624 -160 384 ) ( 16 -160 384 ) ( -624 -160 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 283 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 3 3 0 0 0 ) +( +( ( -1344 -448 255.999985 0 0 ) ( -672.000061 -448 255.999985 0 6 ) ( -0.000038 -448 255.999985 0 12 ) ) +( ( -1344 -448 592 2.625000 0 ) ( -672.000061 -448 592 2.625000 6 ) ( -0.000038 -448 592 2.625000 12 ) ) +( ( -1344 -64 592 5.625000 0 ) ( -672.000061 -64 592 5.625000 6 ) ( -0.000038 -64 592 5.625000 12 ) ) +) + } + } +// brush 284 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 5 3 0 0 0 ) +( +( ( -1344 -64 592 0 0 ) ( -687.999939 -64 592 0 5.875000 ) ( -32.000008 -64 592 0 11.750000 ) ) +( ( -1344 -64 639 0.367188 0 ) ( -687.999939 -64 639 0.367188 5.875000 ) ( -32.000008 -64 639 0.367188 11.750000 ) ) +( ( -1344 -44 681 0.730616 0 ) ( -687.999939 -44 681 0.730616 5.875000 ) ( -32.000008 -44 681 0.730616 11.750000 ) ) +( ( -1344 -28 720 1.059948 0 ) ( -687.999939 -28 720 1.059948 5.875000 ) ( -32.000008 -28 720 1.059948 11.750000 ) ) +( ( -1344 0 744 1.348058 0 ) ( -687.999939 0 744 1.348058 5.875000 ) ( -32.000008 0 744 1.348058 11.750000 ) ) +) + } + } +// brush 285 +{ +( 0 -64 0 ) ( -16 -64 0 ) ( -16 -448 0 ) common/caulk 34 0 0 0.500000 0.500000 0 0 0 +( 0 -96 80 ) ( 0 -448 80 ) ( -16 -448 64 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -16 -448 704 ) ( 0 -448 704 ) ( 0 -448 0 ) common/caulk 34 0 0 0.500000 0.500000 0 0 0 +( 0 -448 80 ) ( 0 -96 80 ) ( 0 -96 0 ) common/caulk 2 0 0 0.500000 0.500000 0 0 0 +( 0 -96 0 ) ( 0 -96 64 ) ( -16 -80 64 ) common/caulk 34 0 0 0.500000 0.500000 0 0 0 +( -16 -80 0 ) ( -16 -80 64 ) ( -16 -448 64 ) gothic_trim/baseboard09_i -28 0 0 0.500000 0.500000 0 0 0 +} +// brush 286 +{ +( 0 448 0 ) ( -16 448 0 ) ( -16 64 0 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( 0 448 80 ) ( 0 96 80 ) ( -16 80 64 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 64 ) ( 0 96 0 ) ( -16 80 0 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( 0 96 80 ) ( 0 448 80 ) ( 0 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 448 704 ) ( -16 448 704 ) ( -16 448 0 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( -16 80 64 ) ( -16 80 0 ) ( -16 448 0 ) gothic_trim/baseboard09_i 27 0 0 0.500000 0.500000 0 0 0 +} +// brush 287 +{ +( 16 96 64 ) ( 0 96 64 ) ( 0 64 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 64 776 ) ( 0 96 776 ) ( 16 96 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 64 768 ) ( 16 64 768 ) ( 16 64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 416 768 ) ( 16 448 768 ) ( 16 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 160 736 ) ( 0 160 736 ) ( 0 160 -32 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 768 ) ( 0 64 768 ) ( 0 64 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 288 +{ +( -16 256 0 ) ( -32 256 0 ) ( -32 -256 0 ) common/caulk 1 0 0 0.500000 0.500000 0 0 0 +( -32 -256 776 ) ( -32 256 776 ) ( -16 256 776 ) common/caulk 1 0 0 0.500000 0.500000 0 0 0 +( 0 -96 784 ) ( 0 -96 0 ) ( -32 -64 0 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 0 -96 0 ) ( 0 -96 784 ) ( 0 96 784 ) common/caulk 1 0 0 0.500000 0.500000 0 0 0 +( 0 96 0 ) ( 0 96 784 ) ( -32 64 784 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -32 256 16 ) ( -32 -256 16 ) ( -32 -256 0 ) gothic_wall/xiantourneywall_c1 126 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "info_player_deathmatch" +"origin" "-1280 0 24" +} +// entity 2 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 -48 592 0 0 ) ( -112 -48 592 0 0.500000 ) ( -80 -48 592 0 1 ) ) +( ( -144 -48 634 0.656250 0 ) ( -112 -48 634 0.656250 0.500000 ) ( -80 -48 634 0.656250 1 ) ) +( ( -144 -33 672 1.294584 0 ) ( -112 -33 672 1.294584 0.500000 ) ( -80 -33 672 1.294584 1 ) ) +( ( -144 -21 707 1.872709 0 ) ( -112 -21 707 1.872709 0.500000 ) ( -80 -21 707 1.872709 1 ) ) +( ( -144 0 728 2.336748 0 ) ( -112 0 728 2.336748 0.500000 ) ( -80 0 728 2.336748 1 ) ) +) + } + } +} +// entity 3 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 432 256 0 0 ) ( -112 432 256 0 0.250000 ) ( -144 432 256 0 0.500001 ) ) +( ( -80 440 584 5.000002 0 ) ( -112 440 584 5.000002 0.250000 ) ( -144 440 584 5.000002 0.500001 ) ) +( ( -80 64 576 10.750113 0 ) ( -112 64 576 10.750113 0.250000 ) ( -144 64 576 10.750113 0.500001 ) ) +) + } + } +} +// entity 4 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 -432 256 0 0 ) ( -1232 -432 256 0 0.250000 ) ( -1200 -432 256 0 0.500001 ) ) +( ( -1264 -440 584 5.000002 0 ) ( -1232 -440 584 5.000002 0.250000 ) ( -1200 -440 584 5.000002 0.500001 ) ) +( ( -1264 -64 576 10.750113 0 ) ( -1232 -64 576 10.750113 0.250000 ) ( -1200 -64 576 10.750113 0.500001 ) ) +) + } + } +} +// entity 5 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 -48 592 0 0 ) ( -336 -48 592 0 0.500000 ) ( -304 -48 592 0 1 ) ) +( ( -368 -48 634 0.656250 0 ) ( -336 -48 634 0.656250 0.500000 ) ( -304 -48 634 0.656250 1 ) ) +( ( -368 -33 672 1.294584 0 ) ( -336 -33 672 1.294584 0.500000 ) ( -304 -33 672 1.294584 1 ) ) +( ( -368 -21 707 1.872709 0 ) ( -336 -21 707 1.872709 0.500000 ) ( -304 -21 707 1.872709 1 ) ) +( ( -368 0 728 2.336748 0 ) ( -336 0 728 2.336748 0.500000 ) ( -304 0 728 2.336748 1 ) ) +) + } + } +} +// entity 6 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 -48 592 0 0 ) ( -560 -48 592 0 0.500000 ) ( -528 -48 592 0 1 ) ) +( ( -592 -48 634 0.656250 0 ) ( -560 -48 634 0.656250 0.500000 ) ( -528 -48 634 0.656250 1 ) ) +( ( -592 -33 672 1.294584 0 ) ( -560 -33 672 1.294584 0.500000 ) ( -528 -33 672 1.294584 1 ) ) +( ( -592 -21 707 1.872709 0 ) ( -560 -21 707 1.872709 0.500000 ) ( -528 -21 707 1.872709 1 ) ) +( ( -592 0 728 2.336748 0 ) ( -560 0 728 2.336748 0.500000 ) ( -528 0 728 2.336748 1 ) ) +) + } + } +} +// entity 7 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 -48 592 0 0 ) ( -784 -48 592 0 0.500000 ) ( -752 -48 592 0 1 ) ) +( ( -816 -48 634 0.656250 0 ) ( -784 -48 634 0.656250 0.500000 ) ( -752 -48 634 0.656250 1 ) ) +( ( -816 -33 672 1.294584 0 ) ( -784 -33 672 1.294584 0.500000 ) ( -752 -33 672 1.294584 1 ) ) +( ( -816 -21 707 1.872709 0 ) ( -784 -21 707 1.872709 0.500000 ) ( -752 -21 707 1.872709 1 ) ) +( ( -816 0 728 2.336748 0 ) ( -784 0 728 2.336748 0.500000 ) ( -752 0 728 2.336748 1 ) ) +) + } + } +} +// entity 8 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 -48 592 0 0 ) ( -1008 -48 592 0 0.500000 ) ( -976 -48 592 0 1 ) ) +( ( -1040 -48 634 0.656250 0 ) ( -1008 -48 634 0.656250 0.500000 ) ( -976 -48 634 0.656250 1 ) ) +( ( -1040 -33 672 1.294584 0 ) ( -1008 -33 672 1.294584 0.500000 ) ( -976 -33 672 1.294584 1 ) ) +( ( -1040 -21 707 1.872709 0 ) ( -1008 -21 707 1.872709 0.500000 ) ( -976 -21 707 1.872709 1 ) ) +( ( -1040 0 728 2.336748 0 ) ( -1008 0 728 2.336748 0.500000 ) ( -976 0 728 2.336748 1 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 -48 592 0 0 ) ( -1232 -48 592 0 0.500000 ) ( -1200 -48 592 0 1 ) ) +( ( -1264 -48 634 0.656250 0 ) ( -1232 -48 634 0.656250 0.500000 ) ( -1200 -48 634 0.656250 1 ) ) +( ( -1264 -33 672 1.294584 0 ) ( -1232 -33 672 1.294584 0.500000 ) ( -1200 -33 672 1.294584 1 ) ) +( ( -1264 -21 707 1.872709 0 ) ( -1232 -21 707 1.872709 0.500000 ) ( -1200 -21 707 1.872709 1 ) ) +( ( -1264 0 728 2.336748 0 ) ( -1232 0 728 2.336748 0.500000 ) ( -1200 0 728 2.336748 1 ) ) +) + } + } +} +// entity 10 +{ +"spawnflags" "1" +"origin" "-112 189 328" +"noise" "sound/world/firesoft.wav" +"classname" "target_speaker" +} diff --git a/docs/developer/TstMaps/realloc.map b/docs/developer/TstMaps/realloc.map new file mode 100644 index 00000000..5db05676 --- /dev/null +++ b/docs/developer/TstMaps/realloc.map @@ -0,0 +1,4661 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +brushDef +{ +( -128 128 576 ) ( -128 0 576 ) ( -128 0 320 ) ( ( 0.007813 0 0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 120 128 576 ) ( -128 128 576 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 16 576 ) ( 640 144 576 ) ( 640 144 320 ) ( ( 0.007813 0 -0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 0 576 ) ( 120 0 576 ) ( 120 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 0 328 ) ( -120 128 328 ) ( 128 128 328 ) ( ( 0.007813 0 -0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 120 128 320 ) ( -128 128 320 ) ( -128 0 320 ) ( ( 0.007813 0 -0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 1 +{ +brushDef +{ +( 128 0 304 ) ( 128 -8 304 ) ( 128 -8 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 0 304 ) ( 128 0 304 ) ( 128 0 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) clan_xb/logo7 0 0 0 +( 384 -8 304 ) ( 384 0 304 ) ( 384 0 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 120 -8 304 ) ( 384 -8 304 ) ( 384 -8 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) clan_xb/logo7 0 0 0 +( 128 -8 328 ) ( 128 0 328 ) ( 392 0 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 0 280 ) ( 128 0 280 ) ( 128 -8 280 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 2 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 232 ) ( 56 136 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 328 ) ( -128 128 328 ) ( 32 136 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 3 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 376 ) ( 640 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 328 ) ( 192 128 328 ) ( 32 136 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 4 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -760 872 -8 ) ( -760 1200 -8 ) ( -760 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 5 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 1200 -8 ) ( -8 1200 -8 ) ( -384 1200 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 6 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1272 -320 -8 ) ( 1272 -648 -8 ) ( 1272 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 7 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1016 -640 -8 ) ( 640 -640 -8 ) ( 1016 -640 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 8 +{ +brushDef +{ +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -384 1216 888 ) ( -384 888 888 ) ( -8 1216 888 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +} +} +// brush 9 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -384 1208 -48 ) ( -8 1208 -48 ) ( -384 880 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +} +} +// brush 10 +{ +brushDef +{ +( 320 192 296 ) ( 192 192 296 ) ( 192 176 296 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 304 ) ( 192 184 304 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 304 ) ( 320 168 304 ) ( 320 168 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 304 ) ( 320 184 304 ) ( 320 184 280 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 184 304 ) ( 192 184 304 ) ( 192 184 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 304 ) ( 192 168 304 ) ( 192 168 280 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 11 +{ +brushDef +{ +( 320 168 296 ) ( 192 168 296 ) ( 192 152 296 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 312 ) ( 192 168 312 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 312 ) ( 320 152 312 ) ( 320 152 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 312 ) ( 320 168 312 ) ( 320 168 288 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 312 ) ( 192 168 312 ) ( 192 168 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 312 ) ( 192 152 312 ) ( 192 152 288 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 12 +{ +brushDef +{ +( 320 152 296 ) ( 192 152 296 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 320 ) ( 192 152 320 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 320 ) ( 320 136 320 ) ( 320 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 136 320 ) ( 320 152 320 ) ( 320 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 320 ) ( 192 152 320 ) ( 192 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 320 ) ( 192 136 320 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 13 +{ +brushDef +{ +( 320 200 296 ) ( 192 200 296 ) ( 192 184 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 304 ) ( 192 200 304 ) ( 320 200 304 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 304 ) ( 320 184 304 ) ( 320 184 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 184 304 ) ( 320 200 304 ) ( 320 200 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 200 304 ) ( 192 200 304 ) ( 192 200 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 200 304 ) ( 192 184 304 ) ( 192 184 296 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 14 +{ +brushDef +{ +( 320 184 304 ) ( 192 184 304 ) ( 192 168 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 312 ) ( 192 184 312 ) ( 320 184 312 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 312 ) ( 320 168 312 ) ( 320 168 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 312 ) ( 320 184 312 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 184 312 ) ( 192 184 312 ) ( 192 184 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 312 ) ( 192 168 312 ) ( 192 168 304 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 15 +{ +brushDef +{ +( 320 168 312 ) ( 192 168 312 ) ( 192 152 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 320 ) ( 192 168 320 ) ( 320 168 320 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 320 ) ( 320 152 320 ) ( 320 152 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 320 ) ( 320 168 320 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 320 ) ( 192 168 320 ) ( 192 168 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 320 ) ( 192 152 320 ) ( 192 152 312 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 16 +{ +brushDef +{ +( 320 152 320 ) ( 192 152 320 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 328 ) ( 192 152 328 ) ( 320 152 328 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 320 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 136 328 ) ( 320 152 328 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 328 ) ( 192 152 328 ) ( 192 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 328 ) ( 192 136 328 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 17 +{ +brushDef +{ +( -40 136 376 ) ( -48 136 376 ) ( -48 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -8 128 424 ) ( -8 136 424 ) ( 0 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 18 +{ +brushDef +{ +( -40 128 480 ) ( -40 136 480 ) ( -32 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -8 136 432 ) ( -8 128 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 19 +{ +brushDef +{ +( 8 136 432 ) ( 8 136 424 ) ( 8 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 128 432 ) ( -96 136 432 ) ( -96 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -8 128 424 ) ( -8 128 432 ) ( 0 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -7.250001 ) ) gothic_trim/wood2 134217728 0 0 +( -8 128 432 ) ( -8 136 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -8 136 432 ) ( -8 136 424 ) ( 0 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -7.250000 ) ) gothic_trim/wood2 134217728 0 0 +( -8 136 424 ) ( -8 128 424 ) ( 0 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 11.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 20 +{ +brushDef +{ +( 112 136 376 ) ( 104 136 376 ) ( 104 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 144 128 424 ) ( 144 136 424 ) ( 152 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 21 +{ +brushDef +{ +( 112 128 480 ) ( 112 136 480 ) ( 120 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 144 136 432 ) ( 144 128 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 22 +{ +brushDef +{ +( 160 136 432 ) ( 160 136 424 ) ( 160 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 56 128 432 ) ( 56 136 432 ) ( 56 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 144 128 424 ) ( 144 128 432 ) ( 152 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -4.875001 ) ) gothic_trim/wood2 134217728 0 0 +( 144 128 432 ) ( 144 136 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 144 136 432 ) ( 144 136 424 ) ( 152 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -4.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 144 136 424 ) ( 144 128 424 ) ( 152 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 9.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 23 +{ +brushDef +{ +( 408 136 376 ) ( 400 136 376 ) ( 400 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 128 424 ) ( 440 136 424 ) ( 448 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 24 +{ +brushDef +{ +( 408 128 480 ) ( 408 136 480 ) ( 416 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 136 432 ) ( 440 128 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 25 +{ +brushDef +{ +( 456 136 432 ) ( 456 136 424 ) ( 456 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 128 432 ) ( 352 136 432 ) ( 352 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 128 424 ) ( 440 128 432 ) ( 448 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -0.250000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 128 432 ) ( 440 136 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 136 432 ) ( 440 136 424 ) ( 448 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -0.250000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 136 424 ) ( 440 128 424 ) ( 448 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 4.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 26 +{ +brushDef +{ +( 560 136 376 ) ( 552 136 376 ) ( 552 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 592 128 424 ) ( 592 136 424 ) ( 600 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 27 +{ +brushDef +{ +( 560 128 480 ) ( 560 136 480 ) ( 568 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 592 136 432 ) ( 592 128 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 28 +{ +brushDef +{ +( 608 136 432 ) ( 608 136 424 ) ( 608 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 128 432 ) ( 504 136 432 ) ( 504 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 128 424 ) ( 592 128 432 ) ( 600 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 128 432 ) ( 592 136 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 136 432 ) ( 592 136 424 ) ( 600 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 136 424 ) ( 592 128 424 ) ( 600 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 29 +{ +brushDef +{ +( 648 128 328 ) ( 632 128 328 ) ( 632 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 384 ) ( 632 128 384 ) ( 648 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 336 ) ( 648 120 336 ) ( 648 120 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 120 336 ) ( 640 128 336 ) ( 640 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 128 336 ) ( 632 128 336 ) ( 632 128 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 128 336 ) ( 632 120 336 ) ( 632 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 30 +{ +brushDef +{ +( -112 128 328 ) ( -128 128 328 ) ( -128 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 120 384 ) ( -128 128 384 ) ( -112 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 120 336 ) ( -112 120 336 ) ( -112 120 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 120 336 ) ( -120 128 336 ) ( -120 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -112 128 336 ) ( -128 128 336 ) ( -128 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 128 336 ) ( -128 120 336 ) ( -128 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 31 +{ +brushDef +{ +( 192 128 512 ) ( 192 136 512 ) ( 224 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 144 480 ) ( 192 136 480 ) ( 320 144 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 32 +{ +brushDef +{ +( 216 136 224 ) ( 184 136 224 ) ( 184 128 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 192 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 33 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 480 ) ( 456 128 480 ) ( 456 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 480 ) ( 504 136 480 ) ( 504 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 34 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 480 ) ( 608 128 480 ) ( 608 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 35 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 480 ) ( 352 136 480 ) ( 352 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 36 +{ +brushDef +{ +( 320 128 512 ) ( 320 136 512 ) ( 640 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 480 ) ( 320 128 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 37 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 232 ) ( 352 128 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 376 ) ( 1088 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 38 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 136 480 ) ( 8 128 480 ) ( 8 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 128 480 ) ( 56 136 480 ) ( 56 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 39 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 136 480 ) ( 160 128 480 ) ( 160 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 40 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 128 480 ) ( -96 136 480 ) ( -96 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 41 +{ +brushDef +{ +( -128 128 512 ) ( -128 136 512 ) ( 192 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 480 ) ( -128 128 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 42 +{ +brushDef +{ +( 640 968 512 ) ( 568 968 512 ) ( 568 920 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 776 768 ) ( 448 320 768 ) ( 64 320 768 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 320 768 ) ( 640 320 768 ) ( 640 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 448 320 768 ) ( 448 776 768 ) ( 640 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 640 776 768 ) ( -128 776 768 ) ( -128 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 64 776 768 ) ( 64 320 768 ) ( -128 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +} +} +// brush 43 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 560 824 8 0 0 ) ( 560 824 40 0 0.500000 ) ( 560 824 72 0 1 ) ) +( ( 560 816 8 0.125000 0 ) ( 560 816 40 0.125000 0.500000 ) ( 560 816 72 0.125000 1 ) ) +( ( 568 816 8 0.250000 0 ) ( 568 816 40 0.250000 0.500000 ) ( 568 816 72 0.250000 1 ) ) +( ( 576 816 8 0.375000 0 ) ( 576 816 40 0.375000 0.500000 ) ( 576 816 72 0.375000 1 ) ) +( ( 576 824 8 0.500000 0 ) ( 576 824 40 0.500000 0.500000 ) ( 576 824 72 0.500000 1 ) ) +( ( 576 832 8 0.625000 0 ) ( 576 832 40 0.625000 0.500000 ) ( 576 832 72 0.625000 1 ) ) +( ( 568 832 8 0.750000 0 ) ( 568 832 40 0.750000 0.500000 ) ( 568 832 72 0.750000 1 ) ) +( ( 560 832 8 0.875000 0 ) ( 560 832 40 0.875000 0.500000 ) ( 560 832 72 0.875000 1 ) ) +( ( 560 824 8 1 0 ) ( 560 824 40 1 0.500000 ) ( 560 824 72 1 1 ) ) +) + } + } +// brush 44 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -64 824 8 0 0 ) ( -64 824 40 0 0.500000 ) ( -64 824 72 0 1 ) ) +( ( -64 816 8 0.125000 0 ) ( -64 816 40 0.125000 0.500000 ) ( -64 816 72 0.125000 1 ) ) +( ( -56 816 8 0.250000 0 ) ( -56 816 40 0.250000 0.500000 ) ( -56 816 72 0.250000 1 ) ) +( ( -48 816 8 0.375000 0 ) ( -48 816 40 0.375000 0.500000 ) ( -48 816 72 0.375000 1 ) ) +( ( -48 824 8 0.500000 0 ) ( -48 824 40 0.500000 0.500000 ) ( -48 824 72 0.500000 1 ) ) +( ( -48 832 8 0.625000 0 ) ( -48 832 40 0.625000 0.500000 ) ( -48 832 72 0.625000 1 ) ) +( ( -56 832 8 0.750000 0 ) ( -56 832 40 0.750000 0.500000 ) ( -56 832 72 0.750000 1 ) ) +( ( -64 832 8 0.875000 0 ) ( -64 832 40 0.875000 0.500000 ) ( -64 832 72 0.875000 1 ) ) +( ( -64 824 8 1 0 ) ( -64 824 40 1 0.500000 ) ( -64 824 72 1 1 ) ) +) + } + } +// brush 45 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -64 928 8 0 0 ) ( -64 928 40 0 0.500000 ) ( -64 928 72 0 1 ) ) +( ( -64 920 8 0.125000 0 ) ( -64 920 40 0.125000 0.500000 ) ( -64 920 72 0.125000 1 ) ) +( ( -56 920 8 0.250000 0 ) ( -56 920 40 0.250000 0.500000 ) ( -56 920 72 0.250000 1 ) ) +( ( -48 920 8 0.375000 0 ) ( -48 920 40 0.375000 0.500000 ) ( -48 920 72 0.375000 1 ) ) +( ( -48 928 8 0.500000 0 ) ( -48 928 40 0.500000 0.500000 ) ( -48 928 72 0.500000 1 ) ) +( ( -48 936 8 0.625000 0 ) ( -48 936 40 0.625000 0.500000 ) ( -48 936 72 0.625000 1 ) ) +( ( -56 936 8 0.750000 0 ) ( -56 936 40 0.750000 0.500000 ) ( -56 936 72 0.750000 1 ) ) +( ( -64 936 8 0.875000 0 ) ( -64 936 40 0.875000 0.500000 ) ( -64 936 72 0.875000 1 ) ) +( ( -64 928 8 1 0 ) ( -64 928 40 1 0.500000 ) ( -64 928 72 1 1 ) ) +) + } + } +// brush 46 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 8 744 8 0 0 ) ( 8 744 40 0 0.500000 ) ( 8 744 72 0 1 ) ) +( ( 8 736 8 0.125000 0 ) ( 8 736 40 0.125000 0.500000 ) ( 8 736 72 0.125000 1 ) ) +( ( 16 736 8 0.250000 0 ) ( 16 736 40 0.250000 0.500000 ) ( 16 736 72 0.250000 1 ) ) +( ( 24 736 8 0.375000 0 ) ( 24 736 40 0.375000 0.500000 ) ( 24 736 72 0.375000 1 ) ) +( ( 24 744 8 0.500000 0 ) ( 24 744 40 0.500000 0.500000 ) ( 24 744 72 0.500000 1 ) ) +( ( 24 752 8 0.625000 0 ) ( 24 752 40 0.625000 0.500000 ) ( 24 752 72 0.625000 1 ) ) +( ( 16 752 8 0.750000 0 ) ( 16 752 40 0.750000 0.500000 ) ( 16 752 72 0.750000 1 ) ) +( ( 8 752 8 0.875000 0 ) ( 8 752 40 0.875000 0.500000 ) ( 8 752 72 0.875000 1 ) ) +( ( 8 744 8 1 0 ) ( 8 744 40 1 0.500000 ) ( 8 744 72 1 1 ) ) +) + } + } +// brush 47 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 104 744 8 0 0 ) ( 104 744 40 0 0.500000 ) ( 104 744 72 0 1 ) ) +( ( 104 736 8 0.125000 0 ) ( 104 736 40 0.125000 0.500000 ) ( 104 736 72 0.125000 1 ) ) +( ( 112 736 8 0.250000 0 ) ( 112 736 40 0.250000 0.500000 ) ( 112 736 72 0.250000 1 ) ) +( ( 120 736 8 0.375000 0 ) ( 120 736 40 0.375000 0.500000 ) ( 120 736 72 0.375000 1 ) ) +( ( 120 744 8 0.500000 0 ) ( 120 744 40 0.500000 0.500000 ) ( 120 744 72 0.500000 1 ) ) +( ( 120 752 8 0.625000 0 ) ( 120 752 40 0.625000 0.500000 ) ( 120 752 72 0.625000 1 ) ) +( ( 112 752 8 0.750000 0 ) ( 112 752 40 0.750000 0.500000 ) ( 112 752 72 0.750000 1 ) ) +( ( 104 752 8 0.875000 0 ) ( 104 752 40 0.875000 0.500000 ) ( 104 752 72 0.875000 1 ) ) +( ( 104 744 8 1 0 ) ( 104 744 40 1 0.500000 ) ( 104 744 72 1 1 ) ) +) + } + } +// brush 48 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 272 744 8 0 0 ) ( 272 744 40 0 0.500000 ) ( 272 744 72 0 1 ) ) +( ( 272 736 8 0.125000 0 ) ( 272 736 40 0.125000 0.500000 ) ( 272 736 72 0.125000 1 ) ) +( ( 280 736 8 0.250000 0 ) ( 280 736 40 0.250000 0.500000 ) ( 280 736 72 0.250000 1 ) ) +( ( 288 736 8 0.375000 0 ) ( 288 736 40 0.375000 0.500000 ) ( 288 736 72 0.375000 1 ) ) +( ( 288 744 8 0.500000 0 ) ( 288 744 40 0.500000 0.500000 ) ( 288 744 72 0.500000 1 ) ) +( ( 288 752 8 0.625000 0 ) ( 288 752 40 0.625000 0.500000 ) ( 288 752 72 0.625000 1 ) ) +( ( 280 752 8 0.750000 0 ) ( 280 752 40 0.750000 0.500000 ) ( 280 752 72 0.750000 1 ) ) +( ( 272 752 8 0.875000 0 ) ( 272 752 40 0.875000 0.500000 ) ( 272 752 72 0.875000 1 ) ) +( ( 272 744 8 1 0 ) ( 272 744 40 1 0.500000 ) ( 272 744 72 1 1 ) ) +) + } + } +// brush 49 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 376 744 8 0 0 ) ( 376 744 40 0 0.500000 ) ( 376 744 72 0 1 ) ) +( ( 376 736 8 0.125000 0 ) ( 376 736 40 0.125000 0.500000 ) ( 376 736 72 0.125000 1 ) ) +( ( 384 736 8 0.250000 0 ) ( 384 736 40 0.250000 0.500000 ) ( 384 736 72 0.250000 1 ) ) +( ( 392 736 8 0.375000 0 ) ( 392 736 40 0.375000 0.500000 ) ( 392 736 72 0.375000 1 ) ) +( ( 392 744 8 0.500000 0 ) ( 392 744 40 0.500000 0.500000 ) ( 392 744 72 0.500000 1 ) ) +( ( 392 752 8 0.625000 0 ) ( 392 752 40 0.625000 0.500000 ) ( 392 752 72 0.625000 1 ) ) +( ( 384 752 8 0.750000 0 ) ( 384 752 40 0.750000 0.500000 ) ( 384 752 72 0.750000 1 ) ) +( ( 376 752 8 0.875000 0 ) ( 376 752 40 0.875000 0.500000 ) ( 376 752 72 0.875000 1 ) ) +( ( 376 744 8 1 0 ) ( 376 744 40 1 0.500000 ) ( 376 744 72 1 1 ) ) +) + } + } +// brush 50 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 464 744 8 0 0 ) ( 464 744 40 0 0.500000 ) ( 464 744 72 0 1 ) ) +( ( 464 736 8 0.125000 0 ) ( 464 736 40 0.125000 0.500000 ) ( 464 736 72 0.125000 1 ) ) +( ( 472 736 8 0.250000 0 ) ( 472 736 40 0.250000 0.500000 ) ( 472 736 72 0.250000 1 ) ) +( ( 480 736 8 0.375000 0 ) ( 480 736 40 0.375000 0.500000 ) ( 480 736 72 0.375000 1 ) ) +( ( 480 744 8 0.500000 0 ) ( 480 744 40 0.500000 0.500000 ) ( 480 744 72 0.500000 1 ) ) +( ( 480 752 8 0.625000 0 ) ( 480 752 40 0.625000 0.500000 ) ( 480 752 72 0.625000 1 ) ) +( ( 472 752 8 0.750000 0 ) ( 472 752 40 0.750000 0.500000 ) ( 472 752 72 0.750000 1 ) ) +( ( 464 752 8 0.875000 0 ) ( 464 752 40 0.875000 0.500000 ) ( 464 752 72 0.875000 1 ) ) +( ( 464 744 8 1 0 ) ( 464 744 40 1 0.500000 ) ( 464 744 72 1 1 ) ) +) + } + } +// brush 51 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 80 ) ( 524 336 80 ) ( 524 304 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 52 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 336 128 ) ( 532 304 128 ) ( 532 336 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 53 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 524 336 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 54 +{ +brushDef +{ +( 520 312 48 ) ( 520 304 48 ) ( 528 304 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 72 ) ( 524 336 72 ) ( 532 304 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 55 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 344 72 ) ( 524 312 72 ) ( 532 312 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 312 80 ) ( 524 344 80 ) ( 524 312 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 56 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 532 312 80 ) ( 524 312 80 ) ( 524 344 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 344 128 ) ( 532 312 128 ) ( 532 344 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 57 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 312 80 ) ( 532 312 80 ) ( 524 344 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 58 +{ +brushDef +{ +( 520 336 48 ) ( 520 328 48 ) ( 528 328 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 312 72 ) ( 524 344 72 ) ( 532 312 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 59 +{ +brushDef +{ +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.187500 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.187500 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 304 128 ) ( 532 336 128 ) ( 532 336 72 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 336 80 ) ( 524 336 80 ) ( 524 336 24 ) ( ( 0.015625 0 5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 336 80 ) ( 524 304 80 ) ( 524 304 24 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 532 304 24 ) ( ( 0.015625 0 -5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 60 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 61 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 62 +{ +brushDef +{ +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 304 104 ) ( 528 304 104 ) ( 528 336 104 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 304 152 ) ( 536 336 152 ) ( 536 336 96 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 536 336 104 ) ( 528 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 304 104 ) ( 528 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 104 ) ( 536 304 104 ) ( 536 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 63 +{ +brushDef +{ +( 488 336 8 ) ( 496 336 8 ) ( 496 344 8 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 -15 ) ) gothic_trim/wood2 134217728 0 0 +( 504 336 40 ) ( 504 328 40 ) ( 496 328 40 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 15 ) ) gothic_trim/wood2 134217728 0 0 +( 488 344 8 ) ( 496 344 8 ) ( 504 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -3.368932 ) ) gothic_trim/wood2 134217728 0 0 +( 488 328 8 ) ( 488 336 8 ) ( 496 336 40 ) ( ( 0.015625 0 13.375000 ) ( 0 0.015625 -1.216441 ) ) gothic_trim/wood2 134217728 0 0 +( 496 336 8 ) ( 488 336 8 ) ( 496 328 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -3.368936 ) ) gothic_trim/wood2 134217728 0 0 +( 496 336 8 ) ( 496 328 8 ) ( 504 328 40 ) ( ( 0.015625 0 -13.375000 ) ( 0 0.015625 -1.216413 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 64 +{ +brushDef +{ +( 496 296 8 ) ( 496 304 8 ) ( 488 304 8 ) ( ( 0 0.015625 11.625000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 496 312 40 ) ( 504 312 40 ) ( 504 304 40 ) ( ( 0 -0.015625 11.625000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 488 296 8 ) ( 488 304 8 ) ( 496 312 40 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -2.580697 ) ) gothic_trim/wood2 134217728 0 0 +( 504 296 8 ) ( 496 296 8 ) ( 496 304 40 ) ( ( 0.015625 0 10.125000 ) ( 0 0.015625 0.299379 ) ) gothic_trim/wood2 134217728 0 0 +( 496 304 8 ) ( 496 296 8 ) ( 504 304 40 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 -2.580694 ) ) gothic_trim/wood2 134217728 0 0 +( 496 304 8 ) ( 504 304 8 ) ( 504 312 40 ) ( ( 0.015625 0 -10.125000 ) ( 0 0.015625 0.299380 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 65 +{ +brushDef +{ +( 536 304 8 ) ( 528 304 8 ) ( 528 296 8 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 40 ) ( 520 312 40 ) ( 528 312 40 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 296 8 ) ( 528 296 8 ) ( 520 304 40 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 -0.761721 ) ) gothic_trim/wood2 134217728 0 0 +( 536 312 8 ) ( 536 304 8 ) ( 528 304 40 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -0.488851 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 8 ) ( 536 304 8 ) ( 528 312 40 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 -0.761720 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 8 ) ( 528 312 8 ) ( 520 312 40 ) ( ( 0.015625 0 -2.625000 ) ( 0 0.015625 -0.488853 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 66 +{ +brushDef +{ +( 528 344 8 ) ( 528 336 8 ) ( 536 336 8 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 328 40 ) ( 520 328 40 ) ( 520 336 40 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 344 8 ) ( 536 336 8 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -1.368011 ) ) gothic_trim/wood2 134217728 0 0 +( 520 344 8 ) ( 528 344 8 ) ( 528 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.125928 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 8 ) ( 528 344 8 ) ( 520 336 40 ) ( ( 0.015625 0 8.250001 ) ( 0 0.015625 -1.368012 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 8 ) ( 520 336 8 ) ( 520 328 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.125930 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 67 +{ +brushDef +{ +( 496 328 40 ) ( 496 304 40 ) ( 528 304 40 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 48 ) ( 496 304 48 ) ( 496 328 48 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 48 ) ( 528 328 48 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 48 ) ( 496 336 48 ) ( 496 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 496 328 48 ) ( 496 304 48 ) ( 496 304 40 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 496 304 48 ) ( 528 304 48 ) ( 528 304 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 68 +{ +brushDef +{ +( 440 352 40 ) ( 464 352 40 ) ( 464 384 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 48 ) ( 464 352 48 ) ( 440 352 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 48 ) ( 440 384 48 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 48 ) ( 432 352 48 ) ( 432 352 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 352 48 ) ( 464 352 48 ) ( 464 352 40 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 352 48 ) ( 464 384 48 ) ( 464 384 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 69 +{ +brushDef +{ +( 424 384 8 ) ( 432 384 8 ) ( 432 392 8 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 384 40 ) ( 440 376 40 ) ( 432 376 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 392 8 ) ( 432 392 8 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 134217728 0 0 +( 424 376 8 ) ( 424 384 8 ) ( 432 384 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 8 ) ( 424 384 8 ) ( 432 376 40 ) ( ( 0.015625 0 7.250001 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 8 ) ( 432 376 8 ) ( 440 376 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 70 +{ +brushDef +{ +( 464 392 8 ) ( 464 384 8 ) ( 472 384 8 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -13 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 40 ) ( 456 376 40 ) ( 456 384 40 ) ( ( 0 0.015625 -3.375000 ) ( -0.015625 0 13 ) ) gothic_trim/wood2 134217728 0 0 +( 472 392 8 ) ( 472 384 8 ) ( 464 376 40 ) ( ( 0.015625 0 -12.500000 ) ( 0 0.015625 -1.004194 ) ) gothic_trim/wood2 134217728 0 0 +( 456 392 8 ) ( 464 392 8 ) ( 464 384 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -3.156694 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 8 ) ( 464 392 8 ) ( 456 384 40 ) ( ( 0.015625 0 12.500000 ) ( 0 0.015625 -1.004192 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 8 ) ( 456 384 8 ) ( 456 376 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -3.156695 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 71 +{ +brushDef +{ +( 472 352 8 ) ( 464 352 8 ) ( 464 344 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 352 40 ) ( 456 360 40 ) ( 464 360 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 344 8 ) ( 464 344 8 ) ( 456 352 40 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.087216 ) ) gothic_trim/wood2 134217728 0 0 +( 472 360 8 ) ( 472 352 8 ) ( 464 352 40 ) ( ( 0.015625 0 -0.875000 ) ( 0 0.015625 0.056903 ) ) gothic_trim/wood2 134217728 0 0 +( 464 352 8 ) ( 472 352 8 ) ( 464 360 40 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.087221 ) ) gothic_trim/wood2 134217728 0 0 +( 464 352 8 ) ( 464 360 8 ) ( 456 360 40 ) ( ( 0.015625 0 0.875000 ) ( 0 0.015625 0.056905 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 72 +{ +brushDef +{ +( 432 344 8 ) ( 432 352 8 ) ( 424 352 8 ) ( ( 0 0.015625 9.875000 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 360 40 ) ( 440 360 40 ) ( 440 352 40 ) ( ( 0 -0.015625 9.875000 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 344 8 ) ( 424 352 8 ) ( 432 360 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.126388 ) ) gothic_trim/wood2 134217728 0 0 +( 440 344 8 ) ( 432 344 8 ) ( 432 352 40 ) ( ( 0.015625 0 12.375000 ) ( 0 0.015625 1.451483 ) ) gothic_trim/wood2 134217728 0 0 +( 432 352 8 ) ( 432 344 8 ) ( 440 352 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.126389 ) ) gothic_trim/wood2 134217728 0 0 +( 432 352 8 ) ( 440 352 8 ) ( 440 360 40 ) ( ( 0.015625 0 -12.375000 ) ( 0 0.015625 1.451492 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 73 +{ +brushDef +{ +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 392 104 ) ( 464 384 104 ) ( 432 384 104 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 392 152 ) ( 432 392 152 ) ( 432 392 96 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 392 104 ) ( 432 384 104 ) ( 432 384 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 464 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 104 ) ( 464 392 104 ) ( 464 392 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 74 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 75 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 76 +{ +brushDef +{ +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 388 128 ) ( 432 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 388 80 ) ( 432 380 80 ) ( 432 380 24 ) ( ( 0.015625 0 16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 380 80 ) ( 464 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 464 388 24 ) ( ( 0.015625 0 -16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 77 +{ +brushDef +{ +( 432 376 48 ) ( 440 376 48 ) ( 440 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 380 72 ) ( 424 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 78 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 380 80 ) ( 456 388 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 79 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 388 80 ) ( 456 380 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 388 128 ) ( 456 388 128 ) ( 424 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 80 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 424 380 72 ) ( 456 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 380 80 ) ( 424 380 80 ) ( 456 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 81 +{ +brushDef +{ +( 456 376 48 ) ( 464 376 48 ) ( 464 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 72 ) ( 432 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 82 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 83 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 388 128 ) ( 464 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 84 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 80 ) ( 432 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 85 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 80 ) ( 464 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 86 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 212 128 ) ( 432 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 87 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 88 +{ +brushDef +{ +( 440 224 48 ) ( 432 224 48 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 72 ) ( 464 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 89 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 80 ) ( 364 304 80 ) ( 364 336 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 90 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 356 304 128 ) ( 356 336 128 ) ( 356 304 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 91 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 92 +{ +brushDef +{ +( 368 328 48 ) ( 368 336 48 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 72 ) ( 364 304 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 93 +{ +brushDef +{ +( 392 312 40 ) ( 392 336 40 ) ( 360 336 40 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 48 ) ( 392 336 48 ) ( 392 312 48 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 48 ) ( 360 312 48 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 48 ) ( 392 304 48 ) ( 392 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 392 312 48 ) ( 392 336 48 ) ( 392 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 392 336 48 ) ( 360 336 48 ) ( 360 336 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 94 +{ +brushDef +{ +( 360 296 8 ) ( 360 304 8 ) ( 352 304 8 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 312 40 ) ( 368 312 40 ) ( 368 304 40 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 296 8 ) ( 352 304 8 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 134217728 0 0 +( 368 296 8 ) ( 360 296 8 ) ( 360 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 8 ) ( 360 296 8 ) ( 368 304 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 8 ) ( 368 304 8 ) ( 368 312 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 95 +{ +brushDef +{ +( 352 336 8 ) ( 360 336 8 ) ( 360 344 8 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 -13.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 40 ) ( 368 328 40 ) ( 360 328 40 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 13.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 344 8 ) ( 360 344 8 ) ( 368 336 40 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 -3.853989 ) ) gothic_trim/wood2 134217728 0 0 +( 352 328 8 ) ( 352 336 8 ) ( 360 336 40 ) ( ( 0.015625 0 15.375000 ) ( 0 0.015625 -2.034964 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 8 ) ( 352 336 8 ) ( 360 328 40 ) ( ( 0.015625 0 7.875002 ) ( 0 0.015625 -3.853986 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 8 ) ( 360 328 8 ) ( 368 328 40 ) ( ( 0.015625 0 -15.375000 ) ( 0 0.015625 -2.034965 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 96 +{ +brushDef +{ +( 392 344 8 ) ( 392 336 8 ) ( 400 336 8 ) ( ( 0 -0.015625 -2 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 392 328 40 ) ( 384 328 40 ) ( 384 336 40 ) ( ( 0 0.015625 -2 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 400 344 8 ) ( 400 336 8 ) ( 392 328 40 ) ( ( 0.015625 0 -11 ) ( 0 0.015625 -1.034511 ) ) gothic_trim/wood2 134217728 0 0 +( 384 344 8 ) ( 392 344 8 ) ( 392 336 40 ) ( ( 0.015625 0 3.750001 ) ( 0 0.015625 -2.792890 ) ) gothic_trim/wood2 134217728 0 0 +( 392 336 8 ) ( 392 344 8 ) ( 384 336 40 ) ( ( 0.015625 0 11 ) ( 0 0.015625 -1.034512 ) ) gothic_trim/wood2 134217728 0 0 +( 392 336 8 ) ( 384 336 8 ) ( 384 328 40 ) ( ( 0.015625 0 -3.750000 ) ( 0 0.015625 -2.792888 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 97 +{ +brushDef +{ +( 400 304 8 ) ( 392 304 8 ) ( 392 296 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -1.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 384 304 40 ) ( 384 312 40 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 1.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 400 296 8 ) ( 392 296 8 ) ( 384 304 40 ) ( ( 0.015625 0 1.875001 ) ( 0 0.015625 -0.276583 ) ) gothic_trim/wood2 134217728 0 0 +( 400 312 8 ) ( 400 304 8 ) ( 392 304 40 ) ( ( 0.015625 0 0.625000 ) ( 0 0.015625 0.329756 ) ) gothic_trim/wood2 134217728 0 0 +( 392 304 8 ) ( 400 304 8 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -0.276584 ) ) gothic_trim/wood2 134217728 0 0 +( 392 304 8 ) ( 392 312 8 ) ( 384 312 40 ) ( ( 0.015625 0 -0.625000 ) ( 0 0.015625 0.329758 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 98 +{ +brushDef +{ +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 336 104 ) ( 360 336 104 ) ( 360 304 104 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 336 152 ) ( 352 304 152 ) ( 352 304 96 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 352 304 104 ) ( 360 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 336 104 ) ( 360 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 104 ) ( 352 336 104 ) ( 352 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 99 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 100 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 101 +{ +brushDef +{ +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0 0.015625 9.437500 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0 -0.015625 9.437500 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 356 336 128 ) ( 356 304 128 ) ( 356 304 72 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 356 304 80 ) ( 364 304 80 ) ( 364 304 24 ) ( ( 0.015625 0 11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 304 80 ) ( 364 336 80 ) ( 364 336 24 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 356 336 24 ) ( ( 0.015625 0 -11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 102 +{ +brushDef +{ +( 368 304 48 ) ( 368 312 48 ) ( 360 312 48 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 328 72 ) ( 364 296 72 ) ( 356 328 72 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 103 +{ +brushDef +{ +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 328 80 ) ( 356 328 80 ) ( 364 296 80 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 104 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 296 72 ) ( 364 328 72 ) ( 356 328 72 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 328 80 ) ( 364 296 80 ) ( 364 328 24 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 105 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 220 72 ) ( 440 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 220 80 ) ( 472 220 80 ) ( 440 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 106 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 212 80 ) ( 440 220 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 212 128 ) ( 440 212 128 ) ( 472 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 107 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 220 80 ) ( 440 212 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 108 +{ +brushDef +{ +( 464 224 48 ) ( 456 224 48 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 220 72 ) ( 472 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 109 +{ +brushDef +{ +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 212 128 ) ( 464 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 212 80 ) ( 464 220 80 ) ( 464 220 24 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 220 80 ) ( 432 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 432 212 24 ) ( ( 0.015625 0 0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 110 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 111 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 112 +{ +brushDef +{ +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 208 104 ) ( 432 216 104 ) ( 464 216 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 208 152 ) ( 464 208 152 ) ( 464 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 208 104 ) ( 464 216 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 432 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 104 ) ( 432 208 104 ) ( 432 208 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 113 +{ +brushDef +{ +( 464 256 8 ) ( 464 248 8 ) ( 472 248 8 ) ( ( 0 -0.015625 -3.625000 ) ( 0.015625 0 -10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 240 40 ) ( 456 240 40 ) ( 456 248 40 ) ( ( 0 0.015625 -3.625000 ) ( -0.015625 0 10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 256 8 ) ( 472 248 8 ) ( 464 240 40 ) ( ( 0.015625 0 -9.625000 ) ( 0 0.015625 -1.367998 ) ) gothic_trim/wood2 134217728 0 0 +( 456 256 8 ) ( 464 256 8 ) ( 464 248 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.459404 ) ) gothic_trim/wood2 134217728 0 0 +( 464 248 8 ) ( 464 256 8 ) ( 456 248 40 ) ( ( 0.015625 0 9.625000 ) ( 0 0.015625 -1.367999 ) ) gothic_trim/wood2 134217728 0 0 +( 464 248 8 ) ( 456 248 8 ) ( 456 240 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.459402 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 114 +{ +brushDef +{ +( 424 248 8 ) ( 432 248 8 ) ( 432 256 8 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 248 40 ) ( 440 240 40 ) ( 432 240 40 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 256 8 ) ( 432 256 8 ) ( 440 248 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.823671 ) ) gothic_trim/wood2 134217728 0 0 +( 424 240 8 ) ( 424 248 8 ) ( 432 248 40 ) ( ( 0.015625 0 15.250000 ) ( 0 0.015625 -1.701477 ) ) gothic_trim/wood2 134217728 0 0 +( 432 248 8 ) ( 424 248 8 ) ( 432 240 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.823672 ) ) gothic_trim/wood2 134217728 0 0 +( 432 248 8 ) ( 432 240 8 ) ( 440 240 40 ) ( ( 0.015625 0 -15.250000 ) ( 0 0.015625 -1.701478 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 115 +{ +brushDef +{ +( 432 208 8 ) ( 432 216 8 ) ( 424 216 8 ) ( ( 0 0.015625 10.125000 ) ( -0.015625 0 -3.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 40 ) ( 440 224 40 ) ( 440 216 40 ) ( ( 0 -0.015625 10.125000 ) ( 0.015625 0 3.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 208 8 ) ( 424 216 8 ) ( 432 224 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 134217728 0 0 +( 440 208 8 ) ( 432 208 8 ) ( 432 216 40 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.754196 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 8 ) ( 432 208 8 ) ( 440 216 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 8 ) ( 440 216 8 ) ( 440 224 40 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.754195 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 116 +{ +brushDef +{ +( 472 216 8 ) ( 464 216 8 ) ( 464 208 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 216 40 ) ( 456 224 40 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 208 8 ) ( 464 208 8 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 224 8 ) ( 472 216 8 ) ( 464 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 8 ) ( 472 216 8 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 8 ) ( 464 224 8 ) ( 456 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 117 +{ +brushDef +{ +( 456 248 40 ) ( 432 248 40 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 48 ) ( 432 248 48 ) ( 456 248 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 48 ) ( 456 216 48 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 48 ) ( 464 248 48 ) ( 464 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 248 48 ) ( 432 248 48 ) ( 432 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 248 48 ) ( 432 216 48 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 118 +{ +brushDef +{ +( 336 256 288 ) ( 0 256 288 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 0 256 296 ) ( 336 256 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 336 136 296 ) ( 336 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 128 296 ) ( 512 248 296 ) ( 512 248 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 336 256 296 ) ( 0 256 296 ) ( 0 256 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 256 296 ) ( 0 136 296 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 119 +{ +brushDef +{ +( 632 96 288 ) ( 512 96 288 ) ( 512 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 4.937803 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 8 296 ) ( 512 64 296 ) ( 632 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -4.937810 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 544 136 296 ) ( 664 136 296 ) ( 664 136 -208 ) ( ( 0.007813 0 -4.937810 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 8 296 ) ( 632 64 296 ) ( 632 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 448 296 ) ( 512 448 296 ) ( 512 448 -208 ) ( ( 0.007812 0 4.937197 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 64 296 ) ( 512 8 296 ) ( 512 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 120 +{ +brushDef +{ +( 0 96 288 ) ( -120 96 288 ) ( -120 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 8 296 ) ( -120 64 296 ) ( 0 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -88 136 296 ) ( 32 136 296 ) ( 32 136 -208 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 8 296 ) ( 0 64 296 ) ( 0 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 448 296 ) ( -120 448 296 ) ( -120 448 -208 ) ( ( 0.007812 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 64 296 ) ( -120 8 296 ) ( -120 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 121 +{ +brushDef +{ +( 48 680 8 ) ( 32 680 8 ) ( 32 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -1.000055 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 32 664 512 ) ( 32 680 512 ) ( 48 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 1.000055 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 24 664 112 ) ( 40 664 112 ) ( 40 664 104 ) ( ( 0.007813 0 1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 40 664 112 ) ( 40 680 112 ) ( 40 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 40 680 112 ) ( 24 680 112 ) ( 24 680 104 ) ( ( 0.007813 0 -1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 24 680 112 ) ( 24 664 112 ) ( 24 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 122 +{ +brushDef +{ +( 496 680 8 ) ( 480 680 8 ) ( 480 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 2.500159 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 480 664 512 ) ( 480 680 512 ) ( 496 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -2.500159 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 472 664 112 ) ( 488 664 112 ) ( 488 664 104 ) ( ( 0.007813 0 -2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 488 664 112 ) ( 488 680 112 ) ( 488 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 488 680 112 ) ( 472 680 112 ) ( 472 680 104 ) ( ( 0.007813 0 2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 472 680 112 ) ( 472 664 112 ) ( 472 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 123 +{ +brushDef +{ +( 368 424 8 ) ( 352 424 8 ) ( 352 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 1.500098 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 352 408 512 ) ( 352 424 512 ) ( 368 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.500098 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 344 408 112 ) ( 360 408 112 ) ( 360 408 104 ) ( ( 0.007813 0 -1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 360 408 112 ) ( 360 424 112 ) ( 360 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 360 424 112 ) ( 344 424 112 ) ( 344 424 104 ) ( ( 0.007813 0 1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 344 424 112 ) ( 344 408 112 ) ( 344 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 124 +{ +brushDef +{ +( 176 424 8 ) ( 160 424 8 ) ( 160 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 160 408 512 ) ( 160 424 512 ) ( 176 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 152 408 112 ) ( 168 408 112 ) ( 168 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 168 408 112 ) ( 168 424 112 ) ( 168 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 168 424 112 ) ( 152 424 112 ) ( 152 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 152 424 112 ) ( 152 408 112 ) ( 152 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 125 +{ +brushDef +{ +( 640 968 0 ) ( 336 968 0 ) ( 336 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 336 960 512 ) ( 336 968 512 ) ( 640 968 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 960 512 ) ( 208 960 512 ) ( 208 960 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 512 ) ( 640 968 512 ) ( 640 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 968 512 ) ( 336 968 512 ) ( 336 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 944 512 ) ( -128 936 512 ) ( -128 936 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 126 +{ +brushDef +{ +( 640 600 8 ) ( 640 632 8 ) ( 632 632 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 640 640 512 ) ( 640 608 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 632 608 512 ) ( 632 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 512 512 ) ( 640 512 512 ) ( 640 512 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 512 ) ( 640 544 512 ) ( 640 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 512 ) ( 632 640 512 ) ( 632 640 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 127 +{ +brushDef +{ +( 640 192 8 ) ( 640 512 8 ) ( 632 512 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 104 ) ( 640 376 104 ) ( 632 480 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 128 +{ +brushDef +{ +( 632 512 512 ) ( 640 512 512 ) ( 640 192 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 232 ) ( 632 480 232 ) ( 640 376 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 129 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 128 ) ( 640 480 128 ) ( 632 480 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 130 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 224 128 ) ( 632 224 128 ) ( 640 224 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 131 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 376 128 ) ( 632 376 128 ) ( 640 376 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 328 128 ) ( 640 328 128 ) ( 632 328 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 132 +{ +brushDef +{ +( 640 640 8 ) ( 640 960 8 ) ( 632 960 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 104 ) ( 648 672 104 ) ( 640 776 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 133 +{ +brushDef +{ +( 632 960 512 ) ( 640 960 512 ) ( 640 640 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 232 ) ( 640 776 232 ) ( 648 672 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 134 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 648 672 128 ) ( 640 672 128 ) ( 648 672 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 135 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 128 ) ( 648 776 128 ) ( 640 776 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 824 128 ) ( 640 824 128 ) ( 648 824 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 136 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 928 128 ) ( 648 928 128 ) ( 640 928 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 137 +{ +brushDef +{ +( 632 824 176 ) ( 640 824 176 ) ( 640 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 928 168 ) ( 640 928 176 ) ( 632 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 824 168 ) ( 632 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 832 168 ) ( 632 832 176 ) ( 632 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 824 176 ) ( 640 824 176 ) ( 640 800 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 848 176 ) ( 640 848 168 ) ( 640 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 138 +{ +brushDef +{ +( 640 872 104 ) ( 640 880 104 ) ( 632 880 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 824 168 ) ( 640 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 139 +{ +brushDef +{ +( 632 880 232 ) ( 640 880 232 ) ( 640 872 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 824 176 ) ( 632 824 176 ) ( 640 800 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 140 +{ +brushDef +{ +( 632 728 232 ) ( 640 728 232 ) ( 640 720 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 672 176 ) ( 632 672 176 ) ( 640 648 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 141 +{ +brushDef +{ +( 640 720 104 ) ( 640 728 104 ) ( 632 728 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 672 168 ) ( 640 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 142 +{ +brushDef +{ +( 632 672 176 ) ( 640 672 176 ) ( 640 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 776 168 ) ( 640 776 176 ) ( 632 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 672 168 ) ( 632 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 680 168 ) ( 632 680 176 ) ( 632 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +( 632 672 176 ) ( 640 672 176 ) ( 640 648 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 696 176 ) ( 640 696 168 ) ( 640 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 143 +{ +brushDef +{ +( 632 376 176 ) ( 640 376 176 ) ( 640 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 480 168 ) ( 640 480 176 ) ( 632 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 376 168 ) ( 632 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 384 168 ) ( 632 384 176 ) ( 632 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 376 176 ) ( 640 376 176 ) ( 640 352 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 400 176 ) ( 640 400 168 ) ( 640 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 144 +{ +brushDef +{ +( 640 424 104 ) ( 640 432 104 ) ( 632 432 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 376 168 ) ( 640 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 145 +{ +brushDef +{ +( 632 432 232 ) ( 640 432 232 ) ( 640 424 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 376 176 ) ( 632 376 176 ) ( 640 352 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 146 +{ +brushDef +{ +( 632 280 232 ) ( 640 280 232 ) ( 640 272 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 224 176 ) ( 632 224 176 ) ( 640 200 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 147 +{ +brushDef +{ +( 640 272 104 ) ( 640 280 104 ) ( 632 280 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 224 168 ) ( 640 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 148 +{ +brushDef +{ +( 632 224 176 ) ( 640 224 176 ) ( 640 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 328 168 ) ( 640 328 176 ) ( 632 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 224 168 ) ( 632 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 232 168 ) ( 632 232 176 ) ( 632 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +( 632 224 176 ) ( 640 224 176 ) ( 640 200 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 248 176 ) ( 640 248 168 ) ( 640 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 149 +{ +brushDef +{ +( -120 616 8 ) ( -120 648 8 ) ( -128 648 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -120 640 512 ) ( -120 608 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -128 608 512 ) ( -128 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 512 512 ) ( -120 512 512 ) ( -120 512 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 512 ) ( -120 544 512 ) ( -120 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 512 ) ( -128 640 512 ) ( -128 640 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 150 +{ +brushDef +{ +( -120 192 8 ) ( -120 512 8 ) ( -128 512 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 136 16 ) ( -120 456 16 ) ( -120 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 104 ) ( -120 376 104 ) ( -128 480 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 151 +{ +brushDef +{ +( -128 512 512 ) ( -120 512 512 ) ( -120 192 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 232 ) ( -128 480 232 ) ( -120 376 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 152 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 128 ) ( -120 480 128 ) ( -128 480 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 153 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 224 128 ) ( -128 224 128 ) ( -120 224 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 154 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 376 128 ) ( -128 376 128 ) ( -120 376 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 328 128 ) ( -120 328 128 ) ( -128 328 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 155 +{ +brushDef +{ +( -120 640 8 ) ( -120 960 8 ) ( -128 960 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 104 ) ( -112 672 104 ) ( -120 776 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 156 +{ +brushDef +{ +( -128 960 512 ) ( -120 960 512 ) ( -120 640 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 232 ) ( -120 776 232 ) ( -112 672 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 157 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -112 672 128 ) ( -120 672 128 ) ( -112 672 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 158 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 128 ) ( -112 776 128 ) ( -120 776 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 824 128 ) ( -120 824 128 ) ( -112 824 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 159 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 928 128 ) ( -112 928 128 ) ( -120 928 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 160 +{ +brushDef +{ +( -128 824 176 ) ( -120 824 176 ) ( -120 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 928 168 ) ( -120 928 176 ) ( -128 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 824 168 ) ( -128 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 832 168 ) ( -128 832 176 ) ( -128 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 824 176 ) ( -120 824 176 ) ( -120 800 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 848 176 ) ( -120 848 168 ) ( -120 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 161 +{ +brushDef +{ +( -120 872 104 ) ( -120 880 104 ) ( -128 880 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 824 168 ) ( -120 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 162 +{ +brushDef +{ +( -128 880 232 ) ( -120 880 232 ) ( -120 872 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 824 176 ) ( -128 824 176 ) ( -120 800 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 163 +{ +brushDef +{ +( -128 728 232 ) ( -120 728 232 ) ( -120 720 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 672 176 ) ( -128 672 176 ) ( -120 648 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 164 +{ +brushDef +{ +( -120 720 104 ) ( -120 728 104 ) ( -128 728 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 672 168 ) ( -120 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 165 +{ +brushDef +{ +( -128 672 176 ) ( -120 672 176 ) ( -120 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 776 168 ) ( -120 776 176 ) ( -128 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 672 168 ) ( -128 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 680 168 ) ( -128 680 176 ) ( -128 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +( -128 672 176 ) ( -120 672 176 ) ( -120 648 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 696 176 ) ( -120 696 168 ) ( -120 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 166 +{ +brushDef +{ +( -128 376 176 ) ( -120 376 176 ) ( -120 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 480 168 ) ( -120 480 176 ) ( -128 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 376 168 ) ( -128 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 384 168 ) ( -128 384 176 ) ( -128 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 376 176 ) ( -120 376 176 ) ( -120 352 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 400 176 ) ( -120 400 168 ) ( -120 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 167 +{ +brushDef +{ +( -120 424 104 ) ( -120 432 104 ) ( -128 432 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 376 168 ) ( -120 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 168 +{ +brushDef +{ +( -128 432 232 ) ( -120 432 232 ) ( -120 424 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 376 176 ) ( -128 376 176 ) ( -120 352 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 169 +{ +brushDef +{ +( -128 280 232 ) ( -120 280 232 ) ( -120 272 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 224 176 ) ( -128 224 176 ) ( -120 200 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 170 +{ +brushDef +{ +( -120 272 104 ) ( -120 280 104 ) ( -128 280 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 224 168 ) ( -120 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 171 +{ +brushDef +{ +( -128 224 176 ) ( -120 224 176 ) ( -120 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 328 168 ) ( -120 328 176 ) ( -128 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 224 168 ) ( -128 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 232 168 ) ( -128 232 176 ) ( -128 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +( -128 224 176 ) ( -120 224 176 ) ( -120 200 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 248 176 ) ( -120 248 168 ) ( -120 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 172 +{ +brushDef +{ +( 384 952 176 ) ( 80 952 176 ) ( 80 920 176 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 184 ) ( 104 952 184 ) ( 408 952 184 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 184 ) ( 408 920 184 ) ( 408 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 920 184 ) ( 408 952 184 ) ( 408 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 952 184 ) ( 104 952 184 ) ( 104 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 952 184 ) ( 104 920 184 ) ( 104 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 173 +{ +brushDef +{ +( 384 952 112 ) ( 80 952 112 ) ( 80 920 112 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 120 ) ( 104 952 120 ) ( 408 952 120 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 120 ) ( 408 920 120 ) ( 408 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 920 120 ) ( 408 952 120 ) ( 408 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 952 120 ) ( 104 952 120 ) ( 104 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 952 120 ) ( 104 920 120 ) ( 104 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 174 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 104 ) ( 104 960 104 ) ( 104 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 175 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 952 104 ) ( 416 952 104 ) ( 96 952 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 176 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 960 104 ) ( 408 920 104 ) ( 408 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 177 +{ +brushDef +{ +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 248 ) ( 96 920 248 ) ( 416 960 248 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 178 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 16 ) ( 416 960 16 ) ( 96 920 16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 179 +{ +brushDef +{ +( 144 776 8 ) ( 144 792 8 ) ( -24 792 8 ) ( ( 0 0.007813 7.250462 ) ( -0.007813 0 2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( 144 792 104 ) ( 144 776 104 ) ( ( 0 -0.007813 7.250462 ) ( 0.007813 0 -2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 776 104 ) ( -24 776 96 ) ( ( 0.007813 0 -3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 776 104 ) ( 144 776 104 ) ( 144 776 96 ) ( ( 0.007813 0 6.125393 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 768 104 ) ( 536 784 104 ) ( 536 784 96 ) ( ( 0.007813 0 3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 792 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 -6.125392 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 180 +{ +brushDef +{ +( -8 960 8 ) ( -24 960 8 ) ( -24 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 960 104 ) ( -8 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -8 792 104 ) ( -8 792 96 ) ( ( 0.007813 0 4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 792 104 ) ( -8 960 104 ) ( -8 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 960 104 ) ( -24 960 104 ) ( -24 960 96 ) ( ( 0.007813 0 -4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 960 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 181 +{ +brushDef +{ +( 536 960 8 ) ( 520 960 8 ) ( 520 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 520 960 104 ) ( 536 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 536 792 104 ) ( 536 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 792 104 ) ( 536 960 104 ) ( 536 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 960 104 ) ( 520 960 104 ) ( 520 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 960 104 ) ( 520 792 104 ) ( 520 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 182 +{ +brushDef +{ +( 272 832 104 ) ( 32 832 104 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 768 112 ) ( 32 832 112 ) ( 272 832 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 768 112 ) ( 272 768 112 ) ( 272 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 760 112 ) ( 480 824 112 ) ( 480 824 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 272 832 112 ) ( 32 832 112 ) ( 32 832 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 832 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +} +} +// brush 183 +{ +brushDef +{ +( 544 960 104 ) ( 480 960 104 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 5.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 768 112 ) ( 480 960 112 ) ( 544 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -5.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 768 112 ) ( 544 768 112 ) ( 544 768 104 ) ( ( 0.015625 0 -5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 544 768 112 ) ( 544 960 112 ) ( 544 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 544 960 112 ) ( 480 960 112 ) ( 480 960 104 ) ( ( 0.015625 0 5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 960 112 ) ( 480 768 112 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +} +} +// brush 184 +{ +brushDef +{ +( 32 960 104 ) ( -32 960 104 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( -32 768 112 ) ( -32 960 112 ) ( 32 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( -32 768 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 768 112 ) ( 32 960 112 ) ( 32 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 960 112 ) ( -32 960 112 ) ( -32 960 104 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( -32 960 112 ) ( -32 768 112 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +} +} +// brush 185 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 512 8.000001 0 0 ) ( 440 512 36 0 0.687500 ) ( 440 512 64 0 1.375000 ) ) +( ( 440 504 8.000001 0.125000 0 ) ( 440 504 36 0.125000 0.687500 ) ( 440 504 64 0.125000 1.375000 ) ) +( ( 448 504 8.000001 0.250000 0 ) ( 448 504 36 0.250000 0.687500 ) ( 448 504 64 0.250000 1.375000 ) ) +( ( 456 504 8.000001 0.375000 0 ) ( 456 504 36 0.375000 0.687500 ) ( 456 504 64 0.375000 1.375000 ) ) +( ( 456 512 8.000001 0.500000 0 ) ( 456 512 36 0.500000 0.687500 ) ( 456 512 64 0.500000 1.375000 ) ) +( ( 456 520 8.000001 0.625000 0 ) ( 456 520 36 0.625000 0.687500 ) ( 456 520 64 0.625000 1.375000 ) ) +( ( 448 520 8.000001 0.750000 0 ) ( 448 520 36 0.750000 0.687500 ) ( 448 520 64 0.750000 1.375000 ) ) +( ( 440 520 8.000001 0.875000 0 ) ( 440 520 36 0.875000 0.687500 ) ( 440 520 64 0.875000 1.375000 ) ) +( ( 440 512 8.000001 1 0 ) ( 440 512 36 1 0.687500 ) ( 440 512 64 1 1.375000 ) ) +) + } + } +// brush 186 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 320 8.000001 0 0 ) ( 440 320 36 0 0.687500 ) ( 440 320 64 0 1.375000 ) ) +( ( 440 312 8.000001 0.125000 0 ) ( 440 312 36 0.125000 0.687500 ) ( 440 312 64 0.125000 1.375000 ) ) +( ( 448 312 8.000001 0.250000 0 ) ( 448 312 36 0.250000 0.687500 ) ( 448 312 64 0.250000 1.375000 ) ) +( ( 456 312 8.000001 0.375000 0 ) ( 456 312 36 0.375000 0.687500 ) ( 456 312 64 0.375000 1.375000 ) ) +( ( 456 320 8.000001 0.500000 0 ) ( 456 320 36 0.500000 0.687500 ) ( 456 320 64 0.500000 1.375000 ) ) +( ( 456 328 8.000001 0.625000 0 ) ( 456 328 36 0.625000 0.687500 ) ( 456 328 64 0.625000 1.375000 ) ) +( ( 448 328 8.000001 0.750000 0 ) ( 448 328 36 0.750000 0.687500 ) ( 448 328 64 0.750000 1.375000 ) ) +( ( 440 328 8.000001 0.875000 0 ) ( 440 328 36 0.875000 0.687500 ) ( 440 328 64 0.875000 1.375000 ) ) +( ( 440 320 8.000001 1 0 ) ( 440 320 36 1 0.687500 ) ( 440 320 64 1 1.375000 ) ) +) + } + } +// brush 187 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 320 8.000001 0 0 ) ( 56 320 36 0 0.687500 ) ( 56 320 64 0 1.375000 ) ) +( ( 56 312 8.000001 0.125000 0 ) ( 56 312 36 0.125000 0.687500 ) ( 56 312 64 0.125000 1.375000 ) ) +( ( 64 312 8.000001 0.250000 0 ) ( 64 312 36 0.250000 0.687500 ) ( 64 312 64 0.250000 1.375000 ) ) +( ( 72 312 8.000001 0.375000 0 ) ( 72 312 36 0.375000 0.687500 ) ( 72 312 64 0.375000 1.375000 ) ) +( ( 72 320 8.000001 0.500000 0 ) ( 72 320 36 0.500000 0.687500 ) ( 72 320 64 0.500000 1.375000 ) ) +( ( 72 328 8.000001 0.625000 0 ) ( 72 328 36 0.625000 0.687500 ) ( 72 328 64 0.625000 1.375000 ) ) +( ( 64 328 8.000001 0.750000 0 ) ( 64 328 36 0.750000 0.687500 ) ( 64 328 64 0.750000 1.375000 ) ) +( ( 56 328 8.000001 0.875000 0 ) ( 56 328 36 0.875000 0.687500 ) ( 56 328 64 0.875000 1.375000 ) ) +( ( 56 320 8.000001 1 0 ) ( 56 320 36 1 0.687500 ) ( 56 320 64 1 1.375000 ) ) +) + } + } +// brush 188 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 512 8.000001 0 0 ) ( 56 512 36 0 0.687500 ) ( 56 512 64 0 1.375000 ) ) +( ( 56 504 8.000001 0.125000 0 ) ( 56 504 36 0.125000 0.687500 ) ( 56 504 64 0.125000 1.375000 ) ) +( ( 64 504 8.000001 0.250000 0 ) ( 64 504 36 0.250000 0.687500 ) ( 64 504 64 0.250000 1.375000 ) ) +( ( 72 504 8.000001 0.375000 0 ) ( 72 504 36 0.375000 0.687500 ) ( 72 504 64 0.375000 1.375000 ) ) +( ( 72 512 8.000001 0.500000 0 ) ( 72 512 36 0.500000 0.687500 ) ( 72 512 64 0.500000 1.375000 ) ) +( ( 72 520 8.000001 0.625000 0 ) ( 72 520 36 0.625000 0.687500 ) ( 72 520 64 0.625000 1.375000 ) ) +( ( 64 520 8.000001 0.750000 0 ) ( 64 520 36 0.750000 0.687500 ) ( 64 520 64 0.750000 1.375000 ) ) +( ( 56 520 8.000001 0.875000 0 ) ( 56 520 36 0.875000 0.687500 ) ( 56 520 64 0.875000 1.375000 ) ) +( ( 56 512 8.000001 1 0 ) ( 56 512 36 1 0.687500 ) ( 56 512 64 1 1.375000 ) ) +) + } + } +// brush 189 +{ +brushDef +{ +( 608 128 176 ) ( 608 136 176 ) ( 608 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 136 168 ) ( 504 136 176 ) ( 504 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 136 168 ) ( 608 128 168 ) ( 632 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -12.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 128 168 ) ( 600 128 176 ) ( 624 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 6.250000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 128 176 ) ( 608 136 176 ) ( 632 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -12.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 584 136 176 ) ( 584 136 168 ) ( 608 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 6.250000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 190 +{ +brushDef +{ +( 560 136 104 ) ( 552 136 104 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 608 128 168 ) ( 608 136 168 ) ( 632 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 191 +{ +brushDef +{ +( 552 128 232 ) ( 552 136 232 ) ( 560 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 608 136 176 ) ( 608 128 176 ) ( 632 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 192 +{ +brushDef +{ +( 400 128 232 ) ( 400 136 232 ) ( 408 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 136 176 ) ( 456 128 176 ) ( 480 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 193 +{ +brushDef +{ +( 408 136 104 ) ( 400 136 104 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 128 168 ) ( 456 136 168 ) ( 480 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 194 +{ +brushDef +{ +( 456 128 176 ) ( 456 136 176 ) ( 456 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 136 168 ) ( 352 136 176 ) ( 352 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 136 168 ) ( 456 128 168 ) ( 480 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 448 128 168 ) ( 448 128 176 ) ( 472 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 3.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 128 176 ) ( 456 136 176 ) ( 480 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 136 176 ) ( 432 136 168 ) ( 456 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 3.875000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 195 +{ +brushDef +{ +( 160 128 176 ) ( 160 136 176 ) ( 160 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 56 136 168 ) ( 56 136 176 ) ( 56 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 160 136 168 ) ( 160 128 168 ) ( 184 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -5.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 152 128 168 ) ( 152 128 176 ) ( 176 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -0.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 160 128 176 ) ( 160 136 176 ) ( 184 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -5.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 136 176 ) ( 136 136 168 ) ( 160 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -0.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 196 +{ +brushDef +{ +( 112 136 104 ) ( 104 136 104 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 160 128 168 ) ( 160 136 168 ) ( 184 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 197 +{ +brushDef +{ +( 104 128 232 ) ( 104 136 232 ) ( 112 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 160 136 176 ) ( 160 128 176 ) ( 184 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 198 +{ +brushDef +{ +( -48 128 232 ) ( -48 136 232 ) ( -40 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 136 176 ) ( 8 128 176 ) ( 32 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 199 +{ +brushDef +{ +( -40 136 104 ) ( -48 136 104 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 128 168 ) ( 8 136 168 ) ( 32 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 200 +{ +brushDef +{ +( 8 128 176 ) ( 8 136 176 ) ( 8 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 136 168 ) ( -96 136 176 ) ( -96 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 136 168 ) ( 8 128 168 ) ( 32 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -3.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 0 128 168 ) ( 0 128 176 ) ( 24 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 128 176 ) ( 8 136 176 ) ( 32 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -3.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -16 136 176 ) ( -16 136 168 ) ( 8 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 201 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 136 128 ) ( -96 144 128 ) ( -96 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 202 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 128 ) ( 56 144 128 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 144 128 ) ( 8 136 128 ) ( 8 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 203 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 128 ) ( 160 136 128 ) ( 160 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 204 +{ +brushDef +{ +( 192 136 8 ) ( -128 136 8 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 104 ) ( 160 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 205 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 128 ) ( 456 128 128 ) ( 456 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 128 ) ( 504 136 128 ) ( 504 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 206 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 128 ) ( 608 128 128 ) ( 608 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 207 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 128 ) ( 352 136 128 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 208 +{ +brushDef +{ +( 640 136 8 ) ( 320 136 8 ) ( 320 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 104 ) ( 456 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 209 +{ +brushDef +{ +( 624 -144 -40 ) ( 408 -144 -40 ) ( 408 -184 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 -16 ) ( 408 -144 -16 ) ( 624 -144 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 0 ) ( 624 -184 0 ) ( 624 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -184 0 ) ( 624 -144 0 ) ( 624 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -144 0 ) ( 408 -144 0 ) ( 408 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -144 0 ) ( 408 -184 0 ) ( 408 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +} +} +// brush 210 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 -192 24 ) ( 408 -136 24 ) ( 408 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 211 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -144 24 ) ( 632 -144 24 ) ( 400 -144 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 212 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 624 -136 24 ) ( 624 -192 24 ) ( 624 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 213 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -184 24 ) ( 400 -184 24 ) ( 632 -184 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 214 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 -40 ) ( 632 -136 -40 ) ( 400 -192 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 215 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 176 128 ) ( 312 176 128 ) ( 304 176 120 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 216 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +( 312 152 128 ) ( 304 152 128 ) ( 312 152 120 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 217 +{ +brushDef +{ +( 304 192 152 ) ( 312 192 152 ) ( 312 144 152 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 176 144 ) ( 304 176 144 ) ( 312 152 144 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 218 +{ +brushDef +{ +( 312 144 64 ) ( 312 192 64 ) ( 304 192 64 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 176 72 ) ( 312 152 72 ) ( 304 176 72 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 219 +{ +brushDef +{ +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.007813 3.375216 ) ( -0.007813 0 -0.562538 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.007813 3.375216 ) ( 0.007813 0 0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 304 176 128 ) ( 304 152 128 ) ( 304 152 120 ) ( ( 0.007813 0 1.062570 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 304 152 128 ) ( 312 152 128 ) ( 312 152 120 ) ( ( 0.007813 0 3.125201 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 312 152 128 ) ( 312 176 128 ) ( 312 176 120 ) ( ( 0.007813 0 -1.062568 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 312 176 128 ) ( 304 176 128 ) ( 304 176 120 ) ( ( 0.007813 0 -3.125200 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 220 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 152 128 ) ( 200 152 128 ) ( 208 152 120 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 221 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +( 200 176 128 ) ( 208 176 128 ) ( 200 176 120 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 222 +{ +brushDef +{ +( 208 144 152 ) ( 200 144 152 ) ( 200 192 152 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 152 144 ) ( 208 152 144 ) ( 200 176 144 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 223 +{ +brushDef +{ +( 200 192 64 ) ( 200 144 64 ) ( 208 144 64 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 152 72 ) ( 200 176 72 ) ( 208 152 72 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 224 +{ +brushDef +{ +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.007813 -0.500000 ) ( 0.007813 0 -3 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.007813 -0.500000 ) ( -0.007813 0 3 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 208 152 128 ) ( 208 176 128 ) ( 208 176 120 ) ( ( 0.007813 0 -3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 208 176 128 ) ( 200 176 128 ) ( 200 176 120 ) ( ( 0.007813 0 0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 200 176 128 ) ( 200 152 128 ) ( 200 152 120 ) ( ( 0.007813 0 3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 200 152 128 ) ( 208 152 128 ) ( 208 152 120 ) ( ( 0.007813 0 -0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 225 +{ +brushDef +{ +( 136 -128 -48 ) ( 136 -152 -48 ) ( 144 -152 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -128 0 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -152 8 ) ( 144 -128 8 ) ( 144 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -128 8 ) ( 136 -128 8 ) ( 136 -128 0 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -152 8 ) ( 144 -152 8 ) ( 144 -152 0 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 226 +{ +brushDef +{ +( 136 -152 -48 ) ( 136 -176 -48 ) ( 144 -176 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -152 -8 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -176 0 ) ( 144 -152 0 ) ( 144 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -152 -8 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -176 0 ) ( 144 -176 0 ) ( 144 -176 -8 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 227 +{ +brushDef +{ +( 136 -176 -48 ) ( 136 -200 -48 ) ( 144 -200 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -176 -16 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -200 -8 ) ( 144 -176 -8 ) ( 144 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -176 -16 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -200 -8 ) ( 144 -200 -8 ) ( 144 -200 -16 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 228 +{ +brushDef +{ +( 136 -200 -48 ) ( 136 -224 -48 ) ( 144 -224 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -200 -24 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -224 -16 ) ( 144 -200 -16 ) ( 144 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -200 -24 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -224 -16 ) ( 144 -224 -16 ) ( 144 -224 -24 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 229 +{ +brushDef +{ +( 136 -224 -48 ) ( 136 -248 -48 ) ( 144 -248 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -224 -32 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -248 -24 ) ( 144 -224 -24 ) ( 144 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -224 -32 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -248 -24 ) ( 144 -248 -24 ) ( 144 -248 -32 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 230 +{ +brushDef +{ +( 136 -248 -48 ) ( 136 -272 -48 ) ( 144 -272 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -272 -40 ) ( 136 -272 -40 ) ( 136 -248 -40 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -272 -32 ) ( 144 -248 -32 ) ( 144 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -248 -40 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -272 -32 ) ( 144 -272 -32 ) ( 144 -272 -40 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 231 +{ +brushDef +{ +( 368 -248 -48 ) ( 368 -272 -48 ) ( 376 -272 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -272 -40 ) ( 368 -272 -40 ) ( 368 -248 -40 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -248 -40 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -248 -32 ) ( 368 -272 -32 ) ( 368 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -272 -32 ) ( 376 -272 -32 ) ( 376 -272 -40 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 232 +{ +brushDef +{ +( 368 -224 -48 ) ( 368 -248 -48 ) ( 376 -248 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -224 -32 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -224 -32 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -224 -24 ) ( 368 -248 -24 ) ( 368 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -248 -24 ) ( 376 -248 -24 ) ( 376 -248 -32 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 233 +{ +brushDef +{ +( 368 -200 -48 ) ( 368 -224 -48 ) ( 376 -224 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -200 -24 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -200 -24 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -200 -16 ) ( 368 -224 -16 ) ( 368 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -224 -16 ) ( 376 -224 -16 ) ( 376 -224 -24 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 234 +{ +brushDef +{ +( 368 -176 -48 ) ( 368 -200 -48 ) ( 376 -200 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -176 -16 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -176 -16 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -176 -8 ) ( 368 -200 -8 ) ( 368 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -200 -8 ) ( 376 -200 -8 ) ( 376 -200 -16 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 235 +{ +brushDef +{ +( 368 -152 -48 ) ( 368 -176 -48 ) ( 376 -176 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -152 -8 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -152 -8 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -152 0 ) ( 368 -176 0 ) ( 368 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -176 0 ) ( 376 -176 0 ) ( 376 -176 -8 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 236 +{ +brushDef +{ +( 368 -128 -48 ) ( 368 -152 -48 ) ( 376 -152 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -128 0 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -128 8 ) ( 368 -128 8 ) ( 368 -128 0 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -128 8 ) ( 368 -152 8 ) ( 368 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -152 8 ) ( 376 -152 8 ) ( 376 -152 0 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 237 +{ +brushDef +{ +( 640 -128 -48 ) ( 664 -128 -48 ) ( 664 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 640 -128 0 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 8 ) ( 640 -120 8 ) ( 640 -120 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -120 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -128 8 ) ( 664 -120 8 ) ( 664 -120 0 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 238 +{ +brushDef +{ +( 664 -128 -48 ) ( 688 -128 -48 ) ( 688 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 664 -128 -8 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -120 0 ) ( 664 -120 0 ) ( 664 -120 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -128 0 ) ( 688 -120 0 ) ( 688 -120 -8 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 239 +{ +brushDef +{ +( 688 -128 -48 ) ( 712 -128 -48 ) ( 712 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 688 -128 -16 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -120 -8 ) ( 688 -120 -8 ) ( 688 -120 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -128 -8 ) ( 712 -120 -8 ) ( 712 -120 -16 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 240 +{ +brushDef +{ +( 712 -128 -48 ) ( 736 -128 -48 ) ( 736 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 712 -128 -24 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -120 -16 ) ( 712 -120 -16 ) ( 712 -120 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.007813 0 -5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -128 -16 ) ( 736 -120 -16 ) ( 736 -120 -24 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 241 +{ +brushDef +{ +( 736 -128 -48 ) ( 760 -128 -48 ) ( 760 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 736 -128 -32 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -120 -24 ) ( 736 -120 -24 ) ( 736 -120 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.007813 0 -6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -128 -24 ) ( 760 -120 -24 ) ( 760 -120 -32 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 242 +{ +brushDef +{ +( 760 -128 -48 ) ( 784 -128 -48 ) ( 784 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 -120 -40 ) ( 784 -128 -40 ) ( 760 -128 -40 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 -120 -32 ) ( 760 -120 -32 ) ( 760 -120 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.007813 0 -6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 -128 -32 ) ( 784 -120 -32 ) ( 784 -120 -40 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 243 +{ +brushDef +{ +( 760 120 -48 ) ( 784 120 -48 ) ( 784 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 128 -40 ) ( 784 120 -40 ) ( 760 120 -40 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 760 120 -40 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 120 -32 ) ( 784 120 -32 ) ( 784 120 -40 ) ( ( 0.007813 0 -6.187878 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 120 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 244 +{ +brushDef +{ +( 736 120 -48 ) ( 760 120 -48 ) ( 760 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 736 120 -32 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 736 120 -32 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 120 -24 ) ( 760 120 -24 ) ( 760 120 -32 ) ( ( 0.007813 0 -6.000367 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 120 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 245 +{ +brushDef +{ +( 712 120 -48 ) ( 736 120 -48 ) ( 736 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 712 120 -24 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 712 120 -24 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 120 -16 ) ( 736 120 -16 ) ( 736 120 -24 ) ( ( 0.007813 0 -5.812856 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 120 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 246 +{ +brushDef +{ +( 688 120 -48 ) ( 712 120 -48 ) ( 712 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 688 120 -16 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 688 120 -16 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 120 -8 ) ( 712 120 -8 ) ( 712 120 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 120 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 247 +{ +brushDef +{ +( 664 120 -48 ) ( 688 120 -48 ) ( 688 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 664 120 -8 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 664 120 -8 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 120 0 ) ( 688 120 0 ) ( 688 120 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 120 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 248 +{ +brushDef +{ +( 640 120 -48 ) ( 664 120 -48 ) ( 664 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 640 120 0 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 128 8 ) ( 640 120 8 ) ( 640 120 0 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 120 8 ) ( 664 120 8 ) ( 664 120 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 120 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 249 +{ +brushDef +{ +( -128 128 -48 ) ( -152 128 -48 ) ( -152 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 120 8 ) ( -128 120 8 ) ( -128 120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -128 120 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 128 8 ) ( -152 120 8 ) ( -152 120 0 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 250 +{ +brushDef +{ +( -152 128 -48 ) ( -176 128 -48 ) ( -176 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 120 0 ) ( -152 120 0 ) ( -152 120 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 128 0 ) ( -176 120 0 ) ( -176 120 -8 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 251 +{ +brushDef +{ +( -176 128 -48 ) ( -200 128 -48 ) ( -200 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 120 -8 ) ( -176 120 -8 ) ( -176 120 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 128 -8 ) ( -200 120 -8 ) ( -200 120 -16 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 252 +{ +brushDef +{ +( -200 128 -48 ) ( -224 128 -48 ) ( -224 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 120 -16 ) ( -200 120 -16 ) ( -200 120 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 128 -16 ) ( -224 120 -16 ) ( -224 120 -24 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 253 +{ +brushDef +{ +( -224 128 -48 ) ( -248 128 -48 ) ( -248 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 120 -24 ) ( -224 120 -24 ) ( -224 120 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 128 -24 ) ( -248 120 -24 ) ( -248 120 -32 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 254 +{ +brushDef +{ +( -248 128 -48 ) ( -272 128 -48 ) ( -272 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 120 -40 ) ( -272 128 -40 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 120 -32 ) ( -248 120 -32 ) ( -248 120 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 128 -32 ) ( -272 120 -32 ) ( -272 120 -40 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 255 +{ +brushDef +{ +( -248 -120 -48 ) ( -272 -120 -48 ) ( -272 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 -128 -40 ) ( -272 -120 -40 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -120 -32 ) ( -272 -120 -32 ) ( -272 -120 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 -120 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 256 +{ +brushDef +{ +( -224 -120 -48 ) ( -248 -120 -48 ) ( -248 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -120 -24 ) ( -248 -120 -24 ) ( -248 -120 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -120 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 257 +{ +brushDef +{ +( -200 -120 -48 ) ( -224 -120 -48 ) ( -224 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -120 -16 ) ( -224 -120 -16 ) ( -224 -120 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -120 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 258 +{ +brushDef +{ +( -176 -120 -48 ) ( -200 -120 -48 ) ( -200 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -120 -8 ) ( -200 -120 -8 ) ( -200 -120 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -120 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 259 +{ +brushDef +{ +( -152 -120 -48 ) ( -176 -120 -48 ) ( -176 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 -120 0 ) ( -176 -120 0 ) ( -176 -120 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -120 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 260 +{ +brushDef +{ +( -128 -120 -48 ) ( -152 -120 -48 ) ( -152 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 8 ) ( -128 -120 8 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -120 8 ) ( -152 -120 8 ) ( -152 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -120 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 261 +{ +brushDef +{ +( 384 -152 0 ) ( 384 -128 0 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -128 8 ) ( 384 -128 8 ) ( 384 -152 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -152 8 ) ( 384 -152 8 ) ( 384 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -128 8 ) ( 128 -128 8 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 262 +{ +brushDef +{ +( 384 -176 -8 ) ( 384 -152 -8 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -152 0 ) ( 384 -152 0 ) ( 384 -176 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -176 0 ) ( 384 -176 0 ) ( 384 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -152 0 ) ( 128 -152 0 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 263 +{ +brushDef +{ +( 384 -200 -16 ) ( 384 -176 -16 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -176 -8 ) ( 384 -176 -8 ) ( 384 -200 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -200 -8 ) ( 384 -200 -8 ) ( 384 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -176 -8 ) ( 128 -176 -8 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 264 +{ +brushDef +{ +( 384 -224 -24 ) ( 384 -200 -24 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -200 -16 ) ( 384 -200 -16 ) ( 384 -224 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -224 -16 ) ( 384 -224 -16 ) ( 384 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -200 -16 ) ( 128 -200 -16 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 265 +{ +brushDef +{ +( 384 -248 -32 ) ( 384 -224 -32 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -224 -24 ) ( 384 -224 -24 ) ( 384 -248 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -248 -24 ) ( 384 -248 -24 ) ( 384 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -224 -24 ) ( 128 -224 -24 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 266 +{ +brushDef +{ +( 384 -272 -40 ) ( 384 -248 -40 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -248 -32 ) ( 384 -248 -32 ) ( 384 -272 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -272 -32 ) ( 384 -272 -32 ) ( 384 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -248 -32 ) ( 128 -248 -32 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 267 +{ +brushDef +{ +( 384 -296 -48 ) ( 384 -272 -48 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -272 -40 ) ( 384 -272 -40 ) ( 384 -296 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -272 -40 ) ( 136 -296 -40 ) ( 136 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -296 -40 ) ( 384 -296 -40 ) ( 384 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -296 -40 ) ( 376 -272 -40 ) ( 376 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -272 -40 ) ( 128 -272 -40 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 268 +{ +brushDef +{ +( 136 -120 -48 ) ( 24 -120 -48 ) ( 24 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 0 ) ( 24 -120 0 ) ( 136 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 -40 ) ( 136 -128 -40 ) ( 136 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -144 -40 ) ( 640 -136 -40 ) ( 640 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -120 -40 ) ( 24 -120 -40 ) ( 24 -120 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 -40 ) ( -128 -136 -40 ) ( -128 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 269 +{ +brushDef +{ +( -152 -128 0 ) ( -128 -128 0 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -152 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 128 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 270 +{ +brushDef +{ +( -176 -128 -8 ) ( -152 -128 -8 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 128 0 ) ( -152 -128 0 ) ( -176 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 128 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 -128 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 271 +{ +brushDef +{ +( -200 -128 -16 ) ( -176 -128 -16 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 128 -8 ) ( -176 -128 -8 ) ( -200 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 128 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 -128 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 272 +{ +brushDef +{ +( -224 -128 -24 ) ( -200 -128 -24 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 128 -16 ) ( -200 -128 -16 ) ( -224 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 128 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 -128 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 273 +{ +brushDef +{ +( -248 -128 -32 ) ( -224 -128 -32 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 128 -24 ) ( -224 -128 -24 ) ( -248 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 128 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 -128 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 274 +{ +brushDef +{ +( -272 -128 -40 ) ( -248 -128 -40 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 128 -32 ) ( -248 -128 -32 ) ( -272 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 128 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 -128 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 275 +{ +brushDef +{ +( -296 -128 -48 ) ( -272 -128 -48 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 128 -40 ) ( -272 -128 -40 ) ( -296 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 128 -40 ) ( -296 128 -40 ) ( -296 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -296 128 -40 ) ( -296 -128 -40 ) ( -296 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -296 -128 -40 ) ( -272 -128 -40 ) ( -272 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 -128 -40 ) ( -272 128 -40 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 276 +{ +brushDef +{ +( 808 128 -48 ) ( 784 128 -48 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 -128 -40 ) ( 784 128 -40 ) ( 808 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 -128 -40 ) ( 808 -128 -40 ) ( 808 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 808 -128 -40 ) ( 808 128 -40 ) ( 808 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 808 128 -40 ) ( 784 128 -40 ) ( 784 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 128 -40 ) ( 784 -128 -40 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 277 +{ +brushDef +{ +( 784 128 -40 ) ( 760 128 -40 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 -128 -32 ) ( 760 128 -32 ) ( 784 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 -128 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 128 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 278 +{ +brushDef +{ +( 760 128 -32 ) ( 736 128 -32 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 -128 -24 ) ( 736 128 -24 ) ( 760 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 -128 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 128 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 279 +{ +brushDef +{ +( 736 128 -24 ) ( 712 128 -24 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 -128 -16 ) ( 712 128 -16 ) ( 736 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 -128 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 128 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 280 +{ +brushDef +{ +( 712 128 -16 ) ( 688 128 -16 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 -128 -8 ) ( 688 128 -8 ) ( 712 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 -128 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 128 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 281 +{ +brushDef +{ +( 688 128 -8 ) ( 664 128 -8 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 664 -128 0 ) ( 664 128 0 ) ( 688 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 -128 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 664 128 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 282 +{ +brushDef +{ +( 664 128 0 ) ( 640 128 0 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 640 128 8 ) ( 664 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 283 +{ +brushDef +{ +( -120 -120 72 ) ( -888 -120 72 ) ( -888 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -888 -128 224 ) ( -888 -120 224 ) ( -120 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -888 -128 232 ) ( -120 -128 232 ) ( -120 -128 72 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -128 232 ) ( -120 -120 232 ) ( -120 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -120 232 ) ( -888 -120 232 ) ( -888 -120 72 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -120 232 ) ( -128 -128 232 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 284 +{ +brushDef +{ +( -56 -120 72 ) ( -824 -120 72 ) ( -824 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -824 -128 224 ) ( -824 -120 224 ) ( -56 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -824 -128 232 ) ( -56 -128 232 ) ( -56 -128 72 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -128 232 ) ( -56 -120 232 ) ( -56 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -120 232 ) ( -824 -120 232 ) ( -824 -120 72 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -120 232 ) ( -64 -128 232 ) ( -64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 285 +{ +brushDef +{ +( 8 -120 72 ) ( -760 -120 72 ) ( -760 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -760 -128 224 ) ( -760 -120 224 ) ( 8 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -760 -128 232 ) ( 8 -128 232 ) ( 8 -128 72 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -128 232 ) ( 8 -120 232 ) ( 8 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -120 232 ) ( -760 -120 232 ) ( -760 -120 72 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -120 232 ) ( 0 -128 232 ) ( 0 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 286 +{ +brushDef +{ +( 72 -120 72 ) ( -696 -120 72 ) ( -696 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -696 -128 224 ) ( -696 -120 224 ) ( 72 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -696 -128 232 ) ( 72 -128 232 ) ( 72 -128 72 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -128 232 ) ( 72 -120 232 ) ( 72 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -120 232 ) ( -696 -120 232 ) ( -696 -120 72 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -120 232 ) ( 64 -128 232 ) ( 64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 287 +{ +brushDef +{ +( 136 -120 72 ) ( -632 -120 72 ) ( -632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -632 -128 224 ) ( -632 -120 224 ) ( 136 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -632 -128 232 ) ( 136 -128 232 ) ( 136 -128 72 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 232 ) ( 136 -120 232 ) ( 136 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -120 232 ) ( -632 -120 232 ) ( -632 -120 72 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -120 232 ) ( 128 -128 232 ) ( 128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 288 +{ +brushDef +{ +( 384 -120 72 ) ( -384 -120 72 ) ( -384 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 134217728 0 0 +( -384 -128 224 ) ( -384 -120 224 ) ( 384 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 134217728 0 0 +( -384 -128 232 ) ( 384 -128 232 ) ( 384 -128 72 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -128 232 ) ( 384 -120 232 ) ( 384 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -120 232 ) ( -384 -120 232 ) ( -384 -120 72 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -120 232 ) ( 376 -128 232 ) ( 376 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 289 +{ +brushDef +{ +( 448 -120 72 ) ( -320 -120 72 ) ( -320 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 134217728 0 0 +( -320 -128 224 ) ( -320 -120 224 ) ( 448 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 134217728 0 0 +( -320 -128 232 ) ( 448 -128 232 ) ( 448 -128 72 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -128 232 ) ( 448 -120 232 ) ( 448 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -120 232 ) ( -320 -120 232 ) ( -320 -120 72 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -120 232 ) ( 440 -128 232 ) ( 440 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 290 +{ +brushDef +{ +( 512 -120 72 ) ( -256 -120 72 ) ( -256 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 134217728 0 0 +( -256 -128 224 ) ( -256 -120 224 ) ( 512 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 134217728 0 0 +( -256 -128 232 ) ( 512 -128 232 ) ( 512 -128 72 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -128 232 ) ( 512 -120 232 ) ( 512 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -120 232 ) ( -256 -120 232 ) ( -256 -120 72 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -120 232 ) ( 504 -128 232 ) ( 504 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 291 +{ +brushDef +{ +( 576 -120 72 ) ( -192 -120 72 ) ( -192 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 134217728 0 0 +( -192 -128 224 ) ( -192 -120 224 ) ( 576 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 134217728 0 0 +( -192 -128 232 ) ( 576 -128 232 ) ( 576 -128 72 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -128 232 ) ( 576 -120 232 ) ( 576 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -120 232 ) ( -192 -120 232 ) ( -192 -120 72 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -120 232 ) ( 568 -128 232 ) ( 568 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 292 +{ +brushDef +{ +( 640 -120 72 ) ( -128 -120 72 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 224 ) ( -128 -120 224 ) ( 640 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 232 ) ( 640 -128 232 ) ( 640 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -128 232 ) ( 640 -120 232 ) ( 640 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -120 232 ) ( -128 -120 232 ) ( -128 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -120 232 ) ( 632 -128 232 ) ( 632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 293 +{ +brushDef +{ +( -128 -128 224 ) ( 640 -128 224 ) ( 640 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 232 ) ( -128 -128 232 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( -128 -128 224 ) ( -128 -128 232 ) ( 640 -128 232 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 320 ) ( 640 128 320 ) ( 640 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -32 128 320 ) ( -128 128 320 ) ( -128 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 232 ) ( -128 -128 224 ) ( -128 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 294 +{ +brushDef +{ +( 664 -120 64 ) ( 384 -120 64 ) ( 384 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 72 ) ( 376 -120 72 ) ( 656 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 72 ) ( 656 -128 72 ) ( 656 -128 16 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -128 72 ) ( 640 -120 72 ) ( 640 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 656 -120 72 ) ( 376 -120 72 ) ( 376 -120 16 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -120 72 ) ( 376 -128 72 ) ( 376 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 295 +{ +brushDef +{ +( 160 -120 64 ) ( -120 -120 64 ) ( -120 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 72 ) ( -128 -120 72 ) ( 152 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 72 ) ( 152 -128 72 ) ( 152 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 72 ) ( 136 -120 72 ) ( 136 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 152 -120 72 ) ( -128 -120 72 ) ( -128 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -120 72 ) ( -128 -128 72 ) ( -128 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 296 +{ +brushDef +{ +( 384 -120 8 ) ( 376 -120 8 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 64 ) ( 376 -120 64 ) ( 384 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 16 ) ( 384 -128 16 ) ( 384 -128 8 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -128 16 ) ( 384 -120 16 ) ( 384 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -120 16 ) ( 376 -120 16 ) ( 376 -120 8 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -120 16 ) ( 376 -128 16 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 297 +{ +brushDef +{ +( 416 -120 8 ) ( 408 -120 8 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 408 -128 64 ) ( 408 -120 64 ) ( 416 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 408 -128 16 ) ( 416 -128 16 ) ( 416 -128 8 ) ( ( 0.015625 0 -8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 416 -128 16 ) ( 416 -120 16 ) ( 416 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 416 -120 16 ) ( 408 -120 16 ) ( 408 -120 8 ) ( ( 0.015625 0 8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 408 -120 16 ) ( 408 -128 16 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 298 +{ +brushDef +{ +( 448 -120 8 ) ( 440 -120 8 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -128 64 ) ( 440 -120 64 ) ( 448 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -128 16 ) ( 448 -128 16 ) ( 448 -128 8 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -128 16 ) ( 448 -120 16 ) ( 448 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -120 16 ) ( 440 -120 16 ) ( 440 -120 8 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -120 16 ) ( 440 -128 16 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 299 +{ +brushDef +{ +( 480 -120 8 ) ( 472 -120 8 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 -128 64 ) ( 472 -120 64 ) ( 480 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 -128 16 ) ( 480 -128 16 ) ( 480 -128 8 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 480 -128 16 ) ( 480 -120 16 ) ( 480 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 480 -120 16 ) ( 472 -120 16 ) ( 472 -120 8 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 -120 16 ) ( 472 -128 16 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 300 +{ +brushDef +{ +( 512 -120 8 ) ( 504 -120 8 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -128 64 ) ( 504 -120 64 ) ( 512 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -128 16 ) ( 512 -128 16 ) ( 512 -128 8 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -128 16 ) ( 512 -120 16 ) ( 512 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -120 16 ) ( 504 -120 16 ) ( 504 -120 8 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -120 16 ) ( 504 -128 16 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 301 +{ +brushDef +{ +( 544 -120 8 ) ( 536 -120 8 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 -128 64 ) ( 536 -120 64 ) ( 544 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 -128 16 ) ( 544 -128 16 ) ( 544 -128 8 ) ( ( 0.015625 0 -10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 544 -128 16 ) ( 544 -120 16 ) ( 544 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 544 -120 16 ) ( 536 -120 16 ) ( 536 -120 8 ) ( ( 0.015625 0 10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 -120 16 ) ( 536 -128 16 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 302 +{ +brushDef +{ +( 576 -120 8 ) ( 568 -120 8 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -128 64 ) ( 568 -120 64 ) ( 576 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -128 16 ) ( 576 -128 16 ) ( 576 -128 8 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -128 16 ) ( 576 -120 16 ) ( 576 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -120 16 ) ( 568 -120 16 ) ( 568 -120 8 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -120 16 ) ( 568 -128 16 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 303 +{ +brushDef +{ +( 608 -120 8 ) ( 600 -120 8 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 -128 64 ) ( 600 -120 64 ) ( 608 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 -128 16 ) ( 608 -128 16 ) ( 608 -128 8 ) ( ( 0.015625 0 -11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 -128 16 ) ( 608 -120 16 ) ( 608 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 -120 16 ) ( 600 -120 16 ) ( 600 -120 8 ) ( ( 0.015625 0 11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 -120 16 ) ( 600 -128 16 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 304 +{ +brushDef +{ +( 640 -120 8 ) ( 632 -120 8 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -128 64 ) ( 632 -120 64 ) ( 640 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -128 16 ) ( 640 -128 16 ) ( 640 -128 8 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -128 16 ) ( 640 -120 16 ) ( 640 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -120 16 ) ( 632 -120 16 ) ( 632 -120 8 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -120 16 ) ( 632 -128 16 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 305 +{ +brushDef +{ +( -88 -120 8 ) ( -96 -120 8 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 -128 64 ) ( -96 -120 64 ) ( -88 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 -128 16 ) ( -88 -128 16 ) ( -88 -128 8 ) ( ( 0.015625 0 -0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -88 -128 16 ) ( -88 -120 16 ) ( -88 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -88 -120 16 ) ( -96 -120 16 ) ( -96 -120 8 ) ( ( 0.015625 0 0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 -120 16 ) ( -96 -128 16 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 306 +{ +brushDef +{ +( -24 -120 8 ) ( -32 -120 8 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -32 -128 64 ) ( -32 -120 64 ) ( -24 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -32 -128 16 ) ( -24 -128 16 ) ( -24 -128 8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -24 -128 16 ) ( -24 -120 16 ) ( -24 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -24 -120 16 ) ( -32 -120 16 ) ( -32 -120 8 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -32 -120 16 ) ( -32 -128 16 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 307 +{ +brushDef +{ +( 40 -120 8 ) ( 32 -120 8 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 32 -128 64 ) ( 32 -120 64 ) ( 40 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 32 -128 16 ) ( 40 -128 16 ) ( 40 -128 8 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 40 -128 16 ) ( 40 -120 16 ) ( 40 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 40 -120 16 ) ( 32 -120 16 ) ( 32 -120 8 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 32 -120 16 ) ( 32 -128 16 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 308 +{ +brushDef +{ +( 104 -120 8 ) ( 96 -120 8 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 96 -128 64 ) ( 96 -120 64 ) ( 104 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 96 -128 16 ) ( 104 -128 16 ) ( 104 -128 8 ) ( ( 0.015625 0 -3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 -128 16 ) ( 104 -120 16 ) ( 104 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 -120 16 ) ( 96 -120 16 ) ( 96 -120 8 ) ( ( 0.015625 0 3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 96 -120 16 ) ( 96 -128 16 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 309 +{ +brushDef +{ +( 136 -120 8 ) ( 128 -120 8 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -128 64 ) ( 128 -120 64 ) ( 136 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -128 16 ) ( 136 -128 16 ) ( 136 -128 8 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 16 ) ( 136 -120 16 ) ( 136 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -120 16 ) ( 128 -120 16 ) ( 128 -120 8 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -120 16 ) ( 128 -128 16 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 310 +{ +brushDef +{ +( 72 -120 8 ) ( 64 -120 8 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -128 64 ) ( 64 -120 64 ) ( 72 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -128 16 ) ( 72 -128 16 ) ( 72 -128 8 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -128 16 ) ( 72 -120 16 ) ( 72 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -120 16 ) ( 64 -120 16 ) ( 64 -120 8 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -120 16 ) ( 64 -128 16 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 311 +{ +brushDef +{ +( 8 -120 8 ) ( 0 -120 8 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -128 64 ) ( 0 -120 64 ) ( 8 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -128 16 ) ( 8 -128 16 ) ( 8 -128 8 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -128 16 ) ( 8 -120 16 ) ( 8 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -120 16 ) ( 0 -120 16 ) ( 0 -120 8 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -120 16 ) ( 0 -128 16 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 312 +{ +brushDef +{ +( -56 -120 8 ) ( -64 -120 8 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -128 64 ) ( -64 -120 64 ) ( -56 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -128 16 ) ( -56 -128 16 ) ( -56 -128 8 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -128 16 ) ( -56 -120 16 ) ( -56 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -120 16 ) ( -64 -120 16 ) ( -64 -120 8 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -120 16 ) ( -64 -128 16 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 313 +{ +brushDef +{ +( -120 -120 8 ) ( -128 -120 8 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 64 ) ( -128 -120 64 ) ( -120 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 16 ) ( -120 -128 16 ) ( -120 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -128 16 ) ( -120 -120 16 ) ( -120 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -120 16 ) ( -128 -120 16 ) ( -128 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -120 16 ) ( -128 -128 16 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 314 +{ +brushDef +{ +( 256 128 0 ) ( -128 128 0 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( 256 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( 256 -128 8 ) ( 256 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 8 ) ( 640 136 8 ) ( 640 136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 960 8 ) ( -64 960 8 ) ( -64 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +} +// entity 1 +{ +"origin" "248 512 336" +"light" "600" +"classname" "light" +} +// entity 2 +{ +"origin" "576 -64 32" +"classname" "info_player_start" +} +// entity 3 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 456 744 72 0 0 ) ( 456 744 76 0 0.062500 ) ( 456 744 80 0 0.125000 ) ) +( ( 456 728 72 0.250000 0 ) ( 456 728 76 0.250000 0.062500 ) ( 456 728 80 0.250000 0.125000 ) ) +( ( 472 728 72 0.500000 0 ) ( 472 728 76 0.500000 0.062500 ) ( 472 728 80 0.500000 0.125000 ) ) +( ( 488 728 72 0.750000 0 ) ( 488 728 76 0.750000 0.062500 ) ( 488 728 80 0.750000 0.125000 ) ) +( ( 488 744 72 1 0 ) ( 488 744 76 1 0.062500 ) ( 488 744 80 1 0.125000 ) ) +( ( 488 760 72 1.250000 0 ) ( 488 760 76 1.250000 0.062500 ) ( 488 760 80 1.250000 0.125000 ) ) +( ( 472 760 72 1.500000 0 ) ( 472 760 76 1.500000 0.062500 ) ( 472 760 80 1.500000 0.125000 ) ) +( ( 456 760 72 1.750000 0 ) ( 456 760 76 1.750000 0.062500 ) ( 456 760 80 1.750000 0.125000 ) ) +( ( 456 744 72 2 0 ) ( 456 744 76 2 0.062500 ) ( 456 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 472 760 72 7.375000 -11.875000 ) ( 456 760 72 7.125000 -11.875000 ) ( 456 744 72 7.125000 -11.625000 ) ) +( ( 488 760 72 7.625000 -11.875000 ) ( 472 744 72 7.375000 -11.625000 ) ( 456 728 72 7.125000 -11.375000 ) ) +( ( 488 744 72 7.625000 -11.625000 ) ( 488 728 72 7.625000 -11.375000 ) ( 472 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 456 744 80 7.125000 -11.625000 ) ( 456 760 80 7.125000 -11.875000 ) ( 472 760 80 7.375000 -11.875000 ) ) +( ( 456 728 80 7.125000 -11.375000 ) ( 472 744 80 7.375000 -11.625000 ) ( 488 760 80 7.625000 -11.875000 ) ) +( ( 472 728 80 7.375000 -11.375000 ) ( 488 728 80 7.625000 -11.375000 ) ( 488 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 4 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 320 64 0 0 ) ( 400 320 68 0 0.062500 ) ( 400 320 72 0 0.125000 ) ) +( ( 400 272 64 0.750000 0 ) ( 400 272 68 0.750000 0.062500 ) ( 400 272 72 0.750000 0.125000 ) ) +( ( 448 272 64 1.500000 0 ) ( 448 272 68 1.500000 0.062500 ) ( 448 272 72 1.500000 0.125000 ) ) +( ( 496 272 64 2.250000 0 ) ( 496 272 68 2.250000 0.062500 ) ( 496 272 72 2.250000 0.125000 ) ) +( ( 496 320 64 3 0 ) ( 496 320 68 3 0.062500 ) ( 496 320 72 3 0.125000 ) ) +( ( 496 368 64 3.750000 0 ) ( 496 368 68 3.750000 0.062500 ) ( 496 368 72 3.750000 0.125000 ) ) +( ( 448 368 64 4.500000 0 ) ( 448 368 68 4.500000 0.062500 ) ( 448 368 72 4.500000 0.125000 ) ) +( ( 400 368 64 5.250000 0 ) ( 400 368 68 5.250000 0.062500 ) ( 400 368 72 5.250000 0.125000 ) ) +( ( 400 320 64 6 0 ) ( 400 320 68 6 0.062500 ) ( 400 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 368 64 7 -5.750000 ) ( 400 368 64 6.250000 -5.750000 ) ( 400 320 64 6.250000 -5 ) ) +( ( 496 368 64 7.750000 -5.750000 ) ( 448 320 64 7 -5 ) ( 400 272 64 6.250000 -4.250000 ) ) +( ( 496 320 64 7.750000 -5 ) ( 496 272 64 7.750000 -4.250000 ) ( 448 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 320 72 6.250000 -5 ) ( 400 368 72 6.250000 -5.750000 ) ( 448 368 72 7 -5.750000 ) ) +( ( 400 272 72 6.250000 -4.250000 ) ( 448 320 72 7 -5 ) ( 496 368 72 7.750000 -5.750000 ) ) +( ( 448 272 72 7 -4.250000 ) ( 496 272 72 7.750000 -4.250000 ) ( 496 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 5 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 192 132 88 0 0 ) ( 192 132 108 0 0.312500 ) ( 192 132 128 0 0.625000 ) ) +( ( 192 128 88 0.062500 0 ) ( 192 128 108 0.062500 0.312500 ) ( 192 128 128 0.062500 0.625000 ) ) +( ( 196 128 88 0.125000 0 ) ( 196 128 108 0.125000 0.312500 ) ( 196 128 128 0.125000 0.625000 ) ) +( ( 200 128 88 0.187500 0 ) ( 200 128 108 0.187500 0.312500 ) ( 200 128 128 0.187500 0.625000 ) ) +( ( 200 132 88 0.250000 0 ) ( 200 132 108 0.250000 0.312500 ) ( 200 132 128 0.250000 0.625000 ) ) +( ( 200 136 88 0.312500 0 ) ( 200 136 108 0.312500 0.312500 ) ( 200 136 128 0.312500 0.625000 ) ) +( ( 196 136 88 0.375000 0 ) ( 196 136 108 0.375000 0.312500 ) ( 196 136 128 0.375000 0.625000 ) ) +( ( 192 136 88 0.437500 0 ) ( 192 136 108 0.437500 0.312500 ) ( 192 136 128 0.437500 0.625000 ) ) +( ( 192 132 88 0.500000 0 ) ( 192 132 108 0.500000 0.312500 ) ( 192 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 196 136 88 3.062500 -2.125000 ) ( 192 136 88 3 -2.125000 ) ( 192 132 88 3 -2.062500 ) ) +( ( 200 136 88 3.125000 -2.125000 ) ( 196 132 88 3.062500 -2.062500 ) ( 192 128 88 3 -2 ) ) +( ( 200 132 88 3.125000 -2.062500 ) ( 200 128 88 3.125000 -2 ) ( 196 128 88 3.062500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 192 132 128 3 -2.062500 ) ( 192 136 128 3 -2.125000 ) ( 196 136 128 3.062500 -2.125000 ) ) +( ( 192 128 128 3 -2 ) ( 196 132 128 3.062500 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ) +( ( 196 128 128 3.062500 -2 ) ( 200 128 128 3.125000 -2 ) ( 200 132 128 3.125000 -2.062500 ) ) +) + } + } +} +// entity 6 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 204 136 88 0 0 ) ( 204 136 108 0 0.312500 ) ( 204 136 128 0 0.625000 ) ) +( ( 208 136 88 0.062500 0 ) ( 208 136 108 0.062500 0.312500 ) ( 208 136 128 0.062500 0.625000 ) ) +( ( 208 140 88 0.125000 0 ) ( 208 140 108 0.125000 0.312500 ) ( 208 140 128 0.125000 0.625000 ) ) +( ( 208 144 88 0.187500 0 ) ( 208 144 108 0.187500 0.312500 ) ( 208 144 128 0.187500 0.625000 ) ) +( ( 204 144 88 0.250000 0 ) ( 204 144 108 0.250000 0.312500 ) ( 204 144 128 0.250000 0.625000 ) ) +( ( 200 144 88 0.312500 0 ) ( 200 144 108 0.312500 0.312500 ) ( 200 144 128 0.312500 0.625000 ) ) +( ( 200 140 88 0.375000 0 ) ( 200 140 108 0.375000 0.312500 ) ( 200 140 128 0.375000 0.625000 ) ) +( ( 200 136 88 0.437500 0 ) ( 200 136 108 0.437500 0.312500 ) ( 200 136 128 0.437500 0.625000 ) ) +( ( 204 136 88 0.500000 0 ) ( 204 136 108 0.500000 0.312500 ) ( 204 136 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 200 140 88 3.187500 -2.125000 ) ( 200 136 88 3.125000 -2.125000 ) ( 204 136 88 3.125000 -2.062500 ) ) +( ( 200 144 88 3.250000 -2.125000 ) ( 204 140 88 3.187500 -2.062500 ) ( 208 136 88 3.125000 -2 ) ) +( ( 204 144 88 3.250000 -2.062500 ) ( 208 144 88 3.250000 -2 ) ( 208 140 88 3.187500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 204 136 128 3.125000 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ( 200 140 128 3.187500 -2.125000 ) ) +( ( 208 136 128 3.125000 -2 ) ( 204 140 128 3.187500 -2.062500 ) ( 200 144 128 3.250000 -2.125000 ) ) +( ( 208 140 128 3.187500 -2 ) ( 208 144 128 3.250000 -2 ) ( 204 144 128 3.250000 -2.062500 ) ) +) + } + } +} +// entity 7 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 312 132 88 0 0 ) ( 312 132 108 0 0.312500 ) ( 312 132 128 0 0.625000 ) ) +( ( 312 128 88 0.062500 0 ) ( 312 128 108 0.062500 0.312500 ) ( 312 128 128 0.062500 0.625000 ) ) +( ( 316 128 88 0.125000 0 ) ( 316 128 108 0.125000 0.312500 ) ( 316 128 128 0.125000 0.625000 ) ) +( ( 320 128 88 0.187500 0 ) ( 320 128 108 0.187500 0.312500 ) ( 320 128 128 0.187500 0.625000 ) ) +( ( 320 132 88 0.250000 0 ) ( 320 132 108 0.250000 0.312500 ) ( 320 132 128 0.250000 0.625000 ) ) +( ( 320 136 88 0.312500 0 ) ( 320 136 108 0.312500 0.312500 ) ( 320 136 128 0.312500 0.625000 ) ) +( ( 316 136 88 0.375000 0 ) ( 316 136 108 0.375000 0.312500 ) ( 316 136 128 0.375000 0.625000 ) ) +( ( 312 136 88 0.437500 0 ) ( 312 136 108 0.437500 0.312500 ) ( 312 136 128 0.437500 0.625000 ) ) +( ( 312 132 88 0.500000 0 ) ( 312 132 108 0.500000 0.312500 ) ( 312 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 316 136 88 4.937500 -2.125000 ) ( 312 136 88 4.875000 -2.125000 ) ( 312 132 88 4.875000 -2.062500 ) ) +( ( 320 136 88 5 -2.125000 ) ( 316 132 88 4.937500 -2.062500 ) ( 312 128 88 4.875000 -2 ) ) +( ( 320 132 88 5 -2.062500 ) ( 320 128 88 5 -2 ) ( 316 128 88 4.937500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 312 132 128 4.875000 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ( 316 136 128 4.937500 -2.125000 ) ) +( ( 312 128 128 4.875000 -2 ) ( 316 132 128 4.937500 -2.062500 ) ( 320 136 128 5 -2.125000 ) ) +( ( 316 128 128 4.937500 -2 ) ( 320 128 128 5 -2 ) ( 320 132 128 5 -2.062500 ) ) +) + } + } +} +// entity 8 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 308 144 88 0 0 ) ( 308 144 108 0 0.312500 ) ( 308 144 128 0 0.625000 ) ) +( ( 304 144 88 0.062500 0 ) ( 304 144 108 0.062500 0.312500 ) ( 304 144 128 0.062500 0.625000 ) ) +( ( 304 140 88 0.125000 0 ) ( 304 140 108 0.125000 0.312500 ) ( 304 140 128 0.125000 0.625000 ) ) +( ( 304 136 88 0.187500 0 ) ( 304 136 108 0.187500 0.312500 ) ( 304 136 128 0.187500 0.625000 ) ) +( ( 308 136 88 0.250000 0 ) ( 308 136 108 0.250000 0.312500 ) ( 308 136 128 0.250000 0.625000 ) ) +( ( 312 136 88 0.312500 0 ) ( 312 136 108 0.312500 0.312500 ) ( 312 136 128 0.312500 0.625000 ) ) +( ( 312 140 88 0.375000 0 ) ( 312 140 108 0.375000 0.312500 ) ( 312 140 128 0.375000 0.625000 ) ) +( ( 312 144 88 0.437500 0 ) ( 312 144 108 0.437500 0.312500 ) ( 312 144 128 0.437500 0.625000 ) ) +( ( 308 144 88 0.500000 0 ) ( 308 144 108 0.500000 0.312500 ) ( 308 144 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 312 140 88 4.812500 -2.125000 ) ( 312 144 88 4.750000 -2.125000 ) ( 308 144 88 4.750000 -2.062500 ) ) +( ( 312 136 88 4.875000 -2.125000 ) ( 308 140 88 4.812500 -2.062500 ) ( 304 144 88 4.750000 -2 ) ) +( ( 308 136 88 4.875000 -2.062500 ) ( 304 136 88 4.875000 -2 ) ( 304 140 88 4.812500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 308 144 128 4.750000 -2.062500 ) ( 312 144 128 4.750000 -2.125000 ) ( 312 140 128 4.812500 -2.125000 ) ) +( ( 304 144 128 4.750000 -2 ) ( 308 140 128 4.812500 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ) +( ( 304 140 128 4.812500 -2 ) ( 304 136 128 4.875000 -2 ) ( 308 136 128 4.875000 -2.062500 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 512 64 0 0 ) ( 400 512 68 0 0.062500 ) ( 400 512 72 0 0.125000 ) ) +( ( 400 464 64 0.750000 0 ) ( 400 464 68 0.750000 0.062500 ) ( 400 464 72 0.750000 0.125000 ) ) +( ( 448 464 64 1.500000 0 ) ( 448 464 68 1.500000 0.062500 ) ( 448 464 72 1.500000 0.125000 ) ) +( ( 496 464 64 2.250000 0 ) ( 496 464 68 2.250000 0.062500 ) ( 496 464 72 2.250000 0.125000 ) ) +( ( 496 512 64 3 0 ) ( 496 512 68 3 0.062500 ) ( 496 512 72 3 0.125000 ) ) +( ( 496 560 64 3.750000 0 ) ( 496 560 68 3.750000 0.062500 ) ( 496 560 72 3.750000 0.125000 ) ) +( ( 448 560 64 4.500000 0 ) ( 448 560 68 4.500000 0.062500 ) ( 448 560 72 4.500000 0.125000 ) ) +( ( 400 560 64 5.250000 0 ) ( 400 560 68 5.250000 0.062500 ) ( 400 560 72 5.250000 0.125000 ) ) +( ( 400 512 64 6 0 ) ( 400 512 68 6 0.062500 ) ( 400 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 560 64 7 -5.750000 ) ( 400 560 64 6.250000 -5.750000 ) ( 400 512 64 6.250000 -5 ) ) +( ( 496 560 64 7.750000 -5.750000 ) ( 448 512 64 7 -5 ) ( 400 464 64 6.250000 -4.250000 ) ) +( ( 496 512 64 7.750000 -5 ) ( 496 464 64 7.750000 -4.250000 ) ( 448 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 512 72 6.250000 -5 ) ( 400 560 72 6.250000 -5.750000 ) ( 448 560 72 7 -5.750000 ) ) +( ( 400 464 72 6.250000 -4.250000 ) ( 448 512 72 7 -5 ) ( 496 560 72 7.750000 -5.750000 ) ) +( ( 448 464 72 7 -4.250000 ) ( 496 464 72 7.750000 -4.250000 ) ( 496 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 10 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 320 64 0 0 ) ( 16 320 68 0 0.062500 ) ( 16 320 72 0 0.125000 ) ) +( ( 16 272 64 0.750000 0 ) ( 16 272 68 0.750000 0.062500 ) ( 16 272 72 0.750000 0.125000 ) ) +( ( 64 272 64 1.500000 0 ) ( 64 272 68 1.500000 0.062500 ) ( 64 272 72 1.500000 0.125000 ) ) +( ( 112 272 64 2.250000 0 ) ( 112 272 68 2.250000 0.062500 ) ( 112 272 72 2.250000 0.125000 ) ) +( ( 112 320 64 3 0 ) ( 112 320 68 3 0.062500 ) ( 112 320 72 3 0.125000 ) ) +( ( 112 368 64 3.750000 0 ) ( 112 368 68 3.750000 0.062500 ) ( 112 368 72 3.750000 0.125000 ) ) +( ( 64 368 64 4.500000 0 ) ( 64 368 68 4.500000 0.062500 ) ( 64 368 72 4.500000 0.125000 ) ) +( ( 16 368 64 5.250000 0 ) ( 16 368 68 5.250000 0.062500 ) ( 16 368 72 5.250000 0.125000 ) ) +( ( 16 320 64 6 0 ) ( 16 320 68 6 0.062500 ) ( 16 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 368 64 7 -5.750000 ) ( 16 368 64 6.250000 -5.750000 ) ( 16 320 64 6.250000 -5 ) ) +( ( 112 368 64 7.750000 -5.750000 ) ( 64 320 64 7 -5 ) ( 16 272 64 6.250000 -4.250000 ) ) +( ( 112 320 64 7.750000 -5 ) ( 112 272 64 7.750000 -4.250000 ) ( 64 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 320 72 6.250000 -5 ) ( 16 368 72 6.250000 -5.750000 ) ( 64 368 72 7 -5.750000 ) ) +( ( 16 272 72 6.250000 -4.250000 ) ( 64 320 72 7 -5 ) ( 112 368 72 7.750000 -5.750000 ) ) +( ( 64 272 72 7 -4.250000 ) ( 112 272 72 7.750000 -4.250000 ) ( 112 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 11 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 512 64 0 0 ) ( 16 512 68 0 0.062500 ) ( 16 512 72 0 0.125000 ) ) +( ( 16 464 64 0.750000 0 ) ( 16 464 68 0.750000 0.062500 ) ( 16 464 72 0.750000 0.125000 ) ) +( ( 64 464 64 1.500000 0 ) ( 64 464 68 1.500000 0.062500 ) ( 64 464 72 1.500000 0.125000 ) ) +( ( 112 464 64 2.250000 0 ) ( 112 464 68 2.250000 0.062500 ) ( 112 464 72 2.250000 0.125000 ) ) +( ( 112 512 64 3 0 ) ( 112 512 68 3 0.062500 ) ( 112 512 72 3 0.125000 ) ) +( ( 112 560 64 3.750000 0 ) ( 112 560 68 3.750000 0.062500 ) ( 112 560 72 3.750000 0.125000 ) ) +( ( 64 560 64 4.500000 0 ) ( 64 560 68 4.500000 0.062500 ) ( 64 560 72 4.500000 0.125000 ) ) +( ( 16 560 64 5.250000 0 ) ( 16 560 68 5.250000 0.062500 ) ( 16 560 72 5.250000 0.125000 ) ) +( ( 16 512 64 6 0 ) ( 16 512 68 6 0.062500 ) ( 16 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 560 64 7 -5.750000 ) ( 16 560 64 6.250000 -5.750000 ) ( 16 512 64 6.250000 -5 ) ) +( ( 112 560 64 7.750000 -5.750000 ) ( 64 512 64 7 -5 ) ( 16 464 64 6.250000 -4.250000 ) ) +( ( 112 512 64 7.750000 -5 ) ( 112 464 64 7.750000 -4.250000 ) ( 64 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 512 72 6.250000 -5 ) ( 16 560 72 6.250000 -5.750000 ) ( 64 560 72 7 -5.750000 ) ) +( ( 16 464 72 6.250000 -4.250000 ) ( 64 512 72 7 -5 ) ( 112 560 72 7.750000 -5.750000 ) ) +( ( 64 464 72 7 -4.250000 ) ( 112 464 72 7.750000 -4.250000 ) ( 112 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 12 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 368 744 72 0 0 ) ( 368 744 76 0 0.062500 ) ( 368 744 80 0 0.125000 ) ) +( ( 368 728 72 0.250000 0 ) ( 368 728 76 0.250000 0.062500 ) ( 368 728 80 0.250000 0.125000 ) ) +( ( 384 728 72 0.500000 0 ) ( 384 728 76 0.500000 0.062500 ) ( 384 728 80 0.500000 0.125000 ) ) +( ( 400 728 72 0.750000 0 ) ( 400 728 76 0.750000 0.062500 ) ( 400 728 80 0.750000 0.125000 ) ) +( ( 400 744 72 1 0 ) ( 400 744 76 1 0.062500 ) ( 400 744 80 1 0.125000 ) ) +( ( 400 760 72 1.250000 0 ) ( 400 760 76 1.250000 0.062500 ) ( 400 760 80 1.250000 0.125000 ) ) +( ( 384 760 72 1.500000 0 ) ( 384 760 76 1.500000 0.062500 ) ( 384 760 80 1.500000 0.125000 ) ) +( ( 368 760 72 1.750000 0 ) ( 368 760 76 1.750000 0.062500 ) ( 368 760 80 1.750000 0.125000 ) ) +( ( 368 744 72 2 0 ) ( 368 744 76 2 0.062500 ) ( 368 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 384 760 72 7.375000 -11.875000 ) ( 368 760 72 7.125000 -11.875000 ) ( 368 744 72 7.125000 -11.625000 ) ) +( ( 400 760 72 7.625000 -11.875000 ) ( 384 744 72 7.375000 -11.625000 ) ( 368 728 72 7.125000 -11.375000 ) ) +( ( 400 744 72 7.625000 -11.625000 ) ( 400 728 72 7.625000 -11.375000 ) ( 384 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 368 744 80 7.125000 -11.625000 ) ( 368 760 80 7.125000 -11.875000 ) ( 384 760 80 7.375000 -11.875000 ) ) +( ( 368 728 80 7.125000 -11.375000 ) ( 384 744 80 7.375000 -11.625000 ) ( 400 760 80 7.625000 -11.875000 ) ) +( ( 384 728 80 7.375000 -11.375000 ) ( 400 728 80 7.625000 -11.375000 ) ( 400 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 13 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 264 744 72 0 0 ) ( 264 744 76 0 0.062500 ) ( 264 744 80 0 0.125000 ) ) +( ( 264 728 72 0.250000 0 ) ( 264 728 76 0.250000 0.062500 ) ( 264 728 80 0.250000 0.125000 ) ) +( ( 280 728 72 0.500000 0 ) ( 280 728 76 0.500000 0.062500 ) ( 280 728 80 0.500000 0.125000 ) ) +( ( 296 728 72 0.750000 0 ) ( 296 728 76 0.750000 0.062500 ) ( 296 728 80 0.750000 0.125000 ) ) +( ( 296 744 72 1 0 ) ( 296 744 76 1 0.062500 ) ( 296 744 80 1 0.125000 ) ) +( ( 296 760 72 1.250000 0 ) ( 296 760 76 1.250000 0.062500 ) ( 296 760 80 1.250000 0.125000 ) ) +( ( 280 760 72 1.500000 0 ) ( 280 760 76 1.500000 0.062500 ) ( 280 760 80 1.500000 0.125000 ) ) +( ( 264 760 72 1.750000 0 ) ( 264 760 76 1.750000 0.062500 ) ( 264 760 80 1.750000 0.125000 ) ) +( ( 264 744 72 2 0 ) ( 264 744 76 2 0.062500 ) ( 264 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 280 760 72 7.375000 -11.875000 ) ( 264 760 72 7.125000 -11.875000 ) ( 264 744 72 7.125000 -11.625000 ) ) +( ( 296 760 72 7.625000 -11.875000 ) ( 280 744 72 7.375000 -11.625000 ) ( 264 728 72 7.125000 -11.375000 ) ) +( ( 296 744 72 7.625000 -11.625000 ) ( 296 728 72 7.625000 -11.375000 ) ( 280 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 264 744 80 7.125000 -11.625000 ) ( 264 760 80 7.125000 -11.875000 ) ( 280 760 80 7.375000 -11.875000 ) ) +( ( 264 728 80 7.125000 -11.375000 ) ( 280 744 80 7.375000 -11.625000 ) ( 296 760 80 7.625000 -11.875000 ) ) +( ( 280 728 80 7.375000 -11.375000 ) ( 296 728 80 7.625000 -11.375000 ) ( 296 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 14 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 96 744 72 0 0 ) ( 96 744 76 0 0.062500 ) ( 96 744 80 0 0.125000 ) ) +( ( 96 728 72 0.250000 0 ) ( 96 728 76 0.250000 0.062500 ) ( 96 728 80 0.250000 0.125000 ) ) +( ( 112 728 72 0.500000 0 ) ( 112 728 76 0.500000 0.062500 ) ( 112 728 80 0.500000 0.125000 ) ) +( ( 128 728 72 0.750000 0 ) ( 128 728 76 0.750000 0.062500 ) ( 128 728 80 0.750000 0.125000 ) ) +( ( 128 744 72 1 0 ) ( 128 744 76 1 0.062500 ) ( 128 744 80 1 0.125000 ) ) +( ( 128 760 72 1.250000 0 ) ( 128 760 76 1.250000 0.062500 ) ( 128 760 80 1.250000 0.125000 ) ) +( ( 112 760 72 1.500000 0 ) ( 112 760 76 1.500000 0.062500 ) ( 112 760 80 1.500000 0.125000 ) ) +( ( 96 760 72 1.750000 0 ) ( 96 760 76 1.750000 0.062500 ) ( 96 760 80 1.750000 0.125000 ) ) +( ( 96 744 72 2 0 ) ( 96 744 76 2 0.062500 ) ( 96 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 112 760 72 7.375000 -11.875000 ) ( 96 760 72 7.125000 -11.875000 ) ( 96 744 72 7.125000 -11.625000 ) ) +( ( 128 760 72 7.625000 -11.875000 ) ( 112 744 72 7.375000 -11.625000 ) ( 96 728 72 7.125000 -11.375000 ) ) +( ( 128 744 72 7.625000 -11.625000 ) ( 128 728 72 7.625000 -11.375000 ) ( 112 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 96 744 80 7.125000 -11.625000 ) ( 96 760 80 7.125000 -11.875000 ) ( 112 760 80 7.375000 -11.875000 ) ) +( ( 96 728 80 7.125000 -11.375000 ) ( 112 744 80 7.375000 -11.625000 ) ( 128 760 80 7.625000 -11.875000 ) ) +( ( 112 728 80 7.375000 -11.375000 ) ( 128 728 80 7.625000 -11.375000 ) ( 128 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 15 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 0 744 72 0 0 ) ( 0 744 76 0 0.062500 ) ( 0 744 80 0 0.125000 ) ) +( ( 0 728 72 0.250000 0 ) ( 0 728 76 0.250000 0.062500 ) ( 0 728 80 0.250000 0.125000 ) ) +( ( 16 728 72 0.500000 0 ) ( 16 728 76 0.500000 0.062500 ) ( 16 728 80 0.500000 0.125000 ) ) +( ( 32 728 72 0.750000 0 ) ( 32 728 76 0.750000 0.062500 ) ( 32 728 80 0.750000 0.125000 ) ) +( ( 32 744 72 1 0 ) ( 32 744 76 1 0.062500 ) ( 32 744 80 1 0.125000 ) ) +( ( 32 760 72 1.250000 0 ) ( 32 760 76 1.250000 0.062500 ) ( 32 760 80 1.250000 0.125000 ) ) +( ( 16 760 72 1.500000 0 ) ( 16 760 76 1.500000 0.062500 ) ( 16 760 80 1.500000 0.125000 ) ) +( ( 0 760 72 1.750000 0 ) ( 0 760 76 1.750000 0.062500 ) ( 0 760 80 1.750000 0.125000 ) ) +( ( 0 744 72 2 0 ) ( 0 744 76 2 0.062500 ) ( 0 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 16 760 72 7.375000 -11.875000 ) ( 0 760 72 7.125000 -11.875000 ) ( 0 744 72 7.125000 -11.625000 ) ) +( ( 32 760 72 7.625000 -11.875000 ) ( 16 744 72 7.375000 -11.625000 ) ( 0 728 72 7.125000 -11.375000 ) ) +( ( 32 744 72 7.625000 -11.625000 ) ( 32 728 72 7.625000 -11.375000 ) ( 16 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 0 744 80 7.125000 -11.625000 ) ( 0 760 80 7.125000 -11.875000 ) ( 16 760 80 7.375000 -11.875000 ) ) +( ( 0 728 80 7.125000 -11.375000 ) ( 16 744 80 7.375000 -11.625000 ) ( 32 760 80 7.625000 -11.875000 ) ) +( ( 16 728 80 7.375000 -11.375000 ) ( 32 728 80 7.625000 -11.375000 ) ( 32 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 16 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -72 928 72 0 0 ) ( -72 928 76 0 0.062500 ) ( -72 928 80 0 0.125000 ) ) +( ( -72 912 72 0.250000 0 ) ( -72 912 76 0.250000 0.062500 ) ( -72 912 80 0.250000 0.125000 ) ) +( ( -56 912 72 0.500000 0 ) ( -56 912 76 0.500000 0.062500 ) ( -56 912 80 0.500000 0.125000 ) ) +( ( -40 912 72 0.750000 0 ) ( -40 912 76 0.750000 0.062500 ) ( -40 912 80 0.750000 0.125000 ) ) +( ( -40 928 72 1 0 ) ( -40 928 76 1 0.062500 ) ( -40 928 80 1 0.125000 ) ) +( ( -40 944 72 1.250000 0 ) ( -40 944 76 1.250000 0.062500 ) ( -40 944 80 1.250000 0.125000 ) ) +( ( -56 944 72 1.500000 0 ) ( -56 944 76 1.500000 0.062500 ) ( -56 944 80 1.500000 0.125000 ) ) +( ( -72 944 72 1.750000 0 ) ( -72 944 76 1.750000 0.062500 ) ( -72 944 80 1.750000 0.125000 ) ) +( ( -72 928 72 2 0 ) ( -72 928 76 2 0.062500 ) ( -72 928 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -56 944 72 7.375000 -11.875000 ) ( -72 944 72 7.125000 -11.875000 ) ( -72 928 72 7.125000 -11.625000 ) ) +( ( -40 944 72 7.625000 -11.875000 ) ( -56 928 72 7.375000 -11.625000 ) ( -72 912 72 7.125000 -11.375000 ) ) +( ( -40 928 72 7.625000 -11.625000 ) ( -40 912 72 7.625000 -11.375000 ) ( -56 912 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -72 928 80 7.125000 -11.625000 ) ( -72 944 80 7.125000 -11.875000 ) ( -56 944 80 7.375000 -11.875000 ) ) +( ( -72 912 80 7.125000 -11.375000 ) ( -56 928 80 7.375000 -11.625000 ) ( -40 944 80 7.625000 -11.875000 ) ) +( ( -56 912 80 7.375000 -11.375000 ) ( -40 912 80 7.625000 -11.375000 ) ( -40 928 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 17 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -72 824 72 0 0 ) ( -72 824 76 0 0.062500 ) ( -72 824 80 0 0.125000 ) ) +( ( -72 808 72 0.250000 0 ) ( -72 808 76 0.250000 0.062500 ) ( -72 808 80 0.250000 0.125000 ) ) +( ( -56 808 72 0.500000 0 ) ( -56 808 76 0.500000 0.062500 ) ( -56 808 80 0.500000 0.125000 ) ) +( ( -40 808 72 0.750000 0 ) ( -40 808 76 0.750000 0.062500 ) ( -40 808 80 0.750000 0.125000 ) ) +( ( -40 824 72 1 0 ) ( -40 824 76 1 0.062500 ) ( -40 824 80 1 0.125000 ) ) +( ( -40 840 72 1.250000 0 ) ( -40 840 76 1.250000 0.062500 ) ( -40 840 80 1.250000 0.125000 ) ) +( ( -56 840 72 1.500000 0 ) ( -56 840 76 1.500000 0.062500 ) ( -56 840 80 1.500000 0.125000 ) ) +( ( -72 840 72 1.750000 0 ) ( -72 840 76 1.750000 0.062500 ) ( -72 840 80 1.750000 0.125000 ) ) +( ( -72 824 72 2 0 ) ( -72 824 76 2 0.062500 ) ( -72 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -56 840 72 7.375000 -11.875000 ) ( -72 840 72 7.125000 -11.875000 ) ( -72 824 72 7.125000 -11.625000 ) ) +( ( -40 840 72 7.625000 -11.875000 ) ( -56 824 72 7.375000 -11.625000 ) ( -72 808 72 7.125000 -11.375000 ) ) +( ( -40 824 72 7.625000 -11.625000 ) ( -40 808 72 7.625000 -11.375000 ) ( -56 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -72 824 80 7.125000 -11.625000 ) ( -72 840 80 7.125000 -11.875000 ) ( -56 840 80 7.375000 -11.875000 ) ) +( ( -72 808 80 7.125000 -11.375000 ) ( -56 824 80 7.375000 -11.625000 ) ( -40 840 80 7.625000 -11.875000 ) ) +( ( -56 808 80 7.375000 -11.375000 ) ( -40 808 80 7.625000 -11.375000 ) ( -40 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 18 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 552 824 72 0 0 ) ( 552 824 76 0 0.062500 ) ( 552 824 80 0 0.125000 ) ) +( ( 552 808 72 0.250000 0 ) ( 552 808 76 0.250000 0.062500 ) ( 552 808 80 0.250000 0.125000 ) ) +( ( 568 808 72 0.500000 0 ) ( 568 808 76 0.500000 0.062500 ) ( 568 808 80 0.500000 0.125000 ) ) +( ( 584 808 72 0.750000 0 ) ( 584 808 76 0.750000 0.062500 ) ( 584 808 80 0.750000 0.125000 ) ) +( ( 584 824 72 1 0 ) ( 584 824 76 1 0.062500 ) ( 584 824 80 1 0.125000 ) ) +( ( 584 840 72 1.250000 0 ) ( 584 840 76 1.250000 0.062500 ) ( 584 840 80 1.250000 0.125000 ) ) +( ( 568 840 72 1.500000 0 ) ( 568 840 76 1.500000 0.062500 ) ( 568 840 80 1.500000 0.125000 ) ) +( ( 552 840 72 1.750000 0 ) ( 552 840 76 1.750000 0.062500 ) ( 552 840 80 1.750000 0.125000 ) ) +( ( 552 824 72 2 0 ) ( 552 824 76 2 0.062500 ) ( 552 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 568 840 72 7.375000 -11.875000 ) ( 552 840 72 7.125000 -11.875000 ) ( 552 824 72 7.125000 -11.625000 ) ) +( ( 584 840 72 7.625000 -11.875000 ) ( 568 824 72 7.375000 -11.625000 ) ( 552 808 72 7.125000 -11.375000 ) ) +( ( 584 824 72 7.625000 -11.625000 ) ( 584 808 72 7.625000 -11.375000 ) ( 568 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 552 824 80 7.125000 -11.625000 ) ( 552 840 80 7.125000 -11.875000 ) ( 568 840 80 7.375000 -11.875000 ) ) +( ( 552 808 80 7.125000 -11.375000 ) ( 568 824 80 7.375000 -11.625000 ) ( 584 840 80 7.625000 -11.875000 ) ) +( ( 568 808 80 7.375000 -11.375000 ) ( 584 808 80 7.625000 -11.375000 ) ( 584 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 19 +{ +"classname" "light" +"light" "600" +"origin" "256 -448 336" +} diff --git a/docs/developer/TstMaps/sput.map b/docs/developer/TstMaps/sput.map new file mode 100644 index 00000000..81836e0e --- /dev/null +++ b/docs/developer/TstMaps/sput.map @@ -0,0 +1,1887 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 3344 -592 -64 ) ( 2760 -592 -64 ) ( 2760 -1240 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2760 -1240 0 ) ( 2760 -592 0 ) ( 3344 -592 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -1216 8 ) ( 3336 -1216 8 ) ( 3336 -1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 -1240 8 ) ( 3392 -592 8 ) ( 3392 -592 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3344 -576 8 ) ( 2760 -576 8 ) ( 2760 -576 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -592 8 ) ( 2752 -1240 8 ) ( 2752 -1240 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 824 3312 -64 ) ( 200 3312 -64 ) ( 200 2688 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 208 2688 0 ) ( 208 3312 0 ) ( 832 3312 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 200 2688 256 ) ( 824 2688 256 ) ( 824 2688 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 2688 256 ) ( 832 3312 256 ) ( 832 3312 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 824 3328 256 ) ( 200 3328 256 ) ( 200 3328 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 3296 256 ) ( -832 2672 256 ) ( -832 2672 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( 3408 3328 -64 ) ( 2776 3328 -64 ) ( 2776 2680 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2760 2680 0 ) ( 2760 3328 0 ) ( 3392 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2760 2688 40 ) ( 3392 2688 40 ) ( 3392 2688 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( 3392 2680 40 ) ( 3392 3328 40 ) ( 3392 3328 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( 3392 3328 40 ) ( 2760 3328 40 ) ( 2760 3328 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( 2752 3328 40 ) ( 2752 2680 40 ) ( 2752 2680 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( -2752 3328 -64 ) ( -3384 3328 -64 ) ( -3384 2704 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3352 2704 0 ) ( -3352 3328 0 ) ( -2720 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3384 2688 1512 ) ( -2752 2688 1512 ) ( -2752 2688 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +( -2752 2704 1512 ) ( -2752 3328 1512 ) ( -2752 3328 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +( -2752 3328 1512 ) ( -3384 3328 1512 ) ( -3384 3328 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +( -3392 3320 1512 ) ( -3392 2696 1512 ) ( -3392 2696 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( -192 3328 -64 ) ( -840 3328 -64 ) ( -840 2688 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 2688 0 ) ( -832 3328 0 ) ( -184 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -800 2432 296 ) ( -152 2432 296 ) ( -152 2432 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( -192 2688 296 ) ( -192 3328 296 ) ( -192 3328 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( -192 3328 296 ) ( -840 3328 296 ) ( -840 3328 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( -832 3328 296 ) ( -832 2688 296 ) ( -832 2688 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( -2768 -584 -64 ) ( -3312 -584 -64 ) ( -3312 -1184 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3312 -1184 0 ) ( -3312 -584 0 ) ( -2768 -584 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3320 -1216 0 ) ( -2776 -1216 0 ) ( -2776 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -1176 0 ) ( -2752 -576 0 ) ( -2752 -576 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2768 -576 0 ) ( -3312 -576 0 ) ( -3312 -576 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 -600 0 ) ( -3392 -1200 0 ) ( -3392 -1200 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -832 -552 0 ) ( -832 472 0 ) ( -832 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1208 2688 -16 ) ( -2744 2688 -16 ) ( -2744 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -64 ) ( -1888 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1728 2672 -64 ) ( -1728 2688 -64 ) ( -1728 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) sfx/jumppadsmall 128 0 0 -0.500000 0.500000 0 0 0 +( -1208 2688 -16 ) ( -2744 2688 -16 ) ( -2744 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -64 ) ( -1888 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1856 2672 -64 ) ( -1856 2688 -64 ) ( -1856 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1728 2688 -64 ) ( -1728 2672 -64 ) ( -1728 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -1208 2688 -16 ) ( -2744 2688 -16 ) ( -2744 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 520 8 ) ( -2752 -504 8 ) ( -2752 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -64 ) ( -1888 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1856 2688 -64 ) ( -1856 2672 -64 ) ( -1856 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -1216 8 ) ( -1216 -1216 8 ) ( -1216 -1216 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -552 0 ) ( -832 472 0 ) ( -832 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 520 8 ) ( -2752 -504 8 ) ( -2752 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1888 2560 -64 ) ( -1864 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -552 0 ) ( 2752 472 0 ) ( 2752 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2376 2688 -16 ) ( 840 2688 -16 ) ( 840 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -64 ) ( 1664 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1856 2664 -64 ) ( 1856 2688 -64 ) ( 1856 2676 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) sfx/jumppadsmall 128 0 0 -0.500000 0.500000 0 0 0 +( 2376 2688 -16 ) ( 840 2688 -16 ) ( 840 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -64 ) ( 1664 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1728 2616 -64 ) ( 1728 2688 -64 ) ( 1728 2652 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1856 2688 -64 ) ( 1856 2664 -64 ) ( 1856 2676 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 2376 2688 -16 ) ( 840 2688 -16 ) ( 840 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 520 8 ) ( 832 -504 8 ) ( 832 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -64 ) ( 1664 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1728 2688 -64 ) ( 1728 2616 -64 ) ( 1728 2652 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 832 -1216 8 ) ( 2368 -1216 8 ) ( 2368 -1216 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -552 0 ) ( 2752 472 0 ) ( 2752 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 520 8 ) ( 832 -504 8 ) ( 832 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1664 2560 -64 ) ( 1720 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 14 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 384 -320 448 0 0 ) ( 448 -320 448 0 0.500000 ) ( 512 -320 448 0 1 ) ) +( ( 384 -320 896 3.500000 0 ) ( 448 -320 896 3.500000 0.500000 ) ( 512 -320 896 3.500000 1 ) ) +( ( 384 0 896 6 0 ) ( 448 0 896 6 0.500000 ) ( 512 0 896 6 1 ) ) +) + } + } +// brush 15 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 512 320 448 0 0 ) ( 448 320 448 0 0.500000 ) ( 384 320 448 0 1 ) ) +( ( 512 320 896 3.500000 0 ) ( 448 320 896 3.500000 0.500000 ) ( 384 320 896 3.500000 1 ) ) +( ( 512 0 896 6 0 ) ( 448 0 896 6 0.500000 ) ( 384 0 896 6 1 ) ) +) + } + } +// brush 16 +{ +( 1112 3296 1536 ) ( -3392 3296 1536 ) ( -3392 1384 1536 ) skies/kcbasesky_arena1_sky 0 0 0 0.500000 0.500000 0 0 0 +( -3384 1384 1600 ) ( -3384 3296 1600 ) ( 1120 3296 1600 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( -3392 -1216 1600 ) ( 1112 -1216 1600 ) ( 1112 -1216 384 ) common/caulk 32 48 0 0.500000 0.500000 0 0 0 +( 3392 1384 1536 ) ( 3392 3296 1536 ) ( 3392 3296 320 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 +( 1112 3328 1560 ) ( -3392 3328 1560 ) ( -3392 3328 344 ) common/caulk 32 48 0 0.500000 0.500000 0 0 0 +( -3392 3296 1560 ) ( -3392 1384 1560 ) ( -3392 1384 344 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 +} +// brush 17 +{ +( 4104 3352 -8 ) ( 5376 3352 -8 ) ( 5376 3384 -8 ) common/caulk -63 1 -180 0.500000 0.500000 0 0 0 +( 5344 3384 1536 ) ( 5344 3352 1536 ) ( 4072 3352 1536 ) common/caulk -63 1 -180 0.500000 0.500000 0 0 0 +( 5344 3392 1536 ) ( 4072 3392 1536 ) ( 4072 3392 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 2752 3384 1536 ) ( 2752 3352 1536 ) ( 2752 3352 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3440 3328 1536 ) ( 4712 3328 1536 ) ( 4712 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3456 3464 1536 ) ( 3456 3496 1536 ) ( 3456 3496 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 18 +{ +( 3456 4008 0 ) ( 3456 5280 0 ) ( 3424 5280 0 ) common/caulk 1 1 90 0.500000 0.500000 0 0 0 +( 3400 5280 1536 ) ( 3432 5280 1536 ) ( 3432 4008 1536 ) common/caulk 1 1 90 0.500000 0.500000 0 0 0 +( 3392 5280 1536 ) ( 3392 4008 1536 ) ( 3392 4008 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3400 2688 1536 ) ( 3432 2688 1536 ) ( 3432 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3456 3376 1536 ) ( 3456 4648 1536 ) ( 3456 4648 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3336 3328 1536 ) ( 3304 3328 1536 ) ( 3304 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 19 +{ +( -3400 4008 0 ) ( -3400 5280 0 ) ( -3432 5280 0 ) common/caulk -63 -63 90 0.500000 0.500000 0 0 0 +( -3448 5280 1536 ) ( -3416 5280 1536 ) ( -3416 4008 1536 ) common/caulk -63 -63 90 0.500000 0.500000 0 0 0 +( -3456 5280 1536 ) ( -3456 4008 1536 ) ( -3456 4008 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3448 2688 1536 ) ( -3416 2688 1536 ) ( -3416 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -3392 3376 1536 ) ( -3392 4648 1536 ) ( -3392 4648 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3512 3328 1536 ) ( -3544 3328 1536 ) ( -3544 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 20 +{ +( -4136 3368 0 ) ( -5408 3368 0 ) ( -5408 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -5408 3336 1536 ) ( -5408 3368 1536 ) ( -4136 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -5408 3328 1536 ) ( -4136 3328 1536 ) ( -4136 3328 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3304 1216 ) ( -2752 3336 1216 ) ( -2752 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3504 3392 1536 ) ( -4776 3392 1536 ) ( -4776 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3456 3272 1536 ) ( -3456 3240 1536 ) ( -3456 3240 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 21 +{ +( 3432 -1272 0 ) ( 3432 0 0 ) ( 3400 0 0 ) common/caulk 0 -31 -180 0.500000 0.500000 0 0 0 +( 3400 0 1536 ) ( 3432 0 1536 ) ( 3432 -1272 1536 ) common/caulk 0 -31 -180 0.500000 0.500000 0 0 0 +( 3392 64 1536 ) ( 3392 -1208 1536 ) ( 3392 -1208 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 3384 -1280 1536 ) ( 3416 -1280 1536 ) ( 3416 -1280 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3456 -1904 1536 ) ( 3456 -632 1536 ) ( 3456 -632 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 3496 1344 1536 ) ( 3464 1344 1536 ) ( 3464 1344 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 22 +{ +( 3416 -1240 -8 ) ( 2144 -1240 -8 ) ( 2144 -1272 -8 ) common/caulk -63 -31 90 0.500000 0.500000 0 0 0 +( 2112 -1272 1536 ) ( 2112 -1240 1536 ) ( 3384 -1240 1536 ) common/caulk -63 -31 90 0.500000 0.500000 0 0 0 +( 2048 -1280 1536 ) ( 3320 -1280 1536 ) ( 3320 -1280 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 3392 -1288 1536 ) ( 3392 -1256 1536 ) ( 3392 -1256 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 4016 -1216 1536 ) ( 2744 -1216 1536 ) ( 2744 -1216 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 832 -1184 1536 ) ( 832 -1216 1536 ) ( 832 -1216 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 23 +{ +( -840 -1192 0 ) ( -2112 -1192 0 ) ( -2112 -1224 0 ) common/caulk 0 -31 90 0.500000 0.500000 0 0 0 +( -2112 -1272 1536 ) ( -2112 -1240 1536 ) ( -840 -1240 1536 ) common/caulk 0 -31 90 0.500000 0.500000 0 0 0 +( -2176 -1280 1536 ) ( -904 -1280 1536 ) ( -904 -1280 320 ) common/caulk -32 0 -180 0.500000 -0.500000 0 0 0 +( -832 -1288 1536 ) ( -832 -1256 1536 ) ( -832 -1256 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -208 -1216 1536 ) ( -1480 -1216 1536 ) ( -1480 -1216 320 ) common/caulk -32 0 -180 0.500000 -0.500000 0 0 0 +( -3392 -1184 1536 ) ( -3392 -1216 1536 ) ( -3392 -1216 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 24 +{ +( -3432 1296 0 ) ( -3432 24 0 ) ( -3400 24 0 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( -3400 0 1536 ) ( -3432 0 1536 ) ( -3432 1272 1536 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( -3392 0 1536 ) ( -3392 1272 1536 ) ( -3392 1272 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( -3384 1344 1536 ) ( -3416 1344 1536 ) ( -3416 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3456 1904 1536 ) ( -3456 632 1536 ) ( -3456 632 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( -3488 -1280 1536 ) ( -3456 -1280 1536 ) ( -3456 -1280 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 25 +{ +( 168 3048 320 ) ( 168 4320 320 ) ( 136 4320 320 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( 136 4320 1536 ) ( 168 4320 1536 ) ( 168 3048 1536 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( 128 4320 1536 ) ( 128 3048 1536 ) ( 128 3048 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 160 2688 1536 ) ( 192 2688 1536 ) ( 192 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 192 2416 1536 ) ( 192 3688 1536 ) ( 192 3688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 112 3328 1536 ) ( 80 3328 1536 ) ( 80 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 26 +{ +( -184 3048 0 ) ( -184 4320 0 ) ( -216 4320 0 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( -184 4320 1536 ) ( -152 4320 1536 ) ( -152 3048 1536 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( -192 4320 1536 ) ( -192 3048 1536 ) ( -192 3048 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -160 2688 1536 ) ( -128 2688 1536 ) ( -128 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -128 2416 1536 ) ( -128 3688 1536 ) ( -128 3688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -208 3328 1536 ) ( -240 3328 1536 ) ( -240 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 27 +{ +( -544 3368 0 ) ( -1816 3368 0 ) ( -1816 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1824 3336 1536 ) ( -1824 3368 1536 ) ( -552 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1824 3328 1536 ) ( -552 3328 1536 ) ( -552 3328 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3304 1536 ) ( 832 3336 1536 ) ( 832 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 80 3392 1536 ) ( -1192 3392 1536 ) ( -1192 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 3312 1536 ) ( -832 3280 1536 ) ( -832 3280 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 28 +{ +( -3432 2616 320 ) ( -3432 1344 320 ) ( -3400 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3400 1344 1536 ) ( -3432 1344 1536 ) ( -3432 2616 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 1344 1536 ) ( -3392 2616 1536 ) ( -3392 2616 320 ) gothic_wall/support2b 0 67 0 -5.250000 4.750000 0 0 0 +( -3384 2688 1536 ) ( -3416 2688 1536 ) ( -3416 2688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3456 3248 1536 ) ( -3456 1976 1536 ) ( -3456 1976 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3432 1344 1536 ) ( -3400 1344 1536 ) ( -3400 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 29 +{ +( -1480 3368 320 ) ( -2752 3368 320 ) ( -2752 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3336 1536 ) ( -2752 3368 1536 ) ( -1480 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3328 1536 ) ( -1480 3328 1536 ) ( -1480 3328 320 ) gothic_wall/support2b 145 67 0 -7.500000 4.750000 0 0 0 +( -832 3336 1536 ) ( -832 3368 1536 ) ( -832 3368 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -848 3392 1536 ) ( -2120 3392 1536 ) ( -2120 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3368 1536 ) ( -2752 3336 1536 ) ( -2752 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 30 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2752 3328 1536 0 0 ) ( -2752 3328 928 0 0.500000 ) ( -2752 3328 320 0 1 ) ) +( ( -3392 3328 1536 0.500000 0 ) ( -3392 3328 928 0.500000 0.500000 ) ( -3392 3328 320 0.500000 1 ) ) +( ( -3392 2688 1536 1 0 ) ( -3392 2688 928 1 0.500000 ) ( -3392 2688 320 1 1 ) ) +) + } + } +// brush 31 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -192 2688 1536 0 0 ) ( -192 2688 928 0 0.500000 ) ( -192 2688 320 0 1 ) ) +( ( -192 3328 1536 0.500000 0 ) ( -192 3328 928 0.500000 0.500000 ) ( -192 3328 320 0.500000 1 ) ) +( ( -832 3328 1536 1 0 ) ( -832 3328 928 1 0.500000 ) ( -832 3328 320 1 1 ) ) +) + } + } +// brush 32 +{ +( 3448 1416 0 ) ( 3448 2688 0 ) ( 3416 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3400 2688 1536 ) ( 3432 2688 1536 ) ( 3432 1416 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 2688 1536 ) ( 3392 1416 1536 ) ( 3392 1416 320 ) gothic_wall/support2b 0 67 0 -5.250000 4.750000 0 0 0 +( 3384 1344 1536 ) ( 3416 1344 1536 ) ( 3416 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3456 784 1536 ) ( 3456 2056 1536 ) ( 3456 2056 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3432 2688 1536 ) ( 3400 2688 1536 ) ( 3400 2688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 33 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 3392 2688 1536 0 0 ) ( 3392 2688 928 0 0.500000 ) ( 3392 2688 320 0 1 ) ) +( ( 3392 3328 1536 0.500000 0 ) ( 3392 3328 928 0.500000 0.500000 ) ( 3392 3328 320 0.500000 1 ) ) +( ( 2752 3328 1536 1 0 ) ( 2752 3328 928 1 0.500000 ) ( 2752 3328 320 1 1 ) ) +) + } + } +// brush 34 +{ +( 2112 3368 0 ) ( 840 3368 0 ) ( 840 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3336 1536 ) ( 832 3368 1536 ) ( 2104 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3328 1536 ) ( 2104 3328 1536 ) ( 2104 3328 320 ) gothic_wall/support2b 110 67 0 -7.500000 4.750000 0 0 0 +( 2752 3336 1536 ) ( 2752 3368 1536 ) ( 2752 3368 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2736 3392 1536 ) ( 1464 3392 1536 ) ( 1464 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3368 1536 ) ( 832 3336 1536 ) ( 832 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 35 +{ +( 192 2688 320 ) ( -192 2688 320 ) ( -192 2648 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -208 2648 1536 ) ( -208 2688 1536 ) ( 176 2688 1536 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -192 2624 448 ) ( 192 2624 448 ) ( 192 2624 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 192 2648 448 ) ( 192 2688 448 ) ( 192 2688 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 192 2688 448 ) ( -192 2688 448 ) ( -192 2688 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -192 2688 448 ) ( -192 2648 448 ) ( -192 2648 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 36 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 3328 1536 0 0 ) ( 832 3328 928 0 0.500000 ) ( 832 3328 320 0 1 ) ) +( ( 192 3328 1536 0.500000 0 ) ( 192 3328 928 0.500000 0.500000 ) ( 192 3328 320 0.500000 1 ) ) +( ( 192 2688 1536 1 0 ) ( 192 2688 928 1 0.500000 ) ( 192 2688 320 1 1 ) ) +) + } + } +// brush 37 +{ +( 16 40 1088 ) ( -288 40 1088 ) ( -288 -32 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -192 1 1152 ) ( 192 1 1152 ) ( 195 -1 1152 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -256 -40 1088 ) ( -192 -1 1152 ) ( 195 -1 1152 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 192 -1 1152 ) ( 256 40 1088 ) ( 256 -40 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -256 40 1088 ) ( 256 40 1088 ) ( 256 1 1152 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -256 40 1088 ) ( -192 1 1152 ) ( -256 -40 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 38 +{ +( -384 112 960 ) ( -368 112 960 ) ( -368 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 128 1024 ) ( -368 112 1024 ) ( -1136 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 128 1024 ) ( -1136 128 1024 ) ( -1136 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 128 1024 ) ( -384 112 1024 ) ( -384 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -1136 112 1024 ) ( -368 112 1024 ) ( -368 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 112 1024 ) ( -368 128 1024 ) ( -368 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 39 +{ +( -272 112 960 ) ( -256 112 960 ) ( -256 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 128 1024 ) ( -256 112 1024 ) ( -1024 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 128 1024 ) ( -1024 128 1024 ) ( -1024 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 128 1024 ) ( -272 112 1024 ) ( -272 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -1024 112 1024 ) ( -256 112 1024 ) ( -256 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 112 1024 ) ( -256 128 1024 ) ( -256 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 40 +{ +( -144 112 960 ) ( -128 112 960 ) ( -128 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 128 1024 ) ( -128 112 1024 ) ( -896 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 128 1024 ) ( -896 128 1024 ) ( -896 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 128 1024 ) ( -144 112 1024 ) ( -144 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -896 112 1024 ) ( -128 112 1024 ) ( -128 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 112 1024 ) ( -128 128 1024 ) ( -128 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 41 +{ +( 0 112 960 ) ( 16 112 960 ) ( 16 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 128 1024 ) ( 16 112 1024 ) ( -752 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 128 1024 ) ( -752 128 1024 ) ( -752 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 128 1024 ) ( 0 112 1024 ) ( 0 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -752 112 1024 ) ( 16 112 1024 ) ( 16 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 112 1024 ) ( 16 128 1024 ) ( 16 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 42 +{ +( 368 112 960 ) ( 384 112 960 ) ( 384 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( 384 112 1024 ) ( -384 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( -384 128 1024 ) ( -384 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 128 1024 ) ( 368 112 1024 ) ( 368 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 112 1024 ) ( 384 112 1024 ) ( 384 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 112 1024 ) ( 384 128 1024 ) ( 384 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 43 +{ +( 256 112 960 ) ( 272 112 960 ) ( 272 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 128 1024 ) ( 272 112 1024 ) ( -496 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 128 1024 ) ( -496 128 1024 ) ( -496 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 128 1024 ) ( 256 112 1024 ) ( 256 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -496 112 1024 ) ( 272 112 1024 ) ( 272 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 112 1024 ) ( 272 128 1024 ) ( 272 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 44 +{ +( 128 112 960 ) ( 144 112 960 ) ( 144 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 128 1024 ) ( 144 112 1024 ) ( -624 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 128 1024 ) ( -624 128 1024 ) ( -624 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 128 1024 ) ( 128 112 1024 ) ( 128 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -624 112 1024 ) ( 144 112 1024 ) ( 144 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 112 1024 ) ( 144 128 1024 ) ( 144 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 45 +{ +( 272 -112 960 ) ( 256 -112 960 ) ( 256 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 -128 1024 ) ( 256 -112 1024 ) ( 1024 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 -128 1024 ) ( 1024 -128 1024 ) ( 1024 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 -128 1024 ) ( 272 -112 1024 ) ( 272 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 1024 -112 1024 ) ( 256 -112 1024 ) ( 256 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 -112 1024 ) ( 256 -128 1024 ) ( 256 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 46 +{ +( 384 -112 960 ) ( 368 -112 960 ) ( 368 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 -128 1024 ) ( 368 -112 1024 ) ( 1136 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 -128 1024 ) ( 1136 -128 1024 ) ( 1136 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 -128 1024 ) ( 384 -112 1024 ) ( 384 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 1136 -112 1024 ) ( 368 -112 1024 ) ( 368 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 -112 1024 ) ( 368 -128 1024 ) ( 368 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 47 +{ +( 144 -112 960 ) ( 128 -112 960 ) ( 128 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -128 1024 ) ( 128 -112 1024 ) ( 896 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -128 1024 ) ( 896 -128 1024 ) ( 896 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 -128 1024 ) ( 144 -112 1024 ) ( 144 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 896 -112 1024 ) ( 128 -112 1024 ) ( 128 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -112 1024 ) ( 128 -128 1024 ) ( 128 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 48 +{ +( 16 -112 960 ) ( 0 -112 960 ) ( 0 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 -128 1024 ) ( 0 -112 1024 ) ( 768 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 -128 1024 ) ( 768 -128 1024 ) ( 768 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 -128 1024 ) ( 16 -112 1024 ) ( 16 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 768 -112 1024 ) ( 0 -112 1024 ) ( 0 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 -112 1024 ) ( 0 -128 1024 ) ( 0 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 49 +{ +( -128 -112 960 ) ( -144 -112 960 ) ( -144 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 -128 1024 ) ( -144 -112 1024 ) ( 624 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 -128 1024 ) ( 624 -128 1024 ) ( 624 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 -128 1024 ) ( -128 -112 1024 ) ( -128 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 624 -112 1024 ) ( -144 -112 1024 ) ( -144 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 -112 1024 ) ( -144 -128 1024 ) ( -144 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 50 +{ +( -272 -112 960 ) ( -272 -128 936 ) ( -256 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 -128 1024 ) ( -272 -112 1024 ) ( 496 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 -128 1024 ) ( 496 -128 1024 ) ( 496 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 -128 1024 ) ( -256 -112 1024 ) ( -256 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 496 -112 1024 ) ( -272 -112 1024 ) ( -272 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 -112 1024 ) ( -272 -128 1024 ) ( -272 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 51 +{ +( -384 -112 960 ) ( -384 -128 936 ) ( -368 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 -128 1024 ) ( -384 -112 1024 ) ( 384 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 -128 1024 ) ( 384 -128 1024 ) ( 384 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 -128 1024 ) ( -368 -112 1024 ) ( -368 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 -112 1024 ) ( -384 -112 1024 ) ( -384 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 -112 1024 ) ( -384 -128 1024 ) ( -384 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 52 +{ +( 160 120 1024 ) ( -376 120 1024 ) ( -376 -48 1024 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 320 -64 1088 ) ( -320 -64 1088 ) ( -320 72 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -320 -64 1088 ) ( 384 -128 1024 ) ( -384 -128 1024 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( 384 -128 1024 ) ( 320 128 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( 320 64 1088 ) ( -384 128 1024 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -128 1024 ) ( -384 128 1024 ) ( -320 72 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 53 +{ +( 368 -312 896 ) ( 480 -312 896 ) ( 480 -216 896 ) common/caulk 0 0 -180 0.500000 0.500000 0 0 0 +( 504 -216 960 ) ( 504 -312 960 ) ( 392 -312 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 504 320 960 ) ( 392 320 960 ) ( 392 320 448 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 384 -216 960 ) ( 384 -312 960 ) ( 384 -312 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 392 -320 960 ) ( 504 -320 960 ) ( 504 -320 448 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 512 -312 960 ) ( 512 -216 960 ) ( 512 -216 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 54 +{ +( -368 312 896 ) ( -480 312 896 ) ( -480 216 896 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -504 216 960 ) ( -504 312 960 ) ( -392 312 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -504 -320 960 ) ( -392 -320 960 ) ( -392 -320 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -384 216 960 ) ( -384 312 960 ) ( -384 312 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -392 320 960 ) ( -504 320 960 ) ( -504 320 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -512 312 960 ) ( -512 216 960 ) ( -512 216 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 55 +{ +( 384 -576 448 ) ( 544 -576 448 ) ( 544 -480 448 ) common/caulk -15 0 -180 0.500000 0.500000 0 0 0 +( 512 -480 960 ) ( 512 -576 960 ) ( 352 -576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 536 -320 576 ) ( 376 -320 576 ) ( 376 -320 448 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 384 -480 576 ) ( 384 -576 576 ) ( 384 -576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 -576 576 ) ( 544 -576 576 ) ( 544 -576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 512 -584 576 ) ( 512 -488 576 ) ( 512 -488 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 56 +{ +( -512 -576 448 ) ( -352 -576 448 ) ( -352 -480 448 ) common/caulk -15 0 -180 0.500000 0.500000 0 0 0 +( -336 -480 960 ) ( -336 -576 960 ) ( -496 -576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -360 -320 576 ) ( -520 -320 576 ) ( -520 -320 448 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -512 -480 576 ) ( -512 -576 576 ) ( -512 -576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -512 -576 576 ) ( -352 -576 576 ) ( -352 -576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -384 -584 576 ) ( -384 -488 576 ) ( -384 -488 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 57 +{ +( -96 -568 896 ) ( 120 -568 896 ) ( 120 -400 896 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -400 960 ) ( 128 -568 960 ) ( -88 -568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 104 -128 960 ) ( -112 -128 960 ) ( -112 -128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -128 -400 960 ) ( -128 -568 960 ) ( -128 -568 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -88 -576 960 ) ( 128 -576 960 ) ( 128 -576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 128 -568 960 ) ( 128 -400 960 ) ( 128 -400 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 58 +{ +( 160 -568 896 ) ( 376 -568 896 ) ( 376 -400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 384 -400 960 ) ( 384 -568 960 ) ( 168 -568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 360 -128 960 ) ( 144 -128 960 ) ( 144 -128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 128 -400 960 ) ( 128 -568 960 ) ( 128 -568 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 168 -576 960 ) ( 384 -576 960 ) ( 384 -576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 384 -568 960 ) ( 384 -400 960 ) ( 384 -400 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 59 +{ +( -352 -568 896 ) ( -136 -568 896 ) ( -136 -400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -128 -400 960 ) ( -128 -568 960 ) ( -344 -568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -152 -128 960 ) ( -368 -128 960 ) ( -368 -128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -400 960 ) ( -384 -568 960 ) ( -384 -568 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -344 -576 960 ) ( -128 -576 960 ) ( -128 -576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -128 -568 960 ) ( -128 -400 960 ) ( -128 -400 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 60 +{ +( 352 568 896 ) ( 136 568 896 ) ( 136 400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 128 400 960 ) ( 128 568 960 ) ( 344 568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 152 128 960 ) ( 368 128 960 ) ( 368 128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 400 960 ) ( 384 568 960 ) ( 384 568 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 344 576 960 ) ( 128 576 960 ) ( 128 576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 128 568 960 ) ( 128 400 960 ) ( 128 400 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 61 +{ +( -160 568 896 ) ( -376 568 896 ) ( -376 400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -384 400 960 ) ( -384 568 960 ) ( -168 568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -360 128 960 ) ( -144 128 960 ) ( -144 128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -128 400 960 ) ( -128 568 960 ) ( -128 568 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -168 576 960 ) ( -384 576 960 ) ( -384 576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -384 568 960 ) ( -384 400 960 ) ( -384 400 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 62 +{ +( 96 568 896 ) ( -120 568 896 ) ( -120 400 896 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 400 960 ) ( -128 568 960 ) ( 88 568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -104 128 960 ) ( 112 128 960 ) ( 112 128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 128 400 960 ) ( 128 568 960 ) ( 128 568 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 88 576 960 ) ( -128 576 960 ) ( -128 576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -128 568 960 ) ( -128 400 960 ) ( -128 400 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 63 +{ +( 512 576 448 ) ( 352 576 448 ) ( 352 480 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( 336 480 960 ) ( 336 576 960 ) ( 496 576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 360 320 576 ) ( 520 320 576 ) ( 520 320 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( 512 480 576 ) ( 512 576 576 ) ( 512 576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 512 576 576 ) ( 352 576 576 ) ( 352 576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 384 584 576 ) ( 384 488 576 ) ( 384 488 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 64 +{ +( -384 576 448 ) ( -544 576 448 ) ( -544 480 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -512 480 960 ) ( -512 576 960 ) ( -352 576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -536 320 576 ) ( -376 320 576 ) ( -376 320 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -384 480 576 ) ( -384 576 576 ) ( -384 576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 576 576 ) ( -544 576 576 ) ( -544 576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -512 584 576 ) ( -512 488 576 ) ( -512 488 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 65 +{ +( -1640 1784 0 ) ( -1952 1784 0 ) ( -1952 1536 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1928 1536 256 ) ( -1928 1784 256 ) ( -1616 1784 256 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -1960 1472 640 ) ( -1648 1472 640 ) ( -1648 1472 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1632 1536 640 ) ( -1632 1784 640 ) ( -1632 1784 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1640 1792 640 ) ( -1952 1792 640 ) ( -1952 1792 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1952 1784 640 ) ( -1952 1536 640 ) ( -1952 1536 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +} +// brush 66 + { + patchDef2 + { + base_wall/bluemetal1b_shiny + ( 9 3 0 0 0 ) +( +( ( -1888 1632 256 0 0 ) ( -1888 1632 896 0 0.500000 ) ( -1888 1632 1536 0 1 ) ) +( ( -1888 1536 256 0.125000 0 ) ( -1888 1536 896 0.125000 0.500000 ) ( -1888 1536 1536 0.125000 1 ) ) +( ( -1792 1536 256 0.250000 0 ) ( -1792 1536 896 0.250000 0.500000 ) ( -1792 1536 1536 0.250000 1 ) ) +( ( -1696 1536 256 0.375000 0 ) ( -1696 1536 896 0.375000 0.500000 ) ( -1696 1536 1536 0.375000 1 ) ) +( ( -1696 1632 256 0.500000 0 ) ( -1696 1632 896 0.500000 0.500000 ) ( -1696 1632 1536 0.500000 1 ) ) +( ( -1696 1728 256 0.625000 0 ) ( -1696 1728 896 0.625000 0.500000 ) ( -1696 1728 1536 0.625000 1 ) ) +( ( -1792 1728 256 0.750000 0 ) ( -1792 1728 896 0.750000 0.500000 ) ( -1792 1728 1536 0.750000 1 ) ) +( ( -1888 1728 256 0.875000 0 ) ( -1888 1728 896 0.875000 0.500000 ) ( -1888 1728 1536 0.875000 1 ) ) +( ( -1888 1632 256 1 0 ) ( -1888 1632 896 1 0.500000 ) ( -1888 1632 1536 1 1 ) ) +) + } + } +// brush 67 + { + patchDef2 + { + base_wall/bluemetal1b_shiny + ( 9 3 0 0 0 ) +( +( ( 1688 1568 256 0 0 ) ( 1688 1568 896 0 0.500000 ) ( 1688 1568 1536 0 1 ) ) +( ( 1688 1472 256 0.125000 0 ) ( 1688 1472 896 0.125000 0.500000 ) ( 1688 1472 1536 0.125000 1 ) ) +( ( 1784 1472 256 0.250000 0 ) ( 1784 1472 896 0.250000 0.500000 ) ( 1784 1472 1536 0.250000 1 ) ) +( ( 1880 1472 256 0.375000 0 ) ( 1880 1472 896 0.375000 0.500000 ) ( 1880 1472 1536 0.375000 1 ) ) +( ( 1880 1568 256 0.500000 0 ) ( 1880 1568 896 0.500000 0.500000 ) ( 1880 1568 1536 0.500000 1 ) ) +( ( 1880 1664 256 0.625000 0 ) ( 1880 1664 896 0.625000 0.500000 ) ( 1880 1664 1536 0.625000 1 ) ) +( ( 1784 1664 256 0.750000 0 ) ( 1784 1664 896 0.750000 0.500000 ) ( 1784 1664 1536 0.750000 1 ) ) +( ( 1688 1664 256 0.875000 0 ) ( 1688 1664 896 0.875000 0.500000 ) ( 1688 1664 1536 0.875000 1 ) ) +( ( 1688 1568 256 1 0 ) ( 1688 1568 896 1 0.500000 ) ( 1688 1568 1536 1 1 ) ) +) + } + } +// brush 68 +{ +( 1936 1720 0 ) ( 1624 1720 0 ) ( 1624 1472 0 ) gothic_wall/support2b 19 102 0 -1.250000 1.250000 0 0 0 +( 1648 1472 256 ) ( 1648 1720 256 ) ( 1960 1720 256 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 1616 1408 640 ) ( 1928 1408 640 ) ( 1928 1408 0 ) gothic_wall/support2b 19 0 0 -1.250000 1 0 0 0 +( 1944 1472 640 ) ( 1944 1720 640 ) ( 1944 1720 0 ) gothic_wall/support2b 102 0 0 -1.250000 1 0 0 0 +( 1936 1728 640 ) ( 1624 1728 640 ) ( 1624 1728 0 ) gothic_wall/support2b 19 0 0 -1.250000 1 0 0 0 +( 1624 1720 640 ) ( 1624 1472 640 ) ( 1624 1472 0 ) gothic_wall/support2b 102 0 0 -1.250000 1 0 0 0 +} +// brush 69 +{ +( 832 576 320 ) ( 384 576 320 ) ( 384 320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 384 320 448 ) ( 384 576 448 ) ( 832 576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 320 424 ) ( 832 320 424 ) ( 832 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 320 424 ) ( 832 576 424 ) ( 832 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 576 424 ) ( 384 576 424 ) ( 384 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 576 424 ) ( 384 320 424 ) ( 384 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 70 +{ +( -384 576 320 ) ( -832 576 320 ) ( -832 320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 320 448 ) ( -832 576 448 ) ( -384 576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 320 424 ) ( -384 320 424 ) ( -384 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 320 424 ) ( -384 576 424 ) ( -384 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 576 424 ) ( -832 576 424 ) ( -832 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 576 424 ) ( -832 320 424 ) ( -832 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 71 +{ +( -384 -320 320 ) ( -832 -320 320 ) ( -832 -576 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -576 448 ) ( -832 -320 448 ) ( -384 -320 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 -576 424 ) ( -384 -576 424 ) ( -384 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -576 424 ) ( -384 -320 424 ) ( -384 -320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -320 424 ) ( -832 -320 424 ) ( -832 -320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 -320 424 ) ( -832 -576 424 ) ( -832 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 72 +{ +( 832 -320 320 ) ( 384 -320 320 ) ( 384 -576 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 384 -576 448 ) ( 384 -320 448 ) ( 832 -320 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 -576 424 ) ( 832 -576 424 ) ( 832 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 424 ) ( 832 -320 424 ) ( 832 -320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 -320 424 ) ( 384 -320 424 ) ( 384 -320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 384 -320 424 ) ( 384 -576 424 ) ( 384 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 73 +{ +( 832 -320 320 ) ( 832 -320 322 ) ( 832 320 325 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 712 -320 424 ) ( 808 -320 424 ) ( 808 -320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 704 320 424 ) ( 704 -320 424 ) ( 704 -320 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 808 320 424 ) ( 712 320 424 ) ( 712 320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 704 320 424 ) ( 832 320 322 ) ( 704 -320 424 ) gothic_wall/support2b 0 120 90 0.391030 0.500000 0 0 0 +( 712 -320 320 ) ( 808 -320 320 ) ( 808 320 320 ) common/caulk 0 0 -180 0.500000 0.500000 0 0 0 +} +// brush 74 +{ +( -712 320 320 ) ( -808 320 320 ) ( -808 -320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -704 -320 424 ) ( -832 -320 322 ) ( -704 320 424 ) gothic_wall/support2b 0 120 270 0.500000 0.500000 0 0 0 +( -808 -320 424 ) ( -712 -320 424 ) ( -712 -320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -704 -320 424 ) ( -704 320 424 ) ( -704 320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -712 320 424 ) ( -808 320 424 ) ( -808 320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -832 320 320 ) ( -832 320 322 ) ( -832 -320 325 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 75 +{ +( 248 312 320 ) ( -384 312 320 ) ( -384 72 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -384 72 424 ) ( -384 312 424 ) ( 248 312 424 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -352 -320 424 ) ( 280 -320 424 ) ( 280 -320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 704 129 424 ) ( 704 369 424 ) ( 704 369 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 247 320 424 ) ( -385 320 424 ) ( -385 320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -705 311 424 ) ( -705 71 424 ) ( -705 71 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 76 +{ +( -832 -576 320 ) ( 832 -576 320 ) ( 832 -488 320 ) common/caulk -15 16 -180 0.500000 0.500000 0 0 0 +( 384 -576 321 ) ( -384 -576 321 ) ( -384 -320 427 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -384 -320 320 ) ( 384 -320 320 ) ( 384 -320 424 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -384 -472 384 ) ( -384 -560 384 ) ( -384 -560 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -384 -576 320 ) ( -384 -576 321 ) ( 384 -576 321 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 384 -568 384 ) ( 384 -480 384 ) ( 384 -480 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 77 +{ +( 832 576 320 ) ( -832 576 320 ) ( -832 488 320 ) common/caulk -16 16 0 0.500000 0.500000 0 0 0 +( -384 576 321 ) ( 384 576 321 ) ( 384 320 427 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 384 320 320 ) ( -384 320 320 ) ( -384 320 424 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( 384 472 384 ) ( 384 560 384 ) ( 384 560 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 384 576 320 ) ( 384 576 321 ) ( -384 576 321 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -384 568 384 ) ( -384 480 384 ) ( -384 480 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 78 +{ +( -440 576 264 ) ( -832 576 264 ) ( -832 -48 264 ) common/caulk 16 -16 0 0.500000 0.500000 0 0 0 +( -832 -48 320 ) ( -832 576 320 ) ( -440 576 320 ) common/caulk 16 -16 0 0.500000 0.500000 0 0 0 +( -840 -576 320 ) ( -448 -576 320 ) ( -448 -576 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 832 8 320 ) ( 832 632 320 ) ( 832 632 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -440 576 320 ) ( -832 576 320 ) ( -832 576 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -832 576 320 ) ( -832 -48 320 ) ( -832 -48 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +} +// brush 79 +{ +( 1224 568 0 ) ( 192 568 0 ) ( 192 -584 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 200 -584 264 ) ( 200 568 264 ) ( 1232 568 264 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 208 -128 320 ) ( 1240 -128 320 ) ( 1240 -128 0 ) gothic_wall/support2b 76 0 0 -2.500000 1.031250 0 0 0 +( 832 -512 320 ) ( 832 640 320 ) ( 832 640 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +( 1280 128 320 ) ( 248 128 320 ) ( 248 128 0 ) gothic_wall/support2b 76 0 0 -2.500000 1.031250 0 0 0 +( 192 568 320 ) ( 192 -584 320 ) ( 192 -584 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +} +// brush 80 +{ +( 200 568 0 ) ( -832 568 0 ) ( -832 -584 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -584 264 ) ( -832 568 264 ) ( 200 568 264 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -816 -128 320 ) ( 216 -128 320 ) ( 216 -128 0 ) gothic_wall/support2b 179 0 0 -2.500000 1.031250 0 0 0 +( -192 -512 320 ) ( -192 640 320 ) ( -192 640 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +( 256 128 320 ) ( -776 128 320 ) ( -776 128 0 ) gothic_wall/support2b 179 0 0 -2.500000 1.031250 0 0 0 +( -832 568 320 ) ( -832 -584 320 ) ( -832 -584 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +} +// brush 81 +{ +( -680 -1216 320 ) ( -832 -1216 320 ) ( -832 -1272 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -888 -1272 1536 ) ( -888 -1216 1536 ) ( -736 -1216 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -696 -1280 768 ) ( -544 -1280 768 ) ( -544 -1280 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -1280 768 ) ( 832 -1224 768 ) ( 832 -1224 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -680 -1216 768 ) ( -832 -1216 768 ) ( -832 -1216 320 ) gothic_wall/support2b 128 67 0 -6.500000 4.750000 0 0 0 +( -832 -1216 768 ) ( -832 -1272 768 ) ( -832 -1272 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 82 +{ +( 64 1320 576 ) ( -64 1320 576 ) ( -64 1224 576 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1224 1536 ) ( -64 1320 1536 ) ( 64 1320 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1216 704 ) ( 64 1216 704 ) ( 64 1216 576 ) gothic_wall/support2b 128 153 0 -0.500000 3.750000 0 0 0 +( 64 1224 704 ) ( 64 1320 704 ) ( 64 1320 576 ) gothic_wall/support2b 221 153 0 -5.500000 3.750000 0 0 0 +( 112 2624 704 ) ( -16 2624 704 ) ( -16 2624 576 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1320 704 ) ( -64 1224 704 ) ( -64 1224 576 ) gothic_wall/support2b 221 153 0 -5.500000 3.750000 0 0 0 +} +// brush 83 +{ +( 160 1280 448 ) ( -224 1280 448 ) ( -224 1216 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1216 576 ) ( -64 2688 576 ) ( 72 2688 576 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 768 ) ( 192 1216 768 ) ( 192 1216 760 ) gothic_wall/support2b 128 118 180 -1.500000 0.500000 0 0 0 +( 192 2688 448 ) ( 192 1216 448 ) ( 64 2688 576 ) gothic_wall/support2b 0 -140 270 0.500000 0.500000 0 0 0 +( 88 2624 768 ) ( -296 2624 768 ) ( -296 2624 760 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 448 ) ( -192 2688 448 ) ( -64 2688 576 ) gothic_wall/support2b 0 -140 90 0.500000 0.500000 0 0 0 +} +// brush 84 +{ +( 160 1280 320 ) ( -224 1280 320 ) ( -224 1216 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 448 ) ( -192 1280 448 ) ( 192 1280 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 640 ) ( 192 1216 640 ) ( 192 1216 632 ) gothic_wall/support2b 128 128 0 -1.500000 0.500000 0 0 0 +( 192 1216 640 ) ( 192 1280 640 ) ( 192 1280 632 ) gothic_wall/support2b 0 117 0 0.500000 0.500000 0 0 0 +( 112 2624 640 ) ( -272 2624 640 ) ( -272 2624 632 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1280 640 ) ( -192 1216 640 ) ( -192 1216 632 ) gothic_wall/support2b 0 117 0 0.500000 0.500000 0 0 0 +} +// brush 85 +{ +( -3392 64 320 ) ( -3392 -128 320 ) ( -3392 -128 256 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -2752 1344 320 ) ( -3392 1344 320 ) ( -3392 1344 256 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -2752 -128 320 ) ( -2752 64 320 ) ( -2752 64 256 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -3008 -576 320 ) ( -2368 -576 320 ) ( -2368 -576 256 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -3392 -128 320 ) ( -3392 64 320 ) ( -2752 64 320 ) mrcleantex_1/floortile4 -80 -16 0 0.500000 0.500000 0 0 0 +( -2752 64 0 ) ( -3392 64 0 ) ( -3392 -128 0 ) common/caulk -16 -16 0 0.500000 0.500000 0 0 0 +} +// brush 86 +{ +( -2248 -576 320 ) ( -2440 -576 320 ) ( -2440 -576 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -832 -1200 320 ) ( -832 -560 320 ) ( -832 -560 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2440 -1216 320 ) ( -2248 -1216 320 ) ( -2248 -1216 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -2752 -496 320 ) ( -2752 -1136 320 ) ( -2752 -1136 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2440 -576 320 ) ( -2248 -576 320 ) ( -2248 -1216 320 ) mrcleantex_1/floortile4 0 64 0 0.500000 0.500000 0 0 0 +( -2248 -1216 0 ) ( -2248 -576 0 ) ( -2440 -576 0 ) common/caulk 0 14 90 0.500000 0.500000 0 0 0 +} +// brush 87 +{ +( 3392 64 0 ) ( 2752 64 0 ) ( 2752 -128 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -128 320 ) ( 2752 64 320 ) ( 3392 64 320 ) mrcleantex_1/floortile4 96 0 0 0.500000 0.500000 0 0 0 +( 2736 -576 320 ) ( 3376 -576 320 ) ( 3376 -576 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 -128 320 ) ( 3392 64 320 ) ( 3392 64 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 1344 320 ) ( 2752 1344 320 ) ( 2752 1344 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 64 320 ) ( 2752 -128 320 ) ( 2752 -128 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 88 +{ +( 1080 -1216 0 ) ( 1080 -576 0 ) ( 888 -576 0 ) common/caulk 0 14 90 0.500000 0.500000 0 0 0 +( 888 -576 320 ) ( 1080 -576 320 ) ( 1080 -1216 320 ) mrcleantex_1/floortile4 0 80 0 0.500000 0.500000 0 0 0 +( 832 -488 320 ) ( 832 -1128 320 ) ( 832 -1128 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 888 -1216 320 ) ( 1080 -1216 320 ) ( 1080 -1216 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 2752 -1184 320 ) ( 2752 -544 320 ) ( 2752 -544 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1080 -576 320 ) ( 888 -576 320 ) ( 888 -576 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 89 +{ +( -2112 3136 0 ) ( -2752 3136 0 ) ( -2752 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 2688 320 ) ( -2752 3136 320 ) ( -2112 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -2752 2688 320 ) ( -2112 2688 320 ) ( -2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 2624 320 ) ( -2112 3072 320 ) ( -2112 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 3328 320 ) ( -2752 3328 320 ) ( -2752 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3136 320 ) ( -2752 2688 320 ) ( -2752 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 90 +{ +( -1472 3136 0 ) ( -2112 3136 0 ) ( -2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 2688 320 ) ( -2112 3136 320 ) ( -1472 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -2112 2688 320 ) ( -1472 2688 320 ) ( -1472 2688 0 ) gothic_wall/support2b 179 0 0 -2.500000 1.250000 0 0 0 +( -1472 2624 320 ) ( -1472 3072 320 ) ( -1472 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1472 3328 320 ) ( -2112 3328 320 ) ( -2112 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 3136 320 ) ( -2112 2688 320 ) ( -2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 91 +{ +( -584 -1216 0 ) ( -584 -576 0 ) ( -776 -576 0 ) common/caulk 0 16 90 0.500000 0.500000 0 0 0 +( -776 -576 320 ) ( -584 -576 320 ) ( -584 -1216 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -832 -488 320 ) ( -832 -1128 320 ) ( -832 -1128 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -776 -1216 320 ) ( -584 -1216 320 ) ( -584 -1216 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 832 -1200 320 ) ( 832 -560 320 ) ( 832 -560 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -584 -576 320 ) ( -776 -576 320 ) ( -776 -576 256 ) gothic_wall/support2b 128 0 0 -6.500000 1.250000 0 0 0 +} +// brush 92 +{ +( -2752 1408 0 ) ( -3392 1408 0 ) ( -3392 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 1216 320 ) ( -3392 1408 320 ) ( -2752 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -3000 1344 320 ) ( -2360 1344 320 ) ( -2360 1344 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 1216 320 ) ( -2752 1408 320 ) ( -2752 1408 256 ) gothic_wall/support2b 0 0 0 -5.250000 1.250000 0 0 0 +( -2752 2688 320 ) ( -3392 2688 320 ) ( -3392 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 1408 320 ) ( -3392 1216 320 ) ( -3392 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 93 +{ +( -832 3136 0 ) ( -1472 3136 0 ) ( -1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1472 2688 320 ) ( -1472 3136 320 ) ( -832 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -1472 2688 320 ) ( -832 2688 320 ) ( -832 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 2624 320 ) ( -832 3072 320 ) ( -832 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 3328 320 ) ( -1472 3328 320 ) ( -1472 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1472 3136 320 ) ( -1472 2688 320 ) ( -1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 94 +{ +( -192 1408 0 ) ( -832 1408 0 ) ( -832 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 1216 320 ) ( -832 1408 320 ) ( -192 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -752 576 320 ) ( -112 576 320 ) ( -112 576 256 ) gothic_wall/support2b 179 0 0 -2.500000 1.250000 0 0 0 +( -192 1216 320 ) ( -192 1408 320 ) ( -192 1408 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 2688 320 ) ( -832 2688 320 ) ( -832 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 1408 320 ) ( -832 1216 320 ) ( -832 1216 256 ) gothic_wall/support2b 211 0 0 -5.750000 1.250000 0 0 0 +} +// brush 95 +{ +( 3392 1408 0 ) ( 2752 1408 0 ) ( 2752 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 1216 320 ) ( 2752 1408 320 ) ( 3392 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 2752 1344 320 ) ( 3392 1344 320 ) ( 3392 1344 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 1216 320 ) ( 3392 1408 320 ) ( 3392 1408 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 2688 320 ) ( 2752 2688 320 ) ( 2752 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 1408 320 ) ( 2752 1216 320 ) ( 2752 1216 256 ) gothic_wall/support2b 0 0 0 -5.250000 1.250000 0 0 0 +} +// brush 96 +{ +( 2752 3136 0 ) ( 2112 3136 0 ) ( 2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2112 2688 320 ) ( 2112 3136 320 ) ( 2752 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 2112 2688 320 ) ( 2752 2688 320 ) ( 2752 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 2624 320 ) ( 2752 3072 320 ) ( 2752 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 3328 320 ) ( 2112 3328 320 ) ( 2112 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2112 3136 320 ) ( 2112 2688 320 ) ( 2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 97 +{ +( 2112 3136 0 ) ( 1472 3136 0 ) ( 1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 2688 320 ) ( 1472 3136 320 ) ( 2112 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 1472 2688 320 ) ( 2112 2688 320 ) ( 2112 2688 0 ) gothic_wall/support2b 76 0 0 -2.500000 1.250000 0 0 0 +( 2112 2624 320 ) ( 2112 3072 320 ) ( 2112 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2112 3328 320 ) ( 1472 3328 320 ) ( 1472 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 3136 320 ) ( 1472 2688 320 ) ( 1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 98 +{ +( 1472 3136 0 ) ( 832 3136 0 ) ( 832 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 2688 320 ) ( 832 3136 320 ) ( 1472 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 832 2688 320 ) ( 1472 2688 320 ) ( 1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 2624 320 ) ( 1472 3072 320 ) ( 1472 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 3328 320 ) ( 832 3328 320 ) ( 832 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3136 320 ) ( 832 2688 320 ) ( 832 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 99 +{ +( 832 1408 0 ) ( 192 1408 0 ) ( 192 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 192 1216 320 ) ( 192 1408 320 ) ( 832 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 256 576 320 ) ( 896 576 320 ) ( 896 576 256 ) gothic_wall/support2b 76 0 0 -2.500000 1.250000 0 0 0 +( 832 1216 320 ) ( 832 1408 320 ) ( 832 1408 256 ) gothic_wall/support2b 211 0 0 -5.750000 1.250000 0 0 0 +( 832 2688 320 ) ( 192 2688 320 ) ( 192 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 192 1408 320 ) ( 192 1216 320 ) ( 192 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 100 +{ +( 512 1216 0 ) ( -128 1216 0 ) ( -128 576 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 576 320 ) ( -192 1216 320 ) ( 448 1216 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -192 576 320 ) ( 448 576 320 ) ( 448 576 256 ) gothic_wall/support2b 128 0 0 -1.500000 1.250000 0 0 0 +( 192 576 320 ) ( 192 1216 320 ) ( 192 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 448 1216 320 ) ( -192 1216 320 ) ( -192 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 320 ) ( -192 576 320 ) ( -192 576 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 101 +{ +( 704 -192 -64 ) ( -832 -192 -64 ) ( -832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -576 0 ) ( -832 448 0 ) ( 704 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -832 -1216 8 ) ( 704 -1216 8 ) ( 704 -1216 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 832 448 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 768 1216 -16 ) ( -768 1216 -16 ) ( -768 1216 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 520 8 ) ( -832 -504 8 ) ( -832 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "target_position" +"targetname" "jump2" +"origin" "-1792 2632 520" +} +// entity 2 +{ +"classname" "trigger_push" +"target" "jump2" +// brush 0 +{ +( -1216 -192 0 ) ( -2752 -192 0 ) ( -2752 -1216 0 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 32 ) ( -2752 448 32 ) ( -1216 448 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1208 2688 24 ) ( -2744 2688 24 ) ( -2744 2688 -40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -24 ) ( -1888 2560 -24 ) ( -1876 2560 40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1856 2672 -24 ) ( -1856 2688 -24 ) ( -1856 2680 40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1728 2688 -24 ) ( -1728 2672 -24 ) ( -1728 2680 40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 3 +{ +"classname" "target_position" +"targetname" "jump1" +"origin" "1792 2632 520" +} +// entity 4 +{ +"classname" "trigger_push" +"target" "jump1" +// brush 0 +{ +( 2376 -192 0 ) ( 840 -192 0 ) ( 840 -1216 0 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 32 ) ( 832 448 32 ) ( 2368 448 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 2376 2688 16 ) ( 840 2688 16 ) ( 840 2688 -48 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -32 ) ( 1664 2560 -32 ) ( 1692 2560 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 1728 2616 -32 ) ( 1728 2688 -32 ) ( 1728 2652 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 1856 2688 -32 ) ( 1856 2664 -32 ) ( 1856 2676 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 5 +{ +"classname" "info_player_deathmatch" +"origin" "-552 992 344" +} +// entity 6 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -512 -320 448 0 0 ) ( -448 -320 448 0 0.500000 ) ( -384 -320 448 0 1 ) ) +( ( -512 -320 896 3.500000 0 ) ( -448 -320 896 3.500000 0.500000 ) ( -384 -320 896 3.500000 1 ) ) +( ( -512 0.000025 896 6 0 ) ( -448 0.000025 896 6 0.500000 ) ( -384 0.000025 896 6 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -512 -320 448 -8 -7 ) ( -512 -320 896 -8 -14 ) ( -512 0.000025 896 -8 -14 ) ) +( ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ) +( ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -384 0.000025 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ( -384 -320 448 -6 -14 ) ) +( ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ) +( ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ) +) + } + } +} +// entity 7 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -384 576 640 0 0 ) ( -384 448 640 0 1 ) ( -384 320 640 0 2 ) ) +( ( -384 576 896 2 0 ) ( -384 448 896 2 1 ) ( -384 320 896 2 2 ) ) +( ( -128 576 896 4 0 ) ( -128 448 896 4 1 ) ( -128 320 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -384 576 640 -6 -10 ) ( -384 576 896 -6 -14 ) ( -128 576 896 -2 -14 ) ) +( ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ) +( ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -128 320 896 -2 -28 ) ( -384 320 896 -6 -28 ) ( -384 320 640 -6 -20 ) ) +( ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ) +( ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ) +) + } + } +} +// entity 8 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2752 1344 320 0 0 ) ( -2752 1344 160 0 0.500000 ) ( -2752 1344 0 0 1 ) ) +( ( -2752 -576.000244 320 0.500000 0 ) ( -2752 -576.000244 160 0.500000 0.500000 ) ( -2752 -576.000244 0 0.500000 1 ) ) +( ( -832 -576.000244 320 1 0 ) ( -832 -576.000244 160 1 0.500000 ) ( -832 -576.000244 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -2752 1344 320 -43 -21 ) ( -2752 -576.000244 320 -43 9.000004 ) ( -832 -576.000244 320 -13 9.000004 ) ) +( ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ) +( ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -832 -576.000244 0 0 0 ) ( -2752 -576.000244 0 0 0.500000 ) ( -2752 1344 0 0 1 ) ) +( ( -2752 -576.000244 0 0.500000 0 ) ( -2752 -576.000244 0 0.500000 0.500000 ) ( -2752 -576.000244 0 0.500000 1 ) ) +( ( -2752 -576.000244 0 1 0 ) ( -2752 -576.000244 0 1 0.500000 ) ( -2752 -576.000244 0 1 1 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 3392 2688 0 0 0 ) ( 3392 2688 160 0 5 ) ( 3392 2688 320 0 10 ) ) +( ( 3392 3328 0 20 0 ) ( 3392 3328 160 20 5 ) ( 3392 3328 320 20 10 ) ) +( ( 2752 3328 0 40 0 ) ( 2752 3328 160 40 5 ) ( 2752 3328 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ) +( ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ) +( ( 3392 2688 0 106 -84 ) ( 3392 3328 0 106 -104 ) ( 2752 3328 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +( ( 3392 2688 320 53 -42 ) ( 3392 3328 320 53 -52 ) ( 2752 3328 320 43 -52 ) ) +) + } + } +} +// entity 10 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 1472 2688 320 0 0 ) ( 1472 2688 160 0 0.500000 ) ( 1472 2688 0 0 1 ) ) +( ( 832 2688 320 0.500000 0 ) ( 832 2688 160 0.500000 0.500000 ) ( 832 2688 0 0.500000 1 ) ) +( ( 832 2048 320 1 0 ) ( 832 2048 160 1 0.500000 ) ( 832 2048 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 1472 2688 320 23 -42 ) ( 832 2688 320 13 -42 ) ( 832 2048 320 13 -32 ) ) +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 2048 0 26 -64 ) ( 832 2688 0 0 0.500000 ) ( 1472 2688 0 0 1 ) ) +( ( 832 2688 0 0.500000 0 ) ( 832 2688 0 0.500000 0.500000 ) ( 832 2688 0 0.500000 1 ) ) +( ( 832 2688 0 1 0 ) ( 832 2688 0 1 0.500000 ) ( 832 2688 0 1 1 ) ) +) + } + } +} +// entity 11 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 2752 2048 320 0 0 ) ( 2752 2048 160 0 0.500000 ) ( 2752 2048 0 0 1 ) ) +( ( 2752 2688 320 0.500000 0 ) ( 2752 2688 160 0.500000 0.500000 ) ( 2752 2688 0 0.500000 1 ) ) +( ( 2112 2688 320 1 0 ) ( 2112 2688 160 1 0.500000 ) ( 2112 2688 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 2752 2048 320 43 -32 ) ( 2752 2688 320 43 -42 ) ( 2112 2688 320 33 -42 ) ) +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 2112 2688 0 26 -64 ) ( 2752 2688 0 26 -84 ) ( 2752 2048 0 46 -84 ) ) +( ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ) +( ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ) +) + } + } +} +// entity 12 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 3328 0 0 0 ) ( 832 3328 160 0 5 ) ( 832 3328 320 0 10 ) ) +( ( 192 3328 0 20 0 ) ( 192 3328 160 20 5 ) ( 192 3328 320 20 10 ) ) +( ( 192 2688 0 40 0 ) ( 192 2688 160 40 5 ) ( 192 2688 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ) +( ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ) +( ( 832 3328 0 106 -84 ) ( 192 3328 0 106 -104 ) ( 192 2688 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +( ( 832 3328 320 13 -52 ) ( 192 3328 320 3 -52 ) ( 192 2688 320 3 -42 ) ) +) + } + } +} +// entity 13 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -192 2688 0 0 0 ) ( -192 2688 160 0 5 ) ( -192 2688 320 0 10 ) ) +( ( -192 3328 0 20 0 ) ( -192 3328 160 20 5 ) ( -192 3328 320 20 10 ) ) +( ( -832 3328 0 40 0 ) ( -832 3328 160 40 5 ) ( -832 3328 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ) +( ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ) +( ( -192 2688 0 106 -84 ) ( -192 3328 0 106 -104 ) ( -832 3328 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +( ( -192 2688 320 -3 -42 ) ( -192 3328 320 -3 -52 ) ( -832 3328 320 -13 -52 ) ) +) + } + } +} +// entity 14 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -832 2048 320 0 0 ) ( -832 2048 160 0 0.500000 ) ( -832 2048 0 0 1 ) ) +( ( -832 2688 320 0.500000 0 ) ( -832 2688 160 0.500000 0.500000 ) ( -832 2688 0 0.500000 1 ) ) +( ( -1472 2688 320 1 0 ) ( -1472 2688 160 1 0.500000 ) ( -1472 2688 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -832 2048 320 -13 -32 ) ( -832 2688 320 -13 -42 ) ( -1472 2688 320 -23 -42 ) ) +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -1472 2688 0 0 0 ) ( -832 2688 0 0 0.500000 ) ( -832 2048 0 0 1 ) ) +( ( -832 2688 0 0.500000 0 ) ( -832 2688 0 0.500000 0.500000 ) ( -832 2688 0 0.500000 1 ) ) +( ( -832 2688 0 1 0 ) ( -832 2688 0 1 0.500000 ) ( -832 2688 0 1 1 ) ) +) + } + } +} +// entity 15 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -2752 3328 0 0 0 ) ( -2752 3328 160 0 5 ) ( -2752 3328 320 0 10 ) ) +( ( -3392 3328 0 20 0 ) ( -3392 3328 160 20 5 ) ( -3392 3328 320 20 10 ) ) +( ( -3392 2688 0 40 0 ) ( -3392 2688 160 40 5 ) ( -3392 2688 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ) +( ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ) +( ( -2752 3328 0 106 -84 ) ( -3392 3328 0 106 -104 ) ( -3392 2688 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +( ( -2752 3328 320 -43 -52 ) ( -3392 3328 320 -53 -52 ) ( -3392 2688 320 -53 -42 ) ) +) + } + } +} +// entity 16 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2112 2688 320 0 0 ) ( -2112 2688 160 0 0.500000 ) ( -2112 2688 0 0 1 ) ) +( ( -2752 2688 320 0.500000 0 ) ( -2752 2688 160 0.500000 0.500000 ) ( -2752 2688 0 0.500000 1 ) ) +( ( -2752 2048 320 1 0 ) ( -2752 2048 160 1 0.500000 ) ( -2752 2048 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -2112 2688 320 -33 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2048 320 -43 -32 ) ) +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2752 2048 0 0 0 ) ( -2752 2688 0 0 0.500000 ) ( -2112 2688 0 0 1 ) ) +( ( -2752 2688 0 0.500000 0 ) ( -2752 2688 0 0.500000 0.500000 ) ( -2752 2688 0 0.500000 1 ) ) +( ( -2752 2688 0 1 0 ) ( -2752 2688 0 1 0.500000 ) ( -2752 2688 0 1 1 ) ) +) + } + } +} +// entity 17 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 -576 320 0 0 ) ( 832 -576 160 0 0.500000 ) ( 832 -576 0 0 1 ) ) +( ( 2752 -576 320 0.500000 0 ) ( 2752 -576 160 0.500000 0.500000 ) ( 2752 -576 0 0.500000 1 ) ) +( ( 2752 1344 320 1 0 ) ( 2752 1344 160 1 0.500000 ) ( 2752 1344 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 832 -576 320 13 9 ) ( 2752 -576 320 43 9 ) ( 2752 1344 320 43 -21 ) ) +( ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ) +( ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 2752 1344 0 -26 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ( 832 -576 0 -86 -42 ) ) +( ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ) +( ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ) +) + } + } +} +// entity 18 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -3392 1343.999756 320 -86 -42 ) ( -3392 -1216.000488 320 -86 18.000008 ) ( -832.000427 -1216.000488 320 -26 18.000008 ) ) +( ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ) +( ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -832.000427 -1216.000488 0 -26 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 1343.999756 0 -86 -42 ) ) +( ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ) +( ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ) +) + } + } +} +// entity 19 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -3392 1343.999756 1536 0 0 ) ( -3392 1343.999756 927.999939 0 0.500000 ) ( -3392 1343.999756 320 0 1 ) ) +( ( -3392 -1216.000488 1536 0.500000 0 ) ( -3392 -1216.000488 927.999939 0.500000 0.500000 ) ( -3392 -1216.000488 320 0.500000 1 ) ) +( ( -832.000427 -1216.000488 1536 1 0 ) ( -832.000427 -1216.000488 927.999939 1 0.500000 ) ( -832.000427 -1216.000488 320 1 1 ) ) +) + } + } +} +// entity 20 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 -1216 320 0 10 ) ( 832 -1216 160 0 5 ) ( 832 -1216 0 0 0 ) ) +( ( 3392 -1216 320 80 10 ) ( 3392 -1216 160 80 5 ) ( 3392 -1216 0 80 0 ) ) +( ( 3392 1344 320 160 10 ) ( 3392 1344 160 160 5 ) ( 3392 1344 0 160 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 -1216 320 -86 -42 ) ( 3392 -1216 320 -86 18.000008 ) ( 3392 1344 320 -26 18.000008 ) ) +( ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ) +( ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 3392 1344 0 -26 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ( 832 -1216 0 -86 -42 ) ) +( ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ) +( ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ) +) + } + } +} +// entity 21 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 -1216 1536 0 0 ) ( 832 -1216 928 0 0.500000 ) ( 832 -1216 320 0 1 ) ) +( ( 3392 -1216 1536 0.500000 0 ) ( 3392 -1216 928 0.500000 0.500000 ) ( 3392 -1216 320 0.500000 1 ) ) +( ( 3392 1344 1536 1 0 ) ( 3392 1344 928 1 0.500000 ) ( 3392 1344 320 1 1 ) ) +) + } + } +} +// entity 22 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 384 320 640 0 0 ) ( 384 448 640 0 1 ) ( 384 576 640 0 2 ) ) +( ( 384 320 896 2 0 ) ( 384 448 896 2 1 ) ( 384 576 896 2 2 ) ) +( ( 128 320 896 4 0 ) ( 128 448 896 4 1 ) ( 128 576 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 384 320 640 6 -20 ) ( 384 320 896 6 -28 ) ( 128 320 896 2 -28 ) ) +( ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ) +( ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 128 576 896 9 -14 ) ( 384 576 896 9 -14 ) ( 384 576 640 9 -10 ) ) +( ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ) +( ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ) +) + } + } +} +// entity 23 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 384 -576 640 0 0 ) ( 384 -448 640 0 1 ) ( 384 -320 640 0 2 ) ) +( ( 384 -576 896 2 0 ) ( 384 -448 896 2 1 ) ( 384 -320 896 2 2 ) ) +( ( 128 -576 896 4 0 ) ( 128 -448 896 4 1 ) ( 128 -320 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 384 -576 640 6 -10 ) ( 384 -576 896 6 -14 ) ( 128 -576 896 2 -14 ) ) +( ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ) +( ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 128 -320 896 2 -28 ) ( 384 -320 896 6 -28 ) ( 384 -320 640 6 -20 ) ) +( ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ) +( ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ) +) + } + } +} +// entity 24 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -384 -320 640 0 0 ) ( -384 -448 640 0 1 ) ( -384 -576 640 0 2 ) ) +( ( -384 -320 896 2 0 ) ( -384 -448 896 2 1 ) ( -384 -576 896 2 2 ) ) +( ( -128 -320 896 4 0 ) ( -128 -448 896 4 1 ) ( -128 -576 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -384 -320 640 -5 -20 ) ( -384 -320 896 -5 -28 ) ( -128 -320 896 -5 -28 ) ) +( ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ) +( ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -128 -576 896 -2 -14 ) ( -384 -576 896 -6 -14 ) ( -384 -576 640 -6 -10 ) ) +( ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ) +( ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ) +) + } + } +} +// entity 25 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -384 320 448 0 0 ) ( -448 320 448 0 0.500000 ) ( -512 320 448 0 1 ) ) +( ( -384 320 896 3.500000 0 ) ( -448 320 896 3.500000 0.500000 ) ( -512 320 896 3.500000 1 ) ) +( ( -384 0 896 6 0 ) ( -448 0 896 6 0.500000 ) ( -512 0 896 6 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -384 320 448 5 -14 ) ( -384 320 896 5 -28 ) ( -384 0 896 0 -28 ) ) +( ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ) +( ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -512 0 896 0 -14 ) ( -512 320 896 5 -14 ) ( -512 320 448 5 -7 ) ) +( ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ) +( ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ) +) + } + } +} +// entity 26 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 512 320 448 8 -7 ) ( 512 320 896 8 -14 ) ( 512 0 896 8 -14 ) ) +( ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ) +( ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 384 0 896 0 -28 ) ( 384 320 896 5 -28 ) ( 384 320 448 5 -14 ) ) +( ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ) +( ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ) +) + } + } +} +// entity 27 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 384 -320 448 -5 -14 ) ( 384 -320 896 -5 -28 ) ( 384 0 896 0 -28 ) ) +( ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ) +( ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 512 0 896 0 -14 ) ( 512 -320 896 -5 -14 ) ( 512 -320 448 -5 -7 ) ) +( ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ) +( ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ) +) + } + } +} diff --git a/docs/developer/TstMaps/ttq3dm3.map b/docs/developer/TstMaps/ttq3dm3.map new file mode 100644 index 00000000..e17645bf --- /dev/null +++ b/docs/developer/TstMaps/ttq3dm3.map @@ -0,0 +1,1099 @@ +{ +"spawnflags" "0" +"classname" "worldspawn" +// brush 0 +{ +brushDef +{ +( 1176 -448 0 ) ( 1160 -448 0 ) ( 1160 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1160 -472 64 ) ( 1160 -448 64 ) ( 1176 -448 64 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1160 -472 64 ) ( 1176 -472 64 ) ( 1176 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1176 -472 64 ) ( 1176 -448 64 ) ( 1176 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1176 -448 64 ) ( 1160 -448 64 ) ( 1160 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1152 -448 64 ) ( 1152 -472 64 ) ( 1152 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +} +} +// brush 1 +{ +brushDef +{ +( 448 -768 8 ) ( 448 -640 8 ) ( 448 -640 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 8 ) ( 424 -640 8 ) ( 424 -640 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 416 -640 192 ) ( 416 -704 384 ) ( 448 -672 288 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 386 -448 192 ) ( 322 -192 192 ) ( 354 -320 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 432 -712 384 ) ( 432 -640 320 ) ( 448 -676 352 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 2 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4280 4944 -952 ) ( -248 4944 -952 ) ( -4280 952 -952 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 3 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 4944 1080 ) ( -4344 952 1080 ) ( -312 4944 1080 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 4 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2440 -1720 -768 ) ( -1592 -1720 -768 ) ( 2440 -1720 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 5 +{ +brushDef +{ +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2424 2256 -768 ) ( 2424 -1736 -768 ) ( 2424 2256 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 6 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4328 3128 -768 ) ( -296 3128 -768 ) ( -4328 3128 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 7 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -2424 792 -768 ) ( -2424 4784 -768 ) ( -2424 792 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 8 +{ +brushDef +{ +( 1176 -448 -256 ) ( 1152 -448 -256 ) ( 1152 -472 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -472 0 ) ( 1152 -448 0 ) ( 1176 -448 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -472 0 ) ( 1176 -472 0 ) ( 1176 -472 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1176 -472 0 ) ( 1176 -448 0 ) ( 1176 -448 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1176 -448 0 ) ( 1152 -448 0 ) ( 1152 -448 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -448 0 ) ( 1152 -472 0 ) ( 1152 -472 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 9 +{ +brushDef +{ +( 1720 -448 -448 ) ( 1168 -448 -448 ) ( 1168 -472 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1176 -472 0 ) ( 1176 -448 0 ) ( 1728 -448 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1176 -472 0 ) ( 1728 -472 0 ) ( 1728 -472 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 -472 0 ) ( 1728 -448 0 ) ( 1728 -448 -776 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1728 -448 0 ) ( 1176 -448 0 ) ( 1176 -448 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1176 -448 0 ) ( 1176 -472 0 ) ( 1176 -472 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 10 +{ +brushDef +{ +( 448 248 -8 ) ( 448 248 0 ) ( 448 -1024 0 ) ( ( 0.031250 0 -50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -1024 0 ) ( 448 248 0 ) ( 1736 248 0 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 25 ) ) base_floor/concrete 134217728 0 0 +( 1736 248 -256 ) ( 448 248 -256 ) ( 448 -1024 -256 ) ( ( 0 0.031250 22 ) ( -0.031250 0 -50 ) ) common/caulk 134217728 0 0 +( 800 -448 0 ) ( 448 -448 -776 ) ( 1152 -448 -776 ) ( ( 0.031250 0 -29.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -472 520 ) ( 1152 -472 -256 ) ( 448 -472 -256 ) ( ( 0.031250 0 29.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -460 0 ) ( 576 -448 -776 ) ( 576 -472 -776 ) ( ( 0.031250 0 50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +} +} +// brush 11 +{ +brushDef +{ +( 800 -472 520 ) ( 1152 -472 -256 ) ( 448 -472 -256 ) ( ( 0.031250 0 29.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -448 0 ) ( 448 -448 -776 ) ( 1152 -448 -776 ) ( ( 0.015625 0 -14.750001 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -388 0 ) ( 1152 256 -776 ) ( 1152 -1032 -776 ) ( ( 0.031250 0 50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1736 248 -256 ) ( 448 248 -256 ) ( 448 -1024 -256 ) ( ( 0 0.031250 22 ) ( -0.031250 0 -50 ) ) common/caulk 134217728 0 0 +( 640 -460 0 ) ( 640 -472 -776 ) ( 640 -448 -776 ) ( ( 0.031250 0 -50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 640 -460 -12 ) ( 1152 -448 -24 ) ( 1152 -472 0 ) ( ( 0.015625 0 -14.750001 ) ( 0 0.015625 -16.086678 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 12 +{ +brushDef +{ +( 576 -460 0 ) ( 576 -472 -776 ) ( 576 -448 -776 ) ( ( 0.031250 0 -50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -472 520 ) ( 1152 -472 -256 ) ( 448 -472 -256 ) ( ( 0.031250 0 29.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -448 0 ) ( 448 -448 -776 ) ( 1152 -448 -776 ) ( ( 0.015625 0 -14.750001 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1736 248 -256 ) ( 448 248 -256 ) ( 448 -1024 -256 ) ( ( 0 0.031250 22 ) ( -0.031250 0 -50 ) ) common/caulk 134217728 0 0 +( 448 -1024 0 ) ( 448 248 0 ) ( 1736 248 0 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 25 ) ) base_floor/concrete 134217728 0 0 +( 640 -460 0 ) ( 640 -448 -776 ) ( 640 -472 -776 ) ( ( 0.031250 0 50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -448 0 ) ( 640 -448 -24 ) ( 640 -472 0 ) ( ( 0.015625 0 -5.032391 ) ( -0.000002 0.015625 -17.199825 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 13 +{ +brushDef +{ +( 1152 128 -776 ) ( 1176 128 -776 ) ( 1164 128 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 256 -256 ) ( 1176 -448 -256 ) ( 1176 -96 520 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 -448 -776 ) ( 1152 256 -776 ) ( 1152 -96 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1728 256 -256 ) ( 456 256 -256 ) ( 456 -1032 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1176 64 -776 ) ( 1152 64 -776 ) ( 1164 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 64 0 ) ( 1152 64 -24 ) ( 1152 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 14 +{ +brushDef +{ +( 1176 256 -256 ) ( 1176 -448 -256 ) ( 1176 -96 520 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 -448 -776 ) ( 1152 256 -776 ) ( 1152 -96 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1736 -448 -776 ) ( 448 -448 -776 ) ( 1092 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1728 256 -256 ) ( 456 256 -256 ) ( 456 -1032 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 64 -776 ) ( 1176 64 -776 ) ( 1164 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 -448 0 ) ( 1152 -448 -24 ) ( 1164 64 -12 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 15 +{ +brushDef +{ +( 1728 256 0 ) ( 456 256 0 ) ( 456 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1728 256 -256 ) ( 456 256 -256 ) ( 456 -1032 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 -448 -776 ) ( 1152 256 -776 ) ( 1152 -96 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 256 -256 ) ( 1176 -448 -256 ) ( 1176 -96 520 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 128 -776 ) ( 1152 128 -776 ) ( 1164 128 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +} +} +// brush 16 +{ +brushDef +{ +( 1728 256 0 ) ( 456 256 0 ) ( 456 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 -1032 0 ) ( 1728 256 0 ) ( 1728 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1720 256 -448 ) ( 448 256 -448 ) ( 448 -1032 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1736 -448 -776 ) ( 448 -448 -776 ) ( 1092 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1176 -448 -776 ) ( 1176 256 -776 ) ( 1176 -96 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 17 +{ +brushDef +{ +( 448 256 0 ) ( 448 -1032 0 ) ( 448 -1032 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 256 0 ) ( 456 256 0 ) ( 456 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 456 -1032 -256 ) ( 456 256 -256 ) ( 1728 256 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1712 256 -448 ) ( 440 256 -448 ) ( 440 -1032 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1736 -472 -776 ) ( 448 -472 -776 ) ( 1092 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1176 248 -776 ) ( 1176 -456 -776 ) ( 1176 -104 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 18 +{ +brushDef +{ +( 448 256 328 ) ( 448 -1032 328 ) ( 448 -1032 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 -1032 0 ) ( 1728 256 0 ) ( 1728 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 456 -1024 0 ) ( 1728 -1024 0 ) ( 1728 -1024 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1728 256 -448 ) ( 456 256 -448 ) ( 456 -1032 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -472 -776 ) ( 1736 -472 -776 ) ( 1092 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 19 +{ +brushDef +{ +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -832 192 ) ( 1544 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -832 320 ) ( 1280 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -640 192 ) ( 1280 -640 192 ) ( 1408 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 -576 192 ) ( 1344 -648 192 ) ( 1344 -612 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 20 +{ +brushDef +{ +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 192 ) ( 1544 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -832 320 ) ( 1280 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -640 192 ) ( 1280 -640 192 ) ( 1408 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 -648 192 ) ( 1344 -576 192 ) ( 1344 -612 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 21 +{ +brushDef +{ +( 1280 256 320 ) ( 1344 256 320 ) ( 1344 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 32 ) ) common/caulk 134217728 0 0 +( 1280 256 264 ) ( 1280 -576 264 ) ( 1280 -576 256 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 -576 264 ) ( 1344 256 264 ) ( 1344 256 256 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 264 ) ( 1280 256 264 ) ( 1280 256 256 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 128 192 ) ( 1280 128 312 ) ( 1344 128 252 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 256 192 ) ( 1280 128 240 ) ( 1344 192 216 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031254 -33.244408 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 22 +{ +brushDef +{ +( 1280 256 320 ) ( 1344 256 320 ) ( 1344 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 32 ) ) common/caulk 134217728 0 0 +( 1280 256 264 ) ( 1280 -576 264 ) ( 1280 -576 256 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 -576 264 ) ( 1344 256 264 ) ( 1344 256 256 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 0 192 ) ( 1280 0 320 ) ( 1344 0 256 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 128 312 ) ( 1280 128 192 ) ( 1344 128 252 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 128 240 ) ( 1280 0 264 ) ( 1344 64 252 ) ( ( 0.031250 0 5.500037 ) ( 0 0.031250 -34.891960 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 23 +{ +brushDef +{ +( 1280 256 320 ) ( 1344 256 320 ) ( 1344 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 32 ) ) common/caulk 134217728 0 0 +( 1280 256 264 ) ( 1280 -576 264 ) ( 1280 -576 256 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 -576 264 ) ( 1344 256 264 ) ( 1344 256 256 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -160 192 ) ( 1280 -160 320 ) ( 1344 -160 256 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 0 320 ) ( 1280 0 192 ) ( 1344 0 256 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 0 264 ) ( 1280 -160 272 ) ( 1344 -80 268 ) ( ( 0.031250 0 5.499999 ) ( 0 0.031246 -35.450680 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 24 +{ +brushDef +{ +( 1344 -240 268 ) ( 1280 -160 272 ) ( 1280 -320 264 ) ( ( 0.031250 0 -5.500003 ) ( 0 0.031250 35.455704 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1344 -320 256 ) ( 1280 -320 192 ) ( 1280 -320 320 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -160 256 ) ( 1280 -160 320 ) ( 1280 -160 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -576 256 ) ( 1344 -576 264 ) ( 1344 256 264 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 256 256 ) ( 1280 256 264 ) ( 1280 -576 264 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 320 ) ( 1344 -576 320 ) ( 1280 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 23.750000 ) ) common/caulk 134217728 0 0 +} +} +// brush 25 +{ +brushDef +{ +( 1344 -384 252 ) ( 1280 -320 264 ) ( 1280 -448 240 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031246 34.887020 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1344 -448 252 ) ( 1280 -448 192 ) ( 1280 -448 312 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -320 256 ) ( 1280 -320 320 ) ( 1280 -320 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -576 256 ) ( 1344 -576 264 ) ( 1344 256 264 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 256 256 ) ( 1280 256 264 ) ( 1280 -576 264 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 320 ) ( 1344 -576 320 ) ( 1280 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 23.750000 ) ) common/caulk 134217728 0 0 +} +} +// brush 26 +{ +brushDef +{ +( 1344 -512 216 ) ( 1280 -448 240 ) ( 1280 -576 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031254 33.244404 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1344 -448 252 ) ( 1280 -448 312 ) ( 1280 -448 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 1344 -576 264 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -576 256 ) ( 1344 -576 264 ) ( 1344 256 264 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 256 256 ) ( 1280 256 264 ) ( 1280 -576 264 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 320 ) ( 1344 -576 320 ) ( 1280 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 23.750000 ) ) common/caulk 134217728 0 0 +} +} +// brush 27 +{ +brushDef +{ +( 128 -80 0 ) ( 128 64 0 ) ( 64 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -640 192 ) ( 192 -640 192 ) ( 96 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 0 ) ( 192 -128 0 ) ( 128 -96 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 384 -440 0 ) ( 320 -184 0 ) ( 352 -312 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 322 -576 0 ) ( 322 -640 192 ) ( 448 -608 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 28 +{ +brushDef +{ +( 1216 -576 216 ) ( 1152 -640 240 ) ( 1280 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1152 -576 252 ) ( 1152 -640 312 ) ( 1152 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -640 256 ) ( 1280 -640 264 ) ( 1280 -576 264 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 448 -576 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 256 ) ( 448 -640 264 ) ( 1280 -640 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 320 ) ( 1280 -576 320 ) ( 1280 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -8.250000 ) ) common/caulk 134217728 0 0 +} +} +// brush 29 +{ +brushDef +{ +( 1088 -576 252 ) ( 1024 -640 264 ) ( 1152 -640 240 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1152 -576 252 ) ( 1152 -640 192 ) ( 1152 -640 312 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1024 -576 256 ) ( 1024 -640 320 ) ( 1024 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 448 -576 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 256 ) ( 448 -640 264 ) ( 1280 -640 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 320 ) ( 1280 -576 320 ) ( 1280 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -8.250000 ) ) common/caulk 134217728 0 0 +} +} +// brush 30 +{ +brushDef +{ +( 944 -576 268 ) ( 864 -640 272 ) ( 1024 -640 264 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1024 -576 256 ) ( 1024 -640 192 ) ( 1024 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 864 -576 256 ) ( 864 -640 320 ) ( 864 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 448 -576 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 256 ) ( 448 -640 264 ) ( 1280 -640 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 320 ) ( 1280 -576 320 ) ( 1280 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -8.250000 ) ) common/caulk 134217728 0 0 +} +} +// brush 31 +{ +brushDef +{ +( 448 -640 320 ) ( 448 -576 320 ) ( 1280 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 264 ) ( 1280 -640 264 ) ( 1280 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -576 264 ) ( 448 -576 264 ) ( 448 -576 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 864 -640 192 ) ( 864 -640 320 ) ( 864 -576 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 704 -640 320 ) ( 704 -640 192 ) ( 704 -576 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 704 -640 264 ) ( 864 -640 272 ) ( 784 -576 268 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 32 +{ +brushDef +{ +( 448 -640 320 ) ( 448 -576 320 ) ( 1280 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 264 ) ( 1280 -640 264 ) ( 1280 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -576 264 ) ( 448 -576 264 ) ( 448 -576 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 704 -640 192 ) ( 704 -640 320 ) ( 704 -576 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -640 312 ) ( 576 -640 192 ) ( 576 -576 252 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -640 240 ) ( 704 -640 264 ) ( 640 -576 252 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 33 +{ +brushDef +{ +( 448 -640 320 ) ( 448 -576 320 ) ( 1280 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 264 ) ( 1280 -640 264 ) ( 1280 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -576 264 ) ( 448 -576 264 ) ( 448 -576 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 264 ) ( 448 -640 264 ) ( 448 -640 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -640 192 ) ( 576 -640 312 ) ( 576 -576 252 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 192 ) ( 576 -640 240 ) ( 512 -576 216 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 34 +{ +brushDef +{ +( 448 -640 0 ) ( 128 -640 0 ) ( 128 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 146 -512 256 ) ( 192 -640 0 ) ( 100 -384 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -640 192 ) ( 448 -640 192 ) ( 256 256 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -576 400 ) ( 64 -576 192 ) ( 448 -576 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 169 -640 320 ) ( 169 -576 320 ) ( 448 -608 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 35 +{ +brushDef +{ +( 48 64 704 ) ( 112 64 704 ) ( 112 -80 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 0 ) ( 128 -640 0 ) ( 128 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 146 -512 256 ) ( 192 -640 0 ) ( 100 -384 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -576 400 ) ( 64 -576 192 ) ( 448 -576 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 169 -576 320 ) ( 169 -640 320 ) ( 448 -608 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 36 +{ +brushDef +{ +( 48 64 704 ) ( 112 64 704 ) ( 112 -80 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 64 -8 ) ( 64 64 8 ) ( 64 -80 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 128 256 -8 ) ( 128 256 8 ) ( 64 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 256 ) ( 128 -640 256 ) ( 128 -640 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 146 -512 256 ) ( 192 -640 0 ) ( 100 -384 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -640 192 ) ( 448 -640 192 ) ( 256 256 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -576 192 ) ( 64 -576 400 ) ( 448 -576 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 37 +{ +brushDef +{ +( 448 -832 704 ) ( 1536 -832 704 ) ( 1536 -832 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 192 ) ( 1544 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -832 320 ) ( 1280 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -640 192 ) ( 1536 -640 192 ) ( 1408 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 38 +{ +brushDef +{ +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 1536 -832 704 ) ( 1536 -832 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 320 ) ( 1536 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 39 +{ +brushDef +{ +( 1536 256 0 ) ( 448 256 0 ) ( 448 -832 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 1536 -832 704 ) ( 1536 -832 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1544 -832 192 ) ( 1280 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 40 +{ +brushDef +{ +( 448 256 704 ) ( 448 -832 704 ) ( 448 -832 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 256 704 ) ( 448 256 704 ) ( 448 256 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 256 -256 ) ( 448 256 -256 ) ( 448 -832 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 256 0 ) ( 448 -576 0 ) ( 864 -160 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 41 +{ +brushDef +{ +( 1288 -576 0 ) ( 448 -576 0 ) ( 868 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -520 0 ) ( 1280 -832 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1528 256 320 ) ( 440 256 320 ) ( 440 -832 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 0 0 0 +( 448 -576 0 ) ( 1280 256 0 ) ( 864 -160 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 42 +{ +brushDef +{ +( 1528 256 320 ) ( 440 256 320 ) ( 440 -832 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 704 ) ( 1536 -640 704 ) ( 1536 -640 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 256 704 ) ( 448 -832 704 ) ( 448 -832 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -520 0 ) ( 1280 -832 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -576 0 ) ( 1288 -576 0 ) ( 868 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 43 +{ +brushDef +{ +( 1560 256 320 ) ( 472 256 320 ) ( 472 -832 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 -840 704 ) ( 1344 248 704 ) ( 1344 248 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 256 704 ) ( 448 256 704 ) ( 448 256 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -576 0 ) ( 1280 -576 0 ) ( 1408 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 44 +{ +brushDef +{ +( 440 768 0 ) ( -64 768 0 ) ( -64 264 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -56 264 192 ) ( -56 768 192 ) ( 448 768 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -72 256 400 ) ( 432 256 400 ) ( 432 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 280 400 ) ( -64 784 400 ) ( -64 784 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -72 760 400 ) ( -72 256 400 ) ( -72 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -72 576 0 ) ( -64 576 0 ) ( -68 576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 45 +{ +brushDef +{ +( 440 768 0 ) ( -64 768 0 ) ( -64 264 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -56 264 192 ) ( -56 768 192 ) ( 448 768 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 280 400 ) ( -64 784 400 ) ( -64 784 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 440 768 400 ) ( -64 768 400 ) ( -64 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -72 760 400 ) ( -72 256 400 ) ( -72 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 576 0 ) ( -72 576 0 ) ( -68 576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 46 +{ +brushDef +{ +( 448 776 0 ) ( -56 776 0 ) ( -56 272 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -48 272 192 ) ( -48 776 192 ) ( 456 776 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 256 768 400 ) ( 760 768 400 ) ( 760 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 776 400 ) ( -56 776 400 ) ( -56 776 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 768 400 ) ( -64 264 400 ) ( -64 264 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 128 776 0 ) ( 128 768 0 ) ( 128 772 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 47 +{ +brushDef +{ +( 448 776 0 ) ( -56 776 0 ) ( -56 272 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -48 272 192 ) ( -48 776 192 ) ( 456 776 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 256 768 400 ) ( 760 768 400 ) ( 760 768 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 792 400 ) ( 448 1296 400 ) ( 448 1296 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 776 400 ) ( -56 776 400 ) ( -56 776 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 128 768 0 ) ( 128 776 0 ) ( 128 772 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 48 + { + patchDef2 + { + base_floor/concrete + ( 3 3 0 0 0 ) +( +( ( -64 576 0 0 0 ) ( -64 576 96 0 1.500000 ) ( -64 576 192 0 3 ) ) +( ( -64 768 0 3 0 ) ( -64 768 96 3 1.500000 ) ( -64 768 192 3 3 ) ) +( ( 128 768 0 6 0 ) ( 128 768 96 6 1.500000 ) ( 128 768 192 6 3 ) ) +) + } + } +// brush 49 + { + patchDef2 + { + base_floor/concrete + ( 3 3 0 0 0 ) +( +( ( 64 448 192 0 0 ) ( 64 448 96 0 1.500000 ) ( 64 448 0 0 3 ) ) +( ( 64 640 192 3 0 ) ( 64 640 96 3 1.500000 ) ( 64 640 0 3 3 ) ) +( ( 256 640 192 6 0 ) ( 256 640 96 6 1.500000 ) ( 256 640 0 6 3 ) ) +) + } + } +// brush 50 +{ +brushDef +{ +( 264 632 0 ) ( 72 632 0 ) ( 72 440 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 440 192 ) ( 72 632 192 ) ( 264 632 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 440 192 ) ( 264 440 192 ) ( 264 440 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 264 440 192 ) ( 264 632 192 ) ( 264 632 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 264 632 192 ) ( 72 632 192 ) ( 72 632 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 632 192 ) ( 72 440 192 ) ( 72 440 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 448 0 ) ( 256 632 0 ) ( 164 540 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 51 +{ +brushDef +{ +( 72 248 0 ) ( 72 752 0 ) ( -432 752 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -432 744 192 ) ( 72 744 192 ) ( 72 240 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 480 400 ) ( 64 -24 400 ) ( 64 -24 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 88 256 400 ) ( 592 256 400 ) ( 592 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 248 400 ) ( 72 752 400 ) ( 72 752 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 448 400 ) ( -440 448 400 ) ( -440 448 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 52 +{ +brushDef +{ +( 456 640 0 ) ( -48 640 0 ) ( -48 136 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -40 136 192 ) ( -40 640 192 ) ( 464 640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 264 632 400 ) ( 768 632 400 ) ( 768 632 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 656 400 ) ( 448 1160 400 ) ( 448 1160 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 456 640 400 ) ( -48 640 400 ) ( -48 640 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 256 632 400 ) ( 256 128 400 ) ( 256 128 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 53 +{ +brushDef +{ +( 448 768 192 ) ( -56 768 192 ) ( -56 264 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -48 264 200 ) ( -48 768 200 ) ( 456 768 200 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 256 400 ) ( 440 256 400 ) ( 440 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 264 400 ) ( 448 768 400 ) ( 448 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 768 400 ) ( -56 768 400 ) ( -56 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 760 400 ) ( -64 256 400 ) ( -64 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 54 +{ +brushDef +{ +( 448 768 -8 ) ( -56 768 -8 ) ( -56 264 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -48 264 0 ) ( -48 768 0 ) ( 456 768 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 256 200 ) ( 440 256 200 ) ( 440 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 264 200 ) ( 448 768 200 ) ( 448 768 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 768 200 ) ( -56 768 200 ) ( -56 768 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 760 200 ) ( -64 256 200 ) ( -64 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 55 +{ +brushDef +{ +( 640 960 -8 ) ( 640 872 -8 ) ( 760 872 -8 ) ( ( 0 0.031250 17.750000 ) ( -0.031250 0 32 ) ) common/caulk 0 0 0 +( 760 872 0 ) ( 640 872 0 ) ( 640 960 0 ) ( ( 0 -0.007813 5.503094 ) ( 0.007813 0 -5.500553 ) ) base_floor/concrete 0 0 0 +( 1728 632 0 ) ( 1728 720 0 ) ( 1728 720 -8 ) ( ( 0.031250 0 7 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +( 760 1152 0 ) ( 640 1152 0 ) ( 640 1152 -8 ) ( ( 0.031250 0 168.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +( 448 960 0 ) ( 448 872 0 ) ( 448 872 -8 ) ( ( 0.007813 0 -4.249445 ) ( 0 0.007813 0 ) ) base_floor/concrete 0 0 0 +( 896 256 0 ) ( 1016 256 0 ) ( 1016 256 -8 ) ( ( 0.031250 0 -168.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +} +} +// brush 56 +{ +brushDef +{ +( 448 768 192 ) ( 448 640 192 ) ( 768 640 192 ) ( ( 0 0.015625 11 ) ( -0.015625 0 11 ) ) base_floor/concrete 0 0 0 +( 768 632 704 ) ( 448 632 704 ) ( 448 760 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 768 640 832 ) ( 768 768 832 ) ( 768 768 256 ) ( ( 0.031250 0 17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 768 832 ) ( 448 768 832 ) ( 448 768 256 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 768 832 ) ( 448 640 832 ) ( 448 640 256 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 640 832 ) ( 768 640 832 ) ( 768 640 256 ) ( ( 0.031250 0 -172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 57 +{ +brushDef +{ +( 1088 624 704 ) ( 768 624 704 ) ( 768 752 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 1088 640 328 ) ( 1088 768 328 ) ( 1088 768 192 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 768 768 328 ) ( 768 640 328 ) ( 768 640 192 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1088 604 192 ) ( 768 640 192 ) ( 928 622 704 ) ( ( 0.031250 0 -173.292160 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 768 192 ) ( 1088 804 192 ) ( 928 786 704 ) ( ( 0.031250 0 169.518250 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 604 296 ) ( 1088 604 296 ) ( 928 804 296 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +} +} +// brush 58 +{ +brushDef +{ +( 768 768 328 ) ( 768 640 328 ) ( 768 640 192 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1088 604 192 ) ( 768 640 192 ) ( 928 622 704 ) ( ( 0.031250 0 -173.292160 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 768 192 ) ( 1088 804 192 ) ( 928 786 704 ) ( ( 0.031250 0 169.518250 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 604 192 ) ( 1088 604 296 ) ( 928 804 244 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 82.021614 ) ) base_floor/concrete 134217728 0 0 +( 1088 604 296 ) ( 768 604 296 ) ( 928 804 296 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 134217728 0 0 +( 832 604 260 ) ( 976 604 260 ) ( 904 804 260 ) ( ( 0 0.015625 11 ) ( -0.015625 0 11 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 59 +{ +brushDef +{ +( 768 768 328 ) ( 768 640 328 ) ( 768 640 192 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1088 604 192 ) ( 768 640 192 ) ( 928 622 704 ) ( ( 0.031250 0 -173.292160 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 768 192 ) ( 1088 804 192 ) ( 928 786 704 ) ( ( 0.031250 0 169.518250 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 604 192 ) ( 1088 604 296 ) ( 928 804 244 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 82.021614 ) ) base_floor/concrete 134217728 0 0 +( 976 604 260 ) ( 832 604 260 ) ( 904 804 260 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 134217728 0 0 +( 868 616 224 ) ( 868 616 260 ) ( 868 792 242 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 60 +{ +brushDef +{ +( 440 1152 704 ) ( 440 264 704 ) ( 1720 264 704 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 1720 264 832 ) ( 440 264 832 ) ( 440 1152 832 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 448 248 832 ) ( 448 1136 832 ) ( 448 1136 704 ) ( ( 0.031250 0 17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1720 1152 832 ) ( 440 1152 832 ) ( 440 1152 704 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 440 1152 832 ) ( 440 264 832 ) ( 440 264 704 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 440 256 832 ) ( 1720 256 832 ) ( 1720 256 704 ) ( ( 0.031250 0 -172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 61 +{ +brushDef +{ +( 640 752 704 ) ( 640 816 704 ) ( 784 816 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 1344 1152 0 ) ( 1344 832 0 ) ( 1344 832 256 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 640 768 -8 ) ( 640 768 8 ) ( 784 768 8 ) ( ( 0.015625 0 -86.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 832 -8 ) ( 448 832 8 ) ( 448 768 8 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 768 256 ) ( 1344 832 256 ) ( 1344 832 0 ) ( ( 0.015625 0 -84.783813 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1216 850 256 ) ( 1344 896 0 ) ( 1088 804 0 ) ( ( 0.015625 0 -78.292961 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1344 768 192 ) ( 1344 1152 192 ) ( 448 960 192 ) ( ( 0 0.015625 11 ) ( -0.015625 0 11 ) ) base_floor/concrete 0 0 0 +} +} +// brush 62 +{ +brushDef +{ +( 784 832 0 ) ( 640 832 0 ) ( 640 768 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 640 768 -8 ) ( 640 768 8 ) ( 784 768 8 ) ( ( 0.015625 0 -86.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 832 -8 ) ( 448 832 8 ) ( 448 768 8 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 1152 192 ) ( 1344 896 192 ) ( 1088 800 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -11 ) ) base_floor/concrete 0 0 0 +( 768 768 0 ) ( 768 768 192 ) ( 768 1152 96 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 63 +{ +brushDef +{ +( 784 832 0 ) ( 640 832 0 ) ( 640 768 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 1152 192 ) ( 1344 896 192 ) ( 1088 800 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -11 ) ) base_floor/concrete 0 0 0 +( 768 768 192 ) ( 768 768 0 ) ( 768 1152 96 ) ( ( 0.015625 0 -8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 832 896 0 ) ( 768 768 0 ) ( 800 832 192 ) ( ( 0.015625 0 -30.969723 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 64 +{ +brushDef +{ +( 784 832 0 ) ( 640 832 0 ) ( 640 768 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 1344 896 272 ) ( 1344 1152 272 ) ( 1344 1152 0 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 1152 192 ) ( 1344 896 192 ) ( 1088 800 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -11 ) ) base_floor/concrete 0 0 0 +( 768 768 0 ) ( 832 896 0 ) ( 800 832 192 ) ( ( 0.015625 0 30.969532 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1144 1088 0 ) ( 888 1024 0 ) ( 1016 1056 192 ) ( ( 0.015625 0 -81.613266 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 65 +{ +brushDef +{ +( 640 640 0 ) ( 640 576 0 ) ( 784 576 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 6.500000 ) ) common/caulk 0 0 0 +( 1344 256 0 ) ( 1344 256 272 ) ( 1344 512 272 ) ( ( 0.015625 0 16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1088 608 192 ) ( 1344 512 192 ) ( 1344 256 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -3.250000 ) ) base_floor/concrete 0 0 0 +( 800 576 192 ) ( 832 512 0 ) ( 768 640 0 ) ( ( 0.015625 0 -52.435787 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1016 352 192 ) ( 888 384 0 ) ( 1144 320 0 ) ( ( 0.015625 0 86.160866 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 66 +{ +brushDef +{ +( 640 640 0 ) ( 640 576 0 ) ( 784 576 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 6.500000 ) ) common/caulk 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1088 608 192 ) ( 1344 512 192 ) ( 1344 256 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -3.250000 ) ) base_floor/concrete 0 0 0 +( 768 256 96 ) ( 768 640 0 ) ( 768 640 192 ) ( ( 0.015625 0 -16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 800 576 192 ) ( 768 640 0 ) ( 832 512 0 ) ( ( 0.015625 0 52.435787 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 67 +{ +brushDef +{ +( 640 640 0 ) ( 640 576 0 ) ( 784 576 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 6.500000 ) ) common/caulk 0 0 0 +( 784 640 8 ) ( 640 640 8 ) ( 640 640 -8 ) ( ( 0.015625 0 84.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 640 8 ) ( 448 576 8 ) ( 448 576 -8 ) ( ( 0.031250 0 -32.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1088 608 192 ) ( 1344 512 192 ) ( 1344 256 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -3.250000 ) ) base_floor/concrete 0 0 0 +( 768 256 96 ) ( 768 640 192 ) ( 768 640 0 ) ( ( 0.015625 0 16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 68 +{ +brushDef +{ +( 784 592 704 ) ( 640 592 704 ) ( 640 656 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -6.500000 ) ) common/caulk 0 0 0 +( 1344 576 256 ) ( 1344 576 0 ) ( 1344 256 0 ) ( ( 0.015625 0 16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 784 640 8 ) ( 640 640 8 ) ( 640 640 -8 ) ( ( 0.015625 0 84.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 640 8 ) ( 448 576 8 ) ( 448 576 -8 ) ( ( 0.031250 0 -32.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1344 576 0 ) ( 1344 576 256 ) ( 768 640 256 ) ( ( 0.015625 0 86.026184 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1088 604 0 ) ( 1344 512 0 ) ( 1216 558 256 ) ( ( 0.015625 0 85.251816 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 448 192 ) ( 1344 256 192 ) ( 1344 640 192 ) ( ( 0 0.015625 11 ) ( -0.015625 0 3.250000 ) ) base_floor/concrete 0 0 0 +} +} +// brush 69 +{ +brushDef +{ +( -112 -80 704 ) ( -112 64 704 ) ( -48 64 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 15.500000 ) ) common/caulk 0 0 0 +( -128 -640 256 ) ( -128 -640 0 ) ( -448 -640 0 ) ( ( 0.015625 0 7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 -80 8 ) ( -64 64 8 ) ( -64 64 -8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 256 8 ) ( -128 256 8 ) ( -128 256 -8 ) ( ( 0.031250 0 -15.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -128 -640 0 ) ( -128 -640 256 ) ( -64 -64 256 ) ( ( 0.015625 0 -0.634981 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -100 -384 0 ) ( -192 -640 0 ) ( -146 -512 256 ) ( ( 0.015625 0 1.209426 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -256 256 192 ) ( -448 -640 192 ) ( -64 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.750000 ) ) base_floor/concrete 0 0 0 +} +} +// brush 70 +{ +brushDef +{ +( -64 64 0 ) ( -128 64 0 ) ( -128 -80 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -15.500000 ) ) common/caulk 0 0 0 +( -64 -80 8 ) ( -64 64 8 ) ( -64 64 -8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 256 8 ) ( -128 256 8 ) ( -128 256 -8 ) ( ( 0.031250 0 -15.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -96 -384 192 ) ( -192 -640 192 ) ( -448 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.750000 ) ) base_floor/concrete 0 0 0 +( -448 -64 96 ) ( -64 -64 192 ) ( -64 -64 0 ) ( ( 0.015625 0 7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 71 +{ +brushDef +{ +( -64 64 0 ) ( -128 64 0 ) ( -128 -80 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -15.500000 ) ) common/caulk 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -96 -384 192 ) ( -192 -640 192 ) ( -448 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.750000 ) ) base_floor/concrete 0 0 0 +( -448 -64 96 ) ( -64 -64 0 ) ( -64 -64 192 ) ( ( 0.015625 0 -7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -128 -96 192 ) ( -64 -64 0 ) ( -192 -128 0 ) ( ( 0.015625 0 6.260992 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 72 +{ +brushDef +{ +( -64 64 0 ) ( -128 64 0 ) ( -128 -80 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -15.500000 ) ) common/caulk 0 0 0 +( -448 -640 0 ) ( -448 -640 272 ) ( -192 -640 272 ) ( ( 0.015625 0 7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -96 -384 192 ) ( -192 -640 192 ) ( -448 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.750000 ) ) base_floor/concrete 0 0 0 +( -128 -96 192 ) ( -192 -128 0 ) ( -64 -64 0 ) ( ( 0.015625 0 -6.260992 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -352 -312 192 ) ( -320 -184 0 ) ( -384 -440 0 ) ( ( 0.015625 0 0.424437 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 73 +{ +brushDef +{ +( 128 -80 0 ) ( 128 64 0 ) ( 64 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 192 ) ( 192 -640 192 ) ( 96 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 192 ) ( 64 -64 0 ) ( 448 -64 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 192 -128 0 ) ( 64 -64 0 ) ( 128 -96 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 74 +{ +brushDef +{ +( 128 -80 0 ) ( 128 64 0 ) ( 64 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 64 -8 ) ( 64 64 8 ) ( 64 -80 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 128 256 -8 ) ( 128 256 8 ) ( 64 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 192 ) ( 192 -640 192 ) ( 96 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 0 ) ( 64 -64 192 ) ( 448 -64 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 75 +{ +brushDef +{ +( 448 264 704 ) ( -440 264 704 ) ( -440 -1016 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -440 -1016 832 ) ( -440 264 832 ) ( 448 264 832 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -456 256 832 ) ( 432 256 832 ) ( 432 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -1016 832 ) ( 448 264 832 ) ( 448 264 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 264 832 ) ( -440 264 832 ) ( -440 264 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -448 264 832 ) ( -448 -1016 832 ) ( -448 -1016 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 76 +{ +brushDef +{ +( 64 -64 328 ) ( -64 -64 328 ) ( -64 -64 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -384 192 ) ( -64 -64 192 ) ( -82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 64 -64 192 ) ( 100 -384 192 ) ( 82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -64 192 ) ( -100 -384 296 ) ( 100 -224 244 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( -100 -272 260 ) ( -100 -128 260 ) ( 100 -200 260 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -88 -164 224 ) ( -88 -164 260 ) ( 88 -164 242 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 77 +{ +brushDef +{ +( 64 -64 328 ) ( -64 -64 328 ) ( -64 -64 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -384 192 ) ( -64 -64 192 ) ( -82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 64 -64 192 ) ( 100 -384 192 ) ( 82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -64 192 ) ( -100 -384 296 ) ( 100 -224 244 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( -100 -384 296 ) ( -100 -64 296 ) ( 100 -224 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -128 260 ) ( -100 -272 260 ) ( 100 -200 260 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 78 +{ +brushDef +{ +( -80 -384 704 ) ( -80 -64 704 ) ( 48 -64 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 -384 328 ) ( 64 -384 328 ) ( 64 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 328 ) ( -64 -64 328 ) ( -64 -64 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -100 -384 192 ) ( -64 -64 192 ) ( -82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 -64 192 ) ( 100 -384 192 ) ( 82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -100 -64 296 ) ( -100 -384 296 ) ( 100 -224 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 79 +{ +brushDef +{ +( 64 256 192 ) ( -64 256 192 ) ( -64 -64 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -72 -64 704 ) ( -72 256 704 ) ( 56 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 -64 832 ) ( 64 -64 832 ) ( 64 -64 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 -64 832 ) ( 64 256 832 ) ( 64 256 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 256 832 ) ( -64 256 832 ) ( -64 256 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 256 832 ) ( -64 -64 832 ) ( -64 -64 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 80 +{ +brushDef +{ +( 256 104 -448 ) ( 168 104 -448 ) ( 168 -16 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 168 -56 0 ) ( 168 64 0 ) ( 256 64 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) base_floor/concrete 0 0 0 +( -72 -1024 0 ) ( 16 -1024 0 ) ( 16 -1024 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -56 328 ) ( 448 64 328 ) ( 448 64 320 ) ( ( 0.031250 0 -4.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +( 256 256 0 ) ( 168 256 0 ) ( 168 256 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) base_floor/concrete 0 0 0 +( -448 -192 0 ) ( -448 -312 0 ) ( -448 -312 -8 ) ( ( 0.031250 0 4.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +} +} +} +// entity 1 +{ +"classname" "light" +"light" "600" +"origin" "-320 -832 320" +} +// entity 2 +{ +"origin" "1164 -460 0" +"model" "models/mapobjects/kmlamp1.md3" +"classname" "misc_model" +} +// entity 3 +{ +"classname" "light" +"light" "300" +"origin" "-64 -216 240" +} +// entity 4 +{ +"origin" "64 -216 240" +"light" "300" +"classname" "light" +} +// entity 5 +{ +"origin" "0 -768 24" +"classname" "info_player_deathmatch" +"angle" "270" +} +// entity 6 +{ +"angle" "0" +"origin" "920 640 240" +"light" "300" +"classname" "light" +} +// entity 7 +{ +"angle" "0" +"classname" "light" +"light" "300" +"origin" "920 768 240" +} +// entity 8 +{ +"_color" "1 0.9 0.9" +"origin" "0 512 128" +"light" "200" +"classname" "light" +} +// entity 9 +{ +"classname" "light" +"light" "200" +"origin" "48 656 128" +"_color" "1 0.9 0.9" +} +// entity 10 +{ +"_color" "1 0.9 0.9" +"origin" "192 704 128" +"light" "200" +"classname" "light" +} +// entity 11 +{ +"classname" "light" +"light" "200" +"origin" "0 384 128" +"_color" "1 0.9 0.9" +} +// entity 12 +{ +"_color" "1 0.9 0.9" +"origin" "0 256 128" +"light" "200" +"classname" "light" +} +// entity 13 +{ +"classname" "light" +"light" "200" +"origin" "320 704 128" +"_color" "1 0.9 0.9" +} +// entity 14 +{ +"_color" "1 0.9 0.9" +"origin" "448 704 128" +"light" "200" +"classname" "light" +} +// entity 15 +{ +"origin" "64 -832 320" +"light" "600" +"classname" "light" +} +// entity 16 +{ +"classname" "light" +"light" "600" +"origin" "448 -832 320" +} +// entity 17 +{ +"origin" "832 -832 320" +"light" "600" +"classname" "light" +} +// entity 18 +{ +"classname" "light" +"light" "600" +"origin" "1408 -1088 256" +} diff --git a/docs/developer/TstMaps/western.map b/docs/developer/TstMaps/western.map new file mode 100644 index 00000000..2141709e --- /dev/null +++ b/docs/developer/TstMaps/western.map @@ -0,0 +1,5062 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -760 872 -8 ) ( -760 1200 -8 ) ( -760 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 1 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 1200 -8 ) ( -8 1200 -8 ) ( -384 1200 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 2 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1272 -320 -8 ) ( 1272 -648 -8 ) ( 1272 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 3 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1016 -640 -8 ) ( 640 -640 -8 ) ( 1016 -640 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 4 +{ +brushDef +{ +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -384 1216 888 ) ( -384 888 888 ) ( -8 1216 888 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +} +} +// brush 5 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -384 1208 -48 ) ( -8 1208 -48 ) ( -384 880 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +} +} +// brush 6 +{ +brushDef +{ +( 392 0 280 ) ( 128 0 280 ) ( 128 -8 280 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -8 328 ) ( 128 0 328 ) ( 392 0 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 120 -8 304 ) ( 384 -8 304 ) ( 384 -8 296 ) ( ( 0.003906 0 -0.500000 ) ( 0 0.020833 6.833333 ) ) clan_xb/logo7 0 0 0 +( 384 -8 304 ) ( 384 0 304 ) ( 384 0 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 0 304 ) ( 128 0 304 ) ( 128 0 296 ) ( ( 0.003906 0 1.500000 ) ( 0 0.020833 6.833333 ) ) clan_xb/logo7 0 0 0 +( 128 0 304 ) ( 128 -8 304 ) ( 128 -8 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 7 +{ +brushDef +{ +( 320 192 296 ) ( 192 192 296 ) ( 192 176 296 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 304 ) ( 192 184 304 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 304 ) ( 320 168 304 ) ( 320 168 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 304 ) ( 320 184 304 ) ( 320 184 280 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 184 304 ) ( 192 184 304 ) ( 192 184 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 304 ) ( 192 168 304 ) ( 192 168 280 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 8 +{ +brushDef +{ +( 320 168 296 ) ( 192 168 296 ) ( 192 152 296 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 312 ) ( 192 168 312 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 312 ) ( 320 152 312 ) ( 320 152 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 312 ) ( 320 168 312 ) ( 320 168 288 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 312 ) ( 192 168 312 ) ( 192 168 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 312 ) ( 192 152 312 ) ( 192 152 288 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 9 +{ +brushDef +{ +( 320 152 296 ) ( 192 152 296 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 320 ) ( 192 152 320 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 320 ) ( 320 136 320 ) ( 320 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 136 320 ) ( 320 152 320 ) ( 320 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 320 ) ( 192 152 320 ) ( 192 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 320 ) ( 192 136 320 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 10 +{ +brushDef +{ +( 320 200 296 ) ( 192 200 296 ) ( 192 184 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 304 ) ( 192 200 304 ) ( 320 200 304 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 304 ) ( 320 184 304 ) ( 320 184 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 184 304 ) ( 320 200 304 ) ( 320 200 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 200 304 ) ( 192 200 304 ) ( 192 200 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 200 304 ) ( 192 184 304 ) ( 192 184 296 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 11 +{ +brushDef +{ +( 320 184 304 ) ( 192 184 304 ) ( 192 168 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 312 ) ( 192 184 312 ) ( 320 184 312 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 312 ) ( 320 168 312 ) ( 320 168 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 312 ) ( 320 184 312 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 184 312 ) ( 192 184 312 ) ( 192 184 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 312 ) ( 192 168 312 ) ( 192 168 304 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 12 +{ +brushDef +{ +( 320 168 312 ) ( 192 168 312 ) ( 192 152 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 320 ) ( 192 168 320 ) ( 320 168 320 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 320 ) ( 320 152 320 ) ( 320 152 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 320 ) ( 320 168 320 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 320 ) ( 192 168 320 ) ( 192 168 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 320 ) ( 192 152 320 ) ( 192 152 312 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 13 +{ +brushDef +{ +( 320 152 320 ) ( 192 152 320 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 328 ) ( 192 152 328 ) ( 320 152 328 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 320 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 136 328 ) ( 320 152 328 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 328 ) ( 192 152 328 ) ( 192 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 328 ) ( 192 136 328 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 14 +{ +brushDef +{ +( -40 136 376 ) ( -48 136 376 ) ( -48 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -8 128 424 ) ( -8 136 424 ) ( 0 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 15 +{ +brushDef +{ +( -40 128 480 ) ( -40 136 480 ) ( -32 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -8 136 432 ) ( -8 128 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 16 +{ +brushDef +{ +( 8 136 432 ) ( 8 136 424 ) ( 8 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( -96 128 432 ) ( -96 136 432 ) ( -96 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( -8 128 424 ) ( -8 128 432 ) ( 0 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -7.250001 ) ) gothic_trim/wood2 0 0 0 +( -8 128 432 ) ( -8 136 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.500000 ) ) gothic_trim/wood2 0 0 0 +( -8 136 432 ) ( -8 136 424 ) ( 0 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -7.250000 ) ) gothic_trim/wood2 0 0 0 +( -8 136 424 ) ( -8 128 424 ) ( 0 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 11.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 17 +{ +brushDef +{ +( 112 136 376 ) ( 104 136 376 ) ( 104 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 144 128 424 ) ( 144 136 424 ) ( 152 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 18 +{ +brushDef +{ +( 112 128 480 ) ( 112 136 480 ) ( 120 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 144 136 432 ) ( 144 128 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 19 +{ +brushDef +{ +( 160 136 432 ) ( 160 136 424 ) ( 160 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 56 128 432 ) ( 56 136 432 ) ( 56 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 144 128 424 ) ( 144 128 432 ) ( 152 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -4.875001 ) ) gothic_trim/wood2 0 0 0 +( 144 128 432 ) ( 144 136 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.125000 ) ) gothic_trim/wood2 0 0 0 +( 144 136 432 ) ( 144 136 424 ) ( 152 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -4.875000 ) ) gothic_trim/wood2 0 0 0 +( 144 136 424 ) ( 144 128 424 ) ( 152 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 9.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 20 +{ +brushDef +{ +( 408 136 376 ) ( 400 136 376 ) ( 400 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 128 424 ) ( 440 136 424 ) ( 448 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 21 +{ +brushDef +{ +( 408 128 480 ) ( 408 136 480 ) ( 416 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 136 432 ) ( 440 128 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 22 +{ +brushDef +{ +( 456 136 432 ) ( 456 136 424 ) ( 456 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 352 128 432 ) ( 352 136 432 ) ( 352 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 128 424 ) ( 440 128 432 ) ( 448 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -0.250000 ) ) gothic_trim/wood2 0 0 0 +( 440 128 432 ) ( 440 136 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 136 432 ) ( 440 136 424 ) ( 448 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -0.250000 ) ) gothic_trim/wood2 0 0 0 +( 440 136 424 ) ( 440 128 424 ) ( 448 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 4.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 23 +{ +brushDef +{ +( 560 136 376 ) ( 552 136 376 ) ( 552 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 592 128 424 ) ( 592 136 424 ) ( 600 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 24 +{ +brushDef +{ +( 560 128 480 ) ( 560 136 480 ) ( 568 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 592 136 432 ) ( 592 128 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 25 +{ +brushDef +{ +( 608 136 432 ) ( 608 136 424 ) ( 608 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 128 432 ) ( 504 136 432 ) ( 504 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 592 128 424 ) ( 592 128 432 ) ( 600 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 592 128 432 ) ( 592 136 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 592 136 432 ) ( 592 136 424 ) ( 600 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 592 136 424 ) ( 592 128 424 ) ( 600 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 2.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 26 +{ +brushDef +{ +( 632 0 384 ) ( 632 8 384 ) ( 504 8 384 ) ( ( 0 0.015625 9.875000 ) ( -0.015625 0 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 8 392 ) ( 632 8 392 ) ( 632 0 392 ) ( ( 0 -0.015625 9.875000 ) ( 0.015625 0 -2.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 8 392 ) ( -120 0 392 ) ( -120 0 336 ) ( ( 0.015625 0 -4.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 0 392 ) ( 632 0 392 ) ( 632 0 336 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 392 ) ( 632 8 392 ) ( 632 8 336 ) ( ( 0.015625 0 4.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 8 392 ) ( -120 8 392 ) ( -120 8 336 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 27 +{ +brushDef +{ +( 640 128 384 ) ( 632 128 384 ) ( 632 0 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 392 ) ( 632 128 392 ) ( 640 128 392 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 392 ) ( 640 0 392 ) ( 640 0 336 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 0 392 ) ( 640 128 392 ) ( 640 128 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 128 392 ) ( 632 128 392 ) ( 632 128 336 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 128 392 ) ( 632 0 392 ) ( 632 0 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 28 +{ +brushDef +{ +( -120 128 384 ) ( -128 128 384 ) ( -128 0 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 392 ) ( -128 128 392 ) ( -120 128 392 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 392 ) ( -120 0 392 ) ( -120 0 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 0 392 ) ( -120 128 392 ) ( -120 128 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 128 392 ) ( -128 128 392 ) ( -128 128 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 128 392 ) ( -128 0 392 ) ( -128 0 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 29 +{ +brushDef +{ +( 648 104 328 ) ( 632 104 328 ) ( 632 96 328 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 96 384 ) ( 632 104 384 ) ( 648 104 384 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 88 336 ) ( 648 88 336 ) ( 648 88 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 80 336 ) ( 640 88 336 ) ( 640 88 328 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 96 336 ) ( 632 96 336 ) ( 632 96 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 104 336 ) ( 632 96 336 ) ( 632 96 328 ) ( ( 0.015625 0 -0.250000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 30 +{ +brushDef +{ +( 648 48 328 ) ( 632 48 328 ) ( 632 40 328 ) ( ( 0.015625 0 1.125000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 40 384 ) ( 632 48 384 ) ( 648 48 384 ) ( ( 0.015625 0 1.125000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 32 336 ) ( 648 32 336 ) ( 648 32 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 24 336 ) ( 640 32 336 ) ( 640 32 328 ) ( ( 0.015625 0 1.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 40 336 ) ( 632 40 336 ) ( 632 40 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 48 336 ) ( 632 40 336 ) ( 632 40 328 ) ( ( 0.015625 0 -1.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 31 +{ +brushDef +{ +( 616 16 328 ) ( 600 16 328 ) ( 600 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 8 384 ) ( 600 16 384 ) ( 616 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 0 336 ) ( 616 0 336 ) ( 616 0 328 ) ( ( 0.015625 0 -11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 608 -8 336 ) ( 608 0 336 ) ( 608 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 616 8 336 ) ( 600 8 336 ) ( 600 8 328 ) ( ( 0.015625 0 11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 600 16 336 ) ( 600 8 336 ) ( 600 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 32 +{ +brushDef +{ +( 552 16 328 ) ( 536 16 328 ) ( 536 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 8 384 ) ( 536 16 384 ) ( 552 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 0 336 ) ( 552 0 336 ) ( 552 0 328 ) ( ( 0.015625 0 -10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 544 -8 336 ) ( 544 0 336 ) ( 544 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 552 8 336 ) ( 536 8 336 ) ( 536 8 328 ) ( ( 0.015625 0 10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 536 16 336 ) ( 536 8 336 ) ( 536 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 33 +{ +brushDef +{ +( 488 16 328 ) ( 472 16 328 ) ( 472 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 8 384 ) ( 472 16 384 ) ( 488 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 0 336 ) ( 488 0 336 ) ( 488 0 328 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 480 -8 336 ) ( 480 0 336 ) ( 480 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 488 8 336 ) ( 472 8 336 ) ( 472 8 328 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 472 16 336 ) ( 472 8 336 ) ( 472 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 34 +{ +brushDef +{ +( 424 16 328 ) ( 408 16 328 ) ( 408 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 8 384 ) ( 408 16 384 ) ( 424 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 0 336 ) ( 424 0 336 ) ( 424 0 328 ) ( ( 0.015625 0 -8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 416 -8 336 ) ( 416 0 336 ) ( 416 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 424 8 336 ) ( 408 8 336 ) ( 408 8 328 ) ( ( 0.015625 0 8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 408 16 336 ) ( 408 8 336 ) ( 408 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 35 +{ +brushDef +{ +( 360 16 328 ) ( 344 16 328 ) ( 344 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 7.375000 ) ) gothic_trim/wood2 0 0 0 +( 344 8 384 ) ( 344 16 384 ) ( 360 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -7.375000 ) ) gothic_trim/wood2 0 0 0 +( 344 0 336 ) ( 360 0 336 ) ( 360 0 328 ) ( ( 0.015625 0 -7.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 352 -8 336 ) ( 352 0 336 ) ( 352 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 360 8 336 ) ( 344 8 336 ) ( 344 8 328 ) ( ( 0.015625 0 7.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 344 16 336 ) ( 344 8 336 ) ( 344 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 36 +{ +brushDef +{ +( 296 16 328 ) ( 280 16 328 ) ( 280 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 6.375000 ) ) gothic_trim/wood2 0 0 0 +( 280 8 384 ) ( 280 16 384 ) ( 296 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -6.375000 ) ) gothic_trim/wood2 0 0 0 +( 280 0 336 ) ( 296 0 336 ) ( 296 0 328 ) ( ( 0.015625 0 -6.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 288 -8 336 ) ( 288 0 336 ) ( 288 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 296 8 336 ) ( 280 8 336 ) ( 280 8 328 ) ( ( 0.015625 0 6.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 280 16 336 ) ( 280 8 336 ) ( 280 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 37 +{ +brushDef +{ +( 240 16 328 ) ( 224 16 328 ) ( 224 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 5.500000 ) ) gothic_trim/wood2 0 0 0 +( 224 8 384 ) ( 224 16 384 ) ( 240 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -5.500000 ) ) gothic_trim/wood2 0 0 0 +( 224 0 336 ) ( 240 0 336 ) ( 240 0 328 ) ( ( 0.015625 0 -5.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 232 -8 336 ) ( 232 0 336 ) ( 232 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 240 8 336 ) ( 224 8 336 ) ( 224 8 328 ) ( ( 0.015625 0 5.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 224 16 336 ) ( 224 8 336 ) ( 224 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 38 +{ +brushDef +{ +( 264 16 328 ) ( 248 16 328 ) ( 248 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 248 8 384 ) ( 248 16 384 ) ( 264 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 248 0 336 ) ( 264 0 336 ) ( 264 0 328 ) ( ( 0.015625 0 -5.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 264 -8 336 ) ( 264 0 336 ) ( 264 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 264 8 336 ) ( 248 8 336 ) ( 248 8 328 ) ( ( 0.015625 0 5.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 248 16 336 ) ( 248 8 336 ) ( 248 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 39 +{ +brushDef +{ +( 176 16 328 ) ( 160 16 328 ) ( 160 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 4.500000 ) ) gothic_trim/wood2 0 0 0 +( 160 8 384 ) ( 160 16 384 ) ( 176 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -4.500000 ) ) gothic_trim/wood2 0 0 0 +( 160 0 336 ) ( 176 0 336 ) ( 176 0 328 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 168 -8 336 ) ( 168 0 336 ) ( 168 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 176 8 336 ) ( 160 8 336 ) ( 160 8 328 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 160 16 336 ) ( 160 8 336 ) ( 160 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 40 +{ +brushDef +{ +( 112 16 328 ) ( 96 16 328 ) ( 96 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 8 384 ) ( 96 16 384 ) ( 112 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 0 336 ) ( 112 0 336 ) ( 112 0 328 ) ( ( 0.015625 0 -3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 104 -8 336 ) ( 104 0 336 ) ( 104 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 112 8 336 ) ( 96 8 336 ) ( 96 8 328 ) ( ( 0.015625 0 3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 96 16 336 ) ( 96 8 336 ) ( 96 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 41 +{ +brushDef +{ +( 48 16 328 ) ( 32 16 328 ) ( 32 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 8 384 ) ( 32 16 384 ) ( 48 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 0 336 ) ( 48 0 336 ) ( 48 0 328 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 40 -8 336 ) ( 40 0 336 ) ( 40 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 48 8 336 ) ( 32 8 336 ) ( 32 8 328 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 32 16 336 ) ( 32 8 336 ) ( 32 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 42 +{ +brushDef +{ +( -16 16 328 ) ( -32 16 328 ) ( -32 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 8 384 ) ( -32 16 384 ) ( -16 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 0 336 ) ( -16 0 336 ) ( -16 0 328 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -24 -8 336 ) ( -24 0 336 ) ( -24 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -16 8 336 ) ( -32 8 336 ) ( -32 8 328 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -32 16 336 ) ( -32 8 336 ) ( -32 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 43 +{ +brushDef +{ +( -80 16 328 ) ( -96 16 328 ) ( -96 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 8 384 ) ( -96 16 384 ) ( -80 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 0 336 ) ( -80 0 336 ) ( -80 0 328 ) ( ( 0.015625 0 -0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -88 -8 336 ) ( -88 0 336 ) ( -88 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -80 8 336 ) ( -96 8 336 ) ( -96 8 328 ) ( ( 0.015625 0 0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -96 16 336 ) ( -96 8 336 ) ( -96 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 44 +{ +brushDef +{ +( -112 72 328 ) ( -128 72 328 ) ( -128 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 64 384 ) ( -128 72 384 ) ( -112 72 384 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 56 336 ) ( -112 56 336 ) ( -112 56 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 56 336 ) ( -120 64 336 ) ( -120 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 72 336 ) ( -128 72 336 ) ( -128 72 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 72 336 ) ( -128 64 336 ) ( -128 64 328 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 45 +{ +brushDef +{ +( 648 72 328 ) ( 632 72 328 ) ( 632 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 64 384 ) ( 632 72 384 ) ( 648 72 384 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 56 336 ) ( 648 56 336 ) ( 648 56 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 56 336 ) ( 640 64 336 ) ( 640 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 72 336 ) ( 632 72 336 ) ( 632 72 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 72 336 ) ( 632 64 336 ) ( 632 64 328 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 46 +{ +brushDef +{ +( 648 128 328 ) ( 632 128 328 ) ( 632 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 384 ) ( 632 128 384 ) ( 648 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 336 ) ( 648 120 336 ) ( 648 120 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 120 336 ) ( 640 128 336 ) ( 640 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 128 336 ) ( 632 128 336 ) ( 632 128 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 128 336 ) ( 632 120 336 ) ( 632 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 47 +{ +brushDef +{ +( 648 8 328 ) ( 632 8 328 ) ( 632 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 384 ) ( 632 8 384 ) ( 648 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 336 ) ( 648 0 336 ) ( 648 0 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 0 336 ) ( 640 8 336 ) ( 640 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 8 336 ) ( 632 8 336 ) ( 632 8 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 8 336 ) ( 632 0 336 ) ( 632 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 48 +{ +brushDef +{ +( 584 8 328 ) ( 568 8 328 ) ( 568 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 0 384 ) ( 568 8 384 ) ( 584 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 0 336 ) ( 584 0 336 ) ( 584 0 328 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 576 0 336 ) ( 576 8 336 ) ( 576 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 584 8 336 ) ( 568 8 336 ) ( 568 8 328 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 568 8 336 ) ( 568 0 336 ) ( 568 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 49 +{ +brushDef +{ +( 520 8 328 ) ( 504 8 328 ) ( 504 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 0 384 ) ( 504 8 384 ) ( 520 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 0 336 ) ( 520 0 336 ) ( 520 0 328 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 512 0 336 ) ( 512 8 336 ) ( 512 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 520 8 336 ) ( 504 8 336 ) ( 504 8 328 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 8 336 ) ( 504 0 336 ) ( 504 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 50 +{ +brushDef +{ +( 456 8 328 ) ( 440 8 328 ) ( 440 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 0 384 ) ( 440 8 384 ) ( 456 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 0 336 ) ( 456 0 336 ) ( 456 0 328 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 448 0 336 ) ( 448 8 336 ) ( 448 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 456 8 336 ) ( 440 8 336 ) ( 440 8 328 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 440 8 336 ) ( 440 0 336 ) ( 440 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 51 +{ +brushDef +{ +( 392 8 328 ) ( 376 8 328 ) ( 376 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 0 384 ) ( 376 8 384 ) ( 392 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 0 336 ) ( 392 0 336 ) ( 392 0 328 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 384 0 336 ) ( 384 8 336 ) ( 384 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 392 8 336 ) ( 376 8 336 ) ( 376 8 328 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 376 8 336 ) ( 376 0 336 ) ( 376 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 52 +{ +brushDef +{ +( 328 8 328 ) ( 312 8 328 ) ( 312 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 6.875000 ) ) gothic_trim/wood2 0 0 0 +( 312 0 384 ) ( 312 8 384 ) ( 328 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -6.875000 ) ) gothic_trim/wood2 0 0 0 +( 312 0 336 ) ( 328 0 336 ) ( 328 0 328 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 320 0 336 ) ( 320 8 336 ) ( 320 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 328 8 336 ) ( 312 8 336 ) ( 312 8 328 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 312 8 336 ) ( 312 0 336 ) ( 312 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 53 +{ +brushDef +{ +( 208 8 328 ) ( 192 8 328 ) ( 192 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 5 ) ) gothic_trim/wood2 0 0 0 +( 192 0 384 ) ( 192 8 384 ) ( 208 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -5 ) ) gothic_trim/wood2 0 0 0 +( 192 0 336 ) ( 208 0 336 ) ( 208 0 328 ) ( ( 0.015625 0 -5 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 200 0 336 ) ( 200 8 336 ) ( 200 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 208 8 336 ) ( 192 8 336 ) ( 192 8 328 ) ( ( 0.015625 0 5 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 192 8 336 ) ( 192 0 336 ) ( 192 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 54 +{ +brushDef +{ +( 144 8 328 ) ( 128 8 328 ) ( 128 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 0 0 0 +( 128 0 384 ) ( 128 8 384 ) ( 144 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 0 0 0 +( 128 0 336 ) ( 144 0 336 ) ( 144 0 328 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 0 336 ) ( 136 8 336 ) ( 136 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 144 8 336 ) ( 128 8 336 ) ( 128 8 328 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 128 8 336 ) ( 128 0 336 ) ( 128 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 55 +{ +brushDef +{ +( 80 8 328 ) ( 64 8 328 ) ( 64 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 0 0 0 +( 64 0 384 ) ( 64 8 384 ) ( 80 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 0 0 0 +( 64 0 336 ) ( 80 0 336 ) ( 80 0 328 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 72 0 336 ) ( 72 8 336 ) ( 72 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 80 8 336 ) ( 64 8 336 ) ( 64 8 328 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 64 8 336 ) ( 64 0 336 ) ( 64 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 56 +{ +brushDef +{ +( 16 8 328 ) ( 0 8 328 ) ( 0 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 0 0 0 +( 0 0 384 ) ( 0 8 384 ) ( 16 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 0 0 0 +( 0 0 336 ) ( 16 0 336 ) ( 16 0 328 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 0 336 ) ( 8 8 336 ) ( 8 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 16 8 336 ) ( 0 8 336 ) ( 0 8 328 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 0 8 336 ) ( 0 0 336 ) ( 0 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 57 +{ +brushDef +{ +( -48 8 328 ) ( -64 8 328 ) ( -64 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 0 0 0 +( -64 0 384 ) ( -64 8 384 ) ( -48 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 0 0 0 +( -64 0 336 ) ( -48 0 336 ) ( -48 0 328 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -56 0 336 ) ( -56 8 336 ) ( -56 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -48 8 336 ) ( -64 8 336 ) ( -64 8 328 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -64 8 336 ) ( -64 0 336 ) ( -64 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 58 +{ +brushDef +{ +( -112 32 328 ) ( -128 32 328 ) ( -128 24 328 ) ( ( 0.015625 0 1.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 24 384 ) ( -128 32 384 ) ( -112 32 384 ) ( ( 0.015625 0 1.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 24 336 ) ( -112 24 336 ) ( -112 24 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 24 336 ) ( -120 32 336 ) ( -120 32 328 ) ( ( 0.015625 0 1.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 32 336 ) ( -128 32 336 ) ( -128 32 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 32 336 ) ( -128 24 336 ) ( -128 24 328 ) ( ( 0.015625 0 -1.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 59 +{ +brushDef +{ +( -112 96 328 ) ( -128 96 328 ) ( -128 88 328 ) ( ( 0.015625 0 0.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 88 384 ) ( -128 96 384 ) ( -112 96 384 ) ( ( 0.015625 0 0.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 88 336 ) ( -112 88 336 ) ( -112 88 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 88 336 ) ( -120 96 336 ) ( -120 96 328 ) ( ( 0.015625 0 0.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 96 336 ) ( -128 96 336 ) ( -128 96 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 96 336 ) ( -128 88 336 ) ( -128 88 328 ) ( ( 0.015625 0 -0.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 60 +{ +brushDef +{ +( -112 8 328 ) ( -128 8 328 ) ( -128 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 384 ) ( -128 8 384 ) ( -112 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 336 ) ( -112 0 336 ) ( -112 0 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 0 336 ) ( -120 8 336 ) ( -120 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 8 336 ) ( -128 8 336 ) ( -128 8 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 8 336 ) ( -128 0 336 ) ( -128 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 61 +{ +brushDef +{ +( -112 128 328 ) ( -128 128 328 ) ( -128 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 120 384 ) ( -128 128 384 ) ( -112 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 120 336 ) ( -112 120 336 ) ( -112 120 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 120 336 ) ( -120 128 336 ) ( -120 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 128 336 ) ( -128 128 336 ) ( -128 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 128 336 ) ( -128 120 336 ) ( -128 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 62 +{ +brushDef +{ +( 192 128 512 ) ( 192 136 512 ) ( 224 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 144 480 ) ( 192 136 480 ) ( 320 144 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 63 +{ +brushDef +{ +( 216 136 224 ) ( 184 136 224 ) ( 184 128 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 192 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 64 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 480 ) ( 456 128 480 ) ( 456 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 480 ) ( 504 136 480 ) ( 504 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 65 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 480 ) ( 608 128 480 ) ( 608 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 66 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 480 ) ( 352 136 480 ) ( 352 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 67 +{ +brushDef +{ +( 320 128 512 ) ( 320 136 512 ) ( 640 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 480 ) ( 320 128 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 68 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 232 ) ( 352 128 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 376 ) ( 1088 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 69 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 136 480 ) ( 8 128 480 ) ( 8 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 128 480 ) ( 56 136 480 ) ( 56 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 70 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 136 480 ) ( 160 128 480 ) ( 160 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 71 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 128 480 ) ( -96 136 480 ) ( -96 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 72 +{ +brushDef +{ +( -128 128 512 ) ( -128 136 512 ) ( 192 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 480 ) ( -128 128 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 73 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 232 ) ( 56 136 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 376 ) ( 640 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 74 +{ +brushDef +{ +( 120 128 320 ) ( -128 128 320 ) ( -128 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 0 328 ) ( -120 128 328 ) ( 128 128 328 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 0 576 ) ( 120 0 576 ) ( 120 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 16 576 ) ( 640 144 576 ) ( 640 144 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 120 128 576 ) ( -128 128 576 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 128 576 ) ( -128 0 576 ) ( -128 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 75 +{ +brushDef +{ +( 640 968 512 ) ( 568 968 512 ) ( 568 920 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 776 768 ) ( 448 320 768 ) ( 64 320 768 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 320 768 ) ( 640 320 768 ) ( 640 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 448 320 768 ) ( 448 776 768 ) ( 640 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 640 776 768 ) ( -128 776 768 ) ( -128 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 64 776 768 ) ( 64 320 768 ) ( -128 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +} +} +// brush 76 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 560 824 8 0 0 ) ( 560 824 40 0 0.500000 ) ( 560 824 72 0 1 ) ) +( ( 560 816 8 0.125000 0 ) ( 560 816 40 0.125000 0.500000 ) ( 560 816 72 0.125000 1 ) ) +( ( 568 816 8 0.250000 0 ) ( 568 816 40 0.250000 0.500000 ) ( 568 816 72 0.250000 1 ) ) +( ( 576 816 8 0.375000 0 ) ( 576 816 40 0.375000 0.500000 ) ( 576 816 72 0.375000 1 ) ) +( ( 576 824 8 0.500000 0 ) ( 576 824 40 0.500000 0.500000 ) ( 576 824 72 0.500000 1 ) ) +( ( 576 832 8 0.625000 0 ) ( 576 832 40 0.625000 0.500000 ) ( 576 832 72 0.625000 1 ) ) +( ( 568 832 8 0.750000 0 ) ( 568 832 40 0.750000 0.500000 ) ( 568 832 72 0.750000 1 ) ) +( ( 560 832 8 0.875000 0 ) ( 560 832 40 0.875000 0.500000 ) ( 560 832 72 0.875000 1 ) ) +( ( 560 824 8 1 0 ) ( 560 824 40 1 0.500000 ) ( 560 824 72 1 1 ) ) +) + } + } +// brush 77 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( -64 824 8 0 0 ) ( -64 824 40 0 0.500000 ) ( -64 824 72 0 1 ) ) +( ( -64 816 8 0.125000 0 ) ( -64 816 40 0.125000 0.500000 ) ( -64 816 72 0.125000 1 ) ) +( ( -56 816 8 0.250000 0 ) ( -56 816 40 0.250000 0.500000 ) ( -56 816 72 0.250000 1 ) ) +( ( -48 816 8 0.375000 0 ) ( -48 816 40 0.375000 0.500000 ) ( -48 816 72 0.375000 1 ) ) +( ( -48 824 8 0.500000 0 ) ( -48 824 40 0.500000 0.500000 ) ( -48 824 72 0.500000 1 ) ) +( ( -48 832 8 0.625000 0 ) ( -48 832 40 0.625000 0.500000 ) ( -48 832 72 0.625000 1 ) ) +( ( -56 832 8 0.750000 0 ) ( -56 832 40 0.750000 0.500000 ) ( -56 832 72 0.750000 1 ) ) +( ( -64 832 8 0.875000 0 ) ( -64 832 40 0.875000 0.500000 ) ( -64 832 72 0.875000 1 ) ) +( ( -64 824 8 1 0 ) ( -64 824 40 1 0.500000 ) ( -64 824 72 1 1 ) ) +) + } + } +// brush 78 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( -64 928 8 0 0 ) ( -64 928 40 0 0.500000 ) ( -64 928 72 0 1 ) ) +( ( -64 920 8 0.125000 0 ) ( -64 920 40 0.125000 0.500000 ) ( -64 920 72 0.125000 1 ) ) +( ( -56 920 8 0.250000 0 ) ( -56 920 40 0.250000 0.500000 ) ( -56 920 72 0.250000 1 ) ) +( ( -48 920 8 0.375000 0 ) ( -48 920 40 0.375000 0.500000 ) ( -48 920 72 0.375000 1 ) ) +( ( -48 928 8 0.500000 0 ) ( -48 928 40 0.500000 0.500000 ) ( -48 928 72 0.500000 1 ) ) +( ( -48 936 8 0.625000 0 ) ( -48 936 40 0.625000 0.500000 ) ( -48 936 72 0.625000 1 ) ) +( ( -56 936 8 0.750000 0 ) ( -56 936 40 0.750000 0.500000 ) ( -56 936 72 0.750000 1 ) ) +( ( -64 936 8 0.875000 0 ) ( -64 936 40 0.875000 0.500000 ) ( -64 936 72 0.875000 1 ) ) +( ( -64 928 8 1 0 ) ( -64 928 40 1 0.500000 ) ( -64 928 72 1 1 ) ) +) + } + } +// brush 79 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 8 744 8 0 0 ) ( 8 744 40 0 0.500000 ) ( 8 744 72 0 1 ) ) +( ( 8 736 8 0.125000 0 ) ( 8 736 40 0.125000 0.500000 ) ( 8 736 72 0.125000 1 ) ) +( ( 16 736 8 0.250000 0 ) ( 16 736 40 0.250000 0.500000 ) ( 16 736 72 0.250000 1 ) ) +( ( 24 736 8 0.375000 0 ) ( 24 736 40 0.375000 0.500000 ) ( 24 736 72 0.375000 1 ) ) +( ( 24 744 8 0.500000 0 ) ( 24 744 40 0.500000 0.500000 ) ( 24 744 72 0.500000 1 ) ) +( ( 24 752 8 0.625000 0 ) ( 24 752 40 0.625000 0.500000 ) ( 24 752 72 0.625000 1 ) ) +( ( 16 752 8 0.750000 0 ) ( 16 752 40 0.750000 0.500000 ) ( 16 752 72 0.750000 1 ) ) +( ( 8 752 8 0.875000 0 ) ( 8 752 40 0.875000 0.500000 ) ( 8 752 72 0.875000 1 ) ) +( ( 8 744 8 1 0 ) ( 8 744 40 1 0.500000 ) ( 8 744 72 1 1 ) ) +) + } + } +// brush 80 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 104 744 8 0 0 ) ( 104 744 40 0 0.500000 ) ( 104 744 72 0 1 ) ) +( ( 104 736 8 0.125000 0 ) ( 104 736 40 0.125000 0.500000 ) ( 104 736 72 0.125000 1 ) ) +( ( 112 736 8 0.250000 0 ) ( 112 736 40 0.250000 0.500000 ) ( 112 736 72 0.250000 1 ) ) +( ( 120 736 8 0.375000 0 ) ( 120 736 40 0.375000 0.500000 ) ( 120 736 72 0.375000 1 ) ) +( ( 120 744 8 0.500000 0 ) ( 120 744 40 0.500000 0.500000 ) ( 120 744 72 0.500000 1 ) ) +( ( 120 752 8 0.625000 0 ) ( 120 752 40 0.625000 0.500000 ) ( 120 752 72 0.625000 1 ) ) +( ( 112 752 8 0.750000 0 ) ( 112 752 40 0.750000 0.500000 ) ( 112 752 72 0.750000 1 ) ) +( ( 104 752 8 0.875000 0 ) ( 104 752 40 0.875000 0.500000 ) ( 104 752 72 0.875000 1 ) ) +( ( 104 744 8 1 0 ) ( 104 744 40 1 0.500000 ) ( 104 744 72 1 1 ) ) +) + } + } +// brush 81 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 272 744 8 0 0 ) ( 272 744 40 0 0.500000 ) ( 272 744 72 0 1 ) ) +( ( 272 736 8 0.125000 0 ) ( 272 736 40 0.125000 0.500000 ) ( 272 736 72 0.125000 1 ) ) +( ( 280 736 8 0.250000 0 ) ( 280 736 40 0.250000 0.500000 ) ( 280 736 72 0.250000 1 ) ) +( ( 288 736 8 0.375000 0 ) ( 288 736 40 0.375000 0.500000 ) ( 288 736 72 0.375000 1 ) ) +( ( 288 744 8 0.500000 0 ) ( 288 744 40 0.500000 0.500000 ) ( 288 744 72 0.500000 1 ) ) +( ( 288 752 8 0.625000 0 ) ( 288 752 40 0.625000 0.500000 ) ( 288 752 72 0.625000 1 ) ) +( ( 280 752 8 0.750000 0 ) ( 280 752 40 0.750000 0.500000 ) ( 280 752 72 0.750000 1 ) ) +( ( 272 752 8 0.875000 0 ) ( 272 752 40 0.875000 0.500000 ) ( 272 752 72 0.875000 1 ) ) +( ( 272 744 8 1 0 ) ( 272 744 40 1 0.500000 ) ( 272 744 72 1 1 ) ) +) + } + } +// brush 82 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 376 744 8 0 0 ) ( 376 744 40 0 0.500000 ) ( 376 744 72 0 1 ) ) +( ( 376 736 8 0.125000 0 ) ( 376 736 40 0.125000 0.500000 ) ( 376 736 72 0.125000 1 ) ) +( ( 384 736 8 0.250000 0 ) ( 384 736 40 0.250000 0.500000 ) ( 384 736 72 0.250000 1 ) ) +( ( 392 736 8 0.375000 0 ) ( 392 736 40 0.375000 0.500000 ) ( 392 736 72 0.375000 1 ) ) +( ( 392 744 8 0.500000 0 ) ( 392 744 40 0.500000 0.500000 ) ( 392 744 72 0.500000 1 ) ) +( ( 392 752 8 0.625000 0 ) ( 392 752 40 0.625000 0.500000 ) ( 392 752 72 0.625000 1 ) ) +( ( 384 752 8 0.750000 0 ) ( 384 752 40 0.750000 0.500000 ) ( 384 752 72 0.750000 1 ) ) +( ( 376 752 8 0.875000 0 ) ( 376 752 40 0.875000 0.500000 ) ( 376 752 72 0.875000 1 ) ) +( ( 376 744 8 1 0 ) ( 376 744 40 1 0.500000 ) ( 376 744 72 1 1 ) ) +) + } + } +// brush 83 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 464 744 8 0 0 ) ( 464 744 40 0 0.500000 ) ( 464 744 72 0 1 ) ) +( ( 464 736 8 0.125000 0 ) ( 464 736 40 0.125000 0.500000 ) ( 464 736 72 0.125000 1 ) ) +( ( 472 736 8 0.250000 0 ) ( 472 736 40 0.250000 0.500000 ) ( 472 736 72 0.250000 1 ) ) +( ( 480 736 8 0.375000 0 ) ( 480 736 40 0.375000 0.500000 ) ( 480 736 72 0.375000 1 ) ) +( ( 480 744 8 0.500000 0 ) ( 480 744 40 0.500000 0.500000 ) ( 480 744 72 0.500000 1 ) ) +( ( 480 752 8 0.625000 0 ) ( 480 752 40 0.625000 0.500000 ) ( 480 752 72 0.625000 1 ) ) +( ( 472 752 8 0.750000 0 ) ( 472 752 40 0.750000 0.500000 ) ( 472 752 72 0.750000 1 ) ) +( ( 464 752 8 0.875000 0 ) ( 464 752 40 0.875000 0.500000 ) ( 464 752 72 0.875000 1 ) ) +( ( 464 744 8 1 0 ) ( 464 744 40 1 0.500000 ) ( 464 744 72 1 1 ) ) +) + } + } +// brush 84 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 304 80 ) ( 524 336 80 ) ( 524 304 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 85 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 336 128 ) ( 532 304 128 ) ( 532 336 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 86 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 524 336 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 87 +{ +brushDef +{ +( 520 312 48 ) ( 520 304 48 ) ( 528 304 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 304 72 ) ( 524 336 72 ) ( 532 304 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 88 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 344 72 ) ( 524 312 72 ) ( 532 312 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 312 80 ) ( 524 344 80 ) ( 524 312 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 89 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 532 312 80 ) ( 524 312 80 ) ( 524 344 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 344 128 ) ( 532 312 128 ) ( 532 344 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 90 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 312 80 ) ( 532 312 80 ) ( 524 344 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 91 +{ +brushDef +{ +( 520 336 48 ) ( 520 328 48 ) ( 528 328 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 312 72 ) ( 524 344 72 ) ( 532 312 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 92 +{ +brushDef +{ +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.187500 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.187500 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 304 128 ) ( 532 336 128 ) ( 532 336 72 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 532 336 80 ) ( 524 336 80 ) ( 524 336 24 ) ( ( 0.015625 0 5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 524 336 80 ) ( 524 304 80 ) ( 524 304 24 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 532 304 24 ) ( ( 0.015625 0 -5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 93 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 94 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 95 +{ +brushDef +{ +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 304 104 ) ( 528 304 104 ) ( 528 336 104 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 304 152 ) ( 536 336 152 ) ( 536 336 96 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 536 336 104 ) ( 528 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 304 104 ) ( 528 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 304 104 ) ( 536 304 104 ) ( 536 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 96 +{ +brushDef +{ +( 488 336 8 ) ( 496 336 8 ) ( 496 344 8 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 -15 ) ) gothic_trim/wood2 0 0 0 +( 504 336 40 ) ( 504 328 40 ) ( 496 328 40 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 15 ) ) gothic_trim/wood2 0 0 0 +( 488 344 8 ) ( 496 344 8 ) ( 504 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -3.368932 ) ) gothic_trim/wood2 0 0 0 +( 488 328 8 ) ( 488 336 8 ) ( 496 336 40 ) ( ( 0.015625 0 13.375000 ) ( 0 0.015625 -1.216441 ) ) gothic_trim/wood2 0 0 0 +( 496 336 8 ) ( 488 336 8 ) ( 496 328 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -3.368936 ) ) gothic_trim/wood2 0 0 0 +( 496 336 8 ) ( 496 328 8 ) ( 504 328 40 ) ( ( 0.015625 0 -13.375000 ) ( 0 0.015625 -1.216413 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 97 +{ +brushDef +{ +( 496 296 8 ) ( 496 304 8 ) ( 488 304 8 ) ( ( 0 0.015625 11.625000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 496 312 40 ) ( 504 312 40 ) ( 504 304 40 ) ( ( 0 -0.015625 11.625000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 488 296 8 ) ( 488 304 8 ) ( 496 312 40 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -2.580697 ) ) gothic_trim/wood2 0 0 0 +( 504 296 8 ) ( 496 296 8 ) ( 496 304 40 ) ( ( 0.015625 0 10.125000 ) ( 0 0.015625 0.299379 ) ) gothic_trim/wood2 0 0 0 +( 496 304 8 ) ( 496 296 8 ) ( 504 304 40 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 -2.580694 ) ) gothic_trim/wood2 0 0 0 +( 496 304 8 ) ( 504 304 8 ) ( 504 312 40 ) ( ( 0.015625 0 -10.125000 ) ( 0 0.015625 0.299380 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 98 +{ +brushDef +{ +( 536 304 8 ) ( 528 304 8 ) ( 528 296 8 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 0 0 0 +( 520 304 40 ) ( 520 312 40 ) ( 528 312 40 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 0 0 0 +( 536 296 8 ) ( 528 296 8 ) ( 520 304 40 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 -0.761721 ) ) gothic_trim/wood2 0 0 0 +( 536 312 8 ) ( 536 304 8 ) ( 528 304 40 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -0.488851 ) ) gothic_trim/wood2 0 0 0 +( 528 304 8 ) ( 536 304 8 ) ( 528 312 40 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 -0.761720 ) ) gothic_trim/wood2 0 0 0 +( 528 304 8 ) ( 528 312 8 ) ( 520 312 40 ) ( ( 0.015625 0 -2.625000 ) ( 0 0.015625 -0.488853 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 99 +{ +brushDef +{ +( 528 344 8 ) ( 528 336 8 ) ( 536 336 8 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 328 40 ) ( 520 328 40 ) ( 520 336 40 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 344 8 ) ( 536 336 8 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -1.368011 ) ) gothic_trim/wood2 0 0 0 +( 520 344 8 ) ( 528 344 8 ) ( 528 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.125928 ) ) gothic_trim/wood2 0 0 0 +( 528 336 8 ) ( 528 344 8 ) ( 520 336 40 ) ( ( 0.015625 0 8.250001 ) ( 0 0.015625 -1.368012 ) ) gothic_trim/wood2 0 0 0 +( 528 336 8 ) ( 520 336 8 ) ( 520 328 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.125930 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 100 +{ +brushDef +{ +( 496 328 40 ) ( 496 304 40 ) ( 528 304 40 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 48 ) ( 496 304 48 ) ( 496 328 48 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 48 ) ( 528 328 48 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 48 ) ( 496 336 48 ) ( 496 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 496 328 48 ) ( 496 304 48 ) ( 496 304 40 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 496 304 48 ) ( 528 304 48 ) ( 528 304 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 101 +{ +brushDef +{ +( 440 352 40 ) ( 464 352 40 ) ( 464 384 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 48 ) ( 464 352 48 ) ( 440 352 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 48 ) ( 440 384 48 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 48 ) ( 432 352 48 ) ( 432 352 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 352 48 ) ( 464 352 48 ) ( 464 352 40 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 352 48 ) ( 464 384 48 ) ( 464 384 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 102 +{ +brushDef +{ +( 424 384 8 ) ( 432 384 8 ) ( 432 392 8 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 384 40 ) ( 440 376 40 ) ( 432 376 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 392 8 ) ( 432 392 8 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 0 0 0 +( 424 376 8 ) ( 424 384 8 ) ( 432 384 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 0 0 0 +( 432 384 8 ) ( 424 384 8 ) ( 432 376 40 ) ( ( 0.015625 0 7.250001 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 0 0 0 +( 432 384 8 ) ( 432 376 8 ) ( 440 376 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 103 +{ +brushDef +{ +( 464 392 8 ) ( 464 384 8 ) ( 472 384 8 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -13 ) ) gothic_trim/wood2 0 0 0 +( 464 376 40 ) ( 456 376 40 ) ( 456 384 40 ) ( ( 0 0.015625 -3.375000 ) ( -0.015625 0 13 ) ) gothic_trim/wood2 0 0 0 +( 472 392 8 ) ( 472 384 8 ) ( 464 376 40 ) ( ( 0.015625 0 -12.500000 ) ( 0 0.015625 -1.004194 ) ) gothic_trim/wood2 0 0 0 +( 456 392 8 ) ( 464 392 8 ) ( 464 384 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -3.156694 ) ) gothic_trim/wood2 0 0 0 +( 464 384 8 ) ( 464 392 8 ) ( 456 384 40 ) ( ( 0.015625 0 12.500000 ) ( 0 0.015625 -1.004192 ) ) gothic_trim/wood2 0 0 0 +( 464 384 8 ) ( 456 384 8 ) ( 456 376 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -3.156695 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 104 +{ +brushDef +{ +( 472 352 8 ) ( 464 352 8 ) ( 464 344 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 352 40 ) ( 456 360 40 ) ( 464 360 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 344 8 ) ( 464 344 8 ) ( 456 352 40 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.087216 ) ) gothic_trim/wood2 0 0 0 +( 472 360 8 ) ( 472 352 8 ) ( 464 352 40 ) ( ( 0.015625 0 -0.875000 ) ( 0 0.015625 0.056903 ) ) gothic_trim/wood2 0 0 0 +( 464 352 8 ) ( 472 352 8 ) ( 464 360 40 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.087221 ) ) gothic_trim/wood2 0 0 0 +( 464 352 8 ) ( 464 360 8 ) ( 456 360 40 ) ( ( 0.015625 0 0.875000 ) ( 0 0.015625 0.056905 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 105 +{ +brushDef +{ +( 432 344 8 ) ( 432 352 8 ) ( 424 352 8 ) ( ( 0 0.015625 9.875000 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( 432 360 40 ) ( 440 360 40 ) ( 440 352 40 ) ( ( 0 -0.015625 9.875000 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 344 8 ) ( 424 352 8 ) ( 432 360 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.126388 ) ) gothic_trim/wood2 0 0 0 +( 440 344 8 ) ( 432 344 8 ) ( 432 352 40 ) ( ( 0.015625 0 12.375000 ) ( 0 0.015625 1.451483 ) ) gothic_trim/wood2 0 0 0 +( 432 352 8 ) ( 432 344 8 ) ( 440 352 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.126389 ) ) gothic_trim/wood2 0 0 0 +( 432 352 8 ) ( 440 352 8 ) ( 440 360 40 ) ( ( 0.015625 0 -12.375000 ) ( 0 0.015625 1.451492 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 106 +{ +brushDef +{ +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 392 104 ) ( 464 384 104 ) ( 432 384 104 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 392 152 ) ( 432 392 152 ) ( 432 392 96 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 392 104 ) ( 432 384 104 ) ( 432 384 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 464 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 384 104 ) ( 464 392 104 ) ( 464 392 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 107 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 108 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 109 +{ +brushDef +{ +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 388 128 ) ( 432 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 388 80 ) ( 432 380 80 ) ( 432 380 24 ) ( ( 0.015625 0 16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 380 80 ) ( 464 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 464 388 24 ) ( ( 0.015625 0 -16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 110 +{ +brushDef +{ +( 432 376 48 ) ( 440 376 48 ) ( 440 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 380 72 ) ( 424 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 111 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 456 380 80 ) ( 456 388 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 112 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 388 80 ) ( 456 380 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 388 128 ) ( 456 388 128 ) ( 424 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 113 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 424 380 72 ) ( 456 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 456 380 80 ) ( 424 380 80 ) ( 456 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 114 +{ +brushDef +{ +( 456 376 48 ) ( 464 376 48 ) ( 464 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 380 72 ) ( 432 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 115 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 116 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 432 388 128 ) ( 464 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 117 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 380 80 ) ( 432 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 118 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 220 80 ) ( 464 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 119 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 212 128 ) ( 432 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 120 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 121 +{ +brushDef +{ +( 440 224 48 ) ( 432 224 48 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 220 72 ) ( 464 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 122 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 336 80 ) ( 364 304 80 ) ( 364 336 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 123 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 356 304 128 ) ( 356 336 128 ) ( 356 304 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 124 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 125 +{ +brushDef +{ +( 368 328 48 ) ( 368 336 48 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 336 72 ) ( 364 304 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 126 +{ +brushDef +{ +( 392 312 40 ) ( 392 336 40 ) ( 360 336 40 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 48 ) ( 392 336 48 ) ( 392 312 48 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 48 ) ( 360 312 48 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 48 ) ( 392 304 48 ) ( 392 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 312 48 ) ( 392 336 48 ) ( 392 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 336 48 ) ( 360 336 48 ) ( 360 336 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 127 +{ +brushDef +{ +( 360 296 8 ) ( 360 304 8 ) ( 352 304 8 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 312 40 ) ( 368 312 40 ) ( 368 304 40 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 296 8 ) ( 352 304 8 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 0 0 0 +( 368 296 8 ) ( 360 296 8 ) ( 360 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 0 0 0 +( 360 304 8 ) ( 360 296 8 ) ( 368 304 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 0 0 0 +( 360 304 8 ) ( 368 304 8 ) ( 368 312 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 128 +{ +brushDef +{ +( 352 336 8 ) ( 360 336 8 ) ( 360 344 8 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 -13.125000 ) ) gothic_trim/wood2 0 0 0 +( 368 336 40 ) ( 368 328 40 ) ( 360 328 40 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 13.125000 ) ) gothic_trim/wood2 0 0 0 +( 352 344 8 ) ( 360 344 8 ) ( 368 336 40 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 -3.853989 ) ) gothic_trim/wood2 0 0 0 +( 352 328 8 ) ( 352 336 8 ) ( 360 336 40 ) ( ( 0.015625 0 15.375000 ) ( 0 0.015625 -2.034964 ) ) gothic_trim/wood2 0 0 0 +( 360 336 8 ) ( 352 336 8 ) ( 360 328 40 ) ( ( 0.015625 0 7.875002 ) ( 0 0.015625 -3.853986 ) ) gothic_trim/wood2 0 0 0 +( 360 336 8 ) ( 360 328 8 ) ( 368 328 40 ) ( ( 0.015625 0 -15.375000 ) ( 0 0.015625 -2.034965 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 129 +{ +brushDef +{ +( 392 344 8 ) ( 392 336 8 ) ( 400 336 8 ) ( ( 0 -0.015625 -2 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 392 328 40 ) ( 384 328 40 ) ( 384 336 40 ) ( ( 0 0.015625 -2 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 400 344 8 ) ( 400 336 8 ) ( 392 328 40 ) ( ( 0.015625 0 -11 ) ( 0 0.015625 -1.034511 ) ) gothic_trim/wood2 0 0 0 +( 384 344 8 ) ( 392 344 8 ) ( 392 336 40 ) ( ( 0.015625 0 3.750001 ) ( 0 0.015625 -2.792890 ) ) gothic_trim/wood2 0 0 0 +( 392 336 8 ) ( 392 344 8 ) ( 384 336 40 ) ( ( 0.015625 0 11 ) ( 0 0.015625 -1.034512 ) ) gothic_trim/wood2 0 0 0 +( 392 336 8 ) ( 384 336 8 ) ( 384 328 40 ) ( ( 0.015625 0 -3.750000 ) ( 0 0.015625 -2.792888 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 130 +{ +brushDef +{ +( 400 304 8 ) ( 392 304 8 ) ( 392 296 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -1.375000 ) ) gothic_trim/wood2 0 0 0 +( 384 304 40 ) ( 384 312 40 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 1.375000 ) ) gothic_trim/wood2 0 0 0 +( 400 296 8 ) ( 392 296 8 ) ( 384 304 40 ) ( ( 0.015625 0 1.875001 ) ( 0 0.015625 -0.276583 ) ) gothic_trim/wood2 0 0 0 +( 400 312 8 ) ( 400 304 8 ) ( 392 304 40 ) ( ( 0.015625 0 0.625000 ) ( 0 0.015625 0.329756 ) ) gothic_trim/wood2 0 0 0 +( 392 304 8 ) ( 400 304 8 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -0.276584 ) ) gothic_trim/wood2 0 0 0 +( 392 304 8 ) ( 392 312 8 ) ( 384 312 40 ) ( ( 0.015625 0 -0.625000 ) ( 0 0.015625 0.329758 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 131 +{ +brushDef +{ +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 336 104 ) ( 360 336 104 ) ( 360 304 104 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 336 152 ) ( 352 304 152 ) ( 352 304 96 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 304 104 ) ( 360 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 336 104 ) ( 360 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 336 104 ) ( 352 336 104 ) ( 352 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 132 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 133 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 134 +{ +brushDef +{ +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0 0.015625 9.437500 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0 -0.015625 9.437500 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 0 0 0 +( 356 336 128 ) ( 356 304 128 ) ( 356 304 72 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 356 304 80 ) ( 364 304 80 ) ( 364 304 24 ) ( ( 0.015625 0 11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 364 304 80 ) ( 364 336 80 ) ( 364 336 24 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 356 336 24 ) ( ( 0.015625 0 -11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 135 +{ +brushDef +{ +( 368 304 48 ) ( 368 312 48 ) ( 360 312 48 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 328 72 ) ( 364 296 72 ) ( 356 328 72 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 136 +{ +brushDef +{ +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 364 328 80 ) ( 356 328 80 ) ( 364 296 80 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 137 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 296 72 ) ( 364 328 72 ) ( 356 328 72 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 364 328 80 ) ( 364 296 80 ) ( 364 328 24 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 138 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 220 72 ) ( 440 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 220 80 ) ( 472 220 80 ) ( 440 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 139 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 212 80 ) ( 440 220 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 212 128 ) ( 440 212 128 ) ( 472 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 140 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 220 80 ) ( 440 212 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 141 +{ +brushDef +{ +( 464 224 48 ) ( 456 224 48 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 220 72 ) ( 472 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 142 +{ +brushDef +{ +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 212 128 ) ( 464 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 464 212 80 ) ( 464 220 80 ) ( 464 220 24 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 464 220 80 ) ( 432 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 432 212 24 ) ( ( 0.015625 0 0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 143 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 144 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 145 +{ +brushDef +{ +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 208 104 ) ( 432 216 104 ) ( 464 216 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 208 152 ) ( 464 208 152 ) ( 464 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 208 104 ) ( 464 216 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 432 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 104 ) ( 432 208 104 ) ( 432 208 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 146 +{ +brushDef +{ +( 464 256 8 ) ( 464 248 8 ) ( 472 248 8 ) ( ( 0 -0.015625 -3.625000 ) ( 0.015625 0 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( 464 240 40 ) ( 456 240 40 ) ( 456 248 40 ) ( ( 0 0.015625 -3.625000 ) ( -0.015625 0 10.875000 ) ) gothic_trim/wood2 0 0 0 +( 472 256 8 ) ( 472 248 8 ) ( 464 240 40 ) ( ( 0.015625 0 -9.625000 ) ( 0 0.015625 -1.367998 ) ) gothic_trim/wood2 0 0 0 +( 456 256 8 ) ( 464 256 8 ) ( 464 248 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.459404 ) ) gothic_trim/wood2 0 0 0 +( 464 248 8 ) ( 464 256 8 ) ( 456 248 40 ) ( ( 0.015625 0 9.625000 ) ( 0 0.015625 -1.367999 ) ) gothic_trim/wood2 0 0 0 +( 464 248 8 ) ( 456 248 8 ) ( 456 240 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.459402 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 147 +{ +brushDef +{ +( 424 248 8 ) ( 432 248 8 ) ( 432 256 8 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 248 40 ) ( 440 240 40 ) ( 432 240 40 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 256 8 ) ( 432 256 8 ) ( 440 248 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.823671 ) ) gothic_trim/wood2 0 0 0 +( 424 240 8 ) ( 424 248 8 ) ( 432 248 40 ) ( ( 0.015625 0 15.250000 ) ( 0 0.015625 -1.701477 ) ) gothic_trim/wood2 0 0 0 +( 432 248 8 ) ( 424 248 8 ) ( 432 240 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.823672 ) ) gothic_trim/wood2 0 0 0 +( 432 248 8 ) ( 432 240 8 ) ( 440 240 40 ) ( ( 0.015625 0 -15.250000 ) ( 0 0.015625 -1.701478 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 148 +{ +brushDef +{ +( 432 208 8 ) ( 432 216 8 ) ( 424 216 8 ) ( ( 0 0.015625 10.125000 ) ( -0.015625 0 -3.625000 ) ) gothic_trim/wood2 0 0 0 +( 432 224 40 ) ( 440 224 40 ) ( 440 216 40 ) ( ( 0 -0.015625 10.125000 ) ( 0.015625 0 3.625000 ) ) gothic_trim/wood2 0 0 0 +( 424 208 8 ) ( 424 216 8 ) ( 432 224 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 0 0 0 +( 440 208 8 ) ( 432 208 8 ) ( 432 216 40 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.754196 ) ) gothic_trim/wood2 0 0 0 +( 432 216 8 ) ( 432 208 8 ) ( 440 216 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 0 0 0 +( 432 216 8 ) ( 440 216 8 ) ( 440 224 40 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.754195 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 149 +{ +brushDef +{ +( 472 216 8 ) ( 464 216 8 ) ( 464 208 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 216 40 ) ( 456 224 40 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 208 8 ) ( 464 208 8 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +( 472 224 8 ) ( 472 216 8 ) ( 464 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +( 464 216 8 ) ( 472 216 8 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +( 464 216 8 ) ( 464 224 8 ) ( 456 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 150 +{ +brushDef +{ +( 456 248 40 ) ( 432 248 40 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 48 ) ( 432 248 48 ) ( 456 248 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 48 ) ( 456 216 48 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 48 ) ( 464 248 48 ) ( 464 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 248 48 ) ( 432 248 48 ) ( 432 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 248 48 ) ( 432 216 48 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 151 +{ +brushDef +{ +( 336 256 288 ) ( 0 256 288 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 0 256 296 ) ( 336 256 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 336 136 296 ) ( 336 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 128 296 ) ( 512 248 296 ) ( 512 248 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 336 256 296 ) ( 0 256 296 ) ( 0 256 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 256 296 ) ( 0 136 296 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 152 +{ +brushDef +{ +( 632 96 288 ) ( 512 96 288 ) ( 512 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 4.937803 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 8 296 ) ( 512 64 296 ) ( 632 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -4.937810 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 544 136 296 ) ( 664 136 296 ) ( 664 136 -208 ) ( ( 0.007813 0 -4.937810 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 8 296 ) ( 632 64 296 ) ( 632 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 448 296 ) ( 512 448 296 ) ( 512 448 -208 ) ( ( 0.007812 0 4.937197 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 64 296 ) ( 512 8 296 ) ( 512 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 153 +{ +brushDef +{ +( 0 96 288 ) ( -120 96 288 ) ( -120 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 8 296 ) ( -120 64 296 ) ( 0 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -88 136 296 ) ( 32 136 296 ) ( 32 136 -208 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 8 296 ) ( 0 64 296 ) ( 0 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 448 296 ) ( -120 448 296 ) ( -120 448 -208 ) ( ( 0.007812 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 64 296 ) ( -120 8 296 ) ( -120 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 154 +{ +brushDef +{ +( 48 680 8 ) ( 32 680 8 ) ( 32 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -1.000055 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 32 664 512 ) ( 32 680 512 ) ( 48 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 1.000055 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 664 112 ) ( 40 664 112 ) ( 40 664 104 ) ( ( 0.007813 0 1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 40 664 112 ) ( 40 680 112 ) ( 40 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 40 680 112 ) ( 24 680 112 ) ( 24 680 104 ) ( ( 0.007813 0 -1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 680 112 ) ( 24 664 112 ) ( 24 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 155 +{ +brushDef +{ +( 496 680 8 ) ( 480 680 8 ) ( 480 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 2.500159 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 480 664 512 ) ( 480 680 512 ) ( 496 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -2.500159 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 472 664 112 ) ( 488 664 112 ) ( 488 664 104 ) ( ( 0.007813 0 -2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 488 664 112 ) ( 488 680 112 ) ( 488 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 488 680 112 ) ( 472 680 112 ) ( 472 680 104 ) ( ( 0.007813 0 2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 472 680 112 ) ( 472 664 112 ) ( 472 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 156 +{ +brushDef +{ +( 368 424 8 ) ( 352 424 8 ) ( 352 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 1.500098 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 352 408 512 ) ( 352 424 512 ) ( 368 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.500098 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 344 408 112 ) ( 360 408 112 ) ( 360 408 104 ) ( ( 0.007813 0 -1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 360 408 112 ) ( 360 424 112 ) ( 360 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 360 424 112 ) ( 344 424 112 ) ( 344 424 104 ) ( ( 0.007813 0 1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 344 424 112 ) ( 344 408 112 ) ( 344 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 157 +{ +brushDef +{ +( 176 424 8 ) ( 160 424 8 ) ( 160 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 160 408 512 ) ( 160 424 512 ) ( 176 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 152 408 112 ) ( 168 408 112 ) ( 168 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 168 408 112 ) ( 168 424 112 ) ( 168 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 168 424 112 ) ( 152 424 112 ) ( 152 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 152 424 112 ) ( 152 408 112 ) ( 152 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 158 +{ +brushDef +{ +( 640 968 0 ) ( 336 968 0 ) ( 336 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 336 960 512 ) ( 336 968 512 ) ( 640 968 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 960 512 ) ( 208 960 512 ) ( 208 960 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 512 ) ( 640 968 512 ) ( 640 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 968 512 ) ( 336 968 512 ) ( 336 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 944 512 ) ( -128 936 512 ) ( -128 936 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 159 +{ +brushDef +{ +( 640 600 8 ) ( 640 632 8 ) ( 632 632 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 640 640 512 ) ( 640 608 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 632 608 512 ) ( 632 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 512 512 ) ( 640 512 512 ) ( 640 512 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 512 ) ( 640 544 512 ) ( 640 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 512 ) ( 632 640 512 ) ( 632 640 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 160 +{ +brushDef +{ +( 640 192 8 ) ( 640 512 8 ) ( 632 512 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 104 ) ( 640 376 104 ) ( 632 480 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 161 +{ +brushDef +{ +( 632 512 512 ) ( 640 512 512 ) ( 640 192 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 232 ) ( 632 480 232 ) ( 640 376 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 162 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 128 ) ( 640 480 128 ) ( 632 480 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 163 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 224 128 ) ( 632 224 128 ) ( 640 224 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 164 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 376 128 ) ( 632 376 128 ) ( 640 376 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 328 128 ) ( 640 328 128 ) ( 632 328 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 165 +{ +brushDef +{ +( 640 640 8 ) ( 640 960 8 ) ( 632 960 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 104 ) ( 648 672 104 ) ( 640 776 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 166 +{ +brushDef +{ +( 632 960 512 ) ( 640 960 512 ) ( 640 640 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 232 ) ( 640 776 232 ) ( 648 672 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 167 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 648 672 128 ) ( 640 672 128 ) ( 648 672 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 168 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 128 ) ( 648 776 128 ) ( 640 776 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 824 128 ) ( 640 824 128 ) ( 648 824 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 169 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 928 128 ) ( 648 928 128 ) ( 640 928 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 170 +{ +brushDef +{ +( 632 824 176 ) ( 640 824 176 ) ( 640 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 928 168 ) ( 640 928 176 ) ( 632 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 824 168 ) ( 632 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 832 168 ) ( 632 832 176 ) ( 632 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 824 176 ) ( 640 824 176 ) ( 640 800 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 640 848 176 ) ( 640 848 168 ) ( 640 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 171 +{ +brushDef +{ +( 640 872 104 ) ( 640 880 104 ) ( 632 880 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 824 168 ) ( 640 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 172 +{ +brushDef +{ +( 632 880 232 ) ( 640 880 232 ) ( 640 872 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 824 176 ) ( 632 824 176 ) ( 640 800 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 173 +{ +brushDef +{ +( 632 728 232 ) ( 640 728 232 ) ( 640 720 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 672 176 ) ( 632 672 176 ) ( 640 648 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 174 +{ +brushDef +{ +( 640 720 104 ) ( 640 728 104 ) ( 632 728 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 672 168 ) ( 640 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 175 +{ +brushDef +{ +( 632 672 176 ) ( 640 672 176 ) ( 640 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 776 168 ) ( 640 776 176 ) ( 632 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 672 168 ) ( 632 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( 632 680 168 ) ( 632 680 176 ) ( 632 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +( 632 672 176 ) ( 640 672 176 ) ( 640 648 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( 640 696 176 ) ( 640 696 168 ) ( 640 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 176 +{ +brushDef +{ +( 632 376 176 ) ( 640 376 176 ) ( 640 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 480 168 ) ( 640 480 176 ) ( 632 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 376 168 ) ( 632 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 384 168 ) ( 632 384 176 ) ( 632 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 376 176 ) ( 640 376 176 ) ( 640 352 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( 640 400 176 ) ( 640 400 168 ) ( 640 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 177 +{ +brushDef +{ +( 640 424 104 ) ( 640 432 104 ) ( 632 432 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 376 168 ) ( 640 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 178 +{ +brushDef +{ +( 632 432 232 ) ( 640 432 232 ) ( 640 424 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 176 ) ( 632 376 176 ) ( 640 352 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 179 +{ +brushDef +{ +( 632 280 232 ) ( 640 280 232 ) ( 640 272 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 224 176 ) ( 632 224 176 ) ( 640 200 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 180 +{ +brushDef +{ +( 640 272 104 ) ( 640 280 104 ) ( 632 280 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 224 168 ) ( 640 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 181 +{ +brushDef +{ +( 632 224 176 ) ( 640 224 176 ) ( 640 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 328 168 ) ( 640 328 176 ) ( 632 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 224 168 ) ( 632 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( 632 232 168 ) ( 632 232 176 ) ( 632 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +( 632 224 176 ) ( 640 224 176 ) ( 640 200 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( 640 248 176 ) ( 640 248 168 ) ( 640 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 182 +{ +brushDef +{ +( -120 616 8 ) ( -120 648 8 ) ( -128 648 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -120 640 512 ) ( -120 608 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -128 608 512 ) ( -128 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 512 512 ) ( -120 512 512 ) ( -120 512 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 512 ) ( -120 544 512 ) ( -120 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 512 ) ( -128 640 512 ) ( -128 640 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 183 +{ +brushDef +{ +( -120 192 8 ) ( -120 512 8 ) ( -128 512 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 136 16 ) ( -120 456 16 ) ( -120 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 104 ) ( -120 376 104 ) ( -128 480 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 184 +{ +brushDef +{ +( -128 512 512 ) ( -120 512 512 ) ( -120 192 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 232 ) ( -128 480 232 ) ( -120 376 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 185 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 128 ) ( -120 480 128 ) ( -128 480 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 186 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 224 128 ) ( -128 224 128 ) ( -120 224 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 187 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 376 128 ) ( -128 376 128 ) ( -120 376 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 328 128 ) ( -120 328 128 ) ( -128 328 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 188 +{ +brushDef +{ +( -120 640 8 ) ( -120 960 8 ) ( -128 960 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 104 ) ( -112 672 104 ) ( -120 776 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 189 +{ +brushDef +{ +( -128 960 512 ) ( -120 960 512 ) ( -120 640 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 232 ) ( -120 776 232 ) ( -112 672 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 190 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -112 672 128 ) ( -120 672 128 ) ( -112 672 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 191 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 128 ) ( -112 776 128 ) ( -120 776 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 824 128 ) ( -120 824 128 ) ( -112 824 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 192 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 928 128 ) ( -112 928 128 ) ( -120 928 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 193 +{ +brushDef +{ +( -128 824 176 ) ( -120 824 176 ) ( -120 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 928 168 ) ( -120 928 176 ) ( -128 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 824 168 ) ( -128 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 832 168 ) ( -128 832 176 ) ( -128 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 824 176 ) ( -120 824 176 ) ( -120 800 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( -120 848 176 ) ( -120 848 168 ) ( -120 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 194 +{ +brushDef +{ +( -120 872 104 ) ( -120 880 104 ) ( -128 880 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 824 168 ) ( -120 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 195 +{ +brushDef +{ +( -128 880 232 ) ( -120 880 232 ) ( -120 872 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 824 176 ) ( -128 824 176 ) ( -120 800 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 196 +{ +brushDef +{ +( -128 728 232 ) ( -120 728 232 ) ( -120 720 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 672 176 ) ( -128 672 176 ) ( -120 648 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 197 +{ +brushDef +{ +( -120 720 104 ) ( -120 728 104 ) ( -128 728 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 672 168 ) ( -120 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 198 +{ +brushDef +{ +( -128 672 176 ) ( -120 672 176 ) ( -120 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 776 168 ) ( -120 776 176 ) ( -128 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 672 168 ) ( -128 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( -128 680 168 ) ( -128 680 176 ) ( -128 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +( -128 672 176 ) ( -120 672 176 ) ( -120 648 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( -120 696 176 ) ( -120 696 168 ) ( -120 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 199 +{ +brushDef +{ +( -128 376 176 ) ( -120 376 176 ) ( -120 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 480 168 ) ( -120 480 176 ) ( -128 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 376 168 ) ( -128 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 384 168 ) ( -128 384 176 ) ( -128 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 376 176 ) ( -120 376 176 ) ( -120 352 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( -120 400 176 ) ( -120 400 168 ) ( -120 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 200 +{ +brushDef +{ +( -120 424 104 ) ( -120 432 104 ) ( -128 432 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 376 168 ) ( -120 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 201 +{ +brushDef +{ +( -128 432 232 ) ( -120 432 232 ) ( -120 424 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 176 ) ( -128 376 176 ) ( -120 352 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 202 +{ +brushDef +{ +( -128 280 232 ) ( -120 280 232 ) ( -120 272 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 224 176 ) ( -128 224 176 ) ( -120 200 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 203 +{ +brushDef +{ +( -120 272 104 ) ( -120 280 104 ) ( -128 280 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 224 168 ) ( -120 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 204 +{ +brushDef +{ +( -128 224 176 ) ( -120 224 176 ) ( -120 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 328 168 ) ( -120 328 176 ) ( -128 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 224 168 ) ( -128 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( -128 232 168 ) ( -128 232 176 ) ( -128 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +( -128 224 176 ) ( -120 224 176 ) ( -120 200 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( -120 248 176 ) ( -120 248 168 ) ( -120 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 205 +{ +brushDef +{ +( 384 952 176 ) ( 80 952 176 ) ( 80 920 176 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 184 ) ( 104 952 184 ) ( 408 952 184 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 184 ) ( 408 920 184 ) ( 408 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 920 184 ) ( 408 952 184 ) ( 408 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 952 184 ) ( 104 952 184 ) ( 104 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 952 184 ) ( 104 920 184 ) ( 104 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 206 +{ +brushDef +{ +( 384 952 112 ) ( 80 952 112 ) ( 80 920 112 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 120 ) ( 104 952 120 ) ( 408 952 120 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 120 ) ( 408 920 120 ) ( 408 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 920 120 ) ( 408 952 120 ) ( 408 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 952 120 ) ( 104 952 120 ) ( 104 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 952 120 ) ( 104 920 120 ) ( 104 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 207 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 104 ) ( 104 960 104 ) ( 104 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 208 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 952 104 ) ( 416 952 104 ) ( 96 952 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 209 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 960 104 ) ( 408 920 104 ) ( 408 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 210 +{ +brushDef +{ +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 248 ) ( 96 920 248 ) ( 416 960 248 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 211 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 16 ) ( 416 960 16 ) ( 96 920 16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 212 +{ +brushDef +{ +( 144 776 8 ) ( 144 792 8 ) ( -24 792 8 ) ( ( 0 0.007813 7.250462 ) ( -0.007813 0 2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( 144 792 104 ) ( 144 776 104 ) ( ( 0 -0.007813 7.250462 ) ( 0.007813 0 -2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 776 104 ) ( -24 776 96 ) ( ( 0.007813 0 -3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 776 104 ) ( 144 776 104 ) ( 144 776 96 ) ( ( 0.007813 0 6.125393 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 768 104 ) ( 536 784 104 ) ( 536 784 96 ) ( ( 0.007813 0 3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 792 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 -6.125392 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 213 +{ +brushDef +{ +( -8 960 8 ) ( -24 960 8 ) ( -24 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 960 104 ) ( -8 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -8 792 104 ) ( -8 792 96 ) ( ( 0.007813 0 4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 792 104 ) ( -8 960 104 ) ( -8 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 960 104 ) ( -24 960 104 ) ( -24 960 96 ) ( ( 0.007813 0 -4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 960 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 214 +{ +brushDef +{ +( 536 960 8 ) ( 520 960 8 ) ( 520 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 520 960 104 ) ( 536 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 536 792 104 ) ( 536 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 792 104 ) ( 536 960 104 ) ( 536 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 960 104 ) ( 520 960 104 ) ( 520 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 960 104 ) ( 520 792 104 ) ( 520 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 215 +{ +brushDef +{ +( 272 832 104 ) ( 32 832 104 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 32 768 112 ) ( 32 832 112 ) ( 272 832 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 32 768 112 ) ( 272 768 112 ) ( 272 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 480 760 112 ) ( 480 824 112 ) ( 480 824 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 272 832 112 ) ( 32 832 112 ) ( 32 832 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 32 832 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +} +} +// brush 216 +{ +brushDef +{ +( 544 960 104 ) ( 480 960 104 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 5.500000 ) ) base_trim/pewter_spec 0 0 0 +( 480 768 112 ) ( 480 960 112 ) ( 544 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -5.500000 ) ) base_trim/pewter_spec 0 0 0 +( 480 768 112 ) ( 544 768 112 ) ( 544 768 104 ) ( ( 0.015625 0 -5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 544 768 112 ) ( 544 960 112 ) ( 544 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 544 960 112 ) ( 480 960 112 ) ( 480 960 104 ) ( ( 0.015625 0 5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 480 960 112 ) ( 480 768 112 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +} +} +// brush 217 +{ +brushDef +{ +( 32 960 104 ) ( -32 960 104 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) base_trim/pewter_spec 0 0 0 +( -32 768 112 ) ( -32 960 112 ) ( 32 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) base_trim/pewter_spec 0 0 0 +( -32 768 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 32 768 112 ) ( 32 960 112 ) ( 32 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 32 960 112 ) ( -32 960 112 ) ( -32 960 104 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( -32 960 112 ) ( -32 768 112 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +} +} +// brush 218 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 512 8.000001 0 0 ) ( 440 512 36 0 0.687500 ) ( 440 512 64 0 1.375000 ) ) +( ( 440 504 8.000001 0.125000 0 ) ( 440 504 36 0.125000 0.687500 ) ( 440 504 64 0.125000 1.375000 ) ) +( ( 448 504 8.000001 0.250000 0 ) ( 448 504 36 0.250000 0.687500 ) ( 448 504 64 0.250000 1.375000 ) ) +( ( 456 504 8.000001 0.375000 0 ) ( 456 504 36 0.375000 0.687500 ) ( 456 504 64 0.375000 1.375000 ) ) +( ( 456 512 8.000001 0.500000 0 ) ( 456 512 36 0.500000 0.687500 ) ( 456 512 64 0.500000 1.375000 ) ) +( ( 456 520 8.000001 0.625000 0 ) ( 456 520 36 0.625000 0.687500 ) ( 456 520 64 0.625000 1.375000 ) ) +( ( 448 520 8.000001 0.750000 0 ) ( 448 520 36 0.750000 0.687500 ) ( 448 520 64 0.750000 1.375000 ) ) +( ( 440 520 8.000001 0.875000 0 ) ( 440 520 36 0.875000 0.687500 ) ( 440 520 64 0.875000 1.375000 ) ) +( ( 440 512 8.000001 1 0 ) ( 440 512 36 1 0.687500 ) ( 440 512 64 1 1.375000 ) ) +) + } + } +// brush 219 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 320 8.000001 0 0 ) ( 440 320 36 0 0.687500 ) ( 440 320 64 0 1.375000 ) ) +( ( 440 312 8.000001 0.125000 0 ) ( 440 312 36 0.125000 0.687500 ) ( 440 312 64 0.125000 1.375000 ) ) +( ( 448 312 8.000001 0.250000 0 ) ( 448 312 36 0.250000 0.687500 ) ( 448 312 64 0.250000 1.375000 ) ) +( ( 456 312 8.000001 0.375000 0 ) ( 456 312 36 0.375000 0.687500 ) ( 456 312 64 0.375000 1.375000 ) ) +( ( 456 320 8.000001 0.500000 0 ) ( 456 320 36 0.500000 0.687500 ) ( 456 320 64 0.500000 1.375000 ) ) +( ( 456 328 8.000001 0.625000 0 ) ( 456 328 36 0.625000 0.687500 ) ( 456 328 64 0.625000 1.375000 ) ) +( ( 448 328 8.000001 0.750000 0 ) ( 448 328 36 0.750000 0.687500 ) ( 448 328 64 0.750000 1.375000 ) ) +( ( 440 328 8.000001 0.875000 0 ) ( 440 328 36 0.875000 0.687500 ) ( 440 328 64 0.875000 1.375000 ) ) +( ( 440 320 8.000001 1 0 ) ( 440 320 36 1 0.687500 ) ( 440 320 64 1 1.375000 ) ) +) + } + } +// brush 220 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 320 8.000001 0 0 ) ( 56 320 36 0 0.687500 ) ( 56 320 64 0 1.375000 ) ) +( ( 56 312 8.000001 0.125000 0 ) ( 56 312 36 0.125000 0.687500 ) ( 56 312 64 0.125000 1.375000 ) ) +( ( 64 312 8.000001 0.250000 0 ) ( 64 312 36 0.250000 0.687500 ) ( 64 312 64 0.250000 1.375000 ) ) +( ( 72 312 8.000001 0.375000 0 ) ( 72 312 36 0.375000 0.687500 ) ( 72 312 64 0.375000 1.375000 ) ) +( ( 72 320 8.000001 0.500000 0 ) ( 72 320 36 0.500000 0.687500 ) ( 72 320 64 0.500000 1.375000 ) ) +( ( 72 328 8.000001 0.625000 0 ) ( 72 328 36 0.625000 0.687500 ) ( 72 328 64 0.625000 1.375000 ) ) +( ( 64 328 8.000001 0.750000 0 ) ( 64 328 36 0.750000 0.687500 ) ( 64 328 64 0.750000 1.375000 ) ) +( ( 56 328 8.000001 0.875000 0 ) ( 56 328 36 0.875000 0.687500 ) ( 56 328 64 0.875000 1.375000 ) ) +( ( 56 320 8.000001 1 0 ) ( 56 320 36 1 0.687500 ) ( 56 320 64 1 1.375000 ) ) +) + } + } +// brush 221 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 512 8.000001 0 0 ) ( 56 512 36 0 0.687500 ) ( 56 512 64 0 1.375000 ) ) +( ( 56 504 8.000001 0.125000 0 ) ( 56 504 36 0.125000 0.687500 ) ( 56 504 64 0.125000 1.375000 ) ) +( ( 64 504 8.000001 0.250000 0 ) ( 64 504 36 0.250000 0.687500 ) ( 64 504 64 0.250000 1.375000 ) ) +( ( 72 504 8.000001 0.375000 0 ) ( 72 504 36 0.375000 0.687500 ) ( 72 504 64 0.375000 1.375000 ) ) +( ( 72 512 8.000001 0.500000 0 ) ( 72 512 36 0.500000 0.687500 ) ( 72 512 64 0.500000 1.375000 ) ) +( ( 72 520 8.000001 0.625000 0 ) ( 72 520 36 0.625000 0.687500 ) ( 72 520 64 0.625000 1.375000 ) ) +( ( 64 520 8.000001 0.750000 0 ) ( 64 520 36 0.750000 0.687500 ) ( 64 520 64 0.750000 1.375000 ) ) +( ( 56 520 8.000001 0.875000 0 ) ( 56 520 36 0.875000 0.687500 ) ( 56 520 64 0.875000 1.375000 ) ) +( ( 56 512 8.000001 1 0 ) ( 56 512 36 1 0.687500 ) ( 56 512 64 1 1.375000 ) ) +) + } + } +// brush 222 +{ +brushDef +{ +( 608 128 176 ) ( 608 136 176 ) ( 608 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( 504 136 168 ) ( 504 136 176 ) ( 504 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 608 136 168 ) ( 608 128 168 ) ( 632 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -12.750000 ) ) gothic_trim/wood2 0 0 0 +( 600 128 168 ) ( 600 128 176 ) ( 624 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 6.250000 ) ) gothic_trim/wood2 0 0 0 +( 608 128 176 ) ( 608 136 176 ) ( 632 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -12.750000 ) ) gothic_trim/wood2 0 0 0 +( 584 136 176 ) ( 584 136 168 ) ( 608 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 6.250000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 223 +{ +brushDef +{ +( 560 136 104 ) ( 552 136 104 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 128 168 ) ( 608 136 168 ) ( 632 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 224 +{ +brushDef +{ +( 552 128 232 ) ( 552 136 232 ) ( 560 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 176 ) ( 608 128 176 ) ( 632 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 225 +{ +brushDef +{ +( 400 128 232 ) ( 400 136 232 ) ( 408 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 0 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 176 ) ( 456 128 176 ) ( 480 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 226 +{ +brushDef +{ +( 408 136 104 ) ( 400 136 104 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 0 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 128 168 ) ( 456 136 168 ) ( 480 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 227 +{ +brushDef +{ +( 456 128 176 ) ( 456 136 176 ) ( 456 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( 352 136 168 ) ( 352 136 176 ) ( 352 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 456 136 168 ) ( 456 128 168 ) ( 480 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 448 128 168 ) ( 448 128 176 ) ( 472 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 3.875000 ) ) gothic_trim/wood2 0 0 0 +( 456 128 176 ) ( 456 136 176 ) ( 480 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 136 176 ) ( 432 136 168 ) ( 456 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 3.875000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 228 +{ +brushDef +{ +( 160 128 176 ) ( 160 136 176 ) ( 160 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( 56 136 168 ) ( 56 136 176 ) ( 56 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 160 136 168 ) ( 160 128 168 ) ( 184 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -5.750000 ) ) gothic_trim/wood2 0 0 0 +( 152 128 168 ) ( 152 128 176 ) ( 176 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -0.750000 ) ) gothic_trim/wood2 0 0 0 +( 160 128 176 ) ( 160 136 176 ) ( 184 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -5.750000 ) ) gothic_trim/wood2 0 0 0 +( 136 136 176 ) ( 136 136 168 ) ( 160 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -0.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 229 +{ +brushDef +{ +( 112 136 104 ) ( 104 136 104 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 0 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 128 168 ) ( 160 136 168 ) ( 184 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 230 +{ +brushDef +{ +( 104 128 232 ) ( 104 136 232 ) ( 112 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 0 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 136 176 ) ( 160 128 176 ) ( 184 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 231 +{ +brushDef +{ +( -48 128 232 ) ( -48 136 232 ) ( -40 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 136 176 ) ( 8 128 176 ) ( 32 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 232 +{ +brushDef +{ +( -40 136 104 ) ( -48 136 104 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 128 168 ) ( 8 136 168 ) ( 32 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 233 +{ +brushDef +{ +( 8 128 176 ) ( 8 136 176 ) ( 8 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( -96 136 168 ) ( -96 136 176 ) ( -96 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 8 136 168 ) ( 8 128 168 ) ( 32 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -3.375000 ) ) gothic_trim/wood2 0 0 0 +( 0 128 168 ) ( 0 128 176 ) ( 24 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 128 176 ) ( 8 136 176 ) ( 32 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -3.375000 ) ) gothic_trim/wood2 0 0 0 +( -16 136 176 ) ( -16 136 168 ) ( 8 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 234 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 136 128 ) ( -96 144 128 ) ( -96 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 235 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 128 ) ( 56 144 128 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 144 128 ) ( 8 136 128 ) ( 8 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 236 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 128 ) ( 160 136 128 ) ( 160 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 237 +{ +brushDef +{ +( 192 136 8 ) ( -128 136 8 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 104 ) ( 160 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 238 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 128 ) ( 456 128 128 ) ( 456 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 128 ) ( 504 136 128 ) ( 504 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 239 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 128 ) ( 608 128 128 ) ( 608 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 240 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 128 ) ( 352 136 128 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 241 +{ +brushDef +{ +( 640 136 8 ) ( 320 136 8 ) ( 320 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 104 ) ( 456 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 242 +{ +brushDef +{ +( 624 -144 -40 ) ( 408 -144 -40 ) ( 408 -184 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 -16 ) ( 408 -144 -16 ) ( 624 -144 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 0 ) ( 624 -184 0 ) ( 624 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -184 0 ) ( 624 -144 0 ) ( 624 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -144 0 ) ( 408 -144 0 ) ( 408 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -144 0 ) ( 408 -184 0 ) ( 408 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +} +} +// brush 243 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 -192 24 ) ( 408 -136 24 ) ( 408 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 244 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -144 24 ) ( 632 -144 24 ) ( 400 -144 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 245 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 624 -136 24 ) ( 624 -192 24 ) ( 624 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 246 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -184 24 ) ( 400 -184 24 ) ( 632 -184 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 247 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 -40 ) ( 632 -136 -40 ) ( 400 -192 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 248 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +( 304 176 128 ) ( 312 176 128 ) ( 304 176 120 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 249 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +( 312 152 128 ) ( 304 152 128 ) ( 312 152 120 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 250 +{ +brushDef +{ +( 304 192 152 ) ( 312 192 152 ) ( 312 144 152 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 176 144 ) ( 304 176 144 ) ( 312 152 144 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 251 +{ +brushDef +{ +( 312 144 64 ) ( 312 192 64 ) ( 304 192 64 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 176 72 ) ( 312 152 72 ) ( 304 176 72 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 252 +{ +brushDef +{ +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.007813 3.375216 ) ( -0.007813 0 -0.562538 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.007813 3.375216 ) ( 0.007813 0 0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 304 176 128 ) ( 304 152 128 ) ( 304 152 120 ) ( ( 0.007813 0 1.062570 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 304 152 128 ) ( 312 152 128 ) ( 312 152 120 ) ( ( 0.007813 0 3.125201 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 312 152 128 ) ( 312 176 128 ) ( 312 176 120 ) ( ( 0.007813 0 -1.062568 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 312 176 128 ) ( 304 176 128 ) ( 304 176 120 ) ( ( 0.007813 0 -3.125200 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 253 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +( 208 152 128 ) ( 200 152 128 ) ( 208 152 120 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 254 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +( 200 176 128 ) ( 208 176 128 ) ( 200 176 120 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 255 +{ +brushDef +{ +( 208 144 152 ) ( 200 144 152 ) ( 200 192 152 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 152 144 ) ( 208 152 144 ) ( 200 176 144 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 256 +{ +brushDef +{ +( 200 192 64 ) ( 200 144 64 ) ( 208 144 64 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 152 72 ) ( 200 176 72 ) ( 208 152 72 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 257 +{ +brushDef +{ +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.007813 -0.500000 ) ( 0.007813 0 -3 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.007813 -0.500000 ) ( -0.007813 0 3 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 208 152 128 ) ( 208 176 128 ) ( 208 176 120 ) ( ( 0.007813 0 -3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 208 176 128 ) ( 200 176 128 ) ( 200 176 120 ) ( ( 0.007813 0 0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 200 176 128 ) ( 200 152 128 ) ( 200 152 120 ) ( ( 0.007813 0 3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 200 152 128 ) ( 208 152 128 ) ( 208 152 120 ) ( ( 0.007813 0 -0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 258 +{ +brushDef +{ +( 136 -128 -48 ) ( 136 -152 -48 ) ( 144 -152 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -128 0 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -152 8 ) ( 144 -128 8 ) ( 144 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -128 8 ) ( 136 -128 8 ) ( 136 -128 0 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -152 8 ) ( 144 -152 8 ) ( 144 -152 0 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 259 +{ +brushDef +{ +( 136 -152 -48 ) ( 136 -176 -48 ) ( 144 -176 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -152 -8 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -176 0 ) ( 144 -152 0 ) ( 144 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -152 -8 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -176 0 ) ( 144 -176 0 ) ( 144 -176 -8 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 260 +{ +brushDef +{ +( 136 -176 -48 ) ( 136 -200 -48 ) ( 144 -200 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -176 -16 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -200 -8 ) ( 144 -176 -8 ) ( 144 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -176 -16 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -200 -8 ) ( 144 -200 -8 ) ( 144 -200 -16 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 261 +{ +brushDef +{ +( 136 -200 -48 ) ( 136 -224 -48 ) ( 144 -224 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -200 -24 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -224 -16 ) ( 144 -200 -16 ) ( 144 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -200 -24 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -224 -16 ) ( 144 -224 -16 ) ( 144 -224 -24 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 262 +{ +brushDef +{ +( 136 -224 -48 ) ( 136 -248 -48 ) ( 144 -248 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -224 -32 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -248 -24 ) ( 144 -224 -24 ) ( 144 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -224 -32 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -248 -24 ) ( 144 -248 -24 ) ( 144 -248 -32 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 263 +{ +brushDef +{ +( 136 -248 -48 ) ( 136 -272 -48 ) ( 144 -272 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -272 -40 ) ( 136 -272 -40 ) ( 136 -248 -40 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -272 -32 ) ( 144 -248 -32 ) ( 144 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -248 -40 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -272 -32 ) ( 144 -272 -32 ) ( 144 -272 -40 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 264 +{ +brushDef +{ +( 368 -248 -48 ) ( 368 -272 -48 ) ( 376 -272 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -272 -40 ) ( 368 -272 -40 ) ( 368 -248 -40 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -248 -40 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -248 -32 ) ( 368 -272 -32 ) ( 368 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -272 -32 ) ( 376 -272 -32 ) ( 376 -272 -40 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 265 +{ +brushDef +{ +( 368 -224 -48 ) ( 368 -248 -48 ) ( 376 -248 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -224 -32 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -224 -32 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -224 -24 ) ( 368 -248 -24 ) ( 368 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -248 -24 ) ( 376 -248 -24 ) ( 376 -248 -32 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 266 +{ +brushDef +{ +( 368 -200 -48 ) ( 368 -224 -48 ) ( 376 -224 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -200 -24 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -200 -24 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -200 -16 ) ( 368 -224 -16 ) ( 368 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -224 -16 ) ( 376 -224 -16 ) ( 376 -224 -24 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 267 +{ +brushDef +{ +( 368 -176 -48 ) ( 368 -200 -48 ) ( 376 -200 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -176 -16 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -176 -16 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -176 -8 ) ( 368 -200 -8 ) ( 368 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -200 -8 ) ( 376 -200 -8 ) ( 376 -200 -16 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 268 +{ +brushDef +{ +( 368 -152 -48 ) ( 368 -176 -48 ) ( 376 -176 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -152 -8 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -152 -8 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -152 0 ) ( 368 -176 0 ) ( 368 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -176 0 ) ( 376 -176 0 ) ( 376 -176 -8 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 269 +{ +brushDef +{ +( 368 -128 -48 ) ( 368 -152 -48 ) ( 376 -152 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -128 0 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -128 8 ) ( 368 -128 8 ) ( 368 -128 0 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -128 8 ) ( 368 -152 8 ) ( 368 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -152 8 ) ( 376 -152 8 ) ( 376 -152 0 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 270 +{ +brushDef +{ +( 640 -128 -48 ) ( 664 -128 -48 ) ( 664 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 640 -128 0 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 8 ) ( 640 -120 8 ) ( 640 -120 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -120 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -128 8 ) ( 664 -120 8 ) ( 664 -120 0 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 271 +{ +brushDef +{ +( 664 -128 -48 ) ( 688 -128 -48 ) ( 688 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 664 -128 -8 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -120 0 ) ( 664 -120 0 ) ( 664 -120 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -128 0 ) ( 688 -120 0 ) ( 688 -120 -8 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 272 +{ +brushDef +{ +( 688 -128 -48 ) ( 712 -128 -48 ) ( 712 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 688 -128 -16 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -120 -8 ) ( 688 -120 -8 ) ( 688 -120 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -128 -8 ) ( 712 -120 -8 ) ( 712 -120 -16 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 273 +{ +brushDef +{ +( 712 -128 -48 ) ( 736 -128 -48 ) ( 736 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 712 -128 -24 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -120 -16 ) ( 712 -120 -16 ) ( 712 -120 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.007813 0 -5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -128 -16 ) ( 736 -120 -16 ) ( 736 -120 -24 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 274 +{ +brushDef +{ +( 736 -128 -48 ) ( 760 -128 -48 ) ( 760 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 736 -128 -32 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -120 -24 ) ( 736 -120 -24 ) ( 736 -120 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.007813 0 -6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -128 -24 ) ( 760 -120 -24 ) ( 760 -120 -32 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 275 +{ +brushDef +{ +( 760 -128 -48 ) ( 784 -128 -48 ) ( 784 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 -120 -40 ) ( 784 -128 -40 ) ( 760 -128 -40 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 -120 -32 ) ( 760 -120 -32 ) ( 760 -120 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.007813 0 -6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 -128 -32 ) ( 784 -120 -32 ) ( 784 -120 -40 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 276 +{ +brushDef +{ +( 760 120 -48 ) ( 784 120 -48 ) ( 784 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 128 -40 ) ( 784 120 -40 ) ( 760 120 -40 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 760 120 -40 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 120 -32 ) ( 784 120 -32 ) ( 784 120 -40 ) ( ( 0.007813 0 -6.187878 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 120 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 277 +{ +brushDef +{ +( 736 120 -48 ) ( 760 120 -48 ) ( 760 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 736 120 -32 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 736 120 -32 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 120 -24 ) ( 760 120 -24 ) ( 760 120 -32 ) ( ( 0.007813 0 -6.000367 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 120 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 278 +{ +brushDef +{ +( 712 120 -48 ) ( 736 120 -48 ) ( 736 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 712 120 -24 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 712 120 -24 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 120 -16 ) ( 736 120 -16 ) ( 736 120 -24 ) ( ( 0.007813 0 -5.812856 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 120 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 279 +{ +brushDef +{ +( 688 120 -48 ) ( 712 120 -48 ) ( 712 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 688 120 -16 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 688 120 -16 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 120 -8 ) ( 712 120 -8 ) ( 712 120 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 120 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 280 +{ +brushDef +{ +( 664 120 -48 ) ( 688 120 -48 ) ( 688 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 664 120 -8 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 664 120 -8 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 120 0 ) ( 688 120 0 ) ( 688 120 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 120 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 281 +{ +brushDef +{ +( 640 120 -48 ) ( 664 120 -48 ) ( 664 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 640 120 0 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 128 8 ) ( 640 120 8 ) ( 640 120 0 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 120 8 ) ( 664 120 8 ) ( 664 120 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 120 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 282 +{ +brushDef +{ +( -128 128 -48 ) ( -152 128 -48 ) ( -152 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 120 8 ) ( -128 120 8 ) ( -128 120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 120 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 128 8 ) ( -152 120 8 ) ( -152 120 0 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 283 +{ +brushDef +{ +( -152 128 -48 ) ( -176 128 -48 ) ( -176 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 120 0 ) ( -152 120 0 ) ( -152 120 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 128 0 ) ( -176 120 0 ) ( -176 120 -8 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 284 +{ +brushDef +{ +( -176 128 -48 ) ( -200 128 -48 ) ( -200 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 120 -8 ) ( -176 120 -8 ) ( -176 120 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 128 -8 ) ( -200 120 -8 ) ( -200 120 -16 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 285 +{ +brushDef +{ +( -200 128 -48 ) ( -224 128 -48 ) ( -224 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 120 -16 ) ( -200 120 -16 ) ( -200 120 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 128 -16 ) ( -224 120 -16 ) ( -224 120 -24 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 286 +{ +brushDef +{ +( -224 128 -48 ) ( -248 128 -48 ) ( -248 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 120 -24 ) ( -224 120 -24 ) ( -224 120 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 128 -24 ) ( -248 120 -24 ) ( -248 120 -32 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 287 +{ +brushDef +{ +( -248 128 -48 ) ( -272 128 -48 ) ( -272 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 120 -40 ) ( -272 128 -40 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 120 -32 ) ( -248 120 -32 ) ( -248 120 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 128 -32 ) ( -272 120 -32 ) ( -272 120 -40 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 288 +{ +brushDef +{ +( -248 -120 -48 ) ( -272 -120 -48 ) ( -272 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 -128 -40 ) ( -272 -120 -40 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -120 -32 ) ( -272 -120 -32 ) ( -272 -120 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 -120 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 289 +{ +brushDef +{ +( -224 -120 -48 ) ( -248 -120 -48 ) ( -248 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -120 -24 ) ( -248 -120 -24 ) ( -248 -120 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -120 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 290 +{ +brushDef +{ +( -200 -120 -48 ) ( -224 -120 -48 ) ( -224 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -120 -16 ) ( -224 -120 -16 ) ( -224 -120 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -120 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 291 +{ +brushDef +{ +( -176 -120 -48 ) ( -200 -120 -48 ) ( -200 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -120 -8 ) ( -200 -120 -8 ) ( -200 -120 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -120 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 292 +{ +brushDef +{ +( -152 -120 -48 ) ( -176 -120 -48 ) ( -176 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -120 0 ) ( -176 -120 0 ) ( -176 -120 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -120 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 293 +{ +brushDef +{ +( -128 -120 -48 ) ( -152 -120 -48 ) ( -152 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 8 ) ( -128 -120 8 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -120 8 ) ( -152 -120 8 ) ( -152 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -120 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 294 +{ +brushDef +{ +( 384 -152 0 ) ( 384 -128 0 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -128 8 ) ( 384 -128 8 ) ( 384 -152 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -152 8 ) ( 384 -152 8 ) ( 384 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -128 8 ) ( 128 -128 8 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 295 +{ +brushDef +{ +( 384 -176 -8 ) ( 384 -152 -8 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -152 0 ) ( 384 -152 0 ) ( 384 -176 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -176 0 ) ( 384 -176 0 ) ( 384 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -152 0 ) ( 128 -152 0 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 296 +{ +brushDef +{ +( 384 -200 -16 ) ( 384 -176 -16 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -176 -8 ) ( 384 -176 -8 ) ( 384 -200 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -200 -8 ) ( 384 -200 -8 ) ( 384 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -176 -8 ) ( 128 -176 -8 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 297 +{ +brushDef +{ +( 384 -224 -24 ) ( 384 -200 -24 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -200 -16 ) ( 384 -200 -16 ) ( 384 -224 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -224 -16 ) ( 384 -224 -16 ) ( 384 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -200 -16 ) ( 128 -200 -16 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 298 +{ +brushDef +{ +( 384 -248 -32 ) ( 384 -224 -32 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -224 -24 ) ( 384 -224 -24 ) ( 384 -248 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -248 -24 ) ( 384 -248 -24 ) ( 384 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -224 -24 ) ( 128 -224 -24 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 299 +{ +brushDef +{ +( 384 -272 -40 ) ( 384 -248 -40 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -248 -32 ) ( 384 -248 -32 ) ( 384 -272 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -272 -32 ) ( 384 -272 -32 ) ( 384 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -248 -32 ) ( 128 -248 -32 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 300 +{ +brushDef +{ +( 384 -296 -48 ) ( 384 -272 -48 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -272 -40 ) ( 384 -272 -40 ) ( 384 -296 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -272 -40 ) ( 136 -296 -40 ) ( 136 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -296 -40 ) ( 384 -296 -40 ) ( 384 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -296 -40 ) ( 376 -272 -40 ) ( 376 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -272 -40 ) ( 128 -272 -40 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 301 +{ +brushDef +{ +( 136 -120 -48 ) ( 24 -120 -48 ) ( 24 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 8 ) ( 24 -120 8 ) ( 136 -120 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 -40 ) ( 136 -128 -40 ) ( 136 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -144 -40 ) ( 640 -136 -40 ) ( 640 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -120 -40 ) ( 24 -120 -40 ) ( 24 -120 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 -40 ) ( -128 -136 -40 ) ( -128 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 302 +{ +brushDef +{ +( -152 -128 0 ) ( -128 -128 0 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -152 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 128 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 303 +{ +brushDef +{ +( -176 -128 -8 ) ( -152 -128 -8 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 128 0 ) ( -152 -128 0 ) ( -176 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 128 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 -128 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 304 +{ +brushDef +{ +( -200 -128 -16 ) ( -176 -128 -16 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 128 -8 ) ( -176 -128 -8 ) ( -200 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 128 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 -128 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 305 +{ +brushDef +{ +( -224 -128 -24 ) ( -200 -128 -24 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 128 -16 ) ( -200 -128 -16 ) ( -224 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 128 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 -128 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 306 +{ +brushDef +{ +( -248 -128 -32 ) ( -224 -128 -32 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 128 -24 ) ( -224 -128 -24 ) ( -248 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 128 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 -128 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 307 +{ +brushDef +{ +( -272 -128 -40 ) ( -248 -128 -40 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 128 -32 ) ( -248 -128 -32 ) ( -272 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 128 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 -128 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 308 +{ +brushDef +{ +( -296 -128 -48 ) ( -272 -128 -48 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 128 -40 ) ( -272 -128 -40 ) ( -296 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 128 -40 ) ( -296 128 -40 ) ( -296 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -296 128 -40 ) ( -296 -128 -40 ) ( -296 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -296 -128 -40 ) ( -272 -128 -40 ) ( -272 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 -128 -40 ) ( -272 128 -40 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 309 +{ +brushDef +{ +( 808 128 -48 ) ( 784 128 -48 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 -128 -40 ) ( 784 128 -40 ) ( 808 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 -128 -40 ) ( 808 -128 -40 ) ( 808 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 808 -128 -40 ) ( 808 128 -40 ) ( 808 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 808 128 -40 ) ( 784 128 -40 ) ( 784 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 128 -40 ) ( 784 -128 -40 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 310 +{ +brushDef +{ +( 784 128 -40 ) ( 760 128 -40 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 -128 -32 ) ( 760 128 -32 ) ( 784 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 -128 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 128 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 311 +{ +brushDef +{ +( 760 128 -32 ) ( 736 128 -32 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 -128 -24 ) ( 736 128 -24 ) ( 760 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 -128 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 128 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 312 +{ +brushDef +{ +( 736 128 -24 ) ( 712 128 -24 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 -128 -16 ) ( 712 128 -16 ) ( 736 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 -128 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 128 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 313 +{ +brushDef +{ +( 712 128 -16 ) ( 688 128 -16 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 -128 -8 ) ( 688 128 -8 ) ( 712 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 -128 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 128 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 314 +{ +brushDef +{ +( 688 128 -8 ) ( 664 128 -8 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 0 ) ( 664 128 0 ) ( 688 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 -128 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 128 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 315 +{ +brushDef +{ +( 664 128 0 ) ( 640 128 0 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 640 128 8 ) ( 664 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 316 +{ +brushDef +{ +( -120 -120 72 ) ( -888 -120 72 ) ( -888 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( -888 -128 224 ) ( -888 -120 224 ) ( -120 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( -888 -128 232 ) ( -120 -128 232 ) ( -120 -128 72 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 -128 232 ) ( -120 -120 232 ) ( -120 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 -120 232 ) ( -888 -120 232 ) ( -888 -120 72 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -120 232 ) ( -128 -128 232 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 317 +{ +brushDef +{ +( -56 -120 72 ) ( -824 -120 72 ) ( -824 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( -824 -128 224 ) ( -824 -120 224 ) ( -56 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 0 0 0 +( -824 -128 232 ) ( -56 -128 232 ) ( -56 -128 72 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -56 -128 232 ) ( -56 -120 232 ) ( -56 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -56 -120 232 ) ( -824 -120 232 ) ( -824 -120 72 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -64 -120 232 ) ( -64 -128 232 ) ( -64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 318 +{ +brushDef +{ +( 8 -120 72 ) ( -760 -120 72 ) ( -760 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 0 0 0 +( -760 -128 224 ) ( -760 -120 224 ) ( 8 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 0 0 0 +( -760 -128 232 ) ( 8 -128 232 ) ( 8 -128 72 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 -128 232 ) ( 8 -120 232 ) ( 8 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 -120 232 ) ( -760 -120 232 ) ( -760 -120 72 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 0 -120 232 ) ( 0 -128 232 ) ( 0 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 319 +{ +brushDef +{ +( 72 -120 72 ) ( -696 -120 72 ) ( -696 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 0 0 0 +( -696 -128 224 ) ( -696 -120 224 ) ( 72 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 0 0 0 +( -696 -128 232 ) ( 72 -128 232 ) ( 72 -128 72 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 72 -128 232 ) ( 72 -120 232 ) ( 72 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 72 -120 232 ) ( -696 -120 232 ) ( -696 -120 72 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 64 -120 232 ) ( 64 -128 232 ) ( 64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 320 +{ +brushDef +{ +( 136 -120 72 ) ( -632 -120 72 ) ( -632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( -632 -128 224 ) ( -632 -120 224 ) ( 136 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( -632 -128 232 ) ( 136 -128 232 ) ( 136 -128 72 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 232 ) ( 136 -120 232 ) ( 136 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -120 232 ) ( -632 -120 232 ) ( -632 -120 72 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -120 232 ) ( 128 -128 232 ) ( 128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 321 +{ +brushDef +{ +( 384 -120 72 ) ( -384 -120 72 ) ( -384 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 0 0 0 +( -384 -128 224 ) ( -384 -120 224 ) ( 384 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 0 0 0 +( -384 -128 232 ) ( 384 -128 232 ) ( 384 -128 72 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -128 232 ) ( 384 -120 232 ) ( 384 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -120 232 ) ( -384 -120 232 ) ( -384 -120 72 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -120 232 ) ( 376 -128 232 ) ( 376 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 322 +{ +brushDef +{ +( 448 -120 72 ) ( -320 -120 72 ) ( -320 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 0 0 0 +( -320 -128 224 ) ( -320 -120 224 ) ( 448 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 0 0 0 +( -320 -128 232 ) ( 448 -128 232 ) ( 448 -128 72 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 -128 232 ) ( 448 -120 232 ) ( 448 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 -120 232 ) ( -320 -120 232 ) ( -320 -120 72 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 -120 232 ) ( 440 -128 232 ) ( 440 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 323 +{ +brushDef +{ +( 512 -120 72 ) ( -256 -120 72 ) ( -256 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 0 0 0 +( -256 -128 224 ) ( -256 -120 224 ) ( 512 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 0 0 0 +( -256 -128 232 ) ( 512 -128 232 ) ( 512 -128 72 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 512 -128 232 ) ( 512 -120 232 ) ( 512 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 512 -120 232 ) ( -256 -120 232 ) ( -256 -120 72 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 -120 232 ) ( 504 -128 232 ) ( 504 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 324 +{ +brushDef +{ +( 576 -120 72 ) ( -192 -120 72 ) ( -192 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 0 0 0 +( -192 -128 224 ) ( -192 -120 224 ) ( 576 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 0 0 0 +( -192 -128 232 ) ( 576 -128 232 ) ( 576 -128 72 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 576 -128 232 ) ( 576 -120 232 ) ( 576 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 576 -120 232 ) ( -192 -120 232 ) ( -192 -120 72 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 568 -120 232 ) ( 568 -128 232 ) ( 568 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 325 +{ +brushDef +{ +( 640 -120 72 ) ( -128 -120 72 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 224 ) ( -128 -120 224 ) ( 640 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 232 ) ( 640 -128 232 ) ( 640 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 232 ) ( 640 -120 232 ) ( 640 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 232 ) ( -128 -120 232 ) ( -128 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -120 232 ) ( 632 -128 232 ) ( 632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 326 +{ +brushDef +{ +( -128 -128 224 ) ( 640 -128 224 ) ( 640 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 232 ) ( -128 -128 232 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( -128 -128 224 ) ( -128 -128 232 ) ( 640 -128 232 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 320 ) ( 640 128 320 ) ( 640 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -32 128 320 ) ( -128 128 320 ) ( -128 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 232 ) ( -128 -128 224 ) ( -128 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 327 +{ +brushDef +{ +( 664 -120 64 ) ( 384 -120 64 ) ( 384 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 72 ) ( 376 -120 72 ) ( 656 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 72 ) ( 656 -128 72 ) ( 656 -128 16 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 72 ) ( 640 -120 72 ) ( 640 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 656 -120 72 ) ( 376 -120 72 ) ( 376 -120 16 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 376 -120 72 ) ( 376 -128 72 ) ( 376 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 328 +{ +brushDef +{ +( 160 -120 64 ) ( -120 -120 64 ) ( -120 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 72 ) ( -128 -120 72 ) ( 152 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 72 ) ( 152 -128 72 ) ( 152 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 72 ) ( 136 -120 72 ) ( 136 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 152 -120 72 ) ( -128 -120 72 ) ( -128 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 -120 72 ) ( -128 -128 72 ) ( -128 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 329 +{ +brushDef +{ +( 384 -120 8 ) ( 376 -120 8 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 64 ) ( 376 -120 64 ) ( 384 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 16 ) ( 384 -128 16 ) ( 384 -128 8 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 384 -128 16 ) ( 384 -120 16 ) ( 384 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 384 -120 16 ) ( 376 -120 16 ) ( 376 -120 8 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 376 -120 16 ) ( 376 -128 16 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 330 +{ +brushDef +{ +( 416 -120 8 ) ( 408 -120 8 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 -128 64 ) ( 408 -120 64 ) ( 416 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 -128 16 ) ( 416 -128 16 ) ( 416 -128 8 ) ( ( 0.015625 0 -8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 416 -128 16 ) ( 416 -120 16 ) ( 416 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 416 -120 16 ) ( 408 -120 16 ) ( 408 -120 8 ) ( ( 0.015625 0 8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 408 -120 16 ) ( 408 -128 16 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 331 +{ +brushDef +{ +( 448 -120 8 ) ( 440 -120 8 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 -128 64 ) ( 440 -120 64 ) ( 448 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 -128 16 ) ( 448 -128 16 ) ( 448 -128 8 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 448 -128 16 ) ( 448 -120 16 ) ( 448 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 448 -120 16 ) ( 440 -120 16 ) ( 440 -120 8 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 440 -120 16 ) ( 440 -128 16 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 332 +{ +brushDef +{ +( 480 -120 8 ) ( 472 -120 8 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 -128 64 ) ( 472 -120 64 ) ( 480 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 -128 16 ) ( 480 -128 16 ) ( 480 -128 8 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 480 -128 16 ) ( 480 -120 16 ) ( 480 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 480 -120 16 ) ( 472 -120 16 ) ( 472 -120 8 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 472 -120 16 ) ( 472 -128 16 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 333 +{ +brushDef +{ +( 512 -120 8 ) ( 504 -120 8 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 -128 64 ) ( 504 -120 64 ) ( 512 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 -128 16 ) ( 512 -128 16 ) ( 512 -128 8 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 512 -128 16 ) ( 512 -120 16 ) ( 512 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 512 -120 16 ) ( 504 -120 16 ) ( 504 -120 8 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 -120 16 ) ( 504 -128 16 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 334 +{ +brushDef +{ +( 544 -120 8 ) ( 536 -120 8 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 -128 64 ) ( 536 -120 64 ) ( 544 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 -128 16 ) ( 544 -128 16 ) ( 544 -128 8 ) ( ( 0.015625 0 -10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 544 -128 16 ) ( 544 -120 16 ) ( 544 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 544 -120 16 ) ( 536 -120 16 ) ( 536 -120 8 ) ( ( 0.015625 0 10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 536 -120 16 ) ( 536 -128 16 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 335 +{ +brushDef +{ +( 576 -120 8 ) ( 568 -120 8 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 -128 64 ) ( 568 -120 64 ) ( 576 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 -128 16 ) ( 576 -128 16 ) ( 576 -128 8 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 576 -128 16 ) ( 576 -120 16 ) ( 576 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 576 -120 16 ) ( 568 -120 16 ) ( 568 -120 8 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 568 -120 16 ) ( 568 -128 16 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 336 +{ +brushDef +{ +( 608 -120 8 ) ( 600 -120 8 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 -128 64 ) ( 600 -120 64 ) ( 608 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 -128 16 ) ( 608 -128 16 ) ( 608 -128 8 ) ( ( 0.015625 0 -11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 608 -128 16 ) ( 608 -120 16 ) ( 608 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 608 -120 16 ) ( 600 -120 16 ) ( 600 -120 8 ) ( ( 0.015625 0 11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 600 -120 16 ) ( 600 -128 16 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 337 +{ +brushDef +{ +( 640 -120 8 ) ( 632 -120 8 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 -128 64 ) ( 632 -120 64 ) ( 640 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 -128 16 ) ( 640 -128 16 ) ( 640 -128 8 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 16 ) ( 640 -120 16 ) ( 640 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 16 ) ( 632 -120 16 ) ( 632 -120 8 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 -120 16 ) ( 632 -128 16 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 338 +{ +brushDef +{ +( -88 -120 8 ) ( -96 -120 8 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 -128 64 ) ( -96 -120 64 ) ( -88 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 -128 16 ) ( -88 -128 16 ) ( -88 -128 8 ) ( ( 0.015625 0 -0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -88 -128 16 ) ( -88 -120 16 ) ( -88 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -88 -120 16 ) ( -96 -120 16 ) ( -96 -120 8 ) ( ( 0.015625 0 0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -96 -120 16 ) ( -96 -128 16 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 339 +{ +brushDef +{ +( -24 -120 8 ) ( -32 -120 8 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 -128 64 ) ( -32 -120 64 ) ( -24 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 -128 16 ) ( -24 -128 16 ) ( -24 -128 8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -24 -128 16 ) ( -24 -120 16 ) ( -24 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -24 -120 16 ) ( -32 -120 16 ) ( -32 -120 8 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -32 -120 16 ) ( -32 -128 16 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 340 +{ +brushDef +{ +( 40 -120 8 ) ( 32 -120 8 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 -128 64 ) ( 32 -120 64 ) ( 40 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 -128 16 ) ( 40 -128 16 ) ( 40 -128 8 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 40 -128 16 ) ( 40 -120 16 ) ( 40 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 40 -120 16 ) ( 32 -120 16 ) ( 32 -120 8 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 32 -120 16 ) ( 32 -128 16 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 341 +{ +brushDef +{ +( 104 -120 8 ) ( 96 -120 8 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 -128 64 ) ( 96 -120 64 ) ( 104 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 -128 16 ) ( 104 -128 16 ) ( 104 -128 8 ) ( ( 0.015625 0 -3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 104 -128 16 ) ( 104 -120 16 ) ( 104 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 104 -120 16 ) ( 96 -120 16 ) ( 96 -120 8 ) ( ( 0.015625 0 3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 96 -120 16 ) ( 96 -128 16 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 342 +{ +brushDef +{ +( 136 -120 8 ) ( 128 -120 8 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 0 0 0 +( 128 -128 64 ) ( 128 -120 64 ) ( 136 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 0 0 0 +( 128 -128 16 ) ( 136 -128 16 ) ( 136 -128 8 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 16 ) ( 136 -120 16 ) ( 136 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 -120 16 ) ( 128 -120 16 ) ( 128 -120 8 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 128 -120 16 ) ( 128 -128 16 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 343 +{ +brushDef +{ +( 72 -120 8 ) ( 64 -120 8 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 0 0 0 +( 64 -128 64 ) ( 64 -120 64 ) ( 72 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 0 0 0 +( 64 -128 16 ) ( 72 -128 16 ) ( 72 -128 8 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 72 -128 16 ) ( 72 -120 16 ) ( 72 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 72 -120 16 ) ( 64 -120 16 ) ( 64 -120 8 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 64 -120 16 ) ( 64 -128 16 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 344 +{ +brushDef +{ +( 8 -120 8 ) ( 0 -120 8 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 0 0 0 +( 0 -128 64 ) ( 0 -120 64 ) ( 8 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 0 0 0 +( 0 -128 16 ) ( 8 -128 16 ) ( 8 -128 8 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 -128 16 ) ( 8 -120 16 ) ( 8 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 -120 16 ) ( 0 -120 16 ) ( 0 -120 8 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 0 -120 16 ) ( 0 -128 16 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 345 +{ +brushDef +{ +( -56 -120 8 ) ( -64 -120 8 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 0 0 0 +( -64 -128 64 ) ( -64 -120 64 ) ( -56 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 0 0 0 +( -64 -128 16 ) ( -56 -128 16 ) ( -56 -128 8 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -56 -128 16 ) ( -56 -120 16 ) ( -56 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -56 -120 16 ) ( -64 -120 16 ) ( -64 -120 8 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -64 -120 16 ) ( -64 -128 16 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 346 +{ +brushDef +{ +( -120 -120 8 ) ( -128 -120 8 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 64 ) ( -128 -120 64 ) ( -120 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 16 ) ( -120 -128 16 ) ( -120 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 -128 16 ) ( -120 -120 16 ) ( -120 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 -120 16 ) ( -128 -120 16 ) ( -128 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 -120 16 ) ( -128 -128 16 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 347 +{ +brushDef +{ +( 256 128 0 ) ( -128 128 0 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( 256 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( 256 -128 8 ) ( 256 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 8 ) ( 640 136 8 ) ( 640 136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 960 8 ) ( -64 960 8 ) ( -64 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +} +// entity 1 +{ +"origin" "248 512 336" +"light" "600" +"classname" "light" +} +// entity 2 +{ +"origin" "576 -64 32" +"classname" "info_player_start" +} +// entity 3 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 456 744 72 0 0 ) ( 456 744 76 0 0.062500 ) ( 456 744 80 0 0.125000 ) ) +( ( 456 728 72 0.250000 0 ) ( 456 728 76 0.250000 0.062500 ) ( 456 728 80 0.250000 0.125000 ) ) +( ( 472 728 72 0.500000 0 ) ( 472 728 76 0.500000 0.062500 ) ( 472 728 80 0.500000 0.125000 ) ) +( ( 488 728 72 0.750000 0 ) ( 488 728 76 0.750000 0.062500 ) ( 488 728 80 0.750000 0.125000 ) ) +( ( 488 744 72 1 0 ) ( 488 744 76 1 0.062500 ) ( 488 744 80 1 0.125000 ) ) +( ( 488 760 72 1.250000 0 ) ( 488 760 76 1.250000 0.062500 ) ( 488 760 80 1.250000 0.125000 ) ) +( ( 472 760 72 1.500000 0 ) ( 472 760 76 1.500000 0.062500 ) ( 472 760 80 1.500000 0.125000 ) ) +( ( 456 760 72 1.750000 0 ) ( 456 760 76 1.750000 0.062500 ) ( 456 760 80 1.750000 0.125000 ) ) +( ( 456 744 72 2 0 ) ( 456 744 76 2 0.062500 ) ( 456 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 472 760 72 7.375000 -11.875000 ) ( 456 760 72 7.125000 -11.875000 ) ( 456 744 72 7.125000 -11.625000 ) ) +( ( 488 760 72 7.625000 -11.875000 ) ( 472 744 72 7.375000 -11.625000 ) ( 456 728 72 7.125000 -11.375000 ) ) +( ( 488 744 72 7.625000 -11.625000 ) ( 488 728 72 7.625000 -11.375000 ) ( 472 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 456 744 80 7.125000 -11.625000 ) ( 456 760 80 7.125000 -11.875000 ) ( 472 760 80 7.375000 -11.875000 ) ) +( ( 456 728 80 7.125000 -11.375000 ) ( 472 744 80 7.375000 -11.625000 ) ( 488 760 80 7.625000 -11.875000 ) ) +( ( 472 728 80 7.375000 -11.375000 ) ( 488 728 80 7.625000 -11.375000 ) ( 488 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 4 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 320 64 0 0 ) ( 400 320 68 0 0.062500 ) ( 400 320 72 0 0.125000 ) ) +( ( 400 272 64 0.750000 0 ) ( 400 272 68 0.750000 0.062500 ) ( 400 272 72 0.750000 0.125000 ) ) +( ( 448 272 64 1.500000 0 ) ( 448 272 68 1.500000 0.062500 ) ( 448 272 72 1.500000 0.125000 ) ) +( ( 496 272 64 2.250000 0 ) ( 496 272 68 2.250000 0.062500 ) ( 496 272 72 2.250000 0.125000 ) ) +( ( 496 320 64 3 0 ) ( 496 320 68 3 0.062500 ) ( 496 320 72 3 0.125000 ) ) +( ( 496 368 64 3.750000 0 ) ( 496 368 68 3.750000 0.062500 ) ( 496 368 72 3.750000 0.125000 ) ) +( ( 448 368 64 4.500000 0 ) ( 448 368 68 4.500000 0.062500 ) ( 448 368 72 4.500000 0.125000 ) ) +( ( 400 368 64 5.250000 0 ) ( 400 368 68 5.250000 0.062500 ) ( 400 368 72 5.250000 0.125000 ) ) +( ( 400 320 64 6 0 ) ( 400 320 68 6 0.062500 ) ( 400 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 368 64 7 -5.750000 ) ( 400 368 64 6.250000 -5.750000 ) ( 400 320 64 6.250000 -5 ) ) +( ( 496 368 64 7.750000 -5.750000 ) ( 448 320 64 7 -5 ) ( 400 272 64 6.250000 -4.250000 ) ) +( ( 496 320 64 7.750000 -5 ) ( 496 272 64 7.750000 -4.250000 ) ( 448 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 320 72 6.250000 -5 ) ( 400 368 72 6.250000 -5.750000 ) ( 448 368 72 7 -5.750000 ) ) +( ( 400 272 72 6.250000 -4.250000 ) ( 448 320 72 7 -5 ) ( 496 368 72 7.750000 -5.750000 ) ) +( ( 448 272 72 7 -4.250000 ) ( 496 272 72 7.750000 -4.250000 ) ( 496 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 5 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 192 132 88 0 0 ) ( 192 132 108 0 0.312500 ) ( 192 132 128 0 0.625000 ) ) +( ( 192 128 88 0.062500 0 ) ( 192 128 108 0.062500 0.312500 ) ( 192 128 128 0.062500 0.625000 ) ) +( ( 196 128 88 0.125000 0 ) ( 196 128 108 0.125000 0.312500 ) ( 196 128 128 0.125000 0.625000 ) ) +( ( 200 128 88 0.187500 0 ) ( 200 128 108 0.187500 0.312500 ) ( 200 128 128 0.187500 0.625000 ) ) +( ( 200 132 88 0.250000 0 ) ( 200 132 108 0.250000 0.312500 ) ( 200 132 128 0.250000 0.625000 ) ) +( ( 200 136 88 0.312500 0 ) ( 200 136 108 0.312500 0.312500 ) ( 200 136 128 0.312500 0.625000 ) ) +( ( 196 136 88 0.375000 0 ) ( 196 136 108 0.375000 0.312500 ) ( 196 136 128 0.375000 0.625000 ) ) +( ( 192 136 88 0.437500 0 ) ( 192 136 108 0.437500 0.312500 ) ( 192 136 128 0.437500 0.625000 ) ) +( ( 192 132 88 0.500000 0 ) ( 192 132 108 0.500000 0.312500 ) ( 192 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 196 136 88 3.062500 -2.125000 ) ( 192 136 88 3 -2.125000 ) ( 192 132 88 3 -2.062500 ) ) +( ( 200 136 88 3.125000 -2.125000 ) ( 196 132 88 3.062500 -2.062500 ) ( 192 128 88 3 -2 ) ) +( ( 200 132 88 3.125000 -2.062500 ) ( 200 128 88 3.125000 -2 ) ( 196 128 88 3.062500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 192 132 128 3 -2.062500 ) ( 192 136 128 3 -2.125000 ) ( 196 136 128 3.062500 -2.125000 ) ) +( ( 192 128 128 3 -2 ) ( 196 132 128 3.062500 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ) +( ( 196 128 128 3.062500 -2 ) ( 200 128 128 3.125000 -2 ) ( 200 132 128 3.125000 -2.062500 ) ) +) + } + } +} +// entity 6 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 204 136 88 0 0 ) ( 204 136 108 0 0.312500 ) ( 204 136 128 0 0.625000 ) ) +( ( 208 136 88 0.062500 0 ) ( 208 136 108 0.062500 0.312500 ) ( 208 136 128 0.062500 0.625000 ) ) +( ( 208 140 88 0.125000 0 ) ( 208 140 108 0.125000 0.312500 ) ( 208 140 128 0.125000 0.625000 ) ) +( ( 208 144 88 0.187500 0 ) ( 208 144 108 0.187500 0.312500 ) ( 208 144 128 0.187500 0.625000 ) ) +( ( 204 144 88 0.250000 0 ) ( 204 144 108 0.250000 0.312500 ) ( 204 144 128 0.250000 0.625000 ) ) +( ( 200 144 88 0.312500 0 ) ( 200 144 108 0.312500 0.312500 ) ( 200 144 128 0.312500 0.625000 ) ) +( ( 200 140 88 0.375000 0 ) ( 200 140 108 0.375000 0.312500 ) ( 200 140 128 0.375000 0.625000 ) ) +( ( 200 136 88 0.437500 0 ) ( 200 136 108 0.437500 0.312500 ) ( 200 136 128 0.437500 0.625000 ) ) +( ( 204 136 88 0.500000 0 ) ( 204 136 108 0.500000 0.312500 ) ( 204 136 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 200 140 88 3.187500 -2.125000 ) ( 200 136 88 3.125000 -2.125000 ) ( 204 136 88 3.125000 -2.062500 ) ) +( ( 200 144 88 3.250000 -2.125000 ) ( 204 140 88 3.187500 -2.062500 ) ( 208 136 88 3.125000 -2 ) ) +( ( 204 144 88 3.250000 -2.062500 ) ( 208 144 88 3.250000 -2 ) ( 208 140 88 3.187500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 204 136 128 3.125000 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ( 200 140 128 3.187500 -2.125000 ) ) +( ( 208 136 128 3.125000 -2 ) ( 204 140 128 3.187500 -2.062500 ) ( 200 144 128 3.250000 -2.125000 ) ) +( ( 208 140 128 3.187500 -2 ) ( 208 144 128 3.250000 -2 ) ( 204 144 128 3.250000 -2.062500 ) ) +) + } + } +} +// entity 7 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 312 132 88 0 0 ) ( 312 132 108 0 0.312500 ) ( 312 132 128 0 0.625000 ) ) +( ( 312 128 88 0.062500 0 ) ( 312 128 108 0.062500 0.312500 ) ( 312 128 128 0.062500 0.625000 ) ) +( ( 316 128 88 0.125000 0 ) ( 316 128 108 0.125000 0.312500 ) ( 316 128 128 0.125000 0.625000 ) ) +( ( 320 128 88 0.187500 0 ) ( 320 128 108 0.187500 0.312500 ) ( 320 128 128 0.187500 0.625000 ) ) +( ( 320 132 88 0.250000 0 ) ( 320 132 108 0.250000 0.312500 ) ( 320 132 128 0.250000 0.625000 ) ) +( ( 320 136 88 0.312500 0 ) ( 320 136 108 0.312500 0.312500 ) ( 320 136 128 0.312500 0.625000 ) ) +( ( 316 136 88 0.375000 0 ) ( 316 136 108 0.375000 0.312500 ) ( 316 136 128 0.375000 0.625000 ) ) +( ( 312 136 88 0.437500 0 ) ( 312 136 108 0.437500 0.312500 ) ( 312 136 128 0.437500 0.625000 ) ) +( ( 312 132 88 0.500000 0 ) ( 312 132 108 0.500000 0.312500 ) ( 312 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 316 136 88 4.937500 -2.125000 ) ( 312 136 88 4.875000 -2.125000 ) ( 312 132 88 4.875000 -2.062500 ) ) +( ( 320 136 88 5 -2.125000 ) ( 316 132 88 4.937500 -2.062500 ) ( 312 128 88 4.875000 -2 ) ) +( ( 320 132 88 5 -2.062500 ) ( 320 128 88 5 -2 ) ( 316 128 88 4.937500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 312 132 128 4.875000 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ( 316 136 128 4.937500 -2.125000 ) ) +( ( 312 128 128 4.875000 -2 ) ( 316 132 128 4.937500 -2.062500 ) ( 320 136 128 5 -2.125000 ) ) +( ( 316 128 128 4.937500 -2 ) ( 320 128 128 5 -2 ) ( 320 132 128 5 -2.062500 ) ) +) + } + } +} +// entity 8 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 308 144 88 0 0 ) ( 308 144 108 0 0.312500 ) ( 308 144 128 0 0.625000 ) ) +( ( 304 144 88 0.062500 0 ) ( 304 144 108 0.062500 0.312500 ) ( 304 144 128 0.062500 0.625000 ) ) +( ( 304 140 88 0.125000 0 ) ( 304 140 108 0.125000 0.312500 ) ( 304 140 128 0.125000 0.625000 ) ) +( ( 304 136 88 0.187500 0 ) ( 304 136 108 0.187500 0.312500 ) ( 304 136 128 0.187500 0.625000 ) ) +( ( 308 136 88 0.250000 0 ) ( 308 136 108 0.250000 0.312500 ) ( 308 136 128 0.250000 0.625000 ) ) +( ( 312 136 88 0.312500 0 ) ( 312 136 108 0.312500 0.312500 ) ( 312 136 128 0.312500 0.625000 ) ) +( ( 312 140 88 0.375000 0 ) ( 312 140 108 0.375000 0.312500 ) ( 312 140 128 0.375000 0.625000 ) ) +( ( 312 144 88 0.437500 0 ) ( 312 144 108 0.437500 0.312500 ) ( 312 144 128 0.437500 0.625000 ) ) +( ( 308 144 88 0.500000 0 ) ( 308 144 108 0.500000 0.312500 ) ( 308 144 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 312 140 88 4.812500 -2.125000 ) ( 312 144 88 4.750000 -2.125000 ) ( 308 144 88 4.750000 -2.062500 ) ) +( ( 312 136 88 4.875000 -2.125000 ) ( 308 140 88 4.812500 -2.062500 ) ( 304 144 88 4.750000 -2 ) ) +( ( 308 136 88 4.875000 -2.062500 ) ( 304 136 88 4.875000 -2 ) ( 304 140 88 4.812500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 308 144 128 4.750000 -2.062500 ) ( 312 144 128 4.750000 -2.125000 ) ( 312 140 128 4.812500 -2.125000 ) ) +( ( 304 144 128 4.750000 -2 ) ( 308 140 128 4.812500 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ) +( ( 304 140 128 4.812500 -2 ) ( 304 136 128 4.875000 -2 ) ( 308 136 128 4.875000 -2.062500 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 512 64 0 0 ) ( 400 512 68 0 0.062500 ) ( 400 512 72 0 0.125000 ) ) +( ( 400 464 64 0.750000 0 ) ( 400 464 68 0.750000 0.062500 ) ( 400 464 72 0.750000 0.125000 ) ) +( ( 448 464 64 1.500000 0 ) ( 448 464 68 1.500000 0.062500 ) ( 448 464 72 1.500000 0.125000 ) ) +( ( 496 464 64 2.250000 0 ) ( 496 464 68 2.250000 0.062500 ) ( 496 464 72 2.250000 0.125000 ) ) +( ( 496 512 64 3 0 ) ( 496 512 68 3 0.062500 ) ( 496 512 72 3 0.125000 ) ) +( ( 496 560 64 3.750000 0 ) ( 496 560 68 3.750000 0.062500 ) ( 496 560 72 3.750000 0.125000 ) ) +( ( 448 560 64 4.500000 0 ) ( 448 560 68 4.500000 0.062500 ) ( 448 560 72 4.500000 0.125000 ) ) +( ( 400 560 64 5.250000 0 ) ( 400 560 68 5.250000 0.062500 ) ( 400 560 72 5.250000 0.125000 ) ) +( ( 400 512 64 6 0 ) ( 400 512 68 6 0.062500 ) ( 400 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 560 64 7 -5.750000 ) ( 400 560 64 6.250000 -5.750000 ) ( 400 512 64 6.250000 -5 ) ) +( ( 496 560 64 7.750000 -5.750000 ) ( 448 512 64 7 -5 ) ( 400 464 64 6.250000 -4.250000 ) ) +( ( 496 512 64 7.750000 -5 ) ( 496 464 64 7.750000 -4.250000 ) ( 448 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 512 72 6.250000 -5 ) ( 400 560 72 6.250000 -5.750000 ) ( 448 560 72 7 -5.750000 ) ) +( ( 400 464 72 6.250000 -4.250000 ) ( 448 512 72 7 -5 ) ( 496 560 72 7.750000 -5.750000 ) ) +( ( 448 464 72 7 -4.250000 ) ( 496 464 72 7.750000 -4.250000 ) ( 496 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 10 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 320 64 0 0 ) ( 16 320 68 0 0.062500 ) ( 16 320 72 0 0.125000 ) ) +( ( 16 272 64 0.750000 0 ) ( 16 272 68 0.750000 0.062500 ) ( 16 272 72 0.750000 0.125000 ) ) +( ( 64 272 64 1.500000 0 ) ( 64 272 68 1.500000 0.062500 ) ( 64 272 72 1.500000 0.125000 ) ) +( ( 112 272 64 2.250000 0 ) ( 112 272 68 2.250000 0.062500 ) ( 112 272 72 2.250000 0.125000 ) ) +( ( 112 320 64 3 0 ) ( 112 320 68 3 0.062500 ) ( 112 320 72 3 0.125000 ) ) +( ( 112 368 64 3.750000 0 ) ( 112 368 68 3.750000 0.062500 ) ( 112 368 72 3.750000 0.125000 ) ) +( ( 64 368 64 4.500000 0 ) ( 64 368 68 4.500000 0.062500 ) ( 64 368 72 4.500000 0.125000 ) ) +( ( 16 368 64 5.250000 0 ) ( 16 368 68 5.250000 0.062500 ) ( 16 368 72 5.250000 0.125000 ) ) +( ( 16 320 64 6 0 ) ( 16 320 68 6 0.062500 ) ( 16 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 368 64 7 -5.750000 ) ( 16 368 64 6.250000 -5.750000 ) ( 16 320 64 6.250000 -5 ) ) +( ( 112 368 64 7.750000 -5.750000 ) ( 64 320 64 7 -5 ) ( 16 272 64 6.250000 -4.250000 ) ) +( ( 112 320 64 7.750000 -5 ) ( 112 272 64 7.750000 -4.250000 ) ( 64 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 320 72 6.250000 -5 ) ( 16 368 72 6.250000 -5.750000 ) ( 64 368 72 7 -5.750000 ) ) +( ( 16 272 72 6.250000 -4.250000 ) ( 64 320 72 7 -5 ) ( 112 368 72 7.750000 -5.750000 ) ) +( ( 64 272 72 7 -4.250000 ) ( 112 272 72 7.750000 -4.250000 ) ( 112 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 11 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 512 64 0 0 ) ( 16 512 68 0 0.062500 ) ( 16 512 72 0 0.125000 ) ) +( ( 16 464 64 0.750000 0 ) ( 16 464 68 0.750000 0.062500 ) ( 16 464 72 0.750000 0.125000 ) ) +( ( 64 464 64 1.500000 0 ) ( 64 464 68 1.500000 0.062500 ) ( 64 464 72 1.500000 0.125000 ) ) +( ( 112 464 64 2.250000 0 ) ( 112 464 68 2.250000 0.062500 ) ( 112 464 72 2.250000 0.125000 ) ) +( ( 112 512 64 3 0 ) ( 112 512 68 3 0.062500 ) ( 112 512 72 3 0.125000 ) ) +( ( 112 560 64 3.750000 0 ) ( 112 560 68 3.750000 0.062500 ) ( 112 560 72 3.750000 0.125000 ) ) +( ( 64 560 64 4.500000 0 ) ( 64 560 68 4.500000 0.062500 ) ( 64 560 72 4.500000 0.125000 ) ) +( ( 16 560 64 5.250000 0 ) ( 16 560 68 5.250000 0.062500 ) ( 16 560 72 5.250000 0.125000 ) ) +( ( 16 512 64 6 0 ) ( 16 512 68 6 0.062500 ) ( 16 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 560 64 7 -5.750000 ) ( 16 560 64 6.250000 -5.750000 ) ( 16 512 64 6.250000 -5 ) ) +( ( 112 560 64 7.750000 -5.750000 ) ( 64 512 64 7 -5 ) ( 16 464 64 6.250000 -4.250000 ) ) +( ( 112 512 64 7.750000 -5 ) ( 112 464 64 7.750000 -4.250000 ) ( 64 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 512 72 6.250000 -5 ) ( 16 560 72 6.250000 -5.750000 ) ( 64 560 72 7 -5.750000 ) ) +( ( 16 464 72 6.250000 -4.250000 ) ( 64 512 72 7 -5 ) ( 112 560 72 7.750000 -5.750000 ) ) +( ( 64 464 72 7 -4.250000 ) ( 112 464 72 7.750000 -4.250000 ) ( 112 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 12 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 368 744 72 0 0 ) ( 368 744 76 0 0.062500 ) ( 368 744 80 0 0.125000 ) ) +( ( 368 728 72 0.250000 0 ) ( 368 728 76 0.250000 0.062500 ) ( 368 728 80 0.250000 0.125000 ) ) +( ( 384 728 72 0.500000 0 ) ( 384 728 76 0.500000 0.062500 ) ( 384 728 80 0.500000 0.125000 ) ) +( ( 400 728 72 0.750000 0 ) ( 400 728 76 0.750000 0.062500 ) ( 400 728 80 0.750000 0.125000 ) ) +( ( 400 744 72 1 0 ) ( 400 744 76 1 0.062500 ) ( 400 744 80 1 0.125000 ) ) +( ( 400 760 72 1.250000 0 ) ( 400 760 76 1.250000 0.062500 ) ( 400 760 80 1.250000 0.125000 ) ) +( ( 384 760 72 1.500000 0 ) ( 384 760 76 1.500000 0.062500 ) ( 384 760 80 1.500000 0.125000 ) ) +( ( 368 760 72 1.750000 0 ) ( 368 760 76 1.750000 0.062500 ) ( 368 760 80 1.750000 0.125000 ) ) +( ( 368 744 72 2 0 ) ( 368 744 76 2 0.062500 ) ( 368 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 384 760 72 7.375000 -11.875000 ) ( 368 760 72 7.125000 -11.875000 ) ( 368 744 72 7.125000 -11.625000 ) ) +( ( 400 760 72 7.625000 -11.875000 ) ( 384 744 72 7.375000 -11.625000 ) ( 368 728 72 7.125000 -11.375000 ) ) +( ( 400 744 72 7.625000 -11.625000 ) ( 400 728 72 7.625000 -11.375000 ) ( 384 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 368 744 80 7.125000 -11.625000 ) ( 368 760 80 7.125000 -11.875000 ) ( 384 760 80 7.375000 -11.875000 ) ) +( ( 368 728 80 7.125000 -11.375000 ) ( 384 744 80 7.375000 -11.625000 ) ( 400 760 80 7.625000 -11.875000 ) ) +( ( 384 728 80 7.375000 -11.375000 ) ( 400 728 80 7.625000 -11.375000 ) ( 400 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 13 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 264 744 72 0 0 ) ( 264 744 76 0 0.062500 ) ( 264 744 80 0 0.125000 ) ) +( ( 264 728 72 0.250000 0 ) ( 264 728 76 0.250000 0.062500 ) ( 264 728 80 0.250000 0.125000 ) ) +( ( 280 728 72 0.500000 0 ) ( 280 728 76 0.500000 0.062500 ) ( 280 728 80 0.500000 0.125000 ) ) +( ( 296 728 72 0.750000 0 ) ( 296 728 76 0.750000 0.062500 ) ( 296 728 80 0.750000 0.125000 ) ) +( ( 296 744 72 1 0 ) ( 296 744 76 1 0.062500 ) ( 296 744 80 1 0.125000 ) ) +( ( 296 760 72 1.250000 0 ) ( 296 760 76 1.250000 0.062500 ) ( 296 760 80 1.250000 0.125000 ) ) +( ( 280 760 72 1.500000 0 ) ( 280 760 76 1.500000 0.062500 ) ( 280 760 80 1.500000 0.125000 ) ) +( ( 264 760 72 1.750000 0 ) ( 264 760 76 1.750000 0.062500 ) ( 264 760 80 1.750000 0.125000 ) ) +( ( 264 744 72 2 0 ) ( 264 744 76 2 0.062500 ) ( 264 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 280 760 72 7.375000 -11.875000 ) ( 264 760 72 7.125000 -11.875000 ) ( 264 744 72 7.125000 -11.625000 ) ) +( ( 296 760 72 7.625000 -11.875000 ) ( 280 744 72 7.375000 -11.625000 ) ( 264 728 72 7.125000 -11.375000 ) ) +( ( 296 744 72 7.625000 -11.625000 ) ( 296 728 72 7.625000 -11.375000 ) ( 280 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 264 744 80 7.125000 -11.625000 ) ( 264 760 80 7.125000 -11.875000 ) ( 280 760 80 7.375000 -11.875000 ) ) +( ( 264 728 80 7.125000 -11.375000 ) ( 280 744 80 7.375000 -11.625000 ) ( 296 760 80 7.625000 -11.875000 ) ) +( ( 280 728 80 7.375000 -11.375000 ) ( 296 728 80 7.625000 -11.375000 ) ( 296 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 14 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 96 744 72 0 0 ) ( 96 744 76 0 0.062500 ) ( 96 744 80 0 0.125000 ) ) +( ( 96 728 72 0.250000 0 ) ( 96 728 76 0.250000 0.062500 ) ( 96 728 80 0.250000 0.125000 ) ) +( ( 112 728 72 0.500000 0 ) ( 112 728 76 0.500000 0.062500 ) ( 112 728 80 0.500000 0.125000 ) ) +( ( 128 728 72 0.750000 0 ) ( 128 728 76 0.750000 0.062500 ) ( 128 728 80 0.750000 0.125000 ) ) +( ( 128 744 72 1 0 ) ( 128 744 76 1 0.062500 ) ( 128 744 80 1 0.125000 ) ) +( ( 128 760 72 1.250000 0 ) ( 128 760 76 1.250000 0.062500 ) ( 128 760 80 1.250000 0.125000 ) ) +( ( 112 760 72 1.500000 0 ) ( 112 760 76 1.500000 0.062500 ) ( 112 760 80 1.500000 0.125000 ) ) +( ( 96 760 72 1.750000 0 ) ( 96 760 76 1.750000 0.062500 ) ( 96 760 80 1.750000 0.125000 ) ) +( ( 96 744 72 2 0 ) ( 96 744 76 2 0.062500 ) ( 96 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 112 760 72 7.375000 -11.875000 ) ( 96 760 72 7.125000 -11.875000 ) ( 96 744 72 7.125000 -11.625000 ) ) +( ( 128 760 72 7.625000 -11.875000 ) ( 112 744 72 7.375000 -11.625000 ) ( 96 728 72 7.125000 -11.375000 ) ) +( ( 128 744 72 7.625000 -11.625000 ) ( 128 728 72 7.625000 -11.375000 ) ( 112 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 96 744 80 7.125000 -11.625000 ) ( 96 760 80 7.125000 -11.875000 ) ( 112 760 80 7.375000 -11.875000 ) ) +( ( 96 728 80 7.125000 -11.375000 ) ( 112 744 80 7.375000 -11.625000 ) ( 128 760 80 7.625000 -11.875000 ) ) +( ( 112 728 80 7.375000 -11.375000 ) ( 128 728 80 7.625000 -11.375000 ) ( 128 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 15 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 0 744 72 0 0 ) ( 0 744 76 0 0.062500 ) ( 0 744 80 0 0.125000 ) ) +( ( 0 728 72 0.250000 0 ) ( 0 728 76 0.250000 0.062500 ) ( 0 728 80 0.250000 0.125000 ) ) +( ( 16 728 72 0.500000 0 ) ( 16 728 76 0.500000 0.062500 ) ( 16 728 80 0.500000 0.125000 ) ) +( ( 32 728 72 0.750000 0 ) ( 32 728 76 0.750000 0.062500 ) ( 32 728 80 0.750000 0.125000 ) ) +( ( 32 744 72 1 0 ) ( 32 744 76 1 0.062500 ) ( 32 744 80 1 0.125000 ) ) +( ( 32 760 72 1.250000 0 ) ( 32 760 76 1.250000 0.062500 ) ( 32 760 80 1.250000 0.125000 ) ) +( ( 16 760 72 1.500000 0 ) ( 16 760 76 1.500000 0.062500 ) ( 16 760 80 1.500000 0.125000 ) ) +( ( 0 760 72 1.750000 0 ) ( 0 760 76 1.750000 0.062500 ) ( 0 760 80 1.750000 0.125000 ) ) +( ( 0 744 72 2 0 ) ( 0 744 76 2 0.062500 ) ( 0 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 760 72 7.375000 -11.875000 ) ( 0 760 72 7.125000 -11.875000 ) ( 0 744 72 7.125000 -11.625000 ) ) +( ( 32 760 72 7.625000 -11.875000 ) ( 16 744 72 7.375000 -11.625000 ) ( 0 728 72 7.125000 -11.375000 ) ) +( ( 32 744 72 7.625000 -11.625000 ) ( 32 728 72 7.625000 -11.375000 ) ( 16 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 0 744 80 7.125000 -11.625000 ) ( 0 760 80 7.125000 -11.875000 ) ( 16 760 80 7.375000 -11.875000 ) ) +( ( 0 728 80 7.125000 -11.375000 ) ( 16 744 80 7.375000 -11.625000 ) ( 32 760 80 7.625000 -11.875000 ) ) +( ( 16 728 80 7.375000 -11.375000 ) ( 32 728 80 7.625000 -11.375000 ) ( 32 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 16 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( -72 928 72 0 0 ) ( -72 928 76 0 0.062500 ) ( -72 928 80 0 0.125000 ) ) +( ( -72 912 72 0.250000 0 ) ( -72 912 76 0.250000 0.062500 ) ( -72 912 80 0.250000 0.125000 ) ) +( ( -56 912 72 0.500000 0 ) ( -56 912 76 0.500000 0.062500 ) ( -56 912 80 0.500000 0.125000 ) ) +( ( -40 912 72 0.750000 0 ) ( -40 912 76 0.750000 0.062500 ) ( -40 912 80 0.750000 0.125000 ) ) +( ( -40 928 72 1 0 ) ( -40 928 76 1 0.062500 ) ( -40 928 80 1 0.125000 ) ) +( ( -40 944 72 1.250000 0 ) ( -40 944 76 1.250000 0.062500 ) ( -40 944 80 1.250000 0.125000 ) ) +( ( -56 944 72 1.500000 0 ) ( -56 944 76 1.500000 0.062500 ) ( -56 944 80 1.500000 0.125000 ) ) +( ( -72 944 72 1.750000 0 ) ( -72 944 76 1.750000 0.062500 ) ( -72 944 80 1.750000 0.125000 ) ) +( ( -72 928 72 2 0 ) ( -72 928 76 2 0.062500 ) ( -72 928 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -56 944 72 7.375000 -11.875000 ) ( -72 944 72 7.125000 -11.875000 ) ( -72 928 72 7.125000 -11.625000 ) ) +( ( -40 944 72 7.625000 -11.875000 ) ( -56 928 72 7.375000 -11.625000 ) ( -72 912 72 7.125000 -11.375000 ) ) +( ( -40 928 72 7.625000 -11.625000 ) ( -40 912 72 7.625000 -11.375000 ) ( -56 912 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -72 928 80 7.125000 -11.625000 ) ( -72 944 80 7.125000 -11.875000 ) ( -56 944 80 7.375000 -11.875000 ) ) +( ( -72 912 80 7.125000 -11.375000 ) ( -56 928 80 7.375000 -11.625000 ) ( -40 944 80 7.625000 -11.875000 ) ) +( ( -56 912 80 7.375000 -11.375000 ) ( -40 912 80 7.625000 -11.375000 ) ( -40 928 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 17 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( -72 824 72 0 0 ) ( -72 824 76 0 0.062500 ) ( -72 824 80 0 0.125000 ) ) +( ( -72 808 72 0.250000 0 ) ( -72 808 76 0.250000 0.062500 ) ( -72 808 80 0.250000 0.125000 ) ) +( ( -56 808 72 0.500000 0 ) ( -56 808 76 0.500000 0.062500 ) ( -56 808 80 0.500000 0.125000 ) ) +( ( -40 808 72 0.750000 0 ) ( -40 808 76 0.750000 0.062500 ) ( -40 808 80 0.750000 0.125000 ) ) +( ( -40 824 72 1 0 ) ( -40 824 76 1 0.062500 ) ( -40 824 80 1 0.125000 ) ) +( ( -40 840 72 1.250000 0 ) ( -40 840 76 1.250000 0.062500 ) ( -40 840 80 1.250000 0.125000 ) ) +( ( -56 840 72 1.500000 0 ) ( -56 840 76 1.500000 0.062500 ) ( -56 840 80 1.500000 0.125000 ) ) +( ( -72 840 72 1.750000 0 ) ( -72 840 76 1.750000 0.062500 ) ( -72 840 80 1.750000 0.125000 ) ) +( ( -72 824 72 2 0 ) ( -72 824 76 2 0.062500 ) ( -72 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -56 840 72 7.375000 -11.875000 ) ( -72 840 72 7.125000 -11.875000 ) ( -72 824 72 7.125000 -11.625000 ) ) +( ( -40 840 72 7.625000 -11.875000 ) ( -56 824 72 7.375000 -11.625000 ) ( -72 808 72 7.125000 -11.375000 ) ) +( ( -40 824 72 7.625000 -11.625000 ) ( -40 808 72 7.625000 -11.375000 ) ( -56 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -72 824 80 7.125000 -11.625000 ) ( -72 840 80 7.125000 -11.875000 ) ( -56 840 80 7.375000 -11.875000 ) ) +( ( -72 808 80 7.125000 -11.375000 ) ( -56 824 80 7.375000 -11.625000 ) ( -40 840 80 7.625000 -11.875000 ) ) +( ( -56 808 80 7.375000 -11.375000 ) ( -40 808 80 7.625000 -11.375000 ) ( -40 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 18 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 552 824 72 0 0 ) ( 552 824 76 0 0.062500 ) ( 552 824 80 0 0.125000 ) ) +( ( 552 808 72 0.250000 0 ) ( 552 808 76 0.250000 0.062500 ) ( 552 808 80 0.250000 0.125000 ) ) +( ( 568 808 72 0.500000 0 ) ( 568 808 76 0.500000 0.062500 ) ( 568 808 80 0.500000 0.125000 ) ) +( ( 584 808 72 0.750000 0 ) ( 584 808 76 0.750000 0.062500 ) ( 584 808 80 0.750000 0.125000 ) ) +( ( 584 824 72 1 0 ) ( 584 824 76 1 0.062500 ) ( 584 824 80 1 0.125000 ) ) +( ( 584 840 72 1.250000 0 ) ( 584 840 76 1.250000 0.062500 ) ( 584 840 80 1.250000 0.125000 ) ) +( ( 568 840 72 1.500000 0 ) ( 568 840 76 1.500000 0.062500 ) ( 568 840 80 1.500000 0.125000 ) ) +( ( 552 840 72 1.750000 0 ) ( 552 840 76 1.750000 0.062500 ) ( 552 840 80 1.750000 0.125000 ) ) +( ( 552 824 72 2 0 ) ( 552 824 76 2 0.062500 ) ( 552 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 568 840 72 7.375000 -11.875000 ) ( 552 840 72 7.125000 -11.875000 ) ( 552 824 72 7.125000 -11.625000 ) ) +( ( 584 840 72 7.625000 -11.875000 ) ( 568 824 72 7.375000 -11.625000 ) ( 552 808 72 7.125000 -11.375000 ) ) +( ( 584 824 72 7.625000 -11.625000 ) ( 584 808 72 7.625000 -11.375000 ) ( 568 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 552 824 80 7.125000 -11.625000 ) ( 552 840 80 7.125000 -11.875000 ) ( 568 840 80 7.375000 -11.875000 ) ) +( ( 552 808 80 7.125000 -11.375000 ) ( 568 824 80 7.375000 -11.625000 ) ( 584 840 80 7.625000 -11.875000 ) ) +( ( 568 808 80 7.375000 -11.375000 ) ( 584 808 80 7.625000 -11.375000 ) ( 584 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 19 +{ +"classname" "info_player_start" +"origin" "576 72 352" +} +// entity 20 +{ +"classname" "light" +"light" "600" +"origin" "256 -448 336" +} diff --git a/docs/developer/UML/modules.zargo b/docs/developer/UML/modules.zargo new file mode 100644 index 0000000000000000000000000000000000000000..5f46c24ab0f084242f4315164d894b522891fab0 GIT binary patch literal 4763 zcmaJ_2T)U6w+=OQ1fn1vq&MkBAV>?H5D<}`NN=InP^5PRK~X_a=~Ze_loEOo=>jUf z#7I+6kp74Ny*qk+@7}fN%$#%ftUdGXwb%N-wT<+Mh(Q1{{5U}M2?2gHD*U^Lr@g9=EMQDJst>}V{5>Mwi8NLSgM!VEMBkywQ~ODIFHk4@Uc`T zya>HLpT>*2n(9Rz^6lZeNRNWR8VgVMI+vGuN;5y`DYMsnhTs%PNHNIiTX&>Kd+d&; z^Lt5`cBK`uSiXxX#$+wmE2{bu^#bGQm7^NVM#EncJ>s=h#4P$N45zrm4!8 z$#&Bf?$KF?w)2mt^`AOK+Wk7tMue}?Sb5x&0mE(j+dgol`ylZX4{ zEo=Ni0)=7C?1R4)(%%N|zz8NaK9ZL;RBp1DyOirM5xa3YrgeUBQ3*HXv$dVq8@5p$pA&LMJdHWbo=P|_e}cC z?ROIpyxap*bN;c&6e7_GIpt^zRhs99hN%+#6$+l2m0KhBS6~G22bA z349IBEzs#t2toEU>jSTfzCsp9+jcFgN0L~$*e4{)t%%O_T@uM^Y$!L=yg$XG(`e4c zs=fzo=Fd`!o{#EYRkKr-_JTT?B#E6e^6>a@;M)zMN)D@$PYJ&2&s)0X+pQCXXl z)g7^|9caEpTN2?B0d?q`g;|#YdduOeR=UaT;egN1F@)I1F%FhpCbM_!*0@>Xd36GR zI>q<~^SUtduzJop*HP9*Lx>Q{fkGpgaxl@26dCHv-uV*GDwqMhVLb{XU?R#e$c@7u zI}EbQE?So8ZsSn9T8^My$UHX6Ka7-JD?c(8Y{GL?10}8*aZ2i=-O#?Ea^~sW`^Z_g ze!1)@oI>4|0aSuqe7Vbi6!F721A4`A8SG%yZV{TpEwpq{mRn>vl{ii9f63-%cf}4v zeU1aBDaU(oa8zEd%}mK>NrGO8J>b4XCl^gnhn2p4{^3>4)za4{h66BP4gQDYU6;Nq zOd1#45DnmFh3dlS-`4pu+vbVN(}`5VZk?P7yML{wh+d^2ssND=f=FfY|Kvf%G7WM9 zBKr-kwH+FLEC-tdw&w|4>^rj*MFapCGya~yhkuX&2%o_Iz7BQ>Ux)uqVTu3du&ALj zWrsNE(~)qVCshB7mZgio5l|IYN@GZ$$wY|0-<1@tGS_gp5VyQFYuy@T78vA$^)O-V z6I35*bkC|Xh|KYUj``iAORIUPbpUU)Wgm{0QPTe@G`#BFLbO3<3XR2#QtF~`8_P3V zvhR!*^~Xs~fDW`(l(_}Tv< zL3dAt{a?^&qwvrVF8+8F^EQu!7ZZn=0o222w6U^qNgZGAddx8|(xwdF9k z6mB-Sn0zHC;rTc~Hd_wb>n4{%r_|C448O5QD|-yA2gkDy6eYRAw$jKTY8qGD75G&9 zs_PC%p;uE)V=Ns=otU|#%^t`VW)5RybR?a96xfqgW=~gWZDObW?KprzbiIQ@@I{O2 zEttlMP;-?;K~_|Jv0LyJ6Xz5r*F@J&k|5+@C~Ic$f5Sc-Rz1{=2etgKu$l3*cAoC; zh})h%2tOB3}K!qbv3w0le23Ph`bOL8hRk+#j~_KWE=@Z3Y85K)6=TA59(vZU&^qB>rP*OPBOeeCau-~ zKq)eM4vx~gz98U_zQxpHsQq=zS^uWRTTq3Nxi%8)*1cUCLC76SNEVPy-nxx6 z(k}X>&OT9{FH5e0YOI4qEQi@v_`ORv{*qZ^W5}ZSMsg?8ytS$)x^9wcSVTB>sRh%5 z{BA&4)+QXzBmU)P>)_4c`vd&O!u0ZnWXl3hFyl)5k{Eq$Z)d~a=1_P>P5?)Z$Kxd-{c!Sys!V78cu+4q#|wAi+N`vnB+*QkLExU~757KZ@6m5sM+)1*MRRh#8Av)(4hG)_Jb`MB zmF%+h)2D!2%pL7wt?wEgp#}AxI1+tio=j|c;}IT_*FZW1U8XH)bEHj`OV&=jw@jN# zdISmS*6tNUy*|BOVgW~d)C#{Pe;Rs19qwDY9v{nrOA49z$};aX-jgL_wbFX`Ln60% zKtvBsilVXEy?CAIp}<;>O;#;#dCH@{=htKlZqD>|Al#hB*AQ1G9Ti<26ldO&sTZI* z)Ly`xs5Twq+#9+oAui}x{zH$K7EYlup6V#e4&2^W(b8eTl z5RrIVQ`<`V5i~6RQYr(>+xL_#Qr>IzFQUJcG85|xi3kW zpmXxs*4O6z;cqP7ZT0J-H3In>pT@a8nyFdt^AwwD-Yy2=7_u#(eGw#O1ZA(-%W%;X zUY)u6t|6QmxnpV{iHJrw2@L#D@JpKv7&O40a%FdK%7c=sV#R%a3+q0- zzAC)OA6cbbPZ#}(+NX)xrwQY*g7g92lS4kth7o_i+{y!@Wk91QV;Lz%nQ2D%^w zwTp2IkEZ)1ONTVe4T|{lQF^TCN+Jva<`p+4vgGNpcnJe*5LL*dC|}>gg-@_SH8hx) zUBvHtV6{%*7(dy7Ia#ww)7FiI`KO9bPZe=QB!tbK6KfcnC(`MBe&tVIh>fs?Q;o1a z%cxKdBz>y*NxWqI3Hb9n%`fj@PGoC8^8wpBv;uf~{ULCd5KHzGVOXN%mA=4zUrXT& zCx&rJ!3zf<#x@fJ-_d`?Z;2O3UeC)g%J+*K&^G;UUMEufZ5PXEGO@6(-%H3>4%;j8 z^~nI2Wa=i0&)MG!m|W)?8DB-$mOlr--jg&+F|>t@HZry>y|@iPEY9iqH#549!}e{m zzSA+%7}pOD)Y#nlp~jY-C1tpuyBft6_P8iFt_EI;!i>a{bY2u?0;AX`wc}iWXza>n ztPiByoN&+=DsR=~8#dJT)V4J{`L(6RSiVbS7cS!h>NGQOgX6{n`ypN&LxIs0@SE_% zE^^-r@kODVn&^fQgqtw*@#bY-RLSw@>oh4V+^Bv!xbIu++iN)8LxoC#Jo_;YgmxB# z#)`N+`a`>SS9vOR-BB82;f-u!U|KKQs+@S*qQ|cRHJEW)B;%AFW`C@!TZScR%vQ+D zBp~CNx_E40X5nb8TwIRpZM|R;*peAu*-LJM(l@Q=$WBUAu+9H zOSUL*Ma;b2K#x4{NYcAFCurNAM0wLntLo*A(H5L=KTSYJ!g@`&0%=&IE>%n2)2s64 z8lILN_L2QQ&-;ywN`@s>bs2>Y`O{#EM^N+Wrf(|E?q?mmA&RGr=jFO#c}YBg1OT9M zI_E0_LJ;8BMaJ*#>G?&*-|esReSWR+r|0jw_`H4nWg7T)_y07rzq_A{$KPe;xp@9% zB&7epl>T#t-xb=q{QPAk_+I-DG5V+T?;L(E;(pmN-ua&;-Jk3HPKD=;|H~LD{*nLx lT;%rvowMdIW5R#_6$Cto8tI*H4gdhek5;?_>Ai6N^&d`@FFODL literal 0 HcmV?d00001 diff --git a/docs/developer/WIN32BETA b/docs/developer/WIN32BETA new file mode 100644 index 00000000..2e71c8f1 --- /dev/null +++ b/docs/developer/WIN32BETA @@ -0,0 +1,247 @@ +THIS FILE IS OFFICIALLY OUTDATED CLOSED NO LONGER USED + +All the stuff that needs to be settled for win32 beta of GtkRadiant: + +- need to add more code checking BSP process execution (Q_Exec or engine spawning) +(TTimo: Assigned to self) + +- the BSP commands are switching in order randomly + +- Need more error checking when executing q3map (in any mode) + (Q_Exec goes out of resources sometimes) + +- Region compiling is broken + +- GL font on win32 uses the default system font .. which can be .. yiddish or cyrilic etc. + force to courier? + NOTE: actually I'm not sure this really is the problem .. some people are getting weird bitmap fonts + +- view n2 needs to wake on whatever widget you raise first +Fixed. + +- entity information box on entity inspector displays with nasty characters + maybe the same problem as above? + +- map snapshot has a bug (allocation and stuff around Str class) +OK (don't use CString stuff = other_stuff; do CString stuff; stuff = other_stuff;) + +- sleep mode on view 2&3 crashing +Fixed for the floating windows mode. + +- sleep mode: need to bring back the bitmap fonts +Fixed + +- sleep mode: need to rebuild the data on models and patches! (call Map_BuildBrushData) +Calling Map_BuildBrushData in Mainframe::OnSleep. +OK (added some crap to reload) ... Maybe more to do + +- sleep mode: need to trigger out sleep mode when raising again! +Done. + +- console: we want output while it's processing .. otherwise it's just useless .. +OK! + +- win32 help format distribution of the manual? + +- update the links page, add stuff from the forum + (TTimo .. will do) + +- check maximized state is working(?) + +<<<<<<< WIN32BETA +- view n.3 crashes on exit in MainFrame::OnDestroy.. + (trying to save prefs) + +Fixed. +======= +- remove high color textures from prefs .. remnant from Q2 .. always on .. off is broken anyway +Done. + +- test sleep mode! + +- check my project template bug checking code is ok + NOTE: it's fuxored. Need a central function to shrink and standardize file paths: + lowercase + short dos8.2 names + unix style forward slashes / + -> then perform the comparisons + +- surface and patch inspector: +[23:37] WHen you make adjustments in surface window, it should show results immediately. Pressing Apply after each change to see how it looks is a pain. +[23:41] true +[23:42] is it the behaviour of the MFC version or not? +[23:42] on the MFC version when you make adjustements it updates on the fly right? +[23:43] Yeah. +[23:44] ANd the fit and axial buittons do not seem to do anything, even if you press Apply afterwords. +[23:44] HDidn't check patches at all, don't know about them. +Fixed + +- check the engine path changes I made didn't break on linux + +- user INI path in prefs: need to look into it .. but my guess is .. it's broken/useless + +- view n.2: doesn't remember the window positions +Fixed + +- view n.2: the Z window doesn't shrink below the default size +Fixed + +- do some performance comparisons with 202 + (specially BrushBuild step) + +- a quickstart.txt file with some explanations about the transition 202 -> GtkRadiant? + like: + what are the actual new features + (new way to deal with project settings, sleep mode, net connect for BSP process) + what are we testing in the alpha + where to report bugs, who is doing what + how to contribute as a coder + some of this stuff goes into the changelog! +>>>>>>> 1.15 + +- is there a way to have something actually drawing when moving the splitters? + +- view n.4: the Z window gets pushed when you resize with the leftmost vertical splitter + +- disable the groups view (it's not functional) +Fixed + +- floating windows mode (n.2 in prefs): + if a message gets printed, the console will raise up. But if something else was active + (like Entities) .. the widgets are still active .. start moving the mouse on top of + the entity window and stuff will start to appear + +- floating windows mode (n.2 in prefs): + when moving in the 2D window the console outputs lots of error messages: + ERROR: glXMakeCurrent failed.. Error:0 + Please restart Q3Radiant if the Map view is not working + but everything seems to work fine, no graphic glitches + +- floating windows mode (n.2 in prefs): + the Z window doesn't resize + +- more window position storage, store maximized state and position on the desktop +Note: maximized state doesn't exist under X, it depends on the WM. + +- keyboard shortcuts break if click in the console window, it keeps the focus.. +Fixed (using GtkText again). + +<<<<<<< WIN32BETA +- upgrade to latest Gtk distribution (there's been a new release) and make sure we are ok + +- enable undo/redo + +Fixed. + +- make sure the BSP monitoring stuff is stored in registry + +- remove the "Buggy GL driver" thing, we'll use another strategy for hardware-specific issues + +- remove the QE4 update model, force always on + +- assertion failed when raising the prefs box for the first time? + +======= +>>>>>>> 1.15 +- use the other view modes to check nothing's wrong with them + +- win32 console doesn't release the focus if you click into it + it also has resize issues .. doesn't seem to want to shrink down +Fixed the focus problem (using GtkText again). + +- some problems with file permissions under linux? + seems it used to create the log and pid file with no write permissions for the user + ends up that when you try to open the console file for output it fails or the .pid remains when you try to erase it + (NOTE: I need someone with an old install to check that) + on win32 more or less same problem. It's created with an archive flag that + fordibs removal as well. +<<<<<<< WIN32BETA + +Fixed: missing fclose in main.cpp that could be causing this problem. +======= +leo: there was a missing fclose in main.cpp that could be causing this problem. +>>>>>>> 1.15 + +- engine path / project loading + when we load a template project file we are using the engine path to build it + if user has several installs and old prefs that rely on another engine path, project + template construction fails. (i.e. is still based on old engine path) + I don't know how to solve: + -check the engine path when we do the template thing? + -check engine path at each project load + actually we can check everytime and ask the user, it seems this happens in weird cases + .. anyway it's not supposed to be a "stable" situation anytime + +- make sure the BSP monitoring stuff is stored in registry +OK (added) + +- the Radiant logo is screwed in the about dialog box? +OK (Leo:) The logo.bmp file in the CVS server is screwed, fixed. + +- remove the "Buggy GL driver" thing, we'll use another strategy for hardware-specific issues +OK (Leo fixed) + +- engine path dialog is broken (need split to get the actual path) +OK (splitting the path, can't edit it must go through the dialog) + +- assertion failed when raising the prefs box for the first time? +WORKSFORM (can't reprodcue this one) +leo: Used to happen sometimes for me (not anymore ?) + +- view n.3 crashes on exit in MainFrame::OnDestroy.. + (trying to save prefs) +Fixed + +- remove the QE4 update model, force always on +Done. + +- custom keyboard shortcuts is buggy .. works halfway +OK all fixed + +- upgrade to latest Gtk distribution (there's been a new release) and make sure we are ok +OK (tested and stuff .. I'm using the latest in the setup) + +- enable undo/redo +leo: it's already enabled +(ok fixed, had to enable back the menus) +OK + +- project settings. GtkRadiant uses a new version of project settings. +Default name is quakev2.qe4 +Must be able to read old project settings as well .. BSP monitoring disabled +if using old project settings +When searching for project settings, will look for quakev2.qe4 first, then quake.qe4 +No more overwriting the loaded project settings. We detect "template" project settings +(ie. the ones we distribute) with a "user_project" "1" keyval +When a template is loaded, save as userxx.qe4 where xx = 1 2 3 4 5 6 etc. +It will trash scripts/ a bit but it doesn't matter .. + +I did some cleanup to the project code, tested on both linux and win32, will need more +testing and stuff while in alpha/beta I guess. But it should be stabilized now. + +OK + +-unify the project file syntax on both platforms! (and yes, the problem is + radiant on linux is in quake3/ instead of quake3/tools) + the expansion rules are not the same between version 1 and v2 project files! + we change the string names so we don't have to adapt.. + NOTE: later we'll remove support for old v1 syntax? + NOTE: we may need to add a g_strHomePath for ~/.q3a/ on linux + +see above, the v2 project file is in data/quakev2.qe4 + +OK + +- preferences dialog for BSP monitoring: do / don't do, launch engine after + compilation. + Right now all the params are in prefs, just need the interface + +OK, need more testing, and the sleep mode code +.. may also want to add more configurable stuff later .. though I'd rather have it done +by a plugin + +- in QE_LoadProject, check the template reading works ok, specially with the new +globals Leo added some time ago + +OK, tested on both win32 and linux + diff --git a/docs/developer/WIN32SETUP b/docs/developer/WIN32SETUP new file mode 100644 index 00000000..2fdd2f3b --- /dev/null +++ b/docs/developer/WIN32SETUP @@ -0,0 +1,36 @@ +Summary of TODO and BUGS for GtkRadiant setup files on win32: + +(most of the times the stuff has to be checked in both versions of the setup) + +- installer back button is broken +OK (it just bails out if you try to back instead) + +- need proper setup splash screen + is there someone skilled with gimp at loki :) ? +OK (Maj did) + +- don't have several files for license and readme .. use a central version + (scripts or proper settings in InstallShield) + in private/GtkRadiant/data <- where we put all the install specific stuff? + NOTE: we could put the gtk.dll libs there as well +OK + +- remove curry from the alpha (it's still MFC) + remove GenSurf as well .. try to get some info from David Hyde +OK + +- have a changelog for the end user (not the DevDocs/CHANGES kind of thing) + something that focuses on features and bug fixes more than on the internals +OK .. need to fill it up a bit + +- use quakev2.qe4 instead of quake.qe4 (both in nomedia and full) + added it in the advanced files section + (need to prompt the user about overwriting it) + for now the nomedia installation needs to run on top of 202 +OK + +- fix bug with shaders names (skies and liquids) +OK + +- add Wolfen to the credits! +OK \ No newline at end of file diff --git a/docs/developer/XML.txt b/docs/developer/XML.txt new file mode 100644 index 00000000..2e2ef596 --- /dev/null +++ b/docs/developer/XML.txt @@ -0,0 +1,27 @@ +printf mess in q3map +(and in the libs) + +q3map: several breeds .. qprintf _printf printf +should all resolve to use a single Sys_Printf thing +and put #define printf .. + +for the static libs? need to use function pointers.. + +q3map uses common/cmdlib.c +Radiant links against cmdlib.lib based on libs/cmdlib/cmdlib.cpp + +but eventually we'll want to use the same Sys_Printf scheme in q3map AND Radiant? +qprintf and _printf are defined in common/cmdlib.c +BUT: modifying cmdlib would probably break bspc and other stuff that relies on it? + +moving q3map to use a custom version of cmdlib.c in q3map/cmdlib.c +removing the qprintf and _printf stuff, moving to a seperate printout.c file + +compiling libxml on win32: need to turn off a bunch of stuff. +problem: we got two xmlversion.h files?? +we can't get rid of using libxml/xmlversion.h, so the solution is to get rid of xmlversion.h +(add ../libxml to the paths) + +fuck! +we also compile some .c files from common/ ! +-> create a common2/ dir .. diff --git a/docs/developer/XMLPush/ReadMe.txt b/docs/developer/XMLPush/ReadMe.txt new file mode 100644 index 00000000..f2c6ab49 --- /dev/null +++ b/docs/developer/XMLPush/ReadMe.txt @@ -0,0 +1,34 @@ +======================================================================== + CONSOLE APPLICATION : XMLPush +======================================================================== + + +AppWizard has created this XMLPush application for you. + +This file contains a summary of what you will find in each of the files that +make up your XMLPush application. + +XMLPush.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +XMLPush.cpp + This is the main application source file. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named XMLPush.pch and a precompiled types file named StdAfx.obj. + + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/docs/developer/XMLPush/StdAfx.cpp b/docs/developer/XMLPush/StdAfx.cpp new file mode 100644 index 00000000..e8b9d80f --- /dev/null +++ b/docs/developer/XMLPush/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// XMLPush.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/docs/developer/XMLPush/StdAfx.h b/docs/developer/XMLPush/StdAfx.h new file mode 100644 index 00000000..fbb8d5e2 --- /dev/null +++ b/docs/developer/XMLPush/StdAfx.h @@ -0,0 +1,22 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) +#define AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) + +#include "libxml/parser.h" +#include "libxml/tree.h" diff --git a/docs/developer/XMLPush/XMLDump.xml b/docs/developer/XMLPush/XMLDump.xml new file mode 100644 index 00000000..fcbaaaee --- /dev/null +++ b/docs/developer/XMLPush/XMLDump.xml @@ -0,0 +1,8 @@ + + +Q3Map - built for GtkRadiant v1.1b - based on v1.0q (c) 1999 Id Software Inc. + +************ ERROR ************ +usage: q3map [general options] [options] mapfile + + diff --git a/docs/developer/XMLPush/XMLPush.cpp b/docs/developer/XMLPush/XMLPush.cpp new file mode 100644 index 00000000..9edc3c63 --- /dev/null +++ b/docs/developer/XMLPush/XMLPush.cpp @@ -0,0 +1,30 @@ +// XMLPush.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" + +int main(int argc, char* argv[]) +{ + FILE *f; + xmlDocPtr doc; + + f = fopen("XMLDump.xml", "r"); + if (f != NULL) { + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + res = fread(chars, 1, 4, f); + if (res > 0) { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, + chars, res, "foooo (filename)?"); + while ((res = fread(chars, 1, size, f)) > 0) { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + xmlFreeParserCtxt(ctxt); + } + } + return 0; +} diff --git a/docs/developer/XMLmap.txt b/docs/developer/XMLmap.txt new file mode 100644 index 00000000..a88dd7f9 --- /dev/null +++ b/docs/developer/XMLmap.txt @@ -0,0 +1,27 @@ +XMLmap branch: + +need to move the map loading / saving code out in a module +what are the main dependencies? + +main functions to move out: +Map_LoadFile +Map_SaveFile +(and all their direct dependencies/call graph) +ex Entity_Parse Brush_Parse Entity_Write Brush_Write + +but? even changing to XML format we would need those functions too? +is it worth having the .map and .xmlmap through a same interface? + +what dependencies? +-> active_brushes +-> GetToken etc. +-> LoadFile (load into a buffer) .. that's VFS right? + +first step: move some code out in map module and try to compile it.. +Map_LoadFile for example +or the whole map.cpp? + +first problem: entity_t is declared in entity.h, currently not available to +the plugin API. Clean way would be to create a wrapper, but speed says we +should move entity_t to qertypes.h.. + diff --git a/docs/developer/changes.201.202 b/docs/developer/changes.201.202 new file mode 100644 index 00000000..449356f7 --- /dev/null +++ b/docs/developer/changes.201.202 @@ -0,0 +1,455 @@ +diff -rup ../Q3Radiant201/PrefsDlg.cpp Q3Radiant/PrefsDlg.cpp +--- ../Q3Radiant201/PrefsDlg.cpp Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/PrefsDlg.cpp Thu Aug 3 17:19:16 2000 +@@ -224,6 +232,8 @@ void CPrefsDlg::DoDataExchange(CDataExch + DDX_Text(pDX, IDC_EDIT_UNDOLEVELS, m_nUndoLevels); + DDV_MinMaxInt(pDX, m_nUndoLevels, 1, 64); + DDX_Check(pDX, IDC_CHECK_VERTEXMODE, m_bVertexSplit); ++ DDX_Check(pDX, IDC_CHECK_LOG, m_bLogConsole); ++ DDX_Check(pDX, IDC_NOALPHA, m_bDisableAlphaChannel); + //}}AFX_DATA_MAP + } + +@@ -236,6 +246,7 @@ BEGIN_MESSAGE_MAP(CPrefsDlg, CDialog) + ON_BN_CLICKED(IDC_BTN_BROWSEUSERINI, OnBtnBrowseuserini) + ON_CBN_SELCHANGE(IDC_COMBO_WHATGAME, OnSelchangeComboWhatgame) + ON_BN_CLICKED(IDC_BUTTON_CLEAN, OnButtonClean) ++ ON_BN_CLICKED(IDC_NOALPHA, OnNoalpha) + //}}AFX_MSG_MAP + END_MESSAGE_MAP() + +@@ -332,7 +344,7 @@ bool SetQdirFromPath( const char *path ) + len = strlen(BASEDIRNAME); + for (c=path+strlen(path)-1 ; c != path ; c--) + { +- int i; ++ unsigned int i; + + if (strnicmp (c, BASEDIRNAME, len) == 0) + { +@@ -448,7 +460,12 @@ void CPrefsDlg::LoadPrefs() + + m_strQuake2 = AfxGetApp()->GetProfileString(PREF_SECTION, Q2_KEY); + // if the path to the engine is empty, we set this flag to call InitEnginePath later +- if (m_strQuake2.GetLength() == 0) ++ // if the path to the engine is empty or points to a file that doesn't exist we call InitEnginePath ++ struct _finddata_t fileinfo; ++ int handle; ++ handle = _findfirst (m_strQuake2.GetBuffer(0), &fileinfo); ++ _findclose( handle ); ++ if (handle == -1 || m_strQuake2.GetLength() == 0) + InitEnginePath(); + + m_iLastLightIntensity = AfxGetApp()->GetProfileInt(PREF_SECTION, "LastLightIntensity", 300); +@@ -697,4 +731,10 @@ void CPrefsDlg::OnButtonClean() + theApp.ResetRegistry(); + g_pParentWnd->OnFileExit(); + } ++} ++ ++void CPrefsDlg::OnNoalpha() ++{ ++ if (static_cast(GetDlgItem(IDC_NOALPHA))->GetState() & 0x0003) ++ MessageBox( "If alpha channel support is disabled, Curry plugin might not work as expected.", "Alpha channel support", MB_OK ); + } +diff -rup ../Q3Radiant201/Radiant.rc Q3Radiant/Radiant.rc +--- ../Q3Radiant201/Radiant.rc Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/Radiant.rc Thu Aug 3 17:19:22 2000 +@@ -1518,7 +1520,7 @@ BEGIN + LTEXT "Height",IDC_STATIC,131,136,22,8 + END + +-IDD_DLG_PREFS DIALOG DISCARDABLE 0, 0, 386, 351 ++IDD_DLG_PREFS DIALOG DISCARDABLE 0, 0, 386, 380 + STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU + CAPTION "Q3Radiant Preferences" + FONT 8, "MS Sans Serif" +@@ -1561,103 +1563,108 @@ BEGIN + CONTROL "Texture subset",IDC_CHECK_TEXTUREWINDOW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,308,94,63,10 + CONTROL "Right click to drop entities",IDC_CHECK_RIGHTCLICK, +- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,137,95,10 ++ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,150,95,10 + CONTROL "Face selection",IDC_CHECK_FACE,"Button",BS_AUTOCHECKBOX | +- WS_TABSTOP,13,149,62,10 +- EDITTEXT IDC_EDIT_ROTATION,58,161,24,12,ES_AUTOHSCROLL ++ WS_TABSTOP,13,162,62,10 ++ EDITTEXT IDC_EDIT_ROTATION,58,174,24,12,ES_AUTOHSCROLL + CONTROL "ALT + multi-drag",IDC_CHECK_ALTDRAG,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,114,137,68,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,114,150,68,10 + CONTROL "Snap T to Grid",IDC_CHECK_SNAPT,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,114,149,62,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,114,162,62,10 + CONTROL "Mouse chaser",IDC_CHECK_MOUSECHASE,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,114,160,68,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,114,173,68,10 + CONTROL "Patch Toolbar",IDC_CHECK_WIDETOOLBAR,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,193,137,61,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,193,150,61,10 + CONTROL "Light drawing",IDC_CHECK_LIGHTDRAW,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,193,149,58,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,193,162,58,10 + CONTROL "Paint sizing info",IDC_CHECK_SIZEPAINT,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,193,160,65,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,193,173,65,10 + CONTROL "Hi Color Textures",IDC_CHECK_HICOLOR,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,281,137,70,10 +- LTEXT "Startup Shaders:",IDC_STATIC,281,150,54,8 +- COMBOBOX IDC_COMBO_SHADERS,281,160,82,54,CBS_DROPDOWNLIST | ++ BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | ++ WS_TABSTOP,281,150,70,10 ++ LTEXT "Startup Shaders:",IDC_STATIC,281,163,54,8 ++ COMBOBOX IDC_COMBO_SHADERS,281,173,82,54,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +- EDITTEXT IDC_EDIT_QUAKE2,13,215,229,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSE,248,216,16,11 ++ EDITTEXT IDC_EDIT_QUAKE2,13,228,229,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSE,248,230,16,11 + CONTROL "Use internal (DLL) QBSP....",IDC_CHECK_INTERNALBSP, +- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,234,102,10 ++ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,247,102,10 + CONTROL "Don't clamp plane points",IDC_CHECK_NOCLAMP,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,13,246,93,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,260,93,10 + CONTROL "Snapshots",IDC_CHECK_SNAPSHOTS,"Button",BS_AUTOCHECKBOX | +- WS_TABSTOP,13,258,49,10 ++ WS_TABSTOP,13,271,49,10 + CONTROL "Use +setgame for run",IDC_CHECK_SETGAME,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,13,270,83,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,284,83,10 + CONTROL "Run game after QBSP3...",IDC_CHECK_RUNQUAKE,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,234,96,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,247,96,10 + CONTROL "Load last project on open",IDC_CHECK_LOADLAST,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,246,96,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,260,96,10 + CONTROL "Load last map on open",IDC_CHECK_LOADLASTMAP,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,258,88,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,271,88,10 + CONTROL "Auto save every ",IDC_CHECK_AUTOSAVE,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,270,66,10 +- EDITTEXT IDC_EDIT_AUTOSAVE,188,270,27,12,ES_AUTOHSCROLL | ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,284,66,10 ++ EDITTEXT IDC_EDIT_AUTOSAVE,188,284,27,12,ES_AUTOHSCROLL | + ES_NUMBER + CONTROL "Spin1",IDC_SPIN_AUTOSAVE,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | +- UDS_ARROWKEYS,212,268,11,14 +- LTEXT "Status point size:",IDC_STATIC,258,235,54,8 +- EDITTEXT IDC_EDIT_STATUSPOINTSIZE,315,233,29,12,ES_AUTOHSCROLL ++ UDS_ARROWKEYS,212,282,11,14 ++ LTEXT "Status point size:",IDC_STATIC,258,249,54,8 ++ EDITTEXT IDC_EDIT_STATUSPOINTSIZE,315,247,29,12,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN_POINTSIZE,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | +- UDS_ARROWKEYS,344,232,11,14 +- LTEXT "Undo Levels:",IDC_STATIC,258,248,43,8 +- EDITTEXT IDC_EDIT_UNDOLEVELS,315,246,29,12,ES_AUTOHSCROLL ++ UDS_ARROWKEYS,344,246,11,14 ++ LTEXT "Undo Levels:",IDC_STATIC,258,262,43,8 ++ EDITTEXT IDC_EDIT_UNDOLEVELS,315,260,29,12,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN_UNDO,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | +- UDS_ARROWKEYS,344,246,11,14 ++ UDS_ARROWKEYS,344,260,11,14 + CONTROL "Use PAK/PK3 file(s):",IDC_CHECK_PAK,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,13,289,81,10 +- EDITTEXT IDC_EDIT_PAKFILE,95,288,227,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSEPAK,328,289,16,11 +- EDITTEXT IDC_EDIT_PREFABPATH,95,305,227,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSEPREFAB,328,306,16,11 +- EDITTEXT IDC_EDIT_USERPATH,95,322,227,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSEUSERINI,328,323,16,11 ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,303,81,10 ++ EDITTEXT IDC_EDIT_PAKFILE,95,302,227,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSEPAK,328,303,16,11 ++ EDITTEXT IDC_EDIT_PREFABPATH,95,319,227,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSEPREFAB,328,319,16,11 ++ EDITTEXT IDC_EDIT_USERPATH,95,335,227,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSEUSERINI,328,337,16,11 + DEFPUSHBUTTON "OK",IDOK,341,7,38,14 + PUSHBUTTON "Cancel",IDCANCEL,341,24,38,14 + CONTROL "Entities are DLL based",IDC_CHECK_DLLENTITIES,"Button", + BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | NOT WS_VISIBLE | +- WS_DISABLED | WS_TABSTOP,273,178,88,12 ++ WS_DISABLED | WS_TABSTOP,273,191,88,12 + CONTROL "Write face color info",IDC_CHECK_FACECOLOR,"Button", + BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | +- WS_TABSTOP,189,178,79,10 +- LTEXT "minutes",IDC_STATIC,216,271,25,8 ++ WS_TABSTOP,189,191,79,10 ++ LTEXT "minutes",IDC_STATIC,216,284,25,8 + GROUPBOX "Mouse",IDC_STATIC,179,7,103,28 +- GROUPBOX "Views / Rendering",IDC_STATIC,7,38,372,86 ++ GROUPBOX "Views / Rendering",IDC_STATIC,7,38,372,98 + GROUPBOX "Game path / Tool settings / Stuff that wouldn't fit anywhere else", +- IDC_STATIC,7,205,372,139 ++ IDC_STATIC,7,216,372,157 + CONTROL 147,IDB_VIEWDEFAULT,"Static",SS_BITMAP,13,48,21,19 + CONTROL 148,IDB_VIEWDEFAULT2,"Static",SS_BITMAP,40,48,21,19 + CONTROL 149,IDB_VIEWDEFAULT3,"Static",SS_BITMAP,67,48,21,19 +- GROUPBOX "New functionality:",IDC_STATIC,7,126,372,74 ++ GROUPBOX "New functionality:",IDC_STATIC,7,139,372,74 + CONTROL 150,IDB_VIEWDEFAULT_Z,"Static",SS_BITMAP,93,48,21,19 + LTEXT "slow",IDC_STATIC,131,69,15,8 + LTEXT "fast",IDC_STATIC,204,69,12,8 +- GROUPBOX "Camera ",IDC_STATIC,126,47,100,72 +- LTEXT "Prefab path:",IDC_STATIC,54,306,40,8 ++ GROUPBOX "Camera ",IDC_STATIC,126,47,100,84 ++ LTEXT "Prefab path:",IDC_STATIC,54,319,40,8 + GROUPBOX "Optimize interface for",IDC_STATIC,7,7,170,28 +- LTEXT "User INI path:",IDC_STATIC,49,324,45,8 +- LTEXT "Rotation inc:",IDC_STATIC,15,163,41,8 ++ LTEXT "User INI path:",IDC_STATIC,49,338,45,8 ++ LTEXT "Rotation inc:",IDC_STATIC,15,176,41,8 + CONTROL "Use Shaders",IDC_CHECK_USESHADERS,"Button", + BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | +- WS_TABSTOP,129,178,57,10 +- GROUPBOX "Texturing",IDC_STATIC,231,47,141,72 ++ WS_TABSTOP,129,191,57,10 ++ GROUPBOX "Texturing",IDC_STATIC,231,47,141,84 + LTEXT "Quality",IDC_STATIC,237,57,22,8 + LTEXT "Low",IDC_STATIC,239,81,14,8 + LTEXT "High",IDC_STATIC,347,82,16,8 + CONTROL "Vertex editing splits faces",IDC_CHECK_VERTEXMODE, +- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,179,94,10 ++ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,192,94,10 + PUSHBUTTON "Reset Registry",IDC_BUTTON_CLEAN,287,24,50,14 ++ CONTROL "Log console to Radiant.log",IDC_CHECK_LOG,"Button", ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,356,97,11 ++ CONTROL "Ignore alpha channel",IDC_NOALPHA,"Button", ++ BS_AUTOCHECKBOX | WS_TABSTOP,236,117,127,10 + END + + IDD_DLG_MAPINFO DIALOG DISCARDABLE 0, 0, 181, 183 +diff -rup ../Q3Radiant201/TexWnd.cpp Q3Radiant/TexWnd.cpp +--- ../Q3Radiant201/TexWnd.cpp Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/TexWnd.cpp Thu Aug 3 17:19:23 2000 +@@ -1439,31 +1550,46 @@ void Delay(float fSeconds) + void ViewShader(const char *pFile, const char *pName) + { + // we load the .shader file to find where it actually is +- CString str; ++ CString fullName = ValueForKey( g_qeglobals.d_project_entity, "basepath" ); ++ fullName += '/'; ++ fullName += pFile; + char* pBuff = NULL; +- int nSize = LoadFile(pFile, reinterpret_cast(&pBuff)); ++ int nSize = LoadFile(fullName.GetBuffer(0), reinterpret_cast(&pBuff)); + if (nSize == -1) + { +- nSize = PakLoadAnyFile(pFile, reinterpret_cast(&pBuff)); +- } +- +- if (nSize > 0) +- { +- str = pBuff; ++ Sys_Printf("Failed to load shader file %s ... check your project settings!\n", pFile ); ++ return; + } +- int nStart = 0; +- if (str.GetLength() > 0) ++ // look for the shader declaration ++ int nStart; ++ CString strFind = pName; ++ CString strLook = pBuff; ++ strLook.MakeLower(); ++ strFind.MakeLower(); ++ // offset used when jumping over commented out definitions ++ int nOffset = 0; ++ while (true) + { +- CString strFind = pName; +- CString strLook = str; +- strLook.MakeLower(); +- strFind.MakeLower(); +- int n = strLook.Find(strFind); +- if (n >= 0) +- { +- nStart = n; ++ nStart = strLook.Find(strFind, nOffset); ++ if (nStart == -1) ++ break; ++ // we have found something, maybe it's a commented out shader name? ++ char *strCheck = new char[strLook.GetLength()+1]; ++ strcpy( strCheck, strLook.GetBuffer(0) ); ++ strCheck[nStart] = 0; ++ char *pCheck = strrchr( strCheck, '\n' ); ++ // if there's a commentary sign in-between we'll continue ++ if (pCheck && strstr( pCheck, "//" )) ++ { ++ delete[] strCheck; ++ nOffset = nStart + 1; ++ continue; + } ++ delete[] strCheck; ++ break; + } ++ // now close the file ++ free(pBuff); + + CString s= "editpad "; + // build the full shader name +@@ -1472,7 +1598,9 @@ void ViewShader(const char *pFile, const + s += pFile; + WinExec(s, SW_SHOWNORMAL); + +- Delay(1.5); ++ // TTimo: we used to call Delay here, to continue processing messages. But it seems to induce a lot of instabilities. ++ // so now the user will simply have to wait. ++ Sleep( 1500 ); + + // now grab the edit window and scroll to the shader we want to edit + HWND hwndEdit = FindEditWindow(); +@@ -1485,8 +1613,6 @@ void ViewShader(const char *pFile, const + { + Sys_Printf("Unable to load shader editor.\n"); + } +- +- + } + + /* +@@ -2319,10 +2459,21 @@ void CTexWnd::OnVScroll(UINT nSBCode, UI + + void LoadShaders() + { ++ CStringList lst; ++ BuildShaderList( lst ); ++ if (lst.GetCount() == 0) ++ return; ++ POSITION pos = lst.GetHeadPosition(); ++ while (pos != NULL) ++ { ++ QERApp_LoadShaderFile( lst.GetAt(pos).GetBuffer(0) ); ++ lst.GetNext(pos); ++ } ++ ++ //++timo clean ++#if 0 + char dirstring[1024]; + char *path; +- //struct _finddata_t fileinfo; +- //int handle; + path = ValueForKey (g_qeglobals.d_project_entity, "basepath"); + sprintf (dirstring, "%s/scripts/shaderlist.txt", path); + char *pBuff = NULL; +@@ -2354,9 +2505,9 @@ void LoadShaders() + } + else + { +- Sys_Printf("Unable to load shaderlist.txt, shaders not loaded!"); ++ Sys_Printf("Unable to load %s, shaders not loaded!\n", dirstring); + } +- ++#endif + } + + // TTimo: modified to expect the reletive path to the skin as input +diff -rup ../Q3Radiant201/WIN_QE3.CPP Q3Radiant/WIN_QE3.CPP +--- ../Q3Radiant201/WIN_QE3.CPP Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/WIN_QE3.CPP Thu Aug 3 17:19:24 2000 +@@ -3,6 +3,11 @@ + #include "mru.h" + #include "PrefsDlg.h" + ++// for the logging part ++#include ++#include ++#include ++ + //////////////////////////////////////////////////////////////////////////// + // BSP frontend plugin + // global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin +@@ -42,10 +47,18 @@ void Sys_SetTitle (char *text) + } + + HCURSOR waitcursor; ++#define TIMING_STATS ++#ifdef TIMING_STATS ++double start,end; ++#endif + + void Sys_BeginWait (void) + { + waitcursor = SetCursor (LoadCursor (NULL, IDC_WAIT)); ++#ifdef TIMING_STATS ++ Sys_Printf("Sys_BeginWait\n"); ++ start = Sys_DoubleTime(); ++#endif + } + + void Sys_EndWait (void) +@@ -55,9 +68,12 @@ void Sys_EndWait (void) + SetCursor (waitcursor); + waitcursor = NULL; + } ++#ifdef TIMING_STATS ++ end = Sys_DoubleTime(); ++ Sys_Printf ("Sys_EndWait: %i ms\n", (int)(1000*(end-start))); ++#endif + } + +- + void Sys_GetCursorPos (int *x, int *y) + { + POINT lpPoint; +diff -rup ../Q3Radiant201/Win_main.cpp Q3Radiant/Win_main.cpp +--- ../Q3Radiant201/Win_main.cpp Mon Jun 26 12:31:01 2000 ++++ Q3Radiant/Win_main.cpp Thu Aug 3 17:19:24 2000 +@@ -341,54 +341,6 @@ void RunBsp (char *command) + Sleep (100); // give the new process a chance to open it's window + + BringWindowToTop( g_qeglobals.d_hwndMain ); // pop us back on top +-#if 0 +- // +- // write qe3bsp.bat +- // +- sprintf (batpath, "%sqe3bsp.bat", temppath); +- hFile = fopen(batpath, "w"); +- if (!hFile) +- Error ("Can't write to %s", batpath); +- fprintf (hFile, sys); +- fclose (hFile); +- +- // +- // write qe3bsp2.bat +- // +- sprintf (batpath, "%sqe3bsp2.bat", temppath); +- hFile = fopen(batpath, "w"); +- if (!hFile) +- Error ("Can't write to %s", batpath); +- fprintf (hFile, "%sqe3bsp.bat > %s", temppath, outputpath); +- fclose (hFile); +- +- Pointfile_Delete (); +- +- GetStartupInfo (&startupinfo); +- +- ret = CreateProcess( +- batpath, // pointer to name of executable module +- NULL, // pointer to command line string +- NULL, // pointer to process security attributes +- NULL, // pointer to thread security attributes +- FALSE, // handle inheritance flag +- 0 /*DETACHED_PROCESS*/, // creation flags +- NULL, // pointer to new environment block +- NULL, // pointer to current directory name +- &startupinfo, // pointer to STARTUPINFO +- &ProcessInformation // pointer to PROCESS_INFORMATION +- ); +- +- if (!ret) +- Error ("CreateProcess failed"); +- +- bsp_process = ProcessInformation.hProcess; +- +- Sleep (100); // give the new process a chance to open it's window +- +- //BringWindowToTop( g_qeglobals.d_hwndMain ); // pop us back on top +- //SetFocus (g_qeglobals.d_hwndCamera); +-#endif + } + } + diff --git a/docs/developer/d2u b/docs/developer/d2u new file mode 100644 index 00000000..16d4e197 --- /dev/null +++ b/docs/developer/d2u @@ -0,0 +1,17 @@ +#!/bin/sh + +for filename in $*; do + if [ -f $filename ]; then + echo -n $filename + tr -d '\r' < $filename > ___$filename_d2u___ + mv ___$filename_d2u___ $filename + echo " converted." + else + echo "$filename is not a file." + fi +done + +echo +echo done. + +# end of d2u ... diff --git a/docs/developer/data-driven-design.txt b/docs/developer/data-driven-design.txt new file mode 100644 index 00000000..698fa1b5 --- /dev/null +++ b/docs/developer/data-driven-design.txt @@ -0,0 +1,76 @@ +Listing of required modules and interfaces as an XML file +========================================================= + +Purpose: +-------- + +Make the editor more data driven. Be able to specify during +startup the full running configuration of the editor: +- what modules to load +- general execution paths (i.e. what's in the project settings) +- configuration for the loaded modules +- user preferences + +Feature Requirements: +--------------------- + +This is primarily intended for multiple games support. A restart +of the editor may be required when going from one game to the +other, but otherwise it should read the XML file and initialize +the right modules and APIs from there. + +Don't have a clear view of what multiple games support is gonna +be like. Can list a few things: + +- some interfaces are required for startup in a given game mode. +That's primarily what the XML config file is there for. +For instance in Q3 you will require Q3 map format module +and Q1 will require Q1 map format module + +- some modules are to be ignored? that's primary intended to +avoid loading unneeded modules. + +- some plugins are loaded for all games? +- some plugins are only relevant for some games? +(those two suggest various installation paths for modules +and directory-based scan?) + +- a plugin might require some other APIs to complete it's loading +process (i.e. sending it's own XML description of required +interfaces). + +Constaints: +----------- + +We have a nasty collision between preferences / project settings +and XML requirements. All three things need to be unified in some way. +The long term target being to have a central installation location +for the editor, and independant packages for each game. + +What kind of difference is there between project settings and prefs? +Prefs would be user settings that survive throughout all games, +whereas project settings are per-game / per-mod configuration. Turns +out it's all a matter of loading the right configuration chunks at the +right time. + +Proposed implementation: +------------------------ + +Use key/values (== property bags) based on XML format for everything. +Use them on project settings, and user prefs. The only difference +between what would be project settings and what would be user pref +is in which game configuration they are loaded, and how they are used. + +Project templates: We have a particular syntax to build settings from +a 'template' version. Instead of loading a project template, we should +be selecting a template from a list. + +Default startup: If we are configured to load last project on startup, +load it .. otherwise display a list of games and templates? + +Module library: +--------------- + +The dynamic loading / interfaces sharing / pure virtual classes needs +to be implemented in a generic module. It should be the basis of the +editor startup process. diff --git a/docs/developer/frp b/docs/developer/frp new file mode 100644 index 00000000..6267f4f9 --- /dev/null +++ b/docs/developer/frp @@ -0,0 +1,6 @@ +#!/bin/sh +for i in *.h; do + sed -e "s/BasePath/EnginePath/" $i > $i.tmp + mv -f $i.tmp $i + done + diff --git a/docs/developer/q3mapfeedback.txt b/docs/developer/q3mapfeedback.txt new file mode 100644 index 00000000..4831eb13 --- /dev/null +++ b/docs/developer/q3mapfeedback.txt @@ -0,0 +1,33 @@ +** currently supported debug messages: + +* map leaked / pointfile information ++ tested + +* duplicate plane ++ tested + +* degenerate plane, mirrored plane ++ testing may not be necessary, exact same code as duplicate plane + +* mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL +- not tested! + +* fog brush has multiple visible sides ++ tested + +* WindingFromDrawSurf failed: MAX_POINTS_ON_WINDING exceeded ++ tested, only outputs a single point, would need much improvement + (TstMaps/western.map) + +* MAX_BUILD_SIDES +uses xml_Select as other warnings, switched xml_Select to error or warn ++ tested + +** to-be-added list (and associated test map file if any) + +* Node without a volume +* leaf with too many portals +-> both in Desktop_p_leaf.map, contributed by y_lavanant@vistech.ie + +Mesh lightmap miscount +(no test map) \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png new file mode 100644 index 0000000000000000000000000000000000000000..faf0c04d26071ad56934bc653f8bed31c0775548 GIT binary patch literal 10232 zcmZ{KcUTi&xAlNju>neNQl*6^AVnfb2SIv~0D^QBB!SRDu+c?&6Q%c#D1ii|N+{BM zk=`RM)W98o?|biepXdGVAIUs(=A1Kg_StLgwf9WeV;!}tmzgdD0B}`9U0ELhh}i*v zNRNUTYIPlsoLOXO{LK18SCuS<8SEZl9FVETa%)?Vr$Nizwva+JGGJ}=$vZ9E|Sxm!uaotS-ctH8-Vs9_4`~~Cyio769 zPaP8h!CQam;SS)lN_FO*t!xFI)eRaM#A}8tT`Vf8*Voter#G_oO*C0V%D36Ki?e;dnJlli`YvcT4ye`oJ={9bn{pD_ zErge*&rW_EIlh_e-gRd%Hl|bOc4~Cl)`Aa=Y9{-|#`m7z2@}&M9oT6?=)I98=-K*^ z!9WcTf;2d6J5B8`|c0^VFqg$BIw-_F~bF5XWIbj`%qenC!^=?ac8%N=O4 z7k~W{{oHotK*rN*u~BUYZ#%Qo;`UqGPp_dCC9y(^NXiJT+!&p7DtS)2W_6u@NXc&0 zc-wATx%K5J#jV;n5!E<*0t3SNU_md>k(V*m} z_OxYKeZBMRaQ!F_r+PBlJyWVKdSR57Fn9Dpc56SKfNV~Y?#mYg-<>n7oIiO!DSp&p zQddwP;e)9Yggi-e;a_wD&!0azm~H5H7TI-bT<~PeaV)fj4J+kR3;X_g zI>R*`9?fsTNX?UJ7`NOT=xl8D6q;=`cRgYFJjQK1@TgHi_SNs?j+YM8?gs@Dd9^H7 zYxaw)(T>-$b?j8xV-aj;i1c>>ES^QGRxmUF&eYPXQOq(vk6oiusFv=&@vV>r(?tCD0&IrdW#isEr-3G;4%xLVE>5#7$YqNm z2kUe;@9n&vI|gx@W(Q8A)m1Z`c2VV?r%ngA>Uz|P3`SSJ5WIbLGuSuoU!IiF4p9B% zxA*q0=beqg7kTA?I);@WVUC~|$R^mn5$gbtu+}2xguBF1&OD;3!ytOZCTf#rt+Pxq znm7KgqiKdxaV^W6@Os=YbHmbFmbRb6GyUf4dI^mEWAl$z1%HUnM`te;z-OZkQtP$v zbSAn_{M1WWvnWBZsGKWCN+(crKg$0Vt?MaFQj-{ZuP`%7w7<26?#pkN90dhW_D{nNQcF`n3QpRJBa-O}uv!qHM3pS+b^oK#1$xOQJ7 zBxp?L9do%pp&a7(%ykT1Vkd&LYipkKzPMqaYM|G196A{I+Wv;bC#$c0f`6jPYnlXa zo2QP9CI84#EV(6IG~AGOGh~ZzKl+_ARxiB(zv?L5uT1QJk#RzQwxU!J7FQ%tVp~%4h`DC#aY2sS!Ol-9C zhH=i|kglA$i7L`5sC3~De8yRLYmcTL`!JwHZQQdnft~Mz&Y*yo<*8HPbl61khC$eg zp>bO50mlGh;JfRj?vv|Yr{6s$V$Kf|0_3Ch(^hKtCPOpcnY-wfM%xWr4&s$r!%wDC zvWxmuWV;Hqj*x`fv&#M{yI5=6kI3Chi7b(x2x#(Nz zh>MA@VV(#~(p)q(AsnbRQ}-y`Bfh^&2x8Uu-gAQ*myu;3Bm|S~<(Fp~#RmQ9?T9AJ zZkb%!IXa#>L=Ba{W|(GC!QMWf4WJv4cb(?hL{d76mOdHNR6Bw_yNsUA4dhv;E?_9d zQaeI1Sae~r(AB&Vld@KI8l%z7%Ii_j2)f)q%-w$AY@CG4wg--2IotZDFdMF4 zUzj2n+7Ahk>s#;T){$Y(jV%O785ylq1SJL=`pY`LwA3DY_S>w6g9xyt$o;##WW;t|zmQ5#6VC(IBuMZW9J$WILt4uR5!FY=cQs<wuN8g76)W4b5h_(pU#}%>UIuk8zvUyEU8I?1IKR?Ucg_uO*M4Jeh2+o(7tsk1`|xO8qeh?oil0_z6*e!TQ2Xw2G}>CIwBDp? zem86B#?d(ytL3|fi*XdVs{SGu%<4e{8o^!9_!9OOA49I<>XEqhdAPZTul?t-VhnYbVbMLjq2@w1jpyVM4AF@d zQP>}p7AM0{1=62Ej$oHLg>7Ysm&FOyiJW~*(`~VWOu9%JZ!0FE!4udzZX_cu;uwpm~f==qh!V!x4%srZ=A_zH|T7{gXRh~@kpe)GFARdW<2A5q(^a^=Lu2>2h zvo=@nqN*=Pt4jExmC|%z`UZ7H0fcLY^%3bfeT|#K=0kezEF_UOXsSI}GOnuj7*fp< zAUvTw!fzekGhE)+=BQ5DJlKnr$+~KDkpJ_!Z0+^sQ=CGAzIpV>l8M84_i!<`>H83D zVo&QfqTv`qzG-$+b#wQi+WwDo>-S_I!Hrfnw-HRL>|;*W0D3e0iHjItz~J|W;^#J= zmmkSqw-GADFPruam}p?M;I1o^(lhbVW+yK(5$bAVgz5g8ee}@n=-IX*(+xk0-T`T3 z*bz+Ir;TCo5cS^dq?Rn31ruRJ_q(s6CQ&MLMkqkSZz?Ufe3t;}(ev*q@cMeK4(Y+L zk18;B(d!i=Xk#KgYAks^#V5Qgm~Cs21a%ABmf6XGTEYTS>;UJ~SQ^yX^{^E;P!nD= z%X3$2cEmTziw%$Z_BATi2`%h3brc;3ZMQS2lI&Z6u9aDB2=>;s89j{sZ4&jRq<+iF z5=z*cUP%ZRvkaJaa=w~3U|7?kl38~s>usZ;pbf7SwofhkVq&h9Tcy5Ws*OBu*8Oy` zw&4(Ta&n_umYyqh+0v#xkhW^{$8!I|N}Y7y3*nAHgNGfl>Ib+jx6H<~-G|T+#xTc2 zG-APpFG^i)ba;C!=xB4vP2ui~v(UpOLZ4;e&X<0}=vSE<56uK^Suoh#eH4i&ePwSl z!>jEcdaE9vU$}w7=FMC(+Cx-LYDcKtNMg49pg{D(6kbq4i`Ij1)mT+71r9LJLKwezavo{W?Xh%A`~p3Dq7h#jz_C>iA<#ZJgwJ;&*J-Qp~UP zvnn1rdmyMEMl|`;5BDPVK+`?bKsjp{mDmYpv1cZ(tUi3FHT-*jQ$SXF*6?apKj zs_UWqPM24T(kRFBG0f1V1LwUx;}I@~(fS^`&rNWT13vO%xE0JHV^MFBdKxUrtND~ zR#t+lv6(7Cd&51r7lEUKXfsOtCL`ZlTC5+7QI7uoS=}aAOC)&VG}XCPy$t`N4jnwI zmCj0oBG__A_j}g|9$3u?&1r&XyQxFuF{B&$6pekh2m33-8-0(_U>D7gc8nV;HER_Z zt&K#7prqh0Eia(U2DW(Q)1agR4T&L>&XwMChyjQC?;uz*_OW z#x|*tEm#$}rcMt4cdieB)r+oB1XwQE%~4SNcD!!Cy{XucRV)=!4ZGZ4zF}4B?q2Df^_vRh-ZPm8ei}t{+1`E~4pS-EwE|Qcnm42HO zCkk%U@5XW3g>v0u`T6^7!pBEQX`Y*}`Ra`)`Q!(rfPH=)BDRcv+#qwz1!?)|{fD59 zp7(T(+fMXWL+uN5(RNNru_DEt9c8qZgGQxb1Co>U(CRwK`TPR@ zmKTj0SOzN}qNb0G$g=ahn%bhNl=3RH=3L)Sh^#5&M_~hr1v+v@=-b$fa3Sw4USV)c zsq!-sVF$fB-j55Oolk7+_T~(XlbLcrlH4H{YzBlV@{{rh-yQs5 z`Uz}&{&@F9Nrb< zIp~-g!;EVYI%l0S(n?NG6<*Y&N5e^z-zLv4 zwc<|SiE)fSm1(~A^?rRWwymvgDuv`8J!FIr$Pv!mK3}XAppja~a7fsv+~$No77FIQ<#HD#J0*x?JDQV>)k- zWR18&Xjj-aqipxgr|XzDQLcJDKPAq4x!ci{8gzIDr5(3PYg-N&U`?TZQ+-gk{@!fN z&mi0L71MM9`QKGK7qUXU0HCevHqA4Z(1AAh0^NrQXi5>Cm$gL;6`tGSuK-OlqP4R; zr6>0=>+Wi&j32In1G;al&9Ac83m)<)20AYn&3zBbQVQ2QF#&+&kGBVS#$M+8?Xg@0 zIfNV&U+O0YL`7)L+H;IwYRZOTa}CJXJUC0*i7FUR@b8S&%opK%l0C?mu2z90LbjyG zXI9WmIV!+iKo{z5&WbyCmnM|@X(jnDJrtz1^^axgzC@FIPdD)R*|reSq~W;sQMb9r z_(UTKo%Q3GL}s~y(!A#E0jZznX;kNx9Mj*h=8vj#L-SCBXHN8U@L z0f62_NuL9dB}7M|_2|9?bS+&QET%^9TPQM#pP)h$Cgx7THWmhF``mD{j6 z1ca#@qnVuZ%!E18HafsBXa${dZx(ernn&f)ReDO-T>g;HyktN&;)d3GJUNlzk3&>s z&bK=aC+?i+1OCAq@s^c{rU2ca@bZv&a}mkd=!OG+Y=f-IYWHz4IgyJ4cbkf^GSY`| zLci>`-LPoyy)C5O^QLDF))z^e;9*acnT+nggwPM{9Lr_!qUY|C;TTTZxk+D3GTpXw zCbIqzNMZCrr?cpo-YRUozT69Q)3MliI?w4a1Iedw@i!G^Ti}N{drh|`@eE@e3K&Z$ zW?cy8qR4H1b@GRzExZ-gRG+?e9@lLM{V->viwrlmQZ=#|+8p3{pWStjP9gwuDIm@~ zKSP+Inewi*NA$Ud5Wn5zuMs-}b5mA(o6dD+xI}vLu`=H$_uMOadoDHl8qG4IMe|v_ zW)9t3+Iu~kVlDA9qhV?A6=ju8*UFsq2c;@&4}93PguMsM5+yn1x>`AN0$Pv zY|LjqfQ|HmD5VDZ)W>aI`T4zzvQI>Pw(o|Acsd1tLgkr5b4bNX`&b&f8#gT7`K6JP z#a>O*ibpP>SvKcsQ5K!|nukq6eEDfRFfu!3UIzeEj=dvT`h6nF z-g2GKaGyUk7c2l^|FqMB@cChzD}Gd(AFlCd3R%|*0VDL1sB%4t-2R~7akJk|fl7Lj zT{6I$vb&*otRf0s89)RGr5~@L8eVk9Gn&iwcV`@K!3o(LW3$;CYRy_UzXKK))tDD{ z(WA>9(8|YJb0wFlLf1-BS4Nmaq>7Vo3wAUup@Kvsq7=*R?iSB1;C}C+*tbf)dUsX~!)Vamw60QL*>Mr>?jS67w?%Q!{7@Lo?1$i}82(Orovv zgR!^n;5;?W&h8E-A?S>G3zRNh^Lc(UQsJz+k9y|2Y}=pyXO72Fz(pA^*{svS*Du{h z94eJ^h7cF&=gZ*f>P|S5Ocdnv5QR2&(V*n%gjaTWXtd*5iK@kx4^d6_qO7l3>Z8@_ zCDu2K!uRb0Xn*#>h3s|GV>N%PVShf0ebT}--Z>NBVn6xdB`!Bv;V$&^jc;tGep& zO>L;%m99C&{XvF~?ozF`&Ei(=&-+)(+BpxP__~G8oU7H;ScXW=b9x&EF)=P!E3dr{ zr~dB`ndZ4}NpaEP-{=PFdinM2%R)%kc=E~P?My>-p3c$g9p;+dAEaD)c&T&Im8WZ*?o2z`p#C1Kuj^iyG6qx7C_*a- zs=jn)c%Ve$__2N2kvR5;==&Q$FvsK>r;n4L)$+>iSV188mRP-=tL3{^8a%qY?^5aw z!1Zl^u9iJgMzO=(AE!0zHdH)EK?975MjUba$oGpc%_LDqk=xRPQ}1adRn{h=?ICJ% zj9zLhmIeHP`-|?);l8Pml5)cjuPQrbD7%6N?JLiA6H63;;9T)NfBFQmFXH`SB3?Kx z{_x#Wc$ftdP!b`NtF>GfA0T29w;7P~O`h+1r4{&W6<5E?%z}$pwhJsj7ih931%5@q z;~|>?lz^y|X*&RXmj4fZTjJ@~HD>4&RH^|+=0_(l)1M9A)5<*d zv&e(n{K$|?{m{w=zW*$?KX2p@O**3E3ldD~UW$5@-Wwo5t7UmIYQNlyLCI^-GXmC) zk%F+qUt0LC(9QXXMGPDlOe=8(sL-aX_cJY-y#LZ-c9eIy;O0U?QU)<#Z42I-yF@#m zB6gJ)p+Q9(qvJ}e!XBbNTrwNR)HZ3X~ifYuN!#6ByTYMK(4<|-6IE9|ue zxHV{WY0zRB0M{@T^`!mfkAdp0Gd2#g8LUVV(0ZX*YrOCCBub#dEAa*6BpX9BNZF>Z zw>^xlNiGG$fi>|<6t{pe`TxTs_V?CL1%IZ&XANNfE+TKBEPyr7{<*!-S7Osygzrzb z#2I41l>T3X4Z4wHF3f_JRgK{#ZaASyoa3FLaFx9Ukm5u(>Nrr^ePLLOXT(uLJG4*7Wjv5rgzw>dFaJxMzwd(^mf zRSW>&{ZHy6OK&_oQMVbVu#5&>+}Z}za${d3TPR)#j;~>UPL0LB*(L()pDANaeIwc} zCpGaC$6~A$06^R13cBCFQ#y$<#P2j~Ab5{t`u}Bkpzi%|VDxnlkk&zgCSDo(X;LvV zK$K^N^RMq|(h0yIOwZIe8zl1NiGe1PNHj5KHXjMONWhdnv)6VI)CK^CwEkRdu)_VX z+_{N2Iw`@(R2@Iv!ct)a0ydRLGs%+qF*uaitiZ%-;XPfq4FI@24V-SHzukQGPAFnq zb8U*^CkY^WRYEJN)x>g*V(sRD91I*WCNv>V1^|L~fml=Cc4H}|D)_ulmw~46 zroY$zKT!DMXHW%zvb+dX13RRYS)k3fx<&pj#t%HC+clpJH|dP$i_?KN%C2f{4#>OEIK%{HY(05JH=OO+G@qw{L- zkIntBKjLHscO>j3$dm2y8PvO^4>@Zs*Fb^7|8HxO{zD-$Tx%g_;Jo6?nK+ugb!5GU zIG;4$9(>l1$yzqwyT2wEZff2HAnFZ52!SlzKXzZDuLGZ z`0DnTRM!53mGU!9px@Zgyvs6uk)aE$fVI{?Xxa`Ct>The#Hil{g0D(s*>xwem$VTB z?!4U#NXqS-jFSfXWL0h4K$8H2c-p|))KYIuN;@P7{650KN2au|R)c}3*kTF8HH)`g~M^Q|Pl-UqRy zAfTE=tGBaI9%0l{jc94XgO{njx;oDO*T{hnb5p{$jsgH+TXAoV^N4BF%F*igXKe$O8}L_xm){{jPSMs zQ22!osvo$!@L28e`kyO>#{;!J|1^-i7N{>J^Pl15{Z;tto_?8mH z!@$QqOXwXD0)Pm+m(~1(;+Mj}c`jE(5`iLnc@#!-&jp^MvP)3e48=}lFM$AU>-ICq z6G4oK;-yD-O{$>*EouO8FXQ+yFS0Z?or_`Mu=1CoFHcE%$N(>5}S6w+tv5pf|u=UkkvF2^{00 zn5zO1X{+h(3`rpPl6umkSM$UG6%lsKyl{wqD?sda=&dArjIS8d39xqQ#z@<_`~Kwx zbqVd4KD$^xxC0CLAp#9(-;_2gt2V~Ir>H{63 zrv028ELbd5l`v)cTPO@=*UVk-$p`@M(Jx=vgXsE7{=W*0{{j_%d7wLaED!wU%U26b zbMoU4f@)uJs>`C)m(#=mQ!3`wa;e88EnY&l+B77=wH2?fImV?jk!!SWw|!!HD5 zgFy#^bmpeoNPq%LF9X{tJ14vS>buUoTH9>Kc0>NBLVZL4-47XrL5dv<>ZlDt&zC*y z^H`vryNI@+kB`9$XgdC|owqBOm9FEOVi&2x97>H;z*n=y7l?^5M}iUh17amxiB)f2 zxiklp${V-mcVPR*;+&Q^xJUFem$?(WWXc({9y08fki-oze(J2f9~lU9>KBg+X4I=E zq59KDB6@kS#h$DB~au6LksbT>E=_J98Ux)O>OshJy!u ztu@`dn@qv$9x_1OltQ}!Ugu<#$XFieVu+Nod`krqnG%mgNKjVdP7TN-2-!b!a#<{C z7Y(c?4kq%7yet2g@uw{bS2urA0uDdOPKvMIRE+xw0gI1thwA`G#MONh<~t$WJg}pi z48X|0JB0jI+5avO|1VOE*%}TS>&pPYyBi}0>x01KPodkpXPKFO8CSukoAfb3C*Irg zAWx2b^Cp}eO!=7J`TJekfmNdsYw?~)AYrM;L^|^Vn}2df2=aGxuM#iZ`6W{xJvhP$ dJm|R~Zyse;OVJ1!1`E}IhKi1InUZzLe*sZCmooqW literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png new file mode 100644 index 0000000000000000000000000000000000000000..e47ad7d6f8252aecffcecb5407994a79db87d1e5 GIT binary patch literal 12471 zcmbVycT`hd*XKn*1VoyEh=PiM(ghLeNReKY-ivf3L0W*&MNt6(=^a!+gwO&+AOS&o z@4ZNGfzU&!bM^h^n|GdhXRTTDS9b1Q>)eyvz0dxY{a#yBiHhPn1pok4D#{Aa0pP+{ z03gb^bOF55#TWVw{2;M^qVWU(N~0)GtVjXi7NDZ=MAtiQV@m5CM_c;nwzu6C;f651 z7bH%@7et1|eA~_`82$Aqhp4!>-uobHto9wE>fPD}`T1W$ zhl1MD(n;A9mPm02pP^e%L<=n`&~lh8d4?aq3DHu0ecJ+o%*@Hm%(&xhhq7Hog{O8; zmju{_X4G;3Kz4{xHGjiP!czo{1MmTUxW2J3sFZWb)3w#|3L*d?_USn3nXiMVm9E5E zq&*y=kvU!TX|^T;TIcG{@?P70c0QCKG_}oI+^{QbqajV1Iz&xIA$gw~9OczXo}bkb zP)6+}z^yM~=ksH)&r3$sJAP$eaUEl~JGf90IIFUMJ~%WKU;W%55M6yVKQz=)P>^UK zaK380i|YvV_3`l`?CdNq;`jvuVT8G+@D8R#fq-K$VEX$3wJ?>e@!rP1F`9IGw^F`vE!7!QQlV6$sMdvKZGY(5|8K)fK zrFeY~XORwFIi!{K2xs9_Z%_A}!2&@%!epj;KivccnQ;o4s;Ca|Io;7q5=I{0Swi3@ zedA9hz&o{5SKW@`sQ6pfZ{@aREY6YD&oqKZMv7lUor5C{wB|+GkE6~vx7!3Xi_W}r zAaT#vjLmp*QdUi7s)lS1kJ#$;Mb{3}C%OVN&zF3V!PC!h4^#710^Pj&Cj}2z1$yd^ z^Wd8y!F`fv>(uej+0K?*V#J2kd4i9h{nGfY>5aS;t2o@C`jTOVUrk8q`A5Cw!;3MU zB%B`p{!^Fd*SBE)?o*9}GJdCIH#KmRRl6smJwsgu1;Mcv84ppTChWN!tPj{p&1X#O z5Yx4u$DXAz!Qz5<;q{8%YU|ML0Xb2d0m;L8uu8#LE@NKxEv?JRcX30vuV(DlYiY_Hw&g!x+wPHhNH2Lt z2pl_ghTtg>%dYln?AE zQzsgac)p$rma@~g?`u3BIRDPF|Iv3@PYu$LR?qSv^~v$XOpX6?clrbjGDE0Omyr2^ zG%mVJE3BJkqGJ_IrBwojTsB0J6b*R_E7d$VShCf0U$t5q$~Z0F?FjV#4oR}KMw9n6 z9Y;PFUE9r^K`wd6ibx-J3{ao#462?GdT=6v#mf@RQ*S<$g>oKB->qw8`Ua$ zuMa%eoNzMMt0-HKBskR~LpUC?aC*7OVe-knG{Rj%#)rCw)-CgX{n@CVp>t!Wx#chS zp0mY8HKc?8t5?fpu)@w%3uxhVow=)yE_i1maA!(cF*w`*EL=WkkSy@k=RB6KG-aW5 z+4GT9PHCNtCNs!4-|XaUEFwHQZlLPW3ZX9c%(qReLnM zhC9d4h+1v#)n%@kV42zN(6R;6n|aeTg>!hU#i{e8VDJ9)i7%3{pPOuc>bigQyy1r) zP2FXpr%P0BzPZe2aPIH-+P*KU(yQd#uaR3zei#ZxFW31L;d(`3jj75wD%a_E`H;aS z>ld68Cr-OhmnCjIkiY$-iq_TM$A14;{8?<6xWDW8A7Q&c}O3swHZC*RV zQn^uF1%-Y*T9~6?UW5HlqCiy%>iFX5gI|pw)eTFv!jN4}b`_?Ggo2?=gnr<`cdc{r z(F(=RT*@Me=2Qz8k86;~q-mSm4Hx2J*XjsOK?SJ=u<0GiKzwyCDy{~Q8gxCA>Dd=N zlYpMLb<9W|AJk3js6MD~bf8a4luMzamk`-Ls5_|?i#X>#F{|^vp+P3%Z-GwUB`{^K zKf_1R3d4h!1Z!_%U$j^&*_HGd@&bTSQhlvXGxO=A0DA09nRLgGug$3QAv`jX9FToV zJ}Urkym5!bxfp(sXP<}2Cjx$&P9CphZ4T-IfTfVcg9xZGpTRGN?p`S%OICsjJ7js=r?=x0 z0DRgWlKAfj{(Uy8re4}3+^lDrRT9X$lFrr($1CAd&i!{5W2M6b!I(lVIxo&W@TmFn zmZUK?@J+sb;Lxu3=ADZuevcbVIkN7wmTv?7jed#{0a>nMVcRpOeKlQ~VoE(QopvP8 z3x(_ob<{$1S5q^#JuG0pG8xJ_>|RI*0Qa;jabu}wezdgsQP{qKCu?jT^fH+icrQov6^W-uPN8+uOji+EG8mSD;n z!wP8scv(MZOOfoaKOJn|u8OSEd76X8|eD@O6ol=5@sB)O}{>KwaBr1U% z0Mz48Od)O5cp^X$p*n3pv&#=+B!+^!qdeAgwvMMtSiGFZizlB^`|6iZ(0N9HUV;IGr1EiGiyj zR(=4mzgt)wO)IO&D?;s=H?<*KACs3#N>G>j0AN z&Nx^}T}_>*Lf8%}zE{5nX{vi?=i`zQO zJ|jKkyixh_B|KI|$TwW|OgD+6L)KrX)eY*iGp2Ih4*(L~muuzj4m-)-Tu6DBYX=0q!1(Pp+zs2 z;0N1W`<)Mu^ih)2ur-?=e+42S$dnF#Kx>Ca<-!?9kK!yGUJdVuqV+ec8_BrQZ4_)6 z0MHeXFNu;FS&DQ=kjptvz8~&4Mz&Ixv!d|{H!Q%P+uYK#X!leGOpWUy{+bHDfNb!k z12NiFB7pSHC^4Wd79s@z@$CP9VXDw*aRSe7Pa0bfM;dcaMoC;~(|*rTY)x$gpP)2K zdRlCA#(_a?!Xw9J`DvcZ=&t2zRmTUHQg-FX^2TF%2-)fOtSHnDBkZinXJOzqp1M$M z$$4(?*s8?`Hd%zp?lzm5t^DZ*Wj=B!HS|uLz@84nNY=IT{8L?%Be^>I63uScy!=?m z_vq|m8u~)(J@*m=)tiBS*z~$7h(Ly!vZ`RJuKR4dt+?P3; z{6Nm)C+GbBWw7$IX)0&i7+fwh?dFwTWrN_?Q!fcSH%F>l7V~0;&4!m3h>K6^&F}An z1#i^;iltm4(7lxW=1>ehN-$Y8@vf$a*&AgIafI=D!ZxJf&`mhw!N__AtXAw>tn;gF zx59xmo9y(pgvuHDD)CjHy()%v539J6_i|$<)Za8moZJ^88+~9(lC}%aWq+`vHH^(S zZgbM+Vm1D{?}ps5RIMq`h%6nq zUD+M&<`3jd*DXA5ZakXq+Nj%XppU_)e9?LKiSy=t!nO%Nn?mP>l)Z;F6fg$1h1ALmj`8pFZV(ob?3`B)jGMP7 zOeqRK-G?@zb0UR<80!$xmYuKa78DJ?Bodqk4N4g(lg-{NF1+4yO7g^c(0G22@KeYh z72d*j&chE*CrV35P+t<(Y1WK2i<}pV3L)FwDNc3EW=C0^`3t<2>TQ!@%A7_JKWVtn zrJOx1rcmkI-1{kKS>eR3;GkZ1?(Ah9W2U}pifp<$VxtB<;ezYQ^L&WtnDPaCkxy*C z?{ETE24B_#P$>hC@mLI+L1*q_COWHC9a^NFka83fL*|dJk$1~=>$sX>FXxDUKd&Kf zB`{KMl2@j!>VlfcvyhUKlJIvu`FZlP3guB(gfuUv#<9JvZFWCvB5b#`OfLuHYGJ6J zky0-w`yPMW)P#BegR_+_hv9-pDWQ)9C;P&+=op=G} zauHG?R>idvxEJ5+jsAcbO=1iu?OETrfJUV; z&6{FZ`HOT)V+iR9Nd+>4b(~{4>2qD;u&EIPnIi|xjot;kAlu3v#rxF?#i#s zCEE2uFx-{)(2J|R?Ws|hnsihtL|b0S2Wz`oJTiX=8#H(<1VupC`E1;8vQKbZ5r0&# zt(%M-sP@_!ih}ktyJ&UY%oIFlfwt+3nIYk#cKxazMJ_ixy`dT%?o`I|9zqSo1Vs|~ ztTKFskbfwwuw&&1yQVKhTdY2!2s1PNdIRU-C@K>7QjG$iC~Dilx~j|3Mn@TOgy4Jf z!$_`x5&G*>e?Q$|dt}$r4MJYyp*7Vw!a$zn*bJgR=`iS3#jJjB#4gi7EyKWts5pDV zb;&Yt>#Y7Rbd9eu;;k!L#eA0~H?!z5+IR=;M5+Gyoz+Q-ht!BGL@s%0NN8El#L{oz zF9^S=*ux4?G;Nd^gODO7QMrUHh;BR1IX?I34Kdi|ui6I&WI0v31(!IUh^W|iG0x!1vj z&LMu6NNN{#p$zR&W>5b5%qy6sZ+VAg=28N@qgN@s>CV|_59FfynOCed!@K31bBIDS z(HcE6lxi$A5U7gSeptJI(6&@})JaDelsx`XTr%jW`@7JFzadqKP>~egWL-1W|2j(f z?0Hbt%+$qRN8I{_F5b=Z)D8{1gU&lH{oLGxCv#!4Y&%{2e~uuia}W`_^RKtFTo!K%splK z7L|v62$}R)MGziHSNinVps>RFJ$=V zn?@)1Qd>0$CEgD{>U^TT6e>FGat~*LhFr}WYS9k&? zl98LKE2QIFTqggZiy6wb4- zaN{U6m!d9k(>CN`r8Z)ybSsI4Jzu| z+Qp`tzL?rC6BT8QDeHb4h-@@opcq}nn5{Ksy<1dqWfr0_NtoU&{;H3t>8UYw7MH$G z%lvC=c(}b_-rr_J&g6c1N=%ba2XyKR!lmCu4Z(LeK#-G-6nL7DXU}H+mL66ucK;zg zq)zbahsj0=KeAK1J;M2JzL)VLCP$ItmAvjq#Up&Uh_J3Qx&d+g*%PnQ3JXqciZs-3 z+N(o2GpRD>TO~B#ANwBD|;ufJ<60@SB*H_zfcWcGmd)WJ$+aWt4^ZN#ajG! zgSM$5gKqz*N9n2dnAcIZm?fbC$MUzzAN;I}xZ!);MXWbnQ>ZyMWN0AgKISjQaf8zT zQNa4#(cS3sg>ZW&v?%30g*n06t(1oAW3e_Wk83!1ZRH>|H~CXINwC{3V%3|{{?rcU z#7#Rx5rt-Xo;b0&p%mHvPd-q_=qX=}=8uT(t)L7MiWHv7r>vCi&ujTzI+JLN{m%91 zH{bC(OPzVfGcSub9cPOkU-~p+Mm5k>Y#Dn&f}@An*A5+}g*sp;tT~H$XcyQ}6Ld8bHO(kSmm_IamMCvv>&`k+;v6 zEnkeZxMZ2;b!r)ZZ`>C+C?7?2vu?XriC7Mn3xNdGhw4}g9`TxXFokB7$VL=t*`p#D z%BMr+#Sw(P*8C3{>EEELPe!w-#TznEusA+GUJ6Wvt64QSS;s80h>z9!!aTg=3hseI zROu9CDl`2iAZ$n+&Qyi`9}@&BWN>&Td}- zfrQ9g{sr)g<5_#*MZofgFr4sKIgg(z_iR5U zg_1p!9zdiTQK2B)Yvk*c34b}W3QO~A^l%?&w-h-#(x+gWTc7Ob`t__K=` zs%a#O)ydu7i%$vTbBy-1TUfhojvB^(5)TzW-FCTC7?Hs~^O#hh81Nc%s&blkUe>fJ z|4+QgqT^q@$ar^TeZOzEuh1e?c*w#1_Ls>wy2JptJKgu5QPfD%`GqoDLtp{0%+L;&YM)sLL*1ON_vg*lVEgFyB=90O;Kc)&v_$0c|YXiR? z=&)o^so$ZuYawOTMV-S|uK&xn&Ebbe-vEJWIYtYlgVzw81KjSot2{e77PZSpSG*L+ z?dY)_;v)H+Sj8fiLLtwiUUlR*ZFAUr{b2E$+0zIRs*i`J>}VL&%|X_9+{dmi=#-KH7-N1R%&Q`EtFDk zE>gh4dSPIAATj>&bdbDfc=_64ayvqP-7S2hU)_1SzIHje$;oE=CoaA6x=tP%LMlfe zBd)YYuR2zFaEQ#W|W<(@Rl)q=WM;qOhP?Av7SL zXT~OqLchxTGxX<4r*rcf&0!l+vg_O^J1s-sBAO)q?%pcy^=GzXm*I9%nH)#F;*neB zt5Y6`yt%XQl2Nt~QZ1pRZuq&u6pJwxvNm53bJLgSz{CI8p3VMi^;V^s_kOO(Ui0esg|Kg04fR92-U@8Hhig+;KHVVq ziAuOBdC;$Kl)*E?Ni}uW`P|!$lrz7r^{6;yp(+|{dnFFlNy<<*xzm+vkHe5br!v~S zMRl1b9JADAj6a!XcBN8ZrdS`g&qk>6#@5Vmm^6;qoYkk#1EF1xd?LdNne2`@Y!hUc9TT4>GjfLTrZRLt(di&x;qv z_i`#HHU^3_GBVPo9|u?lR8E>yTR0mPkA&f=5rpZu6~~j*tFQTAVa(ZXvc74TIiEW@ zoPU8EIE2mANVE*cS3aOb3+q|NmoIgKs)uy{sQ7)K{aL+J{@tfmIP!zpJZhZ32kx)q z_+@Ml3sbNqs*U|)fHMdRgBbpub%)r!TaEnAiX{RahhM(DiD+R(2MV@q!p+l4s;@h^ zGq`EXel#2YU}=%IZNlBsOw*q+dhIi(RJ>6^_QsNN&-EJKk9pgm&}`bBfjQyg20aXi z9g^c<)>zO?KV2k0nB)aje#1%RpPoZW{o(-t&{+SO1^Bn7^PfYVi^rgcakhV70Yk`L z8|HQFP!-Tn*0@)}JuZ9oez3W`;#pq#j`_hTRh-glj$g>2?`e+9rI@%ITDc z#XFt^_uB-}cK?^S`J)c=qFV*Nm`EsN|FN_KS28oXk`*U@J}0@eT7OLTi%;Bb)9H*w zEL&09Ns1#ySbpFW>6_59#*s^l9p}R}3rz9Gk!}7K+0vnM!tz~H++1h*o>|plv3f)W z<-;VO;y>w{By||m3Wrzp-5Fw4Iyac~6*acWwXrophK-wlz3mh3;v&hupvn_y+``5N zUxuPge8Sg!fdg76ZgQXbs?LODSBNfY8hv!1a`BIiqmOCB1qM>t=Nldjyha}&E87&I z38S8`ve7%FZ34TgvvnMUnt&^39ePyR7q5xGIoqTE*Hkt(`eoAxueos{X>(^O{GlN z>u!sI{eTzsH<23GRsD8w%{j?-~5j!@M5LLrzzN2a&E0-^<(^ zy17^22lAr%y!Lu+X47YCF;|mdPZZyz^?gO`yG}TDVrVReH7mllMVmN})Jp}SPqU9H zeG)?)H71eNQ&~bR~w2MqP?4K4+Z4@0QrGD1x^h*7_X5KT5MoMtqg8U}{ z7XY&bYj;}avVUGq+nj&M5hzS2V@kvs&C`IvzGhUalH4uiEu7-iwa0UBpDdW_-wAJL67YQGkBY1*9O3P8^-KD7pwmQz%cmIn+ zef($Wb%fdu?(^{P*p&r280Z|@z0EZt3y~81^ySwVN1hT80YY=&f%oVI`#gAl3Q7xR zY9Awr#2;@GV;Lte_9@s$z9^z5RGsl z(~g%S3IkIy3DM^Tu(lCX-|+P>&oEUidrfhIIdB(Rff7P7U9 z)^H$Zhd!k}G*1l?jnl$={1rWi@wNyWSRK6QA~!m5ahV5K{&lPTb7y#}cF~xML-jD@ z7K8#P#)WXXdQJK%C>Xh}{M^UVLtpT_PSyInOq;5S zTc2;6w;pnyJxkYS8=sPm*jV*5dTh8Ry`{2~x*f7i8cfE1Zrw#v7(pFA~xk}B(saX!w z)1Tqz<>uk7>-;)uGGtXiIzpgrf-6|icD;*|Jf*0qruV|H7Hpk8j#b&HXi|;k&RY)L z6(P0oOd2vL=nE&!M5Z48!n$g9jQ03+-16FZ^&N6wMiHffM`ncS`|hAMi9|taREt!) z9Cx3v2-mn?YU0-J5oH^8<|8@H5g|rNH6m-mqZdBK;T|!xEuMJQcxJlobT?i?Z>Wmd z6Ekc!zv-6y&d1$BNzJhmR~EP&Fk2R;4uB=pvBTtma6B2}ptSHyOkhG+i2O;L~uL1^7 zzM?u&s~@4$)GMV?!8S+rcAAM2pHndE0~&%jOX{pV@qmX+67O;+RA^ZJK zT(4*di3V)*(!o#VcE7lY0S;rZIAu%7noH{HER1I^MQ5!J2U}W1i%o}&&&*_2QvgAX zB*$g{rALZmgl+(W3?crn+R;)=cRGoGnr{8m`%hfXz~J{WI|5IJ@!?%m81v20XuRGh ziTwZ-KsL}P#6M5e2bWduQfA2O@pxolIvD^IE=xy%B4&!rsRdp~YUX6H-TG{Vx7RE! zRaBQ*7z68rkVCrI7rmVsxO)|EkpVUjum-r!j{(A%s?ocbA#k0yZX&y>No!`N4#v{F zv;xAqn%{(8b!ABfvjNdBL%@lE7{iPl9YVU>eihDgNu$7q2et>wJ(?G(4|bld(^7Qm zC5Ntq(rd1ecM0s5)y|jI>wHeVWOS=t#6a0K9Q@#D`=NW1)LB~k*PqhyDw>Qw z6x2Xa|K$m!=&z~;TFLeLYH8AgHlE_Qo;~J5mBpECFA?WpI@LYLrGv8^3QLx_i-OJ{ z@paQJlX5*{70s*42j2U0L+@-ZcSYzv_0E~2T5j|PWVudELFfN}TEYITeq_{uHt$~o zllq%!j|R4lwO-=}DYjgR0HxMAxH(bsH)|3H`Yu_L_2u@%@WK1w%Ao3A>$WBK3EZ;~Oy^iC2CveZ) zE|h_967qS1twOvJu{xF0sN>ZR(Z6-|;I3`EbN~J1uaGV!aeqIZRPwpZ%3-lG5g?03 zCtzO_Kh>q__a}Q4q$6#j64@-Yof&TnZyC~0uX0*Gq~G3)u~lJYD*k>PBNS5bRekmY z*WK_D1Sl6If8rA;lmy}&BP^j_aa}*}U;dnJgBY74k+*r)y=oq?HgccC$oFErx0ipH z)sV*W2PK$rxQVh&cE|_Rh(_7zV#k{CkTui?2zqoNbsT-zN}!3FXXxJOKF}J|84sB> zU9x=I(=gDO$Wizn#s_4n=bVI?FNFNOZihq0MJQ77S$W@Lf>IA%AJDwl-nn?t`o=jX z2hUr_cjtcC6{(;d2D}v9=Q2b?O!G0@k!dj-o3okf-NzMnS}TS%wiJ}Ba_vsY1$&co-v?1D_c7iFW4 zOI)Rj-E6H)Rg<9^F}CuVGA@`s9ZdacGJE))cAjW2X0d)tAC&25=RLQ%<|iF@XEfEQ z85oSM*Y6a%`>&{!w*GRS&c-U2A~@`O_}dtKKlY@m9p1BO_^#4_i6?*B^u7;25bge} zi>B^@&ZM9;0JMhxg&g0h4o(Ik1{~B1T8C34z&F_na9{;^_`&;nU@kb+q;5tE4n_S{ z85B#j8eJa%x4M$*n8$B{xl6#>{3(?stH8jSlVWsD(t25tW#$Tqul`)Nv#gn_M)@n% z(yEtewJ1viw~Dm1d%Sfr|FV^T8;b#@UnoZF(a5^3rx+wSCd!TP0uV&enQyNpcoDc& zf2}^C!nEo%z}ZgtCiU{t#0m#xJny(!Q7S1AWc0Thz$uyLhymY^4Cqt>yTG__4n|b1 z86-l2wcBsEO^B=R_QTdDYe+c<|xZpn_w~@n63b_T96;icQ!j$l{`UF z21H@tk_C@Og-^g+U&g^#0bGCK*HfzxHr!lrOw6)qczxfYC3KM$k7hhWtxv2O=v(P6*Uy428+nxTwh z-u=&p5ec|4gROBEeIlS_evP@g_%}Y#5X>f;HFD5E`1!B&`|BkXEfQgP^*iD-9%T-g z^BKgPf4r~z>o()V260~l`-Uz`AZhq_z4^7iyvV&brtUV+#?}Dfh~?2}O^ls;=_~sL z`qg;h1IwVLBgwnf#I_)tqqLtQH5y-9|}Y`c=-kU-S zPI~=sed@o}yQ%}SJuopY?O(fE005)5rIvMuyiW^SWWhfcu&%ESftr+30Kk8?TP9hk zSHN+`S>3;RVf07&a4`mF#cN?lD-WIh!FR%Pq%Z+~$FE@f3NlXT&kr6~(Sdq+N*WUY zDDS-={6DgWGG{PK=4g9x2+XwC-W~^kD?cdsH1PI4F8`KnkC)(eKt)kgp-9d$NS%G|m0G|+7 zAl<;gaNxiJApQUUe;^k>_$eeL22|1L>EaktG3V%{+k6cQJkH@a{?~7AU^Zi$Y%Xnj z(YZWxiA=X$#+lQcUK2YyW(r%MTwcw$lihvdH|NKvuK$wC-|^$AVP$6Wuf?&u?BD#U z_&G!Vb=}r8XWU;!%RDW9knt+}-CyG--SVG@3TEe5^M8u1od5pC^BeDX-haNS%G|m0G|+7 zAl(4O3=RMP{|C{8KvlrTr$9BWo-U3d6?3*uy3Kb$fy4RqumAsT-k%7F*|g?kW5I$2 zg5f$c8E1l7B{)~G#hC4XRLQVIs#!L?d8W5zwO^)ali`7nkD5f(Oy@1Sx&KM_jo(M# zJl`?nZ!5oEOyS-2=gs*y-};|#SKGCWH(dJg!#A?$*UNnh{_p<(Z=J5z&%)ZQl+Ra! b+zxq~yE?H?m>P143FK%`S3j3^P6NS%G|m0G|+7 zAl(2&4ItwG|NlTPevrTr^cAS0#M8wwq+-t6iMROJ8SwY{%)%1kP5Va||4ID`{-w`gTe~DWM4f9(-1i literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png new file mode 100644 index 0000000000000000000000000000000000000000..2c2f6749faa31599daad9b14e66097fe024901c2 GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^@*vE?3?wxQo^b;ymUKs7M+SzC{oH>NS%G|m0G|+7 zAl<;gaNxiJApQUUe;^k>_$eeL22|1F>EaktF=y{2N1+1>9L$_w|L5oFCW#8znzGBr zE}k%PUCfq+mi2xD=}L=~9wmjA_gOT|dH-kADq$mgHJLs3iShNHUmxhteB e*RNro_nM6@k9()h=Gn7BF7|Zwb6Mw<&;$U5eOW^Q literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png new file mode 100644 index 0000000000000000000000000000000000000000..84015aeeb35f151006151be6a5066a967ea3574d GIT binary patch literal 430 zcmV;f0a5;mP)u0mc!Ed;L z(X;fBW#QZLIMM{c$6q_}?=ThNn2KM>19%cxf0%<)>`Vim0I9-TQ_xH7BVlNlyQ*Ibsh(g_pq? zwn}20{e7zj(bECZcHkWIyyTcD%xbss;F2*;s_(v(5iSd_k<)7hm)DS1 zA9Z$9KSCK}!JHA}K~Fl}5X>WW1hxS0+|0zDYjnX5T)Zv3qh~F(&@2NjEFT%(#HD&( zwpV0IT#+7c)C8d=LoOe~-H0pVO8axRtLB(lEXBfZP!l0fO^VQXWV+V$U{Wur0v0!1 z)km+aqmGoke})i7s|`CI2lOMVB7*-fhvGf!rH5}wuC`(FsQUYR#%-P|GRzYrj;RR8 Y6LRO!?x95CjsO4v07*qoM6N<$g5(IlKL7v# literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png new file mode 100644 index 0000000000000000000000000000000000000000..fd5292fa5ea806e25f1fa098d8ebe2a7161da6e4 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E!!3-p;uDp>3QY`6?zK#qG8~eHcB(ehe1_3@H zu0Xnhf#JY`1OFNR1K9*Y(HrfDKt*1jE{-7;bCMI7nBCmeOc;a{7i?x?vrvd<3@LCB z4S2>qL*!h8k`v>ZnHFmm92uDpKL}t*4PMY7W4?gRR7{&g!-4fmK*K|iH(U(nzgc%y Szw`bAvf9(t&t;ucLK6UihcO8N literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png new file mode 100644 index 0000000000000000000000000000000000000000..28110bfaba048691eed95c427592743094540295 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E!!3-p;uDp>3QY`6?zK#qG8~eHcB(ehe1_3@H zu0Xnhf#JY`1OFNR1K9*Y(HrfDKt;ixE{-7;bM{^c0L>6qL*Oc%g~mo>L{?jlX<9CVYNmv!Vah d$p%w-2j=Uy*(@D%YtDh(;OXk;vd$@?2>@RwJqZ8+ literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png new file mode 100644 index 0000000000000000000000000000000000000000..8761cf55e2bbac5421882c48fcfa3a99dd755dd0 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E!!3-p;uDp>3QY`6?zK#qG8~eHcB(ehe1_3@H zu0Xnhf#JY`1OFNR1K9*Y(HrfDKt-vZE{-7;bJkAo$+`pgG#=!qh0bNUXugSa1ISgLu6{1-oD!M3QY`6?zK#qG8~eHcB(ehe1_3@H zu0Xnhf#JY`1OFNR1K9*Y(HrfDKt+C@E{-7;bCMI1l8$iASkTa@!RjN?Aj8U2;INNr z1p_OWMlrJ!SG##3QY`6?zK#qG8~eHcB(eheoB=)| zu2-*JZD3$%XlOWlWYr&_V2r1WV@SoEwUcghF(`02pZ@>e?7Jc&o%;Z-^IZe7umMWc4oIs8;5A1{>X&1#6-l6ei1VY;Zl5B)5wt=iMGx@dLVE hljVaS^q*(a)jeUtn5nX#`wGw=22WQ%mvv4FO#t_0Jski5 literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a10aca67b2593b17380b45b75529b247dbb71c GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E!!3-p;uDp>3QY`6?zK#qG8~eHcB(ehe1_3@H zt_=(f2M!$g&+s28Kny6Hp2ZJTXW{AM7*a7OIYEU%q9foy1G~U#hUFhsG#aGZohGef xSPf(@Xw%myJ-kAH#Z);BUUsj~taT0nj0{|yOf$vIbyPuidAj35PQ0{qu5LzFsI6_w zhKIpPzh>>)pR`q}p=fRY+gYDwmq*NKzO}PHX1nTwrg8&CxymOeZ8%nx$6c|0H1E>!##n2ap%3}CMS)zf#!z!F*kHS3W$C9&AzwF$n$yhS!Uan!ZB?I?x~x(?nnVW!QkoY=d#Wz Gp$Pz(6Ky*H literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png new file mode 100644 index 0000000000000000000000000000000000000000..db8801f18521b5100fe11f0b8898fbdf2cc5784f GIT binary patch literal 7249 zcmb_hdpwkB-*5NXR@innDw{A*PvlT2Dsq_FsALq8LrQFGGnF!pau}MKZRtp+oF+L; z76~z=8s}LRlf;M|!^B{W(=Z1!=H$JGc302tKF|C4yzd_j_dWM@U)S&V{eFMn-*w$M zcRw`9*YPuY7H!@6PvUfE?lbN3bw zye7f1t<|k}=7+Q=aV%@pibAQ(4M-d_a-dX_rc6wYD;qiDwbBnt z)BVjmj(J>bwYWr9jrj~YcU)4->4e~@IEr*PUG>0*uW?lLwB(k5 zKdoSKfQ6BKgaiD=(G{<`lA)2iRW8iqDdg|x zabofXJ6Gkm7~PDAN+hw2j zI~Xi0`#^Eh)EAwsKREb`Aj9sfI~ZTDj7vc$WTV9&=!JbpH^L^Ok77AjuM;{7FJ6gN?*0b3$7gu6*zU6}7SNFY{FCgMSOx^0U zZ6)_guu43etwZeA@K>m+_(+q_B;@f#~;f|h${olg9e;&a$ zcSVw8q;awWPT!&Ov`T4_Y{-ke75BJV9o_-+Ja~R~bshY&;<+)K8UK#%d><3`50(w^ z6;PEM~ z!g`#_ubf|@TsbV0o*LZ@mCMcU5@*&!F#SrlrVM!t+4??fxZ5S^{y0p1|2vj1zp6^I z2nK#tmvj_^5gyiyh4Y{4d;i=48^z4cW+}ejjv1uMVOfKl9GPEG-;_DFT4JaD@g!G8 zR(|&TvA1k?bv=7n1f@%|BL$Br3sgw&&v+vdZAuY6vp@}sy!Xj|!pFbA&szTA8%R2o zX9nOxdHI(27=VI<%a5MPVx3$S;oGZLPsku5;U26T&_HO=0?8CKP(CU-aG!T^igXn) zrBrP17a6a2YBGugCU_0k_Zfr7olp>WC%lF=+_y+jS8in=!(n+1_0762hLWUFBw&i( zOS_=7wUBhU6qC@xO0r}9Enfe6LIo{6?$ja;!aHC-=ma0QiBm84;40U&WJOfy22}K< zVQgFDOjs3_Fx)=QN3UaoplyF?&+w}kjjgH2c#hKy;-o=Bp)wYq)-vZIk~Buwz+FeB z8#o+wan*rQ>0RNBHbf@6X2XffAfn(Az8Nz2bbTDZ>X9A2v2sxBBg>@s{D88jICmigu8wsO3tLgmIF*h$B=dhl6c$y^DQ z5Qc9NBn))YuOMu-v3K6_PV&$9#l&}?kO9nWy%G+l1R%t*mWz=&&eFVB_mOF@61iz& z%kS~f3g|-qba_y1f!y3dvog}&7OQ%jUtMw42J#gqbS37%s{AjG3wP5SDRBPy*8oxi z>q6*K-C3Agbh@NrL6a6&1Jt1Sr7^?(ytph@0W!_OOpdAlC4mZakLqL*9#;C`VC6TjIC*qG7}=J_(#XrIGOV}4UjXFLr`B}Wm=0+UnQM!PWHWT zJ-{B62diObLg#O@umDYy4)n%SMGiq=cz|mQZ}Oo$jzCXQRxE^eK~!3L6!Zlcu#x1c z)pJgx?2F1Ai=Z0P(2tDN0(qoARA8{y)GWxydIggoEWHr;t{|V~DE8kt_q{V7TzEqXaKkfKomX0vZU8(?eDd<==Z{_2#$9&&{qX172>rO1VTFZR>4KYw;+R_WVTP;8jA)2 z^DzJoPp$6sja1#=s^tO`BYmBr#BD+G+nw!gKz3sTl}@BRBq49fCKXMgX*dP^4N~_ zf<>zdAQI{Oi>2{mbr0y(jg!U+g(YA{Y^GT~5Zlw&uhmdv(Ubp-RTr4=wxR5k{kZ!M zOrQ((jW>5SSmnA^-QnksZiCFy8K3DuP2SgR5`hMdkh}lbV($DS0`uimFjq3mILWEi zVP_s^DP#MQlO39IR9bi!4~9j`va@$wr>)7j7a!WV%2uiZUziTD7;oZb0k#Zq_mNo2yrwx$yt z^XG~#W?CYs9R9n0!dnLD_OUcP7Xd5x_hSm5P&Rn=>UI)Tah2KV3|AZzxY%4G^G^mJ zNZ$tyuwp9Zx27VK2e1Z_XAqb66^WoCEXoV;GBm)F--8ZBHU>DKKho0yOZ!c9AK?Im zKlWij7&xG)fCfXP$gve3O|J`6Ph?7msE&Cp5PTi5;CCG@RW<5Vk ze+Cz`2v+IMt$|MC7M(PD@7&|8%?{YYi^fg3$j~%NfAxj1fx0WhUPO+(t?!D)+GIZ{ z`fQ&L-j%1>6mWt4G$$Al6BE;r(rU>1QQ8!6*wCY(eg9loXlSCFwY7Bv#9lTWyeoZf zbo8N*$vE@2^gIGLhc=q;s4fhqPUsD#!w=i}kGL2CJvdqs9nY|mSs^s;x`D1J7jLOI ze|pe7-^mB-{D88tsj**K_~pyjQsKw! zn8PlJQDHhGmkB2Ay1IQ_P#Ag4i&37R*wfn^`-{OY%~A~{&5+u#cNc6h!Z+R28j<%y ziRF}b6_7*srkOA8gkLp3xs1j+_j+LbHIWiLKdhYyLvt%{&K z+9KWRjW;l)-D;YqcsIK%M3pl~l-I0P5noG6N(wIT4Wfh?8*ka7D-3b7OJr^goXkq> znZM*`nB;4`IVUtUR1>n^1{7b*IEkl);f~a%iO3bSnH#^1HjOr!>fpBxz12_Ot?hN0 zjCJ>7)6G)Uj^gpv{4+N$Bmaf7Q%=8^>q|!B!V3Gd_UA*jprAAOJoi@l%LFVT-L)NzPzavZcaO?%KOmD?KM z3e&6jg>jD`=opAbqcIq7!yGuB5Vq%r3Vt$+RJ+aTA@8JvgP9(Gwi4ywy8Vb<0f!8R zfEZ^Ek=SZI{oNTPl73=KY-?V!SA|P_9<%)Tt|G*BuJmSV z2u><0K^UjDL2Yl={ZQz+nb;_ZI1aB(LJZHT()Cf=Xf3d=(8|73+dCM3ro_gk0Q0=( z!R2XmmUX(b7R_}vJ1N)qPBJ1Vrc@*F>CwtQ=Vnzz-X++4yO$pTdvJMGNy*!@J44p# zT@9^F$B}L@Mcnnon7YCG`uf+e5rv*kD%-M#ZkSdbdL<>Fd3vuX_hL?SQHq9Cv%;N?SaX_gu3&bc5yeeYZEkmkqfNp1w3z+fPyekSZV zWNNOxSnah)RrQKwKG<*gowzAP8@eU4{>45&<&dO%t}a$CDysGfgLJBw-SM0Nck7^n z6MBiwjK&U+_fQlEI^id|7HIEuDvg=9dA5)m>EsvE5AUMR^xuNOrRT??l=u|0-2x`I ze}l11CrKyRl`TWW<#;^Or@p;4Iv853m8`J#^pYnU$Hn|LTg23)3{=;T`98Af@A?jd{L#GrH|pHfE*l#!vV33wb*^S>&vh$%pDmiHEE*Og3mkkJ_=f zrDR99^8DCpuj#{W@+_trf(uE$Eq_Tg%-lve=C;+*hb&b8(p9jrfR)pEi@jsuZ83J= zlfu3rjhMRV-0rgh9R(@l7%`8>6*}*H?S#+vqIHI~g`M7+TJa+Np)XmV5Z}OPoE6+I z_-Us$k8-rovmj~9TY-M9!A-u$mt!`shE${#F07ciUlLn#REhB)?&>AZ#%{?B?KR1- zsfn(RR$&+#>^01kGrNN*=2W{`_2g{vopxTUOaJ%Fv&pS`UMC{G)SGNlkakq%hbaC@ zXShYmU|UY|n}fQ9yO)aTKBn#npo+#+SpUxZH{#~93=nu&r{>wng98;ew!mE_gjtYM zAVtpdZZA8}i~+rOB+QS>IU6@RjSf!iJ-XSbj+}tp_Z{CfQZ3OP{y4%HC;^@OAg3}l z-PvLOFcr}_98A_Y|0aRXYU{gv@u?ohee51p^I_qE3%iLu7w9nJ9-x;wZf{YZVCy?y zZjr3>-Iyrb<=(y!mo#=k<7vTV#|X~7tE7ifQBk#q{SnpjY@Y5eHb3dmP5r}mQ7$Bt z%r|qVz?3kpdfUSrc9G~%Ev;&>bh0m7DUGpkXkgcd(!l% zYrJQ{)6&ul!Ep)h@R4!FzTB5m@fy(+-gb7<8TRJ$Ubyh#K!KpXexKQ9k39E#O(V!# z^dMBfCxWf-L3cQN_N-6EdG_mhpSLfxBhUq^Ce@xs#76z39*-o1-nyoi$+^0^y3pPZ zn}%b_oxU?j4;5n5}!oB*n{WgMz1jLDPHm1GZ?rSo%gmnpgKu9OFitfPg=BVLHT zuJ0<>ewYxc-b&s6#xKu3xrUnUHW^wNTy7&lmWt<^5?f5?$BFG{JfO1|m5<9L1qBpO z7K>%B$LIQ0r)5uW&J2S5^RV4qc~!=YYfAj65%!MtVLQ?eSj;c`)dQr-%==Dzy~=97 zkw4+_pHD2Wez_jgdlsE=B*X8tt?DlH@nZwrz{?DO8xkEE@c@U}bluukUS8{n-#=a- zX@Q&Wgoo$wZ=$|2aL9T4^9$-mk-k?M50)?lw&8x;|DJsD$JxZE#~@2Pl=0k~@$(`M=2q5^ z^Q&)Cg~Fdemo%wF^;0x#ecXjTOG}Zg9=P>540P$1$oalcPH!T7e{T)Ie$1!)rFEsV z12wFE) Q2$wnTb>35C_x;cR1J|DBHUIzs literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png new file mode 100644 index 0000000000000000000000000000000000000000..90681bb4b8b0a966e11c90df6a572cc8e90dcf38 GIT binary patch literal 241 zcmV@AicRE z6hR;a=^g1!KtNh35ke6)$;61!?HtR5FWo|2cjB+02hMGI zsQO;zmJ(>IL9~eAeQC$!?prGH_s7h-I!OUD=zmNquG6<+VtQK+9Kn(CRb z69AD6n5;#P6$b`1u=cZdGsns^k)|51SEDTsc!UsOh=yycOdTAy-47P^)tkRG1u+Yt zgrp~W$Srwa%NM>IzqzN)Gj^f3v2 zW-c`TO}$fM0^M}^UN|~ADPNWUrm?Z$wZ*-W0MXb{HJM(EQLL{6fs_KDoNqcOFx=Y( zXSzW8N>i9_I2EtE87m5_U|yj& zceyf{ClTTjS;aU}i4d0=*yfX-lKp7X574h9Bu%Htc>@ zO@C%PXquvn4|(vQW!5c3ZrmpTiT%93-w(9- z-!Gi4++(JK%Yxy_c2MEfy47~^IAcLHkb)Lz;*{eTC=knGD3o3AS|2%;Sn{|*5lYoj z76l=T6omLw)z2Y{R=#=5f%Q>AU4HY7 zXtiXu$Qgy|zRTi6TOE+s?vFmYCBxrA8+K2LVL}bW1E1Yo&)IGFh+N=x0;x*qD84XW zG$rYEfgz2t-&)#9!4iIa!>^S;goRBQ_{wkg?gc~4T}_unR9%sw`#vKi*`&zt%ZB~y z#syycHKz)fhpqYf&1suk_xN_$zdz)_1BC(nsZkTSvplUDxj)Ukfq{9_GZFQl`mD!D zP#zDBq7Pn3(PVirqk^#%FJgVhJjse5lyBfG+{C?#bZ!_PwQUD;;wi_T5%gjERAYSF zXKjAfq`e!up<;aev!NTQ(uW^VbWIoaQ~88BqpiT>PF8_56w?yo(x+vS&AU%DErQ)6 zSnsYb3!l6ey>LWprr@ZwK>7;_C%Gp3k+gpPfFr>sZcLrkC|c=0HqIm7csXFhOgFJ3K#Se*kFmh;6Bj;?md<}18 z^2R}@lKQB)VH|KHZqpubu@vnX;x{eM2k`QpTUc^Grm+CBPVRFefhdp?3lW%Z7RGp; zknpoS!lqnoI|UX53UK+HaPWEKkt=Vsi7g7WoohJ=+y&g@8+xm2qglcfUMriB<-9+u z0A~~Cxr?&&76dG3Byvc?Z}7U)6w?|ce?;KYJ2pc|6h*qal{_&^XmdW~ak^e(!9B?x zwY(qYl-N>~NFBiP=0xR%7hSBK9lazWw)`hiu6rP%RNHrt)+Pg|M8acOiyh-rAC3!{%# zgMdQF9KtSfC0!k>6Fxz%?jYy2@da{K$-dH%D_+DL8E zH5sSj1Q7T0IS$kEp^GVo3-*dtWG>cU6wjnXQ`$Iv=D2o|>QaO#+%2z98RMvnwBVDv zA0o4v{i~@(5Ls0qSpKteq5>br09H?ta2?KS_eZm{aybLmYsvN?N%%{1o8O86Ep>1t z$nMqge6ykf9#TBIF?BA+Ja-a1TGc3_Km zk=v`1p&Nv`;;@&`wO3D(5N4nN5+r_6kc|FQOLV~> zi}O!(b*~JV$#+)mOIU?u^uM}AsCM!(^KdI|EzSz4fi6cEAjCM89aH0kbu@3ns=N{d z1=qy9mfk2-ZA^`A-i!KnL^GXDNmy@<<*L9CcWg6k; zlA<6@O}~*;*!0mrQZ{=>mh2~(mr_M=Hk$T}b*p0c-mlbT!~tU^E;L9&yR-vqslB;K zH(({;?FFREh0Ezz6ybwGGrhjt7e`JIt#40fMsKQ{;MqLkGTo+Q0k;CbOG@xRNSyd1 zl)HZc_|H4+9z24p4V>`^V13#`0;WH4incId3ihv{<1`i$BdK&;GF?Xn_?xNlx=_8b z424&Et$nGKMI}a+2>!)a!g6UB(9TJIR}mF!ZJ3j`hxh2nI;IGeWmJ|ec-|5};YClL zxmJ5m@Ca|0P-`Fy-mJ%5sXZ&W&kXHy63w1{#AR66q!mKKWEkdTSuX9tngcSLufQcr z4@L<0&+3_ixvLB)%F@P)?WE1`tD5Y4fBtx#O58B}P;i^7^cMEKvlK$r&jq61+g6}m z9W=t&pSnRK2hQ~tqiu_q6!eWg)5HCL(lQQ`KTOQ}?cMelBh7k47qYd?VPd9^ouE!2 zyOb0Xv319PrS}M45$J^d-~zNRj_Er?A{Xnu2b+7pU?T3tQ7lt2mKPT95x9%8jx8@m z^=cbQGC>RM5m|Ht+VOTI1ppxi_PrVU4=1+&wYzr>`h3~Xw!dUY=0^NK#@`;ZDzPv) zk*!nVJ64|6`_6#wmZ{$mC*H*vvWmV0yV!GsAlp5=@NtSA!c_np7)2xgRKUQ5?EFdARcUQa2d4FC@9(n2NQ_ z9}KMTMkI3xpI^wPo2g9#w`WMW@uG15=d}d~MNY~C63<+D%Le?E4-c;2??1wRK6pL6VMs4TOHK>vf2nnQX2jVm&vhld-;Wbp5J__q#M zcX*leqe|lx;8CXF%FMV=Y&wX`Ozab~5tURQb@uoD8;G5@wX2u9co5vZ2|T<1t?e=X00004XF*Lt006O% z3;baP000C4Nklhf}9^){l2L;M9Mile1Gt=;Z9w5&HS=2J9|_Mqhrfd~`tL zzEy+Q)Xc{n(EtD?yN75JHw@2Ho6z2aXwY28t6a9W<&(G5riUmy2rtrR5CJ{_E}m#} zB_jNVi{*4nRle$H36j!~u`U4Pc(t}o9LF&0J4r*vgvq5r^G4JLG(B{W>l{Xo{A;Lv zgrnP9!?T(uE}16$g$dMF{fsr|sRXhCja4qPC~Mn~dOxcgZXGeVxthUYvE0*36Bcs@ z&_SQ>7yF+hZxGp*F=plM*5)=*pUGa@gjMO2kQ#$v~c3faII!EwAorJpgr z<){fp22E>QMomtjz||IcT7z#tNtXvSp1i@qlPibD69G5?+CAHA8eBmw<}3_iH$l%O zh^B!K0JwxZDPz6%WJi!`!dTX}V@(&dN7jxP!^HM>%^B@KC9yHSbmV#Dc@}DGdpZ7Y z*TTMrC+Eo#`6hV#1U*Bh&5UnbtJf;88f|OGYZOW6ZkLc`%~Dn2QbT)BWL+FRP4SY2 zYm;fNb+rMFyc~HQH4{Nomm7=|@OepA9C-~68$SDrGW!}jhBnaY!AL(+f)SH3zoEp> z1g3ka4OQ_;_R*X_`kp*54s;mJwc?=?BVX%?9)tl0M-D>o3Ksz!C_CtT==j^W=38IA zEGW?SecJRu+uZzR{fy_vKJz--R%pw*T9}NuojOI!imfZci;vM;iH?LWjC{1CWpwzJ zZ3CkQAz=vLZuG0LI{*N1QOAR{z?mL9F*731p;Mme^blt;N`oi{z=@qUMH@CmM%!*k zHLA8VG{+M4I_UXi@wRyl+Q}HQ$|eISS6hsCRh{xgyo@N{=8QE>@hhh|ZtACBmI9oX zaSWyKJf$V;O~GOzKU+slo?z`~a>;epLbf4ycI5l;EX}_z@fM3Ai?#{3p(aVfJXUVr z2n^KLZF$g*Qd=7s8$l)UvJ7ex{x2VN1FEOi+{0J}NJROng_DXw+KUW+y3u zCR_X34FXw|T$Z;V0$zzslrzp3_MErmYIGxyd-2YTeVKc>*6R^Yi(NsnTQi0od#voG7TAv8(-D_EMyQ+E39y)jky}#C=os9 zS!3$=fP`-y`TM3A!+U>G*0%AyU6S%MKG&{R)r-TnyT0~|44Upw2LSH(eQ;vVN+6Rv z3x6AUU2p%}g1K+RKcSY+_C7y9`D8O>-&c9gPMz9A=l>i}9ifx6Q%C48PR=5eM$*u? P00000NkvXXu0mjfGUNoV literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png new file mode 100644 index 0000000000000000000000000000000000000000..fa01de360e5cbbbdece84ce295b35ee6e5ec7ff1 GIT binary patch literal 6455 zcmZ{J2Ut^0w{;-&fYN)B-lR)!QF=$Jl+Z+a6A3N!Do8IPy@^yql@bI51O+Kl0)iB2 z211h-y8Q9I|NGtde&4-MPM$fL%*@#{d#%0pP7)0DHONR9NdN!x_ou>7+bm3VNkAQDLd!9N zgwE*P$Y}ZY^&e5FuZcTkypzKI4b3uXd(_N*y-#Hxxw8;;k==EoBc;k6NS|H7i;^rz z2j)tHc)tQc_adXk_yTY5^>&sxxx1ll%>!oZ(dNkI+x=hbJ8NxCq2adITYLKkL|9WL z*gtx;2^Nw8@>cf>J5!4ly4jT#Zq|e5764yarH^m(_Q+`kZVtqQ_~%cR!(RSs0En*l zgr6zGHpteFR{Pa5MC30H(yaq;)||bs7L~bWc>o?kXWMl9Vd3MC&dpO;ZVc*X-5Y7Q z>u3L5FHSBTLJv@&^PAOiIur^;hke-=6^93PTfQALN7as-*CO3c&aoGIXJ8IJpsl>L z4ZA_iC62c4;a~2b@wS~PFMAaZUGnTGIQ0RI!uc~Z<->aUW#bVu`R~3Zz8H-qcW7Sp z_~_KUNW|WKFfaYl%tMOl{AMP=Yv|;#N4KKVwC?v=$jPPiI}!SVt65L>k1Ga6!^-b? zC>4W3YVxb^)M|rxxkj34U zR!_G_tq#}dZZ5Hp?Sk}h*jRYay4?(9#xe(V-5fN}-pqK2G5uJtjDPUF|3*Pf3BA3W z?R#Hi+1PfaIHTA!bvloK5 z<=e7aUOMX_ZM0msJQr!c6WrWd?tJg19~R7~%-S8m5pDrbta}+tKL3Pw%0}43)+XeT z$hS>Nu>RU&`CFkvumNiLRTKSyNZ6j{Z)=%psPRG;%)2!|fAwdDN$Ue*-NS)7I&~QL zXqD=f9MQ2`z0G-C^M%&+*;_Ts7w_Ea zW7<77j$0DxdSL#)KcO6~PNVksG4h|9UKy}0khMYDmSz3#iCeL^u5Lwl9*%3SUPazJ zJ#K>x4u9Wg{<2`h+B-IMvi{KGkcHj)Dkof5fA0)`rLQ2J?!o46_E*aW>6;b3(6;F7 z=nZF`^3YDpnK>_;o6B(8@5$t4X#B!THdbPGubV*jn=h&6om-dk=5FrCDzPa?lpW5` z?W9b+ihp12Axjltakp3>u~~$$t8P8Z+nH~FIwhP3TY#S1G6nFv3MpF&D_ae3M29Q1 zyVbW)*8%(#*MK6-dthy7#a z%~5q1YGYI9@&0mH!yH`tI}`~TT(&w@A{P-64>Ik7?gK-+tjQmEtba8jQtaqfSI$ab z2=EE5IBK{!KsHHqEL_ZV-InY5e7YN41hieLQ~wLM#u_OM=SY+wJMWyg437{z#!p2? zK23bLd0EL=;;??jMnN%gdY#i+T^}bQ>ZnyEz`DpD& z?g#`WEA8uwcEtRLYPfqdV>PSzbkIrtvSyfW8oBI?z@z;7mt&gI*45i*Lk9<$YwNZV zP9WWwHQt%CM@Ji_hW!5eHxhzz_$D1IC}m2hgOT zNEv*CgDvGifcD&RRJR_qN{8s_&1TrvU4UKF_uVm@g7a3ha$%fhwGT-Va4!0Q|3A@? z4qy^92qC;A#0+oDi64H&-W|wKiRF*3N9YNWYHnYBla_tO$PVTA6rC8-^eK%VA>CnM z-C_Hzd@`|AGqY`#%ypr09bxa(oO>Zc$2F*gVSHTMIH>s~{Dm7Z^wVwLwl=vVf;{`r zN$;1khBh|ljNZ1;$)!GKYmm4-_PeNSG6*S``E4kmv#{PBb;YqJ6MT5~wuC!laX$l> zDwM$Kad1A`m((`rkONbZY%OvZhl?V5nCUfA0EncSi~aKK1I}X2m7>`3HP2@-bZ%5X zBwq9|BAvcaxQuJ9k%{k^G~apWT3AxHbiEYuyu0x6tyhU$t6H#=+PPa@&tANIs}m02PR_KKXOBe>+J{Z=WZin}h@)So4t1 z2?>Tym%`6OQsO`+goFR|z%*sFy^e zg1ZPboo zdgh@8a?sI{v`wFZkEK$J)^&9!8Rd9NatcCjMBujXE{eKa+$!v4X!bqUj)f%6(6*IK zUJ^GCHT%xwb<%l1D^+GXv?D?=(-?d=!5RtA58&_TG-FBlDRn5%*Hn+ysw@Iw#?D6@ z)LJ9NjMiOb^sdm_TJP{7^JuYbCZ*1tC=sJ`qrHRRWy#nm1u+$s_|=zWX1h~h2f ziTB>b&j3R8^42+pORy~kGUTC-`zj(9@kXb@d){1C^0ZSR>ihPwK9-mVJ5**5Vd-E< zLbXfYi_#W>nlAbhc-Dt>80jvO^*`WYXU550uz#m_E00J9f{Ly*mneWIL`*@w+80|Q zrz9zS5CkRkhO^X>Q&83txE8R|-N;u4a$6?oN~n(0eiKPrx$Uw33i(;V%m2dU=SW0U zDJNS2{MqDgEyb@>VtJ-*HqYjkUr$3m^vMzXAjW{DQ}06W2ka4m+>L(t73Ll*_J3w% zUi*j#+P43&B`5Jvf7YMSAj3@o2-;4>nxRlW59czMy<69eQ@K5&S}nK}Do6m?3(5en z$UvOqX13;Kr|h_@C;H?v2nIJuu$J91gHU@RBTfF;x8iSsU6ePF(#;p!GGXzH-4g%5 zcC%%)m5-r`49J}7--QPAV$B0gXTM5((?PFYTQ>g!2d%9Ivl*3jt;dM&;YN^DfdB#} z!hos>1fT>L{f~|h*YGT#u-50{q}0SHxqF*+Mpc4h3gv;*lt8t<=38Wa69!y{=E3cX zW5(v#A#HN^o?n^vwf|WT&L2h37ZicuA#*56%its!rtc$Upc07P+xEkKsNgh9%*)VW zBu zi=1>IC1--cfwMsD@=kZs$pwO7q1AZNSb&u{HX$*Dd=UKbTVi5T4h5A1XBu`0#w?WE zRrNM+?xN_YkKl9}wTzx6k0ht$gi)6^#D#w~XJ`^Vg@tr9J>P3E#F)#9lzPY!34-e7 zBrY}9XSwYKnBtAkZjpT(1gD!kj4#A8%3j=x259AKY7%dcrBn;u0H?ALlKnq8^>>*5 zOH13Avnj{MX%A8(`#LbVcmlL&ZPM{GmUkb)D;6-EzI4M9_^}TxtrAYpx8NoMMtM{H z*Lr#sAHhSwX-QXdU~Cq%m?1%d!tY)^4p)8xlCt7s?oV|DZBL&`StdqCZSn#){jEWP zN^#|oO*T)aMJ(O!v};igE?XqleH&6&PRBaCF?@;Rak^g^=gkkEbQ5ae06*m|nlBO; z30$G$qD=(-Hf6wWhxMn2(iX@8@B~v;`d(SJ9n-ZcB@J+3?}wIAvJ1t+YYtp8in3z* zB)86ttGn;$7PvAH4kdRkh5%)I0kTZOEC|_vNiJje)vSc~2XqWJd_^9{n32-tNC%h6 zTt^FgpG-}xy-ljenZG~Q2>NpL${Ku?4YJ!Omp#PjC968!_1&h&4xkL$i4@Kije5KSiKFtNLM! zF~R{03q1YVzvx*2*V>{FU^rpjE7w3!=#!Xe z-^N%SLU^3pyGb~kNthxM4eodg+H}~?Ek|nPp9p9j6=gygl z{}i3naH@ib0u}<6S*1_Ho_TPJ>x7jE8z$*%9M9h$Cr_hdi~OMR9w zU`Pp5T*{GY#M6HyZGT0BzxO}!Sbga{B&>e6fir;hT$mi7yICrHEon4a%QlJYnfAtc z^LSLel_Yg8yW5V*i#Uh<SwGADF4LMGX8{gNh2q+TeVH^`JAF;ag>k;d zX-cq~k2o`$BU2TAuiGKqJN&?fqF5SWL@}eL@g3^7uPGc;VcNjqf{{Yg(Dbf^`!CPYaM~SjQk4A%GsJ^*<=RqZbDU=0)_c!v9?`tk9dDTW zsNO!}79!Xih%33Tpr<<)wJ7BKa|#vAWnH18+4$7Fokd~^4^)RICL<_hN9Cw2uzQb( zV+=|tz#BO^m%o!kif{2kV@YEAi_{Mmq4zV{v_YN&eiNY=L*caQ!{7Kc$F3w;0>~P& zaNjyu1G~fSsGN02W=tJBk!!~eUevOSt{6y=mcJ~vLJCCzlL1e*k z6~A(E#XPqAysJ-rr8xvx-XcO|F&ztdKSf2m#EQC+Os>MJ+TS?%hs+RBqG$%(H1b=D zR^82vfTYOiPKs&#yoxg-Tt$`tCC%7WbZ+lyGf2NJhpmpp0;a(f$0eQk*o-`SO3E-s zKW^l+H2G#@B*%g>!d42{xi|(NyzaU_LwJ@D*)#4lh@VF?tCSFR`pS574{bNis!)rxFvTC=`^F!hM_HI&-*39fSNXVRUj@WrQ%sZQLP#dM^kfM|4;46CxbrjclUlv z=a2e^73$aIMi3;HWbX4XY4&8T8rWd^PL*7KdQiXTi`_<;^jsg9PJk&qw3Rr$9T#8P z9!L|#m6CAyc1?DE-&NfL`K=#&0M#0XUJF;+CU$$+#>S1HDPOsKX5i7aBY|CchqG=b z8lGLlBf<%8nmIVERq{0at2l&M10R^j)UCluwZx4FkU;Hp6-cCwZOFK&ic&A2?{RiH zOyi18u3Qi|$09i)$!PwuQgLxn5$mG7_>2gv&`!2OsUWVcE!p>_2K8Ojyj>ib@E_;W z)^bBH($>71ya)SStDR-WhLmkHn*36tO@AKU;eB@`Q9MqUN_)XLM@`x;%)}RUt0)GS zIIXaDvV$I9jiN+2jQ|SeIY){-IOG6B?r8=^A_jcIMS4(IINnWKSf<)2cafaXM)3Qho zzo`E+g#1;l?_NR%9aqP_7VhzFMRq~4Q|ohlb+mX3o- z0C8Clb9PNPkEHyB%gOLe!EoWqHQV=6q?{2k48VxIx;0^zS5=We?I$GeW)K3ZR>FEf z^S~3MH@k;HG-wHCH}`aATv1j_D1M8*fq4us7SK2~(Xesyh~UV7Pl^9U@IOg&@Uk9U z`162=l*FD=InlXm6Hy^)kXboSv;%b{5DP-xHN}1c+`5JB1^V#wD?G#RPjf`nFkoYlj2$ayG1Ira?;JRa*#JoMh|D#T<`K{-e)thCb!^ zY9HE6l{twM(*CAu3KiEwgHUQx1<3s^a#QwXFa`f zN#kg0L0M_Y7l5zUV+m$AQTnK%B z(9VC&HMRYH@)jemw$!)c^T|ZM|Jg%|+>rI;hI^PMiRbr!FWYgFylK8qges=ttnJ$A zaEa(^W~3=>_)Jb!M^EdM6jUlu7UHLn-*la}zHEar?`agxg!Vp!RKN#X9*WB9CMTs* zCHQ-g#whk5%+l7fjg3{mFyczx9%_A!OmE*kT!bFryR;-MOGpG84*t@9>>g*NIygWY zAJ$r1xZ6<`n}tTpo88h-88MKFA7kM-9RiQwsoxoSy-!pK#l`)h#rGgFwG(VnA}nx6 z2mn5|E>2} zi=J84)zw|6PF0<~&+ds(R+K_PBtQg#KqxZO;wm5z6czAa3jYo$5qE0}0zP0YL={9q zpqe!icahGIT@{b8r#yVjo%Lw06L&LUir4@P;jbwfGF)M&{U zpw-tPv0ZkNEQ%UCk{`|dcS@~pAdRyU+_0XtX9q2<40Uw8W?bmeM%%~r)Atdk%xQ$V z?*461UQCE>{4!2liEOuu+qM|fvx}DeBQ`$=rA1arAe&nzvt^o9kpspFkG>-Cg_>1s zPo0`)x{$M{FI6D;!0<>IP+AeM6&t*9Z;SWAWm#1RU&xzHSDT=YCHy8O>%iNU`N-SQjv>%Jsyy8go|gZufD-{o8{t{=sB4g}-q zh3DzJDxa%prgJ|uae=_TzRx_teTGCIUpLRslluCUJ_tWl<*q}NUXN%{KMLG$_t2o~ zpnk0Xczkvyyx>>;w(@ijQ1R=Ks(TM)<&BUhbi(J=>HbVf_?`|#^pRw|dvxQ1EXr@IfpEd^ z=|$M%=%9Y}7e-|J1B)SyKknNdcSyjqwt(cls@=x8+%*uhxpP?&R`d$+GvKnd)2E&Fd4S^@;JAS3?vqVJLgmHX*_7HGCn(($ky1W6ybE$$NI-$B}88l}%~|;|W)m5K08hj8y?nVXiSc1_CXP6qA(5 zJ3Q`lB9;iI2yx@AK}T0tk@=1SO9DowkgSFx(X#g-WyW4*>vFwN$-a+iBci30;d*7- zk8yAzy=d%M7n`OZV93YW4 z+lJrrgO!>K_lP0qH%v)2B*@9x#Bv?kW>~WCzaZey_e2xk&vF+tUkvrSp1J;EqVwo< zCzYp}>ons-nWdkxO6g=`5^Y$*&DSEDfqcF)mcs#YaYKQ0m;wTraP&`Vevi9F*o-UqqK;PQ-nI_L6^@?^S78;L1f%FJ3iKK| z1Q>m;=mESSN7MdWI=nG&>KIE<;yH>M_BsX6Yt1NGz^!o zf!UTlO80&rldxTu0K0cKmY&*<)bH{NXYPComLl}2WnM*iyQ!w*pWaQCgN z5<=9#8l7*m()`K6SDXd{y*Bgrr^naKMvtRGP0PEd9~NXJOBd>b?vOne@zRl3x>y)2 zgFC4RxHnXWH0|0qJs#Ynm3|=yN0+@e>D=1Mx2?{vXHo1{;C#!N{cY9IIV7x9K=u)9 zK+eXNpw%RzyyeJ~#q9bea=>3P4~3g>;Cn6|S!kX>VxlB`<(lIsO)W3*IsdyC5HZk`3 zQnqP<_4h}3HXXx6 zw0uW(nA#Bed{B|)%O)FWk|O&QWtp`v9FAV~HmLj3mSg?ea^#YQX+Qz8qU>SDA^B(? zsoWAtw|9@v=YLMq3>P+r#%kE4cbnGrfx+bfu@(~BmWha`Vg-EUJHr;

w<*;t!^ZR>v~TynX5tFI?38agp13HR^$dy^;IZn3{Q^fa^Mz5r%@!Bh;c?kl zjsSz61xgwZ+DDZH-oXo<%s$YlcTFVV^?@6wmt;#zptcSgq)fXo?{^-R&yGKGWFn;1 zhBEt$l$dCGFLj%RW93UPMB+~TCyK87!)Wr=fQ%8L7z{lg&Sr3z89moj5!NMmyU^81UWvT=$$8UuO8NWS1&ik{C#MDOgm`F z6w1xHW6E?pyGRJ(dQSs!q+RA?AS!q1DFkkvG2b56cm->8P^3OVc;Nhi7l+>(_Hgy9S`(CW5_~Gc|lV$|7ONd_*Jfk+OkC>=+XvUnC zXahkQ)k9LS@YA4PEt^%|<*d(J%)*to0(&INW-z8e=srXp=&_LrPL z`T92x*VknyQGP@XEonS z5~E7}_WGLy5vFI$tt&6H{QdHv#Iv#7AF%wu$Z#&Dv4sDNoZV7vHU&97+`1H8FdO!e zx%71SJzCkF15780B@&xVzcfU;Av|K}Gvr%)08b6_0;(1&&s}yZrKa>)p9QH!Y1v^Resw;CU+|dU zJ`@NPvHILN!;58K+`neBzE7_D;2wG}%PJxtxSk$=*7fixtGJ$a?SpD80((glMye!& zh25R{YzK*g2D+FRJ$?Uk^SA8&L0ilnTCm~Z`V%-O*Apoo%l;B+8n;O1m6DCr2kK<1>aq0|9umbgQ9+T*!d!E1; zY}?>|1S*FS#mhuOIzlq3spcN{j<;R93DT-2neoJBnFV;8P3r9z?m#^3!$Fj1Kgi7G z^nQX;mVID)vjah{Ge%4eRgz-!#z=FIR{I-u%iKu}PfoYkG{+w*?hSCaJ6?3 zp@6@L1Q1!6^?@gzbxt=YWlno8sdhI954T$ zVH45i|Ab8f&oZ7=VLUbPE`ztd%Rq3{xpr9uw2c>D^)fd9gZf608 ziO7m9TdWxZ@x;qsnDg|*H8u;vZF1J+BRFvgJ$`{g z4C?)qg3Mraq$=`?pZ+-z`Y#FEiJhJaJ2%I!2=_CB4;>m^8W)M(x&EpRV1y43YjKL( zUc$eAu2V+~=v1RRi{GB052%!^(9_ z(%(GZJaG^R3>mF!Aev{`#5ML8d+0n+ewM+hwA)-&!TUJ1 z$3xo7hkPvFLRAu8eVa7_--REtAJc|_i3mhR-!>(0Urz1ij*jEuosb#Y$nsSXEjS2+ zuGO~@=tIMDzIdzL%EQHE+Lvwt_Pvl7Ci3|t0l7HeIe}L_k2c}I-MKE?#$%)tu$P;x zz=EnhFE^6O4@PJm_|k%F?xxX~QYtGMIdIMJYt#0|1>$g%l8Jt`vZf~k5eUOsiCu-2 z2u5Ft4cftDnG;a z{3$dwp`t}Agq5U#2(3k|baSYPEbspiPi+JYq5wfSZED3@ zkzvn0&jJ%xuYgv*lz!Pwvz@OHH3Lfq(|ZjvJI=ws z!Rs$k0j`8>3RfL&Yi-wmsiryH?p!azk`RiZjq*0NAE=-zPYQH6q2xhz%GF{zOrMh2 zphhJ>d&`uW?K;k>9~U3ZEsFK{Miw$6JJaRdVD{GjHuZ+5jxb@cDKoRmu%>hFNPP!; z=y?W_EU1FTYh6Pc`qqw@F0Ta23=R=H3k%#>g<>sJ_Zr*xJY$s8o<5e?QeBSWA6KIgw>{s?$$iw^h0Ew4+`Z<4A%w_={g|pIU&q8E$!$Hocuq+g(T1zQsbBsT zNQMVD^hv(XB5o^r@{<<>c(r(iwifThR@Hh;YEv8&Y^wsumRXM>1{i; ztP>nb09M7jrCj%sPICH?t=VD}Dior^sACtJX&BHD_rhm`lbJaug3onS2%ss?&lWME zg-r(>j7*{x<_f&c54`l}V+jq|N|$c>`Kqs&>W>N@BU zF(s#8>KAx|e(L$4yR**?h|9}9s{%8TDy1ydIwvpHQ%GQi7Mla7{7K9~#zC zOZ-tU&#Rq}cRV#b&dh}3eD-eR?1kIK2VT|b83=DjMl|%f34FK$;(|_=HMZ`-Wo9ml zAkU_(E|0WbRz9!8K(^8}qtPADlf*)3J@j)mYKr)kB3`Iy*ZfKA=@>~R`mX9HGt9(f zG560N+t32fJ61`NWbBhqMVH*NV&0H`?)ETMW~5U=)sN1f7UCMrcg?HY#+%59zS_sy zBgg*uTJHQ0#Wh$@+UZh%7$cSo12+_6q*1SQon8E-#d;@n|6uAduSo36+DA?KH2*O9 zC16&o0IFE&F50xd>;vpy?oKC5{(+~YAX9XhYmNn{k=>y>k^Z@!ZbD_+>lNuWrM}GI zB8u-%{lf69QW8D(X*md`M}iffy+U?bUpB!bA*N zt46fSwkP-fM!U#ObcI&=z=jD{O2PYPGyj~N81S`Z2@>zS6)v5umE$HQ`JFG1FI5_|2pUDW zTV#&W)y1j;aLfwg&Jr1bks>>{YQvGI6>K%D6ELh{X#`b6+K7c1()mv8O@%XysCQ(M zF}Fx!b(Qm_d@qv1hAMTLok17Iw8=GK~dE!l%_nXbv1Rph!Z>V3YcoKw%FJ>dTH;ve#tfGM8%QHi{iyLEw>~h z5y@>oqF3%+>KT$7PH>{%qTn*XgvTrD9;JoUsdJs<4^uY_;Qz!uq+8gfwz2zTUUu)i zGAB4frH0?2>M?*&%$D`ri6uEt?GSsCS7gUkX|?wP1z97vhc5v76Z+#W-12_O4LE!zZa+cI%DP!4g~nn=VhD`f1v-IHgwTV;0fVE)gkyubpsG zWMU@*!KPNoay4r3?=4)!Nlr6gOynAPwo*R-DOBEQ&is=*f<61D-_XD^Q0sQq9E`c) zDE0&nKe#H8f?*@2sd*dh)8!=*!gj0h^bX{4c-);qR6Qw#F@pKa){9HCluH>NPWCSr zCjEEdaR7pMdyK{AdFA6w+o2sY{U3=s$X~vXX`=V)XyBac>vor5F0r>!+RFL2=6j&U2+VzEQ^o`2H4ge+V4Hn z%pSY@=TdEcX@l;is_OMo?hk&!6T32%-cvR8Wh`Cd8 z_1C=oz!#%Gu4ZEVe6|jg%YuBnbhR=WDgEJo_##B%2Lus_`~sl|GyD$iD009v__0}m zp!{HmgkeLL$VE3Xf6|gidv)8kT;iC>gCVxx71J*nmR!2{=8$WTi5lNP1N{eQ{j%EX z^L^fz@_-&Q1*^BzynrRl#Y>waM(i#I+}$e9EA#)CzGUpm%~*ym>DGdjh>PCj9)=&yNj zrkXsL7Cv?iA+pe$d1NPMcL4@D>fPu})oAZe_jyQqvuB<$vt0m`snejF+_Yu~+Zn_6 zUn!b-?K%R>X)I8|H@owpa9j=m9j+VmTj_$6O6d=NiQ{@oI3?#WRWISXrj1efxmFEU zV+L}30W0Nq&m;(ep*E^YS&ljr?+0|3E!cYBMAAU?(f$MgN85Yja|4cJEa5%4p|;@b zwtPkfpdoZ3!$A~*A-Q)G1(^LZ-Kn(!dXT}9X3YL-d_4-io0I26EOw~u{H z-d!7lShQ)gaDw#l=?ScK(sc}}9>VHC!G%oV`Os>c8?>R^qa@nY#-Y-OAN??FP`^{H zWw5sY+*LO7{-}I(1yI`z6-9WGB0Dj^uukUrv?HF>=B)ghuv+?U8Uytc zyb-_htDqKteqMPIlvkH%AGF3SueEzL#LDkh{jKZLVKd848 zlkRn=%)8twbW<&)=>aXs2HM}g8oc4`ya8;sfUsT1BU`v+Mywk*ZD{t{Z!~oa4jLDC z;*t$@-0Xp^PYR;l5OY`WB4|H>nc4PdM>RA-2U5+yrjzRwJIaxH#Zt9QAAH6k^f-QK z#KmuhcaUfv1q*s=0>@|^QBURyjBu7#8+%@sEHftFJXUqsJNzmW6R5k(aLT&;$;s5B zE<9=;*J?|pT~#dCu@StjAy{EqH)c+g3t0vdVauGARZ!jaM%CZqI_s9^ybf*k485+i z)m?ezQY5||dD7%sumR6#+R=I5E1_GUgv#0uJe_ij_a9aq=Fad3W41dmq?b>o0z7KZ z7o-%wXnsYT{J1{8TrOswIhO7_tJ8c>PI3~&4>l<+CV@Yd`|f_U46rawhT$hJD<1Wa zwnbcZW4oVlbDkP-nU@Ge|Jk)Eiu)sIsr7a0ME9ij)u@Scy`h|8pXl3zyUPt}=6iq3 zzV3e1y2WwX*Sx1up`1N$u~Ww)uk2*+S_5I(LLmeFf&AFDeMQZ(yIWTe;$0sBLwFKC zMZm|3pG-cQ*Trdcos9at?zjkiOLgJ+<{g4JKRgWV1G zxe`5osmP?(4-C{HvFJHFooLa-Kco+P5=)_%`y%1S${9ST$|GEZFZLKx)6GBW|Lt_% zXt7`x;O?p+i|!j`pB|*^>xM%#EZI`~RdF=hkz1xlpZXf|zqJ54E$1uGkD)*O_|?Qd z=3;qz1{CykYkX4^91WYF=VS2Tn&sCl6=?6=5^ea=lacX#P zj~*M8*5ZZ=Dnfy76B#Wu-AK4G#rm{4gh5hK`Qrzo=8u2Ap`=&=mM26-t<#>7C#pUf z@uc#zXXe-RFsUp{cS@G6HPCe62$j9Rf}(%@3Hb(%_{qjzd5z22H*JhyeqQBhQ>p=T z_p-+P&v%8wi}=F6tg^Lu8PmtcAN5wwm6x!YqzOYqitJYC^nbt553ER7 zYy+M6SmB##Nz6w8_0gLQqgI%%hNdwmxyo8_!c)>IG|cWXOORog{3ETqhK>C@&VJtC z)L{)XrXAy1G9VtsLe{%QbEk#urmw7+Kgkyy=tE{}{hsF5)=tCR)_fO)O%Oo)zIFGg zRaN-<#Ht5MACmK*lDy%Cb@s1msOAGn;AYdKiUso5+f(hL+OvS=bivbb51EC~G?N`! zh9|>DiE{ZaS2YrtAA!HVUlWMGJFSfl(LfmR!XocpVo? zL>*`cpxk-+x?zoYV$(XU=lUXIwOU}*KOC}_+Q@AK%TyA|_Qyh%Z11&Q^`bd$`%)56ztarCL;5f+Uc0;)9luLeSsJ~F%+qzqnt5JwTyGmF`-!}Ee zv?JC>Y}7i=%hdVOL%>Xxo~Q$>6Q{rGEzOq8g0rIHC_5R8B-XK3-SSrDy6Q~~tZ~mr zm%CeU^pg{%pkahBvnk7#3l($=hVW(N`t9~QP3jBy>$lPMrFnI{0}b9ZSZL z@eo~ZWH;q|@hf9=Iz}hluAqT^qRf9Am3z4RoNU~1E`RN?0QWn&16$+U`pRariNCqC zDSEe-J7`x4K^xx;`)l30OA8PikXA zniV{T(Ec{<^YEnlG@Fx<^JnCeM6hoCcA&ojR(>{bYhB`hXL*B2KAV-7B|HML6Y+J2 zL?C?b)!qbBpV{j+KplrsAdAYg7g;{OcG9&u!e65G_me}s`#(c4A~N$4KciuepBgAS zrVPpf`TPGQ@x>;&r`rYG$+rTlt7(40hKrIu{fnReo6(t>@C;qA(d96be>Id?%u0oi z6a19?oxy%;Tcw3cESmUr&MAG@jLUeKL~i^SQAw`Z(8A@p$VcJt?_?3JRpUe>i^#Rs zf1o>%HVYrLA6>eV##QAIAfe73r&V6M1D9!U&~-^%eUEguVTbqVsI8kiZ~V<9F4$nd z6*hhzDJc(YbeK7&V7#FyB|X6DD5ns}Lec&F*Ir@BUxF}EO0Ki6lg4gXRR-kL4oMaIY~z)V$K5Pdl<=94m>Y8q1M+;C5m zaH-HS*}>7Wn1Jfnp>d8K3QYRKc=!U^oMPli%U|=*Y((NOC%=gl811yx!+@&m zrWq_7_;ACak`&B$%<9v_eqac!`Z*qr)PdU*&b~mXi0z zOZ`Jau(hsaY+a^NG45Odb;9*?x>hbtao5p@&ALHIm99OW*QLjPgb!4hNL8V*n@#+! zp}Z(!5R#62h9ynFmO-%F->CC(V2B4)Ic0Nse#0xhasBR;XiUe0xx4To))*jFx5K~s`Fr)!mqvlMDS~kxFEOjodIh$Q8?#^+3SO!Xg8>~TnBB6CypEn~vU_OkzV2~azZIK@(Dv(_M2 z!2BI_p&cPVZPVZx=bFiB5-O2H2mYdMn!?Be+lK2+3ih1}&tL3Wy48J%d_YVZ=>Ebw zej9UE0s`Fg4BwKFb8+!NkYdrEM5y{xdVuGKSV3eUTt^WG*70{48B)8;P@h7G+bFX z1r2&n1CCUS)X61=wtH>Ti~ZIb>Y=^EZeyoo zf}yC;Ewe0&ClHd)PQNH{wYpM2%I>*d;xalGi^+D{wKxhN6jJ>G*5A5|8A~g+A%nB4 zUv8i_#Vv;1U#1t8X-P~#Q|_X$+c@@@f9IvXPT+~H^&x8MtfZe5QNKE*S{sRm`=OEf zxF)!hz{GO6HL4*~}?NEA%c%9#4}(dMM_E5>M*@wvjH$5Z;_#gz_Yf%W|J4mKV&?2?fItoT0c zRdpg1!2&^Cv4lM_efFqU-O8Gywip1U}Cv;2)u+#Wx8=fNa^AstJcoQ z6{kXvw!Ps6xA*qdYE3=32>;xM4`q3|wy+hi2OJyzhjww-{Oq8t))Xg|lmv<7&h7>%hsEL%|ft95J!I+1<6ewpbPo00^~n3kT7}3 zICD<&Gd~7KME}1w)=QR}>Y^-wtXCL4qNu!p?BlLlBT#TL6b2s$M>Zw#Qf>kNu}uPV zaQjXDdkkr?`ve?(a!d&F#3>a90vC7p{})A+sJWBIDWN$E9P1K2+K^^^PvUm)@V=SR z;<3a+NBnq;Vw*bI-=dG9tu%2ka`C@o222>*TZrqOt1aSSqmlWqo#;<$lTn}V?U6T< zd+>kcWWe~!t%5G&{Iz^psJ$0*&hw={K+j&taJxiG4q?SaeA0o@pgj$()C=7)JECB> zGpvk8{jbt67|hwN)JKgGKY}1MVGP|wsTxg0FEpq0<4?YViPd0RETb50;)Ue!u`gL6 z;vBcvn3$*><)78M2Js)tv}qw?O!2~tskq$CKk!IE>r0#^vz{bS%vgD9DlY~wPiow8 zMK>qYHr6NccN~CX6phf+KL!J9#<7?mmW5p-WXw6;RCB z;pW{<;p@-4tgt&+6i>d4I``CAcTI1o3Albp3Eyg3o^$g!hvqop`abe6o$BG|nK|SH z=l#qc0C~A6Q!km7EOlwogK+!X=mr_(FQg_dHhTNs?e(F;GdvPB6R*<}C9y(K@iwIq ze7~hO5H8bDpIgu0@BG>qCevlsjoY?rC`P!?V#XOTEU6B#HS<`c&pt2fou$`ngKhn| z%%a+6JPo5eRjrKt?CM;`30ny!71I^w{qvr7Keo*WVzW@4((^s$O*xNmJWhJ){5fNV zXS04bGgG-@@Os)78Z*O(Fuk^6+5UvUl$~9U{6S1T{P-C8+AK?@^iD?V_C`d=;W_qa z9oc2!)sgLH!?a6fEdh^f0+VINg{s0N z+bTJ292OcBBT1`+%kPua{xQ?0sm6*wTk+{d5OfdlJL8Qyw)$t!Rv1LMiui-Q1GvQ~ z1xXWx^YgK)r4KhTEwb-9#@xSox3}_LJ#$+Kb;avIy6*v|3#xnL$xAhq&F5)u5jQvX*v`-1RwI?;>UaR>m?%b9B&p zNL2htp@G32+9PnbgO2D%aqbA9WZ3a1Zw^!r@a>~RN4(N3aEwm)5U)l%sJ}C7ZRiKp zxtrJEKD^xrbuNMYfrhi)@~6_cq6gmQ4g}+DZ$j~3l5o>Jl!~XjRqmzU7U+?pkoCRb zK^ZBY9)cls≤GB=@6lS9^0jVefn_m&EClVaTCGT99w}K=N+~xy)bl#~FM5?&I=~ z0CLh$Cc8zX2_GcVkU@{7QvNGD!J0Fg_vN^5BCG4G#M82ra@F1NClK3T?g?U+MW@I8 zRkyhD>`YrOC=db4R<7Yt7|w)zU4(gYUGs0@;_0ZUVGSgmiWfhxCsu$yRK+zE!E{qD z^{!7G`c_PzjOBl!JK=k5mRE#qays$m9gB3p$lTZ#O1pXhfK~>9T(DOmm)}OOUg0~C z6d@srYlsY_JssxTp5rrx-|hoganBKCf9)KZ4sm9WP{MijIIah4Y%2~$j^bk)Z9m+g zFn;CFJ{>+UldmOAkrH~`682qSDxL1E zF}DYJ^6MiD51QZj>B+=aoV$kdKCX5e^Qc1ndn4)&6q1j-QCn(c=oN86&Kj2`;OS7dX`3Ix`?4;rhhYH6?w%sU?sWE%LBF|LYOqu`g!t2> zy6VqW7lPuC1fxl*tkX8N*AGuTvnb#9gn)V<7p# z34Mtim(Ag%R^t`OvE%|sR&2A+7av-6g5#nA>H^e^;Pih`jHYpElSavw4DaWD%1YcY zYY%TtTxpw|z2te3Jk<@h%?ZlIp|-Y^(Gy`qBFCpxbO3}q!UAP_?iWY9f}lCUkp+kukL z#${o0X4MaAKewCQ*E^crEUsvh*D4kvwY4#>rx2EB^Sa^S2aN_;klS02g)N=;hLrH* z(w*NqgYeq}OOE#?MDXp|@AVS=d|6t2`L?@@ivkVut$j-Bdc7`QIULiF$Vo^)y77A% z=k6EtN{%h;Mml%HWq!V!@Ghdmju^f&%<*kKO>X;yYlKfl-cu}mlU}AdzS`n-I!=t7 zR;DI&(?{a_maG4?qpCDK@_VZhQr6ID|Fn9NS+&~!a5#qU`)M7>=v}@TAT|49GovHOY*f}4s0+5Gsd1@0ujO2$0KhUWS}ZTNWy%Mt-Jv>TGVo{l6p>4CdV zUI-<-N=@0WM=j~rrD^jw)u7e+p>X7XUildu&*fMxb%nb_40(q%>QWrU4k{|Dv9I6{ z`2m$ykwU3WIqmZPqE@fr&_kvnQ{qFn4Tn~fDLQy=HQdAp}*`NJZiZgn8ks{^w z5siHVtsQpkIbB0jW*?(%c{lQ!gpmh&q|ZCAh&$jk>Tv}Nki3PU`;N*!j?{>$&6o(O zO8!^ZH{0|gK!o>4@u-Rq;WC7zW||xFbGpMrUjM9Pv!Q-Qx1qW{x?lpQnR0-4daV2X zYYrgSNTI`u@&Tt_r1D$L3fAl}qnle4Yu3BARi)*yZg^Y-)15QS*nA@5=dV6KKtzTe z(Vsr%)MoDEEZs0tpSKDqx|vNTe5T_{AFuMq_h*}Ga&0>!M)X#QZ#Yva)g)eMzEEqh z;-u5l=xRqEAZKLRdQKCJa&C14&)~w;dC=(D4AcUfit;{HxJoI*=ln@k*o|H)4Fg63 z2HcTA^$&($8a+)mISK3^Ik2MaADzJt$aB1sip5@^!WuGexQGWWMyyx5C0LR5#5crc&bY-+VF|yvlABnn0J$x${ zvw6pl)QfAVqB(BNSJ$oTyVUnzCgeY!6#V%9@&e;wTu%|!TLQ$NYL2&z32%T`F$=u- zH`_u#;b7LC>baoP|MlowP*2M2hg$gMGiw*dX=U8YU+mI?1p`;@@n%q>^sZ+w9Rr`D z?6#-?*n!6!B8Jlb3w8BlS5$ODVIew)&>Gx_Xv5*p!yK$ZGj%@}`r4CgUo&kdFftz; z?H>N*I`X@=^@ln^)R$}aZp*!!8SOprQ&K-gz%Zkii$Vys8}$HA@`O?jE!zK=c6mlB13{UGx!8OP+Gl!3L_HJzbt!bz$wJsjB8i156J*j}Y&1lbpiT2Uq&#`+Gk1 z0be8#$kdT{*_C2kPN0ySm}1-g>@KqL_k2o~UB5-s?pl#PAOfpMVZb5$G2b`*iL#f9 z$WP_s7f2)FWSyk)VE^h7@%;t?Ri-e0fLee5)``-G+OnUS^uJ1IA$f4%6}!*Gm)%Bk z5?LJYmbjNws<=W-EwZN;9PAUGp1$M=^1U8$jf)t`8!`XX>0hTk$W#`zL8L}@KvL^3 zLbWU2P6!FY7aRK`KmCcK=^DXUeohIaUtHv0zFYJWR^*ff9s6HGow!D~N}v~o7~XiH zUk>uSih?>5?;vx}w+e>sRQU}MHTTVSGKJRY@=;t5;P**SauJi*q4b9(ss8=4QEn7E znv1;J7UdU+UQ9xws3;>PhxPh%Z*Vv%^{WjpFBLKNB|*{ug#+UrxQ9~^?an+II{hiU zS?tbJcPLr%QN7-hH_Z6fHRL|`f@MMq?d?Fg_e>VcbB;OW5*lRyIBYz~w(nxIBtgZ!2Ue)ztdK7cF5XjEpNLsp5L2Oa1MA>^$Id?Sf3A4bD%bo_ z-H=1*;Pu>wt+3GXod?Mz211PKW9v%avSqhHQ9ir=h||HOA-+Err^lMfK)V=d8Q)Xv zzS)G;OAHa%qQ$T|nyJQndDd+u^ADXP_uO}JO{yQfbZ6b7MP8CJ(YBaE=5N)*oM7Bwhm`mtd!9kYP|JtaKLW%5= ziymF1=Jysm3Pmct{m8|RW*Nk8FD866fTTlM2CXN&I6L+8qhvJIR*4PZCDC;M{Y3k+ z$!37@#$6ir(tA1VLH4-)-8s1VPW%=kS zC#t0H_7JnDPA53c@PMp3kc1j4olzbL_rHf64U%$8ZpJyI*IZFYBcxUgycDUot;-4|A33A2%UG1s)MvC3C6Pcd@MnhE5R z`fRvri6SD5vTiC?b8NX5{eajM{f`(LeQ>*Qs_r@f(C*)E=ebknxz&R4AEMqF*@|<< z!nkj&f*&0!N8^FVbSpzZ{bL3K^7cB@AX2zGX#;EIcvb{U&5`~wf zH$alL25;^z$#Jegyk$2FXyfQb_HOw4pvfoull@^BdewF-;$Bk+cmoHA&~GXgvjXlH zlxk?f4N4{}VC*qF5*F<$mUjD^$=nZ1l7r8Wl2$$@ORRhk0%^N&Zfk@6NjHz*m(omI ze~zisOO?*Np6GgcwE>86V<(cLWSpCk24T+JW}|$D{=J*V6rQ?{z0Z}pRDM$VJXwUjHNPMgu+Xs-RMVKJM>Xgj3|lm;EW9RV20g-ol} zc*vS5c-U$s?}64t2-y3InVj9LY8b;bU=$%seKMux58*i0LXARW(r9y9!DPgMue)!$ z*Xkj04bHP4AuK&)Wzzh8Y`dr7oGS2Iy!%-K?+*?+-*<4*HqnKh+I7pVIj5oL9kqcJ zo#ffc0^c+qRYRdHZ~`*toR&TlPNOoq)LQNWp{`6JXnj5F4vV)zn&!})^%d6X`pN0x zz3o!L>}<=t;hyH=DRYj5f|p?COE_i`NEtgqAKQ{TQ(p@ZIh0pqdw%;l#|>I1&Gh;0 zvc0|j4oe0mlYwew%!<5Wykb3vFl88925*{|2`kJ(oAGw<@;yP;xU6rbut4!qo+XHN z*+vl`_O`9OwDDC``a7%s-|ia3^14Kb-{ai#2!Q&izv&8i6M>DFT;B+v(Hc2>q5ORdiJ%gvE*)uJCk} zbJ;}!0qJ%^R6yXvg|Dbie|1C{P)JT4ZcTMSdntdJhj~+>pk{eKQ;~|e+w`Li(U%IGS*8|p=Mz_ zaR`z`L?4YyqLVsn8c65z{7NYWq5#tZUVWxD&Xrl05n2^?nXpHnoP6rwSO#FKwJ-EH z_O?u`--tS%m_KYz0CmOy4Z-=wO#{&I>m>l=%I6n#i%)9D=bW@%F#rn06A)=gbbU|z z`eQBE8twLxS(QK594h9*CQ2W_&Dx8E7$Z5^)b z;f2KeVhDKAzeRQj0-%`l1El~~77b0q7ewzHhO4J1zqceMP`8%WJ%9{uB*Lj`TIZ8w zou8aS6!$S|EuEd;JzOvP@&UXm3imV*+MAakn|PD3=Kiu}2s0T!0OI%=9t<8&xJ=nW zpbT?6yU?@)>AaVgPzAl)y-1HhK#3Ij(gEC?mJ^kw3i!PO?rEDMxg`!D^ZqpD#?lvj zY9jIEB=H&R3hDx)ijN6Q!{yf4psdmx6lqEv+zIA(dvs9rku|`uVA~Z@1n^n*NgDKR zaR}i<0V*4d{}pBjnfN6?(`-&ZFw*ICyWOU@vxyLim%hz3n{3d+$-%j7C!dd?^&e)l zhuJKgS?rLPMTAPc^bKJzwyX4q~B9}j;W z$VuL&O0u!y#G^Dm8TxxS@@q9sytPi-{gR*FzU5q_{8xA0ZgKCV0>G4Elt4_H+YLd& zOtXp0I3+LL;6hEdz!LwJETR7C?OT7acoyU27taE~AlrLP0Bj#BXP`>VIODJXCVUb* z9X34hYv?>-nqw?1z>j|nxPrM}XNx2gnw9VT`o_$?d${9Bu6tE-t3JQ6F%19!|E*r% zT|Ar5=K&U)BBOb0N)C=`6JHvL_y?C@v0T+W~U+HWByG=+1QR< z>KmIm19e^Sa&&U5j+%3nN;RLmfPqsF``(mc`A!?g^uvet6zcV(`FT7}rBeBPzTQ>T zFaGGq65|N~>5_)~gtDg-ewU# zUR@RLTp;|OM!T#tV}&Cz#cp8zyO+z|Xn3k!)}dO(_^e;o$@gCLZkP3g?z=YlcB$<< z9&KGm%|zwIK>mFNHuJ&G9%i#U@*0^G*yDIWyEJzGq>{d=E1P1;6>AyyMNVrPHq#8i z%)NWjzdFtOb+#ASnC^LY{5*H9WXC!{TV&n|A-q2|YFU(s*ZbWzJ!Fm+?$Fu-m~A#w z>l^uhb2BoL_+9R7JD;N{K2>-D1A&1SpYc}DZ~MK~07 z6L14Qt7|t`dBbh^^yHwvSC_o8jq(0mzUBi|iWF>)>c_JIN0zry|bJmEh(j#|f5PSJ@a z#*T5)H-7H8%!T(p*1?Uo%XLrkeJSTDw#%JuXq5fSBKXCY5t|BE+4-CpN8nAZxm7=U+OmhZ zZ=Y?J@6qZiy>U0GM7=+kJi#yg=tnD@BH<2p>|bMH!B|+hcj5dmpLz8`zw?dkXFij?b0=A^v(Kac;>jo9`_}V+{pBy? z##=VwF{vA$e#I7^*0lfp8^3Y)yO%RhKKUy@|9NVCgI{#=@1B3Y`PHwCWG63r^*aI* z0AQNt_Pg6RU%Pqp)thV|i*cFIVBp6$8q#IWa#R+rFLl>j4U!QL`({WBAhN|JCw6&$ zWMB>7y?giSm8+Ltx^(%a%Qs)U`RZ%0y4trm44#gblT!mHr=%lioW@HCV%&+>c!>n+ zT@Vw%c<3AY!K0RfAO>X&^bM7b`WVERviXO-J-Mm>Mi9~AYTx28Moc!1m@s7i&L4sU&9TOg_Ig~ab7=ypI5Czjy*DfqpF1{(kYm?Q@3zu|^Q{N70*+RjDz!5Z5h%(kQmVj@xfJ`VryP&Ygxx09G) zhSh(Q<1}J6BS{bw$!OLqOEwsc!={`BF(gJj|33QY`6?zK#qG8~eHcB(ehe1_3@H zu0Z<0fdl^;{x>ujW&}n-(4^+h(vTDxU%5sCz;oSX3 z$=fWeRyX87ikl@9|2lDjSA(|9ey+0r&XU*u76`HGXCF$KqG`dvEx~ryTxjQAkb^v3 L{an^LB{Ts5RF6=5 literal 0 HcmV?d00001 diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_a.htm b/docs/manual/Q3Rad_Manual/appndx/appn_a.htm new file mode 100644 index 00000000..af9a048f --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_a.htm @@ -0,0 +1,56 @@ + + +Q3Radiant Editor Manual: Appendix A + + + +

Q3Radiant Editor Manual

+
+

Appendix A: Glossary of Terms

+ +Alpha Channel: This is a fourth 8-bit grayscale channel that is used by the shaders to further manipulate the art. It is often used to create transparency and translucency. +
Arena: A confined space in which Quake III Arena game play occurs. This is also called a "map" or a "level". +
B_Model: An entity, such as a lift, train, door, or rotating object, made of geometry brushes. These models can also contain curve patches and md3 models as components. +
Brush: A single piece of map geometry defined by four or more vertices that define a solid, convex volume. +
Bot: A computer-controlled player. To the server, a bot is treated as if it were a player. Some entities can make a distinction between interaction with, or use by "live" players and/or bots. +
Bsp: An abbreviation for Binary Space Partitioning. This is used as a name for the compiling process. +
BSPC: The utility, which creates a bot navigation .aas file for a map. Currently, it is run from outside the editor. +
Compile: A number crunching process that turns editor code into game code. This is also referred to as "bsp". +
CTF: (g_gametype 4) Abbreviation for the team game type "Capture the Flag." +
Delay:  A keyword for the amount of time, expressed in seconds (value), between the moment when activation occurs and the moment when the event it triggers occurs. +
DM: Abbreviation for "Death Match." +
Editor: Usually refers to the tool, in this case, Q3Radiant, used to make game maps. +
Entity: One of several classes of objects that are placed into game maps. Entities include miscellaneous models, ammo, weapons, point lights, doors, moving objects and so on. +
Event: Something that happens during game play. Activating a trigger is an event. +
FFA: (g_gametype 0) Abbreviation for "Free for All" a style of play in which every player is pitted against all other players. +
FPS: This is Frames per Second, sometimes call frame rate. This number shows approximately how many times the screen is being redrawn each second. This number depends on many factors, including the complexity of the map, the number of players in the map (bots are worse than humans), the processing power of the computer and the processing power of the video accelerator card in that computer. It is not the best measure for determining the playability of a map. +
FOV: Field of View how much of the game world can be see at one time, either in the game or the camera window of the editor. +
Game Unit: The basic unit of measure in a game map. Eight game units are approximately equal to one foot (30.48 cm) in the "real" world. This measure is also referred to as simply a "unit." +
Grid: In the Map Windows, this is a measuring tool, much like graph paper. +
Key: A key is a property possessed by an entity in the game. Light entities have a default value of 300. See the Entity description appendix for details Entering in the key "light" with a "value" of 150 reduces that by half. +
Map: Also called an arena or a game level. It is a self-contained game play area created by an editing tool like +Q3Radiant. It can refer to both the map file and the final playable product. +
Map Component: This is anything placed in the editor to create the map. It includes geometry brushes, curve patches, lights, entities, and models. +
Md3: Shorthand for a mesh model created and textured outside of Q3Radiant. The acronym refers to the custom file format used for the models in Quake III Arena. +
Patch: Any map component built from bezier curves. This includes bevels, caps, patches, and cylinders. +
Pathname: The sequence of file folders/directories from a starting point to a game asset or executable. +
Pixel: The smallest definable graphic component. This literally means, "Picture element". A game unit typically consists of a square cluster of 4 pixels (two pixels by two pixels). +
POV: Point of View. This is essentially, where the eye sits in relation to the game world. +
Project: A text file that contains the path designations for the various editor functions of Q3Radiant. +
PVS: Potential Viewable Set. Refers to those world triangles that might be seen from a position in the game world. +
R_Speeds: This is a set of numbers used to debug maps for visual complexity They show the number of triangles that are being drawn in a given point of view. Lower numbers are better. +
Region: A subset of the map. Selecting one or more map components and using a menu command to set them off temporarily from the rest of the map create regions. +
Script: A text file that contains instructions for the game. Examples: arena.txt, base_floor.shader, debug.cfg. +
Shader: A short script of program commands that define the way the graphic engine processes a texture. +
Team DM: (g_gametype 3) A team of players takes on another team to get the most frags. +
Texture: A graphic file designed to suggest a physical surface or a component for a graphic special effect. +
T-Junction Cracks: A visual artifact resulting from patch vertices that are not properly matched to world geometry. This is characterized by 'sparkles' running along the edge of the patch. +
Tournament: (g_gametype 1) This is a mode of game play characterized by a one on one match with other players watching as spectators while waiting their turns. The winner of the match plays the next opponent. +
Trigger: A map component that activates events in the game world under the right conditions. +
Unit: (See "Game Unit") +
Value: A setting for a key possessed by an entity. Depending on the key, values can be numbers, pathnames, word +strings, or word commands. See individual Entity descriptions for details. +
Z-fighting: A visual artifact caused when two z-buffered surfaces share the same plane, resulting in the engine trying to draw both simultaneously. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm new file mode 100644 index 00000000..c9fb166b --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm @@ -0,0 +1,228 @@ + + +Q3Radiant Editor Manual: Appendix B1 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+This Section owes much of the background and testing research to three dedicated Quake Engine editing supporters, Suicide20, inolen, and EuteTic. It is based on version 1.1 (12/22/99) of a document that they created and gave us permission to include with the official id editor documents. + +

"Keys" are keywords that represent the in-game properties of an +entity. Some are flags that determine whether an entity will +appear in a particular game play mode. Others define extents or +rates for entity movement. Others establish how much of some game +effect will occur (example: damage) or how long to wait until an +event occurs or can reoccur. + + + +

With the exception of properties that can be set by checkboxes, +the map maker will need to type in keys (names for game function +properties) and their values (numbers or strings) into fields +within the entities window. + + + +

Keys that are set by checkboxes in the editor are called +"Spawnflags" and will be shown in All Caps. The rest are shown in +lowercase, as they should be typed into the editor field. + + + +

Basic Key information

+Angle: This is the direction of facing or direction of +movement for an entity. Set this value with the Angle buttons on +the entity window. The angle value can be typed in as any positive +value between 1 and 360. + + + +

Color: This key only affects md3 models that are built +into func_entities. The color is the color of light used to +illuminate the model. It is expressed as a normalized three +digit RGB formula. + + + +

Entity Dimensions: The minimum and maximum coordinate +dimensions of the entity box. + + + +

Light: This key only affects md3 models that are built +into func_entities. + + + +

Map Entity Color: This is the color of the generic entity +box used to represent the entity in the map editor. + + + +

Ammo_* Entities

+The properties for ammo entities are all very similar. + +

Map Entity Color: Blue +
Entity Dimensions: (-16 -16 -16) (16 16 16) + +

These are ammunition boxes for weapons in the game. They can be +represented by either a blue entity box, or the ammo box model +itself. With the exception of the type and amount of ammo given to +the player upon pick up, all ammo entities have the same +properties. + +

ammo_bfg
+Game Function: BFG ammo. Gives the player 15 shots by +default. + + + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 15). + +

ammo_bullets
+ +Game Function: Machine Gun ammo. Gives the player 50 +shots by default. + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 50). + +

ammo_cells
+ +Game Functions: Plasma Gun ammo. Gives the player 30 +shots by default. + + + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 30). + +

ammo_grenades
+ +Game Function: Grenade Launcher ammo. Gives the player 5 +shots by default. + + + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 5). + +

ammo_lightning
+ +Game Function: Lightning Gun ammo. Gives the player 60 +shots by default. + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 60). + +

ammo_rockets
+Game Function: Rocket Launcher ammo. Gives the player 5 +shots by default. + + + +

Custom Keys +
count: sets the amount of ammo given to the player when +picked up (default 5). + +

ammo_shells
+ +Game Function: Shotgun ammo. Gives the player 10 shots by +default. + + + +

Custom Keys +
count: sets the amount of ammo given to the player when +picked up (default 10). + +

ammo_slugs
+Game Function: Railgun ammo. Gives the player 10 shots by +default. + + + +

Custom Keys +
count: sets the amount of ammo given to the player when +picked up (default 10). + + + +

Common Keys +
wait: time in seconds before the item respawns after +being picked up (default 40, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags +
SUSPENDED: item will spawn where it was placed in map and won't +drop to the floor. Set by Checkbox. Bots will only be attracted to +suspended entities if they are reachable by way of a jump pad or +launch pad (trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

Design Notes + +
An ammo item can be given a negative "count" value. Taking away +ammo in combat would be a bad idea but in combination with a +target_give entity, it can be used to set up games mods like Rocket +Arena by removing the machinegun ammunition from a player when he +spawns into the map.
+

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm new file mode 100644 index 00000000..dd9a5104 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm @@ -0,0 +1,651 @@ + + +Q3Radiant Editor Manual: Appendix B2 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Func_* Entities

+Func_Entities include a wider variety of game purposes than +other entity classes. They are sometimes represented by simple +function boxes. But many are built out of brushes, patches and +models. These constructions are sometimes called "b_models", though +for many of them the word "mover" works as well, since they are +made to be moving objects in the game world. + +

func_bobbing
+ +Map Entity Color: N/A + +
Dimensions: size of map components used + +
Game Function: Solid entity that oscillates back and +forth in a linear motion. By default, it will have an amount of +displacement in either direction equal to the dimension of the +brush in the axis in which it's bobbing. Entity bobs on the Z axis +(up-down) by default. It can also emit sound if the "noise" key is +set. Will crush the player when blocked. + + + +

Keys + +
speed: amount of time in seconds for one complete +oscillation cycle (default 4). + +
height: sets the amount of travel of the oscillation +movement (default 32). + +
phase: sets the start offset of the oscillation cycle. +Values must be 0 < phase < 1. Any integer phase value is the +same as no offset (default 0). + +
noise: path/name of .wav file to play. Use looping sounds +only (eg. sound/world/drone6.wav - See Notes). + +
model2: path/name of model to include (eg: +models/mapobjects/jets/jets01.md3). + +
origin: alternate method of setting XYZ origin of sound +and .md3 model included with entity (See Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags +
X_AXIS : entity will bob along the X axis. +
Y_AXIS : entity will bob along the Y axis. + + + +

Notes +
In order for the sound to be emitted from the location of the +entity, it is recommended to include a brush with an origin shader +at its center, otherwise the sound will not follow the entity as it +moves. Setting the origin key is simply an alternate method to +using an origin brush. When using the model2 key, the origin point +of the model will correspond to the origin point defined by either +the origin brush or the origin coordinate value. The movement of +the func_bobbing follows a sinoid wave pattern. + + + +

func_button
+Map Entity Color: N/A + +
Dimensions: size of map components used + +
Game Function: When a button is touched by a player, it +moves in the direction set by the "angle" key, triggers all its +targets, stays pressed by an amount of time set by the "wait" key, +then returns to its original position where it can be operated +again. + + + +

Keys +
angle: determines the direction in which the button will +move (up = -1, down = -2). + +
target: all entities with a matching targetname will be +triggered. + +
speed: speed of button's displacement (default 40). Speed +is in game units per second. + +
wait: number of seconds button stays pressed (default 1, +-1 = return immediately). + +
lip: lip remaining at end of move (default 4 units). + +
health: if set to a non-zero value, the button must be +damaged by "health" amount of points to operate. + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of .md3 +model included with entity (See Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes +
Setting the origin key is simply an alternate method to using an +origin brush. When using the model2 key, the origin point of the +model will correspond to the origin point defined by either the +origin brush or the origin coordinate value. + + + +

func_door
+ +Map Entity Color: N/A + +
Dimensions: size of map components used + +
Game Function: Normal sliding door entity. By default, +the door will activate when player walks close to it or when damage +is inflicted on it. Doors move a distance equal to their dimension +along the selected angle of  travel, minus the "lip" key +value. + + + +

Keys + +
angle: determines the opening direction of door  (up += -1, down = -2). + +
speed: determines how fast the door moves (default 100). +Speed is in game units per second. + +
wait: number of seconds before door returns (default 2, +-1 = return immediately - see Notes). + +
lip: lip remaining at end of move (default 8). + +
targetname: if set, a func_button or trigger is required +to activate the door. + +
health: if set to a non-zero value, the door must be +damaged by "health" amount of points to activate (default 0). + +
dmg: damage to inflict on player when he blocks operation +of door (default 4). Door will reverse direction when blocked +unless CRUSHER spawnflag is set. + +
team: assign the same team name to multiple doors that +should operate together (see Notes). + +
light: constantLight radius of .md3 model included with entity. +Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes. (default 1 1 1). + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of .md3 +model included with entity (See Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
START_OPEN: the door will spawn in the open state and +operate in reverse. + +
CRUSHER: door will not reverse direction when blocked and +will keep damaging player until he dies or gets out of the way. + + + +

Notes + +
Unlike in Quake 2, doors that touch are NOT automatically +teamed. If you want doors to operate together, you have to team +them manually by assigning the same team name to all of them. +Setting wait =-1 for normal touch doors makes them work +erratically. Use this only for damage-only ("health" key set to +non-zero value) or targeted doors. Setting the origin key is simply +an alternate method to using an origin brush. When using the model2 +key, the origin point of the model will correspond to the origin +point defined by either the origin brush or the origin coordinate +value. + + + +

func_group
+ +Map Entity Color:  Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: This is not an entity. It is strictly an +editor utility to group world brushes and patches together for +convenience (selecting, moving, copying, etc). You cannot group +entities with this. + + + +

Notes + +
The TAB key can be used to flip through the component pieces of +a selected func_group entity, isolating individual components. + + + +

func_pendulum
+ +Map Entity Color: Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: Solid entity that describes a pendulum +back and forth rotation movement. Rotates on the X axis by default. +Pendulum frequency is a physical constant based on the length of +the beam and gravity. Contact with the pendulum instantly kills a +player. + + + +

Keys + +
angle: angle offset of axis of rotation from default X +axis (default 0/360). + +
speed: angle of swing arc in either direction from +initial vertical position (default 30). + +
phase: sets the start offset of the swinging cycle. +Values must be 0 < phase < 1. Any integer phase value is the +same as no offset (default 0). + +
noise: path/name of .wav file to play. Use looping sounds +only (eg. sound/world/drone6.wav). + +
model2: path/name of model to include (eg: +models/mapobjects/jets/jets01.md3). + +
origin: alternate method of setting XYZ origin of +entity's rotation axis and .md3 model included with entity (default +"0 0 0" - See Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
You need to have an origin brush as part of this entity. The +center of that brush will be the point through which the rotation +axis passes. Setting the origin key is simply an alternate method +to using an origin brush. Pendulum will rotate along the X axis by +default. Pendulum cannot rotate along Z axis. The speed of swing +(frequency) is not adjustable, and the "dmg" key (although set in +the Q3A maps) has no effect whatsoever. When using the model2 key, +the origin point of the model will correspond to the origin point +defined by either the origin brush or the origin coordinate +value. + +

func_plat
+ +Map Entity Color: Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: This is a rising platform that a player +can ride to reach higher places. Plats must always be drawn in the +raised position, so they will operate and be lighted correctly but +they spawn in the lowered position. The plat will stay in the +raised position until the player steps off. There are no proper +sounds for this entity, only beep noises, so sound call paths must +be adjusted (see Notes). + + + +

Keys + +
speed: determines how fast the plat moves (default 150) +in game units per second. + +
lip: lip remaining at end of move (default 16). Has no +effect if "height" is set. + +
height: if set, this will determine the total amount of +vertical travel of the plat (see Design Notes). + +
dmg: damage to inflict on a player when he blocks +operation of plat (default 4). Plat will reverse direction when +blocked. + +
targetname: if set, the trigger that points to this will +raise the plat each time it fires. The plat raises and comes back +down a second later if no player is on it. + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of .md3 +model included with entity (See Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
By default, the total amount of vertical travel of a platform is +implicitly determined by the overall vertical size of the brushes +of which it's made minus the lip value. But if the "height" key is +used, then the total amount of vertical travel of the plat will be +exactly that value regardless of the shape and size of the plat and +regardless of the value of the "lip" key. Using the "height" key is +the best method for any kind of platforms and the only possible one +for thin plats which need to travel vertical distances many times +their own thickness. Setting the origin key is simply an alternate +method to using an origin brush. When using the model2 key, the +origin point of the model will correspond to the origin point +defined by either the origin brush or the origin coordinate +value. + + + +

Design Notes: + +
     Clip brushes can be used to create the +additional size for "thin" plats. Func_plats were pulled from all +maps in the final build of Quake 3 Arena due to some problems in +their operation, particularly as it related to bot function.  +The id designers recommend using plats with care and that plats be +built as "solid" pillar-like lifts (more like those in Doom). + +
     There is a way to make plats play +proper sounds. Just create a sound\movers\plats folder under baseq3 +and put 2 sounds named pt1_start.wav and pt1_end.wav in it. Those +can be the renamed sounds from the Q2 plats or renamed copies of +the sound\movers\doors sounds you can extract from your pak0.pk3 +file or new custom sounds if you're up to it. Thanks to Fragzilla +for the tip.
+ + + +

func_rotating
+ +Map Entity Color: Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: Solid entity that rotates continuously. +Rotates on the Z axis by default and requires an origin brush. It +will always start on in the game and is not targetable. + + + +

Keys + +
speed: determines how fast entity rotates (default +100). + +
noise: path/name of .wav file to play. Use looping sounds +only (eg. sound/world/drone6.wav). + +
model2: path/name of model to include (eg: +models/mapobjects/bitch/fembotbig.md3). + +
origin: alternate method of setting XYZ origin of +entity's rotation axis and .md3 model included with entity (default +"0 0 0" - See Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
X_AXIS: entity will rotate along the X axis. + +
Y_AXIS: entity will rotate along the Y axis. + + + +

Notes + +
You need to have an origin brush as part of this entity. The +center of that brush will be the point through which the rotation +axis passes. Setting the origin key is simply an alternate method +to using an origin brush. It will rotate along the Z axis by +default. You can check either the X_AXIS or Y_AXIS box to change +that + + + +

func_static
+ +Map Entity Color: N/A + +
Dimensions: Determined by components + +
Game Function: Static solid bspmodel. Can be used for +conditional walls and models for different game types. + + + +

Keys + +
model2: path/name of model to include (eg: +models/mapobjects/bitch/fembotbig.md3). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
When using the model2 key, the origin point of the model will +correspond to the origin point defined by either the origin brush +or the origin coordinate value. Because the map has only a single +bot navigation file, Func_Statics cannot be used to make +significant changes in game play flow between differing game +types. + + + +

func_timer
+ +Map Entity Color: Dark blue (0.3 0.1 0.6) + +
Dimensions: (-8 -8 -8) (8 8 +8) + +
Game Function: Time delay trigger that will continuously +fire its targets after a preset time delay. The time delay can also +be randomized. When triggered, the timer will toggle on/off. + + + +

Keys + +
wait: delay in seconds between each triggering of its +targets (default 1). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
target: this points to the entities to trigger. + +
targetname: a func_button or trigger that points to this +will toggle the timer on/off when activated. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
START_ON: timer will start on in the game and +continuously fire its targets. + + + +

Notes + +
When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

func_train
+ +Map Entity Color: (0 .5 .8) + +
Dimensions: Determined by +components + +
Game Function: Trains are moving solids that follow a +string of path_corner entities. Trains in Q3A are very basic, they +also require an origin brush (see Notes). + + + +

Keys + +
speed: speed of displacement of train (default 100 or +overridden by speed value of path). + +
target: this points to the first path_corner of the path +which is also the spawn location of the train's origin. + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of the +train's brush(es) and .md3 model included with entity (See +Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
1. Trains always start on in the game. + +
2. Trains do not damage the player when blocked. + +
3. Trains cannot emit sound. + +
4. Trains are not triggerable or toggle-able. + +
5. Trains cannot be block-stopped just by getting in their way, +the player must be wedged between the train and another obstacle to +block it. + + + +

Setting the origin key is simply an alternate method to using an +origin brush. When using the model2 key, the origin point of the +model will correspond to the origin point defined by either the +origin brush or the origin coordinate value. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm new file mode 100644 index 00000000..b9ff8fff --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm @@ -0,0 +1,150 @@ + + +Q3Radiant Editor Manual: Appendix B3 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Holdable_* Entities

+ +

holdable_medkit
+ +Map Entity Color: blue (.7 0 1) + +
Dimensions:  (-16 -16 -16) (16 16 16) + +
Game Function:  This is a Medkit that can be picked +up and used (once) later. Brings the player's health back to 100 +when used. Player can only carry one holdable item at a time. + + + +

Keys + +
wait: time in seconds before item respawns after being +picked up (default 60, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SUSPENDED: item will spawn where it was placed in map and +won't drop to the floor.  Bots will only be attracted to +suspended entities if they are reachable by way of a jump pad or +launch pad (trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random).*/ + + + +

holdable_teleporter
+ +Map Entity Color: blue (.7 0 1) + +
  Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Teleporter item that can be picked up and +used (once) later. Teleports the player to a random player spawn +point when used. Player can only carry one holdable item at a +time. + + + +

Keys + +
wait: time in seconds before item respawns after being +picked up (default 60, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SUSPENDED: item will spawn where it was placed in map and won't +drop to the floor. Bots will only be attracted to suspended +entities if they are reachable by way of a jump pad or launch pad +(trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has its "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm new file mode 100644 index 00000000..7d60e126 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm @@ -0,0 +1,209 @@ + + +Q3Radiant Editor Manual: Appendix B4 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Info_* Entities

+ +

info_camp
+ +Map Entity Color: Dark green (0 0.5 0) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This atttracts bots which have a camping +preference in their A.I. characteristics. It should be placed at +least 32 units away from any brush surface. + + + +

Keys +
range: number of units that the bot can move away from +camp entity while camping on it. + +
weight: number that is compared against the weight +assigned to all the other camp spots in the map to determine if a +bot chooses to camp there. The value is normalized against all +other weight values. + + + +

Notes + +
Examples of Q3A bots which have a high camping preference are: +Razor, Tank Jr., Grunt, Patriot and Doom. Examples of Q3A bots +which have a low camping preference are: Klesk, Mynx, Sarge, Keel +and Xaero. Info_Camp entities should be reachable by "normal" +means, including relatively non-complex rocket jumps. + +

info_notnull
+ +Map Entity Color: Dark green (0 0.5 0) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Used as a positional target for entities +that can use directional pointing. A target_position can be used +instead of this but was kept in Q3A for legacy purposes. + + + +

Keys + +
targetname: must match the target key of entity that uses +this for pointing. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

info_null
+ +Map Entity Color: Dark green (0 0.5 0) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Used as a positional target for light +entities to create a spotlight effect. A target_position can be +used instead of this but was kept in Q3A for legacy purposes. + + + +

Keys + +
targetname: must match the target key of entity that uses +this for pointing. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

info_player_deathmatch
+ +Map Entity Color: Pink (1 0 0) + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Normal player spawning location for Q3A +levels. + + + +

Keys + +
angle: direction in which player will look when spawning +in the game. Does not apply to bots. + +
target: this can point at a target_give entity for +respawn freebies. + +
nobots: when set to 1, bots will never use this spawn +point to respawn in the game. + +
nohumans: when set to 1, human players will never use +this spawn point to respawn in the game. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
INITIAL: makes the spawnpoint the initial place for the player +to spawn at the beginning of the game. This is also where the +player spawns as a spectator. + + + +

Design Tip: If you include an +info_player_deathmatch entity in a CTF map, players from both teams +can respawn at that location. Great for placing respawn spots in +contested central battleground areas.
+ +

info_player_intermission
+ +Map Entity Color: Pink (1 0 1) + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Camera for intermission screen between +matches. This also automatically generates the podium for bot arena +matches (see Notes). Can be aimed by setting the "angles" key or +targeting an pointing to an aiming entity. Use only one per +level. + + + +

Keys + +
angles: alternate "pitch, yaw, roll" angles method of +aiming intermission camera (default 0 0 0). + +
target: point this to an info_notnull or target_position +entity to set the camera's pointing angles. + + + +

Notes + +
In Single Player bot arena matches, the podium for the 1st, 2nd +and 3rd place players at the end of the match is generated by this +entity. The podium's origin will automatically be located 128 units +in the direction of the camera's view and 84 units down from the y +height of the view line at that point. It will also always be +generated on a level plane regardless of the pointing angle of the +camera so if that angle is too steep, part of the podium model +might not be visible. If the origin point of the podium model is +inside brush geometry, the podium will not draw. Make sure you +leave at least 106 units of free space in front of where the camera +points to otherwise the podium model won't be visible at all. + + + +

info_player_start
+ +Map Entity Color: Red (1 0 0) + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Player spawn location. It works in Quake +III Arena, but is not used in the id maps. Use +info_player_deathmatch instead. + + + +

Keys + +
angle: direction in which player will look when spawning +in the game. + +
target: this can point at a target_give entity for +respawn freebies. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm new file mode 100644 index 00000000..29bd4fb6 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm @@ -0,0 +1,487 @@ + + +Q3Radiant Editor Manual: Appendix B5 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Item_* Entities

+ +Most of the properties for item entities are the same and are +listed immediately below. Properties that are unique to specific +entities follow those entries. + + + +

Shared Keys (for all item entities) + +
All the entities in this grouping can have the following +keys. + +

team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Two other keys, wait and count, do not apply to all entities and +are described as they apply to individual entity types. + + + +

Check Boxes/Spawnflags + +
SUSPENDED: item will spawn where it was placed in map and won't +drop to the floor. Bots will only be attracted to suspended +entities if they are reachable by way of a jump pad or launch pad +(trigger_push). + + + +

Notes + +
Team: Just as you would set doors to work together with +the "team" key, you can do the same for item, weapon and ammo +entities. Give each entity in the team the same key value (example: +"team" "powerups"). The game randomly selects which team member +respawns next. You can set your own wait times. You can skew the +weighting towards a particular item by including multiple copies of +it. Example: 1 quad and 2 hastes in a team mean a greater chance +that a haste entity will appear next. + +

The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

item_armor_body
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Red Armor - 100 points of protection. All +armor can be cumulated up to a maximum of 200 points and slowly +decays back to 100 points. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 25, -1 = never respawn). + + + +

item_armor_combat
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Yellow Armor - 50 points of protectiong. +All armor can be cumulated up to a maximum of 200 points and slowly +decays back to 100 points. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 25, -1 = never respawn). + +

item_armor_shard
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Green Armor Shard - 5 points of +protection. All armor can be cumulated up to a maximum of 200 +points and slowly decays back to 100 points. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 25, -1 = never respawn). + + + +

Item_botroam
+ +Map Entity Color: orange + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: An invisible entity that attracts a bot to +it. Used to move bots to parts of a map that might otherwise not be +used. + + + +

Custom Keys + +
Weight: non-zero floating point value, most often in the +range 0 to 400. Very low values are unlikely to attract a bot to +that area, since most bots have "desires" that attract them to +other game entities. (Higher values are allowed but keep in mind +that the bot should also be attracted to normal items. Don't +make the weight value too high. + + + +

Notes + +
The item_botroam entity can be used when a bot does not roam the +whole level or prefers to go to only specific areas. But don't +confuse these items with "way points". They are more like magnets. +This (invisible) item can be placed in a map just like regular +items. Nobody can actually pick up the item it's only used to +attract bots to certain places of the map. The value is the weight +of the roam_item is relative to the weight assigned other items in +the map (each bot has its own weights). The bot character specific +item weights are stored with the bot characters in the +botfiles/bots/ sub-folder in the .pk3 file. + +

When a bot should never go for a specific item the key "notbot" +with value "1" can be used for that item. This key with value can +be used for every available item in Quake III Arena. + +

Design Tip: Wait to place these items until you've done a +significant amount of live play testing on the final map against +bots. Observe a bot-only match. See which parts of the map they +DON'T use frequently. Use bot_roam entities to encourage the +bots to follow more paths through the map. Example: In one of id's +CTF maps, it was eventually observed that bots were most likely to +use only one entrance when assaulting the base. Placement of +item_botroam entities along the other entrance paths might have +solved this.
+ + + +

item_enviro
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Battle Suit power-up. Lasts 30 seconds. +Battle suit provides full protection against explosion radius +damage, slime, and lava damage. It gives partial protection against +falling, and direct rocket hits. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds that power-up will last when +picked up (default 30). + + + +

item_flight
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Flight power-up. Lasts 60 seconds. Will +not appear in single player games. Bots do not understand its +use. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 60). + + + +

item_haste
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Speed power-up. Makes player run at double +speed for 30 seconds. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + + + +

item_health
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Yellow cross bubble - 25 Health. Cannot be +picked up over 100 health. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 35, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 25). + + + +

item_health_large
+Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Gold cross bubble - 50 Health. Cannot be +picked up over 100 health. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 35, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 50). + + + +

item_health_mega
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Blue M bubble - 100 Health. Adds 100 +health points to current health up to a maximum of 200. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 40, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 100). + + + +

item_health_small
+ +
Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Green cross bubble - 5 Health. Can be +picked up to give over 100 health but slowly decays back to +100. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 35, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 5). + +

item_invis
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Invisibility power-up. Lasts 30 +seconds. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + +
team : set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + + + +

item_quad
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Quad Damage power-up (3 times damage). +Lasts 30 seconds. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + + + +

item_regen
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Health Regeneration power-up. This will +boost your current health by 5 points every second up to a maximum +of 200. The boost continues for a period of 30 seconds. Aftewards, +any health points over 100 slowly decay back to 100. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + +

Light Entity

+ +

light
+ +Map Entity Color: bright green  (see Notes) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Non-displayed light entity. The default +condition emits white light in all directions at a value of 300. +The apparent brightness of the light is modeled on "real world" +physics, so the falloff in brightness willl be an inverse square of +distance from the source. It can be colored. It can be targeted on +an info_null entity to make a spotlight. + + + +

Keys + +
light: value of light intensity (default 300). + +
_color: weighted RGB value of light color (default white +- 1 1 1). + +
target: point this to an target_position, info_null or +info_notnull to create a spotlight effect. + +
radius: sets radius of light cone for spotlights (default +64) in game units. Radius measurement is made at the targeted +entity. Light must target an info_null entity (info_nulls are only +used by the compiler and need not be "remembered" by the game +engine during play). + + + +

Check Boxes/Spawnflags + +
LINEAR: light falloff will be linear instead of inverse square +of distance from source. + + + +

Notes + +

  • Linear fall off will not make much difference on low value +lights. Useful on high value lights where the light travels long +distances. + +
  • If the "Light drawing" preference is selected (under +Preferences), the editor shows the light entities as diamond shaped +pieces the color of the light they cast. If not, they are light +yellow green cubes.
+ + +

Coloring Lights + +
To quickly change the color of a light entity, use on of the +following methods. + +

  1. CTRL + k:  With the entity +window open, select a light entity in either the map or camera +window. Press CTRL + k. This brings up the windows color selector. +Select a color and choose "OK".  The editor automatically +normalizes the light colors. + +
  2. Sample Texture: Select the light +entity. Select a texture in either the texture window or the camera +window.  Hit SHIFT + middle mouse button. + +
  3. Manual Entry: Type in the value +for the key _color as a 3 numbers between 0 and 1 (inclusive). + +
  4. Copy Existing: Select another +light entity whose color value the user would like to duplicate. In +the editor window, lef click on the key "_color". Now select the +light entity to be colored. Hit ENTER.
+ + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm new file mode 100644 index 00000000..e1dfcb06 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm @@ -0,0 +1,332 @@ + + +Q3Radiant Editor Manual: Appendix B6 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Misc_* Entities

+
misc_model
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Generic, one-size-fits-all placeholder for +inserting .md3 models in game. Requires compilation of map geometry +to be added to level. + +

Keys + +
angle: direction in which model will be oriented. + +
model : path/name of model to use (eg: +models/mapobjects/teleporter/teleporter.md3).*/ + + + +

Notes + +
This is a premade mesh model, created in a program like +Kinetix's 3d Studio Max. It is a static (non-animating) +model.  Shaders can give it the appearance of motion, but no +animation.  The models should be stored in a directory with +the pathname: models/mapobjects. The process by which models are +made is not a part of this document. Currently, models only have +rotation on the Z axis. + +

Models do not "clip" against players or weapon +hits. They are entirely non-solid. If clipping is important, The +user will need to build clip brushes that are roughly the size and +shape of the models. + +

Do not use the flip or rotate tools on models. Only use the +entity facing buttons or manually change the angle value. The +purple "3d crosshair" is the origin point of the model. + +

Make it: Right mouse press on a map window to bring up +the floating entity selector.  Select misc_model. A selection +dialogue box will open giving access to available .md3 files.  +Select the one you want and it will load into the map.  Now, +hit "n" to open the entity window. Click on the "model" key in the +key list box. Now edit the value field to remove part of the +line. + +

Example: "c://program files/quake III +arena/baseq3/models/mapobjects/storch.md3" + +

… should be edited to read: + +

"models/mapobjects/storch.md3" + + + +

misc_portal_camera
+ +Map Entity Color: light orange + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Portal camera. This camera is used to +project its view onto a portal surface in the level through the +intermediary of a misc_portal_surface entity. Use the "angles" key +or target a target_position or info_notnull entity to set the +camera's pointing direction. + + + +

Keys + +
angles: this sets the pitch and yaw aiming angles of the +portal camera (default 0 0). Use "roll" key to set roll angle. + +
target: point this to a target_position entity to set the +camera's pointing direction. + +
targetname: a misc_portal_surface portal surface +indicator must point to this. + +
roll: roll angle of camera. A value of 0 is upside down +and 180 is the same as the player's view. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SLOWROTATE : makes the portal camera rotate slowly along the +axis of camera to target or (selected direction). + +
FASTROTATE : makes the portal camera rotate faster along the +axis of camera to target or (selected direction).. + + + +

Notes +

  • Both the setting "angles" key or "targeting a target_position" +methods can be used to aim the camera. However, the target_position +method is simpler. In both cases, the "roll" key must be used to +set the roll angle. Generally, this is adjusted after compiling the +map at least once. + +
  • If either the SLOWROTATE or FASTROTATE spawnflag is set, then +the "roll" value is irrelevant.
+ + + +

misc_portal_surface
+ +Map Entity Color: light orange + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Portal surface indicator. This will "lock +on" the brush face closest to it and identify as a portal. The view +displayed on the portal surface is the view of the +misc_portal_camera that this entity targets. Also used for mirrors +(see Notes). + + + +

Keys + +
target: point this to a misc_portal_camera that "sees" +the view you want to display on the portal. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • The entity must be no farther than 64 units away from the portal +surface to lock onto it. + +
  • To make a mirror, apply the common/mirror shader to the surface, +place this entity near it but don't target a +misc_portal_camera. + +
  • When used as a mirror, the mirror surface will display what the +entity can "see."
+ + + +

misc_teleporter_dest
+ +Map Entity Color: red + +
Dimensions: (-32 -32 -24) (32 32 -16) + +
Game Function: Teleport destination location point for +trigger_teleporter entities. A "target_position" can also be used +for this. + + + +

Keys + +
angle: direction in which player will look when +teleported. + +
targetname: make the trigger_teleporter point to +this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
In most cases, this is replaced by the "target_position" +entity. + +

Path_* Entities

+ +

path_corner
+ +Map Entity Color: brown + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Path corner entity that define the routes +that func_trains can be made to follow. + + + +

Keys + +
target: point to next path_corner in the path. + +
targetname: the train following the path or the previous +path_corner in the path points to this. + +
speed: speed of func_train (in game units per second) +while moving to the next path corner. This will override the speed +value of the train. + +
wait: number of seconds func_train will pause on path +corner before moving to next path corner (default 0 - see +Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • Setting the wait key to -1 will not make the train stop on the +path corner, it will simply default to 0. + +
  • The center of the origin brush in the func_train follows the +path.
+ + + +

Shooter_* Entities

+ +
shooter_grenade
+ +Map Entity Color: red-violet + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will shoot a grenade each time it's +triggered. Aiming is done by setting the "angles" key or by +targeting an info_notnull or target_position entity. + + + +

shooter_plasma
+ +Map Entity Color: red-violet + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will shoot a plasma ball each time +it's triggered. Aiming is done by setting the "angles" key or by +targeting an info_notnull or target_position entity. + + + +

shooter_rocket
+ +Map Entity Color: red-violet + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will shoot a rocket each time it's +triggered. Aiming is done by setting the "angles" key or by +targeting an info_notnull or target_position entity. + + + +

Keys + +
angles: this sets the pitch and yaw aiming angles of +shooter (default 0 0). The roll angle does not apply. + +
targetname: activating trigger points to this. + +
target: this points to a target_position entity for +aiming the grenades. + +
random: random aiming variance in degrees from the +straight line to the targeted entity (default 0 - see Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in "Teamplay" and +"CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single Player +mode (bot play mode). + + + +

Notes + +

  • When the random key is set, its value is used to calculate a +maximum angle deviation from the normal trajectory formed by a +straight line between the shooter and the aiming entity it targets. +The final trajectory will be a random value anywhere between no +deviation at all (0) to maximum deviation (value of the random +key). + +
  • Both the setting "angles" key or "targeting a target_position" +methods can be used to aim the shooter. However, the +target_position method is simpler.*/
+

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm new file mode 100644 index 00000000..55d28b31 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm @@ -0,0 +1,637 @@ + + +Q3Radiant Editor Manual: Appendix B7 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Target_* Entities

+ + + +
target_delay
+ +Map Entity Color: aqua + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: The target_delay trigger is an +intermediary time delay trigger. Like a target_relay (see below), +this can only be fired by other triggers which will, in turn, cause +it to fire its own targets + + + +

Keys + +
targetname: activating trigger points to this. + +
target: this points to entities to activate when this +entity is triggered. + +
wait: delay in seconds from when this gets triggered to +when it fires its own targets (default approx. 1). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

target_give
+ +Map Entity Color: red + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This is used to give ammo, weapons, health +or items to the player who activates it. + + + +

Keys + +
target: this points to the item(s) to give when +activated. + +
targetname: activating trigger or spawn entity points to +this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • There are 2 ways to use this entity. + +
    1. To automatically give items to players when they spawn +in the game: make a spawn location entity like +info_player_deathmatch or CTF respawn points target this entity, +then make it target the item(s) to give to the player upon +respawn. + +
    2. To give items to players during the game: make a +trigger_multiple target this entity, then make it target the +item(s) to give to the player when the trigger is touched. This is +how the column of health and armor in Q3DM10 works.
    + +
  • Items targeted to be given are not seen in the map.
+ + + +

target_kill
+ +Map Entity Color: gray + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will kill the player who activates +the trigger that fires this target. + + + +

Keys + +
targetname: the activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

target_laser
+ +
Map Entity Color: red + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Generates a red laser beam. I think this +can somehow spawn in the game, I saw it once but it's too +inconsistent to be usable. Commented out. + + + +

Keys + +
angles: alternate "pitch, yaw, roll" angles method of +aiming laser (default 0 0 0). + +
target: point this to a target_position entity to set the +laser's aiming direction. + +
targetname: the activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
START_ON: when set, the laser will start on in the game. + + + +

Notes + +
Since none of the game maps in Quake III Arena used this +function, it is not likely to be a functioning entity. + + + +

target_location
+ +Map Entity Color: Dark Green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Location marker used by bots and players +for team orders and team chat in the course of Teamplay games. The +closest target_location in sight is used for the location. If none +is in sight, the closest in distance is used. + + + +

Keys + +
Message: name of the location (text string). +Displayed in parentheses in front of all team chat and order +messages. Shorter is better. + +
count: color of the location text displayed in +parentheses during team chat. Set to 0-7 for color. + +

    0 : white (default) + +
    1 : red + +
    2 : green + +
    3 : yellow + +
    4 : blue + +
    5 : cyan + +
    6 : magenta + +
    7 : white
+ +notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Design Tips: The target locations are "line-of-sight." If +a player can "see" it, and that target is the closest to the +player, then that location message is displayed. Be +conservative in placing location markers. Because of the way the +location code is implemented, it causes a large amount of data to +be transmitted regularly. It has been explained that the game +serrver has to constantly keep track of, and update to the clients, +a data table equal to all the location markers multiplied by all +the players. Not only that, but it must calculate line of sight +from players to location markers and calculate the distance from +the location marker. + +
   Place the target locations in such a way that the entity can be +"seen" from most, if not all, the positions that a player can stand +in when it is inside that area. Fewer are better, even if it +means that occasionally, a team mate is in an unknown location.
+ +

target_position
+ +Map Entity Color: Dark Green + +
Dimensions: (-4 -4 -4) (4 4 4) + +
Game Function: This is an aiming target for entities like +light, misc_portal_camera, and trigger_push (jump pads and launch +pads) in particular. + + + +

Keys + +
Targetname: the entity that requires an aiming direction +points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
Use this as the target for any entity that must be actively +targeted during the game (do not use it as a target for +spotlights). + +
See Tips, Tricks and Tutorials for the method used to make jump +pads. + + + +

target_print
+ +
Map Entity Color: dark green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will print a message on the center of +the screen when triggered. By default, all the clients will see the +message. + + + +

Keys + +
message: text string to print on screen. + +
targetname: the activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
REDTEAM : only the red team players will see the message. + +
BLUETEAM : only the blue team players will see the message. + +
PRIVATE : only the player that activates the target will see the +message. + + + +

target_push
+ +Map Entity Color: gray + +
Dimensions: (-8 -8 -8) (8 8 8) + + + + + +
Game Function: This is not recommended for creating jump +pads and launch ramps. The direction of push can be set by the +"angles" key or pointing to a target_position or info_notnull +entity. Unlike trigger_push, this is NOT client side predicted and +must be activated by a trigger. + + + +

Keys + +
angles: this sets the pitch and yaw aiming angles of push +entity (default 0 0). The roll angle does not apply. + +
speed: speed of push (default 1000 game units per +second). Has no effect if entity targets an aiming entity. + +
targetname: the activating trigger points to this. Push +originates from the location of the trigger. + +
target: this points to the aiming entity to which the +player will jump. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
BOUNCEPAD : if set, trigger will play bounce noise instead of +beep noise when activated (see notes). + + + +

Notes + +

  • The player will first move from the trigger to the target_push +and then on towards the target_position. + +
  • To make a jump pad or launch ramp, create a trigger_multiple +where the jump must originate. Place the target_push directly above +the trigger_multiple and place the target_position entity at the +highest point of the jump. Target the trigger_multiple to the +target_push and target the target_push to the +target_position/info_notnull (or set the target_push's "angles" +key). + +
  • Note that the "angle" key also +works. + +
  • A target_push can be used to make a wind tunnel push effect (as +opposed to the jump pad effect of a trigger_push). It pushes the +activator in the direction of the angle value or towards its apex, +a targeted target_position entity. + +
  • The default speed is 1000. + +
  • If bouncepad is checked, it will play the bouncepad sound +instead of windfly.
+ + +

Design Tip: + +
There is a way to make the target push play proper sounds. Just +create a sound\movers\plats folder under baseq3 and put a sounds +windfly.wav in it. It can be the sound from the Q2 or your own +custom looping if you're up to it.
+ +

target_relay
+ +Map Entity Color: aqua + +
Map Entity Color: (-8 -8 -8) (8 8 8) + +
Game Function: This can only be activated by other +triggers, which will, in turn, cause it to activate its own +targets. + + + +

Keys + +
targetname: activating trigger points to this. + +
target: this points to entities to activate when this +entity is triggered. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
RED_ONLY : only red team players can activate trigger. + +
BLUE_ONLY : only red team players can activate trigger. + +
RANDOM: one of the targeted entities will be triggered at +random. + + + +

Notes + +
Use this when you need to split off targeting functions along +separate paths. + + + +

target_remove_powerups
+ +
Map Entity Color: blue + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This takes away all item_* type powerups +from player except health and armor (holdable_* items are not taken +away either). This must be activated by a button or +trigger_multiple entity. The player that activates the trigger will +lose any powerup(s) currently in his possession. + + + +

Keys + +
targetname: activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

target_score
+ +Map Entity Color: bright green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This is used to automatically give frag +points to the player who activates this. A spawn location entity +like info_player_* or CTF respawn points can target this entity to +give points to the player when he spawns in the game. Or a trigger +can also be used to activate this. The activator of the trigger +will get the points. + + + +

Keys + +
targetname: activating entity points to this. + +
count: number of frag points to give to player (default +1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

target_speaker
+ +
Map Entity Color: bright green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Sound generating entity that plays .wav +files. Normal non-looping sounds play each time the target_speaker +is triggered. Looping sounds can be set to play by themselves (no +activating trigger) or be toggled on/off by a trigger. + + + +

Keys + +
noise: path/name of .wav file to play (eg. +sound/world/growl1.wav - see Notes). + +
wait: delay in seconds between each time the sound is +played ("random" key must be set - see Notes). + +
Random: random time variance in seconds added or +subtracted from "wait" delay ("wait" key must be set - see +Notes). + +
targetname: the activating button or trigger points to +this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
LOOPED_ON: sound will loop and initially start on in level (will +toggle on/off when triggered). + +
LOOPED_OFF: sound will loop and initially start off in level +(will toggle on/off when triggered). + +
GLOBAL: sound will play full volume throughout the level. + +
ACTIVATOR: sound will play only for the player that activated +the target. + + + +

Notes + +

  • The path portion value of the "noise" key can be replaced by the +implicit folder character "*" for triggered sounds that belong to a +particular player model. For example, if you want to create a +"bottomless pit" in which the player screams and dies when he falls +into, you would place a trigger_multiple over the floor of the pit +and target a target_speaker with it. Then, you would set the +"noise" key to "*falling1.wav". The * character means the current +player model's sound folder. So if your current player model is +Visor, * = sound/player/visor, if your current player model is +Sarge, * = sound/player/sarge, etc. This cool feature provides an +excellent way to create "player-specific" triggered sounds in your +levels. + +
  • The combination of the "wait" and "random" keys can be used to +play non-looping sounds without requiring an activating trigger but +both keys must be used together. The value of the "random" key is +used to calculate a minimum and a maximum delay. The final time +delay will be a random value anywhere between the minimum and +maximum values: (min delay = wait - random) (max delay = wait + +random).
+ + + +

target_teleporter
+ +Map Entity Color: red + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Activating this will teleport players to +the location of the targeted misc_teleporter_dest entity +(target_position can also be used). Unlike trigger_teleport, this +entity must be activated by a trigger and does NOT allow client +prediction of events. + + + +

Keys + +
targetname: activating trigger points to this. + +
target: this must point to a misc_teleporter_dest +entity. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
When you give multiple targets the same target name, the +teleporter will randomly select from one each time it is used. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm new file mode 100644 index 00000000..ec4d957a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm @@ -0,0 +1,352 @@ + + +Q3Radiant Editor Manual: Appendix B8 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Team_* Entities

+ +These entities only function when a team style game is being +played. Most are for Capture the Flag. They do not need to be +marked with notfree, since that is part of their nature. + + + +

team_CTF_blueflag
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Blue team flag for CTF games. + + + +

Notes + +
This cannot be suspended (or the bots won't find it). It must be +reachable by players of both teams, since it is where a player must +return an opponent's flag. + + + +

team_CTF_blueplayer
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Initial Blue team spawning position for +CTF games. This is where players spawn when they join the Blue team +(at the start of a game or upon entering a game in progress). + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

team_CTF_bluespawn
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Blue team respawning position for CTF +games. This is where Blue team players respawn after they get +fragged. + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

team_CTF_redflag
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Blue team flag for CTF games. + + + +

Notes + +
This cannot be suspended (or the bots won't find it). It must be +reachable by players of both teams, since it is where a player must +return an opponent's flag. + + + +

team_CTF_redplayer
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Initial Red team spawning position for CTF +games. This is where players spawn when they join the red team (at +the start of a game or upon entering a game in progress). + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

team_CTF_redspawn
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Red team respawning position for CTF +games. This is where red team players respawn after they get +fragged. + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

Trigger_* Entities

+ +
trigger_always
+ +Map Entity Color: gray + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Automatic trigger. It will fire the +entities it targets as soon as it spawns in the game. + + + +

Keys + +
target: this points to the entity to activate. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
For reliable internet play, make any trigger which can be passed +through at least 32 game units deep. + + + +

trigger_hurt
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: Any player that touches this will be hurt +by "dmg" points of damage once per server frame (very fast). A +sizzling sound is also played while the player is being hurt. + + + +

Keys + +
dmg: number of points of damage inflicted to player per +server frame (default 5 - integer values only). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + +

Check Boxes/Spawnflags + +
START_OFF: if set, the trigger will initially start off in the +game. + +
SILENT: supresses the sizzling sound while player is being +hurt. + +
NO_PROTECTION: player will be hurt regardless of protection (see +Notes). + +
SLOW: changes the damage rate to once per second. + + + +

Notes + +

  • The invulnerability power-up (item_enviro) does not protect the +player from damage caused by this entity regardless of whether the +NO_PROTECTION spawnflag is set or not. + +
  • A trigger_hurt always starts on in the game. + +
  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. +
+ + +

trigger_multiple
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: Variable size repeatable trigger. It will +fire the entities it targets when touched by player. Can be made to +operate like a trigger_once entity by setting the "wait" key to -1. +It can also be activated by another trigger that targets it. + + + +

Keys + +
target: this points to the entity to activate. + +
targetname: activating trigger points to this. + +
wait: time in seconds until trigger becomes +re-triggerable after it's been touched (default 0.2, -1 = trigger +once). + +
random: random time variance in seconds added or subtracted from +"wait" delay (default 0 - see Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + +
  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. +
+ + +

trigger_push
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: This is used to create jump pads and +launch ramps. It MUST point to a target_position or info_notnull +entity to work. Unlike target_push, this is client side +predicted. + + + +

Keys + +
target: this points to the target_position to which the +player will jump. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • To make a jump pad or launch ramp, place the +target_position/info_notnull entity at the highest point of the +jump and target it with this entity. + +
  • This trigger automatically makes the bouncepad sound. + +
  • Speed of travel is determined by the distance needed to reach +the target entity. Longer = faster. + +
  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. +
+ + +

trigger_teleport
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: Touching this will teleport players to the +location of the targeted misc_teleporter_dest or target_position +entities. This entity allows client prediction of events. It is the +preferred method. + + + +

Keys + +
target: this must point to a misc_teleporter_dest entity +or a target_position entity. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. + +
  • When you give multiple targets the same target name, the +teleporter will randomly select from one each time it is used. +
+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm new file mode 100644 index 00000000..5a723bfd --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm @@ -0,0 +1,224 @@ + + +Q3Radiant Editor Manual: Appendix B9 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Weapon Entities

+ +

weapon_bfg
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Big Freaking Gun. Default ammo load +is 20. + + + +

weapon_gauntlet
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Melee weapon. No ammo. There is no +reason to place this entity in a map. + + + +

weapon_ grapplinghook
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Grappling Hook. Spawns in the game and +works but is unskinned. Does not use ammo. + + + +

weapon_grenadelauncher
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Lobs bouncing grenades. Comes with 10 +grenades. + + + +

weapon_lightning
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Also called the "shaft" by some. Comes +with 100 "shocks" + + + +

weapon_machinegun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Player automatically starts with this. +Comes with a default load of 100 "shots." + +

Design Tip: For a "Rocket Arena" type game, the designer +may wish to use the target_give entity to "give" the player an +ammo_bullets entity with a count of -100 to remove the +machinegun from play.
+ + + +

weapon_plasmagun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Comes with 50 shots. + + + +

weapon_railgun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Comes with 10 slugs. + + + +

weapon_rocketlauncher
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Comes with 10 rockets. + + + +

weapon_shotgun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Also called the "shaft" by some. Comes +with 10 rockets. + + + +

Keys + +
wait: time in seconds before item respawns after being +picked up (default 5, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
count: sets the amount of ammo given to the player when +weapon is picked up. + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SUSPENDED : item will spawn where it was placed in map and won't +drop to the floor. Bots will only be attracted to suspended +entities if they are reachable by way of a jump pad or launch pad +(trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + + + +

Worldspawn Entity

+ +
Worldspawn
+ +Only used for the world. You access the worldspawn entity by +selecting any non-entity brush in your map. + + + +

Keys + +
message: text to print at user logon. Used for name of +level. + +
music: path/name of looping .wav file used for level's +music (eg. music/sonic5.wav). This is for a piece of music +with only one part. To make a song play with both an intro and a +looping portion, the following is the correct form for the music +value: + + + +

    music/intro.wav music/loop.wav
+ + + +

ambient: Adds a constant value to overall lighting. Use +not recommended. Ambient light will have a tendency to flatten out +variations in light and shade. + +
_color: This is the normalized formula for RGB +values for ambient light. A value is considered normalized +when it fits in a range between 0 and 1. If you are using a +tool like the Windows color picker, divide the value for each +component of the RGB values by 255. The result will be a +normalized value. + +
gravity: gravity of level (default is normal gravity: +800). +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_c.htm b/docs/manual/Q3Rad_Manual/appndx/appn_c.htm new file mode 100644 index 00000000..eb881f59 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_c.htm @@ -0,0 +1,654 @@ + + +Q3Radiant Editor Manual: Appendix C + + + +

Q3Radiant Editor Manual

+
+

Appendix C: Bot Navigation Files

+ +(Original Document Title: BSP Converter) +
+ + + + + + + + + + + + +
Version:= 1.8
Date:= 2000-01-11
Author:= Mr. Elusive
+ +

Introduction

+ +This appendix is based on documentation that has been released +and updated by Mr. Elusive. It deals with the Navigation file that +must be created in order for the Quake III Arena bots to be +able to navigate and play in game maps. It is not a manual for the +creation of bots. + +

Description

+ +The BSPC tool is used to create AAS files from BSP files. An AAS +file is a file with areas used by the Quake III Arena bot in order +to navigate and understand a map. + +

Installation

+ +Place the BSPC program in your Quake III Arena folder. + +

Usage

+ +Unless you are using a front-end utility, which gives you +check-button access to compiler functions, you will need to run +this program from the command line of your DOS Command Prompt +program. If the command line is not already pointing the Quake +III Arena directory, change directories (cd\quake III +arena). + +

The command line should be formatted as follows: + +

    bspc [-<switch> [-<switch> ...]]
+ +

Example 1: bspc -bsp2aas d:\quake3\baseq3\maps\mymap?.bsp + +
Example 2: bspc -bsp2aas +d:\quake3\baseq3\pak0.pk3\maps/q3dm*.bsp + +

In the first example a "?" is used as a metacharacter variable +to indicate any single keyboard character. This allows you to +compile the latest version of a map ("mymap1" or "mymapb"). + +

In the second example a "*" is used as a metacharacter variable +to indicate any string of keyboard characters. This allows you to +compile the latest version of a map ("mymap1" or "mymapb"). + +

The bot navigation compile process can be further modified by +the use of "switches" that change some of the parmeters used in +compilation. Some of these can be used to compile only +certain features, such as reachability. Others allow the compiler +to use more than a single processor, as is the case with +"threads." + +

Switches: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bsp2aas <[pakfilter/]filter.bsp>= convert BSP to AAS
reach <filter.bsp>= compute reachability & clusters
cluster <filter.aas>= compute clusters
aasopt <filter.aas> = optimize aas file
output <output path> = set output path
threads <X> = set number of threads to X
cfg <filename> = use this cfg file
optimize = enable optimization
noverbose = disable verbose output
breathfirst = breath first bsp building
nobrushmerge = don't merge brushes
freetree = free the bsp tree
nocsg = disables brush chopping
forcesidesvisible = force all sides to be visible
grapplereach = calculate grapple reachabilities
+ +

Several metacharacters may be used in the filter and +pakfilter. + +

+ + + + + + + + + + + + +
*Match any string of zero or more characters
?Match any single character
[abc...]Match any of the enclosed characters; a hyphen can be used to specify a range (e.g. a-z, A-Z, 0-9)
+ +

.pk3 files are accessed as if they are normal folders (whether +they are compressed or not). + +

For instance, use "d:\quake3\baseq3\pak0.pk3\maps/q3dm1.bsp" to +access the map q3dm1.bsp from the pak0.pk3 file. + +

Multiple files may be listed after the switches bsp2map, +bsp2aas, reach, cluster and aasopt. + +

If a BSP file is being converted to an AAS file and no output +path is entered on the command line then the AAS file will +automatically be stored in the same folder as the BSP file. However +if the BSP file was stored in a .pk3 file then the AAS file will be +stored in a folder with the name 'maps' outside the .pk3 file. + +

Updating the Entity Lump

+ +If an AAS file is already available for a BSP file and you ONLY +change the entities inside this BSP file then you only have to +recalculate the reachabilities. This way you can move items, +platforms etc. around without the need to recalculate the whole AAS +file -- which can save quite some compile time. You can recalculate +the reachabilities as follows: + +
    bspc -reach mymap.bsp
+ +

Where mymap.bsp is the BSP file. The mymap.aas file has to be in +the same folder as mymap.bsp or should be in the output folder +specified with the -output option. + +

Keep in mind that as soon as ANY geometry in the map changes +(including b_models and trigger brushes) the whole AAS file HAS to +be recalculated in order to play with bots. + +

Leaks

+ +Just like there can be vis "leaks" in a map there can also be +clipping leaks. Two things can be wrong when the BSPC tool outputs +that a map leaks. + +
  1. + +There are no entities in the map at all, or all entities that are +actually in the map are placed in solid locations (see Test Solid +below). In this case the BSPC tool outputs: "WARNING: no entities +inside." The map must contain at least one player start entity to +load in the game. + +
  2. + +There is a spot in the map where players can go outside the map +into the void. This is bad, players should never be able to fall +out of a level. In this case the BSPC tool outputs: "WARNING: +entity reached from outside." The BSPC tool also writes a mymap.lin +file that can be loaded in the Q3Radiant editor to show lines that +go through the actual leak.
+ +

Make sure the .lin file is stored in the same folder as where +q3radiant stores the .bsp file. Load the map in q3radiant and use +the menu > File > Pointfile... to load the .lin file. +A thick red line will be shown in the map. Follow this line to find +the leak. + +

Useful Map Information

+ +The following information is given as a reference for bot +capabilities. The area file information is used by bots. It tells +them when and where they can make jumps. Human players don't have +this information readily available to them, so you may want to be +more forgiving when designing tricky jumps. + +

Map Boundaries
+ +Currently all the contained area of a Quake III Arena map +should fall within the bounds (8192, 8192, 8192) - (-8192, -8192, +-8192) for the bspc tool to compile. These are the same bounds as +the Q3Map compilers. + +

Game Physics
+ +Player Dimensions + +
Model size: The player model's actual size is a bounding +box 30 units by 30 units square with a height of 56 units. In the +game world, eight units roughly equal one foot (30.5 cm). From +this, we deduce that the characters are a heroic 7 feet tall (2.13 +meters). + +

Step Heights + +
For scale purposes, "normal" steps should be no higher than 8 +units. However, the maximum value that a player may step up is 18 +units (just keep steps 16 units or lower). + +

Normal Jumps + +
The maximum height for barriers the bots will jump on is 32 +units. + +

Water Jump Heights (or "Everyone, out of the pool!") + +
The maximum distance that a bot may jump to exit water is 18 +units. This is the height difference between the water surface and +the adjacent floor that the bot is jumping onto. If the water jump +height is made higher, human players will have a hard time getting +out of the water. + +

Rocket Jumps + +
With normal gravity and without the quad, the maximum rocket +jump height is around 280 units (you can sometimes jump a few units +higher but this is a safe value for reference). In practice, except +for especially tricky jumps, this value should be substantially +lower. Test rocket jumps repeatedly before settling on a +final height. + +

Math for Map Makers + +
Here's some math to calculate some other values of interest: + +

Gravity = 800; + +
Jump velocity = 270; + +
Max vertical rocketjump velocity = 670; + +
Max run velocity = 320; + +
Max step height = 18; + +
Max jump height = 0.5 * gravity * +(jumpvelocity/gravity)*(jumpvelocity/gravity); + +
Max normal jump height = 45 units + +
NOTE: even +though this is the mathematical maximum jump height always keep the +the 32 units maximum barrier height for bots in mind when building +maps. + +
Maximum horizontal jump distance over a gap from one spot +to another when both are at the same height: + +

    t = sqrt((maxjumpheight + maxstep) / (0.5 * gravity)); + +
    t = 0.3986 seconds; + +
    dist = maxrunvelocity * (t + jumpvelocity / gravity); + +
    dist = 235 units;
+ +

Because players use a bounding box we can jump a full bounding +box width further in the ideal case. (15 units at the jump starting +position and 15 at the landing place). + +

    235 + 15 + 15 = 265 units.
+ +

Again, remember that this is the mathematical maximum which +players can only reach under ideal circumstances. + +

Optimizing a Map for bspc Compiling

+ +The area file is the tool that the bots use to understand the +map. If it is overly complex, it can cause navigation problems. +With careful attention to detail, many of these problems can be +eliminated, or avoided altogether. + +

First, understand that hint brushes, which are of great use to +the bsp compiler, have no effect on the bspc tool that creates area +files. Only solid, clip and liquid brushes and curve patches are +used by the bspc tool. Using these mapcomponents, the bspc tool +outputs how many "areas" will be created for a map. Having fewer +areas in a map is better than having more. + +

Quite often, map trim and detail create many of these small +areas. For the most part, these small areas are too small to enter +and are thus useless to the bots. Brushes that project out into the +map's floor cut it up and create additional areas. Often the number +of areas can be greatly reduced by adding additional clip brushes. +Take a look at Q3DM7 in the map editor, and you will see the walls +are literally covered with clip brushes. This not only +smooths out passage for human players, but also has the added +benefit of eliminating unnecesary navigation areas. This is +also why, as many "camping style" players have found, many areas +above door and window trim have also been clipped off. + +

Another way to reduce complexity is to use clip brushes to +simplify the collision area around complex objects. For exmple, the +map maker can add clip brushes with simple shapes (axial or +"square" brushes are prefered) around (small) detail brushes. +Simple shaped clip brushes can also be added around curves to +reduce the collision complexity (for instance, place an axial clip +brush around a small cylinder). It is better to place the clip +brushes around the whole curve (not just part of the curve). The +map maker should also use shader scripts to make the textures on +brushes or curve patches non-solid (surfaceparm nonsolid) when they +are enclosed by (full) clip brushes. This will also speed up bspc +calculations. + +

Always try to align your geometry to the grids. Always use the +largest grid possible for alignment of your geometry. Also try to +align the backsides of brushes which may not be visible. The more +brush sides are aligned the better. This will also speed up bspc +calculations. + +

Align adjacent brushes as much as possible. Make sure that badly +aligned brushes create no tiny faces. + +

Quite often there are also places in a map that are visible to +players but where players can never go (even determined, +rocket-jumping players). If a player could reach that area, they +would be able to walk around upon it. If the mapmaker decides not +to allow that, he or she should use large clip brushes to enclose +the entire unreachable space. This will also speed up bspc +calculations and reduce the number of areas created by the bspc +tool. + +

Note: the number of areas relative to the map size tells +something about the navigation complexity for players in general +(also human players). Reducing the collision complexity for bots +also makes the map easier to navigate for human players + +

Entities & the Navigation File

+ +There are specific rules and guidelines for using a number of +entities and entity-like textures with the bspc tool. + +

Func_plat and Func_bobbing
+ +When func_plat or func_bobbing entities are placed in a map, the +bots will use them if possible. The bots assume they can stand on +top of the bounding box (xy extents of all components used to +create the entity) of the model used for the func_plat or +func_bobbing entity. As a result, creating complex-shaped func_plat +or func_bobbing models is mostly a bad idea. You have to make sure +the bots (and players) can actually stand everywhere on top of the +bounding box of the model. The basic rule: If a bot is going to use +a func_plat or a func_bobbing, make sure the top surface is a +solid, rectilinear rectangle or square. + +

Cluster Portals
+ +Cluster portals are one of the several "texture entities" used +by the game engine. These are textures, which as used by the game +engine, function like entities. The bspc tool divides the map into +many, much smaller areas, which are essentially the surfaces a bot +can move upon during play. Several of these areas can be grouped +together to create a cluster. The clusters are seperated by cluster +portals, which are also areas themselves. One of the things the bot +uses these clusters for is to create a multi-level routing +algorithm. When a map is efficiently divided up into clusters bot +calculations (in run time) will be faster. + +

Guidelines to Consider When Placing Cluster Portals: + +

  • The BSPC tool creates cluster portals automatically, but placing +"clusterportal" brushes can create additional cluster portals. + +
  • Placing "clusterportal" brushes inside the map manually creates +cluster portals. + +
  • The "clusterportal" brushes should not be used outside the world +hull. + +
  • The cluster portals do not have any effect on map vis. + +
  • If a door is already sealed with an areaportal brush, a +clusterportal is not necessary there. (areaportals are used by the +bspc tool as if they were cluster portals). + +
  • Just like the areaportals, the cluster portals must seal a space +off entirely from other areas. + +
  • The cluster portal areas should seal off a cluster in a way that +the only path towards another cluster is through a cluster portal +area. + +
  • Only create cluster portals where people can walk or swim +through. + +
  • Don't create cluster portals in gaps in the floor. (people would +fall through) + +
  • Cluster portals must separate no more and no less than two (2) +clusters. + +
  • Try to create clusters with all the same number of +"reachability" areas. For instance if the map has 5,400 areas try +to create 10 clusters with 540 areas each, or 12 clusters with 450 +areas each, etc. The BSPC tool lists the number of reachability +areas in each cluster. + +
  • Avoid creating clusters with only a few (less than 10) +areas. + +
  • When adding "cluster portal" brushes, try to place them in +places with minimal geometric complexity. For instance place them +inside convex door openings or small hallways (not in front of door +openings). Ideally, the shape of the face through which a player +walks or swims into the cluster portal is the same as the shape of +the face through which a player leaves the cluster portal. Also +ideally, the open space inside the cluster portal brush is +convex. + +
  • Make cluster portals about 16 or 32 units thick.
+ +

"Do Not Enter" Areas
+The Do Not Enter texture is another one of the "texture +entities" that the game engine uses as if they were entities. In +some regards, it is like a clip brush, intended to prevent a bot +from moving into or through it. However, this works more as a +"strong suggestion" and is, in reality, not a physical barrier to +the bot. A simple example of how a bot may enter a "Do Not Enter" +area is knockback. If an explosion tosses a bot about, it may end +up inside a prohibited area. Bots may pass out of such areas, but +they will not actively try to enter them. + +

When bot navigation problems show up or you want to make sure a +bot never tries to go to a certain place use a "do not enter" +brush. + +

Guidelines to consider when placing "Do Not Enter" +brushes: + +

  • The "do not enter" brushes should not be used outside the world +hull. + +
  • The "do not enter" brush is Not a clip brush for the bot. + +
  • The "do not enter" brush is a tool of last resort. Do not use it +unless there are serious navigation problems. + +
  • The number of "do not enter" brushes should be minimized because +these brushes create additional areas for the bots. + +
  • The "do not enter" brush will create a new area that the bot +will try to avoid. However if the bot somehow ends up inside a "do +not enter" area or there is a valid goal (game entity or +item_botroam entity) inside the "do not enter" area then the bot is +allowed to go into and out of that area. So if the bot somehow gets +in a "do not enter" area the bot will be able to get out.
+ +

Bot Control Entities
+ +These entities encourage a bot to move about and use more parts +of the map. + +

Item_botroam +
The item_botroam entity can be used when a bot does not roam the +whole level or prefers to go to only specific areas. This +(invisible) item can be placed in a map just like regular items. +Nobody can actually pick up the item. It's only used to attract +bots to certain places of the map. + +

The item_botroam has a key "origin" that is set by Q3Radiant +automatically. + +

The item_botroam also has a key "weight." The value is the +weight of the roam item and is relative to the weight of other +items in the map, which are individual to each bot. The bot +character-specific item weights are stored with the bot characters +in the botfiles/bots/ sub-folder in the .pk3 file. The value of the +weight is a non-zero floating-point value, most often in the range +0 to 400. Higher values are allowed but keep in mind that the bot +should also still go for normal items, so don't make the +item_botroam weight too high. + +

"Notbot" Means "Don't Touch" + +
When a bot should never go for a specific item, the key +"notbot" with a value of "1" can be used for that item. This +notbot key and its value can be used for every available item in +Quake III Arena. + +

Info_Camp + +
This entity suggests locations where the bot can wait for +enemies to come into view. + + +

Suspended + +
The suspended checkbox flag can be used on all items +(item_botroam included). However keep in mind that when a suspended +item is not anywhere near the ground the bot will ONLY try to go +for this suspended item using jump pads. + +

Testing .AAS files

+ +
Solid Areas
+ +A solid area in the map is an area that looks empty to the human +player, but is solid, like a wall, to a bot player. One of the +easiest ways to test the AAS file for solid areas is to load the +map in Quake III Arena in teamplay mode (type /set +g_gametype 3 on the console before loading the map). Enter a team +and add a bot to your team. Use the team order menu (by default +bound to the F3 key) to command the bot to follow you. Walk around +the map and see if the bot is able to follow you everywhere. If a +bot stops at any point, it may have encountered an area of the map +that appears to be unblocked to you, but to the bot, it is like it +has encountered a solid wall. + +

Test Solid + +
In most cases, solid areas are the result of careless design. +But, if you insist on making maps that are not axial in layout +(say, your average cave), they can result from brushes meeting at +non-axial angles. These "map bugs" can sometimes cause certain +places in the map to show up solid in the AAS file. To test for +these solid places set the cvar bot_testsolid to "1" on the +console. (type /set bot_testsolid 1) + +

As you walk through the map, either "empty area" or "SOLID area" +will be printed on the screen while traveling through a map. + +

The Culprits: What May Cause Map Bugs + +
Several map bugs can cause these solid places in the AAS +file. + +

  • Sometimes microscopic brushes are created by CSG subtraction on +one or more brushes. Search for such brushes in the problem area +and delete them. + +
  • Tiny brush faces (not curves) can also cause problems. Due to +vertex snapping in the q3map tool, those tiny brush faces can be +snapped out of existence. Such faces will not show up in Quake +III Arena and you'll see tiny peek holes or slits where you can +view through the geometry (often into other rooms). Align vertexes +of adjacent brushes to remove and avoid such tiny faces. Placing a +clip brush in front of the face that is snapped out of existence +will also remove the "solid area" but of course it's preferred to +remove the peek hole or slit. Another cause could be a brush with a +collapsed side. Check how many sides a brush has and how many sides +actually have a surface. Rebuild brushes with collapsed sides. + +
  • Lava creates a solid area. All faces contained within liquid +brushes using a shader without "surfaceparm trans" set will be +removed (this includes some lava textures). Those contained +surfaces will not be visible and can cause the liquid to appear +"solid" in the aas file.
+ +

Hacking Away the Problem + +
If you insist creating an .AAS file for a map with bugs, then +the BSPC compile option -forcesidesvisible can be used. This +should fix all the problems with areas showing up solid in the .AAS +file. However creating an .AAS file with this option takes a lot +longer (often more than twice the normal compile time). This is not +recommended as a default option for compiling. + +

Testing Jump and Launch Pads + +
Jumppads can also be tested. Type the following on the Quake +III Arena console, before loading your map: + +

/set bot_maxdebugpolys 1024 + +
/set bot_visualizejumppads 1 + +
/set bot_forcereachability 1 + +

Now load the map. A counter will be shown and goes from 0% to +100%. When the counter has reached 100% type /set r_debugSurface 2 +on the console. For every jumppad the default arc of travel +(without using air control) will be visualized. + +

Version Changes

+ +1.8 (2000-01-08) + +
- increased max points on winding + +
- made "HashVec: point x y z outside valid range" non-fatal + +
- fixed rocket jump reachabilities + +
- added force sides visible option + +
- increased simulated stack size for area traces + +

1.7 (1999-12-22) + +
- fixed ducked bounding box size + +
- fixed sv_maxsteepness being zero in aas configuration + +
- AAS files are now automatically stored in BSP file folder + +
- fixed crash bug caused by overflow of a simulated stack + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_d.htm b/docs/manual/Q3Rad_Manual/appndx/appn_d.htm new file mode 100644 index 00000000..a4650ca3 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_d.htm @@ -0,0 +1,243 @@ + + +Q3Radiant Editor Manual: Appendix D + + + +

Q3Radiant Editor Manual

+
+

Appendix D: Tricks, Tips, and Tutorials

+ +

Making the death fall sound…

+ +The death yell that occurs when a player or bot falls into the +void or fog of death is triggered by the falling character passing +through a trigger multiple (should be no less than 32 units thick) +that is targeted on a target_speaker. If you look at q3DM17 +and find a target speaker, you will see that it plays the falling +to death sound of the player who activates the trigger. Put +that sound in your own target_speaker. + +

Making a Mirror …

+ +Apply a mirror texture to brush (it will only work on brushes, +not curve patches). Next, place a misc_portal_surface entity within +64 units of the mirror and at roughly eye level for the character. +Because a mirror shows all that it can "see" the mapmaker needs to +take special care that his mirror doesn't see so much of the map +that it affects game performance. + +
    Rules: A mirror should not be able to see another +mirror or portal surface. This means no mirror mazes or +mirror facing each other to produce infinite reflections.
+ +

Making a Jump Pad

+ +
  1. Make the brush that contains your pulsing pad texture. It can be +set in the floor or raised up on separate brush. + +
  2. Make a trigger_push brush entity that is smaller than the pad +(the id triggers are usually octagonal). + +
  3. Create a target_position entity and move it to the height and +location you want. The target position is both the aiming point for +the trigger_push and the highest point (apex) of the assisted +jump. + +
  4. Hi-light the trigger first, then the target_position (order is +important). + +
  5. Press CTRL + k to connect the two entities (pointing the first +at the second). + +
  6. Compile and test it. The first compile needs to be a full or +fast vis. If you need to make adjustments to the target_position, +you only need to use an entities compile.
+ +

Lining Up the Pad Texture
+ +The combination of shader keys that make the jump pad pulsing +texture work can be tricky to line up. Try the following methods if +your own attempts bring no joy. + +
  1. Make the brush that will be your pad (128x128 units). + +
  2. Apply the pad texture. If it doesn't line up, turn off the lock +texture feature and move the pad until it lines up perfectly. + +
  3. Lock the texture and move the brush into position.
+ +

If that doesn't work: + +

  1. Build your brush in place. + +
  2. Apply the pad texture so that several corners of the pad circle +are visible. + +
  3. Compile a regioned area with the jump pad in it. + +
  4. At least one of the pad circles should have a pulsing circle in +it. + +
  5. Back in the editor, slide the pad circle with the active pulse +so it fills the pad. + +
  6. Recompile. It should work now.
+ +

Making a Launch Pad

+ +Target the trigger_push that you put above the pad at a +target_position. The player will accelerate until he reaches the +target. Physics does the rest. + +

Note: The center point of the target must be +higher than the center point of the trigger_push. + +

Making a "Rocket Arena" style map

+ +
  1. Create all the entities you want the player to spawn with when +he enters the arena, and make sure they are somewhere within the +enclosed space of the map. + +
  2. Add a "target_give" entity somewhere in the world. + +
  3. Create all the spawn spots you want to be in your map. + +
  4. Select the "target_give" entity. + +
  5. Select one of the "give on spawn in" entities. + +
  6. Hit Ctrl-K in the editor to link the two items together. + +
  7. Repeat steps 4 through 6 until the target_give is linked to +all +the entities you wish the player to spawn into the world with. + +
  8. Select a spawn spot + +
  9. Select the target_give entity + +
  10. Hit Ctrl-K in the editor to link the two entities together. + +
  11. Repeat steps 8 through 10 until all the spawn spots are linked +to +the target_give entity. + +
  12. Compile the map + +
  13. Set g_gametype to tournament mode and set fraglimit of 1. + +
  14. Get a bunch of your friends to connect into your server and +have +fun playing a "Rocket Arena" style game =)
+ +

An alternate use of target_give is how I used it in q3dm10 to +create the +"power tube" that gives you health and armour. The tube has a +trigger_multiple with a wait of 0.5, linked to a target_give which +is linked +to a small health and an armour shard. + +

Making an Environment Box …

+ +This is the shader script taken from the sky.shader that I used +to make a test sky box months and months ago. + + + +

In baseq3, make an 'env' folder. + +

Put your skybox art in here and use this naming +convention: + +

[skyname]_lf.tga + +
[skyname]_rt.tga + +
[skyname]_ft.tga + +
[skyname]_bk.tga + +
[skyname]_up.tga + +
[skyname]_dn.tga + +

  • Make a directory in your quake3 folder with the following path: + +
      quake3/baseq3/textures/[mymapname]
    + +
  • Make a directory in your quake3 folder with the following path: + +
      quake3/baseq3/scripts
    + +
  • Make a script document called [mymapname].shader + +
  • Make a script document called shaderlist.txt
+ +

In shaderlist.txt put [mymapname] on the first line and close +the document. + + + +

+//*******************************************************
+//*	    Sample environment box shader
+//*******************************************************
+
+textures/[mymapname]/[skyname]01
+
+{
+	qer_editorimage textures/[mymapname]/[skyname]
+
+	surfaceparm noimpact
+	surfaceparm nolightmap
+	surfaceparm sky
+	q3map_sun 0.933333 0.541176 03.13725 60 160 11
+	q3map_surfacelight 100 //lots of diffuse light
+	skyparms - 512 -
+	sky env/[skyname]
+
+// the following stuff lays clouds over the skybox map which you may not want with a city skyline
+	//{
+	// map textures/skies/dimclouds.tga
+	//
+	// tcMod turb 0 0.001 0.5 0.001
+	// tcMod scale 3 3
+	// tcMod scroll 0.01 0.01
+	// blendFunc GL_ONE GL_ONE_MINUS_SRC_COLOR
+	// depthWrite
+	//}
+	//{
+	// map textures/skies/pjbasesky.tga
+	// blendfunc GL_ONE GL_ONE
+	// tcMod scroll -0.01 -0.01
+	// tcMod scale 5 5
+	//}
+//}
+ +

Making a Shooter

+The shooters; shooter_rocket, shooter_grenade, and +shooter_plasma all fire a single projectile when they are triggered +by an event. + +
  • Make a shooter entity (rocket, grenade or plasma) + +
  • Give it a facing (1 to 360 degrees), or, + +
  • Target it at a target_position. + +
  • Give it a random value (potential degrees off target) + +
  • Create an Activator. Make a trigger multiple or target an entity +at the shooter. When the trigger is entered or the entity is taken, +the, shooter is activated. + +
  • If you want a shooter to fire multiple times, target the +activator on two or more target_delays. Set the delay time to a +different value for each (if using a trigger multiple, the WAIT +value on the trigger should be greater than the longest delay on +the target_delay). Target each target_delay on the shooter.
+ +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_e.htm b/docs/manual/Q3Rad_Manual/appndx/appn_e.htm new file mode 100644 index 00000000..d243d327 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_e.htm @@ -0,0 +1,225 @@ + + +Q3Radiant Editor Manual: Appendix D + + + +

Q3Radiant Editor Manual

+
+

Appendix E: Online Resources

+ +The Internet is an excellent source for information about Quake +engine editing.  The sites listed here provide a variety of +useful editing resources. + +

Disclaimer: Most of these sites are established, heavily +trafficked web pages with a history of stability. But, because +these sites are not maintained by id Software, we make no claims +that they will be there when you go looking for them or that they +will still have the information of the type you are seeking.
+ +

News about the Editor

+ +
QERadiant.com
+ +Qeradiant.com is the official site for the id editing tool that +was the predecessor of Q3Radiant. + +
http://www.qeradiant.com/ + +

MapCenter
+ +A great online forum based resource for models, skinning, textures, and mapping in many different games. + +
http://www.map-center.com + + +

Quake3World.com
+ +Looking for a heavily trafficked message board where questions +often get answered by the id designers? Look no further than the +community section of Mplayer's Quake3World.com. + + +http://www.quake3world.com/ + +

Editing Tutorials

+ +These tutorials are located at several sites that have been +around for a while, and may continue to be around. + +

Tram Design
+ http://www.planetwolfenstein.com/tramdesign/index.html + +
Tutorials and files for Return To Castle Wolfenstein editing. + +

Claudec's Lair of Shaders
+ + +http://www.claudec.com/lair_of_shaders/ + +
Numerous tutorials on editing subjects. + +

RiceBug.Com
+ + +http://ricebug.qeradiant.com/ + +
Some good tutorials on Q3Radiant (the Quake 3 editor) and QERadiant (the Quake 2 +editor). + +

RUST - Game Design.net
+ + +http://www.gamedesign.net/ + +
RUST has been a prime source for Quake engine editing for some +time. + +

Editing Tools

+ +

GenSurf
+ + +http://tarot.telefragged.com/gensurf/index.shtml + +
GenSurf is a "natural" terrain creation tool that converts a +grayscale bitmap into a web of triangular brushes or curve patches. +Used with care, it can make some very interesting irregular +surfaces. + +

Milkshape 3D
+ + +http://www.swissquake.ch/chumbalum-soft/home.html + +
This is a shareware editor for 3D models. Support for Quake +III Arena's native md3 format is forthcoming. + +

Quake 3 Arena Shader Editor
+ + +http://www.larian.com/rat/q3ase.html + +
This is a tool for editing shaders. It allows you to construct +the shader in realtime, seeing what works you build it. + +

Prefab Sources

+ +
Gamedesign.net Prefabs
+ +http://prefabs.gamedesign.net/game.php3?game_id=13&num=0 + +
This Rust's source for prefabricated map plug-ins. These here +are in the form of .map files instead of Quake III Arena's +native .pfb format. + +

Quake Prefab Park 2
+ + +http://www.planetquake.com/qpp/qpp2/ + +
These are prefabs designed for use with Quake and +Quake 2, which means the ones with movement or action gimmicks +most likely will not work. And of course, you'll need to +retexture anything you find here if it's not a Quake III +Arena prefab. + +

Texture Sources

+ +The following sites include shader documents, downloadable +textures, tutorials or links to tutorials on making your own. + +

Shaderlab - Robot Life
+http://www.shaderlab.com + +
This site has a nice selection of textures and shaders to go with them. + +

[h f x]
+http://www.planetquake.com/hfx/ + +
This is a fantastic source for textures and shaders as well. + +

Mean Arena
+ + +http://www.planetquake.com/meanarena/Q3_textures.html + +
This site has a few texture sets to choose from. + +

Quake III Arena Shader Manual
+ + +http://www.planetquake.com/polycount/resources/quake3/tutorials.shtml + +
+http://www.quake3world.com/files/Q3Ashader_manual.doc + +
This is the official id documentation of Quake III Arena +shaders. The second source is a download. + +

Texture Forest
+ + +http://www.planetunreal.com/forest/main1.html + +
It is possible to learn some tricks from artists who work for +that "other" game engine. + +

Map Object Model Sources

+ +
F.P.S.
+http://fps.brainerd.net/ +
Tons of Quake 3 stuff. The best part though is the map models section. A whole lot of them at this site. + +

Polycount
+ + +http://www.planetquake.com/polycount/resources/quake3/index.shtml + +
This link takes you to the resource page for Quake III Arena +modeling. + +

Frequently Asked Questions (FAQ)

+ +
Developer's FAQ (Quake3mods)
+ + +http://www.q3seek.com/edit.php3 + +
This site answers a lot of questions about map making, model +making, texturing and skinning. Mod makers appear to have +submitted much of the information. + +

Official Quake III Arena FAQ (Quake3world.com)
+ + +http://www.quake3arena.com/faq/ + +
This is the official FAQ, created and maintained by id Software. +Most of the information pertains to general problems players +encounter with Quake III Arena, and doesn't have a lot to do with +map making. + +

RUST - Game Design.net
+ + +http://www.gamedesign.net/quake3/faq/ + +
This development-oriented site has a Quake III Arena FAQ though at the moment it's not particularly helpful. + +

Map Reviews, General Information

+ +
LVL - Q3A Edition
+ + +http://www.planetquake.com/lvl/ + +
A great level review site. It also has a great beta section for people to beta test your maps before you release and get you some feedback to make it one of the best levels out there. + +

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_f.htm b/docs/manual/Q3Rad_Manual/appndx/appn_f.htm new file mode 100644 index 00000000..0458dd6b --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_f.htm @@ -0,0 +1,144 @@ + + +Q3Radiant Editor Manual: Appendix F + + + +

Q3Radiant Editor Manual

+
+

Appendix F: Default Key Shortcuts

+ +On the odd chance that you (like the author of this manual) might seriously mess up your default key bindings when making an .ini file, here are the default assignments to correct your mistake. Copy these below the [commands] line of your .ini file. + +

HideSelected			H
+ShowHidden			Shift + H
+BendMode			B
+FitFace				Control + B
+FitBrush			Shift + B
+FreezePatchVertices		F
+UnFreezePatchVertices		Control + F
+UnFreezeAllPatchVertices	Shift + Control + F
+ViewTextures			T
+ThickenPatch			Control + T
+MakeOverlayPatch		Y
+ClearPatchOverlays		Control + Y
+SurfaceInspector		S
+PatchInspector			Shift + S
+ToggleShowPatches		Shift + Control + P
+ToggleShowPatches		Control + P
+RedisperseRows			Control + E
+RedisperseCols			Shift + Control + E
+InvertCurveTextureX		Shift + Control + I
+InvertCurveTextureY		Shift + I
+InvertCurve			Control + I
+IncPatchColumn			Shift + Control + PLUS
+IncPatchRow			Control + PLUS
+DecPatchColumn			Shift + Control + SUBTRACT
+DecPatchRow			Control + SUBTRACT
+Patch TAB			TAB
+Patch TAB			Shift + TAB
+SelectNudgeDown			Alt + DOWN
+EntityColor			K
+CameraForward			UP
+CameraBack			DOWN
+CameraLeft			LEFT
+CameraRight			RIGHT
+CameraUp			D
+CameraDown			C
+CameraAngleUp			A
+CameraAngleDown			Z
+CameraStrafeRight		PERIOD
+CameraStrafeLeft		COMMA
+ToggleGrid			0
+SetGrid1			1
+SetGrid2			2
+SetGrid4			3
+SetGrid8			4
+SetGrid16			5
+SetGrid32			6
+SetGrid64			7
+DragEdges			E
+DragVertices			V
+ViewEntityInfo			N
+ViewConsole			O
+CloneSelection			SPACE
+DeleteSelection			BACKSPACE
+UnSelectSelection		ESCAPE
+CenterView			END
+ZoomOut				INSERT
+ZoomIn				DELETE
+UpFloor				PAGEUP
+DownFloor			PAGEDOWN
+ToggleClipper			X
+ToggleCrosshairs		Shift + X
+TogTexLock			Shift + T
+TogTexRotLock			Shift + R
+ToggleRealtime			Control + R
+EntityList			L
+Preferences			P
+ToggleCamera			Shift + Control + C
+ToggleConsole			O
+ToggleView			Shift + Control + V
+ToggleZ				Shift + Control + Z
+ConnectSelection		Control + K
+Brush3Sided			Control + 3
+Brush4Sided			Control + 4
+Brush5Sided			Control + 5
+Brush6Sided			Control + 6
+Brush7Sided			Control + 7
+Brush8Sided			Control + 8
+Brush9Sided			Control + 9
+ShowDetail			Control + D
+MakeDetail			Shift + Control + M
+MakeDetail			Control + M
+MapInfo				M
+NextLeakSpot			Shift + Control + K
+PrevLeakSpot			Shift + Control + L
+FileOpen			Control + O
+FileSave			Control + S
+Exit				Control + X
+NextView			Control + TAB
+ClipSelected			RETURN
+SplitSelected			Shift + RETURN
+FlipClip			Control + RETURN
+MouseRotate			R
+Copy				Control + C
+Paste				Control + V
+Undo				Control + Z
+ZZoomOut			Control + INSERT
+ZZoomIn				Control + DELETE
+TexDecrement			Shift + SUBTRACT
+TexIncrement			Shift + PLUS
+TextureFit			Shift + 5
+TexRotateClock			Shift + PAGEDOWN
+TexRotateCounter		Shift + PAGEUP
+TexScaleUp			Control + UP
+TexScaleDown			Control + DOWN
+TexShiftLeft			Shift + LEFT
+TexShiftRight			Shift + RIGHT
+TexShiftUp			Shift + UP
+TexShiftDown			Shift + DOWN
+GridDown			[
+GridUp				]
+TexScaleLeft			Control + LEFT
+TexScaleRight			Control + RIGHT
+CubicClipZoomOut		Control + [
+CubicClipZoomIn			Control + ]
+ToggleCubicClip			Control + \
+MoveSelectionDOWN		SUBTRACT
+MoveSelectionUP			PLUS
+DumpSelectedBrush		Shift + D
+ToggleSizePaint			Q
+SelectNudgeLeft			Alt + LEFT
+SelectNudgeRight		Alt + RIGHT
+SelectNudgeUp			Alt + UP
+CycleCapTexturePatch		Shift + Control + N
+NaturalizePatch			Control + N
+SnapPatchToGrid			Control + G
+ShowAllTextures			Control + A
+SelectAllOfType			Shift + A
+CapCurrentCurve			Shift + C
+
+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm b/docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm new file mode 100644 index 00000000..22e31c02 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm @@ -0,0 +1,977 @@ + + + Shortcut keys and Mouse functions in QeRadiant & Q3Radiant + + + + +

Q3Radiant Editor Manual

+
+

Appendix G: Shortcut keys and Mouse functions
in QeRadiant/Q3Radiant

+ +

By Eutectic

+ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

1. Introduction

+

This is a list of all the command shortcut keys and key-mouse functions in QeRadiant and Q3Radiant. Please note that there are some commands that work in QeRadiant and not in Q3Radiant and vice versa. This is mainly because those are actually 2 different map editors for 2 very different game engines (Quake II and Quake III Arena) even though they share a common interface. But unless otherwise specified, the commands in this list work for both editors. Also note that in QeRadiant, there are some functions that work when selected from the menus but for which the shortcut key doesn't work. Whenever this is the case, this is clearly indicated with a color coded table cell.

+This revised version of this list reflects all the changes and additions in Q3Radiant Build 189.

+ +

2. Shortcut key list

+

The commands are sorted by category and color coding was implemented in the table boxes: + +

    +
  • Red background:

    +This denotes shortcut keys which are listed in the Help command list but don't work.


  • +
  • Green background:

    +This denotes shortcut keys or mouse functions which apply only to QeRadiant.


  • +
  • Orange background:

    +This denotes shortcut keys or mouse functions which apply only to Q3Radiant.


  • +
  • Purple background:

    +This denotes shortcut keys which are assigned to different features in QeRadiant and Q3Radiant.
  • +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionShortcut Key
2D view and Z view navigation & control keys
Toggle ViewOnly used in free window mode. Toggles the 2D view on/off.CTRL+SHIFT+V
Next ViewCycles the 2D view through all 3 views (top, front, side). Not used in 4 view mode.CTRL+TAB
Zoom InZooms 2D view in.DELETE
Zoom OutZooms 2D view out.INSERT
Center On CameraCenters the 2D view on the camera's current location.G
Toggle ZOnly used in free window mode. Toggles the Z view on/off.CTRL+SHIFT+Z
Z Zoom InZooms Z checker window in.CTRL+DELETE
Z Zoom OutZooms Z checker window out.CTRL+INSERT
3D view navigation & control keys
Camera BackMakes the POV in the 3D view move backwards.DOWN ARROW
Camera ForwardMakes the POV in the 3D view move forward.UP ARROW
Camera LeftMakes the POV in the 3D view look left.LEFT ARROW
Camera RightMakes the POV in the 3D view look right.RIGHT ARROW
Camera Strafe LeftMakes the POV in the 3D view move left.COMMA ( , )
Camera Strafe RightMakes the POV in the 3D view move right.PERIOD ( . )
Camera DownMakes the POV in the 3D view move down.C
Camera UpMakes the POV in the 3D view move up.D
Camera Angle DownMakes the POV in the 3D view look down.Z
Camera Angle UpMakes the POV in the 3D view look up.A
Center ViewCenters the POV in the 3D view.END
Down FloorMoves the POV in the 3D view down by one floor.PAGE DOWN
Up FloorMoves the POV in the 3D view up by one floor.PAGE UP
Toggle CameraOnly used in free window mode. Toggles the 3D view on/off.CTRL+SHIFT+C
Toggle Cubic ClipToggles 3D view clipping on/off. This feature works in both editors but shortcut key only works in Q3Radiant.CTRL+\
Cubic Clip Zoom InMakes the cubic clipping plane come in closer. Best used for speed optimizations.CTRL+ ]
Cubic Clip Zoom OutMakes the cubic clipping plane move further out. CTRL+ [
Toggle RealtimeToggles on/off real time 3D view camera updates.
+Feature doesn't work.
CTRL+R
Grid + control keys
Toggle GridTurns grid view on/off.0
Set Grid 1Sets the grid to 1 unit.1
Set Grid 2Sets the grid to 2 units.2
Set Grid 4Sets the grid to 4 units.3
Set Grid 8Sets the grid to 8 units.4
Set Grid 16Sets the grid to 16 units.5
Set Grid 32Sets the grid to 32 units.6
Set Grid 64Sets the grid to 64 units.7
Grid DownDecreases the size of the grid.[
Grid UpIncreases the size of the grid.]
Brush & entity creation and manipulation keys
Brush (3 sided)Creates a 3 sided brush.CTRL+3
Brush (4 sided)Creates a 4 sided brush.CTRL+4
Brush (5 sided)Creates a 5 sided brush.CTRL+5
Brush (6 sided)Creates a 6 sided brush.CTRL+6
Brush (7 sided)Creates a 7 sided brushCTRL+7
Brush (8 sided)Creates a 8 sided brush.CTRL+8
Brush (9 sided)Creates a 9 sided brush.CTRL+9
Unselect SelectionDeselects all currently selected objects.ESC
Delete SelectionDeletes all currently selected objects.BACKSPACE
Clone SelectionCreates a duplicate of the currently selected objects.SPACEBAR
Drag Edges ModeToggles edge manipulation mode on/off. Edges are represented by blue dots on the brush.E
Drag Vertex ModeToggles vertex manipulation mode on/off. Vertices are represented by green dots on the brush.V
Brush Clip modeToggles brush clipping mode on/off.X
Flip ClipSwitches which part of the brush is going to be clipped away on the set clip plane points while in clipping mode.CTRL+ENTER
Clip SelectedClips the selected brush/brushs on the set clip plane points while in clipping mode.ENTER
Split SelectedSplits the selected brush/brushs on the set clip plane points while in clipping mode.SHIFT+ENTER
Move Selection DownMoves the selected object down in Z axis by units equal to the grid size (independent of current 2D view).KEYPAD MINUS
Move Selection UpMoves the selected object up in Z axis by units equal to the grid size (independent of current 2D view).KEYPAD PLUS
Select Nudge DownMoves the selected object down in current 2D view by units equal to the grid size.ALT+DOWN ARROW
Select Nudge UpMoves the selected object up in current 2D view by units equal to the grid size.ALT+UP ARROW
Select Nudge LeftMoves the selected object left in current 2D view by units equal to the grid size.ALT+LEFT ARROW
Select Nudge RightMoves the selected object right in current 2D view by units equal to the grid size.ALT+RIGHT ARROW
Snap Selection To GridSnaps the vertices of the currently selected brush or patch mesh to the grid.CTRL+G
Make DetailTurns selected structural brush into a detail brush.CTRL+M
Make StructuralTurns selected detail brush into a structural brush.CTRL+SHIFT+S
Dump Selected BrushDumps a list of the plane point coordinates of all the faces of the currently selected brush to the console view.SHIFT+D
View Entity InfoBrings up the entity dialog window.N
Select Whole EntitiesQeRadiant only: Toggles feature on/off. When feature is on, selecting any single brush of a multiple brush entity automatically selects all the brushes that belong to that entity (This shortcut key does a Redisperse Rows in Q3Radiant).CTRL+E
Cycle Group SelectionCycle selects each individual brush of currently selected bsp-model entity (Select Whole Entities must not be on in QeRadiant). This command was renamed Patch Tab in Q3Radiant but it's function is unchanged.TAB
Connect SelectionConnect entities target to targetname.CTRL+K
Entity ColorUse this to set the "_color" key of a entity by bringing up the standard Windows RGB color selector. Used for choosing the color of lights for example.K
Texture manipulation keys
View TexturesOnly used in 4 view and free window modes. Brings up the texture selection window (toggle in 4 view mode).T
Surface InspectorBrings up the surface properties dialog (only used to align textures in Q3Radiant).S
Texture Shift DownMoves texture on currently selected brush face(s) downwards. Also works for patches but might sometimes give unexpected results.SHIFT+DOWN ARROW
Texture Shift UpMoves texture on currently selected brush face(s) upwards. Also works for patches but might sometimes give unexpected results.SHIFT+UP ARROW
Texture Shift LeftMoves texture on currently selected brush face(s) to the left. Also works for patches but might sometimes give unexpected results.SHIFT+LEFT ARROW
Texture Shift RightMoves texture on currently selected brush face(s) to the right. Also works for patches but might sometimes give unexpected results.SHIFT+RIGHT ARROW
Texture Rotate ClockwiseRotates texture clockwise on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.SHIFT+PAGE DOWN
Texture Rotate Counter-ClockwiseRotates texture counter-clockwise on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.SHIFT+PAGE UP
Texture Scale DownDecreases vertical scale of texture on currently selected brush
face(s). Also works for patches but might sometimes give unexpected results.
CTRL+DOWN ARROW
Texture Scale UpIncreases vertical scale of texture on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.CTRL+UP ARROW
Texture Scale LeftDecreases horizontal scale of texture on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.CTRL+LEFT ARROW
Texture Scale RightIncreases horizontal scale of texture on currently selected brush
face(s). Also works for patches but might sometimes give unexpected results.
CTRL+RIGHT ARROW
Texture FitAutomatically fits the texture to the size of the currently selected brush face by scaling it vertically and horizontally. This shortcut only works in QeRadiant.SHIFT+5
Texture Fit To FaceSame as Texture Fit. This shortcut only works in QeRadiant.CTRL+F
Toggle Texture LockToggles brush move texture alignment locking on/off. This feature works in both editors but shortcut key only works in Q3Radiant.SHIFT+T
Toggle Texture Rotate LockToggles brush rotation texture alignment locking on/off. This feature works in both editors but shortcut key only works in Q3Radiant.SHIFT+R
Dialogs and special features keys
View ConsoleOnly used in 4 view and free window modes. Brings up the console (this is a toggle function in 4 view mode).O
PreferencesBrings up the user preferences dialog.P
Entity ListBrings up the entity list "tree view" window. This feature works in both editors but shortcut key only works in Q3Radiant.L
Map InfoBrings up the map info status window. This feature works in both editors but shortcut key only works in Q3Radiant.M
Filter SettingsBrings up the filters dialog window. This feature only works in QeRadiant.F
Show DetailToggles display of detail brushes on/off.CTRL+D
Animate Selected EntitiesToggles animation of selected mover entities (doors, buttons, etc.) on/off. This feature only works in QeRadiant.CTRL+A
Previous Leak SpotTakes POV in the 3D view to the previous leak spot (pointfile must be loaded).CTRL+SHIFT+L
Next Leak SpotTakes POV in the 3D view to the next leak spot (pointfile must be loaded). This feature works in both editors but shortcut key only works in Q3Radiant.CTRL+SHIFT+K
Misc utility keys
File OpenOpens a file.CTRL+O
File SaveSaves a file.CTRL+S
ExitCloses the editor.CTRL+X
CopyCopies whatever is currently selected.CTRL+C
PastePastes what ever is in the clip board. Only works with text and Radiant's stuff.CTRL+V
UndoUndo. Doesn't work in all cases.CTRL+Z
RedoRedo. Doesn't work in all cases.CTRL+Y
Q3Radiant miscellaneous features keys
View GroupsBrings up the groups dialog window.G
Toggle Size PaintMomentarily displays the position + dimensions of currently selected brush(es) in the 2D view.Q
Mouse RotateToggles mouse free rotation mode on/off for currently selected objects.R
Select Type AllSelects all "identical" based on type of "currently selected". If type is a surface, all solids with the same texture are selected. If type is an entity, all the other entities of its classname are selected.SHIFT+A
CSG MergeWill merge all currently selected brushes into a single brush. If the shape and size of any one of the selected brushes would cause the merge to produce a concave solid, the merge operation is not performed.SHIFT+M
Toggle CrosshairsToggles between the regular mouse pointer and a large crosshair style pointer in the 2D view.CTRL+SHIFT+X
Fit TextureThis will automatically scale the texture on the currently selected faces so one texture tile will fit exactly on the faces by default. It also brings up Surface Inspector so the texture can be fit to the faces by a different number of texture tiles than 1.SHIFT+B
Hide SelectedHides all currently selected objects from the 2D/3D views.H
Show HiddenUn-hides all objects currently hidden from the 2D/3D views.SHIFT+H
Show All TexturesShows all the textures currently loaded in Q3radiant's texture window. Use this to un-set Show In Use in the textures menu.CTRL+A
Patch TabCycle selects each individual brush or patch of currently selected bsp-model entity. This command was called Cycle Group Selection in QeRadiant but it's function is unchanged.TAB or SHIFT+TAB
Q3Radiant patch manipulation keys
Bend ModeToggles bend mode on/off. This is used to bend patch meshes. Follow the instructions that come up in the dialog box when you use this. Best used for making arches and such.B
Cap Current CurveAutomatically creates cap patches for the currently selected patch if it's a cylinder. For bevels and endcaps, it will bring up the cap dialog instead. The patch and its caps will then automatically be grouped in a func_group.SHIFT+C
Cycle Cap Texture PatchThis cycles the cap texturing type on the currently selected patch.CTRL+SHIFT+N
Cycle Cap Texture AxisThis cycles the cap texturing axis on the currently selected patch.CTRL+SHIFT+P
Naturalize PatchMakes the texture natural on the patch mesh (sometimes the textures are stretched to fit the patch, this will make the texture fit normal instead of streching it).CTRL+N
Increase Patch RowAdds 3 rows to currently selected patch.CTRL+KEYPAD PLUS
Decrease Patch Row Removes 3 rows from currently selected patch (assuming patch currently has more than 3 rows).CTRL+KEYPAD MINUS
Increase Patch ColumnAdds 3 columns to currently selected patch.CTRL+SHIFT+KEYPAD PLUS
Decrease Patch ColumnRemoves 3 columns from currently selected patch (assuming patch currently has more than 3 columns).CTRL+SHIFT+KEYPAD MINUS
Redisperse ColumnsEvenly re-disperses all the columns of the currently selected patch. Useful after adding new columns.CTRL+SHIFT+E
Redisperse RowsEvenly re-disperses all the rows of the currently selected patch. Useful after adding new rows (this shortcut key does a Select Whole Entities in QeRadiant).CTRL+E
Invert CurveThis inverts the patch mesh's matrix. IOW, it changes which side of the patch the texture is applied to.CTRL+I
Invert Curve Texture XInverts the X value of the texture on the matrix. Use this to mirror the texture vertically on a patch.SHIFT+I
Invert Curve Texture YInverts the Y value of the texture on the matrix. Use this to mirror the texture horizontally on a patch.CTRL+SHIFT+I
Matrix TransposeSwaps the rows and columns on a patch. There is no physical change on the patch as such: rows become columns and vice versa. Use this to change the natural texture orientation axis on patches.CTRL+SHIFT+M
Make Overlay PatchTurns on display of the currently selected patches control points. The display of the patches control points will remain on until turned off by Clear Patch Overlays.Y
Clear Patch OverlaysTurns off display of the currently displayed patches control points previously turned on by Make Overlay Patch.CTRL+L
Patch InspectorBrings up the patch inspector dialog.SHIFT+S
Thicken PatchCreates a copy of current patch and spaces it by X amount of units (as per value entered in dialog box) then caps off the mesh.CTRL+T
Toggle Show PatchesToggles display of patch meshes from 2D/3D views on/off.CTRL+P
+


+

3. Mouse Function list

+

This is the list of all the Mouse Functions in QeRadiant and Q3Radiant. Note that these are not shortcuts. The tasks accomplished by the mouse cannot be found in the menus. They provide much of the essential functionality in QeRadiant/Q3Radiant when designing maps.

+ +

Radiant's user interface includes many productivity features and is a very powerful tool. It's no wonder that it's the editor of choice for professional and amateur map designers alike. But it's true power is unleashed when you use a 3-Button mouse. Several extremely useful power features, especially when it comes to texturing, are only accessible if you use a 3-Button mouse. Many people own one nowadays and if you use QeRadiant regularly, I strongly recommend you get one.

+ +

The commands were sorted by category and abbreviations were used to make it easier for me to fit the shortcut names in the table boxes: + +

    +
  • LEFT-SIDE BUTTON or LEFT-CLICK = LEFTBUT


  • +
  • MIDDLE BUTTON or MIDDLE-CLICK = MIDBUT


  • +
  • RIGHT-SIDE BUTTON or RIGHT-CLICK = RIGHTBUT

    The action of these 3 abbreviations mean: click once



  • +
  • LEFT-CLICK & DRAG = LEFTBUT+DRAG


  • +
  • MIDDLE-CLICK & DRAG = MIDBUT+DRAG


  • +
  • RIGHT-CLICK & DRAG = RIGHTBUT+DRAG

    +The action of these last 3 abbreviations mean: click once, hold down button and drag mouse.


  • +
+ +

Also, as with most applications, the action of the mouse is context-sensitive meaning that the same Mouse shortcut might do a different thing depending in what view you click. This is why the categories below are sorted more by context than type.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionMouse Function
2D view mouse functions
Scroll ViewScroll or pan the 2D view. Also works in the Z view.RIGHTBUT+DRAG
Move Z CheckerMoves the location of the Z Checker box icon in the 2D view to where you click. Dragging the mouse makes it follow around.SHIFT+MIDBUT
SHIFT+MIDBUT+DRAG
Move CameraMoves the location of the Camera eye icon in the 2D view to where you click. Dragging the mouse makes it follow around. Also works in the Z view.CTRL+MIDBUT
CTRL+MIDBUT+DRAG
Point CameraPoints the Camera eye icon in the 2D view to where you click. Dragging the mouse makes it follow around.MIDBUT
MIDBUT+DRAG
Create/Modify BrushThis will create a new brush if no object is currently selected. If one or more brushes are selected, this will:

+1. Resize the brush when click-dragging outside.

+2. Move the brush when click-dragging inside.

+If one or more point entities are currently selected, this will just move them. Also works in the Z view but for brushes, only move and vertical resize are possible. In the 3D view, only move and resize work.
LEFTBUT+DRAG
Select ObjectSelects/Deselects brush or entity under cursor. Entities have priority over brushes. This also works in the Z and 3D views.SHIFT+LEFTBUT
Cycle Select ObjectCycle selects all brushes or entities under cursor in order of depth. This only works in the 2D view in QeRadiant but works in all views in Q3Radiant.SHIFT+ALT+LEFTBUT
Drag Brush FaceDrags the face of the currently selected brush. The face nearest to the cursor is dragged. Brushes can also be sheared by using this. This also works in the 3D view.CTRL+LEFTBUT+DRAG
Entity MenuBrings up the entity pop-up menu. You can then select the entity to create. For solid entities (doors, buttons, triggers, etc.), at least one brush must be selected beforehand.RIGHTBUT
3D view mouse navigation functions
Drive CameraMakes the POV in the 3D view move forward/backwards and turn left/right when mouse is dragged.RIGHTBUT+DRAG
Strafe CameraMakes the POV in the 3D view strafe up/down and sideways when mouse is dragged.CTRL+RIGHTBUT+DRAG
3D view mouse texturing functions
Select Brush FaceSelects brush face under cursor. Only one face at a time can be selected. Will automatically deselect any currently selected objects. Also grabs the face's current texture + alignment + flags into Surf Inspector.CTRL+SHIFT+LEFTBUT
Select Multiple Brush FacesSelects brush faces under cursor. Any number of faces at a time can be selected. Will automatically deselect any currently selected objects. Also grabs the face's current texture + alignment + flags into Surf Inspector. This feature only works in Q3Radiant.CTRL+SHIFT+ALT
+LEFTBUT
Grab TextureGrabs the texture + alignment + flags of the brush face under the cursor into Surf Inspector. Any currently selected face or brushes will automatically be assigned the grabbed values.MIDBUT
Apply Texture To BrushApplies the current texture + alignment + flags in Surf Inspector to the whole brush under the cursor.CTRL+MIDBUT
Apply Texture To FaceApplies the current texture + alignment + flags in Surf Inspector to the single brush face under the cursor. +CTRL+SHIFT+MIDBUT
Apply Texture Only To FaceApplies the current texture in Surf Inspector to the single brush face under the cursor but face retains its current alignment + flags.SHIFT+MIDBUT
Shift TextureShifts the texture's vertical and horizontal alignment on the currently selected face or brushes. This feature only works in QeRadiant.ALT+RIGHTBUT+DRAG
Scale TextureStretches up/down the texture's vertical and horizontal scale on the currently selected face or brushes. This feature only works in QeRadiant.SHIFT+ALT+RIGHTBUT
+DRAG
Rotate TextureRotates the texture on the currently selected face or brushes. This feature only works in QeRadiant.CTRL+ALT+RIGHTBUT
+DRAG
Set Light To Average Texture ColorGrabs the average color of the current texture in Surf Inspector and sets the "_color" key of the light entity under the cursor to that RGB color value. This feature only works in Q3Radiant.SHIFT+MIDBUT
Texture window mouse functions
Select TextureSelects the texture under the cursor and pastes the texture + default flags into Surf Inspector. All currently selected brushes or face will automatically be assigned the selected texture.LEFTBUT
Select Texture + Surf InspectorSame as above but also automatically brings up the Surf Inspector window. This feature only works in QeRadiant but shortcut key does a Apply Texture Angled in Q3Radiant.CTRL+LEFTBUT
Scroll Texture WindowScrolls up/down through the texture window (same as scrollbar or mouse wheel).RIGHTBUT+DRAG
Scroll Texture Window FastSame as above but will scroll much faster. Useful for browsing through very large texture folders.SHIFT+RIGHTBUT+DRAG
Edit ShaderShader window function. Shift-click on a shader opens the proper shader file in EditPad and automatically places the cursor at the beginning of the shader. This feature only works in Q3Radiant.SHIFT+LEFTBUT
Apply Texture AngledAutomatically applies and scales the texture under the cursor on currently selected angled faces so it will fit on those faces by exactly one texture tile. This feature only works in Q3Radiant but shortcut key does a Select Texture + Surf Inspector in QeRadiant.CTRL+LEFTBUT
Entity dialog mouse functions
Create EntityDouble-clicking on an entity name in the dialog's list will create an entity at the location of the currently selected brush (mandatory).

+1. If a point entity is chosen from the list, it will automatically replace the selected brush(es).

+2. If a solid entity is chosen from the list, the selected brush(es) will belong to the entity.

+3. If an entity or nothing is selected beforehand, you will get an error dialog: "Failed to create entity".
DOUBLE-LEFTBUT
+
+
+

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/ch01/pg1_1.htm b/docs/manual/Q3Rad_Manual/ch01/pg1_1.htm new file mode 100644 index 00000000..0a452022 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch01/pg1_1.htm @@ -0,0 +1,179 @@ + + +Q3Radiant Editor Manual: Page 1.1 + + + +

Q3Radiant Editor Manual

+
+

Preface

+ +The authors would like to thank the many supporters of Quake Engine +editing who made this work possible. Several sections in the manual +are based on material written by dedicated fans. Others were +"corrected" by fans who found undiscovered bugs in both the editor +and game code. Where possible, we have noted the contributors in +the sections they helped produce. + +

Paul Jaquays
+Robert A. Duffy + +

GtkRadiant note: This version of the manual is meant to be distributed with +GtkRadiant. Being for Q3Radiant 192, some parts are very outdated, specially all +the ones dealing with configuration. But the core features (curves and brush +manipulation, texturing) are still very relevant. If you are willing to help +maintaining this version more up to date get in touch with us (http://www.qeradiant.com) +

Note: Chapter 1 has been updated to follow the GTKRadiant 1.2.1. Mainly the preferences menu and some information on this page and appendix E (links and resources). + +

Introduction

+ +Part of the fun of games like Quake III Arena is the ability to add +to your own ideas to a favorite game and then have others play and +enjoy them. While the technical skills needed to create a 3D +graphic engine is beyond many game fans, the skills and equipment +necessary to make modifications to the game are not. It has become +the custom of many game developers to share their development tools +with the public. This allows fans make their own game content. The +Q3Radiant editor is the software used by the designers at id to +create the arenas in Quake III Arena. In fact, it's an +improvement on that editor, since it contains features that have +been added since the game was completed. If you are familiar with +Q3Radiant's immediate ancestor, the QeRadiant editor for +Quake 2, then a good share of what's in this manual will be +old hat to you. Whether you are a veteran mapmaker or new to the +art of making game arenas, we think you will find some +indispensible information in this manual. + +

Now comes the caveat. + +

This manual will tell you how to use the tools, but not +necessarily, how to make what you have in mind. Many fine on-line +tutorial and resource sites will be listed at the end of the +document. + +

Minimum System Requirements

+ +The designers at id used Q3Radiant on some heavy-duty computing +equipment to make their game maps. Despite the fact that Quake III +Arena runs under several different operating systems, not every +computer that can run Quake III Arena will be able to run the +Q3Radiant editor. Q3Radiant only runs under MS Windows 95, MS +Windows 98, MS Windows NT, or MS Windows 2000 operating systems. +There are currently no plans for Mac or Linux versions. The editor +requires an Open GL compliant 3D graphics acceleration card (it is +expected that all cards capable of running Quake III Arena will be +able to handle editor functions … although some may handle +it better). A 3-button mouse gives the best performance. + +

Minimum System

+ +The minimum system requirements generally require that preferences +such as texture quality and screen resolution be set to absolute +minimums. The editor will run on the systems described, but speed +of operation and visual quality will probably be less than +satisfactory. It should also be noted that you would be limited to +working on relatively small maps with limited texture and model +usage. + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
Processor:P233mmx
RAM:64 meg
Video Card:4 Meg, software Open GL-compliant
Screen Resolution:1024 x 768
Pointing Device:Two-button mouse*
+ +

Recommended System

+ +The more powerful the machine, the better and usually faster the +development experience. This will become especially true when you +get to the point of compiling your maps (turning them from editor +code into game code). It should come as no surprise that, more +powerful machines will crunch the numbers faster when compiling a +map. + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
Processor:P2450 (or better)
RAM:128 meg**
Video Card:Open GL accelerated video card
Screen Resolution:1280 x 1024
Pointing Device:Two-button mouse*
+ +

* This will work, but not well. A three-button mouse, even on a +minimal system is highly preferred.
+** id designers often found it convenient to work with several maps +open at once. The recommended 128 Meg of RAM may not be enough to +accommodate this. + +

What Doesn't Work (well) - and How to +fix it

+ +The key to a satisfactory editing experience is whether your video +card supports the demands of the editor. The original id editor was +designed for a workstation card called the Realizm, which ran on +Intergraph workstations in a WinNT environment. Robert Duffy +expanded this to include the Win9x operating systems and a number +of other video cards. But not all video cards support the editor +equally well. + +
    +
  • The G200 and G400 require updated drivers from Matrox
  • + +
  • The 3fx Voodoo 3000 chipset requires a driver upgrade in order +for the map grids to show.
  • + +
  • If the map grids don't appear when using some ATI chip +sets, try turning the settings on you desktop up to 32 bit (true +color).
  • + +
  • Nvidia TNT and GeFORCE have slowdown issues when the user +selects curve patches. While this is a driver issue, it can be +addressed by checking the "Solid selection boxes" +feature under preferences.
  • +
+ +

Back | Home | Next + + + diff --git a/docs/manual/Q3Rad_Manual/ch01/pg1_2.htm b/docs/manual/Q3Rad_Manual/ch01/pg1_2.htm new file mode 100644 index 00000000..95c7bb9a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch01/pg1_2.htm @@ -0,0 +1,391 @@ + + +Q3Radiant Editor Manual: Page 1.2 + + + +

Q3Radiant Editor Manual

+
+

Installation & Set Up

+Instalation of the editor has changed in the latest build. It is much more simple then before. + +

Installing the editor

+Run the setup file you downloaded of the latest GTKradiant program. You know longer have to install GTKRadiant to the Quake3 directory. It can reside in any directory you would like to have it. + +

Setting up Paths

+During installation you will be asked where your Quake3 game is located. Browse to the folder and select Ok. Then you will be prompted for a directory name for the Quake3 game pak. Setup will create this directory in the Quake3 game directory. +

+You will then be prompted for your Return To Castle Wolfenstein folder. Repeat the same process as you did for Quake3, only this time pointing to your RTCW directory. + +

Improving Performance

+If you find that the editor is sluggish on your system, try some or all of the following tweaks: + +
    +
  • On the View menu, check Cubic Clipping to be ON. This reduces the number of game components in view, by shortening the distance that the editor can "see." Use CTRL + to set the distance to 13 (a good number in this case). +
  • On the Textures menu, open the Render Quality option and select an option higher on the list than your current setting. We recommend not going below Nearest MipMap first. This reduces the amount of blending and filtering in the textures as they are seen in the Camera window, but still lets you see what the textures look like in a relatively undistorted manner. The Nearest setting will further improve performance, but textures may be distorted when seen in perspective. +
  • On View Menu, open the Entities asÂ… option and select an option higher on the list than your current setting. +
  • Select Preferences Â… from the Edit Menu. Under “Display / 3D View”, deselect (uncheck) “Update XY views during mouse drags.” This will stop the 2D-map window(s) from being repeatedly redrawn during Camera window mouse drags. +
  • Select Preferences Â… from the Edit Menu. Under “Display / Texturing Settings”, move the slider bar under "Texture Quality" one or more settings to the left, reducing overall texture quality. +
  • Select Preferences - from the Edit Menu. Under “Interface / Editing”, lower the number of “Patch Subdivisions” to a lower number. +
  • Further performance can be gained by turning off curves (CTRL + p) or reducing curve displays to wireframe only. +
+ +

Setting up Preferences

+To set up your editing preferences, open the Edit menu and select Preferences. Use preferences to set a variety of options and editor behavior based on your personal preferences. + + +

Globals +
+Game Settings / Select The Game
+
+
+GTKRadiant now stores preferences on a per game basis. For instance: Any settings you set up for Quake3 are stored for that game mode only. Switching to Return To Castle Wolfenstein mode, will use the preferences you setup when that Game mode was set up. + +

Display +
+2D Display +

    +
  • OpenGl Display Lists - Uncheck this option if you encounter any graphic errors. This can some times cuase problems with bad opengl drivers. +
  • OpenGL Antialliased Points and Lines - This will render all points and lines in the 2D view using antialiasing. This can slow down the 2d view if your video card can not handle antialiasing very well. +
  • Solid Selection Boxes - This will make anything selected draw with solid lines rather then the old style of dashed boxes. This can slow down the 2D view as well. +
  • Display Size Info - If this is checked on, it will display the size information of any object selected. +
  • Alternate Vertex Edge Handles - This changes the shape (a little bit) of the vertex and edge points when in either vertex or edge manipulation mode. +
+ +

3D View +
Thanks to some new code. Radiants 3D View is Ultra fast. +

    +
  • Movement Velocity - This will increase or decrease the movement of forward, back, and strafing speed in the 3d view. +
  • Rotational Velocity - This will increase or decrease the turning speed in the 3D View. +
  • Freelook in Camera View - With this checked, you will be able to use free look in the 3D View. Just Right Click in the 3d view to turn on free look, and Shift + Right Click again to turn it off. +
  • Invert Mouse In Freelook - This will reverse the mouse controls in freelook mode. +
  • Discrete Movement - If checked, this cuases the view in the 3d view to move one step at a time. If unchecked the movement is smoother. +
  • Update XY Views On Camera Move - When interacting with the camera (which you will do a lot), turning this off will NOT update the camera icon location in the Map windows automatically. This can help with speed but prevents you from seeing exactly where the camera icon is positioned. +
+ +

Texture Settings +

    +
  • Texture Quality - This will increase or decrease the texture quality displayed in the texture window and 3D View. +
  • Texture Subsets - This provides a texture edit window within the texture window. It is still buggy as of build 188. It puts a text field at the top of the Texture window. Type in the first few letters of a texture name and the window will only display the textures beginning with that letter or letters. +
  • Texture Scrollbar - If checked, this will add a scroll bar to the texture window. +
  • Tex Increment Matches Grid - If checked, this will cuase Radiant to use the grid spacing when moving and aligning textures with the shift + arrow keys. +
  • Default Scale - The default scaling of textures on load up of the editor. +
  • Startup Shaders - You can choose to have certain shaders load upong startup of the editor or to not have any load on startup. +
+ +

Interface +
+Layout +

    +
  • Layout - Choose 1 of 4 layouts. +
      +
    • Split Window View - This is the QeRadiant default view. The Camera, XY Map, Z-axis Scale, Texture, and Console windows are constantly displayed. While the arrangement of the windows cannot be changed, their size is adjustable by pulling the window border splitters. The Entity and Group windows share a common pop-up window. This arrangement is one that may work particularly well for mappers using smaller monitors and slower computers.

      +
    • Floating Window View - This is the view used by id designers. The position, arrangement, and size of the windows are all adjustable. The windows initially come up on top of one another (a known bug), but once positioned, this view offers the greatest flexibility. The Camera, XY Map, Z-axis Scale, and a shared Entity/Texture/Console/Group window are all displayed simultaneously. Changing the size of one window does not automatically affect the others (it can lay atop the others). Additional map layout views can be cycled from menu commands or bound keys. This view only works well if you have a 20+-inch monitor. +

      Make it Big! In floating windows mode (ONLY), you can double-click on any windowÂ’s Title Bar to enlarge the contents of the window to fill the screen. Double clicking on it again reduces it back to normal size.

      +

    • Quad View - The display window is split into four equal-sized windows: Camera, XY Map, YZ Map, and XZ Map. This is similar to other editors and offers four-way viewing. You see the map components in three views simultaneously. The size of the windows (relative to each other) can be adjusted, by pulling the splitters. The combined Entity/Texture/Console/Group window is brought into view as a single, floating window that lays over the others. The Z-axis window is not used in this view. This is a popular editing configuration, but it has significant performance issues. The editor is drawing all the 2D map components three times (plus maintaining a camera view). Some mappers have notice significant performance slow-downs when working with curves. Using the Quad view is only recommended for mappers with more powerful computers.

      +
    • Reverse Split Window View - Essentially the same as the Split Window view, except that the windows are all flopped left to right.

      +
    +
  • Floating Z Window - This will make the Z-Window float in the Floating Window View mode. +
  • Patch Toolbar - Seems to have been disabled. +
  • Use Win32 File Load Dialog - If checked, this will use the common windows style file browser. Unchecked it will have the unique GTK / Linux X-Windows file browser. +
+ +Mouse +
    +
  • 2 Button / 3 Button - Use 2 button mode or 3 button mode. Each mode is different in some ways. The hot keys and key combinations are generally different for each mode. +
  • Right Click To Drop Entities - If checked, this will create a menu where ever you click in the 2D View with a list of the entities you can select and place. +
  • Mouse Chaser - Turning this on causes the view to chase the mouse if you drag something off the edge. +
  • Alt + Multi-Drag - If this option is checked, you must hold down the ALT key to drag multiple brush edges. This lets you resize more than one brush at a time. +
  • Wheel Mouse Inc - This number will adjust the amount the texture window scrolls in the texture window when using the mouse wheel. The higher the number, the faster it scroll basically. +
+ +Editing +
    +
  • Vertex Editing Splits Face - This will cuase face splits in brushes when in moving vertex points around and the brush becomes a concave shape. +
  • Fix Target/Targetname Collisions - This prevents duplicate target/targetnames from happening if you load a map into your current map. For instance: if you load q3dm7 into q3dm7, it adds _1 to duplicate target/targetname pairs. +
  • Cliiper Tool Uses Caulk - When using the clipper tool, the faces that are created from the clip will add a cualk texture to the brush. +
  • Dont Clamp Plane Points - This turns off clamping of plane points. This allows for very precise brush/vertex manipulation but can make it difficult to get things properly aligned and can also cause the bsp process to take a LOT longer. In general, this should be unchecked. +
  • Select Patches by Bounding Boxes - If checked, you will be able to select patches by there bounding boxes. Note: Bounding boxes for patches must be turned on. +
  • Rotation Increment - This allows you to choose the increments in pixels a texture is rotated when rotating a texture with the shift + pgup or pgdn keys. +
  • Undo Levels - Set how many undos you can do. This does require memmory so do not set it to high if you do not have alot of memmory. +
  • Patch Subdivisions - Select how many subdivisions are drawn on the patches in all views. If set to high it can slow down the editor. If set very low it will look blocky. Essentially it works like the games r_subdivisions option. +
+ +

Other +
+Startup/Autosave +

    +
  • Snapshots - If checked, this will create snapshots every 5 minutes of your level. They are saved into your maps directory and have a numbered order (eg. .001 .002) for the file extension. +
  • Load Last Project On Open - If checked, GTKRadiant will automatically load the project settings you last used. +
  • Load Last Map On Open - If checked, GTKRadiant will load the last map you had open during your last session. +
  • Auto-Save Every - Here you can choose to use auto saving, and how many minutes between each auto-save. +
+ +Paths +
    +
  • Prefab Path - Here you can choose the directory of where you will have your prefabs ( .pfb ) stored. +
  • Game Path - This is now controlled by GTKRadiant. It displays the path of your game executable for which game mode you are in. +
  • User Ini Path - This will allow you to choose a user .ini file and its path. +
+ +Misc +
    +
  • Light Drawing - This draws lights as shaded triangle things (octahedrons) instead of standard square entities. When enabled, the light entities also show their emitted light color. +
  • Log The Console To radiant.log - This will cuase GTKRadiant to create a log file of all output from the GTKRadiant console. This can cuase the editor to slow down, and is normally used for debugging purposes. +
  • Use Pak/PK3 Files - This will force GTKRadiant to read from .pak or .pk3 files before searching in the game directories like baseq3. +
+ +BSP Monitoring +
    +
  • Enable BSP Process Monitoring - This will have a ms-dos window open when you compile a map from the BSP menu. +
  • Stop Compilation On Leak - This will cuase the bsp compile process to halt when a leak is found in a map during the BSP process. +
  • Run Engine After Compile - This will cuase the game to launch after the compile process is complete. +
  • Activate Sleep Mode When Running The Engine - This is automatic now. GTKRadiant will go into sleep mode when you load the engine after a compile.

    Warning. With some video drivers, it is a bad idea to run Quake 2 or Quake III Arena and the Q3Radiant editor. The drivers just will not sustain two demanding OpenGL applications simultaneously. This feature is best left turned off. + +

+ + + +

The Project File

+The project file contains the paths for the various GTKRadiant file-processing functions. Using the installer to set up the editor should write these for you. + +

New Project +

+
This creates a new folder (which you must name) in your Quake III Arena or RTCW directory. +
This is a good function for mods. You can use a different directory other then baseq3 if you plan to have alot of new resources and dont want to clutter it into the baseq3 folder. + +

Load Project +

+
This opens up a browse directory pointed at the scripts directory. It is looking for a text file with a .qe4 file extension. + +

Changing the Project File +

+
You can edit the project file by changing the pathnames to various functions in field of the dialogue window that pops up. HOWEVER, before doing this, you should make a backup copy of your Quake project file and give it a new name. Make your changes to this new file. If you mess things up, you can always reload the original. This is a good thing to do if you are making maps for a mod that uses a separate set of definitions for entities or directories for textures and want to easily change between types of projects. + +

Project Settings +

    Basepath: This traces a path, beginning in your root directory to the baseq3 where the editor expects to find resources. +

    Mapspath: This traces a path, beginning in your root directory, to the location where maps are saved and from which they are loaded. The default is the maps directory. + + + +

    Rshcmd: This means "remote shell command." Use it only if you are directing a remote processing device (not your editing computer) to compile maps. The syntax for the field is: "rsh [processor name]" + + + +

    Remotebasepath: If you are running your compile from your editing computer, this should be the same as your basepath. If you are working off a remote compling device, this should trace the full path to the to the baseq3 folder where the compiler will find the resources it requires. + + + +

    Entitypath: This traces a path to the definition file for your game entities. This can either be a .c file which contains the game code, or a .def file which contains more instructive information about the entities. +

    Note: As of GTKRadiant 1.2.1 the default path for this is "Radiant", also known as the new game packs style it uses which allows for the remote installation of GTKRadiant anywhere on your computer. + + +

    Texturepath: This traces a path, beginning in your root directory, to the location from which textures are loaded. The default is the textures directory. +

+ + +

Menu commands +
These commands are your map compile commands. You can CHANGE these commands or ADD your own. Each new command must start with “bsp_” The following is the compile command string for “bsp_Fullvis” taken off one of our project files. + +

    ! q3map $ && ! q3map -vis -threads 8 $ && ! q3map -light -threads 8 $
+ +

Command parameters: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
!The exclamation mark is replaced by the contents of the rshcmd field. It is the path to the processor.
$The dollar sign is replaced by the Mapspath.
&&The double ampersand is the command terminator (end of command)
q3mapThis is the process command. Without a switch after it, it performs the .bsp compile phase.
-visThis is a switch to select the vis compile phase.
-lightThis is a switch to select the lighting compile phase.
-threadsThis is a switch to break the compile up into a number of different processor threads. The number of processors follows the switch parameter.
+ + +

Other parameters +

+ + + + + + + + + + + + + + + + + + + + +
-onlyentsProcess only the entities in the map.
-fastA quicker process. However, it treats the map as if it were all one vis area.
-extraAs in -light -extra. This is a second lighting pass that more finely subdivides the map into areas of light and shadow.
-nowaterCompiled without liquids in the map. Used in the first compile phase only.
-nocurvesCompiles without curves in the map. Used in the first compile phase only.
+ + +

Misc settings +
Use brush primitives in MAP files. +
Once this is set for a map, the program converts the texture mapping to this format. Once chosen, there is no going back to the old format. Brush primitives are described in detail under the Working with Textures section. + +

Setting up the Windows

+There are six configurable windows in Q3Radiant. + +

The Camera Window (CAM) +
The Camera window initially shows a gray field. This is where the 3D in-progress view of your map appears. You can SHIFT + click mouse button 1 to select objects in this window. If the images in this window appear overly dark, you can adjust the gamma value. Open the Misc menu and select Gamma. Enter a value between 0 and 1 for the light value. Close the program. Reopen the program. Check the darkness. Repeat this until you have a value you like. + +

Entity/Texture/Console/Group Window +
Depending on the Windows layout view that youÂ’ve chosen, one or more of the following sub-windows share this window. They are selectable by the tab at the bottom of the window, or by shortcut keys. + +

Entity Window +

+The Entity window is one of four windows that share the same window space: Console, Entity and Texture and Group. The entity window is used to create and modify the properties of game entities. The uppermost box in this window contains the entity names. Use the scroll bar to find the one you want or for speed, type in the first letter of the class of entity you desire (“w” for weapon, “I” for item and so on). Refer to the Working with Entities section for more details on this. + +

Texture Window +

+The Texture window displays textures that have been loaded from the texture directories for easy use. The texture subset tool (set in preferences) allows you to quickly jump to a texture if you know the first few letters of its name. The scrollbar tool adds normal Windows functionality to the window. The most common method of navigating the window is to right-mouse click and drag through the window contents. SHIFT + right-mouse click and drag speeds up the rate of movement through the windowÂ’s contents. A thin green outline around a texture indicates a non-shadered texture in use in the map. A thin white outline indicates a shadered texture. A bold red outline indicates a selected texture. + +

Console Window +

+The console tracks the editorÂ’s processes, like loading, saving, and compiling. When you compile (selecting an option from the bsp menu), the contents of the console are dumped into the junk.txt file in your Temp file folder on your root drive. In the Split Window view layout, the Console window is always in view. + +

Groups Window +

+This window will deal with the future grouping functions that will soon be a part of the editor. At this time, it is only a non-functioning window. + +

Z-axis Scale Window +
This window is used by three of the four views to show the Z-axis position (height) of the Point of View and any selected map components. + +

Map Window(s) +

The Grid +
Think of the Map window as a piece of graph paper, neatly divided into squares. However, unlike graph paper, you can change the size of the grid to fit your needs of the moment. You can change grid size from the Grid menu, but itÂ’s faster to learn the key shortcuts listed below. + +

Setting Grid Size + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Grid sizeKey
1 unit grid(1)
2 unit grid(2)
4 unit grid(3)
8 unit grid(4)
16 unit grid(5)
32 unit grid(6)
64 unit grid(7)
Grid DownDecreases the size of the grid. [ key
Grid UpIncreases the size of the grid. ] key
+ + +

Grid and Window Layouts +
There are four distinct ways of laying out the work windows for Q3Radiant. + +

Design Notes: +
Try not to build architecture with a grid smaller than 8 units. +
Use a smaller grid if you need to build small details. +
Use a large grid (32 or 64) for roughing in a level. +
Use a large grid for moving large chunks of architecture around.
+ +

Snap to Grid +
When this is checked, the edges and vertices of brushes and patches will “snap” to grid coordinates. Unless you are attempting some very fussy maneuvering of a map component, Snap to Grid makes life much easier. In fact, if you are building objects out of curve patches, it is crucial that you be able to line up patch control points with the vertices of surrounding solid geometry brushes. + +

Colors +
Q3Radiant allows you to select the colors of your grids and tools. Because the manual refers to the colors of some features, you may wish to wait until you are more comfortable using the editor before changing too many things. You can always revert to the Q3Radiant defaults, should you choose change too much. + +

To change Map window and Texture window colors, select the “Misc” menu and choose colors. The pop-up lists a number of options. + +

Themes +
Brings up three options: + +

    QE4 Original: The settings for idÂ’s original Quake 2 editor +
    Q3Radiant Original: The default setting. +
    Black & Green: a black background with a green grid major. +
+ +

Each of the following options opens the Windows color selector. + +

Grid BackgroundÂ… +
The background color for the map window. + +

Texture BackgroundÂ… +
The background color behind the textures in the texture window. This is probably best left a neutral color. + +

Grid MajorÂ… +
These bolder grid lines mark 64 unit increments in the map window. These never change. + +

Grid MinorÂ… +
The finer grid lines in the map window. + +

Grid TextÂ… +
The color of the scale numbers along the left and top of the map window. + +

Grid BlocksÂ… +
These lines mark the 1024 x 1024 unit grids on the map. + +

Default BrushÂ… +
This is the color of unselected brushes in the map. + +

Selected BrushÂ… +
The color of selected brushes in the map. + +

Active View NameÂ… +
This is the text that says “XY Top” or “YZ Side” or “XZ Front” in the map view window(s). + + + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch02/pg2_1.htm b/docs/manual/Q3Rad_Manual/ch02/pg2_1.htm new file mode 100644 index 00000000..758469fd --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch02/pg2_1.htm @@ -0,0 +1,213 @@ + + +Q3Radiant Editor Manual: Page 2.1 + + + +

Q3Radiant Editor Manual

+
+

Entities and Assets

+

What are Entities?

+Quake III Arena divides map components into two classes: World Geometry and Entities. World Geometry represents the brushes (the Q3A term for the blocks of geometry used to build the physical game world) and patches (anything built with calculated curves). Entities are a broad category that not only includes simplistic editor representations of game play objects like weapons and ammo, but also includes diverse things like player start spots, and lights. Typically, they are displayed as brightly colored cubes (for those entities not constructed of brushes). The following are the general category of entity types. The actual entities and the rules and tips for their use are listed in Appendix B. + +

Brush entities. The “brush” is the basic building block of Quake engine games (including Quake, Quake 2, Quake III Arena, and a host of games using the engine licenses). In its most basic form, it’s a block, a solid rectangular volume defined by the coordinates of its corner vertices. A single brush or a linked grouping of brushes can be turned into a brush entity. Brush entities include the movers (see below), triggers, and func_statics. + +

Movers. Most moving objects or "Movers" are built from brushes. These include doors, lifts or “plats”, rotating objects, buttons, pendulums and trains (objects following pre-defined paths), and bobbers (platforms that are constantly in motion, up and down or side to side). + +

Triggers. Triggers are brush entities that cause an event to occur when a playerÂ’s bounding box moves inside the volume of the trigger. Triggers can be targeted on many other entities, including most movers and targets. Some triggers also have more specialized functions. There are triggers that cause injury, activate other entities, and push or teleport the players. + +

Targets. Targets are the entities that are activated to cause events to happen in Q3A, or to redirect activations, insert time delays, mark locations for team play, or act as destination points for teleportation or pushing. + +

Lights. These are point lights, disembodied (read as no visible source) sources of illumination. They ca n be targeted at info_nulls to create spotlights. They can be turned into colored lights. Usually, they are used to create unfocused fill light in a large area or placed near glowing surface textures to create an effect. + +

Info. This category includes non-team player spawn spots, targets for lights, and camera locators for intermission shots. + +

Items. With the exception of ammo and weapons, these are things in the map that the players grab to use during play. Included are armor, power ups like the quad, and one-use items like the personal teleporter. + +

Ammo. Locations for ammo boxes. Each weapon type in Q3A has its own unique ammo entity. + +

Weapons. Each of the weapons that can be picked up has an entity that can be placed. + +

Miscellaneous. This is another catchall category. It includes things like the misc_model which links into the models directory when placed, func_timers which are automated repeating triggers, shooters which fire one of three different weapon fire types, camera and portal surfaces, and path corners. + +

What are Assets?

+Assets are the textures, sounds, and models that are used to flesh out the appearance and ambience of a game map. The editor is designed to use the assets stored in the pak0.pk3 file in your quake3 directory. Using Q3Radiant, the mapmaker can work with the assets in the Quake III Arena pak0.pk3 file or create new ones. + +

What are Textures? +
The art appearing on the walls of maps are generally referred to as “textures.” Textures are created and stored as true color targa (.tga) or jpeg (.jpg) graphic files. The textures do not use a pre-defined color palette (as was the case with both Quake and Quake 2). Shader scripts can further combine textures and/or modify them in numerous ways. This document will briefly touch on shaders. For an in-depth treatment of shaders, refer to the accompanying Shader Manual. + +

What are Sounds? +
Quake III Arena world sounds are played by target_speaker entities in the maps. They are stored as 22 khz, 16-bit, mono format .wav files. + +

What are Models? +
The statues and lights in Q3A are models, just like the player characters. They are placed with the misc_model entity. + +

Creating New Assets

+If you are familiar with the required tools, creating new assets for use in Quake III Arena is not particularly difficult. As a rule, you should create new directories for each map with names different from the names used by id. If you are making a map that will be called “H4x0r_D00M”, every directory containing new assets for that map should be titled H4x0r_D00M. This is to try and avoid asset directories overwriting each other as the editor and the game load in assets. + +

Creating Textures +
Any combination of graphic programs and plug-ins that can output a 24 bit MS windows compatible Targa (.tga) or JPEG (.jpg) graphic file. If you plan to make textures that will have an alpha channel component (see glossary for definition), you must have a program that can create 32-bit art with that fourth channel. + +

Adobe PhotoShop has the ability to easily create alpha channels. Paint Shop Pro from JASC (v5.0+) can also make an alpha channel by creating a mask and naming it “alpha”. + +

Generally speaking, regardless of the program used, we found it best to do most of the art manipulation of the alpha channel in a separate layer or file and then paste it into the alpha channel before saving. + +

Setting up Files +
The editor and the game program look for assets to be located along the paths set up in your project file. Start by creating a directory for you new textures by creating file folders to make a directory path as follows: quake3\baseq3\textures\[mymapname] + +

The installation of Q3Radiant will create a text document called “shaderlist.txt” in the following path: + +

    Quake3\baseq3\scripts\shaderlist.txt
+ +

Q3Radiant will use the contents of this script to grab your new textures for inclusion in the game. The contents of shaderlist.txt document will contain a listing of all the shader documents that were used by id Software to create Quake III Arena. + +

Since you will obviously want to create your own shaders, you need to put them in separate folders and create a new shader script for them. + +

If you plan to work on several maps at once and want to distinguish between textures used in each map, simply add additional map names here. For map and mod makers, we STRONGLY recommend that any new shader scripts created use the name of the map or mod in the shader file name. We know we canÂ’t avoid every incident of files overwriting each other, but we certainly can advise you how to try. + +

Now, create another text file within the scripts directory and call it: + +

    [mymapname].shader
+ + + +

This file will contain the shader scripts you write to modify a particular texture. + + + +

Rules +
Follow these rules when creating textures for the Quake III Arena engine: +

    +
  • Save your textures into your new [map name] directories. +
  • DonÂ’t use the same names that id used for textures. It will cause problems. +
  • For best quality, save textures without an alpha channel as 24 bit TARGA files. Using JPEG files can save memory space, but at the risk of losing detail and depth in the texture. JPEG files cannot be used for textures requiring an alpha channel. +
  • Textures containing an alpha channel must be saved as 32 bit TARGA files. +
  • If a new texture requires no further manipulation, it does not need a shader script. +
  • Size textures in powers of 2. Example: 8x8, 16x16, 32x32, 64x64 pixels and so on. +
  • Textures donÂ’t need to be square. A 32x256-pixel texture is perfectly acceptable. +
+ +

Guidelines +
The following are some things the id designers learned about textures. +

    +
  • Create textures in “suites” built around one or two large textures with a number of much smaller supporting detail or accent textures. +
  • Very large textures are possible, but some video cards compress textures larger than 256x256 pixels. +
  • Textures are grouped alphabetically by name in the texture display window, so you may want to give suites of textures similar names. +
  • Use the shader function qe3_editorimage to conserve memory when making multiple versions of a single texture (as in the case of a glowing texture with several light values). +
  • Unless you are creating special effects or textures designed to draw the playerÂ’s eye to a specific spot, muted, middle value colors work best with the game engine. +
  • Extremely busy (a lot of fussy detail) textures can break up or form visually unpleasant patterns when seen at distances. +
+ +

Creating Sounds +
Tools needed: Any sound editing program that can create and save out sound files as 22 khz, 16-bit, mono format .wav files. + +

Set up: The editor and the game program look for assets to be located along the paths set up in your project file. Start by creating a directory for you new textures by creating file folders to make a directory path as follows: quake3\baseq3\sounds\world\[map name] + +

Place your completed .wav files in the [map name] folder. You can access (and play) this file from within the editor (see instructions for Target_Speaker). + +

Creating Models +
Map models need to be converted from their native file format into Quake III ArenaÂ’s native md3 file format. The modeling program, Milkshape 3D supports the file format needed to create map models for Quake III Arena (a link for this program is in the On-line Resources appendix). The compiling process merges the models into the bsp file. If you want other mappers to be able to use your models, you will need to include the md3 and supporting texture files within your pk3. + +

Making the .pk3 File

+When you go to distribute your creation to the gaming world, you need to put your newly created map, textures, bot area files, and shader documents into an archive format called a “pk3” file. You do not need to include the shaderlist.txt file, since only the Q3Radiant editor uses that. Start by creating folders/directories in your root drive (C: for most of us). The game assumes that these folders are placed in the baseq3 directory, so you need to write your path names accordingly. You will need to keep the paths to the various assets the same as they are for the rest of the assets in the game. So your paths should be something like this: + +
    Textures: textures/[mymapnamefolder] + +
    New Models: models/mapobjects/[mymodelnamefolder] + +
    Map, bsp & aas: maps/mymapname.bsp , mymapname.aas + +
    Shader scripts: scripts/mymapname.shader + +
    Server scripts: scripts/mymapname.arena +
+ + +

Move or copy all your new game assets in their folders. + + + +

We used an archiving program call Winzip to make the pk3 file. Get Winzip from WinZip.com + +

NOTE: Do not include or redistribute any game assets that are not your own (at least without permission). This specifically refers to id-copyrighted material that came with the original game or subsequent id released patches. + +

Make a zip archive called “map-mymapname.zip” + + + +

If you plan on distributing other resources separately, we strongly recommend the following naming conventions: + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
md3-xxx.pk3User Model with original associated skin files and sound files
bot-xxx.pk3User bot files. May contain additional model or skin and texture files
skin-xxx.pk3User skin with associated skin and texture files
map-xxx.pk3User created map(s) and supporting files (arena, texture, sound, music)
tex-xxx.pk3User texture and shader files
snd-xxx.pk3Sounds only
mus-xxx.pk3Music only
pfb-xxx.pk3Map prefabs
+ + +

(special thanks to Rogue13 of http://www.polycount.com for this naming convention) + + + +

When you go to add a resource to the archive, click on options to “Recurse Folders” and “Save Extra Folder Info” + + + +

Zip all the required assets into a zip archive file (Quake III Arena DOES support compressed pk3 files). + + + +

Rename the zip archive to mymapname.pk3 + + + +

Put it where the Quake III Arena community can find it. + + + +

My .pk3 File is Huge! No One is downloading it! +
Large pak files are daunting as downloads. And as specified by the Quake III Arena End User License Agreement, that is the only way those new game assets may be distributed. Be kind and remember that not everyone has access to DSL, ADSL, ISDN, Satellite, Cable Modem or other high speed internet connections. Before packing up your resources, you may want to look into some dieting tricks to make it smaller. + + + +

    +
  • First, resave all your new non-alpha channel textures in JPG format. That will give you some significant art size savings. +
  • Streamline your mapÂ’s art package. Id designers had to go on a rip ‘n strip rampage through their levels to cut down on unique texture usage. Do you really need all that additional art? Can you substitute more of the original Q3A art, or get more duty out of some of your new work? +
  • Recompile your area files with the optomize switch. That will reduce their size. That's why it's in there as a command. This is also one of the biggest savings that you can make. +
  • Turn up the level of compression when archiving into the pk3 file. +
  • Compress again when zipping up the files. +
  • Take a SERIOUS look at any new sound resources you've created. Sounds, especially long sounds can be HUGE! Can short sounds be cleverly used to replace longer sounds in your map? The id designers did a bunch of that for Q3A. Very short sounds, played off sync against each other were made to sound like longer, more expensive sound files. +
+ +

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/ch03/pg3_1.htm b/docs/manual/Q3Rad_Manual/ch03/pg3_1.htm new file mode 100644 index 00000000..91bbb4c5 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch03/pg3_1.htm @@ -0,0 +1,265 @@ + + +Q3Radiant Editor Manual: Page 3.1 + + + +

Q3Radiant Editor Manual

+
+

Map Building Basics

+Once you have the editor installed and the preferences set, open the map and letÂ’s get started. + +

Moving Around

+There are a number of ways to move your point of view around in the map and camera windows. Some are easy to master. Others are a bit trickier. Find one that works for you and master it. + + +

Moving in All Directions +
All movement directions are given relative to directions in the XY map. When other map views are shown, movement is still calculated in terms of the XY view. Key press movement occurs in discrete increments. + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Forward (in facing direction)(Up Arrow Key) or (Keypad 8)
Turn left(Left Arrow Key) or (Keypad 4)
Turn right(Right Arrow Key) or (Keypad 6)
Backward(Down Arrow Key) or (Keypad 2)
Move up(D)
Move down(C)
Look up(A)
Look down(Z)
Level View(END)
+ +

Flying Â… through the Map (and other 3D commands) +
Some mappers prefer using mouse-fly to move around their map. Mousefly works by clicking and pressing with the Mouse button 2 (Right mouse button) on the Camera window. This takes a lot of practice to master. Clicking farther away from the window center increases the speed of movement. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Forward (in facing direction)(Right Mouse click above of window center)
Turn left(Right Mouse click left of window center)
Turn right(Right Mouse click right window center)
Backward(Right Mouse click below window center)
Move up(D)
Move down(C)
Look up(A)
Look down(Z)
Level View(END)
+ +

Zoom with a View +
The zoom keys increase or decrease the visual scale of the map, letting you move in close to work with small details or move away to see the entire map at once. Currently, there are 24 steps of zoom, from most distant to closest. If Quad view is used (XY, YZ, and XZ views simultaneously), all three windows may zoomed at different scales. The Z-axis scale window is also zoomed separately + + + +

Zoom in +
(DELETE) + + + +

Zoom out +
(INSERT) + + + +

Z-axis Zoom in +
(CTRL + DELETE) + + + +

Z-axis Zoom out +
(CTRL + INSERT) + + + +

Jump to Location +
(CTRL + Middle Mouse Button) + +
Click on a 2D map or the Z-axis window and your point of view immediately moves to that location. In the 2D map windows, neither the facing, nor the “height” of the point of view changes. + + + +

Moving the Maps Around +
A right-mouse-button click and drag on a 2D Map window will cause the map to be dragged, allowing you to easily reposition what is being viewed. + + + +

Basic Construction Tutorial

+ + +This is a simple, step-by-step guide to making your first room. Before attempting it, you may want to familiarize yourself with some of the Brush selecting and handling tools. A Quake III Arena aficionado who goes by the handle “The Dog!” posted this simple tutorial on a Quake III Arena on-line message board. It appears here with his permission. It will walk you through creating a new map file, making your first “brush,” adding a start spot and a light and then compiling the map. + +

The Dog!Â’s Ten Quick-n-Dirty steps to a SIMPLE room: + + +

  1. Create new map: + + +
    1. Click file, new map
    + + + +

  2. Create a small hollow room (make a box and hollow it out): + + +
    1. Make a box. In the XY Top window, click/hold your left mouse button at coordinates 256,-256 (upper left) - then drag your mouse to the -256,256 (lower right) [you should see a red square appear in grid]. + + + +

    2. Make the box taller. In the Z Window (this is also called the height bar): This brush appears as a red box. Click/hold your left mouse button above the upper edge of the box and drag that bar up to about 256. [you have just raised the height of the box] + + + +

    3. Make it hollow. On your Toolbar below the Menu bar, locate the 'Make Hollow' Button (should be a red box with a dotted box inside of it )located under the M in Misc). Press that button. This breaks the box up into six pieces: four walls, a ceiling and a floor. [you should now see a hollow room in the texture view window] +
    + + +

  3. Press Escape to deselect the box (you are finished with room/box for now). + + + +

  4. Add a player starting point: + + + +
    1. Bring up the Easy Entity Menu. With your pointer over the room in the XY Top window, right mouse click INSIDE the newly created room box to open up the easy entity menu. + + + +

    2. Place a Start Spot. Select info, then select info_player_deathmatch. [you should see a small pink box appear - this is where you will start in this map anytime its loaded] + + + +

    3. Is it in there? Make sure that your new starting point is 'really inside' the room that you have created. + + + +
      1. Click the xyz button on your toolbar so that you can toggle through each 'view' of that coordinate (XY top, XZ front, or YZ side). + + + +

      2. Watch the red box (info_player_deathmatch) as you toggle through each view to make sure the red box is inside room + + + +

      3. If there is a view it is not located inside - simply stop and drag it inside the box. (You can learn how to put it in optimal places later), until it is totally inside the room. +
      +
    + +

  5. Press Escape to deselect the info_player_deathmatch item. + +
    The box now turns into a solid pink, box outline. + + + +

  6. Now add some textures: + + + +
    1. Load up Textures. Click on the texture menu and drag down to select the gothic_wall texture directory. + +
    2. Open Texture window. Press “T” to open the texture window. It should be full of wall textures. + +
    3. That wall will do just fine. Then decide what wall surface you want to apply the texture to. Hold the left-CTRL and the left-SHIFT key down and then left click on a wall. The wall will turn red. + +
    4. Pick a Texture, any Texture. in the 'texture view' window, left mouse click on any wall texture. A red border will now surround this texture. And presto, the wall becomes that texture too. + +
    5. Repeat this step for all the walls that you want to apply textures to. +
    + + + +

  7. Save your map. +
    The editor doesn’t like to work with “unnamed” map files. From the menu, select File > Save. Name the map “test1”. Always use lower case for your map names. + + + +

  8. Add a light. + +
    1. Bring up the Easy Entity Menu Again. With your pointer over the room in the XY Top window, right-mouse-click INSIDE the newly created room box to open up the easy entity menu. + + + +
    2. Place a Light. Select info, and then select light. [You should see a small red box appear (smaller than the player start).] + +
    3. Move it into place. Do the same procedure you did for the player start spot, making sure that this light is inside the room. + +
    4. Deselect the light. It will become a green box. +
    + + + +

  9. Compile it. +
    In the BSP menu, select “bsp_fastvis”. Wait patiently for the program to finish three phases of compile: bsp, vis, light. + + + +

  10. Start ‘er up. +
    Start your Quake III Arena game. When the menu appears, hit the tilda key (~). On most American keyboards, this is in the upper left corner of the keyboard, below ESC. + +
      +
    1. Set your game to run the map. In the console, type "/sv_pure 0" +
    2. Enter the Devmap. In the console, type “\devmap test1” and then ENTER. +
    3. Play it for all itÂ’s worth. The map should start and you will be standing in the center of your first room. +
    +
+ + + +

Now go make something more complicated on your own! + +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch04/pg4_1.htm b/docs/manual/Q3Rad_Manual/ch04/pg4_1.htm new file mode 100644 index 00000000..94575ba3 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch04/pg4_1.htm @@ -0,0 +1,174 @@ + + +Q3Radiant Editor Manual: Page 4.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 1: Selecting and deselecting

+The most basic interaction with the editor is selecting and deselecting the map components. Everything else builds off from these commands. + + + +

The Component Handling Tools

+
Escape (ESC)
+This is the all-purpose deselect key. Use it to back out of operations you donÂ’t want to complete or to stop working on a map component or group of components. + + + +

Select single component
+ + +In the XY Window (or XZ or YZ), this selects a single map component that is “closest” to the top of all components beneath the pointer. The following is an exception: If an entity is directly beneath the pointer, it will be chosen in preference to a non-entity, even if the non-entity is “between” it and the pointer. + + + +

Select single face on brush
+ + +This selects a single face on one brush, not the brush itself. + + + +

Select multiple faces on one or more brushes
+ +Use this to select several brush faces on one or more brushes. + +

Cycle through stacked components
+ +Beginning with the component that has the greatest Z value, the user can cycle through vertically stacked components that are directly beneath the mouse pointer. + + + +

Deselect single component
+ +In the XY Window (or XZ or YZ), SHIFT clicking on a selected component deselects it. The following is an exception: If a selected entity is directly beneath the pointer, it will be chosen and deselected in preference to a non-entity, even if the non-entity is “between” it and the pointer. + + +

Deselect all selected components
+ + +All selected components are deselected. + + + +

Group Component Selections

+There are four commands for selecting large groups of components. These involve creating a brush that encloses or touches numerous other components. In most cases, the brush used to create the grouping is deleted by the operation. These operations can be selected by menu commands or by buttons on the toolbar. The toolbar buttons are in the third grouping (as counted from the left). The command buttons on the toolbar are given as they relate to the Selection sub-grouping on the toolbar. + + + +

Design Note: These grouping commands are particularly useful when you want to region off a small area of the map.
+ +

Select Complete Tall
+ +All brushes from the top to the bottom of the map that are totally enclosed within the XY dimensions of the grouping brush will be selected. The grouping brush is discarded. + + + +

WARNING: Undo will restore selected components but will delete the selection brush. + + + +

Select Touching
+ +All brushes that are in contact with the grouping brush will be selected. The grouping brush is NOT discarded. + + + +

Design Tip: Need to work an area around a particular brush? Use this tool to select the brush and then use the selected brushes to create a regioned area.
+ + + +

Select Partial Tall
+ +All brushes from the top to the bottom of the map that are touched by the XY dimensions of the grouping brush will be selected. The grouping brush is discarded. + + + +

Select Inside
+ +All brushes from the top to the bottom of the map that are totally enclosed by the XY and Z dimensions of the grouping brush will be selected. The grouping brush is discarded. + +

Copying, Pasting, Cloning, Deleting and Prefabs

+
Save Selected
+(Menu: File) +
The selected brushes are saved as a map file. Not a true prefab, but a way to duplicate pieces of a map for later insertion. + +

Copy brush
+(Menu: Edit) +
(CTRL+C) +
This function copies all hi-lighted brushes, patches, and entities onto clipboard. Contents of clipboard may be pasted into the current open map file or into another open map file. + +

Paste brush
+(Menu: Edit) +
(CTRL+V) +
The map information previously copied into the clipboard is pasted at the same XYZ coordinates as the original. UNDO will delete the paste + +

Clone
+(Menu: Selection > Clone) +
(Shortcut: SPACE) +
Selected map components are immediately duplicated. The clone appears +1x and -1y units (current map grid) away from the original (down and to the right). The clone remains hi-lighted until deselected. + +

Save Selection as Prefab
+(Menu: EditèSave Selection as Prefab) +
(Shortcut: none) +
The user is prompted to save the selected map components as a prefab file (*.pfb) in the directory set by Preferences. + + +

Load Prefab
+(Menu: EditèLoad Prefab) +
(Shortcut: none) +
Opens a file selection window into the directory set in Preferences. Select from that directory or browse for another. The selected prefab is pasted into the map at the same XYZ coordinates as the original. + +

Delete
+(Menu: Selection > Delete) +
(Shortcut: BACKSPACE) +
All selected map components are removed from the map. + +

Undo
+(Menu: Edit > Undo) +
(Shortcut: none) +
Undo will undo recent command actions affecting brush geometry, curve patches, and in-map comands that affect entities (move, rotate, delete, etc.). Undo has no effect on texture operations. + +

The number of levels or layers of Undo can be set in Preferences. The maximum number is 64. Unless your computer memory is extremely low, there is no real reason to use less than all 64 levels of Undo. + +

Working with Regions

+Regions are an important tool to learn and use early on. Whether you isolate off a single brush, or half a map, you’ll wonder how you ever got along without this tool in other editing programs. The selections on the Region Menu allow the mapper to isolate, and work on, a subset of the map. There are innumerable benefits to working in a “regioned” area of the map. However, the following are the most important: +
    +
  • It allows you to work with a few map components at a time, without the distraction of the rest of the map pieces. +
  • When you want to perform CSG operations, regioning lets you isolate the pieces from the rest of the map, reducing risk of making unwanted cuts or splits. +
  • Map regions can be compiled without having to compile the rest of the map. This can be an incredible timesaver. Instead of spending hours to compile an entire map just to check for leaks in new construction, or check the appearance of a room, or test a lighting effect, minutes can be spent processing just the room itself. +
+ +

There are several ways to select a region, by a group selection, by XY map window dimensions (or the corresponding view in YZ and XZ), or by a few selected map components. + +

The commands for selecting regioned areas are found under the Region Menu heading. + +

Region Menu
+Off + +This returns you back to the full map. Brushes that were selected while in the regioned mode remain selected until ESC is pressed to unselect them. + +

Set XY +

+Any map components that are inside, or that are touched by the bounds of the XY Map window are converted into a region. The size or shape of the window does not matter. Nor does the degree of Zoom matter. This is an excellent way to select are larger subset of your map, such as a complex room or group of rooms. Any brushes selected before regioning the map remain selected. + +

Set Tall Brush +

+This functions in a similar manner to the group selection command, Select Partial Tall. Any map components contained within the XY bounds, or touching the XY bounds of the brush will be regioned off. The selecting brush itself is discarded. + +

Set Brush +

+This functions in a similar manner to the group selection command, Select Touching. Any map components contained within the XYZ bounds of the brush, or touching the XYZ bounds of the brush will be regioned off. The selecting brush itself is discarded. + +

Set Selected Brushes +

+If you need to work with just a few brushes, this is the option to choose. Hi-light the brushes to be worked upon then select this option. Only those brushes are moved to the region. The selected brushes are unselected when the region is created. + +

Compiling Notes: Sometimes, when compiling a regioned area, md3 map object models near the edge of the region can cause a “false leak” situation to occur. This can usually be corrected by adjusting the region size to include more of the map near the md3 map object model. + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch05/pg5_1.htm b/docs/manual/Q3Rad_Manual/ch05/pg5_1.htm new file mode 100644 index 00000000..ec02e30a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch05/pg5_1.htm @@ -0,0 +1,784 @@ + + +Q3Radiant Editor Manual: Page 5.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 2: Working with Brushes

+ +

The geometry brushes are the basic building block of the Quake +III Arena engine. These are the tools to make them work for +you. + +

Geometry Brush Handling Tools

+
Escape (ESC)
+This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on a brush +or group of brushes. + +

Create New Brush
+ + + +While mouse1 clicking over the main map window (or any open map +window) drag the mouse pointer across the grid. A brush will be +created that has the height of the current map grid size. If you +have the "snap to grid" function set in your preferences, the brush +will start and stop on gridlines. The texture will be either the +default texture (if none has been selected) or the most recently +used texture. For all these functions, you will first need to +select a brush in either the Map or Camera windows. + +

Move Geometry Brush
+ + + +The Undo command will return the brush to its original size (if +the brush is still selected). If the brush has been deselected, the +resized version will remain and another brush will be created at +full size. + +
    In the Map Window. In the map window, select the +brush. Click on the selected brush. With the mouse 1 button +depressed move the brush around the map to the position you +desire. + +
    In the Z (height) Window. In the map window, select the +brush. Next, click on the selected brush in the Z window. With the +mouse 1 button depressed move the brush around the map to the +position you desire. + +
    In the Camera Window. Select a brush in the camera +window (see select single component above). +Mouse button 1 click on the brush and drag it in the desired +direction. You may need to adjust your camera view to make dragging +easier.
+ +

Stretching the Brush
+ + + +Think of this as stretching the brush. The Undo command will +return the brush to its original size (if the brush is still +selected). If the brush has been deselected, the resized version +will remain and another brush will be created at full size. + +
    In the Map Window. In the map window, click next to the +selected brush on the side you want to pull. With the mouse 1 +button depressed pull in a direction away from the nearest edge. +The brush will grow larger in that direction. + +
    In the Z (height) Window. Use this to make the +brush taller. In the Map or Camera window, select the brush. +Next, click above or below the selected brush in the Z window. With +the mouse 1 button depressed pull away from the select brush. The +brush will grow in that direction. + +
    In the Camera Window. Select a brush in the camera +window (see select single component above). +Mouse1 click near the edge of the selected brush. With the mouse 1 +button depressed pull in a direction away from the nearest edge. +The brush will grow larger in that direction. You may need to +adjust your camera view to make dragging easier.
+ +

Shrinking the Brush
+ +Think of this as crunching the brush smaller. + +
    In the Map Window: In the map window, select the +brush. Click next to the selected brush on the side you want +to pull. With the mouse 1 button depressed pull in a direction +toward the nearest edge. The brush will shrink in that +direction. + +
    In the Z (height) Window: Use this to make the brush +shorter. In the Map or Camera window, select the brush. Next, +click above or below the selected brush in the Z window. With the +mouse button 1 depressed, push towards the select brush. The brush +will shrink in that direction. + +
    In the Camera Window: Select a brush in the camera window +(see select single component above). Mouse1 +click near the edge of the selected brush. With the mouse 1 button +depressed push in a direction towards the nearest edge. The brush +will grow larger in that direction. You may need to adjust your +camera view to make dragging easier.
+ +

Flip Brush
+ + + +There are three separate actions here. They flip a brush +along either X, Y, or Z-axes. A menu command and toolbar button +controls each. The six flip and rotate toolbar commands are the +second grouping (from the left) on the toolbar. The rotate +command for the same axis is always next to the flip command. +Flipping will not change the facing on non-model entities. + +
    Flip X (Menu: Selection) (Toolbar: Leftmost button) + +
    + +Flips brush along x-axis. + +
    + +Flip Y (Menu: Selection) (Toolbar: left of center +button) + +
    + +Flips brush along y-axis. + +
    Flip Z (Menu: Selection) (Toolbar: second button from the +right) + +
    + +Flips brush along z-axis.
+ +

Rotate Brush
+ + +There are three separate actions here. They rotate a brush +in 90 degree increments around a brush's X, Y, or Z axes. Both a +menu command and toolbar button controls each action. The six flip +and rotate toolbar commands are the second grouping (from the left) +on the toolbar. The flip command for the same axis is always next +to the rotate command for the same axis. The rotation will not +change the facing on non-model entities. + +
    + +Rotate X + + +Rotates brush around the x-axis. + +
    + +Rotate Y + + + +Rotates brush around the y-axis. + +
    Rotate Z + + +Rotates brush around the Z-axis.
+ +

Arbitrary Rotation
+ +The Rotate commands accessed from the toolbar all rotate +affected map components 90 degrees; no more, no less. Arbitrary +Rotation allows the user to set angles individually for the X, Y, +and/or Z-axes. Enter a number value for each axis you want to +rotate. Value can be positive or negative. After the values are +entered, select OK. This rotates the object and closes the pop-up +window. If you don't like the rotation, you can use Undo, so long +as the brush is still selected, and the brush will return to its +un-manipulated facing. + +

Free Rotate in Map Window
+ +Press the "R" key. The selected map component(s) turns lavender. +The purple square at the center is the center of the selection and +the axis around which it will rotate. Left Mouse clicking on or +near the selected component (in the map or camera window) and +dragging will cause it to rotate. If the user does a SHIFT + middle +mouse button click on the 2D map window, the axis square will +relocate to the coordinates of the click. Deselecting and +reselecting the component returns the axis to its original +center. + +

Drag
+ +There are two "drag" functions that involve control points or +"handles" on the brush. + +
    Drag Edges + + + +This highlights the edges of a geometry brush, marking those +edges with a blue "handle" box at the center of each side. Press +again and the feature will toggle off. Pull on a handle to resize +part of a brush. If Snap-to-Grid is active (Menu: Grid), the +handle will snap to the nearest grid coordinate as it is pulled. +Undo functions with this effect. + +
    Drag Vertices + + + +This highlights the corner vertices of a geometry brush, marking +those corners with a green "handle" box where the sides of each +brush face connect. Press again and the feature will toggle off. +Pull on a handle to resize part of a brush. If Snap-to-Grid +is active (Menu: Grid), the handle will usually snap to the nearest +grid coordinate as it is pulled. Undo does NOT function with this +effect.
+ +

Design Note: Drag Vertices is a balky tool at best. It +works well if the user is manipulating a triangular brush face, +raising or lowering corners of the triangle. Work with care, it is +quite easy to pull a brush out of useable (or recoverable) +shape.
+ +

Scale
+ + + +With Scale you can enlarge or reduce a brush, patch, or group of +brushes and patches. You choose the axes to scale (X, Y, or Z) and +the factor of the scale. The scaling factor can be different for +each axis. Selecting this option brings up a tool window. The size +of the brush or group of brushes is multiplied by the numbers in +the boxes adjacent to the X, Y, or Z axes. Leave the value as 1 and +no change occurs. If the value is a decimal less than one, the size +of that axis shrinks. If the value is greater than 1, it grows. Hit +OK to activate the scaling function with you chosen values. Undo +functions with this effect. + +

CSG Operations
+ +CSG stands for "Constructive Solid Geometry". The two +functions here, CSG Subtract and Make +Hollow, calculate the removing of sections from that +geometry and breaking solid brushes (not curve patches) into +smaller pieces. Although they are convenient to use for some +operations, they often do things that the user may not care for. +These "side effects" can include breaking brushes into inconvenient +parts, cutting up adjacent brushes, and creating hard to find and +remove micro brushes. + +

Subtract +

+When you select this, the selected brush or brushes subtract its +volume from all the geometry that contacts it. The cutting brush is +not removed. Undo does not fix this action. + +

Design Note: Region off together the brushes that will be +cut and the brushes which will be used for cutting. This keeps +other brushes in the map from being affected by the action. It's +also a good idea to save just before doing the action, so the user +can "back up" to an earlier version.
+ +

Hollow + +

+ +When the user selects this, the sides of the highlighted brush +are turned into separate brushes. The thickness of these brushes is +equal to the grid size. Undo functions with this action. + +

Design Note: This works best with rectangular +brushes. The edges of the created brushes overlap each +other.
+ +

Merge +

+When the user selects this, the highlighted brushes are turned +into a single, convex brush. If the result of the merge would not +create a convex brush, the following message appears in the editor +console: " Cannot add a set of brushes with a concave hull." + +

Examples: Example "A" shows two brushes can be +merged together. Example "B" shows two brushes that cannot +merge. + +

image028.png + +

Clipper
+ + + +If you think of this tool as being near the same as the miter +box that a carpenter uses to cut wood or moldings, then you are not +far from the truth. + +

Placing Clip Points + +
Clip points are placed in the map views by two methods: + +

+ +

The figure below shows a square brush that has been "clipped" +from the lower left (point 1) to the upper right (point 2). The +editor creates a line between the first point and the second point. +The piece to be kept when the brush is cut is always created in a +clockwise direction from the line (assuming that the first point is +the center of the "clock") + +

In a two-point clip (shown here), the cut occurs perpendicular +(at a 90 degree angle) from the plane of the map view. Adding a +third point, and adjusting its position in a different map view can +change the angle of the cutting plane. This will take practice to +master. + +

    Toggle Clipper + + + +This toggles the Clipper function on and off. After completing a +cut, the tool remains active and must be toggled off before another +brush is selected. + +
    Clip Selection + + + +If the "clip selection" action is completed the red portion of +the brush will be discarded and only the yellow will remain. The +brush is unselected. Undo currently returns the original brush and +keeps the clipped off piece. + +
    Split Selection + + + +If the "split selection" action is completed the red and yellow +portions of the brush will remain, split into two triangular +brushes. The brush is unselected. + +
    Flip Clip Orientation + + +The yellow and red hi-lights toggle so what was red is now +yellow and what was yellow is now red.
+ +

Make Detail
+ + + +In Quake 2, this was a surface flag. In Quake III +Arena, it is used on the brush itself. Detail makes a brush +non-structural. This means that it cannot be used to seal the hull +of the map world. Don't use it for wall, floors, or ceilings. If it +is used as a hull, the map will "leak" when compiled. But it can be +used on things that jut out away from the walls (as long as there +is a structural brush behind it). + +

Detail has two beneficial effects: + +

1. Detail brushes are less likely to cause additional cuts to +occur in non-detail brushes that they touch ... thus reducing +triangle counts. This can help reduce frame rate. + +

2. When the compiler does Vis, it breaks the world up into many +small volumes. Any break in the surface of the box that forms a +room creates additional volumes that must be. Detail brushes don't +create these breaks. Therefore, using them speeds up compiling. + +

Make Structural
+ + + +Structural is the Default State for brushes. Textures that are +not manipulated by shader scripts to be transparent or non-solid) +do not change this. Essentially, this is a change-it-back +command for Make Detail. It removes the detail flag from the brush. +This surface WILL block Vis when the map is compiled (so long as +there isn't shader content that says otherwise). + +

Func_Group
+ + + +Technically, this is a b_model (brush model) entity. However, +it's a great way to manage and handle related groups of map +components for ease of selection. To use, select the brushes +and patches you want to group and then open the Entity window +(press "N"). Click on the entity list sub-window and type in "F" to +move to the top of the "funcs". Double-click on Func_Group and all +the brushes and patches selected are bound together into a group. +Select one and you select them all. + +

Thumb through Components + +
(Shortcut: TAB) + +When you have a Func_Group b_model entity selected, press the +TAB key to "thumb" through the component pieces, hi-lighting them +individually, one at a time. This allows you to work on part of a +multi-piece group without having to work on all pieces + +

Find Brush
+ + + +Find brush allows you to locate a brush in the map by its +identifying number. As the map is built, the editor assigns +identification numbers to each map component. For brushes (and +patches) these include an Entity number and a brush number. For any +brush that is not part of a brush model (b_model), the entity +number is zero (0). Each b_model will have it's own number. + +

When the compiler outputs error messages in the console and +junk.text file, an identification number will call out brushes with +problems. Be prepared for them. Even when you do things right, you +will get error messages. + +

Selecting Find brush pops up a dialogue window with two fields. +The first field is the entity number. For most brushes, this will +be zero. The second number is the brush's individual number. +Selecting "OK," jumps the 2D map window(s) to the selected +component and hi-lights it. + +

Brush scripts…
+ + + +The command allows you to perform multiple step operations that +manipulate a single brush. Currently, only two of the list scripts +function. + +

+ + + + + + + + +
BuildSpiralThis walks you through the steps of building a spiral staircase. +Select a brush, then click on the map to locate the spiral origin. +Click again to bring up a dialogue window that prompts you to enter +the number of steps, the angle of rotation, and the height of each +step.
+ BuildStepThis clones the selected brush and moves it +X 16 units and +Z 8 +units.
+ +

Brush Menu Commands

+ +The Brush menu lets the mapmaker convert a selected brush into a +brush of a different shape. Most of the commands change the number +of sides that the brush possesses. It will also change the brush to +a single color. There are individual commands for three through +nine sides. The brush will be given the number of sides indicated +by the command (Plus top and bottom). The "top" facing is always +relative to the view in which it is created. The sides are always +at right angles to the view facing. + +

Poly-Sided Brushes
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Arbitrary sided…
+ + + +This command opens a dialogue window. You can enter a number of +sides in the field from 3 to 64. Select OK to execute the +command. + +

Primitives
+ + + +Primitives are pre-made shapes other than squares or the +polygonal multisided boxes made by the "number" sided brush +commands. + +

Cone… + +

+ +This opens a pop-up dialogue window that lets you enter an +arbitrary number of sides. The height of the cone is equal to the Z +height of the brush. The cone is always made with its axis along +the Z-axis. At first, the radius of the base of the cone appears to +be unrelated, or at least unevenly related to the XY dimensions of +the brush from which it is transformed. However, if you make a four +sided brush, the point to point "diameter" of the resulting pyramid +is equal to the longest XY dimension of the brush. Starting the +same size brush as you used for the four-side cone, an eight-sided +cone fits neatly within the volume of the four-sided cone, four of +its sides congruent with the side planes of the four-sided cone. Do +the same for a 16 sided cone, and the same again for both a 32 +sided cone. However, the number of sides seems to max out at +56. + +

Sphere… + +

+ +This opens a pop-up dialogue window that lets you enter an +arbitrary number of sides. The maximum number of sides, which the +editor seems willing to handle is 32.The diameter of the sphere, is +roughly equal to the length of the longest XY side of the brush +from which it is transformed. Attempts to create spheres with more +faces than 32 may result in the brush disappearing and becoming +infinitely tall. Use Undo to back up from this or hit backspace to +discard the brush. + +

Torus… + +
Non functioniong command. No donuts for you! + +

Moving +Selected Brushes

+ +
Moving the Brush
+ +These keys move the brush around the map in discrete map grid +increments. + +
    Move Selection Down + + +Each press moves the selected map component down along the +Z-axis by one grid position (at current grid setting). Not affected +by current 2D-map view. + +

    Move Selection Up + +

    +Each press moves the selected map component up along the Z-axis +by one grid position (at current grid setting). Not affected by +current 2D-map view.
+ +

Nudging the Brush
+ +These keys move the brush around the map in discrete map grid +increments. The movement is in terms of the selected window, not in +terms of XYZ coordinates. + +
    Nudge Down + + + +Each press moves the selected map component "down" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + + + +

    Nudge Up + +

    + +Each press moves the selected map component "up" the map view by +one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Left + +

    + +Each press moves the selected map component "left" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Right + +

    + +Each press moves the selected map component "right" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates.
+ +

Snap Selection To Grid
+ + + +If you are using the map grid to keep brushes in alignment, this +is a great tool. Rotated brushes and brushes that have had their +vertices tweaked can have vertices that no longer lie on map grid +intersections. This snaps the vertices to align with the +grid. Be warned that snapping to large grids may be hazardous +to the health of your brush (Snap and it's gone! But that's what +UNDO is for). + +

Efficient Brush Building +Techniques

+ +

Developed from a Quake 3 World online posting by +Astrocreep + +

Compiling a map is a necessary evil. It takes time, it ties up +your processor, and in the early phases of map construction, comes +up with construction errors as often as not. Nothing you can do +about that … except the time thing. It is possible, +through more careful construction (or perhaps reconstruction) to +significantly reduce both map and bot compile times, and reduce map +and .bsp file sizes (the latter being important for downloads). The +following is based on reports written by Astrocreep that documents +his extensive work to streamline the compile on one of the id +sample maps. + +

Brush Construction
+ +It cannot be overstressed. If you want shorter compile times and +small file sizes, efficient brush construction is "critical" in +building your map. There is one rule that stands above all: + +

+DO NOT OVERLAP BRUSHES AT ANYTIME. + +

No matter what you have to do to build your map, do not overlap +brushes. Overlapping means that all or parts of two or more +brushes share the same physical space. If brushes overlap, you can +expect to add time to your compiling, and add size to your .map, +.bsp and, .aas file sizes. + +

Efficient map construction means that all brushes butt up +against each other, but never intersect. + +

Brush Counts
+ +The sample map to be reworked on had 1,100 brushes in it. +Without changing the layout or appearance of the map, Astrocreep +was able to remove 110, or 10% of the total brush count. + +

Learn how to do more with a single brush than with multiple +brushes. Evaluate your map after you complete initial construction +phases on all or part of it. Pick a part of the map, look at +the layout and ask yourself if you could do that with fewer +brushes. In all likelihood, nine times out of 10, the answer will +be yes. + +

If you make a structure out of three brushes (or whatever) and +have the same floor height and ceiling height (in some cases +heights can be different), look at it in the "top view". Can you +draw a line from each vertex and not cross out side of those three +brushes? If you can, then that grouping of three can become one +brush instead of three. + +

Example: here's how the engine might look at this. + +

Using 3 square brushes, you have 18 faces (with a texture mapped +on each side) to be calculated. This doesn't take into +consideration the number of in-game triangle faces that those +brushes may generate. Even if two-thirds of those faces are not +being drawn, they are still being calculated by both the compile +process and the bot navigation compile process. + +

As compared to: + +

Using one brush (filling the same area), you have only 6 faces +to be calculated. Here, you are compiling only a third of the total +geometry. It should go faster. + + +

Efficient map construction means using fewer brushes to build +the world. + +

+Caulking
+ +It is possible to even further reduce the number of brush faces +being calculated by applying a special non-drawing, but "solid" +texture called "caulk" (common/caulk) to surfaces that cannot be +seen in the game. When seen in the editor, this texture is a bright +garish pink. In the game, it does not draw at all. Apply caulk to +any brush face that either doesn't form the "shell" of the world or +can't be seen by a player during play. Doing this may not improve +your map's frame rate, but since your are telling the compiler that +as many as five of the six faces on a square brush don't have to be +calculated, it should have some significant effects on compile +times. As long as you do not have any brushes that "share" the same +space, caulking brushes should help reduce compile times. However, +if you use caulk on a brush that "shares" the space of another, +your compile time and all file sizes will actually increase. + + +

Astrocreep compiled the test level nearly 200 times, many of +those times were when he moved just a single brush, just to see +what would change. Caulking seems to help the -light phase +of compiling the most. + +

+Efficient map construction means caulking all unseen brush +faces. + +

Miscellaneous Tips
+ +Lights: You can further improve compile times by careful +use of lights. Entity lights, especially LOTS of entity lights can +reduce compile time. If you need to reduce compiling time even more +look to this. + +

Clip brushes: Clip brushes that have more than two sides +not touching another brush appear to increase compile times. + +

Hint brushes: Use these only if you need to resolve a vis +problem. Using them can significantly add to compile times. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch06/pg6_1.htm b/docs/manual/Q3Rad_Manual/ch06/pg6_1.htm new file mode 100644 index 00000000..e9133e04 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch06/pg6_1.htm @@ -0,0 +1,624 @@ + + +Q3Radiant Editor Manual: Page 5.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 3: Working with Curve Patches

+ +
Escape (ESC)
+ +This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on a patch +or group of patches. + +

Curve Menu Commands

+ +The next set of commands comes from the Curve Menu. Some are +duplicated on the Patch Tool Bar. + +

Cylinder
+ + +This creates the simplest cylinder. Cylinders are always drawn +with their open ends facing up and down. It does not matter which +map view is open when the cylinder is created. + +

More Cylinders: + +

+ +
    Dense Cylinder + +
    This is a cylinder with a set of extra rows. It allows a +180-degree bend into a half donut (half torus). + +

    Very Dense Cylinder + +
    This is a cylinder with two extra sets of rows. This allows a +bend into a full donut (torus). + +

    Square Cylinder + +
    This is a cylinder whose columns have been adjusted so that a +square, with flat sides, is formed. +

+ +

End Cap
+ + +This is a half cylinder. + +

Bevel
+ + +This is a quarter cylinder + +

More End caps, Bevels: + +

+ +

Square Endcap + +
This is an endcap without the backside removed. + +

Square Bevel + +
This is a bevel with squared off back faces + +

Cone
+ + + +A cone is a cylinder with control points drawn together and +welded at one end to form a point. + +

Sphere
+ + + +
Design Note: A curve patch sphere can be constructed from +a cone. Start with a cubic brush. Convert into a cone. Go into edit +vertexes mode and grab the control point at the peak of the +cone. Pull it downward to half the height of the cone. Clone +the resulting piece and flip it upside down.
+ +

Simple Patch Mesh…
+ + + +The patch mesh is the basic building block use to create all +curves. All the curve primitives are deformations of this +item. For this to work, you must first create a brush of the +dimension desired for the patch. Selecting this opens a Patch +dialogue window. This lets you select the vertical (rows) and +horizontal (columns) complexity of the patch. The more complexity +means being able to perform more deformations on the patch. It also +means adding a greater number of triangles that must be +rendered. + +

Insert
+ + +Adding control points increases the complexity of a mesh. This +action does not increase the physical size of a mesh. Additions are +usually done before manipulating the patch mesh. + +
    Insert (2) Columns +
    This adds two columns of control points to the left edge of a +patch. + +
    Add (2) Columns + +
    This adds two columns of control points to the right edge of a +patch. + +
    Insert (2) Rows + +
    This adds two rows of control points to the lower edge of a +patch. + +
    Add (2) Rows +
    This adds two rows of control points to the upper edge of a +patch. +
+ +

Delete
+ + + +Deleting control points reduces the complexity of a patch mesh. +Be warned that the features created by the removed points are also +removed. It does not make the mesh a less complex version of the +former design. Deletions also change the dimensions of the mesh, +removing the area created by the deleted control points. A mesh +cannot be reduced smaller than a 3 column by 3 row complexity. + +
    First (2) Columns + +
    This removes two columns of control points from the left edge of +a patch. + +
    Last (2) Columns + +
    This removes two columns of control points from the right edge +of a patch. + +
    First (2) Rows + +
    This removes two rows of control points from the lower edge of a +patch. + +
    Last (2) Rows + +
    This removes two rows of control points from the upper edge of a +patch. +
+ +

Matrix
+ + + +This has nothing to do with Neo and Trinity. It's the patch mesh +taken as a whole. + +

Invert + +

+ +This command inverts the normals of the patch mesh. The normals +control the direction of facing for the texture skin and the +clipping surfaces. + +

Re-disperse + +

+This is used on a selected patch. When rows or columns are +inserted or added to a patch, the dimensions of the patch are not +changed. The distances between the new additions and the old points +are not the same. This command averages out the distance between +the points. It does not change the size of the patch. +WARNING! Only apply this BEFORE adjusting the patch. Otherwise, +you may lose your work on it. With some patches, selecting this +command will destroy the patch itself. + + +
    Cols + + + +The distance between columns is averaged and evened out. + +

    Rows + +

    +The distance between rows is averaged and evened out.
+ +

Transpose + +

+ +(Function undetermined) + +

Cap
+ + + +This command adds "cap" patches to the ends of the patch. The +original brush and the caps are linked together as a func_group +entity. A Patch Tool Bar button duplicates this command. The type +of cap depends on the selected patch: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +CylinderThe ends of the cylinder are sealed with circular patches.
Square +CylinderThe ends of the cylinder are sealed with square patches.
+ConeBoth ends are capped (open and point). You will want to discard the +cap on the point end.
+BevelIf you select to cap a bevel, a dialogue window pops up. +A normal bevel cap covers the space between the curve and the +center.
Inverted +BevelAn inverted bevel covers the space between the curve and the outer +corner.
+EndcapIf you select to cap an endcap, the same dialogue window pops +up.
Patch +MeshThe bevel/endcap window will pop up. Results will vary depending on +the manipulations done to the mesh.
Square +BevelCapped in the same manner as a cylinder
Square End CapCapped +in the same manner as a cylinder
+ +

Cycle Cap Texture + +

+ +Press this repeatedly until the texture on the cap patch looks +correct. + +

Overlay
+ + + +Overlay turns the grid of control points on for the selected +patches and leaves them on until the Clear command is selected. By +having the control points on a curve patch be visible, it is easier +for the designer to align the vertices of adjacent solid geometry +brushes. + +
    Set + + + +This is the command to turn on the control points in a selected +patch. + +

    Clear + +

    + +This is the command to turn off all control points in all +patches.
+ +

Thicken
+ + + +If you think about it conceptually, Thicken transforms a curve +patch into a three-dimensional object. It does this by duplicating +the selected curve and moving it a distance away from the copied +curve, and, if the "seams" checkbox is checked, it will cover the +space between the original and the copy with patches. The distance +between original and copy is selected in a pop-up dialogue window. +The direction is determined by the facing of the curve's normals +(the textured side). The duplicated curve appears on the opposite +side of the textured face. The resulting object depends on the +nature of the curve primitive being thickened. The following +are some examples: + +

+ + + + + + + + + + + + + + + + +
+CylinderA pipe is created. Checking "seams" caps the ends.
BevelA matching bevel is created. Checking "seams" creates a bent square +tube.
EndcapA matching endcap is created. Checking "seams" creates an +arch.*
Patch +MeshA mesh that echoes the shape of the selected patch is created, but +with XY dimensions smaller or larger by the measure of the +thickness (smaller if the normals are on the concave side; larger +if on the convex side).
+ +

* Thickening an Endcap is not the best way to create this shape. +Bending a square cylinder will produce better results. + + + +

Patch Tool Bar

+ +
The patch tool part is turned on in the Preferences. Each +of these buttons enables or disables a curve editing feature, or +initiates a process on a selected curve patch. + +

Don't Select Curved Brushes
+ +This button toggles the ability to select or not select curve +patches in the map. If turned on (depressed), the user will not be +able to individually select curve patches. Group selections +will still include any curve patches within their boundaries. + + + +

Show Patch Bounding Box
+ +This button toggles the display of the bounding box that defines +the limits of the patch. On (button depressed) shows the bounding +box. + + + +

Show Patches as Wireframe
+ +This button toggles the display of patches between a fully +textured mesh (off) and a wireframe-only mode (on). The wireframe +mode makes it easier to see the deformations of the mesh and allows +the user to see some control points that may be hidden by the +texture when it is mapped on the mesh. It can also be a +performance-enhancer for the editor (by setting the view to +wireframe until you need to see the brush textured). + + + +

Design Tip: When manipulating the control points on a +patch mesh, using wire frame allows you to best see both the +control points and the deformations.
+ + + +

Patch Bend Mode
+ +If a curve patch is selected, this button initiates a multi-step +bending procedure. There are tutorials available on several +sites that address the fine points of bending a patch, whether it +is a cylinder or a simple flat mesh. The ESC key will exit the +procedure at any point. The following are just the steps: + + + +
  • Select the patch (and only the patch). + +
  • Press the Patch Bend Mode button. This brings up an instruction +window that says: +
+ + + + + + +

This highlights (turns pink) a row or column of patch control +points. One of these control points will likely be the axis for +your bend. Pressing ENTER locks in your choice and advances to the +next step. + + + +

  • A second instruction window message appears:
+ + + + + + + +

This highlights the specific control point around which the +patch will bend. Pressing ENTER locks in your choice and advances +to the next step. You can also choose the control point by +SHIFT + middle mouse button clicking on the map window. The +click need not be within the bounds of the patch. + + + +

  • A third instruction window message appears:
+ + + + + + + +

This highlights the side or end of the patch (relative to the +bend point) around which the patch will bend. Pressing ENTER +locks in your choice and advances to the next step. + + + +

  • A fourth instruction window message appears:
+ + + + + + + +

Clicking and holding the Left mouse button on the map window and +dragging it around will cause the patch to bend. Pressing ENTER or +ESC at this point will accept any changes that you have made. + + + +

Redisperse Patch Points
+ +This is used on a selected patch. When rows or columns are +inserted or added to a patch, the dimensions of the whole patch are +not automatically adjusted. The distances between the new additions +and the old points are not the same. This command averages out the +distance between the points. + + + +

WARNING: Only apply this BEFORE making adjustments to the +patch, otherwise you may lose your work on it. With some +patches, the patch itself will be destroyed. + + + +

CAP (put caps on the current patch)
+This is used on a selected patch. + + + +

Design Notes: + +
    Endcaps: Don't cap endcaps with this tool. Make a +pair of opposing bevel caps that match the arch of the endcap + +
    Messed Up Texturing: If an inverted bevel endcap covers +something other than an arc of a perfect circle, it is likely that +the texture won't appear right when you apply the CAP function to +the texture. Press SHIFT + CTRL + P a few times until it looks +right.
+
+ +

Weld Equal Patch Points (welds equal patch points during +moves) + +
(Patch Control Bar only) This feature, when selected (button +pressed in) causes control points to weld together if they are +moved to the same coordinates. Undo will undo the move and the +weld. + + + +

Drill Down (selects drill down rows and columns) + +
When this is toggled on (depressed), clicking on a control point +in a 2D Map view selects all the control points in the row or +column beneath it. + + + + + +

Moving Patches

+ +
Moving Selected Curve Patch
+ +These keys move the curve patch around the map in discrete map +grid increments. + +
    Move Selection Down + + + +Each press moves the selected map component down along the +Z-axis by one grid position (at current grid setting). Not affected +by current 2D-map view. + +

    Move Selection Up + +

    + +Each press moves the selected map component up along the Z-axis +by one grid position (at current grid setting). Not affected by +current 2D-map view.
+ +

Nudging the Curve Patch
+ +These keys move the curve patch around the map in discrete map +grid increments. The movement is in terms of the selected window, +not in terms of XYZ coordinates. + +
    Nudge Down + + +Each press moves the selected map component "down" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + + + +

    Nudge Up + +

    + +Each press moves the selected map component "up" the map view by +one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Left + +

    + +Each press moves the selected map component "left" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Right + +

    + +Each press moves the selected map component "right" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates.
+ +

Snap Selection To Grid
+ + + +If you are using the map grid to keep curve patches in +alignment, this is a great tool. Rotated curve patches and curve +patches that have had their vertices tweaked can have vertices that +no longer lie on map grid intersections. This snaps the vertices to +align with the grid. Be warned that snapping to large grids +may be hazardous to the health of your curve patch (Snap and it's +gone! But that's what UNDO is for). +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch07/pg7_1.htm b/docs/manual/Q3Rad_Manual/ch07/pg7_1.htm new file mode 100644 index 00000000..ec331a7d --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch07/pg7_1.htm @@ -0,0 +1,945 @@ + + +Q3Radiant Editor Manual: Page 7.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 4: Working with Textures

+ +There are three skill and knowledge components to working with +textures as they regard Quake III Arena. They are Texture +creation, Texture Manipulation, and Texture Application. Only the +third, Texture Application, is absolutely necessary for making +maps. You need not master all three. + +

Brush Primitives: A New Format

+ +With the release of version 192, the Q3Radiant editor takes a +new direction in the way textures are mapped to the surfaces of +brushes. The texturing format will roughly be the same as the way +textures are handled on curve patches. While there are no changes +to the user interface within the editor, you should see a change in +the way textures behave on brushes during transformation operations +like move and rotate. Because textures are mapped to the S +and T coordinates of a brush (as they are with curve patches), +locked textures will now maintain their positions on brushes when +they are moved or located. Even complex rotations should now be +possible without the textures going askew. + +

Checking the Brush Primitives checkbox turns on this feature. +(Menu: Project Settings… > Use brush primitives in map +files). Once you change a map to Brush Primitives, you cannot go +back to the earlier method of texture mapping with that map. The +prudent mapper makes backups before making major changes to +projects. + +

Texture Creation: Making new Assets

+ +This is covered earlier in the manual. + +

Texture Manipulation: Shader Overview

+ +Technically, each texture already has a default shader that +passes it through the pipeline to appear much as it does in the +graphic program that made it. A shader is a short script, +separate from the texture file, that the game engine uses to make +further adjustments to the texture's appearance or function. The +shader is to Q3A what the surface properties flags were to +Q2, only ever so much more powerful. If you plan on creating +your own textures, you should get to know and understand how +shaders work. The Q3A Shader Manual contains the information you +need. + +

Shaders and Multi-Pass Texture Effects
+ +(Drawn from an original essay by Small Pile of Gibs) + +

Shaders give the mapper control over special graphics effects +that require multiple redrawing passes before they are finally +displayed on the game screen. Every shader that changes the visual +component of a texture uses these "Multitexture" effects. +Multitexture is ON by default in Quake III Arena. It is +turned off with the cvar, "set r_ext_multitexture 0 (entered in the +console or bound to a key) - see the Debugging section in this +document for more details. + +

To understand how multitexture works, you need to understand how +the Quake III Arena graphic engine renders a scene. All the +faces you see in Quake III Arena are made up of triangles - +you can see this by using the cvar command "r_showtris 1." +Initially, each triangle adds one to the "tris" number in r_speeds +(the numbers that are used to estimate whether a scene is too +complex). With every frame that Q3A "paints", it draws +triangles onto the scene in layers, starting at the back of the +scene and drawing every triangle visible until it reaches the +front. It takes time to draw each triangle. If a triangle is +painted with a texture that is "see through" in some way (either +transluscent, transparent, or containing cut-outs), any triangles +seen through that triangle must be redrawn one additional time for +each stage in the the shader. If a single transparent triangle +takes up the whole screen, for example, a glass window - The whole +area of the screen has to be redrawn. Each triangle of glass takes +an entire screen worth of "overdraw" and each extra stage on the +glass adds another screenful, which is why glass can be such a big +framerate hit. + +

The simplest form of multitexture is a Lightmap. In most cases, +the Q3A engine first draws the lightmap (precalculated light and +shadow information). Then, on top of that, it adds in the +information from the texture art specified for that triangle using +a special effect (blendfunc filter) - which blends the lightmap +with the texture to make areas of the texture look light or dark. +Using the cvar command "r_vertexlight 1" (Vertex Lighting +instead of Lightmaps) stops Q3 from drawing the lightmap triangles +(which is why many gamers use vertex lighting to gain additional +playing speed). + +

Every extra stage in a shader is an extra triangle drawn over +and blended with the first triangle in a special way. Like the +lightmap example above, each additional stage requires an extra +triangle to be drawn for each frame. On certain 3D accelerator +cards (like the TNT - TwiN Texture), the multitexture effect +cancels out the real cost of the first pass of blending. The +blending for the first additional stage is done before the triangle +is drawn. However, if the shader takes 3 stages (like all the shiny +metal effects) it costs an extra triangle for every triangle it is +used on. Every extra triangle used adds a triangle to the r_speeds +triangle count. Because there are cards that don't automatically +handle this first blending pass, the map maker needs to +occasionally check his r_speeds with the multitexture turned +off. + +

Texture Application: Texture Handling +Tools

+ +These tools manipulate textures within the editor. They do not +create textures or shader scripts. + +

Escape (ESC)
+ +This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on a brush +face, a brush, a patch, or a group of brushes or patches. + +

View Textures
+ + + +This is only used in the four-view and floating windows modes +(as set in Preferences). It brings up the Texture selection window +(also accessible from a folder tab). If the Entity window is open, +you may need to click on a map view window first for the "T" +command shortcut to work. + +

Show in Use
+ + + +This command affects the content of the Textures window. It +filters the contents so that only those textures currently in use +in the map are displayed in the window. + +

Show All
+ + + +This command affects the content of the Textures window. It +"un"-filters the contents so that all the texture directories +previously loaded during the mapping session are re-displayed. + +

Surface Inspector
+ + + +

+ +

This brings up a pop-up dialogue box. This is one of the more +complicated interfaces used during map development and may take +some getting used to. + +

Texture + +
This is the path/name (beginning in Textures directory) for the +texture. You can copy from this field or paste into it. If you know +the pathname of a texture, you can enter it here. It will load +without having to first load the entire directory that contains +it. + +

The next five commands work on both patches and brushes. +However, the results of applying a Horizontal Shift to a brush and +to a patch may be substantially different. When working with +patches, the numbers in the fields do not change … although +the texture on the map component may be changing. + +

Design Note: When a curve patch butts flush up against a +piece of solid geometry, as if it were an extension of that +geometry, it may be difficult to align the textures exactly. In +fact is often extremely difficult to align a texture on a +patch with the texture on an adjacent geometry brush. It works best +when the dimensions of the patch are an exact multiple of the +dimensions of the texture being used. Otherwise, you may want to +consider designing your architecture in such a way that it is +logical for a new texture to begin at that point. Use your +judgement.
+ +

Horizontal Shift + +
This allows you to change the Horizontal texture offset +(position of texture on a surface). You can type an offset value +into field or use the scroll buttons on the right to shift the +texture. If "Snap T to Grid" is set in Preferences, the scroll +increments will move a number of pixels equal to the grid size. + +

Vertical Shift + +This allows you to change the Vertical texture offset (position +of texture on a surface). You can type an offset value into field +or use the scroll buttons on the right to shift the texture. If +"Snap T to Grid" is set in Preferences, the scroll increments will +move a number of pixels equal to the grid size. + +

Horizontal Stretch + +This allows you to change the dimensions of textures as they are +mapped into the world. You can type a size value into field or use +the scroll buttons on the right to enlarge or reduce the texture. +The default value is 0.5. This gives a presentation in the game +world of two pixels for each game unit. A Horizontal Stretch value +of 1.0 would double the amount of area covered by a single repeat +of the texture. Of course, doing that also reduces the apparent +resolution of the texture by half (can you say blurry?)! Making the +stretch value a negative number horizontally flops the texture's +normals (i.e.; flops the texture left to right). + +

Design note: Textures are "projected" onto brush +surfaces. This means that if a surface is angled, the texture +stretches to fit the space upon which it is projected. To make the +texture look "unstretched" you need to change the dimension so that +it looks correct when stretched. Example: If you want to map a +texture on a 45-degree angle, it should be scaled to 0.35 along the +direction perpendicular to the axis of the angle.
+ +

Vertical Stretch + +This is the same as for the Horizontal Stretch, but along the +vertical axis. Making the stretch value a negative number +vertically flops the texture's normals (i.e.; flops the texture up +and down). + +

Rotate + +This rotates the texture around the center point of the brush +(or patch). If the texture is not centered on the map component, +the rotation will not necessarily look correct. The increment of +rotation is set by the value given for the Rotation Inc field on +the Preferences window. The default value is 45 (degrees), roughly +1/8 rotation around the axis. + +

Value + +(This Quake 2 function is not used by Quake III +Arena) + +

Texturing + +

This next grouping of commands in the lower left corner of the +window provides two separate sets of buttons. The top set deal with +texturing geometry brushes. The lower set is for texturing curve +patches. + +

    Axial (Brush) + +
    Realigns texture to the X and Y axes (removing the effects of +rotation) + +

    Fit (Brush) + +
    The texture is stretched to fit the dimensions of the brush. The +width and height fields to the right are the number of repetitions +to be used in the S and T dimensions (S corresponds to X on +the actual texture and T corresponds to Y on the actual texture). +The default value for the height and width fields is 1. You can +type a size value into field or use the scroll buttons on the right +to enlarge or reduce the texture. Only integer values can be +entered (meaning that you can't enlarge a texture 1.5 times). + +

    CAP (Patch) + +
    This function is most often applied to patches used to fill in +the gaps between curves and solid geometry. It can also be applied +to flat patches so that the texture doesn't appear to follow the +arc of the patch. You may need to use the SHIFT + CTRL + N command +to normalize the texture on the patch. + +

    Set… (Patch) + +
    This command functions almost like the "Fit" command above for +brushes. The texture will be fit across the patch based on the X +and Y values given. However, there is a notable difference. The X +and Y fields will accept non-integer values (e.g. 6.4 x 3.8). It +may take some experimentation to determine which dimension of your +patch is considered to be "X" and which is thought to be "Y". If a +value of 1x1 is given, the texture will be "fit" to the +patch. + +

    Natural (Patch) + +
    The engine does its best to map the texture onto the patch in a +"natural" appearing manner. This means that the texture will curve +and flow with the curves and bends in the patch. Unless you are +texturing a cap, this should be your first choice when applying a +texture. + +

    Fit + +
    The texture's coordinates are mapped to fit the patch +(with no repeats). +

+

Find / Replace
+ + + +This feature allows the user to replace a texture within a +single brush, a set of selected brushes or globally throughout the +entire map. Selecting the command from the menu opens up a dialogue +window. The top line is for the texture path and name of the +texture to be replaced. The second line is for the texture to be +used for replacement. Several checkboxes allow fine control over +what, exactly, is to be changed. This command does not respond to +UNDO. If you accidentally mistype a texture name in the replace +line, you will need to enter it again (as mistyped) on the find +line and then enter the correct texture on the replace line. + +

Texture replacement is global (throughout the map) unless the +selected checkboxes state otherwise. + +

    Replace within selected brushes only. Only the hi-lighted +brushes that contain the texture to be replaced will be +affected. + +

    Force replacement (ignore current texture name). +All textures in the map will be replaced. Best if used with +Replace within selected brushes only. Be very careful +with this one. + +

    Live Updates from Texture/Camera windows. Using +Live Update the user can find and replace textures with a fully +point and click interface. + +

    Texture Replacement using Live Updates + +
    Click on the Find box, then click on any texture in either the +Camera window or the Texture window. The texture path/name for that +texture appears in the box. Next click on the Replace box and click +on the replacement texture. That texture's path/name appear in the +Replace box. Select "OK" and the replacement will occur.

+ +

Step-by-step for replacing a texture on a brush face +(if live update is not used). + +

  • In the Camera window, hi-light (CTRL+SHIFT+mouse1) the texture +to be replaced. + +
  • Open Surface Inspector. If the name of the texture is not +hi-lighted, then hi-light it. + +
  • Press CTRL+C to copy the texture name. + +
  • Open the Find/Replace window. + +
  • Paste (CTRL+V) the name into the find window. + +
  • Hit ESC to deselect the texture in the CAM winow. + +
  • Open the Textures Window. Find the texture you want to replace +with and select it. + +
  • Open Surface Inspector again. + +
  • Copy the texture name there. + +
  • Open Find/Replace again and paste the new texture into the +Replace box. + +
  • Select OK. Replacement occurs and the dialogue window +closes.
+ +

Texture Lock
+ + + +Opens Pop-up window with two options for "locking" texture +shifting during brush or patch movement. NOTE: If you have +selected the BRUSH PRIMITIVES option under Project Settings… +then Texture lock will always be on. + +
    Moves + + +When this option is checked, textures stay locked in position on +the brush as brushes are moved around the map. If unchecked, the +texture appears to shift across the brush, because they are fixed +to the world, not the individual brush. On small brushes and small +textures (such as the small square lights), some "creepage" may +occur, with textures shifting 1 or 2 units off their locked +position. + +

    Rotation + +

    + +When this option is checked, textures stay locked in position on +the brush or brushes as they are rotated around the map. If +unchecked, the texture appears to shift across the brush, because +they are fixed to the world, not the individual brush. On small +brushes and small textures (such as the small square lights), some +"creepage" may occur, with textures shifting 1 or 2 units off their +locked position.
+ +

Load from List…
+ + + +Opens a dialogue box listing all texture directories currently +recognized by the editor. Hi-light a directory title then +click on the "Load" button. The textures in the selected +directory will be loaded into the Textures window. + +

Shaders
+ + + +This command pops up a Pop-up window with two shader-related +commands. + +
    Load All (Reload) + + + +This command loads or reloads all the .shader scripts recognized +by your shaderlist.txt file. When you change and save a shader +script, execute this command, then reload the affected texture +directory to see any changes. + +

    Show + +

    + +When checked, this command surrounds all shader-manipulated +textures in the Texture window with a thin white border.
+ +

Flush
+ + + +The flush command frees up texture memory and should improve +editor performance. Exactly how much is flushed depends on your +choice of commands. + +
    Flush All + + + +This command flushes all the texture memory, restarts OpenGL and +reloads the map from the last saved copy. + +

    Flush Unused + +

    + +This command flushes all UNUSED textures from memory.
+ +

Texture Window Scale-
+ + + +This affects the size of the texture images displayed in the +Textures window. Clicking on the menu entry opens up a pop-up +window with the following size selections: 200%, 100%, 50%, 25%, +and 10%. Adjust it to suit your liking. If seeing the detail in the +textures is important to you, set the size to 100% or larger. If +you know your way around the textures without having to see each +pixel, set it for smaller. + +

Texture Directories
+ + + +This is not a command. The entries on the Textures Menu below +"Texture Window Scale" are the names of the available texture +directories (all whose filenames are listed in the shaderlist.txt +script). Clicking on one loads the contents of the directory into +the Texture window. + +

Texture Shift Key Shortcuts
+ +A brush, brush surface, or curve patch must already be selected +before using these shortcuts. This feature closely copies the +function of the Texture Shift fields and scroll bars on Surface +Inspector pop-up window. If Snap to T is selected in preferences, +then the texture shifts in pixel increments equal to the current +grid setting. Shifting textures on curve patches may produce +unexpected results. + +

+ + + + + + + + + + + + + + + + + + +

Texture Rotate Key Shortcuts
+ +A brush, brush surface, or curve patch must already be selected +before using these shortcuts. This feature closely copies the +function of the Texture Rotate field and scroll bar on Surface +Inspector pop-up window. The texture rotates in degree increments +set in Preferences. Rotating textures on curve patches may produce +unexpected results. + +

+ + + + + + + + + + +

Texture Scaling Shortcuts
+ +A brush, brush surface, or curve patch must already be selected +before using these shortcuts. This feature changes the scale of the +texture (the amount of area that a single instance of the texture +covers). The texture scale seems inconsistent, except that opposite +directions appear to cancel each other out. The amount of increase +delivered by the first use appears to be about a ratio of 1:15. + +

+ + + + + + + + + + + + + + + + + + +

Using Interactive Textures

+ +Interactive textures are the shader-manipulated textures that +have an effect on game play, not just the appearance of the map. +There are two classes of Interactive Textures: Special Content +Textures and Texture Entities. For more detail and +instructions regarding shader manipulation of textures, refer to +the Q3A Shader Manual. + +

Special Content Textures + +Special content textures are textures where the "surface" +parameters of the texture actually change the physical nature of +the geometry brush and in so doing, affects the play of the +game. + +

Water + +
Water is a content parameter that allows a player to "swim" +inside a geometry brush, causes a pulsing visual distortion of the +underwater geometry, and prompts the game engine to draw bubbles as +projectiles pass through it. A player can only remain under water +for a short time (without a battlesuit) and then begins to +drown. + +

Water usage rules: + +

    +
  • A water texture is defined by the presence of surfaceparm water +in the shader that creates it. + +
  • Because water is typically a "transparent" surface, the shader +passes used to create surface effects on water are added to the +shader passes of textures seen through the water surface. This can +significantly increase the number of redraw passes necessary to +draw the game world and may negatively affect performance. + +
  • If you place water brushes side by side, the touching sides must +be marked with the common/nodraw texture. + +
  • Both the top and the bottom surfaces of a water brush must be +water texture. + +
  • Water brushes cannot be stacked so they touch another water +brush vertically, only set side by side. + +
  • If you want to be able to exit water easily, keep the +distance from the top of the water brush to the adjacent "shore" or +pool edge at no more than 16 game units. Somewhat less is actually +better. + +
  • If fog is to be used as a part of a water volume, the water +surface should not deform.
+ +

Fog + +Fog content is used to block or diminish player vision and +provide "atmosphere" for a level. Like water, fog can affect game +performance, especially if one can see additional shader effects +within it. The following information is taken from the Q3A +Shader Manual regarding fog creation and usage. + +

fogparms <red value> <green value> <blue +value> <distance to Opaque> + +
This surface parameter (or "surfaceparm") defines the contents +of the fog. + +
Note: you must also specify "surfaceparm fog" to cause +q3map to identify the surfaces inside the volume. Fogparms +only describes how to render the fog on the surfaces. + +

<red value> <green value> <blue value> +These are normalized values (number range from 0 to 1). A good +computer art program should give you the RGB values for a color. To +obtain the values that define fog color for Quake III Arena, +divide the desired color's Red, Green and Blue values by 255 to +obtain three normalized numbers within the 0.0 to 1.0 +range. + +

<distance to opaque> This is the distance, in +game units, until the fog becomes totally opaque, as measured from +the point of view of the observer. By making the height of the fog +brush shorter than the distance to opaque, the apparent density of +the fog can be reduced (because it never reaches the depth at which +full opacity occurs). + +

Fog usage rules: + +

    +
  • If a room (or rooms) is to be filled completely with a fog +volume, it can only be entered through one surface (and still have +the fog function correctly). + +
  • The fog volume can only have one surface visible (from outside +the fog). + +
  • Fog must be made of one brush. It cannot be made of adjacent +brushes. + +
  • Fog brushes must be axial. This means that only square or +rectangular brushes may contain fog, and those must have their +edges drawn along the axes of the map grid (all 90 degree +angles). + +
  • If a water texture contains a fog parameter, it must be treated +as if it were a fog texture when in use. + +
  • Additional shader passes may be placed on a fog brush, as with +other brushes. + +
  • If a light-emitting fog brush is placed beneath normal brush +geometry, the light may cause light artifacting on the solid brush +surface. Use with care. + +
  • Brush models (trains, doors, rotating objects, etc.) within, or +partially within fog volumes will have drawing priority problems +against the fog. It is best not to place these entities in +fog volumes. + +
  • There are unconfirmed reports of moving entities being made with +fog shaders.
+ +

Lava + +
Lava content, for most practical purposes, is a variation of +water content. The damage that it does to players in contact with +it is defined by game code and cannot be directly affected by the +map designer. + +

Slime + +
Slime content, for most practical purposes, is a variation of +water content. The damage that it does to players in contact with +it is defined by game code and cannot be directly affected by the +map designer. + +

Texture Entities
+ +There are a number of shader-manipulated textures that are used +in an entity-like fashion. The shader files that manipulate the +textures are what give them their game properties. These are +the ones that id used and their relevant properties. + +

Areaportal + +
Color: Opaque Red Orange + +
Location: (textures/common/areaportal) + +
The bsp tool uses areaportals to create hard, visual breaks +between areas in the map. Until triggered, the areaportal blocks +geometry behind it from being drawn or seen. The area portal brush +should be a thin (2 to 4 units thick) brush. It should touch all +the brushes that form the hull of the opening being portalled. It +must be placed inside a door. The opening of the door triggers the +portal function. The closing of the door returns it to its former +state. The areaportal texture must completely seal off a volume +from another volume (although this can be in conjunction with other +areaportals). If a door is being used to block off an area from +view, consider placing an areaportal brush inside the door. Example +in Quake III Arena: All the doors out of the central courtyard in +Q3DM12, The Dredwerkz, are areaportalled. + +

Caulk + +
Location: (common/caulk) + +
Color: Opaque Pink + +
Game Function: Caulk, the miracle texture. It blocks vis. +It seals the world off from the void. It doesn't draw (so it +doesn't add to triangle counts). It keeps curves from competing +with textures behind them. It looks like hell if you see it in your +world. From the View menu (View > Show > Caulk), you can +toggle on and off the display of caulk brush sides. + +

Design Tips: When you build a brush entity (a.k.a. +b_model), mark all the brush sides that you will never see with +caulk. Otherwise, the game draws every one of them. Even if you're +only making a one-piece door, mark all the non-viewed sides with +caulk. The same holds true for detail brushes. If you can't +(or won't ever) see a brush face on a brush that's been marked as +detail, paint it with caulk. Next, whenever you build a curve, try +to build the brush geometry immediately behind it out of caulk. +Finally, look around your map for brush faces that you suspect are +being drawn, but are never seen: door pockets, bars, underneath +bridges or very low railings and so on. It may sound like work, but +attention to detail like this buys you both the appearance of +greater geometric detail in the map AND faster game running +speed. + +

More Design Tips: Finally, and this should be used with +great care, a caulk brush can be used to create an invisible +support for entities. If you place a very thin caulk brush floating +above a surface that would otherwise not support an entity +(example: a grate made of clip brush), the brush will not draw in +the world, but will support the entity. The reason for this is that +SUSPENDED entities are not "seen" by bots unless they can be +reached by a jump pad.

+ +

Clip + +
Location: (textures/common/clip) + +
Color: Transparent Red + +
Game Function: If you look at a professionally made map, +quite often you'll see that nearly every bit of wall surface is +covered in a transparent red texture called "common/clip." Clip is +a nondrawing texture that blocks player movement. Clip does not +block weapon fire. Entities, such as ammo or weapons, are not +supported by clip brushes. If placed or dropped on a clip brush, +they will pass through them. + +

Design Tips: Place clip brushes to smooth the passage of +players through the world. This could mean creating a slope that +allows the player to slip past a piece of architectural trim, or +filling a window to keep players from getting into it. It can be +used to create an artificial ceiling that prevents players from +flying or jumping too high.
+ +

Cluster Portal + +
Location: (textures/common/clip) + +
Color: Translucent lavender + +
Game Function: Works like an area portal, but for the bot +navigation file only. Cluster portal is used by the bspc utility to +subdivide the map into smaller areas for calculating bot +navigation. Appendix C: Bot Navigation Files contains the specific +details for using cluster portal texture entities. + +

Cushion + +
Location: (textures/common/clusterportal) + +
Color: Translucent pale aqua + +
Game Function: A player falling on this does not take +damage. They also don't make a "landing" sound, so use with +caution. + +

Do Not Enter + +
Location: (textures/common/donotenter) + +
Color: Transparent Pale Orange + +
Game Function: It is a tool used to solve bot navigation +problems. Use it like a clip brush, but sparingly. When you observe +bots doing stupid things in your map, try to block off the area +with this texture. The Bot Navigation Files appendix contains the +specific details for using the Do Not Enter texture entity. + +

Hint + +
Location: (textures/common/clusterportal) + +
Color: Transparent Yellow Green + +
Game Function: Helps determine the vis portals. It is +used as a suggestion to the compiler during the vis phase, when the +world is subdivided. Generally speaking, they are used to correct +vis problems, whose chief symptom is the "hall of mirrors" effect +seen during game play. These can often be corrected by careful +placement of a hint brush. If you fill the volume where the +error is seen or the volume adjacent to it, the problem may be +corrected in the next compile. This is really more art than +science. + +

Invisible + +
Location: (textures/common/noimpact) + +
Color: + +
Game Function: This was used to create a surface that +would be marked by weapon fire, but would not be drawn in the +world. This was created specifically to resolve a problem where +func_static brushes were being used to replace floor textures that +marked the location of weapons in Q3DM8. Because the rocket +launcher was located in different places between the team and the +deathmatch games, the designer wanted to make floor markers that +would not only change between game types, but would be marked like +adjacent floor pieces. + +

Nodrawnonsolid + +
Location: (textures/common/trigger) + +
Color: Opaque light yellow + +
Game Function: This is the same as nodraw. + +

Noimpact + +
Location: (textures/common/noimpact) + +
Color: black + +
Game Function: Used to create a surface which does not +block weapon fire. + +
Weapon fire will pass through this. This usually used as a +shader key on other textures. + +

Origin + +
Location: (textures/common/origin) + +
Color: Opaque Orange + +
Game Function: Used to create origin point in moving +b_models, such as trains, plats, and rotating objects. This +texture, applied to a square or rectangular brush, is used to +create the point of origin for moving b_models, such as trains, +plats, and rotating objects. It is used by func_trains as the point +that passes through path entities and the source for sound +attachment + +

Skip + +
Location: (textures/common/skip) + +
Color: Transparent yellow + +
Game Function: Do not use in Q3A. This texture was used +in Quake 2 maps to discard sides of hint brushes. It is +nonfunctional in Q3A. + +

Slick + +
Location: (textures/common/trigger) + +
Color: Translucent Pale Blue + +
Game Function: Not stick coating for map surfaces. +Reduces friction. Use like a very thin clip brush over surfaces you +want to be low friction. + +

Trigger + +
Location: (textures/common/trigger) + +
Color: Transparent Dark Yellow + +
Game Function: Used to make trigger brushes. + +

Weapon Clip + +
Location: (textures/common/weap_clip) + +
Color: Transparent Red + +
Game Function: This version of the clip brush only stops +weapon projectiles from passing through it. No marks are left on +the surface. + +
Design Tip: Use to create clip surfaces for map object +models. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch08/pg8_1.htm b/docs/manual/Q3Rad_Manual/ch08/pg8_1.htm new file mode 100644 index 00000000..328e35d8 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch08/pg8_1.htm @@ -0,0 +1,347 @@ + + +Q3Radiant Editor Manual: Page 8.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 5: Working with Entities

+ +The entities in Quake III Arena are limited to those +defined by the game code. The editor can draws entity information +from the game code, or from special definition (.def) files. +Version 192 of the editor comes with a .def file developed from an +original supplied by EutecTic. Mods made to Quake III Arena +can add to and/or subtract from the entities used by a game. If you +plan to work on mods, you should create multiple project files +(copy and rename your project file) with the changes required for +the mod. + +

The Entity Window

+ +You make game design decisions about entities and modify their +features within the Entity Window. The definition file that you +select on the Project Settings… window determines what +entities will be shown in the Entity List and what, if any, +property descriptions appear in the Key Descriptions and Check box +Spawn Flags. + + + +

Entity List
+ +The Entity List is the field on the Entity Window. It +contains the "classnames" of all the entities defined by the +definition file in alphabetical order. + + + +

You can use the scroll bar to scroll through the entities or, +after clicking on the field, type in the first letter of the class +you want to use (e.g.; type in "T" to select "target", or "A" for +ammo, "W" for weapon). + + + +

Double-click on the classname to select it and enter it on the +first line of the Active Properties field. + + + +

The Entities appendices of this document contain a complete listing of all the entities used in Quake III Arena. + + + +

Key Descriptions
+ +The entries in the Key Description field are the "rules of use" +for the hi-lighted classname in the Entity List field. You can use +the scroll bar to scroll up and down through the lines, but +the entries are not interactive. If you are using the .def file +accompanying release version 192 of the editor (or Eutectic's +original), all the key commands are described and their acceptable +values (or value ranges) are listed. If you are using the +descriptions in the .c game code file, they may be substantially +less descriptive. + + + +

Check box Spawn Flags
+ +Spawn flags are properties assigned to entities by use of check +boxes. Check the box to set the feature for the selected entity. +Many entities have only a single spawn flag property, while others +have numerous ones. Note that the check boxes to the right are only +relevant for Quake 2 single player games and will not work for Quake III Arena. + +

Active Properties
+ +This field shows all the properties currently assigned to the +selected (or newly-created) entity. Each property has two parts: +key and value. Once created or assigned, they appear on the same +line together. Only properties that are valid for an entity (that +is, ones that appear in the Key Descriptions field) will function +in game. Adding others may create error messages. You cannot +directly affect the properties in this field. + + + +

Clicking on an active property hi-lights it and fills in the key +and value fields below. You can edit both the key and the +value in those fields, or use the Del Key/Pair button to delete it +altogether. + + + +

Key & Value Fields
+ +Keys (and their values) are assigned to entities by typing them +into the fields. There is no spell check or auto-correction, so +make sure that your typing is accurate. Start by typing in +the name of the key. Then hit TAB or ENTER to change to the value +field. This also clears the contents of the value field. Now type +in the value for the key (the Key Descriptions list the acceptable +value ranges for the keys). If you hit ENTER, the key and value +appear in the Active Properties field. If you hit TAB, the +cursor moves up to the key field. You can also click directly on a +field to edit it. The cursor will appear after the last character +in the field. Use arrow keys to position the cursor within the +field. + + + +

Angle Buttons
+ +The Angle Buttons (below the value field) are used to assign a +facing direction (as is the case with player start spots or +misc_models) or movement direction to entities (such as doors and +buttons). Click on a button to create an Angle key with that +button's value in the Active Properties field. Clicking on +another key changes the angle value. + + + +

There are two clusters of angle buttons. The first cluster +represents rotation around the Z-axis for entities like player +start or spawn spots or misc_models. The entity will face in the +selected direction. The buttons represent angle directions in +45 degree increments. There is a direct correspondance between the +angle that the entity will face (or move) and the position of the +button in the cluster. If you select the 90-degree button at the +top center of the cluster, the entity will face "up" on the XY 2D +Map. If you select the 180-degree button on the left side of +the cluster, the entity will face left on the XY 2D Map. + + + +

For entities like doors or buttons, it represents the direction +that entity will move when activated. + + + +

The second angle button cluster assigns an up (-1) or down +(-2) direction to the entity. Note that an entity can only have one +facing direction. It cannot face up and 45 degrees. It can only +affect one or the other. + + + +

It is also possible to directly edit the angle value in the +value field. This allows for a much more precise angle +selection. + + + +

The Other Buttons
+ +

A third cluster of buttons sits to the right of the Angle +buttons. Each has a unique function. + + + +

Reset + +
Clicking on this button will reset all properties from the entity to the default values. + + +

Del Key/Pair + +
If you have selected an active property, clicking on this button +will delete the property. + + + +

Sound… + +
This opens a Windows directory browser in the directory that +contains the map sounds. Double clicking on a sound file name +in the browser window creates an active property with the +appropriate key and the value as the path/name for that sound. + + + +

Model… +
This opens a Windows directory browser in the models/mapobjects +directory. Double clicking on an .md3 file name in the +browser window creates classname misc_model active property with +the value as the path/name for that model. + + + +

Entity Handling Tools

+ +These tools manipulate the in game entities. The map component +handling tools that are described in the Working with Brushes +section also work with entities. + +

Escape (ESC)
+ +This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on an +entity. + +

Connect Entities
+ + + +This targets one entity, typically an activating trigger, at +another entity, usually a target of some kind. Some entities +may be linked in multi-part chains, where each entity has some +effect on the one(s) that follow it. To use, do the following: + +
    +
  1. Hi-light the acting entity (usually a trigger, or a button). + +
  2. Hi-light the targeted entity (examples: target_position, +target_relay, a door). + +
  3. Select Connect Entities (or press CTRL + k). + +
  4. A path is drawn between the two entities. The first entity +selected always targets on the second.
+ +Troubleshooting: If the connection is not made check the +following: + +
  • Are both objects already entities? Sometimes it's easy to forget +to make a trigger brush into a trigger. + +
  • Did you select ONLY two objects? If you accidentally click +on something you don't intend to link, you have to start the +linkage over. + +
  • Did you select the objects in the correct order? + +
  • Is the second object something that can be triggered +remotely?
+ +

Ungroup Entity
+ +
(Menu: Selection > Ungroup Entity) + +
(Shortcut: none)
+ +This unbinds an entity made of brushes, and/or patches, and md2 +models back into separate map components. Once ungrouped, the +entity is no longer an entity and loses any and all key value +properties it may have had. + +

Design Note: If you intend to rebuild an entity after +ungrouping it, write down its key properties and values first.
+ +

Moving Selected Entity
+ +These keys move the Entity around the map in discrete map grid +increments. + +
    Move Selection Down + + + +Each press moves the selected map component down along the +Z-axis by one grid position (at current grid setting). Not affected +by current 2D-map view. + +

    Move Selection Up + +

    + +Each press moves the selected map component up along the Z-axis +by one grid position (at current grid setting). Not affected by +current 2D-map view.
+ +

Nudging the Entity
+ +These keys move the Entity around the map in discrete map grid +increments. The movement is in terms of the selected window, not in +terms of XYZ coordinates. + +
    Nudge Down + + + +Each press moves the selected map component "down" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + + + +

    Nudge Up + +

    + +Each press moves the selected map component "up" the map view by +one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Left + +

    + +Each press moves the selected map component "left" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Right + +

    + +Each press moves the selected map component "right" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates.
+ +

Rotating Entities = BAD!
+ +All the commands that rotate brushes and patches will work on +entities. Unfortunately, what they do to some entities is BAD! +Don't use free rotate or menu rotation commands to rotate +Misc_models or any entity model represented by a wireframe model in +your map. The movement will separate the model wireframe from its +bounding box and will not actually change the facing of the +entity. + +

Changing Facing = GOOD!
+ +To change the direction that a misc_model or entity with a +facing (such as a player start or spawn spot) faces, use Angle keys +and values. You should "rotate" (change facing) entities with +either the Angle buttons on the Entity Window or by entering an +Angle key and giving it a rotation value between 1 and 360 +(inclusive). + +

Mass Rotations
+ +If you are building a Capture the Flag map, or other map where +you only build one portion and rotate it to make the others, +consider doing the following. Change the display of all +non-misc_model entities to bounding boxes only. Select the +entities to be moved and clone them. Then rotate them using the +menu rotating commands. Position them in the new map +section. Next, move misc_models individually. Change +their facing and set them in place. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch09/pg9_1.htm b/docs/manual/Q3Rad_Manual/ch09/pg9_1.htm new file mode 100644 index 00000000..f79b44bc --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch09/pg9_1.htm @@ -0,0 +1,87 @@ + + +Q3Radiant Editor Manual: Page 9.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 6: Lights & Lighting

+ +Lighting a map is both an art and a science. For Quake III +Arena, the id designers worked to create instances of dramatic +lighting, while attempting to maintain a relatively consistent +intensity of light throughout the maps. Other designers worked to +create dark realms, full of shadows in which lurking assassins +could hide. + +

Whatever style of lighting you strive for, remember one key +rule: The bots don't use light information. In a pitch-black room, +they would still see an opponent. Keep that in mind when designing +your maps. + +

Entity Lights
+ +There are several ways to create light emitting objects.  +The simplest is to place a light entity into your map.  If you +do nothing, it has a default value of 300 and emits white light. If +you think of the light value as the wattage for an incandescent +light bulb, you are not far off target. The section on the Light +entity in the Entities Description Appendix contains specific +information on using light entities. + +

Texture Lights
+ +Textures can be made to emit light. The amount of light that +they give off is determined by two factors: the size of the texture +and the value given for its q3map_surfacelight parameter. + +

If you only plan on using id textures in your maps, simply use +the textures surrounded by a white box in the texture window. Many +of them have their light values as part of their names: Example: +ceil22a_5k.  This would be a small, square light with a light +value of 5000.  There is not a direct correspondence between +the light value of a texture light and an entity light. + +

If you want to make your own lights, either with new, custom +textures, or changing the light and/or color values of the emitted +light in existing id textures, plan on learning your way around the +shader files.  The Shader Manual explains the light commands. +Place the new lights in unique directories. Example: +Mymapname_light\skull_light_2k.  Use the q3map_editorimage key +to make multiple light intensity versions of your new lights. + +

Generally speaking, very small lights need to have very large +values to look right (a 32x32 pixel light could easily have a +surfacelight value of 10,000 or more).  As the surface area of +the light becomes larger, the amount of light needs to be +substantially reduced for it to look right in the world.  A +word of warning, though. Very large glowing surfaces (other than +skies) can look odd in the game world, especially if they are made +from a repeating texture.  The light source will appear to be +generated from the center of the brush with the glowing +texture. + +

"Sky" Lights
+ +Quake III Arena was designed so that sky textures could +appear to emit light in a natural way. The q3map_sun parameter +creates a single light source in the sky. The mapper can control +the brightness, color, and position in the sky of this light +source.  Furthermore, the designer can add a +q3map_surfacelight value to the sky, giving it an overall lighting +value. + +

Ambient Light
+ +Ambient light is a property of the map's worldspawn entity. By +assigning a number value to the ambient key, the overall lighting +level of the map is raised. This has the tendency to flatten the +difference between light and shadow. The color of the light can +also be modified. This technique is considered a "hack." It does +not come recommended. You will find instructions that are more +complete later in this manual under the worldspawn entity heading +in the Entities Appendix. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch10/pg10_1.htm b/docs/manual/Q3Rad_Manual/ch10/pg10_1.htm new file mode 100644 index 00000000..07bdc11b --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch10/pg10_1.htm @@ -0,0 +1,858 @@ + + +Q3Radiant Editor Manual: Page 10.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 7: Miscellaneous Commands

+ +

Feedback & Read-outs

+ +The bottom border of the map window holds four clusters of +feedback information. + +

Z-Axis Layers
+ + + +If you are using any window layout that includes the Z-axis +scale, you can see the vertical relationships between components +with this function. + +

Cursor Coordinates
+ +These three coordinates, found to the left of center, report the +xyz position of the cursor in the 2D map window. + +
+ +

Brush & Entity Counter
+ +This readout is located at roughly center position. It reports +the number of brushes (including brushes forming brush entities) +and the number of non-brush entities (items, spawn spots, lights, +etc.) + +
+ +

Pushing the Limits + +This is a good place (as any) to talk about limits. +Quake III Arena has an upper limit of 2048 entities (including +entity lights!!) and while it's not an upper limit, staying under +8000 brushes is a pretty good idea. + +

Selection
+ +This readout temporarily replaces the Brush & Entity counter +when a map component is selected. The numbers represent the +dimensions of the selection. + +
+ +

Origin
+ +This readout temporarily replaces the Brush & Entity counter +when a select map component is moved. The numbers represent the +origin point of the selection (and track it as it moves). + +
+ +

Cursor Travel Distance
+ +These three coordinates, found to the right of the brush and +entity counter, report the distance that cursor has traveled from +the point where the user has clicked on the 2D map window. + +
+ +

Control Settings
+ +In the lower right corner of the editor window, you will see a +string of letters and numbers that might look something like +this: + +
+ +Each of these letter/number combinations represents the setting +for one of the commonly used tools. + +

+ + + + + + + + + + + + + + + + + + + + +
GGrid. Here, it's set to 8 units.
TTexture Tweak. This the increment in pixels that a texture will +shift. Here, it's set to 16 pixels.
RRotation. This is the amount of increment, in degrees that a +texture or brush will rotate.
CCubic Clip depth of field. When cubic clip is set, this is how far, +in terms of 64 unit blocks that you can see into the map. Here, the +setting of 10 would allow you to see 640 units into the map.
LTexture Lock. If M is showing, then it is locked for moves. +If R is showing, then it is locked for rotations.
+ +

Viewing, Seeing, Not seeing, and Hiding

+ +This group of commands all relates to what you see in the map and how you see it. Some are designed to reduce map clutter. Others are designed to improve editor performance. + +

Toggle…
+ +
    Camera View + +Toggles (hides or shows) the Camera View (CAM) window. + +

    Console View + +

    +Toggles (hides or shows) the Console window. + +

    + +Entity View + +

    + +Toggles (hides or shows) the Entity window. + +

    + +XY (Top) + +

    + +Toggles (hides or shows) the XY map window. + +

    + +YZ (Side) + +

    + +Toggles (hides or shows) the YZ map window. + +

    + +XZ (Front) + +

    + +Toggles (hides or shows) the XZ map window. + +

    + +Z View + +

    + +Toggles (hides or shows) the Z (height) window.
+ +

Center
+ + + +Centers the pitch (up and down) angle of the user view. + +

Up Floor
+ + + +This is a shortcut for moving up between "floors" in map. It +changes the user's Z height in the camera and map views. The view +moves to a point where it appears that the user is "standing" on a +"floor" (a brush with "air" space directly above it) directly above +the user's current position in the map. + +

Down Floor
+ + + +This is a shortcut for moving down between "floors" in map. It +changes the user's Z height in the camera and map views. The view +changes to a point where it appears the user is "standing" on a +"floor" (a brush with "air" space directly above it) directly below +the user's current position in the map. + +

Next (XY, YZ, XZ)
+ + + +Cycles the content of the XY map window with the other views +(side and front). + +

Layout
+ + + +
    + +XY (Top) + + + +This returns the main map view to XY Top view. + +

    + +YZ + +

    + +Changes main (XY) map view to YZ Side view + +

    + +XZ + +

    + +Changes main (XY) map view to XZ Side view
+ +

Zoom
+ + + +If the XY Top window is changed to display either +XZ front or YZ side the XY commands +below function the same way relative to the window, zooming in and +out as commanded. + +
    + +XY 100% + + + +Changes zoom on main map view to full size. + +

    + +XY Zoom In + +

    + +Zooms closer to main map. Working in smaller grid scale becomes +easier. + +

    + +XY Zoom Out + +

    + +Zooms out away from the main map. Working in larger grid scale +becomes easier. + +

    Z 100% + +

    + +Changes zoom on the z (height) scale to full size. + +

    Z Zoom In + +

    + +Zooms in closer on the z (height) scale. + +

    + +Z Zoom Out + +

    + +Zooms out and away from the z (height) scale. + +

    Cubic Clip Zoom In + +

    + +This requires that the Cubic Clipping function be toggled on. It +decreases the Depth of Field (distance in which map components are +seen) in the Camera window. Less map components are seen at one +time. Decreasing the distance seen in the Camera window can +significantly improve editor performance when viewing large numbers +of map components. See Cubic Clipping. + +

    Cubic Clip Zoom Out + +

    + +This requires that the Cubic Clipping function be toggled on. It +Increases the Depth of Field (distance in which map components are +seen) in the Camera Window. Increasing the distance seen in the +Camera window can significantly slow down speed at which your point +of view moves in the camera window. Increase the zoom to maximum +distance only if you have a relatively powerful editing system. See +Cubic Clipping.
+ +

Show
+ + + +This is a pop-up menu with checked toggle functions for each of +the features on the list. If a feature is checked, all map +components of that type will show in both the Camera window and the +Map windows. If the feature is not checked, all map components of +that type will be hidden. + +
    Names + + + +Shows names of entities. + +

    Blocks + +

    + +Shows an additional grid over the Map window with subdivisions +every 1024 units. + +

    Coordinates + +

    + +Shows the Map window coordinates along the left and top edges of +the Map window. + +

    Entities + +

    + +Shows entities, including brush entities, lights, and +models. + +

    Paths + +

    + +Shows the linkage connections between entities. This includes +triggers targeted at entities and path lines. + +

    Lights + +

    + +Shows Light entities. + +

    Water + +

    + +Currently non-functional. Look for future fix. Shows brushes +with water, lava, or slime content. + + + +

    Clip Brush + +

    + +This shows brushes with the common/clip content, including +common/clip and common/weapon_clip. The entire brush is +affected, not just clip brush texture sides. + +

    Hint Brush + +

    + +Shows brushes made with the hint texture. + +

    World + +

    + +Shows all non-entity brushes. + +

    Detail + +

    + +Shows all brushes marked with a Detail setting. + +

    Curves + +

    + +Shows all curve patches. + +

    Caulk + +

    + +Shows brush sides containing the common/caulk texture (does not +affect entire brush). + +

    Design Tip: When you optimize detail brushes by caulking +unseen brush faces, isolate the detail brushes in a region then +turn off Caulk. Brush faces that need caulking will show up clearly +as you move around the brushes.
    + +

    Angles + +

    + +Shows facing angle of player start spots by way of a white +arrow.
+ +

Hide/Show
+ + + +This is an immensely powerful and useful tool. It lets the user +temporarily hide map components that may be in the way of working +on other brushes. Hidden components are not affected by CSG +actions. + +
    + +Hide Selected + + +Selected map components are hidden from view (and CSG cutting +operations) until the Show Hidden command is executed. + +

    Show Hidden + +

    + +Previously hidden map components are returned to view.
+ +

Entities as…
+ + + +The editor can show model entities (referring at this point only +to Misc_Model entities) in several formats. Note: More +detail in a model shown in the Camera and map views will affect the +ability of the editor to display the map. If the editor responds +sluggishly, try reducing the level and/or type of detail shown for +models. + +
    Bounding Box + + +This is the simplest form of display. A box defines the outer +dimensions of the model. This is the least costly manner of +display. + +

    Wireframe + +

    + +Non-functioning. + +

    Selected Wireframe + +

    + +The Model is displayed as a bounding box until selected, at +which point the wireframe mesh for the model appears. + + + +

    Selected Skinned + +

    +The Model is displayed as a bounding box until selected, at +which point the skinned mesh for the model appears. + +

    Skinned + +

    +Only the skinned mesh for the model appears in the map and +Camera views. + +

    Skinned and boxed + +

    +The skinned mesh for the model appears inside a wire frame of +the bounding box in both the map and Camera views.
+ +

+ + + +This command toggles on (checked) or off when selected. Cubic +Clipping may be the most effective way to improve editor +performance. When turned on, only those map components near +the player are displayed in the Camera window. Any map components +beyond a certain depth of field will not be displayed in the camera +window (it has no effect on map windows). As the user moves +through the map in camera view, map components will pop into being +as the point-of-view (POV) draws closer and disappear as the POV +moves farther away. The shorter the distance "seen" in the +camera view, the better will be the editor performance when moving +through the map. Use the Cubic Clip Zoom commands +(see above) to modify the depth of field seen in the camera +view. + +

Open GL Lighting
+ + + +This feature is not fully implemented yet. It toggles on +(checked) or off when selected. When it is finished, all planes +facing a particular direction will shade the same way (curves will +shade like brushes) and the overall quality of the camera view will +be better. It will be slower however. + +
    + +Tip: As it currently is implemented, this lighting can be +useful when working with irregular surfaces all covered with the +same texture.
+ +

Show Brush/Patch Dimensions
+ + + +When you select a brush, the hi-lighted image in the map window +shows its dimensions, in game units. If multiple patches or brushes +are selected, the size will be the dimensions of the grouping. If +any kind of non-brush model entity is included in the grouping, the +dimensions are not shown. + +

File Management Commands

+ +
New Map
+ + + +This creates a new map file. If the current map file contains +any unsaved changes, the editor will offer the option to +cancel. + +

Open…
+ + + +This opens up the Maps folder as defined in the preferences. It +will show all valid map files in that directory. User may browse to +other directories from here. Double clicking on a map file +icon or hi-lighting that map and selecting Open will open +the map. The user may also type in a map file name. Be sure to add +the ".map" or ".reg" extensions or the editor will not find the +file. + +

Save…
+ + + +Saves a new map file to the default Maps directory. A reopened +map file will be saved to its source directory. Note, that it is +usually a good idea to save the map into the directory used by the +compiler as the source of its map data. Remember to give the file a +name. The compiler doesn't like to work with files called Unnamed +Map. + +

Save As…
+ + + +Opens the default directory for maps and prompts the user to +give the map a filename. + +

Save Selected…
+ + + +The selected brushes are saved as a map file. This is not the +way to make prefabs, though. + +

Save Region
+ + + +If the user has "regioned off" a subset of the map, this command +will save it as a separate file. It is grayed out unless the user +has created a regioned area. The editor prompts the user to enter a +file name before saving. + + + +

Reopening Maps
+ + + +(ALT+1 to 6 when File menu is held open) + +
OK, There isn't actually a command called this. When you open +the File Menu, you will see (after you've done some work on maps), +the path/file names for the last six maps that you worked on. They +are listed here for easy opening access). + +

Projects and Preferences

+ +

New project…
+ + + +Make a new project file. This allows you to set up different +preferences. + +

Load project…
+ + + +Make a new project file. This allows you to set up different +preferences. + +

Project Settings…
+ + + +Change pathnames and add, remove or modify commands. + +

Miscellaneous Commands

+ +
Map info…
+ + + +This gives a readout of brushes (including curve patches) and +entities in the map, including the total number of brushes that are +not part of entities. There is also a breakdown, by type, showing +the number of entities in the map. + + + +

Entity info…
+ + + +This gives a read-out of the entities in a map by their +type. It allows you to select an entity, which +hi-lights it in the XY Map. Good for locating lost entities. + +

Preferences
+ + + +This opens the window for setting or modifying the parameters, +paths and features of the editor. Preferences are discussed in the +Installation & Set Up section earlier in this document. + +

Opening Menus from the Keyboard

+ +These are the keyboard shortcuts that open up the menus. If you +continue to hold down the ALT key, many of the commands in that +menu may be activated with an ALT+ keystroke command. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File(ALT + F)
Edit(ALT + E)
View(ALT + V)
Selection(ALT + S)
Bsp(ALT + B)Note: Toggles between BSP & Brush. Hit enter to open selected.
Grid(ALT + G)
Textures(ALT + T)
Misc(ALT + M)
Region(ALT + R)
Brush(ALT + B)
Curve(ALT + C)
Plugins(ALT + P)
Help(ALT + H)
+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch11/pg11_1.htm b/docs/manual/Q3Rad_Manual/ch11/pg11_1.htm new file mode 100644 index 00000000..e495ca6c --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch11/pg11_1.htm @@ -0,0 +1,116 @@ + + +Q3Radiant Editor Manual: Page 11.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 8: Compiling Maps

+ +To turn a map file from editor code into game code, it must be +processed or "compiled". In Quake engine gaming, this is often +referred to by the name "BSP", as in "I need to BSP my map before +you can play it." The word "BSP" is actually an abbreviation +for "binary space partition", the type of data organization +procedure John Carmack used when creating the graphic engine for +"DOOM". + +

The primary BSP process builds the game spaces, +establishes the position of entities, and builds a lighting map of +the arena. Altogether, there are four distinct processes that +can be run together or separately. The first, the bsp process +establishes the data organization of the map. The second phase, the +vis process, builds the walls and internal spaces. The third +process lights the map, calculating brightness and shadow and the +color of the light that falls on every map surface. The fourth and +final process is the Bot bsp, which creates the area (.aas) file +that the bots use to navigate the map. + +

The size and complexity of a map and the computer's raw +processing speed determine how long it will take a map to compile. +Tiny one-room maps that lack detail or numerous lights will compile +rapidly. As maps become larger, are broken up into more +spaces and have more complex lighting, the speed of compile +drops. + +

Generally speaking, if you have an older, slower processor, you +may want to make very small maps. + +

The BSP Menu
+ +The bsp menu contains a number of compile options. The process +you choose will depend on what you are doing with the map at the +time you choose to compile. + +

novis - Only the bsp function is performed. Checks +for map leaks. No light information is created, so the map is seen +at "fullbright". Because there are no shadows to get in the +way, this mode is also good for looking for overlapping brushes, +and texture misalignment. + + + +
fastvis - Performs a bsp and a quick version of the vis +process. The entire world is made into a single bsp partition. It's +fast, but when you look in a particular direction, you see every +single detail in that direction. Nothing is blocked. A light map is +created. This mode was used for space maps. + + + +
fullvis - the world is subdivided and broken up +into smaller chunks so you can see only what is logically in your +view. A light map is created. This is what is used to check +polygon-in-view counts. Combined with light extra, it is the final +compile for all maps. + + + +
entities only - When you add or subtract non-brush model +entities from a map, use this compiler. It's very quick. If you +change the brush components of a brush model entity (like a trigger +or a door), you must do a compile that includes a vis stage (fast +or full). If you are only changing the properties, an entities-only +will do. However,, if a brush model entity also has a md3 model +component, the map must be at least fastvis'd for that entity to +appear in the map. + + + +
relight - Use only if no geometry (or light emitting +textures) have been changed. It will rebuild the light map with the +new information. + + + +
(nocurves) - This function is always a modifier to +another bsp command. It does (or doesn't do) what it says. The map +is compiled without curves. + + + +
(nowater) - This function is always a modifier to another +bsp command. The map is compiled without water, lava, or slime. + + + +
(no light) - This function is always a modifier to +another bsp command. No light map is generated. A fast way to check +polycounts. Most often used in conjunction with the novis bsp +command. + + + +
(-light extra) - This function is always a modifier to +another bsp command. A finer degree of subdivision is used to +create a more detailed light map. This is generally only done when +the lighting is going through a final fine-tuning because it takes +a long time. Instead of being calculated in 16 unit increments, the +light is calculated in 8 unit increments. This has no effect on +final map size, only on the time needed to compile. + +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch12/pg12_1.htm b/docs/manual/Q3Rad_Manual/ch12/pg12_1.htm new file mode 100644 index 00000000..2b79b319 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch12/pg12_1.htm @@ -0,0 +1,285 @@ + + +Q3Radiant Editor Manual: Page 12.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 9: Debugging Maps

+ +Regardless of your skills, you can almost guarantee that you are going to make mistakes building your maps. You need tools to help you find and correct those mistakes. There are two classes of map debugging tools usable with Quake III Arena. The first are those that the editor gives you. The second are commands usable in the game. + +

The Editor's Debug Tools

+ +The Q3Radiant editor has some built in debugging tools + +

The Pointfile
+ +One of the most useful tools in the box, this is the "red flag" that warns you about problems with the "hull" or "shell" of the map. When you compile a map, the bsp process checks the integrity of the map hull. If a map has a hole in it's hull or if an entity's origin point is placed outside the map hull, the map will "leak". Quake III Arena maps must be totally contained volumes. They cannot have "leaks" in them. Leaks are openings in the hull between the contained space (or "breathable" as one mapper has described it) and the outer void where nothing can abide. + +

The pointfile appears as a series of points, connected by red line segments, that traces a connecting path between an entity inside the hull and a point in the outside world.. Follow the pointfile through the map and note where it passes out of the enclosed space and into the void. In the case of an entity outside the world, it may just draw a line near the entity. You may need to turn off the display of clip and hint brushes, and curves to find the leaks. Adjust your solid map geometry to close up the leaks. + +

When you save the map (or an auto-save occurs), the pointfile disappears. You can bring the pointfile back by toggling this command. + +

Note: If you use a front-end program for compiling, such as Q3Build, you will need to reload the map file and select the "pointfile" command under the File menu. + +

Next leak spot
+ + +If you have a pointfile displayed in your map, use this command to move from point to point along the file. It's an easy way to move along the path to the point where the red line passes out of the contained space of the map. + +

Previous leak spot
+ +A feature just like "Next leak spot", except that you move backwards along the pointfile. + +

Junk.txt
+The Q3MAP compiler outputs this log file. It logs what the compiler is doing during the process; displays error messages and +gives final compile times for each phase. Because the compiler works in three discrete phases, you can also use this +output to gauge how far along the compile has gone. Edit the project file to change the path to the destination for this +output. + +

Error Messages
+When you compile a map, you are likely to get error messages. Most of these are not serious and the game engine either corrects them or ignores them. This is a sampling of common messages and what you should do about them. + +

Mixed faces: One or more faces on a brush has a surface parameter that conflicts with the other surface parameters. This is not a problem. Putting nodraw or clip on a brush that has a face that draws will cause this. That includes most all "flame" brushes, many water brushes, and just about every instance where alpha-channel textures are used to create see-through brush faces. + +

Bad point to polygon form factor: A curve patch is larger than 512 units in at least one dimension. This is not fatal, but may result in some unusual light artifacts on the curve. + +

Unknown surfaceparm: "nomipmaps" Some shaders contain old or incorrectly spelled parameters. This is not a problem. + +

Too many portals. Your map is broken into too many separate hulls by areaportal brushes. Try to keep the number of +discrete portalled areas under 16. + +

Duplicate plane. During the course of manipulating brushes, you may have moved edges in such a manner that two +adjacent sides of a brush now form a single brush side. Use Find brush to locate the problem brush. Use the old brush as a template or pattern, but build the new one with a single side in the place of the duplicate plane sides. One way to solve the problem is to use the Clipper tool cut off a corner instead of collapsing two faces into one. While this is not a serious problem for multiplayer play, it can create "solid" areas in the bot navigation (.aas) file. This makes the bots think there are walls in places where there appear to be none. You can check for solid areas with the "bot_testsolid 1" inside the game (after creating an .aas file). See the Bot Navigation appendix for more details. + +

******* Leaked *******. There is a hole between the contained space of your map and the outer void. Use the pointfile to locate the problem. + +

Couldn't load baseq3/pics/colormap.pcx trying tools/colormap.pcx...failed! This is not a compile error, +but a loading error. Correct it by checking the hi-color textures setting in Preferences. + +

Loading base_light/light_flare...failed, using default shader. Just ignore this. + +

match token ("{") failed at line [line number]. You broke a shader while editing it. Go closely look at the shader you most recently edited. Chances are you'll find a bracket error in the syntax. + +

In-game Debug tools

+One of the best places to look for errors in your map is within the Quake III Arena game itself. After the map has compiled, +execute your Debug Config and load your map. The commands here will help you discover the errors in your map. + +

General Cheats
+The following are the general Quake III Arena cheat codes (they're actually developer's tools). You can enter them from the console, or bind them to whatever keys you prefer using the syntax bind [key] [command]. If the command is a string with spaces, then the string should be enclosed with quotation marks. + +

give [weapon/item/ammo/health] [amount] // Give selected weapon/item/ammo/health + +

give all // Gives all weapons, ammo, armor, and items + +

god // Godmode + +

noclip // Pass through anything. Use in conjunction with r_fastsky 1 or r_clear 1, or you will have hall of mirror problems when you pass out of the bounds of the map. + +

notarget // Bots think you're a pal viewpos // Outputs player coordinate position and facing angle. + +

General Toggle Binds
+(Thanks to original authors GrandMaMa and Eutectic) +
The following are some binds that you might like handy. Note that some of these will alter saved settings, so make sure that your preferred settings are loaded on startup, like in your autoexec.cfg file. + +

bind "your key" toggle r_speeds // polycount report +
bind "your key" toggle r_showtris // tris triangles +
bind "your key" toggle cg_drawfps // framerate counter +
bind "your key" toggle com_speeds // shows all stats +
bind "your key" toggle r_drawentities // ents won't be drawn +
+ +

Debug Mode: Logfile Creation
+One method that can be used for troubleshooting maps where curious errors occur (usually when simply too much is going on at +once) is to resort to poring over the developer output. The console buffer is limited, and error-producing maps may crash, so printing the output to a logfile is desired. This script allows the toggling of these functions. + +

bind "your key" vstr dbg set dbg vstr debug_1 + +

set developer 0 set logfile 0 set debug_1 "set dbg vstr debug_0;echo DEBUGMODE ON;developer 1;logfile 2" set debug_0 "set +dbg vstr debug_1;echo DEBUGMODE OFF;developer 0;logfile 0"

+ +

GL_Showtris/R_Speeds/FrameCounter Toggle
+(Based in part on an article by orginal author MD) +

The "gl_showtris" and "r_speeds" commands allow you to see the number and location of polygons (surface triangles) in your view. The " + +

Show me the Triangles +Showtris draws a white line around each triangle used to create the world when it is a part of a map's potential viewable set (PVS). This is especially effective tool, since it shows the triangle outlines of map areas that are being "seen" by the engine, which are not always just the ones that the player sees. + +

Depending on your video card, this may work well, or it may not. For some (like the Matrox cards, it comes with a huge performance hit). + +

The Need for (R_) Speeds +This output is one of the more valuable reports you can get on a map. The numbers show you the numbers that can tell you what kind of real visual costs you are encounter. Combined with other commands that turn features like entities, curves, and multi-pass texturing on and off, you can get a realistic idea of where you're having problems. + +

Here's what those cryptic numbers mean. +When r_speeds = 1, the numbers read as follows (where the # sign equals a number) + +

# / # shaders/surfs is the number of shaders in view, followec by the number of surfaces in view. + +

# leafs is how many leaf nodes are potentially visible. + +

# verts is how many vertexes are in view + +

# / # tris is the number of trangles drawn by the renderer in a single pass single pass followed by the number of +triangles drawn by the renderer with all passes. These are the numbers that are most often implied when someone talks about +"r_speeds." If the r_ext_multitexture variable is off, the numbers will reflect a more accurate accounting of the real triangle count (see multi-pass texturing section below). + +

# .## mtex #.## dc [definition under construction] + +

Frame Rate +There is a tendency for rate of frame display to become a sort of god (or at least a "greatest good") for some players. Their quality of play, whether real or psychological, revolves around how fast their computer is flipping through screen updates. Everything else, to them, is throw away. While the design and complexity of a map can affect this, so can many features that are outside of the designer's control. For that reason, frame rate is not a particularly good way to judge the quality of your map. + +

The "cg_drawfps 1" command gives you instantaneous frame rate readout. + +

Use this command string to toggle the three at once. Include the following lines in your Debug Config script: + +

set r_showtris 0 +
set r_speeds 0 +
set cg_drawfps 0

+
bind "your key" "toggle r_showtris;toggle r_speeds;toggle cg_drawfps"
+ +

Lock the PVS Table
+(Author: MD) +
"PVS" means "potential viewable set." The PVS includes all the polygons that can be seen from a particular location in the map (i.e., where you are standing now). The game engine updates what is visible and what is not as you move through the map. You can stop this updating process, and see just how far the engine can see by moving until you find an area of the world that's not being drawn. Use this to debug views where the frame rate drops below an acceptable level. Go to a place where you get a bad "fps" reading. Execute this command. When the PVS Table is locked, you can walk through the map and see exactly how far your view extends. Surfaces in view will be drawn as normal. Non-seen surfaces will show up as the Hall of Mirrors effect (unless the fast sky or r_clear options are also set). Use the information as a guide for changing what can be seen in a view. + +

This command string script toggles the use of the PVS table to let you do this. It also toggles on the r_clear option, so +instead of Hall of Mirrors the void beyond the world is seen in fashion doll pink. + +

set r_lockpvs 0 set r_clear 0 +
bind "your key" vstr lockview set lockview vstr lockview1 +
set lockview1 "set lockview vstr lockview0;echo PVS Locked;r_lockpvs 1;r_clear 1" +
set lockview0 "set lockview vstr lockview1;echo PVS Unlocked;r_lockpvs 0;r_clear 0"
+ +

MultiPass Texturing Toggle
+(Based on an article by original author: MD<) +
The number of triangles that must be drawn before a frame can be displayed affects the speed at which the game is played. More triangles means lower speed. When a texture on a triangle requires additional drawing passes, it is the same as drawing an additional triangle again for each pass of redraw. The ideal video card for the Quake III Arena game is one that has a multi-pass texturing feature. What this means is that the second rendering pass on a texture is essentially free. Its triangle cost is not calculated into the r-speeds. Unfortunately, the map designer cannot plan on every user having such a card and must instead design for worst case scenarios. If you are working on machine that has a multi-pass texturing feature, you will need to find out how the other half plays. You need to toggle the feature off for this. + +

This feature toggles between multi-pass texturing and single-pass texturing. When multi-pass texturing is enabled, the +additional triangles are masked. They won't appear in the r_speeds report. + +

For this feature to work, the video must be restarted. That command is included in the binding. For best results, refrain from pressing the bound key again until the video has re-initialized and the map has re-loaded. Your normal setting for r_ext_multitexture should appear also. In the key binding below, it's been set to a value of 1, which is the most common. This way it will be properly set on startup, since this toggle can hose that setting. + +

set r_ext_multitexture 1 +
bind "your key" "toggle r_ext_multitexture;vid_restart"
+ +

Turning Off Curves and Entities
+How much of the r_speed cost in your map can be attributed to entities. How much to curves? These two commands turn off the +drawing of those entities. The set commands start by setting the features to their "on" condition. + +

bind "your key" toggle r_drawentities // entities won't be drawn +
bind "your key" toggle r_nocurves // curves won't be drawn
+ +

Curves, Caulk, T-Junctions and Cracks

+(From an article on the same by Martin Ka'ai Cluney) + +

During the course of Quake III Arena development, a number of solutions were created to deal with the idiosyncrasies of the compiling process. None of these problems is a game killer, but the presence of these little flaws tends to reduce the professional appearance of game maps. + +

An Explanation of "Z-Fighting"
+"Z-fighting" is caused when the engine tries to simultaneously draw two surfaces that share the same plane. "Z-fighting" +commonly occurs when two brushes with different textures are in the same place (see fig. X-1,) but it can also occur on some video cards when a patch is placed over a textured brush (see fig. X-2.) + +

An Explanation of T-Junction Cracks
+"T-junction cracks" are a little more complicated than 'Z-fighting', and can be more difficult to track down and fix. They +are caused when the vertices (control points) of a curve patch don't match up with surrounding world geometry. They can be caused when a patch extends into the world on one or more sides (see fig. X-3,) or when there is a split in the faces that make up one or more edges of a patch (fig. X-4.) + +

Avoiding T-Junction Cracks and Z-fighting
+The best way to keep maps free of "T-junction cracks" and "Z-fighting" is to keep these problems in mind while adding patches and supporting geometry. There are a few simple methods for adding patches. Initially, they may seem like more work that they're worth, but they will save hours of hunting down and fixing problems that can arise through careless construction. + +
  1. Avoid spanning more than one brush with one edge of a patch. For example, if an inverted bevel is 128 units tall, back it with 128 unit tall caulk brushes. Likewise, if the wall is made up of two vertically stacked brushes; use two +vertically stacked patches of matching heights. + +
  2. Avoid patches that extend into world brushes, unless all of the edges extend into world brushes. When +adding patches, if one edge of the patch extends into the world, while the other edges line up with other brushes, there will most likely be cracking. Sometimes, particularly in the case of 'flesh' elements, it is necessary to extend parts of a patch into the world. In these cases, extend all edges into the world, or into surrounding patches. + +
  3. Be Careful with vertices. Use Snap to Grid. Without it, your curves will create far more problems than they will otherwise might. Sometimes, especially after resizing patches, vertices can get "knocked off" the grid. Always make sure vertices are where they're supposed to be. If needed, patch vertices can always be snapped back to the grid using CTRL+ G. It's always a good idea to be completely aware of where things are in relation to the grid. + +
  4. Caulk, caulk and more caulk. Get into the habit early of building the space behind curve patches with caulk brushes. You will eliminate Z-fighting, seal up the area behind the curves, and unless you are building a map in fashion doll pink, edges that aren't aligned with the curves have a better chance of showing up.
+ +

Here are a few examples of common elements from the maps in Quake III Arena, and how they should (and should not) be built to avoid Cracks and "Z-Fighting": + +

Jump Pads +
Jump pads are probably the most common occurrence of T-junction cracks in Quake III Arena Maps. They usually extend upwards +through at least two 'levels' (layers) of textures, so they're a perfect illustration of proper caulking. They are also a +perfect illustration of 'binding' curves within structural brushes. + +

Flat arches +
Flat Arches are another good example of 'binding' curves with structural brushes. This is a handy technique when incorporating a curve into a complex map element seamlessly. + +

Rounded Wall Edges (endcapped) +
This is a simple example of terminating a wall in a rounded edge. The most important thing to keep in mind here is where +the vertices are placed. If the patch is extended into the ceiling or floor, there will almost certainly be cracks. + +

Inverted Wall Bevels +
Filleting a wall seems like it would be a simple thing, but there are many cases that could cause cracks. It's important +to make sure heights are consistent, especially in the case of layered texturing, as is the case in this example. + +

Finding and Fixing T-Junction Cracks and Z-Fighting
+There will usually be cases where, despite careful building, cracks appear. When looking for cracks that may have been missed, there are three console commands that will be a great help: + +

\r_clear 1: This will clear the frame buffer on each frame, eliminating the Hall of Mirrors effect. + +

\r_fastsky 1: This will draw the sky as a single, solid color, making it easier to see the void behind curves. This makes cracks stand out. Be aware that fastsky also disables the function of portal screens and mirrors. + +

\r_showtris 1: This will draw white lines around all of the triangles in the world, showing exactly how the geometry in the map is affecting the patches. + +

NOTE: Another good way to use these commands is to set them to toggle on a key. The Debug Config below contains these commands as toggles. + +

Turn on r_clear, and r_fastsky, and run through the map, looking at the patches from all possible angles. If there is a crack, turn on r_showtris, and make sure that the patch does not extend into the world, unless it was intended to. Next, look at the surrounding brushes. Make sure that no splits meet the edge of the patch. If neither case is true (it happens these case… 'mystery cracks'), then try a different approach to building the area; perhaps splitting one patch into two, or rearranging the brushes surrounding the patch. When none of the above seems to work, experiment with as many different ways as possible. If something works, keep it in mind for the next time. + +

A Debug Config

+The following script should be copied and pasted into a text file. Save the text file as "debug.cfg". When you want to use +these commands while playing a map, you need to load the map using the console. First type in "/devmap [mymapname] to load the map. Next type in "/debug.cfg". This executes your development configuration. Note that this changes the key assignments of some keys (you define which one is used for each assignment of "yourkey". These debugging tools are considered "cheats." They will not function during normal game play. + +

//+++++++++++++++++++++ +
//toggle on/off frames per second, polygon wireframes, and polygon in view counts with one keypress +
set r_showtris 0 //sets triangle display to off +
set r_speeds 0 //sets triangle counter display to off +
set cg_drawfps 0 //sets frame display counter to off +
bind "your key" "toggle r_showtris;toggle r_speeds;toggle cg_drawfps" + +

//The following are some individual binds for a few debug tools +
set r_drawentities 1 +
set toggle r_nocurves 0 +
bind "your key" "toggle r_speeds" // polycount report +
bind "your key" "toggle r_showtris" // Shows the actual triangles that form the world +
bind "your key" "toggle cg_drawfps" // framerate counter +
bind "your key" "toggle com_speeds" // shows all stats +
bind "your key" "toggle r_fastsky" //turns off detailed sky and turns void to sky color +
bind "your key" "toggle r_clear 1" // This will clear the frame buffer on each frame. + +

//Show coordinates that can be related to map coordinates. +
bind "your key" "viewpos" // Outputs player coordinate position and facing angle. + +

//Turn off Entities and Curves +
bind "your key" "toggle r_drawentities" // entities won't be drawn +
bind "your key" "toggle r_nocurves" // curves won't be drawn + +

//Toggle off the multi-pass texturing feature +
set r_ext_multitexture 1 +
bind "your key" "toggle r_ext_multitexture;vid_restart" + +

//Output console messages to a log file +
bind "your key" vstr dbg set dbg vstr debug_1 +
set developer 0 set logfile 0 set debug_1 "set dbg vstr debug_0;echo DEBUGMODE ON;developer 1;logfile 2" set debug_0 "set dbg vstr debug_1;echo DEBUGMODE OFF;developer 0;logfile 0" + +

//Lock the PVS Table +
set r_lockpvs 0 //turns off any existing PVS lock +
set r_clear 0 //turns "void" bright pink +
bind "your key" vstr lockview set lockview vstr lockview1 //binds three vstr scripts to a key +
set lockview 1 "set lockview vstr lockview 0;echo PVS Locked;r_lockpvs 1;r_clear 1" +
set lockview 0 "set lockview vstr lockview 1;echo PVS Unlocked;r_lockpvs 0;r_clear 0" + +

//Game Cheats (for debugging purposes) +
bind "your key" "give all" // Gives all weapons, ammo, armor, and items +
bind "your key" "god" //toggles god mode //makes player invulnerable to everything but kill triggers +
bind "your key" "toggle noclip; toggle r_clear 1"//toggles ability to pass through walls and clear function +
bind "your key" "notarget" // Bots think you're a pal (until you shoot them) +

+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm b/docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm new file mode 100644 index 00000000..182f2f2a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm @@ -0,0 +1,69 @@ + + +Q3Radiant Editor Manual: New functionality in GtkRadiant + + + + + +Better movement in camera window + +

Q3Radiant Editor Manual

+
+

Better movement in camera window

+ +

+By enabling "Freelook in 3D window" in the preferences screen you can use a +noclip style of movement in the camera window. Rightclick in your camera window +(or shift+rightclick if you are in 2 mouse button mode) to start freelook mode. +The mouse can be used to look around, up arrow is forward, down arrow is +backwards, left and right are strafing. You can control the sensitivity of the +camera controls in the preferences screen, directional velocity is for movement +(forward/back/strafe) and angular velocity is mouse sensitivity. Also you can +enable inversed mouse mode here. +

+ +

+Another way of moving backward and forward in the camera window is by using +your mousewheel, scroll up is forward, scroll down is backwards. This works in +all camera modes, classic as well as freelook. +

+ +

Mod support

+ +

+1.1-TA was the first version to add builting support for mod directories, +bringing easy editing capabilities for Quake III: Team Arena. This has been +extended to support any mod developement. Simply open the project settings +dialog to set the mod directory (among several builtins, +Quake III Arena, Quake III: Team Arena and custom mods). +

+ +

Misc functionalities

+ +

+The mousewheel has gotten another new option for the 2D windows. Scroll up is +zoom in, scroll down is zoom out. +

+ +

+It is possible to texture faces simply by selecting a texture in the +texturewindow and dragging it into the 3D (Cam) window onto the face you want +to texture with it. +

+ +

+More GtkRadiant tips and tricks have been gathered on the +qeradiant.com FAQ. +

+ +

Known issues

+ +

+Current known issues for GtkRadiant releases are listed in the +qeradiant.com FAQ. +

+ +

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/index.htm b/docs/manual/Q3Rad_Manual/index.htm new file mode 100644 index 00000000..45e06e96 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/index.htm @@ -0,0 +1,180 @@ + + +Q3Radiant Editor Manual: Contents + + + + +

+

Q3Radiant Editor Manual

+ +
Based on Version 192 - partly updated to GtkRadiant
+ +

By Paul Jaquays + +

With additional contributions by Astrocreep, Christian Antkow, +
EutecTic, Inolen, Mr. Elusive, Maddog, Martin KaÂ’ai Cluney, +
Robert A. Duffy, Small Pile of Gibs, Suicide20, and The Dog! + +

Special thanks go out to the members of the Quake3world Editing forum. + +

Your questions prompted many of the sections in this manual. + +

QERadiant.com thanks John Hutton for re-formating this manual into a more +web friendly version. +

+ +

Table of Contents

+Preface +
Introduction +
Minimum System Requirements + + +Installation & set-up + + +Entities and assets + + +New Functionalities in GtkRadiant + + +Map-building basics + + +Tools 1: Selecting and deselecting + + +Tools 2: Working with brushes + + +Tools 3: Working with curve patches + + +Tools 4: Working with textures + + +Tools 5: Working with entities + + +Tools 6: Lights & lighting + +
Tools 7: Miscellaneous commands + + +Tools 8: Compilings maps +
Tools 9: Debugging maps + + +Appendix A: Glossary of Terms +
Appendix B: Entity descriptions + + +Appendix C: Bot navigation files + + +Appendix D: Tips, tricks, and tutorials + + +Appendix E: Online resources + + +Appendix F: Default key shortcuts +
Appendix G: Shortcut keys and mouse functions + + + diff --git a/docs/manual/Q3Rad_Manual/styles/q3rad.css b/docs/manual/Q3Rad_Manual/styles/q3rad.css new file mode 100644 index 00000000..b4daab91 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/styles/q3rad.css @@ -0,0 +1,23 @@ +body { font: 12pt "Times New Roman"; + margin-left: 5mm; + margin-right: 5mm; + text-align: justify; + background: #ffffff; + color: #000000 } +h1 { font: bold 24pt Arial, Helvetica } +h2 { font: bold italic 18pt Arial, Helvetica } +.subheading { font: bold 16pt Arial, Helvetica } +:link {color: blue; + text-decoration: none; } +:visited {color: purple; + text-decoration: none; } +h6 { font: 10pt "Times New Roman" } +.MsoToc2 { font: bold small-caps 12pt "Times New Roman" } +.MsoTitle { text-align:center; + font: bold 24pt "BankGothic Md BT"; + letter-spacing:2.5pt } +.heading { font: italic 10pt "Times New Roman" } +.subcontents { font: 10pt "Times New Roman" } +.tip { font: 10pt "Comic Sans MS" } +.type { font: 10pt "Courier New" } +.menu { font: 10pt Arial, Helvetica } \ No newline at end of file diff --git a/docs/manual/quake3/Compile_Manual/bspc.txt b/docs/manual/quake3/Compile_Manual/bspc.txt new file mode 100644 index 00000000..90fd96d4 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/bspc.txt @@ -0,0 +1,565 @@ + + +Title: BSP Converter +Version: 2.1h +Date: 2001-03-28 +Author: Mr. Elusive + + +Description +----------- + +The BSPC tool is used to create AAS files from BSP files. +An AAS file is a file with areas used by the Quake III Arena bot in order +to navigate and understand a map. The Quake III Arena maps are stored in +BSP files. + + +Usage +----- + +bspc [- [- ...]] + +Example 1: bspc -bsp2aas d:\quake3\baseq3\maps\mymap?.bsp +Example 2: bspc -bsp2aas d:\quake3\baseq3\pak0.pk3\maps/q3dm*.bsp + +Switches: + bsp2aas <[pakfilter/]filter.bsp> = convert BSP to AAS + reach = compute reachability & clusters + cluster = compute clusters + aasopt = optimize aas file + output = set output path + threads = set number of threads to X + cfg = use this cfg file + optimize = enable optimization + noverbose = disable verbose output + breadthfirst = breadth first bsp building + nobrushmerge = don't merge brushes + freetree = free the bsp tree + nocsg = disables brush chopping + forcesidesvisible = force all sides to be visible + grapplereach = calculate grapple reachabilities + + +Several metacharacter may be used in the filter and pakfilter. + +* match any string of zero or more characters +? match any single character +[abc...] match any of the enclosed characters; a hyphen can + be used to specify a range (e.g. a-z, A-Z, 0-9) + +.pk3 files are accessed as if they are normal folders. For instance +use "d:\quake3\baseq3\pak0.pk3\maps/q3dm1.bsp" to access the +map q3dm1.bsp from the pak0.pk3 file. + +Multiple files may be listed after the switches bsp2map, bsp2aas, reach, +cluster and aasopt. + +If a BSP file is being converted to an AAS file and no output path +is entered on the command-line then the AAS file will automatically +be stored in the same folder as the BSP file. However if the BSP file +was stored in a .pk3 file then the AAS file will be stored in a folder +with the name 'maps' outside the .pk3 file. + + +Updating entity lump +-------------------- + +If an AAS file is already available for a BSP file and you ONLY change +the entities inside this BSP file then you only have to recalculate the +reachabilities. This way you can move items, platforms etc. around +without the need to recalculate the whole AAS file which can save quite +some compile time. You can recalculate the reachabilities as follows: + +bspc -reach mymap.bsp + +Where mymap.bsp is the BSP file. The mymap.aas file has to be in the +same folder as mymap.bsp or should be in the output folder specified +with the -output option. + +Keep in mind that as soon as ANY geometry in the map changes the whole +AAS file HAS to be recalculated in order to play with bots. + +NOTE: -reach does not work on optimized .AAS files! +NOTE: don't use -reach when moving the position of doors. + + +Leaks +----- + +Just like there can be vis leaks in a map there can also be clipping +leaks. Two things can be wrong when the BSPC tool outputs that a map +leaks. + +1. There are no entities in the map at all, or all entities that are +actually in the map are placed in solid. In this case the BSPC tool +outputs "WARNING: no entities inside". (At least a player start entity +is needed to load a map.) + +2. There is a spot in the map where players can go outside the map +into the void. This is bad, players should never be able to fall out +of a level. In this case the BSPC tool outputs "WARNING: entity +reached from outside". The BSPC tool also writes a mymap.lin file +that can be loaded in the Q3Radiant editor to show lines that go +through the actual leak. + +Make sure the .lin file is stored in the same folder as where q3radiant +stores the .bsp file. Load the map in q3radiant and use the +menu -> File -> Pointfile... to load the .lin file. A thick red line +will be shown in the map. Follow this line to find the leak. + + +Map bounds +---------- + +Currently a map should be within the bounds (-65536, -65536, -65536) - +(65536, 65536, 65536) for the bspc tool to compile. These are the same +limits the q3map tool has. + + +Physics +------- + +The player bounding box is a 30 units by 30 units square with a height +of 56 units. If we assume 1.75 meters being the average height of a human +and a player in Quake III Arena being 56 units high we get 32 units = 1 meter. + +Maximum step height of a player is 18 units (just keep steps 16 units or +lower). + +The maximum water jump height for bots has been set to 18 units. (height +difference between water surface and the floor jumping onto). If the +waterjump height is made higher human players will have a hard time getting +out of the water. + +With normal gravity and without the quad the maximum rocket jump height is +around 280 units (you can sometimes jump a few units higher but this is a +safe value for reference). + +The maximum height for barriers the bots will jump on is 32 units. + +Some math to calculate some other values of interest: + +gravity = 800; +jump velocity = 270; +max vertical rocketjump velocity = 670; +max run velocity = 320; +max step height = 18; + +max jump height = 0.5 * gravity * (jumpvelocity/gravity)*(jumpvelocity/gravity); +max jump height = 45 units; +NOTE: even though this is the mathematical maximum jump height always keep +the the 32 units maximum barrier height for bots in mind when building maps. + +maximum horizontal jump distance over a gap from one spot to another both +at the same height: + +t = sqrt((maxjumpheight + maxstep) / (0.5 * gravity)); +t = 0.3986 seconds; +dist = maxrunvelocity * (t + jumpvelocity / gravity); +dist = 235 units; +Because players use a bounding box we can jump a full bounding box width +furter in the ideal case. (15 units at the jump start and 15 at the +landing place). +235 + 15 + 15 = 265 units. +Again this is the mathematical maximum which players can only reach under +ideal circumstances. + + +Optimizing a map for bspc +------------------------- + +Hint brushes have no effect on the bspc tool. Only solid, clip, liquid, +cluster portal and do not enter brushes are used by the bspc tool. + +The bspc tool outputs how many areas are created for a map. Less areas +is better. Often the number of areas can be reduced by adding additional +clip brushes. By adding these additional clip brushes the complexity +of the geometry used for collision can be reduced. Do not add clip +brushes in front of the complex geometry but get the complex shaped +geometry contained within these clip brushes. Things that should be +contained within clip brushes are small or complex shaped (often detail) +brushes and complex and twisted curves, but also more regular curves +can be placed within a clip brush. When containing a curve within a +clip brush it's preferred to place the whole curve within the clip +brush (not just part of the curve). +Note: you can make brushes or curves non-solid when they are contained +within *full* clip or *weap* clip brushes to speed up bspc calculations. + +Always try to align your geometry to the grids. Always use the largest +grid possible for alignment of your geometry. Also try to align the +back sides of brushes which may not be visible. The more brush sides +are aligned the better. This will also speed up bspc calculations. + +Align adjacent brushes as much as possible. Make sure no tiny faces are +created due to badly aligned brushes. + +Quite often there are places in a map that are visible to players +but that players can never get to. Players would be able to walk around there +but since players can never reach such places they will never actually +move around there. If players are never able to get to such places +it's better to put a large clip brush which encloses that whole space. +This will also speed up bspc calculations and reduce the number of areas +created by the bspc tool. + +Note: the number of areas relative to the map size tells something about +the navigation complexity for players in general (also human players). +Reducing the collision complexity for bots also makes the map easier to +navigate for human players + + +func_plat and func_bobbing +-------------------------- + +When func_plat or func_bobbing entities are placed in a map the bots will +use them if possible. The bots assume they can stand on top of the bounding +box of the model used for the func_plat or func_bobbing entity. As a result +creating complex shaped func_plat or func_bobbing models is mostly a bad +idea. You have to make sure the bots (and players) can actually stand +everywhere ontop of the bounding box of the model. + + +Cluster Portals +--------------- + +A map is divided into areas. Several of these areas can be grouped together +to create a cluster. The clusters are seperated by cluster portals which are +areas themselves. One of the things the bot uses these clusters for is a +multi-level routing algorithm. When a map is efficiently divided up into +clusters bot calculations will be faster. + +several things to take into account: + +- The BSPC tool tries to create cluster portals automatically but additional + cluster portals can be created by placing "clusterportal" brushes. +- Cluster portals are manually created by placing "clusterportal" brushes + inside the map. +- Cluster portal brushes are a tool to optimize a map for CPU usage by the + bots. They are not needed for the bots to operate correctly. +- The "clusterportal" brushes should not be used outside the world hull. +- The cluster portals do not have any effect on vis. +- If a door is already sealed with an areaportal brush, a clusterportal is + not necessary there. (area portals are also used as cluster portals). +- Just like the area portals, the cluster portals must seal a space off + entirely from other areas. +- The cluster portal areas should seal off a cluster in a way that the only + path towards another cluster is through a cluster portal area. +- Only create cluster portals where people can walk or swim through. +- Don't create cluster portals in gaps in the floor. (people would fall through) +- If you have two sealed off clusters and you add a teleporter between them + then the two clusters will be merged again because of the teleporter. +- Cluster portals must seperate no more and no less than two (2) clusters. +- Try to create clusters with all the same number of 'reachability' areas. + for instance if the map has 5400 areas try to create 10 clusters with 540 + areas each, or 12 clusters with 450 areas each, etc. The BSPC tool lists + the number of reachability areas in each cluster. + With Q3A version 1.25 and up you can use /set bot_testclusters 1 on the + console and the area number and cluster number you're in will be printed + on the screen. These cluster number correspond to the cluster numbers + the BSPC tool prints. +- Minimize the number of clusters with only a few (less than 10) areas. +- When adding "cluster portal" brushes try to place them in places with + minimal geometric complexity. For instance place them inside convex door + openings or small hallways (not infront of door openings). Ideally the shape + of the face through which a player walks or swims into the cluster portal + is the same as the shape of the face through which a player leaves the + cluster portal. Also ideally the open space inside the cluster portal + brush is convex. +- Make cluster portals about 16 or 32 units thick or align them with + adjacent geometry. Don't make them too thick though. +- Minimize the total number of cluster portal areas at all times. The more + cluster portal areas you have the more CPU the bots need. +- Items have no effect at all on the creation of areas or clusters. + The same goes for item_botroam. + + +Do Not Enter areas +------------------ + +When bot navigation problems show up or you want to make sure a bot never tries +to go to a certain place "do not enter" brushes can be used. + +several things to take into account: + +- The "do not enter" brushes should not be used outside the world hull. +- The "do not enter" brush is Not a clip brush for the bot. +- The "do not enter" brush is a tool of last resort. Do not use it unless + there are serious navigation problems. +- The number of "do not enter" brushes should be minimized because these + brushes create additional areas for the bots. +- The "do not enter" brush will create a New area that the bot will try to + avoid. However if the bot somehow ends up in a "do not enter" area or there + is a valid goal inside the "do not enter" area then the bot is allowed to + go into and out of that area. So if the bot somehow gets in a "do not enter" + area the bot will be able to get out. + + +Bot roaming +----------- + +The item_botroam entity can be used when a bot does not roam the whole level +or prefers to go to only specific areas. This (invisible) item can be placed +in a map just like regular items. Nobody can actually pick up the item it's +only used to attract bots to certain places of the map. The item_botroam has +a key "origin". The value is set by Q3Radiant automatically. The item_botroam +also has a key "weight". The value is the weight of the roam item and is +relative to the weight of other items in the map. The bot character specific +item weights are stored with the bot characters in the botfiles/bots/ sub-folder +in the .pk3 file. The value of the weight is a non-zero floating point value, +most often in the range 0 to 400. (Higher values are allowed but keep in mind +that the bot should also still go for normal items, so don't make the +item_botroam weight to high.) + +When a bot should never go for a specific item the key "notbot" with value "1" +can be used for that item. This key with value can be used for every available +item in Quake III Arena. + +The suspended flag can be used on all items (item_botroam included). +However keep in mind that when a suspended item is not anywhere near the +ground the bot will ONLY try to go for this suspended item using jump pads. + + +Team based entities +------------------- + +You can use the "bot_notteam" entity key with value "1" or "2" on teleporters +(trigger_teleport or trigger_multiple pointing at a target_teleporter), +elevators (func_plat), cyclic movers (func_bobbing), jumppads (trigger_push) +and areas that hurt the player (trigger_hurt). +When "notteam" is set to "1" only bots using the travel flag TFL_NOTTEAM1 will +use the entity or move through the area. When "bot_notteam" is set to "2" only +bots using the travel flag TFL_NOTTEAM2 will use the entity or move through the +area. These travel flags can be used in the game source code. Using this entity +key also only has effect if the mod the map is being made for supports team based +navigation for bots. + + +Testing AAS files +----------------- + +One of the easiest ways to test the AAS file is to load the map in +Quake3 in teamplay mode (type /set g_gametype 3 on the console before +loading the map). Enter a team and add a bot to your team. Use the +team order menu (by default bound to the key F3) to command the bot +to follow you. Walk around the map and see if the bot is able to +follow you everywhere. + +Map bugs can sometimes cause certain places in the map to show up +'solid' in the AAS file. The bots cannot travel through these 'solid' +areas. To test for these 'solid' places set the cvar bot_testsolid +to 1 on the console. (type /set bot_testsolid 1) The map has to be +started with devmap instead of map before the cvar bot_testsolid can +be set. When the cvar is set to 1 then either "empty area" or +"SOLID area" will be printed on the screen while traveling through a map. +Several map bugs can cause these 'solid' places in the AAS file. +- Sometimes microscopic brushes are left over after a brush CSG. Search + for such brushes in the problem area and delete them. +- Tiny brush faces (not curves) can also cause problems. Due to vertex + snapping in the q3map tool those tiny brush faces can be snapped out + of existence. Such faces will not show up in Quake3 and you'll see + tiny peek holes or slits where you can view through the geometry. + Allign vertexes of and edges of adjacent brushes to remove and avoid + such tiny faces. Placing a clip brush in front of the face that is + snapped out of existence will also remove the 'solid' area but ofcourse + it's much better to remove the peek holes and slits. +- Another cause could be a brush with a collapsed side. Check how many + sides a brush has and how many sides actually have a surface. Rebuild + brushes with collapsed sides. +- All faces contained within liquid brushes using a shader without + "surfaceparm trans" set will be removed. Those contained surfaces will + not be visible and can cause the liquid to appear "solid" in the AAS file. + +If you insist creating an AAS file for a map with bugs then the option +-forcesidesvisible can be used. This should fix all the problems with areas +showing up solid in the AAS file. However creating an AAS file with this +option takes a lot longer (often more than twice the normal compile time). + +Clusters can be tested with the cvar bot_testclusters. +(type "/set bot_testclusters 1" on the console) + +Jumppads can also be tested. Type the following on the Quake3 console +before loading your map: + +/set bot_maxdebugpolys 1024 +/set bot_visualizejumppads 1 +/set bot_forcereachability 1 + +Now load the map. A counter will be shown and goes from 0% to 100%. +When the counter has reached 100% type /set bot_debug 1 and +/set r_debugSurface 2 on the console. For every jumppad the +default arch of travel (without using air control) will be visualized. +This only works if your .aas file is not optimized. + + +Error messages +-------------- + +Level designers should not worry too much about the following messages and/or warnings. The things reported are non fatal and won't cause any major problems. Some of the messages are just debug left overs. + +"AAS_CheckArea: area %d face %d is flipped\n" +"AAS_CheckArea: area %d center is %f %f %f\n" +"AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n" +"AAS_CheckFaceWindingPlane: face %d winding reversed\r\n" +"area %d face %d flipped: front area %d, back area %d\n" +"area %d face %d is tiny\r\n" +"face %d and %d, same front and back area but flipped planes\r\n" +"AAS_SplitFace: tiny back face\r\n" +"AAS_SplitFace: tiny back face\r\n" +"AAS_SplitArea: front area without faces\n" +"AAS_SplitArea: back area without faces\n" +"gsubdiv: area %d has a tiny winding\r\n" +"AAS_TestSplitPlane: tried face plane as splitter\n" +"found %d epsilon faces trying to split area %d\r\n" +"AAS_SplitArea: front area without faces\n" +"AAS_GetFace: face %d had degenerate edge %d-%d\r\n" +"AAS_GetFace: face %d was tiny\r\n" +"WARNING: huge winding\n" +"bogus brush after clip" +"split removed brush" +"split not on both sides" +"two tiny brushes\r\n" +"possible portal: %d\r\n" +"portal %d: area %d\r\n" +"WARNING: CM_GridPlane unresolvable\n" +"WARNING: CM_AddFacetBevels... invalid bevel\n" +"WARNING: CM_SetBorderInward: mixed plane sides\n" +"WARNING: bevel plane already used\n" +"trigger_multiple model = \"%s\"\n" +"trigger_teleport model = \"%s\"\n" +"found a trigger_push with velocity %f %f %f\n" +"AAS_TraceBoundingBox: stack overflow\n" +"AAS_TraceAreas: stack overflow\n" +"AAS_LinkEntity: stack overflow\n" +"MergeWindings: degenerate edge on winding %f %f %f\n" +"Warning: MergeWindings: front to back found twice\n" +"FindPlaneSeperatingWindings: winding1 non-convex\r\n" +"FindPlaneSeperatingWindings: winding2 non-convex\r\n" + + +When one of the following messages, errors or warnings is found then there is often something to be fixed. + +"WARNING! HashVec: point %f %f %f outside valid range\n" +"This should never happen!\n" + While storing the AAS file some vertex was found outside the valid map bounds. When this happens some part of the map is likely to have badly aligned brushes or weird shaped curves. Clipping off or rebuilding complex shapes often helps. +"trigger_push start solid\n" + The trigger_push start point is in solid. Try making the trigger_push brush a bit larger or move it around a bit. +"trigger_push without target entity %s\n" + Could not find the target entity of the trigger_push with the target field %s. +"trigger_push without time\n" + trigger_push entity found without "time" field. +"trigger_multiple not in any jump pad area\n" +"trigger_push not in any jump pad area\n" + A trigger_push entity was found not to be in any valid jumppad area. (the message states trigger_multiple but it should have been trigger_push) Try making the trigger_push brush a bit larger or move it around a bit. +"trigger_multiple at %1.0f %1.0f %1.0f without target\n" + A trigger multiple was found at the given coordinates without a "target" field. +"target_teleporter without target\n" + A target_teleporter entity was found without target field. +"trigger_teleport at %1.0f %1.0f %1.0f without target\n" + A trigger_teleport entity was found at the given coordinates without "target" field. +"teleporter without misc_teleporter_dest (%s)\n" + The destination of a teleporter with target field %s could not be found. +"teleporter destination (%s) without origin\n" + A teleporter destination with the target name %s was found without origin field. +"teleporter destination (%s) in solid\n" + A teleporter destination with the targetname %s was found to be in solid. +"teleported into slime or lava at dest %s\n" + A player would be pushed into slime or lave at the teleporter destination with the targetname %s. +"trigger_multiple not in any area\n" + A teleporter trigger was found not to be in any valid area. Try moving the trigger around a bit. +"func_plat without model\n" + A func_plat entity was found without model field. +"func_plat with invalid model number\n" + A func_plat entity was found with the model field set to some invalid number. +"func_bobbing without model\n" + A func_bobbing entity was found without model field. +"func_bobbing with invalid model number\n" + A func_bobbing entity was found with the model field set to some invalid number. +"%s in solid at (%1.1f %1.1f %1.1f)\n" + An item with classname %s was found to be in solid at the given coordinates. +"empty aas link heap\n" + Some part of the map has some rather complex clipping. Reduce the geometric complexity or use clip brushes to reduce the clipping complexity. +"too many entities in BSP file\n" + There are too many entities in the bsp file. +"error opening %s\n" + Could not create a new AAS file. Hard disk might be full. +"error writing lump %s\n" + Could not write an AAS lump to file. Hard disk might be full. + + + +Version Changes +--------------- + +2.1h (2001-03-28) + +- fixed crash bug + +2.1g (2001-02-18) + +- added bot_notteam support on trigger_hurt entities + + +2.1f (2001-02-06) + +- added some AAS statistics +- don't flood through faces when creating clusters + + +2.1e (2001-01-10) + +- fix map size limitation + + +2.1d (2000-12-17) + +- renamed "notteam" to "bot_notteam" + + +2.1c (2000-11-02) + +- added fs_maxfallheight +- compiled with larger map size bounds + + +2.1b (2000-09-15) + +- fixed cfg file loading + + +2.1 (2000-06-28) + +- added model numbers for AREACONTENTS_MOVER +- added team based func_plat, func_bobbing, trigger_teleport and trigger_push reachabilities + + +2.0 (2000-06-21) + +- fixed swim reachabilities +- fixed some reachabilities through cluster portals +- fixed jump reachabilities +- changed some start travel times +- added travel time settings to cfg + + +1.9 (2000-03-27) + +- fixed func_bobbing entities with origin brush + + +1.8 (2000-01-14) + +- fixed trigger_teleport bug. +- increased max map bounds to (-8192, -8192, -8192)-(8192, 8192, 8192) +- increased max points on winding +- made "HashVec: point x y z outside valid range" non-fatal +- fixed rocket jump reachabilities +- added force sides visible option +- increased simulated stack size for area traces + + +1.7 (1999-12-22) + +- fixed ducked bounding box size +- fixed sv_maxsteepness being zero in aas configuration +- AAS files are now automatically stored in BSP file folder +- fixed crash bug caused by overflow of a simulated stack diff --git a/docs/manual/quake3/Compile_Manual/cfgq3.c b/docs/manual/quake3/Compile_Manual/cfgq3.c new file mode 100644 index 00000000..b3694bef --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/cfgq3.c @@ -0,0 +1,78 @@ +//=========================================================================== +// BSPC configuration file +// Quake3 +//=========================================================================== + +#define PRESENCE_NONE 1 +#define PRESENCE_NORMAL 2 +#define PRESENCE_CROUCH 4 + +// more bounding boxes can be added if required +// always minimize the number of bounding boxes listed here to reduce AAS file size +// for instance if players cannot crouch then it's good to remove the bbox definition for it + +//bounding box when running/walking +bbox //30x30x56 +{ + presencetype PRESENCE_NORMAL + flags 0x0000 + mins {-15, -15, -24} + maxs {15, 15, 32} +} + +// bounding box when crouched +bbox //30x30x40 +{ + presencetype PRESENCE_CROUCH + flags 0x0001 + mins {-15, -15, -24} + maxs {15, 15, 16} +} + +// do not forget settings as they might not be defaulted correctly when this cfg is used +settings +{ + // physics settings + phys_gravitydirection {0, 0, -1} // direction of gravity + phys_friction 6 // friction + phys_stopspeed 100 // stop speed + phys_gravity 800 // gravity + phys_waterfriction 1 // friction in water + phys_watergravity 400 // gravity in water + phys_maxvelocity 320 // maximum run speed + phys_maxwalkvelocity 320 // maximum walk speed (set for running) + phys_maxcrouchvelocity 100 // maximum crouch speed + phys_maxswimvelocity 150 // maximum swim speed + phys_walkaccelerate 100 // acceleration for walking + phys_airaccelerate 0 // acceleration flying through the air + phys_swimaccelerate 0 // acceleration for swimming + phys_maxstep 18 // maximum step height + phys_maxsteepness 0.7 // maximum floor steepness a player can walk on + phys_maxwaterjump 19 // maximum height for an out of water jump + phys_maxbarrier 33 // maximum barrier a player can jump onto + phys_jumpvel 270 // jump velocity + phys_falldelta5 40 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) + phys_falldelta10 60 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) + // reachability settings + // the following are all additional travel times added + // for certain reachabilities in 1/100th of a second + rs_waterjump 400 + rs_teleport 50 + rs_barrierjump 100 + rs_startcrouch 300 + rs_startgrapple 500 + rs_startwalkoffledge 70 + rs_startjump 300 + rs_rocketjump 500 + rs_bfgjump 500 + rs_jumppad 250 + rs_aircontrolledjumppad 300 + rs_funcbob 300 + rs_startelevator 50 + rs_falldamage5 300 // avoid getting 5 damage + rs_falldamage10 500 // avoid getting 10 damage + // if != 0 then this is the maximum fall height a reachability can be created for + rs_maxfallheight 0 + // maximum height a bot may fall down when jumping to some location + rs_maxjumpfallheight 450 +} diff --git a/docs/manual/quake3/Compile_Manual/headskins.txt b/docs/manual/quake3/Compile_Manual/headskins.txt new file mode 100644 index 00000000..2418fd6b --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/headskins.txt @@ -0,0 +1,75 @@ +search orders with different settings + + +===================== +NON-TEAMPLAY +===================== + +------------------------------------------------- +headmodel = *callisto/lily + +models/players/heads/callisto/lily/head_default.skin +models/players/heads/callisto/head_lily.skin + + +------------------------------------------------- +headmodel = callisto/lily + +models/players/callisto/lily/head_default.skin +models/players/callisto/head_lily.skin +models/players/heads/callisto/lily/head_default.skin +models/players/heads/callisto/head_lily.skin + + + +===================== +Q3 TEAMPLAY +===================== + +------------------------------------------------- +team_headmodel = *callisto/lily +team = red + +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin + + +------------------------------------------------- +team_headmodel = callisto/lily +team = red + +models/players/callisto/lily/head_red.skin +models/players/callisto/head_red.skin +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin + + + +===================== +TA TEAMPLAY +===================== + +------------------------------------------------- +team_headmodel = *callisto/lily +team = red +teamName = Stroggs + +models/players/heads/callisto/lily/Stroggs/head_red.skin +models/players/heads/callisto/Stroggs/head_red.skin +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin + + +------------------------------------------------- +team_headmodel = callisto/lily +team = red +teamName = Stroggs + +models/players/callisto/lily/Stroggs/head_red.skin +models/players/callisto/Stroggs/head_red.skin +models/players/callisto/lily/head_red.skin +models/players/callisto/head_red.skin +models/players/heads/callisto/lily/Stroggs/head_red.skin +models/players/heads/callisto/Stroggs/head_red.skin +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin diff --git a/docs/manual/quake3/Compile_Manual/index.html b/docs/manual/quake3/Compile_Manual/index.html new file mode 100644 index 00000000..aabf7b16 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/index.html @@ -0,0 +1,65 @@ + + + + + Compiling Manual + + + + + + + +
+
+
+ + +
+

Compiling Manual, q3map & bspc help

+
+
+ +

+ Table of Contents +

    + · + Q3Map Documentation + +
    · + BSPC Documentation + +
    . + BSPC Configuration file + +
    . + modelskins: Q3 and TA search order for model skins + +
    . + headskins: Q3 and TA search order for head skins + +
+

+ +
+ + +
+ Last updated: Jan 21, 2002   +
+
+ +
+
+ + + diff --git a/docs/manual/quake3/Compile_Manual/modelskins.txt b/docs/manual/quake3/Compile_Manual/modelskins.txt new file mode 100644 index 00000000..6c253559 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/modelskins.txt @@ -0,0 +1,73 @@ +search orders with different settings + + +===================== +NON-TEAMPLAY +===================== + +------------------------------------------------- +model = hunter/harpy + + +legs: + models/players/hunter/lower_harpy_default.skin + models/players/hunter/lower_harpy.skin + models/players/characters/james/lower_harpy_default.skin + models/players/characters/james/lower_harpy.skin +torso: + models/players/hunter/upper_harpy_default.skin + models/players/hunter/upper_harpy.skin + models/players/characters/hunter/upper_harpy_default.skin + models/players/characters/hunter/upper_harpy.skin + + +===================== +Q3 TEAMPLAY +===================== + +------------------------------------------------- +team_model = hunter/harpy +team = red + +legs: + models/players/hunter/lower_harpy_red.skin + models/players/hunter/lower_red.skin + models/players/characters/hunter/lower_harpy_red.skin + models/players/characters/hunter/lower_red.skin +torso: + models/players/hunter/upper_harpy_red.skin + models/players/hunter/upper_red.skin + models/players/characters/hunter/upper_harpy_red.skin + models/players/characters/hunter/upper_red.skin + + +===================== +TA TEAMPLAY +===================== + +------------------------------------------------- +team_model = james/badass +team = red +teamName = Stroggs + +legs: + models/players/james/Stroggs/lower_badass_red.skin + models/players/james/Stroggs/lower_red.skin + models/players/james/lower_badass_red.skin + models/players/james/lower_red.skin + models/players/characters/james/Stroggs/lower_badass_red.skin + models/players/characters/james/Stroggs/lower_red.skin + models/players/characters/james/lower_badass_red.skin + models/players/characters/james/lower_red.skin +torso: + models/players/james/Stroggs/upper_badass_red.skin + models/players/james/Stroggs/upper_red.skin + models/players/james/upper_badass_red.skin + models/players/james/upper_red.skin + models/players/characters/james/Stroggs/upper_badass_red.skin + models/players/characters/james/Stroggs/upper_red.skin + models/players/characters/james/upper_badass_red.skin + models/players/characters/james/upper_red.skin + + + diff --git a/docs/manual/quake3/Compile_Manual/q3map.html b/docs/manual/quake3/Compile_Manual/q3map.html new file mode 100644 index 00000000..b1aaba23 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/q3map.html @@ -0,0 +1,410 @@ + + + + + Q3Map Manual + + + + + +

Q3map Manual

+ +
+ + + + +
+

q3map command line switches:

+
+q3map
+-----
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-glview
+	Write a .gl file of the bsp tree for debugging.
+-v
+	Output verbose information.
+-draw
+	Enable realtime debug drawing output.
+-nowater
+	Water, slime and lava brushes are not compiled and won't show up when running the map in Quake.
+-noopt
+	unused.
+-nofill
+	unused.
+-nodetail
+	Detail brushes are not compiled and won't show up when running the map in Quake.
+-fulldetail
+	Detail brushes will be treated as normal brushes.
+-onlyents
+	Only change the entities in a .bsp using a .ent file.
+-onlytextures
+	Only change the textures in a .bsp file.
+-micro
+	unused.
+-nofog
+	Visible surfaces that cross fog boundaries will not be split along the bound.
+	This can cause visually incorrect fog in the map.
+-nosubdivide
+	Visible surfaces are not subdivided as required by shader tesselation.
+	The shader parameter "tesssize" sets the tesselation of a surface.
+-leaktest
+	Only test the map for leaks. If a leak is found the compilation is stopped.
+-verboseentities
+	Output verbose information about entity sub-models.
+-nocurves
+	Curves are not compiled and won't show up when running the map in Quake.
+-notjunc
+	T-junctions are not fixed. This can cause tiny slits where a surface meets halfway another surface.
+-expand
+	Expands all the brush planes and saves a new map out to allow visual inspection of the clipping bevels
+-tmpout
+	Output files to a folder called "tmp".
+-fakemap
+	Write out a fakemap.map This map will contain a worldspawn entity with all the world brushes.
+-samplesize <N>
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-custinfoparms
+	Will enable custom surface flags (see below)
+
+q3map -vis
+----------
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-fast
+	Only calculate a very loose visiblity list. It doesn't take much time to
+	calculate but a lot more polygons will be drawn by the Q3 engine than necesary.
+-merge
+	Merge bsp leaves before calculating the visibility list. This will speed up
+	the vis calculations but mostly more polygons will be drawn by the Q3 engine
+	than necesary.
+-nopassage
+	Disable the passage visibility algorithm. The passage vis is faster and a bit more
+	tight than the old algorithm.
+-level
+	unused.
+-v
+	Output verbose information.
+-nosort
+	Don't sort the portals on complexity. Sorting mostly speeds up visibility calculations
+	because more complex portals can use information from less complex portals.
+-saveprt
+	Don't delete the .prt file after creating the visibility list.
+-tmpin <path>
+	Input files will be read from a folder called "tmp".
+-tmpout <path>
+	Output files will be written to a folder called "tmp".
+
+
+q3map -light
+------------
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-bounce <N> [NEW]
+	Enable radiosity calculation. Rediffuses the light emitted onto surfaces N
+	times. Will write out the BSP after every pass, so it can be cancelled.
+	Light reflected is the lightmap/vertex * texture color, subsampled to a certain
+	granularity across every lit surface. Use q3map_lightimage in a shader
+	to override the reflected color.
+-bouncegrid [NEW]
+	Radiosity affects lightgrid (entity lighting).
+-fast [NEW]
+	Enables light envelopes for area lights, speeding light up by 50x or more on
+	some maps. Has the side effect of dimmer maps with large numbers of dim surface
+	lights.
+-fastgrid [NEW]
+	Same as fast, but only for lightgrid calculation.
+-fastbounce [NEW]
+	Enables fast for radiosity passes only.
+-cheap [NEW]
+	Stop calculating light at a sample when it exceeds (255, 255, 255). This may
+	produce odd artifacts on maps with lots of saturated colored lighting. Also,
+	do not use -cheap with radiosity if you wish to preserve all light emitted.
+-cheapgrid [NEW]
+	Same as cheap, but only for lightgrid calculation.
+-area <scale>
+	This scales the light intensity of area lights.
+-point <scale>
+	This scales the light intensity of point lights.
+-notrace
+	No light tracing is performed. As a result no shadows will be casted.
+-patchshadows
+	Enable patches casting shadows.
+-novertex
+	Don't calculate vertex lighting.
+-nogrid
+	Don't calculate light grid for dynamic model lighting.
+-smooth [NEW]
+	Smart version of -extra. Only subsamples lightmap pixels that are shadowed.
+	Produces results comparable to -extra in roughly 1/3 the time. Can also be
+	used with -extra or -extrawide for 16- or 48-tap sampling respectively
+	(smoother shadows).
+-extra
+	Take four samples per lightmap pixel and store the average light value of these
+	four samples for the actual lightmap pixel.
+	This super sampling is used for anti-aliasing.
+-extrawide
+	Just like -extra four samples per lightmap pixel are calculated. However the
+	average of 12 samples is stored per lightmap pixel.
+-samplesize <N>
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-border
+	Create a debugging border around the lightmap.
+-v
+	Output verbose information.
+-nosurf
+	Disables surface tracing (detail brushes and patches) for shadow calculation.
+-dump
+	Dumps prefab files when used with radiosity for each bounce.
+
+
+q3map -vlight
+-------------
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-area <scale>
+	This scales the light intensity of area lights.
+-point <scale>
+	This scales the light intensity of point lights.
+-novertex
+	Don't calculate vertex lighting.
+-nogrid
+	Don't calculate light grid for dynamic model lighting.
+-nostitching
+	No polygon stitching before lighting.
+-noalphashading
+	Don't use alpha shading at all.
+-nocolorshading
+	Don't use colored alpha shading. The alpha channel will be used as if it were binary.
+	The light goes through or not and does not change color.
+-tracelight
+	Use the "-light" light algorithm for all surface unless a surface
+	uses a shader with the shader option "q3map_vlight".
+-samplesize <N>
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-v
+	Output verbose information.
+
+ + + +

The q3map options are a subset of the shader instructions that require +recompiling of the map.

+ +

q3map_bounce <fraction>

+

      [NEW] +Specify a number between 0 and 1.0 (or higher) to scale the amount of light reflected in radiosity passes. +Default: 1.0

+ +

q3map_nofast

+

      [NEW] +Surfaces that emit light with this shader parameter will disable -fast optimisation. Useful for +large areas of dim sky where you want all the dim light to reach all surfaces.

+ +

q3map_tracelight

+

      [NEW] Surfaces using a shader with this option will always be lit with the +original "-light" light algorithm. Patches will not cast shadows on +this surface unless the shader option q3map_patchshadows is used.

+

q3map_patchshadows

+

      [NEW] When this option is used in conjunction with the original (-light) +lighting algorithm, surfaces with textures modified by this option will will +show shadows cast by curve patches (under normal circumstances, curve patches do +not cast shadows).

+

q3map_vertexshadows

+

      [NEW] By default, no shadows are cast on vertex-only lit surfaces (see +surfaceparm pointlight). Also when running Quake III Arena in vertex  lighting +mode, no shadows are cast upon any surfaces (shadows are part of the light map). +When using this shader option shadows *will* be cast on the surface when vertex +lit. However sharp shadow edges won't be seen on the surface because light +values are only calculated at the vertexes.

+

q3map_novertexshadows

+

      [NEW] Shaders used for misc_models and terrain can now use +q3map_novertexshadows to disable shadows to be cast at the vertex lit surfaces. +Shadows being cast at small misc_model objects often makes sense. However +shadows on large vertex lit terrain surfaces often look bad. By default no +shadows are cast at forced vertex list surfaces ( shaders with "pointlight" +).

+

q3map_forcesunlight

+

      [NEW] No sunlight is cast at vertex lit md3 models and terrain by default. +Using this option sunlight (overbright bits created by q3map_sun option) will be +cast on these surfaces.

+

q3map_vertexscale <scale>

+

      [NEW] The light value at the vertexes of a surface using a shader with this +option is multiplied by the scale value. This is a way to lighten or darken a +vertex light only surface in comparison to other, light-map lit surfaces around +it.

+

q3map_notjunc

+

      [NEW] Surfaces modified by a shader with this option are not used for +tjunction fixing.

+

q3map_vlight

+

      [NEW] Surfaces modified by a shader with this option will always be lit with +the "-vlight" algorithm when q3map is used with the options "-vlight +-tracelight".

+

q3map_lightmapsamplesize <S>

+

      [NEW] Surfaces using a shader with this shader option will use lightmaps with +pixel size SxS. This option can be used to produce high resolution shadows on +certain surfaces or can be used to reduce the size of lightmap data where high +resolution shadows are not required.

+

q3map_lightimage <image>

+

      Image to use for the light color of a surface light instead of the image(s) +used by the shader. Color is averaged from the texture. Texture must be the same +size as the base image map.

+

q3map_surfacelight <value>

+

Sets the amount of light this surface emits.

+

q3map_lightsubdivide <value>

+

      A surface light is subdivided into a bunch of point lights for the actual +lighting of the world. This parameter controls the space between those point +lights. Default value is 120.

+

q3map_backsplash <percent> <distance>

+

      A surface light is also lit by itself using back splash point lights with a +lower intensity. The <percent> parameter specifies the intensity +percentage they use from the q3map_surfacelight <value> parameter. The +<distance> parameter controls the distance of these back splash lights +from the surface. You can set the <percent> to zero or a negative value to +disable the back splash lights.

+

      q3map_globaltexture

+

When this option is set the texture is not aligned to the world.

+

      q3map_backshader <shader>

+

<shader> is the path/name of the shader or texture to be used at the +back side of the surface.

+

      q3map_flare <shader>

+

Creates a flare using the specified <shader> at the center of the +surface using a shader with this option.

+

      light <value>

+

Old style flare specification always using the shader "flareshader". +The <value> parameter is unused.

+

      q3map_sun <red> <green> <blue> <intensity> +<degrees> <elevation>

+

Color will be normalized, so it doesn't matter what range you use. The +intensity falls off with angle but not distance. A value of 100 is a fairly +bright sun.

+

      degree of 0 = from the east, 90 = north, etc.

+

      elevation of 0 = sunrise/set, 90 = noon

+

      surfaceparm pointlight

+

Surfaces using a shader with this parameter will always be vertex lit

+

This option can be used to reduce the lightmap data. Often used on surfaces

+

that don't need any shadows.

+ + +

Surfaceparm dust

+

If a player lands (jumps onto) on a surfaces using a shader with this +parameter, a put of dust will appear at the playerÂ’s feet. Note that the +worldspawn entity of that map must have an enableDust key set to a value of 1. +Note: This surfaceflag has been replaced by "surfaceparm woodsteps" in +Return to Castle Wolfenstien.

+ + +

Custom surfaceparms

+
+

With the new q3map tool you can add custom surface parameters for mods +without the need to recompile the q3map tool. These custom surfaceparms are +stored in a file called ‘custinfoparms.txt’ in the folder scripts/. An +example of this file with the new surfaceparm treacle and surfaceparm grass is +shown below.

+

// Custom Infoparms File
+// Custom Contentsflags
+{
+treacle 0x4000
+}
+// Custom Surfaceflags
+{
+grass 0x80000
+}

+

 

+ +

NOTE: For linux users, when using the -custinfoparms parameter q3map +first looks in your homedir, and only if it doesn't find a custinfoparms.txt +there, it uses the one stored in the

+

quake3 install dir (usually /usr/local/games).

+

 

+
+

Content Flags

+
+

Contents flags are flags similar to CONTENTS_FOG in the original Q3A. These +flags define the contents of volumes inside the game (for instance lava, fog, +water, etc.).

+

If you look in the source file game/surfaceflags.h, it has defines for all +contents flags. The define is split into a name and a hexadecimal value, for +instance CONTENTS_PLAYERCLIP 0x10000. These hexadecimal values are powers of 2 +and can be ored together (binary) to form a bit mask. Up to 32 contents flags +can be ored together this way.

+ +

Example: creating a volume with treacle.

+

The following outlines how a custom contents flag can be added and used in a +mod. First open the ‘custinfoparms.txt’ file and add ‘treacle 0x4000’ +to the Custom Contentsflags section as shown in the example file above (0x4000 +is one of the unused values available for custom use). Next write a shader +script which uses ‘surfaceparm treacle’. Apply this new shader to all sides +of a brush in a test map. When you compile the map, add the -custinfoparms +parameter to the command line following q3map.

+

Next, add CONTENTS_TREACLE 0x4000 to the source file game/surfaceflags.h in +your mod. Now you can call the point contents function. If the point is inside +the brush with the shader using the ‘surfaceparm treacle’ then the point +contents call will return a bit mask with CONTENTS_TREACLE set. This can for +instance be used to slow down player movement when a player is inside such a +brush.

+

 

+
+

Surface Flags

+
+

The surface flags are texture properties that often affect entities in +contact with surfaces using such flags. The ‘surfaceparm metalsteps’ +parameter from Q3A is a good example.

+

If you look in the source file game/surfaceflags.h, it has defines for all +surface flags. The define is split into a name and a hexadecimal value, for +instance SURF_NODAMAGE 0x1. These hexadecimal values are powers of 2 and can be +ored together (binary) to form a bit mask. Up to 32 surface flags can be ored +together this way.

+ +

Example: Making ‘footsteps on grass’ sounds

+

The following outlines how a custom surface flag can be added and used in a +mod. First open up the ‘custinfoparms.txt’ file and add 'grass 0x80000' to +the Custom Surfaceflags section as shown in the example file above (0x80000 is +the first available unused value in surfaceflags.h for surface flags). Next +write a shader script which uses a grass image and has 'surfaceparm grass’. +Create a test map with the grass shader covering the ground surface. When you +compile the map, add the -custinfoparms parameter to the command line following +q3map.

+

Next, add SURF_GRASS 0x80000 to the source file game/surfaceflags.h in your +mod. Now you'll be able to execute a trace and the trace information will be +returned in the trace_t structure. If the trace hits a surface with the grass +surfaceparm then the SURF_GRASS flag will be set in trace_t->surfaceFlags. +Such a trace can be used to trigger playing a sound of a person stepping on +grass. For a reference example, see the existing metal steps in the game code.

+

 

+
+

 

+ +
+ + + +

 

+
+ +

 

+

 

+

-27-

+ + + + diff --git a/docs/manual/quake3/Model_Manual/model_manual.htm b/docs/manual/quake3/Model_Manual/model_manual.htm new file mode 100644 index 00000000..3af5ebd5 --- /dev/null +++ b/docs/manual/quake3/Model_Manual/model_manual.htm @@ -0,0 +1,217 @@ + + + +Q3A Player Characters: Putting them in the Game + + + +
+

Putting New Models in Quake III Arena

+ +Based on original notes by Paul Steed + +

Edited by Paul Jaquays
+

Edited 12/22/99 by ps
+

QERadiant.com thanks John Hutton for re-formating this manual into a more web friendly version
+

+
+The purpose of this document is to explain how to set up a model for Quake 3 Arena, create the necessary animation and conversion files, and then export it into the MD3 format required by the game. It is intended to be informative only and not a tutorial on building or animating models. + +

The player models for Quake III Arena were built using the commercial modeling software, 3D Studio Max R2.5 (3ds Max) by +Kinetix. These models were then animated using Physique and Biped, components of a plugin for 3dsMax called Character Studio +(also by Kinetix). The following instructions assume that you will model and animate with 3dsMax and Character Studio. + +

1. Setting up the Files

+Begin in your Quake3 directory. If you don't have one already, create a baseq3 directory. Inside the baseq3 directory, create a models directory. Inside the models directory, create a players directory. Inside the players directory, create a directory with the name of your model (we will use [character] in this document to represent information requiring the name of the model). It is generally a good idea to create a 'work' directory under [character] so that the [character] directory itself remains uncluttered. Place all versions of your model and temp textures here, saving the [character] directory purely for the finished model files. + +

2. Building and Naming the Mesh

+The mesh should be built keeping in mind the game engine needs three distinct body part grouping: the head, the upper body, and the lower body. These groupings can consist of different parts or sub-objects, but keep in mind too many sub-objects does impact performance and game play speed. A good rule of thumb is to consolidate your objects (i.e. attach them to each other) as long as they remain a part of a major group. For example, you decide to create a character that has its arms as separate objects for easier animation. Unless the arms or torso has different textures assigned to them go ahead and attach the arms to the torso. It may be more difficult to assign the vertices to the biped skeleton later on, but the efficiency of the model is much better. However, if you must keep the limbs detached for unique shader assignment then keep the following naming conventions in mind: + +

2.1 Head Geometry

+All head geometry needs to begin with lower case 'H_' (h_head, h_glasses, h_hat, etc...). Keep in mind that the head has no +animations itself other than to respond to player mouse-look input. + +

2.2 Upper Body Geometry

+All upper body geometry needs to begin with lower case 'U_' (u_torso, u_arms, u_abdomen, etc.) This is your model's torso and arms. The individual animations for the upper body are listed below. + +

2.3 Lower Body Geometry

+All lower body geometry begins with lower case 'L_' (l_hips, l_legs, l_lfoot, l_rfoot, etc...). This is your model's buttocks, legs and feet. The individual animations for the upper body are listed below. + +

2.4 Tags

+Tags are connection points for other model parts and represent the limited hierarchical system of the game. They include links between the three character body parts and the weapons. Keep in mind that these tags are representations of geometry so they can be animated to represent that geometry. For example, tag_head represents the head, tag_torso represents the torso and tag_weapon represents the weapon. This is important to understand since for example, any time the character is performing a locomotive animation, the upper body can and will animate independently of the lower body, using the relative position of the tag as a base or 'home' position. The tags for the body parts and weapons are named tag_weapon, tag_torso and tag_head. + +

3. Texturing

+Once you finish building your character go ahead and attach it to your biped and do some basic test animations to make certain the mesh doesn't deform in weird ways. Turn edges, ad faces, whatever you need to do to make sure that while animating, the character retains its mesh integrity. Handing the mesh over to another artist to assign UVW's or assigning and texturing yourself without testing the animation integrity of the mesh is very risky. Major modifications after UV assignment can cost you valuable time resulting in re-assigning not just the UV's, but re-attaching the mesh to your biped as well. Once your model is ready, go ahead and apply the texture to it. Typically the textures used in Q3A consist of one 256 x 256 texture for the body and one 128 x 128 texture for the head. Keep in mind that it's best to consolidate your texture on a single page rather than break it up into smaller pages. Also some video cards cannot process a texture size larger than 256, so making a high-rez 1024 x 512 texture just won't be seen since the card will knock it down to +256 x 128 to digest it. + +

4. Set Up for Animation

+Once the character is textured or skinned, bring the mesh back into 3dsMax (2.5) and attach it to an adjusted Biped using the Character Studio plug-in. As a rule of thumb, it's always better to just assign the mesh to the biped using the default +settings and then manually assign vertices to appropriate skeletal 'limbs'. + +

5. Animation

+When animating the character, keep all animations in one file. It's crucial that the animations adhere to a specific order that pertains to the separate body parts as this supports our current tag system. + +

Basically the order of animations goes: full body (animations that combine both upper and lower), upper body, and lower body. Each character file has the following animations in them and for now that's all the modeler is allowed. The division is basically death (all body parts), extraneous upper body, and dedicated locomotive animations. That way all the upper body animations can be performed at any time, separate from whatever it is that that lower body animations may be doing. There is a set number of animation types which are (in order): + +

  • death1 (approx. 30 frames) +
  • death2 (approx. 30 frames) +
  • death3 (approx. 30 frames) + +

  • taunt (approx. 45 frames) +
  • weapon attack (exactly 6 frames) +
  • melee attack (exactly 6 frames) +
  • change weapon (exactly 9 frames) +
  • weapon idle (exactly 1 frame) +
  • melee idle (exactly 1 frame) + +

  • crouched walk (approx. 10 frames) +
  • walk (approx. 15 frames) +
  • run (approx. 12 frames) +
  • backpedal (approx. 10 frames) +
  • swim (approx. 10 frames) +
  • jump forward (approx. 10 frames) +
  • jump forward-land (approx. 6 frames) +
  • jump backward (approx. 10 frames) +
  • jump backward-land (approx. 6 frames) +
  • standing idle (approx. 10 frames) +
  • crouched idle (approx. 10 frames) +
  • turn in place (approx. 8 frames)
+ +

A good rule of thumb is to create an idle pose at the frame right after the final death frame. Keep this pose for the +entire lower body and center of mass of the biped up through melee idle frame since any animation by the lower body during these frames will not register during the grab process. Similarly, once the animations for the lower body start, copy the pose for the upper body at the weapon idle frame to the first frame of the crouched walk animation and don't animate the upper body at all after that frame. This allows you to more closely approximate what happens during the game where the upper body is basically just along for the ride as the lower body carries it along via the tag_torso. + +

Keep in mind that an animation.cfg has to be generated for each character that is a direct reflection of your animation file above. + +

6. Setting up Tags

+After the modeler is satisfied with the animations for the character, it's time to bring in the tags that up until now, have +kept in a separate file. This is milestone mark that lets the modeler know that the character is nearly complete. 'Merge' +the tags into your scene. Turn off 'inherit scale' for the tags under the hierarchy/link command panel in Max. Then, +assign a Physique modifier (Character Studio), linking them to specific areas in the biped: + +

tag_torso is linked to the Biped 'pelvis' +
tag_head is linked to the Biped 'head'. +
tag_weapon is linked to the right 'hand'. + +

6.1 Animate Body Tags

+Now, go in and actually animate the tag_torso so that it matches the default position (established previously at +approximately the standing idle frame- from the top view it looks like a perfect 90 degree triangle with the base half as wide as the length, pointing forward) when appropriate. "Appropriate" means that as the character goes through the lower body animations, if the triangle is pointing anywhere else but forward, the upper body will point that way as well since to the code the upper body IS the tag. This works out to the modeler's advantage, though because even if the upper body LOOKS crazy in the animation you simply rely on the tag representation to compensate for it. + +

6.2 Handling Weapon Tags

+Tag_weapon is a bit different. Basically there is no difference between view model weapons (the weapon as seen by the player when it is in use by his or another player) and the world model weapons (weapons as they are found rotating in the maps) in Quake III Arena. However, for visually clarity and identification, they are doubled in scale when they become seen as world models. They are the same object. This reduces the number of models needed the game and creates an overall more efficient system. Unfortunately a drawback to the system is that there can be only one firing animation for the character. Thusly all weapons need to fit within the grip of the character regardless of size or geometry. This also makes it impossible to see hands on your weapons or otherwise perform vertex animation on the weapons other than barrel rotations vis the tag system (tag_barrel). +

Since the placement is always the same for the character's hands on the weapons , create the animations to the point where it begins the weapon attack sequence. Then merge one of the weapon models into the character file as a guide. The weapons have a nested triangle of same dimensions as the tag_head and tag_torso triangles (each weapon in the game has this triangle saved with it. Move the weapon into a horizontal firing position (using the side view) to about where the character would be holding the weapon correctly. Then move the character's hands into the appropriate position and link the weapon to the character's right hand. + +

When you get to the point where you bring in the tags, make a snapshot of the weapon, hide the original and simply delete all the vertices and faces of the copy of the weapon object except for the nested triangle. Rename it tag_weapon, turn off the 'inherit scale' attributes (very important), and assign Physique to it (linking it to the 'right hand' of the biped) and voila. Ready to export. + +

Level of Detail

+Each of the Quake III Arena player characters have a base model and two lower polygon versions of the model (to help with speed issues). For use in the game, the three levels of detail are file formatted as follows: + +

+ + + + + + + + + + + + +
[character].[file extension]This is the highest detail model for close up viewing
[character]_1.[file extension]This is a slightly lower polygon model for mid distance viewing
[character]_2.[file extension]This is the lowest polygon model for long distance viewing.
+ +

Level of detail means you need to make three versions of your model to get the best performance during gameplay. Each +version needs to have the same textures assigned and same animations assigned to them in order to work in the game. The +numbers you need to shoot for are 800 faces for the highest level, 500 faces for next level and 300 for the lowest level. This works out roughly to be a 60% drop in each LOD, but your numbers will vary in order to maintain mesh integrity. Most LOD's created in Q3A were done with the plugin called MRM (multiple resolution mesh) by Intel. The stock Optimize modifier or manual optimization techniques can be applied. + +

8. Exporting

+Once the tags are in place (also with the Physique modifier attached to them) the model is ready to export to an ase(ascii) +file. To make the models available for use in Quake III Arena, the model was exported to a native 3dsMax ASCII format +file called an '.ase' file. This export option in Max has several check boxes to tweak and then just exports the character +with its animation data (via Character Studio) to a huge ase/ascii file. Under 'Output Options' make sure the 'Mesh Definition', 'Materials', 'Transform Animation Keys', and 'Animated Mesh' boxes are checked. Under 'Mesh Options' and 'Object Types' make sure 'Mapping Coordinates' and 'Geometric' are the only boxes checked, respectively and let it run. Your 'Time Configuration' must reflect a '0' starting point up through the last frame of your animation. The native Max exporter will rely on the time configuration as a guide on which frames to actually grab during the conversion process. Of course there will be better exporters available in the future…this is just how it was done for the characters in Q3A. + +

9. Animation Config File

+The character's animations are controlled by an 'animation.cfg' file where the model maker specifies reference frames and frame rates. The animation.cfg file is a text file (originally created with MS Excel) which contains the frame and animation sequence data. Place this in the model's directory. Note, when the modeler is testing the model in Quake III Arena, changes to the animation.cfg can be made without having to re-grab the model…just do a 'vid_restart' at the cvar command line +prompt. + +

Edit an animation.cfg file which matches the frame/animation sequences and place it in the character's directory. Each animation can have different frame rates that the modeler can tweak, save out in the animation.cfg, hit 'vid_restart' to see the change right away in the game (no need to re-grab the model). The file for visor is shown here below in it's entirety. You may clip this portion of the file out and use it as the basis for your own animation files. + +

+////////////////////////////////////////////////////////////////////////////////
+
+// animation config file
+
+sex		m
+
+headoffset	0 0 0
+footsteps	normal
+
+// first frame, num frames, looping frames, frames per second
+
+0	30	0	25	// BOTH_DEATH1
+29	1	0	25	// BOTH_DEAD1
+30	30	0	25	// BOTH_DEATH2
+59	1	0	25	// BOTH_DEAD2
+60	30	0	25	// BOTH_DEATH3
+89	1	0	25	// BOTH_DEAD3
+90	40	0	20	// TORSO_GESTURE
+130	6	0	15	// TORSO_ATTACK (MUST NOT CHANGE -- hand animation is synced to this)
+136	6	0	15	// TORSO_ATTACK2 (MUST NOT CHANGE -- hand animation is synced to this)
+142	5	0	20	// TORSO_DROP (MUST NOT CHANGE -- hand animation is synced to this)
+147	4	0	20	// TORSO_RAISE (MUST NOT CHANGE -- hand animation is synced to this)
+151	1	0	15	// TORSO_STAND
+152	1	0	15	// TORSO_STAND2
+153	8	8	20	// LEGS_WALKCR
+161	12	12	20	// LEGS_WALK
+173	9	9	18	// LEGS_RUN
+182	10	10	20	// LEGS_BACK
+192	10	10	15	// LEGS_SWIM
+202	8	0	15	// LEGS_JUMP
+210	1	0	15	// LEGS_LAND
+211	8	0	15	// LEGS_JUMPB
+219	1	0	15	// LEGS_LANDB
+220	10	10	15	// LEGS_IDLE
+230	10	10	15	// LEGS_IDLECR
+240	7	7	15	// LEGS_TURN
+
+//////////////////////////////////////////////////////////////////
+ +

10. The Conversion Process

+ +The models need to be run through id's custom md3 conversion/'grabber' program. The program uses the information in the Quake Data text file ([filename].qdt) to grab and convert the 3dsMax files. + +

10.1 The Conversion File

+ +Create a "Quake Data" text file for the model with the extension ".qdt". The contents for our [character].qdt file would read something like: + +

$asecanimconvert models/players/[character]/[character].ase -playerparms 92 155 +
$asecanimconvert models/players/[character]/[character]_1.ase -lod 1 -playerparms 92 155 +
$asecanimconvert models/players/[character]/[character]_2.ase -lod 2 -playerparms 92 155 + +

+This is the grabber program executable. + +

+ +This is the path to the model's .ase file. The program looks for files starting in your Quake3\baseq3 directory. + +

+This tells the converter that this is the first level of reduced detail for the model. The value "-lod 2" is for the second, +or lowest level of detail for the model. + +

+This tells the converter which frame the upper body anims only start (first value) and which frame the lower body only anims start (second value). The numbers here are only used as examples + +
+When the qdt file is set up correctly, run the grabber by opening MSDOS command prompt, going to the quake3 directory +containing the model files and typing in 'q3data [character].qdt' + +

11. Review the Model

+Load up Quake 3 Arena. Go to map Q3DM0 (or any map containing a mirror). Bring down the console and type "\model +[character name]". Hit your Show Score key (default is TAB). You should see your new model here. Tweak the frame rates in +your animation.cfg file and save them. Type in "\vid_restart" on the console and hit enter to see the changes. + + + + + diff --git a/docs/manual/quake3/Model_Manual/styles/q3rad.css b/docs/manual/quake3/Model_Manual/styles/q3rad.css new file mode 100644 index 00000000..b4daab91 --- /dev/null +++ b/docs/manual/quake3/Model_Manual/styles/q3rad.css @@ -0,0 +1,23 @@ +body { font: 12pt "Times New Roman"; + margin-left: 5mm; + margin-right: 5mm; + text-align: justify; + background: #ffffff; + color: #000000 } +h1 { font: bold 24pt Arial, Helvetica } +h2 { font: bold italic 18pt Arial, Helvetica } +.subheading { font: bold 16pt Arial, Helvetica } +:link {color: blue; + text-decoration: none; } +:visited {color: purple; + text-decoration: none; } +h6 { font: 10pt "Times New Roman" } +.MsoToc2 { font: bold small-caps 12pt "Times New Roman" } +.MsoTitle { text-align:center; + font: bold 24pt "BankGothic Md BT"; + letter-spacing:2.5pt } +.heading { font: italic 10pt "Times New Roman" } +.subcontents { font: 10pt "Times New Roman" } +.tip { font: 10pt "Comic Sans MS" } +.type { font: 10pt "Courier New" } +.menu { font: 10pt Arial, Helvetica } \ No newline at end of file diff --git a/docs/manual/quake3/New_Teams_For_Q3TA/index.html b/docs/manual/quake3/New_Teams_For_Q3TA/index.html new file mode 100644 index 00000000..75046c9c --- /dev/null +++ b/docs/manual/quake3/New_Teams_For_Q3TA/index.html @@ -0,0 +1,2258 @@ + + + + + + + + +New Teams For Q3TA + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+

 

+
+

New + Teams for Team Arena (and other stories)
+ By Paul Jaquays Script files by various id design team members Bot Search Material by Jan Paul “MrElusive” + van Waveren

+
+

 

+
+

 

+
+

Table + of Contents
+ Introduction
+ The Team Pak
+ Scripts
+ User Interface Assets
+ In Game Team Logo Icons
+ New Models for Team Skins
+ Appendix A: The .Bot File
+ Appendix B: The .Team File
+ Appendix C: The Voice List
+ Appendix D: Model Sound List
+ Appendix E: .VC File Sample
+ Appendix F: Sample Team Arena Animation.Cfg + File and New Animation Commands
+ Appendix G: Teamname.shader
+ Appendix H: Search Order for Model and Head model Assets
+ Appendix I: Expanded Team Skin Functionality for Q3A
+ Appendix J: Contents of the tm_kreechurs.pk3
+ Appendix K: A Minimal Team
+ Appendix L: Contents of the TAhead_lily.pk3

+
+

 

+
+

 

+
+

Introduction
+ The original intent for Teams in Quake III: Team Arena was to allow the use + and creation of new Teams. However, it was not until community modelers attempted + to build new teams that we discovered that the hooks that we put in place for + team creation did not work as intended. This point release contains the fixes + and additions necessary to make new teams work.

+

This document presupposes + that the person wanting to create a new team already knows the basics of + creating, animating, and skinning new character models for Quake III Arena. + There are numerous good tutorials on-line covering both the basics and the + more in-depth skills needed to make models that work inside the game.

+

Special Thanks
+ The content used to test and debug the team creation code is based on a test + model provided and made “Team Arena compatible” by Bill and Mike Jukes, + a.k.a. “The Brothers Grimm” and a re-skinning of the original Team Arena Callisto head model provided by artist Camilla “milla” Bennett. Also thanks to milla + for providing the .html version of this document. Names of some of the files + used in examples have been changed. Furthermore, thanks go to Graeme Devine, + Robert Duffy, and MrElusive for putting up with + semi-constant harassment to get the team content working for the point + release.

+

Notices: QUAKE III ARENA and QUAKE III: Team + Arena are trademarks of id Software, Inc. This + document is copyright 2000, 2001 by id Software, Inc. Id Software grants + permission to redistribute and or redisplay this document in electronic form + only. It may not be included as a part of any permanent media without first + obtaining permission from id Software, inc. Permission is granted to use the + contents of the scripts embedded in this document as a base for creating + additional teams for Team Arena.
+

+

TOP

+

The Team Pak File
+ It takes a surprisingly large amount of new content to create an entirely new + team. Our test file contained 186 separate files (model included only one + head). An additional head added another 16 files (we tested with only one + extra head model). The content required covers every discipline of game + creation Â… skin painting, scripting, modeling, and sound production. In fact, + if the new team is to have new voice taunt sounds, it can easily exceed 10 + megabytes in compressed form inside the pak file. + Each of the files necessary to create a team is listed below in outline and + will be discussed later in detail. The paths for these files begin in the missionpack directory. Appendix J + contains the file list for the test team, Appendix K + shows a team with the bare minimum of files needed to create a new team with + a male and female uniform, and Appendix L contains the + file list for the Callisto/Lily test head.

+

Naming Conventions
+ When naming a pak file that contains the assets for + a new team, preface the team name with the letters + “tm_”. This usage is for organizational purposes only. It is done to identify + the pak as a team file. Example: tm_kreechurs.pk

+

Including What id DidnÂ’t Make
+ You donÂ’t need to include any of the game content + that id put in the original pak0.pk3 that shipped with Team Arena. The game + should have no problem finding those assets if they are called for by the new + team. Any new assets created for the team need to be in the pak file. Any assets created by other artists or authors + for use with Team Arena need to be in the pak file. + The team creator cannot assume that players will have those assets in their + possession. When including assets created by others, including modified id + game content, be sure to give notice of original + authorship in the readme that accompanies the pakfile.

+

Teamname_readme.txt
+ This text file tells all about the contents of your new team, including who + made it, how they can reach the author, who else contributed to the project, + what tools were used, how long it took, when it was released (copyright data + goes here), where the ideas came from, and so on. Essentially, it should + contain whatever the team creator wants to reveal about himself + or herself and the process of making the team. Any resources that were + created by others should be acknowledged here. If the team creator agrees to + let others use the original contents of the pak + file in other projects, it should be noted here also, along with any special + terms or contact information.

+

NOTE: The scripts used to create the + various aspects of the new team are included throughout this document. Team + creators have permission to copy the scripts in this document and paste them + into new scripts for use in original teams. Details such as team name, + character names, and bot names should be changed to + fit the new team.

+

TOP

+

Scripts
+ Priority: Unless otherwise noted, all of the scripts listed below are + required to be in the team pak file (see Appendix K: A Minimal Team, for a detailed list of the + contents required for a basic team using existing models).

+

These are the various + scripts used to define the team and model characteristics.

+

Teamname.team (in root directory) : A text file that defines the components of the team. This file + corresponds to the original team.txt file in pak0.pk3. It is required for all + new teams. See Appendix B for details.

+

Teamname.bot (scripts\) : This file defines the resources + used by the five bots that are used by the team in single player (model, head_model, and bot a.i.). It is required for all new teams. See Appendix A for details.

+

Teamname.shader (scripts\) : Shader + scripts for all shaders used to create the new_model and the five new_headmodels. + This is required for the team icons to work properly in game. Other shader-modified textures may be included. See Appendix G for the sample version of this shader.

+

Animation.cfg (models\players\newmodel\) : The animation configuration file. + Team Arena models have a few a few more animation sequences than their Q3A + counterparts, but the basics are the same. The contents of a sample Q3:TA animation.cfg are included + at the end of this document. ItÂ’s a script, but not + one thatÂ’s resident in the scripts file. This is + only required if a new model is included in the pak. +

+

New_model.voice (scripts\) : This is the script that assigns + individual voice wav files to specific message or status commands. See + Appendix C for a sample script and discussion of its use. Voice files are + optional and only required if an entirely new set of voice wav files is to be + included in the pak. Sound files are large and can + add significantly to the size of the pakfile. If + creating a human-based team, consider using the 8 voices that came with Team + Arena to save file space.

+

New_headmodel_1.vc + (scripts\) : This file selects which .voice file is linked to a head + file. Each head model in the pak needs one of + these. A separate version of this file is required for each new headmodel included with the team. The name of the file is + the same as the name of the bot that uses the headmodel. A sample .vc file is + included in Appendix E.

+

TOP

+

User Interface + Assets
+
Priority: The tga files are required. The roq + file is optional. The User Interface menus use these files to show the team + logo icons and movies of the characters in actions.

+

Teamname, of course, refers to the name of + the new team.

+

Teamname_name_alt.tga (ui\assets\) : This is a 256 x 128 pixel, 32 bit .tga file + (with alpha channel) depicting the name of the team as a black and white + (grayscale) art file. Teamname is the name of the + new team, the rest of the filename is part of its format. The alpha channel should + be the same as the image (not reversed).

+

Teamname_name.tga (ui\assets\) : This is a 256 x 128 pixel, 32 bit .tga file + (with alpha channel) depicting the name of the team with a glow around it. It + is a black and white art file (grayscale). The alpha channel should be the + same as the image (not reversed).

+

Teamname.tga (ui\assets\) : This is a 128 x 128 pixel, 32 bit .tga file + (with alpha channel) that depicts a black and white version of the team logo + or symbol. The alpha channel should be the same as the image (not reversed).

+

Teamname_metal.tga (ui\assets\) : This is a 128 x 128 pixel, 32 bit .tga file + (with alpha channel). If the team creator wants to keep the same style as the + original game, this version of the teamÂ’s logo is + rendered to look like brushed metal, perhaps with a bluish cast. But in + reality, it can be anything, any color. The alpha channel should be the same + as the alpha channel in the Teamlogo.tga art.

+

Teamname.roq (ui\assets\) : The .roq movie displays in the center area + of the player set up screen when the player selects one of the teams. Movie + file sizes can be large, so the team creator may wish to take the overall + size of the team pakfile into consideration before + including a movie. Uncompressed, the team movies in Team Arena were over a + megabyte each Â… and being compressed format files already; they donÂ’t get much smaller in the pakfile. + The good news is that if no movie file is present, the game displays the teamname_metal.tga in the center area instead. It must be + noted that team movie files will not be offered for viewing in the Cinematics menu option unless the teamname.roq + file is also present in the video\ directory.

+

TOP

+

In Game Team Logo + Icons
+ Priority: Required

+

The team style game maps + for Team Arena are usually set up to display the icons of the competing + teams. The game uses a separate set of art files located in the team_icon directory off the root missionpack + directory for the team icons displayed in game. For Team Arena, these art + files were a single color, red or blue. But that need not be the case. If a + game clan wanted to use a full color version of their clan symbol, it would + work in game - though the team creator may want to consider tinting the art + either bluish or reddish to better suit the color used in play (most team + maps are likely to use the blue/red color theme as was done in the original + game).

+

Also, take into + consideration that the art will be transparent, with background textures + (floors, walls, colored banners) showing through behind it. Simple, graphic + treatments of logos will probably work the best in all cases.

+

Art files can be larger or + smaller than those shown here. However, while having smaller files will save + memory, image quality will suffer. If using larger art files, image quality + may improve substantially but the memory usage will be substantial also. + Whether increasing or reducing file size, remember to keep the file dimension + proportional to the original.

+

The Teamname.shader + references this art. Make sure that the file names in the shader + match those of the artwork.

+

Teamname.tga (team_icon\): + This is a 128 x + 128 pixel art file, the exact same file as used in ui\assets\teamname.tga. + It is a black and white 32 bit version of the team logo with the same art in + the alpha channel.

+

Teamname_blue.tga (team_icon\): + For Team Arena, we + created solid color logos, but that need not be the case. This 32 bit 128 x + 128 pixel art file can be full color. The alpha channel should be the same as + the teamname.tga file. If you choose to make it + solid blue, consider using the same color value as the original TA logos. The + RGB formula for that blue is: 0 148 255.

+

Teamname_red.tga (team_icon\): + Even though id + chose to make our logoÂ’s single, solid colors, this + 32 bit 128 x 128 pixel art file can be whatever color the team creator + wishes. The alpha channel should be the same as the teamname.tga + file. If you choose to make it solid red, consider using the same color value + as the original TA logos. The RGB formula for that red is: 255 0 0.

+

TOP

+

New Models and Skins + for Teams
+ The process by which body models are created is outside the scope of this + document. While body model has a few more animations than the corresponding + Quake III Arena model, the process of creation is quite similar Â… except for + one very key element. The Team Arena model has no head. Head models for Team + Arena teams are created and stored separately from the body. Where the + pathname to a body model might be models\players\BoB, + the path to the head models is different:

+

Example: models\players\heads\Kreecha.

+

New Team Arena Models + based on Q3A models +
+ For the Team Arena test model, the Brothers Grimm converted a character model + that they had previously made for Quake III Arena. In order to keep the game + from confusing two models with the same file name, the search code for models + and skins was changed to allow extended search paths for models. In this + case, we placed the Team Arena model in a “characters” directory nested + within the “players” directory. The path to the new model read: + models\players\characters\BoB\. The model directory + contains the torso and legs models only, which are Upper.md3 and Lower.md3 + respectively. There are no head models in that directory. Furthermore, + include any art and skin files used for the default version of the model + along with the animation.cfg.

+

NOTE: When creating your models for + export as .ASE files for use with the Q3data.exe, you must have a head on the + model (e.g.; an h_head in the max file) for the + converter to work. The converter looks for and expects to see an h_head for of the model. If the converter does not find + the head during the conversion, the process will halt. After the conversion + is complete just use the Upper and lower Md3 files for that characterÂ’s directory. Place the head model in its own + separate directory.

+

Icons for new models
+ The Loading Screen for Team Arena uses the icons associated with a team memberÂ’s body model, not the memberÂ’s + head model. Be certain to include an icon_default.tga + file in new modelÂ’s directory. This icon will be + used on the map loading screen. It represents the Body model in use by a + player Â… not the Head model.

+

New Team Skins
+ When creating a team, make a red and a blue version + of the skin. Name the skins as noted below. Do not use the team or character + name in the skin. That information is taken from the name of the directory in + which it resides.

+

The team skins (red and + blue) for a Team Arena model reside in a directory within the model directory + (which contains the model md3 pieces).

+

Example: models\players\characters\BoB\Kreechurs\.

+

The teamname + directory (Kreechurs in this case) would contain + the art files for the skin, and the .skin files that link art to model.

+

In simple form, the skin + assets required to be in the teamname file are as + follows:

+

TGA file names
+ Blue.tga //the body skin for the blue team version
+ Red.tga //the body skin for the red team version

+

Skin File Names
+ Lower_blue.skin //blue version of legs skin file
+ Upper_blue.skin //blue version of torso skin file
+ Lower_red.skin //red version of legs skin file
+ Upper_red.skin //red version of torso skin file
+ Lower_default.skin //default legs skin file (used + by U.I.). Usually, this is the red skin.
+ Upper_default.skin //default torso skin file (used + by U.I.). Usually, this is the red skin.

+

New Heads
+ Each new player on a new team should either have a new head model or have a + new skin for an existing Team Arena model. Each new head model and all its + assets go into a directory named for it. In the case of new skins for + pre-existing models, the new skin assets reside in a directory nested within + the modelÂ’s directory.

+

Example: models\players\heads\callisto\lily is a new skin for the Callisto + head.

+

Note that other assets, + such as the .vc file for this head will also need + to be nested in directories a layer deeper in their normal files.

+

Example: scripts\callisto\lily.vc. +

+

New head models need to + have all the assets specific to the model (md3 files, skin files and art + files) in the directory named for the model head.

+

No MD3 Models Required + for New Skins on id Models
+ New skins created for existing head models (id created or community created) + do not require that the md3 models be in their directories. The assets + specific to the new skin (skin art, skin file, icons) are placed in a + directory. You do not need to redistribute md3 models for the heads that are + a part of the original id game.

+

Using the Work of + Others
+ If you are reskinning or simply using a head model + previously created and distributed by a member of the community, make sure + that the original creator has authorized such use (and remember to give + credit where credit is due). When using community-created models, the team + creator must plan to include that model and all its assets in the pakfile.

+

TOP

+

Appendix A: The .Bot File
+ Five Heads, Five Bots, Five Team Members

+ Priority: Required for each new team

+

A Team Arena team consists + of five players. In the original game, the five players were drawn from a mix + of 11 new player heads sitting atop two body models. New teams should also + have five players each. However, five players on the new team should each have + a unique head/skin combination. These can either be new models or new skins + using the original Q3:TA models.

+

The .bot + file (whose file name is the same as the name of the new team, e.g.; Kreechurs.bot or Scumsukkers.bot) + is a text script whose “.txt” file extension has been renamed to “.bot.” This file corresponds to the bots.txt file used in + the original Team Arena game. Appendix A shows a + sample bot file.

+

Name = the name of the bot as it appears on the Start Server Menu.

+

Model = the body model used by this bot. A team can use more than one body model. However, + adding multiple body models can and will add significantly to the size of the + team pak file and to memory usage in game. Limiting + the number of body models used by a team is a good design practice. No more + than two models per team should be the limit.

+

Headmodel = *modelname. + The headmodel is what makes the bot + unique. It has links to the voice files and is used when creating name + aliases for the bots to use in the single player game. The asterisk is a + necessary part of the file name here.

+

The headmodel + called Callisto/Lily is a new skin on the Callisto model mesh. The pathname is required for the + model to work.

+

Aifile = the bot + ai used by the team member. The computer-controlled + opponents in Team Arena used three individual ai + files that define their general role in the game: defense (tad_c.c), offense (tao_c.c) and + all-arounder (taa_c.c). + New bots can use these same a.i. files or, if + desired the team creator can make new ai files + based on the Team Arena ai files.

+

Filename: Teamname.bot

+
//bot file begins here
{
name           Kreecha
model          BoB
headmodel      *Kreecha
aifile  bots/taa_c.c
}
 
{
name           Callisto/Lily
model          BoB
headmodel      *Callisto/Lily
aifile  bots/tad_c.c
}
 
{
name           Infinite
model          BoB
headmodel      *Infinite
aifile  bots/tad_c.c
}
 
{
name           Prime
model          BoB
headmodel      *Prime
aifile  bots/tao_c.c
}
 
{
name           Vlad
model          BoB
headmodel      *Vlad
aifile  bots/tao_c.c
}
//bot file ends here
+

TOP

+

Appendix B: The + .TEAM File
+ Priority: Required for each new team.

+

The team file is a text + file that has had the file extension renamed from .txt to .team.

+

Kreechurs is a test Team Arena team created + to test the team and head model code for point release v1.28. It uses the + hypothetical “BoB” model to create a new team.

+

The team definition + appears on a single line in the file:

+

“Team name” “asset + path/name” “bot 1” “bot + 2” “bot 3” “bot 4” “bot 5”

+

//Teams define the assets + used by the team: team name, path to U.I. assets, player names
+ // Character definitions act as a link between head models used by a team and + models that have the proper team skin assets. The Player Set Up User + Interface primarily uses the character definitions. The first entry is the + head model as defined in the .bot file. The second + entry is body model used by that character. For everything to work out for + the best, each character should have a unique model/skin combination that + defines it.

+

Filename: Teamname.team

+
// .team file begins here
teams {
  { "Kreechurs" "ui/assets/kreechurs"  "BoB" "Lily" "Vlad" "Infinite" "Prime"}
}
 
characters {
{ "Callisto/Lily" " BoB " }
{ "Kreecha"  " BoB " }
{ "Infinite"  " BoB " }
{ "Prime"  " BoB " }
{ "Vlad" " BoB " }
}
 
// Aliases are the link between character name, headmodel, and bot A.I.
 
aliases {
        { "Kreecha"           "BoB"              "a"  }
        { "Lily"        "Callisto/Lily" "d"   }
            { "Vlad"           "Vlad"              "o"       }
            { "Infinite"       "Infinite"           "d"      }
            { "Prime"          "Prime"             "o"       }              
}
 
//.team file ends here
+

TOP

+

Appendix C: The + Voice List
+ Priority: Optional.

+

The voice file is a text + file that has had the file extension renamed from .txt to .voice. Each unique + set of voice recordings requires its own voice file. This file contains the + code script that defines the voice and corresponding text messages used by + the player models in game. Like the text chat messages that appeared in + original Q3A, these messages are triggered by game conditions and statuses.

+

The file directory name + for the voice does not have to be the same as a head or body model, though + giving it a unique name that identifies it with the team is always a good + idea. The specific file names for each voice message ARE VERY IMPORTANT, as + the voice script that corresponds to the file directory for the voice calls + them. Example: If the new voice is called “monster”, then the directory would + be called “monster” and the voice file would be called monster.voice. +

+

If you create a new set of + recorded voices for your team or for a new model, be certain to include at + least one voice message for each category (defined by a name like “getflag” and follow by opening and closing brackets) on + this list. It is not necessary to provide as many different messages as shown + below. Example: Your character may not need more than one way to say “yes” or + have as many kill insults. You can also rewrite the scripts. Your team need + not say the same thing as the id teams said or use the same style of + speaking. Just remember that the text portion of the message will display on + screen, so having it match the audio is always a good thing. And remember + that in game, shorter speeches are better and cheaper.

+

The file path is as + follows: sound\voices\newmodel\soundname.wav

+

You may include additional + voices but these are the ones currently the phrases accessed by the game.

+

As with any script, these + are lines of game code. Take care to maintain the proper syntax, otherwise, + you are likely to either disable the file or even crash the game.

+

To create new voice + recordings use a sound editing program that can produce a .wav format file + that conforms to the following: Mono 22k 16bit

+

(This is taken from the + male5 voice file. Substitute the name of your model for male5 in the file + pathnames).

+

Filename: Voicename.voice

+
//voice file starts here
 
getflag
{
        sound/voices/male5/or_01.wav   "Get the flag"
        sound/voices/male5/or_02.wav   "Secure the flag"
}
 
offense
{
        sound/voices/male5/or_03.wav   "You're on offense"
}
 
defend
{
        sound/voices/male5/or_04.wav   "Stay Home"
        sound/voices/male5/or_05.wav   "Guard the base"
        sound/voices/male5/or_07.wav   "You're on defense"
}
 
defendflag
{
        sound/voices/male5/or_06.wav   "Guard our flag"
}
 
patrol
{
        sound/voices/male5/or_08.wav   "Patrol"
        sound/voices/male5/or_09.wav   "Take point"
        sound/voices/male5/or_10.wav   "Go on patrol"
}
 
followme
{
        sound/voices/male5/or_11.wav   "Follow me"
        sound/voices/male5/or_12.wav   "Cover me"
        sound/voices/male5/or_13.wav   "Watch my back"
}
 
yes
{
        sound/voices/male5/re_01.wav   "Yessir"
        sound/voices/male5/re_02.wav   "Yes ma'am"
        sound/voices/male5/re_03.wav   "Aye, aye, sir"
        sound/voices/male5/re_04.wav   "Aye, aye, ma'am"
        sound/voices/male5/re_05.wav   "Affirmative"
        sound/voices/male5/re_06.wav   "Copy"
        sound/voices/male5/re_07.wav   "Roger"
}
 
no
{
        sound/voices/male5/re_08.wav   "No sir"
        sound/voices/male5/re_09.wav   "No ma'am"
        sound/voices/male5/re_10.wav   "Negative"
        sound/voices/male5/re_11.wav   "I'm busy"
}
 
ihaveflag
{
        sound/voices/male5/gs_01.wav   "I'm coming in hot!"
        sound/voices/male5/gs_02.wav   "I've secured the flag!"
        sound/voices/male5/gs_03.wav   "I've got the flag!"
        sound/voices/male5/gs_04.wav   "Bringing home the bacon!"
}
 
baseattack
{
        sound/voices/male5/gs_05.wav   "We're taking enemy fire!"
        sound/voices/male5/gs_06.wav   "Security breach!"
        sound/voices/male5/gs_07.wav   "Our base is under attack."
}
 
enemyhasflag
{
        sound/voices/male5/gs_08.wav   "Our flag is gone!"
        sound/voices/male5/gs_09.wav   "They've got our flag!"
        sound/voices/male5/gs_10.wav   "Enemy has secured our flag!"
}
 
ongetflag
{
        sound/voices/male5/ps_03.wav   "Getting the flag..."
}
 
onoffense
{
        sound/voices/male5/ps_01.wav   "I'm taking offense"
        sound/voices/male5/ps_02.wav   "I'm going in..."
}
 
ondefense
{
        sound/voices/male5/ps_04.wav   "I'll stay home"
        sound/voices/male5/ps_05.wav   "Securing base"
        sound/voices/male5/ps_06.wav   "Guarding the base now"
}
 
onpatrol
{
        sound/voices/male5/ps_07.wav   "On patrol..."
        sound/voices/male5/ps_08.wav   "Patroling..."
        sound/voices/male5/ps_09.wav   "I'll take point"
}
 
startleader
{
        sound/voices/male5/ps_10.wav   "I'm the leader"
        sound/voices/male5/ps_11.wav   "I'm in charge"
}
 
stopleader
{
        sound/voices/male5/ps_12.wav   "I don't want to lead"
        sound/voices/male5/ps_13.wav   "Someone else lead"
        sound/voices/male5/ps_14.wav   "I resign"
}
 
kill_insult
{
        sound/voices/male5/tt_06.wav   "Next time don't get up"
        sound/voices/male5/tt_05.wav   "You're just a waste of space"
        sound/voices/male2/tt_07.wav   "Are you blind?"
        sound/voices/male5/tt_13.wav   "Duck next time"
        sound/voices/male5/tt_19.wav   "Suh-weeet!"
        sound/voices/male5/tt_20.wav   "Woo-Hoo!"
        sound/voices/male5/tt_22.wav   "You just got schooled!"
//      sound/voices/male5/tt_16.wav   "You talkin' ta ME?"
}
 
taunt {
        sound/voices/male5/tt_18.wav   "How about some competition here?"
        sound/voices/male5/tt_01.wav   "FRAGbait!"    
        sound/voices/male5/tt_11.wav   "My momma shoots better!"
        sound/voices/male5/tt_14.wav   "Try hitting that barn over there!"
        sound/voices/male5/tt_17.wav   "Wanna BUY a shot?"
//      sound/voices/male5/tt_03.wav   "Get a clue moron!"
//      sound/voices/male5/tt_09.wav   "MORON!"
//      sound/voices/male5/tt_02.wav   "You're such a Loser!"
//      sound/voices/male5/tt_08.wav   "LOSER!"
//      sound/voices/male5/tt_10.wav   "No-skill idiot!"
//      sound/voices/male5/tt_12.wav   "Watched that all the way..."
}
 
death_insult {
        sound/voices/male5/tt_15.wav   "Thank you sir.. may I have another!"
        sound/voices/male5/tt_23.wav   "Bite me!"
        sound/voices/male5/tt_25.wav   "Cheap shot!"
        sound/voices/male5/tt_26.wav   "DOH"
        sound/voices/male5/tt_28.wav   "Lucky shot!"
        sound/voices/male5/tt_29.wav   "That's it!"
        sound/voices/male5/tt_30.wav   "Ooh! That's it!"
//      sound/voices/male5/tt_35.wav   "Hey, dumbass"
//      sound/voices/male5/tt_04.wav   "What an ass!"
//      sound/voices/male5/tt_24.wav   "Screw you!"
}
 
kill_gauntlet {
        sound/voices/male5/tt_21.wav   "Eat gauntlet baby!"
}
 
praise {
        sound/voices/male5/tt_27.wav   "Nice!"
}
 
camp                   // command someone to camp
{
        sound/voices/male5/voc_01.wav  "Camp this position."
        sound/voices/male5/voc_02.wav  "Camp here."
 
}
 
returnflag                     // return our flag  (CTF only)
{
        sound/voices/male5/voc_03.wav  "Get our flag!"
        sound/voices/male5/voc_04.wav  "Return our flag!"
        sound/voices/male5/voc_05.wav  "Recover our flag!"
}
 
whoisleader                    // who is the team leader
{
        sound/voices/male5/voc_06.wav  "Who's our leader?"
        sound/voices/male5/voc_07.wav  "Who's in charge?"
        sound/voices/male5/voc_08.wav  "Who leads this team?"
}
 
followflagcarrier              // follow the flag/skull carrier (CTF, Oneflag, Harvester)
{
        sound/voices/male5/voc_09.wav  "Follow our carrier."
        sound/voices/male5/voc_10.wav  "Stay with the carrier."
        sound/voices/male5/voc_11.wav  "Protect the carrier."
        sound/voices/male5/voc_12.wav  "Cover the carrier."
}
 
inposition                     // I'm in position
{
        sound/voices/male5/voc_13.wav  "I'm in place."
        sound/voices/male5/voc_14.wav  "I'm at my post."
        sound/voices/male5/voc_15.wav  "I am in position."
        sound/voices/male5/voc_15a.wav "I am in position"
}
 
wantondefense          // I want to be on defense
{
        sound/voices/male5/voc_16.wav  "Let me defend."
        sound/voices/male5/voc_17.wav  "I'd rather defend."
}
 
wantonoffense          // I want to be on offense
{
        sound/voices/male5/voc_18.wav  "Let me go on offense."
        sound/voices/male5/voc_19.wav  "I'd rather go on offense."
}
 
wantonpatrol           // I want to go on patrol
{
        sound/voices/male5/voc_20.wav  "Let me patrol."
        sound/voices/male5/voc_21.wav  "I'd rather patrol."
}
 
oncamp  //I'm Camping (status)
{
        sound/voices/male5/voc_22.wav  "I'm camping here."
}
 
onfollow
{
        sound/voices/male5/voc_23.wav  "I'm following."
        sound/voices/male5/voc_24.wav  "Following!"
}
 
onfollowcarrier
{
        sound/voices/male5/voc_27.wav  "Guarding the carrier."
}
 
onreturnflag
{
        sound/voices/male5/voc_28.wav  "Getting our flag."
}
 
harvest //harvester game type only
{
        sound/voices/male5/voc_25.wav  "Go collect skulls."
        sound/voices/male5/voc_26.wav  "Harvest some skulls."
}
// voice file ends here
+

TOP
+
+
Appendix D: + Model Sound List
+ Priority: Only required if a new body model is included in the team pak file.

+

The following game sounds + are associated with the team model. Each of the sounds listed below is a + separate file. They need to be located in a directory having the same name as + the body model and be nested within the sounds directory.

+

Example: sounds/newmodel/Death1.wav.

+

If new sound files are to + be created, make sure that they conform to the following wav file format: + Mono 22k 16bit.

+

Death1.wav
+ Death2.wav
+ Death3.wav
+ Drown.wav
+ Fall1.wav
+ Falling1.wav
+ Gasp.wav
+ Jump1.wav
+ Pain100_1.wav
+ Pain25_1.wav
+ Pain50_1.wav
+ Pain75_1.wav
+ Taunt.wav

+

TOP

+

Appendix E: .VC + File Sample
+ Priority: Required for each head model

+

The vc + file is a text file script that has had the file extension renamed from .txt + to .vc. The script is linked to a bot name. Bot names are defined + in the .bot file included in the pak file. Each bot needs to + have a .vc file. ItÂ’s + best, if at all possible, to have the model name (or model/skin combination) + and the bot name be the same. The very brief + contents are simply a path to a voice file. The selected voice file can be + either one of the original Team Arena voices or an original voice included + with the team. When creating the voice file for a re-skinned head model, be + sure to include the head name in the path to the voice script. That script + must also be nested a layer deeper in the directory, such as: scripts/callisto/lily.vc.

+

The contents of a sample .vc file are shown below.

+
        //VC script begins here
scripts/newcharacter.voice
           //VC script ends here
+

TOP

+

Appendix F: Sample + Team Arena Animation.Cfg File and New Animation + Commands
+ Priority: Required only if a new model is included.

+

The animation.cfg + file is a text file that has had the file extension renamed from .txt to .cfg. This file goes in the directory with the body model + components (model\players \new_model\ -- or -- + model\players\characters\new_model\). The specifics + of using or modifying the contents of this file are a part of the model + making process and are mostly outside the focus of this document.

+

It is included in this + document because the Team Arena animation configuration is different from the + Quake 3 Arena Configuration. Furthermore it contains the “sex” key that + determines the gender/sex of a character (as does the Q3A animation.cfg). + This key/value pair determines which pronouns (masculine, feminine, or + neuter) are used when the game generates messages about the player.

+

Additionally, two new + animation commands (for both Q3A and Q3:TA) are + shown here. These were done at the request of modelers doing non-traditional + biped models. When put in the animation.cfg file, + they literally stop the model from responding to the programmatic animations + for those body parts. If you freeze the legs, the hips don't tilt during + running animation. If the modelÂ’s legs were too + much outside of bipedal norms (as is the case for quadrupeds), the front or + back legs would disappear into the ground as the leg models programmatically + tilted around the modelÂ’s pelvis. If you freeze the + torso, you don't get waist twists or bends. Depending on what you are making, + you may want to use one, but not the other.

+

Fixedlegs : put in the animation .cfg this command freezes programmatic rotation of the + legs

+

Fixedtorso : when put in the animation .cfg this command freezes programmatic rotation of the + torso

+

These commands are + commented out in the sample below.

+
// animation.config file begins here
sex     m      // THIS VALUE  (m, f, n) DETERMINES GENDER OF MODEL
//fixedlegs  // PREVENTS PROGRAMMATIC ROTATION OF LEGS
//fixedtorso // PREVENTS PROGRAMMATIC ROTATION OF TORSO
headoffset -3 0 0
footsteps boot
 
 
 
// first frame, num frames, looping frames, frames per second
0       30      0       20             // BOTH_DEATH1
29      1       0       20             // BOTH_DEAD1
30      30      0       20             // BOTH_DEATH2
59      1       0       20             // BOTH_DEAD2
60      30      0       20             // BOTH_DEATH3
89      1       0       20             // BOTH_DEAD3
 
90      26      0       20             // TORSO_GESTURE
 
116     6       0       15             // TORSO_ATTACK        (MUST NOT CHANGE -- hand animation is synced to this)
122     6       0       15             // TORSO_ATTACK2       (MUST NOT CHANGE -- hand animation is synced to this)
 
128     5       0       20             // TORSO_DROP          (MUST NOT CHANGE -- hand animation is synced to this)
133     4       0       20             // TORSO_RAISE         (MUST NOT CHANGE -- hand animation is synced to this)
 
137     1       0       15             // TORSO_STAND
138     1       0       15             // TORSO_STAND2
 
199     8       8       20             // LEGS_WALKCR
207     12      12      20             // LEGS_WALK
219     10      10      20             // LEGS_RUN
229     10      10      20             // LEGS_BACK
239     10      10      15             // LEGS_SWIM
 
249     7       0       15             // LEGS_JUMP
256     9       0       15             // LEGS_LAND
265     9       0       15             // LEGS_JUMPB
274     6       0       15             // LEGS_LANDB
280     15      15      15             // LEGS_IDLE
295     11      11      15             // LEGS_IDLECR
307     9       9       15             // LEGS_TURN
 
139     10      0       15             // TORSO_GETFLAG    //TA Gesture
149     10      0       15             // TORSO_GUARDBASE   //TA Gesture
159     10      0       15             // TORSO_PATROL   //TA Gesture
169     10      0       15             // TORSO_FOLLOWME   //TA Gesture
179     10      0       15             // TORSO_AFFIRMATIVE   //TA Gesture
189     10      0       15             // TORSO_NEGATIVE   //TA Gesture
 
// animation.config file ends here
+

TOP

+

Appendix G: Teamname.shader
+ Priority: Required for team icons to work in the game

+

This is a text file script + with the file extension renamed from .txt to ..shader.

+
//Teamname.shader begins here
team_icon/Kreechurs_red
{              
        cull none
        surfaceparm nolightmap
        surfaceparm trans
        surfaceparm nomarks
        {
               map team_icon/Kreechurs_red.tga
               blendFunc Add
               rgbgen wave triangle 0.2 0.5 0 0.2           
        }
}
 
team_icon/Kreechurs_blue
{              
        cull none
        surfaceparm nolightmap
        surfaceparm trans
        surfaceparm nomarks
        {
               map team_icon/Kreechurs_blue.tga
               blendFunc Add
               rgbgen wave triangle 0.2 0.5 0 0.2       
        }
}
//Teamname.shader ends here
+

TOP

+

Appendix H: Search + Order for Model and Head model Assets

+

The means by which headmodels are used and selected was unified as much as + possible between Q3A and Q3:TA code. The byproduct + of this change allows players some more choices when selecting head models. + The following documents the new procedures.

+

Searching for Head + skins
+ The game uses the following paths and order of search when looking for headmodel assets. The asterisk (*) is only used for head + models. When the asterisk is used, the game will try to load the head model + from the models/players/heads folder first. After that, it looks deeper into + the directories.

+

More Variety of Head + Skins
+ If the team creator so chooses, different skins can be created for each team + (note that id chose to use the same head skins for each team Â… but that doesnÂ’t have to be the case).

+
===================================
Q3A/TA NON-TEAMPLAY SEARCH ORDER
===================================
 
-------------------------------------------------
headmodel = *callisto/lily
 
models/players/heads/callisto/lily/head_default.skin
models/players/heads/callisto/head_lily.skin
 
-------------------------------------------------
headmodel = callisto/lily
 
models/players/callisto/lily/head_default.skin
models/players/callisto/head_lily.skin
models/players/heads/callisto/lily/head_default.skin
models/players/heads/callisto/head_lily.skin
 
============================
Q3A TEAMPLAY SEARCH ORDER
============================
-------------------------------------------------
Example:
team_headmodel = *callisto/lily
team = red
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
 
-------------------------------------------------
Example:
team_headmodel = callisto/lily
team = red
 
models/players/callisto/lily/head_red.skin
models/players/callisto/head_red.skin
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
 
===========================
TA TEAMPLAY SEARCH ORDER
===========================
Example:
team_headmodel = *callisto/lily
team = red
teamName = Stroggs
 
models/players/heads/callisto/lily/Stroggs/head_red.skin
models/players/heads/callisto/Stroggs/head_red.skin
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
 
Example:
team_headmodel = callisto/lily
team = red
teamName = Stroggs
 
models/players/callisto/lily/Stroggs/head_red.skin
models/players/callisto/Stroggs/head_red.skin
models/players/callisto/lily/head_red.skin
models/players/callisto/head_red.skin
models/players/heads/callisto/lily/Stroggs/head_red.skin
models/players/heads/callisto/Stroggs/head_red.skin
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
+

Searching for Model + Skins
+ The following list shows the order in which the game searches for model + skins. When creating new skins for Team Arena or Quake 3 Arena (or related mods of either), use the following directory arrangement. +

+
===================================
Q3A/TA NON-TEAMPLAY SEARCH ORDER
===================================
-------------------------------------------------
Example:
model = hunter/harpy
 
 
legs:
        models/players/hunter/lower_harpy_default.skin
        models/players/hunter/lower_harpy.skin
        models/players/characters/james/lower_harpy_default.skin
        models/players/characters/james/lower_harpy.skin
torso:
        models/players/hunter/upper_harpy_default.skin
        models/players/hunter/upper_harpy.skin
        models/players/characters/hunter/upper_harpy_default.skin
        models/players/characters/hunter/upper_harpy.skin
 
============================
Q3A TEAMPLAY SEARCH ORDER
============================
 
-------------------------------------------------
Example:
team_model = hunter/harpy
team = red
 
legs:
        models/players/hunter/lower_harpy_red.skin
        models/players/hunter/lower_red.skin
        models/players/characters/hunter/lower_harpy_red.skin
        models/players/characters/hunter/lower_red.skin
torso:
        models/players/hunter/upper_harpy_red.skin
        models/players/hunter/upper_red.skin
        models/players/characters/hunter/upper_harpy_red.skin
        models/players/characters/hunter/upper_red.skin
 
 
===========================
TA TEAMPLAY SEARCH ORDER
===========================
 
-------------------------------------------------
Example:
team_model = james/badass
team = red
teamName = Stroggs
 
legs:
        models/players/james/Stroggs/lower_badass_red.skin
        models/players/james/Stroggs/lower_red.skin
        models/players/james/lower_badass_red.skin
        models/players/james/lower_red.skin
        models/players/characters/james/Stroggs/lower_badass_red.skin
        models/players/characters/james/Stroggs/lower_red.skin
        models/players/characters/james/lower_badass_red.skin
        models/players/characters/james/lower_red.skin
torso:
        models/players/james/Stroggs/upper_badass_red.skin
        models/players/james/Stroggs/upper_red.skin
        models/players/james/upper_badass_red.skin
        models/players/james/upper_red.skin
        models/players/characters/james/Stroggs/upper_badass_red.skin
        models/players/characters/james/Stroggs/upper_red.skin
        models/players/characters/james/upper_badass_red.skin
        models/players/characters/james/upper_red.skin
+

TOP

+

Appendix I: + Expanded Team Skin Functionality for Q3A

+

Technically speaking, the + following information has nothing to do with Team Arena teams, but this + document is just as good a place for this information to reside as any.

+

At the request of several + modelers who worked with the modeling and skin making forums and archives at Polycount, + we changed the way that Quake III Arena (not just Team Arena) handles skin + replacement in team games. Originally, if a skinner made a new skin for a Q3A + model AND made team color versions of that skin, the game would not + automatically use the team version. Instead, it would display the id default + red or blue skin. To see a new team skin in the game, the skinner literally + had to remove the default skins and replace them with the new versions.

+

With version 1.28 of the + game code, weÂ’ve been able to get that changed. The + file format that we used is the one requested by the skinners themselves. + However, because of the way searches for head skins now work, pre-existing + Q3A files are not going to work correctly. They need to have one, renamed + skin file added for the proper head skins to appear in the game.

+

When a properly set-up + user-created skin for a model is accompanied by matching team color skins, + the game will now use them instead of the default team skin for that model.

+

The example below shows + the assets that must be in the pakfile for the Blue + version of a skin named Hellion that uses the id-created Crash model.

+
 Hellion_blue.tga                          models\players\crash\
 Hellion_blue_f.tga                       models\players\crash\
 Hellion_blue_t.tga                       models\players\crash\
 Head_Hellion_blue.skin              models\players\crash\
 Icon_Hellion_blue.tga                 models\players\crash\
 Lower_Hellion_blue.skin            models\players\crash\
 Upper_Hellion_blue.skin            models\players\crash\
 Head_blue.skin                            models\players\crash\Hellion\
+

The last file is the key + to making it work Â… a skin file with the same contents as Head_Hellion_blue.skin, + only renamed Head_blue.skin and placed one layer + deeper in the Hellion directory. Note that BOTH head_hellion_blue.skin + in the crash directory and head_blue.skin in the + crash/Hellion directory are necessary for the model to work properly.

+

To see a working example + of a properly set up Q3A skin, look for Hades Orphan, the revised version + (h20.pk3), by Camilla “milla” Bennett for the Crash + model.

+

TOP

+

Appendix J: + Contents of the tm_kreechurs.pk3

+

The following list is + taken directly from the contents of the pak file contain + the BoB model and the Kreechurs + team information. Use this as a reference when creating your own team pak files.

+
tm_kreechurs.pk3
Name    Modified       Size    Ratio   Packed  Path
kreechurs.team  5/9/2001 12:01 PM      1,968   61%     770
kreechurs_readme.txt   5/9/2001       3,162   59%     1,286   
animation.cfg  5/161/2001 4:32 PM     1,173   59%     478         models\players\characters\BoB\
default_flame1.jpg     513/2000 7:19 PM       5,972   10%     5,385        models\players\characters\BoB\
default_flame2.jpg     51312000 7:19 PM       5,984   10%     5,359        models\players\characters\BoB\
default_flame3.jpg     5/3/2000 7:20 PM       5,623   11%     5,014        models\players\characters\BoB\
default_flame4.jpg     51312000 7:20 PM       5,284   12%     4,658        models\players\characters\BoB\
default_flame5.jpg     513/2000 7:21 PM       5,231   10%     4,691         models\players\characters\BoB\
default_flame6.jpg     5/3/2000 7:21 PM       5,318   11%     4,735         models\players\characters\BoB\
qefault_flame7.jpg     5/3/2000 7:21 PM       5,807   11%     5,197         models\players\characters\BoB\
default_flame8.jpg     5/3/2000 7:22 PM       6,114   10%     5,510         models\players\characters\BoB\
default_flameball.jpg  5/3/2000 7:22 PM       3,010   26%     2,216         models\players\characters\BoB\
defaultjets.tga        611412000 2:55 AM      49,196  37%     31,075         models\players\characters\BoB\
icon_blue.tga  6/13/2000 8:15 PM      16,402  58%     6,845         models\players\characters\BoB\
icon_red.tga   6/13/2000 8:15 PM      16,402  61%     6,327         models\players\characters\BoB\
lower.md3      3/3/2001 12:11 PM      593,972        33%     398,956         models\players\characters\BoB\
lower_1.md3    3/3/2001 12:11 PM      593,972 33%     398,956         models\players\characters\BoB\
lower_2.md3    3/3/2001 12.11 PM      593,972        33%     398,956         models\players\characters\BoB\
upper.md3      3/3/2001 12:11 PM      721,388        33%     483,599         models\players\characters\BoB\
upper_1.md3    3/3/2001 12:11 PM      721,388        33%     483,599         models\players\characters\BoB\
upper_2.md3    3/3/2001 12:11 PM      721,388        33%     483,599         models\players\characters\BoB\
icon_default.tga       6/13/2000 8:15 PM      16,402  61%     6,328         models\players\ characters\BoB\
blue.tga       10/23/2000 7: 17 PM    196,626        41%     115,756         models\players\characters\BoB\kreechurs\
lower_blue.skin        4/6/2001 11 :20 AM     203     52%     98         models\players\characters\BoB\kreechurs\
lower_default.skin     4/6/200 111:25AM       204     50%     102         models\players\characters\BoB\kreechurs\
lower_red.skin  4/6/2001 11:20AM       204     50%     102         models\players\characters\BoB\kreechurs\
red.tga        10/23/2000 7:17 PM     196,626        43%     111,607         models\players\characters\BoB\kreechurs\
upper_blue.skin        41612001 11:20AM       281     58%     118         models\players\characters\BoB\kreechurs\
upper_default.skin     416/2001 11:25AM       282     58%     119         models\players\characters\BoB\kreechurs\
upper_red.skin  4/6/2001 11 :20 AM     282     58%     119         models\players\characters\BoB\kreechurs\
blue_h.tga     6/14/2000 10:26 AM     196,652        56%     86,873         models\players\heads\Kreecha\
default_fc.tga  5/29/2000 10:07 AM     3,090   90%     323         models\players\heads\Kreecha\
default_visor.tga      10/23/2000 7:57 PM     196,626        96%     7,656         models\players\heads\Kreecha\
Kreecha.md3    3/3/2001 12:12 PM      5,868   46%     3,171         models\players\heads\Kreecha\
Kreecha_1.md3  3/3/2001 12:12 PM      5,868   46%     3,171         models\players\heads\Kreecha\
Kreecha_2.md3  3/3/2001 12:12 PM      5,868   46%     3,171         models\players\heads\Kreecha\
head_blue.skin  3/12/2001 4:58 PM      56      7%      52         models\players\heads\Kreecha\
head_default.skin      3/1212001 4:57 PM      53      8%      49         models\players\heads\Kreecha\
head_red.skin  3/12/2001 4:58 PM      55      7%      51         models\players\heads\Kreecha\
icon_blue.tga  6/13/2000 8:15 PM      16,402  58%     6,846        models\players\heads\Kreecha\
icon_default.tga       6/13/2000 8:15 PM      16,402  61%     6,328         models\players\heads\Kreecha\
icon_red.tga   6/1312000 8.15 PM      16,402  61%     6,328         models\players\heads\Kreecha\
red_h.tga      3112/2001 6:06 PM      196,626        66%     66,666         models\players\heads\Kreecha\
BoB.shader     3/12/2001 5:49 PM      2,912   89%     308     scripts\
kreechurs.bot  5/9/2001 11 :43 AM     405     70%     123     scripts\
kreechurs.shader       4/6/2001 3:05 PM       500     67%     163     scripts\
Kreecha.vc     5/2/2001 5:53 PM       21      0%      21      scripts\
Infinite.vc    4/9/2001 11: 18 AM     24      0%      24      scripts\
Prime.vc       4/9/2001 11: 18 AM     24      0%      24      scripts\
Vader.vc       4/9/2001 11: 18 AM     24      0%      24      scripts\
death1.wav     2/23/2000 9:20 AM      16,720  47%     8,900   sound\player\BoB\
death2.wav     5/7/2000 5:46 PM       18,496  17%     15,356  sound\player\BoB\
death3.wav     5/7/2000 5:46 PM       18,496  17%     15,356  sound\player\BoB\
fall1.wav      5/9/2000 6:40 AM       13,944  62%     5,327   sound\player\BoB\
falling1.wav   5/7/2000 5:22 PM       40,722  26%     30,585  sound\player\BoB\
gasp.wav       5/7/2000 5:15 PM       55,230  4%      53,293  sound\player\BoB\
jump1.wav      5/7/20009:26 PM 47,778   8%     44,070  sound\player\BoB\
pain100_1.wav  5/7/20005:33PM 6,894    29%    4,880   sound\player\BoB\
pain25_1.wav   5/7/20005:34 PM 9,832    26%    7,248   sound\player\BoB\
pain50_1.wav   5/7/20005:33 PM 6,444    22%    5,007   sound\player\BoB\
pain75_1.wav   5/7/20005:33 PM 9,512    26%    6,997   sound\player\BoB\
taunt.wav      3/3/2001 12:17 PM      163,874  11%    146,434 sound\player\BoB\
gs_01.wav      10/20/20005:05 PM      51,304   10%    46,296  sound\voices\BoB\
gs_02.wav      10/20/20005:05 PM      69,704   10%    62,811  sound\voices\BoB\
gs_03.wav      10/20/20005:05 PM      53,394   8%     49,195  sound\voices\BoB\
gs_04.wav      10/20/20005:05 PM      48,802   3%     47,157  sound\voices\BoB\
gs_05.wav      10/20/20005:05 PM      62,170   4%     59,614  sound\voices\BoB\
gs_06.wav      10/20/2000 5:05 PM     53,622   5%     51,075  sound\voices\BoB\
gs_07 .wav     10/20/2000 5:05 PM     67,756   10%    60,889  sound\voices\BoB\
gs_08.wav      10/20/2000 5:05 PM     61,458   4%     59,265  sound\voices\BoB\
gs_09.wav      10/20/2000 5:05 PM     60,042   6%     56,640  sound\voices\BoB\
gs_10.wav      10/20/2000 5:05 PM     82,526   4%     79,337  sound\voices\BoB\
or_01.wav      10/20/2000 5.05 PM     46,892   8%     42,990  sound\voices\BoB\
or_02.wav      10/20/2000 5:05 PM     63,152   10%    56,946  sound\voices\BoB\
or_03.wav      10/20/2000 5:05 PM     54,714   6%     51,246  sound\voices\BoB\
or_04.wav      10/20/2000 5:05 PM     43,640   4%     41,815  sound\voices\BoB\
or_05.wav      10/20/2000 5:05 PM     56,694   6%     53,172  sound\voices\BoB\
or_06.wav      10/20/2000 5:05 PM     44,248   6%     41,468  sound\voices\BoB\
or_07.wav      10/20/2000 5:05 PM     57,616   4%     55,043  sound\voices\BoB\
or_08.wav      10/20/2000 5:05 PM     22,626   5%     21,538  sound\voices\BoB\
or_09.wav      10/20/2000 5:05 PM     36,260   30%    25,528  sound\voices\BoB\
or_10.wav      10/20/2000 5:05 PM     43,396   7%     40,432  sound\voices\BoB\
or_11.wav      10/20/2000 5:05 PM     37,070   4%     35,592  sound\voices\BoB\
or_12.wav      10/20/2000 5:05 PM     25,714   4%     24,796  sound\voices\BoB\
ps_01.wav      10/20/2000 5:05 PM     58,040   4%     55,538  sound\voices\BoB\
ps_02.wav      10/20/2000 5:05 PM     40,686   4%     39,161  sound\voices\BoB\
ps_03.wav      10/20/2000 5:05 PM     44,870   5%     42,695  sound\voices\BoB\
ps_04.wav      10/20/2000 5:05 PM     50,550   4%     48,465  sound\voices\BoB\
ps_05.wav      10/20/2000 5:05 PM     64,256   9%     58,718  sound\voices\BoB\
ps_06.wav      10/20/2000 5:05 PM     60,770   4%     58,385  sound\voices\BoB\
ps_07.wav      10/20/2000 5:05 PM     41,604   3%     40,372  sound\voices\BoB\
ps_08.wav      10/20/2000 5:05 PM     33,102   4%     31,860  sound\voices\BoB\
ps_09.wav      10/20/2000 5:05 PM     43,578   14%    37,279  sound\voices\BoB\
ps_1 0.wav     10/20/2000 5:05 PM     48,126   3%     46,467  sound\voices\BoB\
ps_11.wav      10/20/2000 5:05 PM     52,114   7%     48,442  sound\voices\BoB\
ps_12.wav      10/20/2000 5:05 PM     46,054   3%     44,632  sound\voices\BoB\
ps_13.wav      10/20/2000 5:05 PM     52,026   4%     49,921  sound\voices\BoB\
ps_14.wav      10/20/2000 5:05 PM     38,428   3%     37,165  sound\voices\BoB\
re_01.wav      10/20/2000 5:05 PM     42,970   5%     40,707  sound\voices\BoB\
re_02.wav      10/20/2000 5:05 PM     42,010   16%    35,118  sound\voices\BoB\
re_03.wav      10/20/2000 5:05 PM     44,994   4%     43,387  sound\voices\BoB\
re_04.wav      10/20/2000 5:05 PM     26,620   3%     25,824  sound\voices\BoB\
re_05.wav      10/20/2000 5:05 PM     31,732   4%     30,549  sound\voices\BoB\
re_06.wav      10/20/2000 5:05 PM     20,342   5%     19,287  sound\voices\BoB\
re_07.wav      10/20/2000 5:05 PM     23,544   4%     22,526  sound\voices\BoB\
re_08.wav      10/20/2000 5:05 PM     38,070   3%     36,822  sound\voices\BoB\
re_09.wav      10/20/2000 5:05 PM     33,436   4%     32,041  sound\voices\BoB\
re_10.wav      10/20/2000 5:05 PM     29,016   7%     26,898  sound\voices\BoB\
re_11.wav      10/20/2000 5:05 PM     31,998   3%     30,885  sound\voices\BoB\
tt_01.wav      10/20/2000 5:05 PM     56,240   7%     52,038  sound\voices\BoB\
tt_02.wav      10/20/2000 5:05 PM     57,144   5%     54,206  sound\voices\BoB\
tt_03.wav      10/20/2000 5:05 PM     68,484   9%     62,426  sound\voices\BoB\
tt_04.wav      10/20/2000 5:05 PM     55,838   5%     52,785  sound\voices\BoB\
tt_05.wav      10/20/2000 5:05 PM     75,106   6%     70,367  sound\voices\BoB\
tt_06.wav      10/20/2000 5:05 PM     81,630   10%    73,342  sound\voices\BoB\
tt_07.wav      10/20/2000 5:05 PM     60,354   5%     57,333  sound\voices\BoB\
tt_08.wav      10/20/2000 5:05 PM     56,642   5%     53,981  sound\voices\BoB\
tt_09.wav      10/20/2000 5:05 PM     49,216   3%     47,675  sound\voices\BoB\
tt_10.wav      10/20/2000 5:05 PM     60,656   5%     57,563  sound\voices\BoB\
tt_11.wav      10/20/2000 5:05 PM     75,106   5%     71,690  sound\voices\BoB\
tt_12.wav      10/20/2000 5:05 PM     90,760   6%     84,879  sound\voices\BoB\
tt_13.wav      10/20/2000 5:05 PM     52,628   8%     48,347  sound\voices\BoB\
tt_14.wav      10/20/2000 5:05 PM     72,848   4%     70,004  sound\voices\BoB\
tt_15.wav      10/20/2000 5:05 PM     109 184  12%    96,020  sound\voices\BoB\
tt_16.wav      10/20/2000 5:05 PM     48,812   3%     47,245  sound\voices\BoB\
tt_17.wav      10/20/2000 5:05 PM     64,506   10%    57,951  sound\voices\BoB\
tt_18.wav      10/20/2000 5:05 PM     85,018   6%     79,532  sound\voices\BoB\
tt_19.wav      10/20/2000 5:05 PM     72,978   17%    60,260  sound\voices\BoB\
tt_20.wav      10/20/2000 5:05 PM     73,328   6%     68,967  sound\voices\BoB\
tt_21.wav      10/20/2000 5:05 PM     79,434   7%     74, 101 sound\voices\BoB\
tt_22.wav      10/20/2000 5:05 PM     74,636   4%     71,397  sound\voices\BoB\
tt_23.wav      10/20/2000 5:05 PM     37,034   18%    30,448  sound\voices\BoB\
tt_24.wav      10/20/2000 5:05 PM     43,316   5%     41,087  sound\voices\BoB\
tt_25.wav      10/20/2000 5:05 PM     48,376   13%    42,005  sound\voices\BoB\
tt_26.wav      10/20/2000 5:05 PM     35,464   8%     32,716  sound\voices\BoB\
tt_27.wav      10/20/2000 5:05 PM     38,430   6%     35,995  sound\voices\BoB\
tt_28.wav      10/20/2000 5:05 PM     40,698   13%    35,580  sound\voices\BoB\
tt_29.wav      10/20/2000 5:05 PM     36,074   17%    29,767  sound\voices\BoB\
tt_30.wav      10/20/2000 5:05 PM     83,012   5%     79,167  sound\voices\BoB\
tt_31.wav      10/20/2000 5:05PM      55,530   14%    47,706  sound\voices\BoB\
tt_32.wav      10/20/2000 5:05 PM     52,040   15%    44,369  sound\vojces\BoB\
tt_33.wav      10/20/2000 5:05 PM     96,360   10%    86,316  sound\voices\BoB\
tt_34.wav      10/20/2000 5:05 PM     100,896  5%     96,263  sound\voices\BoB\
tt_35.wav      10/20/2000 5:05 PM     104,038  10%    93,172  sound\voices\BoB\
tt_36.wav      10/20/2000 5:05 PM     34,940   4%     33,701  sound\voices\BoB\
tt_37.wav      10/20/2000 5:05 PM     81,704   12%    71,904  sound\voices\BoB\
tt_38.wav      10/20/2000 5:05 PM     58,670   19%    47,593  sound\voices\BoB\
tt_39.wav      10/20/2000 5:05 PM     57,012   4%     54,683  sound\voices\BoB\
tt_40.wav      10/20/2000 5:05 PM     94,790   5%     90,171  sound\voices\BoB\
tt_41.wav      10/20/2000 5:05 PM     89,030   7%     82,981  sound\voices\BoB\
tt_42.wav      10/20/2000 5:05 PM     76,556   14%    65,952  sound\voices\BoB\
tt_43.wav      10/20/2000 5:05 PM     67,744   10%    60,694  sound\voices\BoB\
tt_44.wav      10/20/2000 5:05 PM     44,188   20%    35,183  sound\voices\BoB\
voc_01.wav     10/20/2000 5:05 PM     51,640   12%    45,423  sound\voices\BoB\
voc_02.wav     10/20/2000 5:05 PM     37,916   12%    33,258  sound\voices\BoB\
voc_03.wav     10/20/2000 5:05 PM     40,364   9%     36,548  sound\voices\BoB\
voc_04.wav     10/20/2000 5:05 PM     60,412   4%     57,815  sound\voices\BoB\
voc_05.wav     10/20/2000 5:05 PM     56,172   6%     52,986  sound\voices\BoB\
voc_06.wav     10/20/2000 5:05 PM     41,284   3%     39,918  sound\voices\BoB\
voc_07.wav     10/20/2000 5:05 PM     49,442   9%     45,003  sound\voices\BoB\
voc_08.wav     10/20/2000 5:05 PM     61,656   5%     58,449  sound\voices\BoB\
voc_09.wav     10/20/2000 5:05 PM     44,306   7%     41,295  sound\voices\BoB\
voc_10.wav     10/20/2000 5:05 PM     58,298   9%     52,997  sound\voices\BoB\
voc_11.wav     10/20/2000 5:05 PM     55,050   18%    45,254  sound\voices\BoB\
voc_12.wav     10/20/2000 5:05 PM     40,614   9%     37,135  sound\voices\BoB\
voc_13.wav     10/20/2000 5:05 PM     43,068   4%     41,307  sound\voices\BoB\
voc_14.wav     10/20/2000 5:05 PM     45,512   9%     41,619  sound\voices\BoB\
voc_15.wav     10/20/2000 5:05 PM     47,532   3%     45,886  sound\voices\BoB\
voc_16.wav     10/20/2000 5:05 PM     40,756   3%     39,412  sound\voices\BoB\
yoc_17.wav     10/20/2000 5:05 PM     52,070   7%     48,546  sound\voices\BoB\
voc_18.wav     10/20/2000 5:05 PM     55,394   6%     51,854  sound\voices\BoB\
voc_19.wav     10/20/2000 5:05 PM     74,718   8%     68,688  sound\voices\BoB\
voc_20.wav     10/20/2000 5:05 PM     47,504   10%    42,821  sound\voices\BoB\
voc_21.wav     10/20/2000 5:05 PM     52,034   7%     48,188  sound\voices\BoB\
voc_22.wav     10/20/2000 5:05 PM     36,558   10%    32,925  sound\voices\BoB\
voc_23.wav     10/20/2000 5:05 PM     35,880   4%     34,606  sound\voices\BoB\
voc_24.wav     10/20/2000 5:05 PM     28,234   4%     27,227  sound\voices\BoB\
voc_25.wav     10/20/2000 5:05 PM     50,004   14%    42,898  sound\voices\BoB\
voc_26.wav     10/20/2000 5:05 PM     62,516   10%    56,117  sound\voices\BoB\
voc_27.wav     10/23/2000 3:01 PM     49,444   5%     46,934  sound\voices\BoB\
voc_28.wav     10/23/2000 3:05 PM     54,600   6%     51,556  sound\voices\BoB\
Kreechurs.tga  4/6/2001 1 :08 PM      65,580   99%    873     team_icon\
Kreechurs_blue.tga     4/6/2001 1 :09 PM      65,580   98%    1,030   team_icon\
Kreechurs_red.tga      4/6/2001 1 :09 PM      65,580   98%    1,016   team_icon\
Kreechurs.roq  5/09/2001 5:45 PM      1,078,120      9%      976,146 ui\assets\
Kreechurs.tga  3/2/2001 11 :57 AM     65,580   99%    873     ui\assets\
Kreechurs_metal.tga    3/2/2001 10:58 AM      65,580   74%    16,883  ui\assets\
Kreechurs_name.tga     3/2/200111:16AM 131,116  91%    11,640  ui\assets\
Kreechurs_name_alt.tga         3/2/200111:05AM 131,116  97%    3,870   ui\assets\
 
188 file(s)            12,590,550      25%    9,496,872
+

TOP

+

Appendix K: A + Minimal Team

+

The following list is the + minimum number of files needed to make a new team and assumes that the team + creator is using both the Janet and James models (the models shipped with Quake + III: Team Arena) and the pre-existing heads that work with those models. Note + that no sound or voice files are necessary. No head files are necessary. When + adding new heads, refer to the Kreecha head in + Appendix J. When reskinning previously created heads, + refer to the Callisto/Lily head in Appendix J. Use + this list as a reference when creating your own team pak + files.

+
tm_kreechurs.pk3
Name    Modified       Size    Ratio   Packed  Path
kreechurs.team  5/9/2001 12:01 PM      1,968   61%     770
kreechurs_readme.txt   5/9/2001       3,162   59%     1,286   
blue.tga       10/23/2000 7: 17 PM    196,626        41%     115,756         models\players\James\kreechurs\
lower_blue.skin        4/6/2001 11 :20 AM     203     52%     98         models\players\James\kreechurs\
lower_default.skin     4/6/200 111:25AM       204     50%     102         models\players\James\kreechurs\
lower_red.skin  4/6/2001 11:20AM       204     50%     102         models\players\James\kreechurs\
red.tga        10/23/2000 7:17 PM     196,626        43%     111,607         models\players\James\kreechurs\
upper_blue.skin        41612001 11:20AM       281     58%     118         models\players\James\kreechurs\
upper_default.skin     416/2001 11:25AM       282     58%     119         models\players\James\kreechurs\
upper_red.skin  4/6/2001 11 :20 AM     282     58%     119         models\players\James\kreechurs\
blue.tga       10/23/2000 7: 17 PM    196,626        41%     115,756         models\players\Janet\kreechurs\
lower_blue.skin        4/6/2001 11 :20 AM     203     52%     98         models\players\Janet\kreechurs\
lower_default.skin     4/6/200 111:25AM       204     50%     102         models\players\Janet\kreechurs\
lower_red.skin  4/6/2001 11:20AM       204     50%     102         models\players\Janet\kreechurs\
red.tga        10/23/2000 7:17 PM     196,626        43%     111,607         models\players\Janet\kreechurs\
upper_blue.skin        41612001 11:20AM       281     58%     118         models\players\Janet\kreechurs\
upper_default.skin     416/2001 11:25AM       282     58%     119         models\players\Janet\kreechurs\
upper_red.skin  4/6/2001 11 :20 AM     282     58%     119         models\players\Janet\kreechurs\
kreechurs.bot  5/9/2001 11 :43 AM     405     70%     123     scripts\
kreechurs.shader       4/6/2001 3:05 PM       500     67%     163     scripts\
kreechurs.tga  4/6/2001 1 :08 PM      65,580   99%    873     team_icon\
kreechurs_blue.tga     4/6/2001 1 :09 PM      65,580   98%    1,030   team_icon\
kreechurs_red.tga      4/6/2001 1 :09 PM      65,580   98%    1,016   team_icon\
kreechurs.tga  3/2/2001 11 :57 AM     65,580   99%    873     ui\assets\
kreechurs_metal.tga    3/2/2001 10:58 AM      65,580   74%    16,883  ui\assets\
kreechurs_name.tga     3/2/200111:16AM 131,116  91%    11,640  ui\assets\
kreechurs_name_alt.tga         3/2/200111:05AM 131,116  97%    3,870   ui\assets\
 
27 file(s)             1,354,162              271,112 
+

TOP

+

Appendix L: + Contents of the TAhead_lily.pk3

+

The following list is + taken directly from the contents of the pak file + that contains the Lily head model that is a part of the Kreechurs + team. Lily is based on the Callisto head model from + the original TA game (blinking female head with red or blue hair cut in a + pageboy style). Use this as a reference when creating your own pak files for new character heads.

+
TAhead_lily.pk3
 
Name    Modified       Size    Ratio   Packed  Path
Lily.vc        5/112001 6:56 PM       23      0%      23      scripts\Callisto\
red_Iily.shader        4/9/20011:18 PM        557     79%     117     scripts\
lily .shader   4/9/2001 1: 19 PM      528     78%     114      scripts\
blue_lily.shader       5/1/20015:50 PM        566     79%     119     scripts\
Lily_redface2.tga      4/3/200111:41 PM       16,428  32%     11,092         models\players\heads\Callisto\Lily\
Lily_redface.tga       4/3/2001 11 :40 PM     16,428  33%     11,062         models\players\heads\Callisto\Lily\
Lily_red.tga   4/2/2001 2:14 PM       65,580  79%     13,873         models\players\heads\Callisto\Lily\
Lily_blueface2.tga     4/3/2001 11 :42 PM     16,428  32%     11, 182         models\players\heads\Callisto\Lily\
Lily_blueface.tga      4/3/200111:41 PM       16,428  32%     11,174         models\players\heads\Callisto\Lily\
LJily_blu.tga  4/10/2001 12:55 AM     65,580  33%     43,929         models\players\heads\Callisto\Lily\
icon_red.tga   3/27/20016:15 AM       12,306  30%     8,581         models\players\heads\Callisto\Lily\
icon_default.tga       3/27/20016:15 AM       12,306  30%     8,595         models\players\heads\Callisto\Lily\
icon_blue.tga  3/29/2001 10:20 PM     16,428  41%     9,707         models\players\heads\Callisto\Lily\
head_red.skin  4/17/20014:35 PM       125     44%     70         models\players\heads\Callisto\Lily\
head_default.skin      4/17/20014:35 PM       126     41%     74         models\players\heads\Callisto\Lily\
head_blue.skin  4/17/20014:33 PM       126     44%     71         models\players\heads\Callisto\Lily\
 
16 file(s)             239,963        46%     129,783
 
+

TOP

+
+

 

+
+ +

 

+ +
+ + + + diff --git a/docs/manual/quake3/Q3AShader_Manual/appendix/appA.html b/docs/manual/quake3/Q3AShader_Manual/appendix/appA.html new file mode 100644 index 00000000..907f7f38 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/appendix/appA.html @@ -0,0 +1,60 @@ + + +Quake III Arena Shader Manual: Appendix A + + + +

Q3Radiant Shader Manual

+ +TTimo
+2001.31.08
+
+
+

Appendix A: usage of targetShaderName and targetShaderNewName

+ +

+The targetShaderName and targetShaderNewName keys can be used with any entity +that supports the target key (the entity instance does not actually have to use +the target key for these new keys to work). If both are defined, then when the +entity decides to activate its targets, all shaders/textures in the map that +were originally the same name as the targetShaderName value, will be changed to +the targetShaderNewName value. +

+ +

+For example this would make it look like the red light shader is "turning on": +

+ +

+"targetShaderName" "textures/proto2/redlight_off"
+"targetShaderNewName" "textures/proto2/redlight_on" +

+ +

+And this would turn it back off: +

+ +

+"targetShaderName" "textures/proto2/redlight_off"
+"targetShaderNewName" "textures/proto2/redlight_off" +

+ +

+Note that the ORIGINAL shader name is used in both instances, not whatever it +happens to be currently. Also, of course, this will happen globally. If the +mapper wanted to affect only a certain set of red lights, he/she would need to +make a unique shader name to be used with that set. +

+ +

+The code that supports these keys is in G_UseTargets in g_utils.c. +

+ +

+For more information, see this thread:
+ +http://www.quake3world.com/ubb/Forum6/HTML/014812.html#9 + +

+ + diff --git a/docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm new file mode 100644 index 00000000..4edf8735 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm @@ -0,0 +1,126 @@ + + +Quake III Arena Shader Manual: Introduction + + + +

Q3Radiant Shader Manual

+
+

1 Preface: Making Your Own Shaders

+ +The Manual for the Q3Radiant editor program contains a section called Creating New Assets that has the necessary information for setting up the files to create your own custom Quake III Arena shaders. It is recommended that you study the scripts in this document and in the individual shader scripts. Pay careful attention to syntax and punctuation. This is where you are most likely to make mistakes. + +

2 Introduction

+ +The graphic engine for QuakeIII Arena has taken a step forward by putting much more direct control over the surface +qualities of textures into the hands of designers and artists. In writing this manual, we have tried to define the +concepts and tools that are used to modify textures in a way that, it is hoped, will be graspable by users who already have basic knowledge ofcomputer graphics but are not necessarily computer programmers. It is not a tutorial, nor was it intended to be one. + +

2.1 What is a Shader?

+ +Shaders are short text scripts that define the properties of a surface as it appears and functions in a game world (or compatible editing tool). By convention, the documents that contain these scripts usually has the same name as the texture set which contains the textures being modified (e.g; base, hell, castle, etc,). Several specific script documents have also been created to handle special cases, like liquids, sky and special effects. + +

For Quake III Arena,Shader scripts are located in quake3/baseq3/scripts. + +

A Quake III Arena shader file consists of a series of surface attribute and rendering instructions formatted +within braces ("{" and "}"). Below you can see a simple example of syntaxand format for a single process, including the +Q3MAP keywords or "SurfaceParameters", which follow the first bracket and a single bracketed "stage": + +

textures/liquids/lava
+	{
+	deformVertexes wave sin 0 3 0 0.1
+	tessSize 64
+	{
+	map textures/common/lava.tga
+	}
+}
+
+ +

2.2 Shader Name & File Conventions

+The first line is the shader name. Shader names can be up to 63 characters long. The names are often a mirror of +a pathname to a .tga file without the extension or base dir (/quake3/baseq3 in ourcase), but they do not need to be. + +

Shaders that are only going to be referenced by the gamecode, not modeling tools, often are just a single world, +like"projectionShadow" or "viewBlood". + +

Shaders that are used on characters or other polygon models need to mirror a .tga file, which allows the modelers to build with normal textures, then have the special effects show up when the model is loaded into the game. + +

Shaders that are placed on surfaces in the map editor commonly mirror a .tga file, but the "qer_editorimage" shader parameter canforce the editor to use an arbitrary image for display. + +

Shader pathnames have a case sensitivity issue - on windows, they aren't case sensitive, but on unix they are. Try to always use lowercase for filenames, and always use forward slashes "/" for directory separators. + +

2.3 Shader Types

+The keywords that affect shaders are divided into two classes. The first class of keywords are global parameters. Some global parameters ("surfaceparms." And all "q3map_" keywords) are processed by Q3MAP, and change physical attributes of the surface that uses the shader. These attributes can affect the player. To see changes in these +parameters one must re-bsp the map. + +

The remaining global keywords, and all Stage Specific Keywords are processed by the renderer. They are appearance changes +only and have no effect on game play or game mechanics. Changes to any of these attributes will take effect as soon as the game goes to another level or vid_restarts (type command vid_restart in the game console). + +

Shader keywords are notcase sensitive. + +

IMPORTANT NOTE: some of the shader commands may be order dependent, so it's good practice to place all global shader commands (keywords defined in this section) at the very beginning of the shader and to place shader stages at the end (see various examples). + +

2.4 Key Concepts

+ +Ideally, a designer or artist who is manipulating textures with shader files has a basic understanding of wave forms and knows about mixing colored light (high school physics sort of stuff). If not, there are some concepts you need to have a +grasp on to make shaders work for you. + +

2.4.1 Surface Effects vs. Content Effects vs. Deformation Effects
+Shaders not only modify the visible aspect of textures on a geometry brush, curve, patch or mesh model, but they can also have an effect on both the content, "shape," and apparent movement of those things. A surface effect does nothing to modify +the shape or content of the brush. Surface effects include glows, transparencies and rgb (red, green, blue) value +changes. Content shaders affect the way the brush operates in the game world. Examples include water, fog, nonsolid, and +structural. Deformation effects change the actual shape of the affected brush or curve, and may make it appear to move. + +

2.4.2 Power Has a Price
+The shader script gives the designer, artist and programmer a great deal of easily accessible power over the appearance of +and potential special effects that may be applied to surfaces in the gameworld. But it is power that comes with a price tag +attached, and the cost is measured in performance speed. Each shader phase that affects the appearance of a texture causes the Q3:Aengine to make another processing pass and redraw the world. Think of it as if you were adding all +the shader-affected triangles to the total r_speed count for each stage in the shader script. A shader-manipulated texture that is seen through another shader-manipulated texture (e.g. a light in fog) has the effect of adding the total number of passes together for the affected triangles. A light that required two passes seen through a fog that requires one pass will be treated as having to redraw that part of the world three times. + +

2.4.3 RGB Color
+ +RGB means "Red, Green, Blue."Mixing red, green and blue light in differing intensities creates the colors in computers and television monitors. This is called additive color (as opposed to the mixing of pigments in paint or colored ink in the printing process, which is subtractive color). In Quake III Arena and most higher-end computer art programs (and the color selector in Windows), the intensities ofthe individual Red, Green and Blue components are expressed as number values. When mixed together on a screen, number values of equal intensity in each component color create a completely neutral (gray) color. The lower the number value (towards 0), the darker the shade. The higher the value, the lighter the shade or the more saturated the color until it reaches a maximum value of 255 (in the art programs). All colors possible on the computer can be expressed as a formula of three numbers. The value for complete black is 0 0 0. The value for complete white is 255 255 255. However, the QuakeIII Arena graphics engine requires that the color range be "normalized" into a range between 0.0 and 1.0. + +

2.4.4 Normalization: a Scale of 0 to 1
+The mathematics in Quake III Arena use a scale of 0.0 to 1.0 instead of 0 to 255. Most computer art programs that can express RGB values as numbers use the 0 to 255 scale. To convert numbers, divide each of the artprogram's values for the component colors by 255. The resulting three values are your Quake III Arena formula for that color component. The same holds true for texture coordinates. + +

2.4.5 Texture Sizes
+TGA texture files are measured in pixels (picture elements). Textures are measured in powers of 2, with 16 x16 pixels being the smallest (typically) texture in use. Most will be larger. Textures need not be square, so long as both dimensions are powers of 2. Examples include: 32x256, 16x32, 128x16. + +

2.4.6 Color Math
+ +In Quake III Arena , colors are changed by mathematical equations worked on the textures by way ofthe scripts or +"programlets" in the shader file. An equation that adds to or multiplies the number values in atexture causes it to become +darker. Equations that subtract from or modulate number values in a texture cause it to become lighter. Either equation can change the hue and saturation of a color. + +

2.4.7 Measurements
+ +The measurements used in the shaders are in either game units, color units, or texture units. + +

· Game unit: A game unit is used by deformations to specify sizes relative to the world. Game units are the same scale we have had since way back in the Wolfensteindays - 8 units equals one foot. The default texture scale used by the Q3Radiant map editor results in two texels for each game unit, but that can be freely changed. + +

· Color units: Colors scale the values generated by the texture units to produce lighting effects. A value of 0.0 will be completely black, and a value of 1.0 will leave the texture unchanged. Colors are sometimes specified with a single value to be used across all red, green,and blue channels, or sometimes as separate values for each channel. + +

· Texture units: This is the normalized (see above) dimensions of the original texture image (or a previously modified texture at a given stage in the shader pipeline). A full texture, regardless of its original size in texels, has a normalized measurement of 1.0 x 1.0. For normal repeating textures, it is possible to have value greater than 1.0 or less than 0.0, resulting in repeating of the texture. The coordinates are usually assigned by the level editor or +modeling tools, but you still need to be aware of this for scrolling or turbulent movement of the texture at runtime. + +

2.4.8 Waveform Functions
+Many of the shader functions use waveforms to modulate measurements over time. Where appropriate, additional information is provided with wave modulated keyword functions to describe the effect of a particular waveform on that process. Currently there are five waveforms in use in Q3A shaders: + +

Sin: Sin standsfor sine wave, a regular smoothly flowing wave ranging from -1 to 1. +
Triangle: Triangle is a wave with a sharp ascent and a sharp decay, ranging from 0 to 1.It will make a choppy looking wave forms. +
Square: A squarewave simply switches from -1 to 1 with no in-between. +
Sawtooth: In the sawtooth wave, the ascent is like a triangle wave from 0 to 1, but the decay cuts off sharply back to 0. +
Inversesawtooth: This is the reverse of the sawtooth… instant ascent to the peak value (1), then a triangle wave descent to the valley value (0). The phase on this goes from 1.0 to 0.0 instead of 0.0 to 1.0. This wave is particularly usefulfor additive cross-fades. + +

Waveforms all have thefollowing properties: +
<base> Where the wave form begins. Amplitude is measured from this base value. +
<amplitude> This is the height of the wave created, measured from the base. You will probably need to test and tweak this value to get it correct for each new shader stage. The greater the amplitude, the higher the wave peaks and the deeper the valleys. +
<phase> This is a normalized value between 0.0 and 1.0. Changing phase to a non-zero value affects the point on the wave at which the wave form initially begins to be plotted. Example: In Sin or Triangle wave, a phase of 0.25 means it begins one fourth (25%) of the way along the curve, or more simply put, it begins at the peak of the wave. A phaseof 0.5 would begin at the point the wave re-crosses the base line. A phase of 0.75 would be at the lowest point of the valley. If only one wave form is being used in a shader, a phase shift will probably not be noticed and phase should have a value of zero (0). However, including two or more stages of the same process in a single shader, but with the phases shifted can be used to create interesting visual effects. Example: using rgbGen in two stages with different colors and a 0.5 difference in phase would cause the manipulated texture to modulate between two distinct colors. Phase changes can also be used when you have two uses of the same effect near each other, and you don't want them to be synchronized. You would write a separate shader for each, changing only the phase value. +
<freq>Frequency. This value is expressed as repetitions or cycles of the wave per second. A value of 1 +would cycle once per second. A value of 10 would cycle 10 times per second. A value of 0.1 would cycle once every 10 +seconds. +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm new file mode 100644 index 00000000..9bdf0c35 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm @@ -0,0 +1,222 @@ + + +Quake III Arena Shader Manual: General Shader Keywords + + + +

Q3Radiant Shader Manual

+
+

3 General Shader Keywords

+IMPORTANT NOTE: Once again, be aware that some of the shader commands may be order dependent, so it's good practice to place all global shader commands (keywords defined inthis section) at the very beginning of the shader and to place shader stages at the end (see various examples). + +

These Keywords are global to a shader and affect all stages. They are also ignored by Q3MAP. + +

3.1 skyParms <farbox> <cloudheight> <nearbox>

+ +Specifies how to use the surface as a sky, including an optional far box (stars, moon, etc), optional cloud layers with any shader attributes, and an optional near box (mountains in front of the clouds, etc). + +

<farbox> Specifies a set of files to use as an environment box behind all cloudlayers. Specify "-" for no +farbox, or a file base name. A base name of "env/test" would look for files "env/test_rt.tga", "env/test_lf.tga", +"env/test_ft.tga", "env/test_bk.tga", "env/test_up.tga", "env/test_dn.tga" to use as the right / left / front / back / up / +down sides. + +
<cloudheight> controls apparent curvature of the cloud layers - lower numbers mean more curvature (and thus more distortion at the horizons). Higher height values create "flatter" skies with less horizon distortion. Think of height +as the radius of a sphere on which the clouds are mapped. Good ranges are 64 to 256. The default value is 128. + +
<nearbox> Specified as farbox, to be alpha blended ontop of the clouds. This has not be tested in a long time, so it probably doesn't actually work. Set to "-" to ignore. + +

Design Notes: + +
  • If you are making a map where the sky is seen by looking up most of the time, use a lower cloudheight value. Under those circumstances the tighter curve looks more dynamic. If you are making a map where the sky is seen by looking out windows most of the time or has a map area that is open to the sky on one or more sides, use a higher height to make the clouds seem more natural. + +
  • It is possible to create a sky with up to 8 cloudlayers, but that also means 8 processing passes and a potentially large processing hit. + +
  • Be aware that the skybox does not wrap around the entire world. The "floor" or bottom face of the skybox is not drawn by the game. If a player in the game can see that face, they will see the "hall of mirrors" effect.
+ +

Example: Sky script + +

textures/skies/xtoxicsky_dm9
+{
+	qer_editorimage textures/skies/toxicsky.tga
+	surfaceparm noimpact
+	surfaceparm nolightmap
+q3map_globaltexture
+q3map_lightsubdivide 256
+	q3map_surfacelight 400
+	surfaceparm sky
+	q3map_sun 1 1 0.5 150 30 60
+	skyparms full 512 -
+	{
+		map textures/skies/inteldimclouds.tga
+		tcMod scroll 0.1 0.1
+		tcMod scale 3 2
+	}
+	{
+		map textures/skies/intelredclouds.tga
+		blendFunc add
+		tcMod scroll 0.05 0.05
+		tcMod scale 3 3
+	}
+}
+
+ +

3.2 cull <side>

+Every surface of a polygon has two sides, a front and a back. Typically, we only see the front or "out" side. For +example, a solid block you only show the front side. In many applications we see both. For example, in water, you can see both front and a back. The same is true for things like grates and screens. + +

To "cull" means to remove. The value parameter determines the type of face culling to apply. The default value is cull front if this keyword is not specified. However for items that should be inverted then the value back should be used. To disable culling, the value disable ornone should be used. Only one cull instruction can be set +for the shader. + +

3.2.1 cull front
+ +The front or "outside" of the polygon is not drawn in the world. This is the default value. It is used if the keyword "cull " appears in the content instructions without a <side>value or if the keyword cull does not appear at all in the shader. + +

3.2.2 cull back
+ +Cull back removes the back or "inside" of a polygon from being drawn in the world. + +

3.2.3 cull disable, cull none
+Neither side of the polygon is removed. Both sides are drawn in the game. Very useful for making panels or barriers that +have no depth, such as grates, screens, metal wire fences and so on and for liquid volumes that the player can see from within. Also used for energy fields, sprites, and weapon effects (e.g. plasma). + +

Design Notes: For things like grates and screens, put the texture with the cull none property on one face only. On the other faces, use a non-drawing texture.
+ +

3.3 deformVertexes

+ +This function performs a general deformation on the surface's vertexes, changing the actual shape of the surface before drawing the shader passes. You can stack multiple deformVertexes commands to modify positions in more complex ways, making an object move in two dimensions, for instance. + +

3.3.1 +deformVertexes wave <div> <func> +<base><amplitude> <phase> <freq>
+ +Designed for water surfaces, modifying the values differently at each point. It accepts the standard wave functions of the type sin,triangle, square, sawtooth orinversesawtooth . The "div" parameter is used to +control the wave "spread" - a value equal to the tessSizeof the surface is a good default value (tessSize is subdivision size, in game units, used for the shader when seen in the game world). + +

3.3.2 +deformVertexes normal <div> <func> +<base><amplitude ~0.1-~0.5> <frequency +~1.0-~4.0>
+ +This deformation affects the normals of a vertex without actually moving it, which will effect later shader options like +lighting and especially environment mapping. If the shader stages don't use normals in any of their calculations, there will +be novisible effect. + +

Design Notes: Putting values of 0.1 to 0.5 in Amplitude and 1.0 to 4.0 in the Frequency can produce some satisfying results. Some things that have been done with it: A small fluttering bat, falling leaves, rain, flags.
+ +

3.3.3 +deformVertexes bulge <bulgeWidth> +<bulgeHeight><bulgeSpeed>
+ +This forces a bulge to move along the given s and t directions. Designed for use on curved pipes. + +

Specific parameter definitions for deform keywords: + +
<div> This is roughly defined as the size of the waves that occur. It is measured in game units. Smaller +values create agreater density of smaller wave forms occurring in a given area. Larger values create a lesser density of waves, or otherwise put, the appearance of larger waves. To look correct this value should closely correspond to the value (in pixels) set for tessSize (tessellation size) of the texture. A value of 100.0 is a good default value (which means your tessSize should be close to that for things tolook "wavelike"). + +
<func> This is the type of wave form being created. Sin stands for sine wave, a regular smoothly flowing +wave. Triangle is a wave with a sharp ascent and a sharp decay. It will make a choppy looking wave forms. A square +wave is simply on or off for the period of the frequency with no in between. The sawtooth wave has the ascent of a triangle wave, but has the decay cut off sharply like a square wave. An inversesawtooth wave reverses this. + +
<base> This is the distance, in game units that the apparent surface of the texture is displaced from the +actual surface of the brush as placed in the editor. Apositive value appears above the brush surface. A negative value appears below the brush surface. An example of thisis the Quad effect, which essentially is a shell with a positive base value to stand it away from the model surface and a 0 (zero) value for amplitude. + +
<amplitude> The distance that the deformation moves away from the base value. See Wave Forms in the introduction for a description of amplitude. + +
<phase> SeeWave Forms in the introduction for a description of phase) +
<frequency> See Wave Forms in the introduction for a description of frequency) + +

Design Note: The div and amplitude parameters, when used in conjunction with liquid volumes like water should take into consideration how much the water will be moving. A large ocean area would have have massive swells (big div values) that rose and fell dramatically (big amplitude values). While a small, quiet pool may move very little.
+ +

3.3.4 +deformVertexes move<x> <y> <z> <func> +<base> <amplitude> <phase> <freq>
+ +This keyword is used to make a brush, curve patch or md3model appear to move together as a unit. The <x> <y> +and <z> values are the distance and direction in game units the object appears to move relative to it's point of origin in the map. + +

The <func> <base> <amplitude><phase> and <freq> values are the same as found in other wave +form manipulations. + +

The product of the function modifies the values x, y, and z.Therefore, if you have an amplitude of 5 and an x value of 2, the object will travel 10 units from its point of origin along the x axis. This results in a total of 20 units of motion along the x axis, since the amplitude is the variation both above and below the base. + +

It must be noted that an object made with this shader does not actually change position, it only appears to. + +

Design Note: If an object is made up of surfaces with different shaders, all must have matching deformVertexes move values or the object will appear to tear itself apart.
+ +

3.3.5 +DeformVertexes autosprite
+ +This function can be used to make any given triangle quad (pair of triangles that form a square rectangle) automatically behave like a sprite without having to make it a separate entity. This means that the "sprite" on which the texture is placed will rotate to always appear at right angles to the player's view as a sprite would. Any four-sided brush side, flat patch, or pair of triangles in an .md3 model can have the autosprite effect on it. The brush face containing a texture with this shader keyword must besquare. + +

Design Note :This is best used on objects that would appear the same regardless of viewing angle. An example might be a glowing light flare.
+ +

3.3.6 +DeformVertexes autosprite2
+ +Is a slightly modified "sprite" that only rotates around the middle of its longest axis. This allows you to make a +pillar of fire that you can walk around, or an energy beam stretched across the room. + +

3.4 fogparms <red +value> <green value> <bluevalue> <distance to +Opaque>

+ +

Note: you must also specify "surfaceparm fog" to cause q3map to identify the surfaces inside the volume. Fogparms only +describes how to render the fog on the surfaces. + +

<red value> <green value> <blue value> These are normalized values. A good computer art program should give you the RGB values for a color. To obtain the values that define fog color for Quake III Arena, divide the desired color's Red, Green and Blue values by 255 to obtain three normalized numbers within the 0.0 to 1.0 range. + +
<distance toopaque> This is the distance, in game units, until the fog becomes totally opaque, as measured from the point of view of the observer. By making the height of the fog brush shorter than the distance to opaque, the apparent density of the fog can be reduced (because it never reaches the depth at which full opacity occurs). + +

  • The fog volume can only have one surface visible (from outside the fog). +
  • Fog must be made of one brush. It cannot be made of adjacent brushes. +
  • Fog brushes must be axial. This means that only square or rectangular brushes may contain fog, and those must have their edges drawn along the axes of the map grid (all 90 degree angles). +
+ +

Design Notes: + +
  • If a water texture contains a fog parameter, it must be treated as if it were a fog texture when in use. +
  • If a room is to be filled completely with a fog volume,it can only be entered through one surface (and still have the fog function correctly). +
  • Additional shader passes may be placed on a fog brush, as with other brushes.
+ +

3.5 nopicmip

+This causes the texture to ignore user-set values for the r_picmip cvar command. The image will always be high +resolution. Example: Used to keep images and text in the heads up display from blurring when user optimizes the game graphics. + +

3.6 nomipmaps

+This implies nopicmip, but also prevents the generation of any lower resolution mipmaps for use by the 3d card. This will +cause the texture to alias when it gets smaller, but there are some cases where you would rather have this than a blurry image. Sometimes thin slivers of triangles force things to very low mipmap levels, which leave a few constant pixels on otherwise scrolling special effects. + +

3.7 polygonOffset

+Surfaces rendered with the polygonOffset keyword are rendered slightly off the polygon's surface. This is typically +used for wall markings and "decals." The distance between the offset and the polygon is fixed. It is not a variable in QuakeIII Arena. + +

3.8 portal

+Specifies that this texture is the surface for a portal or mirror. In the game map, a portal entity must be placed directly in front of the texture (within 64 game units). All this does is set "sortportal", so it isn't needed if you specify +that explicitly. + +

3.9 sort <value>

+Use this keyword to fine-tune the depth sorting of shaders as they are compared against other shaders in the game world. The +basic concept is that if there is a question or a problem with shaders drawing in the wrong order against each other, this allows the designer to create a hierarchy ofwhich shader draws in what order. + +

The default behavior is to put all blended shaders in sort "additive" and all other shaders in sort "opaque", so you only +need to specify this when you are trying to work around a sorting problem with multiple transparent surfaces in a scene. + +

The value here can be either a numerical value or one of the keywords in the following list (listed in order of ascending priority): + +

    portal (1): This surface is a portal, it draws over every other shader seen inside the portal, but before anything in the main view. + +
    Sky (2): Typically, the sky is the farthest surface in the game world. Drawing this after other opaque surfaces can be an optimization on some cards. This currently has the wrong value for this purpose, so it doesn't do much of anything. + +
    Opaque (3):This surface is opaque (rarely needed since this is the default with noblendfunc) + +
    Banner (6) :Transparent, but very close to walls. + +
    Underwater (8): Draw behind normal transparent surfaces. + +
    Additive (9): normal transparent surface (default for shaders with blendfuncs) +
    nearest (16):this shader should always sort closest to the viewer, e.g. muzzle flashes and blend blobs
+

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm new file mode 100644 index 00000000..00a4ed66 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm @@ -0,0 +1,197 @@ + + +Quake III Arena Shader Manual: Specific Shader Keywords + + + +

Q3Radiant Shader Manual

+
+

4 Q3MAP Specific Shader Keywords

+These keywords change the physical nature of the textures and the brushes that are marked with them. Changing any of these values will require the map to be re-compiled. These are global and affect the entire shader. + +

4.1 tessSize <amount>

+For consistency's sake, this really should have been called q3map_tessSize. But it wasn't. The tessSize shader controls +the tessellation size (how finely a surface is chopped up in to triangles), in game units, of the surface. This is only +applicable to solid brushes, not curves, and is generally only used on surfaces that are flagged with the deformVertexes keyword. Abuse of this can create a huge number of triangles. This happens during q3map processing, so maps must be reprocessed for changes to take effect. + +

Design Note: It can also be used on tesselating surfaces to make sure that tesselations arelarge, and thus, less costly in terms of triangles created.
+ +

4.2 q3map_backshader <shadername>

+This allows a brush to use a different shader when you are inside it looking out. By way of example, this would allow a water brush (or other) surfaces to have a different sort order (see sort above) or appearance when seen from the inside. + +

4.3 q3map_globaltexture

+Use this shader in the global keyword commands whenever the tcMod scale function is used in one of the later render stages. Many problems with getting shader effects to work across multiple adjacent brushes are a result of the way q3map optimizes texture precision. This option resolves that, but at the expense of some precision of the textures when they are far away from the origin of the map. + +

4.4 q3map_sun <red> <green> <blue> <intensity> <degrees> <elevation>

+This keyword in a sky shader will create the illusion of light cast into a map by a single, infinitely distance light source (sun, moon, hellish fire, etc.). This is only processed during the lighting phase of q3map. + +

<red><green> <blue> Color is described by three normalized rgbvalues. Color will be normalized to a 0.0 to 1.0 range, so it doesn't matter what range you use. + +
<intensity> is the brightness of the generated light. A value of 100 is a fairly bright sun. The +intensity of the light falls off with angle but not distance. + +
<degrees> is the angle relative to the directions on the map file. A setting of 0 degrees equals east. 90 +isnorth, 180 is west and 270 is south. + +
<elevation> is the distance, measured in degrees from the horizon (z value of zero in the map file). An +elevation of 0 is sunrise/sunset. An elevation of 90 is noon. + +

DESIGN NOTE: Sky shaders should probably still have aq3map_surfacelight value. The "sun" gives a strong directional light, but doesn't necessarily give the fill light needed to soften and illuminate shadows. Skies with clouds should probably have a weaker q3map_sunvalue and a higher q3map_surfacelight value. Heavy clouds diffuse light and weaken shadows. The opposite is true of a cloudless or nearly cloudless sky. Insuch cases, the "sun" or "moon" will cast stronger, shadows that have a greater degree of contrast. + +

Design Trick: Not certain what color formula you want to use for the sun's light? Try this. Create a light entity. Use the Q3Radiant editor's color selection tools to pick a color. The light's _color key's value will be the normalized RGB formula. Copy it from the value line in the editor (CTRL+c) and paste it into your shader.

+ +

4.5 q3map_surfaceLight <light value>

+ +The texture gives off light equal to the <light value> set for it. The relative surface area of the texture in the world affects the actual amount of light that appears to be radiated. To give off what appears to be the same amount +of light, a smaller texture must be significantly brighter than a larger texture. Unless the qer_lightimage keyword is used to select a different source for the texture's light color information, the color of the light will be the averaged color of the texture. + +

4.6 q3map_lightimage <texturepath/texturename>

+The keyword q3map_lightimage generates lighting from the average color of the TGA image specified by the +q3map_lightimage. + +

The keyword sequence for generating light on a q3map_surfacelight should be ordered as follows: + +

  1. q3map_lightimage ; (the texture providing the light and the color of the light) +
  2. qer_editorimage ; (the editor-only image used to select the source map for the texture) +
  3. the average color of the light emitted from the shader is calculated from the lightimage.)
+ +

The reason q3map_lightimageis specified for the light in the example below, is because the blend map is predominantly yellow, and the designer wanted more yellow light to be emitted from the light. + +

Example: Taking light from another source texture + +

+textures/eerie/ironcrosslt2_10000
+{
+q3map_lightimagetextures/gothic_light/ironcrosslt2.blend.tga
+// this TGA is the source for the color of the blended light
+
+qer_editorimagetextures/gothic_light/ironcrosslt2.tga
+//base TGA (used because the shader is used with several
+// different light values
+
+q3map_surfacelight 10000
+//emitted light value of10,000
+
+{
+map $lightmap
+//source texture is affected by the lightmap
+rgbGen identity
+// this command handles the overbright bits created by "sunlight"
+// in the game
+}
+{
+maptextures/gothic_light/ironcrosslt2.tga
+blendFunc filter
+rgbGen identity
+}
+{
+maptextures/gothic_light/ironcrosslt2.blend.tga
+blendFunc add
+}
+}
+
+ +

4.7 q3map_lightsubdivide <value>

+This allows the user to define how large, or small to make the subdivisions (triangles) in a textured surface, particularly aimed at light-emitting textures like skies. It defaults to 120 game units, but can be made larger (256 or 512) for sky boxes or smaller for light surfaces at the bottoms of cracks. This can be a dominant factor in processing time for q3map lighting. + +

4.8 surfaceparm <parm>

+ +

All surfaceparm keywords are preceded by the word surfaceparm as follows: surfaceparm fogor surfaceparm noimpact. + +

4.8.1 alphashadow
+This keyword applied to a texture on a brush, patch or model will cause the lighting phase of the q3map process to use the texture's alpha channel as a mask for casting static shadows in the game world. + +

Design Note: Alphashadow does not work well with fine line detail on a texture. Fine lines may not cast acceptable shadows. It appears to work best with well-defined silhouettes and wider lines within the texture. Most of our tattered banners use this to cast tattered shadows.
+ +

4.8.2 areaportal
+A brush marked with this keyword functions as an area portal, a break in the Q3MAP tree. It is typically placed on a very thin brush placed inside a door entity (but is not a part of that entity). The intent is to block the game from processing +surface triangles located behind it when the door is closed. It is also used by the BSPC (bot area file creation compiler) in the same manner as a clusterportal. The brush must touch all the structural brushes surrounding the +areaportal. + +

4.8.3 clusterportal
+A brush marked with this keyword function creates a subdivision of the area file (.aas) used by the bots for navigation. It +is typically placed in locations that are natural breaks in a map, such a sentrances to halls, doors, tunnels, etc. The intent is keep the bot from having to process the entire map at once. As with the the areaportal parameter, the affected brush must touch all the structural brushes surrounding the areaportal. + +

4.8.4 donotenter
+Read as "do not enter." Like clusterportal, this is a bot-only property. A brush marked with donotenter will not affect +non-bot players, but bots will not enter it. It should be used only when bots appear to have difficulty navigating around some map features. + +

4.8.5 flesh
+This will cue different sounds (in a similar manner to metalsteps) and cause blood to appear instead of bullet impact flashes. + +

4.8.6 fog
+Fog defines the brush as being a "fog" brush. This is a Q3MAP function that chops and identifies all geometry inside the +brush. The General shader keyword fogparms must also be specified to tell how to draw the fog. + +

4.8.7 lava
+ +

Assigns to the texture the game properties set for lava. This affects both the surface and the content of a brush. + +

4.8.8 metalsteps
+The player sounds as if he is walking on clanging metal steps or gratings. Other than specifiying flesh, metalsteps, nosteps, or default (i.e. specify nothing) it is currently not possible for a designer to create or assign a specific sound routine to a texture. Note: If no sound is set for a texture, then the default footsteps sound routines are heard. + +

4.8.9 nodamage
+The player takes no damage if he falls onto a texture with this surfaceparm + +

4.8.10 nodlight
+Read as "No DeeLight". A texture containing this parameter will not be affected or lit by dynamic lights, such as +weapon effects. And example in Quake III Arena would be solid lava. + +

4.8.11 nodraw
+A texture marked with nodraw will not visually appear in the game world. Most often used for triggers, clip brushes, origin +brushes, and so on. + +

4.8.12 nodrop
+When a player dies inside a volume (brush) marked nodrop, no weapon is dropped. The intend use isfor "Pits of Death." Have a kill trigger inside a nodrop volume, and when the players die here, they won't drop their weapons. The intent is to prevent unnecessary polygon pileups on the floors of pits. + +

4.8.13 noimpact
+World entities will not impact on this texture. No explosions occur when projectiles strike this surface and no marks +will be left on it. Sky textures are usually marked with this texture so those projectiles will not hit the sky and leave +marks. + +

4.8.14 nomarks
+Projectiles will explode upon contact with this surface, but will not leave marks. Blood will also not mark this surface. +This is useful to keep lights from being temporarily obscured by battle damage. + +

Design Note: Use this on any surface with a deformVertexes keyword. Otherwise, the marks will appear on the unmodified surface location of the texture with the surface wriggles and squirms through the marks.
+ +

4.8.15 nolightmap
+This texture does not have a lightmap phase. It is not affected by the ambient lighting of the world around it. It does not +require the addition of an rgbGen identity keyword in that stage. + +

4.8.16 nosteps
+The player makes no sound when walking on this texture. + +

4.8.17 nonsolid
+This attribute indicates a brush, which does not block the movement of entities in the game world. It applied to +triggers, hint brushes and similar brushes. This affects the content of a brush. + +

4.8.18 origin
+Used on the "origin" texture. Rotating entities need to contain an origin brush in their construction. The brush must be +rectangular (or square). The origin point is the exact center of the origin brush. + +

4.8.19 playerclip
+Blocks player movement through a nonsolid texture. Other game world entities can pass through a brush marked +playerclip. The intended use for this is to block the player but not block projectiles like rockets. + +

4.8.20 slick
+This surfaceparm included in a texture should give it significantly reduced friction. + +

4.8.21 slime
+Assigns to the texture the game properties for slime. This affects both the surface and the content of a brush. + +

4.8.22 structural
+This surface attribute causes a brush to be seen by the Q3MAP process as a possible break-point in a BSP tree. It is used +as a part of the shader for the "hint" texture. Generally speaking, any opaque texture not marked as "detail" is, by +default, structural, so you shouldn't need to specify this. + +

4.8.23 trans
+Tells q3map that pre-computed visibility should not be blocked by this surface. Generally, any shaders that have blendfuncs +should be marked as surfaceparm trans. + +

4.8.24 water
+Assigns to the texture the game properties for water. +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm new file mode 100644 index 00000000..d014d2e1 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm @@ -0,0 +1,64 @@ + + +Quake III Arena Shader Manual: Editor Specific Shader Instructions + + + +

Q3Radiant Shader Manual

+
+

5 Editor specific shader instructions

+These instructions only affect the texture when it is seen in the Q3Radiant editor. They should be grouped with the surface +parameters but ahead of them in sequence. + +

5.1 qer_editorimage <texture path/texturename>

+This keyword creates a shader name in memory, but in the editor, it displays the TGA art image specified in qer_editorimage (in the example below this is textures/eerie/lavahell.tga). + +

The editor maps a texture using the size attributes of the TGA file used for the editor image. When that editor image represents a shader, any texture used in any of the shader stages will be scaled up or down to the dimensions of the editor image. If a 128x128 pixel image is used to represent the shader in the editor, then a 256x256 image used in a later stage will be shrunk to fit. A 64x64 image would be stretched to fit. Be sure to check this on bouncy, acceleration, and power-uppads placed on surfaces other than 256 x 256. Use tcMod scale to change the size of the stretched +texture. Rememberthat tcMod scale 0.5 0.5 will double your image, while tcMod scale 2 2will halve it. + +

Design Notes: The base_light and gothic_light shaders contain numerous uses of this. It can be very useful for making different light styles (mostly to change the light brightnesses) without having to create a new piece of TGA art for each new shader.
+ + +

textures/liquids/lavahell2//path and name of new texture
+{
+qer_editorimagetextures/eerie/lavahell.tga
+//based on this
+qer_nocarve
+//cannot be cut by CSG subtract
+surfaceparm noimpact
+//projectiles do not hitit
+surfaceparm lava
+//has the game properties of lava
+surfaceparm nolightmap
+//environment lighting does not affect
+q3map_surfacelight 3000
+//light is emitted
+tessSize 256
+//relatively large triangles
+cull disable
+//no sides are removed
+deformVertexes wave 100sin 5 5 .5 0.02
+fogparms 0.85191420.309723 0.0 128 128
+{
+maptextures/eerie/lavahell.tga
+//base texture artwork
+tcMod turb .25 0.2 1 0.02
+//texture is subjected to turbulence
+tcMod scroll 0.1 0.1
+//the turbulence is scrolled
+}
+}
+
+ +

5.2 qer_nocarve

+A brush marked with this instruction will not be affected by CSG subtract functions. It is especially useful for water and fog textures. + +

5.3 qer_trans <value>

+This parameter defines the percentage of transparency that a brush will have when seen in the editor (no effect on game +rendering a tall). It can have a positive value between 0 and 1. The higher the value, the less transparent the texture. +Example: qer_trans 0.2 means the brush is 20% opaque and nearly invisible. + +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm new file mode 100644 index 00000000..d3506d69 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm @@ -0,0 +1,483 @@ + + +Quake III Arena Shader Manual: Stage Specific Keywords + + + +

Q3Radiant Shader Manual

+
+

6 Stage Specific Keywords

+Stage specifications only affect rendering. Changing any keywords or values within a stage will usually take effect as soon +as a vid_restart is executed. Q3MAP ignores stage specific keywords entirely. + +

A stage can specify a texture map, a color function, an alpha function, a texture coordinate function, a blend function, and a few other rasterization options. + +

6.1 Texture map specification

+
6.1.1 map <texturepath/texturename>
+Specifies the source texture map (a 24 or 32-bit TGA file) used for this stage. The texture may or may not contain alpha +channel information. The special keywords $lightmap and $whiteimage may be substituted in lieu of an actual +texture map name. In those cases, the texture named in the first line of the shader becomes the texture that supplies the light mapping data for the process. + +

$lightmap
+This is the overall lightmap for the game world. It is calculated during the Q3MAP process. It is the initial color +data found in the framebuffer. Note: due to the use of overbright bits in light calculation, the keyword rgbGen +identity must accompany all $lightmap instructions. + +

$whiteimage
+This is used for specular lighting on MD3 models. This is a white image generated internally by the game. This image can +be used in lieu of $lightmap or an actual texture map if, for example, you wish for the vertex colors to come +through unaltered. + +

6.1.2 Clampmap <texturepath>
+Dictates that this stage should clamp texture coordinates instead of wrapping them. During a stretch function, the area, +which the texture must cover during a wave cycle, enlarges and decreases. Instead of repeating a texture multiple times +during enlargement (or seeing only a portion of the texture during shrinking) the texture dimensions increase or contract accordingly. This is only relevant when using something like deformTexCoordParms to stretch/compress texture coordinates for a specific special effect. Remember that the Quake III Arena engine normalizes all texture coordinates (regardless of actual texture size) into a scale of 0.0 to1.0. + +

Proper Alignment: When using clampTexCoords make sure the texture is properly aligned on the brush. The +clampTexCoords function keeps the image from tiling. However, the editor doesn't represent this properly and shows a tiled image. Therefore, what appears to be the correct position may be offset. This is very apparent onanything with a tcMod rotate and clampTexCoords function. + +

AvoidingDistortion: When seen at a given distance (which can vary, depending onhardware and the size of the texture), the compression phase of a stretchfunction will cause a "cross"-like visual artifact to form on the modified texture due to the way that textures are reduced. This occurs because the texture undergoing modification lacks sufficient "empty space" around the displayed (non-black) part of the texture (see figure 2a). To compensate for this, make the non-zero portion of the texture substantially smaller (50% of maximum stretched size -- see figure 2b)than the dimensions of the texture. Then, write a scaling function (tcScale) into the appropriate shader phase, to enlarge the image to the desired proportion. + +

The shaders for the bouncy pads (in the sfx.shader file) show the stretch function in use, including the scaling of the +stretched texture: + +

Example: UsingclampTexCoords to control a stretching texture + +

+textures/sfx/metalbridge06_bounce
+{
+	//q3map_surfacelight 2000
+	surfaceparm nodamage
+	q3map_lightimage textures/sfx/jumppadsmall.tga
+	q3map_surfacelight 400
+	{
+		map textures/sfx/metalbridge06_bounce.tga
+		rgbGen identity
+	}
+	{
+		map $lightmap
+		rgbGen identity
+		blendfunc gl_dst_color gl_zero
+	}
+	{
+		map textures/sfx/bouncepad01b_layer1.tga
+		blendfunc gl_one gl_one
+		rgbGen wave sin .5 .5 0 1.5
+	}
+	{
+		clampmap textures/sfx/jumppadsmall.tga
+		blendfunc gl_one gl_one
+		tcMod stretch sin 1.2 .8 0 1.5
+		rgbGen wave square .5 .5 .25 1.5
+	}
+	// END
+}
+
+ +

+ +

6.1.3 AnimMap <frequency> <texture1> … <texture8>
+The surfaces in the game can be animated by displaying asequence of 1 to 8 frames (separate texture maps). These animations +are affected by other keyword effects in the same and later shader stages. + +

<Frequency>: the number of times that the animation cycle will repeat within a one second time period. The +larger the value, the more repeats within a second. Animations that should last for more than a second need to be expressed as decimal values. + +
<texture1> …<texture8>: the texture path/texture name for each animation frame must be +explicitly listed. Up to eight frames (eight separate .tga files) can be used to make an animated sequence. Each frame is +displayed for an equal subdivision of the frequency value. + +

Example: AnimMap 0.25 animMap 10textures/sfx/b_flame1.tga textures/sfx/b_flame2.tga textures/sfx/b_flame3.tgatextures/sfx/b_flame4.tga would be a 4 frame animated sequence, calling each frame in sequence over a cycle length of 4 seconds. Each frame would be displayed for 1 second before the next one is displayed. The cycle repeats after the last frame in sequence is shown. + +

Design Notes: To make a texture image appear for an unequal (longer) amount of time (compared to other frames), repeat that frame more than once in the sequence.
+ +

textures/sfx/flameanim_blue
+{
+
+	//	*************************************************
+	//	*	Blue Flame				*
+	//	*	July 20, 1999 Surface Light 1800 	*
+	//	*	Please Comment Changes			*
+	//	*************************************************
+	qer_editorimage textures/sfx/b_flame7.tga
+	q3map_lightimage textures/sfx/b_flame7.tga
+	surfaceparm trans
+	surfaceparm nomarks
+	surfaceparm nolightmap
+	cull none
+	q3map_surfacelight 1800
+	// texture changed to blue flame.... PAJ
+	{
+		animMap 10 textures/sfx/b_flame1.tgatextures/sfx/b_flame2.tga
+textures/sfx/b_flame3.tga textures/sfx/b_flame4.tgatextures/sfx/b_flame5.tga
+textures/sfx/b_flame6.tga textures/sfx/b_flame7.tgatextures/sfx/b_flame8.tga
+		blendFunc GL_ONE GL_ONE
+		rgbGen wave inverseSawtooth 0 1 0 10
+
+	}
+	{
+		animMap 10 textures/sfx/b_flame2.tgatextures/sfx/b_flame3.tga
+textures/sfx/b_flame4.tga textures/sfx/b_flame5.tgatextures/sfx/b_flame6.tga
+textures/sfx/b_flame7.tga textures/sfx/b_flame8.tgatextures/sfx/b_flame1.tga
+		blendFunc GL_ONE GL_ONE
+		rgbGen wave sawtooth 0 1 0 10
+	}
+	{
+		map textures/sfx/b_flameball.tga
+		blendFunc GL_ONE GL_ONE
+		rgbGen wave sin .6 .2 0 .6
+	}
+}
+
+ +

6.2 Blend Functions

+Blend functions are the keyword commands that tell the Quake III Arena graphic engine's renderer how graphic layers are to be mixed together. + +

6.2.1 Simplified blend functions:
+The most common blend functions are set up here as simple commands, and should be used unless you really know what you are +doing. + +

6.2.1.1 blendfunc add +
This is a shorthand command for blendfunc gl_one gl_one. Effects like fire and energy are additive. + +

6.2.1.2 blendfunc filter +
This is a shorthand command that can be substituted for either blendfunc gl_dst_color gl_zero or blendfunc gl_zero gl_src_color. A filter will always result in darker pixels than what is behind it, but it can also remove color selectively. Lightmaps are filters. + +

6.2.1.3 blendfunc blend +
Shorthand for blendfunc gl_src_alphagl_one_minus_src_alpha. This is conventional transparency, where part of the background is mixed with part of the texture. + +

6.2.2 Explicit blend functions:
+Getting a handle on this concept is absolutely key to understanding all shader manipulation of graphics. + +

BlendFunc or "Blend Function" is the equation at the core of processing shader graphics. The formula reads as follows: + +

[Source *<srcBlend>] + [Destination * +<dstBlend>] + +

Source is usually the RGB color data in a texture TGA file (remember it's all numbers) modified by any rgbgen and alphagen. In the shader, the source is generally identified by command MAP, followed by the name of the image. + +

Destination is the color data currently existing in the frame buffer. + +

Rather than think of the entire texture as a whole, it maybe easier to think of the number values that correspond to a single pixel, because that is essentially what the computer is processing … one pixel of the bit map at a time. + +

The process for calculating the final look of a texture in place in the game world begins with the precalculated lightmap for the area where the texture will be located. This data is in the frame buffer. That is to say, it is the initial data in the Destination. In an unmanipulated texture (i.e. one without a special shader script), color information from the texture is combined with the lightmap. In a shader-modified texture, the $lightmap stage must be present for the lightmap to be included in the calculation of the final texture appearance. + +

Each pass or "stage" of blending is combined (in a cumulative manner) with the color data passed onto it by the +previous stage. How that data combines together depends on the values chosen for the Source Blends and Destination Blends at each stage. Remember it's numbers that are being mathematically combined together that are ultimately interpreted as colors. + +

A general rule is that any Source Blend other than GL_ONE (or GL_SRC_ALPHA where the alpha channel is entirely white) will cause the Source to become darker. + +

6.2.3 Source Blend <srcBlend>
+The following values are valid for the Source Blend part of the equation. + +

GL_ONE This is the value 1. When multiplied by the Source, the value stays the same the value of the color information does not change. + +
GL_ZERO This is the value 0. When multiplied by the Source, all RGB data in the Source becomes Zero (essentially black). + +
GL_DST_COLOR This is the value of color data currently in the Destination (frame buffer). The value of that information depends on the information supplied by previous stages. + +
GL_ONE_MINUS_DST_COLOR This is nearly the same as GL_DST_COLOR except that the value for each component color +is inverted by subtracting it from one. (,i.e. R = 1.0 - DST.R, G = 1.0 - DST.G, B = 1.0 - DST.B, etc.) + +
GL_SRC_ALPHA The TGA file being used for the Source data must have an alpha channel in addition to its RGB channels (for a total of four channels). The alpha channel is an 8-bit black and white only channel. An entirely white alpha channel will not darken the Source. + +
GL_ONE_MINUS_SRC_ALPHA This is the same as GL_SRC_ALPHA except that the value in the alpha channel is inverted by subtracting it from one.(i.e. A=1.0 - SRC.A) + +

6.2.4 Destination Blend <dstBlend>
+The following values are valid for the Destination Blend part of the equation. + +

GL_ONE This is the value 1. When multiplied by the Destination, the value stays the same the value of the color information does not change. + +
GL_ZERO This is the value 0. When multiplied by the Destination,all RGB data in the Destinationbecomes Zero (essentially black). + +
GL_SRC_COLOR This is the value of color data currently in the Source (which is the texture being manipulated here). + +
GL_ONE_MINUS_SRC_COLOR This is the value of color data currently in Source, but subtracted from one(i.e. +inverted). + +
GL_SRC_ALPHA The TGA file being used for the Source data must have an alpha channel in addition to its RGB channels (four a total of four channels). The alpha channel is an 8-bit black and white only channel. An entirely white alpha channel will not darken the Source. + +
GL_ONE_MINUS_SRC_ALPHA This is the same as GL_SRC_ALPHA except that the value in the alpha channel is inverted by subtracting it from one. (i.e. A=1.0 - SRC.A). + +

Doing the Math: The Final Result + +
The product of the Source side of the equation is added to the product of the Destination side of the equation. The sum is then placed into the frame buffer to become the Destination information for the next stage. Ultimately, the equation creates a modified color value that is used by other functions to define what happens in the texture when it is displayed in the game world. + +

6.2.5 Default Blend Function
+If no blendFunc is specified then no blending will take place. A warning is generated if any stage after the first stage does not have a blendFunc specified. + +

6.2.6 Technical Information/Limitations Regarding Blend Modes:
+The Riva 128 graphics card supports ONLY the following blendmodes: + +

GL_ONE, GL_ONE +
GL_DST_COLOR, GL_ZERO + +
GL_ZERO, GL_SRC_COLOR + +
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA + +
GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA + +

Cards running in 16 bit color cannot use any GL_DST_ALPHA blends. + +

6.3 rgbGen <func>

+There are two color sources for any given shader, the texture file and the vertex colors. Output at any given time will be equal to TEXTURE multiplied by VERTEXCOLOR. Most of the time VERTEXCOLORwill default to white (which is a normalized value of 1.0), so output will be TEXTURE (this usually lands in the Sourceside of the shader equation). Sometimes you do the opposite and use TEXTURE = WHITE, but this is only commonly used when doing specular lighting on entities (i.e. shaders that level designers will probably never create + +

The most common reason to use rgbGen is to pulsate something. This means that the VERTEXCOLOR will oscillate between two +values, and that value will be multiplied (darkening) the texture. + +

If no rgbGen is specified, either "identityLighting" or"identity" will be selected, depending on which blend modes are +used. + +

Valid <func> parameters are wave, identity, identityLighting, entity, oneMinusEntity, fromVertex, and +lightingDiffuse. + +

6.3.1 RgbGen identityLighting
+Colors will be (1.0,1.0,1.0) if running without overbright bits (NT, linux, windowed modes), or (0.5, 0.5, 0.5) if running +with overbright. Overbright allows a greater color range at the expense of a loss of precision. Additive and blended stages +will get this by default. + +

6.3.2 rgbGen identity
+Colors are assumed to be all white (1.0,1.0,1.0). All filters stages (lightmaps, etc) will get this by default. + +

6.3.3 rgbGen wave <func> <base> <amp><phase> <freq>
+Colors are generated using the specified waveform. An affected texture with become darker and lighter, but will not change +hue. Hue stays constant. Note that the rgb values for color will not go below 0 (black) orabove 1 (white). Valid waveforms are sin, triangle, square, sawtooth and inversesawtooth. + +

<func> Waveforms and their effects: + +
Sin: color flows smoothly through changes. + +
Triangle: color changes at a constant rate and spends noappreciable time at peaks and valleys. + +
Square: color alternates instantly between its peak and valley values. + +
Sawtooth: With a positive frequency value, the color changes at aconstant rate to the peak then instantly drops to its valley value. + +
Inversesawtooth: An inverse sawtooth wave will reverse this, making the ascent immediate (like a square wave) and the decay fall off like a triangle wave. + +
<base> Baseline value. The initial RGB formula of a color (normalilzed). + +
<amp> Amplitude. This is the degree of change from the baseline value. In some cases you will want +values outside the 0.0 to 1.0 range, but it will induce clamping (holding at the maximum or minimum value for a time period) +instead of continuous change. + +
<phase> See the explanation for phase under the waveforms heading of Key Concepts. + +
<freq> Frequency. This is a value (NOT normalized) that indicates peaks per second. + +

6.3.4 RgbGen entity
+Colors are grabbed from the entity's modulate field. This isused for things like explosions. + +

Design Note: This keyword would probably not be used by a level designer.
+ +

6.3.5 rgbGen oneMinusEntity
+Colors are grabbed from 1.0 minus the entity's modulate field. + +

Design Note: This keyword would probably not be used by a level designer.
+ +

6.3.6 rgbGen Vertex
+Colors are filled in directly by the data from the map or model files. + +

Design Note: rgbGen vertex should be used when you want the RGB values to be computed for a static model (i.e. mapobject) in the world using precomputed static lighting from Q3BSP. This would be used on things like +the gargoyles, the portal frame, skulls, and other decorative MD3s put into the Quake III Arena world.
+ +

6.3.7 rgbGen oneMinusVertex
+As rgbGen vertex, but inverted. + +

Design Note: This keyword would probably not be used by a level designer
+ +

6.3.8 rgbGen lightingDiffuse
+Colors are computed using a standard diffuse lighting equation. It uses the vertex normals to illuminate the object correctly. + +

Design Note: -rgbGen lightingDiffuse is used when you want the RGB values to be computed for a dynamic model (i.e. non-map object) in the world using regular in-game lighting. For example, you would specify on shaders for items, characters, weapons, etc.
+ +

6.4 AlphaGen <func>

+The alpha channel can be specified like the rgbchannels. If not specified, it defaults to 1.0. + +

6.4.1 AlphaGen portal
+This rendering stage keyword is used in conjunction with the surface parameter keyword portal. The function +accomplishes the "fade" that causes the scene in the portal to fade from view. Specifically, it means "Generate alpha values +based on the distance from the viewer to the portal." Use alphaGen portal on the last rendering pass. + +

6.5 tcGen <coordinate source>

+Specifies how texture coordinates are generated and where they come from. Valid functions are base,lightmap and environment. + +

<base> = base texture coordinates from the original art. +
<lightmap> = lightmap texture coordinates +
<environment> = Make this object environment mapped. + +

6.5.1 tcGen vector (<sx> <sy> <sz>) +(<tx><ty> <tz>)
+New texcoord generation by world projection. This allows you to project a texture onto a surface in a fixed way, regardless of its orientation. + +

S coordinates correspond to the "x" coordinates on the texture itself. + +
T coordinates correspond to the "y" coordinates on the texture itself. + +

The measurements are in game units. + +

+ +

Example: tcGen vector (0.01 0 0) (0 0.01 0) +
This would project a texture with a repeat every 100 units across the X/Y plane. + +

6.6 tcMod <func> <…>

+Specifies how texture coordinates are modified after they are generated. The valid functions for tcMod are rotate, +scale,scroll, stretch and transform. Transform is a function generally reserved for use by programmers who suggest that designers leave it alone. When using multiple tcMod functions during a stage, place the scroll command last in order, because it performs a mod operation to save precision, and that can disturb other operations. Texture coordinates are modified in the order in which tcMods are specified. In otherwords, if you see: + +

tcMod scale 0.5 0.5 +
tcMod scroll 1 1 + +

Then the texture coordinates will be scaled then scrolled. + +

6.6.1 tcMod rotate <degrees per per second>
+This keyword causes the texture coordinates to rotate. The value is expressed in degrees rotated each second. A positive value means clockwise rotation. A negative value means counterclockwise rotation. For example "tcMod rotate 5" would +rotate texture coordinates 5 degrees each second in a clockwise direction. The texture rotates around the center +point of the texture map, so you are rotating a texture with a single repetition, be careful to center it on the brush (unless off-center rotation is desired). + +

6.6.2 tcMod scale <sScale> <tScale>
+Resizes (enlarges or shrinks) the texture coordinates bymultiplying them against the given factors of <sScale> +and <tScale). The values "s" and "t"conform to the "x" and "y" values (respectively) as they are found in the original texture TGA. The values for sScale and tScale are NOT normalized. This means that a value greater than 1.0 will increase the size of thetexture. A positive value less than one will reduce the texture to a fraction of its size and cause it to repeat within the same area as the original texture (Note: see clampTexCoords for ways to control this).; + +

Example: tcMod scale 0.5 2 would cause the texture to repeat twice along its width, but expand to twice its height (in which case half of the texture would be seen in the same area as the original) + +

6.6.3 tcMod scroll <sSpeed> <tSpeed>
+Scrolls the texture coordinates with the given speeds. The values "s" and "t" conform to the "x" and "y" values +(respectively) as they are found in the original textureTGA. The scroll speed is measured in "textures" per second. A "texture" is the dimension of the texture being modified and includes any previous shader modifications to the original TGA). A negative s value would scroll the texture to the left. A negative t value would scroll the texture down. + +

Example: tcMod scroll 0.5 -0.5 moves the texture down and right (relative to the TGA files original coordinates) at the rate of a half texture each second of travel. + +

This should be the LAST tcMod in a stage. Otherwise there maybe popping or snapping visual effects in some shaders. + +

6.6.4 tcMod stretch <func> <base> +<amplitude><phase> <frequency>
+ +Stretches the texture coordinates with the given function. Stretching is defined as stretching the texture coordinate away from the center of the polygon and then compressing it towards the center of the polygon. + +

<base>: A base value of one is the original dimension of the texture when it reaches the stretch stage. +Inserting other values positive or negative in this variable will produce unknown effects. + +
<amplitude>: This is the measurement of distance the texture will stretch from the base size. It is +measured, like scroll, in textures. A value of 1 here will double the size of the texture at its peak. + +
<phase>: See the explanation for phase under the deform vertexes keyword. + +
<frequency>: this is wave peaks per second. + +
Wave Functions <func> + +
Sin wave: the texture expands smoothly to its peak dimension and then shrinks smoothly to its valley dimension in a flowing manner. + +
Triangle wave: The textures stretch at a constant rate and spend no appreciable time at the peak or valley points. + +
Square wave: The texture is shown at its peak for the duration of the frequency and then at its valley for the +duration of the frequency. + +
Sawtooth: the texture stretches like a triangle wave until it reaches a peak, then instantly drops to the valley, as in a square wave. + +
Inversesawtooth: this is the reverse of the sawtooth wave. + +

6.6.5 tcMod <transform> <m00> <m01> <m10><m11> <t0> <t1>
+Transforms each texture coordinate as follows: + +

S' = s * m00 + t * m10 + t0 + +
T' = s * m01 + t * m11 + t1 + +

This is for use by programmers. + +

6.6.6 tcMod turb <base> <amplitude> +<phase><freq>
+ +

Applies turbulence to the texture coordinate. Turbulence is a back and forth churning and swirling effect on the texture. + +

The parameters for this shader are defined as follows: + + +

<base> Currently undefined. + +
<amplitude> This is essentially the intensity of the disturbance or twisting and squiggling of the texture. + +
<phase> See the explanation for phase under the deformvertexes keyword. + +
<freq> Frequency. This value is expressed as repetitions or cycles of the wave per second. A value of one +would cycle once per second. A value of 10 would cycle 10 times per second. A value of 0.1 would cycle once every 10 +seconds. + +

6.7 depthFunc <func>

+This controls the depth comparison function used while rendering. The default is "lequal" (Less than or equal to) +where any surface that is at the same depth or closer of an existing surface is drawn. This is used for textures with +transparency or translucency. Under some circumstances you may wish to use "equal", e.g. for light-mapped grates that are alpha tested (it is also used for mirrors). + +

6.8 depthWrite

+By default, writes to the depth buffer when depthFunc passes will happen for opaque surfaces and not for translucent surfaces. Blended surfaces can have the depth writes forced with this function. + +

6.9 Detail

+This feature was not used in Quake III Arena maps, but should still function. +Designates this stage as a detail texture stage, which means that if the c_var, r_detailtextures, is set to 0 then this stage will be ignored (detail will not be displayed). This keyword, by itself, does not affect rendering at all. If you do put in a detail texture, it has to conform to very specific rules. Specifically, the blendFunc: + +

blendFuncGL_DST_COLOR GL_SRC_COLOR + +

This is also the simple blend function: blendfuncfilter + +

And the average intensity of the detail texture itself must be around 127. + +

Detail is used to blend fine pixel detail back into a base texture whose scale has been increased significantly. When detail iswritten into a set of stage instructions, it allows the stage to be disabled by the c_var console command setting "r_detailtextures 0". + +

A texture whose scale has been increased beyond a 1:1 ratio tends not to have very high frequency content. In other words, one texel can cover a lot of real estate. Frequency is also known as "detail." Lack of detail can appear acceptable if the player never has the opportunity to see the texture at close range. But seen close up, such textures look glaringly wrong within the sharp detail of the Quake III Arena environment. A detail texture solves this problem by taking a noisy "detail" pattern (a tiling texture that appears to have a great deal of surface roughness) and applying it to the base texture at a very densely packed scale (that is, reduced from its normal size). This is done programmatically in the +shader, and does not require modification of the base texture. Note that if the detail texture is the same size and scale as the base texture that you may as well just add the detail directly to the base texture. The theory is that the detail texture's scale will be so high compared to the base texture (e.g.; 9 detail texels fitting into 1 base texel) that it is literally impossible to fit that detail into the base texture directly. + +

For this to work, the rules are as follows: + +

    + +
  1. the lightmap must be rendered first. This is because the subsequent detail texture will be modifying the lightmap in the framebuffer directly; +
  2. the detail texture must be rendered next since it modifies the lightmap in the framebuffer; +
  3. the base texture must be rendered last; +
  4. the detail texture MUST have a mean intensity around 127-129. If it does not then it will modify the displayed texture's perceived brightness in the world; +
  5. the detail shader stage MUSThave the "detail" keyword or it will not be disabled if the user uses the "r_detailtextures 0" setting; +
  6. the detail stage MUST use "blendFunc GL_DST_COLOR GL_SRC_COLOR". Any other BlendFunc will cause mismatches in brightness between detail and non-detail views.; +
  7. the detail stage should scale its textures by some amount (usually between 3 and 12) using "tcMod" to control density. This roughly corresponds to coarseness. A very large number, such as 12, will give very fine detail, however that detail will disappear VERY quickly as the viewer moves away fromthe wall since it will be MIP mapped away. A very small number, e.g. 3, gives diminishing returns since not enough is brought in when the user gets very close. I'm currently using values between 6 and 9.5. You should use non-integral numbers as much as possible to avoid seeing repeating patterns. +
  8. detail textures add one pass of overdraw, so there is a definite performance hit . +
  9. detail textures can be shared, so designers may wish to define only a very small handful of detail textures for common surfaces such as rocks, etc.
+ +

An example (non-existent) detailshader is as follows: +

Example: Texture with Detail + +

+textures/bwhtest/foo
+{
+// draw the lightmap first
+{
+map $lightmap
+rgbGen identity
+}
+// modify the lightmap in the framebuffer by
+// a highly compressed detail texture
+{
+map textures/details/detail01.tga
+blendFunc GL_DST_COLOR GL_SRC_COLOR
+// YOU MUST USE THIS!!
+detail
+// for the detail to be disabled, this must be present
+tcMod scale 9.1 9.2
+}
+// now slap on the base texture
+{
+map textures/castle/blocks11b.tga
+blendFunc filter
+}
+}
+
+ +

6.10 alphaFunc <func>

+Determines the alpha test function used when rendering this map. Valid values are GT0, LT128, and GE128. These +correspond to "GREATER THAN 0", "LESS THAN 128", and "GREATER THAN OR EQUAL TO 128". This function is used when determining if a pixel should be written to the framebuffer. For example, if GT0 is specified, the only the portions of the texture map with corresponding alpha values greater than zero will be written to the framebuffer. By default alpha testing is disabled. + +

Both alpha testing and normal alpha blending can be used to get textures that have see-through parts. The difference is that alphaFunc is an all-or-nothing test, while blending smoothly blends between opaque and translucent at pixel edges. Alpha test can also be used with depthwrite, allowing other effects to be conditionally layered on top of just the opaque pixels by setting depthFunc to equal. + +

Back | Home | Next + + + diff --git a/docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm new file mode 100644 index 00000000..c5a6b87d --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm @@ -0,0 +1,145 @@ + + +Quake III Arena Shader Manual: Notes on Alpha Channels + + + +

Q3Radiant Shader Manual

+
+

7 Notes on Alpha Channels

+To use some blend modes of alphaFunc, you must add an alpha channel to your texture files. Photoshop can do this. +Paintshop Pro has the ability to make an alpha channel but cannot work directly in to it. In Photoshop you want to set the type to Mask. Black has a value of 255. White has a value of 0. The darkness of a pixel's alpha value determines the +transparency of the corresponding RGB value in the game world. Darker = more transparent. + +

Care must be taken when reworking textures with alpha channels. Textures without alpha channels are saved as 24 bit images while textures with alpha channels are saved as 32 bit. If you save them out as 24 bit, the alpha channel is erased. Note: Adobe Photoshop will prompt you to save as 32, 24 or 16 bit. Choose wisely. If you save a texture as 32 bit and you don't actually have anything in the alpha channel, Quake III Arena may still be forced to use a lower quality texture format (when in 16 bit rendering) than if you had saved it as 24 bit. + +

To create a texture that has "open" areas, make those areas black in the alpha channel and make white the areas that are to be opaque. Using gray shades can create varying degrees of opacity/transparency. + +

Example: An opaque texture with see-through holes knocked in it. + +

+textures/base_floor/pjgrate1
+{
+	surfaceparm metalsteps
+	cull none
+
+	// A GRATE OR GRILL THAT CAN BE SEEN FROM BOTH SIDES
+	{
+		map textures/base_floor/pjgrate1.tga
+		blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+		alphaFunc GT0
+		depthWrite
+		rgbGen identity
+	}
+	{
+		map $lightmap
+		rgbGen identity
+		blendFunc GL_DST_COLOR GL_ZERO
+		depthFunc equal
+	}
+	}
+
+ +

The alpha channel can also be used to merge a texture (including one that contains black) into another image so that the merged art appears to be and opaque decal on a solid surface (unaffected by the surface it appears to sit on), without actually using an alpha function. The following is a very simple example: + +

+ +
Figure 1 + +

Start with a TGA file image. In this case, a pentagram on a plain white field (figure 1A). The color of the field surrrounding the image to be merged is not relevant to this process (although having a hard-edged break between the image to be isolated and the field makes the mask making process easier). Make an alpha channel. The area of the image to be merged with another image is masked off in white. The area to be masked out (notused) is pure black (figure 1B). The image to be merged into is greenfloor.tga (figure 1C). + +

Make a qer_editorimage of greenfloor.tga. This is placed inthe frame buffer as the map image for the texture. By +using GL_SRC_ALPHA as the source part of the blend equation, the shader adds in only the non-black parts of the pentagram. +Using GL_MINUS_ONE_SRC_ALPHA, the shader inverts the pentagram's alpha channel and adds in only the non-black parts of the green floor. + +

In a like manner, the alpha channel can be used to blend the textures more evenly. A simple experiment involves using a +linear gradiant in the alpha channel (white to black) and merging two textures so they appear to cross fade into each other. + +

A more complicated experiment would be to take the pentagram in the first example and give it an aliased edge so that the pentagram appeared to fade or blend into the floor. + +

8 Troubleshooting Shaders

+If a shader is not working, look first for syntax errors. +
  • Are the brackets correctly set? +
  • Do you have too many parameter values on a line? +
  • Are you using a word in a parameter that wants a numerical value? +
  • Are you using a numerical value in a parameter that wants a word? +
  • Are the path names to your textures correct? +
  • Are your texture names correct? There is a chance that the texture name is too long or too complex. Try renaming a +texture with a shorter, simpler name.
+ +

9 Creating New Textures

+If you are familiar with the required tools, creating new assets for use in Quake III Arena is not particularly difficult. As a general rule, you should create new directories for each map with names different from the names used by id. If you are making a map that will be called "H4x0r_D00M", every directory containing new assets for that map should be titled H4x0r_D00M. This is to try and avoid asset directories overwriting each other as the editor and the gameload in assets. + +

9.1 Tools Needed

+Any combination of graphic programs and plug-ins that canout put a 24 bit MS windows compatible Targa (.tga) or JPEG (.jpg) graphic file.If you plan to make textures that will have an alpha channel component (a 4th 8-bit greyscale channel that is used by the shaders to further manipulate the art), you must have a program that can create 32-bit art with that fourth channel. + +

Adobe Photoshop has the ability to easily create alpha channels. PaintShop Pro from JASC (v5.0+) can also make an +alpha channel by creating a mask and naming it "alpha". + +

Generally speaking, regardless of the program used, we found it best to do most of the art manipulation of the alpha channel in a separate layer or file and then paste it into the alpha channel before saving. + +

9.2 Setting up Files

+The editor and the game program look for assets to be located along the paths set up in your project file. Start by creating +a directory for you new textures by creating file folders to make a directory path as follows: + +

quake3\baseq3\textures\[mymapname]
+ +

The installation of Q3Radiant will create a text document called "shaderlist.txt" in the following path: + +

quake3\baseq3\scripts\shaderlist.txt
+ +

Q3Radiant will use the contents of this script to grab your new textures for inclusion in the game. The contents of shaderlist.txt document will contain a listing of all the shader documents that were used by id Software to create Quake III Arena. + +

Since you will obviously want to create your own shaders, you need to put them in separate folders and create a new shader script for them. + +

If you plan to work on several maps at once and want to distinguish between textures used in each map, simply add additional map names here. For map and mod makers, we STRONGLY recommend that any new shader scripts created use the name of the map or mod in the shader file name. We know we can't avoid every incident of files overwriting each other, but we certainly can advise you how to try. + +

Now, in the scripts directory that you just created, create another text file and call it: + +

[mymapname].shader
+ +

This file will contain the shader scripts you write to modify a particular texture. + +

9.3 Rules and Guidelines

+
9.3.1 Rules
+Follow these rules when creating textures for the Quake III Arena engine: + +
  • Save your textures into your new [map name] directories. +
  • Don't use the same names that id used for textures. It will cause problems. +
  • For best quality, save textures without an alpha channel as 24 bit TARGA files. Using JPEG files can save memory space, but at the risk of losing detail and depth in the texture. JPEG files cannot be used for textures requiring an alpha channel. +
  • Textures containing an alpha channel must be saved as32 bit TARGA files. +
  • If a new texture requires no further manipulation, it does not need a shader script. +
  • Size textures in powers of 2. Example: 8x8, 16x16,32x32, 64x64 pixels and so on. +
  • Textures don't need to be square. A 32x256 pixel texture is perfectly acceptable.
+ +

9.3.2 Guidelines
+The following are some things the id designers learned about textures. + +
  • Create textures in "suites" built around one or two large textures with a number of much smaller supporting detail or accent textures. +
  • Very large textures are possible, but some video cards compress textures larger than 256x256 pixels. +
  • Textures are grouped alphabetically by name in the texture display window, so you may want to give suites of textures +similar names. +
  • Use the shader function qe3_editorimage to conserve memory when making multiple versions of a single texture (as in the case of a glowing texture with several light values). +
  • Unless you are creating special effects or textures designed to draw the player's eye to a specific spot, muted, middle value colors work best with the game engine. +
  • Extremely busy (a lot of fussy detail) textures can break up or form visually unpleasant patterns when seen at distances.
+ +

9.4 Making the .pk3 File>

+When you go to distribute your creation to the gaming world, you need to put your newly created map, textures, bot area files, and shader documents into an archive format called a "pk3" file. You do not need to include the shaderlist.txt file, since that is only used by the editor. You will need to keep the paths to the various assets the same. So your paths should be something like this: + +

Textures: baseq3/textures/[mymapnamefolder] +
Bsp & aas: baseq3/maps/mymapname.bsp, mymapname.aas +
Shader scripts: baseq3/scripts/mymapname.shader + +

You need to use an archiving program call Winzip to make the pk3 file. Get Winzip from http://www.winzip.com/winzip/winzip.htm + +
Make a zip archive called mymapname.zip + +
Zip all the required assets into a zip archive file (Quake III Arena DOES support compressed pk3 files). + +
Rename the zip archive to mymapname.pk3 + +
Put it where the Quake III Arena community can find it. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/index.htm b/docs/manual/quake3/Q3AShader_Manual/index.htm new file mode 100644 index 00000000..5e80b29a --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/index.htm @@ -0,0 +1,76 @@ + + +Quake III Arena Shader Manual: Table of Contents + + + +

+

Q3Radiant Shader Manual

+ +

Revision #12

+ +

By Paul Jaquays and Brian Hook + +

(with additional material by John Carmack, Christian Antkow, Kevin Cloud, & Adrian Carmack) +

QERadiant.com thanks John Hutton for re-formating this manual into a more web friendly version

+
+

Table of Contents

+1 Preface: Making Your Own Shaders +
2 Introduction + + +3 General Shader Keywords + + +4 Q3MAP Specific Shader Keywords + + +5 Editor specific shader instructions + + +6 Stage Specific Keywords + + +7 Notes on Alpha Channels +
8 Troubleshooting Shaders +
9 Creating New Textures + +
Appendix A: targetShaderName and targetNewShaderName + + diff --git a/docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg b/docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9cc0ffc7d070348330ed1362946a82c50790b7ec GIT binary patch literal 26981 zcmd43by!G!P~3{U6qn-e?v|hd zLUQw-d-nHz@7eq8eeXX1ob^02dGfI4Tw~0+<`}>68)Jf+L#+Xxs4A)`0x-}QHwHHV zfLa8|1F$i%u&^+((I42@*bi|CaBVZ!a$;htr&Kib z^o)#*q?FHCo-we{F)%XxH3$Z}E6zh4LR?%z1~OtYhX3Cesslib3+R7ffQj)8@PHTt zlNbZl4PXQSFtGoU76SwDKQD|2m{@2jaUbE~qi?8v0(gLdiTMC6KUx9w-G1o51F(p( zNuKh{J|xw8kMqolOdv4+2QIT*>m|DqQ$TCWG_Wx>MvOD~KE9_WTijD`J_{~?L27S4Mo(q{sJxMXti zKPrDeVitT0CI8?&jz_^Fw9X3qOSS)@+5b1ig8o~Y{X?;T>a_qMz{Ef=9wspW2)N^o zc>evt|CNoS{0n>~Vs1Y^4eNBwjck;S@n)Ox{_OeLdlVo`3k6txmi2kXw4D)-xtH(t z0tFa-jsl#g@&K4SbZu>eswT_%7~*A1vp*1uGyeLY(;oW| z1^NER11~#mCEA*uHh`2y)(a7ak7*S{)m}m$y%~L;92L`uUH2skn*fI=V+-8y&oL_7 z*Qu)**ji>%?HBJ@YFg{8x>$bWlQ~=|lZc5O;Eu{F2DdarKu+6f_i;>joftDcVLkNjx6zcImQ5S=r2RxMQT0OjGZa9Vl9B0Z&FNTA2!yxaq}S|I zEK3I-tqYpKrC>EU{{C5H>ZP>da`-i7Ee-be-0J^TbN`<$_L(NNjrSJv2|Tf6{!rhY zbpJNUXyL}-+4J`iY@FYt9vriL{zcn}34Gpz0z6U4KWGEa3Z0U})6NxZC(GWYz7D0= zI+ADR5HLAW1ic8ue$gE=Ke@A8R|_3Ue3)0V;+M&)ZkX#+;-zKuY%fqWKkJMV+f6G63 zVycM|^3(eB-qDkQH==Q6^#F^n0fJ^>h7$IH@4+Pp-o+dVr&?Bj%GZ30XpUcL#gJLV zPKTEP|Mf+jU6P5g{I|{jPkW#k^k2Wg|Jfw|w|C5JlnsxE7jyygL?+jV{Gv@TN`pDo zrirbzu85TA1UK1VE5=KFV6^I=qUyN*7p7(W`zi10?2@NP)QQxyHa>WQWjnFw1Xm%j zl4QaC&g0vC_NNcTIT^_U46@i78lJ=64qe|Im|={OHO*o7%Vn1>;ZHsckq+6CB@`!) zOfn0C>o!eO|L2sEE2*GO5chIzUR5|BFU`(|l4P0+;X@Uf0M5WMY=GnQG4y7iU9$R* z4T1h&wia;9k@au3=%3~Zy=N9-C_un}ygGqi?g+@*|Hht~{a4l~rDc+e$v?VSc+$@Ilzx*eCAcLxVHT z#+~o8HR^)K6P6Q~v=%87emPdZ7hB~qYvM;HqllMCB*(v_Rjz2rR&Gc*RH<(ICO0JX zh`EsJH|HaAoBv~r&!HzawymXeN1*k6GF3++;`vXl(S4EGrjVNYx3+0f=F28b%H6WM zdX~DF&ove34_2?#NAGbiL5N@!pmz^ij|j>}w)3`Mi=y3nY!%WCDe-g@DHbnTXyW#bbL z>`WA3Su0^Rpj;jVk4n)CJ>W7{qcxkAD4U({mG*6+0Lm#?O2mbA4@I%_#83YxkDmQ} z$jI0tZtD*-^;NI@Ote0E(Ygld$ac3W&92c8#u>)xzRPEZTTC!BAytVEwT?IE(~3!K z-R^y3zXPl6A$!1L6kv-HDXR3Z(jWG>0Aca9luDDnTI+V!v`B+Nh7oyq0@?}Fmv5@W zlMC*@8+!(8G>x0KZ5{a@>R*$5??k)Qpm90{aY>VJT7}6+uI=-pzzfD{$Qcm|K%0BV zwu=nDtw7460Gn>Pc2bmjuq9)4y0QKr3CeQ5A^jNhpbsbEQz6mumD+I`meK}k>ijWzAtUmzVZw-6Bj(3SF1-_CSLVyFK<3{ z#3lvCrnH_o+|b$q4?7|E)a1UBcOEFffD7Z*qk8nxW|iX|t$fxg_~?KFbeVgOB16KJ++F^^&L>K9*h}%uUUDqiV#tXLIL)4#(<|q?eJpYdXo@E`Z_}AwWND0lY+ZmdVwQ*52f^%e>=-D(VBEx8cU-GKv=GZy|SmKv>Z(RawI zHUy@7D9Tu+**P1MLVXF(xPa7gfwSe32W>%>Sy50(cY5#j)j844UA2mCYnz@N&`AGF z(y!AW{r|-rIjufH0Y1it`;&#A9DjNb!%lcG%A2v63Al{@)rWlW*t2_lfS`J5eiFZ3_nsvP+L)y9{vq@r-3I|?r$JDS(;KQ55DH+HvU*E9k@Qy4tw`>L z9rLU|kFPF_F~rx}CD*!chQzps%syX-wao%+cZZ?2Ysr7CO(1-c#y_zJGAV*amkh<( zHOag2Fg-Y+@ySb{-4ncXotiuMn?Jw0G1i@q&7=-B1idp3h#g;FmI+=3z(N*&+48U& zxZY2qJIj@Ql@amGfAfb&sFVK;5sehy&@(p_51BWA>p}8R@Hk>N#*lRh+yMY5MikDb zIQ4|~bMg3CSrPlg|D@8ZymS;BscotXMJlZ18YFmE99%F+T0OpQ#Y8&mY(XAK`!9Xcd6RV?bs>Jsfk0mw=%5=K?oaR9yO z+d1Ipn@^hCy7Hb#Y>51|5Zxv!38iavmRS(IG2~e9!|s~~=8D}OcB2AC;yg=h=Et?-&%~t|`#ty_L-cQOd2X(SU0V21+O zEH21j5mn##%f)94{uy!ByvFuOGdifRQ*mDSF1OvLW#5451kjK4@1uydY2*0l_HJX8 ziXqDbG}1cM1v#8|N8 zKYm)>u@#{JvJgay(RjIK9})<42q-1F?m;qDPkcy}F-S^Dc>{lnWQG;)O_$JBRZ+^G?b6%KJkwhm$x-nsyyQXw7WlO4 zk~rZX##8D2(cVQ}RP#RfwESC_=f`o8a>(X>Eacj@S6E#J9k{iG(&9TCD!%w$$#M(e z`Z*~>XJcfd=2Kzgtr1U9a$SBR7k?Uq0;sZnabMN8n$VDBh~zt_E-X0);Tu(s05|vB z;c4Ff{$y-O-6>RO1fnh={mpBh=_`f^>h) ziOb;dQNbN;-_|-VPQ7%UKE25*;5#PuZJ1wgR%D5h`Acf<>>82$$i#IY5CYEu$<{K# z_<&w^#uT$#LZ*U|AV)Hw)UU1*SsPipaA0JsW(Ua|vhNCDk$dR1=PkNsBU7!_O3nX$ zwmViY^(tj*GI(9`H3~4h2!RO~Sl`LokmfW(x4*s>N9$(aem(3dl%{=5Xc@*{&sMR2 z%}K^pNRW%!#&4uV%04xk!tu$c+ShIBEitpF`;<2d@UspFDQQp-s);GUiYe%<`^@{o ze+G@^(26T;^FPqvvY)>!2kY0T?H~=~6NJR5Mx~teN(Nd7@)P~fWQO3vo8Mae)*COq zN|~$pO}@&pg#7Ld&WMw?D%ZYJuk!(gT^HUtyFCQ*-9;+6%dT+53ngX7s{ai@mR8_H z`Z-X5!?Q!Q3M^$tdB3vO&0JuN8`4?fU_qk;iaI^m_Q$FGF3uMRmF$RGdq>S>`ZLc` z#s&Nhg^IA6p~zRw30ywT*!zK31A=jQ9nlDJx@N+Fz^T~*5l49BrhBtX89Yqe6#sYA z8+<8vw_|}-E@;DkHTu0?`M#uA`eZ?|1Bkf{M%lai1fFZ0C=a*HT{)0Q+63E>#ER_5 z9%g*tpA8J)N}lq?Ci8G`ff@Hz4-_&$s%ri$4QDI*9)o6TeL;_Rr${kz=_D9itg$^t+`dCJqTfQ$hJo!SY+EB`|Cy^E>(993m=^*Qj4!#^x_b1zH5vxi zjg`w0svV!L=BT)xrsvxZ>mH5x%dQID?_0MQCFN2j^z1g4$1K?Hvm6=r=uQ(eR}EUcG6{Y<$vMF<0v<=v?MJr&>y|Z2s_86*QlK!O9xm zcA+72CfabXh`TnE>7Jj~B$j49|4kdxzi5rdKBQ>W+F!E1x`=inUr~Tx>g~wSm)B&g zXCe!b+0Q7ztpF$7r!$96m$V%gv*?F8Eq+)ojiQ2a0l&|Ig0R;Mcm*7gVI4{zK_d%rC=ee zp_dJ@>5rBP)|J)1j4sFf#qK#v>WwFlDuy^%m0pY6+?F68Eu#R;l#ysdFtLaN$a~-D zwV}hWAP-1?&jxzRFY3^+d?oyo9y9z?NVvGwV3slbwJ&#Qr_4VEv-9R=gW5r@yKDuy4cu#sr8-8bMAKz22n zUGO;9Bq_lp#6GM1V|ufj z_uQ|Tai_~%=dF2SBa8Uv!zznj)fsbr68g1LFAT2{!354KLAwR#M^c!2A6=tFX$=T| zVN&J43Y@Eg;s`5;Pt9uEjEFO8niPor{*B-aE{Xg`R%oV)lc!?s#GdkHM8u7$T!s97 zx3yyzHD&?*0Yy}A#$xhM8QMBr4B3#=3>|B-iWeV5>dmIXM;V-IiW8;yTv-J_+v>CPpPD(n@siepLa6&LRSNP=GbiEpY|aeL}yWXCc~;ngeeo zTC@KJ&b3M~cD>SpN7E=i)v100pk}$ss|ahigT$uRFZ8T-K^`9PJ^sv*A;}(VWOgYIRjy|#V4g0;rX#;P@ zZPUm8CdgqFfbtUfIZKGLpQUk}PqnXTKKOdflCUkNk;VH=a(2Hx%&m;C+lW5DKF6%b zufR-^r9KPTba*(*-0*vg_$B3G<``tl6~=epgtjTwrsOV7M2MIyRurHfbWdT0xy2X7 ztJK3siaB|ws6pg!6PigEU9i^c{E(1;qE?2lZ^u^$#zbGS#eQBYsrJpcEIo9>Ym_Ah zUO`dOJ&S*~U1~jRFu@g!|N%|5^;2bS$Cmz@+LC^<0kYVpJ`+ z_7J+#s_O-Ns&z~P)4#*B&7iG&z-Bf0pLk1T6Fc)+nJWy`0}Q*$MUp7LgIR{=(|R zq|y#p3O>*B>bxDd)>JGvpL$5nPp38gC+$37-^W06L0OjWQu-}{Y z`vx`%N?cFhh-8JuATJ}!;QDGXjb!W1(@>jRhF0>5#qtX`XM^Z%wVvZ-c81S-yMa>1 zb}*9PGY7(9-7^E>oBLO_n5P)?9dv=ShbCtQwhaix=Z(C>8x-I-AAT>IJSgdXh{5s> zN&dJ+!0WE=So(M0dEuH07?crmvF1A3Y8>;5F0fBt#l~6I==H7q6$ovJae3BE-ho6l zuk|8guM9Uk>T|_=?p#m+3?r`TT<9}S-`5wAzX7;HU%N7TqL(QL^r0tm&uSI-CPZJ~ zVWh}(Os!C$2|sN#cHN#uCaIWl-5J1ZtZs#Ox`M&BRe~sh`tBwWO4S8fb=66X5?XSM z6&n4D@RCL|MSPJ@;F_u}PGJ0ol=acU_}DbV#pN$N@IWIO)~SoT!m=8AT;cYRn$8cE zVRV01d$_Jyzl=&t=z+RC61!F(^Im=pHwE?R^VniFP{%AV-*p04*vYYHvYRdEPmCUC z0g_-8o$^|g;1mF_RBv!1F; zpa9xF%QBXe!pe?gAf*hA=xg5|dgp>uLO7@j zrM~15m}byb;St17IRFfRCYh0#s?Igysq$kT@5xn>gFo%_Yc5UO%R^_<%hW83)bb9- z^3#i=KGJvfX9K&V#N?Eu-LvL~ZC4Js>>QrPQK>>oz0OJ~@0QPx#D(?WOt>~5Dn{zQ zO>tCw)L{MPtjfCphy6Z&rg0dk(E2Sm(zGRIqj!m@N=c||keVHz1M9{-;04hnbKYyV z;&O|E%duI?fGoWFU;gJllE+BCbK?{WpJU%**4}=dOrcA{#~bAjlC_d?0PZ-4Z5f=6qsgDbA_q4^I(-bAhxb}4ZXg}P7d(PT zF!^`R?eleq6tcfbfu}6umsn^95u-e@w@J`f4!YI!6R&8Khw#N&71Ryi3E`hUMd)WM zC~v5(sh?S|$uBUdY5K?69CZ8>vDWsixed>-l&BdWkUi2|#bfE%S7Zg(1D>+=qR9?@4F+3_>S_PNwK9eZw;vUv zi0HcP%XJ_!Dx!`4z8TE`G{)Xxq4(OJCdf%0je_h7?mab8fZS&lVGw&1;D#5B{EeoL zZb@e?qzAivAy5#x(%6VGN1)RfE!|b2%cPPLk(M8VD3QJ2gEs2*7;jtcitp z*~C%sA(x%f)nBoxN|L!qPdfWjy|VJ?w8qJG4^(`Lh^`y4INl~ zmXn?vrS^ylbB1NDj&)r5QYbsTIJc;*(at}YTDBumGVC0|d4%7pbAlg;P|S_S3KN%# z`3XMM|JBZAPj}0Z9b-KtPxrdC=4l9VM3UG^%jRX#{AZh=h*i-y-fzo03%CLF5}Ogx zgUl3SA2bLx_YJ9K2T%6AlBwyqdR4c4B7&?{ihre-s07AoE@SWrxvs zUsqxMuaMCAF@i;+c*5!o&DJb#`1lII^_`pwUNg_S>4~H{6q8*2$AIY>70RP&^FCC7^ zVeY1s-HgyO;i1y~w8WH&q1|gr9M(97Ku{tQx>@F%r{`L7*UG0|J5|bN#as5#@JGDn z^8;C&b25xOMw1gXv%_2v4mqAh0Tj|?sNp$_y;*>9DQ%m6@Kou<$4BEJD!1M7V4}`w z9Hf#a2@0@Sfs7QwI1B5^TZI9;4VZ`_?0S9P1JIRB?BkQeu(L9r@%)CwyDz!iO6~7Y z6dVx7CJ43JIdu5QI6;6pYP9LkdeGICjmN5k!Rr?8`|}-SJIRvgrVyt$Z_Yi2QV zU9jh@r?&p`3{Q}ayfou(B_KAh+>;oQjX}X8N;byD*Ns{@aJ;<6^>CLBWGwIck z9Ao3g#i7QDpF8*ok^uihx6a!O<~;V8mh?=KE8ID1ch=6^u&6aOTNDN1j8$DOsWA$S zcjDwy$uO^1yoY?vd+QtjR_RCTJO9eJI-ER4O?$K1hv!1R(iQTau@2N}l3xbSKW*JGZieulc4=$|_&vD%c*PiP=^3U_)gI)hXvkjM5^^Q$%5w#+R%?SO!_$U4Qv{&&MgJfek3Yq<;L~Rkf!ua>Aw^ZE-Fa+Z z^4HRqq5c<5!u6xY{-)jr&a5lV)Cpjxg1vKRMcIb7-zVPKqX;Z_0tI83lpRH&!}_rZ zSsik+NtvlmvHuM&x0)L`^Bemr6?wDG%oS|F5#EqyPw6h>0^fQEo@k6L3FmDAJGnfe zbxnuxz7S)yO59#^@8SnS@mz}=N7dub3CgLYgiJDbd88$gIEL#tmeo@+wK+?|Ep=zy z?r&pqo`?4IUog?ddV6&HaXoT?>Hi)}r~dJkx5APbxHoD3zVD7_7FJaHo}y06n4OCT z8&LxJtuF#ST%Dgih|W9YPv`1>A3wVEK{}l*|LA5GA#vozo83G(jL)M-MC$orwueHN z#5nZqWD|5_A#lk&A2tl9$&+fPTMs>Q>C-j|>r84Klk%!Sh_&5dFIE|!NO2dcJwDP=Kl${StY&Rc}sBnlxkQ>KPv77J&|gCc?Qk+85OfQf!^2{-ob4Zuc|9H+5vg zk03=AwNmI{lc@j&s2Hlaf1c3x=)OcZ`ZR3ft+G$acNOu`TjQPle3($dRk)O<)q;QS z&ppl`;PDzC&tyL{g>xz-YYET%q>~AFiDnU2w7jWq*c8B|6?^hUpM1zxqLe};-!lGv zi2r3*RJqf*60H8$n#Z$-59yT$y-q>1U|M4ymlw57?sBUFpKsdfeDt}nhiluv@Ez+$ zFW3C3`oO+Wx@L};+Y=S*KU~ObO1K6kePK>m8PV(AVH%Q=Oq}z7=`(%TN`KJ|Skagc z|D3KQMM%qDw8>V+ieoKpcywp;wb-dhm98?hzV239n)~*2F2JjPS3bw zSPXDxf?ah-~@iXE{GpBcW#?rIO=)|~V5a_2RKhn|rggT9)(1Yee< zF?-cftbX+Q!XD{kLL&Al<3R%!v}Nl8A!s;g$3r}?_DI8}CjYXz3X-j;U*8n#6u9{< zg*YBZ{|i6>{P6(inhGkxFde@BEm3#6)=(~(XXqKrD?}$?UW^{DOI3F7qMAS}mSOTr z@GfLNM$J*v%<&QUA_oO{T|MpE&&nSuz7D$ZX-Ep!dEg!jIG^(Y$GR6QDBj;@)I!}3 zbgzuhY#nsRuT}OZ$M)^=A`E7f>CFVkiZ-(5ICYMx4~Ly8nrcTJzxp$`y1CCjQ?&Z2O|bT$zmFZ~2bQDkC7rhQPtOVKf%4X@ZN_NT*>(ac z=JL>oJ{$#A?x$xm`WM2Nvqu%BnR1;cBA@O{G^^S`?wl|nGD35t?G5}3ITBm7+4<>A zzxIA325_(~;6CEyTUkws`)ktmnGf@ab%(L{gtcAwsXL<*ZD&g3g8zM1&|B!5`7sO; zn+E~=5eq>ABG<$%9vyMJkz+ZFKVAES5S#+|pfnCX&@W!d<>^STBkeo-cn7TffH2eVp5{|8S= z1w7(GyYue@W)>&_)(Hv_AK8NfT<+VUxyx3oHqt6yxVzzf!2p_70}wG<23(>5`5zk8 z*l#fFs0df@y)QHu44*kf)^~q*KVza*kwOHu+%vs#58>2&O=?E(5Pchwr(CS^v_~$* zZatM6zsI1`3cs4nq_Ed(qeQjf&ti}_iL+NB=Fvx8@Zm)%OGUVphG%%UMKa+VShU zYf-x)bmtoFBV)wyRWaXgCfEy0?DexUMaYLWCsBH*jhxdM4Wef z-d%|VmqT`2eQ42{P+%+C{z=AeT^_xkF8VPIpTCjbeEbnY>{+2ZYj04~6tY!Mpp1E1 zDUCBzRhUyR_z&vq-zYHjH&70^mX)?P<^O2O8hflQv1l+*(V5~U3pGMbzupRXCgGWi zT!vg2R(xw;OM{&8cupeQc_0^$xb`#u4u2?nj*nrWZl?+$OdyWXv6Mr6Xqj2{{n zJhlB=Z~SOfo{hfow$%d#pxR`FR!hBx}CP=K22(9JkRklF{} z>BJM;q0mH!sSDc32o-lW*r%P--rMcL@5DV$SIVhWi*%~QFA>=0>fG_&J>nJ<&~hG*)#<)=6SnKu&8N4%X~Mr;+wFWsx>9gQ~rAnvH1Q}5wz zV!e=lA-j>=7{P^a&78HM_m#e~?M3lg)cI#N~c2V!N!v+_99gA?fvKJ3%ir#qGdMT=#nv$G6#{eddH-yO^}rV{}Vu{L)ZzB0L$ zu3~&n`C~G8uzix|Q$Nc2@~J3M3IDM5p|{VXY4_yk7;24;@X;Y^9ICbZjo?-GiBz3& z#NwArX_l@$8*Ts-q^My;?42j|;r^(!pk@}Qgtbd(8!hqMpN*-aY$=Ba&HLl0=hOoNrg=5}S)&u-RBJ zF8AFYIF4>uPGna>5Q%qx-a!iLG3)zlw1MWSe9)_l_*nQ?F%+OrFXF;#U!5*lhRqui z(!NE8HjX!FtDHxok2cA5{#i2+^SE6R@4OAyqe-vGTQS7p3DMtZuZqm}Pas^i;&~ef zI*Y6gs#7Kuz&iJV_{&?qBnXYJtEy=<$H9_M78mTLgxXQGo6r#Z_#(&q-Biy|4|C0!6`L|t-) z=_ih)pbZgl5TVRFi6Ft?QLTNWG`8F|HFqbr7M?5m#oX|89|CeF;$BUyMXC$oU9(3~ zMrH@M+~tOLY($JK_HW&HQGl1gXg810aajuJ*LV$GlanrQAAceJH&IRB)+(v8EiD|H zO@ZqXSyHn#rXD@&k3;TToaAZ68XDsYGKK>*jPuDvL8ln|h6%PtuSl!dsy{r$Adx$* zkMX>5$?p7B16}CND?HSe#U4*FudOxAT`GuaxYA|JbmfPCG;Qh1i7g920ca+4HvRSe zu$5kP%klo?DLGzLm2SZe`fTcgXXgdQijB4jL}hO(I*^ zQGoGy{jT%>hiaaZba|~wTXvqlxYNk= zy80Y-d6q}7gm`4UAAbl^f16OvU&3HmgXRR7U;GOo`U@Ok?gAID->Nx$Ua(Jl$>&r2 zgYN7Ba{@%`W)}P3gB=V1Rex?%%?-lTbumVc9Aj#BOr-Y+`7i%3g^)GHTFBpNC!Ukc zmb$LA?3x;<`kwSFz)cV?nvV|9|0aCc=h`nA_mZ9NqC)dNk0;+DQgk9W`QZw|o#RWiis55JzsruVfogT(i6Y*bsbKw z%M{1_r+yFj;l60lXsb=j?-Rzxr#l`|3y9(mqSCSH&%?lZR&iitIZx;1;;`f;w*O|% zSV3rmE!7hAHKLXxUTgd6y>pOdjP&*+X(uf+>$v=Vg)Vb~GtLX>*PlyOC%*^R6<+UE zDFt;fgvBHi`4K!zP9BdXVD~489=(&cHNqVi5n|eMV=^CSO?#C$^KO-+17E{fWs~}x zkmwEN_nd=;G{s><;ssEBdaeJ7hRxC|ftKi}?Baa|Y?YY=8U`8h$G>-KE*AA0qv=$C zxSYRp%^UEG_-wsY!4Yltil8TaVDx>&Xgc?BC^jL#DP0yLNmzqV6zN_DxZbG|s;Vg8z!R~PBBHg?NT0hUi!U9vFC7yc7O>|!I z_&%~TaHF;TVmBKRYX)1dxOrfVuC;ByU^Yv}wy_$lZCsA+=P?^p7u9W<%pd(`E7^HN zwQW$eS+81RR()pz*K@%0^@Y(le(tk{0Ix!dM&wy?o%+VFV>?^YY6boyTqT39U=MP% zR=0!Bc1tvqMjmT{wHApLfhB3Tl<2Cb_{r|}D|97G&aew(HD9oCM>|%FmT(uhV-g;yrFH zX{1~GtPAX)%|)07xxuqH#4+C+A?2eOzLn!_nkBPULO0cC?9O?56S=zhF_W=EL0yFi zuHmTMV{Uf^pFBt;TAbQP-|wi~Qf|Fis?UiNsD6J!bZ7AI22TFCD%V$qhFq0CY%Q@( z(;Yq^G<5AD<{a&I~Z`$JI5Tsz3bXdp=}2$#t`cn2oM(8NwM~b}X8hJUfd* z^kJ}+gp?QsaUhg5tD#R@zeO00^#(}XU<#Q(qT38cdfCOX=(ZdmZDG#-qPrRGn*Y%Z zMc_L#DAc>)7q=10KsWaw^2XkoJ!MIJuDRPGYP{zO9WEDpoHo7u*}OmBSGsMheG_(& zmweMUDIEL6)YQ;q?zc52i^^4Go@SDH<<C#+F&@mS)o`#ca6s>e9k?^Re zk2>Ymke3J8&dZ}nouzm(wewj9=~?`A6%cPZwlf#gJvoQ50v*=%=v5ayJX&N+0f*;l zrcvn6mR(+)Q5Ttd+UiWK*H7{B7$&FN{+vtU-u%&vyIG)_r#IfBPTrQ2=3e4QKlgrn z@gT0qQY!<4lh6dR*;VJQmjkyE?w}C~fUFp5B8N@+y2>6bc{Yt0x8iqYo7WCccXvK| z6wXXr?>u(|D2Xh+&$MeISs89f$8@Q+xB_Hr&f(mpO7*5yPS0guSzPd8`X=P zD{*m8Jm^Z5cJ51nkfL|x5GXhQWVB|=6aCwBe`Cqk+f&ly;Q z4wGIQaW$oO#HhB@N~`^iTq4~V3Ah~%jUN6f<93zx8rlooF5VT4Hu*-Q_*i-nCW_8WmdqY5Sm~OVGD`Zmc8EI zE%wt?XrO80w8W@#OCo-XE-K=@xKnM~pQ~~IZDC3)KPF;iy|E1 zTMgHt`2nKvtbR4QVfb3~ovB7H%MpGf{0jdmqtU+W)HbzD_K#>OokHy*b^EKEJ!?;q z4x^s;RtKU+#y4kZgUIu7modnWd@4aen)9)QIE~7QWt0-nR2dg9e}Fg9Cj#BM?+Ml^ zLQ&0?ogvgLGcK9SeOObU`f=YU)&qQ|%RJtKusq-T8Ex6kxKX{9_=I!XL%p8ITxlPC zUiR4HA{JvGon6R!PCQ&hXy=-_RCzS9`JIlwRow+i3Oy;?$aLnT^{kq)y&KvOvRY7H zKV{tmF3a|6zQ#+l&DO8q-LllP;T(b-YM0(;`cp3-JbcW#>o_I#5__b8GscdaY}ejL zC=5^XJgc|uDCqh3ATg$BaD*`Kmt2gOQ~)B?Eq@ZY5L~j$U-zhT*;X`q*G6Btfkb6q z$Nd%68|mt$S+H5Am{>{c{I*V7V%0qL|3Mj73u-Fjp8#o=Kai0q1DsWkK>+_5bTv$0Hy>Gk*pDUB^ZdvCjOACfm2;_ zcU#r;A}$8`O?v;k9vP0Q7WtyK!&bTVg2ar##14jzcSL!99RD7Z`IdlmA-^Ttw?4oi z_uj^kJqIH-a8pyQh#hi*QU#~Sc+^a=H!&Y43@37OUKH|!XvuaXZ>>Kl|4rjCa z@Ac8Sm2&+W5Cgc>xZ$Ls3yHv*&wsGD5owk^AC+UPppEkkw@4G4Ak%vK;ZI+z&5ykK z(Z_vR?xI*EKamDyT+x$*R7!zkPPf`8Um}E;8hL*A=nK|HhIQ&TJU937`yS=Ck(2gB z<|rdE15=@cgx?$o6N`i18a5QRBeHctU&792OLpv>NUb5e7$-PT##q-4&?bpn0((F@ z3zw9GUcRyjFiDJZR?t`CZjj2j5W0St#1I0@*ObC{l=@yOfMNfwWZ_dd4L1qrwt%#( zOe=>SGvB)?Fw+`l$Fa`W7Y%OsOR)YNK@WkqZGA7RmBG9b?hMGTg~nxX>VoD6*vjLi zSc$W%gk*8bC=hrDg1@ScyAM53X!N*%wNC!wlYo}+zs-F?iPwo1@~J0OPczx zbT!v}ySZk_DU5w1v)XJibxK-iH4G8PT3DWV^8Q4VAGW1)9dPWMokxum3N+f?* zt364Hgb;9IkTnQk$$n{j$-b7|)ylOV)^*5;zu%Cc-1p7PCB~lJp=EdR7kvO3#-hID zcl3F;{SD9^nkX3m*u?q2RM`)%Qk>+(Zh*e%PBI@)JiKW-H#DO#$dB0Rdi#pTET>H; z*WD?>y-qrIPhD~o6Yb(BU@w?skEz8jcdBc)*)_3>sHpB5$v1V}6D2malbNHTjH&Cf zqz9`6zFHh%8tv(R(L=65PJ?1sQkX^yDcN2HAoYUPAE5`Bbqc+*7fiRr!=|vX(8N9o zqy6#6X~$pLM&uknVrDi<8xW0>r?1758N(A6fDhrFvia~t%|9X@)sC!;=Y#Ty@RIZ$ zlfzx4r3FV}n^~;G8IvO>IK!iVUst&B&%&pohp&pUz9_vJbOt8d9yUo|C3@Nkb6Eyi z9Qhv-z40d2xgrjF{L0eJ)lKm8_(wG&3Y(Ppq9-eg^>NrTx$Za!?63Z0?N4~^qoXL4 zzpJ=!2t`xzO9d$^L7HzSFFRcAv=yg&b-5iFW71lHPhDfWJuye0ZBln_vYyhFipq^hdU2LJ-RzrvF%sN06EEu|z%~;xPBBQ*imTbS z8cAYnLYy`IFxtxQ6LUZSJ>||dc;H^8$XVS3vTdyDr|_>Fj{%yT$$|>r@3u}WSOoR4Rilsn-X)^eMVqx z_+zCm3KD%A3Q;&-sr2Re4zd<3h-^_pCU5w?`o_(}Dt;$%odwEw#yGInzHZ&E-vJw0 z`;IUt^aQvhHM;oL0#hsvmb>pS3(EVE`;Cy$?2~ zsQ#(9`0$1{;Y8`SPud{+tykf@@TkQ)%Pd(cr0acd>j<{wkVe>edzEfW$|_Msf&w0- zhAw~*5@=P@UX9xqSl*X+4%y>U@Ycy(i?W0XjC6>4TXgjqGuF>j#)+-6~rnZFQSN_J3e1q6474c;0rYMh!oaco_ z>gqP85-~*b=M$sK@JMJ6Yj)Q}MTC@)LFvr4XdykWt5gwVU|ub(uZzdqH1#SiHiXYx zxlju30cmpVf)4u)Z-B6^(zbSB8wsOYeUvF>Rhn>0OLT1wrkU_DjJ0-R3scCeU-X!WL3>k~li= zOI@bey?Kvm7?|X;^W2d#5_a263B1BtwmejW9qJ(O!% zO8QP{|H_3s1&K59%&9-!VA{Ni({EF@`cim*LH~E5c}>h>w-Mr+B63!9Vx5Ab+nfG# zBO~nuDjgJ^xc$W%t-0B%PVv>0sjj}Aw9l()sf$w~7#EpQL>K$%Ma-Sb zY}}&b0UPTl+$ulET!t?CRF9evyjqq(6x2!RPjJcuWU&}z=?~8YTD8~t z`eGRnk_M%vr=bP8?1-)ke{(Hlm*3Xm+~z{HY{rEzOKNN{M}wV`n*ukXAyGxxrAXWpOrF@Milr*@rMXVtD#-&fz> zSEVVx_b7TE9BmK|b-3G>{cx+{T$?j*|RJ)-^?P%!v+|5d#istEAszkpyk zI3v9GMJq}sKGrV_$vvBl}PaYQx{GvQeP-MLOsS6ypw^Brg0%bxi<;A ziHrok{pIln7k2=-UwO^$aUX5Oi|XwuIXn;?Z0Y?QmcII2v^;X&|1v{{y?0^CsA!q! zff5*0-IzlDc?0g$FY&RB>M~IsMcArL_P!x@L$%sdKDKVY{ZXYb>V*h4B0%NJ9P?}h zrGBgOmr{9cGMmH&KYN6qD)03O_)c-e$)wGr~YRq>z6Vsu1HeXKv%B}%Mm-* zoP&McK_F*OBoWQ(t;Xv`r8A2vetv6P1BX8^KL4Q{z@m{nQIpFt+wxKy5q{nJcoMrY zD`7r8K-?S?;JPDWi7d9EnQnFCnqL~+;-s@3V;2>@EHx6;4_g_aA9H!Iu6u>a)aS+M zK_N~;t@Y(cJ90ZO{ez--zNqF^)558}xHG@EW@DC_2WxC`Mob#@90FfEz(dn&ld~(+ z{@!JxT%3aH*w*LjFg*_3t8-*W2tK~>0sjjZEA=ptBk7Se8h}lS0u&oifZ{*#^R)?& zRrsyN2gZLfGF;2RmO;pov2b5VvAlorB3cu5vbpJaayVz_6-Aq@?dzMSI~3O5&U5YH z;_`Ekc&y^u(7F3mh{3M;_FZs7+%Z}#sQ(@E=R;a0-gW&Q&%MaWRE_c60yxY~d(b9E zQa)v8Iv>pYa8{SA2e@CzZ_hZ9KQudGgjmtaOxGD&^L>#vxACI(qva&J$8E$Ln}=># zluxA~R+R>E=^P@rvE;5WqzC|BFDUjqkfR;XI(DU}{ErX8_lE9L^bc{5Jl6bX>fs9G zNr3J33k!)0>L?FL<)k3m*@zn>!9CjgN`&{$B{-zcs~#^DFw_|uNddaa9>W!tgot(y zR@SsLeCcB#nkWoA=+i^&M7%IEf@9nXV%(DAxHH@s+~VHq!B@ zn%$`NTmoW=QkTZ37xD(E$7jmipY_9th_m4y5%#Vx^?x+v;Uu7)FSo|^Xd%KnO068z zR@2`)KWU~Rmr$0RI?;tTTf*AhKf-5&^J87ICv^-Ybiqewal_-DZF+q8n- z0ZK-0b7~Unteci_$Z4m&HVb=-{c%b{*R0h-T}UZFveEX@&1h_G1;&48G2?6ID9l42*c{&CaD*L$) zZ!fpH)X(eyLev5+KL;(Nu!Vq1_7kC(Z^Vud9u+v(SyL*O!x+PTS&FXTZ&e=cKu<&> z&$_sqCkERV3ZN{3857Vjh}8ChdTZkC>8IgY!dH#AoUxJOxJvqNQF!)&6rQ*R(SDqL ztCbAvGQwW_oa}0YSh0)BzG0Muhr;!_mXKpaA^@&P>w)vOD@R=X_MehgGZ z)p;`aoRdp>g?*S!p%zb^-mLO5G#1rgB=(%vFEz%zYKsoWOGrpsUg-XpnRnI>ujR`*|3{R_a&I98uTaH}khAX-(qf&^F;(8IaNdHkHE`^zOAxE91=HcOF*lH2${hege#DcO$T9KPu>D?I2xr#0~wkm~hu zIDGOUZl>Mq;l~%ib;~-WCvaU7H4^bIX!h`xKB6fh_(;9y{6qgRaIZPY=eGh+IpR}O zB%p6b6U02SP-ls0r==-hyIr7=4awDP!6i znN#1kB;cx)W5@I&BfJ|m%ROLB;=jv{Qp(r^Uq^!fi!q8TS@|85lD6Em(MQ zL-c%v?og^$_1fW)25+7B;b|Sw-2)0#B$2=8r|L1j#Y1U`+(I6ox38z{!%;Bmj~u}a zzhw=JsPIW<{F~tYdjz#;k?*Fz0X_hsyMH5%>Lo_;uJ?wb9yMElbF1amFhMG4>y z{0le{I$l|5X3Uf@UJ&z0x9zett}FV;{@pb9+k@3u`RBid5{^(Uv^eU{^bPZ%04Q`nX76As=)Vo65aJmIdxVy+i2Cz($4F zAiUtL3%pk@b5Q~zzJjkaZrR|T_I4YM z4H=-k1R2(ZDhm^DVtEXWWU$7Mxe=hS?+Vf3NhM2*zrB^N!zJS%AC1$;G57`#neN1F z07zcqi{`ls`7&kZuIAE_S4S6bct%{nXobUZIZyk_rY$k%jcLyj&&mI1F|?9btv7W8voQLe5|(Xk9{9n@M%E8ugC{zWKiVGx5FE0U*y z6RR1N6fG`|<|4d{AJD<47N75oN>Q0E?mk`btYCwP!bqMi`y-RcOI9ZV?yMh(p;j6% zLia|KBixumle1a-(S!{{y`A1>`vi}|Rz8F7w-dCMs)?bW@Tqe&5Pi5v$g(8oAzk!= z)GSKlg5@uOO)IW`KldCPMMz7opwc-pj%@$)sRkNBE8m!61Fn9rt1epfoZX@MaErX` zB{i3n7B#ooBN>=@@jB&7wsulo!jM&Ka#44%UfYK&w9`K`;1}VCu)SDClTAyD%eD`X zfs8l&b$*o^sGKGLs9f$u#UOH`u4Ay$zc#Y_r)LJ~#lsp=r&V#d8BfOxXI-@eH?e@& zDP0}Nu4CkG4C!G@m+2{EDm$R+hGzFKzy>8TLh=`o1eAwgKyESoH-~0PN<5*x@dm7w z7Ia$GhLrL0rd-iTM5|`pvETaT2|bMQK*NmD`$uYzp}QuON?3R%x>lYn-FCZo-mAyI zg*mdnp2pzFaŷU&HG*){$*OXRNjzCMwRo2T?6Fi-Kpv8Q3FOSN_O;%`-IaeuET z^hP+=oGv!JVBD>eM5*=j|iS-wveut&W&1^+(o*#@@#LchY1F*i@IfD15Yf;=(?LThe>&ImC*Vc0? zE>=G7%KW41(-i3+zj`R_xNvl0IAvu;KQTDQQ)!FX+LkbR91{zE#l7xh%kb(_3$+85 zCOnQp_kgHmiX)WA{+O+w175DwoRVVk{L+2GU6FV}bHo<#D#q!q)VJ8bEivzUmDH&>no_GA1lZ7%#)kcn`Ty-T@&$o))kNio;mE{#O(rt-wR3Wq4rJk!qy4g7wp zRwr%|xk_j~cF&cKH)Io6W8Gn4Pyo3!t$W9GHmoy>Sm%Q%TSo6h8fz5K*<=G5w4Lt6 z_SGBw*Iw2?sk&qFKhc2QiCSZzqloadAojzUu}4Xx{tC}y*e$_QeNmGj-1Q2bO*UN& zi;MqVBHxeq8(BQslCoz0-9x$+i2SNQLU@fku5j2#VVY{F4WD=uRu--e9;Djff}uDg zZXTw(NPV3%9Pa}cK}isOV4R1en)?ze*5uJ7|0A|#b8ZltJ$K<-yFbvjmWGZxo2d-! zsb7vSBWUO-u^8Lm1K2C+w9Nn8P$KJA-n1PiHP!z^@}D+o*{94v}H@FBI-BgIEm$y}Um^9KH+IXMkWG9{4>={tF06nJSfts}-s6 zZ&O#flUQyN_m%(L1U}n$`NzjsEOWxB&{dJ;qX9gsi(GT8?V^?aP8RSjI%&-x|!0FAG93 zP4;M{`2l_WejF8}ku$HE3 z&71F|%{e_D&p-o%bU}nb)Nl16Ih+wpQBJ( zO_m&>O|ijg=u>hs$hBs$1%__9qy-ro|(2LU-d_vFz z6(*7(UXaHQFrY2<_YIr;{VJk=h-}#Iu6fJbqr4uO`V~?Cz_vfB0TtGwB88?*Hdlvk ze~TE^grd=Yr>nsCJHqbvk9Dbw@tV&`c5_n5^ZAbwHcxhSK=fbA6fu+}w zzSAY^qFJqZD<{vSep+kNn?&AY{+3R3p{MZySmKU~08NAOcMmEA+Fe)A!deOQ-0WCM zjr|J64TozX)OOvxT*Q$q)T(ldboZ#7d5)Biw&)mnY;q8)OKCtF)EFql2zTLp;-m^r z+oT~Fh)04jQB~4C_c{A#{>h?Z#=C{L}S&G91E3V z9=xn+j%KQdFY1>}vy+thu0aV}hO+YDbS9B#V17RcOuIpyRfIthI_YrCEZi{mVgbwT zbm>igHEry+Ou`twi=Gq(GN;n6c$r41?yQ2#vOY+s=fQ?)=X{f{tWAIU@IOp>f$k*GG;-$LHDKA(s(9s_nF=hC{+6Na_2#ilxFrhUy ziw7)%*txv?z;bP^$hgbO`xmz=$t8R*x(PnlL7sn=kw_x$2H_+SPGfvIbV4 z4%TjLxA8Qc%xgO{_q$>qq4?oBf6>iCxQ59HR&eOzm&R?OL66O)CZIitl4jLIMDbI0SkUtKOUH6nlX zhyJQ#pV(>o`u)z80H+qJ&D!*O8;6i0jVRut`s(#SfGk|`Atz1$-c$XZ{-Q{RjJn@ z6mVh09E2sXcy$GDahIxrw7>kd2XDfbpo0&K*A{aOD~r4T*3a53LOhq~4Et>4HQLJjNOCaO>2ONFr;p7D*L>sBaU{G}M~TmCJ7Lr7JPF zVo9-jw&9v(#}kVsGi>eooz`%8f%oZk?z>srI)oU8zUTd=(xltVFpSSUBxdsojWnz= zV{dRo2UMq5?xiN&{HR{rfpr=q*JZPp*%YHQ)nZrEIkIt>oF?hTv}I+1@!NB#Z1D9T z^gM|>8RUya@3Teg53-kdiphu14J-P|B<9VkeX1@%#|cSBj3HuzlpnF(fUD!*bPTf+ ztA8p45`jg21MyGp&-MgAG#MOj+TA}bTBwI6xjB|Oa3sk8KKp26B`x6+Y+bNBqHBe0 z801>3G5mCJII~}lPW_xK@t0bEYqddDj|oD;B{l$US3}Kl$5Lpm5=S=Q*l_=)?-kW- z;M++Fj;5Z8cMF=*cr7DL8+YGNogqL|rMR0RGuM*({XhJV@P z$wrYV-rhON*e6Jcpe*tzkT5>gd5M+luttGzMIfbrRcEH2T>ZuVe-b!!#KI#U$9_UA zYznQZ4y>w-Q~)YfR9#Q-yRs1C5vq=o*WaxS;9=ONE1NwDH?fA7(e`Fjx!$l7qOaNt z)6CVBF3T!n?8*4dG6Dh!Mu94|$-MhJt%{funV(kG#+?<_zq2q8x>#Zhrd5bd)>_W}ZzKLo@ zG$`QG(|YgJK%FA(u6hoDmXW6U)+(maiw06Xulx(rgF@I{g!#k?y)%lv)+^Bo(1G>i zcAE_yK}$xUM2fT#MafEH^DCvpUw%v-Bd4K|cQ= zb;dg<-RY8pUB|2?BG2Fi*Stsetm}RV5cXp`7kl! zgs(6!iQ`4SQ8J&?`191p2=7EH+p6rfnIM%OqAFrZ9-VuNc@qld=naHBIR}e^c@!jH zhNhYow4HqU*39K`x-j;le8S)x?d#mD=9B5dSrQmS@)!3p z`nHWveB9=VTjk06+rPh@P+N%L<6jjGmhN4ll)yV`j?Q)1eK0a~E^sul=7+7Ux8xMr zAEjjMZ=^d{H-tv_p^p?DCv4dzDnEvUhG9 zA}K5(>-;|om#U7=sHoXRZ7u1pD0bkr_h95>t#HmVZH;~u9@f;AtaX}dK$WV0`&;wC z-QYi3JCXOsc58Rzc0yT63D&dfd^sH5eZ^Q0W)+aC{BG+z7He+a_fZc( z0~+crzcf{x+I}fbM2oJO5O73I?AQBT&rjvq&b`x`qI+3m$w*tkw4&ZiRkF{;Mj3^r)F`g3o+Ir~NJ^^7RvoI9Q6vV>T znip$jDMMa-O&JJvz0t{&jib5irTFI2odB=gHzJy>tgNVfk+CW{6~hwB0{9jvx-qc? z7SM%5V0L)#TgeKc0?&sGpC{QT`ApovcgqXX0JC@4+hw{cUYq^S=wuI z$>Mau>gGTu^^?s@lb;Gl0Ksbuq~A(ZZ)mH#_Ol*5?%!!uBRJa8!iNmhsYdPL6HR4| zVWdX${MS($$wy?is)G1&4HVJxRogGL1^}n6-WmI?;5BhOst@`tJ_n^tVW5qMhIqCC zj0x66lTdu;0ixmeVz_AYw!kh2`P7V(I!f6NvOC8pd%ePmRyw~Fxhy$a^QuqL z!p#jN3FCxLeX2V|e6OvKota?`qyEPEJo+g^(2xB13ew%p&Q=f zk$9S4e=}vf-8OmrPP*N%r4$r?Bs{C7GS|uOz(n*~i?@zI@3PO1=eUR4t=OO&X@K+V zkAXrgwnH{HfaE14|IVrI(1OQxm_oa!;z6$b{u zD#3DH@3sHhE}Vu*zr-@E56GJQ;-;GH?fAfJYW|l&;7mFMAPDf}SAJAndRA|LFxPgq z4+LSTOS)#RKT(r+XA+;dY{H>ImdGEdK!*+h=%&ie@C@ELL=>vTv}096iCgU^vxoOL zFrxVrR!UHyD;1RhC_;kZd#{az+)LIJyJ&l3t7Jo3M>p{=9~zHV%_ISIYBp<%bpz`v zj0UZt+^N6of_8E88lo>W)#@{=p3XM}1_l~Rk{f{1dslqL#xLZWT4vaCHZ+<)Syh@! zsda^Pt7*rVZ6!8tp1yas`S=^AHNKBmvM-YQtQRi7CC`26xJBh?kKt587uz^uuOQ>`p~~55tj$n8%G|6ntqpYaVX+S&>s^w@Op8@ nW!q`LkR#1X31UxSZ?hVgHbjjoO9%abd2-DE{X`q0zw`eA#a9h! literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css b/docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css new file mode 100644 index 00000000..b4daab91 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css @@ -0,0 +1,23 @@ +body { font: 12pt "Times New Roman"; + margin-left: 5mm; + margin-right: 5mm; + text-align: justify; + background: #ffffff; + color: #000000 } +h1 { font: bold 24pt Arial, Helvetica } +h2 { font: bold italic 18pt Arial, Helvetica } +.subheading { font: bold 16pt Arial, Helvetica } +:link {color: blue; + text-decoration: none; } +:visited {color: purple; + text-decoration: none; } +h6 { font: 10pt "Times New Roman" } +.MsoToc2 { font: bold small-caps 12pt "Times New Roman" } +.MsoTitle { text-align:center; + font: bold 24pt "BankGothic Md BT"; + letter-spacing:2.5pt } +.heading { font: italic 10pt "Times New Roman" } +.subcontents { font: 10pt "Times New Roman" } +.tip { font: 10pt "Comic Sans MS" } +.type { font: 10pt "Courier New" } +.menu { font: 10pt Arial, Helvetica } \ No newline at end of file diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html new file mode 100644 index 00000000..0d72ce1f --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html @@ -0,0 +1,113 @@ + + + + + + +Design Tips and Suggestions + + + + + +

Design Tips and Suggestions

+
+
+ + + + +
  +
+
+

· The skull + generator in Harvester tosses skulls about it to a maximum distance + of 96 units. The id map designers usually allowed for a drop radius + of 104 to 128 units as a minimum. As a rule, the generator should + drop skulls only in a places accessible to the players. Skulls + should not drop out into death fog or the void.

+

· Where you place + the persistent team power-ups is really more a matter of personal + style than a fixed requirement. Generally speaking, we found having + all or most of them in easy view of the initial start positions was + a good thing. In some cases, we found that placing the scout in a + contested area made for interesting game challenges.

+

· It is not + necessary to put every team power-up on every map. If a team + power-up would be overpowering on a map, leave it out. If you study + the id team maps, you’ll note that not every map has every power + up. In a small map, the scout can be unreasonable. In a map where + the base is easily attacked and overwhelmed, the guard can unbalance + things. In a map where the base is easily defended by snipers, the + doubler is powerful.

+

· For One Flag CTF, + the flag should be placed in an area that is roughly equidistant + from both bases and can be easily reached by players from either + team.

+

· The same (as + above) is true for Harvester.

+

· You don’t have + to place the white flag and the Harvester skull generator in the + same place in the map.

+

· Don’t feel + obligated to put the CTF flag bases, the skull receptacles, and the + Overload skull obelisk in the exact same location in the bases. Just + remember to mark gametypes correctly.

+

· Don’t include a + kamikaze in a map where players are unlikely to ever see the full + effect of the explosion.

+

· The personal + teleporter entity takes the player to a deathmatch spawn. That’s + how we restricted where the player teleported to in some maps.

+

· When converting + Q3A CTF maps with small base areas around their flags will probably + need to have their bases enlarged to accommodate the Overload skull + obelisk.

+

· OVERLOAD: When + designing the base for the placement of the skull obelisk, don’t + make it easy for attackers to shoot the obelisk from protected + locations.

+

· FLOOR ARROWS: The + graphic arrows were added to map floors to help the players find + their ways through potentially confusing arenas and to give the + player a sense of how close to the flag room he or she might be. The + rule of thumb was that the greater the distance to the flag, the + more stripes or bars would follow the arrow. Exact style of arrow + use varied from mapper to mapper. Study the individual maps to + determine which works best for your own map. The floor arrows act + like decals (if you ever built plastic model kits, these are the + little graphic things that you soaked in water and then stuck on the + surfaces of the model). The images will appear to be a part of the + surface upon which they rest. For the arrows, you will want to build + them as nodraw brushes of the proper dimension with a surface raised + about 2 units above the floor or wall. For the arrow, use + missionpack/proto2/bluea_dcl for the blue arrows and missionpack/proto2/reda_dcl + for the red. You may have to scale and rotate the texture to get + what you want. For more than three trailing bars, add additional + decals and arrange to suit.

+
+
+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + Map Converter's Checklist
+
+ -9-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html new file mode 100644 index 00000000..03ed5879 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html @@ -0,0 +1,101 @@ + + + + + + +Design Tips and Suggestions + + + + + +

Map ConverterÂ’s Checklist

+
+
+ + + + +
  +

The following is a list of things to look for, do, or + be aware of when converting a pre-existing CTF map to Q3:TA game types.

+
+
+

· New file name. Don’t + overwrite your old CTF map.

+

· If you want to + convert an existing Q3A CTF map to the team arena game types, it + would be good to make a clean break from Q3A. Give it a new file + name and even a new map name. We did the same for our original CTF + maps.

+

· If you don’t + already have one, build a central “neutral” area in keeping with + the style of the rest of the map. This is an important play area, + perhaps even more so than the bases. Make the opportunities for + gameplay here just as exciting as the flag bases.

+

· Fix-up Time. This is + your opportunity to fix all those things that players have been + telling you are wrong with your map (sticky spots, bad hallway + connections, misaligned textures, poor item placement). The id guys + did it, so can you. It’s also a good time to read or re-read the + Q3Radiant section on optimizing maps for bots (you may want to look + for the recent updates that accompany the bspc tool). Pay particular + attention to placement of clip brushes and cluster portals. If + players can’t reach an area of the map (such as sky above ceiling + grills, or beyond window bars, fill the unreachable space with clip + brush - just walling it off is often worse than doing nothing.

+

· Add Team Power-ups + in or near bases.

+

· Place .md3 powerup + pad bases beneath Power-ups

+

· Remove “ow” + marks from floors that were used as weapon locators. Replace them + with the base floor for that texture. You may also be able to + simplify the geometry.

+

· Place Weapon pad + markers (use the pfbs) beneath weapon spawns.

+

· Consider adding new + weapon types or replacing existing ones with the new weapons. Don’t + just do it because they are new, though. Make sure the weapon is + appropriate to the map. If you don’t like a weapon or it’s + effect on play, don’t add it to your map.

+

· Replace old Q3A CTF + banners with new Q3: TA banners. Use the banner prefabs (pfbs) for + ease of placement.

+

· Consider adding team + logos as decals (see FLOOR ARROWS above) to other parts of the map, + like walls and floors.

+

· Make sure that the + team logos on banners and floors; walls, etc. have the proper + facing. You should be able to properly read the word “red” or + “blue” on the placeholder logo.

+

· Add in the flag + bases and obelisks. Follow directions noted above (page 9) to mark them for + gameplay types.

+
+
+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + Related Links
+
+ -10-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html new file mode 100644 index 00000000..cae26324 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html @@ -0,0 +1,40 @@ + + + + + + +If you are already familiar with the tools and processes for making your +own + + + + +

 

+

 

+

If you are already familiar with the tools +and processes for making your own

+

Quake III Arena game maps, then this +document and the other files in this directory

+

are what you need to create Quake III: Team +Arena maps. If you have previously

+

created team play style maps (for Capture +the Flag or other game “mods”),

+

it will not be difficult to add the new game +entities and models.

+

If you think you might be interested in +making game maps, consider

+

stopping by the Level Editing forum at Quake3World

+

registering as a forum user and asking what +you need to do to

+

get started. From the Quake3World home page, +click

+

on the “Community” button, and then

+

select the “Level Editing” button.

+

 

+

Back - Table of Contents

+

-2-

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html new file mode 100644 index 00000000..44c6ec1e --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html @@ -0,0 +1,51 @@ + + + + + + +Related Links + + + + + +

Related Links

+
+ +
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ -11-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html new file mode 100644 index 00000000..89a7d629 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html @@ -0,0 +1,199 @@ + + + + + + +Design for all Team Arena Game Types + + + + + +

Design for All Team Arena Game Types

+
+
+ + + + +
      We + encourage designers to make their maps compatible with all “team” + style games. Team DM and Tournament are the exceptions here. Experience + shows that balanced CTF style maps do not make great (or even good) Team + DM maps. To do this, you will need to mark some of the team game + entities for multiple game types. An example is the obelisk used in + Overload. The entity is also used to mark the location of the + skull-receiving base in Harvester. If your Overload obelisk and your + Harvester base are to be in the same location give the entity a + key/value of “gametype/obelisk, harvester”. If you choose to place + the entities in different locations in each game type, you will need to + place separate entities and mark them appropriately. +

 

+
+

Placing Common Entities for all Game types

+
+

     Typically, the player + start, respawn, power-ups, ammo and weapon placement are the same for + each game type. It helps players if they donÂ’t have to remember a lot + of placement locations from game to game. But this doesnÂ’t have to be + the case. Use the gametype key to control placement if you want them + different between game types.

+

      Place + team_CTF_blueplayer entities in the locations where you want blue team + members to join the game and team_CTF_redplayer entities in the + locations where you want red team members to join the game. You should + place enough of these to accommodate the maximum number of players that + will be on a side (though usually no more than 8 to a side in a “normal” + map and as many as 32 in an extremely large terrain map). If you place + too few, teammates are likely to telefrag each other as they join the + game.

+

      Place + team_CTF_bluespawn entities in the locations where you want blue team + members to respawn when they die in the game. Place team_CTF_redspawn + entities in the locations where you want red team members to respawn + when they die in the game. You should place enough of these to + accommodate the maximum number of players that will be on a side (though + usually no more than 8 to a side).

+

      Place the four + persistent power-ups (guard, doubler, scout, and ammo_regen) in or near + the bases of each team. On the blue side, check the BLUETEAM spawn flag + box for each entity. On the red side, check the REDTEAM spawn flag box + for each entity. Place (and center) the appropriate spawn spot model + beneath each power-up (spawn.md3 on the blue side, spawn_red.md3 on the + red side).

+ +

 

+
+

Placing Game-type Specific Entities

+
+

      Each of the four + team-style game types has a set of associated entities that go with it, + whether itÂ’s the flags and bases in Capture the Flag, or the obelisk + in Overload.

+ +

Capture the Flag (required entities)

+
+

      This corresponds + to the cvar: “/g_gametype 4” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/ctf”

+

      Place a + team_CTF_blueflag in the blue base.

+

      Place a + team_CTF_redflag in the red base.

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. This forms the flag base. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. This + forms the flag base. Do not mark any gametype.

+ +

 

+ +

One Flag CTF (required entities)

+
+

      This corresponds + to the cvar: “/g_gametype 5” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/oneflag”

+

      Place a + team_CTF_blueflag in the blue base.

+

      Place a + team_CTF_redflag in the red base.

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. This forms the flag base. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. This + forms the flag base. Do not mark any gametype.

+

      Place a + team_neutralflag some place in the neutral area of the map, preferably + equidistant from both bases.

+ +

 

+ +

Overload (required entities)

+
+

     This corresponds to + the cvar: “/g_gametype 6” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/obelisk”

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. Do not + mark any gametype.

+ +

 

+ +

Harvester (required entities)

+
+

      This corresponds + to the cvar: “/g_gametype 7” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/harvester”

+

      Place a + team_blueobelisk in the blue base. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base. Do not mark any gametype.

+

      Place a + team_neutralobelisk some place in the neutral area of the map, + preferably equidistant from both bases.

+ +

 

+ +

Using Entities for All Gametypes

+
+

      This assumes + that the designer will use the same entities, in the same locations for + all gametypes. Mark the gametypes on each entity as noted:

+

      Place a + team_CTF_blueflag in the blue base.

+

      Gametype: ctf, oneflag

+

      Place a + team_CTF_redflag in the red base.

+

      Gametype: ctf, oneflag

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. This forms the flag base.

+

      Gametype: Do not mark + any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. This + forms the flag base.

+

      Gametype: Do not mark + any gametype.

+

      Place a + team_neutralobelisk some place in the neutral area of the map, + preferably equidistant from both bases.

+

      Gametype: harvester

+

      Place a + team_neutralflag some place in the neutral area of the map, preferably + equidistant from both bases.

+

      Gametype: oneflag

+

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + Design Tips
+
+ -8-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm new file mode 100644 index 00000000..536bfc7a --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm @@ -0,0 +1,77 @@ + + + + + + + +Table of Contents + + + + +

Table of Contents
+
(HTML Conversion by AstroCreep)

+
+ + + + + +
+

Title..........................1
+
+ +Preface..........................2
+
+ +Table of Contents..........................3
+
+ +Team Arena Entity Definitions..........................4
+
+ +Team Arena Prefabs..........................5
+
+ +Team Power-Up Bases..........................6
+
+ +Using the New Game Entities..........................7
+
+ +Design for All Team Arena Game Types...........................8
+
+ +Design Tips and Suggestions...........................9
+
+ +Map ConverterÂ’s Checklist.........................10
+
+Related Links.........................11
+

+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + T A Entity Definitions
+
+ -3-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html new file mode 100644 index 00000000..23682fa3 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html @@ -0,0 +1,66 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Team Arena Entity +Definitions

+
+ + + + +
The enclosed tadef_ptch.def + file a bare bones list of entity descriptions for use in the Q3Radiant + editor. You can paste it onto the end of your current def file (or better + yet, into a copy of that file). +

This is the Quake III: Team Arena entities definition + file patch (note that it is not the entire definition file). The Q3Radiant + editing tool uses this data to place game entities (ammo, weapons, + power-ups, etc.) in the game map and the game. It contains the definitions + for all the power-ups, game-specific items (like the Obelisks from + Harvester and Overload). To use these definitions, open the text file and + copy it. Now open the definitions file that you are currently using + (probably in Baseq3/Scripts) and paste the contents of your clipboard at + the end of the file. Now save this modified document as “teamarena.def” + in a folder in your Quake III Arena folder called Missionpack/scripts. + Open the Q3Radiant editor. Click on the File menu, and then select the “Project + Settings” entry. This brings up the Project Settings pop-up window. + Change the entitypath field so the pathname leads to the new definitions + file.

+

Example: If the field currently reads c:/quake3 or + g:/quake3/missionpack/scripts/*.def, change it to + c:/quake3/baseq3/scripts/teamarena.def

+ +

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ +  Team Arena Prefabs
+
+ -4-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html new file mode 100644 index 00000000..8aa53d50 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html @@ -0,0 +1,96 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Team Arena Prefabs

+
+ + + + +
There are eight prefabricated brush groups + in this folder. They are pre-built game components (using brushes and/or + curve patches) for some of the objects frequently used in Quake III: + Team Arena. The shader scripts and textures for these prefabs are + already a part of the Team Arena Mission Pack pak file and need not be + added separately. +

      The pads act like + decals (if you ever built plastic model kits, these are the little + graphic things that you soaked in water and then stuck on the surfaces + of the model). The images will appear to be a part of the surface upon + which they rest. For the pads, you will want to place them in such a way + that they are centered under the entity boxes above them. The surface of + the pad should be one to two units above the surface beneath them.

+

When positioning the banners, the banner brush should + not touch the surface behind it.

+ +

     armorpad_blue.pfb + Place this prefab beneath yellow and/or red armor on the blue teamÂ’s + side.

+ +

     armorpad_red.pfb Place + this prefab beneath yellow and/or red armor on the red teamÂ’s side

+ +

     armorpad_neutral.pfb + Place this prefab beneath yellow and/or red armor in neutral areas.

+ +

     weaponpad_blue.pfb + Place this prefab beneath weapons and (non persistent) power-ups on the + blue teamÂ’s side.

+ +

     weaponpad_red.pfb + Place this prefab beneath weapons and (non-persistent) power-ups on the + red teamÂ’s side.

+ +

     weaponpad_neutral.pfb + Place this prefab beneath weapons and (non-persistent) power-ups in the + mapÂ’s neutral areas (in between bases).

+ +

TA_banner_blue.pfb This + prefab is a smallish blue team flag with the placeholder blue team logo + placed over the flag surface as a decal. During game play, this logo + will change to show the logo selected by the blue team. Designers may + wish to scale the size or proportions of this banner to suit their + needs. Always make sure that the word “blue” on the logo reads + correctly. Otherwise, non-symmetrical team logos will appear backwards + on the banner.

+ +

TA_banner_red.pfb This + prefab is a red team flag with the placeholder red team logo placed over + the flag surface as a decal. During game play, this logo will change to + show the logo selected by the red team. Designers may wish to scale the + size or proportions of this banner to suit their needs. Always make sure + that the word “red” on the logo reads correctly. Otherwise, + non-symmetrical team logos will appear backwards on the banner.

+

 

+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+  Team Power-up Bases +

-5-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html new file mode 100644 index 00000000..349ad089 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html @@ -0,0 +1,62 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Team Power-up Bases

+
+
+ + + + +
In Quake III: Team Arena, a base model + marks the location of each of the four persistent Team Power-Ups (Ammo + Regen, Guard, Doubler, and Scout). These models are not generated + programmatically (as is the case with the obelisks and flag bases) and + must be placed in the game maps by the mapmaker. Position the model such + that the center of its origin sits on top of the floor and so that it is + centered beneath the Team Power-Up. There are separate models for the + blue and red team sides. If you choose to place a powerup in neutral + territory (as in MPTERRA3), place a weaponpad_neutral.pfb under the + powerup. +

Copy the spawn folder into the models/mapobjects + directory in your missionpack directory (if necessary, create all three + directories now). Do not create a new directory for them. Shader scripts + and textures for these models are already a part of the Mission Pack pak + file and need not be added separately.

+

spawn.md3  This model is the location marker for the + blue side.

+

spawn_red.md3  This model is the location marker for + the red side.

+ +

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+  New Game Entities +

-6-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html new file mode 100644 index 00000000..6d4ae40d --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html @@ -0,0 +1,115 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Using New Game Entities

+
+
+ + + + + +
The best way to get a feeling for how the + new game entities should be used is to play Team Arena for a while. Here + are the id teamÂ’s rules and suggestions for using the new entities. +

 

+
+

Game Types

+
+

There are eight game types (including those from + original Quake III Arena). Unless marked with a gametype key, entities + will appear in every game type. The game types are:

+ +

Gametype Type of play corresponds to cvar Â…

+
+

FFA (multiplayer Free for All deathmatch) corresponds + to g_gametype 0

+

Tournament (1 on 1 deathmatch) corresponds to + g_gametype 1

+

Single (Single Player Free for All) corresponds to + g_gametype 2

+

Team (Team deathmatch) corresponds to g_gametype 3

+

CTF (Capture the Flag Â… traditional rules) + corresponds to g_gametype 4

+

Oneflag (single flag CTF) corresponds to g_gametype 5

+

Overload (destroy the opponentÂ’s obelisk) + corresponds to g_gametype 6

+

Harvester (collect skulls, take to opponentÂ’s base) + corresponds to g_gametype 7

+ +

 

+
+

The “notfree”, “notteam”, and “notsingle” + Keys

+
+

These are still checked by the game engine. They are + checked AFTER the gametype keys are checked. Because they complicate the + design (simple is usually best), we recommend not using them in Quake 3 + Team Arena maps.

+ +

 

+
+

Enable/Disabled entities for TA / Vanilla Q3

+
+

+ Entities can now have one of the following epairs: +

+ +

+ "notta" "1" +

+ +

+ for when the entity is not supposed to show up in Team Arena, and: +

+ +

+ "notq3a" "1" +

+ +

+ for when the entity is not supposed to show up in Quake III Arena. +

+ +

+ An entity may have both epairs, meaning it will only show up in mods. +

+ +

+ The epairs only work on "gameplay" type entities such as weapons, + powerups, items, ammo, etc. They will not affect entities that are + compiled into maps, such as models. +

+ +

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ T.A. Game Types +

-7-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif new file mode 100644 index 0000000000000000000000000000000000000000..002d850c6e91b0aba7a4cb88f1b0614ec96efc02 GIT binary patch literal 4292 zcmeH`Yg%Q)&MUf$M zH9DXJZ@}M~nwt9a&p$tW`0(!CySH!OzIpTJ_uqei_3G8c#KemiFP=YtK0ZGF?Af!i zv9Zz7(UFl6o6YviFTV^A4?lYJXlQ8Y{{8!dgM)YP-W?bixPANf_uqei^XAR|{{HLN zuV1}-wWp`2ySw}H<;#~YUAlPjVrOUPg$ozXojZ5-?AiAA_O`aR*4Eb3r%$)Ev>ZQv z{MfN$M~)n^SS*JRA8u-DI(YD4V`F1|eSKYBT}@4m$z-aks@k(>&+gs3D=I3=%gakk zOAQ8tUav1ME-or6+OcED_U+sA^Yioa^0sc>nw6EcWy_Y#%*>4&H)dpHq^GB^U%!6s z+O-;uX3d&4t5&UAv0_C^O3KouOOun66B82?5)$I$>Q!Ey{ zySux(x;i^M3xz^HpU>m*9334Ygbof43%Ei%>H!eBoR~Lx;1FG z>!O!p^G6<}mRhT1Nq@a8ibPwdJQi2SJ@mA)|Ll|SAn(nztCd%e{BSfH>9pw8Eq4*o z*OD*Z1;jJ)__L>6MI-ckZNg!-HD>9*5UKiZWJI{7^$}^w;Eh!+h6Gt=Imr=xwQV%382C$|qwPw@{wq=~F@KYDQXyOXc* zMGOY{kdsVj?#7s&OK({f+WuPa$XySz5{{raL1PI-BDIg6>b)~1`z(<+UYhr<;G{xH zLJnf0+9`YWD3#~8`bM)p+}q*s$M@NPK0A6n-Zdz#C$oc8T4~~Qxmll})4sEZ^EQE; zRf@b2eGd{u1qzxxRvhVC)cfQU_xvV(DSNhBWRAgdVT8+%&jzlt>TxrmDOV0ex}W@@ zxXzEcr9vuwqQ&K98;<$wW9ViXKF#w3yWB}ptGdG7VD+hSUu~6X0T!Z2abtD%l|}1+ z6JK+1+38)21*B-oOI+SoCxTR2q%o#YV=U*-tF^8LoL+k`f7x&C-9XB-BFx0z?&%A2 za!+`n8?`l%aK9$l$dqEY|;yixURw!>^G|^5~P7Y#%u@FLkU#-qrNB zT~-CYjv^3Oa6NBEQfsSni`HDjlx><=MM{=o6bd4+UCZm3)}F0Qh_$;Rt^!S2E&r`_ zA)Ve*D`%Z%<>uV@$T8?OvL@hllyH8o`Z)fvuEQ~+xIvFmj4y>KFZ#fq0EDuI98Dpu zd9M;>QaX;tz)9UJ<%$B+c{Hfvaa4q-S{Sr`SLPJ#BIVBHRyaOo4Mqv0TR&eIp5s~u zm@8uELze})U#jA;hH7W`53}SlLDZsh;?yXX zE{b(dYxkzpj1JpTv2cpwL7sV1EQSoV;whX(3_|gCbVxpyWq1*y-U46OQ(Loo+9oZG zAe}W%Bs(uRiGX8!ll-;1zKkt_8|6K9%d?=E=%meBTfys9<0)6^n%C4rKKS4A^; z0_B~88bUHJa>icQ3IU}KHQc(1Ja_5iZ0;m~>ekCzpjt$u)xdf{)8#S*a~A4+B8<$nxe1g^fCu-cGhw1ak*RACVEa4@8W3%us7K!- z4*D{-!u^366E@f?;RHe}gJttDzedE$QB>@1U`UcYGD7Yr9+bkcm1SsVa^_&^*4N~un)eT^lvIHMhfg;;3S;+*R+=(5tqHjgR@xf3CX9DcUMj{LeGX^5ZI|! z^xEqm?gn#q2x=G%Wnb&yGjWFX-*FzQk3pvR0`?ZkBid69&HAqood>tabctfF@j_oB z$>|JeIrIg~;}jjR`r1opBlyJqU?#>5h1i71cT4{$fevsO>idkJF7~SH?#R}eK z_PO=^t{Wo(nsi8^cxT`Bjj4C>pGZ9wkEWV5HL232X^9R)tn=N3RRZ=c~ zQ2I~u)ZEOAv_!I!=OoVW+{UyuLe)P@(boHYF1tG<=aXm7<3~C zp(^MC-mQa~7BE=_XIFI&#Wi%oiO>+CywBYrxz9K=%U=4>dH%UR>ai)?T znDZS7`9`$0>jrrwv^uncGtWa_BAkq`3k}rc=%viaF`n+LC;yh+zSSoA&)IjLS|tB!1!C6}n~TOd`6$BUIIYqwR`zLE|)! zIlj7=3=ZW?5!cgC)j!;JH(1Ln^0>NW=oR(lS7_|zA;Eo=TG-92B&j4i8-4x7Y?R}hq&IbK`YFP*^t z-Xc0XoEQzh6wbcI0rq@I^)YhwA2%9GNt)82IqXgz*jf(v@xhoA+iHlsa9y7$0Be2N zP67~Xf~nIDj@iqVX=S7dGCZ@*v3olrTS;_~NmBtNu4Wmcb23uEoNN#!VSkaQBiKZo zA{8POcT>PwZQ1i5*Rm8#W3(_=$CG-oC;7m&z4)j4^sEr}J#HFVPwY)lIVcQ!msWoH zhrsH^?hgj4a=4@2lMPGeoZwU~t2F1QvnOU@>RoRCif74mbhb?Hy@#YQd`f0#W+C+B zFg*!0J%t;fi;hy2dTkZcvSIBx((MOW2OD^+cGI(S7lSHN2l0Uv%NQVHv%Ea*c-s?l zkll@&OawVTl)NJOV;x#Y8pnn1c*1t^AN?q_HFB$_rQ; zT$~z+caS@(jbQ2-#<~ER!4=$YT&jqoiHQ{PULe#~=D}iHd`~c2ClAAA>D2B>M2&b7 zRl+B7DqGv~0B)gF4rf%|K}{r$jNGNBX^4C=B6$Y$>T3yv@?fpMc5dLUdywD(HNoDb zOBBlWWJTHB^s*wE6HT_0o=yHW@-v@i&YBju%T#ohs0u7VI`_fkG~7W!YuovwI z?ZnaF8>kALbOZ_H*YDw@ZNcRF0Z_4_2}Ouq;oxRHjIg?TnQBN=7B!+G-S&amGAGnt z^k5O(1n2K-gwp+mXp3H~D%bqzwDZ9s$^dT60k8MNyc47!&XozQ`@Jgtkgm}8m9T|C zEyEJ^61A?d<*822NuZ>th4!}>ZHz7>3j-+_z1bt5qxy&79_ Wfn+}Lm4|}tW#4OG-bSz?2>UN<@72Ws literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif new file mode 100644 index 0000000000000000000000000000000000000000..34a52f0eccc420f91de6ced9b2f26ea41213b332 GIT binary patch literal 4732 zcmZ9OX*`sB*vJ3(J@?Gqv)?mhhS1ou6h=uzJu_uX(kO|PMk%yt6e(@@SRz{^9SLQW zooYy>j+_~Lola+@Ma!unqD`YkT27wM^YZz(|N2$uD2NOiWCC{`~pVr%xY0e*Ey^!}$2PPN#eS z{{7h4*t>V{-oAbN=FOW|uU?Igj*g6synOj`czAedXz0a@7lVU?0|NtEt@ioz=g*!! z`{$p3o<4p0%FU$<}H{`1d2Z{50e^XAQ-o}TXR?yjz`&d$z`j*j;B_O`Y*wOXxGsajiGZ``=i z($ez#@4sKae*N0DYt7BgSFc{Za^=e9%a@y)nl4?s)Y#bA(9ob%DlcBVc;Ui@^XJdk z*Vot8)z#M4*3{HgS65e6RaI72R#a4!mzSSAckb-jvt?yv3WcJywDk1p(W9o0F51ot>SPm6e&9dGzSf zjEs!*^z(+&Zg{@t?HZ(LeBqU_bnl-_} z!K+uV4hjldwQAMMl`8`S1I1$TiWMsY0s@vVU+(YkziinuKR>^vOPBik`uh0zczb($ zd3kwydM;VAWbxv~B9Um(qD2cAF7)v5aCdiKuwa3ko13ev>-_oiU0ht|&70@!>^yhw z+&OdRI5{~91Oi7#M+XN7dwcuYvuDqmHOtP<&eqn}#>U3l+Ir^9nO0U-mX?+l78d5_ z=4NJQd_I51j2Wh;rY0sP#>U3er%yLBGBPwY9Pfw4-;jr0k48vF~ z7L&?L?RJE5CVY!!!QIvzaalV*#G}9`-(sSOoG|} zE&jU+fKCAjHTG31)G4T*-MSuSS$jHW;aB3@aJDmxH+SpPo`!SX$M{PsKQ6X=(c%^T zI&IyfxaBz5+!7jDIaFa$;Og|6s!H|2v0FB^yD*6mNAK;j`z<8EGh^4=2?WP$`5uv} zB|&EKbW?SFbofl3kdJecmi4)`aPWt!aC-O)+>!e^5LZzG)o# znm)%u-^x?g4ZBaX7YEbd+}}yJTsHb!#Pwmq8ipf2+59*H(oZ-s(%19~7+w#Z+OQV! z`k0eV-#_ILb>L1oWS0m2d+ui};`zbN0}UH|?;}bdpECc%=P}kl z5*0q%Ect!j4$B00 zT#t$77kWaHZMl4vQh+-fhb}n*{9PUm0WnqJIc-%?%&>k?WXrbJQH6A7+%e&ZuMXI^>IO&8 z$-SvDjwgb*zN%=Ex954B_%`^eO7U~>m1B9q*4H)F1yp~5kAH!xj$$*#ud9c6HkySV znB-1s3-v^5-Nie0vo;rDmOkM3PYcT2ZRns**=Vj53Xszr-1?U3=yGByk+uUe$ylP9 z2le+d7mQXGUs&+I>CM>hx~?a&9*(Vqzi&*wtb5=3r8fW0AAs=m&TOi&Zgvwi$sZJs zYv(}-=40G|7;Tq~ck*_s)Lq8ApUP1CAU%$|uUye~)26DvjcSvjZA2}y!KK?qk#ZTy zb)+65e`dT+6X6}gc8w=@$EV&U4;7#8`aKb+1RhE)N6Q?SD%+V0A`gCk;PFZO`JrS= z(9s`xav{PjHP$!J-hTDn#1rXNlK>*LS9-_ifds=LB5z9j<@wK{5k`dw|+C1V;{fk^0g2)#&ce=?#Ysxsh?tw_Kzuos|qIh3P}Pjq$kG_ zx)9CHXh*PW9I^IQQ`c!DuuTA(-wX&zx)jnn)s*+-AAO#X*?OMLxl-L`a9x+?c%p0G zby2&~WBHLM{r9~G)j6?yU!)7^gRH3rQI5IMc!saP`Me8kgJ`pQ3~fk-;|uK{IGcfh zl4&qUK})sV1RAQ%x7~q~;mE*Xk``}f!pCU+qU^d?UZr=calo@PTPamL$<^J9zKtKl z{g3d;r|6q9d~ADNNoM(F+1?92rumXqm%N2#TzG_PNuB?)f zGMk?-ie2SI$ZB_UuKbi{J=#vD?3qto6!T#z7Sm9VpR`()n?JY zu;*`g6(N6ZO-Xp0x+FCMstPEuN{cgx7#i75*CCS`uANb9+8A`6F!*GUiey5~Go8}x zzRbVb5$TZi2&{w6Q~1Dor7Ux>D7m6%v#nqL^pHM>VbfZq!ivU9fun z*iVqvV)Bl31!70}t`^@+y1@F-X4x0_z9nw!V$avT8LsyRT4U4d4m~$Q8*49P>A%Rt z%L?qY`sYv#r($^-B=u{w$<&ienqotg1 zSU4iuDgy+`*VP1xdSC1SPI3jQ)&9=VcB$!6k4u!58Oi16FvLWfLtY;ygJbDQWzZAZEgY5~t^mcmH(BN@7T)|Je_l7qv_QAhERd5(m}{4Ce?664-@u&U6w4S{^~>jrd*!q)`RxnQ`dTVO3h?rXkavzjxc$ z&d25}g;wx@*Ax^EgkRV_sIT!;mG0kouX3Z7`BI7hjin2uH zV?_2-1vpklT2PP}pbs3C+kut{iIe83HfJ?34RADL4wNs!)=0rb7d9bAK0xf|jmQDq zT33}w5zmrmqOx$d_tsHA?_6t zvaeoE=qlSo*CYz{K%)w)=fku~tXesL<->hstpO>IMw5e(sUA{y91%uAmIO+1#ohyg zjbt0jCc7)ruwDjNyQ5&9EEHrS5sYbkVL~L@JwS5eo9_|B9?@7U29gxm7n~pwu)py6 za|*o>99o))4Qru^DgaB?)Hjf4s5V~;$s&~z*?c23g2@p}_2OplECjHQOo_|B84YTs z#-&;?G%bf>MrHD&vZ?{%!VV7Jefl97O~(dZlNdsJw-W=#DL|2n#-YZ_IFg8BpxCJg zF)%5JzZX@H<@VSto~1gPDPlQ`kzb{DCO?PRK$ zj=cDk7bGD$#DHmTrsFt#j89p<4;#l|&!bq61{ejicZXzZj&Eh99qZwN8>6PlDtM;` zcD2QZB~X7dR)j%kyx3hDz_gu>lxMqPi9`{z#}^EbnhpzLHrR(k43?NiDI+=XkF(>L zW{TrG_boNba3l3Hj2e;b7?W5&FUK3ZrUSE%V2c$*t_WYVZ|RprXk9`PR|*oY&gjzu zD_s$RP33^CWHr+W7#lz-171Q@3rzPEF(kz;ZDdo491)>>)oDU6ojIjA#VrdfsEDOV z!Fe2eEQGteW@+Wf&>n0Db{sXMv28EE|U%{j*_}UsQ9fP&D>}R^-pSGYxaF!ZK z;R;GuH^X&q?8wN&`Xd>ytj>|+Xr<{`jDlb|z?>xnYZC!izDKwgd!PgCeb_o2F*IY% z$7T9!fSqQ~inZ7~6_kZzfnuUz1j~~T*lUq9Un?fWgeV+af{~2aC)h?+8~sv! zz04W9d~z?kP*X{3 zU>Jb2#BF}C2I08Zq-eq8U~I2sBS*$GQ=Q}PKTqV>P@lNdG(z$?k!#H!=M((CiK?c8 zfV1-KWG3RQJh@bSk}a!r3%OXW4-P0BNf9fqI^!;YtZ!yWIuT6~Lp~Wz1QE*uCz04J zD-6|V8ywx@2PyM|mtk=_*!(EdP?^dZPmTB!AadSjcL%mE3}LUxvt?K4T_LLACtEM? zkb_IM*stWfA!MHw0~+o}O@Jh*xDbZD5x~>MOdu!QYp<~anS2~< ztV5=MzxM6h+-MEq;J07Mz$8hbv5x*nF@|HHBveIQC1$UvDn|s=e~PiUQi7oXb_!)5 zmo2zo+)8j_7!5Y+%gmi6DWAfyDn8im&Q4H(`;Y!W%}7pb*|?HVs>cR!hQT=f?L(FR RI<>(8HLpa?Wn;koe*u;cen|iT literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif new file mode 100644 index 0000000000000000000000000000000000000000..cdd9c0296603914b6b5cf5f814890db744c3e443 GIT binary patch literal 25903 zcmX84c~}$I`#wBtHbOE9AqEJLK!C7^Jt)E?Y*A4If`Xt11P!iHv7&-b79b#Ma7F79 z6cv~HiEFWSNdhV=YP4!`YvWF>wXtf8it_S)fAi;auDRySbMAZQdG2$c>@iu=}5F3*?Zj|CX`NUOI=j;!P$Os6Ik4?<*^c&?LHi69zjEEnflBM?c3zz52EttMS z6kEs-8qHw)#ih+$pg+&`4vrr^IcLhU5#9kLMgWZ+%;1J|eB;>OQQiSb5y?|U;VBVu z8S$fX!lF|~;o~DSmd#kOer*1n;Ws0>`_R|{3~n$#G=uFOHau}r%s8&!@Qtwywzpq! zBAe?c8&l-tCkhOX$S9x~u)Tx1eqnyWv7<8cY208= zP>OeOVpM#JrTh0ei)-C|B6!i`_<<3#R__vp$4{%Q_DYyUqIwz=Vv5 z(K+tkBA>8?^z5-TuAgs0CR-3DN*N!OQ_A)W&d{uj&7B>dRp=j^mNHqbT%d<&%($XO z$unzHr)eV7a}#okxuOWgtm?E$(>=X?*X%q%^6=({#naea(a1~&*IN`8nS#qBQ_@Ln zE^Qb9-hOPq07+c@wApjGegbLsIM09}->}GAA3pN~MXK7>5RLYKxM0w@++kdh{tpeq z$oPM72o#CJBO=Dnscir8bZ+64wA=}c>b1ilDyf=1{Mhi=$odV9`Lhe%Js6^}AZQqT zG!l(T8m-V zCj=a(01)wiR2b$2Kp6r+3SVI{+w>HVu#z52TUP@XICh8P*q)1PcyV(c^&H!KdA%UL zi9hCe`<0F2Nry_V9N%|st7PWY9b-=Hzy7^+$?Hc~P8_(o8`sl($DZuCwO3I@dY@DZ z3B#7*+Mkw?9d{1p@13=e*1yi8V%URy!}AH-D5jnC=g2jABI)v{N3ZBZ7CcT_^6uqY zdjrjUq0~2}8b7TWe**DER+>)bh!XSKOO8J|VB8tjvhTE>$z311%MeBJf8iQ3EC;Ify%j@s>TX&Jy zwF*~0eY!bs-&lTPZGdbDO%#6j*L!cYce>ka=8lB#1|1jmv)7tJbN^Xsd@7{87XpwJ z<$oI=a}kpbke#b3|GZLh0!7RGYh7c&UwP*KCxGlk+pD&8#-n$a{mjYi22C|CHDHt` zVLcXQwCz|!U4^T3vJbCpl;o$pZp>dK?Oqy3dlI0VgxD@~?p(ALEiITo@MM!4x}?E- zZub+>G-ZZ1a7|gK0BN4t^iE4w?@6|AS2jELe;?5NF8KQe>rBDh)9n5BrkO{18LKLq zwU@E#k080graUMH=H@~d{b~npk^L%^;6+}bh-$`UHO|WI->nnaJ7y|D&~txYOxPh- zhUWF51N(O5cC%im^AczdkDJ3pm#XG?lN z8DY%39R}r3JN5b39|?N!+fF9o^VXM@@2Nes_o?e85ARQUZqnchB+E*Q+hu| zD<0X%?Th+K#X)lhrGdIVH^RaWVYu?HYCQT2v+zF0dGpdYiuK)P-_<1q{H>6mGs%Pg zU3PcJJ@1hHx%7i7&YUB$8vm8Xwo4IS-$rfnGk3HsJTb@BR=*T@+4=H_RPko(+^@P9 z$BHHew)>S$DSmuxg>U#ve9~$eYP&Y~-w{Yl#SsX#%zZxCotOHBBeB%(=(zM)lW{AA z6TN;&81qx-$3KY`fGYBPd`igCfu~0Q>D5mlL&0zGA97ds5ytLF!`1}mqwlU?y0muV z=E8rq?;p=G9&2#ZRBH~tV5N_iUh!p|9QdpA)w(aT*DZq|5u)`og0%iSyZuHDF3ftU zIr7x7e9txH!}WSOShqUrZT002Y||HOp3lPtKfisxb>X*pCl;OUJG1w?C)cG-|hdwZ;aZ66~OelpYI;K z{Me^@cm^+0oT4<{oH^smxB`21LyUt$%O~`II9eYxPW)aIhJMn z-&A2tX)=r44A#x<+=1N_kXQyc%pgDnYI2S*P+A(|@<>ASi)?^om!80dCQ5lvE(FP+eMi0iXfE*}eIw&mv%dhcDpXk)5KWqRE; zadSvS)ekSCeP1}zjwPP@K6pPbDzoU!TO5sW0>u@CjohoM54D=V9Vzmqa44>3Gg66WEUp`K zx59hloNbvU7ZX1KOd~)`@8oj~`$(+3DFQR5=X!3L_yBNC` zm;4%m+8J5F&#+0rn%c;SeCH;z@kf5@Biqn%|MPIo1WsMZ^Dv9yU3Sda2W6Crr`B>F z^1tJJe4Pi}{`!XEjS%A6UWe+e?5Y+ngfdgW}R zWJ~Qd6`^Ogek`5tH_PkY)G7Z!_?hI#m|$$PpaAt`)DUqQ2g=AHn>}cL)mk?{YYeVD zJ>%q-rFYBq6R$P`WQo95xlj2!!wOJ~75eqxEA@-N|Cu~p4YhAJBYuWa?kP?i)#Q8| z=`d3_B>s5jd&!IVc_3AylGX0R5zIu~4KP~a&+jHM>gdK3lNXF@_ymkNODx1xhrCrY z^Ofo=s)@#ps;w?a3q^{l=C*>`iyx`UWG_y zZu!?C4_+;4L?1Y!(+NlQ;tYXAM&96nM99}y#cKJDW#>_DulePq3GOTdu46d~8rR`K zwo;E*Pp}q;lC5rATmb9CYsN~Vt9ZZ9=u6!pj2UnK-~k$VMD?4_+;j8L#!v!E!3zQj zEtaT(x4(DZGA*#P!pw$vgRuW#qK>MNpm94sp3@G5onB_qKU%eP{DJ7ho;fOmCtuj# z*ov^jG|19l@Sb<~{&r8aoM{+M>=qQL42#CzUw6hy0x%nvVu@{|&TR@jo8CUCY8VYX z$)2mx4v`as4HRVm&PhKwL&lLPG^>@)7eLF1=1+d6hu=cX@)2xSJr}ng?vSIjDfDM1 z_lF{%`wr$sJQ?gL#vD+oi82jGV>GKbOrDcg@0DQ%_h*B&f3rjzvu=p6`xuucK>XsM zD4-A*K=QyqF?Y1tTKnj-BD~B$UlVK7XpYOW+4sgZJ>mQij0lv=KQt`duzx{_1Kd}K z9&{k3PPCZ~4r0t_SoSv+^Ir+0q;+D6lrdGD{mjZ7BuW4$TIxU!66n6WphB~7v=ZJB z3@2ORvJk{yLb`n?Iy7*4b!G{iOA?v&l`kQG3=JTnH4-=belanG`LEIh{2E9~5|Dns zJFd5W)z^F}s-*WFkHiQ#U1{Lb*%Z%w5GGw9k4QUOqA(X=E$Wb0T#GOgQRGh+PM|s8dxAf#-~$G z>0mBV1C>tMV`%&-5n1^ZeETG#MnYOUAY7r8O#P5KQ-b74kmaQ58m_V~uBbjSIOYVH z=TtB1gHr@6;shYe?CxRJyr_0t=%C!t(7nyzXAPY~FbBm}eA}&zcsJ zlfKqP`Vr6kCSiD(-3R0RQ_dqHr!{Lr>MEH#3z;7Pw_-`lAt$;}0vrOGXLK>Y znB9H%5*#y{)PRg97RIVzBm^n1L?sybRU#ctF>ZjRa?R$N_u`RD$YeFohD%ln(h_mf zIGi;5A5e+&NkSqT=YP+#YAHwmyt#cVPmM$OKC0+`ZQom@eQ zGpmcT;gMJ7`{IaHF#h23N#7_GrR)2%m2k9#G}D=O*fmR8lr-Tujfs)R;fwuTfM3_* zYqLj9;eZomXrN=pKiq}k0K~Rvd?x`9u-(@*NW6=52q0A|fe#XDlOU{MKax$*8_Zy{ ziN?cP|2i{qkN^)_Dc%}Nj|LfQ8Xk>o!bl&KKqWw08471x=*=e3Lq*&T1_c)A-FMJ; ztuq3NFoRih=*;%;2Qf?ul&9R2=R~v|YKw$)s*%Gm7m|kJNK6b7SY{dDk1@f<>dig@ z0DL!q==g3U^^fUXlly;nn3t^-i>uzF$UQ+)5#wN<-HLuQ(T!$gz7o8wq4Nl^hXA=a zh4p%~K?VM_{qT=d!72wSQbYMhkit!L4-BrF3g5MCh$j$>m2%mt`Pbym1>iUpvTG`u zfq?;7oJ2KYQvRr)yAoE?wtT;rtQAE}G<9S?0sMa@AI8z(M2LXrZ}rS;i~%tTB-g;v z0yIegaV?Pg3|f!vW1eC5nCW9&dsP5wsR@24g{PV590$o_rq3r9(qKk_1Q~RCEbBT3F5j07^@3Z<%$=}LI9h7$KLa?uGC%%OZy zQ7)T6FAMXF^UP)QnR*<2pei|MKkQ|q6`Lqo7C6E|QV^6l03PkOjTa8n1zSl1;H#OE zV1h=QK&}djS0WdVZS=>%-dSV9wo5PGJ)QkYp_G8D1$@7Z|KU%VQ}gsIB&7BsFXSA; z>ng&g#DlkITV{Ke-FIxAjbowwGJf40VX-&`DP?bx$aNhe5n8$uG=t2ab!Kq9$$3IJ_jny z@_j@~HKD#r?OK2oFCecq!(lF}?~+|vCQ_^kiWzG5lAA6K{ha=y?>mGQWj&FSuJo)n z#T^DHS&I^8TF9%g#@drQnda1uf5)XaPMj#CNHJ6(Kod=HR&Yg?iav;Kf(T@WlXQqc zc-P=?6WT;jBCXIOa?0G^Ikf*S3Ew50-*bt;HsuJ(Jy(HX3#0(HDa^D5E>vOKHt3>N zVGDD%zQWZUYhXPfz}NP+)P{G)?;0d3rPm&+09MqbvwcCov&$ zU{N{wsG&4efHDB^<$q_N#91Cl^(Iz;EfMTp@kK^b3ZsundxX|Ht&PAdbD0C;h zXtvDzHt?>4E&3(e4{qjZ!1H))sd=j#w!1;KYOoyWv7#|J9Atu{T~LY@d~D3MZBB1| z62`zf(glziN3+vWvt;gQR&w?x@*?bN85URA*cRXzmuN`;>XQ2X!XzY6rWg)V!SXFg zKh~NU|4Wvcd6j@n*HAABeEHpXR1WE*egPInIrldJ(e ztjufXTVovPro*`SFqlL@BOP$E0G<6~t|l&ap#1)N5Biy>K)wKtGLKzOruinEZUBFr zaErXzf_!J8?LIOuAFK6IzWA$L<}9Gkf3#{&GkTv3hnk@<3v^}ay{iIpxQnz<0E-+< ziX;#YUX#iD?luw5WG@6q`PqkbCTp2vcF$&AK3=C`14AkVL4x%3^W!M>=G*8jOOXT~r9qYm zdag(?55}1b&2W?XR*DIHQOFTK1NJl>|6*dUdi(0LGnnpE(DGr^m_Q=x`%)I)Bh~YmsZL(=c_># zNY-4;QT1|6XqC9j*ExOm>@nwuu2}&Bourac5>6#rNUKeSi&WHA$KHk6?$}kNS}V2O zk}1U&GabNxVyLkUtiT>t<~P&gW9!Z6WDQzCYzYN=y@-ia)1ON)H?9@BFb}y?1Nv+r z>TNN)<;>?QAYeV?lZ!gi3@_1u^sV&8VP|8N=oHoVdSH_0^ED^#F)LJHb3pC4>B~w^ zl`hAq%YdZBCou-x?TCi@Jx&^X(d+xQjjO}}*MYC7zs76?N2!o(&6ZFlWVE86O%uPF zz(<4VwBCijniGSLQSuAteBkE)B;bIF*^jw-P)XjdC!ejTQ3*AbAla^;c*?xjZN&bC zVE!)+ONScP&n4h(&E!9jzhj@ocsOYLHPp7>YPmm>2HzE&%gDsIgOUZ{G6M9pq6$ZO z8wqRrOchXYU0BjNHSf&r{nruTD<3cy-g=tZ?3J+KdEc#PnX93}kAEhC{<=apO=YVf z7f;I!8ryDeG>k)OtcVY=^MAwz69iEHN`3+|_#5lm}!szJIFE3&Vm3_9`5a$~GHi3?VBswb3)nwW(>!K>Oah_JEWbU9#!2;gLpvrc zj{w5@`+mH4?|&kh-4J?%=My>|$5+gjOD-NR_!8J2bk#F7Z-J^2)BTU;JJOV&VpA8b zE9{hP${&3Ab>$^t_CFh^{B5m+2M2_-|H(5O84=c}^>2$VAWERFdo z%6WU~So<+~Q^4XL zAt^GrPgd`;kAs2e-;6e$*CvHQyDN3m;<4)}P4oO$MBuZxt(@ArSK*b~pS^}x6CtMw z_w#JfX@ppp<@E(L&{)9oQfmAs)n4`(idRp1*#Fp9w5pTX^Oo^FJwsj0*n3!4Ju{$M z^+QtzbSSJX*gCv9u|Ql#zzS2%|YE{inMflvIn1GGef!oR-~JT{pgR{?`tf91+%e zJS=hdQ3$|zeGEA$>_(~=DX);)J=rUznquVqMQ9Pw?utlpECtl9w?!UR;qc~=0p zaO#}DXP;jErEy2if`iZ2ilnI^KcYyQuX0Kb1WHeC^ldZdIMw6E)~6FarSjE?+v==hajUPuQ4BG6a&1QPbat2*HH zy_PnXUo1tx``Vgi%wKDxlw~a|_Vkjb)Xow^MLs8ghDekht=5mbSHQSI=qJW0LY;B% zh6L!3ZdN*Fk#+Xz#}WHY6NZ_vF*HgT$Y8Qx6&jc)$E5y8BMCIBI-mTu?9?V1xyHI4 z`d|nN!R4fp7!)aj;7iZUGtJ9}z*>GA%A!&))>w71+YZvM(Ylws^bBn2>xU1`-R_k# z+~DO0uxD2rLQkr+|1EO(U+$@k7Q{4F9n_AQ@TBe5FkN6b`7^%do3Ej=nwk`cHSb7XJee2MZC2*xQ_QFxzz8=rQTF;>z2Qbi zu$W>)JD*Kl$+;29*#-=_l68~}mHSppcblJWO};sJr_Dk{_bZ!n%{up;0zGEI>&U=U z5OXwgUVYp_?R`P7BWyIrXMaQD9@a6lf|uW7#KgL4ZqVUu#H{rdw0W1B6%i*Nc-=Is zP>HzPE9aN>D*RO~dJIPdraNRM=q7i;J`tseV$%uUTz#v;C|(m^Z6EU3+BeCwT~){G z*jF*%dz1ciEU_lW?vf*Muo+MY7vZi$svFsKHCqj0v70r-*aNU0i)%7^n$VFlAjElzVMl=*g%&h#lA?fuV z>IEqp5@l ziGVzp4s?s@I~&GYY_wd}4Ub82F#-QQ8*cDG)*%zD^vw?**#Rep>DEaMZEioBI}VaAbtis&T+y0Ee~rW;?zNG-fn_}Bc`kbqzX z_cf%JwKdt^R0NAVKK`z9yi{@au3WI(>KlNgLW_;nB8e9XglnS8%{;8DfTUuP=Iq|X z`QDk~=d#v^My!}Fdq+(xd<(dl1f*EAtfOR`!*KMp*Ft4CjiCj04Gz94*dZICx%H3= zpI_LvK}(;2>&nzed06|;Y2Vd0gjzu6erbH@ZDmuUT6OH{Pc5VcEyj_3of+#)22oBa z>G1!8>cf9;xM~=xg1pRIf>(|a^ALKySD|Wh)0DG7UJSK;h)dtO?W61q59S>~XM8cO zpcgM$97oyn?@sXqZ$%rWPyqL=zEn_s&b1~tUi;TNRb6Q*PGQ_q^Dh^!sae0cZb^Ei zAuLtm0KqT13`NSzNoSE(M4~p3ccfZ3Hv08w!#W{;HKEe%q^c6Vw*h#6)ApF1Y2cd2w^1T}wm1{@w;Bbo8N1{6?>!8pr zzkP;+D0;XMfB9zvLeUq1da?m`->40f=prZ}n+Lz5P){8T?zd}mFy!-LWP%tSnnoBB z6)3%W7tgJpt~3;@p*cS2>EhjCk~&<1FqUteM5B(bhQyf8)2I#W2f}-Ffql9pB|3Ic z_uC;5#DUNfe3hy}QZ4==uWn?Yj@JW)_Y+}8ttU_C-wFRW)oWZRLA4N*JJ3lTxm${!7Nmqc1 zYErZ%rsaG7WJ#S&jW+UoTL6N}YuM-mhD)?qKjEc7v&;=DD|tmHIVujMwQ7GfjGOen zVTA;Mo#d=Sgw&@UifYxm2|z9d^sq)8b|cLf2*c*Irty$TeL0DP+0)eesJ^4Rl4hS$ zBtv1CK}oh~405p{MN%iPMt3_8X!{z%jsxi(Kv~~eOAN4FK&&ucZ{7~FTyc-$Pc1Sx zEbAw)z{&1bz~7}6o)|@^xVu@1MSTrhDL&yWVu~1<)T95W3Yp+U-s{mB0~eXg8_WB3 zg%mg#yE#r{m?AOw@{tJV)fR!V)~H-X2rbKZ&9gSF=pfesL_ivkP&gHmU6q)>CqVAqxXRMtwcO3`2l6U2;MJjJ6rK;LIA2}Zu&A?PH$IMcoU_`}Fzd}J zTXXX&jFc{}FT>VF2cZfaDOA*J?{}8r34LD-KE=5YR-$EANX|R1vXGO`G~Y_DaWFSXh5hS zJ^%QoRlJ5(io6;lIU|VrRZ8?ysMjm+rFEcwd!jCW;J+zhUWp)v%9ZtFh;s?GhM7wc zyrkgz8BV#QVXhRY<=wA!lKVC_EFE7|)7hX>pvh7ws_)nFXF0n~%_TNqxw)Y_a^$9j z`|W4*$m05$6hj>EK#9SSr_Ra3aWtwtL^P?H~$5%Ev8;*pE{ z>W3E!c93iP>aTZ+Ib!In<^K2`0IiR@p^tRxF_|s}7GuT7+#mXXX{=vfHx)xB_aljt zM1`X+$^n=jO@bP3P)Y2_FA)mpp{HY^3E3TP!>YGo+~M#%fTJsV>u%Kh)ba z`yqRpakMvnvdhyTry!+f2(;erks!6|yxWnF7r4gL#YmJ<7Xs8%t@;2nu+lUw^bMI! zF(lRM#7>>OI&f8g{ck~!2OZ?})?XH3fE=sG#fZ#!U_!Ma+f;XF<+0ygQS_d=G1j^n zD&3XW2LAg#e1NNX+)&<0IuSWzzNBH5%0N{i$+$jT?7T(y`8*8=tD!I_IieGi^+Q<> zQWlTAq?Pz5vv00~^xs*Io1kQp2AR@&vxeSudy36gQ%;P|9CwlUI*`fq=(N8*=I@hglR|{5b2zq>M zEvrJJ<8|l*S~I`)H1uD877=Km^)yqR+L0Epapa3V*NV%rhrC7DKuw*j6Uy#EZqIy> z;Xo_;8v7m_TQuh+)%xTCLtejdTq}R7tM{)%KL_~Tchs57I_n}f=whAZNEPDVI;%K1 z9CYf)VQ?t6jn|3d=2q3chJ?w*H=c#c)pb*(9K~DYW+jw~lUEt{T&kv)cQlVA>W4T% zb%&4_@&WylzfR2?=t+3{s-8>usTz+yP8{~EVX`|2sVAhpQw z!~PZvu=WP>>=d%<5tQF*h!Rh$zGOUJTtD~Tq2OvmdqUlm9s_PBUiF`HR6LtmIA!@x zC}@X1fKt!j0w;G~-+b>l*#xgL>mV^??{5ypC$B1;0`ndo4i=Hyph(N`-xnQ&9mvDc zX@#Wnf&7TKWcOC2@AD5=p3YVJ8IY)oWqmcD+xK zK3Q3pj6*&=q~zB6nXU6~e?3;jsXwZkl_-S`3!s>54U!f8Wjzf;9|+PfS?GhqqvNc) zDS)9ixZRQ2S8^sdz>Ng$GGruDGiC{?C#zFQ$hB zrGR0I6^c{UJ@8qVt2%Z2t|v>tV_Gnr1x?xxOjqC*$2h~08F6K3J7sERI3~3O9-lCeZlEp%FH@o>x41N^dfOx zq^0xi%;r~Dfh_#Z9JN7y7)kgbEK{R4{D?;Nui^3ac06-s>?EI!>620l0tJv>H`5dx?e|i zkn{;v%SZ34k3k}<(ety=>>g3HOE(5@D3iV(YirK5*3EIg&oiH!&&%*b zb;4qbN;^`e<15gSYKXRx7&CN+VU~AfqYsgE9nyB1Csp!oxJ z8LftL)y4ra>FS+@sXwa6Xy)jGNjzDQ#)mR0veCzrh`^4D3$@%1tw;iGn)ltL;&IV} zN~ZLO2&1t+m@5Cz)+nS7;e!6jPT`@m$oLI!51f0tsOU*?-}_`<-MDIGiUy6OJeg8@ zv;`=Pv{J^M(j}=4Y?C%n0bu}G7&5^4hs;pu0>vF!)p{>WezODGV7+aplIZ=naffch zYG}!afKe5n1Tx`hcKnos6^$RHJ3f-ApD5xKba(x=~&WtbJz#zc$NvC`j zsYAkkBCh@Bny<60^CW;VxIm%;kY{6k zGAcKy-@TF)UYPGe@wI!XO@Z0%DQ)rw?d~)nAbUeZa-P)y_XpqI_Wt0e!(sbx^dy(t zaEkPiRg3lR!yLvRh8AD8}kn2{V?Za*u5iDe_Z@xj;$M|7nq33 ze**eqXwtWiZCd2|x|!b)Bs}rSOJVYCSN`kgw7XlzG@CyD8D{q1Tf9*-^!0Q1AG!PD zHgGD1$PxdS(ATh%7@NMXk@D?xsadu6%J;l*(VKpUu>9A)rr@x15m{`g}&-#4=vKpR%g5 z%BtlK=3xE;ZjRZ=npJh1D%#iHMu`wf4%+Gf*7$hd<#sD zX>X}p^&nrVMTeXFEcXJFMNj2NR0nM-ntsK`5OphI-gHjs5XkjZd-T$aTo}BSTtj)j zeuY(@zAkyo@l2ooLZx-t)U{h~#%?@&OA#17`e~2nm?~jF%|%YvMA8V6Fx?|%2Z5&X ztOAgh)4_Jq&TTUX9o)D5Pyx9utAoZHrvSRL3wK!4J>rjOWTZjqgPZHQRW050By-_d zk7E&g*Dovfw61Ty(XnT2V238J(W~f}xlE8<5H4x*kW zf&JjStKrdH_Q{pDNaG`w46$*tZD>ikMgjVR)Y-;SQudgjt?joAacd;UCxXRm_vb{E z=EL(t+w(V!p=Y^hJ$v8(1?Nfr?F(cp7&*=%Jf`^w9asEweP!H@DfP(rKr`nVp2isH zTCezbVB>X1$jvD^r@!)8=}Wib_MCtU+ zM(S^$;xu5ZZRn!EAwi)}f^H`vj;;Ny>1(#IpLL{l7RaBPUt@v^N6J zcr_F}&q|$GEg#V&X+XdGH91S%HLQ1B49z;$I4-}$3~1UNLtJ z=vfI0o0}iLoyI@bLJV7hcDQtYcL3kL$E+oQ#uzCM^e3zNv;L8S^pj?H)02$Lr!CFp znyB#fz?+z%tO4NTPrC|eDzJhQRyAxo;G-?H zr~v?5{yiRJe4kP!mQx4&rcL|&j!3R~;b(5vQbNYyy;f$vE?>q~>H^-7 zHtfhT12(|G>@?AmYb>07j?5A9nw09iOyItgJbHxdRC4T8dMQfyAr9k3T zGX>yS{r|1@@?7DdNao3CTxmTy?9kmj-!3Sx58`>>g2Os{)irq;Zk9#B-dQo~`XMZA zgu`Xa-4VbtT8c}L?@4giJaaGIsSnv7M6JN~(DjZjAFA!lEbAV(`&CAG4XF2cgMW9Q zmw}x=RJ7AQzz1k0m=gf~nPi9mrEZdMV$xReXEjzKFvRvdEaP|Vq5g!EW6QTDtn3fu zb`n{EFD0}IC33c8Z=Mst= z4+`1FvZk&Bs6i)HWY1A_yw+jx#7dFEVV^BR`HgjX79_FShbTsiE_lEibtTNom^$pR zOeyn!(#X`Wj~QC;qYYj!DxOfrs?(!< z*;la-04i|dabpB!?2XCcMC*RCkrU^}+{cLw33ByS**z8|W=- z%r-XQ=i|H!ba-Y-Y<6}}8}>heLEo5uViCV9cTjNSp6} z{d0^mP4dix#GNPn2K)hW^gY|kx>+V5f@=sP4GVG}-ZlgG&Kxw3m)w`h)zlb5?a+cCu0OHCclg-K9_*B$9z7{jtS(pW zu5{U(Hks<<=h@tr0(zhPT>X%@qjXX!`Ddh1*}(3wyRYrgk2oz@Zc0sc54%om8J+R> zRF0f|)OBLqL-T{uiJ8Cy>0%z;FFP+q=Xu_o8LqQ2uQvyKc0JJr^y3Xt4jUy~0sZ>I&Tgxa|PuIIQlQz!7!$z}oNA1^{%E z&D~-3iMLTzPI|tRVZlfAXeotOp#d4&e>LWgE?TOKFhOB0P=M9GuVTY=cXuE3_h_{} zxLO`69g;`oXT?0yuPIL_sk=NC0`Gxg11#Ci0Ww7p?}OFNWZlqeZLM<}M-xcrHIY^p z-~xPAW@<0NG=mX6HqRU)HNV&KC_N@4J4&5#+4cJuFZ?2)icwnwMBd;6U4+6OB}hNH zyyqz&N;BcU!8XAgfNml97JwZO^6uDpr^iuJ0Pl5ExAE-cv(^_0AlqRJv0E8*IlH{g z)77=|R!PiBo$!rL)T09z>mp9dV)+xNNP!8FS!-+Ls#CI%R(aS--I~fGQhz!^$z-da zc$u~QR)9_1_30xp6~OJqJNE@_8$$?H0Hx3RVm`=jCHQ8Wmt&}uJ(!R5r;}62ZyOYoIk_R;F_-Ev)+jWsDYfO!Ci?2Mb3FkU&47H81!^ZcM8RB*HW?|&2onv)d(=-9p zvjly|^qi&_UNtWm4jI=75a+gT8E=ij{@P$*U|gO^^ zn;>7aEK;DCNc?xdNk8i9^0eSl>LEOP4|sQUbKyB48Q9zk8O*HVbWC#^-JrNL3Q7jLf-n?x9M6irL(Z`%z#;M5~bJU{h^wE^G5| z0R2t>nmLiJRUe0~N-}1* z6*JmAq&Ii^%I_pkjNt*MYVI%h?NP0AzxZYm1@c9T%RY}eVzUSE{|r_^!JYOf{w^V> zewLD06O>Nw#yz*(IXl|s(TRJu3#fw>sK+K;5eZff;iQ2chB?c#6L|3*`SEz1)Qyt| z_;{{Wn%`W*N{{T5cjfB@3SD%e^~kMDrEl~D?b;A5YU5IQFwY*|IsSHuH)Hrf!~kGw z?%MPfXPvc;sFn!^ds2Hgy<(dH{@(S?R;b42!?7_RZL3l1na{0sr}gm8=5&623{M{1 zzeDv-XUdy0pT0IA>kxmwT~j2FHx1Jz<_|ei#Wt$Q_H*jIG(?MGGFp?>1A$$~Uy^}g$Noc;5? z0A}~#K6rN;doAxQ;eH2*!ev<18p-^3zkj%mARxyncki>h8D%H`$&;LvF~neO=Z&8) z{cqwd`P-Mqa0_@Lc-(wfMz25~fGrRkA>Ch4jOu`**JqY1J*-_$M%dTSZXf*y$2c2ZlpEWyc$OtZ@ z-_g=JpwN&u8m>wA`<85zk_BY3Z$X-eCfHtsD9>z~s{7#ytA_C^w#44S7i7v2Q7g;4{mBz8THyhv@nLAI*#m;~de1wwl6E*SM zZ>^73+!VvZA717gD;>)~-&k1^S)9fLD3`GY#S?29_L24fUjt_z57qw0@pES1n}t~z zv!F?mCM1_VRf->O*ISpTk4kOwzmkc z(h=KSABzaSVg$L(t4u_V28iW)Qkp&BbxM1Zh#MT#vwSgdL>*p9XHE#&OR@%o#N z_t?_o1v^9!d0dKdYfe9jO zPoHB|tqw`vFM_-mJg5WGFi0~6N|w800CI(%v0^dFDC29Z=LLIvOz7c+rTuWo%c0$D z(%5O?Hueac8+*@J02Wgm>!C%3+|~cwm|jPIFm7~T%V#U#+214B{xLkoEN!bm-6m)> zZ&wAe#COQI(`!Ue0%Y(w8Rm_i7z{3H64^$*Jkougqw(s;%j%rlF0N>^SO2KkB_bKU zZ3vdY2NCH593Y1WMu*KBfX(4Kd}nV%jlC-wS0SeqS?6vF`odp41ix7KC8Xc8s|TWR z`ngUbTZw^Krl$ZMr3-hwe=L1in~lK(O!w3&a*S^_ZFXdH8YT9Q`N!{a_T^5zvtj|& zY{@1V=I&q8TpuN^6)igm<9w>RbS`ve$Z?N|m^Xh%Ei1QLfa@zYJfp9y^i6!&oNY-D zwo-shN0I1u27Su1@FHwle{=7yGz-(k(}8(b$Uog+M{1DEDtEqndU^k|m}MDP+o}UC zCWuVo0uB3LmkWT*(j{m764{*SP;PL8_I2j0atJ=^7`WI?D%g=YsrA{k#9@62FyB2|x{#h3@fA*l{ z>5j}1g;NfwKPh}E;b-9rwK|kQKjmGrFsd)W`MWQ>&^PP*HBlk*{dn8q=J#cRE zu|+V1gWxb8b(S~H%~1T?rGt@pe$?fT*AUc5Hmie-SFq}Q4}PC-bPM-2s7iv|&vs-j zAA@Qg&oz5zaSxc`4&*tPshUjF7JZ0Mgw@$9p+Cln^1$=o3A7U5qMj+F6Jb@^mc?bW zK;BvhTcu0?wQaS+cS)Pb|FL_jX_2J)2)Ct32Q4#hd*PuYbC$muA*^yP^vPdsRrwbX zC#(gEm?Ko#iG}3}m52@dfvS9as)UF2cY&(8OH2NES_yOMlO4{OT#GttC@WK9IYknc zjrF%|6T(T@*Cp#_2KkX9RxEm56uS6bb&)HoSW08R2xA?iQ#S`J)YT8Q4{CHi~ z#@QII%D0H2Iq>`YCst&hgEZXb47AZ-lmBj$ZAvFd6UX6Myv-9G#JHH zc-={8i^Gg$Kh1LYegw@4X{s#K9sOmoac!t+&5=dk(#}&MoaX^9=Mr2XuHjO*Nqwv} z%1E?tm5h>|?}t?9k5q)AxT7zBXLKA8a@5#p!8JdMFR%iE&BKnrRkNE~6w{|N2*MYR znP2vH6mCTrMvnaDBn_`A_+<)!`#sd#7k`;Yu`dxv7ur3~`uV(zi)+$?)Xbk@qr@Xx zpmnhEkZ&B?>LNyIOV$#MOUD=e@>u5-!)FQ!)!6K)^;EKsfb`IF=WE4uhooiq7F2Un zl90<0I!?%>!GhVSPxlne#3zAtjgcXUHenW#6%7CGLvb=++L1R((%jm$^KnptpOY5v z6lGXjF4C;G;1Q(S_9eZbc;2AjVoB`(Y+;`(7ftFn{V}G9W!s_G_VKwi34O)=Blv)E z1sP27o#o8WHj|IZJ1$9Y1yOQVK$Wx#-l5siAokUXE^h90%OO;LGREGsje8lZWQ3S~ zS{|R0t@jt~xCrD)mF$hHH~Awpa(thGbwr3>w%t%kO&6mV89^J4NOr(n7g!Bsp|%^; zI&+_kCPT=0;+#8670GwT9{=;*P_WuTVNr!SB#e%dwbW}|MwBo+DpYIptsCi-bP>sNt3)L7#0Yjf z+)C&T{1gSCyp<)vpOncbrc|>yhV~FMFguv0U6xbm^+&E^W94{v_n ze|C@b;gX0Owe6g1V|s!EGy|A=O~0z~K?;**d>-%-gmvgiEsgo^o(atxCc84+v<1$6 zQkzfOF1N{PoqS_q3@Tcy?{O3=NmF{xn7LhxYyRT^bC{`8BkV&A*D9T8!=p3Bc(X}qB?^e!;bET@#=>GKZh8Ur7{a*}yzx z=b3&M7iILE;b!YX56bDvR?yB2sO(k!I3GZ0^UO5(5xgwBzx6GH>n$(yfYQw9$^@IipHkaH6(91xpZqtnE{gZ0) z;opxvrlh%%WN-3uX6H=Lt+=@u<%Nw-{;2T6%(4lUMKKI%=B9!(*>Lbj-<^`Yq|A>^ zv6K{YP4Jg{3iVB~Wl&$%B2~7Wa(vy|W>eSFzN=RR&B5@o{wVO2!663;Uij^uIa@!aT)l0$qPmx~De7NU*aFyDe27sO^f;mkV<{nFi(9}l# zr7_t%!UwzgZ|-eawn07-A^bu8{Z7Rj0gea`h6S-aR8Ic=^UkQJW1b&PIyBeu*+{O! zVRf#$G@>~9uDNd9 zDeBo$na>%6I=1}RpGhb=iEjP`I09hvFee{mk>p%5z>4cl^|$~yX_t=bXM5|Y2r+rL z^!3DYMT^#=v@*lZgdYW{2Wpwke@ECmTh@Z$^asAR@!W~`I!>{aRRkepWax(?QbN1u zPmunSM@a&~VbHpl&ruir9#uTLI|59Y=zThyK54WYK=IO{LV2jEcTlesmd|HK_i-jc zdJ*5csq5gBj)^faoJ~A$xofl-KZe9c1O~O}8H3O)p?tQZ!7@lkPH9L{J2<&PtV#Ln zTO{DI;YX>C7^Q{h>(R~PGwaThjN9;A&*KLSm~Hd0?_vZvZLk31j+wR!#H>LBTO)=u z#n?C=KF_>7a?YT<--Ra#pUWyj7UhViQgjyS-X9zE78>#Q(H$jQVy%nhq{p$X-;p#6 zIdi)zQ|rs+_;IJ5jW^bdf=KK4r!dq8euUvC|* zMV0f24d(t151Y#~Oc-Xq;d4>0yGCEn%agti=g*xlZcQJ4TGs9g4+;{BC}Ua+q3Kh6 z9gS@6+R8J7i}*PPAfFG`ujDjO0CizDZ+OHwo|!P;H(`Rsi?CEaAy*44Ho2{ZY`Udv zBlT6sgu^`q_ltr3_+NT0A9oRC_3@FvKT=wFmg#`_Z$22E&!rlf1nBI@`-tyyW*kWQ zvdJ7jLRDmP7dyX0@T{jmvOq)%l_vU|EWC7-=>t02)`@u^FYF^}xf60=SjQQWbErnQ z5D1?Fp_>fuB;GDJJ=&XhI9~)Cky8fv^kJRN+ev2BEeZ;{;HPI>* ziK}(2GPzZ{0R}sp3TVr#XM!3XcTCECZ(#SzL9!SX0-?jZfL1Ys2B9EXK=x{UEy#Xq z;tU%CJMZ`4wCK|+uEwz9o7m=>_EZtyveCfM0K{+*MTcWsx4+DnbACF4r1);DCyoO1 zg2`>lbSx`z>$JNxB3ycV%=NY;mYZXsZ!ubwSI)krr3}ifQlxAFFF5#NTyV|4$iF!R zBS4bj2la@2BccUhO}M)J)NS1jz~i;J5iQbL&;FUn9uZqliLHBI*KJX96@0-I|IrsY zK01&~)-#F?QIT^PMOs?ipU7N2B1DFCPSj!ci2AX%x}%BDs5Q|?MV1m$Af!ui zDfm5^$6T;E(N{_;my*m}wtF~a&{yo_s>!5tH-5g9Y@3uCpERDI8Ku`XgFd)wzZb8<{%jCn^XXZspL51Kt7 zoyGloDJ=!vclew!6X&N15c1%S5GohI*4!tWKBLncV`~4{fGBAO;vmE9qgH0O1Pjb$%?sK*8E+Rq_ zWMbVHTh%;SmcEii(z!n^abUH9+ns0@AhkT^_-e6by@7QFoI}w2s}rs_@tMPNcIDO$ zt^isDA>-_^O*~75?fjoQ{1)TFDA_Dz)8CKP_~~xLP0tzdMiEGV;uB#1)=7r5<-y{d ztnU~=XA!CKF*@GduMi);s|F*_VgH0x(j#)U z$TXv4hAcWkiB5qQEHGl+1F?~i8A7m3m%F$oD(1^zwE)bPXQD@JJq}mJw81cPm;(>S z(ZfQ|aMefgju0BhM-1xmR2`D4=OyrnQw5ZG5oP>8OcR8%Hv$^IxcapF!+FUGF>IH6 zTtIGh3$)T38J+~{^kP2aamnT%YnogLOaW-=C7-=D(o$k3O)OAKu4quGp!{A|8KF5ne2PF0Kud^Ph&FJZgWolO3VB>0&-Z zG>={k*i@(4UH{7I7IPbCJj%>$2qIhxI%yxdCpomnl>P1l}hhU$YC`y#M8`K zdB(8!$y^H^HV(kXNk}1DxSEHk7%)e|a3z2v-fFWd|+`>Z2D0_1D z&HVU1(i(p;tesE?1|mD~VJ-eNbd|*C0Khvj{R( zkN5sBf4w#eM{bcZLgm+%8D!^l=BHMpyMtGi(L ziR&?A`vOKQ`sdSfb#LdGE(D1jJNEH0{{oa=Yd48!($znVz_k*`gVhL zJ=lFv3<<9W9zZ;qt2j*%Un3dtUi|2lCPvP8>qa>r2MjJoJzCM!p)kN4^n~3;T)hk) z3~VjpA>u`Ndc>uKSnd~(?L)4d`#P&OeryYXa(>EwDiuC6*$j%`{m*1mbl}}9)7Ubr zd%GdjAVi7LSq&ICEx;Oz{%-^6)Z-yC<}RWLz=rS;9(r5@gl=GygX%L1*g@64Oq?&P zf<-73Gp1vr>7VX_qS&2bFTn3|GDghYpu@&H`mJeZ)k&$ValS|YtC*fx^&KQP0;rb# z2!9C2`4_QH7Mx*(jUt~Td4JIU;&#i~&}L4I)SSE`FE+5JesV?(GfjpsCh^y8uY_+* zjep5G#X4eZEEpr@yoA6HCeGHPSE5+<{UvYa>CsGJ@<$E42KpQbpqhE-sUL4N?EiF= z3kZO}BjhZoVlz)i>|K&M>wudAgcEdh0B<=tZV_VoGXiALb!wn;z?^G}!+AuJ^@am9 z`%ot6qoOnIgHt6bus}TBHGOq=s8bZUAA#)H&$x5X7CyS}Q&m7gv}gL%^hnRSMAum% zDO1CR%4-jzy>?E~_hPH+Plcnu3J{kxVnr#-$>pTvp#gzquJhIF`QB}+1Hexk&*gp4 z?HI(bxkZsHEStkBB)f*+{2ehL9Z&oI3-8frG^p^_UeSH85QJ_FOVRORwcUz3tIqS8 zbx~q`oaM>?j)ux&aH}1B(?o_j=0a~VyGK2O!PC6#eamF~6>`7BS30cs6ukZGQJ!%g8v;jQ_md5>q`pSa{fdTN_jk zTKGhqw`$&a+YH#+ck%Wk;Z`vyjv7*AetYy_)rDZ0zfGQ-3wrusUu}4v>lF_`&+B5- zHg3c%G8Tu^*gMg5VJHHI_h(aHrd{lxucSwXYF6T}cEmhbO7ETg-%|a8Ju5x^=!y14 z{;-844L!j%pBm^?L_jL_jqtR&`rU0f|2VKMQV1nyAv@iey$DiqYU##Kwkrl84Gae_ z$P?KST~DRi9(L)N^3kesq@V=dAuO4|S79K6t3{;43cI@63F3kuV~V@;F6zIoT_69g z-MC5>%9A6OBqjO%8F&MA+~0{@bkBBMDn-t>fRg^+MjNsl@%WMpuU~o_wIl@8o8p0n z7AvZlvCU~1j&f?|y~IA{m}cVF^foFH9z$Ei)52deN2`QNeq5;aZEfW}_j~EC@8&%n z>j}2aY3w|z`~K1DQu`wZR;L2syq~ zO@xZr_PmV}bqs)^<8#O7B4oLK4I3+G7n7H@N@$1YJ&vNSvAZo)1`VqFE;4F=-6Aej zkS2Hb@;eBZ@UB1K{W^RiW$BUS&iA7pp*r7$I1LW9_>n<66}skwInR>%Qq7uZrtL9q zzqfUuy}`TR%q`-ix5@!hbz&7MlDiuVE6Mm`_2bx|e5 zCh5H+5RCRgkC@jKIqjcj=D|iFyi08r!92xYJepjvegHP(cenCi&0CB=WFU>m?%dVbA$d7`;&RLqI)UYaTT1R7%;Nb9cNd=Z3~aZ4DD!u9 z{7&2~vSW7vBKO`RTyN$@(E+JuRZw8B+fx07+`|Auva0+8N_f3mYDxvA=KROnBgN@p z&F67+y8S&z8_Y3m0Nb0A ztsdKc6UvH{#Q|VV-y(y;(&)F z_#@Xu?44O@pbXnx#W78tcWj}UlZ1WRvePo1()ol%=J_>Zd($n++T0l40N9h}aI(Ii z2x?-R%Rr@@zCVA5L^;>(L*qWUvLWQe*Q0g|E-cL%17b#3UgOq$E(c_}8`G<7j2aa4 zWLVygq}NukG5=**V>cO#_x2~vi76KQV*IvBm)&ncdJcon{6eQ&ShwbOfgk#LpYtah zlHrND6h+G@XQX!8rpxQDArW^jhVntyS0>DYdVNQn?u`a zudhD9o-T{1v1N1sDq$=6u#z9m{v^xteA-XiQ5^ez`c>IJk5X~&fy%`%?{?R{;Nd)jv=wS+JQ7hHWE6*0_gWefOlimOMFbTt5zWv8 zoi9+fE1l_f006egz0zU6rn%~^ai=RLEzV->rci~ljD24#|WMay}AFon# z6B6F8Xs_*b+iJq!NFu#LA9#Bw^`kL$#WT{ozUd?i9o4GETn?o(8-u!l*gIM2tTd*5 zI6x`2A*Z5K2wZ`Wxhflw=#!S+{Br&l@A% ztW^;A>@{iet&NzI4ureUX0&NQ(?bC>A?JmJS?#;BMmQ&{!U0EmJ#e(Ip~WgYcOU<}#U}C1Y#M6}%AFJD%@@A`SBj5Z7{VIUIQ&kX`I? z#09$-u~tKTn~Tk!eVT{84&j^0gfIPjRAlGQu4sC8;fh6G9r3}#-N-AUc)kvO9>NRu zVk?YT#~#9#UDJvo*FDhvd%|nI}jDG2U zfjJ@AGF+QLHVkxCBWpCc>k#(5h%m8dVSQ3jbtvwnk$Y+qyKiU2fF1FTer0mY`V-&s zo2N=nsoX07Y=aSZq7mOLB0L8OFbz=_ia#&Htf?wqM=QJ5GfzuBo)d$)5Q<5K@Cs4M z3>IOZ5Z?}AH9fc+5U!#TTcs&_v=?`VhpQyxs>rw}dvPa2an(uK+UMB%#)?uQ;ZkTG zA}stognMgtv3Z1VHOD{C_Clmo?3+oTlZ%u>%mp5{ArxCr*4pkR>xKA!p5k)jH10AP zdn^<`!wP#vSUe-=WY^kaTv*XDt?sfABkRNM+ax&c78vbwYUbjt2gSTUV+37&xU5Dz zClPmnj4chtUx08YAlxwsUmuDu?yI^CVQV1VWux{o58FJB!w%w>Z^2y(Jx+(bLd0Zt z%38se(x4n1`t`=G9!G>+VyZNC1EOL}SVzu#fbKr5?b#zrw>_MyAl6|4{H5*b~ zf;J+;kK>p#rDt__cN9C;o!(M+Ca3OfUER66b?4vLUBI2Y=y>i@5aHbAE$6Q0oV!*| J20>uS{{fyDIxqkL literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif new file mode 100644 index 0000000000000000000000000000000000000000..ec299c782f9f804287115c1e43dbdc09daef8f77 GIT binary patch literal 21338 zcmW(+2T+qu*L~6}kOqVvdIAAL5fMd`&_dJDlqQ6tq5=j5MMO|dp0yI#BW|Y00zL{f&Z1+*;$t* z>HoR_0K#GokQf{kfkqk-;3zB@0)->d1S@Bpr4!1Cge97p(|oZ6Qy2`mWH=>w)A9DgOiYk1bSqK6Fc6K8EfL?>9CMXk4QJC&qL!) zT*Fdr{Wuig5SP$ohk(U4K7m9E&Dh?}$c*C5j6oR@ZM<0+f~lpuzZuQP);9=eZfou` z$JEio*v{3)b0Hc>f+5j3GaEPxgTkA*$E|f;oMl4wriG_k`v$v4Wl%$t>=s11Em>jZ z&7$~)T6ip=N2R-jrI@?Tb7IG0h-CLAnJ%1UTfa~Zn_;PbsU&fM5T40?6@F;VC7(7Y;H;Sg<}lunb8)W z3r$_-xJ9q@h+pF#o9((d-8G6w3rnGer#Oc!a|(*LogeNVz0xIoISNN|k6uAvoKE8; zIkKYd7e?7Fh_If+Hlxoqc62A%)7_S2xJIP9MyA^RGvQ`BGP%^?rB+@G4awFBtdVD2 zHX~*wndXhRa&TXq?h=~d%1Lxw7)7vlv|`K$Lt(Tf8T7bpqJx{uk_<-DI@jndT2z{i zKgVO~TDRDh^yn;SPNK0hgJ4T@kISZWGu`7>xy7t-42*S;T}ca1c8^)%7M>%i7#s>mxc;-{X3&OgC=2b8sv@GTAje(IqtA+|?UJG=-tDG;TW4-UWpt5^bGL z99=O4V0YD%S7z}~Izz_%+`mciiIr_i$-|#=r zxBUSH{R;tr{{NxyzaT))0wAO%M#R zft8kFr#r4UP-Bm#Tt9tqxS5eTv?uJ$p&PA!8{UmyKXdrjer74!D!jXMw4Kx7vV5rf z$eqL7_VB&oXOG@HmT+dxlcBT69-QL!R$4`zJO1!Y_MM~4htHjOe4hVeXm7;%lTR)c zeR=m}`24A7R|OD^b)-@;(JLjorj97PUR;yeN9>EdaQfA7i}%{6BNx2W?bzb+uy#XE z!<|lH=f?cdFzPKurjbLvTdNGG{IBIv?wY!toHGBy;-EFM{1-dw1HDL2(FX7>-&!=v%56c?@$!XFbO*N~{6d7*qm1^tCF`Q{M#&@GXO5q5pJD_>Nb#w$aW261q8o!^LY&3FMHyQ? z@-{>m)%JM5YMVm?BqWq7L+HJNKjG-RV(FT<2R&}i#n`Wxo{_*&9A0+d31*$@$Q-I& zt;JsCfg2so8MEF)o+!#1*NE?t-Zk^1vT(JQ9SD{EriE}29Aj)2!o$Lq-UCCsX;U48WuY@XkXNb4i= z3^m!8OQ=-S&qvPJoUF})zyQ77!-+elmu1W9T-5kq|cyS%)pA!>o+-vx88@Y znMiHd!Rh>2+j0vFX`7J5wd6A&IQ+;|LQxA8Nb+H%X5-^^%bwaD^zMlM{u<#KeGMxq z3VXflXFe<3%myF?A`W!m8lcP8Gp_Fwk9G}O0@zQxVpF0*D2sE{9)HC-m z&&FEgd=qy3DS72vAQVqOU|P*dYf*F^2^|M8TaX}xkF3$M;0>XkL$IBB za5eL*h}6&200%n+@d74($Kbx7zV}LF09)t*=@5D;2v$j8hWcw>nZB(6e-OhAKC~f2+LcF)slo10L7jR z$7va5>7DvY{tKAvX?5_8MhdFqACf}mRHdg(AhH3w1hEbjp7p$j??ALQoZ9QZbO5l` zu^Gq54kSz;FsjEkLjqKkNlWw=bc{y51TvaL;Rbv0P3D>bORUN31;n|+g;Y-I`z zD#jjDd&L+QVB54qDDq$PJv^tIha8|@OV+j_fI*9kb(h19=3h*2@K9K-4=smub#0c9VRFTCY4twZ^qt-@`j0D0oKrXAUk z7^6Ft2y8lua?jS?A-b|-$Ps4E?Q^4EH%KnBCEbauh6q$rUdoGI%533+%kNB_941W9 zAn&-L>)7AFV`x|_dP3%ePE)NaNo~Z^#W-SHKB!Qb{*C@(Rv6Q}~MMx>yc!38% zNP9qRLPpyi!)dDZvacEW6Y}O>ZuDx3Jz&VU*WcIlk**(z#E<%mQF4wOz_VO%Y|DUGy8RckHaY}^&hvmnsc8Mx!ze0Xwjx}n9V z{R?T|a9e_UuYjpRc57Z`w9YVzj7pg4-Si3ln7xfRa?*J7+V1j3z|g~ALadBzfH3VV zlw%ziBAJNjZ$=jBQbJ%P1r=_6V0I{FTLok#?$C}VLCR}?0b<(k)jVy!?GFV+w)`%} z=-NX^tD*tAZ*>*Dk=Y)*88BR+hxttRx*&>J&ZmE#OVv^?qAJQ18WM(+{YmTkFxZn1 zI%I;<5VI1{HeexSDM^jGp$H_@3t-mLJGfS*#-vE`e!1zySeim?{H=>b73=VOHYS_J zv694m3bypn9^d+WaNJ=iGKuo83OR+aBOSD~^AjQV=)|TRkqO8#_4_u@>a>3s)HGg9 zc^6O}nsVAyG6uEl(SwWl~u+h=70AviT8tapw@%^{ZfELov1gd023ZL{@4yB zHc{#iB;dff*jZfoycU6Y;S2?%oPpURg_jp?c3t{|Wo$i`5w!48#{IB+^O{V)cGRirz-paO(*$Je-J3H^%4Ul>d7Vc6YE zh}MAG@h)q6AD;)mD)qf~lwU3iYR5Jbp{@WQm8ztg?4J2@FW|tA_yV@j?Wo28T(@+u z)DHSCTVt5VsE%&oe8l#L7$ZF^Lvz^JC_qHmokFx7Q=87)_LyF;t`#Cdh96eoO)FVR z+nK$l?n7X!--?;q@lw<-3Zv?|xp*&MXShWLeiN|cz|yqJf-i4jb4&88!bY9Hwa>pZ zI~lP<8WY65;U_G&mOo*oMLwSoCyOX4aWHRACPfdF`?@5;BNSI=2tq?Ic?nn%e^Exf z!?X6+Zr+ceX4P-_Ik4{YeM}+~BNf0Jfpt3z!metCy%glb2AdTkn{gGUU4>jofg0(z zdqjg4%L;aGz|?cWrwWVc3Jk0Zu}kawNDgCy1!Og-OvMY|2?7@o;XLRZxx>9>G;BfG z02`x`gZq}|T!W)Y0{9#NKrz=^^K*jbYcCBze1UbvcLF$Zv{fR^r!$xkLBiZoY>lF@ z$s6M@i)xC44aVb6a1pts20a3(8(d6k16kml>M5zd(I8J9WXG&L^#1p7ZV}8!1z#nD zdN4r4H9lOU2e*i0806f+ljkD^gbcnt;dv?+_u#+b>`#d??%kKm|>G%^vJ+vn;Yq$>I7g$iuY zQeqT;37>>X7x3U9bc{*$1UI*52KQYDYA!4?0m?mDZcF))l_5^uTF3?kY`Fk%_cSoo zp^9Y4mfIMf9Ad~Y=%x~P3Rdv@z>{(uO$Ji=VH)+a|2lEshSU;*D{M#%s| z!lRY_!#pM=K?d>72YeZj&HSpS+2?RRAN7_^Y*N(zv4>2Z#gzc4##q=vRi@Pu+-f;$ zX*a5cA@xXy?&raG#vs$>$g>O>+`h>>ow1DxNz%DDokrQq!9GIpMh4cZ5tgYE0X!oI z#`dNHWY@VyR2PQSv_c3pJLaPT70pIe#BKm{@isdAI`JMDeHce?`iu$`Y;zw)Tl1DH zV_~hlywrB|P&2Af!7ob0ZIWSjeMTMxcDqdgfm)BpQUfv*Z6<@DxSQA$hA12~kBNpR ztOqOLyN!u=shv)<{N&>-02w{|=Msx1*`B?Dp044$Z)T z@Q?-M>TxD=FCP`cGvwkSMmkuvKKk7kOa(97qYb*^rEfd~{%Hos<>kBIM&Y!3z#z0z z#fz6AJzo+YTt`wQ2G`qRY%X}_A?bh$GzUPH%F4PVm@qArkq#S{(xh*Yq&oNtX37`< zpCf60Cy(utL*(ZOgF0x69>egmX=kDn_=w6?#%MXzT@KqE6xM~qmNP+pO2P>}*zBiU z_{KGt6Ho=$?al*+6En4JEwc1Jrd1z7_cY?ju_veP&M=Xeb?ilh#_U-D>LPc@nuAOL zI_YhoBB+OG6Mk5Ryxkl?*Op>?lL;KU-*$PeJuC zm!4Chj%f*89(E{+_I1;CvwY~4iv~*O5nvKv$Og3jTTzdL2!~|fn=vHeyPQTQL&CcCP!6WEFv(VA79#C<+V{qL7TMB>x`2h-s@PK z4=rFGcVBPNu7DfijyvTe0+Dlz$M7M%eQx!zv{^v#13-5S74F9!rL+N_dW2-CCX)-z zj|LU14rg}2<%$EeX!J`zr_+OVt9se=|$}3+3l|wy}!-#@f$2K76Z0qnvR3NWo z0|>N1ah$Q8U87wzr0&x3YJCvpJiIX$8O*dU2yLn$i}DyhLu1(rIc+=Q{;D+B$x5KaL`S`jr> zgu4{O+|pgUX#_){$e<9~dB`xV+(4$NbhHH>Wriu4=+&yzTk?&*axopa3NRBBOfjO_ z8k`K;Gw>EqW5D;%N0ggDG>X>s+FZvrXgv;7H-_1dgDgB|O2DDl70+wsgPyL%L-{DN z4y{k@HJ>nIDo!+I6}oRUYS12W`;3g?5^Q-Ohwpan4EXCpGECEHyZWaV_IjF#za~;A@}o94e4Nx?wk$`N1GbI%3g5GvR!Zqvf(KO&+xcEf{CH&3Aq-(1C2vdy^QK&F7zO%fTWK=gvZ(a4 z3CGSBNG>d1;6&G@S=52=C9f%_47GHjJ$~DbE8w-f8=S85?&~qzTI0U+V0o6VBt8BF z53yI9uBZb?5|fL#Tb8IH`-eGU{fKl$4dXT@*}rga>&0RE(!HYT{)`W5no zw^hjpDb|wOv{#0A!`=rlPiP@70ZvzO2FD#?m5MXf{4 zH6EP1wMa>M92O119Yfw#1sluu{0#)(K8u;NZQfoSD1v41j}F&~2FtD79Y}|nH&<_Ww5$@*I&w1AiHyDv* zx@*s0d);^##$BJHK-?}NbOcAL3IVd+MNK-N_) z{K^LCZp^zgpE95T^w$kL$stmc*7uAGMNIYFfO|jdg{>?~cVZw+A7K1aNndo>kcIC; zOW}Dn^d7}N)7M7LI(TlcLGNCY1<%0kGbUU0c5gbgLOcFUgLzzNq7c9{^f2Dw+5{eg zHwg+Az<(4Pe`279Qn26LiEPzQbvArss(ZzyfV{uQQ|iD6`Opt= za~GpEzQcuZnBW8o(8okq%h&nNwYjhQ`eUMBso0SC3?rq$9RRRj3+}4|Gpb$hM_IgA z8*yHT5iud7swoc;^zPBQ{uC{{4afjW)Ps*qHt34~GRCw>PL%Np#zu-B4CV(s`Tq6M zcXXTz(~?%)!9Y6=V&Zhp$=l`9V%Sm@lqGm}M+QO#5#oFc`@te)L7C%r>~zA@TOhAd2$b>a2&iUk&dZ zv)=2Mc*luD4KG012TLt{*NzpV?CuTYC=nc)Kv{5|8EmL%X=I-k_w8iwAWvxEB#ZN` z^A|H7pCcR^&W*P&oZ#QdMFo!eJV)CPeSA`9hg|*AHwcuf62gp5CbAmF&r}$1_yv{d zGiAemC2#w(?~kSR7LOi%DQ1VBuhlBn$3y}r)6Zno#UJ-GX-94P!2UbgL7W}V3(XFE zje~oh3v}FQwfuQ!x^rfV|LD|gzhztAYo4@uI+G01Q`V>UC7N%2d+yn@MIT8ECg1_!EnO<%EOdC4nQif;_*ia6MX?u&WJqwNe_3ABwsJ|vXFqF{apN$!6F*-_-Mmbb)mnt4lPskaJE6{K^WqOoRv*o)=mz$m*tK~)sexH@Bn&;HeHMmvr<_sEN@t987$ zc;~E;36?9aY?pqQe7n)o+M+<6LZu#r0HHtbJlnj2x?^_fU zb60G>sa^l7C(zgAk%Q%Hm|0}nef-Qg$tAk4$Id3Y4N|eoeb%-#bm3BW6VB^|fh(Y- z>?5Z1@!Wnx5xNpq)ArbKHT*=y-r#ze-Z-P4JB1 z1&|$CORf^YWL{Rqmp>;_@txL#8Eq2SPnY;aB9pIeW9duyN$A7 zWA=oJFGWGQ%pV|*H=&3A*n;c|9{YS?y50=Xpx=0bVaQQi_FXk>K^DjLKt9sU$;m{F zWCw{DQW;H@Hyn&=kTMu`pMBKf|m~yJg5#qC7#^&$DHN0`x8uKsZ{_h4Cvgo7Bz7MLg1IAS@ z4z^nwat8fN`0Q6B8tlAm4*0%ofBvXqlVf!M&(wNU_MZ1vJ6eW~uwg@K(e304Xru7a zlxu8`o&A_hZ7BF5BWLLX&vRgACbugcW+M$P){cpRvgmSbeaFsK>Ja;-)2_s#(air$DFYhTQ7GWI5o(HpI!YNn_u##V4)9&Pw%x}_B-5O#6Vq;9RSTSdz0w0iJo#f zlkkYaF{}Q5GffCi?>(dTn8-3(;{*2e;(|?}9BYVlMen%sGra%{_pJTC8B3q~y z6CllZ_@)rLrGLgG|8YS-oiQ*#0`cJ|*u)P+z>*Sv1dUBkNmQx4`q0bD#!I0oTD{?@AKLE$RG?tKf4HVU*Xq6?MqFO{>j)$FiLw@kuHd9>Q?i z-acm#2Od}ZcWH$_9B`H4S-5GM()Hk{DM>eqf<1nhzUxuj{BLz&S>to{>meR$n~5nf z^)9Cpju%%yX-8fegF84)xz#b+F2YB}!~9^8ZUBtC{qeT{z%Scn1sUZ{Y|U$abOr9T z>F&(2__ZZE39W* zv|eRNDnrhHjZ0}6$uRgLLE@j=3F3}39rC&S3`KfrniUWEzIOmO9`^h%r}XFti#`mk zP{jG2Vew>^%C;8v$edePB_60~DD`%AI#NzNk3rRp-jR}iha0VgX&PpU;_LaJOsizT z!QU#>r=M(Ny6=X-aFx0_<-FaJ8S!R~inF5+)L%)161K&oCZ1@th1-ngIC-v+O^I@= zKZg>ac&{j2^QhqwAtn31!TgdS(-f(M(t~@wLq;J_zO4$K2r9c^^3rq>Qh%ttK@b^t zR#7MOJQ$WKu`Smspx&eg94<~Qo(o3)-> zh91f#G=08i3XhfqZ@Og5^;^MJGal|}6ddJ^91l8FW1XhZEc;6ql~a!R6$Zi)|2cAJ zZTG|;*)le<0kjHfwqVphr7_N7-DJNnH2q~|LWZ_d-S04xe1u|YVIfvQ*O+}WG3+wJ zJ3k=XlnJWR9E1)`8B08{yl&}l-iwNdWp3|EU8z!+h=qe5!yxY(>&c&imvzGHHH(kr zlw=s3{5EK@E#qcoW2wo?cthJ3+!HTHikb9bh|{*;1+B;J4u%r@K-$0V3xOnu|8V!{ zPOPtGX{@(y^R7{ECLUR>*NHodK0aQjNxYdJh{^R`KxzX^@(6n002jJV}uTSc+PLXGkQ{5J6MCcw(Q$Rx3 zyOnMBzwCAyzd=s?_}Y5Pc>chE!4;3XnB#lz?d)wr3KAsl(yKe<<-saO)I%qG9Mjq# zM6$K0EJ8ff;sa$J;dqe=6Pu@nz>Z6e$zHMvxWDR(K~AgLplFRZtWqy>o{|)_H~x6x zN#>~V)l%x%0-2}SdYAeO3dHs+Pe7inpb8fw&);u>1v7C=j+D}liDE}t{ic%wXVi>CXlTc?@;_06?sVYC$M$@^C!WG{A!+3BI z`GPr49l;EmR!K^ak(`PgVrJ&eiJT|fC9!P@O6}R>d5N-GjI>t>B7BgTqGRDgaOwdX zyXBynSd;)U3y~>T_gI>$%e<)l|k6U$NpCEUQE^?|cdf>6<2@)o)H8&ZKXHgtI34>Q(GxKv;6q)@+_k(h`Zs7eQrPLyfMGEjgRbf-*J#QD{da3w57 z2i;kKbo8?Wt0i`dP;(S4L#3*}t48qJ+jqfMiAK)hyGym4GNdGJEF^~sbr&}n;{a<2 zVq40hyN^TqdBXYJ8?)!|uwY$TnjGkf09o?`EHLn7pN7>caFUvC6$fqxo5dl+Ci!tj>KNNw8-x*WI9J! z^+;8cUHbQcX=e4Ub5jN>W0Hy%Q4lv`{g8OMxFLoDuNf2#n6rFyM&`T~y98-#rVvVX zS>7J0zku5^26s;g_PYR0eqIK|jr6v#R|ya}_k7_wE+{_kpmT-!e6i0sBpm{g8aFTe>OwZ0evS`rYu=ag!vigWptnKIeL{ z?$(D`k;K6yr8BS~z|@py&teQqxZu>WkbwiFExe;=dZV#^0F{1&6u9wa#yb%avJZV>~D zC(1IHCuXq>H|^1u`z-<6iXA&iG#<1@2iu$5LyQVq1WQV(06nAhSKzvDjEl~^uP2f< zQ|Y27IX%VP{Xrv+NB4VR`c^`YN?y`c?z;I_ z>Q*U5mSE8KL6VX^Fr*?t)5w>@-<&Yfb}K8J@#0JKh)I0ok>HoP6&qem0}O%vG_ZT=3)- zMI50YAzXkwb}JqK)ANjQ%Sa7>^7~16m~##fw7f-Xy<*O_+z1N?*zUnA#O%QDjnI(p zr_eBgfvzldMp#hXjZQT#w zlf(%*3*upBEF>53Z3rMsz~=(_!A5^pG@fNw8`fSig73ne)OmF+zSJsR_Xo!+O0h6Y z2k~`ZW5K;0v2%-3i6`;#X9b!q$n8u??jDH^ImN3&N8We)LvPx5EW-5W1YrUIUxCAG zq}-+(k4qc4x=K-zWU6MNBb*bIo#Fh~C{!R!#f?-9-k#0<0e!Zjjv(j}jh*0s^#o%+Jx64B|15w#ldCWnFE8!VtlKD3>Z4yO1B}~?Yq#;A6k)^)w z_=QxXQa#A-?*jirrm6Cj&~tcmB9z@IJ$0}53{xDr7>A<5<$dt!8&`1LmrKoF#e5>n zw!&hYki;U->1<*650TH>hUpc``Esz#3>Ncrg$YPR=Racv40Dum%{*a&oMg#q{T{ip za2VlP1d~mrWS^^BF(`Po>q!|?czt|lrYwG4YU#3-el)50hvVUN>g5e9@xK|XDv+R+ z-`W?alRR7A6dU?cDU9#kceb6xAG@=nBH{HcING)}WO6bB@K(Kkx?!?>Wu0`}%5vl@ ztA8kaVQzm!b|G>8swjMj?#+&GJ7oK$9!m`oS&dtWz_Qwf1})Kog1as5b-VUur{vY7 zGI-t(m+xKrHm`JWC!AJ#b*J;X%=;QZ6knbAkuQ?z4bY-n;N5>BwnJqHBLR7q5dO>oy{^NHglc7onaA3Do!~F+I z1(fDig7t@5c{)1s7ye-aLH)U+PFSm~}A>z2v5wR7F0*ZPzat zYel3Y(XyvI6AajrhBE(mx?|7R2Rty}UcIs@y~1x2e4XpJddkgU;TDNx|bo{AGlqi6B*Aw-m(WQI@g03%eEx%}9C_XyB5YaKx3RMCyQ#vN z5b@(Hi#LSkdS8HUUHAA)-X`XcoLS*1)aU^G_D9ELs%kW2I$7lwHG%o0jX>noGTt4fqN(;9I00pHW!$LF>0tECNcj~ z8t?abpcbEnk@||#CT${(e-bvYtx>&f-@*A_{qCSM%323^;k_yATz%pY>6i!d)WV+` z2V>=*epbAISJWcw4RgY6e~P4Q$1~rSB6FU6`}CaM7bxH)oN* zvwv5Z{CQx%)tmJ;pYb8;QhD}d+3ZUA@B8bdMcRQo^$&VMn|-D4zGl!5G~b&2 zQ;{uN{Th5B7fH)bWBoA?SzWOEVu^?Q8fL|o$#UeZ{c!n>CX2BF*G|%sxyWE(RblIv zDE#cyCTZ+a3hyTLNO?ss0ttW-1bVifq7kD(EwYX%0gzLVq#w_ovKy#2pS!ZB7h^Xl zvkR@YG?v&8HM%T2o%8my<49$09xV9)U(KlZx7AFUesLD$;BD7G22WFOcR&I@<%D~Y zcb9}8jybXBtIN>p1n8g2cDst{(__E^EdaWJ;lba z{lp)ek&>#TgRly>=!ch)5wpw~SDmSOfBp6{N?ZcnH_+T^!>12F4&vO$Py2*%c(pGy zW7%WB7AT;e*Tj*^lY664?RT5QGF$^6`|5S7{LC{9$F{4Si~Tn>?5>TC>9w#wCV6`) zQ%|D8;;(-Cb1B(Tz4C1$)%|{+yFuBTvKbC(=KaI7@B5nU7ykVn_7ODE|FMSsN!4aW z(*vfGxwUocMcY(UYR&p-p%2E$AgQP={8Nstxd4@@*5r+4-F~v_3kqygw$IJGmrnTX z6t_{ZM^>d%mdF6pOq~wd z(VX8<1y!L?w?$kRli6z?;kAwB4H-u(_BW2H+63%I{+U)vLih7mq4*l*%G9jgv>0*; z+I&A$#48we4%#>77x-Mh%r^S6S{a>7ZGvbAU-4!IXTiweQqTj&bTrLCbYCFWnl6H8o@>{hT>!Shjif2N9n!Lp(E}CqKaF=ry4~D;|z8I+X#Llc9}Zr zG}ZUAIHNm)O%k~VU2PQ288e@wVtc4l_R0wD3!(__9AK4^U+vce{lxS$K9mPnWtnrI zVQlj;zEX0XHh`6|F_GS_1okX?;rDGA_TO|({i4l$Hzva&^2$8c_mU}$d+>Mzj^us( zau(beT7DilA2e_w~ zIGSY4``APCJDNb6>y&@Vz#6(7ORDm9vYlsA8;R~vz%32sxCAZ2BAuDA>d?+(|BWgr z=Go%2e;sHLlYT-~HMshG%J)w7F=biRgM0bOn-v50pX9iOIXVe=EX4Wws@9llR}5wH1+$SM z9Zr8iWQsfFWB|2RmH|Su*a;iGs}@yv`EFIU04L?Aohq-%7NbZ`TMm{d_8pjoRW2Be z+(@iSo_t>4FwgP09XDtduz< zyQ*hj62wMc>w6Af^C8py!hiv9?BM>j&sFpC)lkW}=Z@wJ{ZB>h(6>x6CbDV;P0G5S zm~;0)hRdEdp3FePWD&y}hqYp&$d(m^Gp< zZG;;Y)Si2(j@Gd+hD|ikqx3TQp z*BSk$Ptg@=yg+;{chHA0y8Liwx=Qc=9ID#az(iZK(}Emw_GEM#zKsD9+eTO z%jPR(&~1`0@Sg#%*SarPFUX%$^*s8af4{Wfm%&JqIHY%8nJg_#nkc2`uI9Vr zw=Z%ba|)9uVC_ZO2D+D-!x0JBpmcBrgEKokFgyiD)^Gim`T-9PoXD{a)pu@v!?$`r z^`O3{Un5&CuHlnRo)m2k^DP)4-Hz{a|0OORF7ym(_wYA1vYn$8c#_{w@8$UgFj7yi!#ehk0}>}Gg@8ECuQ9p zejX3JSQ)x*k)a2J@yxOf{pW|f{l-qsJY-#Dl}_+}@pZR0Nonnu&j(Q7st@9ovVwY< zv)^AG$kx{uJ|4!yESB7J+Or%#>zD(!=tYB8PJk>|CDaW z>Nf*c;~HP2$Sw~1>;ubqW*>*Ie&i?)7y))jSks9?R|kV_BcB$MSe9oW7lc8?tX=

TF zQx46DD*J87(;8p>EZed(Z8T2cvLG>b1dJs!*^NwRWCFSGLGVjnEDv%S`2@?oft6aW zTMm9SQ8|Y%bXMbwWnft2?V$pd*~^O98I9qjC2K}#rX@H)H6bbC>3p?yQ7CRuFy48u z+)RC%^^lRBn%kr5>JwSY)s+F&^Y~z(a5)4W&2kou+Yz}AY%aB z^iT*sJpoU+7BHjgnueb~5sB8dx~olDdW318=FGG_L?t@^FMl9lJKYai=m&B+D=3PEU@PE4@{S%_X3iMCXm`@@QPy|$fcSPI)VC(xr29y%`M&V!x(xVP}- ztjd^s!<_W!12fU1XE(nQvWB$RSh@5vlSLp8tx%}UnSHy}6}4@l9%I7rG3FH(6p<9V zLch$jXS^VuJu|1;MZ7OVtO2w7XpL;z#_)yJ!i{8&L$(U>%@E`x@DA!T&uS0JZd%-@ zu{~bCNomC43pHmSq9ReqZ#N6adcAl|cahM_$Nq4fz?n>NIIdnfuAW!HF?_iLXkqE^6_9zmD-X8${RtHX^%&o^vB^|rsK-fs#V=Buw>$(%auA3}0$wtgY_C9@5ig;P) zm!ny>uoQF%x};w0t#9MEs1PQ5^--qV_Yjel@=fCqd=}I4vU-Uak&hjx5ur7_DuH8!HLc;M^LICJScqRLjuj2K%4U9n{X^Vj{V<+$Y^Aj zoFXjzIN*zABPl`1$e29XgYY0+SOH{mYxxJgseK=%Nhn~m6X_l75(mIU5BAN0xa&X* zPKJ4pHM&Qu@zg&27}!+1BE0V&C#Tn7=HaFwFozE@n0ZzZufnEuRAp(z#pO14Rra_L zXG;x!@^Brcl&BL`)k00V8W$7j?e4gUz;KlY=a?Zd^DwScMBB77yxRwsNP-;enRXLR!-M(n>-sL*70_NTXQoub9=dqe?L zU#!T1(wjFCis%s9?jb+Nv8@>U6HC-xQnAxm`=*vV6^5+B=Lr@LYYt(-gl-!DxB!t2 za#xwT|9j7JO1JR^rk(2S18Dm_=|u_cfKFrDcWqHkgsl!3i4OcAkNn$!wP6*_Of=($%>BeMLRy=0BX3^*1O*^BGL%*_#%qY*KQ5Kg1eUzTH-4Z3wZ z)a1jEB(m2?nQ%-foQ^Eb`_%6fS!zt5cz#__cdlYgf_?I^gaK_Jf~~ zX*V;TidU45m4Xvy*<|i}r)rhmB+M)exc@iIgs1Y7y^M|ww8CLIjjs|<)~4gwTkGk- z%Tnv06B`F#jlM1i3r?8vRP=2kBjkZZ3eyzJN_&oWZ&~>nk)l)acn&2NHaxryzRw7&G^NStAiMjOYh2UWFW%=4K=$Lv6X8) zGn-9U2~0_9j3vk%wRII42g!}8y;1KVcJv5hN?UnO*+XiNnFk^%B>><#e~ zV4(j#(*Wi#!I(a^`gQO;OHCqPWIP#)76{K4h#UxCA(4XrhF~6jXS@9XCq^NS0wVN* zP%?p|k1vXPF5>|c_W``9PmCeG%IZ)VQfK8JcZKhZ%V>K{eW|4*xUU;ub&2)tmj}+p zd|+jv1-?Px(#dkWgkcY<+O7SZNvE&y<;k_q{XPniF+0dCr*c~XldNCnbaySEsQTex zvKjV08V4Y;V6)6XD{HaBQn5J1zEn!~$kNT4me4v7}owjt|>^ z^gOQfXgv=?p6)Kb)aToP<|e2d(%7fZMnUQ*`okFLY3em(dMdtH?9iYJQFMf9Hf12 z1x*sM#$Nxx&tXn&rh4Y$Ea$b(FMHf^+d_dh!4G=d;c3o89bUGoOvz5|Z31?K88M3KgQ9noFfpXUdTy z)i#%eG*a%GE-J?nk}uV%O-NFQbTp;f*F=4v^b6Rl{L#n4t>InerY>9paJvg3P*h|S^(4BO zgl*dO-P7aVe4nVh+T&YnE^eQ@@c3~u>sGslaIp4f2V(%v^$GfW<@EWF1b0pH)nEi- zW}2cIai7%Hl(wsaWyia})jLY&1Mm_R%B}!B{Q8bfJIL9mI)B-p19%^#gkGkHkThc2 z?wxrjezr*qcVDebmMo!9wr^<(YGvhf?FZc(RMGLWtvM3clHHf@wQngjo7!*nkox@^ zM2HNZT*MdA!9Ty=AauDY;m-v_w-$Aw3nZ?Ig$0V}o#A@IXnXN|9mjAzM&TPa8i+8a zRNCm+OE)kt>I$56c71E@t3KVjkZCddby7_TQz*G!$RgV)i>dFje%0N0EM+u7e{TQf zEo!2n^g~b9GM?U}9j1w{c~X_Q450g?d(Qpb6^zqz|zb7kG0r| z=$tdjk#(twqu*{-X1ee?Wb)g#j{;Tzl05h7cAQ6IQz=0C8}Lf`LWz?cr8`HqrcvXi z$GCPo4KVg8oOv^#Y%GnoH8_vhlFQ2qR0WqW+A-YvGyOuhRYlxUMs)Y8kX+}72{`BC zO?ASLS>8W=^Eyj$)fe&;B#x-?UpXvd`A<{k4GWz&-95GV0COG|4zS$2@Y2bZ?3f4( zxgF{aZsTtU-1kOZ8Fs7{SU$+ZuS2}!`#dG%>-DU?33q*QRUO@tI(Mgp%7U*!tW8b+ z2@a*+_l!eZi<+@kcT-cJST5d2EIYVjJ=gaw-2l~u?xTwdlf?y1KL))=1D z;fVu=q+TOKqdewWFDG!rod(`kZ=YJ?l!??l9bWW`hOv%ng z75@;w7ERb+y;q)#n^|_A{B6cxY^LwEtT?--%6=eToY_8&3Ol?2y{BSj8w1C+ow>F` zZO4!Oq}`q9{Hid2cX})~@Zb{%!kW~D>n}%Ki!eaUwBEl|EX%$#TTW(sugN4C-fZpJ zw4qE@vaZ?WP!v4Lv7SdZB&rfJ<9_ZcB)bH>#jSZ55rv`bS!blrHi3c2`e%g=C??+P z4^85iJbhkBddIe5^&9Niy8_W#RB1zVto_L)#Q(|)rO5#oG2|pfcQS~&>oV0p7#x3M zVaEsxce4(+m9V&{aTj}0Ra)4`BNNT`xFr1YZ$)_{IU(v@ujVvOx5&lPGzmYH$$;8;$H$5KGm*S~?H!pJU;6|<}(oj1GVmX_u3KVAPN zwvOj%Flb9}2Jp>QXhSCZTKdA5>ogrmC#m4_Y0VkpazNFQ!$kaGFj5P8H-3a*FloBm z=7$N%r6-Qa;c5x^gY5Bw9*OKZ=lWHY@x6-yYK2OUsp$V`baccu16_jzB$%+&3g z-SSMr*@4b^S&%CAtBHKdL*kLX5Kh7hsc}uhEqR`>gLRg-)6YnOSNI}YI2a` zWx_dS-omR7eQj@GsW)L(U=&#TR|(Fc6{rZ&p0zp;f?NibkQ8>MLhY0(%xWU8ZMO@= zOz1pQ=hDgj>XPOO9O?N0IMmun?f_pmDoTp>pZis_r2T}yUpj3*q;?xsApO1l%fr6N ziTIc69YUHxFM9|K3!^F40Yhv#Ouvvu4cK4@Fbxn6J9XbnExLWwrC~LzD{Z3$YRl1+32_(2dIZ9Vv}5ZMT*&E%cwFz?CK=g zWy*+*DhmSR*hqc=bmPueJ*l|2XPNi+%2mEQt{&gV400X3^rZ}Jx@z@zU|lR&+>NkY zGIM`f-C8w=tv>XwQpc-l&bE=OYy&GXF0TQZk?xH#F3dLRDyza@uD=nR(Q4V{TyDXUPAAjQVgMHgWbt=gT!n z`<~%^KT)wiEf?l_O=HE-OwIAzJwuHv`~6)WK{>K6rf+lh%5gRGT%*2%6Q_GDcRV_b*5 z9wu>=!4_U0TMzDPb8t)im$2OSpMpgDF1tQ?ra6o)z+lORw&CE><^Q9xHnx}8VPBu< z^|MFc9gqrcL6aeyd@YjM(tUBwN9~*M@Yg$mn1=vSrWxzsmGjeC+tOWblm7G*?MO`U zl=xGLl6E@wf1%r`IJ+b!r&7-M&cFbNli)KEY_(tGv#I^4Say76kYk=k;E6Sn7t6Xj zh7SJz)87ZU9X%ET*f%bSam0O(_7x+FF$Nd*|2r?q>BsAU0*>{am znV1k?sL&Ir5W@{XSi5R)>!#GKEF;<{;kQ@IpR6BVZ_Zwz4Z+9EnrI>!a)-JVvtVN9 zi(jZ&zM#l*<#!2s9E-e?2L5*1Y+m|v2m7hFbS?2B`X~^rL(xTHneIF>J=^fajt}Eg z=;AlwzkhRwj=z@^GpDOPPz#h)?EFVc9PE*<5mC@b>y|Oq7uzLcU_tXjWFKO#9U}Ookn8eb`(|fg|3GTMSs&Rc9J6 zgi!GlJ02giyvCv?5KqK^1u;vLUK~nLh+mw1sG_-{GbkkplD$(9>CxLpRFrx}*JX`T zfN>R4@T$xv0X?$zU+V$XQhkjj=rpQ4Wgw#6|dUQ`b z)g$RJMW(&Ro__K{59)wLEjmPGC_Pk-43BO3GzFzV=5+L7Tt=62Umq5(HWJWwd5~)|MyMt>xYMp5$wiqj` zC|tCFG+qSR3N5-Iy5V)YOhq#6q1b>VvWn1B^lZ*oBwvCS(SW*GD~H&p9(HUZjQVd6 zMP)>=Yw-agv+a7$fR41d1+r73tOfsR#H2Rh zz`iz`8wg-$w3Iv?>k(w_(*Nm|inv!LI^-E(zNsR&ySte_*yM?*hN1;B0VmhEzwsU4 z-$=lYQ@_`LeXe_szv7WC$7U%)WqNc0fOnua*9pM6aSNb%+)t!u=(vmb&Ho!@^eZ>U zIs7&deB%Kg5mL))c!=AfCr^OhM}`EEfTeoZ2CrI7u)tQfs0eH1e~6`hfVM;qIfiBX zUZDe%CVrWSEM0|oti&)^R7V0l`+oml?ve&{epmO+{}{_jlE3clrZDtq9-%Z?MP4UZ z)*&H_A^x*{^DX5T{wC&uo#=4=`>+Xqv5tNtPxx8GwFWs)){6*>(APwy@w|;qwPG#U zU+Boy#?n&GdJZ+x)8!oV=8xhd>k)h?jJ_Wa?4KZj9PYq zHYop*fTuzNCTg1MjmPbpq}|j)IV;=2LZQPo0<3KU@meZZrowm*$?|6aF~EE!Tj2MK z}6 zmk1z4DgS6oS-^n_!={B_8SDL&xNGw9ijq}LFc+<2+!RnfK

oXU_ysEV8LEVxn|h z>6|ofhjg4{(RwipBQ|h_78((eqUUDJY#nwDUkTD^dW-iEUTWz}Rw7H}mUAdIZZX?@ z@jWkN$Uk1i?g3DHQ#RbP0@O;Y9xdxZN)#LsUM-+zDUn~~R7X1tz7{1m5mK~tDg36% z#M^l?Mo~+x(67-)$Zdq&idd?rD$>f~ajR;)3Z_Ovh`kV+{lN8oEa%}IkpW2FDvs2| zY&f~)Rz1tUmXy0!j%kCBnec7!LaWsK+fM$U>D zDXCh8H#$a66skBf{qV!dOcvc1?uz0_xD#u9k%)jP_@E`olj{d#Qpl9&&Cy=^S#KU{clp|5jtZnZiXH9 zi4v{@@H9ET$w&!-Dcj%=8%xnErQD*{A=lba=K8!+Gzsa%89dOHhXncp0;pJAc6;BgmMcW{&;BgJTDzqsI&}L zTKYnaxad>y<^P_VM09y+d3ohX`DsqY z+2{(N3*{BRj8t6aR9=a${9k$H^^wY3oT}T=Rd>p(?u}Ia&Z!=Xu6|rz{dA=I1*hg^ Pbj|DXntOf_04(`Grl5?Z literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif new file mode 100644 index 0000000000000000000000000000000000000000..9eb6c4e57fd2c503120abffef83f1b25b13b048b GIT binary patch literal 3861 zcmWlY`6JVf1AsrfFSZZc9CK|(j?hR&j_)?t9JwNtG*{>?SExjN#)xukG)bztDn*T` z>3Szelxn)@c9u$omlD0N@B2Rg!1K%VczC+o*+)VE1pEa4V`XLKpMU=O`|rPh|Ngza zyu7ru^y}BJ#l^*+KY#xC@nd0OVSax8ufP79o12@Rot>GP`TqU;w{PFRe*HQetPvuDqqK7IP+$&$`XFUT<%2Pft&GcXwA;*WJ5!J3BiS3dNs){(0xlo!hr>-@0|{=FOWo zZrteT=#b0h*RNl{cI{ewdwW}3+tsUATU%ROT3Tc>*_A6-E?>Uf+}zyM)O6|6rHdCY zHa0e1xNzb8`Sa(_ooi@lsIRZDtE;Q6t*xo4kxHd!&z?PV=FI8Sr>m>0Pn|kdRaJHJ zSPm38po!OYCe0|yT5-@kv~zI_=P z8R_ZiX=!PD_wG$iO-)HjNls2qN=iyhOx&|)&+gs3|M=sNUAuNABqYSg$H&FR?cBLD zHa0dUCMG&MIw~qEGBT3S=kM6DBO)SV`}XbO;o;l1ZQHtaYgkxVXlQ6iNXV8gTY`gw zgMxxKZ{8dj7#I)`;P3D6=jZ3^>$_>wCLbRkZ*OleFE39|Pacow;o;%#?(XL1=IZL| z;^M;Payc9ho6UB1c6M@da&&ZbaB$eTaihJxy`7!ih7B9muV24z-8x%a+qG-g+Su4w zTU)bOtTk)aSXo(FT3T9ISgc;X+T7gS%*@Qx)YQbpWYwxw#>U1*Mn+5~)6me6!C=to zbOQqeeSLjBJw07rT^$`A8jYr{t*xb{rKzc@p`k&gQYjP)nM_t!S65S013{2PA`yv1 zRaI3L6%_)3fXCx;I2;y>#b7XKG#Z6MA(2P~0s)7^VKCUg+5a0q;};SJ0RI3M|DEvP z699GvfMIocGHGWnmTVp*FMWUa2*~uR=82=64}7S8xg<0tRatnaPD!8St63#3ECq-6 zw>EeSKJ8@OWuEI-`PYsd?!Wrc7lwB=ZCRTTY@M)X>8BH(I*P6Z4r8kP$-q)=jV>WSb?|twy(tcBr`LLdkyh|rO zn@mQ2Fg72(CnWoOwuhv=-j{@Czf_&yh|(Sd2;$&T#^5i8&F$Heu=mJzzVp=?4Xvx{#w02^@9Q8)5sIAn!B zhv)mqU)fs^=RpRZ&kMk{ffVQkk!GI%SUtlnpjb>;h!T_D3({QM0(L86N{xVUE}k`U zo%4yTp!3sf%fq;IrqVD_GB@S2lxzbFM#;vgtMQfT3LOc~^@tyPV&$(-E|0?PsOX0l z!Fc#ihO(ctf6=wSiFBLU`-gLl(#X5ZD7nHES2IXP4}r@{^E$5ugtKLTbXORD)x0n0 zT8+1DvgH)c*+AA5mpA0=ZxIM!o=-LcP98TvCT-2yYp!xl0#nH*F~cILDyZEgJ| zc+Pi4APVM?5YX=0nW+pOg`d32^;=D;@}~uTl|JUkgVZEyhuoi)K2Y0h1+H?2mH69i z{NZ|xJNbK%4L|SG<_28rBSH=a^R}+s82<&N>jW>Si}uA;=u5DWMQ72SRDl7`Pk)PG z_&r`)sby^uIl#^gioCT!F&SvR#K{Gk<$6S9;hhQf~Z~7ny+ZdYl4| z{aLnxR*}%F8?#Prvn>Oo9}mGZSp^Z{R<`$fR6mDnp8JB-#Q9>DbSo0(v2jI?(%3dXfkoT%{i;UvvKNc!-}-v=+LYLBG2>~G zY=Q>5mgrzH0$a_8(<@p?=Z2Xm#{)1mR4r+neY5*FB}$(?QjXajt;ca8SWFETsPbZg z|H)CC-zm!RSs?H+KAiEorRI>Sz}yIctUjyfOa!|jbPpC<|EPy{TbxU9_{D*4)u}Ff z8WVs5S|S`O6v)Q)C{5Voa5}UDbX5;baVd`Xp!PULN??l|M_*VTAqYYT?ayT@jl^Ly zLJBfq4Eu*s{zah9AT4|n#$`(oGhD+d*;zw$D~Yop1bX75ERoiEtv-41*^&IKP=W@@ zG@0>N-#I;W>I#uMI{|kHFJ>yaNWiZAOx!P+BmHja43d8c4nv#fHkLj2XCB%)7;9t4 z*MQk3OTr7V)C_guQH}9BhX6#18APC=XyVHiBNL{&+t1mh*#5gD0GNzje^g2RQl z@NULHK zW27!m6lH?hkJfps1>pJ5ZHD@QI9pj>!1Sbk|5UFDcppx45^6dgsA9+Tm1{LwTZbr$ zktGUaAPru#(RAG9;%F1fGRo^We(sgU_b!f7PtiQ{`X-WHfN&N z#8`fETV{&cSyP49duguWr@MK#r=l@KJua?t5DEp6G=o~mx3jjC5!8Ssj=JlzHcH@4 z3PLTt7I(!VuOMjcPI!QaK0*rR&Q4O}0=mhaDHzQQ3KTt&qmn~E5@DeU%+rU>Q8QHo z&O!rQEkPuTTYBorlZuSF?_q4H&}6Jj|0j0NX~x>?Kw2z0-He^~Fb9^1hVq-706gw) zslhywn$@v;JC9X(jV7cW5#2@e221tN7^|+edjNEcn%_DKSF~V@xg432>>+p4i`Oku z`Me(7T@MGHz)}3XAm#=zs)Ia(*CSFP!iBGl6IjSZCAHwp^i|6o=77G67ml`WY=@&5 z%D%)tfn>SR4%QykcrluDdOySP$wdoJiFnueA!F@L&E7g=gL$XzY8-x4=Ba~hv=V>@ z<6ubO&Q_|LxKDay4JNidGtpshX6}FD zS)d4OLl@qAWC$u7n!3))26L8F#)zAEj6*6beF9oW%T{0jK~P;}6OtihGyrH=)w9;q zqY42wnGyW9Uw(V6=*`J9y3%cj{j49ey8Tb)|<*J%zic*XmfxtyC zi_6D=4Qpa)ycx?Enq{T>iYSI#Fw|dpw|KW9h0uGsz)T0og-~5XZws>+ttuvUd9ZqqzK!%-U~0GD>m4;o-~8zBa$V~P9nQz_RY_oi z&pN}zVNZDKf+SK(sYEHau5gyb$0Er)f8xSCW>k~@9L_c-bdVrpqD@hldOpwaKw5TDOO=r=5E>HE!QJb?Hqo|R4weu}^82_^ zEP)Swq%N_ML)1eE7`mYo=#B&bmWHj4RK=ahs?{$gad=UkCohIUzM9b_LObOkyTm~NJCbI#BqI5Ss@3`i~L%G#1l)RecN$n&`v9!qjdnN??3oF-1fkJv_W7)Z;w5nN;?P3#w}J_)u70zPmcp3| zm049xx5d9_P6)$ELJ}Z=Ck%oJ5+)I(nuIBWU_haa5|mLKP(~H?gjsP2sDM^9 zARr3XXdU?}2E>Y>{({`;ll?H9t;l;4-F07y?gi0ojZergST$ox^d%1e}Dh=>({ScyVl#= z+tbt2-QC^Q)phC8rOwXI3l}b&J9qB%>C>l9oziNxCr+F=e*AcQdwW}3TWf1;OG`^r zQ&VGO~-@e+~+P!=C*3{If)#_clc5UCjecQHem6eqh6&0nWr6naL zG)-^WvZbh~Xye9>g@uI$1qFF|c{w>b+1c4^)~s2%a^;E@D>5@P)6&vXQc{*LU#?Ut zlai7W6BFa(<6~lCqNAguqM{ZrUK|k-v1rkvu&}Vu&``Nt9vmDT5D?(+?=O)^=FOYu z=jS(f?pz-qA8&7OPft$|4-c_eJZsi0XJ=<8CnrZoM+XN7dwY9ZTU&~vtgWrBtgM7W zp_!SPKp^1pcpMIg&1M@L8ygxLvREtzgMs5XhG8%aLlE@Ug8#MR|JVPu0;0cA2!LYX z{O{p^nE;F_05L4(T1|HegX@&gr)|7aLE6e*9}aH1TD;*?!o$9ZrfC-OzHtvDuk7mE z?a2IclC25tuSkSPz`Ik=uFi9VQATFYD8Iqo^Mhrl;=cwB(D!6mAvU9GTj*iqCpmCt zm!O>$D?fju~3fd;OcJ#sa2#Ucvr!|elF0>KwiDGnXwnGaRhu+_LM*O8R)174i` z7Q|7#M0!K)QGRV@n2wMw!f9#TH%6)@Cd>4zFz z3KWzrwU-voepuKa$+H$?pkT)O?n_^u-8<3Z7HfHjhsijtjKOIYKb8L~U7U8qJrNzt zS8q6zIX)pM1=**mrj%pNaybeb|E>;tnXeX=feo0s zAZbaI+Nb`ei>p#TP0^;Fw|y7&Jxcg#z|K5 z8c_}{^#6mZC{yg1WoCBhhmIz2pBE5e2(4^#Ubhb$9yBlJCuJ+NoJ`=JwL%@#!lb9X|pAD(J*B)WXJV&$>}OiZGgMqH*3!Gs>Jn(@bkeufbcWHK znXGWMO_@g2f_+?E47P=;O=z$c*8D1g8xz|}kPkn0 zK58tByJ!?(Vj>wj(ed=+FV?-`t7C5}5%QYqoeDP17_=-6QUBZ-*l{OpXMCDIMy05A zo#OUQL!HbylG7Q{Qou0|B_(%1M&3?LD6wh>m_CH!J`;dj>Lu@N>_~artjI!rvZ{2u zt1E*;)m#-Idj_cx@t@Jd@%_g{Ey!UH6-YA#-Xsl%F`Xrpoa8&2v{ZN~zFw)5R1J^vGx z*qI94V^+yL1M7?wzN@O&hMMu#l^uN93mwF0Uh&PKS$FuGk$olS5d~O=jIbKJ_MG4~ zc`W7h;jmwvfjqsms#*g=eX)@=Too**I6XiCTx9+q0^^6mypja0e|}t-5Po_ z(~6VX{Le_a%lAE+_Dz_n;(-e)rm?$;W5+)4pz^ge)Vy*pqyemFXZw*hMM}xLvq=a&j*wq&32I@ zXTIF()6P9)ZsSXo*~|I4ydJ6q1_9oELc7g$78f-Mr@H_9qKCFetxqPZU-iD9MM{=z zH@xJ@FkAS=+3{jgyVLN+aBEHEtjuI0Jo6h8&YfeX+~f9xAKXw$Aks@^elc;k{Zk^M_bC;^e=QiuV!D@1Cwq+$kRgSu zi|@w(W|sp)Saa-g$$8O%nnox&noKytWsawyQX+_4(;!`kC!@+%&c@^{giW}myE{oR z9s!(|^Xx$Zs={k)ElecAj7GwKgkKgwZX~gp$~8qI=rLxtD~R+V0U=%hH{voH7CWwV zAHh7OS@K4x`s3yc&n+PdR2)d=k>MU(#!?bVwKr#}VSlYXei9Sf#9?eN6HOVhmWUle z?CJC(5umi_CoF?#B>Ik&LKG~NFI`;?g^=*6=X|CDo~Oow=a4JZmUwz_=TIr`Muci$ zBdWrB3gn~R^VUtyVC(FYFec}jXd##q(J6-qWRs)@*Kc>9pK>G`MyURw>v zHv|lu8)m~1>J5f&#L$%(Vldm+4W4t(DN+Le6C@xN6^JT!cLvWSk6cd{UG|3~$Fq;- z`uIwHVn_L6x-jGo9;t&LwN^2t%Ig_C-#5#f&aHA0W7(P=#3JwE2@*&lR@xaG(#SC`Koq!OY67)B!u8K1-MYOF z;$X9u$ft+`9dZ9Wer2*?D+kz;c11KM*4CH;Bu=5&qMP|Gcju9`#g}`C0x^-VCFsT2 z!Xw=N+2zc1+F1!(kdQ$(Fc3plH0%Y?1tb;&@QiVMy$=5=m0~u!|KLepHU-jH^4ejT z2{~UlgRdXQbL+4O4JuP0jw29W;hIhzI0EIpB*jmJ^m*D%ur8qe1gStL5y zy=t53fun9UFn8Pi7v6bS3Bgn$_|DuDrcfF%{AnljYf&iI{r7NK#)pPzHY}je#IW{$;P~ZpdKbbru33_?*TMzN}y4jGg9*b9C3N;!CP(K>+A`urg z?4X6L>!9W~8RTS2*qa+n-}UJX)}Mb#+YAWtK9BE1F0UJNvC_OiS@c&Obr|gP=;cs8M|WfdvcQ&bEP1T9&!*P ze&QTUh*6{?4xJ-ctFt?<9Elon%U7kc*Y@u$T#J1-bp)Qj z7q?J=f$HL#K|8qw2){n@!z#HOSj`ae-SQzlSRf-ab#oK#jzx=*HOko-RSr*}J7Quq z2J9jl56edE#t&wi!J(3wTohehZsw?V{uKcQTGU3n+gEzfPKkukIK>cc(BLr&)I|(k z+-la9HiM@w&2@v^>ZCm_r3eMNDA8CA{^KxL1-8C>0vl_OOP;Uw_91U*!$awA4Kcg0lZ1T4p3nh7He^Wpvef90 za$BCRd82w$t{Y&AAxa0A^hQ{%O$(`n7@6c|t)MBMTuI^CG%>rB$R=^ecrxEcV=N^M z&1V0;f}J#SLf>-sr(US?FV5ax2&?kS`s;92EytT-!+1ch#*J zMom)g#Nck@#&1rfv)57J+9%TL1)r}w?NE(1OaR$2(oqk}s@e<{n@!w^H5)T0Vz{P4 z(Ef^?se$fiu~k~gn87wGGgIE@=4xx?qRadVc;+N$2Iym8QsR(sQKD zRfT+-B#mD4gR{8%g}^wwlXVh#Rlr#wUPDTWTVoC}-IwKdADE#Z^3thyTu_SJx}V&%(s|3CMA&U=36KF^JciS+YNWdH*{g8!e< z(NPYYLyAZRTw zI9o?Y2L}iHi4#3NJv}@;+yesx{QRa)nKC&(eokB*9UB`H8Y%EUd-3$?Q#*Fl*3_uV$~LE` zrKZYL3f8V!m8Uq`(%jN~r1?nG;X{q}>Vvy~+BN$9+xKr@jn^3O_;+~d!{ET+fWh$o z-P<>>-@JbH`qj%9&-?qIJ$?4{$z%QB`oI5r_~6g`_wL@k^T!{3xBG7Yw^w&dckAZ$ z->+S{eCgtE7ta5BuKkP=-gc_(WZTIT$9_Kg{p*)+Up{~R{OQZ5kd{SXrAwD) zXJ=<+Wu&L4r==Mcrpo1u7cE+loSZao-n)PPdGY-DlgE$$di2OB(;I1<>dth1-ZGoImS#ZU7DGhnUaz+Yu2n8GiF3bM~8=phlPbv6crK@5*!>H z6ciK?5HNM>R9|0TA0Hp7R623uM0a<0H#avI7Z+z|XD25od!s;!#Mai<+S+>T*s+$D zmgeT>X2!6Znu^6@fk43L^9f^!xm*mxAT$mHMG(Z8eEUxjF|Gjc`2QySeiaA@V0TZ|`9^y36dwJLd>e>p%sIS!$Lo%k zYp%JrUou&6V%xoxO*@=+ElW zq_p*zJw5)S(`(V$U!5*a-qGpZaSHk6O5ge6(uZdc_8+jK*1v7Ly>U|G+~WG-J6Rgh z@5Azdqal_^f(;d<$WcB1X?<8vxf`|9q8pnPk?F>W`lIe1=NNM5=Y#mezN0slk6un` zn>uUb!Q_Z2CV_Kp<=daCA6Ec(tGV0j&Y4#M4=0T(Wccc3a>^yCZx}dIT6=vxqG1uq z)gJjG(La{WG;9gC*M`QQQX)KZPVdaDueOIOR$Dm_O$Y44Miro;dOFLg$#oHkPoV3h zyl)@Frg&QI5O`-Jdvs7_;dpD!H02n|45h`CC-K-6OP=1Bc!=8UTW(?Y(FxvEG(>~` z)T3{Im=5MhRV0UkOy|z;g;zyBBOTs0HJq82l!GBRsx!3(P&0t1wpPVQY!F_uV_^$7 zd9f4y$cOvwvJ#p%liK>CdKSY)zLLVwVc)Fj*mO85CuUov(R;jK1Nn6DdpJW2k-*2d z{OfAg?`ioqh}cRl#ZZE4G-0hzjSMeg@L%in&Aj7|gp$d4~%xjKzWnBk1{);2#ev*%vAAhbgmR z;$Z5`zVaBW)eV`EP7Z~NUES!bfp8FL`BG#de&<8lr5#w)?QwgDql@$0O*2S=sQ9)40LdY?=fyb_4-tUWDTcJK)$`^K3AypB~^Y1wcm zNs-=G(M0lIa%kqHd*>TThps&{=rM@vfM4iWxjII=R`3k{Pla{!%{9WP()D1Bb@#b9 z;(wmTf|G5W1PvBEw84N0Mn8v@QZ6%Vg5cWi@4I9d*MpTa-s?7oMGKz3pUZt4dbW}vQKn?3V*aL1^lVCDtY@f7Z>BnhqTCMSH|RD=~lhlYE{wO z&GV}KI6)p_>@Ul3G(>*Tz+zyqjgwW4uIw&<6&mN+7|QOrJaOWST5huo=+35OHqtH* z@{2^N?iP&J)(ezFUE}terpkWF+$!iUmsFmJ_t1ztl>7A@MACVZFhTBM5}%;6)eCcb z14ECoJm*X8WqL2vLA@DsN<$`?84xS28k>3YAeHp7#LKsXw@1Q8w-xVlOcD}PC^bcP zlqP%v#g@&=O9`q{qOaTIz5lpD31FfM$^(|0RzPLk9{rG#td_Eh64qH&at-XYp_P`q zB}bD$n)UqV+oGh_o?^0d0rFA_fn+K&vCWjvlDsVl1Lvi+PTLzKy%ow( zQ-|tnZ4K)jVt@%tSF)LLARf3zi)cmJr^AQrYN$$|IaA1@9ZMywD`iRepxylA>Eo+k zUN^DnO%%eWrh2oAX$!?=z$tqCi`@xeagBTFLPu~_%kuJN_JL!a)7>X*cB`V5BF|Z+ixQ_U&NYSag}Ijbl1h;3j)ggGvBGEE&GaRl&_JOL(4Zt(hs)#P<#~ zmzdgA%nm$c7Rucw76=pq{em$H(EkzZT zeNV=V<2l+f?b77+m+V23>z3Kh^D`|df(HM?&p&y5XY}z)Fo&F+_ED>CCG2`EO^BZajZ{MzHBs~HyATnw<@88^u``_ z^TxB}rFjx)@P?%bP+Avp7(|Oi_AT$?wHqpDD&*G$ zd!nXJjH}GKHXb|DuAJDA%2A$w&OW&takhzja-QFS?&OrYUs1q((#g747vXe3Q`YJH zz$}q-$@OOOa;1b4|CD{ns%Rr{eimwCn{+wImtd?R#aTOdmP?TeZm?E>=aLA{iW*{a z>0@@-Xm*&prPo$SzZthrjpZkgMdQqrPwKr&2+FtgVx5I({d5%l)Se z5RS*{IWn@#D#;!tIfv|C-YfMsz?X~O}9CAWU6Yz%Y4Vlpi6wM zj@%@nY{#`D6X{gwqgz0nagCf(#`Ry9uOD;to@a6*iP=7sSeuj7fos2gIFJr)AGlQn zPm42bS%~r{s=rWQ^Q!anDd=BNY<;>!>FZZ-@l$j+u+Wi#a$v1Z+T8!_1S?uzYz_S* zj~-L=tahZmwD2!}{fls0!NLq%X9+H9l0ru(E8ut~)J&zROQ@6maa#dL1D!)^0uF_l z>DqgE5051(lLB{T-`7NJtJ$v{31dI5qGxBs zUue-*d1{Lx5op0{1?!T6mqP-njxl+RZHOlqf;h7{P7IAF7pmO#!Y`4$7~!sV;kd3;I($3~ex2eW~NXz2*3;O zm`;s=GyTZF6_XJy&pb8HDaq$(sMu`Oz)E3ofB6FJF*i+4k?MG9A)Idr@SG1<29M%sN1o*Fs#JIZZC+O9T;8 zJVsYK1Tacr8`X*;a(o;c3`!S8GWjNP9BbEYm^d>*n`l$1eDthG<7;A6~H0ZS~!V{|Z8ioJIrwJO#uW>%!VNV}>66HjVnfweT!C`}dQ z1-LTRXbmrf#(%p)3Z+Cj3cjn*6glzShulD78G3x5Vu`PpP{ml}sgMAtn3*)cW>mL& z0y&=DA-eo8YB_=Qm#|$`TLs17R|A@@A_4(FQpM^{B&#Ku8;##IfXOn}(H*QFkO~J7 z896;f;+CS|3&f(8Qk+^xhJC{3cacRjZ-N9i88Ae}a@P}A=8+|OEKQ2n=(F9tL>I`= zSnYOpFFnb?SL+0f1?ZJ-1uAwAg@2)n@ldRcJ3~iDo-@fHOQ=ilyrx=YnYuprYU6N+V3Gk1Q4{{IBuZnHoX3$7%V|7X4l@8Z@r)oxj=%IbZBV)G z0}~L2s8(?69Xz=&z$ae!Q%mmTWIHiSNnWCRmMA#?= z`+@%@3Z?<rq!pGqfjS0c<9Pgp`#4@Dwfd*0lh&sDsASXzYJpNSft#05zH_Cz2H0v5FRJ5M8_G{ z3Z3ANWo=RpX+mbm^Sk_KSeh?%9x%XE-CWI1B3Z*H za%|aIph2P}_yRsSr((^aooy9(IC+FMz)RP|ccY|m28}1t6ut^gk+2t&+z>s1MG?EM zTCcx;nO)CIm0*4-UkxJ- zsPGsGJV#x)(2A_G-pP#<$mB#nIQOuS3?yN^UQ{b(H|vr(HKJB2-b&qwXy8ULZR{H1 z3IKOA!f3@UyaP?6utF(MMxuQItQFFIDcJCERQkw3gqt9}qOj;W-tNslV;+3FD-^Fa@@KS)X~H z=orn8RlzWQpXCpDtO3tdbS4T+v=lo^esOUS8K}UQ>kdy|bjSKJlBK$nB}dtDa3F3MFK5CujhIm9T#1oLR4G(_%_8?tMf`I=4 DCCwN5 literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..3dfbdca55a7d08a672af5052a5fd1bc277a27dfc GIT binary patch literal 42182 zcmW)Hc{o(>`~U1_#tdU03lxU z;}__LBM=}cS0i&%96=s}A`y&&z5FeV%ux`OJW76ZeG>wahd@v$6b^-wClHLHqT<%K zgD3(@-bfy24%v>&6O?eedPWuyoRhqfKSbULVidKs`W=e1f;sVFcE_PcK@wK6P#sr@ z{Ps}tio0V_I3r1)T$FQ~l(D-aIT&@|D$*iE$>XRJ(W>?NY~SkzRN4?K>AsCmpu>0w?7?~bc>aXJZBLQt$3^o zh11^U?Jsp84QuBHm&anu9)#W*Q1K3S3)-iwqi0}Ywe;(cgm;i)&Lx8fFOR{9}DObK~Z+oO)D)wk|G9uO2n+ekY&BzSG}i;;!i(5qe) z3SwlWO(1A(Zhl=~{~i+P`oH!6Y|QnQ>PFVL)KhtTw{)+w&D7)TUCniRN~pB`?lFNL{Y@p!W!bsu$v8A5$VUHqPMW)c z%0_8KZqmW~wIu{8$nO{}BZ4Mb2^HeuJeBNsVt?TKi5EsFNJqe~+7k&MX8+sHcis-1 zo3*7K3i8EL&Q$?byUXB$=dPPk!8u`m)6bqdp&(3U$yg=H5CzE-dN{JaUVn3AxjZyW z0p^8*ytFeoqk~&43tUZ8d>} z@DWfZ0vd~ejws0lA>r3F)q<6kG7NNs42bukkVYuvq6E|n0&#*s>>!Y9XtX&5Vg!K@ zAP^h`;)Oyvp-_Ak<#IJOrZU!UyDlM+Sgevc3T1>sxnY$E+ts@LBnoAP#mb{lSS6*+ z%}pbt?VHVel+)RI4U0*)l@xZ#??fPdIh<;6B&u(9RUZ(c7{{p!=BNG#0teGFMxY? zX_e>Qmbck{!s$29%f1A)9r-e6C)sgxw%g~TREc3%+k9WZ-IY(C_rARm6nGvmNhd>j z^3oLU89F)H@AgH%8wbu8-T3%;E#i4;qV$17w;DqtE3bDR&G}Ej1?#=FY}(7tJ!W`t zIIL!JpnY8Eski@6!kbf1PNJuAbD_hBGh(*f3Tqzz{wB&+ib0-8`1W~i-l}Cvp)+A+ zVs!SuBfBi$KmVq)zW>OTzlzgoa9#3c_KN<~ceKyWa7`XCFjmt+Zn}OpQ#GPo?clGg z+~F+3WyiU!|Bb#*y>M z%8eb?OL1CEQ#$97^5gZDH_(cOY8G;;@k;YQ@>G## zPS&tpImB_u{L903pZ1}m?^5+kgORmo%9E}iPP*a#UO#pzBc}nrP#WJNWk#n#6{2eI zR>$yvlRrL8c&QqHL%yO%)2+31_RAB11Zqiu!3?Uq+|>!Ym@?z8ARkQiZdmInp7jXH zT9zkC+kYE0JEuJ{Qa5a)o&RvS{Y#J5i{i4MOJ!G@trI4%z0ZzsxVLb;`l!UhKLHPv z8N0@ovaJ2{=HyRZ?=Q`*E>|@#U&`zW-RB}Qk;}X6g?8Hz`rd$OUZpXhv*JI$*IWPcM3NlbZ4{l1JdNdm{DK`S ze14dWRht~ZaTiUf+6w=P(Y5yxl zQtLsCcMO=-M4!Fr-iv+2f#MsB+QpsNe!D;Im0N#;IF|RTk?oCIKwu5R)t?<^Mh1Vt zVk@l_R`Vf}Q4mkLYxUl}oKY^|B|#u`Nm)b4vg%(tk!9reeM1}*)FUi@L&TMsj6F<_ z67?eJT)MOGhJ&lVe@M<=X01BEH5`2?R;@*>Lxq zPH8ZeS%XL0v|k)aZ!oV@_EvpWC;w6wKv-^*I_ajRkcaJ+H=NB%j-#rKW%d0*@w)`@dQFYl_HK6X;GZ0wfsPkrMLM;4X@gNd;}@UjHu+t>KN!2%o%x}w&qwV?9=)EU zvQq7;19!+uDOHfIVmTS$+j6|>{Z1c9fAznai^e9O5GFfnLsXm#tWSSyhs!gZ49qoq zpJW`(k=zg>niw>w?m9wwxqdCsZ7SoRWC1H3KQ86|B&RvK)UJ^yabD92W zfV7LB^{w9I{HJ)=?6IP)r$0M)+;sCgf6Pk1L*!xQoXObfn-kb9>nG#BclV!&2M6aq z-}@6QfbC}b`~7Pw_x|K+U+*z=?f9<;!-IX=-wFe6+GpR0$lzHue6@OVEJD5=@3ap} zfdlL3lwZ)6#4fLlj)pxy)P<WKg_V8f1HJUi{$v_;E&& zT=I2d@~JmEOkuy1&u!1}gaSXGzTl;-6vK$GZ!XPokBDv-&532^FRton{C4xVU;i35 z{iCk1=A~=J(Y^%}xx%d-eRukfe+NpF-uxbB4!2+aZud^L;+Ok3N`}?D8mS`~MOnUy zAy17h;W{XKyh-XYaM47s%d~_Tp8GGyCRDz9-6cgCKR%Sw@ZyX?wJeBYVXYbN?ACg+ zxg@w-o`{EB{!4+_;HS^y-?$^{1+NAFI$F8jtN&$~*B^rGgYD`$5~T=NaFVC~DkvvL0B>a(?`t zoo~2j?!OH|&%nPo1rDEjkB4^-X<8E5Hs*ra!%6k|&%8QbAxEEQ{c$we60p)^%PyXJ z`h8c+$$;IL(iil$?k=XOIitZCmio*Zj37S?ccMhdV*()|`xASC*od1IleJ3Mpil3A zdrvMD-cWw#XEtyeA9MO|Jn!||cSEV_(MlTR#{Tnx7G6TA-kLIBp$mjA-v!!3vDH5} z^fP>`VzSTYxBx#Ap>*^QarAQA`Q)$+i;cHm0vbUQ%|p^jT-%wB`1al6({D)RcVGX@ zOJ7j_!c?<+_tnK`z-i@G=uzfnTw4~@VD0M{difdI4T|%!cX8eot@`qmR}xk6<8B{3 zf;8+cjX$4Gm`ICsGwfNF>?{18mCvtS=-d7H$_Zp_T7RUfu>*;3qe{V}PZRz7PWKbC|%4MG-}8McCKS|R90 zU`_q;!)3=`1f1)D@9pwqce_ykuDPBy_w}oh8SQkiI}SU&bRxDOcOaI-j$!hzMgIlJ z90G6;;JJBL;7A56QUJuYo}VJa{9Czm8{D0WJm0yrMT(SjEN=sY9H+zE>3~cU`T~P@ zM|^Nud=mOqq0c`iy^Zk)qngh`vBhp(L6Pqk6W_v;RQ)9c3+(>|XUbk6dY4GgUQMT4 zru1JcOeFGCiPA&2x2Hh*9R;mx9he6|_}3%29f1b-0=d12Dlz(hKa33h0Fzr()$ftX zMh^5?p>{Eo{)YfL*MI<1;K%MDU-4saxC92?fiVRTGN~jy$fTJGl!BjY&pIws0Frat zTPW{-#Hv*DY6J|Ns}AIJ#Y7UiU;{+JR()=)xRhnZv{8hs>j1~x&gTblBS|oJ42&HD zJ!=j2C&BW5fwO-zuNH^>IBs>tRcf9hshy1+$0J~PL^}z+?k3&H$X{ehg&oHn9F>m4 zM&D6_|Dvh>VwD9G_aUr-x2-vEkMGmC<0&kc!MZA+rK@%VQ|1rF5Mvw(uM2z9Dtqsx zhrTD`(@c4F_A?miv1-Izl)Yl0k3Pb_f+V@gK#YtahG`eZw?wAP5_`TD%M}IVV|jbh zukIlW5M`{mS4&0LNdTiX=MwQ*9=?RU22uwc|EmqUTN;0AJ*OS(Au}2OXz}>tr`3AV zBzvlcda~~y4E)Wj6VHeMW^0YALD@4bg%eYDa0B913L;IG9U*}O=rE)EwVbKiNY?or zW!P>~-R?D*J|$_9DOLDP^1@-sMsZ$+HKmAzuAxY;QzRF}2kY+T|6EHJDyza<9ryrg z%R9dQt*7>rf&P?BHkO>0>(MS(v7?T%XG{wNG5~OT;i*@Jy%#Hw#HI{dNvH1P4_}v> z5u;v+QDe`F-aBPsV909Pl~V%gs%7*Cv($n)AM35dm+i7;FUhD!+}7RW8kevRVlWV* zR@l#uz<+wq*9(yC6rZ>PhykN%XX~E7OK%J&f}#Xl8V+z=qscqr?~nn*Xx()s@}RWbIz4YN_!T^Bc}PRe(Iq=ch$0I5tRuReR=-Y{wD*u&!el_d)}v`Ddh61jcSGaC=MN)74@1t=OUt@_fw8hOP0r590!!e^OBrZZ2wq`W`o zcyyprGvxL(ri%O=U9^TW+WL4_2tbHN5MWvXCbQkzFm+|*V9tCNa8cIVk0jn}_O;B~ zWMq#n0HiB`R8>m@T46j4;=Lr|Rx6Sla8RNj;)MZUZ|e9v-UP`hX{!LXVu6KF_Ti@NUhSY5jF`@v(wyEFZXjlB*x0v?KD8_t7Ib&Osb`ndnhOq<4~065L@ z1BtKorcx{W+LJB8qt5`;TYMGSmGT7|?sWrRjYoeLT>IE_aAK^{RjKWAfJ>oV@z*|= zL>_qa5(EQ-gT(ME3NnuYZ&`(V;UQ!iNVnkm|86w>>o!wc3`g|p5(V)~!uW;c!4hX` zd4QYRn9Skmn$vf0GU<0u;kW-LLrlqT7?VYL2;*1*|B#ZTW}*3>+xaguLiWJAhEYZk z-Uo;etH&J$J1|ln{vH0I)x&3|WezVjO+%f-A>UD)gVqsOSoM2ndTT$_M>a_RAU)Oo z1&<6X_(glLNrPtaTT@Prs-pX1)-rIZmqyDiB6k*^8U)0htPm;ljc!)H4!t(Sk$&rc z`{UNUWFHAx$3SKNJOI&gHd}({RKpkFAgl~8AASF9q+Pb4?(#4H>%L`luWFDZ22nUd zud0Ue$xUA}zy^45L(_9S03>b4lCi7qaxu4A%dz|hiTB>CX~|BKz+EY{p^lN%3Vr?Q zxk=fu<;63*4($m+YOheJcyVbG%V0RZg6xt^($lSRf;FXCWdH=$pRUi=vB zSra3g?!5ThjIOCWfrw@(E0lYlWsVUn$|$DvFd zV^mXRMxPA4_TIPVQ1pXj+`WjgwUJ8`#f2lMD~)faWTy9T(D`QPuT57!7HqGJTLt5N z)spwcacsAv{*PdCcmNoWen&gZjl8fVZqEe|Fl!VY+^tLR@7alm9@<6L0);? z(u<$|(2WM6AM=<8HQVhgKTfYvGaA+sjRJGskhaV&kO6My~nGv*xI z8`vuK@vQM=ieN77O>-=3RCNTP{RnfY6;g1j&Mv*n=JDq=Lx|A|pBV ztrgr{Ou4bRDY$Ch$-ynKt-g}ZM~-#uv|M8WK8$z;A9{3p>+@1*M@s5I<*?H7u<1DO zpX3U!Ju7ed?Ff2|f$9>+%C{m-KGGT4ffwwMbe$mDT-J-HJN|xC{`qkNk`?&xH3B4% z=Cw)`P>?dw;qrKAdCEs^66o$@ao6J~k&il>2RhUiJJd^GY0y@?516CO)wLQ1zeeo% z?C>AeA#(r9-DhOznbV(M+e4<*C!Jd*>@MeOs12ico_E^>2aQ0yN1#z_zpGzBYhFO> z_x!2+54yh^5=MgkeBAT<-PA9dP8&sX(?|-Gk3JW+HXr2r^Eb*|e{EX4cJQH+tZ~@W zBM&4`AU6e8*9risABGq+CvddxxTM7xT4We=-}S4~sI6)y_lxDNn!eYCV=2 zy+O>4-6>jz%er5vpd+Fc zj{*KdJF8=p*$L^=|UOth}`zt{JZ3aY8y z@t=#}P$L-#&h%88i1NR6pz1zCX)-LY|IFKkoUIF_1Al-&W2N6cI{AIydBcWJ(_iCX z6>0A_`7~wbGDc1Qe$`v`*3l2EUx(m3_CKQZ_ndouLVD^t6fvw9%#HRgfd(L-+}itu zv1zcW3z-&NdGZ(ySmgts0J_iZ0Cf7b*5|6Ej#x3Z)`zu_Y{P1G6t_D{UCOpNMm>#+ zlF>+`374wmUJLt5k7?EN)sJ;$7pkhvx9wCvk&?<+Q%_5{cF7m1>7+MS|L~GH|0cmA2*2mmW!(@a>#FX?Rs)vFRh>!q1hlTj&3* zm_IlDW6Qnrv)nBg^b~v4>-GSxYW4Q6oXJR}-AJPr=JY!7(+))A#+cxcO|-=# zxi9ij>oWOQpc@XlY`Rn^_wnXRxAfybE4JOc4K_Txo}BqdY}MW)x$Y{2$W?9#VLB7# zqSVh0*Dmix5_P(y93X{G#qX`Z_MCWE)AwHSpucOh^5OcgWvYo2JNwk94)?_zXN0>} z_(o45ihK-`dx~7#G_T5d!kMm@k0QIa;C1|tiGB56nlybb>EKF_?B0qy^>W_Z?3Sz> zdC~HUX640Wo*(bucy1z- z%M2>~qr8feVo<>Oe&?_p35~HjJh|HbdV4l*&FYjM-_fb3@!iK7pqvh> z3A#d=oL`bZBi%jwNYqrF|L@Q8l3oGtcb^3&%%WN&$fm#*YuKmFOynb z2arwZwI&m4F*Q_m<9T{!r&TwRdG#(FS_uNHORo&|#abJLeHrCoggRsdduc()<1mYt(z-V*`G8 zeMkH-1NJ}7OhoOxP%4fN9sezmxE}ge>bQXW>RyYfA6=v()sX)dpnD<&ufFD$HlSM| z47tXmDwe*sGYa@9^Gg6RZjq6Sp3pkgL2};V{MD2G?{?Y!hnFn{d;sjdw#E-~{_jfV z%YFrMz-4RH^5%Q>|7}h2=~H&)bX^iV1K6rDZ&%y9$`%}L@Nmk<$R`Nv<+ zpHG6!NZ&Sfm6>SE%fC&TCziwtQPot0}Lj1Rv)|FUiCSh4$0`Q3GVO4 zX^zG0e*Ja7(h$mpl;fN0!+ggSqiSsYh?4u4MF%!SN{{fFsPK(k-{$Lb?Erx$VKn>n zDhJ@JHRs%7zE>v&p<|Fd=gA{w0VrVkc!Pd|!A^iV?rMWdY3SR5uJOy4Wf~n6418~l z0p+{v8SVj1a}_HScl`}gjteIm{*{+Kg6{=|8s{!GP#|qZ7U*a+g`npSR@q>|j%-11 zM@8{7xzJh-H%PYqFaSzi^RWoSci)B^UNYoa!@?Dflv-FB#>)Y>e9E~ktqYgF(C3t% zjKC~KU(d&d<==k1siQ-B0}uDHRO!xg-X*ou=g@TgK_OW{2$mFp*XEV)ExTATb|T4w z8i~06JHc<`B(!-I&5VK<%AEt!eo7~H|H0td^@eX@E?JR3x(fJRZ-if_wRmQdn!CDY z<1bAasax#3Wy`1^iKjbGP12=~Hiw^2%$QespY_x#Q<#@XDOQEDA$r4|s;4j@#j4aa5k@d5*IKT8XQJ_qArWOVWw@<)arYBx$kSulExcwZpkR5Tw1k=W1B5 zi9Yn7Y*^ax`>6ODE_Pm*JabM^Da(o?d-{yWxNgbV}u2! z?3Jk$pqt$?9<1-|^la8wFj-!c*Vv*ho`ZIhg+}pQ<1Em-Le5S&@B06wlFKCy z^xuy$D?8GEInFK9DXZ3nl-UxQ8Ap6@tX!hk@#ZO-`I*=UxQLsP{m?K#Mr3ej7~I4^ zBv+lqef->b&keSU7-%k*kP=InZZ`Z1@8}K1_g(1dkMG_>U3`e5$_&tavA zX*xywyNjoawYq>S90w!1DEV-Rem}=}1avY1oECN8m_gXx1=h#{NjsVKOj{epa*UU) zjYdGjSvur+XmYGuGQBfVS*hiJnNb*?h5=+NcrqhaaQXHBG9v_#C|W~0%{Ge6>NImd zV+{+-;)jtqL2j0bjZ}+rIiG2;g}_*g#eJ7@L#=?IP3J)S%YJEgL;6e1qwsz4j#twi zi+q*kg%X38l*8M*6~-bLd0oP+qSp;7P@ba|6a@!pocP5Bw4OBx?Oabm~*;PMovw z$>zD8T|{s^q+V~ia#YjW*RX1ffg3g_sks@L8q#in>e(vG?Aes|C#*jDPBUY-%O?G% zcnqYSY7JT7S}s$reN;PH%;uVN5e!!_$1E{RA`!#4X@}YOm}#bGQZboMB*S1g$lm_; zIL4#6k<2u>`^3Hn--B75momdxA{#lFb{3Br>qdjOT&yhFRSlR~F;-`R@$e3F20)?_ zi0qfHC3J^n+d;BAQt=vBbL|>dF;TROCC}`_JsU^HJ?M>hTB7*37Ch9f^RmpJx8uro zJ3ZQf@T1}%MPp&{1(&wwo=E0YG*x7Q+ zkig(9^TO*tezUif86X|OpmwaE4vnKbGWcS3FnDl$-}+$a`s01LA)B4#a6-<6k$(iC z>+(r&=~$N=3WPzWJXDara;!S^b*3Jn;%j7d|N_{VruRnsp^)GVqzQZK+wm9ckB2tLzr5+S+X)O`*P=pLeuBzD9uq@KYy@H^PeHf^a?Z`XebB@ zAE+)?n%h6XKQ@{skjUd&*dK z8Wga5BhQBcQL%(j$lLNVPa_Mc)4z{E0TEk)gSkLiKn8Q?9;dh_$>?)!%(gi|@Le{*z5lI`UaPfknTl9|z5W^bXrtBMSLtaOLRl>^2d z0^Dos)mlr?#C?DfF8v;7$4J=Za?gJF+x^Cnz$}O*#YShtXJQ0oMB_xBHv1yTjKD|~ z>g|CBTVm!1X3FksC+ zu;gq@#=q{{4>B`xbkOlVwl_L2pvPdx>50}-9qE=4!D9)rnFnJflJMOYS<@ag-hK?s zdkvP@KX%lx7UmFc{Goz$+KOz$ws6aE>*BdB^R^oIa}i?x!G&-lg+p`!>9hiM7(iL^ zV;%blUCTGxupuH1WJ2POG3N~N+)v}q6RW)wpPUaQ0JWaZ-8(-Ny*j5MU_Iy!CA|Wm zM?%p|kVlog0j5e_?0=-5jcEilwXDoJ8TOnfczT%XgsPF6IRkHHN7ndel=FI}Ad>=+ z1uN5Sc|X0(tPSzA>|F%TdK88wTh_A^25bl z^j1+bQfUMd9t-g)hf+wqbRbWelB3JwsFKz5Tl^Ho_M_&9Z=>Hx@Oz0_AWLS18HsBJ z0GI1>FMNJH0!hZw-YC+5a#n1mEVj}b%Q)$&GGL|pAF%cSo79rr&g9ge;lRs*qwe!b zMgrF+mO~@UygKfV?C@!d+RNFMmd6CUMvk2&{%rYeAN_a}=G;LUPH$$$U8((hCncN# z+}CiMtBz>>*!^3AHFRnL%ni$rQCq#On#mx-9BJ?oZ-|GOm#zv;pNDOvTP9F49EqF{>kQvQRYVUXA@idbw%yOJwSCjKfx`_9~wz~zE5IlG4K&Xkh%5uU`OTD zw`hL)qC`T{19~~MqM(qNosrg`cViU(xZ#V>GpAO4FR}<6-U@MbW35X;OzpT>ED#e5 zG!ids_$U&Voh7a?c3T`q++`Cd*_ictD=fF{X^P24?1)#y?hG~-^VBdi^jB!I;;+L> z<-jc^EDnXORF<8n+ZMFDrV5~p8HUv$eEF>%%IlHP%Jb>zy~tGZWIY-u*BY0umuBxqya2i zxs$_Gi^)3=uOvy{m1 z)A^F%pZ~$acR$j6m>DH~gzz#m0|`4*p2=K;CNXawX2Q0THd-F9 zKTp_A`qOfxzW2!0W3#)KAwW2cQqH>GFI}k4#*)`mH^K>YHZulT{Ldbqzh?WEZHz75 zA!e9Sw%3Kjq%MxhhSv+oSI!e>*%ue&g4j_}Ulq3wJ6vZvx))0V;Al@;>_~wFn6Kqn zg!(WW&6m+OPp93P>(1#tci3nQAkrRi%C%SpTofHSZ+{j5pe!%lcGwNa4EP^TdEcOD z8YEiN?zrJw>r!eN0-Av(&%Fb**e*hAt~|s zjTK|EAIR#tF4x#qOic6CYni&sc-2yK|Ad>yZSdQamtBW$zG(+CX0|8>fEP1{ws8}* z>Q<~z{QJqJ1aX zQ01_&uf0k~SYKhqzMSL?S*PiOx;&?M^sA-1ch(L`5*q1SqVgR*j0TCFU9Gy8Oe)v9 zFYTs}%pz@?*Vr(KF?$3fsW1wbrnvb#IxB{!5?yWAC_PdcD%+md#+z;I-T&?o*!Fvt zwH=fXxrrf4HF2X5#n3x#5JFi2HHTD6Go8@AQDh3N3n^CN6}cAdQ{Wm-&5Hx~pN6Vg zMuwOjFnj4AdER=RVT#ntVVMRQ&XKOYw&ibLl?J{gT*$TU%bm-VVPIL+c2!-z%Fwut zSum#3_mxS^#UGS?hmrmbPXUcX)bjwL*bEVW^AR`SxbuDIn`@qyHNB z^gp_`&#|$Kj(OG^r!t1xp3+2lA<gssL*$GQwesvHdlC4Gxov&|%R)yEnTiAcTp5 zOr)IID`pQo^fQ+5mij93SE;Ylm~&AOoSms0&XeI6dldRt4-OUeJ%xNt+}W9nsN*%|A52fXUECUC3^taor+$r%J8)c^D^ z6gB)YYCEj9r(6hC_HJ!+R*YC>WayT`B>-*qYO;0uTUm-Y zW_4BoUfW@brgZpcbtYy5us3NL1*Q6_fQ_nolK2|Hx`i@yFhUVl?m~i(sH8VLhNH%Z zj-=N)o>-$reEZ;HYtUJF?hwlOHMWmT$-I;A-G_U94@SP7Y#JXMiJOG?4HSJhE!T97 zHgBIIRmh;@H>mcXtMgBvsX-^LFYN}#WsD&q`PL26fJa3t>fgJnJ$(DA*s-1DZNUcTrX9xsrD;;8l2SPI`3MOKpOctG|Ifuz4 zIvn;081tP=xzlC*mbC?`O0O*UqUg$bC8g*HaF@*ctZh$!2Kmt7rvK|9=4{|0nyn%; z>8O$egMMUHkKurN0%!>wa~HA*u%LLF)cJQid-PXsgYWU5Tb`NblIl9j~!2`$jmsqc^BB z^+cp0C<`4e->NbM;Qw3ss+6AUsM@#eq{jfFPU7L}8!Vod=_EKiy}-==DoRDMfaQn7 zV-)t^aBVxvJ--8W~$rv@sIo{w&f!M>V2XHk)S-c+SeNho$Db?r3Y0`%kB$P#Rn zQ=iQ{-~7_^DjNE!7R`y?1zgl6$${gY&gwwq1t*RyEq+=%xTy5b%xE4RK)@DLBy8{w zk_#g+BSwvE(Z)>zsBORs?!%zn7ol(St{Uq5Bw4fA2pelqSl;2XhjxAlgAk5ImB9Om zEO2SrUk|r=eUBrNDtmljFlI0B5e3Uxg&k{DTW1lxD2_3pQE7ym7_nFnQn187)FXw% zpN)f5OV=|DooZz=Fc1w{AUY5pp}~pmG11b@#hcei2Ggi=d18pws$xy>;fgKl-%(mh zKUk(@+x2|L*XVY-w#tB(zS&I8tP^}rRF8+{bvrso0bEpuX?+%R!o2v(NW%}+E_z}L zd)F#ZiUOeSdD*J0U#AH?;Is0gsKVcIP)p$t$5C&?0uAztXzB=`JTmt%K;5PJM(<%) z@PpaBl-!Q2S@C3u=B2>G4h5T88q@@Te`Dm!Isbi+(+lseH>p_D^2Os#tArLC}PACVTYvj0czAjRh)Jh3M!T3n%*(4>{g=4sw>jeztz5MQ!8R_OLp?jd zvF-+lQ%u6)sqmLYX8EFW6r(B6)?%8d2^`f^&ts=(}W{@0u+ zI9K8PB+npeH0E5D#K@g$zVTpTV24Map+ZL{Ikzx&>mzR!Hz|%7L1XjQ!?U$zWaG}}%9ZzbMMFr$P{dodvH4V{UJ z4}h{ohMtpu8X^BOm@o#N@3UHi-qpX2M11+ew3^K(qtB`ptzGX8l1fdtMUY@x(n`bs z?oTHEIx#zBjWe%*ht>qGtO}e+a?TSh*9n$PW1h^Ul%=l|Xs~^0)0Vb_` zg&3lUa$dN|5+dM26N0F(q#B_MG9q%2&6OK&Yl`KDE6%5|tPu0VN?a5%Pbr-N&w?U&& z-T$dPky7$WAmN)?`qdMJcckM0rj=Ey_h*4v(R9g0&_gw7DwR+GdYi_zVt|2bFa}(L z)B~11%q;?r1}X5xi6Fv0ktrEqMB$PasOC(5a7V61Gt`>F)s3a<(7^UtDpA>}<8*ba zevlkHcgdJPVl5H87BGb2o}v{duX6%N9Z!qFk!s#!)!QqVpVjJkt&kfb@K>?k zYojVzGb$3rEW~ofHwTBfXKruOgJ;q&m9z?w)dC6=h!nF)M1dj(s97n}WU>u<*|zs1 zJ8#OSbZE?xw#v{L2YCR{eN7uDxU%`S=-zdfB$;jULzZ+8P`Uiy2LOJ>$YVtyRf9pI zM_2%#s2Z#X8dtf^?Ba+Z6(hEi5gR%z#8v`X#z0jDN2On=&KUnMjQZ>%-unR7P$2w} z3e(V~64D)%CWV^x-dziLwNGMeFU}Ef5kXw3OQGsfs0QgA6$ME>3fR238c))cXM=a9 zb`vR79lYa_hg=);5p{WoLt@}IiLLHGCDHc$F%5w9Rrb@TkVeAyDhsB49SzDasz0ro z*#*YSMld#DsZ3};oi7dS-T~+q|CQD^7uoLz9ZC@ylhjjq+`%j^xe;uEq8MPeIGW8u zqAb9;a;|^mg)xA;Pe*3kN;XpB%1l5RyX>o<&9z)bNxygf2<56iJ75T}i}EhrMLWM! zOFQL2h6m02%PxRfbidijA!#GP?m1rvNsO8oEVW|m$RHF~te*v%(Dm)eoyzk)YG9^!$LGpysxk6MW zft4YYXHW^LoS9y+4jt?LGgfoqLO>B`=GlIGv;$^x8)4{-FKksiR)I~4S2Z^Si%qGz z0mObDdEe<3sI!b?tQL!(@=LWZV-5i=gAj0_Jm`?RJl_QYc%eMCdsm%1KWMy6K0g(OzGR_#CoMmB1JsCf*SpE&o zJQFJq7xQJ=R~9Zk{z{Q%M(Opl#e;%#c|xqeP`T0pI|#rzc@oHn2u>U=Cy-Gv)`+ZG zCK7RloKf|}Q3H-jtB3X^P$q#|Wa74~V4AVmWL?bJ>jBcnQ%SjwJJ!^+qCj40^7?R* zsermGgsL?ur^lk|EpyCpB7MTE1R7U)z~Mm@EasukgV;lcQI>erw^N*88AA^DqJF*5} z?8Jybl_LGDhR;#~_(6^?nQG7sww6C3*m9sm<(6>!ny~r8Xsz3m3c^jYGZEaT0+B*H^3b0c!kv2URiGwZu)XoYa094c z%udnbzAjR+Nk`e>xth(N4E;fNfU4V3T*EG^$(_$lo6-Oasy4yVq>HoD3A|&2tH}iK zqB*_}e;QFg8|C%1Sj{9FUQ)jQcDay7x`RQX2QNQ0Af5tSP@1e33Xbrc+gM4vCPlV5 zunDE9aFk=SDcZrKlKe%)hn$a(KVP$dZ$NhZ9yn`(WyOAT1Z9Qnyutzai)`x`Ni!T9 zUat8$Zc3}yhnHHX?zo!KWTbVJEyYjWAz)ZIdct3l2qZc8;U7hN*7>>92^~Y!Ok7quMNC(@JY(HnkQ5$ zh(hHGN)?(_*R(;Ab5M9AOK=s#-(mqF05QVAR3vzDgux} zu>%Hpke1R)!496Y!W36;#4(=7v2x>@eB|uA-aWz-9SHyt;b8ssnk~pLBDvdwDCv;_ zO@we`^QK}!A|rp!vEV|Bgl@|M$M}d}OC7lfc-_GxT9$lAvxUVUPq```?^OD^tImPf z_1%)2%+fu#H*g;@v!6#b-p*BFIKtQO+ za^$L?RS*`u=gsBd4hn++n3y6<0Low;(AX_J0QmzoNKp{8ajE;Y$E8#b#6J39ge438 zE&-*SI))8Egh~(|!*ToQpuXv#LE((fEf*XY=}ZD~gCfnw9?e0JX4XB;=3`oo?Egp6 zxyLiTKYo1o``G3-3>#u3=Gt7+Hg}=PZ7yj;5~`7;o3`2JuDK+1n@dv38L7~1bFWm> z?Wj~!l5P&AzPg;_=lAa(kNxxhJRa}M>-~H^-|-ec3IF?PV{hvu+hKo1Wc5eBMpl-n zTe@cDj*aogstnY$1?;itL;BR8Y_ZdFL-vX2Vd7k=(HJP4GGL<_2&Y7aLkC(z(6g79()UE7OcqY z{_7;gPGE%tY)dTIv*p$vewkYh^vu!3Gbaxa{RW6YvB%!IH@wpSZFmXHM^6uV!~iz; z<;-iIU3#w#0F)WJ=PoYcQvxe3g7#0&J}`qE#hJDQRsyX`w9R~r>N=&bj}XX=Ix@50 zx6GI=r#kL;8OG~x;JK9JVd+GCDg#ULnb{Cc+x1FZtTVD)YH&zk#e4YPcY}dl{Bs%4 zA^=P3M#O|tC>F7KiR_@6t$%#%LMBq&22QWcS!^Ju_sbYj-w{z=N2ieK0lOs{BZGh-=md(FlXUj{RPf=;%fh9 zC#ci~RTIkiDX#Xnb64p2GCri#gp+T#5H@P+lS*6(^mn=`E+I-;aH=X`AVOEp1)!)C z$pXR?TGkN3M$n?;nv$?eFI_h;)#xCC%w29UIk#`7F8M^3e*-LvH*A#k&}LXaCHtUQ z5K^%qIkr20VXH}w)wpGK)C$g39p*7LO$g)n!jA8%J2%s?lxH(z5PQ%OZs?Qh2*I)1 z@ByUF)U2TsS&B}Wab`y+Y@FZEtReajP*UsCn#NP*8E+Q+jQ7k2afK1n+o9&g)UH|c zAHg1aPa>oKMVzULO#g5OV<#)N!k^c?FVo5W_~C3z_UM$fxrPBM){oOR*|iGR;4wW z$4x3WEDl@n+P5N|u#z_wyOS_}2**LJnScQku$_3c>yf0ORY${Y-7QbE6MIu? zHhy*=tZ)(J`BsKb5}Sni0P5Rf@NBiVNzNGMJ*jhqS!jMbU|e!H+-bG|O0ud}hwV|EWulLPlypo)6C-RidmeH54Og3Mq6pC1yQ^ ziK$`hCgC$U!CYoUAOfsUya08?2`${1aHq(-ap8^qmZ(P;gGg_1XNX{ZxeU7IpbB%6 z4Y7RVWU#i4sU@!W-9p5pHb#Q*MQvhBZxzDp{PqJ$Px>{TC_%l zPaSKUm?k!nOA+!$Woj!;Y`Q1_h19VU_A|sL0HD@2UjN+|oU;{w7!w94FgG73eWfQ6 zMwgccSLfh|!l^8svK(LQoJwTE_5MUD+t=tvqcoT*()FDXd3Q&{9In47eRm8vcqdmY zyUc=puz#!XtP0_q1|k5{ea#`2MZK{s#-DL9MZ-kzNPCOJGKMWv!;#vCTzwP~;A$C8 zAECSjz;J?hcGiI16}th`B&D<6$osrKbf)lqDAAml^pxw=-=-T-%6$H1PEz%8^3f6m$6C=(0a?BJylW z$~hcA$}kR8jgbqY&57w9!3v$zi+8A@xC|W`?kT=s16y@n6~~i9Hc(lp$6Zfj!W@f( zh%7?YY;BH)CtZ`GD&*1%ga}GuuX1X$m{Gv9T__I9>&F$zAX@*55C{GR>SWJ~^g#uP zz%dXHc0iSOQU+PK)Bi|>2BTHQfRsJqx~?|H>rlxSa6eI{FO7xGxzu0|IV;=5$eh>*G` zsSS1k>?STWIC z1`AB3$^whW^3rU(^X#d%?Z3P6>s_WI^Y5j>&g>7DZ6W)b0207Xnu17hoY*7e&__A) zB)+B{0^15Kp-h zJDi>AI=t)OZlT+OK+(Pv6NC0BNA3oG65$6Oo{xTE^)@h^;S^OePF3cOj|ISyXOs|Ahqt_7Uqt;}6>1lX6Czy1C z9ifu_(?7YS3t(x0SJBCc7Qw43E~<)wAgPf*u!K!O?3_URk3h#re8!%M_fTogDYZri zwW&Z|WeXlc0W50(1YH%r!5SeY<17Uk_H!m_QzqGL)9Jgl!>OdC?WB^ao2Yl}uZ1Ll za-Y7qFHlIZ;~70vvD;Or2UQ(L0R*oxoCs(}w{iRO1Ju zfKxX|vJjepjtV1=^(UCfWTMezLilwF65hc3$}c9(eY*QbrLW=Xb9rVc6(LZlQw7vD zrx@M@lG=I3=@g?0p+UFGAPH!=LMP5l8SDpAN_eC|Ya&blKm?M^H-3d}C4MYKX-m#_ z3r+0K9PVM7JO&zq5QdDQ2mX?E6X5TW4~Q{CLQ`sVN4k}_2E%7T(*C*NHVf<0z?O^7 zAUiaO8Vw>r0QD-rn6Hct=F)GHwLX$@n=aBY6y2}E1R|3_0~$UDJk2k{NpIJA2sfJx zwRT$l)ml`t_)&XITMw1}uN6=0rUsP)ki-F~S~G}54a$FY`JBUx$P4B%U^tBd{WE$w z9RS$JuoNoc2j#HbyNEo-+PO5uY$$qy{9^td5;BY@F~{cQxL{m}E$S*}uFp=TO%M{O zjd+ww8^hCFhv<@-uRu(*1RG2%55AiZPo`ut?(6y27xfKFGnv|luuToIZ)E+eRfgv&zG$AMb?F$1>B6r&OXDV z@HY>R9If3MWZXYhuOC8sg$W-6;`JXejZ$>{nWV>Ms25{KnNw@NJhXQn?3f4o$|$<| zzB*ley=Wdl2B$4BX?v#h5*wMQN3`{Y=mp`&kGD@L!i+4PwQZ_R+L>R?|2ge#?_HuY zxDNz;W#Vfn08}IXO@|H@pc@?#-UVzOGzsVOW~Xpx5C2jPHcqGe3fQ2S4lN zVC43|V6xG`+acmBBM^T%gd_JF zxm4gA_~_{!SR5C53b3Ywdueeheg(p4OWQKKtHE1^8(pcXYtZuoLW2uFuH>aTP)oGK z?kS@(2Vfh`fK%^1vek#hDaGW+lu$C&i)t2IkEdJ+407r9SlT=igZiS^) zd7S_}iO`Y?ki=G5x(m{tf?Z-@(`&F*+#<42*A7TflLNm92%j~C#VknqB7yIOFRMyd z{BvviK1L(}0hneFKVdCZ`u%R1szqDykbD?;Yp{{nh70$)Y&b~K`8c!Qe@c%IBq*3) zpX=ZH^Vps#-nFbkntdi1_91glQHU;$>=7ruD`iHoOX1bPY~v^4$OwZ|D&tn>9y^2G zH-vl0k4#ReO!|aQFMwaYkG6KGoS7Zo2UP}f!gZT?1`sBWt0Isqb*m^w>9$4)iNRRnSG>cLty&= zsOMZQ|3>cFE4coL_LFiQ1W-q-k#P(FHFv{Aul%bre}@2if45DU1QID{9nr9YdU(rT z8YrjK=Rh;u2nJ3iORE{HHs-*a1PK0;B=j!kF}dQa_O>%h|J7t{2?skWUm@;MgDpC8 z%F0@T6Ft@zI1xxH>>LC4N4}5Wg)7@+=D|xZe|kpA$N)|uH<2;#LjTdD(^?Ny;l-f5JoJWAf$tlt=Rii9Z zDHrO>fjcc7TCI*azfM7H<~5%e8a_=4J>PixVa?GeXYbu<3^#qpUY1VPPpUT2|A~Fa z0|B70yYWn zZsOSmF%7P)NEP=~yT=l3f9FyRbg9MJ$VWr;V}a~?6W_m09)CU*x36}v)%ji{F$GAx zKehc2MK7?Cs>3tLRcU_?bG`-K_ZQP7jYmqGA}LfvU*)o$U4$_foA$$iF?Y>u2rII$pwvX z;LrCw;tC*6`Yp^KP)0N=MUJ$@!S56;FLS;^Qw3lbFg!t%hwK+u|zzb+0L>owmtiUyi%52EMQ_7=C zImzP`$n76JDkW_Bt=^kOqm&Yq^OGW|dB^aI7BO<)eelmi^PD}O3P|}t z;uSdHKaJ^E9-t&QJ(g!s)o7G<-YD^3qgmCE+qh8^Q!lbH;$NGNA(g@NsY8T!Y{U@z zv$g&c-r*Bb7Z)hFo?iEJPt2FEUnSmpajiP*dNS1W0r}+iBQb$;h)jM+BB9!c-h8BU z_yu>(e<($p1A0Q^KvadV60Sh~xX)5yEE{J&MIdvuY=Jsf%uXvKsEdZN`UI4IadWv} za=db2t8(fx0~UC_Y(<`wu=L-bw5_99M3bgGk5R6*9i|3sHJ1WQ8K@F6qzQm(JMwP3 z9M;E;>z1Q%_pKa&=XnZ3dKV#)4gRUo`UCKc>>#vg;7UPRsUYLVQ=>amckc>~t%P=( zPtGGbq!Psr)l}VI6hmqw*jP_j|F4{&Fm_U-E;0Q9(zr$QRre#%5JRrglBJ~JySW+wlK;kS=wbskyR2|_b^VPjcmrc;cJIXyvUpVu%jA@J{q-{HOiO$o0w6+Y zlU;KG!2aaI{sJGdC9hvNpliNPGd~-iQbJno)4&j#TeZ}=c=aVrJzOE$!x}JtU2m;Z zEnUUS7{mTYAF57!?#=bM13~FpQo@u1Bnzmn)=gA$uBDc9db0<6Li@#YC)~4U6#oyI z9;at&?nEc&e$hJ{bCOZM>GwyY9{$tr&8wwf3~z$Ie>{4=(2mx%A1;C(*T)#PavLxa z$A5$z>qz*^_7Gxt|oy0^N|#akaSTc7e?-MHbHmKW%`k9-|q3Cs|o>_@o;THXkrm=H#7 zTwbrw5>Oy3peYMx$Px6z%}%HuK+I3DSx9mn7lgDNln-J9$LK4JDJiP}OPl0_F`LE~ zB)V~dz+oa++$q+L&m8wNjtIlLJChst$?}7UIaJLW2!r z)r<~z8gUkz{agS++LftADBHn#mX1>!UyO1xa8^LG`UKQ{a{-+LMaRX+N`yjZ2ikVp8RGmyC_#vaTTO z6Frn6ZSJTd0Q8IYUF`amx4S$t^5+UA`)_4)x$8t(vWeTknEw4`hm&O+P}Zv}t4b5z zu9N(|wYgpNVBLorb0QZW;&jhtY4-R(F4gSaW%j#b-HcM}k&g^*S}d#Yru1pd4b#uL zH^;4gIqGM;$z&h@ckT6pW2TH*8Gh ze?F6Odq{7~!A7WwXA2&%TJc#&>6AYGF>qBQxvJRmsJwS@nXsDN>x=gKN`3!%ZMVR4 z&g%1R5hmb|4YZL?yd%VwZhGv)f&n`V@aQj$LEXV-M?d`S2wx_`*JXt)ZOMlWY3*e2 z2*D+YfLZ}Wwc-kMc$kw5Em8!Auc^;norq{%%V z3$^p@G`jyjYY=F{$q?bi%(BcDi`6-em>nwt4gp^r61h^=QTna$J6hgN5IZUm>13qR zZ>KyvW)@DME z0`O}EK=RMjBZ99$biPL^4NMTNQVGP2*MB1e=pa1G4`Qi&AxndW| zds?<8eDzRX((RN5bhhqW{I5DcC!@w8|DvYSd%!|xT}|o9r1!?SNseoo&?ih_ZO|Ql z?&0&@BdKZ426OY!L;s~+?zz`2OZa32z$}icOMX;xOH&M82Crz}*n$0{1iXywHaFM| zM4cWyTfP$@(N_u@+z=v?Q~+BU4}A4(foZ}Ah>fBV>&G1k8dbM!uuISLLd^Arh~*$62p7p=0X8c^X%BZc*s+0gkzA3%=*r5CVCh6Ms1yL@k%Tor$3*KpmEf>U)oB(g&B86by70Meh(PH}UgRdN zT!%#;YZF^h!;20v-UKomKx6>1@YMGt&q2gUWK(51c^kZK{Ur-X=eR!Gr3q*D3SwR5 z`0zCIf@d=^-Kpf`bZ{9C_#H89sU-+W9|M^^=J-Wzr4NXnurHi8EVn;3g-!SJX@3Zi zdiLRubd?2^?-r5?p1E3aJ2-M+hRfj00mriF%X!6c_ z_G;D&!r&S?;ruX_`_|w!)tmv) zOl_0iWdy|Z*^90n-D?RGT)x^0WHL9B63l7(=h!}|xmXFCtzzz`0AAMCOm(pYNre6U zwU*cK7Ht%>2#4hTIthySbxEF&T|%=#;JGu_wkziW+%m+8Y^lZL|B2%FJA3IBfzudN z9~lnu6!*s!x{iUO;E-YS&;Y>Zmj&@`GR9B6jzi1Nl*9a<5RL+nC&|cPGWcmf@?kFJ zCk-j4*-K@}4Ofua^HARp%J!*cm}hM4$ryC!ibPN8?4RuNnu}@S zdzbJd*1m(iQEh+Lw1#J}<^#}d>yzbxi&p>{jKG_J#}?<12jOMPwhTiMFyn0or3p+@ zz(|bD@sXeyL43ZBMJNEgwkzHpuw%v&eo}^bnT9OqB5M>#nVg;i*c{pg_Ex&j45P|r zh-N;b8n*-a1X+YbHPVpP4CpG^u5OFak4G)CtE>+itezP zkCZEruhW*1*EIfb&9yf242BqyrUZZlGcpf(i=v?v1Ji8hPr{ zMgY;ft)i7U?ZTdIg*E}jL7eOJ==*$3Jq|TO#@=LOe#nshwDq@fSmWePiHoQ=wv!|GiC{`m&BC4#A(0DS;MNyIP2JRZQGRp9) zAf)Tk=0*WhN(O@w(CegDf0 zU1_+bcuzCn*cOR{iVt|DiP}?mY;Vu8W{nTP8L;Jv&tu%Sq<5HyIBn0Pjse}<@>`1> zhR_QuIyQyRLjn3eyZ!X z;5RIE5ec>*NgRD{_M&^;#E5beX-ev$YS!Tn-0c3LR zJpdS+wrNwWBpT5YZr$=siFwAwTm_&eJ~+u`$lH9(w0zB>7VIPq%ZiGukzuyjU^0Nn zEklSSoesi%nAF_DUU}hBis3q!ZCq$HjK6HegPu*5_!b3~1m$460hkd1x`$zunvOmq zM{n7O?48$5&C$QiKn~NKFD+ol7|3>7{>I#hEr!UK41)nR=DEuB)h2A!nScW=*!En& z9|i2I`oNhua@+ay$6o{v7amldJ9x_ zM(8!byxCxAWBcufitTKmHx9Z}xkpAj`8ojcKWi(g8ZO0ItZUl!2PX5X>T{5TthUP# zKSNnc$j_q?LU5SR{Fb+9E(6D%InH0VqV|=;Knl37+$Ms2%LtDwm%}WAV4KMB5DmhW zj+V|tQ)$RDwv~Wi?OM2uv^ambN|qhpdnylrJfMWcvk*4(P&U_OQ_#^o%RMHT7UvC@ zE^{&GmHKo)WEo%U{kX}BhI5jk-5|qU<3`qZN_7@%g+bUteBHW~)Z||%Cl{j@ieaAu zl?aW_(vQ})xRQLq|5ByziKnQ;?uIRu$VtBT1vc}z2K7AKx6luHS-C>94Y$rqlAaZA zxs5u(J@>THw0=J}tXZqZ)$GSq`dPB}d%5e4S=Z9R-a`p)?In~u$AFZtz}wW!ksy%0 z9CCWm)43|qO$o9SKz0k@T^rz)+-uK1z<(>Ww`*>@$lAjd;HFHdoCGaV?kN+%^8~OA z0etka;t*{aDP`Qa=y~JgnO!ucb+7{Z>x00cO*Z)n2VE;1xK4d@S2!{WF5x2&(7;<{ z8+ua|JCra#GA4U|$7Z&>OoKQeN6KjEs(GkPxl_wE#PjF9|NY%0lc7{J)cVd-B{Xy; z4j{n+c(nL48g$fBmyhk9|NcB6pTJtJ>OU{TH1f6H0`$&CV{S13kLOXFj~T|KA~}B} zF9-(Qy|7s`QR`d=Q%d$W(+0gEb%~{eXBW_W_ebY?TrqrvUSeoBa?xk;s3k7Cldav% zKY5!K#0sVleq$`3 zzjds4`27fPjoYo;88y1*<}_f`$_W#9s51(*Sq2_+x40{XK6wlZ-t|Pn-%HzV0RrajQJC${+E~MgVwrgRpU|X2QRlz*(YCkFU$uXP2snwj%SP1IV_uG9o(TdX zE;6g$p}#WCo-4F!GDh;eGU~4#Px|s!hY+;&Vw`ysSd;@BL4ww^Edu$_zF+tlKEzi8 zTm2rkQw}>JU-jK<^E>~Ea5c@T96EKZ%GcC9=vyrcSxrYxh1> zexWtV!U^zPep2{(+NQK$j=Umg2^v?7J0TC(-8ahKp+HXVdyyc};k`k)b;4PdsMBhs zLl&}ykIcm(o8=yIHS+yAb_IKK+gDyO1IUwY%(&aBVk`r$;5gy2S}$+ZzgnXPhpNXF z=lX79CpB0Dd!sjnw5G88kJ(6Jy+h*a%X^ z9)0Dk7F-#(q(=Qa^#syCvVLw}t0_YnTXrX4)SL#sKk_v9k-5EKV-5k_?Me^eL*luR ziS*T1x^5?c(4rgKE@aqrb7Q;$yn_MbYf_5l3%2K#m1A$--i`Y_4b$zEhtQUxEIA;A`(7GW_0n+XW(K5^49(Sg7YI=8 zdPa~c6wNykM`a(FjhyKOQqw8aS@q{QMC6euJrIRr5fxnmiC;&WsR|f zz3o%9;VV$6nq}0|MaHfjL@r=iO*c{e`p?<^SP1`hpdHrB&Je7lyB<@=5Wmi}#e(cL z_cho_vg@Wto3c^%2lchO6sPX315^XFzbaq#X)yDEuH*8n-@Kil$S@sbW9b=GTn*w& zn_sTt(QO5`tjKhB9P?U`Q;arS(4Z?fX#c8wyN^Ux!sD>Z^Z(o;GrfZbkQZt^fg|;6 z<=vzDxnMx!Af$@AcT!!PvOE%I$pqG_P`L4uBPQW;+4cenrk)x;s+jUcKDK66AcCA+ zkUCZYHAb$_lLlZl#%oia4%Sx>Ra!Vkw&gYY&gz#kYb^1i))F*{F4i?rg|_x-da|kOYfOCkU$=`d6X#qk0pjK;;`6F0mn*&o-U?(r}sgF5y_Ietd3s zX7{C+wTE6z%sn4Z2)G6<(WUar#ZhyR?RuAkkG8E#UMyC+?0VI<`Ph%ob@rQ^J#PGZ zwLR*`rziK0zpqVPcXc^$VY2s{bjKb#e^K?);cThMqFP3#G#46ePZ)n!9gP`Z)sSAt zgOPGRPgxlx-|RiopH{W-c2!vP!mip_k6tJ#V~~WWNnhC>9h_!3?LE!7Ds%Yf>s?%SqUgli=FOR|J(S`4AF6rEYWpZ33If) zaZ?!M!_-CyE`&yb*{6!k;nbDQBg&pT%7d?;6j)Skm=st6nA~U90JF5Vv{L&XWm>b_ zY?=@HrW@0e7Q|Au)C75KAFK+c7PnZ{XDU8KuzAEOgiauvDLpONl!Ugc88t6iBV)X= zrs&tHkjrP~MomTL)5NAiN~^K}>B3hI-~$oJCbZM25qiz`@vi3Tt35?LglTG))$WbFw8O19`N9{s(o5%th!MHYsmF8E?!G%3>U2Y_!>-vN>5aAB*ZOXIV(b0B z&)si3u7&%LZxwuMb96`r@3rpr^Q zCdvfxQ@p@O8-PJJw)WMI#1LohSH;y?!I`}AbP0|tz zNp0X#3Q0{9Is|tO8{ELk?HxcF4Ng!>eg5iMnWJB&gSEow&mc8y4Dy|hzkg6G{%|$$ zot`=CGNtf1H*Km&e|Q%Y7A4$21#ONSGB35OnKeh)v;;PlAg^bmu>bxqpa86;Ru)*f zG`0tqok8-)Sp)+8qE!M*Yw(%~xt|Ncuz9*AYTur~PGn#tOQ%_Lq>Jo$HI|XIMIJb0 zd0)c3Dd;DZ6D3-G0O);88MlKr;V78GYy%7!T$f8c@_8!{7PPO`S)DXwx7^xUUY}$< zRU~!HreM+{{qb)M8M{-N<&i1|#VlY>?Mp6$%)@}Qs&e;- z$rT?c&kvM6)$;BdFgpC%|1o{~QFEig|1Vez%eSO~&D{FKSECd?!_NlHezYaf zB<^E(qL8~|9&Up5Os}F97n`Lx=`@51#B0wnff;<3j`$&@o+{Mh%YAl}D20{J8qM`o zAOkYT%c-pzT{)_|ie6d#L1Kw7$04b1oy94>tjORr&`%Ccz5Mm)uBZ&01!!%#5a^(3 z)Tuy7Ep5TYk^DgSuOcx8lT{KW0O_6#Y_#ymV(zObBQyXCViofx_a_wG#t*~hUC*)H z(SC!Aa*1nKczLI(qtWZSa)LuGHo1+ZdwybgZ5IUexw>(t-$zGsGY66%%(q!wFZj#fYe0W;$=9l?61_QafHb`X zrSa);SpbHyIV;1-G6I!zJ()0y@L#RKSFF!p-a&jW8?@1)6sOU^wF~pmsi$~^@ofuz zkB{LFhk`7VqW|vu`|_kCMd7~HNhhbNnf0M5R%A6zM$4AO-cQL;yXzfRG=#_q(J2iI zWD$-MkG1D2pnGnfIa%}^VeFPwe~i<=3R-*C$_a=Hw)DXV6IDz8N)S=WmD`bD|4fp3 zYv;+4OazD!2bHWr_#xxetfFiEM{MOh?f;OC7Lc~$NPvIaVl~*>oLOQr05Ynq6X{Ep zNSn5ENGCvl$N&Jg46)Fyz*WGHUMiVRYa(1iz%1#&%lm%@;A?syHsbKVoev5zoHm~Q z3-kR&_?1W zg~RcRJsppng1?Ocb}q(lpC-C|4}6;TxvhPx`*aZyfg@;oeXVsP^hpw+TPZ#y)$m# zjJBkN8(e!0+v|8P=ggPvjtyH-I_s^-BBy#JqyayGV+)HT6>H%fuIj)CIU*oXge#i` zTM&E-*O0VZm$&*DKbOOTNh<-QkZ$b{EDpR5!v8fYw)(-CLdDm~?PN@JBp0-JLq5>W z0u^nJdEQPrr(QycK#jJ^&Di}!d@ZB znb@nl3(WafVZhImD;FOgPd5S)KJ6g@5M$V;A)?q7VvgI^LnWV*iRjmP`it~?+u2NX z->rhV>qNN2=lkfJ-&iE)rZa2Ke?tNfv5Z7f0gi*6d0A!2{#}bwmqaFNgV!H=-cYGa z%fg8$@|E$&X^SpxW!fnki-%RGV9Dp4IqnaADke4E&TpnLdjZKu4o*t#Yu~SN2qSH2 z&`8(LHljZRn~9SX6)x!x*w`Kr@k5U#{fZ-r3wZ0&JPKVKd|+)RAklb;9$;4@#3rri zM;2t4J(eG5mCQ8wWO@CT-Ui~(8Aj=fcUu`01hNm+Q zWT^`xQ9W!JjvaxbrbkB|X<(OGcLrVJ%_!)df;)OiTta*pvjwj6vRHdfFl& z41ZPp@=#$7y+wu1b`>%Pd0Yfj*EjcEWikhKnuY`g+j89mAImz9|PI`bBG2d`Br@E)Q(;804lrb|#p)p$)_4 zh+}#T*;J6BW!u8fV(cfHfjr3c#OX!DenY;{kO(GmOU##bMK&p*M$8>~4oiz((8?&V zzy#Zn`+kmtem!HYSlK8p1-5D`Pzh#m?L8o3E^dHPG!TIhU(`A8qpJkE3vT-n681bSa8b(Uz^}iBZlh`Uhuk>zw#ld& z*7$YM#aH?QH54H>+$DoVB@9Jp4t)~T$F}<&R5U*-yYcM6k)43cxwF#kvcdytf*VB! zwi_^P_4O}B{_I)Uj#){(OcK+!dYc-SSp>~1DvZ&HW9YDL^OakQ{A1YAn6%I=mxllG z;nP)>ahq=K3G~UA!FQ|iiKr@a=g7D25z4Yqko>S}&4=~s@UGk z_-`c8a{|78#imC?`YTNQ$PxAyqe=~hvN*xWI#ib znIYL-M?=$=2N~o6ZRq1V_ij73wIxge%yUZQq&tS8CCTSN%kBlXN}vla*oFo^TO(Sn zWZ7^*XLCdj@;i=coimzX2B+Y{2A@klQo75v2!w$Tryy$ofH&=$r;8YpCvutx(ds07 z8IrvU$+gIc8`F1hw0QbO4koeJ$K%Gnaoa0X{@aKL1ukTuU0I^0<>HQ0U@NP9oId&HWb#pE_W8@E%N8m;2SxTL5+CzCjT(C zWD6grPP>_)u}$ice7G)oxF6o(4oO!^b{4@C0jsvv+`n1{^)`}z5?97n;nO2-RrA{wJ0M1ZLtGljhn7aL2OABy#fZHNqD~ z3eW8MXN>yThL?p*B4lfkIC5ULl@ZU$E80w#fZHB#;7WS7N;XeG!4pkUEwD`j>5X^s zy!rTB_Z|l+;g7sR!!F)f2ZE`K;5l{TP%iZ5OK~1v%U4$Thz!qGNLI|vu}Wyn1T42` z_+ghM4{$l#WyRtMPb?~oJ+wNpJ8Wt6KJna{mGRv>;W2-ra3O{C6Ks|K{bl;*2N_YV z|2+a?=srIeqg{|O*{*-@z6@T^iTUY)oUIfGwL#cv;?XF`{-_=wW=+o$$Xa$RoQ-i1 ziAR_HARj8l47%7yDJ+oOt^@;F`#6Q=6TdG`=s%hG_Y0@uJBLnXwVV(bt(3SGA{FZ2* ztRN~^(Y|9|vV{!KA;S|DlAWWH51*lI=jfD+XSQ&j?&&#$qyzS)LAM>X=Pp-0eSIc{ zcV~Te#)G-99nN)to!_56dbV-qBrWHAL7<>u>p5{yJtX)xIEDV&e->iTW=oO_#F1wm zsK8OcL`WONfdvWTAXAiLA9{fS8@SuVjKHYICUc~RCVn5~6n_E!dvBurJBKsNp)2ng zuLIjsH6Z`kqg$U*@?xEdU>YY5C57eFp(*S*?3IUCy&#Q!+)JOh`GTn;H6%`PZ7+X{ zGy0xrkA1Ybt>faej(0p$Q*qZxD43jNE`|EhA}vq7=-nLoVAAls^ouk6QB{E5)QS5)tF+ZXE&8>c(9vC+6E8g#`FL)v=6(wL3AWq^ahWY@iC}^^ zNT)QP{523?T!r6~I4Dnu{?wyi2XsjjA|g`txPjX`w%oqYxpPW*_rHlF&}SeiSW7d5 zoB*q}c8n)-;ep__#C}_s0yD;YWa{%nIKYp4?>oK32S+`+NW6RwAOMl(mj-C&GI^$cP^}Jx^N%=*7;idU7zMNj#X`dW!+yOEsScfOp|;wPxEaWRGdWzGZ%j?*rb<9B*YN_xrz!?!}ww|BnOsXBP~!+1!Rg7kobF zbKd9uIp=kGJlmb?8<5CMMiXWgp6LUr&-Y%fCiYd$C zVWdaLCO$uy=DUqR&cdSnqPSXet~NzEs4P3u2YQUb6-2(zf`cnVc=!sCndWh!3m7Mt zT8p_R_4T_)W7Mp`ABbRl8An(LwwVTF&uMYYGBWS)EFT9H`Z#yEj6@% zAjD?C3D{$18`b1PTf-p^T`RWWqsnR{5-bz%RY(LDcC{_%ms2OM)Rh?DzN9EMetsWz zhIpis_R@4y|G!>G0RS3NE!47($Tju9s~vQ;C8RtcZI9&{qn9`0kHwlD>^p78dKLc` zY+-A>xk7;gOnwi!aQ8qRc&(HW=LSDEB==;39CFo;$Rj1OhZd}o3&yh zwcM)6H2qzlj&-?#3pi^!s7$+#kmahYE9hp;d*s984TES6&en463PkX69+77GL0T5%4H1QoHz!LH|8-r5`7$j~A0~ zGLm`&j1MfLY;R&Ij~$xI+SGj*v<9>#=|1$?Ip@|KEpLyHQ_t3aZK2l@M?)j93S5aNRssXFn&o1u@<@k{&kT;~!M zf$)n^Ckbf2_li7LXuY%0w=ivEWAp8a^Nl-i9#`I?b|rzuO)?SUr21UO_^UlPo@c*? z+2EXlEw1G8gr?buACFAVE)A;gui*5l;-lGV3W}A&GqNlm4(}#RW|^v59QF#&27;>V zq{)u$W82YddiqF@F+zM(MTTl_!|e2AA?1>Dd{J{74-p&U)ByKeZX)Ls z^pz$DPj9&aeiRscM(~sXRZJX|u5Ry!KC>l1_shSK_G=13Iv`cbvtMRI`W<^13y;V@ z01}58wK*OJsJnx6A~!S-J-JeJ#=majGpykW@j?4!C~@YEX}%j}+y4CeIrbHeJnsD+ zVYb;dkk4^pgI60rHQpS(yQ|`-T2o7X&8=6+z9;|Aq!37^_WxXD@5?b2!rg*Cl`49; zRw4yGfJsS=b@6Ba zLF;zU!!tW}SbB{IcpZmmnA!kupSlsFo9xcAf^8Hev3v(_GEXWQnX3N9~K<-DTk_#$Qt4)soAy=}HNF<#tV zOLHnNKc_R}M?VjTH%4`zr`%wb+vOe3TGbaPI^ay1Lx%fzAI16o!6TgKI*SrDUs zf0gMX@S4jR0;FXc?8LC*l@g_>;}uA)>RmB2-1WcTo0+(2Ci^a2i1`E7cFc+8P=BxC zciDZfSQEO6=U^KFteBnctSDQ0vIB)HV>hxoK_akzTdU?y9AsGEL{aEoa)|(GZa$Md!{V!d=&#BxtzBQ``m8Mv!Hj z3(9In*yB=_rtb5Wru)`C`yFlEJ05O>-d#})3ghO{tEINN(|&HoU5L(e{%JGISsocE zn^XbM;4}_!Js+;VfdnxuGt=?05F?pQX6acTp>dc=Oi-0eb5adq=6K}!XVVm@Q3dZy z9R0#85+3c9p_G=fL+FFeaz9npdCP&H7uvx?U#x%__R5u=qPb^M+G&<8&s0N~$L7bmlH+5qbZ|}QU1lY`UsneH*vG1k<}uuxD;(AC zRI-?Xb$XO^Q$r1?27Vtd*R;Oy_=uUwN%q%tNb5;M6xhEg!!Pb`2qRs*!A~A&<*ECs zT4$7iL26{F2UJ7Zyb`9MRBIS#ii(*-xGxEEY!0k_-xLdv9HTiLqbd2c zZz^QMgHa8EU4EoE7(G4Cb`+<+{tcJuDQOMsvQmy2m9Vz5Acij#L(OG#8qIfQdY|2U ztixIhS}f)x6HcGra&%_LizPMina=8@+~*+F><*VpP5G+O+c{w!aoVR~t4cPEH0`a6 zaj3%fJYR%kPGUIt%t2v|-D`1_6NQJ)84)1wt8j>l+#k0wu#O0?>Q@ol_Q|?gg|SCq zc)$x;`F`-moj}99eWsJpQcGxVPS) z{8sl}rHO`c3_o9K>LN@uIS5nEosn<*27ZL-qYV0ZqNK7?wB`%t~qf~veF@FA`{B{1BS?G6du7|3l4F9dqwq|l0V&oHgqZ!$5qRQ-ME1E_F zyOa5^J7+Vn9{9`Y@ko|v?2?-|1U(OM)XqWd7n+T$>iuwAb^3rvDd%HvRjiGnZ6XJ_ z&S&_Jy7%0{#@|-%Bd2|#sO+4LJVrVN-NzAN%Q(s&oH*327JsYbtuU4ySf}ho2Di&4>%He#triTsvm( zlCY-Y=C{3rzox0xCc}L5=;R$O@{u(UIgdKl= za^xPxvk0lJQB`#6FivzZ9GL+l8%Yli;c`=wqrB45b@kJ0AH<_$O9c<)E#KDR@Fg$K zGL8N0Osx-2Xzi*W)|+t8aKAeKn=OJEy#lhy1!=3=4e?PLkZGv(U9{>cD=-?~axx+y z6s~A=MHJ6xc`8VUeWD%M33;}(tLRQd!tV98(pFQ)2W15^-@m1m@z=BSc&2?zP-jZ8 zoh#)6rbV)&NOGqFM6lx#mwBv@c=u33jAbpl(a8RP1tgzz1 zR^)6%8)f*I#7?27F?qywJfBXA(`nt^pwQp&PzfQA{9IglZkvYPmbXb9!(~eKPmY23 zEr0pntbTFTVTo3?n077{h<-s4(}ZInQK-oKr_2O9s%uPxOy>#fC6fcsK86~`6i+K0oVr?KKyf`T&@>y@$cKQ$XWjhr=YdGz@l6QvXGlp#acFd6MK zPdUV9S?1n`aTh>bD`dpW- z)2S{9oPMUnfW&hq;7BXdGm+g|Fo|)6L=OwXluAsdd8VO-M#&&uie#`AWSm*CG|kl` zgWxS+TMOcGbEt2S!e1|vz(!+;=a zi&Cg$740QK*HR4JD=Ai+`pUr~%y!@YT-|F^<3W`FH2iEwS1M{y_qEdV}{F5gC7qZF{cwIgNKKN85*Nf=}g3id({6)(rAHNgwgZxuDE5ciG2Zo z`C^>g3eAoXL3+g_vmuRb{}mkWcHCmo(|THz-#w$*rxqwJy{~RoK_jJuwHRyf^rA7q zMk_*vWmGr5iR)@gGw-LWW>Sqp6{k!WS-nx)OV^NKbdb!$mI3fKF%m;twFuc-#6a1}7)5q_u|RH^qdXTG`^Ds~W!$B7|+?m15V;~(+|F^*ereu+Il zeAeU_-bZ_I=A4FN)}2J)JM^kDU|G&hT_N_}E-S_k*C008Qf8o%b$t;jeIhc?l)!wv zJzDlPO|~V|{30c|n)291`+cnO&gC4wGaE8B%kz+zlJmgcBD$UENx|GmLR?Z|!h5IV zl;|L^StiYDCBTXWwn+pN0;PtGp7dym;j|>Yjh9ftS=FX&!~kFy5)a@0uVFfPO)*GQ zPSJ+r482aWw}Tx&a*X4pY6en+?=lRQtIrm18wfZ6HV~8JD+iGpxGhyF9A!JMaw0`j zc|0RqtmP*@yt}`qfqJx-qA!{{8q8UjD>Ui1%$?2MHLEuMl5PwVY#i8cpwwiHH0xPX92+69-t{uE}k>*$p z0mSrg$LQ|Sd{@C`i}r-PePGKLUf4GO>>!A}MY+ca-L6+E{w@`FM=4SW*2v?QjjUsz zggXjy?K{9$fqds#FwJhLAmL;8wdbq5hD}=HhoGA4*_mLAKxu};atx$l>p$v*uEj1h zVuJ$o^Qf9ou6A#+^B&l6H zkW$a70f&z0z?GMK-~@P8&D+16-Srb(q*$79sTmn4))G@!;XK2(UHTLtsQW6Vl-e@C ztu?!MPP5S$28jBD2~&CTZT%Zy*Mu{?9n({B>`^CebFVk_sefftVW}Towr-5tqd6`x ziIClT1@*}T3l*)A_tJ-dpm)HsJCCI`+H^ZP&AN@}k||TL&h9LkM>V)(Ti1OWe`D`E z#sJ@g6Jy&?x0>!+ovcs-chkS)lh@4D7wOh|bkb~eA@*LfH(0*CAd>V65-Q;w7=0+Z9FF>nqk+TX^n+@o6N9Z0wEl38ZRh+biz zubM0!n zf$`IzzPomqMOnP~ya`6i zGSi|5$}xaC=Ef^)=~<1d&7svDTU{Mmy&K~gj^HVX|9|{2G+uwY}K3u0_e*tb*8(pg^3eT*chGU&M9lO!Ix6iOG$tW;DZH1%F=IQ|yBA#w6px)t7bxmcY zO|1Bf=ddI-Yb(-0W{71x*n+(u@kXo%1-E0RYKqikT)gLwt9w#*Nt1WG*h|zZ*xq{p ztjMPN@Uzsew^~zF-%Y&;6#&po6T&FeQ-M2|TUPa5DQIGwLCZ6m(my*!=-4BdT3;$4 zM*z%B(=h`AzJV==A)n^PKj*Y!`XJGl(t_&9)&$6rMzR>Bbh$<8`{v-+ZR)6o z$GZ+~IojSl8*F|j^5-S7s(7EtG*$6@n@~NX;|GTqpypDEeiK)VE%5+zEEk8&hCvt( z^$;L7Veu^Uz}AV>J1x}3K#5+NWEkjLF5b*Doq0ak<<_Tkz7yeYw>o>{k zo~ezjJ*NUomVMU(Kt3w5ufDHe1+oC+MQ13SW-vADBdXpDQT2r#62>c!Mi?95Zd0Ax zs81hrbj|&U^aH*$A7=X0_O_1+>E87qj7+fhlv~)vMe_=BaNX@-{vNj#=!eeI(3^D0 zkz89L&j#Ro=gC|;q~;7&!eWwTD8wmIYJ-E|{lK7Vh^MAvY37|rURg~&y|4}37+P+e z#y@!n<(de&$mVYvhnSxoVKF~$-t_+D{xw@~N7~8`sI+J6S4di+QbHi^#HsDZe%}1(-x%yLRbDWegCDEJWU`7B83BbeX zusHCE9W+usXEo^?0IT~>e!dprkXN65wcdxT?8iCQawp~CPh34{hQi63YJrd*ZLnLU z#V9xH*0&&jvGtBEp_TGIgLQ>+a8CFQPh7Vb zQy=6GA+aIe?%@%4WFR2mL*5cT?Yi}vh}&z9Crs~79)klknPEs^p^zoQ+x)f?ljkTxAQx3@my+x3z+d4@On?t)0RB?{=^EX zUcI=Er;_QRnL&b`5|>>UD@|3Ld#$1sxVpFpI9lsf9sBUHZ(!finXH-b{SXSQqTfmG zRT-15d=5{gXQR!?B^liu&#zc150Ibuvo_VI^iq(Ow^M~Gg`x#phatzSe86iR{5V9* zuErJTmgdFzN6)plmMrz1wL3WC`50~8ciJla_LHA{X#R$)O4+=DPtbuUHOvBSeaa!k zHcwzSc`oOCQH1 zJ3c)%0dDUd?>@ceZ0fdqhvwctzxTpn>j_PuF0e=f&PAH~rMrjo=FU;Li=gFa|2D5a zwA^v614R0`p(ZHpK_@Wzbd>O{>{7bIx4O+F#qe@Jp#R$$wyj=_ELZaNpYKtEJT`^5Lr{N~( zk|ASbvrcDzeRT5lwy-w|X9GV`YfH8%=Q`puMdt#_3{6bU&w(|KNB(+^Z*o3xC}EYBO|4Vo4Rvk*PJ|5l>!%EduYJuMBf^X^b`Tk2 zLvky6=d_LH(sA}EEAPq5OF^69VO2Pn{=pasHzg8sJ^D9A}K(ex^6#2p3?L~ z`o}BjqQ6m#`gD*6KmcZk*EDXoZt%Ivuvy7TK$sb7p~tGO{BX8uRYV@TNC=AP(y=&3 zO(+d<4;N^i6tu?ch2YNBmViV_@30v|Kh5i11{{0j`+LW;2I`Is2I^YuA9U8*HGLR< znfl-0uX6Ahv+q(4_1N&&dvi}NINSo%lUt;SkQqT&7(1EQyW&xeBojO)^NCyjdEOR; zu%@e!7=bGyx>tit9cC=)EZI;pavJfrSNr-a8*q1p_ekI|PmH@GLD z$=SlVyGB=KK=hY(vqNX+I{EKZHHH=ZsliB=5==G1$_yGcwberKYegR#llkK)W&#*y zEK}~;FiEih0bViA110*#t*+eYnMiOzgm-2JPB}WXuEO+HILeQdP2nZ@9l`KBP;2Af z8)v%g^skG$9XrO=S=f(yTjsKeJo2rrz+~7hcYjM9IwvHVW~$jSXr$;H18kyr%%ILMDg8?yS&VhY+wDMfBE>U8z(u`WaK9;`LcXRbrU8)6V*vBJI3!Thq`WN9zW|@V-W`JZ zx;$1sf+~!0zhY+!5GBD6|t1CDM84N__Tl&x`L_UhhjO+JYkr!A8E znd3k(5_!BRQZB%gVukDbO}DNgt%8vx#^cX+REP^JA>;3>4og3=#-}3Vd&4-;%uDXk zH~gnKIm2Y`t)&JckiS(<>IW(%Wm-4-%n7AFw}EMD`In|$w(0l;cN{(Rqr8i(TeT5P zGU@vrMOYj(RV#glkS7jO+om*C5S)PJX+dECK0ny~ir$UsE@B%uzkV5P^LE)^rO*#~ zw48>zFeaexZOh4~K($4UvuNc?Ml`Lx= zb@vCZs|jsgn-F)Nr8JqJdaQByzf_xcEfx+QBOlQETDCTx;h?lVgJulO!s5qT_k|41 z;^&LJPpp8nMiXR_tLqNkwe6LlV^Rd>v$KL=k`yIWbfKm4EQ?Z>>S>k|HrOmDN&Xzx z>3nIvlB#MxhzF+xWJn!|cy z0dQ627gtjcG+uyyPCayQ@an&@O3tLDL+EHF2kkqWyGFchP4O!J8m2r8{z+x@&{xq)b z$aCMaC8V;^UDnT^o(Go;b}c|t6VFX_dt5sB4~`K^Qq5yV+Nt%U6D6L`-7XKlpN;4y+I!Ew zp*++rS}nY^XnDKmarnc1H)V=d_kRxmoBp?;%DdIu z5C5e6Zs30Ga!>{^zyoXf}2Cn-}P{)xvw2Dbm{S?Rn+{Cxw)d^I5kS^yBR7|375 zuopv#OU&y_6MKwVMBRg_-xCWB%dY?2z22z35+aL(a2=r37Rb5v&?KVLL&UFx*HWe= zDfLfh{1AXri*jqTWd56^qn^}3bcBXELLKS^Y*?1&Se}SoAo|)l0P87a?^A=lMmoX~ z<5R2G=dj;EUy15J_Ri0|n|CTmjmlL{(L9A9fd*z5p3K7O*Fi657sHTCQPjH>MbowU)bVa#DlAQ?K|0Uykjj}6tR1^%J^4O zI%fhtDD2cO!7spu4_5C@IZ=3j4V9m_z!c{69J>Y(+OXoNzT zEX=9ho;88YtDgwRq2Ly4zUsLYq^6@lzJ)acN06QzWX1q*yKea3d%}y)@6{@FdY$Yx z+%VkWWcqTS{fnWcF?1@XXsI6&E*>Anw+T7}j-Q-9ZQEvu!84a%)f)8k7d<$*wtrk0!wBC;@ zK^>iN*}C6l>w1@@o31G(OYw-MH*#_Cem(C6w*^!B&Il8|f;r6IIZ+7-2Jx6&Pa6N` zk+P3ev){8p)ARH*cf;%BJ6nB7&dv|z)(KY^I2*py4^0M?EIgJ2hKzTnjQ11D_M;`c zr*1mD(*l24@R@U7I#}W+V|)F%87|oGzSN3ty-Cqnq@Wb{+fAp0qWO-SzAD9l+k$WG zJ{&}o?7i349}#Xmt1-8r;XO?M@=Rk*x?f$rhWaeZI^F-XB1L`gJmK27a(X~gTR=)W zDRnsD%Tww(G+A}XZ8JF#1@}Ju43l5FXcYj;CkMHtD}Q)TyBrZ%bA{=ExS^gj7rg7n zL<=e4PH71KTFAY{U=TXkF+F&I8Q$5FYfN@-NGJa`T^MD0Jxvdrl=?R>_P3DNFQu=y zy}m{!vi?YBG{XXa1cZG9FPxvBgdPb0ug!UI|GJ;=O;TD{Q(Gg<4n)iio1C3r?Jr^I zFKwW@FrSt#R2SnuR0YpjMjmVPGH3exFGa?>Y)tq^8K1r}WocuY%ccVdHXYX41OWqU F{s%}u*9QOq literal 0 HcmV?d00001 diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/start.html b/docs/manual/quake3/Team_Arena_Mapping_Help/start.html new file mode 100644 index 00000000..412d5057 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/start.html @@ -0,0 +1,30 @@ + + + + + + + +MAPPING HELP + + + + +

 

+

+

MAPPING +HELP

+

by +Paul Jaquays
+
Copyright © 2000 id software, inc.

+

      +    +    +    +

+

 

+

START

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/Image3.gif b/docs/manual/quake3/Terrain_Manual/pages/Image3.gif new file mode 100644 index 0000000000000000000000000000000000000000..fdb98d272da61e4e970315c6ad6fc3bdc5606a09 GIT binary patch literal 46899 zcmWiec{o(<8^_H)7-KLPV=(qzW6j=d7_yA5C~7Q;QpS=by_v<#*vFD6vR0C6luBA& zGj^$lRMPSesnn|)OQqh*&+lC4&*xm%bDi^i@9RFF`{U>D>$*8^KmiQ+uJHd00001i zKoAH727@6G2ows1!C-JWTv1U`Nl8grSs8&qsHmtQkw{flRTK)PrlzK@uCAe>fkvY> zH8r)gw6wLgF&K=Fjt&-!)z#I-;c$9-diwhM1_lOrJl@dI(8$Qh*x1;_#KhFp)XdDx z+}zy4!ot$h(#p!p+S=O2#>Upx*3Qmu)22-X0>R$i-oe4a(b3V#$;sK-*~P_W^XAR2 zuC8uwZtm{x9v&W^o}OM_Uf$l`TefT=5{V=diA*L_C=@D{>f__%>+9?1=SQQ_{Qdm{ z0s^*f-5MAe7!(u~92^`H5<;ibLqkKu!otGC!y_UhA|oTWZQHhe`}U})sOaeE9XodH z+_^I*CMGsEcGs?5yLazqFc@)haq;o-2?+^_iHUpm>`6*W+Pimea&mG?O3J={`}XhO zpPHI_;J|@{2M?yDr7@Yz^z`(MjEv08%&e@eLx&D!XJ;Qid^jg3=g5&Gxw*MVj~>m- z%R6@L*k6DBb^Q48{QP_ti^XQMIUEj`%PlA<;PH5TK3^aZ6c!d16%`d17nhWjl$Ms3 zm6es3mkWi$ii(QL%F3#$s_N?M6DLm8)YP0jd9t>)wyv)3)TvXaPoJ)@uWx8*ICJJq zV`F1eQ&V$ub4yE0Yiny;Tie;QXV0BGcmDkO_V)G*7cO*kbX>f6v9q)D(xpq6FJHcL z<%&oo>gwvcdiCnHYuCEFyRTore&fcCn>TOv^z_`ib*s0x_xA1EckbM|d-v|Wd-wkS z`|rNKKCxIVkx2Uc`v(RF1_uX+hK7cRhet+6Mn^}-#>Vd7zdt@c{@}rbhYueesJdzkU1m{rmT|wY48Ve*FCT^S}T8`}OPB@87@w{Q0xKzHayf ztN_>ufzAJu@c&E@;p+-7L@C$KJv!r^#~3U!y;$eC_mQMfL)*^aUh&40Z}^YSc;!9s zKG0utvF6gwo6J{NA&V!k?4BQ~v*v#}<6Zn?b@t-sv|V0V?;f5#z3lGSscmotB#{+{|Y0sG|4;8EF~L&}H07~efk z|GM<=$u#{tIV%E9YqOGwc6tl>&@y`8$xVzqPfde{(+sv83v*n5e1H3y+lQAdcq`D( zlPT`)AE;GBr}S=Te;%sP*j{Ea!Jnvk@&X&O`|o45zbl?xOfzslL@Q{aoV3=qi!H~y z6`_;qcv1mW#i4toqSd#Ka9~|B-+t8CCFx=N5%oO*8s@=gMjHR-`d69ym*M^AxQZI) z;ZdQ3=noZfP+Vr88sC8R3jjAN#8tu#j?8z#OsZ%=f5&l~H-R2YeJf>2IX^O0y}nO9 zMtXb}RjF+LCuU{be$0t7UOIqjZMAoHX$^G!Cr<;pWo157b=Pj4!VvFg+^kYt`pjIF z=U3P3p<7Ozy%yu%Gfq~v%SVL4@zr#7f79k_HYVWaltZx%bFxKfQxzEIZ^FD|2*d3u ziSyOjnb=jJ6-Km&pufF3+4z^Y)5ql20FyYbda|ejiWOQ+(u~>QFoD4l8H=xnoBj~MdMVYHcjU5>)CAKpFfw=Gv3<}K6BelPzTp7@T-Xeye)rT4|H z>mKVD^RQPqYCP>Y0vhf4jcZ0E!F@46wXA#)Zc%~dg8_0By7<2MIp%(A>Z76l;#fIb z8^s!OjOssixK^q+De!e_GK7=4L8RQV7q3T%P-pojm1-fCCu~L}niyjrE6h2q)7pz; z7mc*zHL9Arn+i-U;uQT9B=S7wo%v7sFxwZTmA?pJ{2CsyTQ0$n(~H7NS}bM+LtZZd znEMg$%-nSR+$8qM(2_Zg7W#`94m3EGV5C;K7JL}L1oxwwt8??XMuuXVuZyz!!xk#f zL@e+nvXR++99$dYuDOjEPMcO$FB5{D+GoRZL?FFyC;_G90V>g&3vXRQh^Ch}|E9w{ zvTg}Jo5ZW^#k|t&Bs$t88Y)LMHR}vX1=Q6_$~be#J!S=)-Py0VB8PkB$2%Q}0_i># zLacYq7SZ$K(G3a^3wJ}Ms3~CZlXhR1wyyHFS_l0BVXWN9Pe^h`=Tx;@ZL5w+TL05iF&2 z(P|xN!hT4hCi|JIOhff<2K1KmI2*a)eamcHw1DIi{n!&dw zzE{rYj_rpymu7^80SutVefYl)4_U~oWyX4C#eUo0RUl{TLAdS@zLSe_S|-m=80b77 z-rPG;nkL`3-F9}6;9{s0k_9BI8FBFvEtkQJOR9enMsDDXQCr|-)Uh0J4{ky^RxZ(g zl3eNhPOT-EaImp|lD1`mhGbU1GrbU1U=D#4H$YZBqHtx~a|J$OH6=Tab|tr8 z4jc0|Qtxe`8XGMMpeik@92E7kMTO$lsCc{AYeS;N-tzrKW9(E^fpwHvX=?;q{p83c zr1k9Xtz0&mcMD>h9H+d)8-$(2v?x(*O80U_I?`HS$Ds)oW{L3`s@gaqDW*jC?wsbO z93Ru{m~-xf=zFWqCPun-BYuQAk1}{aW`MxMzHEZJDx5(HWDvV#0Adf})kpL^bk{st z`)(7zc5tyO2Nh-TO*ZT#3RT&ccWXVS3~yqxNPxMI$EoZSp*vp_U>?(eotX{wLrYNv)P&&Qf(sN~oYj#m4# z&1mvPf&IJ;HmLm8qJIIhiIAgtiSEm3Z?Tulxp;S+S8j_{m2D@yh_8SAv;3oPkzMPW{P?fG2k^O&9}%F67%9C+kV|IWyc zgT)};ZF_H$5i%>M6*s2< zv#0GSVIVk!xm`Sm8mqE&E?hsN4z~Si^VV!p(nj$~m+c08-cD#adE!^FvDVTsm7spK zZhFAfHC<_26IrusWY8yiLMfsTsJ+|8XjAU2a_mbZ?VC{|>uqsSA^Bu9#tcFTFh(Rt zaGdGR7X2YCr7wAWwZ6Snb9sB=?w68l z42)u{tJjsTGn?jAyE-YExmp>pM%sW!IEe-BHQc<`yc}`uB%r!)a6@w$l8oe^y zZMo44k;*t7F~&svYoc_T5p^1+RD{<%4a}Qf*~OjL+nb?yFVic@%%r*g#K%hu;_Dqkb0K65gn zvEvOO@aOjM9Vm-kGLUDJgEIl-LI(k#gFK}M-)9YiL>~S!s;3BKLjgH3g^qZT0|DgB z6gm?sqMQUI1u)mObW4+iw+KXJR>l(S|Ev(Y-?$}85A2c=KAO6xt}~(0!kFzMD5x3Q z*r!Mv9{h(M8C zpZ*n)g)um!4IIP>+$MzlC2?yAhsNXWV`Y#C0)86gGSvfg=T z&<%4$uv1dSAz!z7I+A3sff!;;NfD;skc$d6do5Jugs^@hVmcv_FL&WFqZ_U!e~NUq zg2BM{usCUHBGKx2KI|4s8TZcXjSO)g6|{q3zf%OX5(1|_)HyPJ-1|V`y!!PxgI0~e zV?3)JUt2pLL)#5uA+_%DsEUXYkQ<@GK>?)mp~Y4N+%Da;LuNdzpz=Wh8SvKZmV&Yt z**05)0H&ZGIwx}$Hg5WCk1e%E7(Z`5-o$~yn_}f z(0KCg8|^{ePjtwH>gtTDQ0W4D)=5U(H%AETV<5PM2tI1dUn^DzHr5kihnO%7Sy6~b zj5Qg1ByVI;ds(KFI)!YpM`kZGKBZgGyA2+`ao8#ahswa{w`WH12=}?%Mw#N}H_)hj z$o3{k@_PQ>eWG2vMb~ySBQJpL(Nz#eK4^>ll+_Bz>pU$sN`FfCJvyI3x;iUQP!Cj@UoHCFwC*YWQ%-SgJfmx5d% zB7x`a9w-Ery=lDSq4G?s)I|(_%~w2$*Q-G7EvfdpJGJ$63!LPdH`+%T6{*bhsl1Tm zZs#k1^2b3R7g5f8)9_Jv&_)()@tA*`KL9uW|K zi@aJ1qu1Xl)_4ZHW#^uMuY7Ka2U|(YNmGzvT{yj z4PRpG(xOP2gA&WS0We`-jz+|Lz&p_8QkBUn-cqmLfb`5bk`XW(68$ z(1q9J_-T*rVP<2V43@*(jhyTY_bJniZ*lHT`1+Mz5FY-`&2iN~A2-bNGS{(#S7h0vC+xb4j&POf8;ee`cv)b{W=j)4% zEZC~6(&#gLtScYrn_mQ{d0zHKfrIkFA@h1g+!y7d{xV^T{Djx!#0zYt;R&H3(nYa` zm~;B{(F2DOY33^Oq>YcEGN%wWZ%j70fwf#c_yk3LzJ5R*cOz5e7l*8QCU;IzHQU+I zr$mfUkurwrD)zlrKvv5bHKHinf&J{qHdr<)7X^b+KT!!0yg)CZmTsK!b` zCVL{^-qa2gyT*&}Yj531L{j~@^561vuf%vr5ErVJp*Eg8({)IIf|sCd$p|IlTJ$** zVw`~(mB!EDkvZ43_oP0UOjVr<+PA3$Y48gfV2B<;sW`_ER`n^S$)J_5%#W)Rj%P^o zWEAge9ov_Z+vJ*S`N}tl%Bv@yO*%watUH#P{s3{vbE0a!iDudb!iNqb-!oXZZCe_s zM(5ahq(*bB=PtA?NV$m-+$0Npt=?g4(jM(KK9G-iY_bWkN8|5!os}JFJpr;cxV!F=8d^?W}r?LWIMxs zzYywp7XEY|`0HweCK?ALOXW1^XyC3J;-f`NDaGqDlp&bA-{QH*>O2It9}h9qhisLBO?B(T>5!tS zZwJ@u1z^Rx8_z0*!Tq0e8-yv`)pG|8^tk7CE3&aQQ7{cnC6bAX6y^O>sF}PuOhQET zAI*vA^A9Dg3}t${34cUVTgTsA@8{G%-)Znl*ZY5Tgq(BS9&8|q-Ikegl;3+Ypu(a_rnl8xnB`VdQ<@}wuD5|!K(+sX`NuI z6#9|mek~0OUsscQ{DN1b^-2j!*!79?Or`oxWpR^Y!4t)!L~fh<=A-h>Yb&;|)gwcF zR9BkTwOJ1oSY%V^gw>RkG^?j4)Lc`CO#k%MHT7C8JIoq9^V-KVs7(;KLFrpSMFOF96AHH@!ygWzR zfTczu&E#YIptds($5s|zUGw{5zvbfZ)!EyKM|yX%XKuu<3?)50z4_pbi1Z-o!Kuju zuScGH3_nWsKC&)7F6frbIODy;SBqh>21;{kt-FeEW(>;6B5(= zHTDT(f;y02FwVcqEVRgU>rsol5C4f5pTv5sqm|K6Qu_N1HD?Wu9&)h3kb3=PBy)g~}$SD*7v zXU`nj+mQG1)_eVnzbvIzhhHB#->|nfWvDIyU)ZMZiIW&tP?6DX<;3jb1W)%7*H(mM zik^woVZPUIJ8`6AUZW6094{>Z&j z*mJ}ciIYv%)PT~sPz#8*x1_I+V$1R6(j9kFGlRHzz5VGR6LRY`c|DNxi z%aiDsTAOZF^`4R4D)q&rB&r2#O>%4F1%M%JN=wBMjy?Wd?Rj9u z0oZy}4ldKYA+hMk+mq4pbv|10T*IW=;z!Z%_l>?x8P+>Yi>*Bw`|cj(WO=dJBQ2ps z&8Iq)yws{HR<<7yQe@VH=&1N~pPIN5dn|^*1(==M+tTHUO>VdJtxK$q+uM*my~OYP zi|~8+YT?)BVf);+nIzr&%_;A65B5GcJH!0P|CJRBV&_5xtjzja9UzeOH8OvByq`Y$ zySZYhJgsie$= z&h^??SzLe{^N4I!0jkmnErr888R~&X4QBbHiorST`k89Tr)1K$E+YzkT!wwNNLp9b zPaU+{Auckwo}d@?VWP{y+3v6I%la#f8K?U6qR_tgmTV<3J_`dUfsIh7r32)mikA4i zgxG)jhMarV$}*bz58PXR;`!0AJh%2=gSK3rgMKqy{EMaPZbQ+TWI(?NScp_6C{(7v zckL59c^w7mzQ*&u2m#yTQ6TM}|5K`2r5$}hbi^{a3O@{|5)=LM>0W)M;RIC1SCEsIu7I_FW&+Qh4sH-QaN04EA+4#n+L-nA$SbRPjA+q<9WEfC=p#TI`4I)-XNvsVhu>OcJt z9#uZH`QBd7ex1p7*r4Z4MB)?)nJENe280?Ld=^0=J;2T%<~ec!<#7t2;68#hKbuq@ zD^S$xq!(CL*Az5&s{r9QsFv+jdI{{k}O57L;!h^WY`<|p#Rc}JjR|4P)WkS!5k|N!9Eo7 z>`#fW95+p%OYyKB&kfau#L6RPhKd2xe(HsUf%U3yAGce!B?eBA$SC46=&hUqYka~& zdV9=BKjy=>EQnPJx4|x#yU=IzL!1+js^m_;iR%Sv+xEE>cOmEO4A3zKzvM8zKY-2x z4A=Q+`^&e;miC#r`<~t;1Y`k@I;lAX4 z!Fi8YUEi*6YMCRcQgn*+Qzi>e<-~br2tm7i#K^;)9KEt1H9L2nq$<|Mlg>q%g}pF= zSj8ABe?Lv$bAbV|VazH~Q#iW%tZ7l`Fh*+muG|j)w|ig({_;_;LeOwcKnd09np#n zjEWzdpWg0P5BmrG&G^u&5Z1=hR6X+Y4fzKivnP-5aEjXE~l6=M@op%l?A(E^1 zVv?L%6HP!mBX~bI)Te)sgy?9TBz%G0{rKeb>fJB4WU{0O_pr1LjML8^x-t|Wv6 zeIduwk=Gq|&Zpn&Mo)oxho+M6tF`&B&2A@xW*LzPP`+$0pOgMZ~HtUfXX=AWuX8cA8uPB_TKSo&@Fh_?e`s4lI zRU~t%C^T7WNL=H1PjkFvoELqi-%<>kdqJLS#VtSae7M~#_VTNCXCfTDB}bh~01tL> z1E;y_1KhwIHv^-~ujCw}5adC)leyoM+(e>Aaj6XO)&-5Ak+Z$cyn<$4+5(g*=UtAf z-A$|5iRW1N0qydU#x$fs6w(HD`#=>a>0f9X1_cP!%q;LACn37N8Mo{3Z?OfUWk<5&a1SXx7Wq2^PF?T79^MTT?ptVnX#1 z&kF%P;Hb4zI~YcP8P-%AN)AT3qyb@n=`=FsC?>5XwTE{=jyOnY*>yx~ox$&l;;$c4 zgryM$yA}!}BEaMdQxcv?#Z*gJHWUSHv_}0axba^ZY$%(Jn+E7h0kd?Dvxv8!)`FPj z=On}S#+~k%;6I*)JrKf7^I)daE0w>&{A`5C%W@TbDaMIiAr4YHg}KBIp@#*+~g)~bw(kbEI>|p&?OI$r={CyUH#iS zwC{cN@pkB`N+?lU=S@VK(%GOLAtpq&nE<$8)6sn!96_rOTlhN^EH>{deNoG?0(3YR zfxKHe68n0kCq;@6FqtTR5?DP>Stq6)az_gCB-$2tur_v!T?^I|v5esCPIlSX#rDpt z0BjFHHy?lz0x+l$+z4P|2B6o((jh*^(!qIc)PB|B{~oUm)8M#WrRDH`j7rxOVyyxOO5o zVkbZ|3ZTVg*%h!HG%vlSBaPM!jH3!aPG4LjopnK}DqIV7CmNq=-oSw2#zL~?9TwK& zkyaEyo52DXvE!4W2sw}}7C5p_bYYoM{x>G#`jgW@#}2*pW%BOrR%ceY!SfDFSXPeB?s7<0iA5T(I1j z$ovWeUC1b;6t(M5v-F!rbHW?sbaOxOp5@VNkB(U93ZjpSU`rZ*2P9t$u!!BW2HCw(>sRaN$1r`7 z+$y)|@ap5N|NY_gi_=1-F5zGK7xvh{-V{bt)dF9bivaWm}?4jDA+!s{&*uJ|5mef2_N?D&5A3jiG19Nvjh&R!-2WyE;M3Svn1uM{!pQ}lQlBR<)MWutw3 zO`Ia&QHXZrwGcN8mByk_&2L8Ftb61>u<#;GyKNNgNTOtRBG`Q5RSAIZ%L?`$xvThK^qUp`$yR<~zf#dwy`W5|2MWCx3t=23j$?a- z!Be2^H1fYO(UdOhPa9&(0h8i#f4s5Dtz@ei! zK~57tt+_uNBMIuooF~Da^kdQ&pef1FM@Md*JPL_YNE-342>T&96a~8>R-3xpfbrMO zCBSTxffgb*0i;+?HnDB;CiE2SM)7tDp(#z!WCd933iL`oZ|?}i=x%|<3$EksX7U8F ztrzrjzHeT=qz7}Vz~bP~cGb7b%|LLvO6Q*D2h>O_t6e3;9rkzNcT}pc@A0Xx+?u~D zAb-C3)@=>Q+whzlrI~yNi(fPW)65M>wlTjC;2TnnOm0A9fI1spgZb_FFCu{v5s0&R ztXB(1I$rUVah85|MN!_*@4q+CDN4Yi*U3zETq3&ebj`h#6X265LgGTxqNJ$);Q2bQ zEQUFK>_M2|Q>aN74ddg_5PZ39%HCRnbv$3cvp^hJpbC4nV_V;Hu4xZ)prF{JU2jL^Xft%#!FX^TOz4kJS z{^1y587qE=2(oRlV7KeHi7*o9R7>Cr`1 ze^2q&X>LcopTDbHU3e#b030kUFh@c&#u+L@O4%sq9NF|nIj?AVCz`O0lO-|;TN{O+{fm6$MfrJANjF|bQ-lJK|AWV=M>BV!G!%Lh9ez@P4IrZb9(o? za3CF_A&%hM+-rrDP=gI9quy@{Ldy;v(??Yn7AYaATwM^_PGr|7J-_47QHKvk+ z2?b$ITXuQaZ!}n0t~GnqP<6-c_1$Xn+J#4@hzB(7qs)b*m_X(luSY75-UcEp00}bV z(=v7vTjkiZ?}B32XW{%CvZ#a{kHq9oq3%81yfUMvm%bl82&g{2H(&h)1(EfTu4FCn zO7&_hEP+y!S$lW%4sV|*kRHbS@}KwY{i_Mh8E^bhh924S>08&%hn(@uSyPyMGhAWfTS+Zko-f2Y zCrdF#5dxuUK(uA(sjNce8ISC7p>sG7QRlGdVf&uPNkO_HjqZo`Z4>I8zf&)5-a2e| zW+eB+)Y7HM{aTm0sKx4f?B%vm4P#mf?g(&DvD$I(x!|Cxq48RWxX!?4BS>W%zbcHv zo~KQ=`Cc*f%9w{wwgvPqO^;^257Ko#_;I|M!be{SYwd`$VzJ|D;RyrpBAj77xTxAZ^ql;B{97fh?Kyxm+8Yp! zhe<49)$B;Rw8V%|W7`jDC-jm0aGBHBOC0{Jwm$Oi5UjTsZMwTAQFeb@oA7YU`r1l} z%gjKOlI1yJ*a^b|1)#uyJwn3i9qb0wr``J`9@ak^b+yg(u6%jxrYC_3D$eiahmdY> zN+@L;o@&)2kCg#qRr52+--iwIer;%>Oi>qKFTP+|(W1%o4Z`VRi3ZZ`ZGQiG*T*!< z17|TR9AV$UY+2CWg|HYvQQ=DzRk=#~g<~{)IyfoV6VRj?#S{-}{i8Bnz)q~K7{aFZ zJ>l&sc(Wdzs^~C zu=zC@6i5)qRE}0^{#f!e=nZp%_qK2yiY%Twt?vz@t&Tj7Fa9(ApV8ev@;7l_E7OkU zgnn>%pkA)5!cX^LPZt!M*w6(T*pXZT84RTv`k>3Azi~B!2whxte-jc_je?s6<+{aU zQ;zru>Ic+=ay|}dM#nS{Vv^d&boFzbfT6~c)UAjO%{1YmhrGvF)or0Rv#iAORhY8v zHCg3W@~7_pV2@vm*B;&bYUY^jaJaUCZ(7%WskG#UtTn{@$7*KUmP0S@hZHl`A3u71 z^!tl1E-yqurNqaH$`3a$^%;kF?mF&u_|@tkN`w1HLKVVseA-7UdPH5>O88rWQew}S zsNc8l5|E25nsDS1Ja?hvVoVk`)8q3HdYy8}_A2f2Ha+Tdjd~o}e46IE*4z?wg-l_y+%7-q$O? zOuMl>_TiMr%6Ov$P?jfqqrcXty=6JB+zxV3cUn4VYb3b7W1g+uw=if|d#D>Y^lATp zBm9#eL(5wmjP)MV{hcSfjI!hh(!O8SzB>;n*SS1`o5zHE&UD>8)-Cdx7=>;597oLU zks72~H!0j+Dh1AQ1gk~JEpq$v!*`7JhkF_bw9xY*IW2+B(!r`+66R1_>(QT;_4CB; z@}t!QCO|NMv)y#@uBqm-L-I&tbk}-eV6u^h7&Ao34^>G)1o*tQ;1};&B|A+P>wRGk zyT5GiJ`6@+`kM-D2$lqv+a=rwcopIei!!TNu6=vjhroza-Z|BRxtwMCnQB-RS`Sn` z+B0I9ktM)RjA&kA6j%x4O5#v&wC^blZ36qavWTtN;U1jBNKe@zTA9J2l~dkVM_rGM zC+I%;$aAb$E8UyJ(Vafk?D=}B{8)~l;%ivqt9LaIRI?LwU&?qhQ!Xm|j=R1Jwys_0S|MhbBzS_ zf$*=)HcuM6wIUh1t$7w1I>f2?1}r>z;~g@a0n&Zm2X(BDLlN~mFhj0G_KTAxdjz0# z8Ler{@{;PE9~6_HJ$%rY6iokW!KT^AC%63h@o3@g1}Up8h>Pcz9;l`0nZA6z`_v7i zjKmMPyKp^%zFOgopa7X2rHmbs7T6@Slz*fsY1GQNrWleUnZQOB$v}qH=l8s^WQUwk z&?!6e(bDm2gjO%UYg1mcGJ_tugEzq2EZ?V^RSU7+F`;xQx%|{WD<5C2y}fc|vC6Hv z_N@i&r+da%@w%$VPZ0h_YXimYOVmFvhc@5nLS}Uu>&>lQaeWu6dSr@HVXNM_LnsL{ttt1`i7*6o#ilPc>V{;tP0^kWGDLE zhIA@HEs%%oE1OFex*z+j(>p!T<7HX07Ok7o!F?8niqz^=RBn%B+D9Va9Y3miG-@DR zqe3w-hOE&uU0|0XRuLcQ&;KqOb~*z=vBy1y^4HHyD7v%aFAM<6bY)F2588FtBTXQ~P9ymL)yoU6PEQjRi$XmI zwwE+#M((=F_mq#N9&YF0WO!zm4Dc!+HQ+}I5QIvT(JHG$_ZA~5nW6-}ohv)OUp0JA zh6A%>lP_zRL@%D3}2}kB~pB%*gq1|FlPkT?`;1(n3YEo^5X`r7Duv+)x$} z1HJDGaH?oY?Xs-VdQGg#lJ{pXv?vpnTX255Fz=5f)uSVv^relC-M+aUlA?0gZf2_Ry$M7-dd-*jVHV=sC$M}rVidhANtodI)~=^q4%up3YJtdyz*fMOR;!4Lc^&IFXaDmWU{zQ3;dE z9|YP`)t^Z@fJu-|574@g?K&-Vt(92TZ~Sr_V7RRQtaaYrdKPv8u~R_OsgAkWrxde+ zrbJ>4Mu3s?(J^B6!kn+9*Kd|_S0ew$Nyp81FfrjiXiP^lwZk26ExS5bFezO=x5jJjbCs#EAxS!pwyF$fwFb@|7Oh zNEl({#Ch+uPI1{&HJ@Bq^AeCY&%$zN+w)+o92WBq3D;RxN~?T|VR&Lf2oL)=?c!KA zNi1uD={6_AJ;h1^2(8q&=&6zi`LD6{EK}FFCUW+s>Jjg4YKX5YYm4-k^BmX0a1**@ z-#fT}sb1K=9Y#(-GbVfEwj?%Xj7(bO0kw|+W9K0TDL}IbiAhd;ft$p{!rYih{xLz) z?`904^-!z%=U^YXRB38{Cj5vFMY;N!KNT z4#RI0D!k=Es?U}Gc}e+Bt?){WJ^odj>TA*y12h{bbAI?H{CZh0z0_99{)_|J(=XzRPcM<6eZ|~8)9TKZHpfz*2g+VrB^0S!|QzE-2jQhA@YCQ%0 zlsV#H!kHUEr34_Op7eVi0&P|R-2_uC>&c}#Myb=#fKSnSnz3cE>q;mDATg=n<2WSLd{5QXvR$9$%R>UU{RFo(? z`qtuCS?BG@#*1Xg4Y=Vz!L{s+SZfeZR=&ay9b^wkg4c z(tu~M8e+pkd(r49uR!<4BI$k9{6C_oPMWy z3x{-Nt0uBlo5Z3-(i$5{j+)%U;cySopMDv7KpJ8~WrA<6^Y(iJsp!P9Cw(f(OcaWQLWqamilXn#=voBg z7TNY+B?M$bPuT-k`f1n1hld#Cn@Qxk>)Wxk0xV2Mf6YWunosxN;#Mm|Qen!i|2(pz;k`*4r$5Rx~Qp~+n4nw-N1HqP_m~TrX$G z;}1m!jDa4LXs#aHX#V__U+aw~3%)=P!t9@t1H`ij-ud*QIfR!Vj@w(mNX&5R+3K99 zMUb0K0Tv2=n+cK5h zyr(1WAkeg%XVT=m4+reUke#rvFGpO|Z)%9Lse7Kk`;q)b!xHPLsZPH{+XegDZ|R@N z`A;T^9W4>S=2)_m?{wKJ2|oh(@c`i1`wTx2YnXFB9`5|=vbycG#9L9Rv*z(x#jz3Z zQLP+S(R0i}6~NiGb%lIFM&JnGI+LO2)bA(R$Xb4uzXF%q#>PrdeP zRJjUi6az421B?cchCShHi48Q7$_pyPs#fAk0y)uj8`pdWHQR{=pc`3~?#{i>#QmPk zr`L?eVl~3;6*%VY56p7*{xzmI+8yUMa&Ooqfz~5u(`+2}TZ+{K zhZK>GX6@}}IPk%(H~D$ni{+5rxJlP`&gR5XS2)LX@Fro+Vq3-e@^a3cNzgOVHl)RrvHOnF!*qYgnl5Oe9)&oH6J7nLW2H$1iroabN^{LkF zz}VCmy<9u_Dx2W?KZ?%9pUM9J<7TrB8#_1*!#1ahm}Aa1$2lbD9BV^PsV0<4wG-w% zr$VX?Nm4mgDs^v8Q4*3=>NX@veI2^Hb-44}@A23_aP4z#*Y$b5pReb~eec~eORW2` z%d$HVUAJe8M)?Ec6@{Y`IQe3y+l zP@6t@#r;E6^sX)Tg}?L4Yrp+j@3tweGLsT)bq7MW#fjFVX%+yLal)1QS&Us^I3`+?93E{f^bsm;w!30oO)_xQU&7@okW{y4SG@==3|+ zk(&Psfj~DWec)Nzv}dT>WLYgyPWh^q~xMT+`Pxx0*wM}(C+{C09_D|cRe=KA}Y)1o}ZT9$y7B~%Tm*a5CqQp70s z``Xy2xmi!)!xf)ihyB(|GwgeIYpH^NKYVuSSmsURHnvf*+r@7ahRJ<5)Qt-pWmjML zJi3oc%H`NOop4Gh`<~_l+{d|h5NO%0Y$@|%N4wi0vYQ?mLp6Bc)9oAkW)n3`*b^vD z2oQ@$0Xj_uIQXuhv!7;3wdxYr$W=n1`q!li@4Ppar{-jkiylp zj~W;bdgirD%Ob8jIjGT_&vZ!zeVP!u7bvZNdf{EB?U1pI*kRo=el_qi`M}%eofmo- za|2hR&wq`1khL=XG9>!>zUWgclY=D&CgE+?i8EEKibZ)ej>3b=Z!n-3bNcYw5A<>w z)-GeQ$-Z&vX01i?>he8~w=|kPS+ybQ_o=+<|5C8KGOx_$5w+6L)9t_$mDaS`o% zg;Uq;j?E1hxDAe|;9S{T0wgC7R%A^|U9@}WRibHYz0#A;9WK|~-_2(p zaa-2UPmeFd?VFl4Q*Q?CDRZs}T;}PQ66bk_=NNJFj!TTz3SUx3lS)u>C8%OX$ryxm z-)QOY+Vx%lR3iMHokn)Z(dY6H-mD$cRQhk^gIY{#`A6;S*&mOep1nlRt4)*v3@B4N zm!;HU&N2Y1n_44u&^fluf*92>8VZ~*(A*02eSeF0+aE$#-CtvekousUPMgv3hC-9p9+dJyW?6vO~vlq*aF7=Gl^DzmT)lDevy$uUW z|Gf|FFWsJ}>LcA%kW>tP;M!hn#;83+`|P9NotIC}6&UHnroJ{%|Mq)$AwOPHg&)Hn zoe_fxe6*}QIRxvrpq0Ev1TV$S5cRZ=jZ+|+iR8?@D)+pagaWhM;s8QkU;~uwm%x5* zJr%eBvk0i}E1+i`bCWl2sUavhRny|=x@SldF4{j?yrNc2Bz&fte!5?O>*XhJ-JI`| zkGdW9ixAzrEgeI3sa{9}mEgIz3uTYznC@0TaRnX~-Z>ge=V^SOAE4?H4nwV0uZtvDo5C%bAn?)Ej+;JKF8$pXce6 zBolOwiYO4Ra55!Vg~kH}8BzWMYaQ&omh|P+S0Utb$3N>yx_6d?l#f=$V?Q9!R;59O zduRsE-)r5m8`B#9B+KrtCp~^O%2I+ia8$JuJOLy4(vEj}x^F7-o%t4qiP8kKrpE&} zn%PX=Vj)iO%5+ZN0oypyllLsMlm)iesK(M}yd7Kns};oCX&zbH!&be?%>73S{O#Nx zf2UY{7pQ|PgL)#|ka=i1V*wqWLgi@9k}v5!#4BY|ea>txfK5dTio{@^GU+8pi`E1d zodPJHV{&s%8#SIqfdBfru6$}uPxsfd*RH;al4LtQ&51cr^GtD3Xq&9+wdDarTXDg8 zT!QkI)&ECPd1O;hi%VNCjh2vpzdmu!-Jh(sZlJ@Hdw|+sXx`G~v-AWse(&Jch#rQ; zbL$4-TR{W5bHHaVyhP=T6coGdRc-2gpIT4Ppq(^vN;mD-7>)3{)+5S&AC#W`^#$NZ z_P8e=MoIFG=+pRGk!L?ezwF_*;QFrp`RU*?*a3_Wx?-Gz9rpo~_>^tf^j)?}8cQ*J zhHY72UYyX>i2Y2=-x-%)6xr)-on+^(F)DDkZK1eqP(JAXl<9Z*Evz+?hG8$o`aD!*@d0AIhJS?Y{xh%Gs@$@`u6iJ~YyJl|Zzm{*iyo*_kDYS8=HrWc+iSRm%W@My zJ=dCyCd!SJbA~zZ8h+*{{RE(Q4h&c>-G?0-jMw=t`rA2qyF4Z;lc9Qp=)Ev%AxEZW4J~fqc(apSp9xy}xqi^v6nBjmv{Llm-c5C%L9TgVl_FfWpFPC{Tc_a_qebkZpVrT(VttG3Ng7H@ zHo)uu+&nHV@2}GM^JVboV3QY6-5com&oXqVGr~=^o1AOXE_OP!Hj76{tLXX*n40U4 zom;wvFk{Zhla>L4`^`ZK#CSK+u%|)I7O%Pq!d7l;K6F}jS6WQJ=1k9H=#O&z@E6Xr zAH&|RYeJ=rfm~Dt6aGxLOIB_9ACLjRPAzMWvu!{Y$`97|C7iIcCOSza2*eRgpUBF( z2QSY(HsMw!ZP{b!P{UKT9@+eI>?{rZHC`h_&G+hbN)q@>B}JG(18PDj&Dsby47sirW7{6f>%t1b0XdJ_BIu z;o&DyU&qylr6h6<6$Ps08j!ZdH(du7bZ#wd>Pm$PD$>CLNCHbH_iJdJ#GYr{D_kq< z(|R{IvpNpLWRBH>h#eodJC>i@Sj_Y}C0H4{ekd zgt%Z8X21|2_pJ$8vc%}2iwW!r(2#LL3wBL?^vZ1IB?;+$>-KV(9HgL|$ zRP7pjD|X3hS>h!sJacW@Q2slt;0z38ZNbE6d1Bn2#{OIXnff^JIpsC1)S$%};ir%u z(f|5LlR|KUyVl#8A>#m+Lg)V_SVF&f_w)7 z9hOMsa9;)rPEXT~x6dqd9``frD-LRsN=n^S#$@0Gf3M?x4A@9j#5CrmqYGrJo4Mi8w)U+H9)FRklAs_ z1O^f%M1Uj)Uqx?Ma4_bQVuh#Y7H_J4LGGj|Cv(nD&1=ukMdi%T%7t_ckA;~MuTRrQ zZ{oG|_iXfCM|)6i@=SGP!7Zb445k?4CQ(W4M_IB^L?PM%fVRU!kn_?eC&Ct}ydqF& zntN{;2RVb2uM?!qFyXTT_^NVU@TX-%3Tky!HA<`+DAXtg#Prfl?$fbmRP3A(4fLXI z&*R?@OEA!R%z$5SAVoE}Ts2sz8p=Xj(yyQKl=uRE28i$5;?bsJ`0)ec`>A7#AV{^kDB33aAe zJqLe|Wcm70g7&loJ1x1&zJ~r==+}DGw6jzD0eAl&v8KR7s|j*N{|e+>;+{1h%XyBp zY#H1BECVJ+zzF6cK8Trk#2*~$FaecKSI-ox-@Lh!GqQuTVmiH}{ytr+N2t}~W->5h zGA6kK{gz|fpxXmX^Wj%ai^P9?ivg-cf`5}OR+ zvE2uB+6`(Jg<9>mv=W7CsbaOcakPt2HHu|0Au*j|`TidCLyag%#A&@;hZ|k{f77v# z#3rk4V|-jB2_EQX5E@!w9!XIRr>NHL(Q1=uEEP)m3F5YT3qGD;j#DR4i4DxZF{ ziel3u(Z~}UpQf)!7tTej3PY$d#J-u7jU1smxRMx2SB*HT)_TM_QlerjM#Vs*nCpfI z+6|)^M%i)B_9>bIy!7*~?dY{7A^IIfXMn{VO1X&$a2sP_xIzqbQ;Nl@^HkK^0a`71 ztx?I2=X70B(Ca^99|MT*JE8U*Mf)pWXWRtlF9+L#dv@dIyXWpWxT}V+obe%AZ3Z>7 zbia0rNt;+Lfv%P;HVh0!@+^=EN7Y?b+?WJ#R}lWo9_ycTMCNFB=s1$z56|dCo&gOb z0GUb>gSE+8rFkGkj5zlRp+Yg*R%7M19>lQe`-WK9J{ES4rPDsB@J_7NC(#nIun8}* zt)v#sN-Xr6M!oRh{bqH;DfOB?THTT}OOiDGBzMBq{cGa1C82hJs&+B&@6{CjPBQEc z88$u#AIB*Tr9DzvGu_AyzX!n5vToK>G^hZTOFO{pQ)Y09{0E@xSJ9u}GRg`PC4j_v z^;Q*i+)6VU0#Kv<&D$@ZWlZHOw|=r3F8e*Yr}ekMxn-WXJQ=Ho|LO3_=ptQn5u#O- zmQh82a*lr1EPu!C!)a#Tjn=7VP?EyIP0dz-Z`-7)=|`QP63w6ON6)oGgnu&LSNbADT_noqeLSlJ0or z0Je^$F;*D!m#h{kNG+A(?kGk(QB)qy=?~+Q%W>mpmKC~jg`>*WXFy05G3d~mobyNE zmHCVoHlpF*$7%rSzc-2~@ya<*%@C`-L2C`S@7|eUiW=|5c<-;HXuwizMTL7m`+MjL zHwbjJ6aLTprxrRpcn4ZL#9b(l8v4Om-M)m;=Q;4yic5l7uSS$1tN;H@nn!S6- zie;Xx9~w8C?5^BAsd^QqIdR00h0;uSer}!muq@%1L`&zI*2>rX4AMy{9^VvMhdib% zOIHjYgoJp)Rw6=6Jxc#2&m__Vk|yQa zSBr5_tJkni4MwfpJV;;>_w~b#@aa1!Xe{3Lumh$svaSquX!{h!Ee8-CK>S?s%vU1R zK1L_m_^5`l%n|`=1dSd0fwpeB0*?a}|0l3XnJeQo3y@fOcuS-Hrmpni;X~B*cSzJw zK}p<=OF2V)a#9UWu@mR->K$VIKf@TYYMr9h3(DD5`a{!voiSnPW5ChLV$%`J@^0(s z<&TH-%cKt-Lp3q-H`8L}SRne?3CLaN`T>ND(t6I0648j!5KPj&Bp z;Wwk05%ALT>SrwJsFzV7CzyKEjD?GCe|Jr`ES%2N8P2C;QI?KMp zN5!;ER+qC@w@De206;Sa?~i`JZ$}3{Q&G*9RAfqKtv7sr;UizHrcuA^eq(XJ3QaEm z1bkrWpnTkIvAafucWo)?$zk|3(+?i6NIjsav+Ua7(CUrVdu5@mV5GqpswJ}mSV7)r zK*q!m<^%)ibi(dG_YpNMhD!G;7q4n|(y`6grO2;o$9AQ5d>-gKYOo_D>3N$X^k(q4dw!#j|O=e%W%t?Y797KYDojT8MjcUy$9tWt` z(=`SX)IW`ZQ`$YMXq85uP&c_UWtLKOJCcA`OJmu+z!P2qqUZ3@iJ3aSInTENoKb); z)iSqcHPwcNPP-fOdBe=68o`W+sTyk=9(u;NdHV0H?)^^f(-gO}Jzpou`Mw{+ZZfw7 zqRg92#R^(-y~ub#>E|)dqv1B4Wq{sW$?OS^iZ9-74yQEfqu4{?Njz4~DCf1&@Y zeKrGoxD3$wP0{_1*S#b;e_7J3KzWgei~OT6-{fmn)^Mh*07Vw6cnMY703Pka-K-IG zx{l5h{Qhw~;1x^zoRVf8KyACKOSNvfdEHv;c5KM`Yl!RxuTf#B?mL}tkA18bqh{zj zEp)9X{*n#*FsU(yKfAOq5i=j{bUeZuK6;0>(rZvrbBjJe$ z+8zr^cgtFQ=aeiSLl8$ickRu1O5rem=`Q<4XqPv`%bk25Iga)tUOayQ`@MYND9VM> z>mX5$yQf+&S!nD*Rf^qPDVhy-8dWUpy-&nv=ZN}ZWVlaV^R==c%m9lw03cLPBGG98 zXtjzp`}|a>V)z_WX`bm>C6G@oCE$kosm%#vI$sRjzP!FVMk>`%^mIxNtLT|{cP}4bXkyxQuR;r&R`;T#G%N~J)&(Uwg3yrl_+V%<{>bR~0 zV`*3%|1m&2ND%JEQG;v#b=vQ7xt`HsOgpVlEi%m7(>Gkl>DcNxAl$pO!@iHLeLWuX zN}G}=gY0Z7KpE~?@#;t(RH(IxA8ls=AD2ig_cKlQ9J_T5>*UEMi>@AjjQM^M|9-Kr z)F7}#I8j=4c=LYt_myYyuS#Qk_jV^v1P@Tl^$Y^)>?|qBzP zW%63c@o&q90T(S#zwYx?_l6~Nk)BwL2ZAiK&XGDc=WtwC(=8y<6Gk6E2Rk8ikA{Y( z%c(`gNIcbJ1HoQ}ac$H*jbh=1mlpJf(5r-2Bay>oOi6~YBc!fkOX*9*9@kdvHD9xy z#fqo)9|ai!uG{`Uo|-=bRZI&%^SW3FB@Li>VVWoC3ncFdBLb4gv-`iKL;U;lnO-kJ3uHOj}E#@NP>-=XLzXC zlW7$EJr}d%9IIx(#m#gtjRQ67o&~W91;hB+w0^j4NI>N7d)qHVHHyub`Teh}{w!`j zvwfW$;!9kSw}cY7zX3d5)^O0{6NkGeUSN+cvLHIpk3j_n)uF+B^E+woyKSbLy2c!q zi-7@l^HcH4&KosqWlr3qvI;tPv+UcU>{aJCJ0Qir+b$0OKWq0eaEQe%PkI?XtIM#>Q^)X{#VMGuuI zM){yx!g&j@_R`2Y$)I|8@{Q@8SvS9(jl~TWKGZnWIhg?*)PnbCf~~g9L^+)6Q#sr7 z`N({GjZL$KQdurXdzA`t>{*8&W;ANO-^$y?wos)fv(Xib1Dk*5@?EyX%-j|s@!M3v z;TWLSD^aNPnppW!$@OEmAH=$D0US?_0x_cHT=QT#hx7MXQSmr;jb3uCSu$QRa$NQZ zcAiUe!J8q2+)!2RTq~qhsv5B{l_%p(7~bxH`nKqKWN&g!5+n*=-8n_F;Sk5{fdJ8( zr#aU`iCEpJ{RIQJpPC@2jegd=%hvP)Hbz)ee)R1{j;GyG^pa0}gf%1Q{0~<2o*kOOMf_AE#%Cg&|SrSElF@xv) zIrzLGsmUTOuwReX2MtJYJ6c2q>8Y{E?zlh%3p$XY4=9M9W&2!6!If_yDQ`#eb+`EW zj_2f?4p_%0tC>JTN6SmSn%x_=Q7`*>Yyt&yRp7xi>ECO#RR{i$5s5wHD}JY-pH0Z;Pi*KofuWPK)x zO2amuACd}0qt+FIc?~K}L=YYp1of0iRCZwpE&li#$3v%Ws$pK{%}3#>5eu4MBAOjr zeaf zs$LfJ7NIA`OO1uF?GMf?>F-Nf3tBh2yiF;u9d>_-e{{L(iYt3LBAfsJNxyec(Mrtm z{}!(POUZX=wSX6eO=15@UNgB`ShicDr(18FZ(j#3-aji_d1n}G5-aZ~|K_l6$TM#{ zOJZrS&4NY;GuJdu3^}(h%(jSgr-x5NT!?(NvE_BEY{OCpHLKNqD*y9FM?_kLUZr0} z^3KBm7(JoJDzIWDc>Jvc-85Y%ava$7s&4#mYhVjfxZ|%=(M{W96OLLaH?~UbZJ1Tj3KWmAf20%mmL9nu)HJF|^EMm83w&uz?Pbul~4Gg=>wUErA_! zEL?vb4~wq8yc2A}ZqqovcA@SiH-8Yk_sV_{@T_9}4O-b5m`iP+iXdL)k(9FzYI>}4 zJwk3rIDH$IAj0PMBfvJzfV7uE3m9^omjkR`>0)W*fbqxt3legDIVCaM^bV) zFr(#?+2#nvNB^2_nAV$NuJkI?y_0hUwZx(Q`RQuV93fb|>g<8J(Um1g4L zj+hCBF#Z0eVX{z~#AX#43~Ia}=UK5qBR{E|S3P4C%EOiaJuzaU>0ad3ONGA7&VIAu zK6S0-T47o9q$gbzi?#c}s!;gP#VARh*Z$^;=P z>Yp=B;{(A`GgH|Hn88Og5l}1-S|otfy?|7TcAr~=jkU)$3@VLWlEj@?fjZS9;gc$&OtL;rreB5wH?o!IzX64Os_y+>K2Uprd zqf0x;O>(j0gGyhSntlz6cSwr2WE4ASA#cXvANi+?yOq`i8cSO$3k;?F+;E)5t!2zvjMv&T2gv^jkV;F-k9yQVf;dsKIB-i7P&QM#@}zW>`yHeEu zuh&@rwOUy!XN)>f85aqi(ttjUkgp-_JvDi;|9f1=TAcZJg?C);fV3*WCdt3<2BGFrT?JE??XL(pxi)iF~PlCLnm7RG01irvJ!rJt#?`! z$RryNeoMNs8L~+^gbB(0Oj5dsQ@pjNP(0kg5d>NoR~{on8t+3+jzerxp*$w^0^>rx zKvAwk(fSJfEuv|Q)U*<~-82%p@2QA8DuC{~4?PhGkv|De6oC2bm~-;Y912E0-RUqN ze2CUIj=F5rw`0G^f_(VI(6iIDZAu^SBe0tpEKyKKmfS~TN;GJGW+Il1U2?+6(=>;~w)!cB&?i7N>&PXI;8;KHR&y$yM> zAZv)cedc)}eDEK*HabDl&V7b}UlP>`aFEQo=uh&HqwTfDoqE|a5cmg!@ZV1m92kd;@1>RMJp|=z0GT`cRg7Jpjel*VLwM`hpkSOh9(!4gSOx#4c zBR_HEK*RYiZ>eJTte`eWB>xMb@Bo)7nydd5s5Ev?xn|?g*)Zes$(^ZaJqbXkt~S2g z-W^>;ZavwUPlHxulTQ_rPid-HEf8MyMVk=7ITqk2Xw1t3^V59dSz1wJ$jN@%Hq7ZI z8D6D{9oUuB1Lxr!^7wjH9T+p&2c4(D-JdVrz3|}v(+9D04<4g>g9P|MX3ayki2@4W zb=1V2Vd&ZJ-PRx=jmZD*kbnMfjy`0^Z+=pTp7OW$@W)J;Z5%s>UR5*kjSI0iXJl zR>72iLj1R2qifnK>fm_tgH*%=1q(eLSl^wZ2lpO47>Vn{v-?7EhOl+ep#;$3avWUN zrP~s3Zt9Xa=>>`Ft`eh!bMoKw&ua85-9dXy3*c>;zAYq$jB&jb|Lyp}e*2F|mE+Qb zWa2w0;A^;Td__s|RzJ8`f{V9YwMyAyZM z5~LbA?t$ZYFbMQ^x!CJBrFIPs_d|N$m8bdeznT>U?K&UIAxD@_Y&^z!Ir`{zL2vI< zw~o|feA^@K-~<7IPLK;{j6P~8f0~9bCN(3Ky;L05hJh|0b6&L%4l~@{G)8AXU!$p zlTMIa=sIm)kR($`sqExv6o%Uit`={<4v{fMQPf?Ty>7HuC$wwSWsOcTA%*J3o+*20 z%jM4_i1$f~lOn%ik{u_++N*N+=o+lrP~qSt`0#@50NrzMEJRUH{t{mPd)Mx_3G$T! zsCf}I%UACP(exgG11Ffw|2O?XTP^d(dq06qAY(=s$>?&6a?oSB8nxATf0xNGv?0Qa- zFXzM6cA6~&=dRXRUDJbl+C!bUEdTQx%E9X$d%ycF7dB7@o0y9tc%ON}u3i<#+Vf(C>2Kv#1zaEhdqp`C$JImv*C9Od>1KytyLlaD}Oa=MO2L!>&} zO_RU)$L{$Sr@j zw;n0b*eTC||EVF5s-;Y*Ix>L{OrY(!S6JnPgtL{xj0O5pF(lH$Ff0Rqg@`Qa7#p>MY-$yx zltN2!h{O+P!m~UE!(vz-kZk74LD3E$McY^sza4vO_?3NlcGXYGQ|dXRgS5qSs$UoI8d z=vii+HNUuBFy$U3aM=wDLrx7AT(C~OA6gJ>;8Ud&R>)03U2!&QNC{jpiO^^?kzgQ+k5Qm@9zh1BybA*Da* zPLa0po7`9m2CegJ1(%&tCR?t>Pk5grgt4thg048`Y!WR-^`Yf>*QQ?X%1?Z#OTAg1sC&xpo40QBDsXrA z_{zk`OV}?XS1)Ca2N_+AFQs_ZzPFQjAlzh-ivkZ7`CQMy%EqlWA{62q*L3N1rM8aKfV!1~JMBRR|*kTCBf#@Dv0~8qWsq6v+9cK^Z zWu}`x-beqzffv!=CEmJcX705ky|Ao=V#_g-dxuH;u$$t}&cJF4RWrS*{J^=OyxPoj z+x{Q5X$wNBGGN6xADiLUYk1*cIQ_~%pp(zxo}iclxpR@pz2FPCSA`#6JpcAOsr$@N z`I1XHwu}7!QA?8{DX6;c(P#|m*ti3^i#@CsnOtsAYgBeGPxD}FQ04Ajl7SEBVzQ0p zRKtSHgVB3*%0U&>H;(!xa?gk95bcw8ZUx?zfo=tc3fFcb-$oUNdB|jU*`Io?4%aei~YEj9@wSvF?(*rGjZQ6f8n}WkAr5)uA0P! zPtIlPN%c?rcYSerX1~`+=lHDDb$fD3?a=D@pVvt-lO)K-#apjF4R-F^=&aoJaJ^(# z;4hG&!14t?bLm zE4y6Jt^%>|=i)7X+ZA8>Lcr9?qzqW=$1R4Es-6FjS(jbJ0(k^{+z2FhT8$Akpz0Mybtt9TT+3VfTJ|c576qgzo?uJnDh% zyAkh0cglAdYv{75>&Gr8U$I*eyPV2tK67OP((+C0t^5NI-2Xun|qc`Or9= z(qo9rH@Y(VB2m}yCxk53xn4-{(DPC+rbYB?z7~0H&Igs{kaDf}eok`z#_~vK_U{%! zy>^7A8#RW`qt3EH22<_UwsUjfT{SF3&KyT4RICu*(}#^p&MyY9t9s>l+PtO1;#A@> z5g9{Py>?JgTCVvV%jHDd zRH@*ez-bN-8~7fFUcWb>Z}$DFj|Tz8e|hb1YkXwv`zPUPHwN^fSNkfP0@S($o;w?m zB`J3CT5tQn?e8Z_vl@Vzf6oo2Hmt+=gzo{Zfu5c&_(J}+G@ECK2r)yn7)%ciY{^hT zS21v=fq3`WM1`7mrGc?)K`nFFv8Unk}o*GGD0|J@ha<=`bsa8tuT}<6g1^ye^Wz zd9|l_V6J%q>6ddY`#IAq^>$Fn{oaLJhd;k`NQ{1)s*Qp4n$h*}j=a6pYQlC#4A9StAjhH;R4>D+~g1%9(BtvtVFmXdsk$H9yS zz9Th7K1-QyS=0agnrheA#g+l#Wsw&g_snmjs%i#y4FQxGuyfvjhVyM2@Fl73^B&jN zs0?E*T|e$TzLAMDJ0^K~(>Gr81%F8BSn>&@`$l77Ye?%VrNj#Eem!zdj0%EGeQt?EPBa{;#s^dpNZY@=rqs z4_FXenya%h_r;Ej4tu%#;Jv3`0`pzeQ2f(eyk?5I16me!@dkI7NO}-h!ZWKM?d8oW zDSme@kwPkWK8Z5gsSs$h+QTZ<-Tip z^PPOvvZ~`l`f{p^;d7874AN`UhKC<)Z%{q^BhO};Zm>fP)LxYtaQTg>P}=>=IGC;w z<`l0v&iCrS98?rF)2BB2nrnm=K4tCsu9x=gsd0EmagzQY?5fi_lR;i-W?Ej|SDA3f zn%g`5T%X&S)}`%H6nA=H+`hFJ!0}K(`0J@9L_?DEr%jne7k`O@-+utaNg1xbwXeKq zJ_nnbR^O{`t~J^>6fz)$#Ts)i-Kc-AF5wjTHN|G9jyq`8<^1=#iv>R%=>9s)4bt&S zm@ifLUEE$9-hBIsKGyPJdqC^vzfv~{`qJEh(VwsM>0EACHrsLjA$2H|49OruETfG6 zlQwq|)&DUd2gkuuon|!EE{3EOh{6bpiZ=^*mCXsP`75wpE{d5OEdn2z0jE(L7&ZAPTJp1p1!sHmbJ}ZDY82CW zxV#S4=z>mrJ|{7rV?FoKj^wC*RH)VmJQ5=Q`;(B@sn3%IRj(IB)4AR?urj-Xu}OpC zAp6mul>sx{fML+1&f;CN-OopQ7(I6x0&rSOUg}(K&wOssOhpim;`I|xUK8plG;C^t zUTA>=1n1G)CvwB79>Iv*pL)5wX?Pz^O&b<|yNz^Z>%LUM}diUWvu0#D__MdWNm%*n-?OaCfjv(?4 znu`9r2a{~wP|9q|v&0t3a=kt3y%o4i;~=RZG$IFYvkkQ3bD_=<*eTdQEOvNl#842Ol2Kds|@vhAF6QCZyl8&v7LmE`ikLK*~Ow z)%)iLGnAaKiGr3vDknj)agV)-pxf@l#VB`|9^hPzubQRf;o>JgokZt3V86W1`?Qv} z-}qA&&g2;z9}#zHSgY5IH)UpEfz;sH-B<{ch}oTi>XKBs)V27I3ncHL;) z-3U&efs8iktw-wS%;d*X6f)hwi9O&$Qt|HAcmi2&PUQ2zIF}vR@`eO*6ZujQ-c3`$ zBc~qvw6^$eJo_6IfGbg`jwoo6u~Kmw^V`64zj1E=zJuL8rXTz8^)TvRQVX^c%lzbS z=bJCHIGKsbKZF}d<#G12IXkmGcamid$g)NlwoRBU3Cgk9V!LCwuMxU!c#8kk=FHRDtPVhSh++CvDq$6OLL^Al5zG5dy+k@%%W*f(Iw|nS?((!W$E^Hw3 z6kb{^PF;m{;ox0|>RWtPCj1HsDzltd>wUZxAVNjV!tsh`DiRo|1ZqP%PS2v1uV9QR zXW!Yy=LCCb8qj1bBV`j~*$Z_q#(@;4T;0>6eEUxCQv)L*xZETfI8O_5m6(6aM|2eP zDh-`~WCr#pyXX$1Q0i1H)5@dE+>^T69!j)4;%X7AB8_*xlZp{N+@~JNpy|kdSNYyp z6xORHw5OYByb|}x6A}gTLb;|n){s$(zr3;8$;c({>nE~quOF7Hp=^PpQ&oA zYNslc7dAGx4&?U0-|E*l$P|DTR7!8Fp5x>uvvUs(OEc}fZtCUKqxp|U!H21G;VlN{ zQyfQ;?3MendbnBw4oKQ!|N9f_AAy#BSprqvtccjGHAK1{1=v%qv z{@|9ZD@*dv?(*}qTM)-+`R)td?p@=18ESjU(83S;Tn56EZyNHt#D5tSnj9G}$cd`-A>57?RE-QOK#x)o_m#c@eEWvIoIbQ+>5afS`G~y=I(3H zeN4|wzyv`?!BKI!A-E@AZssekucgvn0>40ys(lCbDtz+pa~h;FR_hEC0uu`+ldq(c zA&0i=kF>lxE;NqAfGukOKB$;HJB~E9$%+|47((TTvAHz!!N|L!HQ4Spto(L zEmBN)c5YOUToY$FEIHR6x&PNUxy@W$M7!GFHSUiW9r-vpF$f$-`wMkpe*!V@uv}^3 zA<*_P>H|^#d#_w{M5WC&B)ecR%r4hq@QEc+#gY+D_3_7V0ZMtwE~xy>;rz*(%csX7 zcgHnGUqil~xUm+gV76_OpCMIuM(hh5zp$I%9MO||h)iJEy`~}eWy@GUkEEaUY&*F# z_ivnB*~RD;EcQ_fDVdGT>OnNilpLP(EAF@38GkkV%GHOfc~9E>bNm{bWAj@*A?lmB z!^^obHR!%DuG@@nTY|n$Fb-+`@C|};q_OF{8_>GFz=+S*fwDCn%obV|D>ll{@+Bvz z`BuJ=wiJls2}lq{cRDQJP(hSI%?}T>4%-4b&T^yphB3?FlbRo@PG4O*QOF>I<09zs zTaBI2QtP&v^F>xv5om^sEDy`4y+hV4>M`c>oICFxMKtdH2|n}!Jn|C!bTKdZSHERk zVxmiaR(2y}dl|gr5_+)U-VS-tjiw48>;Cayz2kn|+x`JoWDbDEKF^btk(1RWS6e|j z=;(6}arsN>5G^l=9v2eCg4k3*IuhSGtrTZxL+(g5i#@Q?Ii4HO-cuwsi*f__ck(9k z4llom$K}Od`761+B0wg0wq4a@M>Xe5@KL#`Uhctgug?a&SK{&qbEaShQG!=;h(5~z7P(y6nL;t_n`a6DVAlmAW&{XV|90Y_l5RTpLiiJM8i@>1`8ei+25X9hdS5 z6e1c4WAOgYu4}nA%Q|+>aUXKe8mLeQ9KXc}{JwrSfPAdo@T6t_L2AsQZARz;yYld4 zxtDnPuI`TPoWX+vWPSX!rvv%Os z29C|u5?iBsD)r*g6{ru?Z*vG#kIfBT1MOAI{i{GT;*`yW)YsS-9kE>XmP2|MiCn0O#STkk

lZOIzz&i0oy4&w3KA+k06rhxk6rE+2C*(=Zxn&6hQ5ktOmA!hf@Zw*eM* z$`;H?r}ksr`Ttkaz4$ZP|9=4A%wgEsu(8c%!^ru3&NgRqCY8!5NfJ>>s-4Us7y{d{>}3V_%MxWoJYn<~) zZlo=D|9o&)b`A9{M8yND!wzj-fNwCt%^ru-@Voo&wVvwf#8 zgjM8szc`$`mVNqGsFDi_Wk-kfSQOJ@`}D|Ml82XtOrh>suKNh&;W2NvW25qhI@{!l zk=qFm0BrQ&;_PIj&l7`y8hT`<{f5o=OMlTL+id+bO(I&mIp1!6!5W92pAyGu7!_$6 zM;u)dJ3$06obA!^uKx{)5!d&3p^XJ)`rhIK$(6|6ESE!n6fpyONB%73>)izKQDVx~_tk`bkL^@;?d=vR6XNQv zytl^{%av%y6@RE(N*0%goj-TJJ5glfEGV%Xi{<&~<;-O8clyye{E|RRa3AJC@90T` zQ;A`!#=-(?wbTwuSV8KM39HbUtj;CnZRrD6D#T31eNYOY;IP4d?ZlUcN9LVFfXzAI zzKXPYEcPp)@KD#3v^S;7A;|TsAw4krF)T%Ob)SC)0Uw zd)q-)kVm>&FY?@PR0`5<_95>~wg9Yr6lj1~#%~v^dE?@Xt-KkjLWz)Gm;*JT;FHHe}U{g_MeAi`UdG?sQ&9xXjP@JaJ$3eOKHoz)mM> z#iW-TWgq$L$7*z&@9@L~&?Suxb)5E{VMl{f-ke|KETC*!-yYeV`MCBsJ5MVn87+7c zUls>!$`8!h;I_960$HqZG*4?wA|ph1U*d8hy{YqX>NR1mbsjdDJ_|gu>rIlDVj1cw%(X>v|n3Xnx6ERg_k!$p=Wah1~ zvefzGA0Pre@xZDf5V{!M7^bzUcV!6sWkM!cP5a%&VKC+$^dKk@81m<+V)c#Zm zwwx87MYt@E%!XNtQ9VmcIr-0`i)@62V6Iv!qWoj`CMO5|8MMW(XN~qA2==g2!iI*# z{lzwTq5mM5yih^2C5A;%@SKuWkE;~NK3)VA}O$px+AbQ zKBAzBqCi<>DQ#7|FiY4-_&DLy^Ecy!;CrK<$+VCA!jgD*GF5k+thC#^Jb!Re0?*8T zM4T0)Zieb({(*X1tZ_N8|FwZvPn#b02Oj0&tJzC#w7~_CuTdns z$9SaWntbR_nFES}Yxc%tOGY0$NBV=#%1fif*49v--P-MSupwavLs`;IJnccetk zGo%62XwA==E2KMhfYrmq3Yx2`%InCAUTSgq9|n zR^oi7bx1iE%bbUfd#{J57&%f()AK+wk&>{)&z+FIn3vvgIg&*wl^s+`n znJ^~m2oSw1b5zzBpK`dL!_}!>G!FVyS{Uq$)tC)YaT$n1mu4$cg*R<9n}lTxxf1o? zZLQOjKBvPvm^V7&EpGo2INX2uwED+&K}wKFtu|DOUTHGY9r19VkNAj5xuuw}7JCbK z!fKb>0=RT9zfpHIR$x;%dVKUdQ?uPS&%}~J+n~q|;^Fq{foKJbIxR?cM_tFXeCAN+ zL}g#iKC9F%r5Uy;y?#?|_lhOhPC8WsC_FPz3?+kWy-?XWl-|UMuDv72CJ6fcaHbKT zUL}eshqy&{V>knkAdFlH=QExxh(4 zo}abkbs%&)VER2ouga7F{ss1kx`>$VKl!wDv1IQ^a=-1_xQ1-nhc)6f!rPJ!F8F+t9^6oTP99Ru_h(vL?E#cO@YHgT$#z%=HH&#jBjR*wZ4 z<6$Wws^(0Mvtm5Ah62y*;8ib9XS_)qVZ>%9;C#pVG~X+sW&UdFQNk3{EXK}ZcE7cd zf!GVoDt8umnJ0==Ud@Uk6X-16ADKeP7r93+6vdVvo?+s+@&E4UQw3JA1PL{3G2O@I zrMxtm?WQx5EwHUaBM)@5ZWOipnEOr~_Y%9Iu~bjW)Q0N2+R%Gm-d{;Y2vhFt>B-p= zCDSB|y6;&Y@nN#EO^qn;Xp;PBUKQhT(&Bvvn&a-d){?DJFZQ-aq@`o8J$(>RX|U;G zN{`R1M0h}a7vJuobgoZBdmsen$Vec_a1R_(DaSVtOd}4(`r?PgChNWcX~;BBj}|6$ zTVbHUYS!5*O9j3j)97BYi52#GP3PTr#HYA_Y(e(0_}K)#D`y_KPFo>^U^g_De)L59 zKgw@9rrmvdfN$uYQ54lFHCbeu10tvg&(^cYhRxc?fw*_#++F*vVqaK~m7;AWsvY6# z6XJ;pHWFB=UG|h#Nz5#mS z|7A=<-b36KW5jS4&`9*#N#;HV>6!$(ekzQHbjgYZ|1sVkgfq$MOv6|%@IM38%$2M# z%{_-~JXio3=upt(Hp_z82^7!}8`JQl=vXx|+j&ncd;-+!sD_y-z~pXDybAs_`GU}{ zw53C)+bz^-;=B+d8z;$0=qH=yAXtsYwliYYcCn`G2F>n(bKs3kI%mL=g9LUIv;Bis zK!*zjI`k6V8P29f$=#AX&f+;eds2J(BiE50h|>suSOIhm$ZjCcu&K~9JVWt0qj@lC zo2>#?Gr3Z;YxoQd!uKfC0F zza7J~3+yKeP6gj#t9j0NrfDId)z(^)1ak`Je6Xe`7?;l3Ue<)GmuM#!;9@v8LcnVp zRmA}xg0itERsi{SqUrFEhjN|9ayMwVxtF&j9QD{EC9G*Py3avVf-XL3cc{tMY6CU( zq&}8s)%nPcTCZ!Xy)5IsIwz~x%b)O2{xiw4cT&1gMthncmP)fN1!-K#X1YK zrP`7p*XLrD@o?AsRPz~y(reZ6uKnxV3!ZNx8Z1^EFoxKyNKM~M4PxG|(M)~!9@JOS4V}pw?Lfgdz==LP`S~DK9 zhGZI+bR4!6-v!3-gMt233`&xy%2;#^UbH-+kuker+yj9P7T6;T#|;Za$@;2{MC;9e zVG=~DY(g;)Hp55FgQ{jEq*+vH67j^3mZH?RZDEsQK4jnJY^|>-lZK8H zZKX%em{zo&ALm)lWf12fh->ycmx&Pe0v8y}AyrxyqwtF#TxzO@ z%r1gQfKPaEjH{%^Lhkb$0Y=#hK;m(wBUG?SGKxd!HWjsZex49WwEy(ACUX|()N|Rf z3yPczGfz}<%9~z#82;cN8WHCwsWnsu_Spptt(NE7_Vs=!7VcnBU6gaYA$-w7t0PZk2GMmw2%s@MiJ|cUaZ;I4< z65TScQ5BPJs_&T2GXa7gp@JFN(kz$dkj`_!hFBWV>?3;WX|F!s>6^XR2Xsbp>nrqy zsT8rYfvc3>r8pnOJu&%$IK;=app#}Us~_uQC7Rn6tHOw=kE`v{0$+<2=9Re@0}uW2 zV@3F?=}Xt>}y^2rARgy6JdfL@IknuLkK2ey_I3T zAmHozpEm;#3W)8DzxUHj*j$IeGzTFU;9!l%n4}j{2N=x2t{6DJvh#)1#xV_TPm{z6 zI~)~>5dxihurAh<;rL#+L+SeK?Gs!M5-Pc%m{K%sj8(*X++aGjab093&SZ`K=c{r} zik*e5nr4VUz`-Uj*u}E`9Aft26e!t!M@IEHWCdzd>JMY?TTg`_W)@USg(=DFA(L-I zn2&cfnbnC8+lSPWsy2kCj|NY8z+yfxc9|hv!AW%RCfEZV(nqHVgiAEfXAeZRd?aJ( zDlov#a#y?pw9V0DnFb*W*A32Wc2y+JFo>NTx#KdvJ65+hk6?LvQ!Yb$wQoLK*04cK z?|jBZP=sHnf@wX^xnPU$B+s=y0)JrZ8}eBv@(a`BVL;oUQP+ym>^{nvggYUzSOe?R z6oOnbsVgbx+-z*aiNQZjs3EWQZ3}@*=EzCqOD%%~vVlgD>H9v9z@t7FK#VVArRnpO z$l>$O=U7guEc@&+i?Z()y>IC_);lwZo8#o`7T!9Qp66&5y)4~0LTX_9G==|}%-^`n zk54k~B@Tf#n=-I$+1XB-#;V%+a_yYa?c`PP8ryT-Y>kO61ZUWj7|pY1^Vas1^lZ6U zcug=YcGKLb2if}UyNRNVek#EvS*p5S;RRXM7~5f-sxV%$$pEH0x{RcGFlkNm6iWqi zNO7QrFH!8ToeSQY`q2Ez+{o?0dT)-k#gz%pnb*BN2~#gG9Z@h!WzunwcLqI`_gF4X zJ%ur^EeH_0kZD{dr6qF>BBUX^6zGIWlF3%Rsg3JGn>S=PAXEDX+BrJd*BtBsNg3KH z?KkO=t`kaad}Y?j3rWX&!b^Ij9jthMkSl#-7?Jl68A1;<=3Qh0#HdLJ(7MMp%;Fk! zC|7vy0dMCT&Yv@2_ZrOFm-=v3`UI)4gOuEd{osxJ@+G`7<+ZZ#V$^XCeyW@+-MXI| zZ@bv;X4!9f$kTm5YTBz{Mr$(r=Z14)*R}gSAFv~?GM?L1PhI+%6ZZY86o|F>6{$WL z8^J&Ux1m_&i@l#M2cer1DgSBua#o$l(R+-t6arMNS8w-NiEjIU;kna4kKaH!hx}f* zKGG@Hxu$|;9|5tC<*Dx4*u3`+J&sp+V&DAl=*QmNx2r#>reF0@-(yVy*XNXxsm6gl zJo~@}Ga1)hCarmW6FvCaF#VLlA~SA2gsGM(=3&|;I=fD@K6sa{>y`qIp>5l_ZC^KDgp^wM{05#S-EyQx zWS*ivi~c^RbXsawTx*!fw6T%W+RJKd9=7&FqUKm1W+8WI+gx+c#i!mq@w;cs-H?}i zh_`mLF7ISr8c`F!yqsLaxqp(g=?}qX9k;`Xo1Sd9JzqQfmn5IAK%JMqSd%*7o;#Aa zz4yR4D|TdM=g=?Rb7<;xVz)YFvmBZf9VU)AbVvOb4ZI&xFzu4|Zt?7Mk+!J|ViR+z z#R|q%Tw_>I6~56+P;f>{>Vu!G9G!gXRkRlnp5CWhRp zzt!OL+r@S9$rYA!M^Aja)~x__$v4^a->jxeQqB57ayN!R9 zpIVhradFhDLi1IH4|=Ekwv;-1VDx;BUe-PmodC%i$fOJ$dv}&+ zn!Cd^q`R;2bnv&8X^X$VHoeX$VL5{MuG!1elHD(Y-rUM~Cw|`M^=RBMxZd&hzP>q4 z=l!2Xetnxg@%Epi|NTArM?3he%b~x24|%p$oPTiiPqaXHV`;rXz$sI_aeVIpTIADP zph^{tkeOWboAG%YPTx!!t};$&4tQa{^{n&$t!pbM(T&~-!RM{_4^CW-?{D^NRNhl_ zC06YHTvKT<{7t0x)=BC6TN^F5ZQlQWaDPVR#pvsa66gK?CtEk1vfY)Vs9MqJRfsXh zyecSf7(O0zW8aOoy3SqC#&2(VkoKlK``ep)yH$_`r;O=pvv5Iiw57b4uS!kIjB$*4 zlyP!K``Y_|4lccUOx?6E=lkci)i0k-Q+_(G|Tt| z$fbowgxCFkhWNx%D?yFvv0poIJ37%12$^a4Z(1pBwaU7g6MjC#%D|Vy8!E3^0UxXvW%CADCVBV?Q4%Va$%IEwn0M{X)z81Nt!gxpZF1?zY?gI$6VhAAe*Gh3?e#xeZ>p1rNq6 zp*=B9{5?!HdE 0 master pointer --> 0 + + * 1 1 + + * ... ... + + * M-3 M-3 + + * M-2 M + + * M-1 M+1 + + * M M-2 + + * M+1 M-1 + + * 0 0 + + * We read alternate iMCU rows using each master pointer; thus the last two + + * row groups of the previous iMCU row remain un-overwritten in the workspace. + + * The pointer lists are set up so that the required context rows appear to + + * be adjacent to the proper places when we pass the pointer lists to the + + * upsampler. + + * + + * The above pictures describe the normal state of the pointer lists. + + * At top and bottom of the image, we diddle the pointer lists to duplicate + + * the first or last sample row as necessary (this is cheaper than copying + + * sample rows around). + + * + + * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that + + * situation each iMCU row provides only one row group so the buffering logic + + * must be different (eg, we must read two iMCU rows before we can emit the + + * first row group). For now, we simply do not support providing context + + * rows when min_DCT_scaled_size is 1. That combination seems unlikely to + + * be worth providing --- if someone wants a 1/8th-size preview, they probably + + * want it quick and dirty, so a context-free upsampler is sufficient. + + */ + + + + + +/* Private buffer controller object */ + + + +typedef struct { + + struct jpeg_d_main_controller pub; /* public fields */ + + + + /* Pointer to allocated workspace (M or M+2 row groups). */ + + JSAMPARRAY buffer[MAX_COMPONENTS]; + + + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + + + /* Remaining fields are only used in the context case. */ + + + + /* These are the master pointers to the funny-order pointer lists. */ + + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + + + int whichptr; /* indicates which pointer set is now in use */ + + int context_state; /* process_data state machine status */ + + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ + +} my_main_controller; + + + +typedef my_main_controller * my_main_ptr; + + + +/* context_state values: */ + +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ + +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ + +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + + + + +/* Forward declarations */ + +METHODDEF void process_data_simple_main + + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); + +METHODDEF void process_data_context_main + + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void process_data_crank_post + + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); + +#endif + + + + + +LOCAL void + +alloc_funny_pointers (j_decompress_ptr cinfo) + +/* Allocate space for the funny pointer lists. + + * This is done only once, not once per pass. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, rgroup; + + int M = cinfo->min_DCT_scaled_size; + + jpeg_component_info *compptr; + + JSAMPARRAY xbuf; + + + + /* Get top-level space for component array pointers. + + * We alloc both arrays with one call to save a few cycles. + + */ + + main->xbuffer[0] = (JSAMPIMAGE) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + + main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + /* Get space for pointer lists --- M+4 row groups in each list. + + * We alloc both pointer lists with one call to save a few cycles. + + */ + + xbuf = (JSAMPARRAY) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + + xbuf += rgroup; /* want one row group at negative offsets */ + + main->xbuffer[0][ci] = xbuf; + + xbuf += rgroup * (M + 4); + + main->xbuffer[1][ci] = xbuf; + + } + +} + + + + + +LOCAL void + +make_funny_pointers (j_decompress_ptr cinfo) + +/* Create the funny pointer lists discussed in the comments above. + + * The actual workspace is already allocated (in main->buffer), + + * and the space for the pointer lists is allocated too. + + * This routine just fills in the curiously ordered lists. + + * This will be repeated at the beginning of each pass. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, i, rgroup; + + int M = cinfo->min_DCT_scaled_size; + + jpeg_component_info *compptr; + + JSAMPARRAY buf, xbuf0, xbuf1; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + xbuf0 = main->xbuffer[0][ci]; + + xbuf1 = main->xbuffer[1][ci]; + + /* First copy the workspace pointers as-is */ + + buf = main->buffer[ci]; + + for (i = 0; i < rgroup * (M + 2); i++) { + + xbuf0[i] = xbuf1[i] = buf[i]; + + } + + /* In the second list, put the last four row groups in swapped order */ + + for (i = 0; i < rgroup * 2; i++) { + + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + + } + + /* The wraparound pointers at top and bottom will be filled later + + * (see set_wraparound_pointers, below). Initially we want the "above" + + * pointers to duplicate the first actual data line. This only needs + + * to happen in xbuffer[0]. + + */ + + for (i = 0; i < rgroup; i++) { + + xbuf0[i - rgroup] = xbuf0[0]; + + } + + } + +} + + + + + +LOCAL void + +set_wraparound_pointers (j_decompress_ptr cinfo) + +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + + * This changes the pointer list state from top-of-image to the normal state. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, i, rgroup; + + int M = cinfo->min_DCT_scaled_size; + + jpeg_component_info *compptr; + + JSAMPARRAY xbuf0, xbuf1; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + xbuf0 = main->xbuffer[0][ci]; + + xbuf1 = main->xbuffer[1][ci]; + + for (i = 0; i < rgroup; i++) { + + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + + } + + } + +} + + + + + +LOCAL void + +set_bottom_pointers (j_decompress_ptr cinfo) + +/* Change the pointer lists to duplicate the last sample row at the bottom + + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, i, rgroup, iMCUheight, rows_left; + + jpeg_component_info *compptr; + + JSAMPARRAY xbuf; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Count sample rows in one iMCU row and in one row group */ + + iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size; + + rgroup = iMCUheight / cinfo->min_DCT_scaled_size; + + /* Count nondummy sample rows remaining for this component */ + + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + + if (rows_left == 0) rows_left = iMCUheight; + + /* Count nondummy row groups. Should get same answer for each component, + + * so we need only do it once. + + */ + + if (ci == 0) { + + main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + + } + + /* Duplicate the last real sample row rgroup*2 times; this pads out the + + * last partial rowgroup and ensures at least one full rowgroup of context. + + */ + + xbuf = main->xbuffer[main->whichptr][ci]; + + for (i = 0; i < rgroup * 2; i++) { + + xbuf[rows_left + i] = xbuf[rows_left-1]; + + } + + } + +} + + + + + +/* + + * Initialize for a processing pass. + + */ + + + +METHODDEF void + +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + + + switch (pass_mode) { + + case JBUF_PASS_THRU: + + if (cinfo->upsample->need_context_rows) { + + main->pub.process_data = process_data_context_main; + + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + + main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + + main->context_state = CTX_PREPARE_FOR_IMCU; + + main->iMCU_row_ctr = 0; + + } else { + + /* Simple case with no context needed */ + + main->pub.process_data = process_data_simple_main; + + } + + main->buffer_full = FALSE; /* Mark buffer empty */ + + main->rowgroup_ctr = 0; + + break; + +#ifdef QUANT_2PASS_SUPPORTED + + case JBUF_CRANK_DEST: + + /* For last pass of 2-pass quantization, just crank the postprocessor */ + + main->pub.process_data = process_data_crank_post; + + break; + +#endif + + default: + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + break; + + } + +} + + + + + +/* + + * Process some data. + + * This handles the simple case where no context is required. + + */ + + + +METHODDEF void + +process_data_simple_main (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + JDIMENSION rowgroups_avail; + + + + /* Read input data if we haven't filled the main buffer yet */ + + if (! main->buffer_full) { + + if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer)) + + return; /* suspension forced, can do nothing more */ + + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + + } + + + + /* There are always min_DCT_scaled_size row groups in an iMCU row. */ + + rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size; + + /* Note: at the bottom of the image, we may pass extra garbage row groups + + * to the postprocessor. The postprocessor has to check for bottom + + * of image anyway (at row resolution), so no point in us doing it too. + + */ + + + + /* Feed the postprocessor */ + + (*cinfo->post->post_process_data) (cinfo, main->buffer, + + &main->rowgroup_ctr, rowgroups_avail, + + output_buf, out_row_ctr, out_rows_avail); + + + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + + if (main->rowgroup_ctr >= rowgroups_avail) { + + main->buffer_full = FALSE; + + main->rowgroup_ctr = 0; + + } + +} + + + + + +/* + + * Process some data. + + * This handles the case where context rows must be provided. + + */ + + + +METHODDEF void + +process_data_context_main (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + + + /* Read input data if we haven't filled the main buffer yet */ + + if (! main->buffer_full) { + + if (! (*cinfo->coef->decompress_data) (cinfo, + + main->xbuffer[main->whichptr])) + + return; /* suspension forced, can do nothing more */ + + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + + main->iMCU_row_ctr++; /* count rows received */ + + } + + + + /* Postprocessor typically will not swallow all the input data it is handed + + * in one call (due to filling the output buffer first). Must be prepared + + * to exit and restart. This switch lets us keep track of how far we got. + + * Note that each case falls through to the next on successful completion. + + */ + + switch (main->context_state) { + + case CTX_POSTPONED_ROW: + + /* Call postprocessor using previously set pointers for postponed row */ + + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + + &main->rowgroup_ctr, main->rowgroups_avail, + + output_buf, out_row_ctr, out_rows_avail); + + if (main->rowgroup_ctr < main->rowgroups_avail) + + return; /* Need to suspend */ + + main->context_state = CTX_PREPARE_FOR_IMCU; + + if (*out_row_ctr >= out_rows_avail) + + return; /* Postprocessor exactly filled output buf */ + + /*FALLTHROUGH*/ + + case CTX_PREPARE_FOR_IMCU: + + /* Prepare to process first M-1 row groups of this iMCU row */ + + main->rowgroup_ctr = 0; + + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1); + + /* Check for bottom of image: if so, tweak pointers to "duplicate" + + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + + */ + + if (main->iMCU_row_ctr == cinfo->total_iMCU_rows) + + set_bottom_pointers(cinfo); + + main->context_state = CTX_PROCESS_IMCU; + + /*FALLTHROUGH*/ + + case CTX_PROCESS_IMCU: + + /* Call postprocessor using previously set pointers */ + + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + + &main->rowgroup_ctr, main->rowgroups_avail, + + output_buf, out_row_ctr, out_rows_avail); + + if (main->rowgroup_ctr < main->rowgroups_avail) + + return; /* Need to suspend */ + + /* After the first iMCU, change wraparound pointers to normal state */ + + if (main->iMCU_row_ctr == 1) + + set_wraparound_pointers(cinfo); + + /* Prepare to load new iMCU row using other xbuffer list */ + + main->whichptr ^= 1; /* 0=>1 or 1=>0 */ + + main->buffer_full = FALSE; + + /* Still need to process last row group of this iMCU row, */ + + /* which is saved at index M+1 of the other xbuffer */ + + main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1); + + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2); + + main->context_state = CTX_POSTPONED_ROW; + + } + +} + + + + + +/* + + * Process some data. + + * Final pass of two-pass quantization: just call the postprocessor. + + * Source data will be the postprocessor controller's internal buffer. + + */ + + + +#ifdef QUANT_2PASS_SUPPORTED + + + +METHODDEF void + +process_data_crank_post (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + + (JDIMENSION *) NULL, (JDIMENSION) 0, + + output_buf, out_row_ctr, out_rows_avail); + +} + + + +#endif /* QUANT_2PASS_SUPPORTED */ + + + + + +/* + + * Initialize main buffer controller. + + */ + + + +GLOBAL void + +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) + +{ + + my_main_ptr main; + + int ci, rgroup, ngroups; + + jpeg_component_info *compptr; + + + + main = (my_main_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_main_controller)); + + cinfo->main = (struct jpeg_d_main_controller *) main; + + main->pub.start_pass = start_pass_main; + + + + if (need_full_buffer) /* shouldn't happen */ + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + + + /* Allocate the workspace. + + * ngroups is the number of row groups we need. + + */ + + if (cinfo->upsample->need_context_rows) { + + if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */ + + ERREXIT(cinfo, JERR_NOTIMPL); + + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + + ngroups = cinfo->min_DCT_scaled_size + 2; + + } else { + + ngroups = cinfo->min_DCT_scaled_size; + + } + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, + + compptr->width_in_blocks * compptr->DCT_scaled_size, + + (JDIMENSION) (rgroup * ngroups)); + + } + +} + diff --git a/libs/jpeg6/jdmarker.cpp b/libs/jpeg6/jdmarker.cpp new file mode 100644 index 00000000..15760981 --- /dev/null +++ b/libs/jpeg6/jdmarker.cpp @@ -0,0 +1,1052 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "radiant_jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#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++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters can + * fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments, + * but we use skip_input_data to get past those, and thereby put the problem + * on the source manager's shoulders. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL boolean +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->density_unit = 0; /* set default JFIF APP0 values */ + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL boolean +get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +METHODDEF boolean +get_app0 (j_decompress_ptr cinfo) +/* Process an APP0 marker */ +{ +#define JFIF_LEN 14 + INT32 length; + UINT8 b[JFIF_LEN]; + int buffp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* See if a JFIF APP0 marker is present */ + + if (length >= JFIF_LEN) { + for (buffp = 0; buffp < JFIF_LEN; buffp++) + INPUT_BYTE(cinfo, b[buffp], return FALSE); + length -= JFIF_LEN; + + if (b[0]==0x4A && b[1]==0x46 && b[2]==0x49 && b[3]==0x46 && b[4]==0) { + /* Found JFIF APP0 marker: check version */ + /* Major version must be 1, anything else signals an incompatible change. + * We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec. + * Minor version should be 0..2, but process anyway if newer. + */ + if (b[5] != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, b[5], b[6]); + else if (b[6] > 2) + TRACEMS2(cinfo, 1, JTRC_JFIF_MINOR, b[5], b[6]); + /* Save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->density_unit = b[7]; + cinfo->X_density = (b[8] << 8) + b[9]; + cinfo->Y_density = (b[10] << 8) + b[11]; + TRACEMS3(cinfo, 1, JTRC_JFIF, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + if (b[12] | b[13]) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, b[12], b[13]); + if (length != ((INT32) b[12] * (INT32) b[13] * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) length); + } else { + /* Start of APP0 does not match "JFIF" */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) length + JFIF_LEN); + } + } else { + /* Too short to be JFIF marker */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) length); + } + + INPUT_SYNC(cinfo); + if (length > 0) /* skip any remaining data -- could be lots */ + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +METHODDEF boolean +get_app14 (j_decompress_ptr cinfo) +/* Process an APP14 marker */ +{ +#define ADOBE_LEN 12 + INT32 length; + UINT8 b[ADOBE_LEN]; + int buffp; + unsigned int version, flags0, flags1, transform; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* See if an Adobe APP14 marker is present */ + + if (length >= ADOBE_LEN) { + for (buffp = 0; buffp < ADOBE_LEN; buffp++) + INPUT_BYTE(cinfo, b[buffp], return FALSE); + length -= ADOBE_LEN; + + if (b[0]==0x41 && b[1]==0x64 && b[2]==0x6F && b[3]==0x62 && b[4]==0x65) { + /* Found Adobe APP14 marker */ + version = (b[5] << 8) + b[6]; + flags0 = (b[7] << 8) + b[8]; + flags1 = (b[9] << 8) + b[10]; + transform = b[11]; + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe" */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) length + ADOBE_LEN); + } + } else { + /* Too short to be Adobe marker */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) length); + } + + INPUT_SYNC(cinfo); + if (length > 0) /* skip any remaining data -- could be lots */ + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +LOCAL boolean +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_DHT_COUNTS); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + quant_ptr->quantval[i] = (UINT16) tmp; + } + + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i ], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +METHODDEF boolean +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + (*cinfo->src->skip_input_data) (cinfo, (long) length - 2L); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL boolean +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF int +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*cinfo->marker->process_APPn[cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*cinfo->marker->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF boolean +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 2, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL boolean +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF void +reset_marker_reader (j_decompress_ptr cinfo) +{ + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + cinfo->marker->saw_SOI = FALSE; /* set internal state too */ + cinfo->marker->saw_SOF = FALSE; + cinfo->marker->discarded_bytes = 0; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL void +jinit_marker_reader (j_decompress_ptr cinfo) +{ + int i; + + /* Create subobject in permanent pool */ + cinfo->marker = (struct jpeg_marker_reader *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(struct jpeg_marker_reader)); + /* Initialize method pointers */ + cinfo->marker->reset_marker_reader = reset_marker_reader; + cinfo->marker->read_markers = read_markers; + cinfo->marker->read_restart_marker = read_restart_marker; + cinfo->marker->process_COM = skip_variable; + for (i = 0; i < 16; i++) + cinfo->marker->process_APPn[i] = skip_variable; + cinfo->marker->process_APPn[0] = get_app0; + cinfo->marker->process_APPn[14] = get_app14; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} diff --git a/libs/jpeg6/jdmaster.cpp b/libs/jpeg6/jdmaster.cpp new file mode 100644 index 00000000..9d88bb2f --- /dev/null +++ b/libs/jpeg6/jdmaster.cpp @@ -0,0 +1,558 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "radiant_jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL boolean +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL void +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ +#if 0 // JDC: commented out to remove warning + int ci; + jpeg_component_info *compptr; +#endif + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + +#ifdef IDCT_SCALING_SUPPORTED + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_DCT_scaled_size = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_DCT_scaled_size = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_DCT_scaled_size = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_DCT_scaled_size = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_DCT_scaled_size; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) { + ssize = ssize * 2; + } + compptr->DCT_scaled_size = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL void +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL void +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NO_PROGRESSIVE); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapi.c will crank the pass to completion.) + */ + +METHODDEF void +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF void +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL void +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL void +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} + diff --git a/libs/jpeg6/jdpostct.cpp b/libs/jpeg6/jdpostct.cpp new file mode 100644 index 00000000..3aba0a38 --- /dev/null +++ b/libs/jpeg6/jdpostct.cpp @@ -0,0 +1,580 @@ +/* + + * jdpostct.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the decompression postprocessing controller. + + * This controller manages the upsampling, color conversion, and color + + * quantization/reduction steps; specifically, it controls the buffering + + * between upsample/color conversion and color quantization/reduction. + + * + + * If no color quantization/reduction is required, then this module has no + + * work to do, and it just hands off to the upsample/color conversion code. + + * An integrated upsample/convert/quantize process would replace this module + + * entirely. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Private buffer controller object */ + + + +typedef struct { + + struct jpeg_d_post_controller pub; /* public fields */ + + + + /* Color quantization source buffer: this holds output data from + + * the upsample/color conversion step to be passed to the quantizer. + + * For two-pass color quantization, we need a full-image buffer; + + * for one-pass operation, a strip buffer is sufficient. + + */ + + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + + JDIMENSION strip_height; /* buffer size in rows */ + + /* for two-pass mode only: */ + + JDIMENSION starting_row; /* row # of first row in current strip */ + + JDIMENSION next_row; /* index of next row to fill/empty in strip */ + +} my_post_controller; + + + +typedef my_post_controller * my_post_ptr; + + + + + +/* Forward declarations */ + +METHODDEF void post_process_1pass + + JPP((j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void post_process_prepass + + JPP((j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +METHODDEF void post_process_2pass + + JPP((j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +#endif + + + + + +/* + + * Initialize for a processing pass. + + */ + + + +METHODDEF void + +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + + + switch (pass_mode) { + + case JBUF_PASS_THRU: + + if (cinfo->quantize_colors) { + + /* Single-pass processing with color quantization. */ + + post->pub.post_process_data = post_process_1pass; + + /* We could be doing buffered-image output before starting a 2-pass + + * color quantization; in that case, jinit_d_post_controller did not + + * allocate a strip buffer. Use the virtual-array buffer as workspace. + + */ + + if (post->buffer == NULL) { + + post->buffer = (*cinfo->mem->access_virt_sarray) + + ((j_common_ptr) cinfo, post->whole_image, + + (JDIMENSION) 0, post->strip_height, TRUE); + + } + + } else { + + /* For single-pass processing without color quantization, + + * I have no work to do; just call the upsampler directly. + + */ + + post->pub.post_process_data = cinfo->upsample->upsample; + + } + + break; + +#ifdef QUANT_2PASS_SUPPORTED + + case JBUF_SAVE_AND_PASS: + + /* First pass of 2-pass quantization */ + + if (post->whole_image == NULL) + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + post->pub.post_process_data = post_process_prepass; + + break; + + case JBUF_CRANK_DEST: + + /* Second pass of 2-pass quantization */ + + if (post->whole_image == NULL) + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + post->pub.post_process_data = post_process_2pass; + + break; + +#endif /* QUANT_2PASS_SUPPORTED */ + + default: + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + break; + + } + + post->starting_row = post->next_row = 0; + +} + + + + + +/* + + * Process some data in the one-pass (strip buffer) case. + + * This is used for color precision reduction as well as one-pass quantization. + + */ + + + +METHODDEF void + +post_process_1pass (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + JDIMENSION num_rows, max_rows; + + + + /* Fill the buffer, but not more than what we can dump out in one go. */ + + /* Note we rely on the upsampler to detect bottom of image. */ + + max_rows = out_rows_avail - *out_row_ctr; + + if (max_rows > post->strip_height) + + max_rows = post->strip_height; + + num_rows = 0; + + (*cinfo->upsample->upsample) (cinfo, + + input_buf, in_row_group_ctr, in_row_groups_avail, + + post->buffer, &num_rows, max_rows); + + /* Quantize and emit data. */ + + (*cinfo->cquantize->color_quantize) (cinfo, + + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + + *out_row_ctr += num_rows; + +} + + + + + +#ifdef QUANT_2PASS_SUPPORTED + + + +/* + + * Process some data in the first pass of 2-pass quantization. + + */ + + + +METHODDEF void + +post_process_prepass (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + JDIMENSION old_next_row, num_rows; + + + + /* Reposition virtual buffer if at start of strip. */ + + if (post->next_row == 0) { + + post->buffer = (*cinfo->mem->access_virt_sarray) + + ((j_common_ptr) cinfo, post->whole_image, + + post->starting_row, post->strip_height, TRUE); + + } + + + + /* Upsample some data (up to a strip height's worth). */ + + old_next_row = post->next_row; + + (*cinfo->upsample->upsample) (cinfo, + + input_buf, in_row_group_ctr, in_row_groups_avail, + + post->buffer, &post->next_row, post->strip_height); + + + + /* Allow quantizer to scan new data. No data is emitted, */ + + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + + if (post->next_row > old_next_row) { + + num_rows = post->next_row - old_next_row; + + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + + (JSAMPARRAY) NULL, (int) num_rows); + + *out_row_ctr += num_rows; + + } + + + + /* Advance if we filled the strip. */ + + if (post->next_row >= post->strip_height) { + + post->starting_row += post->strip_height; + + post->next_row = 0; + + } + +} + + + + + +/* + + * Process some data in the second pass of 2-pass quantization. + + */ + + + +METHODDEF void + +post_process_2pass (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + JDIMENSION num_rows, max_rows; + + + + /* Reposition virtual buffer if at start of strip. */ + + if (post->next_row == 0) { + + post->buffer = (*cinfo->mem->access_virt_sarray) + + ((j_common_ptr) cinfo, post->whole_image, + + post->starting_row, post->strip_height, FALSE); + + } + + + + /* Determine number of rows to emit. */ + + num_rows = post->strip_height - post->next_row; /* available in strip */ + + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + + if (num_rows > max_rows) + + num_rows = max_rows; + + /* We have to check bottom of image here, can't depend on upsampler. */ + + max_rows = cinfo->output_height - post->starting_row; + + if (num_rows > max_rows) + + num_rows = max_rows; + + + + /* Quantize and emit data. */ + + (*cinfo->cquantize->color_quantize) (cinfo, + + post->buffer + post->next_row, output_buf + *out_row_ctr, + + (int) num_rows); + + *out_row_ctr += num_rows; + + + + /* Advance if we filled the strip. */ + + post->next_row += num_rows; + + if (post->next_row >= post->strip_height) { + + post->starting_row += post->strip_height; + + post->next_row = 0; + + } + +} + + + +#endif /* QUANT_2PASS_SUPPORTED */ + + + + + +/* + + * Initialize postprocessing controller. + + */ + + + +GLOBAL void + +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) + +{ + + my_post_ptr post; + + + + post = (my_post_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_post_controller)); + + cinfo->post = (struct jpeg_d_post_controller *) post; + + post->pub.start_pass = start_pass_dpost; + + post->whole_image = NULL; /* flag for no virtual arrays */ + + post->buffer = NULL; /* flag for no strip buffer */ + + + + /* Create the quantization buffer, if needed */ + + if (cinfo->quantize_colors) { + + /* The buffer strip height is max_v_samp_factor, which is typically + + * an efficient number of rows for upsampling to return. + + * (In the presence of output rescaling, we might want to be smarter?) + + */ + + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + + if (need_full_buffer) { + + /* Two-pass color quantization: need full-image storage. */ + + /* We round up the number of rows to a multiple of the strip height. */ + +#ifdef QUANT_2PASS_SUPPORTED + + post->whole_image = (*cinfo->mem->request_virt_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + + cinfo->output_width * cinfo->out_color_components, + + (JDIMENSION) jround_up((long) cinfo->output_height, + + (long) post->strip_height), + + post->strip_height); + +#else + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + +#endif /* QUANT_2PASS_SUPPORTED */ + + } else { + + /* One-pass color quantization: just make a strip buffer. */ + + post->buffer = (*cinfo->mem->alloc_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, + + cinfo->output_width * cinfo->out_color_components, + + post->strip_height); + + } + + } + +} + diff --git a/libs/jpeg6/jdsample.cpp b/libs/jpeg6/jdsample.cpp new file mode 100644 index 00000000..a15e252c --- /dev/null +++ b/libs/jpeg6/jdsample.cpp @@ -0,0 +1,956 @@ +/* + + * jdsample.c + + * + + * Copyright (C) 1991-1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains upsampling routines. + + * + + * Upsampling input data is counted in "row groups". A row group + + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + + * sample rows of each component. Upsampling will normally produce + + * max_v_samp_factor pixel rows from each row group (but this could vary + + * if the upsampler is applying a scale factor of its own). + + * + + * An excellent reference for image resampling is + + * Digital Image Warping, George Wolberg, 1990. + + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Pointer to routine to upsample a single component */ + +typedef JMETHOD(void, upsample1_ptr, + + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + + + +/* Private subobject */ + + + +typedef struct { + + struct jpeg_upsampler pub; /* public fields */ + + + + /* Color conversion buffer. When using separate upsampling and color + + * conversion steps, this buffer holds one upsampled row group until it + + * has been color converted and output. + + * Note: we do not allocate any storage for component(s) which are full-size, + + * ie do not need rescaling. The corresponding entry of color_buf[] is + + * simply set to point to the input data array, thereby avoiding copying. + + */ + + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + + + /* Per-component upsampling method pointers */ + + upsample1_ptr methods[MAX_COMPONENTS]; + + + + int next_row_out; /* counts rows emitted from color_buf */ + + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + + + /* Height of an input row group for each component. */ + + int rowgroup_height[MAX_COMPONENTS]; + + + + /* These arrays save pixel expansion factors so that int_expand need not + + * recompute them each time. They are unused for other upsampling methods. + + */ + + UINT8 h_expand[MAX_COMPONENTS]; + + UINT8 v_expand[MAX_COMPONENTS]; + +} my_upsampler; + + + +typedef my_upsampler * my_upsample_ptr; + + + + + +/* + + * Initialize for an upsampling pass. + + */ + + + +METHODDEF void + +start_pass_upsample (j_decompress_ptr cinfo) + +{ + + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + + + /* Mark the conversion buffer empty */ + + upsample->next_row_out = cinfo->max_v_samp_factor; + + /* Initialize total-height counter for detecting bottom of image */ + + upsample->rows_to_go = cinfo->output_height; + +} + + + + + +/* + + * Control routine to do upsampling (and color conversion). + + * + + * In this version we upsample each component independently. + + * We upsample one row group into the conversion buffer, then apply + + * color conversion a row at a time. + + */ + + + +METHODDEF void + +sep_upsample (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + int ci; + + jpeg_component_info * compptr; + + JDIMENSION num_rows; + + + + /* Fill the conversion buffer, if it's empty */ + + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Invoke per-component upsample method. Notice we pass a POINTER + + * to color_buf[ci], so that fullsize_upsample can change it. + + */ + + (*upsample->methods[ci]) (cinfo, compptr, + + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + + upsample->color_buf + ci); + + } + + upsample->next_row_out = 0; + + } + + + + /* Color-convert and emit rows */ + + + + /* How many we have in the buffer: */ + + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + + /* Not more than the distance to the end of the image. Need this test + + * in case the image height is not a multiple of max_v_samp_factor: + + */ + + if (num_rows > upsample->rows_to_go) + + num_rows = upsample->rows_to_go; + + /* And not more than what the client can accept: */ + + out_rows_avail -= *out_row_ctr; + + if (num_rows > out_rows_avail) + + num_rows = out_rows_avail; + + + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + + (JDIMENSION) upsample->next_row_out, + + output_buf + *out_row_ctr, + + (int) num_rows); + + + + /* Adjust counts */ + + *out_row_ctr += num_rows; + + upsample->rows_to_go -= num_rows; + + upsample->next_row_out += num_rows; + + /* When the buffer is emptied, declare this input row group consumed */ + + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + + (*in_row_group_ctr)++; + +} + + + + + +/* + + * These are the routines invoked by sep_upsample to upsample pixel values + + * of a single component. One row group is processed per call. + + */ + + + + + +/* + + * For full-size components, we just make color_buf[ci] point at the + + * input buffer, and thus avoid copying any data. Note that this is + + * safe only because sep_upsample doesn't declare the input row group + + * "consumed" until we are done color converting and emitting it. + + */ + + + +METHODDEF void + +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + *output_data_ptr = input_data; + +} + + + + + +/* + + * This is a no-op version used for "uninteresting" components. + + * These components will not be referenced by color conversion. + + */ + + + +METHODDEF void + +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + *output_data_ptr = NULL; /* safety check */ + +} + + + + + +/* + + * This version handles any integral sampling ratios. + + * This is not used for typical JPEG files, so it need not be fast. + + * Nor, for that matter, is it particularly accurate: the algorithm is + + * simple replication of the input pixel onto the corresponding output + + * pixels. The hi-falutin sampling literature refers to this as a + + * "box filter". A box filter tends to introduce visible artifacts, + + * so if you are actually going to use 3:1 or 4:1 sampling ratios + + * you would be well advised to improve this code. + + */ + + + +METHODDEF void + +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register JSAMPLE invalue; + + register int h; + + JSAMPROW outend; + + int h_expand, v_expand; + + int inrow, outrow; + + + + h_expand = upsample->h_expand[compptr->component_index]; + + v_expand = upsample->v_expand[compptr->component_index]; + + + + inrow = outrow = 0; + + while (outrow < cinfo->max_v_samp_factor) { + + /* Generate one output row with proper horizontal expansion */ + + inptr = input_data[inrow]; + + outptr = output_data[outrow]; + + outend = outptr + cinfo->output_width; + + while (outptr < outend) { + + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + + for (h = h_expand; h > 0; h--) { + + *outptr++ = invalue; + + } + + } + + /* Generate any additional output rows by duplicating the first one */ + + if (v_expand > 1) { + + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + + v_expand-1, cinfo->output_width); + + } + + inrow++; + + outrow += v_expand; + + } + +} + + + + + +/* + + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + + * It's still a box filter. + + */ + + + +METHODDEF void + +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register JSAMPLE invalue; + + JSAMPROW outend; + + int inrow; + + + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + + inptr = input_data[inrow]; + + outptr = output_data[inrow]; + + outend = outptr + cinfo->output_width; + + while (outptr < outend) { + + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + + *outptr++ = invalue; + + *outptr++ = invalue; + + } + + } + +} + + + + + +/* + + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + + * It's still a box filter. + + */ + + + +METHODDEF void + +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register JSAMPLE invalue; + + JSAMPROW outend; + + int inrow, outrow; + + + + inrow = outrow = 0; + + while (outrow < cinfo->max_v_samp_factor) { + + inptr = input_data[inrow]; + + outptr = output_data[outrow]; + + outend = outptr + cinfo->output_width; + + while (outptr < outend) { + + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + + *outptr++ = invalue; + + *outptr++ = invalue; + + } + + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + + 1, cinfo->output_width); + + inrow++; + + outrow += 2; + + } + +} + + + + + +/* + + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + + * + + * The upsampling algorithm is linear interpolation between pixel centers, + + * also known as a "triangle filter". This is a good compromise between + + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + + * of the way between input pixel centers. + + * + + * A note about the "bias" calculations: when rounding fractional values to + + * integer, we do not want to always round 0.5 up to the next integer. + + * If we did that, we'd introduce a noticeable bias towards larger values. + + * Instead, this code is arranged so that 0.5 will be rounded up or down at + + * alternate pixel locations (a simple ordered dither pattern). + + */ + + + +METHODDEF void + +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register int invalue; + + register JDIMENSION colctr; + + int inrow; + + + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + + inptr = input_data[inrow]; + + outptr = output_data[inrow]; + + /* Special case for first column */ + + invalue = GETJSAMPLE(*inptr++); + + *outptr++ = (JSAMPLE) invalue; + + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + + invalue = GETJSAMPLE(*inptr++) * 3; + + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + + } + + + + /* Special case for last column */ + + invalue = GETJSAMPLE(*inptr); + + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + + *outptr++ = (JSAMPLE) invalue; + + } + +} + + + + + +/* + + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + + * Again a triangle filter; see comments for h2v1 case, above. + + * + + * It is OK for us to reference the adjacent input rows because we demanded + + * context from the main buffer controller (see initialization code). + + */ + + + +METHODDEF void + +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr0, inptr1, outptr; + +#if BITS_IN_JSAMPLE == 8 + + register int thiscolsum, lastcolsum, nextcolsum; + +#else + + register INT32 thiscolsum, lastcolsum, nextcolsum; + +#endif + + register JDIMENSION colctr; + + int inrow, outrow, v; + + + + inrow = outrow = 0; + + while (outrow < cinfo->max_v_samp_factor) { + + for (v = 0; v < 2; v++) { + + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + + inptr0 = input_data[inrow]; + + if (v == 0) /* next nearest is row above */ + + inptr1 = input_data[inrow-1]; + + else /* next nearest is row below */ + + inptr1 = input_data[inrow+1]; + + outptr = output_data[outrow++]; + + + + /* Special case for first column */ + + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + } + + + + /* Special case for last column */ + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + + } + + inrow++; + + } + +} + + + + + +/* + + * Module initialization routine for upsampling. + + */ + + + +GLOBAL void + +jinit_upsampler (j_decompress_ptr cinfo) + +{ + + my_upsample_ptr upsample; + + int ci; + + jpeg_component_info * compptr; + + boolean need_buffer, do_fancy; + + int h_in_group, v_in_group, h_out_group, v_out_group; + + + + upsample = (my_upsample_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_upsampler)); + + cinfo->upsample = (struct jpeg_upsampler *) upsample; + + upsample->pub.start_pass = start_pass_upsample; + + upsample->pub.upsample = sep_upsample; + + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + + + /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1, + + * so don't ask for it. + + */ + + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1; + + + + /* Verify we can handle the sampling factors, select per-component methods, + + * and create storage as needed. + + */ + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Compute size of an "input group" after IDCT scaling. This many samples + + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + + */ + + h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; + + v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; + + h_out_group = cinfo->max_h_samp_factor; + + v_out_group = cinfo->max_v_samp_factor; + + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + + need_buffer = TRUE; + + if (! compptr->component_needed) { + + /* Don't bother to upsample an uninteresting component. */ + + upsample->methods[ci] = noop_upsample; + + need_buffer = FALSE; + + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + + /* Fullsize components can be processed without any work. */ + + upsample->methods[ci] = fullsize_upsample; + + need_buffer = FALSE; + + } else if (h_in_group * 2 == h_out_group && + + v_in_group == v_out_group) { + + /* Special cases for 2h1v upsampling */ + + if (do_fancy && compptr->downsampled_width > 2) + + upsample->methods[ci] = h2v1_fancy_upsample; + + else + + upsample->methods[ci] = h2v1_upsample; + + } else if (h_in_group * 2 == h_out_group && + + v_in_group * 2 == v_out_group) { + + /* Special cases for 2h2v upsampling */ + + if (do_fancy && compptr->downsampled_width > 2) { + + upsample->methods[ci] = h2v2_fancy_upsample; + + upsample->pub.need_context_rows = TRUE; + + } else + + upsample->methods[ci] = h2v2_upsample; + + } else if ((h_out_group % h_in_group) == 0 && + + (v_out_group % v_in_group) == 0) { + + /* Generic integral-factors upsampling method */ + + upsample->methods[ci] = int_upsample; + + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + + } else + + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + + if (need_buffer) { + + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, + + (JDIMENSION) jround_up((long) cinfo->output_width, + + (long) cinfo->max_h_samp_factor), + + (JDIMENSION) cinfo->max_v_samp_factor); + + } + + } + +} + diff --git a/libs/jpeg6/jdtrans.cpp b/libs/jpeg6/jdtrans.cpp new file mode 100644 index 00000000..70e67379 --- /dev/null +++ b/libs/jpeg6/jdtrans.cpp @@ -0,0 +1,244 @@ +/* + + * jdtrans.c + + * + + * Copyright (C) 1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains library routines for transcoding decompression, + + * that is, reading raw DCT coefficient arrays from an input JPEG file. + + * The routines in jdapimin.c will also be needed by a transcoder. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Forward declarations */ + +LOCAL void transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + + + + +/* + + * Read the coefficient arrays from a JPEG file. + + * jpeg_read_header must be completed before calling this. + + * + + * The entire image is read into a set of virtual coefficient-block arrays, + + * one per component. The return value is a pointer to the array of + + * virtual-array descriptors. These can be manipulated directly via the + + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + + * To release the memory occupied by the virtual arrays, call + + * jpeg_finish_decompress() when done with the data. + + * + + * Returns NULL if suspended. This case need be checked only if + + * a suspending data source is used. + + */ + + + +GLOBAL jvirt_barray_ptr * + +jpeg_read_coefficients (j_decompress_ptr cinfo) + +{ + + if (cinfo->global_state == DSTATE_READY) { + + /* First call: initialize active modules */ + + transdecode_master_selection(cinfo); + + cinfo->global_state = DSTATE_RDCOEFS; + + } else if (cinfo->global_state != DSTATE_RDCOEFS) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Absorb whole file into the coef buffer */ + + for (;;) { + + int retcode; + + /* Call progress monitor hook if present */ + + if (cinfo->progress != NULL) + + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + + /* Absorb some more input */ + + retcode = (*cinfo->inputctl->consume_input) (cinfo); + + if (retcode == JPEG_SUSPENDED) + + return NULL; + + if (retcode == JPEG_REACHED_EOI) + + break; + + /* Advance progress counter if appropriate */ + + if (cinfo->progress != NULL && + + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + + /* startup underestimated number of scans; ratchet up one scan */ + + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + + } + + } + + } + + /* Set state so that jpeg_finish_decompress does the right thing */ + + cinfo->global_state = DSTATE_STOPPING; + + return cinfo->coef->coef_arrays; + +} + + + + + +/* + + * Master selection of decompression modules for transcoding. + + * This substitutes for jdmaster.c's initialization of the full decompressor. + + */ + + + +LOCAL void + +transdecode_master_selection (j_decompress_ptr cinfo) + +{ + + /* Entropy decoding: either Huffman or arithmetic coding. */ + + if (cinfo->arith_code) { + + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + + } else { + + if (cinfo->progressive_mode) { + +#ifdef D_PROGRESSIVE_SUPPORTED + + jinit_phuff_decoder(cinfo); + +#else + + ERREXIT(cinfo, JERR_NOT_COMPILED); + +#endif + + } else + + jinit_huff_decoder(cinfo); + + } + + + + /* Always get a full-image coefficient buffer. */ + + jinit_d_coef_controller(cinfo, TRUE); + + + + /* We can now tell the memory manager to allocate virtual arrays. */ + + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + + + /* Initialize input side of decompressor to consume first scan. */ + + (*cinfo->inputctl->start_input_pass) (cinfo); + + + + /* Initialize progress monitoring. */ + + if (cinfo->progress != NULL) { + + int nscans; + + /* Estimate number of scans to set pass_limit. */ + + if (cinfo->progressive_mode) { + + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + + nscans = 2 + 3 * cinfo->num_components; + + } else if (cinfo->inputctl->has_multiple_scans) { + + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + + nscans = cinfo->num_components; + + } else { + + nscans = 1; + + } + + cinfo->progress->pass_counter = 0L; + + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + + cinfo->progress->completed_passes = 0; + + cinfo->progress->total_passes = 1; + + } + +} + diff --git a/libs/jpeg6/jerror.cpp b/libs/jpeg6/jerror.cpp new file mode 100644 index 00000000..e4f65f78 --- /dev/null +++ b/libs/jpeg6/jerror.cpp @@ -0,0 +1,233 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "radiant_jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + +// Rad additions, longjmp out of the LoadJPGBuff +GLOBAL jmp_buf rad_loadfailed; +GLOBAL char rad_errormsg[JMSG_LENGTH_MAX]; + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF void +error_exit (j_common_ptr cinfo) +{ +// char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo,rad_errormsg); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + longjmp( rad_loadfailed, -1 ); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + */ + +METHODDEF void +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + /* Send it to stderr, adding a newline */ + printf("%s\n", buffer); +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF void +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF void +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF void +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL struct jpeg_error_mgr * +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/libs/jpeg6/jerror.h b/libs/jpeg6/jerror.h new file mode 100644 index 00000000..d23dfb0c --- /dev/null +++ b/libs/jpeg6/jerror.h @@ -0,0 +1,278 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_COUNTS, "Bogus DHT counts") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_PROGRESSIVE, "Progressive JPEGs not supported, use regular JPEG instead") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_MINOR, "Unknown JFIF minor revision number %d.%02d") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Skipping marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + +#ifndef JERROR_H +#define JERROR_H + +// Rad additions, using longjmp to recover from errors +#include +EXTERN jmp_buf rad_loadfailed; +EXTERN char rad_errormsg[JMSG_LENGTH_MAX]; + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/libs/jpeg6/jfdctflt.cpp b/libs/jpeg6/jfdctflt.cpp new file mode 100644 index 00000000..f41bff82 --- /dev/null +++ b/libs/jpeg6/jfdctflt.cpp @@ -0,0 +1,336 @@ +/* + + * jfdctflt.c + + * + + * Copyright (C) 1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains a floating-point implementation of the + + * forward DCT (Discrete Cosine Transform). + + * + + * This implementation should be more accurate than either of the integer + + * DCT implementations. However, it may not give the same results on all + + * machines because of differences in roundoff behavior. Speed will depend + + * on the hardware's floating point capacity. + + * + + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + + * on each column. Direct algorithms are also available, but they are + + * much more complex and seem not to be any faster when reduced to code. + + * + + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + + * JPEG textbook (see REFERENCES section in file README). The following code + + * is based directly on figure 4-8 in P&M. + + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + + * possible to arrange the computation so that many of the multiplies are + + * simple scalings of the final outputs. These multiplies can then be + + * folded into the multiplications or divisions by the JPEG quantization + + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + + * to be done in the DCT itself. + + * The primary disadvantage of this method is that with a fixed-point + + * implementation, accuracy is lost due to imprecise representation of the + + * scaled quantization values. However, that problem does not arise if + + * we use floating point arithmetic. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jdct.h" /* Private declarations for DCT subsystem */ + + + +#ifdef DCT_FLOAT_SUPPORTED + + + + + +/* + + * This module is specialized to the case DCTSIZE = 8. + + */ + + + +#if DCTSIZE != 8 + + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ + +#endif + + + + + +/* + + * Perform the forward DCT on one block of samples. + + */ + + + +GLOBAL void + +jpeg_fdct_float (FAST_FLOAT * data) + +{ + + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + + FAST_FLOAT *dataptr; + + int ctr; + + + + /* Pass 1: process rows. */ + + + + dataptr = data; + + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + + tmp0 = dataptr[0] + dataptr[7]; + + tmp7 = dataptr[0] - dataptr[7]; + + tmp1 = dataptr[1] + dataptr[6]; + + tmp6 = dataptr[1] - dataptr[6]; + + tmp2 = dataptr[2] + dataptr[5]; + + tmp5 = dataptr[2] - dataptr[5]; + + tmp3 = dataptr[3] + dataptr[4]; + + tmp4 = dataptr[3] - dataptr[4]; + + + + /* Even part */ + + + + tmp10 = tmp0 + tmp3; /* phase 2 */ + + tmp13 = tmp0 - tmp3; + + tmp11 = tmp1 + tmp2; + + tmp12 = tmp1 - tmp2; + + + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + + dataptr[4] = tmp10 - tmp11; + + + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + + dataptr[2] = tmp13 + z1; /* phase 5 */ + + dataptr[6] = tmp13 - z1; + + + + /* Odd part */ + + + + tmp10 = tmp4 + tmp5; /* phase 2 */ + + tmp11 = tmp5 + tmp6; + + tmp12 = tmp6 + tmp7; + + + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + + + z11 = tmp7 + z3; /* phase 5 */ + + z13 = tmp7 - z3; + + + + dataptr[5] = z13 + z2; /* phase 6 */ + + dataptr[3] = z13 - z2; + + dataptr[1] = z11 + z4; + + dataptr[7] = z11 - z4; + + + + dataptr += DCTSIZE; /* advance pointer to next row */ + + } + + + + /* Pass 2: process columns. */ + + + + dataptr = data; + + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + + + /* Even part */ + + + + tmp10 = tmp0 + tmp3; /* phase 2 */ + + tmp13 = tmp0 - tmp3; + + tmp11 = tmp1 + tmp2; + + tmp12 = tmp1 - tmp2; + + + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + + dataptr[DCTSIZE*6] = tmp13 - z1; + + + + /* Odd part */ + + + + tmp10 = tmp4 + tmp5; /* phase 2 */ + + tmp11 = tmp5 + tmp6; + + tmp12 = tmp6 + tmp7; + + + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + + + z11 = tmp7 + z3; /* phase 5 */ + + z13 = tmp7 - z3; + + + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + + dataptr[DCTSIZE*3] = z13 - z2; + + dataptr[DCTSIZE*1] = z11 + z4; + + dataptr[DCTSIZE*7] = z11 - z4; + + + + dataptr++; /* advance pointer to next column */ + + } + +} + + + +#endif /* DCT_FLOAT_SUPPORTED */ + diff --git a/libs/jpeg6/jidctflt.cpp b/libs/jpeg6/jidctflt.cpp new file mode 100644 index 00000000..9e966daf --- /dev/null +++ b/libs/jpeg6/jidctflt.cpp @@ -0,0 +1,482 @@ +/* + + * jidctflt.c + + * + + * Copyright (C) 1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains a floating-point implementation of the + + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + + * must also perform dequantization of the input coefficients. + + * + + * This implementation should be more accurate than either of the integer + + * IDCT implementations. However, it may not give the same results on all + + * machines because of differences in roundoff behavior. Speed will depend + + * on the hardware's floating point capacity. + + * + + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + + * on each row (or vice versa, but it's more convenient to emit a row at + + * a time). Direct algorithms are also available, but they are much more + + * complex and seem not to be any faster when reduced to code. + + * + + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + + * JPEG textbook (see REFERENCES section in file README). The following code + + * is based directly on figure 4-8 in P&M. + + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + + * possible to arrange the computation so that many of the multiplies are + + * simple scalings of the final outputs. These multiplies can then be + + * folded into the multiplications or divisions by the JPEG quantization + + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + + * to be done in the DCT itself. + + * The primary disadvantage of this method is that with a fixed-point + + * implementation, accuracy is lost due to imprecise representation of the + + * scaled quantization values. However, that problem does not arise if + + * we use floating point arithmetic. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jdct.h" /* Private declarations for DCT subsystem */ + + + +#ifdef DCT_FLOAT_SUPPORTED + + + + + +/* + + * This module is specialized to the case DCTSIZE = 8. + + */ + + + +#if DCTSIZE != 8 + + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ + +#endif + + + + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + + * entry; produce a float result. + + */ + + + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + + + + +/* + + * Perform dequantization and inverse DCT on one block of coefficients. + + */ + + + +GLOBAL void + +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, + + JSAMPARRAY output_buf, JDIMENSION output_col) + +{ + + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + + FAST_FLOAT z5, z10, z11, z12, z13; + + JCOEFPTR inptr; + + FLOAT_MULT_TYPE * quantptr; + + FAST_FLOAT * wsptr; + + JSAMPROW outptr; + + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + + int ctr; + + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + + SHIFT_TEMPS + + + + /* Pass 1: process columns from input, store into work array. */ + + + + inptr = coef_block; + + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + + wsptr = workspace; + + for (ctr = DCTSIZE; ctr > 0; ctr--) { + + /* Due to quantization, we will usually find that many of the input + + * coefficients are zero, especially the AC terms. We can exploit this + + * by short-circuiting the IDCT calculation for any column in which all + + * the AC terms are zero. In that case each output is equal to the + + * DC coefficient (with scale factor as needed). + + * With typical images and quantization tables, half or more of the + + * column DCT calculations can be simplified this way. + + */ + + + + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] | + + inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | + + inptr[DCTSIZE*7]) == 0) { + + /* AC terms all zero */ + + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + + + wsptr[DCTSIZE*0] = dcval; + + wsptr[DCTSIZE*1] = dcval; + + wsptr[DCTSIZE*2] = dcval; + + wsptr[DCTSIZE*3] = dcval; + + wsptr[DCTSIZE*4] = dcval; + + wsptr[DCTSIZE*5] = dcval; + + wsptr[DCTSIZE*6] = dcval; + + wsptr[DCTSIZE*7] = dcval; + + + + inptr++; /* advance pointers to next column */ + + quantptr++; + + wsptr++; + + continue; + + } + + + + /* Even part */ + + + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + + + tmp10 = tmp0 + tmp2; /* phase 3 */ + + tmp11 = tmp0 - tmp2; + + + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + + + tmp0 = tmp10 + tmp13; /* phase 2 */ + + tmp3 = tmp10 - tmp13; + + tmp1 = tmp11 + tmp12; + + tmp2 = tmp11 - tmp12; + + + + /* Odd part */ + + + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + + + z13 = tmp6 + tmp5; /* phase 6 */ + + z10 = tmp6 - tmp5; + + z11 = tmp4 + tmp7; + + z12 = tmp4 - tmp7; + + + + tmp7 = z11 + z13; /* phase 5 */ + + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + + + tmp6 = tmp12 - tmp7; /* phase 2 */ + + tmp5 = tmp11 - tmp6; + + tmp4 = tmp10 + tmp5; + + + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + + wsptr[DCTSIZE*7] = tmp0 - tmp7; + + wsptr[DCTSIZE*1] = tmp1 + tmp6; + + wsptr[DCTSIZE*6] = tmp1 - tmp6; + + wsptr[DCTSIZE*2] = tmp2 + tmp5; + + wsptr[DCTSIZE*5] = tmp2 - tmp5; + + wsptr[DCTSIZE*4] = tmp3 + tmp4; + + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + + + inptr++; /* advance pointers to next column */ + + quantptr++; + + wsptr++; + + } + + + + /* Pass 2: process rows from work array, store into output array. */ + + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + + + wsptr = workspace; + + for (ctr = 0; ctr < DCTSIZE; ctr++) { + + outptr = output_buf[ctr] + output_col; + + /* Rows of zeroes can be exploited in the same way as we did with columns. + + * However, the column calculation has created many nonzero AC terms, so + + * the simplification applies less often (typically 5% to 10% of the time). + + * And testing floats for zero is relatively expensive, so we don't bother. + + */ + + + + /* Even part */ + + + + tmp10 = wsptr[0] + wsptr[4]; + + tmp11 = wsptr[0] - wsptr[4]; + + + + tmp13 = wsptr[2] + wsptr[6]; + + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + + + tmp0 = tmp10 + tmp13; + + tmp3 = tmp10 - tmp13; + + tmp1 = tmp11 + tmp12; + + tmp2 = tmp11 - tmp12; + + + + /* Odd part */ + + + + z13 = wsptr[5] + wsptr[3]; + + z10 = wsptr[5] - wsptr[3]; + + z11 = wsptr[1] + wsptr[7]; + + z12 = wsptr[1] - wsptr[7]; + + + + tmp7 = z11 + z13; + + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + + + tmp6 = tmp12 - tmp7; + + tmp5 = tmp11 - tmp6; + + tmp4 = tmp10 + tmp5; + + + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + + & RANGE_MASK]; + + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + + & RANGE_MASK]; + + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + + & RANGE_MASK]; + + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + + & RANGE_MASK]; + + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + + & RANGE_MASK]; + + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + + & RANGE_MASK]; + + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + + & RANGE_MASK]; + + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + + & RANGE_MASK]; + + + + wsptr += DCTSIZE; /* advance pointer to next row */ + + } + +} + + + +#endif /* DCT_FLOAT_SUPPORTED */ + diff --git a/libs/jpeg6/jinclude.h b/libs/jpeg6/jinclude.h new file mode 100644 index 00000000..5ff60fed --- /dev/null +++ b/libs/jpeg6/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/libs/jpeg6/jmemmgr.cpp b/libs/jpeg6/jmemmgr.cpp new file mode 100644 index 00000000..9204b324 --- /dev/null +++ b/libs/jpeg6/jmemmgr.cpp @@ -0,0 +1,2230 @@ +/* + + * jmemmgr.c + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the JPEG system-independent memory management + + * routines. This code is usable across a wide variety of machines; most + + * of the system dependencies have been isolated in a separate file. + + * The major functions provided here are: + + * * pool-based allocation and freeing of memory; + + * * policy decisions about how to divide available memory among the + + * virtual arrays; + + * * control logic for swapping virtual arrays between main memory and + + * backing storage. + + * The separate system-dependent file provides the actual backing-storage + + * access code, and it contains the policy decision about how much total + + * main memory to use. + + * This file is system-dependent in the sense that some of its functions + + * are unnecessary in some systems. For example, if there is enough virtual + + * memory so that backing storage will never be used, much of the virtual + + * array control logic could be removed. (Of course, if you have that much + + * memory then you shouldn't care about a little bit of unused code...) + + */ + + + +#define JPEG_INTERNALS + +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jmemsys.h" /* import the system-dependent declarations */ + + + +#ifndef NO_GETENV + +#ifndef HAVE_STDLIB_H /* should declare getenv() */ + +extern char * getenv JPP((const char * name)); + +#endif + +#endif + + + + + +/* + + * Some important notes: + + * The allocation routines provided here must never return NULL. + + * They should exit to error_exit if unsuccessful. + + * + + * It's not a good idea to try to merge the sarray and barray routines, + + * even though they are textually almost the same, because samples are + + * usually stored as bytes while coefficients are shorts or ints. Thus, + + * in machines where byte pointers have a different representation from + + * word pointers, the resulting machine code could not be the same. + + */ + + + + + +/* + + * Many machines require storage alignment: longs must start on 4-byte + + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + + * always returns pointers that are multiples of the worst-case alignment + + * requirement, and we had better do so too. + + * There isn't any really portable way to determine the worst-case alignment + + * requirement. This module assumes that the alignment requirement is + + * multiples of sizeof(ALIGN_TYPE). + + * By default, we define ALIGN_TYPE as double. This is necessary on some + + * workstations (where doubles really do need 8-byte alignment) and will work + + * fine on nearly everything. If your machine has lesser alignment needs, + + * you can save a few bytes by making ALIGN_TYPE smaller. + + * The only place I know of where this will NOT work is certain Macintosh + + * 680x0 compilers that define double as a 10-byte IEEE extended float. + + * Doing 10-byte alignment is counterproductive because longwords won't be + + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + + * such a compiler. + + */ + + + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ + +#define ALIGN_TYPE double + +#endif + + + + + +/* + + * We allocate objects from "pools", where each pool is gotten with a single + + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + + * overhead within a pool, except for alignment padding. Each pool has a + + * header with a link to the next pool of the same class. + + * Small and large pool headers are identical except that the latter's + + * link pointer must be FAR on 80x86 machines. + + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + + * of the alignment requirement of ALIGN_TYPE. + + */ + + + +typedef union small_pool_struct * small_pool_ptr; + + + +typedef union small_pool_struct { + + struct { + + small_pool_ptr next; /* next in list of pools */ + + size_t bytes_used; /* how many bytes already used within pool */ + + size_t bytes_left; /* bytes still available in this pool */ + + } hdr; + + ALIGN_TYPE dummy; /* included in union to ensure alignment */ + +} small_pool_hdr; + + + +typedef union large_pool_struct FAR * large_pool_ptr; + + + +typedef union large_pool_struct { + + struct { + + large_pool_ptr next; /* next in list of pools */ + + size_t bytes_used; /* how many bytes already used within pool */ + + size_t bytes_left; /* bytes still available in this pool */ + + } hdr; + + ALIGN_TYPE dummy; /* included in union to ensure alignment */ + +} large_pool_hdr; + + + + + +/* + + * Here is the full definition of a memory manager object. + + */ + + + +typedef struct { + + struct jpeg_memory_mgr pub; /* public fields */ + + + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + + + /* Since we only have one lifetime class of virtual arrays, only one + + * linked list is necessary (for each datatype). Note that the virtual + + * array control blocks being linked together are actually stored somewhere + + * in the small-pool list. + + */ + + jvirt_sarray_ptr virt_sarray_list; + + jvirt_barray_ptr virt_barray_list; + + + + /* This counts total space obtained from jpeg_get_small/large */ + + long total_space_allocated; + + + + /* alloc_sarray and alloc_barray set this value for use by virtual + + * array routines. + + */ + + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ + +} my_memory_mgr; + + + +typedef my_memory_mgr * my_mem_ptr; + + + + + +/* + + * The control blocks for virtual arrays. + + * Note that these blocks are allocated in the "small" pool area. + + * System-dependent info for the associated backing store (if any) is hidden + + * inside the backing_store_info struct. + + */ + + + +struct jvirt_sarray_control { + + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + + JDIMENSION rows_in_array; /* total virtual array height */ + + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + + JDIMENSION rows_in_mem; /* height of memory buffer */ + + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + + boolean pre_zero; /* pre-zero mode requested? */ + + boolean dirty; /* do current buffer contents need written? */ + + boolean b_s_open; /* is backing-store data valid? */ + + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + + backing_store_info b_s_info; /* System-dependent control info */ + +}; + + + +struct jvirt_barray_control { + + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + + JDIMENSION rows_in_array; /* total virtual array height */ + + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + + JDIMENSION rows_in_mem; /* height of memory buffer */ + + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + + boolean pre_zero; /* pre-zero mode requested? */ + + boolean dirty; /* do current buffer contents need written? */ + + boolean b_s_open; /* is backing-store data valid? */ + + jvirt_barray_ptr next; /* link to next virtual barray control block */ + + backing_store_info b_s_info; /* System-dependent control info */ + +}; + + + + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + + + +LOCAL void + +print_mem_stats (j_common_ptr cinfo, int pool_id) + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + small_pool_ptr shdr_ptr; + + large_pool_ptr lhdr_ptr; + + + + /* Since this is only a debugging stub, we can cheat a little by using + + * fprintf directly rather than going through the trace message code. + + * This is helpful because message parm array can't handle longs. + + */ + + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + + pool_id, mem->total_space_allocated); + + + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + + lhdr_ptr = lhdr_ptr->hdr.next) { + + fprintf(stderr, " Large chunk used %ld\n", + + (long) lhdr_ptr->hdr.bytes_used); + + } + + + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + + shdr_ptr = shdr_ptr->hdr.next) { + + fprintf(stderr, " Small chunk used %ld free %ld\n", + + (long) shdr_ptr->hdr.bytes_used, + + (long) shdr_ptr->hdr.bytes_left); + + } + +} + + + +#endif /* MEM_STATS */ + + + + + +LOCAL void + +out_of_memory (j_common_ptr cinfo, int which) + +/* Report an out-of-memory error and stop execution */ + +/* If we compiled MEM_STATS support, report alloc requests before dying */ + +{ + +#ifdef MEM_STATS + + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ + +#endif + + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); + +} + + + + + +/* + + * Allocation of "small" objects. + + * + + * For these, we use pooled storage. When a new pool must be created, + + * we try to get enough space for the current request plus a "slop" factor, + + * where the slop will be the amount of leftover space in the new pool. + + * The speed vs. space tradeoff is largely determined by the slop values. + + * A different slop value is provided for each pool class (lifetime), + + * and we also distinguish the first pool of a class from later ones. + + * NOTE: the values given work fairly well on both 16- and 32-bit-int + + * machines, but may be too small if longs are 64 bits or more. + + */ + + + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = + +{ + + 1600, /* first PERMANENT pool */ + + 16000 /* first IMAGE pool */ + +}; + + + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = + +{ + + 0, /* additional PERMANENT pools */ + + 5000 /* additional IMAGE pools */ + +}; + + + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + + + + +METHODDEF void * + +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) + +/* Allocate a "small" object */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + small_pool_ptr hdr_ptr, prev_hdr_ptr; + + char * data_ptr; + + size_t odd_bytes, min_request, slop; + + + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + + if (odd_bytes > 0) + + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + + + /* See if space is available in any existing pool */ + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + prev_hdr_ptr = NULL; + + hdr_ptr = mem->small_list[pool_id]; + + while (hdr_ptr != NULL) { + + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + + break; /* found pool with enough space */ + + prev_hdr_ptr = hdr_ptr; + + hdr_ptr = hdr_ptr->hdr.next; + + } + + + + /* Time to make a new pool? */ + + if (hdr_ptr == NULL) { + + /* min_request is what we need now, slop is what will be leftover */ + + min_request = sizeofobject + SIZEOF(small_pool_hdr); + + if (prev_hdr_ptr == NULL) /* first pool in class? */ + + slop = first_pool_slop[pool_id]; + + else + + slop = extra_pool_slop[pool_id]; + + /* Don't ask for more than MAX_ALLOC_CHUNK */ + + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + + /* Try to get space, if fail reduce slop and try again */ + + for (;;) { + + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + + if (hdr_ptr != NULL) + + break; + + slop /= 2; + + if (slop < MIN_SLOP) /* give up when it gets real small */ + + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + + } + + mem->total_space_allocated += min_request + slop; + + /* Success, initialize the new pool header and add to end of list */ + + hdr_ptr->hdr.next = NULL; + + hdr_ptr->hdr.bytes_used = 0; + + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + + if (prev_hdr_ptr == NULL) /* first pool in class? */ + + mem->small_list[pool_id] = hdr_ptr; + + else + + prev_hdr_ptr->hdr.next = hdr_ptr; + + } + + + + /* OK, allocate the object from the current pool */ + + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + + hdr_ptr->hdr.bytes_used += sizeofobject; + + hdr_ptr->hdr.bytes_left -= sizeofobject; + + + + return (void *) data_ptr; + +} + + + + + +/* + + * Allocation of "large" objects. + + * + + * The external semantics of these are the same as "small" objects, + + * except that FAR pointers are used on 80x86. However the pool + + * management heuristics are quite different. We assume that each + + * request is large enough that it may as well be passed directly to + + * jpeg_get_large; the pool management just links everything together + + * so that we can free it all on demand. + + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + + * structures. The routines that create these structures (see below) + + * deliberately bunch rows together to ensure a large request size. + + */ + + + +METHODDEF void FAR * + +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) + +/* Allocate a "large" object */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + large_pool_ptr hdr_ptr; + + size_t odd_bytes; + + + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + + if (odd_bytes > 0) + + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + + + /* Always make a new pool */ + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + + SIZEOF(large_pool_hdr)); + + if (hdr_ptr == NULL) + + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + + + /* Success, initialize the new pool header and add to list */ + + hdr_ptr->hdr.next = mem->large_list[pool_id]; + + /* We maintain space counts in each pool header for statistical purposes, + + * even though they are not needed for allocation. + + */ + + hdr_ptr->hdr.bytes_used = sizeofobject; + + hdr_ptr->hdr.bytes_left = 0; + + mem->large_list[pool_id] = hdr_ptr; + + + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ + +} + + + + + +/* + + * Creation of 2-D sample arrays. + + * The pointers are in near heap, the samples themselves in FAR heap. + + * + + * To minimize allocation overhead and to allow I/O of large contiguous + + * blocks, we allocate the sample rows in groups of as many rows as possible + + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + + * NB: the virtual array control routines, later in this file, know about + + * this chunking of rows. The rowsperchunk value is left in the mem manager + + * object so that it can be saved away if this sarray is the workspace for + + * a virtual array. + + */ + + + +METHODDEF JSAMPARRAY + +alloc_sarray (j_common_ptr cinfo, int pool_id, + + JDIMENSION samplesperrow, JDIMENSION numrows) + +/* Allocate a 2-D sample array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + JSAMPARRAY result; + + JSAMPROW workspace; + + JDIMENSION rowsperchunk, currow, i; + + long ltemp; + + + + /* Calculate max # of rows allowed in one allocation chunk */ + + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + + ((long) samplesperrow * SIZEOF(JSAMPLE)); + + if (ltemp <= 0) + + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + if (ltemp < (long) numrows) + + rowsperchunk = (JDIMENSION) ltemp; + + else + + rowsperchunk = numrows; + + mem->last_rowsperchunk = rowsperchunk; + + + + /* Get space for row pointers (small object) */ + + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + + (size_t) (numrows * SIZEOF(JSAMPROW))); + + + + /* Get the rows themselves (large objects) */ + + currow = 0; + + while (currow < numrows) { + + rowsperchunk = MIN(rowsperchunk, numrows - currow); + + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + + * SIZEOF(JSAMPLE))); + + for (i = rowsperchunk; i > 0; i--) { + + result[currow++] = workspace; + + workspace += samplesperrow; + + } + + } + + + + return result; + +} + + + + + +/* + + * Creation of 2-D coefficient-block arrays. + + * This is essentially the same as the code for sample arrays, above. + + */ + + + +METHODDEF JBLOCKARRAY + +alloc_barray (j_common_ptr cinfo, int pool_id, + + JDIMENSION blocksperrow, JDIMENSION numrows) + +/* Allocate a 2-D coefficient-block array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + JBLOCKARRAY result; + + JBLOCKROW workspace; + + JDIMENSION rowsperchunk, currow, i; + + long ltemp; + + + + /* Calculate max # of rows allowed in one allocation chunk */ + + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + + ((long) blocksperrow * SIZEOF(JBLOCK)); + + if (ltemp <= 0) + + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + if (ltemp < (long) numrows) + + rowsperchunk = (JDIMENSION) ltemp; + + else + + rowsperchunk = numrows; + + mem->last_rowsperchunk = rowsperchunk; + + + + /* Get space for row pointers (small object) */ + + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + + + /* Get the rows themselves (large objects) */ + + currow = 0; + + while (currow < numrows) { + + rowsperchunk = MIN(rowsperchunk, numrows - currow); + + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + + * SIZEOF(JBLOCK))); + + for (i = rowsperchunk; i > 0; i--) { + + result[currow++] = workspace; + + workspace += blocksperrow; + + } + + } + + + + return result; + +} + + + + + +/* + + * About virtual array management: + + * + + * The above "normal" array routines are only used to allocate strip buffers + + * (as wide as the image, but just a few rows high). Full-image-sized buffers + + * are handled as "virtual" arrays. The array is still accessed a strip at a + + * time, but the memory manager must save the whole array for repeated + + * accesses. The intended implementation is that there is a strip buffer in + + * memory (as high as is possible given the desired memory limit), plus a + + * backing file that holds the rest of the array. + + * + + * The request_virt_array routines are told the total size of the image and + + * the maximum number of rows that will be accessed at once. The in-memory + + * buffer must be at least as large as the maxaccess value. + + * + + * The request routines create control blocks but not the in-memory buffers. + + * That is postponed until realize_virt_arrays is called. At that time the + + * total amount of space needed is known (approximately, anyway), so free + + * memory can be divided up fairly. + + * + + * The access_virt_array routines are responsible for making a specific strip + + * area accessible (after reading or writing the backing file, if necessary). + + * Note that the access routines are told whether the caller intends to modify + + * the accessed strip; during a read-only pass this saves having to rewrite + + * data to disk. The access routines are also responsible for pre-zeroing + + * any newly accessed rows, if pre-zeroing was requested. + + * + + * In current usage, the access requests are usually for nonoverlapping + + * strips; that is, successive access start_row numbers differ by exactly + + * num_rows = maxaccess. This means we can get good performance with simple + + * buffer dump/reload logic, by making the in-memory buffer be a multiple + + * of the access height; then there will never be accesses across bufferload + + * boundaries. The code will still work with overlapping access requests, + + * but it doesn't handle bufferload overlaps very efficiently. + + */ + + + + + +METHODDEF jvirt_sarray_ptr + +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + + JDIMENSION samplesperrow, JDIMENSION numrows, + + JDIMENSION maxaccess) + +/* Request a virtual 2-D sample array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + jvirt_sarray_ptr result; + + + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + + if (pool_id != JPOOL_IMAGE) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + + /* get control block */ + + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + + SIZEOF(struct jvirt_sarray_control)); + + + + result->mem_buffer = NULL; /* marks array not yet realized */ + + result->rows_in_array = numrows; + + result->samplesperrow = samplesperrow; + + result->maxaccess = maxaccess; + + result->pre_zero = pre_zero; + + result->b_s_open = FALSE; /* no associated backing-store object */ + + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + + mem->virt_sarray_list = result; + + + + return result; + +} + + + + + +METHODDEF jvirt_barray_ptr + +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + + JDIMENSION blocksperrow, JDIMENSION numrows, + + JDIMENSION maxaccess) + +/* Request a virtual 2-D coefficient-block array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + jvirt_barray_ptr result; + + + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + + if (pool_id != JPOOL_IMAGE) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + + /* get control block */ + + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + + SIZEOF(struct jvirt_barray_control)); + + + + result->mem_buffer = NULL; /* marks array not yet realized */ + + result->rows_in_array = numrows; + + result->blocksperrow = blocksperrow; + + result->maxaccess = maxaccess; + + result->pre_zero = pre_zero; + + result->b_s_open = FALSE; /* no associated backing-store object */ + + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + + mem->virt_barray_list = result; + + + + return result; + +} + + + + + +METHODDEF void + +realize_virt_arrays (j_common_ptr cinfo) + +/* Allocate the in-memory buffers for any unrealized virtual arrays */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + long space_per_minheight, maximum_space, avail_mem; + + long minheights, max_minheights; + + jvirt_sarray_ptr sptr; + + jvirt_barray_ptr bptr; + + + + /* Compute the minimum space needed (maxaccess rows in each buffer) + + * and the maximum space needed (full image height in each buffer). + + * These may be of use to the system-dependent jpeg_mem_available routine. + + */ + + space_per_minheight = 0; + + maximum_space = 0; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + + space_per_minheight += (long) sptr->maxaccess * + + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + + maximum_space += (long) sptr->rows_in_array * + + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + + } + + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + + space_per_minheight += (long) bptr->maxaccess * + + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + + maximum_space += (long) bptr->rows_in_array * + + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + + } + + } + + + + if (space_per_minheight <= 0) + + return; /* no unrealized arrays, no work */ + + + + /* Determine amount of memory to actually use; this is system-dependent. */ + + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + + mem->total_space_allocated); + + + + /* If the maximum space needed is available, make all the buffers full + + * height; otherwise parcel it out with the same number of minheights + + * in each buffer. + + */ + + if (avail_mem >= maximum_space) + + max_minheights = 1000000000L; + + else { + + max_minheights = avail_mem / space_per_minheight; + + /* If there doesn't seem to be enough space, try to get the minimum + + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + + */ + + if (max_minheights <= 0) + + max_minheights = 1; + + } + + + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + + if (minheights <= max_minheights) { + + /* This buffer fits in memory */ + + sptr->rows_in_mem = sptr->rows_in_array; + + } else { + + /* It doesn't fit in memory, create backing store. */ + + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + + (long) sptr->rows_in_array * + + (long) sptr->samplesperrow * + + (long) SIZEOF(JSAMPLE)); + + sptr->b_s_open = TRUE; + + } + + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + + sptr->samplesperrow, sptr->rows_in_mem); + + sptr->rowsperchunk = mem->last_rowsperchunk; + + sptr->cur_start_row = 0; + + sptr->first_undef_row = 0; + + sptr->dirty = FALSE; + + } + + } + + + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + + if (minheights <= max_minheights) { + + /* This buffer fits in memory */ + + bptr->rows_in_mem = bptr->rows_in_array; + + } else { + + /* It doesn't fit in memory, create backing store. */ + + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + + (long) bptr->rows_in_array * + + (long) bptr->blocksperrow * + + (long) SIZEOF(JBLOCK)); + + bptr->b_s_open = TRUE; + + } + + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + + bptr->blocksperrow, bptr->rows_in_mem); + + bptr->rowsperchunk = mem->last_rowsperchunk; + + bptr->cur_start_row = 0; + + bptr->first_undef_row = 0; + + bptr->dirty = FALSE; + + } + + } + +} + + + + + +LOCAL void + +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) + +/* Do backing store read or write of a virtual sample array */ + +{ + + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + + file_offset = ptr->cur_start_row * bytesperrow; + + /* Loop to read or write each allocation chunk in mem_buffer */ + + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + + /* One chunk, but check for short chunk at end of buffer */ + + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + + /* Transfer no more than is currently defined */ + + thisrow = (long) ptr->cur_start_row + i; + + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + + /* Transfer no more than fits in file */ + + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + + if (rows <= 0) /* this chunk might be past end of file! */ + + break; + + byte_count = rows * bytesperrow; + + if (writing) + + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + else + + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + file_offset += byte_count; + + } + +} + + + + + +LOCAL void + +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) + +/* Do backing store read or write of a virtual coefficient-block array */ + +{ + + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + + file_offset = ptr->cur_start_row * bytesperrow; + + /* Loop to read or write each allocation chunk in mem_buffer */ + + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + + /* One chunk, but check for short chunk at end of buffer */ + + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + + /* Transfer no more than is currently defined */ + + thisrow = (long) ptr->cur_start_row + i; + + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + + /* Transfer no more than fits in file */ + + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + + if (rows <= 0) /* this chunk might be past end of file! */ + + break; + + byte_count = rows * bytesperrow; + + if (writing) + + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + else + + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + file_offset += byte_count; + + } + +} + + + + + +METHODDEF JSAMPARRAY + +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + + JDIMENSION start_row, JDIMENSION num_rows, + + boolean writable) + +/* Access the part of a virtual sample array starting at start_row */ + +/* and extending for num_rows rows. writable is true if */ + +/* caller intends to modify the accessed area. */ + +{ + + JDIMENSION end_row = start_row + num_rows; + + JDIMENSION undef_row; + + + + /* debugging check */ + + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + + ptr->mem_buffer == NULL) + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + + + /* Make the desired part of the virtual array accessible */ + + if (start_row < ptr->cur_start_row || + + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + + if (! ptr->b_s_open) + + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + + /* Flush old buffer contents if necessary */ + + if (ptr->dirty) { + + do_sarray_io(cinfo, ptr, TRUE); + + ptr->dirty = FALSE; + + } + + /* Decide what part of virtual array to access. + + * Algorithm: if target address > current window, assume forward scan, + + * load starting at target address. If target address < current window, + + * assume backward scan, load so that target area is top of window. + + * Note that when switching from forward write to forward read, will have + + * start_row = 0, so the limiting case applies and we load from 0 anyway. + + */ + + if (start_row > ptr->cur_start_row) { + + ptr->cur_start_row = start_row; + + } else { + + /* use long arithmetic here to avoid overflow & unsigned problems */ + + long ltemp; + + + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + + if (ltemp < 0) + + ltemp = 0; /* don't fall off front end of file */ + + ptr->cur_start_row = (JDIMENSION) ltemp; + + } + + /* Read in the selected part of the array. + + * During the initial write pass, we will do no actual read + + * because the selected part is all undefined. + + */ + + do_sarray_io(cinfo, ptr, FALSE); + + } + + /* Ensure the accessed part of the array is defined; prezero if needed. + + * To improve locality of access, we only prezero the part of the array + + * that the caller is about to access, not the entire in-memory array. + + */ + + if (ptr->first_undef_row < end_row) { + + if (ptr->first_undef_row < start_row) { + + if (writable) /* writer skipped over a section of array */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + undef_row = start_row; /* but reader is allowed to read ahead */ + + } else { + + undef_row = ptr->first_undef_row; + + } + + if (writable) + + ptr->first_undef_row = end_row; + + if (ptr->pre_zero) { + + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + + end_row -= ptr->cur_start_row; + + while (undef_row < end_row) { + + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + + undef_row++; + + } + + } else { + + if (! writable) /* reader looking at undefined data */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + } + + } + + /* Flag the buffer dirty if caller will write in it */ + + if (writable) + + ptr->dirty = TRUE; + + /* Return address of proper part of the buffer */ + + return ptr->mem_buffer + (start_row - ptr->cur_start_row); + +} + + + + + +METHODDEF JBLOCKARRAY + +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + + JDIMENSION start_row, JDIMENSION num_rows, + + boolean writable) + +/* Access the part of a virtual block array starting at start_row */ + +/* and extending for num_rows rows. writable is true if */ + +/* caller intends to modify the accessed area. */ + +{ + + JDIMENSION end_row = start_row + num_rows; + + JDIMENSION undef_row; + + + + /* debugging check */ + + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + + ptr->mem_buffer == NULL) + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + + + /* Make the desired part of the virtual array accessible */ + + if (start_row < ptr->cur_start_row || + + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + + if (! ptr->b_s_open) + + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + + /* Flush old buffer contents if necessary */ + + if (ptr->dirty) { + + do_barray_io(cinfo, ptr, TRUE); + + ptr->dirty = FALSE; + + } + + /* Decide what part of virtual array to access. + + * Algorithm: if target address > current window, assume forward scan, + + * load starting at target address. If target address < current window, + + * assume backward scan, load so that target area is top of window. + + * Note that when switching from forward write to forward read, will have + + * start_row = 0, so the limiting case applies and we load from 0 anyway. + + */ + + if (start_row > ptr->cur_start_row) { + + ptr->cur_start_row = start_row; + + } else { + + /* use long arithmetic here to avoid overflow & unsigned problems */ + + long ltemp; + + + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + + if (ltemp < 0) + + ltemp = 0; /* don't fall off front end of file */ + + ptr->cur_start_row = (JDIMENSION) ltemp; + + } + + /* Read in the selected part of the array. + + * During the initial write pass, we will do no actual read + + * because the selected part is all undefined. + + */ + + do_barray_io(cinfo, ptr, FALSE); + + } + + /* Ensure the accessed part of the array is defined; prezero if needed. + + * To improve locality of access, we only prezero the part of the array + + * that the caller is about to access, not the entire in-memory array. + + */ + + if (ptr->first_undef_row < end_row) { + + if (ptr->first_undef_row < start_row) { + + if (writable) /* writer skipped over a section of array */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + undef_row = start_row; /* but reader is allowed to read ahead */ + + } else { + + undef_row = ptr->first_undef_row; + + } + + if (writable) + + ptr->first_undef_row = end_row; + + if (ptr->pre_zero) { + + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + + end_row -= ptr->cur_start_row; + + while (undef_row < end_row) { + + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + + undef_row++; + + } + + } else { + + if (! writable) /* reader looking at undefined data */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + } + + } + + /* Flag the buffer dirty if caller will write in it */ + + if (writable) + + ptr->dirty = TRUE; + + /* Return address of proper part of the buffer */ + + return ptr->mem_buffer + (start_row - ptr->cur_start_row); + +} + + + + + +/* + + * Release all objects belonging to a specified pool. + + */ + + + +METHODDEF void + +free_pool (j_common_ptr cinfo, int pool_id) + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + small_pool_ptr shdr_ptr; + + large_pool_ptr lhdr_ptr; + + size_t space_freed; + + + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + +#ifdef MEM_STATS + + if (cinfo->err->trace_level > 1) + + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ + +#endif + + + + /* If freeing IMAGE pool, close any virtual arrays first */ + + if (pool_id == JPOOL_IMAGE) { + + jvirt_sarray_ptr sptr; + + jvirt_barray_ptr bptr; + + + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + + if (sptr->b_s_open) { /* there may be no backing store */ + + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + + } + + } + + mem->virt_sarray_list = NULL; + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + + if (bptr->b_s_open) { /* there may be no backing store */ + + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + + } + + } + + mem->virt_barray_list = NULL; + + } + + + + /* Release large objects */ + + lhdr_ptr = mem->large_list[pool_id]; + + mem->large_list[pool_id] = NULL; + + + + while (lhdr_ptr != NULL) { + + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + + space_freed = lhdr_ptr->hdr.bytes_used + + + lhdr_ptr->hdr.bytes_left + + + SIZEOF(large_pool_hdr); + + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + + mem->total_space_allocated -= space_freed; + + lhdr_ptr = next_lhdr_ptr; + + } + + + + /* Release small objects */ + + shdr_ptr = mem->small_list[pool_id]; + + mem->small_list[pool_id] = NULL; + + + + while (shdr_ptr != NULL) { + + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + + space_freed = shdr_ptr->hdr.bytes_used + + + shdr_ptr->hdr.bytes_left + + + SIZEOF(small_pool_hdr); + + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + + mem->total_space_allocated -= space_freed; + + shdr_ptr = next_shdr_ptr; + + } + +} + + + + + +/* + + * Close up shop entirely. + + * Note that this cannot be called unless cinfo->mem is non-NULL. + + */ + + + +METHODDEF void + +self_destruct (j_common_ptr cinfo) + +{ + + int pool; + + + + /* Close all backing store, release all memory. + + * Releasing pools in reverse order might help avoid fragmentation + + * with some (brain-damaged) malloc libraries. + + */ + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + + free_pool(cinfo, pool); + + } + + + + /* Release the memory manager control block too. */ + + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + + cinfo->mem = NULL; /* ensures I will be called only once */ + + + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + +} + + + + + +/* + + * Memory manager initialization. + + * When this is called, only the error manager pointer is valid in cinfo! + + */ + + + +GLOBAL void + +jinit_memory_mgr (j_common_ptr cinfo) + +{ + + my_mem_ptr mem; + + long max_to_use; + + int pool; + + size_t test_mac; + + + + cinfo->mem = NULL; /* for safety if init fails */ + + + + /* Check for configuration errors. + + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + + * doesn't reflect any real hardware alignment requirement. + + * The test is a little tricky: for X>0, X and X-1 have no one-bits + + * in common if and only if X is a power of 2, ie has only one one-bit. + + * Some compilers may give an "unreachable code" warning here; ignore it. + + */ + + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + + * a multiple of SIZEOF(ALIGN_TYPE). + + * Again, an "unreachable code" warning may be ignored here. + + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + + */ + + test_mac = (size_t) MAX_ALLOC_CHUNK; + + if ((long) test_mac != MAX_ALLOC_CHUNK || + + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + + + /* Attempt to allocate memory manager's control block */ + + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + + + if (mem == NULL) { + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + + } + + + + /* OK, fill in the method pointers */ + + mem->pub.alloc_small = alloc_small; + + mem->pub.alloc_large = alloc_large; + + mem->pub.alloc_sarray = alloc_sarray; + + mem->pub.alloc_barray = alloc_barray; + + mem->pub.request_virt_sarray = request_virt_sarray; + + mem->pub.request_virt_barray = request_virt_barray; + + mem->pub.realize_virt_arrays = realize_virt_arrays; + + mem->pub.access_virt_sarray = access_virt_sarray; + + mem->pub.access_virt_barray = access_virt_barray; + + mem->pub.free_pool = free_pool; + + mem->pub.self_destruct = self_destruct; + + + + /* Initialize working state */ + + mem->pub.max_memory_to_use = max_to_use; + + + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + + mem->small_list[pool] = NULL; + + mem->large_list[pool] = NULL; + + } + + mem->virt_sarray_list = NULL; + + mem->virt_barray_list = NULL; + + + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + + + /* Declare ourselves open for business */ + + cinfo->mem = & mem->pub; + + + + /* Check for an environment variable JPEGMEM; if found, override the + + * default max_memory setting from jpeg_mem_init. Note that the + + * surrounding application may again override this value. + + * If your system doesn't support getenv(), define NO_GETENV to disable + + * this feature. + + */ + +#ifndef NO_GETENV + + { char * memenv; + + + + if ((memenv = getenv("JPEGMEM")) != NULL) { + + char ch = 'x'; + + + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + + if (ch == 'm' || ch == 'M') + + max_to_use *= 1000L; + + mem->pub.max_memory_to_use = max_to_use * 1000L; + + } + + } + + } + +#endif + + + +} + diff --git a/libs/jpeg6/jmemnobs.cpp b/libs/jpeg6/jmemnobs.cpp new file mode 100644 index 00000000..bd236e54 --- /dev/null +++ b/libs/jpeg6/jmemnobs.cpp @@ -0,0 +1,206 @@ +/* + + * jmemnobs.c + + * + + * Copyright (C) 1992-1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file provides a really simple implementation of the system- + + * dependent portion of the JPEG memory manager. This implementation + + * assumes that no backing-store files are needed: all required space + + * can be obtained from ri.Malloc(). + + * This is very portable in the sense that it'll compile on almost anything, + + * but you'd better have lots of main memory (or virtual memory) if you want + + * to process big images. + + * Note that the max_memory_to_use option is ignored by this implementation. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jmemsys.h" /* import the system-dependent declarations */ + + + +/* + + * Memory allocation and ri.Freeing are controlled by the regular library + + * routines ri.Malloc() and ri.Free(). + + */ + + + +GLOBAL void * + +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) + +{ + + return (void *) malloc(sizeofobject); + +} + + + +GLOBAL void + +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) + +{ + + free(object); + +} + + + + + +/* + + * "Large" objects are treated the same as "small" ones. + + * NB: although we include FAR keywords in the routine declarations, + + * this file won't actually work in 80x86 small/medium model; at least, + + * you probably won't be able to process useful-size images in only 64KB. + + */ + + + +GLOBAL void FAR * + +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) + +{ + + return (void FAR *) malloc(sizeofobject); + +} + + + +GLOBAL void + +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) + +{ + + free(object); + +} + + + + + +/* + + * This routine computes the total memory space available for allocation. + + * Here we always say, "we got all you want bud!" + + */ + + + +GLOBAL long + +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + + long max_bytes_needed, long already_allocated) + +{ + + return max_bytes_needed; + +} + + + + + +/* + + * Backing store (temporary file) management. + + * Since jpeg_mem_available always promised the moon, + + * this should never be called and we can just error out. + + */ + + + +GLOBAL void + +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + + long total_bytes_needed) + +{ + + ERREXIT(cinfo, JERR_NO_BACKING_STORE); + +} + + + + + +/* + + * These routines take care of any system-dependent initialization and + + * cleanup required. Here, there isn't any. + + */ + + + +GLOBAL long + +jpeg_mem_init (j_common_ptr cinfo) + +{ + + return 0; /* just set max_memory_to_use to 0 */ + +} + + + +GLOBAL void + +jpeg_mem_term (j_common_ptr cinfo) + +{ + + /* no work */ + +} + diff --git a/libs/jpeg6/jmemsys.h b/libs/jpeg6/jmemsys.h new file mode 100644 index 00000000..9c8028bc --- /dev/null +++ b/libs/jpeg6/jmemsys.h @@ -0,0 +1,364 @@ +/* + + * jmemsys.h + + * + + * Copyright (C) 1992-1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This include file defines the interface between the system-independent + + * and system-dependent portions of the JPEG memory manager. No other + + * modules need include it. (The system-independent portion is jmemmgr.c; + + * there are several different versions of the system-dependent portion.) + + * + + * This file works as-is for the system-dependent memory managers supplied + + * in the IJG distribution. You may need to modify it if you write a + + * custom memory manager. If system-dependent changes are needed in + + * this file, the best method is to #ifdef them based on a configuration + + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR. + + */ + + + + + +/* Short forms of external names for systems with brain-damaged linkers. */ + + + +#ifdef NEED_SHORT_EXTERNAL_NAMES + +#define jpeg_get_small jGetSmall + +#define jpeg_free_small jFreeSmall + +#define jpeg_get_large jGetLarge + +#define jpeg_free_large jFreeLarge + +#define jpeg_mem_available jMemAvail + +#define jpeg_open_backing_store jOpenBackStore + +#define jpeg_mem_init jMemInit + +#define jpeg_mem_term jMemTerm + +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + + + + +/* + + * These two functions are used to allocate and release small chunks of + + * memory. (Typically the total amount requested through jpeg_get_small is + + * no more than 20K or so; this will be requested in chunks of a few K each.) + + * Behavior should be the same as for the standard library functions malloc + + * and free; in particular, jpeg_get_small must return NULL on failure. + + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + + * size of the object being freed, just in case it's needed. + + * On an 80x86 machine using small-data memory model, these manage near heap. + + */ + + + +EXTERN void * jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); + +EXTERN void jpeg_free_small JPP((j_common_ptr cinfo, void * object, + + size_t sizeofobject)); + + + +/* + + * These two functions are used to allocate and release large chunks of + + * memory (up to the total free space designated by jpeg_mem_available). + + * The interface is the same as above, except that on an 80x86 machine, + + * far pointers are used. On most other machines these are identical to + + * the jpeg_get/free_small routines; but we keep them separate anyway, + + * in case a different allocation strategy is desirable for large chunks. + + */ + + + +EXTERN void FAR * jpeg_get_large JPP((j_common_ptr cinfo,size_t sizeofobject)); + +EXTERN void jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + + size_t sizeofobject)); + + + +/* + + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + + * matter, but that case should never come into play). This macro is needed + + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + + * On those machines, we expect that jconfig.h will provide a proper value. + + * On machines with 32-bit flat address spaces, any large constant may be used. + + * + + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + + * size_t and will be a multiple of sizeof(align_type). + + */ + + + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ + +#define MAX_ALLOC_CHUNK 1000000000L + +#endif + + + +/* + + * This routine computes the total space still available for allocation by + + * jpeg_get_large. If more space than this is needed, backing store will be + + * used. NOTE: any memory already allocated must not be counted. + + * + + * There is a minimum space requirement, corresponding to the minimum + + * feasible buffer sizes; jmemmgr.c will request that much space even if + + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + + * all working storage in memory, is also passed in case it is useful. + + * Finally, the total space already allocated is passed. If no better + + * method is available, cinfo->mem->max_memory_to_use - already_allocated + + * is often a suitable calculation. + + * + + * It is OK for jpeg_mem_available to underestimate the space available + + * (that'll just lead to more backing-store access than is really necessary). + + * However, an overestimate will lead to failure. Hence it's wise to subtract + + * a slop factor from the true available space. 5% should be enough. + + * + + * On machines with lots of virtual memory, any large constant may be returned. + + * Conversely, zero may be returned to always use the minimum amount of memory. + + */ + + + +EXTERN long jpeg_mem_available JPP((j_common_ptr cinfo, + + long min_bytes_needed, + + long max_bytes_needed, + + long already_allocated)); + + + + + +/* + + * This structure holds whatever state is needed to access a single + + * backing-store object. The read/write/close method pointers are called + + * by jmemmgr.c to manipulate the backing-store object; all other fields + + * are private to the system-dependent backing store routines. + + */ + + + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + + + +typedef unsigned short XMSH; /* type of extended-memory handles */ + +typedef unsigned short EMSH; /* type of expanded-memory handles */ + + + +typedef union { + + short file_handle; /* DOS file handle if it's a temp file */ + + XMSH xms_handle; /* handle if it's a chunk of XMS */ + + EMSH ems_handle; /* handle if it's a chunk of EMS */ + +} handle_union; + + + +#endif /* USE_MSDOS_MEMMGR */ + + + +typedef struct backing_store_struct * backing_store_ptr; + + + +typedef struct backing_store_struct { + + /* Methods for reading/writing/closing this backing-store object */ + + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + + backing_store_ptr info, + + void FAR * buffer_address, + + long file_offset, long byte_count)); + + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + + backing_store_ptr info, + + void FAR * buffer_address, + + long file_offset, long byte_count)); + + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + + backing_store_ptr info)); + + + + /* Private fields for system-dependent backing-store management */ + +#ifdef USE_MSDOS_MEMMGR + + /* For the MS-DOS manager (jmemdos.c), we need: */ + + handle_union handle; /* reference to backing-store storage object */ + + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ + +#else + + /* For a typical implementation with temp files, we need: */ + + FILE * temp_file; /* stdio reference to temp file */ + + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ + +#endif + +} backing_store_info; + + + +/* + + * Initial opening of a backing-store object. This must fill in the + + * read/write/close pointers in the object. The read/write routines + + * may take an error exit if the specified maximum file size is exceeded. + + * (If jpeg_mem_available always returns a large value, this routine can + + * just take an error exit.) + + */ + + + +EXTERN void jpeg_open_backing_store JPP((j_common_ptr cinfo, + + backing_store_ptr info, + + long total_bytes_needed)); + + + + + +/* + + * These routines take care of any system-dependent initialization and + + * cleanup required. jpeg_mem_init will be called before anything is + + * allocated (and, therefore, nothing in cinfo is of use except the error + + * manager pointer). It should return a suitable default value for + + * max_memory_to_use; this may subsequently be overridden by the surrounding + + * application. (Note that max_memory_to_use is only important if + + * jpeg_mem_available chooses to consult it ... no one else will.) + + * jpeg_mem_term may assume that all requested memory has been freed and that + + * all opened backing-store objects have been closed. + + */ + + + +EXTERN long jpeg_mem_init JPP((j_common_ptr cinfo)); + +EXTERN void jpeg_mem_term JPP((j_common_ptr cinfo)); + diff --git a/libs/jpeg6/jmorecfg.h b/libs/jpeg6/jmorecfg.h new file mode 100644 index 00000000..afb6e26c --- /dev/null +++ b/libs/jpeg6/jmorecfg.h @@ -0,0 +1,693 @@ +/* + + * jmorecfg.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains additional configuration options that customize the + + * JPEG software for special applications or support machine-dependent + + * optimizations. Most users will not need to touch this file. + + */ + + + + + +/* + + * Define BITS_IN_JSAMPLE as either + + * 8 for 8-bit sample values (the usual setting) + + * 12 for 12-bit sample values + + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + + * JPEG standard, and the IJG code does not support anything else! + + * We do not support run-time selection of data precision, sorry. + + */ + + + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + + + + +/* + + * Maximum number of components (color channels) allowed in JPEG image. + + * To meet the letter of the JPEG spec, set this to 255. However, darn + + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + + * really short on memory. (Each allowed component costs a hundred or so + + * bytes of storage, whether actually used in an image or not.) + + */ + + + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + + + + +/* + + * Basic data types. + + * You may need to change these if you have a machine with unusual data + + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + + * but it had better be at least 16. + + */ + + + +/* Representation of a single sample (pixel element value). + + * We frequently allocate large arrays of these, so it's important to keep + + * them small. But if you have memory to burn and access to char or short + + * arrays is very slow on your hardware, you might want to change these. + + */ + + + +#if BITS_IN_JSAMPLE == 8 + +/* JSAMPLE should be the smallest type that will hold the values 0..255. + + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + + */ + + + +#ifdef HAVE_UNSIGNED_CHAR + + + +typedef unsigned char JSAMPLE; + +#define GETJSAMPLE(value) ((int) (value)) + + + +#else /* not HAVE_UNSIGNED_CHAR */ + + + +typedef char JSAMPLE; + +#ifdef CHAR_IS_UNSIGNED + +#define GETJSAMPLE(value) ((int) (value)) + +#else + +#define GETJSAMPLE(value) ((int) (value) & 0xFF) + +#endif /* CHAR_IS_UNSIGNED */ + + + +#endif /* HAVE_UNSIGNED_CHAR */ + + + +#define MAXJSAMPLE 255 + +#define CENTERJSAMPLE 128 + + + +#endif /* BITS_IN_JSAMPLE == 8 */ + + + + + +#if BITS_IN_JSAMPLE == 12 + +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + + * On nearly all machines "short" will do nicely. + + */ + + + +typedef short JSAMPLE; + +#define GETJSAMPLE(value) ((int) (value)) + + + +#define MAXJSAMPLE 4095 + +#define CENTERJSAMPLE 2048 + + + +#endif /* BITS_IN_JSAMPLE == 12 */ + + + + + +/* Representation of a DCT frequency coefficient. + + * This should be a signed value of at least 16 bits; "short" is usually OK. + + * Again, we allocate large arrays of these, but you can change to int + + * if you have memory to burn and "short" is really slow. + + */ + + + +typedef short JCOEF; + + + + + +/* Compressed datastreams are represented as arrays of JOCTET. + + * These must be EXACTLY 8 bits wide, at least once they are written to + + * external storage. Note that when using the stdio data source/destination + + * managers, this is also the data type passed to fread/fwrite. + + */ + + + +#ifdef HAVE_UNSIGNED_CHAR + + + +typedef unsigned char JOCTET; + +#define GETJOCTET(value) (value) + + + +#else /* not HAVE_UNSIGNED_CHAR */ + + + +typedef char JOCTET; + +#ifdef CHAR_IS_UNSIGNED + +#define GETJOCTET(value) (value) + +#else + +#define GETJOCTET(value) ((value) & 0xFF) + +#endif /* CHAR_IS_UNSIGNED */ + + + +#endif /* HAVE_UNSIGNED_CHAR */ + + + + + +/* These typedefs are used for various table entries and so forth. + + * They must be at least as wide as specified; but making them too big + + * won't cost a huge amount of memory, so we don't provide special + + * extraction code like we did for JSAMPLE. (In other words, these + + * typedefs live at a different point on the speed/space tradeoff curve.) + + */ + + + +/* UINT8 must hold at least the values 0..255. */ + + + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char UINT8; + +#else /* not HAVE_UNSIGNED_CHAR */ + +#ifdef CHAR_IS_UNSIGNED + +typedef char UINT8; + +#else /* not CHAR_IS_UNSIGNED */ + +typedef short UINT8; + +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + + +/* UINT16 must hold at least the values 0..65535. */ + + + +#ifdef HAVE_UNSIGNED_SHORT + +typedef unsigned short UINT16; + +#else /* not HAVE_UNSIGNED_SHORT */ + +typedef unsigned int UINT16; + +#endif /* HAVE_UNSIGNED_SHORT */ + + + +/* INT16 must hold at least the values -32768..32767. */ + + + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ + +typedef short INT16; + +#endif + + + +/* INT32 must hold at least signed 32-bit values. */ + + + +//#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ + +//typedef long INT32; + +//#endif + + + +/* Datatype used for image dimensions. The JPEG standard only supports + + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + + * "unsigned int" is sufficient on all machines. However, if you need to + + * handle larger images and you don't mind deviating from the spec, you + + * can change this datatype. + + */ + + + +typedef unsigned int JDIMENSION; + + + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + + + + +/* These defines are used in all function definitions and extern declarations. + + * You could modify them if you need to change function linkage conventions. + + * Another application is to make all functions global for use with debuggers + + * or code profilers that require it. + + */ + + + +#define METHODDEF static /* a function called through method pointers */ + +#define LOCAL static /* a function used only in its module */ + +#define GLOBAL /* a function referenced thru EXTERNs */ + +#define EXTERN extern /* a reference to a GLOBAL function */ + + + + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + + * by just saying "FAR *" where such a pointer is needed. In a few places + + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + + */ + + + +#ifdef NEED_FAR_POINTERS + +#undef FAR + +#define FAR far + +#else + +#undef FAR + +#define FAR + +#endif + + + + + +/* + + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + + * in standard header files. Or you may have conflicts with application- + + * specific header files that you want to include together with these files. + + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + + */ + + + +//#ifndef HAVE_BOOLEAN + +//typedef int boolean; + +//#endif + +#ifndef FALSE /* in case these macros already exist */ + +#define FALSE 0 /* values of boolean */ + +#endif + +#ifndef TRUE + +#define TRUE 1 + +#endif + + + + + +/* + + * The remaining options affect code selection within the JPEG library, + + * but they don't need to be visible to most applications using the library. + + * To minimize application namespace pollution, the symbols won't be + + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + + */ + + + +#ifdef JPEG_INTERNALS + +#define JPEG_INTERNAL_OPTIONS + +#endif + + + +#ifdef JPEG_INTERNAL_OPTIONS + + + + + +/* + + * These defines indicate whether to include various optional functions. + + * Undefining some of these symbols will produce a smaller but less capable + + * library. Note that you can leave certain source files out of the + + * compilation/linking process if you've #undef'd the corresponding symbols. + + * (You may HAVE to do that if your compiler doesn't like null source files.) + + */ + + + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + + + +/* Capability options common to encoder and decoder: */ + + + +#undef DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ + +#undef DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ + +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + + + +/* Encoder capability options: */ + + + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ + +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ + +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ + +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ + +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + + * precision, so jchuff.c normally uses entropy optimization to compute + + * usable tables for higher precision. If you don't want to do optimization, + + * you'll have to supply different default Huffman tables. + + * The exact same statements apply for progressive JPEG: the default tables + + * don't work for progressive mode. (This may get fixed, however.) + + */ + +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + + + +/* Decoder capability options: */ + + + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ + +#undef D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ + +#undef D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ + +#undef BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ + +#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ + +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ + +#undef UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ + +#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ + +#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + + + +/* more capability options later, no doubt */ + + + + + +/* + + * Ordering of RGB data in scanlines passed to or from the application. + + * If your application wants to deal with data in the order B,G,R, just + + * change these macros. You can also deal with formats such as R,G,B,X + + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + + * the offsets will also change the order in which colormap data is organized. + + * RESTRICTIONS: + + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + + * is not 3 (they don't understand about dummy color components!). So you + + * can't use color quantization if you change that value. + + */ + + + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ + +#define RGB_GREEN 1 /* Offset of Green */ + +#define RGB_BLUE 2 /* Offset of Blue */ + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 +// ydnar: setting this fucks jpeg loading in q3map2, disabling "fix" (3) +#define RGB_PIXELSIZE 4 /* JSAMPLEs per RGB scanline element */ + + + + + +/* Definitions for speed-related optimizations. */ + + + + + +/* If your compiler supports inline functions, define INLINE + + * as the inline keyword; otherwise define it as empty. + + */ + + + +#ifndef INLINE + +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ + +#define INLINE __inline__ + +#endif + +#ifndef INLINE + +#define INLINE /* default is to define it as empty */ + +#endif + +#endif + + + + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + + */ + + + +#ifndef MULTIPLIER + +#define MULTIPLIER int /* type for fastest integer multiply */ + +#endif + + + + + +/* FAST_FLOAT should be either float or double, whichever is done faster + + * by your compiler. (Note that this type is only used in the floating point + + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + + * Typically, float is faster in ANSI C compilers, while double is faster in + + * pre-ANSI compilers (because they insist on converting to double anyway). + + * The code below therefore chooses float if we have ANSI-style prototypes. + + */ + + + +#ifndef FAST_FLOAT + +#ifdef HAVE_PROTOTYPES + +#define FAST_FLOAT float + +#else + +#define FAST_FLOAT double + +#endif + +#endif + + + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/libs/jpeg6/jpeg6.vcproj b/libs/jpeg6/jpeg6.vcproj new file mode 100644 index 00000000..a763fd29 --- /dev/null +++ b/libs/jpeg6/jpeg6.vcproj @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/jpeg6/jpegint.h b/libs/jpeg6/jpegint.h new file mode 100644 index 00000000..9b02525d --- /dev/null +++ b/libs/jpeg6/jpegint.h @@ -0,0 +1,776 @@ +/* + + * jpegint.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file provides common declarations for the various JPEG modules. + + * These declarations are considered internal to the JPEG library; most + + * applications using the library shouldn't need to include this file. + + */ + + + + + +/* Declarations for both compression & decompression */ + + + +typedef enum { /* Operating modes for buffer controllers */ + + JBUF_PASS_THRU, /* Plain stripwise operation */ + + /* Remaining modes require a full-image buffer to have been created */ + + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ + +} J_BUF_MODE; + + + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ + +#define CSTATE_START 100 /* after create_compress */ + +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ + +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ + +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ + +#define DSTATE_START 200 /* after create_decompress */ + +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ + +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ + +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ + +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ + +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ + +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ + +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ + +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ + +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ + +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + + + + +/* Declarations for compression modules */ + + + +/* Master control module */ + +struct jpeg_comp_master { + + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + + + /* State variables made visible to other modules */ + + boolean call_pass_startup; /* True if pass_startup must be called */ + + boolean is_last_pass; /* True during last pass */ + +}; + + + +/* Main buffer control (downsampled-data buffer) */ + +struct jpeg_c_main_controller { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, process_data, (j_compress_ptr cinfo, + + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + + JDIMENSION in_rows_avail)); + +}; + + + +/* Compression preprocessing (downsampling input buffer control) */ + +struct jpeg_c_prep_controller { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + + JSAMPARRAY input_buf, + + JDIMENSION *in_row_ctr, + + JDIMENSION in_rows_avail, + + JSAMPIMAGE output_buf, + + JDIMENSION *out_row_group_ctr, + + JDIMENSION out_row_groups_avail)); + +}; + + + +/* Coefficient buffer control */ + +struct jpeg_c_coef_controller { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + + JSAMPIMAGE input_buf)); + +}; + + + +/* Colorspace conversion */ + +struct jpeg_color_converter { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + + JDIMENSION output_row, int num_rows)); + +}; + + + +/* Downsampling */ + +struct jpeg_downsampler { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + + JMETHOD(void, downsample, (j_compress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + + JSAMPIMAGE output_buf, + + JDIMENSION out_row_group_index)); + + + + boolean need_context_rows; /* TRUE if need rows above & below */ + +}; + + + +/* Forward DCT (also controls coefficient quantization) */ + +struct jpeg_forward_dct { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + + /* perhaps this should be an array??? */ + + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + + jpeg_component_info * compptr, + + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + + JDIMENSION start_row, JDIMENSION start_col, + + JDIMENSION num_blocks)); + +}; + + + +/* Entropy encoding */ + +struct jpeg_entropy_encoder { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + +}; + + + +/* Marker writing */ + +struct jpeg_marker_writer { + + /* write_any_marker is exported for use by applications */ + + /* Probably only COM and APPn markers should be written */ + + JMETHOD(void, write_any_marker, (j_compress_ptr cinfo, int marker, + + const JOCTET *dataptr, unsigned int datalen)); + + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + +}; + + + + + +/* Declarations for decompression modules */ + + + +/* Master control module */ + +struct jpeg_decomp_master { + + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + + + /* State variables made visible to other modules */ + + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ + +}; + + + +/* Input control module */ + +struct jpeg_input_controller { + + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + + + /* State variables made visible to other modules */ + + boolean has_multiple_scans; /* True if file has multiple scans */ + + boolean eoi_reached; /* True when EOI has been consumed */ + +}; + + + +/* Main buffer control (downsampled-data buffer) */ + +struct jpeg_d_main_controller { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +}; + + + +/* Coefficient buffer control */ + +struct jpeg_d_coef_controller { + + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + + JSAMPIMAGE output_buf)); + + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + + jvirt_barray_ptr *coef_arrays; + +}; + + + +/* Decompression postprocessing (color quantization buffer control) */ + +struct jpeg_d_post_controller { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, + + JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +}; + + + +/* Marker reading & parsing */ + +struct jpeg_marker_reader { + + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + + /* Read markers until SOS or EOI. + + * Returns same codes as are defined for jpeg_consume_input: + + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + + */ + + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + + /* Read a restart marker --- exported for use by entropy decoder only */ + + jpeg_marker_parser_method read_restart_marker; + + /* Application-overridable marker processing methods */ + + jpeg_marker_parser_method process_COM; + + jpeg_marker_parser_method process_APPn[16]; + + + + /* State of marker reader --- nominally internal, but applications + + * supplying COM or APPn handlers might like to know the state. + + */ + + boolean saw_SOI; /* found SOI? */ + + boolean saw_SOF; /* found SOF? */ + + int next_restart_num; /* next restart number expected (0-7) */ + + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ + +}; + + + +/* Entropy decoding */ + +struct jpeg_entropy_decoder { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + + JBLOCKROW *MCU_data)); + +}; + + + +/* Inverse DCT (also performs dequantization) */ + +typedef JMETHOD(void, inverse_DCT_method_ptr, + + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, + + JSAMPARRAY output_buf, JDIMENSION output_col)); + + + +struct jpeg_inverse_dct { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + /* It is useful to allow each component to have a separate IDCT method. */ + + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; + +}; + + + +/* Upsampling (note that upsampler must also call color converter) */ + +struct jpeg_upsampler { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, + + JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + + + + boolean need_context_rows; /* TRUE if need rows above & below */ + +}; + + + +/* Colorspace conversion */ + +struct jpeg_color_deconverter { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION input_row, + + JSAMPARRAY output_buf, int num_rows)); + +}; + + + +/* Color quantization or color precision reduction */ + +struct jpeg_color_quantizer { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + + int num_rows)); + + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); + +}; + + + + + +/* Miscellaneous useful macros */ + + + +#undef MAX + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#undef MIN + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + + + + +/* We assume that right shift corresponds to signed division by 2 with + + * rounding towards minus infinity. This is correct for typical "arithmetic + + * shift" instructions that shift in copies of the sign bit. But some + + * C compilers implement >> with an unsigned shift. For these machines you + + * must define RIGHT_SHIFT_IS_UNSIGNED. + + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + + * It is only applied with constant shift counts. SHIFT_TEMPS must be + + * included in the variables of any routine using RIGHT_SHIFT. + + */ + + + +#ifdef RIGHT_SHIFT_IS_UNSIGNED + +#define SHIFT_TEMPS INT32 shift_temp; + +#define RIGHT_SHIFT(x,shft) \ + + ((shift_temp = (x)) < 0 ? \ + + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + + (shift_temp >> (shft))) + +#else + +#define SHIFT_TEMPS + +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) + +#endif + + + + + +/* Short forms of external names for systems with brain-damaged linkers. */ + + + +#ifdef NEED_SHORT_EXTERNAL_NAMES + +#define jinit_compress_master jICompress + +#define jinit_c_master_control jICMaster + +#define jinit_c_main_controller jICMainC + +#define jinit_c_prep_controller jICPrepC + +#define jinit_c_coef_controller jICCoefC + +#define jinit_color_converter jICColor + +#define jinit_downsampler jIDownsampler + +#define jinit_forward_dct jIFDCT + +#define jinit_huff_encoder jIHEncoder + +#define jinit_phuff_encoder jIPHEncoder + +#define jinit_marker_writer jIMWriter + +#define jinit_master_decompress jIDMaster + +#define jinit_d_main_controller jIDMainC + +#define jinit_d_coef_controller jIDCoefC + +#define jinit_d_post_controller jIDPostC + +#define jinit_input_controller jIInCtlr + +#define jinit_marker_reader jIMReader + +#define jinit_huff_decoder jIHDecoder + +#define jinit_phuff_decoder jIPHDecoder + +#define jinit_inverse_dct jIIDCT + +#define jinit_upsampler jIUpsampler + +#define jinit_color_deconverter jIDColor + +#define jinit_1pass_quantizer jI1Quant + +#define jinit_2pass_quantizer jI2Quant + +#define jinit_merged_upsampler jIMUpsampler + +#define jinit_memory_mgr jIMemMgr + +#define jdiv_round_up jDivRound + +#define jround_up jRound + +#define jcopy_sample_rows jCopySamples + +#define jcopy_block_row jCopyBlocks + +#define jzero_far jZeroFar + +#define jpeg_zigzag_order jZIGTable + +#define jpeg_natural_order jZAGTable + +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + + + + +/* Compression module initialization routines */ + +EXTERN void jinit_compress_master JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_c_master_control JPP((j_compress_ptr cinfo, + + boolean transcode_only)); + +EXTERN void jinit_c_main_controller JPP((j_compress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_c_prep_controller JPP((j_compress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_c_coef_controller JPP((j_compress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_color_converter JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_downsampler JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_forward_dct JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_huff_encoder JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_phuff_encoder JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_marker_writer JPP((j_compress_ptr cinfo)); + +/* Decompression module initialization routines */ + +EXTERN void jinit_master_decompress JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_d_main_controller JPP((j_decompress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_d_post_controller JPP((j_decompress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_input_controller JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_marker_reader JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_huff_decoder JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_inverse_dct JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_upsampler JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_color_deconverter JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); + +/* Memory manager initialization */ + +EXTERN void jinit_memory_mgr JPP((j_common_ptr cinfo)); + + + +/* Utility routines in jutils.c */ + +EXTERN long jdiv_round_up JPP((long a, long b)); + +EXTERN long jround_up JPP((long a, long b)); + +EXTERN void jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + + JSAMPARRAY output_array, int dest_row, + + int num_rows, JDIMENSION num_cols)); + +EXTERN void jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + + JDIMENSION num_blocks)); + +EXTERN void jzero_far JPP((void FAR * target, size_t bytestozero)); + +/* Constant tables in jutils.c */ + +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ + +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + + + +/* Suppress undefined-structure complaints if necessary. */ + + + +#ifdef INCOMPLETE_TYPES_BROKEN + +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ + +struct jvirt_sarray_control { long dummy; }; + +struct jvirt_barray_control { long dummy; }; + +#endif + +#endif /* INCOMPLETE_TYPES_BROKEN */ + diff --git a/libs/jpeg6/jpgload.cpp b/libs/jpeg6/jpgload.cpp new file mode 100644 index 00000000..02c021f6 --- /dev/null +++ b/libs/jpeg6/jpgload.cpp @@ -0,0 +1,167 @@ + + +#include "radiant_jpeglib.h" +#include "jerror.h" +#include + +GLOBAL int LoadJPGBuff(unsigned char *fbuffer, int bufsize, unsigned char **pic, int *width, int *height ) +{ + + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + + struct jpeg_error_mgr jerr; + /* More stuff */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + unsigned char *out, *bbuf; + int nSize; + int jmpret; + + // Rad additions: initialize the longjmp buffer + jmpret = setjmp( rad_loadfailed ); + if (jmpret != 0) + { + *pic = (unsigned char *)rad_errormsg; + return -1; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, fbuffer, bufsize); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* ydnar: radiant only handles RGB, non-progressive format jpegs */ + if( cinfo.output_components != 4 ) + { + *pic = (unsigned char*) "Non-RGB JPEG encountered (unsupported)"; + return -1; + } + if( cinfo.progressive_mode ) + { + *pic = (unsigned char*) "Progressive JPEG encountered (unsupported)"; + return -1; + } + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + nSize = cinfo.output_width*cinfo.output_height*cinfo.output_components; + + out = reinterpret_cast( malloc( nSize+ 1 ) ); + memset( out, 255, nSize + 1 ); + + *pic = out; + *width = cinfo.output_width; + *height = cinfo.output_height; + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) + { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + bbuf = out + row_stride * cinfo.output_scanline; + buffer = &bbuf; + (void) jpeg_read_scanlines( &cinfo, buffer, 1 ); + } + + // clear all the alphas to 255 + { + int i, j; + unsigned char *buf; + + buf = *pic; + + j = cinfo.output_width * cinfo.output_height * 4; + for ( i = 3 ; i < j ; i+=4 ) { + buf[i] = 255; + } + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + //free (fbuffer); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 0; +} + diff --git a/libs/jpeg6/jutils.cpp b/libs/jpeg6/jutils.cpp new file mode 100644 index 00000000..f5454a6e --- /dev/null +++ b/libs/jpeg6/jutils.cpp @@ -0,0 +1,350 @@ +/* + + * jutils.c + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains tables and miscellaneous utility routines needed + + * for both compression and decompression. + + * Note we prefix all global names with "j" to minimize conflicts with + + * a surrounding application. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* + + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + + * of a DCT block read in natural order (left to right, top to bottom). + + */ + + + +const int jpeg_zigzag_order[DCTSIZE2] = { + + 0, 1, 5, 6, 14, 15, 27, 28, + + 2, 4, 7, 13, 16, 26, 29, 42, + + 3, 8, 12, 17, 25, 30, 41, 43, + + 9, 11, 18, 24, 31, 40, 44, 53, + + 10, 19, 23, 32, 39, 45, 52, 54, + + 20, 22, 33, 38, 46, 51, 55, 60, + + 21, 34, 37, 47, 50, 56, 59, 61, + + 35, 36, 48, 49, 57, 58, 62, 63 + +}; + + + +/* + + * jpeg_natural_order[i] is the natural-order position of the i'th element + + * of zigzag order. + + * + + * When reading corrupted data, the Huffman decoders could attempt + + * to reference an entry beyond the end of this array (if the decoded + + * zero run length reaches past the end of the block). To prevent + + * wild stores without adding an inner-loop test, we put some extra + + * "63"s after the real entries. This will cause the extra coefficient + + * to be stored in location 63 of the block, not somewhere random. + + * The worst case would be a run-length of 15, which means we need 16 + + * fake entries. + + */ + + + +const int jpeg_natural_order[DCTSIZE2+16] = { + + 0, 1, 8, 16, 9, 2, 3, 10, + + 17, 24, 32, 25, 18, 11, 4, 5, + + 12, 19, 26, 33, 40, 48, 41, 34, + + 27, 20, 13, 6, 7, 14, 21, 28, + + 35, 42, 49, 56, 57, 50, 43, 36, + + 29, 22, 15, 23, 30, 37, 44, 51, + + 58, 59, 52, 45, 38, 31, 39, 46, + + 53, 60, 61, 54, 47, 55, 62, 63, + + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + + 63, 63, 63, 63, 63, 63, 63, 63 + +}; + + + + + +/* + + * Arithmetic utilities + + */ + + + +GLOBAL long + +jdiv_round_up (long a, long b) + +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ + +/* Assumes a >= 0, b > 0 */ + +{ + + return (a + b - 1L) / b; + +} + + + + + +GLOBAL long + +jround_up (long a, long b) + +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ + +/* Assumes a >= 0, b > 0 */ + +{ + + a += b - 1L; + + return a - (a % b); + +} + + + + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + + * and coefficient-block arrays. This won't work on 80x86 because the arrays + + * are FAR and we're assuming a small-pointer memory model. However, some + + * DOS compilers provide far-pointer versions of memcpy() and memset() even + + * in the small-model libraries. These will be used if USE_FMEM is defined. + + * Otherwise, the routines below do it the hard way. (The performance cost + + * is not all that great, because these routines aren't very heavily used.) + + */ + + + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ + +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) + +#define FMEMZERO(target,size) MEMZERO(target,size) + +#else /* 80x86 case, define if we can */ + +#ifdef USE_FMEM + +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) + +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) + +#endif + +#endif + + + + + +GLOBAL void + +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + + JSAMPARRAY output_array, int dest_row, + + int num_rows, JDIMENSION num_cols) + +/* Copy some rows of samples from one place to another. + + * num_rows rows are copied from input_array[source_row++] + + * to output_array[dest_row++]; these areas may overlap for duplication. + + * The source and destination arrays must be at least as wide as num_cols. + + */ + +{ + + register JSAMPROW inptr, outptr; + +#ifdef FMEMCOPY + + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); + +#else + + register JDIMENSION count; + +#endif + + register int row; + + + + input_array += source_row; + + output_array += dest_row; + + + + for (row = num_rows; row > 0; row--) { + + inptr = *input_array++; + + outptr = *output_array++; + +#ifdef FMEMCOPY + + FMEMCOPY(outptr, inptr, count); + +#else + + for (count = num_cols; count > 0; count--) + + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ + +#endif + + } + +} + + + + + +GLOBAL void + +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + + JDIMENSION num_blocks) + +/* Copy a row of coefficient blocks from one place to another. */ + +{ + +#ifdef FMEMCOPY + + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); + +#else + + register JCOEFPTR inptr, outptr; + + register long count; + + + + inptr = (JCOEFPTR) input_row; + + outptr = (JCOEFPTR) output_row; + + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + + *outptr++ = *inptr++; + + } + +#endif + +} + + + + + +GLOBAL void + +jzero_far (void FAR * target, size_t bytestozero) + +/* Zero out a chunk of FAR memory. */ + +/* This might be sample-array data, block-array data, or alloc_large data. */ + +{ + +#ifdef FMEMZERO + + FMEMZERO(target, bytestozero); + +#else + + register char FAR * ptr = (char FAR *) target; + + register size_t count; + + + + for (count = bytestozero; count > 0; count--) { + + *ptr++ = 0; + + } + +#endif + +} + diff --git a/libs/jpeg6/jversion.h b/libs/jpeg6/jversion.h new file mode 100644 index 00000000..784a088c --- /dev/null +++ b/libs/jpeg6/jversion.h @@ -0,0 +1,28 @@ +/* + + * jversion.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains software version identification. + + */ + + + + + +#define JVERSION "6 2-Aug-95" + + + +#define JCOPYRIGHT "Copyright (C) 1995, Thomas G. Lane" + diff --git a/libs/jpeglib.h b/libs/jpeglib.h new file mode 100644 index 00000000..7dece342 --- /dev/null +++ b/libs/jpeglib.h @@ -0,0 +1,1123 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * jpeglib.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +// LZ: linux stuff +#if defined (__linux__) || defined (__APPLE__) + +#include +#include + +#ifndef boolean +#ifdef __cplusplus +#define boolean bool +#else +typedef int boolean; +#endif +#endif + +#endif + +#ifdef __MACOS__ + +// JDC: stuff to make mac version compile +#define boolean qboolean +#define register +#define INT32 int + +#endif + +// rad additions +// 11.29.99 + +//#include "cmdlib.h" +#ifdef _WIN32 +#include "windows.h" +#include "stdio.h" +#endif + +#ifndef INT32 +#define INT32 int +#endif + +// TTimo: if LoadJPGBuff returns -1, *pic is the error message +extern int LoadJPGBuff(unsigned char *fbuffer, int bufsize, unsigned char **pic, int *width, int *height ); +// rad end + + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jpeg6/jconfig.h" /* widely used configuration options */ +#endif +#include "jpeg6/jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 60 /* Version 6 */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This field directly represents the contents of a JPEG DQT marker. + * Note: the values are always given in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is not currently used by the compressor. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + boolean is_decompressor; /* so common code can tell which is which */\ + int global_state /* for checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker: */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_create_compress jCreaCompress +#define jpeg_create_decompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN struct jpeg_error_mgr *jpeg_std_error JPP((struct jpeg_error_mgr *err)); + +/* Initialization and destruction of JPEG compression objects */ +/* NB: you must set up the error-manager BEFORE calling jpeg_create_xxx */ +EXTERN void jpeg_create_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_create_decompress JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN void jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN void jpeg_stdio_src JPP((j_decompress_ptr cinfo, unsigned char *infile, int bufsize)); + +/* Default parameter setup for compression */ +EXTERN void jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN void jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN void jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN void jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN void jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN int jpeg_quality_scaling JPP((int quality)); +EXTERN void jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN JQUANT_TBL * jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN JHUFF_TBL * jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN void jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN JDIMENSION jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN void jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN JDIMENSION jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN void jpeg_write_marker JPP((j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN void jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN int jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN boolean jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN JDIMENSION jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN boolean jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN JDIMENSION jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN boolean jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN boolean jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN boolean jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN boolean jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN int jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN void jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN void jpeg_set_marker_processor JPP((j_decompress_ptr cinfo, + int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN jvirt_barray_ptr * jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN void jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN void jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN void jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN void jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN boolean jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* JPEGLIB_H */ diff --git a/libs/l_net/.cvsignore b/libs/l_net/.cvsignore new file mode 100644 index 00000000..877bc8c4 --- /dev/null +++ b/libs/l_net/.cvsignore @@ -0,0 +1,5 @@ +Debug +Release +*.plg +*.BAK +.consign diff --git a/libs/l_net/l_net.c b/libs/l_net/l_net.c new file mode 100644 index 00000000..fed856b5 --- /dev/null +++ b/libs/l_net/l_net.c @@ -0,0 +1,627 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//==================================================================== +// +// Name: l_net.c +// Function: - +// Programmer: MrElusive +// Last update: - +// Tab size: 3 +// Notes: +//==================================================================== + +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" + +#define GetMemory malloc +#define FreeMemory free + +#define qtrue 1 +#define qfalse 0 + +#ifdef _DEBUG +void WinPrint(char *str, ...) +{ + va_list argptr; + char text[4096]; + + va_start (argptr,str); + vsprintf (text, str, argptr); + va_end (argptr); + + printf(text); +} +#else +void WinPrint(char *str, ...) +{ +} +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_SetAddressPort(address_t *address, int port) +{ + sockaddr_t addr; + + WINS_StringToAddr(address->ip, &addr); + WINS_SetSocketPort(&addr, port); + strcpy(address->ip, WINS_AddrToString(&addr)); +} //end of the function Net_SetAddressPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_AddressCompare(address_t *addr1, address_t *addr2) +{ +#ifdef _WIN32 + return stricmp(addr1->ip, addr2->ip); +#endif +#ifdef __linux__ + return strcasecmp(addr1->ip, addr2->ip); +#endif +} //end of the function Net_AddressCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_SocketToAddress(socket_t *sock, address_t *address) +{ + strcpy(address->ip, WINS_AddrToString(&sock->addr)); +} //end of the function Net_SocketToAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Send(socket_t *sock, netmessage_t *msg) +{ + int size; + + size = msg->size; + msg->size = 0; + NMSG_WriteLong(msg, size-4); + msg->size = size; + //WinPrint("Net_Send: message of size %d\n", sendmsg.size); + return WINS_Write(sock->socket, msg->data, msg->size, NULL); +} //end of the function Net_SendSocketReliable +//=========================================================================== +// returns the number of bytes recieved +// -1 on error +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Receive(socket_t *sock, netmessage_t *msg) +{ + int curread; + + if (sock->remaining > 0) + { + curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); + if (curread == -1) + { + WinPrint("Net_Receive: read error\n"); + return -1; + } //end if + sock->remaining -= curread; + sock->msg.size += curread; + if (sock->remaining <= 0) + { + sock->remaining = 0; + memcpy(msg, &sock->msg, sizeof(netmessage_t)); + sock->msg.size = 0; + return msg->size - 4; + } //end if + return 0; + } //end if + sock->msg.size = WINS_Read(sock->socket, sock->msg.data, 4, NULL); + if (sock->msg.size == 0) return 0; + if (sock->msg.size == -1) + { + WinPrint("Net_Receive: size header read error\n"); + return -1; + } //end if + //WinPrint("Net_Receive: message size header %d\n", msg->size); + sock->msg.read = 0; + sock->remaining = NMSG_ReadLong(&sock->msg); + if (sock->remaining == 0) return 0; + if (sock->remaining < 0 || sock->remaining > MAX_NETMESSAGE) + { + WinPrint("Net_Receive: invalid message size %d\n", sock->remaining); + return -1; + } //end if + //try to read the message + curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); + if (curread == -1) + { + WinPrint("Net_Receive: read error\n"); + return -1; + } //end if + sock->remaining -= curread; + sock->msg.size += curread; + if (sock->remaining <= 0) + { + sock->remaining = 0; + memcpy(msg, &sock->msg, sizeof(netmessage_t)); + sock->msg.size = 0; + return msg->size - 4; + } //end if + //the message has not been completely read yet +#ifdef _DEBUG + printf("++timo TODO: debug the Net_Receive on big size messages\n"); +#endif + return 0; +} //end of the function Net_Receive +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_AllocSocket(void) +{ + socket_t *sock; + + sock = (socket_t *) GetMemory(sizeof(socket_t)); + memset(sock, 0, sizeof(socket_t)); + return sock; +} //end of the function Net_AllocSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_FreeSocket(socket_t *sock) +{ + FreeMemory(sock); +} //end of the function Net_FreeSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_Connect(address_t *address, int port) +{ + int newsock; + socket_t *sock; + sockaddr_t sendaddr; + + // see if we can resolve the host name + WINS_StringToAddr(address->ip, &sendaddr); + + newsock = WINS_OpenReliableSocket(port); + if (newsock == -1) return NULL; + + sock = Net_AllocSocket(); + if (sock == NULL) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock->socket = newsock; + + //connect to the host + if (WINS_Connect(newsock, &sendaddr) == -1) + { + Net_FreeSocket(sock); + WINS_CloseSocket(newsock); + WinPrint("Net_Connect: error connecting\n"); + return NULL; + } //end if + + memcpy(&sock->addr, &sendaddr, sizeof(sockaddr_t)); + //now we can send messages + // + return sock; +} //end of the function Net_Connect + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_ListenSocket(int port) +{ + int newsock; + socket_t *sock; + + newsock = WINS_OpenReliableSocket(port); + if (newsock == -1) return NULL; + + if (WINS_Listen(newsock) == -1) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock = Net_AllocSocket(); + if (sock == NULL) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock->socket = newsock; + WINS_GetSocketAddr(newsock, &sock->addr); + WinPrint("listen socket opened at %s\n", WINS_AddrToString(&sock->addr)); + // + return sock; +} //end of the function Net_ListenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_Accept(socket_t *sock) +{ + int newsocket; + sockaddr_t sendaddr; + socket_t *newsock; + + newsocket = WINS_Accept(sock->socket, &sendaddr); + if (newsocket == -1) return NULL; + + newsock = Net_AllocSocket(); + if (newsock == NULL) + { + WINS_CloseSocket(newsocket); + return NULL; + } //end if + newsock->socket = newsocket; + memcpy(&newsock->addr, &sendaddr, sizeof(sockaddr_t)); + // + return newsock; +} //end of the function Net_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_Disconnect(socket_t *sock) +{ + WINS_CloseSocket(sock->socket); + Net_FreeSocket(sock); +} //end of the function Net_Disconnect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_StringToAddress(char *string, address_t *address) +{ + strcpy(address->ip, string); +} //end of the function Net_StringToAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_MyAddress(address_t *address) +{ + strcpy(address->ip, WINS_MyAddress()); +} //end of the function Net_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Setup(void) +{ + WINS_Init(); + // + WinPrint("my address is %s\n", WINS_MyAddress()); + // + return qtrue; +} //end of the function Net_Setup +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_Shutdown(void) +{ + WINS_Shutdown(); +} //end of the function Net_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_Clear(netmessage_t *msg) +{ + msg->size = 4; +} //end of the function NMSG_Clear +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteChar (netmessage_t *msg, int c) +{ + if (c < -128 || c > 127) + WinPrint("NMSG_WriteChar: range error\n"); + + if (msg->size >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteChar: overflow\n"); + return; + } //end if + msg->data[msg->size] = c; + msg->size++; +} //end of the function NMSG_WriteChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteByte(netmessage_t *msg, int c) +{ + if (c < -128 || c > 127) + WinPrint("NMSG_WriteByte: range error\n"); + + if (msg->size + 1 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteByte: overflow\n"); + return; + } //end if + msg->data[msg->size] = c; + msg->size++; +} //end of the function NMSG_WriteByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteShort(netmessage_t *msg, int c) +{ + if (c < ((short)0x8000) || c > (short)0x7fff) + WinPrint("NMSG_WriteShort: range error"); + + if (msg->size + 2 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteShort: overflow\n"); + return; + } //end if + msg->data[msg->size] = c&0xff; + msg->data[msg->size+1] = c>>8; + msg->size += 2; +} //end of the function NMSG_WriteShort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteLong(netmessage_t *msg, int c) +{ + if (msg->size + 4 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteLong: overflow\n"); + return; + } //end if + msg->data[msg->size] = c&0xff; + msg->data[msg->size+1] = (c>>8)&0xff; + msg->data[msg->size+2] = (c>>16)&0xff; + msg->data[msg->size+3] = c>>24; + msg->size += 4; +} //end of the function NMSG_WriteLong +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteFloat(netmessage_t *msg, float c) +{ + if (msg->size + 4 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteLong: overflow\n"); + return; + } //end if + msg->data[msg->size] = *((int *)&c)&0xff; + msg->data[msg->size+1] = (*((int *)&c)>>8)&0xff; + msg->data[msg->size+2] = (*((int *)&c)>>16)&0xff; + msg->data[msg->size+3] = *((int *)&c)>>24; + msg->size += 4; +} //end of the function NMSG_WriteFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteString(netmessage_t *msg, char *string) +{ + if (msg->size + strlen(string) + 1 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteString: overflow\n"); + return; + } //end if + strcpy(&msg->data[msg->size], string); + msg->size += strlen(string) + 1; +} //end of the function NMSG_WriteString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_ReadStart(netmessage_t *msg) +{ + msg->readoverflow = qfalse; + msg->read = 4; +} //end of the function NMSG_ReadStart +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadChar(netmessage_t *msg) +{ + if (msg->size + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadChar: read overflow\n"); + return 0; + } //end if + msg->read++; + return msg->data[msg->read-1]; +} //end of the function NMSG_ReadChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadByte(netmessage_t *msg) +{ + if (msg->read + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadByte: read overflow\n"); + return 0; + } //end if + msg->read++; + return msg->data[msg->read-1]; +} //end of the function NMSG_ReadByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadShort(netmessage_t *msg) +{ + int c; + + if (msg->read + 2 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadShort: read overflow\n"); + return 0; + } //end if + c = (short)(msg->data[msg->read] + (msg->data[msg->read+1]<<8)); + msg->read += 2; + return c; +} //end of the function NMSG_ReadShort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadLong(netmessage_t *msg) +{ + int c; + + if (msg->read + 4 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadLong: read overflow\n"); + return 0; + } //end if + c = msg->data[msg->read] + + (msg->data[msg->read+1]<<8) + + (msg->data[msg->read+2]<<16) + + (msg->data[msg->read+3]<<24); + msg->read += 4; + return c; +} //end of the function NMSG_ReadLong +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float NMSG_ReadFloat(netmessage_t *msg) +{ + int c; + + if (msg->read + 4 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadLong: read overflow\n"); + return 0; + } //end if + c = msg->data[msg->read] + + (msg->data[msg->read+1]<<8) + + (msg->data[msg->read+2]<<16) + + (msg->data[msg->read+3]<<24); + msg->read += 4; + return *(float *)&c; +} //end of the function NMSG_ReadFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *NMSG_ReadString(netmessage_t *msg) +{ + static char string[2048]; + int l, c; + + l = 0; + do + { + if (msg->read + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadString: read overflow\n"); + string[l] = 0; + return string; + } //end if + c = msg->data[msg->read]; + msg->read++; + if (c == 0) break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + string[l] = 0; + return string; +} //end of the function NMSG_ReadString diff --git a/libs/l_net/l_net.h b/libs/l_net/l_net.h new file mode 100644 index 00000000..dd27d38b --- /dev/null +++ b/libs/l_net/l_net.h @@ -0,0 +1,125 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//==================================================================== +// +// Name: l_net.h +// Function: - +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab size: 2 +// Notes: +//==================================================================== + +//++timo FIXME: the l_net code understands that as the max size for the netmessage_s structure +// we have defined unsigned char data[MAX_NETMESSAGE] in netmessage_s but actually it cannot be filled completely +// we need to introduce a new #define and adapt to data[MAX_NETBUFFER] +#define MAX_NETMESSAGE 1024 +#define MAX_NETADDRESS 32 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum { qfalse, qtrue } qboolean; +typedef unsigned char byte; +#endif + +typedef struct address_s +{ + char ip[MAX_NETADDRESS]; +} address_t; + +typedef struct sockaddr_s +{ + short sa_family; + unsigned char sa_data[14]; +} sockaddr_t; + +typedef struct netmessage_s +{ + unsigned char data[MAX_NETMESSAGE]; + int size; + int read; + int readoverflow; +} netmessage_t; + +typedef struct socket_s +{ + int socket; //socket number + sockaddr_t addr; //socket address + netmessage_t msg; //current message being read + int remaining; //remaining bytes to read for the current message + struct socket_s *prev, *next; //prev and next socket in a list +} socket_t; + +//compare addresses +int Net_AddressCompare(address_t *addr1, address_t *addr2); +//gives the address of a socket +void Net_SocketToAddress(socket_t *sock, address_t *address); +//converts a string to an address +void Net_StringToAddress(char *string, address_t *address); +//set the address ip port +void Net_SetAddressPort(address_t *address, int port); +//send a message to the given socket +int Net_Send(socket_t *sock, netmessage_t *msg); +//recieve a message from the given socket +int Net_Receive(socket_t *sock, netmessage_t *msg); +//connect to a host +// NOTE: port is the localhost port, usually 0 +// ex: Net_Connect( "192.168.0.1:39000", 0 ) +socket_t *Net_Connect(address_t *address, int port); +//disconnect from a host +void Net_Disconnect(socket_t *sock); +//returns the local address +void Net_MyAddress(address_t *address); +//listen at the given port +socket_t *Net_ListenSocket(int port); +//accept new connections at the given socket +socket_t *Net_Accept(socket_t *sock); +//setup networking +int Net_Setup(void); +//shutdown networking +void Net_Shutdown(void); +//message handling +void NMSG_Clear(netmessage_t *msg); +void NMSG_WriteChar(netmessage_t *msg, int c); +void NMSG_WriteByte(netmessage_t *msg, int c); +void NMSG_WriteShort(netmessage_t *msg, int c); +void NMSG_WriteLong(netmessage_t *msg, int c); +void NMSG_WriteFloat(netmessage_t *msg, float c); +void NMSG_WriteString(netmessage_t *msg, char *string); +void NMSG_ReadStart(netmessage_t *msg); +int NMSG_ReadChar(netmessage_t *msg); +int NMSG_ReadByte(netmessage_t *msg); +int NMSG_ReadShort(netmessage_t *msg); +int NMSG_ReadLong(netmessage_t *msg); +float NMSG_ReadFloat(netmessage_t *msg); +char *NMSG_ReadString(netmessage_t *msg); + +//++timo FIXME: the WINS_ things are not necessary, they can be made portable arther easily +char *WINS_ErrorMessage(int error); + +#ifdef __cplusplus +} +#endif diff --git a/libs/l_net/l_net.vcproj b/libs/l_net/l_net.vcproj new file mode 100644 index 00000000..b9ff7052 --- /dev/null +++ b/libs/l_net/l_net.vcproj @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/l_net/l_net_berkley.c b/libs/l_net/l_net_berkley.c new file mode 100644 index 00000000..60912aee --- /dev/null +++ b/libs/l_net/l_net_berkley.c @@ -0,0 +1,770 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.c +// Function: WinSock +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab Size: 2 +// Notes: +//=========================================================================== + +//#include +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 + +extern void WinPrint(char *str, ...); + +#define WinError WinPrint + +#define qtrue 1 +#define qfalse 0 + +#define ioctlsocket ioctl +#define closesocket close + +int WSAGetLastError() +{ + return errno; +} + +/* +typedef struct tag_error_struct +{ + int errnum; + LPSTR errstr; +} ERROR_STRUCT; +*/ + +typedef struct tag_error_struct +{ + int errnum; + const char *errstr; +} ERROR_STRUCT; + +#define NET_NAMELEN 64 + +static char my_tcpip_address[NET_NAMELEN]; + +#define DEFAULTnet_hostport 26000 + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_hostport; // udp port number for acceptsocket +static int net_broadcastsocket = 0; +//static qboolean ifbcastinit = qfalse; +//static struct sockaddr_s broadcastaddr; +static struct sockaddr_s broadcastaddr; + +static unsigned long myAddr; + +ERROR_STRUCT errlist[] = { + {EACCES,"EACCES - The address is protected, user is not root"}, + {EAGAIN,"EAGAIN - Operation on non-blocking socket that cannot return immediatly"}, + {EBADF, "EBADF - sockfd is not a valid descriptor"}, + {EFAULT, "EFAULT - The parameter is not in a writable part of the user address space"}, + {EINVAL,"EINVAL - The socket is already bound to an address"}, + {ENOBUFS,"ENOBUFS - not enough memory"}, + {ENOMEM, "ENOMEM - not enough memory"}, + {ENOTCONN, "ENOTCONN - not connected"}, + {ENOTSOCK,"ENOTSOCK - Argument is file descriptor not a socket"}, + {EOPNOTSUPP,"ENOTSUPP - The referenced socket is not of type SOCK_STREAM"}, + {EPERM, "EPERM - Firewall rules forbid connection"}, + {-1, NULL} +}; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_ErrorMessage(int error) +{ + int search = 0; + + if (!error) return "No error occurred"; + + for (search = 0; errlist[search].errstr; search++) + { + if (error == errlist[search].errnum) + return (char *)errlist[search].errstr; + } //end for + + return "Unknown error"; +} //end of the function WINS_ErrorMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Init(void) +{ + int i; + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct sockaddr_s addr; + char *p; + int r; +/* + linux doesn't have anything to initialize for the net + "Windows .. built for the internet .. the internet .. built with unix" + */ +#if 0 + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(2, 2); + + r = WSAStartup (wVersionRequested, &winsockdata); + + if (r) + { + WinPrint("Winsock initialization failed.\n"); + return -1; + } +#endif + /* + i = COM_CheckParm ("-udpport"); + if (i == 0)*/ + net_hostport = DEFAULTnet_hostport; + /* + else if (i < com_argc-1) + net_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("WINS_Init: you must specify a number after -udpport"); + */ + + // determine my name & address + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name +// if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } +// Cvar_Set ("hostname", buff); + } + + //++timo WTF is that net_controlsocket? it's sole purpose is to retrieve the local IP? + if ((net_controlsocket = WINS_OpenSocket (0)) == SOCKET_ERROR) + WinError("WINS_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); + + WINS_GetSocketAddr (net_controlsocket, &addr); + strcpy(my_tcpip_address, WINS_AddrToString (&addr)); + p = strrchr (my_tcpip_address, ':'); + if (p) *p = 0; + WinPrint("Winsock Initialized\n"); + + return net_controlsocket; +} //end of the function WINS_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_MyAddress(void) +{ + return my_tcpip_address; +} //end of the function WINS_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void WINS_Shutdown(void) +{ + //WINS_Listen(0); + WINS_CloseSocket(net_controlsocket); +// WSACleanup(); + // + WinPrint("Winsock Shutdown\n"); +} //end of the function WINS_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +void WINS_Listen(int state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + WinError ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} //end of the function WINS_Listen*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((u_short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + return newsocket; +} //end of the function WINS_OpenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenReliableSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _true = 0xFFFFFFFF; + + //IPPROTO_TCP + // + if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_port = htons((u_short)port); + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + + return newsocket; +} //end of the function WINS_OpenReliableSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Listen(int socket) +{ + u_long _true = 1; + + if (ioctlsocket(socket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (listen(socket, SOMAXCONN) == SOCKET_ERROR) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Listen +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Accept(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int newsocket; + qboolean _true = 1; + + newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); + if (newsocket == INVALID_SOCKET) + { + if (errno == EAGAIN) return -1; + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + return newsocket; +} //end of the function WINS_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CloseSocket(int socket) +{ + /* + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + */ +// shutdown(socket, SD_SEND); + + if (closesocket(socket) == SOCKET_ERROR) + { + WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return SOCKET_ERROR; + } //end if + return 0; +} //end of the function WINS_CloseSocket +//=========================================================================== +// this lets you type only as much of the net address as required, using +// the local network components to fill in the rest +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + num = 0; + if (*++b < '0' || *b > '9') return -1; + while (!( *b < '0' || *b > '9')) + num = num*10 + *(b++) - '0'; + mask<<=8; + addr = (addr<<8) + num; + } + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} //end of the function PartialIPAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Connect(int socket, struct sockaddr_s *addr) +{ + int ret; + u_long _true2 = 0xFFFFFFFF; + + ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (ioctlsocket(socket, FIONBIO, &_true2) == -1) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Connect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CheckNewConnections(void) +{ + char buf[4]; + + if (net_acceptsocket == -1) + return -1; + + if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) + return net_acceptsocket; + return -1; +} //end of the function WINS_CheckNewConnections +//=========================================================================== +// returns the number of bytes read +// 0 if no bytes available +// -1 on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int ret; + + if (addr) + { + ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { +// errno = WSAGetLastError(); + + if (errno == EAGAIN || errno == ENOTCONN) + return 0; + } //end if + } //end if + else + { + ret = recv(socket, buf, len, 0); + // if there's no data on the socket ret == -1 and errno == EAGAIN + // MSDN states that if ret == 0 the socket has been closed + // man recv doesn't say anything + if (ret == 0) + return -1; + if (ret == SOCKET_ERROR) + { +// errno = WSAGetLastError(); + + if (errno == EAGAIN || errno == ENOTCONN) + return 0; + } //end if + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return ret; +} //end of the function WINS_Read +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} //end of the function WINS_MakeSocketBroadcastCapable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + WinError("Attempted to use multiple broadcasts sockets\n"); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + WinPrint("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} //end of the function WINS_Broadcast +//=========================================================================== +// returns qtrue on success or qfalse on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int ret, written; + + if (addr) + { + written = 0; + while(written < len) + { + ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != EAGAIN) + return qfalse; + //++timo FIXME: what is this used for? +// Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end if + else + { + written = 0; + while(written < len) + { + ret = send(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != EAGAIN) + return qfalse; + //++timo FIXME: what is this used for? +// Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return (ret == len); +} //end of the function WINS_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_AddrToString (struct sockaddr_s *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} //end of the function WINS_AddrToString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_StringToAddr(char *string, struct sockaddr_s *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); + return 0; +} //end of the function WINS_StringToAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof(struct sockaddr_s); + unsigned int a; + + memset(addr, 0, sizeof(struct sockaddr_s)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} //end of the function WINS_GetSocketAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + strcpy (name, WINS_AddrToString (addr)); + return 0; +} //end of the function WINS_GetNameFromAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} //end of the function WINS_GetAddrFromName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} //end of the function WINS_AddrCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketPort (struct sockaddr_s *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} //end of the function WINS_GetSocketPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_SetSocketPort (struct sockaddr_s *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); + return 0; +} //end of the function WINS_SetSocketPort diff --git a/libs/l_net/l_net_wins.c b/libs/l_net/l_net_wins.c new file mode 100644 index 00000000..56ee6789 --- /dev/null +++ b/libs/l_net/l_net_wins.c @@ -0,0 +1,789 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.c +// Function: WinSock +// Programmer: MrElusive +// Last update: - +// Tab Size: 3 +// Notes: +//=========================================================================== + +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" +//#include +//#include "mpdosock.h" + +#define WinError WinPrint + +#define qtrue 1 +#define qfalse 0 + +typedef struct tag_error_struct +{ + int errnum; + LPSTR errstr; +} ERROR_STRUCT; + +#define NET_NAMELEN 64 + +char my_tcpip_address[NET_NAMELEN]; + +#define DEFAULTnet_hostport 26000 + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_hostport; // udp port number for acceptsocket +static int net_broadcastsocket = 0; +//static qboolean ifbcastinit = qfalse; +static struct sockaddr_s broadcastaddr; + +static unsigned long myAddr; + +WSADATA winsockdata; + +ERROR_STRUCT errlist[] = { + {WSAEINTR, "WSAEINTR - Interrupted"}, + {WSAEBADF, "WSAEBADF - Bad file number"}, + {WSAEFAULT, "WSAEFAULT - Bad address"}, + {WSAEINVAL, "WSAEINVAL - Invalid argument"}, + {WSAEMFILE, "WSAEMFILE - Too many open files"}, + +/* +* Windows Sockets definitions of regular Berkeley error constants +*/ + + {WSAEWOULDBLOCK, "WSAEWOULDBLOCK - Socket marked as non-blocking"}, + {WSAEINPROGRESS, "WSAEINPROGRESS - Blocking call in progress"}, + {WSAEALREADY, "WSAEALREADY - Command already completed"}, + {WSAENOTSOCK, "WSAENOTSOCK - Descriptor is not a socket"}, + {WSAEDESTADDRREQ, "WSAEDESTADDRREQ - Destination address required"}, + {WSAEMSGSIZE, "WSAEMSGSIZE - Data size too large"}, + {WSAEPROTOTYPE, "WSAEPROTOTYPE - Protocol is of wrong type for this socket"}, + {WSAENOPROTOOPT, "WSAENOPROTOOPT - Protocol option not supported for this socket type"}, + {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT - Protocol is not supported"}, + {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT - Socket type not supported by this address family"}, + {WSAEOPNOTSUPP, "WSAEOPNOTSUPP - Option not supported"}, + {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT - "}, + {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT - Address family not supported by this protocol"}, + {WSAEADDRINUSE, "WSAEADDRINUSE - Address is in use"}, + {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL - Address not available from local machine"}, + {WSAENETDOWN, "WSAENETDOWN - Network subsystem is down"}, + {WSAENETUNREACH, "WSAENETUNREACH - Network cannot be reached"}, + {WSAENETRESET, "WSAENETRESET - Connection has been dropped"}, + {WSAECONNABORTED, "WSAECONNABORTED - Connection aborted"}, + {WSAECONNRESET, "WSAECONNRESET - Connection reset"}, + {WSAENOBUFS, "WSAENOBUFS - No buffer space available"}, + {WSAEISCONN, "WSAEISCONN - Socket is already connected"}, + {WSAENOTCONN, "WSAENOTCONN - Socket is not connected"}, + {WSAESHUTDOWN, "WSAESHUTDOWN - Socket has been shut down"}, + {WSAETOOMANYREFS, "WSAETOOMANYREFS - Too many references"}, + {WSAETIMEDOUT, "WSAETIMEDOUT - Command timed out"}, + {WSAECONNREFUSED, "WSAECONNREFUSED - Connection refused"}, + {WSAELOOP, "WSAELOOP - "}, + {WSAENAMETOOLONG, "WSAENAMETOOLONG - "}, + {WSAEHOSTDOWN, "WSAEHOSTDOWN - Host is down"}, + {WSAEHOSTUNREACH, "WSAEHOSTUNREACH - "}, + {WSAENOTEMPTY, "WSAENOTEMPTY - "}, + {WSAEPROCLIM, "WSAEPROCLIM - "}, + {WSAEUSERS, "WSAEUSERS - "}, + {WSAEDQUOT, "WSAEDQUOT - "}, + {WSAESTALE, "WSAESTALE - "}, + {WSAEREMOTE, "WSAEREMOTE - "}, + +/* +* Extended Windows Sockets error constant definitions +*/ + + {WSASYSNOTREADY, "WSASYSNOTREADY - Network subsystem not ready"}, + {WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED - Version not supported"}, + {WSANOTINITIALISED, "WSANOTINITIALISED - WSAStartup() has not been successfully called"}, + +/* +* Other error constants. +*/ + + {WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND - Host not found"}, + {WSATRY_AGAIN, "WSATRY_AGAIN - Host not found or SERVERFAIL"}, + {WSANO_RECOVERY, "WSANO_RECOVERY - Non-recoverable error"}, + {WSANO_DATA, "WSANO_DATA - (or WSANO_ADDRESS) - No data record of requested type"}, + {-1, NULL} +}; + +#ifdef _DEBUG +void WinPrint(char *str, ...); +#else +void WinPrint(char *str, ...); +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_ErrorMessage(int error) +{ + int search = 0; + + if (!error) return "No error occurred"; + + for (search = 0; errlist[search].errstr; search++) + { + if (error == errlist[search].errnum) + return errlist[search].errstr; + } //end for + + return "Unknown error"; +} //end of the function WINS_ErrorMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Init(void) +{ + int i; + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct sockaddr_s addr; + char *p; + int r; + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (wVersionRequested, &winsockdata); + + if (r) + { + WinPrint("Winsock initialization failed.\n"); + return -1; + } + + /* + i = COM_CheckParm ("-udpport"); + if (i == 0)*/ + net_hostport = DEFAULTnet_hostport; + /* + else if (i < com_argc-1) + net_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("WINS_Init: you must specify a number after -udpport"); + */ + + // determine my name & address + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name +// if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } +// Cvar_Set ("hostname", buff); + } + + if ((net_controlsocket = WINS_OpenSocket (0)) == -1) + WinError("WINS_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); + + WINS_GetSocketAddr (net_controlsocket, &addr); + strcpy(my_tcpip_address, WINS_AddrToString (&addr)); + p = strrchr (my_tcpip_address, ':'); + if (p) *p = 0; + WinPrint("Winsock Initialized\n"); + + return net_controlsocket; +} //end of the function WINS_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_MyAddress(void) +{ + return my_tcpip_address; +} //end of the function WINS_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void WINS_Shutdown(void) +{ + //WINS_Listen(0); + WINS_CloseSocket(net_controlsocket); + WSACleanup(); + // + WinPrint("Winsock Shutdown\n"); +} //end of the function WINS_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +void WINS_Listen(int state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + WinError ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} //end of the function WINS_Listen*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((u_short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + return newsocket; +} //end of the function WINS_OpenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenReliableSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + BOOL _true = 0xFFFFFFFF; + + //IPPROTO_TCP + // + if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_port = htons((u_short)port); + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + + return newsocket; +} //end of the function WINS_OpenReliableSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Listen(int socket) +{ + u_long _true = 1; + + if (ioctlsocket(socket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (listen(socket, SOMAXCONN) == SOCKET_ERROR) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Listen +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Accept(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int newsocket; + BOOL _true = 1; + + newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); + if (newsocket == INVALID_SOCKET) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) return -1; + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + return newsocket; +} //end of the function WINS_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CloseSocket(int socket) +{ + /* + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + */ +// shutdown(socket, SD_SEND); + + if (closesocket(socket) == SOCKET_ERROR) + { + WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return SOCKET_ERROR; + } //end if + return 0; +} //end of the function WINS_CloseSocket +//=========================================================================== +// this lets you type only as much of the net address as required, using +// the local network components to fill in the rest +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + num = 0; + if (*++b < '0' || *b > '9') return -1; + while (!( *b < '0' || *b > '9')) + num = num*10 + *(b++) - '0'; + mask<<=8; + addr = (addr<<8) + num; + } + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} //end of the function PartialIPAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Connect(int socket, struct sockaddr_s *addr) +{ + int ret; + u_long _true2 = 0xFFFFFFFF; + + ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (ioctlsocket(socket, FIONBIO, &_true2) == -1) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Connect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CheckNewConnections(void) +{ + char buf[4]; + + if (net_acceptsocket == -1) + return -1; + + if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) + return net_acceptsocket; + return -1; +} //end of the function WINS_CheckNewConnections +//=========================================================================== +// returns the number of bytes read +// 0 if no bytes available +// -1 on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int ret, errno; + + if (addr) + { + ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { + errno = WSAGetLastError(); + + if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + return 0; + } //end if + } //end if + else + { + ret = recv(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + errno = WSAGetLastError(); + + if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + return 0; + } //end if + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return ret; +} //end of the function WINS_Read +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} //end of the function WINS_MakeSocketBroadcastCapable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + WinError("Attempted to use multiple broadcasts sockets\n"); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + WinPrint("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} //end of the function WINS_Broadcast +//=========================================================================== +// returns qtrue on success or qfalse on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int ret, written; + + if (addr) + { + written = 0; + while(written < len) + { + ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return qfalse; + Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end if + else + { + written = 0; + while(written < len) + { + ret = send(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return qfalse; + Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return (ret == len); +} //end of the function WINS_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_AddrToString (struct sockaddr_s *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} //end of the function WINS_AddrToString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_StringToAddr(char *string, struct sockaddr_s *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); + return 0; +} //end of the function WINS_StringToAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof(struct sockaddr_s); + unsigned int a; + + memset(addr, 0, sizeof(struct sockaddr_s)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} //end of the function WINS_GetSocketAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + strcpy (name, WINS_AddrToString (addr)); + return 0; +} //end of the function WINS_GetNameFromAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} //end of the function WINS_GetAddrFromName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} //end of the function WINS_AddrCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketPort (struct sockaddr_s *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} //end of the function WINS_GetSocketPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_SetSocketPort (struct sockaddr_s *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); + return 0; +} //end of the function WINS_SetSocketPort diff --git a/libs/l_net/l_net_wins.h b/libs/l_net/l_net_wins.h new file mode 100644 index 00000000..0a06ea7a --- /dev/null +++ b/libs/l_net/l_net_wins.h @@ -0,0 +1,52 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.h +// Function: WinSock +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab Size: 3 +// Notes: +//=========================================================================== + +int WINS_Init(void); +void WINS_Shutdown(void); +char *WINS_MyAddress(void); +int WINS_Listen(int socket); +int WINS_Accept(int socket, struct sockaddr_s *addr); +int WINS_OpenSocket(int port); +int WINS_OpenReliableSocket(int port); +int WINS_CloseSocket(int socket); +int WINS_Connect (int socket, struct sockaddr_s *addr); +int WINS_CheckNewConnections(void); +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr); +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr); +int WINS_Broadcast (int socket, byte *buf, int len); +char *WINS_AddrToString (struct sockaddr_s *addr); +int WINS_StringToAddr (char *string, struct sockaddr_s *addr); +int WINS_GetSocketAddr (int socket, struct sockaddr_s *addr); +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name); +int WINS_GetAddrFromName (char *name, struct sockaddr_s *addr); +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2); +int WINS_GetSocketPort (struct sockaddr_s *addr); +int WINS_SetSocketPort (struct sockaddr_s *addr, int port); diff --git a/libs/mathlib.h b/libs/mathlib.h new file mode 100644 index 00000000..97fcf461 --- /dev/null +++ b/libs/mathlib.h @@ -0,0 +1,305 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h +#include + +#include "bytebool.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec5_t[5]; +typedef vec_t vec4_t[4]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +// plane types are used to speed some tests +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_NON_AXIAL 3 + +#define Q_PI 3.14159265358979323846f + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +#ifndef VEC_MAX +#define VEC_MAX 3.402823466e+38F +#endif + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorIncrement(a,b) ((b)[0]+=(a)[0],(b)[1]+=(a)[1],(b)[2]+=(a)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +#define VectorSet(v, a, b, c) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c)) +#define VectorScale(a,b,c) ((c)[0]=(b)*(a)[0],(c)[1]=(b)*(a)[1],(c)[2]=(b)*(a)[2]) +#define VectorMid(a,b,c) ((c)[0]=((a)[0]+(b)[0])*0.5f,(c)[1]=((a)[1]+(b)[1])*0.5f,(c)[2]=((a)[2]+(b)[2])*0.5f) +#define VectorNegative(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define CrossProduct(a,b,c) ((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]) +#define VectorClear(x) ((x)[0]=(x)[1]=(x)[2]=0) + +#define Q_rint(in) ((vec_t)floor(in+0.5)) + +vec_t VectorLength(vec3_t v); + +void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ); + +void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (const vec3_t in, vec3_t out); +vec_t ColorNormalize( const vec3_t in, vec3_t out ); +void VectorInverse (vec3_t v); +void VectorPolar(vec3_t v, float radius, float theta, float phi); + +// default snapping, to 1 +void VectorSnap(vec3_t v); + +// integer snapping +void VectorISnap(vec3_t point, int snap); + +// Gef: added snap to float for sub-integer grid sizes +// TTimo: we still use the int version of VectorSnap when possible +// to avoid potential rounding issues +// TTimo: renaming to VectorFSnap for C implementation +void VectorFSnap(vec3_t point, float snap); + +// NOTE: added these from Ritual's Q3Radiant +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void VectorToAngles( vec3_t vec, vec3_t angles ); + +#define ZERO_EPSILON 1.0E-6 +#define RAD2DEGMULT 57.29577951308232f +#define DEG2RADMULT 0.01745329251994329f +#define RAD2DEG( a ) ( (a) * RAD2DEGMULT ) +#define DEG2RAD( a ) ( (a) * DEG2RADMULT ) + +void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out); +void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out); + +// some function merged from tools mathlib code + +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ); +void NormalToLatLong( const vec3_t normal, byte bytes[2] ); +int PlaneTypeForNormal (vec3_t normal); +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); + +// Spog +// code imported from geomlib + +/*! +\todo +FIXME test calls such as intersect tests should be named test_ +*/ + +typedef vec_t m3x3_t[9]; +/*!NOTE +m4x4 looks like this.. + + x y z +x axis ( 0 1 2) +y axis ( 4 5 6) +z axis ( 8 9 10) +translation (12 13 14) +scale ( 0 5 10) +*/ +typedef vec_t m4x4_t[16]; + +#define M4X4_INDEX(m,row,col) (m[(col<<2)+row]) + +typedef enum { TRANSLATE, SCALE, ROTATE } transformtype; // legacy, used only in pmesh.cpp + +typedef enum { eXYZ, eYZX, eZXY, eXZY, eYXZ, eZYX } eulerOrder_t; + +// constructors +/*! create m4x4 as identity matrix */ +void m4x4_identity(m4x4_t matrix); +/*! create m4x4 as a translation matrix, for a translation vec3 */ +void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation); +/*! create m4x4 as a rotation matrix, for an euler angles (degrees) vec3 */ +void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); +/*! create m4x4 as a scaling matrix, for a scale vec3 */ +void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale); +/*! create m4x4 as a rotation matrix, for a quaternion vec4 */ +void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation); +/*! create m4x4 as a rotation matrix, for an axis vec3 and an angle (radians) */ +void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); + +// a valid m4x4 to be modified is always first argument +/*! translate m4x4 by a translation vec3 */ +void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation); +/*! rotate m4x4 by a euler (degrees) vec3 */ +void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); +/*! scale m4x4 by a scaling vec3 */ +void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale); +/*! rotate m4x4 by a quaternion vec4 */ +void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation); +/*! rotate m4x4 by an axis vec3 and an angle (radians) */ +void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); +/*! transform m4x4 by translation/euler/scaling vec3 (transform = translation.euler.scale) */ +void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale); +/*! rotate m4x4 around a pivot point by euler(degrees) vec3 */ +void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint); +/*! scale m4x4 around a pivot point by scaling vec3 */ +void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint); +/*! transform m4x4 around a pivot point by translation/euler/scaling vec3 */ +void m4x4_pivoted_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale, const vec3_t pivotpoint); +/*! rotate m4x4 around a pivot point by quaternion vec4 */ +void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint); +/*! rotate m4x4 around a pivot point by axis vec3 and angle (radians) */ +void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint); +/*! post-multiply m4x4 by another m4x4 */ +void m4x4_multiply_by_m4x4(m4x4_t matrix, const m4x4_t other); +/*! pre-multiply m4x4 by another m4x4 */ +void m4x4_premultiply_by_m4x4(m4x4_t matrix, const m4x4_t other); + +/*! multiply a point (x,y,z,1) by matrix */ +void m4x4_transform_point(const m4x4_t matrix, vec3_t point); +/*! multiply a normal (x,y,z,0) by matrix */ +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); +/*! multiply a vec4 (x,y,z,w) by matrix */ +void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector); + +/*! multiply a point (x,y,z,1) by matrix */ +void m4x4_transform_point(const m4x4_t matrix, vec3_t point); +/*! multiply a normal (x,y,z,0) by matrix */ +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); + +/*! transpose a m4x4 */ +void m4x4_transpose(m4x4_t matrix); +/*! invert an orthogonal 4x3 subset of a 4x4 matrix */ +void m4x4_orthogonal_invert(m4x4_t matrix); +/*! invert any m4x4 using Kramer's rule.. return 1 if matrix is singular, else return 0 */ +int m4x4_invert(m4x4_t matrix); + +/*! +\todo object/ray intersection functions should maybe return a point rather than a distance? +*/ + +/*! +aabb_t - "axis-aligned" bounding box... + origin: centre of bounding box... + extents: +/- extents of box from origin... + radius: cached length of extents vector... +*/ +typedef struct aabb_s +{ + vec3_t origin; + vec3_t extents; + vec_t radius; +} aabb_t; + +/*! +bbox_t - oriented bounding box... + aabb: axis-aligned bounding box... + axes: orientation axes... +*/ +typedef struct bbox_s +{ + aabb_t aabb; + vec3_t axes[3]; +} bbox_t; + +/*! +ray_t - origin point and direction unit-vector +*/ +typedef struct ray_s +{ + vec3_t origin; + vec3_t direction; +} ray_t; + + +/*! Generate AABB from min/max. */ +void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max); +/*! Update bounding-sphere radius. */ +void aabb_update_radius(aabb_t *aabb); +/*! Initialise AABB to negative size. */ +void aabb_clear(aabb_t *aabb); + +/*! Extend AABB to include point. */ +void aabb_extend_by_point(aabb_t *aabb, const vec3_t point); +/*! Extend AABB to include aabb_src. */ +void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src); +/*! Extend AABB by +/- extension vector. */ +void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension); + +/*! Return 2 if point is inside, else 1 if point is on surface, else 0. */ +int aabb_intersect_point(const aabb_t *aabb, const vec3_t point); +/*! Return 2 if aabb_src intersects, else 1 if aabb_src touches exactly, else 0. */ +int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src); +/*! Return 2 if aabb is behind plane, else 1 if aabb intersects plane, else 0. */ +int aabb_intersect_plane(const aabb_t *aabb, const float *plane); +/*! Return 1 if aabb intersects ray, else 0... dist = closest intersection. */ +int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist); +/*! Return 1 if aabb intersects ray, else 0. Faster, but does not provide point of intersection */ +int aabb_test_ray(const aabb_t* aabb, const ray_t* ray); + +/*! Generate AABB from oriented bounding box. */ +void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox); +/*! Generate AABB from 2-dimensions of min/max, specified by axis. */ +void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis); +/*! Generate AABB to contain src * transform. NOTE: transform must be orthogonal */ +void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform); + + +/*! Generate oriented bounding box from AABB and transformation matrix. */ +/*!\todo Remove need to specify euler/scale. */ +void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, + const m4x4_t matrix, const vec3_t euler, const vec3_t scale); +/*! Return 2 is bbox is behind plane, else return 1 if bbox intersects plane, else return 0. */ +int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane); + + +/*! Generate a ray from an origin point and a direction unit-vector */ +void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction); + +/*! Transform a ray */ +void ray_transform(ray_t *ray, const m4x4_t matrix); + +/*! return true if point intersects cone formed by ray, divergence and epsilon */ +vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence); +/*! return true if triangle intersects ray... dist = dist from intersection point to ray-origin */ +vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATHLIB__ */ diff --git a/libs/mathlib/bbox.c b/libs/mathlib/bbox.c new file mode 100644 index 00000000..510c4e7c --- /dev/null +++ b/libs/mathlib/bbox.c @@ -0,0 +1,391 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "mathlib.h" + +void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max) +{ + VectorMid(min, max, aabb->origin); + VectorSubtract(max, aabb->origin, aabb->extents); +} + +void aabb_update_radius(aabb_t *aabb) +{ + aabb->radius = VectorLength(aabb->extents); +} + +void aabb_clear(aabb_t *aabb) +{ + aabb->origin[0] = aabb->origin[1] = aabb->origin[2] = 0; + aabb->extents[0] = aabb->extents[1] = aabb->extents[2] = -FLT_MAX; +} + +void aabb_extend_by_point(aabb_t *aabb, const vec3_t point) +{ + int i; + vec_t min, max, displacement; + for(i=0; i<3; i++) + { + displacement = point[i] - aabb->origin[i]; + if(fabs(displacement) > aabb->extents[i]) + { + if(aabb->extents[i] < 0) // degenerate + { + min = max = point[i]; + } + else if(displacement > 0) + { + min = aabb->origin[i] - aabb->extents[i]; + max = aabb->origin[i] + displacement; + } + else + { + max = aabb->origin[i] + aabb->extents[i]; + min = aabb->origin[i] + displacement; + } + aabb->origin[i] = (min + max) * 0.5f; + aabb->extents[i] = max - aabb->origin[i]; + } + } +} + +void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src) +{ + int i; + vec_t min, max, displacement, difference; + for(i=0; i<3; i++) + { + displacement = aabb_src->origin[i] - aabb->origin[i]; + difference = aabb_src->extents[i] - aabb->extents[i]; + if(aabb->extents[i] < 0 + || difference >= fabs(displacement)) + { + // 2nd contains 1st + aabb->extents[i] = aabb_src->extents[i]; + aabb->origin[i] = aabb_src->origin[i]; + } + else if(aabb_src->extents[i] < 0 + || -difference >= fabs(displacement)) + { + // 1st contains 2nd + continue; + } + else + { + // not contained + if(displacement > 0) + { + min = aabb->origin[i] - aabb->extents[i]; + max = aabb_src->origin[i] + aabb_src->extents[i]; + } + else + { + min = aabb_src->origin[i] - aabb_src->extents[i]; + max = aabb->origin[i] + aabb->extents[i]; + } + aabb->origin[i] = (min + max) * 0.5f; + aabb->extents[i] = max - aabb->origin[i]; + } + } +} + +void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension) +{ + VectorAdd(aabb->extents, extension, aabb->extents); +} + +int aabb_intersect_point(const aabb_t *aabb, const vec3_t point) +{ + int i; + for(i=0; i<3; i++) + if(fabs(point[i] - aabb->origin[i]) >= aabb->extents[i]) + return 0; + return 1; +} + +int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src) +{ + int i; + for (i=0; i<3; i++) + if ( fabs(aabb_src->origin[i] - aabb->origin[i]) > (fabs(aabb->extents[i]) + fabs(aabb_src->extents[i])) ) + return 0; + return 1; +} + +int aabb_intersect_plane(const aabb_t *aabb, const float *plane) +{ + float fDist, fIntersect; + + // calc distance of origin from plane + fDist = DotProduct(plane, aabb->origin) + plane[3]; + + // trivial accept/reject using bounding sphere + if (fabs(fDist) > aabb->radius) + { + if (fDist < 0) + return 2; // totally inside + else + return 0; // totally outside + } + + // calc extents distance relative to plane normal + fIntersect = (vec_t)(fabs(plane[0] * aabb->extents[0]) + fabs(plane[1] * aabb->extents[1]) + fabs(plane[2] * aabb->extents[2])); + // accept if origin is less than or equal to this distance + if (fabs(fDist) < fIntersect) return 1; // partially inside + else if (fDist < 0) return 2; // totally inside + return 0; // totally outside +} + +/* +Fast Ray-Box Intersection +by Andrew Woo +from "Graphics Gems", Academic Press, 1990 +*/ + +#define NUMDIM 3 +#define RIGHT 0 +#define LEFT 1 +#define MIDDLE 2 + +int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist) +{ + int inside = 1; + char quadrant[NUMDIM]; + register int i; + int whichPlane; + double maxT[NUMDIM]; + double candidatePlane[NUMDIM]; + vec3_t coord, segment; + + const float *origin = ray->origin; + const float *direction = ray->direction; + + /* Find candidate planes; this loop can be avoided if + rays cast all from the eye(assume perpsective view) */ + for (i=0; iorigin[i] - aabb->extents[i])) + { + quadrant[i] = LEFT; + candidatePlane[i] = (aabb->origin[i] - aabb->extents[i]); + inside = 0; + } + else if (origin[i] > (aabb->origin[i] + aabb->extents[i])) + { + quadrant[i] = RIGHT; + candidatePlane[i] = (aabb->origin[i] + aabb->extents[i]); + inside = 0; + } + else + { + quadrant[i] = MIDDLE; + } + } + + /* Ray origin inside bounding box */ + if(inside == 1) + { + *dist = 0.0f; + return 1; + } + + + /* Calculate T distances to candidate planes */ + for (i = 0; i < NUMDIM; i++) + { + if (quadrant[i] != MIDDLE && direction[i] !=0.) + maxT[i] = (candidatePlane[i] - origin[i]) / direction[i]; + else + maxT[i] = -1.; + } + + /* Get largest of the maxT's for final choice of intersection */ + whichPlane = 0; + for (i = 1; i < NUMDIM; i++) + if (maxT[whichPlane] < maxT[i]) + whichPlane = i; + + /* Check final candidate actually inside box */ + if (maxT[whichPlane] < 0.) + return 0; + for (i = 0; i < NUMDIM; i++) + { + if (whichPlane != i) + { + coord[i] = (vec_t)(origin[i] + maxT[whichPlane] * direction[i]); + if (fabs(coord[i] - aabb->origin[i]) > aabb->extents[i]) + return 0; + } + else + { + coord[i] = (vec_t)candidatePlane[i]; + } + } + + VectorSubtract(coord, origin, segment); + *dist = DotProduct(segment, direction); + + return 1; /* ray hits box */ +} + +int aabb_test_ray(const aabb_t* aabb, const ray_t* ray) +{ + vec3_t displacement, ray_absolute; + vec_t f; + + displacement[0] = ray->origin[0] - aabb->origin[0]; + if(fabs(displacement[0]) > aabb->extents[0] && displacement[0] * ray->direction[0] >= 0.0f) + return 0; + + displacement[1] = ray->origin[1] - aabb->origin[1]; + if(fabs(displacement[1]) > aabb->extents[1] && displacement[1] * ray->direction[1] >= 0.0f) + return 0; + + displacement[2] = ray->origin[2] - aabb->origin[2]; + if(fabs(displacement[2]) > aabb->extents[2] && displacement[2] * ray->direction[2] >= 0.0f) + return 0; + + ray_absolute[0] = (float)fabs(ray->direction[0]); + ray_absolute[1] = (float)fabs(ray->direction[1]); + ray_absolute[2] = (float)fabs(ray->direction[2]); + + f = ray->direction[1] * displacement[2] - ray->direction[2] * displacement[1]; + if((float)fabs(f) > aabb->extents[1] * ray_absolute[2] + aabb->extents[2] * ray_absolute[1]) + return 0; + + f = ray->direction[2] * displacement[0] - ray->direction[0] * displacement[2]; + if((float)fabs(f) > aabb->extents[0] * ray_absolute[2] + aabb->extents[2] * ray_absolute[0]) + return 0; + + f = ray->direction[0] * displacement[1] - ray->direction[1] * displacement[0]; + if((float)fabs(f) > aabb->extents[0] * ray_absolute[1] + aabb->extents[1] * ray_absolute[0]) + return 0; + + return 1; +} + +void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox) +{ + int i; + vec3_t temp[3]; + + VectorCopy(bbox->aabb.origin, aabb->origin); + + // calculate the AABB extents in local coord space from the OBB extents and axes + VectorScale(bbox->axes[0], bbox->aabb.extents[0], temp[0]); + VectorScale(bbox->axes[1], bbox->aabb.extents[1], temp[1]); + VectorScale(bbox->axes[2], bbox->aabb.extents[2], temp[2]); + for(i=0;i<3;i++) aabb->extents[i] = (vec_t)(fabs(temp[0][i]) + fabs(temp[1][i]) + fabs(temp[2][i])); +} + +void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis) +{ + aabb_clear(aabb); + aabb->extents[axis] = FLT_MAX; + aabb_extend_by_point(aabb, area_tl); + aabb_extend_by_point(aabb, area_br); +} + +void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform) +{ + VectorCopy(src->origin, dst->origin); + m4x4_transform_point(transform, dst->origin); + + dst->extents[0] = (vec_t)(fabs(transform[0] * src->extents[0]) + + fabs(transform[4] * src->extents[1]) + + fabs(transform[8] * src->extents[2])); + dst->extents[1] = (vec_t)(fabs(transform[1] * src->extents[0]) + + fabs(transform[5] * src->extents[1]) + + fabs(transform[9] * src->extents[2])); + dst->extents[2] = (vec_t)(fabs(transform[2] * src->extents[0]) + + fabs(transform[6] * src->extents[1]) + + fabs(transform[10] * src->extents[2])); +} + + +void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, const m4x4_t matrix, const vec3_t euler, const vec3_t scale) +{ + double rad[3]; + double pi_180 = Q_PI / 180; + double A, B, C, D, E, F, AD, BD; + + VectorCopy(aabb->origin, bbox->aabb.origin); + + m4x4_transform_point(matrix, bbox->aabb.origin); + + bbox->aabb.extents[0] = aabb->extents[0] * scale[0]; + bbox->aabb.extents[1] = aabb->extents[1] * scale[1]; + bbox->aabb.extents[2] = aabb->extents[2] * scale[2]; + + rad[0] = euler[0] * pi_180; + rad[1] = euler[1] * pi_180; + rad[2] = euler[2] * pi_180; + + A = cos(rad[0]); + B = sin(rad[0]); + C = cos(rad[1]); + D = sin(rad[1]); + E = cos(rad[2]); + F = sin(rad[2]); + + AD = A * -D; + BD = B * -D; + + bbox->axes[0][0] = (vec_t)(C*E); + bbox->axes[0][1] = (vec_t)(-BD*E + A*F); + bbox->axes[0][2] = (vec_t)(AD*E + B*F); + bbox->axes[1][0] = (vec_t)(-C*F); + bbox->axes[1][1] = (vec_t)(BD*F + A*E); + bbox->axes[1][2] = (vec_t)(-AD*F + B*E); + bbox->axes[2][0] = (vec_t)D; + bbox->axes[2][1] = (vec_t)(-B*C); + bbox->axes[2][2] = (vec_t)(A*C); + + aabb_update_radius(&bbox->aabb); +} + +int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane) +{ + vec_t fDist, fIntersect; + + // calc distance of origin from plane + fDist = DotProduct(plane, bbox->aabb.origin) + plane[3]; + + // trivial accept/reject using bounding sphere + if (fabs(fDist) > bbox->aabb.radius) + { + if (fDist < 0) + return 2; // totally inside + else + return 0; // totally outside + } + + // calc extents distance relative to plane normal + fIntersect = (vec_t)(fabs(bbox->aabb.extents[0] * DotProduct(plane, bbox->axes[0])) + + fabs(bbox->aabb.extents[1] * DotProduct(plane, bbox->axes[1])) + + fabs(bbox->aabb.extents[2] * DotProduct(plane, bbox->axes[2]))); + // accept if origin is less than this distance + if (fabs(fDist) < fIntersect) return 1; // partially inside + else if (fDist < 0) return 2; // totally inside + return 0; // totally outside +} diff --git a/libs/mathlib/linear.c b/libs/mathlib/linear.c new file mode 100644 index 00000000..bdef7145 --- /dev/null +++ b/libs/mathlib/linear.c @@ -0,0 +1,100 @@ +#ifndef __APPLE__ +#include +#else +#include +#endif +#include +#include + +#include "mathlib.h" + +#define TINY FLT_MIN + +void lubksb(float **a, int n, int *indx, float b[]) +// Solves the set of n linear equations A.X=B. Here a[n][n] is input, not as the matrix +// A but rather as its LU decomposition determined by the routine ludcmp. indx[n] is input +// as the permutation vector returned by ludcmp. b[n] is input as the right-hand side vector +// B, and returns with the solution vector X. a, n and indx are not modified by this routine +// and can be left in place for successive calls with different right-hand sides b. This routine takes +// into account the possibility that b will begin with many zero elements, so it is efficient for use +// in matrix inversion +{ + int i,ii=-1,ip,j; + float sum; + + for (i=0;i=0) + for (j=ii;j=0;i--) { + sum=b[i]; + for (j=i+1;j big) big=temp; + if (big == 0.0) return 1; + vv[i]=1.0f/big; + } + for (j=0;j= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (k=0;k i ) + idst = ti-1; + + for ( tj = 0; tj < 4; tj++ ) + { + if ( tj < j ) + jdst = tj; + else + if ( tj > j ) + jdst = tj-1; + + if ( ti != i && tj != j ) + mb[idst*3 + jdst] = mr[ti*4 + tj ]; + } + } +} + +float m4_det( m4x4_t mr ) +{ + float det, result = 0, i = 1; + m3x3_t msub3; + int n; + + for ( n = 0; n < 4; n++, i *= -1 ) + { + m4_submat( mr, msub3, 0, n ); + + det = m3_det( msub3 ); + result += mr[n] * det * i; + } + + return result; +} + +int m4x4_invert(m4x4_t matrix) +{ + float mdet = m4_det( matrix ); + m3x3_t mtemp; + int i, j, sign; + m4x4_t m4x4_temp; + + if ( fabs( mdet ) < 0.0000000001 ) //% 0.0005 + return 1; + + memcpy(m4x4_temp, matrix, sizeof(m4x4_t)); + + for ( i = 0; i < 4; i++ ) + for ( j = 0; j < 4; j++ ) + { + sign = 1 - ( (i +j) % 2 ) * 2; + + m4_submat( m4x4_temp, mtemp, i, j ); + + matrix[i+j*4] = ( m3_det( mtemp ) * sign ) / mdet; + } + + return 0; +} diff --git a/libs/mathlib/mathlib.c b/libs/mathlib/mathlib.c new file mode 100644 index 00000000..0c26a963 --- /dev/null +++ b/libs/mathlib/mathlib.c @@ -0,0 +1,593 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// mathlib.c -- math primitives +#include "mathlib.h" +// we use memcpy and memset +#include + +vec3_t vec3_origin = {0.0f,0.0f,0.0f}; + +/* +================ +MakeNormalVectors + +Given a normalized forward vector, create two +other perpendicular vectors +================ +*/ +void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up) +{ + float d; + + // this rotate and negate guarantees a vector + // not colinear with the original + right[1] = -forward[0]; + right[2] = forward[1]; + right[0] = forward[2]; + + d = DotProduct (right, forward); + VectorMA (right, -d, forward, right); + VectorNormalize (right, right); + CrossProduct (right, forward, up); +} + +vec_t VectorLength(vec3_t v) +{ + int i; + float length; + + length = 0.0f; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = (float)sqrt (length); + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return qfalse; + + return qtrue; +} + +/* +// FIXME TTimo this implementation has to be particular to radiant +// through another name I'd say +vec_t Q_rint (vec_t in) +{ + if (g_PrefsDlg.m_bNoClamp) + return in; + else + return (float)floor (in + 0.5); +} +*/ + +void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +vec_t VectorNormalize( const vec3_t in, vec3_t out ) { + vec_t length, ilength; + + length = (vec_t)sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0f/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +vec_t ColorNormalize( const vec3_t in, vec3_t out ) { + float max, scale; + + max = in[0]; + if (in[1] > max) + max = in[1]; + if (in[2] > max) + max = in[2]; + + if (max == 0) { + out[0] = out[1] = out[2] = 1.0; + return 0; + } + + scale = 1.0f / max; + + VectorScale (in, scale, out); + + return max; +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +/* +void VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} +*/ + +void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out) +{ + vec3_t vWork, va; + int nIndex[3][2]; + int i; + + VectorCopy(vIn, va); + VectorCopy(va, vWork); + nIndex[0][0] = 1; nIndex[0][1] = 2; + nIndex[1][0] = 2; nIndex[1][1] = 0; + nIndex[2][0] = 0; nIndex[2][1] = 1; + + for (i = 0; i < 3; i++) + { + if (vRotation[i] != 0) + { + float dAngle = vRotation[i] * Q_PI / 180.0f; + float c = (vec_t)cos(dAngle); + float s = (vec_t)sin(dAngle); + vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s; + vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c; + } + VectorCopy(vWork, va); + } + VectorCopy(vWork, out); +} + +void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out) +{ + vec3_t vTemp, vTemp2; + + VectorSubtract(vIn, vOrigin, vTemp); + VectorRotate(vTemp, vRotation, vTemp2); + VectorAdd(vTemp2, vOrigin, out); +} + +void VectorPolar(vec3_t v, float radius, float theta, float phi) +{ + v[0]=(float)(radius * cos(theta) * cos(phi)); + v[1]=(float)(radius * sin(theta) * cos(phi)); + v[2]=(float)(radius * sin(phi)); +} + +void VectorSnap(vec3_t v) +{ + int i; + for (i = 0; i < 3; i++) + { + v[i] = (vec_t)floor (v[i] + 0.5); + } +} + +void VectorISnap(vec3_t point, int snap) +{ + int i; + for (i = 0 ;i < 3 ; i++) + { + point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; + } +} + +void VectorFSnap(vec3_t point, float snap) +{ + int i; + for (i = 0 ;i < 3 ; i++) + { + point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; + } +} + +void _Vector5Add (vec5_t va, vec5_t vb, vec5_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; + out[3] = va[3]+vb[3]; + out[4] = va[4]+vb[4]; +} + +void _Vector5Scale (vec5_t v, vec_t scale, vec5_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; + out[3] = v[3] * scale; + out[4] = v[4] * scale; +} + +void _Vector53Copy (vec5_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +// NOTE: added these from Ritual's Q3Radiant +void ClearBounds (vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} + +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over +#ifndef M_PI +#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h +#endif + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + static float sr, sp, sy, cr, cp, cy; + // static to help MS compiler fp bugs + + angle = angles[YAW] * (M_PI*2.0f / 360.0f); + sy = (vec_t)sin(angle); + cy = (vec_t)cos(angle); + angle = angles[PITCH] * (M_PI*2.0f / 360.0f); + sp = (vec_t)sin(angle); + cp = (vec_t)cos(angle); + angle = angles[ROLL] * (M_PI*2.0f / 360.0f); + sr = (vec_t)sin(angle); + cr = (vec_t)cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (right) + { + right[0] = -sr*sp*cy+cr*sy; + right[1] = -sr*sp*sy-cr*cy; + right[2] = -sr*cp; + } + if (up) + { + up[0] = cr*sp*cy+sr*sy; + up[1] = cr*sp*sy-sr*cy; + up[2] = cr*cp; + } +} + +void VectorToAngles( vec3_t vec, vec3_t angles ) +{ + float forward; + float yaw, pitch; + + if ( ( vec[ 0 ] == 0 ) && ( vec[ 1 ] == 0 ) ) + { + yaw = 0; + if ( vec[ 2 ] > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + yaw = (vec_t)atan2( vec[ 1 ], vec[ 0 ] ) * 180 / M_PI; + if ( yaw < 0 ) + { + yaw += 360; + } + + forward = ( float )sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] ); + pitch = (vec_t)atan2( vec[ 2 ], forward ) * 180 / M_PI; + if ( pitch < 0 ) + { + pitch += 360; + } + } + + angles[ 0 ] = pitch; + angles[ 1 ] = yaw; + angles[ 2 ] = 0; +} + +/* +===================== +PlaneFromPoints + +Returns false if the triangle is degenrate. +The normal will point out of the clock for clockwise ordered points +===================== +*/ +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) { + vec3_t d1, d2; + + VectorSubtract( b, a, d1 ); + VectorSubtract( c, a, d2 ); + CrossProduct( d2, d1, plane ); + if ( VectorNormalize( plane, plane ) == 0 ) { + return qfalse; + } + + plane[3] = DotProduct( a, plane ); + return qtrue; +} + +/* +** NormalToLatLong +** +** We use two byte encoded normals in some space critical applications. +** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format +** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format +** +*/ +void NormalToLatLong( const vec3_t normal, byte bytes[2] ) { + // check for singularities + if ( normal[0] == 0 && normal[1] == 0 ) { + if ( normal[2] > 0 ) { + bytes[0] = 0; + bytes[1] = 0; // lat = 0, long = 0 + } else { + bytes[0] = 128; + bytes[1] = 0; // lat = 0, long = 128 + } + } else { + int a, b; + + a = (int)( RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ) ); + a &= 0xff; + + b = (int)( RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ) ); + b &= 0xff; + + bytes[0] = b; // longitude + bytes[1] = a; // lattitude + } +} + +/* +================= +PlaneTypeForNormal +================= +*/ +int PlaneTypeForNormal (vec3_t normal) { + if (normal[0] == 1.0 || normal[0] == -1.0) + return PLANE_X; + if (normal[1] == 1.0 || normal[1] == -1.0) + return PLANE_Y; + if (normal[2] == 1.0 || normal[2] == -1.0) + return PLANE_Z; + + return PLANE_NON_AXIAL; +} + +/* +================ +MatrixMultiply +================ +*/ +void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) +{ + float d; + vec3_t n; + float inv_denom; + + inv_denom = 1.0F / DotProduct( normal, normal ); + + d = DotProduct( normal, p ) * inv_denom; + + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +/* +** assumes "src" is normalized +*/ +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ + int pos; + int i; + vec_t minelem = 1.0F; + vec3_t tempvec; + + /* + ** find the smallest magnitude axially aligned vector + */ + for ( pos = 0, i = 0; i < 3; i++ ) + { + if ( fabs( src[i] ) < minelem ) + { + pos = i; + minelem = (vec_t)fabs( src[i] ); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; + tempvec[pos] = 1.0F; + + /* + ** project the point onto the plane defined by src + */ + ProjectPointOnPlane( dst, tempvec, src ); + + /* + ** normalize the result + */ + VectorNormalize( dst, dst ); +} + +/* +=============== +RotatePointAroundVector + +This is not implemented very well... +=============== +*/ +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, + float degrees ) { + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + vec3_t vr, vup, vf; + float rad; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector( vr, dir ); + CrossProduct( vr, vf, vup ); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + memcpy( im, m, sizeof( im ) ); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + memset( zrot, 0, sizeof( zrot ) ); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; + + rad = DEG2RAD( degrees ); + zrot[0][0] = (vec_t)cos( rad ); + zrot[0][1] = (vec_t)sin( rad ); + zrot[1][0] = (vec_t)-sin( rad ); + zrot[1][1] = (vec_t)cos( rad ); + + MatrixMultiply( m, zrot, tmpmat ); + MatrixMultiply( tmpmat, im, rot ); + + for ( i = 0; i < 3; i++ ) { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; + } +} diff --git a/libs/mathlib/mathlib.vcproj b/libs/mathlib/mathlib.vcproj new file mode 100644 index 00000000..4dfa2c0e --- /dev/null +++ b/libs/mathlib/mathlib.vcproj @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/mathlib/ray.c b/libs/mathlib/ray.c new file mode 100644 index 00000000..08cb9f87 --- /dev/null +++ b/libs/mathlib/ray.c @@ -0,0 +1,135 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "mathlib.h" +/*! for memcpy */ +#include + +vec3_t identity = { 0,0,0 }; + +void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction) +{ + VectorCopy(origin, ray->origin); + VectorCopy(direction, ray->direction); +} + +void ray_transform(ray_t *ray, const m4x4_t matrix) +{ + m4x4_transform_point(matrix, ray->origin); + m4x4_transform_normal(matrix, ray->direction); +} + +vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence) +{ + vec3_t displacement; + vec_t depth; + + // calc displacement of test point from ray origin + VectorSubtract(point, ray->origin, displacement); + // calc length of displacement vector along ray direction + depth = DotProduct(displacement, ray->direction); + if(depth < 0.0f) return (vec_t)VEC_MAX; + // calc position of closest point on ray to test point + VectorMA (ray->origin, depth, ray->direction, displacement); + // calc displacement of test point from closest point + VectorSubtract(point, displacement, displacement); + // calc length of displacement, subtract depth-dependant epsilon + if (VectorLength(displacement) - (epsilon + (depth * divergence)) > 0.0f) return (vec_t)VEC_MAX; + return depth; +} + +// Tomas Moller and Ben Trumbore. Fast, minimum storage ray-triangle intersection. Journal of graphics tools, 2(1):21-28, 1997 + +#define EPSILON 0.000001 + +vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2) +{ + float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + float det,inv_det; + float u, v; + vec_t depth = (vec_t)VEC_MAX; + + /* find vectors for two edges sharing vert0 */ + VectorSubtract(vert1, vert0, edge1); + VectorSubtract(vert2, vert0, edge2); + + /* begin calculating determinant - also used to calculate U parameter */ + CrossProduct(ray->direction, edge2, pvec); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = DotProduct(edge1, pvec); + + if (bCullBack == qtrue) + { + if (det < EPSILON) + return depth; + + // calculate distance from vert0 to ray origin + VectorSubtract(ray->origin, vert0, tvec); + + // calculate U parameter and test bounds + u = DotProduct(tvec, pvec); + if (u < 0.0 || u > det) + return depth; + + // prepare to test V parameter + CrossProduct(tvec, edge1, qvec); + + // calculate V parameter and test bounds + v = DotProduct(ray->direction, qvec); + if (v < 0.0 || u + v > det) + return depth; + + // calculate t, scale parameters, ray intersects triangle + depth = DotProduct(edge2, qvec); + inv_det = 1.0f / det; + depth *= inv_det; + //u *= inv_det; + //v *= inv_det; + } + else + { + /* the non-culling branch */ + if (det > -EPSILON && det < EPSILON) + return depth; + inv_det = 1.0f / det; + + /* calculate distance from vert0 to ray origin */ + VectorSubtract(ray->origin, vert0, tvec); + + /* calculate U parameter and test bounds */ + u = DotProduct(tvec, pvec) * inv_det; + if (u < 0.0 || u > 1.0) + return depth; + + /* prepare to test V parameter */ + CrossProduct(tvec, edge1, qvec); + + /* calculate V parameter and test bounds */ + v = DotProduct(ray->direction, qvec) * inv_det; + if (v < 0.0 || u + v > 1.0) + return depth; + + /* calculate t, ray intersects triangle */ + depth = DotProduct(edge2, qvec) * inv_det; + } + return depth; +} diff --git a/libs/md5lib.h b/libs/md5lib.h new file mode 100644 index 00000000..32963357 --- /dev/null +++ b/libs/md5lib.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5lib.h,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/libs/md5lib/Conscript b/libs/md5lib/Conscript new file mode 100644 index 00000000..63db5316 --- /dev/null +++ b/libs/md5lib/Conscript @@ -0,0 +1,11 @@ +Import qw( BASE_CFLAGS CC ); + +$env = new cons +( + ENV => { PATH => $ENV{PATH}, HOME => $ENV{HOME} }, + CC => $CC, + CPPPATH => "#libs", + CFLAGS => $BASE_CFLAGS +); +Library $env 'md5lib', 'md5lib.c'; +Install $env '..', 'md5lib.a'; diff --git a/libs/md5lib/md5lib.c b/libs/md5lib/md5lib.c new file mode 100644 index 00000000..6fb45f13 --- /dev/null +++ b/libs/md5lib/md5lib.c @@ -0,0 +1,395 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5lib.c,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2003-07-17 ydnar added to gtkradiant project from + http://sourceforge.net/projects/libmd5-rfc/ + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5lib.h" /* ydnar */ +#include + +/* ydnar: gtkradiant endian picking */ +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ +#define ARCH_IS_BIG_ENDIAN 1 +#else +#define ARCH_IS_BIG_ENDIAN 0 +#endif +/* ydnar: end */ + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/libs/md5lib/md5lib.vcproj b/libs/md5lib/md5lib.vcproj new file mode 100644 index 00000000..e1e603f4 --- /dev/null +++ b/libs/md5lib/md5lib.vcproj @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/missing.h b/libs/missing.h new file mode 100644 index 00000000..a9288d5c --- /dev/null +++ b/libs/missing.h @@ -0,0 +1,212 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _MISSING_H_ +#define _MISSING_H_ + +// NOTE TTimo +// this goes along with str.h and provides various utility classes +// and portability defines +// the filename is a legecy issue, it would be better to clean that up +// in a central 'portability' lib + +#include +#include + +#ifdef _WIN32 +#include +#include + +#define MyCopyFile(a,b) CopyFile(a,b,FALSE) + +#define S_ISDIR(mode) (mode & _S_IFDIR) +#define R_OK 04 +#define mymkdir(a,b) _mkdir(a) + +#else + +#define MyCopyFile CopyFile +#define mymkdir(a,b) mkdir(a,b) + +#endif + +#ifndef _WIN32 + +// LZ: very ugly hacks +inline int GetLastError () { return 0; }; + +// temp stuff +inline int GetPrivateProfileInt(char* a, char* b, int i, char* c) { return i; }; +#define VERIFY(a) a; +int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart); +bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName); + +#ifndef APIENTRY +#define APIENTRY +#endif + +int MemorySize(void *ptr); +#define _msize MemorySize + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 + +#endif + +#define CString Str +#include "str.h" + +class CPtrArray +{ +public: + CPtrArray () + { m_ptrs = g_ptr_array_new (); }; + virtual ~CPtrArray () + { g_ptr_array_free (m_ptrs, TRUE); }; + + void* operator[](int i) const + { return g_ptr_array_index (m_ptrs,i); }; + void* GetAt(int i) const + { return g_ptr_array_index (m_ptrs,i); }; + int GetSize () const + { return m_ptrs->len; }; + void Add (void* ptr) + { g_ptr_array_add (m_ptrs, ptr); }; + void RemoveAll () + { g_ptr_array_set_size (m_ptrs, 0); }; + void RemoveAt(int index, int count = 1) + { + if ((index < 0) || (count < 0) || (count + index > (int)m_ptrs->len)) + return; + for (; count > 0; count--) + g_ptr_array_remove_index (m_ptrs, index); + } + void InsertAt(int nStartIndex, CPtrArray* pNewArray) + { + for (int i = 0; i < pNewArray->GetSize(); i++) + InsertAt(nStartIndex+i, pNewArray->GetAt(i)); + } + void InsertAt(int nIndex, void* newElement, int nCount = 1) + { + if ((guint32)nIndex >= m_ptrs->len) + { + g_ptr_array_set_size (m_ptrs, nIndex + nCount); // grow so nIndex is valid + } + else + { + // inserting in the middle of the array + int nOldSize = m_ptrs->len; + g_ptr_array_set_size (m_ptrs, m_ptrs->len + nCount); + // shift old data up to fill gap + memmove(&m_ptrs->pdata[nIndex+nCount], &m_ptrs->pdata[nIndex], + (nOldSize-nIndex) * sizeof(gpointer)); + + memset(&m_ptrs->pdata[nIndex], 0, nCount * sizeof(gpointer)); + } + + // insert new value in the gap + while (nCount--) + m_ptrs->pdata[nIndex++] = newElement; + } + void Copy(const CPtrArray& src) + { + g_ptr_array_set_size (m_ptrs, src.m_ptrs->len); + memcpy (m_ptrs->pdata, src.m_ptrs->pdata, m_ptrs->len*sizeof(gpointer)); + } + +protected: + GPtrArray* m_ptrs; +}; + +typedef struct stringmap_s +{ + char* key; + char* value; +} stringmap_t; + +class CMapStringToString +{ +public: + CMapStringToString () + { m_map = g_ptr_array_new (); }; + ~CMapStringToString () + { + for (guint32 i = 0; i < m_map->len; i++) + FreeElement ((stringmap_t*)g_ptr_array_index (m_map,i)); + g_ptr_array_set_size (m_map, 0); + g_ptr_array_free (m_map, TRUE); + }; + void SetAt(char* key, char* newValue) + { + for (guint32 i = 0; i < m_map->len; i++) + { + stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); + if (strcmp (entry->key, key) == 0) + { + g_free (entry->value); + entry->value = g_strdup (newValue); + return; + } + } + stringmap_t* entry = (stringmap_t*)g_malloc (sizeof (stringmap_t)); + entry->key = g_strdup (key); + entry->value = g_strdup (newValue); + g_ptr_array_add (m_map, entry); + } + + bool Lookup(const char* key, CString& rValue) const + { + for (guint32 i = 0; i < m_map->len; i++) + { + stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); + if (strcmp (entry->key, key) == 0) + { + rValue = entry->value; + return true; + } + } + return false; + } + +protected: + GPtrArray* m_map; + + void FreeElement(stringmap_t* elem) + { + g_free (elem->key); + g_free (elem->value); + g_free (elem); + }; +}; + +#endif // _MISSING_H_ diff --git a/libs/multimon.h b/libs/multimon.h new file mode 100644 index 00000000..9a4e9ad7 --- /dev/null +++ b/libs/multimon.h @@ -0,0 +1,381 @@ +#ifndef __MULTIMON_H +#define __MULTIMON_H + +#ifdef _WIN32 + +//============================================================================= +// +// MULTIMON +// stub module that "stubs" multiple monitor APIs on pre-Memphis Win32 OSes +// +// By using this header your code will work unchanged on Win95, +// you will get back correct values from GetSystemMetrics() for new metrics +// and the new APIs will act like only one display is present. +// +// exactly one source must include this with COMPILE_MULTIMON_STUBS defined +// +//============================================================================= + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// +// if we are building on Win95/NT4 headers we need to declare this stuff ourselves +// +#ifndef SM_CMONITORS + +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#define SM_SAMEDISPLAYFORMAT 81 + +DECLARE_HANDLE(HMONITOR); + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + +#define MONITORINFOF_PRIMARY 0x00000001 + +typedef struct tagMONITORINFO +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; + +#define CCHDEVICENAME 32 + +#ifdef __cplusplus +typedef struct tagMONITORINFOEX : public tagMONITORINFO +{ + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; +#else +typedef struct +{ + MONITORINFO; + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; +#endif + +typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM); + +#endif // SM_CMONITORS + +#ifndef DISPLAY_DEVICE_ATTACHED_TO_DESKTOP + +typedef struct { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD StateFlags; +} DISPLAY_DEVICE; + +#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 +#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 +#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 + +#endif +#define DISPLAY_DEVICE_VGA 0x00000010 + +#ifndef ENUM_CURRENT_SETTINGS +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) +#endif + +#undef GetMonitorInfo +#undef GetSystemMetrics +#undef MonitorFromWindow +#undef MonitorFromRect +#undef MonitorFromPoint +#undef EnumDisplayMonitors +#undef EnumDisplayDevices + +// +// define this to compile the stubs +// otherwise you get the declarations +// +#ifdef COMPILE_MULTIMON_STUBS + + //--------------------------------------------------------------------------- + // + // Implement the API stubs. + // + //--------------------------------------------------------------------------- + + int (WINAPI* g_pfnGetSystemMetrics)(int); + HMONITOR (WINAPI* g_pfnMonitorFromWindow)(HWND, BOOL); + HMONITOR (WINAPI* g_pfnMonitorFromRect)(LPCRECT, BOOL); + HMONITOR (WINAPI* g_pfnMonitorFromPoint)(POINT, BOOL); + BOOL (WINAPI* g_pfnGetMonitorInfo)(HMONITOR, LPMONITORINFO); + BOOL (WINAPI* g_pfnEnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + BOOL (WINAPI *g_pfnEnumDisplayDevices)(LPVOID, int, DISPLAY_DEVICE *, DWORD); + + BOOL InitMultipleMonitorStubs(void) + { + HMODULE hUser32; + static BOOL fInitDone; + + if (fInitDone) + { + return g_pfnGetMonitorInfo != NULL; + } + + if ((hUser32 = GetModuleHandle(TEXT("USER32"))) && + (*(FARPROC*)&g_pfnGetSystemMetrics = GetProcAddress(hUser32,"GetSystemMetrics")) && + (*(FARPROC*)&g_pfnMonitorFromWindow = GetProcAddress(hUser32,"MonitorFromWindow")) && + (*(FARPROC*)&g_pfnMonitorFromRect = GetProcAddress(hUser32,"MonitorFromRect")) && + (*(FARPROC*)&g_pfnMonitorFromPoint = GetProcAddress(hUser32,"MonitorFromPoint")) && + (*(FARPROC*)&g_pfnEnumDisplayMonitors = GetProcAddress(hUser32,"EnumDisplayMonitors")) && + #ifdef UNICODE + (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoW")) && + (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesW")) && + #else + (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoA")) && + (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesA")) && + #endif + (GetSystemMetrics(SM_CXVIRTUALSCREEN) >= GetSystemMetrics(SM_CXSCREEN)) && + (GetSystemMetrics(SM_CYVIRTUALSCREEN) >= GetSystemMetrics(SM_CYSCREEN)) ) + { + fInitDone = TRUE; + return TRUE; + } + else + { + g_pfnGetSystemMetrics = NULL; + g_pfnMonitorFromWindow = NULL; + g_pfnMonitorFromRect = NULL; + g_pfnMonitorFromPoint = NULL; + g_pfnGetMonitorInfo = NULL; + g_pfnEnumDisplayMonitors = NULL; + g_pfnEnumDisplayDevices = NULL; + + fInitDone = TRUE; + return FALSE; + } + } + + //--------------------------------------------------------------------------- + // + // "stubbed" implementations of Monitor APIs that work with the primary // display + // + //--------------------------------------------------------------------------- + + int WINAPI + xGetSystemMetrics(int nIndex) + { + if (InitMultipleMonitorStubs()) + return g_pfnGetSystemMetrics(nIndex); + + switch (nIndex) + { + case SM_CMONITORS: + case SM_SAMEDISPLAYFORMAT: + return 1; + + case SM_XVIRTUALSCREEN: + case SM_YVIRTUALSCREEN: + return 0; + + case SM_CXVIRTUALSCREEN: + nIndex = SM_CXSCREEN; + break; + + case SM_CYVIRTUALSCREEN: + nIndex = SM_CYSCREEN; + break; + } + + return GetSystemMetrics(nIndex); + } + + #define xPRIMARY_MONITOR ((HMONITOR)0x42) + + HMONITOR WINAPI + xMonitorFromRect(LPCRECT lprcScreenCoords, + UINT uFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromRect(lprcScreenCoords, uFlags); + + if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || + ((lprcScreenCoords->right > 0) && + (lprcScreenCoords->bottom > 0) && + (lprcScreenCoords->left < GetSystemMetrics(SM_CXSCREEN)) && + (lprcScreenCoords->top < GetSystemMetrics(SM_CYSCREEN)))) + { + return xPRIMARY_MONITOR; + } + + return NULL; + } + + HMONITOR WINAPI + xMonitorFromWindow(HWND hWnd, + UINT uFlags) + { + RECT rc; + + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromWindow(hWnd, uFlags); + + if (uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) + return xPRIMARY_MONITOR; + + if (GetWindowRect(hWnd, &rc)) + return xMonitorFromRect(&rc, uFlags); + + return NULL; + } + + HMONITOR WINAPI + xMonitorFromPoint(POINT ptScreenCoords, + UINT uFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromPoint(ptScreenCoords, uFlags); + + if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || + ((ptScreenCoords.x >= 0) && + (ptScreenCoords.x < GetSystemMetrics(SM_CXSCREEN)) && + (ptScreenCoords.y >= 0) && + (ptScreenCoords.y < GetSystemMetrics(SM_CYSCREEN)))) + { + return xPRIMARY_MONITOR; + } + + return NULL; + } + + BOOL WINAPI + xGetMonitorInfo(HMONITOR hMonitor, + LPMONITORINFO lpMonitorInfo) + { + RECT rcWork; + + if (InitMultipleMonitorStubs()) + return g_pfnGetMonitorInfo(hMonitor, lpMonitorInfo); + + if ((hMonitor == xPRIMARY_MONITOR) && lpMonitorInfo && + (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) && + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0)) + { + lpMonitorInfo->rcMonitor.left = 0; + lpMonitorInfo->rcMonitor.top = 0; + lpMonitorInfo->rcMonitor.right = GetSystemMetrics(SM_CXSCREEN); + lpMonitorInfo->rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN); + lpMonitorInfo->rcWork = rcWork; + lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY; + + if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEX)) + lstrcpy(((MONITORINFOEX*)lpMonitorInfo)->szDevice, + TEXT("DISPLAY")); + + return TRUE; + } + + return FALSE; + } + + BOOL WINAPI + xEnumDisplayMonitors(HDC hdc, + LPCRECT lprcIntersect, + MONITORENUMPROC lpfnEnumProc, + LPARAM lData) + { + RECT rcCallback, rcLimit; + + if (InitMultipleMonitorStubs()) + return g_pfnEnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc, lData); + + if (!lpfnEnumProc) + return FALSE; + + rcLimit.left = 0; + rcLimit.top = 0; + rcLimit.right = GetSystemMetrics(SM_CXSCREEN); + rcLimit.bottom = GetSystemMetrics(SM_CYSCREEN); + + if (hdc) + { + RECT rcClip; + HWND hWnd; + + if ((hWnd = WindowFromDC(hdc)) == NULL) + return FALSE; + + switch (GetClipBox(hdc, &rcClip)) + { + default: + MapWindowPoints(NULL, hWnd, (LPPOINT)&rcLimit, 2); + if (IntersectRect(&rcCallback, &rcClip, &rcLimit)) + break; + //fall thru + case NULLREGION: + return TRUE; + case ERROR: + return FALSE; + } + + rcLimit = rcCallback; + } + + if (!lprcIntersect || IntersectRect(&rcCallback, lprcIntersect, &rcLimit)) + { + lpfnEnumProc(xPRIMARY_MONITOR, hdc, &rcCallback, lData); + } + + return TRUE; + } + + BOOL WINAPI + xEnumDisplayDevices(LPVOID lpReserved, + int iDeviceNum, + DISPLAY_DEVICE * pDisplayDevice, + DWORD dwFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnEnumDisplayDevices(lpReserved, iDeviceNum, pDisplayDevice, dwFlags); + + return FALSE; + } + + #undef xPRIMARY_MONITOR + #undef COMPILE_MULTIMON_STUBS + +#else // COMPILE_MULTIMON_STUBS + + extern int WINAPI xGetSystemMetrics(int); + extern HMONITOR WINAPI xMonitorFromWindow(HWND, UINT); + extern HMONITOR WINAPI xMonitorFromRect(LPCRECT, UINT); + extern HMONITOR WINAPI xMonitorFromPoint(POINT, UINT); + extern BOOL WINAPI xGetMonitorInfo(HMONITOR, LPMONITORINFO); + extern BOOL WINAPI xEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + extern BOOL WINAPI xEnumDisplayDevices(LPVOID, int, DISPLAY_DEVICE *, DWORD); + +#endif // COMPILE_MULTIMON_STUBS + +// +// build defines that replace the regular APIs with our versions +// +#define GetSystemMetrics xGetSystemMetrics +#define MonitorFromWindow xMonitorFromWindow +#define MonitorFromRect xMonitorFromRect +#define MonitorFromPoint xMonitorFromPoint +#define GetMonitorInfo xGetMonitorInfo +#define EnumDisplayMonitors xEnumDisplayMonitors +#define EnumDisplayDevices xEnumDisplayDevices + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // WIN32 + +#endif // __MULTIMON_H \ No newline at end of file diff --git a/libs/pak/.cvsignore b/libs/pak/.cvsignore new file mode 100644 index 00000000..b5ee5ae1 --- /dev/null +++ b/libs/pak/.cvsignore @@ -0,0 +1 @@ +Debug Release *.ncb *.opt *.plg *.001 *.BAK \ No newline at end of file diff --git a/libs/pak/.cvswrappers b/libs/pak/.cvswrappers new file mode 100644 index 00000000..cdfd6d4a --- /dev/null +++ b/libs/pak/.cvswrappers @@ -0,0 +1,3 @@ +*.dsp -m 'COPY' -k 'b' +*.dsw -m 'COPY' -k 'b' +*.scc -m 'COPY' -k 'b' diff --git a/libs/pak/pakstuff.cpp b/libs/pak/pakstuff.cpp new file mode 100644 index 00000000..f3ae725e --- /dev/null +++ b/libs/pak/pakstuff.cpp @@ -0,0 +1,979 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#ifdef _WIN32 +#include +#endif +#include "pakstuff.h" +#include "unzip.h" +#include "str.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +int m_nPAKIndex; +FILE* pakfile[16]; +struct PACKDirectory pakdir; +PACKDirPtr pakdirptr = &pakdir; +UInt16 dirsize; +bool pakopen = false; +int f_type; +DIRECTORY *paktextures = NULL; +UInt32 PakColormapOffset; +UInt32 PakColormapSize; +DIRECTORY *dirhead = NULL; +bool g_bPK3 = false; +char g_strBasePaths[16][1024]; +int g_numBasePaths = 0; + +struct PK3FileInfo +{ + unzFile m_zFile; + char *m_pName; + unz_s m_zInfo; + long m_lSize; + ~PK3FileInfo() + { + delete []m_pName; + } + bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; } +}; + +#define __PATHSEPERATOR '/' + +//#define LOG_PAKFAIL + +#ifdef LOG_PAKFAIL + +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#endif +#include + +class LogFile +{ +public: + FILE *m_pFile; + LogFile(const char* pName) + { +#if defined (__linux__) || defined (__APPLE__) + // leo: use ~/.q3a/radiant/paklog instead of /tmp/paklog.txt + char *home = NULL; + + home = getenv("HOME"); + if ( home == NULL ) + { + uid_t id = getuid(); + struct passwd *pwd; + + setpwent(); + while( (pwd = getpwent()) != NULL ) + if( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + endpwent(); + } + + if (home != NULL) + { + char path[PATH_MAX]; + strcpy (path, home); + if (path[strlen(path)-1] != '/') + strcat (path, "/"); + strcat (path, ".q3a/radiant/paklog"); + m_pFile = fopen(path, "w"); + } + else +#endif + m_pFile = fopen(pName, "w"); + } + ~LogFile() + { + if (m_pFile) + { + fclose(m_pFile); + } + } + void Log(const char *pFormat, ...) + { + if (m_pFile == NULL) + return; + + va_list arg_ptr; + va_start(arg_ptr, pFormat); + fprintf(m_pFile, pFormat, arg_ptr); + va_end(arg_ptr); + } +}; + +LogFile g_LogFile("/tmp/paklog.txt"); +#endif + +template class StrPtr : public Str +{ +protected: + T* m_pPtr; + StrPtr() + { + m_pPtr = NULL; + } + + StrPtr(const char *pStr, T *p) : Str(pStr) + { + m_pPtr = p; + } + + T* Ptr() + { + return m_pPtr; + } + + T& Ref() + { + return *m_pPtr; + } + + +}; +// PtrList +// a list of ptrs +// +template class PtrList +{ +protected: + T *m_pPtr; + PtrList *m_pNext; + +public: + + PtrList() + { + m_pNext = NULL; + m_pPtr = NULL; + } + + PtrList(T *ip) + { + m_pNext = NULL; + m_pPtr = ip; + } + + virtual ~PtrList() + { + delete m_pPtr; + } + + PtrList* Next() + { + return m_pNext; + } + + void Add(T *ip) + { + PtrList *pl = this; + while (pl && pl->m_pNext) + { + pl = pl->Next(); + } + pl->m_pNext = new PtrList(ip); + } + + void Remove() + { + PtrList *p = m_pNext; + if (p) + { + while (p->m_pNext != this && p->m_pNext != NULL) + { + p = p->m_pNext; + } + if (p->m_pNext == this) + { + p->m_pNext = m_pNext; + } + } + } + + virtual PtrList* Find(T *ip) + { + PtrList *p = m_pNext; + while (p) + { + if (*p->m_pPtr == *ip) + { + return p; + } + p = p->m_pNext; + } + return NULL; + } + + // remove vp from the list + void Remove(T *ip) + { + PtrList *p = Find(ip); + if (p) + { + p->Remove(); + } + } + + T* Ptr() + { + return m_pPtr; + } + + T& Ref() + { + return *m_pPtr; + } + + void RemoveAll() + { + PtrList *p = m_pNext; + while (p) + { + PtrList *p2 = p; + p = p->m_pNext; + delete p2; + } + } +}; + + +typedef PtrList ZFileList; +typedef PtrList StrList; +typedef PtrList PK3List; + + +StrList g_PK3TexturePaths; +PK3List g_PK3Files; +ZFileList g_zFiles; +#define WORK_LEN 1024 +#define TEXTURE_PATH "textures" +#define PATH_SEPERATORS "/\\:\0" + +/* +char* __StrDup(char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} + +char* __StrDup(const char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} +*/ + +#define MEM_BLOCKSIZE 4096 +void* __qblockmalloc(size_t nSize) +{ + void *b; + // round up to threshold + int nAllocSize = nSize % MEM_BLOCKSIZE; + if ( nAllocSize > 0) + { + nSize += MEM_BLOCKSIZE - nAllocSize; + } + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +void* __qmalloc (size_t nSize) +{ + void *b; + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + + +/* +==================== +Extract file parts +==================== +*/ +void __ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != __PATHSEPERATOR) + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void __ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void __ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void __ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +void __ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + + + + + +static void AddSlash(Str& str) +{ + int nLen = str.GetLength(); + if (nLen > 0) + { + if (str[nLen-1] != '\\' && str[nLen-1] != '/') + str += '\\'; + } +} + +static void FindReplace(Str& strContents, const char* pTag, const char* pValue) +{ + if (strcmp(pTag, pValue) == 0) + return; + for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) + { + int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; + Str strLeft(strContents.Left(nPos)); + Str strRight(strContents.Right(nRightLen)); + strLeft += pValue; + strLeft += strRight; + strContents = strLeft; + } +} + + + + + +void ClearFileList(FILELIST **list) +{ + FILELIST *temp; + + while(*list) + { + temp = *list; + *list = (*list)->next; + free(temp); + } +} + +void ClearDirList(DIRLIST **list) +{ + DIRLIST *temp; + + while(*list) + { + temp = *list; + *list = (*list)->next; + free(temp); + } +} + +DIRECTORY *FindPakDir(DIRECTORY *dir, char *name) +{ + DIRECTORY *currentPtr; + + for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(name, currentPtr->name)) + { + return currentPtr; + } + } + return NULL; +} + + +// LoadPK3FileList +// --------------- +// +// This gets passed a file mask which we want to remove as +// we are only interested in the directory name and any given +// extension. Only handles explicit filenames or *.something +// +bool LoadPK3FileList(FILELIST **filelist, const char *pattern) +{ + char cSearch[WORK_LEN]; + __ConvertDOSToUnixName( cSearch, pattern ); + char cPath[WORK_LEN]; + char cExt[WORK_LEN]; + char cFile[WORK_LEN]; + char cWork[WORK_LEN]; + __ExtractFilePath(pattern, cPath); + __ExtractFileName(pattern, cFile); + __ExtractFileExtension(pattern, cExt); + const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile; + + PK3List *p = g_PK3Files.Next(); + while (p != NULL) + { + // qualify the path + PK3FileInfo *pKey = p->Ptr(); + if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare)) + { + __ExtractFileName(pKey->m_pName, cWork); + AddToFileListAlphabetized(filelist, cWork, 0, 0, false); + } + p = p->Next(); + } + return (*filelist) != NULL; +} + +bool GetPackFileList(FILELIST **filelist, char *pattern) +{ + char *str1, *str2; + int i; + DIRECTORY *dummy = paktextures; + FILELIST *temp; + + if (!pakopen) + return false; + + if (g_bPK3) + { + return LoadPK3FileList(filelist, pattern); + } + + str1 = pattern; + + for(i = 0; pattern[i] != '\0'; i++) + { + if(pattern[i] == '\\') + pattern[i] = '/'; + } + + while(strchr(str1, '/')) + { + str2 = strchr(str1, '/'); + *str2++ = '\0'; + dummy = FindPakDir(dummy, str1); + if(!dummy) + return false; + str1 = str2; + } + for(temp = dummy->files; temp; temp=temp->next) + { + AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false); + } + return true; +} + +bool GetPackTextureDirs(DIRLIST **dirlist) +{ + UInt16 i; + char buf[57]; + + if (!pakopen) + return 1; + + if (g_bPK3) + { + StrList *pl = g_PK3TexturePaths.Next(); + while (pl != NULL) + { + AddToDirListAlphabetized(dirlist, pl->Ref(), 0); + pl = pl->Next(); + } + return true; + } + + for (i = 0; i < dirsize; i++) + { + if(!strnicmp(pakdirptr[i].name, "textures", 8)) + { + strncpy(buf, &(pakdirptr[i].name[9]), 46); + if(strchr(buf, '\\')) + *strchr(buf, '\\') = '\0'; + else if(strchr(buf, '/')) + *strchr(buf, '/') = '\0'; + else + buf[56] = '\0'; + + if(strchr(buf, '.')) + continue; + + AddToDirListAlphabetized(dirlist, buf, 0); + } + } + return true; +} + +bool AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from) +{ + DIRLIST *currentPtr, *previousPtr, *newPtr; + + strlwr(dirname); + for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(dirname, currentPtr->dirname)) + { + return false; + } + } + previousPtr = NULL; + currentPtr = *list; + + if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL) + return false; + + strcpy(newPtr->dirname, dirname); + newPtr->from = from; + + while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } //End while + if(previousPtr == NULL) + { + newPtr->next = *list; + *list = newPtr; + } //End if + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } //End else + return true; +} + +bool AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, bool dirs) +{ + FILELIST *currentPtr, *previousPtr, *newPtr; + + for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(filename, currentPtr->filename)) + { + return false; + } + } + previousPtr = NULL; + currentPtr = *list; + + if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL) + return false; + + strcpy(newPtr->filename, filename); + newPtr->offset = offset; + newPtr->size = size; + + while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } //End while + if(previousPtr == NULL) + { + newPtr->next = *list; + *list = newPtr; + } //End if + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } //End else + return true; +} + +int PakLoadAnyFile(const char *filename, void **bufferptr) +{ + char cWork[WORK_LEN]; + if (g_bPK3) + { + // leo: hack to be able to use pak files from multiple directories + for (int i = 0; i < g_numBasePaths; i++) + { + PK3FileInfo *pInfo; + Str strKey; + // need to lookup the file without the base/texture path on it + Str strBase(g_strBasePaths[i]); + AddSlash(strBase); + __ConvertDOSToUnixName(cWork, strBase); + Str strFile(filename); + __ConvertDOSToUnixName(strFile, strFile); + strFile.MakeLower(); + strlwr(cWork); + FindReplace(strFile, cWork, ""); + + PK3FileInfo infoFind; + infoFind.m_pName = __StrDup(strFile.GetBuffer()); + PK3List *pList = g_PK3Files.Find(&infoFind); + if (pList) + { + pInfo = pList->Ptr(); + memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s)); + if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK) + { + void *buffer = __qblockmalloc(pInfo->m_lSize+1); + int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize); + *bufferptr = buffer; + unzCloseCurrentFile(pInfo->m_zFile); + return n; + } + } + } + +#ifdef LOG_PAKFAIL + sprintf(cWork, "PAK failed on %s\n", filename); + g_LogFile.Log(cWork); +#endif + return -1; + } + + for (int i = 0; i < dirsize; i++) + { + if(!stricmp(filename, pakdirptr[i].name)) + { + if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0) + { + void *buffer = __qmalloc (pakdirptr[i].size+1); + ((char *)buffer)[pakdirptr[i].size] = 0; + if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size) + { + *bufferptr = buffer; + return pakdirptr[i].size; + } + } + } + } +#ifdef LOG_PAKFAIL + sprintf(cWork, "PAK failed on %s\n", filename); + g_LogFile.Log(cWork); +#endif + return -1; +} + + + +DIRECTORY *AddPakDir(DIRECTORY **dir, char *name) +{ + DIRECTORY *currentPtr, *previousPtr, *newPtr; + + for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(name, currentPtr->name)) + { + return currentPtr; + } + } + previousPtr = NULL; + currentPtr = *dir; + + if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL) + return NULL; + + strcpy(newPtr->name, name); + newPtr->files = NULL; + + while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } + if(previousPtr == NULL) + { + newPtr->next = *dir; + *dir = newPtr; + } + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } + return newPtr; +} + + +// OpenPK3 +// ------- +// Opens a PK3 ( or zip ) file and creates a list of filenames +// and zip info structures +// +bool OpenPK3(const char *filename) +{ + char cFilename[WORK_LEN]; + char cName[WORK_LEN]; + char cWork[WORK_LEN]; + unz_file_info zInfo; + unzFile *zFile = new unzFile(unzOpen(filename)); + g_zFiles.Add(zFile); + if (zFile != NULL) + { + int nStatus = unzGoToFirstFile(*zFile); + while (nStatus == UNZ_OK) + { + cFilename[0] = '\0'; + unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0); + strlwr(cFilename); + __ConvertDOSToUnixName( cWork, cFilename); + if (strstr(cWork, ".") != NULL) + { + PK3FileInfo *pInfo = new PK3FileInfo(); + pInfo->m_pName = __StrDup(cWork); + memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s)); + pInfo->m_lSize = zInfo.uncompressed_size; + pInfo->m_zFile = *zFile; + g_PK3Files.Add(pInfo); + } + char *p = strstr(cFilename, TEXTURE_PATH); + if (p != NULL) + { + // FIXME: path differences per os ? + // catch solo directory entry + if (strlen(p) > strlen(TEXTURE_PATH) + 1) + { + // skip textures + path seperator + p += strlen(TEXTURE_PATH) + 1; + int nEnd = strcspn(p, PATH_SEPERATORS); + strncpy(cName, p, nEnd); + cName[nEnd] = '\0'; + + bool bFound = false; + StrList *pl = g_PK3TexturePaths.Next(); + while (pl != NULL) + { + if (strcmpi(pl->Ref(), cName) == 0) + { + // already have this, continue + bFound = true; + break; + } + pl = pl->Next(); + } + if (!bFound) + { + g_PK3TexturePaths.Add(new Str(cName)); + } + } + } + nStatus = unzGoToNextFile(*zFile); + } + } + return (zFile != NULL); +} + +void closePK3(unzFile zf) +{ + unzClose(zf); +} + +void OpenPakFile(const char *filename) +{ + if(!pakopen) + paktextures = NULL; + + pakopen = g_bPK3 = OpenPK3(filename); +} + +void ClearPaKDir(DIRECTORY **dir) +{ + DIRECTORY *d1 = *dir, *d2; + + while(d1) + { + ClearFileList(&(d1->files)); + d2 = d1; + d1 = d1->next; + free(d2); + } +} + +void CleanUpPakDirs() +{ + ClearPaKDir(&paktextures); + paktextures = NULL; + dirhead = NULL; + g_PK3TexturePaths.RemoveAll(); + g_PK3Files.RemoveAll(); +} + +void ClosePakFile(void) +{ + if(pakopen) + { + if (g_bPK3) + { + ZFileList *p = g_zFiles.Next(); + while (p != NULL) + { + unzFile uz = p->Ref(); + closePK3(uz); + p = p->Next(); + } + } + else + { + fclose(pakfile[m_nPAKIndex]); + } + } + pakopen = false; + CleanUpPakDirs(); +} + + +void WINAPI InitPakFile(const char * pBasePath, const char *pName) +{ + if (g_numBasePaths == 0) + { + m_nPAKIndex = 0; + pakopen = false; + paktextures = NULL; + } + strcpy(g_strBasePaths[g_numBasePaths], pBasePath); + g_numBasePaths++; + + if (pName == NULL) + { + //++timo FIXME: use some kind of compatibility lib here! +#if defined (__linux__) || defined (__APPLE__) + char cWork[WORK_LEN]; + struct dirent *dirlist; + DIR *dir; + + dir = opendir (pBasePath); + if (dir != NULL) + { + while ((dirlist = readdir (dir)) != NULL) + { + if (strstr (dirlist->d_name, ".pk3") == NULL) + continue; + sprintf(cWork, "%s/%s", pBasePath, dirlist->d_name); + OpenPakFile(cWork); + } + closedir (dir); + } +#endif +#ifdef _WIN32 + char cWork[WORK_LEN]; + Str strPath(pBasePath); + AddSlash(strPath); + strPath += "*.pk3"; + bool bGo = true; + struct _finddata_t fileinfo; + int handle = _findfirst (strPath, &fileinfo); + if (handle != -1) + { + do + { + sprintf(cWork, "%s/%s", pBasePath, fileinfo.name); + OpenPakFile(cWork); + } while (_findnext( handle, &fileinfo ) != -1); + _findclose (handle); + } +#endif + } + else + { + OpenPakFile(pName); + } +} + diff --git a/libs/pak/unzip.cpp b/libs/pak/unzip.cpp new file mode 100644 index 00000000..304dc6d3 --- /dev/null +++ b/libs/pak/unzip.cpp @@ -0,0 +1,4534 @@ +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * + *****************************************************************************/ + +#include +#include +#include +#include "unzip.h" + +typedef unsigned char byte; + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + 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. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + 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. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +int deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +int deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +int gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +// private stuff to not include cmdlib.h +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short __LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __BigShort (short l) +{ + return l; +} + + +int __LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __BigLong (int l) +{ + return l; +} + + +float __LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __BigFloat (float l) +{ + return l; +} + + +#else + + +short __BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __LittleShort (short l) +{ + return l; +} + + +int __BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __LittleLong (int l) +{ + return l; +} + +float __BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __LittleFloat (float l) +{ + return l; +} + + + +#endif + + + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +const char * zError OF((int err)); +int inflateSyncPoint OF((z_streamp z)); +const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#define zmemcpy memcpy +#define zmemcmp memcmp +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +static uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)malloc(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)malloc(sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + free(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + malloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + free(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + free(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + free(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef DYNAMIC_CRC_TABLE + +static int crc_table_empty = 1; +static uLong crc_table[256]; +static void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLong * get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLong *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong crc32(uLong crc, const Byte *buf, uInt len) +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} + + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} + + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} + +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidp)malloc(items*size); +} + +void zcfree (voidp opaque, voidp ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + diff --git a/libs/pak/unzip.h b/libs/pak/unzip.h new file mode 100644 index 00000000..d5c165dc --- /dev/null +++ b/libs/pak/unzip.h @@ -0,0 +1,300 @@ + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef void* unzFile; +#endif + + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + unsigned long number_entry; /* total number of entries in the central dir on this disk */ + unsigned long size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + unsigned long version; /* version made by 2 unsigned chars */ + unsigned long version_needed; /* version needed to extract 2 unsigned chars */ + unsigned long flag; /* general purpose bit flag 2 unsigned chars */ + unsigned long compression_method; /* compression method 2 unsigned chars */ + unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ + unsigned long crc; /* crc-32 4 unsigned chars */ + unsigned long compressed_size; /* compressed size 4 unsigned chars */ + unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ + unsigned long size_filename; /* filename length 2 unsigned chars */ + unsigned long size_file_extra; /* extra field length 2 unsigned chars */ + unsigned long size_file_comment; /* file comment length 2 unsigned chars */ + + unsigned long disk_num_start; /* disk number start 2 unsigned chars */ + unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ + unsigned long external_fa; /* external file attributes 4 unsigned chars */ + + tm_unz tmu_date; +} unz_file_info; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ +} unz_file_info_internal; + +typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void* opaque, void* address); + +struct internal_state; + +typedef struct z_stream_s { + unsigned char *next_in; /* next input unsigned char */ + unsigned int avail_in; /* number of unsigned chars available at next_in */ + unsigned long total_in; /* total nb of input unsigned chars read so */ + + unsigned char *next_out; /* next output unsigned char should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total nb of unsigned chars output so */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + unsigned char* opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ + unsigned long stream_initialised; /* flag set if stream structure is initialised*/ + + unsigned long offset_local_extrafield;/* offset of the static extra field */ + unsigned int size_local_extrafield;/* size of the static extra field */ + unsigned long pos_local_extrafield; /* position in the static extra field in read*/ + + unsigned long crc32; /* crc32 of all data uncompressed */ + unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ + unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ + unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + unsigned long compression_method; /* compression method (0==store) */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ + unsigned long num_file; /* number of the current file in the zipfile*/ + unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ + unsigned long current_file_ok; /* flag about the usability of the current file*/ + unsigned long central_pos; /* position of the beginning of the central dir*/ + + unsigned long size_central_dir; /* size of the central directory */ + unsigned long offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_CASESENSITIVE 1 +#define UNZ_NOTCASESENSITIVE 2 +#define UNZ_OSDEFAULTCASE 0 + +extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + +extern unzFile unzOpen (const char *path); +extern unzFile unzReOpen (const char* path, unzFile file); + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int unzClose (unzFile file); + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of unsigned char copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int unzGoToFirstFile (unzFile file); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int unzGoToNextFile (unzFile file); + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); + +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int unzOpenCurrentFile (unzFile file); + +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int unzCloseCurrentFile (unzFile file); + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); + +/* + Read unsigned chars from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of unsigned char copied if somes unsigned chars are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern long unztell(unzFile file); + +/* + Give the current position in uncompressed data +*/ + +extern int unzeof (unzFile file); + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of unsigned chars copied in buf, or (if <0) + the error code +*/ diff --git a/libs/pakstuff.h b/libs/pakstuff.h new file mode 100644 index 00000000..4c709cae --- /dev/null +++ b/libs/pakstuff.h @@ -0,0 +1,150 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PAKSTUFF_H_ +#define _PAKSTUFF_H_ + +#ifndef _WIN32 +#define WINAPI +#else +#include +#endif + +#ifndef __cplusplus +typedef int bool; // leo +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef char Int8; +typedef short Int16; +typedef long Int32; +typedef unsigned char UInt8; +typedef unsigned short UInt16; +typedef unsigned long UInt32; +typedef float Float32; +typedef double Float64; +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define RANDOM(x) (random() % (x)) +#define RANDOMIZE() srand((int) time(NULL)) + +#define FTYPE_UNKNOWN 0 +#define FTYPE_IWAD 1 /* .wad "IWAD" */ +#define FTYPE_PWAD 2 /* .wad "PWAD" */ +#define FTYPE_PACK 3 /* .pak "PACK" */ +#define FTYPE_WAD2 4 /* .wad "WAD2" */ +#define FTYPE_BSP 10 /* .bsp (0x17 0x00 0x00 0x00) */ +#define FTYPE_MODEL 11 /* .mdl "IDPO" */ +#define FTYPE_SPRITE 12 /* .spr "IDSP" */ +#define FTYPE_WAV 20 /* .wav "RIFF" */ +#define FTYPE_AU 21 /* .au ".snd" */ +#define FTYPE_VOC 22 /* .voc ? */ +#define FTYPE_PBM_ASC 30 /* .pbm "P1" */ +#define FTYPE_PGM_ASC 31 /* .pgm "P2" */ +#define FTYPE_PPM_ASC 32 /* .ppm "P3" */ +#define FTYPE_PBM_RAW 33 /* .pbm "P4" */ +#define FTYPE_PGM_RAW 34 /* .pgm "P5" */ +#define FTYPE_PPM_RAW 35 /* .ppm "P6" */ +#define FTYPE_BMP 36 /* .bmp "BM" */ +#define FTYPE_GIF 37 /* .gif "GIF8" */ +#define FTYPE_PCX 38 /* .pcx (0x0a 0x05 0x01 0x08) */ +#define FTYPE_ERROR -1 + +#ifdef FAT_ENDIAN +Bool ReadInt16 (FILE *file, UInt16 huge *x); +Bool ReadInt32 (FILE *file, UInt32 huge *x); +Bool ReadFloat32 (FILE *file, Float32 huge *x); +Bool WriteInt16 (FILE *file, UInt16 huge *x); +Bool WriteInt32 (FILE *file, UInt32 huge *x); +Bool WriteFloat32 (FILE *file, Float32 huge *x); +UInt16 SwapInt16 (UInt16 x); +UInt32 SwapInt32 (UInt32 x); +Float32 SwapFloat32 (Float32 x); +#else +#define ReadInt16(f, p) ReadBytes((f), (p), 2L) +#define ReadInt32(f, p) ReadBytes((f), (p), 4L) +#define ReadFloat32(f, p) ReadBytes((f), (p), 4L) +#define WriteInt16(f, p) WriteBytes((f), (p), 2L) +#define WriteInt32(f, p) WriteBytes((f), (p), 4L) +#define WriteFloat32(f, p) WriteBytes((f), (p), 4L) +#define SwapInt16(x) (x) +#define SwapInt32(x) (x) +#define SwapFloat32(x) (x) +#endif /* FAT_ENDIAN */ + +#define FROMDISK -1 +struct PACKDirectory +{ + char name[56]; /* name of file */ + UInt32 offset; /* offset to start of data */ + UInt32 size; /* byte size of data */ +}; +typedef struct PACKDirectory *PACKDirPtr; + +typedef struct DirListStruct +{ + char dirname[1024]; + int from; + struct DirListStruct *next; +} DIRLIST; + +typedef struct FileListStruct +{ + char filename[1024]; + UInt32 offset; + UInt32 size; + struct FileListStruct *next; +} FILELIST; + +typedef struct DirStruct +{ + char name[1024]; + FILELIST *files; + struct DirStruct *next; +} DIRECTORY; + + +extern int m_nPAKIndex; +extern FILE* pakfile[16]; +extern bool pakopen; +extern DIRECTORY *paktextures; + +void ClearFileList (FILELIST **); +void ClearDirList (DIRLIST **); +bool GetPackFileList (FILELIST **, char *); +bool GetPackTextureDirs (DIRLIST **); +bool AddToDirListAlphabetized (DIRLIST **, char *, int); +bool AddToFileListAlphabetized (FILELIST **t, char *, UInt32, UInt32, bool); +bool PakLoadFile (const char *, void **); +void OpenPakFile (const char *); +void ClosePakFile (void); +int PakLoadAnyFile(const char *filename, void **bufferptr); +void WINAPI InitPakFile(const char * pBasePath, const char *pName); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel.h b/libs/picomodel.h new file mode 100644 index 00000000..8642527a --- /dev/null +++ b/libs/picomodel.h @@ -0,0 +1,345 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef PICOMODEL_H +#define PICOMODEL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* version */ +#define PICOMODEL_VERSION "0.8.20" + + +/* constants */ +#define PICO_GROW_SHADERS 16 +#define PICO_GROW_SURFACES 16 +#define PICO_GROW_VERTEXES 1024 +#define PICO_GROW_INDEXES 1024 +#define PICO_GROW_ARRAYS 8 +#define PICO_GROW_FACES 256 +#define PICO_MAX_SPECIAL 8 +#define PICO_MAX_DEFAULT_EXTS 4 /* max default extensions per module */ + + +/* types */ +typedef unsigned char picoByte_t; +typedef float picoVec_t; +typedef float picoVec2_t[ 2 ]; +typedef float picoVec3_t[ 3 ]; +typedef float picoVec4_t[ 4 ]; +typedef picoByte_t picoColor_t[ 4 ]; +typedef int picoIndex_t; + +typedef enum +{ + PICO_BAD, + PICO_TRIANGLES, + PICO_PATCH +} +picoSurfaceType_t; + +typedef enum +{ + PICO_NORMAL, + PICO_VERBOSE, + PICO_WARNING, + PICO_ERROR, + PICO_FATAL +} +picoPrintLevel_t; + +typedef struct picoSurface_s picoSurface_t; +typedef struct picoShader_s picoShader_t; +typedef struct picoModel_s picoModel_t; +typedef struct picoModule_s picoModule_t; + +struct picoSurface_s +{ + void *data; + + picoModel_t *model; /* owner model */ + + picoSurfaceType_t type; + char *name; /* sea: surface name */ + picoShader_t *shader; /* ydnar: changed to ptr */ + + int numVertexes, maxVertexes; + picoVec3_t *xyz; + picoVec3_t *normal; + + int numSTArrays, maxSTArrays; + picoVec2_t **st; + + int numColorArrays, maxColorArrays; + picoColor_t **color; + + int numIndexes, maxIndexes; + picoIndex_t *index; + + int numFaceNormals, maxFaceNormals; + picoVec3_t *faceNormal; + + int special[ PICO_MAX_SPECIAL ]; +}; + + +/* seaw0lf */ +struct picoShader_s +{ + picoModel_t *model; /* owner model */ + + char *name; /* shader name */ + char *mapName; /* shader file name (name of diffuse texturemap) */ + picoColor_t ambientColor; /* ambient color of mesh (rgba) */ + picoColor_t diffuseColor; /* diffuse color of mesh (rgba) */ + picoColor_t specularColor; /* specular color of mesh (rgba) */ + float transparency; /* transparency (0..1; 1 = 100% transparent) */ + float shininess; /* shininess (0..128; 128 = 100% shiny) */ +}; + +struct picoModel_s +{ + void *data; + char *name; /* model name */ + char *fileName; /* sea: model file name */ + int frameNum; /* sea: renamed to frameNum */ + int numFrames; /* sea: number of frames */ + picoVec3_t mins; + picoVec3_t maxs; + + int numShaders, maxShaders; + picoShader_t **shader; + + int numSurfaces, maxSurfaces; + picoSurface_t **surface; + + const picoModule_t *module; /* sea */ +}; + + +/* seaw0lf */ +/* return codes used by the validation callbacks; pmv is short */ +/* for 'pico module validation'. everything >PICO_PMV_OK means */ +/* that there was an error. */ +enum +{ + PICO_PMV_OK, /* file valid */ + PICO_PMV_ERROR, /* file not valid */ + PICO_PMV_ERROR_IDENT, /* unknown file magic (aka ident) */ + PICO_PMV_ERROR_VERSION, /* unsupported file version */ + PICO_PMV_ERROR_SIZE, /* file size error */ + PICO_PMV_ERROR_MEMORY, /* out of memory error */ +}; + +/* convenience (makes it easy to add new params to the callbacks) */ +#define PM_PARAMS_CANLOAD \ + char *fileName, const void *buffer, int bufSize + +#define PM_PARAMS_LOAD \ + char *fileName, int frameNum, const void *buffer, int bufSize + +#define PM_PARAMS_CANSAVE \ + void + +#define PM_PARAMS_SAVE \ + char *fileName, picoModel_t *model + +/* pico file format module structure */ +struct picoModule_s +{ + char *version; /* internal module version (e.g. '1.5-b2') */ + + char *displayName; /* string used to display in guis, etc. */ + char *authorName; /* author name (eg. 'My Real Name') */ + char *copyright; /* copyright year and holder (eg. '2002 My Company') */ + + char *defaultExts[ PICO_MAX_DEFAULT_EXTS ]; /* default file extensions used by this file type */ + int (*canload)( PM_PARAMS_CANLOAD ); /* checks whether module can load given file (returns PMVR_*) */ + picoModel_t *(*load)( PM_PARAMS_LOAD ); /* parses model file data */ + int (*cansave)( PM_PARAMS_CANSAVE ); /* checks whether module can save (returns 1 or 0 and might spit out a message) */ + int (*save)( PM_PARAMS_SAVE ); /* saves a pico model in module's native model format */ +}; + + + +/* general functions */ +int PicoInit( void ); +void PicoShutdown( void ); +int PicoError( void ); + +void PicoSetMallocFunc( void *(*func)( size_t ) ); +void PicoSetFreeFunc( void (*func)( void* ) ); +void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ); +void PicoSetFreeFileFunc( void (*func)( void* ) ); +void PicoSetPrintFunc( void (*func)( int, const char* ) ); + +const picoModule_t **PicoModuleList( int *numModules ); + +picoModel_t *PicoLoadModel( char *name, int frameNum ); + + +/* model functions */ +picoModel_t *PicoNewModel( void ); +void PicoFreeModel( picoModel_t *model ); +int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ); + + +/* shader functions */ +picoShader_t *PicoNewShader( picoModel_t *model ); +void PicoFreeShader( picoShader_t *shader ); +picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ); + + +/* surface functions */ +picoSurface_t *PicoNewSurface( picoModel_t *model ); +void PicoFreeSurface( picoSurface_t *surface ); +picoSurface_t *PicoFindSurface( picoModel_t *model, char *name, int caseSensitive ); +int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ); + + +/* setter functions */ +void PicoSetModelName( picoModel_t *model, char *name ); +void PicoSetModelFileName( picoModel_t *model, char *fileName ); +void PicoSetModelFrameNum( picoModel_t *model, int frameNum ); +void PicoSetModelNumFrames( picoModel_t *model, int numFrames ); +void PicoSetModelData( picoModel_t *model, void *data ); + +void PicoSetShaderName( picoShader_t *shader, char *name ); +void PicoSetShaderMapName( picoShader_t *shader, char *mapName ); +void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderTransparency( picoShader_t *shader, float value ); +void PicoSetShaderShininess( picoShader_t *shader, float value ); + +void PicoSetSurfaceData( picoSurface_t *surface, void *data ); +void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ); +void PicoSetSurfaceName( picoSurface_t *surface, char *name ); +void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ); +void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ); +void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); +void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ); +void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ); +void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ); +void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ); +void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); +void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ); + + +/* getter functions */ +char *PicoGetModelName( picoModel_t *model ); +char *PicoGetModelFileName( picoModel_t *model ); +int PicoGetModelFrameNum( picoModel_t *model ); +int PicoGetModelNumFrames( picoModel_t *model ); +void *PicoGetModelData( picoModel_t *model ); +int PicoGetModelNumShaders( picoModel_t *model ); +picoShader_t *PicoGetModelShader( picoModel_t *model, int num ); /* sea */ +int PicoGetModelNumSurfaces( picoModel_t *model ); +picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ); +int PicoGetModelTotalVertexes( picoModel_t *model ); +int PicoGetModelTotalIndexes( picoModel_t *model ); + +char *PicoGetShaderName( picoShader_t *shader ); +char *PicoGetShaderMapName( picoShader_t *shader ); +picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ); +picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ); +picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ); +float PicoGetShaderTransparency( picoShader_t *shader ); +float PicoGetShaderShininess( picoShader_t *shader ); + +void *PicoGetSurfaceData( picoSurface_t *surface ); +char *PicoGetSurfaceName( picoSurface_t *surface ); /* sea */ +picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ); +char *PicoGetSurfaceName( picoSurface_t *surface ); +picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ); /* sea */ + +int PicoGetSurfaceNumVertexes( picoSurface_t *surface ); +picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ); +picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ); +picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ); +picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ); +int PicoGetSurfaceNumIndexes( picoSurface_t *surface ); +picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ); +picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ); +picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ); +int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ); + + +/* hashtable related functions */ +typedef struct picoVertexCombinationData_s +{ + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; +} picoVertexCombinationData_t; + +typedef struct picoVertexCombinationHash_s +{ + picoVertexCombinationData_t vcd; + picoIndex_t index; + + void *data; + + struct picoVertexCombinationHash_s *next; +} picoVertexCombinationHash_t; + +int PicoGetHashTableSize( void ); +unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ); +picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ); +void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ); +picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ); +picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ); + +/* specialized functions */ +int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ); +void PicoFixSurfaceNormals( picoSurface_t *surface ); +int PicoRemapModel( picoModel_t *model, char *remapFile ); + + +void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, picoShader_t* shader ); + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel/lwo/clip.c b/libs/picomodel/lwo/clip.c new file mode 100644 index 00000000..349222a4 --- /dev/null +++ b/libs/picomodel/lwo/clip.c @@ -0,0 +1,249 @@ +/* +====================================================================== +clip.c + +Functions for LWO2 image references. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreeClip() + +Free memory used by an lwClip. +====================================================================== */ + +void lwFreeClip( lwClip *clip ) +{ + if ( clip ) { + lwListFree( (void*) clip->ifilter, lwFreePlugin ); + lwListFree( (void*) clip->pfilter, lwFreePlugin ); + _pico_free( clip ); + } +} + + +/* +====================================================================== +lwGetClip() + +Read image references from a CLIP chunk in an LWO2 file. +====================================================================== */ + +lwClip *lwGetClip( picoMemStream_t *fp, int cksize ) +{ + lwClip *clip; + lwPlugin *filt; + unsigned int id; + unsigned short sz; + int pos, rlen; + + + /* allocate the Clip structure */ + + clip = _pico_calloc( 1, sizeof( lwClip )); + if ( !clip ) goto Fail; + + clip->contrast.val = 1.0f; + clip->brightness.val = 1.0f; + clip->saturation.val = 1.0f; + clip->gamma.val = 1.0f; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* index */ + + clip->index = getI4( fp ); + + /* first subchunk header */ + + clip->type = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + sz += sz & 1; + set_flen( 0 ); + + switch ( clip->type ) { + case ID_STIL: + clip->source.still.name = getS0( fp ); + break; + + case ID_ISEQ: + clip->source.seq.digits = getU1( fp ); + clip->source.seq.flags = getU1( fp ); + clip->source.seq.offset = getI2( fp ); + getU2( fp ); /* not sure what this is yet */ + clip->source.seq.start = getI2( fp ); + clip->source.seq.end = getI2( fp ); + clip->source.seq.prefix = getS0( fp ); + clip->source.seq.suffix = getS0( fp ); + break; + + case ID_ANIM: + clip->source.anim.name = getS0( fp ); + clip->source.anim.server = getS0( fp ); + rlen = get_flen(); + clip->source.anim.data = getbytes( fp, sz - rlen ); + break; + + case ID_XREF: + clip->source.xref.index = getI4( fp ); + clip->source.xref.string = getS0( fp ); + break; + + case ID_STCC: + clip->source.cycle.lo = getI2( fp ); + clip->source.cycle.hi = getI2( fp ); + clip->source.cycle.name = getS0( fp ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the CLIP chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) + return clip; + + /* process subchunks as they're encountered */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TIME: + clip->start_time = getF4( fp ); + clip->duration = getF4( fp ); + clip->frame_rate = getF4( fp ); + break; + + case ID_CONT: + clip->contrast.val = getF4( fp ); + clip->contrast.eindex = getVX( fp ); + break; + + case ID_BRIT: + clip->brightness.val = getF4( fp ); + clip->brightness.eindex = getVX( fp ); + break; + + case ID_SATR: + clip->saturation.val = getF4( fp ); + clip->saturation.eindex = getVX( fp ); + break; + + case ID_HUE: + clip->hue.val = getF4( fp ); + clip->hue.eindex = getVX( fp ); + break; + + case ID_GAMM: + clip->gamma.val = getF4( fp ); + clip->gamma.eindex = getVX( fp ); + break; + + case ID_NEGA: + clip->negative = getU2( fp ); + break; + + case ID_IFLT: + case ID_PFLT: + filt = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !filt ) goto Fail; + + filt->name = getS0( fp ); + filt->flags = getU2( fp ); + rlen = get_flen(); + filt->data = getbytes( fp, sz - rlen ); + + if ( id == ID_IFLT ) { + lwListAdd( &clip->ifilter, filt ); + clip->nifilters++; + } + else { + lwListAdd( &clip->pfilter, filt ); + clip->npfilters++; + } + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the CLIP chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return clip; + +Fail: + lwFreeClip( clip ); + return NULL; +} + + +/* +====================================================================== +lwFindClip() + +Returns an lwClip pointer, given a clip index. +====================================================================== */ + +lwClip *lwFindClip( lwClip *list, int index ) +{ + lwClip *clip; + + clip = list; + while ( clip ) { + if ( clip->index == index ) break; + clip = clip->next; + } + return clip; +} diff --git a/libs/picomodel/lwo/envelope.c b/libs/picomodel/lwo/envelope.c new file mode 100644 index 00000000..4ece5951 --- /dev/null +++ b/libs/picomodel/lwo/envelope.c @@ -0,0 +1,600 @@ +/* +====================================================================== +envelope.c + +Envelope functions for an LWO2 reader. + +Ernie Wright 16 Nov 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* +====================================================================== +lwFreeEnvelope() + +Free the memory used by an lwEnvelope. +====================================================================== */ + +void lwFreeEnvelope( lwEnvelope *env ) +{ + if ( env ) { + if ( env->name ) _pico_free( env->name ); + lwListFree( env->key, _pico_free ); + lwListFree( env->cfilter, lwFreePlugin ); + _pico_free( env ); + } +} + + +static int compare_keys( lwKey *k1, lwKey *k2 ) +{ + return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0; +} + + +/* +====================================================================== +lwGetEnvelope() + +Read an ENVL chunk from an LWO2 file. +====================================================================== */ + +lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ) +{ + lwEnvelope *env; + lwKey *key; + lwPlugin *plug; + unsigned int id; + unsigned short sz; + float f[ 4 ]; + int i, nparams, pos, rlen; + + + /* allocate the Envelope structure */ + + env = _pico_calloc( 1, sizeof( lwEnvelope )); + if ( !env ) goto Fail; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* index */ + + env->index = getVX( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TYPE: + env->type = getU2( fp ); + break; + + case ID_NAME: + env->name = getS0( fp ); + break; + + case ID_PRE: + env->behavior[ 0 ] = getU2( fp ); + break; + + case ID_POST: + env->behavior[ 1 ] = getU2( fp ); + break; + + case ID_KEY: + key = _pico_calloc( 1, sizeof( lwKey )); + if ( !key ) goto Fail; + key->time = getF4( fp ); + key->value = getF4( fp ); + lwListInsert( &env->key, key, compare_keys ); + env->nkeys++; + break; + + case ID_SPAN: + if ( !key ) goto Fail; + key->shape = getU4( fp ); + + nparams = ( sz - 4 ) / 4; + if ( nparams > 4 ) nparams = 4; + for ( i = 0; i < nparams; i++ ) + f[ i ] = getF4( fp ); + + switch ( key->shape ) { + case ID_TCB: + key->tension = f[ 0 ]; + key->continuity = f[ 1 ]; + key->bias = f[ 2 ]; + break; + + case ID_BEZI: + case ID_HERM: + case ID_BEZ2: + for ( i = 0; i < nparams; i++ ) + key->param[ i ] = f[ i ]; + break; + } + break; + + case ID_CHAN: + plug = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !plug ) goto Fail; + + plug->name = getS0( fp ); + plug->flags = getU2( fp ); + plug->data = getbytes( fp, sz - get_flen() ); + + lwListAdd( &env->cfilter, plug ); + env->ncfilters++; + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the ENVL chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return env; + +Fail: + lwFreeEnvelope( env ); + return NULL; +} + + +/* +====================================================================== +lwFindEnvelope() + +Returns an lwEnvelope pointer, given an envelope index. +====================================================================== */ + +lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ) +{ + lwEnvelope *env; + + env = list; + while ( env ) { + if ( env->index == index ) break; + env = env->next; + } + return env; +} + + +/* +====================================================================== +range() + +Given the value v of a periodic function, returns the equivalent value +v2 in the principal interval [lo, hi]. If i isn't NULL, it receives +the number of wavelengths between v and v2. + + v2 = v - i * (hi - lo) + +For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1. +====================================================================== */ + +static float range( float v, float lo, float hi, int *i ) +{ + float v2, r = hi - lo; + + if ( r == 0.0 ) { + if ( i ) *i = 0; + return lo; + } + + v2 = lo + v - r * ( float ) floor(( double ) v / r ); + if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 )); + + return v2; +} + + +/* +====================================================================== +hermite() + +Calculate the Hermite coefficients. +====================================================================== */ + +static void hermite( float t, float *h1, float *h2, float *h3, float *h4 ) +{ + float t2, t3; + + t2 = t * t; + t3 = t * t2; + + *h2 = 3.0f * t2 - t3 - t3; + *h1 = 1.0f - *h2; + *h4 = t3 - t2; + *h3 = *h4 - t2 + t; +} + + +/* +====================================================================== +bezier() + +Interpolate the value of a 1D Bezier curve. +====================================================================== */ + +static float bezier( float x0, float x1, float x2, float x3, float t ) +{ + float a, b, c, t2, t3; + + t2 = t * t; + t3 = t2 * t; + + c = 3.0f * ( x1 - x0 ); + b = 3.0f * ( x2 - x1 ) - c; + a = x3 - x0 - c - b; + + return a * t3 + b * t2 + c * t + x0; +} + + +/* +====================================================================== +bez2_time() + +Find the t for which bezier() returns the input time. The handle +endpoints of a BEZ2 curve represent the control points, and these have +(time, value) coordinates, so time is used as both a coordinate and a +parameter for this curve type. +====================================================================== */ + +static float bez2_time( float x0, float x1, float x2, float x3, float time, + float *t0, float *t1 ) +{ + float v, t; + + t = *t0 + ( *t1 - *t0 ) * 0.5f; + v = bezier( x0, x1, x2, x3, t ); + if ( fabs( time - v ) > .0001f ) { + if ( v > time ) + *t1 = t; + else + *t0 = t; + return bez2_time( x0, x1, x2, x3, time, t0, t1 ); + } + else + return t; +} + + +/* +====================================================================== +bez2() + +Interpolate the value of a BEZ2 curve. +====================================================================== */ + +static float bez2( lwKey *key0, lwKey *key1, float time ) +{ + float x, y, t, t0 = 0.0f, t1 = 1.0f; + + if ( key0->shape == ID_BEZ2 ) + x = key0->time + key0->param[ 2 ]; + else + x = key0->time + ( key1->time - key0->time ) / 3.0f; + + t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time, + time, &t0, &t1 ); + + if ( key0->shape == ID_BEZ2 ) + y = key0->value + key0->param[ 3 ]; + else + y = key0->value + key0->param[ 1 ] / 3.0f; + + return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t ); +} + + +/* +====================================================================== +outgoing() + +Return the outgoing tangent to the curve at key0. The value returned +for the BEZ2 case is used when extrapolating a linear pre behavior and +when interpolating a non-BEZ2 span. +====================================================================== */ + +static float outgoing( lwKey *key0, lwKey *key1 ) +{ + float a, b, d, t, out; + + switch ( key0->shape ) + { + case ID_TCB: + a = ( 1.0f - key0->tension ) + * ( 1.0f + key0->continuity ) + * ( 1.0f + key0->bias ); + b = ( 1.0f - key0->tension ) + * ( 1.0f - key0->continuity ) + * ( 1.0f - key0->bias ); + d = key1->value - key0->value; + + if ( key0->prev ) { + t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + out = t * ( a * ( key0->value - key0->prev->value ) + b * d ); + } + else + out = b * d; + break; + + case ID_LINE: + d = key1->value - key0->value; + if ( key0->prev ) { + t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + out = t * ( key0->value - key0->prev->value + d ); + } + else + out = d; + break; + + case ID_BEZI: + case ID_HERM: + out = key0->param[ 1 ]; + if ( key0->prev ) + out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + break; + + case ID_BEZ2: + out = key0->param[ 3 ] * ( key1->time - key0->time ); + if ( fabs( key0->param[ 2 ] ) > 1e-5f ) + out /= key0->param[ 2 ]; + else + out *= 1e5f; + break; + + case ID_STEP: + default: + out = 0.0f; + break; + } + + return out; +} + + +/* +====================================================================== +incoming() + +Return the incoming tangent to the curve at key1. The value returned +for the BEZ2 case is used when extrapolating a linear post behavior. +====================================================================== */ + +static float incoming( lwKey *key0, lwKey *key1 ) +{ + float a, b, d, t, in; + + switch ( key1->shape ) + { + case ID_LINE: + d = key1->value - key0->value; + if ( key1->next ) { + t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + in = t * ( key1->next->value - key1->value + d ); + } + else + in = d; + break; + + case ID_TCB: + a = ( 1.0f - key1->tension ) + * ( 1.0f - key1->continuity ) + * ( 1.0f + key1->bias ); + b = ( 1.0f - key1->tension ) + * ( 1.0f + key1->continuity ) + * ( 1.0f - key1->bias ); + d = key1->value - key0->value; + + if ( key1->next ) { + t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + in = t * ( b * ( key1->next->value - key1->value ) + a * d ); + } + else + in = a * d; + break; + + case ID_BEZI: + case ID_HERM: + in = key1->param[ 0 ]; + if ( key1->next ) + in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + break; + return in; + + case ID_BEZ2: + in = key1->param[ 1 ] * ( key1->time - key0->time ); + if ( fabs( key1->param[ 0 ] ) > 1e-5f ) + in /= key1->param[ 0 ]; + else + in *= 1e5f; + break; + + case ID_STEP: + default: + in = 0.0f; + break; + } + + return in; +} + + +/* +====================================================================== +evalEnvelope() + +Given a list of keys and a time, returns the interpolated value of the +envelope at that time. +====================================================================== */ + +float evalEnvelope( lwEnvelope *env, float time ) +{ + lwKey *key0, *key1, *skey, *ekey; + float t, h1, h2, h3, h4, in, out, offset = 0.0f; + int noff; + + + /* if there's no key, the value is 0 */ + + if ( env->nkeys == 0 ) return 0.0f; + + /* if there's only one key, the value is constant */ + + if ( env->nkeys == 1 ) + return env->key->value; + + /* find the first and last keys */ + + skey = ekey = env->key; + while ( ekey->next ) ekey = ekey->next; + + /* use pre-behavior if time is before first key time */ + + if ( time < skey->time ) { + switch ( env->behavior[ 0 ] ) + { + case BEH_RESET: + return 0.0f; + + case BEH_CONSTANT: + return skey->value; + + case BEH_REPEAT: + time = range( time, skey->time, ekey->time, NULL ); + break; + + case BEH_OSCILLATE: + time = range( time, skey->time, ekey->time, &noff ); + if ( noff % 2 ) + time = ekey->time - skey->time - time; + break; + + case BEH_OFFSET: + time = range( time, skey->time, ekey->time, &noff ); + offset = noff * ( ekey->value - skey->value ); + break; + + case BEH_LINEAR: + out = outgoing( skey, skey->next ) + / ( skey->next->time - skey->time ); + return out * ( time - skey->time ) + skey->value; + } + } + + /* use post-behavior if time is after last key time */ + + else if ( time > ekey->time ) { + switch ( env->behavior[ 1 ] ) + { + case BEH_RESET: + return 0.0f; + + case BEH_CONSTANT: + return ekey->value; + + case BEH_REPEAT: + time = range( time, skey->time, ekey->time, NULL ); + break; + + case BEH_OSCILLATE: + time = range( time, skey->time, ekey->time, &noff ); + if ( noff % 2 ) + time = ekey->time - skey->time - time; + break; + + case BEH_OFFSET: + time = range( time, skey->time, ekey->time, &noff ); + offset = noff * ( ekey->value - skey->value ); + break; + + case BEH_LINEAR: + in = incoming( ekey->prev, ekey ) + / ( ekey->time - ekey->prev->time ); + return in * ( time - ekey->time ) + ekey->value; + } + } + + /* get the endpoints of the interval being evaluated */ + + key0 = env->key; + while ( time > key0->next->time ) + key0 = key0->next; + key1 = key0->next; + + /* check for singularities first */ + + if ( time == key0->time ) + return key0->value + offset; + else if ( time == key1->time ) + return key1->value + offset; + + /* get interval length, time in [0, 1] */ + + t = ( time - key0->time ) / ( key1->time - key0->time ); + + /* interpolate */ + + switch ( key1->shape ) + { + case ID_TCB: + case ID_BEZI: + case ID_HERM: + out = outgoing( key0, key1 ); + in = incoming( key0, key1 ); + hermite( t, &h1, &h2, &h3, &h4 ); + return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset; + + case ID_BEZ2: + return bez2( key0, key1, time ) + offset; + + case ID_LINE: + return key0->value + t * ( key1->value - key0->value ) + offset; + + case ID_STEP: + return key0->value + offset; + + default: + return offset; + } +} diff --git a/libs/picomodel/lwo/list.c b/libs/picomodel/lwo/list.c new file mode 100644 index 00000000..d07b0337 --- /dev/null +++ b/libs/picomodel/lwo/list.c @@ -0,0 +1,101 @@ +/* +====================================================================== +list.c + +Generic linked list operations. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwListFree() + +Free the items in a list. +====================================================================== */ + +void lwListFree( void *list, void ( *freeNode )( void * )) +{ + lwNode *node, *next; + + node = ( lwNode * ) list; + while ( node ) { + next = node->next; + freeNode( node ); + node = next; + } +} + + +/* +====================================================================== +lwListAdd() + +Append a node to a list. +====================================================================== */ + +void lwListAdd( void **list, void *node ) +{ + lwNode *head, *tail; + + head = *(( lwNode ** ) list ); + if ( !head ) { + *list = node; + return; + } + while ( head ) { + tail = head; + head = head->next; + } + tail->next = ( lwNode * ) node; + (( lwNode * ) node )->prev = tail; +} + + +/* +====================================================================== +lwListInsert() + +Insert a node into a list in sorted order. +====================================================================== */ + +void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * )) +{ + lwNode **list, *item, *node, *prev; + + if ( !*vlist ) { + *vlist = vitem; + return; + } + + list = ( lwNode ** ) vlist; + item = ( lwNode * ) vitem; + node = *list; + prev = NULL; + + while ( node ) { + if ( 0 < compare( node, item )) break; + prev = node; + node = node->next; + } + + if ( !prev ) { + *list = item; + node->prev = item; + item->next = node; + } + else if ( !node ) { + prev->next = item; + item->prev = prev; + } + else { + item->next = node; + item->prev = prev; + prev->next = item; + node->prev = item; + } +} diff --git a/libs/picomodel/lwo/lwio.c b/libs/picomodel/lwo/lwio.c new file mode 100644 index 00000000..eea380bf --- /dev/null +++ b/libs/picomodel/lwo/lwio.c @@ -0,0 +1,442 @@ +/* +====================================================================== +lwio.c + +Functions for reading basic LWO2 data types. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +flen + +This accumulates a count of the number of bytes read. Callers can set +it at the beginning of a sequence of reads and then retrieve it to get +the number of bytes actually read. If one of the I/O functions fails, +flen is set to an error code, after which the I/O functions ignore +read requests until flen is reset. +====================================================================== */ + +#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ +#define FLEN_ERROR INT_MIN + +static int flen; + +void set_flen( int i ) { flen = i; } + +int get_flen( void ) { return flen; } + + +#ifdef _WIN32 +/* +===================================================================== +revbytes() + +Reverses byte order in place. + +INPUTS + bp bytes to reverse + elsize size of the underlying data type + elcount number of elements to swap + +RESULTS + Reverses the byte order in each of elcount elements. + +This only needs to be defined on little-endian platforms, most +notably Windows. lwo2.h replaces this with a #define on big-endian +platforms. +===================================================================== */ + +void revbytes( void *bp, int elsize, int elcount ) +{ + register unsigned char *p, *q; + + p = ( unsigned char * ) bp; + + if ( elsize == 2 ) { + q = p + 1; + while ( elcount-- ) { + *p ^= *q; + *q ^= *p; + *p ^= *q; + p += 2; + q += 2; + } + return; + } + + while ( elcount-- ) { + q = p + elsize - 1; + while ( p < q ) { + *p ^= *q; + *q ^= *p; + *p ^= *q; + ++p; + --q; + } + p += elsize >> 1; + } +} +#endif + + +void *getbytes( picoMemStream_t *fp, int size ) +{ + void *data; + + if ( flen == FLEN_ERROR ) return NULL; + if ( size < 0 ) { + flen = FLEN_ERROR; + return NULL; + } + data = _pico_alloc( size ); + if ( !data ) { + flen = FLEN_ERROR; + return NULL; + } + if ( 1 != _pico_memstream_read( fp, data, size )) { + flen = FLEN_ERROR; + _pico_free( data ); + return NULL; + } + + flen += size; + return data; +} + + +void skipbytes( picoMemStream_t *fp, int n ) +{ + if ( flen == FLEN_ERROR ) return; + if ( _pico_memstream_seek( fp, n, PICO_SEEK_CUR )) + flen = FLEN_ERROR; + else + flen += n; +} + + +int getI1( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = _pico_memstream_getc( fp ); + if ( i < 0 ) { + flen = FLEN_ERROR; + return 0; + } + if ( i > 127 ) i -= 256; + flen += 1; + return i; +} + + +short getI2( picoMemStream_t *fp ) +{ + short i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 2 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 2, 1 ); + flen += 2; + return i; +} + + +int getI4( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 4 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 4, 1 ); + flen += 4; + return i; +} + + +unsigned char getU1( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = _pico_memstream_getc( fp ); + if ( i < 0 ) { + flen = FLEN_ERROR; + return 0; + } + flen += 1; + return i; +} + + +unsigned short getU2( picoMemStream_t *fp ) +{ + unsigned short i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 2 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 2, 1 ); + flen += 2; + return i; +} + + +unsigned int getU4( picoMemStream_t *fp ) +{ + unsigned int i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 4 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 4, 1 ); + flen += 4; + return i; +} + + +int getVX( picoMemStream_t *fp ) +{ + int i, c; + + if ( flen == FLEN_ERROR ) return 0; + + c = _pico_memstream_getc( fp ); + if ( c != 0xFF ) { + i = c << 8; + c = _pico_memstream_getc( fp ); + i |= c; + flen += 2; + } + else { + c = _pico_memstream_getc( fp ); + i = c << 16; + c = _pico_memstream_getc( fp ); + i |= c << 8; + c = _pico_memstream_getc( fp ); + i |= c; + flen += 4; + } + + if ( _pico_memstream_error( fp )) { + flen = FLEN_ERROR; + return 0; + } + return i; +} + + +float getF4( picoMemStream_t *fp ) +{ + float f; + + if ( flen == FLEN_ERROR ) return 0.0f; + if ( 1 != _pico_memstream_read( fp, &f, 4 )) { + flen = FLEN_ERROR; + return 0.0f; + } + revbytes( &f, 4, 1 ); + flen += 4; + return f; +} + + +char *getS0( picoMemStream_t *fp ) +{ + char *s; + int i, c, len, pos; + + if ( flen == FLEN_ERROR ) return NULL; + + pos = _pico_memstream_tell( fp ); + for ( i = 1; ; i++ ) { + c = _pico_memstream_getc( fp ); + if ( c <= 0 ) break; + } + if ( c < 0 ) { + flen = FLEN_ERROR; + return NULL; + } + + if ( i == 1 ) { + if ( _pico_memstream_seek( fp, pos + 2, PICO_SEEK_SET )) + flen = FLEN_ERROR; + else + flen += 2; + return NULL; + } + + len = i + ( i & 1 ); + s = _pico_alloc( len ); + if ( !s ) { + flen = FLEN_ERROR; + return NULL; + } + + if ( _pico_memstream_seek( fp, pos, PICO_SEEK_SET )) { + flen = FLEN_ERROR; + return NULL; + } + if ( 1 != _pico_memstream_read( fp, s, len )) { + flen = FLEN_ERROR; + return NULL; + } + + flen += len; + return s; +} + + +int sgetI1( unsigned char **bp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = **bp; + if ( i > 127 ) i -= 256; + flen += 1; + *bp++; + return i; +} + + +short sgetI2( unsigned char **bp ) +{ + short i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 2 ); + revbytes( &i, 2, 1 ); + flen += 2; + *bp += 2; + return i; +} + + +int sgetI4( unsigned char **bp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 4 ); + revbytes( &i, 4, 1 ); + flen += 4; + *bp += 4; + return i; +} + + +unsigned char sgetU1( unsigned char **bp ) +{ + unsigned char c; + + if ( flen == FLEN_ERROR ) return 0; + c = **bp; + flen += 1; + *bp++; + return c; +} + + +unsigned short sgetU2( unsigned char **bp ) +{ + unsigned char *buf = *bp; + unsigned short i; + + if ( flen == FLEN_ERROR ) return 0; + i = ( buf[ 0 ] << 8 ) | buf[ 1 ]; + flen += 2; + *bp += 2; + return i; +} + + +unsigned int sgetU4( unsigned char **bp ) +{ + unsigned int i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 4 ); + revbytes( &i, 4, 1 ); + flen += 4; + *bp += 4; + return i; +} + + +int sgetVX( unsigned char **bp ) +{ + unsigned char *buf = *bp; + int i; + + if ( flen == FLEN_ERROR ) return 0; + + if ( buf[ 0 ] != 0xFF ) { + i = buf[ 0 ] << 8 | buf[ 1 ]; + flen += 2; + *bp += 2; + } + else { + i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ]; + flen += 4; + *bp += 4; + } + return i; +} + + +float sgetF4( unsigned char **bp ) +{ + float f; + + if ( flen == FLEN_ERROR ) return 0.0f; + memcpy( &f, *bp, 4 ); + revbytes( &f, 4, 1 ); + flen += 4; + *bp += 4; + return f; +} + + +char *sgetS0( unsigned char **bp ) +{ + char *s; + unsigned char *buf = *bp; + int len; + + if ( flen == FLEN_ERROR ) return NULL; + + len = strlen( buf ) + 1; + if ( len == 1 ) { + flen += 2; + *bp += 2; + return NULL; + } + len += len & 1; + s = _pico_alloc( len ); + if ( !s ) { + flen = FLEN_ERROR; + return NULL; + } + + memcpy( s, buf, len ); + flen += len; + *bp += len; + return s; +} diff --git a/libs/picomodel/lwo/lwo2.c b/libs/picomodel/lwo/lwo2.c new file mode 100644 index 00000000..1d72af7d --- /dev/null +++ b/libs/picomodel/lwo/lwo2.c @@ -0,0 +1,308 @@ +/* +====================================================================== +lwo2.c + +The entry point for loading LightWave object files. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ +#endif + + +/* +====================================================================== +lwFreeLayer() + +Free memory used by an lwLayer. +====================================================================== */ + +void lwFreeLayer( lwLayer *layer ) +{ + if ( layer ) { + if ( layer->name ) _pico_free( layer->name ); + lwFreePoints( &layer->point ); + lwFreePolygons( &layer->polygon ); + lwListFree( layer->vmap, lwFreeVMap ); + _pico_free( layer ); + } +} + + +/* +====================================================================== +lwFreeObject() + +Free memory used by an lwObject. +====================================================================== */ + +void lwFreeObject( lwObject *object ) +{ + if ( object ) { + lwListFree( object->layer, lwFreeLayer ); + lwListFree( object->env, lwFreeEnvelope ); + lwListFree( object->clip, lwFreeClip ); + lwListFree( object->surf, lwFreeSurface ); + lwFreeTags( &object->taglist ); + _pico_free( object ); + } +} + + +/* +====================================================================== +lwGetObject() + +Returns the contents of a LightWave object, given its filename, or +NULL if the file couldn't be loaded. On failure, failID and failpos +can be used to diagnose the cause. + +1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and + failID will be unchanged. + +2. If an error occurs while reading, failID will contain the most + recently read IFF chunk ID, and failpos will contain the value + returned by _pico_memstream_tell() at the time of the failure. + +3. If the file couldn't be opened, or an error occurs while reading + the first 12 bytes, both failID and failpos will be unchanged. + +If you don't need this information, failID and failpos can be NULL. +====================================================================== */ + +lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + lwObject *object; + lwLayer *layer; + lwNode *node; + unsigned int id, formsize, type, cksize; + int i, rlen; + + /* open the file */ + + if ( !fp ) return NULL; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return NULL; + } + + /* is this a LW object? */ + + if ( id != ID_FORM ) { + if ( failpos ) *failpos = 12; + return NULL; + } + + if ( type != ID_LWO2 ) { + if ( type == ID_LWOB ) + return lwGetObject5( filename, fp, failID, failpos ); + else { + if ( failpos ) *failpos = 12; + return NULL; + } + } + + /* allocate an object and a default layer */ + + object = _pico_calloc( 1, sizeof( lwObject )); + if ( !object ) goto Fail; + + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + object->layer = layer; + + /* get the first chunk header */ + + id = getU4( fp ); + cksize = getU4( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process chunks as they're encountered */ + + while ( 1 ) { + cksize += cksize & 1; + + switch ( id ) + { + case ID_LAYR: + if ( object->nlayers > 0 ) { + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + lwListAdd( &object->layer, layer ); + } + object->nlayers++; + + set_flen( 0 ); + layer->index = getU2( fp ); + layer->flags = getU2( fp ); + layer->pivot[ 0 ] = getF4( fp ); + layer->pivot[ 1 ] = getF4( fp ); + layer->pivot[ 2 ] = getF4( fp ); + layer->name = getS0( fp ); + + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) goto Fail; + if ( rlen <= cksize - 2 ) + layer->parent = getU2( fp ); + rlen = get_flen(); + if ( rlen < cksize ) + _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); + break; + + case ID_PNTS: + if ( !lwGetPoints( fp, cksize, &layer->point )) + goto Fail; + break; + + case ID_POLS: + if ( !lwGetPolygons( fp, cksize, &layer->polygon, + layer->point.offset )) + goto Fail; + break; + + case ID_VMAP: + case ID_VMAD: + node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset, + layer->polygon.offset, id == ID_VMAD ); + if ( !node ) goto Fail; + lwListAdd( &layer->vmap, node ); + layer->nvmaps++; + break; + + case ID_PTAG: + if ( !lwGetPolygonTags( fp, cksize, &object->taglist, + &layer->polygon )) + goto Fail; + break; + + case ID_BBOX: + set_flen( 0 ); + for ( i = 0; i < 6; i++ ) + layer->bbox[ i ] = getF4( fp ); + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) goto Fail; + if ( rlen < cksize ) + _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); + break; + + case ID_TAGS: + if ( !lwGetTags( fp, cksize, &object->taglist )) + goto Fail; + break; + + case ID_ENVL: + node = ( lwNode * ) lwGetEnvelope( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->env, node ); + object->nenvs++; + break; + + case ID_CLIP: + node = ( lwNode * ) lwGetClip( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->clip, node ); + object->nclips++; + break; + + case ID_SURF: + node = ( lwNode * ) lwGetSurface( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->surf, node ); + object->nsurfs++; + break; + + case ID_DESC: + case ID_TEXT: + case ID_ICON: + default: + _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); + break; + } + + /* end of the file? */ + + if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + cksize = getU4( fp ); + if ( 8 != get_flen() ) goto Fail; + } + + if ( object->nlayers == 0 ) + object->nlayers = 1; + + layer = object->layer; + while ( layer ) { + lwGetBoundingBox( &layer->point, layer->bbox ); + lwGetPolyNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; + if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, + &object->surf, &object->nsurfs )) goto Fail; + lwGetVertNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail; + if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail; + layer = layer->next; + } + + return object; + +Fail: + if ( failID ) *failID = id; + if ( fp ) { + if ( failpos ) *failpos = _pico_memstream_tell( fp ); + } + lwFreeObject( object ); + return NULL; +} + +int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + unsigned int id, formsize, type; + + /* open the file */ + + if ( !fp ) return PICO_PMV_ERROR_MEMORY; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return PICO_PMV_ERROR_SIZE; + } + + /* is this a LW object? */ + + if ( id != ID_FORM ) { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_SIZE; + } + + if ( type != ID_LWO2 ) { + if ( type == ID_LWOB ) + return lwValidateObject5( filename, fp, failID, failpos ); + else { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_IDENT; + } + } + + return PICO_PMV_OK; +} diff --git a/libs/picomodel/lwo/lwo2.h b/libs/picomodel/lwo/lwo2.h new file mode 100644 index 00000000..1fe1dd97 --- /dev/null +++ b/libs/picomodel/lwo/lwo2.h @@ -0,0 +1,651 @@ +/* +====================================================================== +lwo2.h + +Definitions and typedefs for LWO2 files. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#ifndef LWO2_H +#define LWO2_H + +/* chunk and subchunk IDs */ + +#define LWID_(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d)) + +#define ID_FORM LWID_('F','O','R','M') +#define ID_LWO2 LWID_('L','W','O','2') +#define ID_LWOB LWID_('L','W','O','B') + +/* top-level chunks */ +#define ID_LAYR LWID_('L','A','Y','R') +#define ID_TAGS LWID_('T','A','G','S') +#define ID_PNTS LWID_('P','N','T','S') +#define ID_BBOX LWID_('B','B','O','X') +#define ID_VMAP LWID_('V','M','A','P') +#define ID_VMAD LWID_('V','M','A','D') +#define ID_POLS LWID_('P','O','L','S') +#define ID_PTAG LWID_('P','T','A','G') +#define ID_ENVL LWID_('E','N','V','L') +#define ID_CLIP LWID_('C','L','I','P') +#define ID_SURF LWID_('S','U','R','F') +#define ID_DESC LWID_('D','E','S','C') +#define ID_TEXT LWID_('T','E','X','T') +#define ID_ICON LWID_('I','C','O','N') + +/* polygon types */ +#define ID_FACE LWID_('F','A','C','E') +#define ID_CURV LWID_('C','U','R','V') +#define ID_PTCH LWID_('P','T','C','H') +#define ID_MBAL LWID_('M','B','A','L') +#define ID_BONE LWID_('B','O','N','E') + +/* polygon tags */ +#define ID_SURF LWID_('S','U','R','F') +#define ID_PART LWID_('P','A','R','T') +#define ID_SMGP LWID_('S','M','G','P') + +/* envelopes */ +#define ID_PRE LWID_('P','R','E',' ') +#define ID_POST LWID_('P','O','S','T') +#define ID_KEY LWID_('K','E','Y',' ') +#define ID_SPAN LWID_('S','P','A','N') +#define ID_TCB LWID_('T','C','B',' ') +#define ID_HERM LWID_('H','E','R','M') +#define ID_BEZI LWID_('B','E','Z','I') +#define ID_BEZ2 LWID_('B','E','Z','2') +#define ID_LINE LWID_('L','I','N','E') +#define ID_STEP LWID_('S','T','E','P') + +/* clips */ +#define ID_STIL LWID_('S','T','I','L') +#define ID_ISEQ LWID_('I','S','E','Q') +#define ID_ANIM LWID_('A','N','I','M') +#define ID_XREF LWID_('X','R','E','F') +#define ID_STCC LWID_('S','T','C','C') +#define ID_TIME LWID_('T','I','M','E') +#define ID_CONT LWID_('C','O','N','T') +#define ID_BRIT LWID_('B','R','I','T') +#define ID_SATR LWID_('S','A','T','R') +#define ID_HUE LWID_('H','U','E',' ') +#define ID_GAMM LWID_('G','A','M','M') +#define ID_NEGA LWID_('N','E','G','A') +#define ID_IFLT LWID_('I','F','L','T') +#define ID_PFLT LWID_('P','F','L','T') + +/* surfaces */ +#define ID_COLR LWID_('C','O','L','R') +#define ID_LUMI LWID_('L','U','M','I') +#define ID_DIFF LWID_('D','I','F','F') +#define ID_SPEC LWID_('S','P','E','C') +#define ID_GLOS LWID_('G','L','O','S') +#define ID_REFL LWID_('R','E','F','L') +#define ID_RFOP LWID_('R','F','O','P') +#define ID_RIMG LWID_('R','I','M','G') +#define ID_RSAN LWID_('R','S','A','N') +#define ID_TRAN LWID_('T','R','A','N') +#define ID_TROP LWID_('T','R','O','P') +#define ID_TIMG LWID_('T','I','M','G') +#define ID_RIND LWID_('R','I','N','D') +#define ID_TRNL LWID_('T','R','N','L') +#define ID_BUMP LWID_('B','U','M','P') +#define ID_SMAN LWID_('S','M','A','N') +#define ID_SIDE LWID_('S','I','D','E') +#define ID_CLRH LWID_('C','L','R','H') +#define ID_CLRF LWID_('C','L','R','F') +#define ID_ADTR LWID_('A','D','T','R') +#define ID_SHRP LWID_('S','H','R','P') +#define ID_LINE LWID_('L','I','N','E') +#define ID_LSIZ LWID_('L','S','I','Z') +#define ID_ALPH LWID_('A','L','P','H') +#define ID_AVAL LWID_('A','V','A','L') +#define ID_GVAL LWID_('G','V','A','L') +#define ID_BLOK LWID_('B','L','O','K') + +/* texture layer */ +#define ID_TYPE LWID_('T','Y','P','E') +#define ID_CHAN LWID_('C','H','A','N') +#define ID_NAME LWID_('N','A','M','E') +#define ID_ENAB LWID_('E','N','A','B') +#define ID_OPAC LWID_('O','P','A','C') +#define ID_FLAG LWID_('F','L','A','G') +#define ID_PROJ LWID_('P','R','O','J') +#define ID_STCK LWID_('S','T','C','K') +#define ID_TAMP LWID_('T','A','M','P') + +/* texture coordinates */ +#define ID_TMAP LWID_('T','M','A','P') +#define ID_AXIS LWID_('A','X','I','S') +#define ID_CNTR LWID_('C','N','T','R') +#define ID_SIZE LWID_('S','I','Z','E') +#define ID_ROTA LWID_('R','O','T','A') +#define ID_OREF LWID_('O','R','E','F') +#define ID_FALL LWID_('F','A','L','L') +#define ID_CSYS LWID_('C','S','Y','S') + +/* image map */ +#define ID_IMAP LWID_('I','M','A','P') +#define ID_IMAG LWID_('I','M','A','G') +#define ID_WRAP LWID_('W','R','A','P') +#define ID_WRPW LWID_('W','R','P','W') +#define ID_WRPH LWID_('W','R','P','H') +#define ID_VMAP LWID_('V','M','A','P') +#define ID_AAST LWID_('A','A','S','T') +#define ID_PIXB LWID_('P','I','X','B') + +/* procedural */ +#define ID_PROC LWID_('P','R','O','C') +#define ID_COLR LWID_('C','O','L','R') +#define ID_VALU LWID_('V','A','L','U') +#define ID_FUNC LWID_('F','U','N','C') +#define ID_FTPS LWID_('F','T','P','S') +#define ID_ITPS LWID_('I','T','P','S') +#define ID_ETPS LWID_('E','T','P','S') + +/* gradient */ +#define ID_GRAD LWID_('G','R','A','D') +#define ID_GRST LWID_('G','R','S','T') +#define ID_GREN LWID_('G','R','E','N') +#define ID_PNAM LWID_('P','N','A','M') +#define ID_INAM LWID_('I','N','A','M') +#define ID_GRPT LWID_('G','R','P','T') +#define ID_FKEY LWID_('F','K','E','Y') +#define ID_IKEY LWID_('I','K','E','Y') + +/* shader */ +#define ID_SHDR LWID_('S','H','D','R') +#define ID_DATA LWID_('D','A','T','A') + + +/* generic linked list */ + +typedef struct st_lwNode { + struct st_lwNode *next, *prev; + void *data; +} lwNode; + + +/* plug-in reference */ + +typedef struct st_lwPlugin { + struct st_lwPlugin *next, *prev; + char *ord; + char *name; + int flags; + void *data; +} lwPlugin; + + +/* envelopes */ + +typedef struct st_lwKey { + struct st_lwKey *next, *prev; + float value; + float time; + unsigned int shape; /* ID_TCB, ID_BEZ2, etc. */ + float tension; + float continuity; + float bias; + float param[ 4 ]; +} lwKey; + +typedef struct st_lwEnvelope { + struct st_lwEnvelope *next, *prev; + int index; + int type; + char *name; + lwKey *key; /* linked list of keys */ + int nkeys; + int behavior[ 2 ]; /* pre and post (extrapolation) */ + lwPlugin *cfilter; /* linked list of channel filters */ + int ncfilters; +} lwEnvelope; + +#define BEH_RESET 0 +#define BEH_CONSTANT 1 +#define BEH_REPEAT 2 +#define BEH_OSCILLATE 3 +#define BEH_OFFSET 4 +#define BEH_LINEAR 5 + + +/* values that can be enveloped */ + +typedef struct st_lwEParam { + float val; + int eindex; +} lwEParam; + +typedef struct st_lwVParam { + float val[ 3 ]; + int eindex; +} lwVParam; + + +/* clips */ + +typedef struct st_lwClipStill { + char *name; +} lwClipStill; + +typedef struct st_lwClipSeq { + char *prefix; /* filename before sequence digits */ + char *suffix; /* after digits, e.g. extensions */ + int digits; + int flags; + int offset; + int start; + int end; +} lwClipSeq; + +typedef struct st_lwClipAnim { + char *name; + char *server; /* anim loader plug-in */ + void *data; +} lwClipAnim; + +typedef struct st_lwClipXRef { + char *string; + int index; + struct st_lwClip *clip; +} lwClipXRef; + +typedef struct st_lwClipCycle { + char *name; + int lo; + int hi; +} lwClipCycle; + +typedef struct st_lwClip { + struct st_lwClip *next, *prev; + int index; + unsigned int type; /* ID_STIL, ID_ISEQ, etc. */ + union { + lwClipStill still; + lwClipSeq seq; + lwClipAnim anim; + lwClipXRef xref; + lwClipCycle cycle; + } source; + float start_time; + float duration; + float frame_rate; + lwEParam contrast; + lwEParam brightness; + lwEParam saturation; + lwEParam hue; + lwEParam gamma; + int negative; + lwPlugin *ifilter; /* linked list of image filters */ + int nifilters; + lwPlugin *pfilter; /* linked list of pixel filters */ + int npfilters; +} lwClip; + + +/* textures */ + +typedef struct st_lwTMap { + lwVParam size; + lwVParam center; + lwVParam rotate; + lwVParam falloff; + int fall_type; + char *ref_object; + int coord_sys; +} lwTMap; + +typedef struct st_lwImageMap { + int cindex; + int projection; + char *vmap_name; + int axis; + int wrapw_type; + int wraph_type; + lwEParam wrapw; + lwEParam wraph; + float aa_strength; + int aas_flags; + int pblend; + lwEParam stck; + lwEParam amplitude; +} lwImageMap; + +#define PROJ_PLANAR 0 +#define PROJ_CYLINDRICAL 1 +#define PROJ_SPHERICAL 2 +#define PROJ_CUBIC 3 +#define PROJ_FRONT 4 + +#define WRAP_NONE 0 +#define WRAP_EDGE 1 +#define WRAP_REPEAT 2 +#define WRAP_MIRROR 3 + +typedef struct st_lwProcedural { + int axis; + float value[ 3 ]; + char *name; + void *data; +} lwProcedural; + +typedef struct st_lwGradKey { + struct st_lwGradKey *next, *prev; + float value; + float rgba[ 4 ]; +} lwGradKey; + +typedef struct st_lwGradient { + char *paramname; + char *itemname; + float start; + float end; + int repeat; + lwGradKey *key; /* array of gradient keys */ + short *ikey; /* array of interpolation codes */ +} lwGradient; + +typedef struct st_lwTexture { + struct st_lwTexture *next, *prev; + char *ord; + unsigned int type; + unsigned int chan; + lwEParam opacity; + short opac_type; + short enabled; + short negative; + short axis; + union { + lwImageMap imap; + lwProcedural proc; + lwGradient grad; + } param; + lwTMap tmap; +} lwTexture; + + +/* values that can be textured */ + +typedef struct st_lwTParam { + float val; + int eindex; + lwTexture *tex; /* linked list of texture layers */ +} lwTParam; + +typedef struct st_lwCParam { + float rgb[ 3 ]; + int eindex; + lwTexture *tex; /* linked list of texture layers */ +} lwCParam; + + +/* surfaces */ + +typedef struct st_lwGlow { + short enabled; + short type; + lwEParam intensity; + lwEParam size; +} Glow; + +typedef struct st_lwRMap { + lwTParam val; + int options; + int cindex; + float seam_angle; +} lwRMap; + +typedef struct st_lwLine { + short enabled; + unsigned short flags; + lwEParam size; +} lwLine; + +typedef struct st_lwSurface { + struct st_lwSurface *next, *prev; + char *name; + char *srcname; + lwCParam color; + lwTParam luminosity; + lwTParam diffuse; + lwTParam specularity; + lwTParam glossiness; + lwRMap reflection; + lwRMap transparency; + lwTParam eta; + lwTParam translucency; + lwTParam bump; + float smooth; + int sideflags; + float alpha; + int alpha_mode; + lwEParam color_hilite; + lwEParam color_filter; + lwEParam add_trans; + lwEParam dif_sharp; + lwEParam glow; + lwLine line; + lwPlugin *shader; /* linked list of shaders */ + int nshaders; +} lwSurface; + + +/* vertex maps */ + +typedef struct st_lwVMap { + struct st_lwVMap *next, *prev; + char *name; + unsigned int type; + int dim; + int nverts; + int perpoly; + int *vindex; /* array of point indexes */ + int *pindex; /* array of polygon indexes */ + float **val; +} lwVMap; + +typedef struct st_lwVMapPt { + lwVMap *vmap; + int index; /* vindex or pindex element */ +} lwVMapPt; + + +/* points and polygons */ + +typedef struct st_lwPoint { + float pos[ 3 ]; + int npols; /* number of polygons sharing the point */ + int *pol; /* array of polygon indexes */ + int nvmaps; + lwVMapPt *vm; /* array of vmap references */ +} lwPoint; + +typedef struct st_lwPolVert { + int index; /* index into the point array */ + float norm[ 3 ]; + int nvmaps; + lwVMapPt *vm; /* array of vmap references */ +} lwPolVert; + +typedef struct st_lwPolygon { + lwSurface *surf; + int part; /* part index */ + int smoothgrp; /* smoothing group */ + int flags; + unsigned int type; + float norm[ 3 ]; + int nverts; + lwPolVert *v; /* array of vertex records */ +} lwPolygon; + +typedef struct st_lwPointList { + int count; + int offset; /* only used during reading */ + lwPoint *pt; /* array of points */ +} lwPointList; + +typedef struct st_lwPolygonList { + int count; + int offset; /* only used during reading */ + int vcount; /* total number of vertices */ + int voffset; /* only used during reading */ + lwPolygon *pol; /* array of polygons */ +} lwPolygonList; + + +/* geometry layers */ + +typedef struct st_lwLayer { + struct st_lwLayer *next, *prev; + char *name; + int index; + int parent; + int flags; + float pivot[ 3 ]; + float bbox[ 6 ]; + lwPointList point; + lwPolygonList polygon; + int nvmaps; + lwVMap *vmap; /* linked list of vmaps */ +} lwLayer; + + +/* tag strings */ + +typedef struct st_lwTagList { + int count; + int offset; /* only used during reading */ + char **tag; /* array of strings */ +} lwTagList; + + +/* an object */ + +typedef struct st_lwObject { + lwLayer *layer; /* linked list of layers */ + lwEnvelope *env; /* linked list of envelopes */ + lwClip *clip; /* linked list of clips */ + lwSurface *surf; /* linked list of surfaces */ + lwTagList taglist; + int nlayers; + int nenvs; + int nclips; + int nsurfs; +} lwObject; + + +/* lwo2.c */ + +void lwFreeLayer( lwLayer *layer ); +void lwFreeObject( lwObject *object ); +lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); +int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); + +/* pntspols.c */ + +void lwFreePoints( lwPointList *point ); +void lwFreePolygons( lwPolygonList *plist ); +int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ); +void lwGetBoundingBox( lwPointList *point, float bbox[] ); +int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ); +int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); +void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ); +int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ); +int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, + lwSurface **surf, int *nsurfs ); +void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ); +void lwFreeTags( lwTagList *tlist ); +int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ); +int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, + lwPolygonList *plist ); + +/* vmap.c */ + +void lwFreeVMap( lwVMap *vmap ); +lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, + int perpoly ); +int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ); +int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ); + +/* clip.c */ + +void lwFreeClip( lwClip *clip ); +lwClip *lwGetClip( picoMemStream_t *fp, int cksize ); +lwClip *lwFindClip( lwClip *list, int index ); + +/* envelope.c */ + +void lwFreeEnvelope( lwEnvelope *env ); +lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ); +lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ); +float lwEvalEnvelope( lwEnvelope *env, float time ); + +/* surface.c */ + +void lwFreePlugin( lwPlugin *p ); +void lwFreeTexture( lwTexture *t ); +void lwFreeSurface( lwSurface *surf ); +int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ); +int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ); +int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ); +int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ); +int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ); +lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ); +lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ); +lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ); +lwSurface *lwDefaultSurface( void ); + +/* lwob.c */ + +lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ); +int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); +lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); +int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); + +/* list.c */ + +void lwListFree( void *list, void ( *freeNode )( void * )); +void lwListAdd( void **list, void *node ); +void lwListInsert( void **vlist, void *vitem, + int ( *compare )( void *, void * )); + +/* vecmath.c */ + +float dot( float a[], float b[] ); +void cross( float a[], float b[], float c[] ); +void normalize( float v[] ); +#define vecangle( a, b ) ( float ) acos( dot( a, b )) + +/* lwio.c */ + +void set_flen( int i ); +int get_flen( void ); +void *getbytes( picoMemStream_t *fp, int size ); +void skipbytes( picoMemStream_t *fp, int n ); +int getI1( picoMemStream_t *fp ); +short getI2( picoMemStream_t *fp ); +int getI4( picoMemStream_t *fp ); +unsigned char getU1( picoMemStream_t *fp ); +unsigned short getU2( picoMemStream_t *fp ); +unsigned int getU4( picoMemStream_t *fp ); +int getVX( picoMemStream_t *fp ); +float getF4( picoMemStream_t *fp ); +char *getS0( picoMemStream_t *fp ); +int sgetI1( unsigned char **bp ); +short sgetI2( unsigned char **bp ); +int sgetI4( unsigned char **bp ); +unsigned char sgetU1( unsigned char **bp ); +unsigned short sgetU2( unsigned char **bp ); +unsigned int sgetU4( unsigned char **bp ); +int sgetVX( unsigned char **bp ); +float sgetF4( unsigned char **bp ); +char *sgetS0( unsigned char **bp ); + +#ifdef _WIN32 + void revbytes( void *bp, int elsize, int elcount ); +#else + #define revbytes( b, s, c ) +#endif + +#endif diff --git a/libs/picomodel/lwo/lwob.c b/libs/picomodel/lwo/lwob.c new file mode 100644 index 00000000..0e386a30 --- /dev/null +++ b/libs/picomodel/lwo/lwob.c @@ -0,0 +1,723 @@ +/* +====================================================================== +lwob.c + +Functions for an LWOB reader. LWOB is the LightWave object format +for versions of LW prior to 6.0. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ +#endif + + +/* IDs specific to LWOB */ + +#define ID_SRFS LWID_('S','R','F','S') +#define ID_FLAG LWID_('F','L','A','G') +#define ID_VLUM LWID_('V','L','U','M') +#define ID_VDIF LWID_('V','D','I','F') +#define ID_VSPC LWID_('V','S','P','C') +#define ID_RFLT LWID_('R','F','L','T') +#define ID_BTEX LWID_('B','T','E','X') +#define ID_CTEX LWID_('C','T','E','X') +#define ID_DTEX LWID_('D','T','E','X') +#define ID_LTEX LWID_('L','T','E','X') +#define ID_RTEX LWID_('R','T','E','X') +#define ID_STEX LWID_('S','T','E','X') +#define ID_TTEX LWID_('T','T','E','X') +#define ID_TFLG LWID_('T','F','L','G') +#define ID_TSIZ LWID_('T','S','I','Z') +#define ID_TCTR LWID_('T','C','T','R') +#define ID_TFAL LWID_('T','F','A','L') +#define ID_TVEL LWID_('T','V','E','L') +#define ID_TCLR LWID_('T','C','L','R') +#define ID_TVAL LWID_('T','V','A','L') +#define ID_TAMP LWID_('T','A','M','P') +#define ID_TIMG LWID_('T','I','M','G') +#define ID_TAAS LWID_('T','A','A','S') +#define ID_TREF LWID_('T','R','E','F') +#define ID_TOPC LWID_('T','O','P','C') +#define ID_SDAT LWID_('S','D','A','T') +#define ID_TFP0 LWID_('T','F','P','0') +#define ID_TFP1 LWID_('T','F','P','1') + + +/* +====================================================================== +add_clip() + +Add a clip to the clip list. Used to store the contents of an RIMG or +TIMG surface subchunk. +====================================================================== */ + +static int add_clip( char *s, lwClip **clist, int *nclips ) +{ + lwClip *clip; + char *p; + + clip = _pico_calloc( 1, sizeof( lwClip )); + if ( !clip ) return 0; + + clip->contrast.val = 1.0f; + clip->brightness.val = 1.0f; + clip->saturation.val = 1.0f; + clip->gamma.val = 1.0f; + + if ( p = strstr( s, "(sequence)" )) { + p[ -1 ] = 0; + clip->type = ID_ISEQ; + clip->source.seq.prefix = s; + clip->source.seq.digits = 3; + } + else { + clip->type = ID_STIL; + clip->source.still.name = s; + } + + *nclips++; + clip->index = *nclips; + + lwListAdd( clist, clip ); + + return clip->index; +} + + +/* +====================================================================== +add_tvel() + +Add a triple of envelopes to simulate the old texture velocity +parameters. +====================================================================== */ + +static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs ) +{ + lwEnvelope *env; + lwKey *key0, *key1; + int i; + + for ( i = 0; i < 3; i++ ) { + env = _pico_calloc( 1, sizeof( lwEnvelope )); + key0 = _pico_calloc( 1, sizeof( lwKey )); + key1 = _pico_calloc( 1, sizeof( lwKey )); + if ( !env || !key0 || !key1 ) return 0; + + key0->next = key1; + key0->value = pos[ i ]; + key0->time = 0.0f; + key1->prev = key0; + key1->value = pos[ i ] + vel[ i ] * 30.0f; + key1->time = 1.0f; + key0->shape = key1->shape = ID_LINE; + + env->index = *nenvs + i + 1; + env->type = 0x0301 + i; + env->name = _pico_alloc( 11 ); + if ( env->name ) { + strcpy( env->name, "Position.X" ); + env->name[ 9 ] += i; + } + env->key = key0; + env->nkeys = 2; + env->behavior[ 0 ] = BEH_LINEAR; + env->behavior[ 1 ] = BEH_LINEAR; + + lwListAdd( elist, env ); + } + + *nenvs += 3; + return env->index - 2; +} + + +/* +====================================================================== +get_texture() + +Create a new texture for BTEX, CTEX, etc. subchunks. +====================================================================== */ + +static lwTexture *get_texture( char *s ) +{ + lwTexture *tex; + + tex = _pico_calloc( 1, sizeof( lwTexture )); + if ( !tex ) return NULL; + + tex->tmap.size.val[ 0 ] = + tex->tmap.size.val[ 1 ] = + tex->tmap.size.val[ 2 ] = 1.0f; + tex->opacity.val = 1.0f; + tex->enabled = 1; + + if ( strstr( s, "Image Map" )) { + tex->type = ID_IMAP; + if ( strstr( s, "Planar" )) tex->param.imap.projection = 0; + else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1; + else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2; + else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3; + else if ( strstr( s, "Front" )) tex->param.imap.projection = 4; + tex->param.imap.aa_strength = 1.0f; + tex->param.imap.amplitude.val = 1.0f; + _pico_free( s ); + } + else { + tex->type = ID_PROC; + tex->param.proc.name = s; + } + + return tex; +} + + +/* +====================================================================== +lwGetSurface5() + +Read an lwSurface from an LWOB file. +====================================================================== */ + +lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ) +{ + lwSurface *surf; + lwTexture *tex; + lwPlugin *shdr; + char *s; + float v[ 3 ]; + unsigned int id, flags; + unsigned short sz; + int pos, rlen, i; + + + /* allocate the Surface structure */ + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) goto Fail; + + /* non-zero defaults */ + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* name */ + + surf->name = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_COLR: + surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f; + surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f; + surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f; + break; + + case ID_FLAG: + flags = getU2( fp ); + if ( flags & 4 ) surf->smooth = 1.56207f; + if ( flags & 8 ) surf->color_hilite.val = 1.0f; + if ( flags & 16 ) surf->color_filter.val = 1.0f; + if ( flags & 128 ) surf->dif_sharp.val = 0.5f; + if ( flags & 256 ) surf->sideflags = 3; + if ( flags & 512 ) surf->add_trans.val = 1.0f; + break; + + case ID_LUMI: + surf->luminosity.val = getI2( fp ) / 256.0f; + break; + + case ID_VLUM: + surf->luminosity.val = getF4( fp ); + break; + + case ID_DIFF: + surf->diffuse.val = getI2( fp ) / 256.0f; + break; + + case ID_VDIF: + surf->diffuse.val = getF4( fp ); + break; + + case ID_SPEC: + surf->specularity.val = getI2( fp ) / 256.0f; + break; + + case ID_VSPC: + surf->specularity.val = getF4( fp ); + break; + + case ID_GLOS: + surf->glossiness.val = ( float ) log( getU2( fp )) / 20.7944f; + break; + + case ID_SMAN: + surf->smooth = getF4( fp ); + break; + + case ID_REFL: + surf->reflection.val.val = getI2( fp ) / 256.0f; + break; + + case ID_RFLT: + surf->reflection.options = getU2( fp ); + break; + + case ID_RIMG: + s = getS0( fp ); + surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips ); + surf->reflection.options = 3; + break; + + case ID_RSAN: + surf->reflection.seam_angle = getF4( fp ); + break; + + case ID_TRAN: + surf->transparency.val.val = getI2( fp ) / 256.0f; + break; + + case ID_RIND: + surf->eta.val = getF4( fp ); + break; + + case ID_BTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->bump.tex, tex ); + break; + + case ID_CTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->color.tex, tex ); + break; + + case ID_DTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->diffuse.tex, tex ); + break; + + case ID_LTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->luminosity.tex, tex ); + break; + + case ID_RTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->reflection.val.tex, tex ); + break; + + case ID_STEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->specularity.tex, tex ); + break; + + case ID_TTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->transparency.val.tex, tex ); + break; + + case ID_TFLG: + flags = getU2( fp ); + + if ( flags & 1 ) i = 0; + if ( flags & 2 ) i = 1; + if ( flags & 4 ) i = 2; + tex->axis = i; + if ( tex->type == ID_IMAP ) + tex->param.imap.axis = i; + else + tex->param.proc.axis = i; + + if ( flags & 8 ) tex->tmap.coord_sys = 1; + if ( flags & 16 ) tex->negative = 1; + if ( flags & 32 ) tex->param.imap.pblend = 1; + if ( flags & 64 ) { + tex->param.imap.aa_strength = 1.0f; + tex->param.imap.aas_flags = 1; + } + break; + + case ID_TSIZ: + for ( i = 0; i < 3; i++ ) + tex->tmap.size.val[ i ] = getF4( fp ); + break; + + case ID_TCTR: + for ( i = 0; i < 3; i++ ) + tex->tmap.center.val[ i ] = getF4( fp ); + break; + + case ID_TFAL: + for ( i = 0; i < 3; i++ ) + tex->tmap.falloff.val[ i ] = getF4( fp ); + break; + + case ID_TVEL: + for ( i = 0; i < 3; i++ ) + v[ i ] = getF4( fp ); + tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v, + &obj->env, &obj->nenvs ); + break; + + case ID_TCLR: + if ( tex->type == ID_PROC ) + for ( i = 0; i < 3; i++ ) + tex->param.proc.value[ i ] = getU1( fp ) / 255.0f; + break; + + case ID_TVAL: + tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f; + break; + + case ID_TAMP: + if ( tex->type == ID_IMAP ) + tex->param.imap.amplitude.val = getF4( fp ); + break; + + case ID_TIMG: + s = getS0( fp ); + tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips ); + break; + + case ID_TAAS: + tex->param.imap.aa_strength = getF4( fp ); + tex->param.imap.aas_flags = 1; + break; + + case ID_TREF: + tex->tmap.ref_object = getbytes( fp, sz ); + break; + + case ID_TOPC: + tex->opacity.val = getF4( fp ); + break; + + case ID_TFP0: + if ( tex->type == ID_IMAP ) + tex->param.imap.wrapw.val = getF4( fp ); + break; + + case ID_TFP1: + if ( tex->type == ID_IMAP ) + tex->param.imap.wraph.val = getF4( fp ); + break; + + case ID_SHDR: + shdr = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !shdr ) goto Fail; + shdr->name = getbytes( fp, sz ); + lwListAdd( &surf->shader, shdr ); + surf->nshaders++; + break; + + case ID_SDAT: + shdr->data = getbytes( fp, sz ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the SURF chunk? */ + + if ( cksize <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return surf; + +Fail: + if ( surf ) lwFreeSurface( surf ); + return NULL; +} + + +/* +====================================================================== +lwGetPolygons5() + +Read polygon records from a POLS chunk in an LWOB file. The polygons +are added to the array in the lwPolygonList. +====================================================================== */ + +int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) +{ + lwPolygon *pp; + lwPolVert *pv; + unsigned char *buf, *bp; + int i, j, nv, nverts, npols; + + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) goto Fail; + + /* count the polygons and vertices */ + + nverts = 0; + npols = 0; + bp = buf; + + while ( bp < buf + cksize ) { + nv = sgetU2( &bp ); + nverts += nv; + npols++; + bp += 2 * nv; + i = sgetI2( &bp ); + if ( i < 0 ) bp += 2; /* detail polygons */ + } + + if ( !lwAllocPolygons( plist, npols, nverts )) + goto Fail; + + /* fill in the new polygons */ + + bp = buf; + pp = plist->pol + plist->offset; + pv = plist->pol[ 0 ].v + plist->voffset; + + for ( i = 0; i < npols; i++ ) { + nv = sgetU2( &bp ); + + pp->nverts = nv; + pp->type = ID_FACE; + if ( !pp->v ) pp->v = pv; + for ( j = 0; j < nv; j++ ) + pv[ j ].index = sgetU2( &bp ) + ptoffset; + j = sgetI2( &bp ); + if ( j < 0 ) { + j = -j; + bp += 2; + } + j -= 1; + pp->surf = ( lwSurface * ) j; + + pp++; + pv += nv; + } + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreePolygons( plist ); + return 0; +} + + +/* +====================================================================== +getLWObject5() + +Returns the contents of an LWOB, given its filename, or NULL if the +file couldn't be loaded. On failure, failID and failpos can be used +to diagnose the cause. + +1. If the file isn't an LWOB, failpos will contain 12 and failID will + be unchanged. + +2. If an error occurs while reading an LWOB, failID will contain the + most recently read IFF chunk ID, and failpos will contain the + value returned by _pico_memstream_tell() at the time of the failure. + +3. If the file couldn't be opened, or an error occurs while reading + the first 12 bytes, both failID and failpos will be unchanged. + +If you don't need this information, failID and failpos can be NULL. +====================================================================== */ + +lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + lwObject *object; + lwLayer *layer; + lwNode *node; + unsigned int id, formsize, type, cksize; + + + /* open the file */ + + if ( !fp ) return NULL; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return NULL; + } + + /* LWOB? */ + + if ( id != ID_FORM || type != ID_LWOB ) { + if ( failpos ) *failpos = 12; + return NULL; + } + + /* allocate an object and a default layer */ + + object = _pico_calloc( 1, sizeof( lwObject )); + if ( !object ) goto Fail; + + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + object->layer = layer; + object->nlayers = 1; + + /* get the first chunk header */ + + id = getU4( fp ); + cksize = getU4( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process chunks as they're encountered */ + + while ( 1 ) { + cksize += cksize & 1; + + switch ( id ) + { + case ID_PNTS: + if ( !lwGetPoints( fp, cksize, &layer->point )) + goto Fail; + break; + + case ID_POLS: + if ( !lwGetPolygons5( fp, cksize, &layer->polygon, + layer->point.offset )) + goto Fail; + break; + + case ID_SRFS: + if ( !lwGetTags( fp, cksize, &object->taglist )) + goto Fail; + break; + + case ID_SURF: + node = ( lwNode * ) lwGetSurface5( fp, cksize, object ); + if ( !node ) goto Fail; + lwListAdd( &object->surf, node ); + object->nsurfs++; + break; + + default: + _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); + break; + } + + /* end of the file? */ + + if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + cksize = getU4( fp ); + if ( 8 != get_flen() ) goto Fail; + } + + lwGetBoundingBox( &layer->point, layer->bbox ); + lwGetPolyNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; + if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, + &object->surf, &object->nsurfs )) goto Fail; + lwGetVertNormals( &layer->point, &layer->polygon ); + + return object; + +Fail: + if ( failID ) *failID = id; + if ( fp ) { + if ( failpos ) *failpos = _pico_memstream_tell( fp ); + } + lwFreeObject( object ); + return NULL; +} + +int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + unsigned int id, formsize, type; + + + /* open the file */ + + if ( !fp ) return PICO_PMV_ERROR_MEMORY; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return PICO_PMV_ERROR_SIZE; + } + + /* LWOB? */ + + if ( id != ID_FORM || type != ID_LWOB ) { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_IDENT; + } + + return PICO_PMV_OK; +} diff --git a/libs/picomodel/lwo/pntspols.c b/libs/picomodel/lwo/pntspols.c new file mode 100644 index 00000000..d6c3152d --- /dev/null +++ b/libs/picomodel/lwo/pntspols.c @@ -0,0 +1,537 @@ +/* +====================================================================== +pntspols.c + +Point and polygon functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreePoints() + +Free the memory used by an lwPointList. +====================================================================== */ + +void lwFreePoints( lwPointList *point ) +{ + int i; + + if ( point ) { + if ( point->pt ) { + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].pol ) _pico_free( point->pt[ i ].pol ); + if ( point->pt[ i ].vm ) _pico_free( point->pt[ i ].vm ); + } + _pico_free( point->pt ); + } + memset( point, 0, sizeof( lwPointList )); + } +} + + +/* +====================================================================== +lwFreePolygons() + +Free the memory used by an lwPolygonList. +====================================================================== */ + +void lwFreePolygons( lwPolygonList *plist ) +{ + int i, j; + + if ( plist ) { + if ( plist->pol ) { + for ( i = 0; i < plist->count; i++ ) { + if ( plist->pol[ i ].v ) { + for ( j = 0; j < plist->pol[ i ].nverts; j++ ) + if ( plist->pol[ i ].v[ j ].vm ) + _pico_free( plist->pol[ i ].v[ j ].vm ); + } + } + if ( plist->pol[ 0 ].v ) + _pico_free( plist->pol[ 0 ].v ); + _pico_free( plist->pol ); + } + memset( plist, 0, sizeof( lwPolygonList )); + } +} + + +/* +====================================================================== +lwGetPoints() + +Read point records from a PNTS chunk in an LWO2 file. The points are +added to the array in the lwPointList. +====================================================================== */ + +int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ) +{ + float *f; + int np, i, j; + + if ( cksize == 1 ) return 1; + + /* extend the point array to hold the new points */ + + np = cksize / 12; + point->offset = point->count; + point->count += np; + if ( !_pico_realloc( (void *) &point->pt, (point->count - np) * sizeof( lwPoint ), point->count * sizeof( lwPoint )) ) + return 0; + memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint )); + + /* read the whole chunk */ + + f = ( float * ) getbytes( fp, cksize ); + if ( !f ) return 0; + revbytes( f, 4, np * 3 ); + + /* assign position values */ + + for ( i = 0, j = 0; i < np; i++, j += 3 ) { + point->pt[ i ].pos[ 0 ] = f[ j ]; + point->pt[ i ].pos[ 1 ] = f[ j + 1 ]; + point->pt[ i ].pos[ 2 ] = f[ j + 2 ]; + } + + _pico_free( f ); + return 1; +} + + +/* +====================================================================== +lwGetBoundingBox() + +Calculate the bounding box for a point list, but only if the bounding +box hasn't already been initialized. +====================================================================== */ + +void lwGetBoundingBox( lwPointList *point, float bbox[] ) +{ + int i, j; + + if ( point->count == 0 ) return; + + for ( i = 0; i < 6; i++ ) + if ( bbox[ i ] != 0.0f ) return; + + bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f; + bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f; + for ( i = 0; i < point->count; i++ ) { + for ( j = 0; j < 3; j++ ) { + if ( bbox[ j ] > point->pt[ i ].pos[ j ] ) + bbox[ j ] = point->pt[ i ].pos[ j ]; + if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] ) + bbox[ j + 3 ] = point->pt[ i ].pos[ j ]; + } + } +} + + +/* +====================================================================== +lwAllocPolygons() + +Allocate or extend the polygon arrays to hold new records. +====================================================================== */ + +int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ) +{ + int i; + + plist->offset = plist->count; + plist->count += npols; + if ( !_pico_realloc( (void *) &plist->pol, (plist->count - npols) * sizeof( lwPolygon ), plist->count * sizeof( lwPolygon )) ) + return 0; + memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon )); + + plist->voffset = plist->vcount; + plist->vcount += nverts; + if ( !_pico_realloc( (void *) &plist->pol[ 0 ].v, (plist->vcount - nverts) * sizeof( lwPolVert ), plist->vcount * sizeof( lwPolVert )) ) + return 0; + memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert )); + + /* fix up the old vertex pointers */ + + for ( i = 1; i < plist->offset; i++ ) + plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts; + + return 1; +} + + +/* +====================================================================== +lwGetPolygons() + +Read polygon records from a POLS chunk in an LWO2 file. The polygons +are added to the array in the lwPolygonList. +====================================================================== */ + +int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) +{ + lwPolygon *pp; + lwPolVert *pv; + unsigned char *buf, *bp; + int i, j, flags, nv, nverts, npols; + unsigned int type; + + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + type = getU4( fp ); + buf = getbytes( fp, cksize - 4 ); + if ( cksize != get_flen() ) goto Fail; + + /* count the polygons and vertices */ + + nverts = 0; + npols = 0; + bp = buf; + + while ( bp < buf + cksize - 4 ) { + nv = sgetU2( &bp ); + nv &= 0x03FF; + nverts += nv; + npols++; + for ( i = 0; i < nv; i++ ) + j = sgetVX( &bp ); + } + + if ( !lwAllocPolygons( plist, npols, nverts )) + goto Fail; + + /* fill in the new polygons */ + + bp = buf; + pp = plist->pol + plist->offset; + pv = plist->pol[ 0 ].v + plist->voffset; + + for ( i = 0; i < npols; i++ ) { + nv = sgetU2( &bp ); + flags = nv & 0xFC00; + nv &= 0x03FF; + + pp->nverts = nv; + pp->flags = flags; + pp->type = type; + if ( !pp->v ) pp->v = pv; + for ( j = 0; j < nv; j++ ) + pp->v[ j ].index = sgetVX( &bp ) + ptoffset; + + pp++; + pv += nv; + } + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreePolygons( plist ); + return 0; +} + + +/* +====================================================================== +lwGetPolyNormals() + +Calculate the polygon normals. By convention, LW's polygon normals +are found as the cross product of the first and last edges. It's +undefined for one- and two-point polygons. +====================================================================== */ + +void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ) +{ + int i, j; + float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ]; + + for ( i = 0; i < polygon->count; i++ ) { + if ( polygon->pol[ i ].nverts < 3 ) continue; + for ( j = 0; j < 3; j++ ) { + p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ]; + p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ]; + pn[ j ] = point->pt[ polygon->pol[ i ].v[ + polygon->pol[ i ].nverts - 1 ].index ].pos[ j ]; + } + + for ( j = 0; j < 3; j++ ) { + v1[ j ] = p2[ j ] - p1[ j ]; + v2[ j ] = pn[ j ] - p1[ j ]; + } + + cross( v1, v2, polygon->pol[ i ].norm ); + normalize( polygon->pol[ i ].norm ); + } +} + + +/* +====================================================================== +lwGetPointPolygons() + +For each point, fill in the indexes of the polygons that share the +point. Returns 0 if any of the memory allocations fail, otherwise +returns 1. +====================================================================== */ + +int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ) +{ + int i, j, k; + + /* count the number of polygons per point */ + + for ( i = 0; i < polygon->count; i++ ) + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) + ++point->pt[ polygon->pol[ i ].v[ j ].index ].npols; + + /* alloc per-point polygon arrays */ + + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].npols == 0 ) continue; + point->pt[ i ].pol = _pico_calloc( point->pt[ i ].npols, sizeof( int )); + if ( !point->pt[ i ].pol ) return 0; + point->pt[ i ].npols = 0; + } + + /* fill in polygon array for each point */ + + for ( i = 0; i < polygon->count; i++ ) { + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { + k = polygon->pol[ i ].v[ j ].index; + point->pt[ k ].pol[ point->pt[ k ].npols ] = i; + ++point->pt[ k ].npols; + } + } + + return 1; +} + + +/* +====================================================================== +lwResolvePolySurfaces() + +Convert tag indexes into actual lwSurface pointers. If any polygons +point to tags for which no corresponding surface can be found, a +default surface is created. +====================================================================== */ + +int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, + lwSurface **surf, int *nsurfs ) +{ + lwSurface **s, *st; + int i, index; + + if ( tlist->count == 0 ) return 1; + + s = _pico_calloc( tlist->count, sizeof( lwSurface * )); + if ( !s ) return 0; + + for ( i = 0; i < tlist->count; i++ ) { + st = *surf; + while ( st ) { + if ( !strcmp( st->name, tlist->tag[ i ] )) { + s[ i ] = st; + break; + } + st = st->next; + } + } + + for ( i = 0; i < polygon->count; i++ ) { + index = ( int ) polygon->pol[ i ].surf; + if ( index < 0 || index > tlist->count ) return 0; + if ( !s[ index ] ) { + s[ index ] = lwDefaultSurface(); + if ( !s[ index ] ) return 0; + s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 ); + if ( !s[ index ]->name ) return 0; + strcpy( s[ index ]->name, tlist->tag[ index ] ); + lwListAdd( surf, s[ index ] ); + *nsurfs = *nsurfs + 1; + } + polygon->pol[ i ].surf = s[ index ]; + } + + _pico_free( s ); + return 1; +} + + +/* +====================================================================== +lwGetVertNormals() + +Calculate the vertex normals. For each polygon vertex, sum the +normals of the polygons that share the point. If the normals of the +current and adjacent polygons form an angle greater than the max +smoothing angle for the current polygon's surface, the normal of the +adjacent polygon is excluded from the sum. It's also excluded if the +polygons aren't in the same smoothing group. + +Assumes that lwGetPointPolygons(), lwGetPolyNormals() and +lwResolvePolySurfaces() have already been called. +====================================================================== */ + +void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ) +{ + int j, k, n, g, h, p; + float a; + + for ( j = 0; j < polygon->count; j++ ) { + for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) { + for ( k = 0; k < 3; k++ ) + polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ]; + + if ( polygon->pol[ j ].surf->smooth <= 0 ) continue; + + p = polygon->pol[ j ].v[ n ].index; + + for ( g = 0; g < point->pt[ p ].npols; g++ ) { + h = point->pt[ p ].pol[ g ]; + if ( h == j ) continue; + + if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp ) + continue; + a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm ); + if ( a > polygon->pol[ j ].surf->smooth ) continue; + + for ( k = 0; k < 3; k++ ) + polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ]; + } + + normalize( polygon->pol[ j ].v[ n ].norm ); + } + } +} + + +/* +====================================================================== +lwFreeTags() + +Free memory used by an lwTagList. +====================================================================== */ + +void lwFreeTags( lwTagList *tlist ) +{ + int i; + + if ( tlist ) { + if ( tlist->tag ) { + for ( i = 0; i < tlist->count; i++ ) + if ( tlist->tag[ i ] ) _pico_free( tlist->tag[ i ] ); + _pico_free( tlist->tag ); + } + memset( tlist, 0, sizeof( lwTagList )); + } +} + + +/* +====================================================================== +lwGetTags() + +Read tag strings from a TAGS chunk in an LWO2 file. The tags are +added to the lwTagList array. +====================================================================== */ + +int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ) +{ + char *buf, *bp; + int i, len, ntags; + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) return 0; + + /* count the strings */ + + ntags = 0; + bp = buf; + while ( bp < buf + cksize ) { + len = strlen( bp ) + 1; + len += len & 1; + bp += len; + ++ntags; + } + + /* expand the string array to hold the new tags */ + + tlist->offset = tlist->count; + tlist->count += ntags; + if ( !_pico_realloc( (void *) &tlist->tag, (tlist->count - ntags) * sizeof( char * ), tlist->count * sizeof( char * )) ) + goto Fail; + memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * )); + + /* copy the new tags to the tag array */ + + bp = buf; + for ( i = 0; i < ntags; i++ ) + tlist->tag[ i + tlist->offset ] = sgetS0( &bp ); + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + return 0; +} + + +/* +====================================================================== +lwGetPolygonTags() + +Read polygon tags from a PTAG chunk in an LWO2 file. +====================================================================== */ + +int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, + lwPolygonList *plist ) +{ + unsigned int type; + int rlen = 0, i, j; + + set_flen( 0 ); + type = getU4( fp ); + rlen = get_flen(); + if ( rlen < 0 ) return 0; + + if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) { + _pico_memstream_seek( fp, cksize - 4, PICO_SEEK_CUR ); + return 1; + } + + while ( rlen < cksize ) { + i = getVX( fp ) + plist->offset; + j = getVX( fp ) + tlist->offset; + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) return 0; + + switch ( type ) { + case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break; + case ID_PART: plist->pol[ i ].part = j; break; + case ID_SMGP: plist->pol[ i ].smoothgrp = j; break; + } + } + + return 1; +} diff --git a/libs/picomodel/lwo/surface.c b/libs/picomodel/lwo/surface.c new file mode 100644 index 00000000..6456a957 --- /dev/null +++ b/libs/picomodel/lwo/surface.c @@ -0,0 +1,1004 @@ +/* +====================================================================== +surface.c + +Surface functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreePlugin() + +Free the memory used by an lwPlugin. +====================================================================== */ + +void lwFreePlugin( lwPlugin *p ) +{ + if ( p ) { + if ( p->ord ) _pico_free( p->ord ); + if ( p->name ) _pico_free( p->name ); + if ( p->data ) _pico_free( p->data ); + _pico_free( p ); + } +} + + +/* +====================================================================== +lwFreeTexture() + +Free the memory used by an lwTexture. +====================================================================== */ + +void lwFreeTexture( lwTexture *t ) +{ + if ( t ) { + if ( t->ord ) _pico_free( t->ord ); + switch ( t->type ) { + case ID_IMAP: + if ( t->param.imap.vmap_name ) _pico_free( t->param.imap.vmap_name ); + break; + case ID_PROC: + if ( t->param.proc.name ) _pico_free( t->param.proc.name ); + if ( t->param.proc.data ) _pico_free( t->param.proc.data ); + break; + case ID_GRAD: + if ( t->param.grad.key ) _pico_free( t->param.grad.key ); + if ( t->param.grad.ikey ) _pico_free( t->param.grad.ikey ); + break; + } + _pico_free( t ); + } +} + + +/* +====================================================================== +lwFreeSurface() + +Free the memory used by an lwSurface. +====================================================================== */ + +void lwFreeSurface( lwSurface *surf ) +{ + if ( surf ) { + if ( surf->name ) _pico_free( surf->name ); + if ( surf->srcname ) _pico_free( surf->srcname ); + + lwListFree( surf->shader, lwFreePlugin ); + + lwListFree( surf->color.tex, lwFreeTexture ); + lwListFree( surf->luminosity.tex, lwFreeTexture ); + lwListFree( surf->diffuse.tex, lwFreeTexture ); + lwListFree( surf->specularity.tex, lwFreeTexture ); + lwListFree( surf->glossiness.tex, lwFreeTexture ); + lwListFree( surf->reflection.val.tex, lwFreeTexture ); + lwListFree( surf->transparency.val.tex, lwFreeTexture ); + lwListFree( surf->eta.tex, lwFreeTexture ); + lwListFree( surf->translucency.tex, lwFreeTexture ); + lwListFree( surf->bump.tex, lwFreeTexture ); + + _pico_free( surf ); + } +} + + +/* +====================================================================== +lwGetTHeader() + +Read a texture map header from a SURF.BLOK in an LWO2 file. This is +the first subchunk in a BLOK, and its contents are common to all three +texture types. +====================================================================== */ + +int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int pos, rlen; + + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* ordinal string */ + + tex->ord = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_CHAN: + tex->chan = getU4( fp ); + break; + + case ID_OPAC: + tex->opac_type = getU2( fp ); + tex->opacity.val = getF4( fp ); + tex->opacity.eindex = getVX( fp ); + break; + + case ID_ENAB: + tex->enabled = getU2( fp ); + break; + + case ID_NEGA: + tex->negative = getU2( fp ); + break; + + case ID_AXIS: + tex->axis = getU2( fp ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the texture header subchunk? */ + + if ( hsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetTMap() + +Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP +defines the mapping from texture to world or object coordinates. +====================================================================== */ + +int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos, i; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_SIZE: + for ( i = 0; i < 3; i++ ) + tmap->size.val[ i ] = getF4( fp ); + tmap->size.eindex = getVX( fp ); + break; + + case ID_CNTR: + for ( i = 0; i < 3; i++ ) + tmap->center.val[ i ] = getF4( fp ); + tmap->center.eindex = getVX( fp ); + break; + + case ID_ROTA: + for ( i = 0; i < 3; i++ ) + tmap->rotate.val[ i ] = getF4( fp ); + tmap->rotate.eindex = getVX( fp ); + break; + + case ID_FALL: + tmap->fall_type = getU2( fp ); + for ( i = 0; i < 3; i++ ) + tmap->falloff.val[ i ] = getF4( fp ); + tmap->falloff.eindex = getVX( fp ); + break; + + case ID_OREF: + tmap->ref_object = getS0( fp ); + break; + + case ID_CSYS: + tmap->coord_sys = getU2( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the TMAP subchunk? */ + + if ( tmapsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetImageMap() + +Read an lwImageMap from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_PROJ: + tex->param.imap.projection = getU2( fp ); + break; + + case ID_VMAP: + tex->param.imap.vmap_name = getS0( fp ); + break; + + case ID_AXIS: + tex->param.imap.axis = getU2( fp ); + break; + + case ID_IMAG: + tex->param.imap.cindex = getVX( fp ); + break; + + case ID_WRAP: + tex->param.imap.wrapw_type = getU2( fp ); + tex->param.imap.wraph_type = getU2( fp ); + break; + + case ID_WRPW: + tex->param.imap.wrapw.val = getF4( fp ); + tex->param.imap.wrapw.eindex = getVX( fp ); + break; + + case ID_WRPH: + tex->param.imap.wraph.val = getF4( fp ); + tex->param.imap.wraph.eindex = getVX( fp ); + break; + + case ID_AAST: + tex->param.imap.aas_flags = getU2( fp ); + tex->param.imap.aa_strength = getF4( fp ); + break; + + case ID_PIXB: + tex->param.imap.pblend = getU2( fp ); + break; + + case ID_STCK: + tex->param.imap.stck.val = getF4( fp ); + tex->param.imap.stck.eindex = getVX( fp ); + break; + + case ID_TAMP: + tex->param.imap.amplitude.val = getF4( fp ); + tex->param.imap.amplitude.eindex = getVX( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the image map? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetProcedural() + +Read an lwProcedural from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_AXIS: + tex->param.proc.axis = getU2( fp ); + break; + + case ID_VALU: + tex->param.proc.value[ 0 ] = getF4( fp ); + if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp ); + if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp ); + break; + + case ID_FUNC: + tex->param.proc.name = getS0( fp ); + rlen = get_flen(); + tex->param.proc.data = getbytes( fp, sz - rlen ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the procedural block? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetGradient() + +Read an lwGradient from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos, i, j, nkeys; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_PNAM: + tex->param.grad.paramname = getS0( fp ); + break; + + case ID_INAM: + tex->param.grad.itemname = getS0( fp ); + break; + + case ID_GRST: + tex->param.grad.start = getF4( fp ); + break; + + case ID_GREN: + tex->param.grad.end = getF4( fp ); + break; + + case ID_GRPT: + tex->param.grad.repeat = getU2( fp ); + break; + + case ID_FKEY: + nkeys = sz / sizeof( lwGradKey ); + tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey )); + if ( !tex->param.grad.key ) return 0; + for ( i = 0; i < nkeys; i++ ) { + tex->param.grad.key[ i ].value = getF4( fp ); + for ( j = 0; j < 4; j++ ) + tex->param.grad.key[ i ].rgba[ j ] = getF4( fp ); + } + break; + + case ID_IKEY: + nkeys = sz / 2; + tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short )); + if ( !tex->param.grad.ikey ) return 0; + for ( i = 0; i < nkeys; i++ ) + tex->param.grad.ikey[ i ] = getU2( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the gradient? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetTexture() + +Read an lwTexture from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ) +{ + lwTexture *tex; + unsigned short sz; + int ok; + + tex = _pico_calloc( 1, sizeof( lwTexture )); + if ( !tex ) return NULL; + + tex->type = type; + tex->tmap.size.val[ 0 ] = + tex->tmap.size.val[ 1 ] = + tex->tmap.size.val[ 2 ] = 1.0f; + tex->opacity.val = 1.0f; + tex->enabled = 1; + + sz = getU2( fp ); + if ( !lwGetTHeader( fp, sz, tex )) { + _pico_free( tex ); + return NULL; + } + + sz = bloksz - sz - 6; + switch ( type ) { + case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break; + case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break; + case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break; + default: + ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); + } + + if ( !ok ) { + lwFreeTexture( tex ); + return NULL; + } + + set_flen( bloksz ); + return tex; +} + + +/* +====================================================================== +lwGetShader() + +Read a shader record from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ) +{ + lwPlugin *shdr; + unsigned int id; + unsigned short sz; + int hsz, rlen, pos; + + shdr = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !shdr ) return NULL; + + pos = _pico_memstream_tell( fp ); + set_flen( 0 ); + hsz = getU2( fp ); + shdr->ord = getS0( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( hsz > 0 ) { + sz += sz & 1; + hsz -= sz; + if ( id == ID_ENAB ) { + shdr->flags = getU2( fp ); + break; + } + else { + _pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); + id = getU4( fp ); + sz = getU2( fp ); + } + } + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_FUNC: + shdr->name = getS0( fp ); + rlen = get_flen(); + shdr->data = getbytes( fp, sz - rlen ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the shader block? */ + + if ( bloksz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return shdr; + +Fail: + lwFreePlugin( shdr ); + return NULL; +} + + +/* +====================================================================== +compare_textures() +compare_shaders() + +Callbacks for the lwListInsert() function, which is called to add +textures to surface channels and shaders to surfaces. +====================================================================== */ + +static int compare_textures( lwTexture *a, lwTexture *b ) +{ + return strcmp( a->ord, b->ord ); +} + + +static int compare_shaders( lwPlugin *a, lwPlugin *b ) +{ + return strcmp( a->ord, b->ord ); +} + + +/* +====================================================================== +add_texture() + +Finds the surface channel (lwTParam or lwCParam) to which a texture is +applied, then calls lwListInsert(). +====================================================================== */ + +static int add_texture( lwSurface *surf, lwTexture *tex ) +{ + lwTexture **list; + + switch ( tex->chan ) { + case ID_COLR: list = &surf->color.tex; break; + case ID_LUMI: list = &surf->luminosity.tex; break; + case ID_DIFF: list = &surf->diffuse.tex; break; + case ID_SPEC: list = &surf->specularity.tex; break; + case ID_GLOS: list = &surf->glossiness.tex; break; + case ID_REFL: list = &surf->reflection.val.tex; break; + case ID_TRAN: list = &surf->transparency.val.tex; break; + case ID_RIND: list = &surf->eta.tex; break; + case ID_TRNL: list = &surf->translucency.tex; break; + case ID_BUMP: list = &surf->bump.tex; break; + default: return 0; + } + + lwListInsert( list, tex, compare_textures ); + return 1; +} + + +/* +====================================================================== +lwDefaultSurface() + +Allocate and initialize a surface. +====================================================================== */ + +lwSurface *lwDefaultSurface( void ) +{ + lwSurface *surf; + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) return NULL; + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + return surf; +} + + +/* +====================================================================== +lwGetSurface() + +Read an lwSurface from an LWO2 file. +====================================================================== */ + +lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ) +{ + lwSurface *surf; + lwTexture *tex; + lwPlugin *shdr; + unsigned int id, type; + unsigned short sz; + int pos, rlen; + + + /* allocate the Surface structure */ + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) goto Fail; + + /* non-zero defaults */ + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* names */ + + surf->name = getS0( fp ); + surf->srcname = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_COLR: + surf->color.rgb[ 0 ] = getF4( fp ); + surf->color.rgb[ 1 ] = getF4( fp ); + surf->color.rgb[ 2 ] = getF4( fp ); + surf->color.eindex = getVX( fp ); + break; + + case ID_LUMI: + surf->luminosity.val = getF4( fp ); + surf->luminosity.eindex = getVX( fp ); + break; + + case ID_DIFF: + surf->diffuse.val = getF4( fp ); + surf->diffuse.eindex = getVX( fp ); + break; + + case ID_SPEC: + surf->specularity.val = getF4( fp ); + surf->specularity.eindex = getVX( fp ); + break; + + case ID_GLOS: + surf->glossiness.val = getF4( fp ); + surf->glossiness.eindex = getVX( fp ); + break; + + case ID_REFL: + surf->reflection.val.val = getF4( fp ); + surf->reflection.val.eindex = getVX( fp ); + break; + + case ID_RFOP: + surf->reflection.options = getU2( fp ); + break; + + case ID_RIMG: + surf->reflection.cindex = getVX( fp ); + break; + + case ID_RSAN: + surf->reflection.seam_angle = getF4( fp ); + break; + + case ID_TRAN: + surf->transparency.val.val = getF4( fp ); + surf->transparency.val.eindex = getVX( fp ); + break; + + case ID_TROP: + surf->transparency.options = getU2( fp ); + break; + + case ID_TIMG: + surf->transparency.cindex = getVX( fp ); + break; + + case ID_RIND: + surf->eta.val = getF4( fp ); + surf->eta.eindex = getVX( fp ); + break; + + case ID_TRNL: + surf->translucency.val = getF4( fp ); + surf->translucency.eindex = getVX( fp ); + break; + + case ID_BUMP: + surf->bump.val = getF4( fp ); + surf->bump.eindex = getVX( fp ); + break; + + case ID_SMAN: + surf->smooth = getF4( fp ); + break; + + case ID_SIDE: + surf->sideflags = getU2( fp ); + break; + + case ID_CLRH: + surf->color_hilite.val = getF4( fp ); + surf->color_hilite.eindex = getVX( fp ); + break; + + case ID_CLRF: + surf->color_filter.val = getF4( fp ); + surf->color_filter.eindex = getVX( fp ); + break; + + case ID_ADTR: + surf->add_trans.val = getF4( fp ); + surf->add_trans.eindex = getVX( fp ); + break; + + case ID_SHRP: + surf->dif_sharp.val = getF4( fp ); + surf->dif_sharp.eindex = getVX( fp ); + break; + + case ID_GVAL: + surf->glow.val = getF4( fp ); + surf->glow.eindex = getVX( fp ); + break; + + case ID_LINE: + surf->line.enabled = 1; + if ( sz >= 2 ) surf->line.flags = getU2( fp ); + if ( sz >= 6 ) surf->line.size.val = getF4( fp ); + if ( sz >= 8 ) surf->line.size.eindex = getVX( fp ); + break; + + case ID_ALPH: + surf->alpha_mode = getU2( fp ); + surf->alpha = getF4( fp ); + break; + + case ID_AVAL: + surf->alpha = getF4( fp ); + break; + + case ID_BLOK: + type = getU4( fp ); + + switch ( type ) { + case ID_IMAP: + case ID_PROC: + case ID_GRAD: + tex = lwGetTexture( fp, sz - 4, type ); + if ( !tex ) goto Fail; + if ( !add_texture( surf, tex )) + lwFreeTexture( tex ); + set_flen( 4 + get_flen() ); + break; + case ID_SHDR: + shdr = lwGetShader( fp, sz - 4 ); + if ( !shdr ) goto Fail; + lwListInsert( &surf->shader, shdr, compare_shaders ); + ++surf->nshaders; + set_flen( 4 + get_flen() ); + break; + } + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the SURF chunk? */ + + if ( cksize <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return surf; + +Fail: + if ( surf ) lwFreeSurface( surf ); + return NULL; +} diff --git a/libs/picomodel/lwo/vecmath.c b/libs/picomodel/lwo/vecmath.c new file mode 100644 index 00000000..44d317b0 --- /dev/null +++ b/libs/picomodel/lwo/vecmath.c @@ -0,0 +1,37 @@ +/* +====================================================================== +vecmath.c + +Basic vector and matrix functions. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include + + +float dot( float a[], float b[] ) +{ + return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; +} + + +void cross( float a[], float b[], float c[] ) +{ + 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 ]; +} + + +void normalize( float v[] ) +{ + float r; + + r = ( float ) sqrt( dot( v, v )); + if ( r > 0 ) { + v[ 0 ] /= r; + v[ 1 ] /= r; + v[ 2 ] /= r; + } +} diff --git a/libs/picomodel/lwo/vmap.c b/libs/picomodel/lwo/vmap.c new file mode 100644 index 00000000..1a24bee0 --- /dev/null +++ b/libs/picomodel/lwo/vmap.c @@ -0,0 +1,243 @@ +/* +====================================================================== +vmap.c + +Vertex map functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreeVMap() + +Free memory used by an lwVMap. +====================================================================== */ + +void lwFreeVMap( lwVMap *vmap ) +{ + if ( vmap ) { + if ( vmap->name ) _pico_free( vmap->name ); + if ( vmap->vindex ) _pico_free( vmap->vindex ); + if ( vmap->pindex ) _pico_free( vmap->pindex ); + if ( vmap->val ) { + if ( vmap->val[ 0 ] ) _pico_free( vmap->val[ 0 ] ); + _pico_free( vmap->val ); + } + _pico_free( vmap ); + } +} + + +/* +====================================================================== +lwGetVMap() + +Read an lwVMap from a VMAP or VMAD chunk in an LWO2. +====================================================================== */ + +lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, + int perpoly ) +{ + unsigned char *buf, *bp; + lwVMap *vmap; + float *f; + int i, j, npts, rlen; + + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) return NULL; + + vmap = _pico_calloc( 1, sizeof( lwVMap )); + if ( !vmap ) { + _pico_free( buf ); + return NULL; + } + + /* initialize the vmap */ + + vmap->perpoly = perpoly; + + bp = buf; + set_flen( 0 ); + vmap->type = sgetU4( &bp ); + vmap->dim = sgetU2( &bp ); + vmap->name = sgetS0( &bp ); + rlen = get_flen(); + + /* count the vmap records */ + + npts = 0; + while ( bp < buf + cksize ) { + i = sgetVX( &bp ); + if ( perpoly ) + i = sgetVX( &bp ); + bp += vmap->dim * sizeof( float ); + ++npts; + } + + /* allocate the vmap */ + + vmap->nverts = npts; + vmap->vindex = _pico_calloc( npts, sizeof( int )); + if ( !vmap->vindex ) goto Fail; + if ( perpoly ) { + vmap->pindex = _pico_calloc( npts, sizeof( int )); + if ( !vmap->pindex ) goto Fail; + } + + if ( vmap->dim > 0 ) { + vmap->val = _pico_calloc( npts, sizeof( float * )); + if ( !vmap->val ) goto Fail; + f = _pico_alloc( npts * vmap->dim * sizeof( float )); + if ( !f ) goto Fail; + for ( i = 0; i < npts; i++ ) + vmap->val[ i ] = f + i * vmap->dim; + } + + /* fill in the vmap values */ + + bp = buf + rlen; + for ( i = 0; i < npts; i++ ) { + vmap->vindex[ i ] = sgetVX( &bp ); + if ( perpoly ) + vmap->pindex[ i ] = sgetVX( &bp ); + for ( j = 0; j < vmap->dim; j++ ) + vmap->val[ i ][ j ] = sgetF4( &bp ); + } + + _pico_free( buf ); + return vmap; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreeVMap( vmap ); + return NULL; +} + + +/* +====================================================================== +lwGetPointVMaps() + +Fill in the lwVMapPt structure for each point. +====================================================================== */ + +int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ) +{ + lwVMap *vm; + int i, j, n; + + /* count the number of vmap values for each point */ + + vm = vmap; + while ( vm ) { + if ( !vm->perpoly ) + for ( i = 0; i < vm->nverts; i++ ) + ++point->pt[ vm->vindex[ i ]].nvmaps; + vm = vm->next; + } + + /* allocate vmap references for each mapped point */ + + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].nvmaps ) { + point->pt[ i ].vm = _pico_calloc( point->pt[ i ].nvmaps, sizeof( lwVMapPt )); + if ( !point->pt[ i ].vm ) return 0; + point->pt[ i ].nvmaps = 0; + } + } + + /* fill in vmap references for each mapped point */ + + vm = vmap; + while ( vm ) { + if ( !vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + j = vm->vindex[ i ]; + n = point->pt[ j ].nvmaps; + point->pt[ j ].vm[ n ].vmap = vm; + point->pt[ j ].vm[ n ].index = i; + ++point->pt[ j ].nvmaps; + } + } + vm = vm->next; + } + + return 1; +} + + +/* +====================================================================== +lwGetPolyVMaps() + +Fill in the lwVMapPt structure for each polygon vertex. +====================================================================== */ + +int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ) +{ + lwVMap *vm; + lwPolVert *pv; + int i, j; + + /* count the number of vmap values for each polygon vertex */ + + vm = vmap; + while ( vm ) { + if ( vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { + pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; + if ( vm->vindex[ i ] == pv->index ) { + ++pv->nvmaps; + break; + } + } + } + } + vm = vm->next; + } + + /* allocate vmap references for each mapped vertex */ + + for ( i = 0; i < polygon->count; i++ ) { + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { + pv = &polygon->pol[ i ].v[ j ]; + if ( pv->nvmaps ) { + pv->vm = _pico_calloc( pv->nvmaps, sizeof( lwVMapPt )); + if ( !pv->vm ) return 0; + pv->nvmaps = 0; + } + } + } + + /* fill in vmap references for each mapped point */ + + vm = vmap; + while ( vm ) { + if ( vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { + pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; + if ( vm->vindex[ i ] == pv->index ) { + pv->vm[ pv->nvmaps ].vmap = vm; + pv->vm[ pv->nvmaps ].index = i; + ++pv->nvmaps; + break; + } + } + } + } + vm = vm->next; + } + + return 1; +} diff --git a/libs/picomodel/picointernal.c b/libs/picomodel/picointernal.c new file mode 100644 index 00000000..6afae90a --- /dev/null +++ b/libs/picomodel/picointernal.c @@ -0,0 +1,1353 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOINTERNAL_C + + + +/* todo: + * - fix p->curLine for parser routines. increased twice + */ + +/* dependencies */ +#include +#include "picointernal.h" + + + +/* function pointers */ +void *(*_pico_ptr_malloc )( size_t ) = malloc; +void (*_pico_ptr_free )( void* ) = free; +void (*_pico_ptr_load_file )( char*, unsigned char**, int* ) = NULL; +void (*_pico_ptr_free_file )( void* ) = NULL; +void (*_pico_ptr_print )( int, const char* ) = NULL; + +typedef union +{ + float f; + char c[4]; +} +floatSwapUnion; + +/* _pico_alloc: + * kludged memory allocation wrapper + */ +void *_pico_alloc( size_t size ) +{ + void *ptr; + + /* some sanity checks */ + if( size == 0 ) + return NULL; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate memory */ + ptr = _pico_ptr_malloc(size); + if (ptr == NULL) + return NULL; + + /* zero out allocated memory */ + memset(ptr,0,size); + + /* return pointer to allocated memory */ + return ptr; +} + +/* _pico_calloc: + * _pico_calloc wrapper + */ +void *_pico_calloc( size_t num, size_t size ) +{ + void *ptr; + + /* some sanity checks */ + if( num == 0 || size == 0 ) + return NULL; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate memory */ + ptr = _pico_ptr_malloc(num*size); + if (ptr == NULL) + return NULL; + + /* zero out allocated memory */ + memset(ptr,0,num*size); + + /* return pointer to allocated memory */ + return ptr; +} + +/* _pico_realloc: + * memory reallocation wrapper (note: only grows, + * but never shrinks or frees) + */ +void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ) +{ + void *ptr2; + + /* sanity checks */ + if( ptr == NULL ) + return NULL; + if( newSize < oldSize ) + return *ptr; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate new pointer */ + ptr2 = _pico_alloc( newSize ); + if( ptr2 == NULL ) + return NULL; + + /* copy */ + if( *ptr != NULL ) + { + memcpy( ptr2, *ptr, oldSize ); + _pico_free( *ptr ); + } + + /* fix up and return */ + *ptr = ptr2; + return *ptr; +} + +/* _pico_clone_alloc: + * handy function for quick string allocation/copy. it clones + * the given string and returns a pointer to the new allocated + * clone (which must be freed by caller of course) or returns + * NULL on memory alloc or param errors. if 'size' is -1 the + * length of the input string is used, otherwise 'size' is used + * as custom clone size (the string is cropped to fit into mem + * if needed). -sea + */ +char *_pico_clone_alloc( char *str, int size ) +{ + char *cloned; + size_t cloneSize; + + /* sanity check */ + if (str == NULL) return NULL; + + /* set real size of cloned string */ + cloneSize = (size < 0) ? strlen(str) : size; + + /* allocate memory */ + cloned = _pico_alloc( cloneSize+1 ); /* bugfix! */ + if (cloned == NULL) + return NULL; + + /* zero out memory allocated by cloned string */ + memset( cloned,0,cloneSize ); + + /* copy input string to cloned string */ + if (cloneSize < strlen( str )) { + memcpy( cloned,str,cloneSize ); + cloned[ cloneSize ] = '\0'; + } else { + strcpy( cloned,str ); + } + /* return ptr to cloned string */ + return cloned; +} + +/* _pico_free: + * wrapper around the free function pointer + */ +void _pico_free( void *ptr ) +{ + /* sanity checks */ + if( ptr == NULL ) + return; + if (_pico_ptr_free == NULL) + return; + + /* free the allocated memory */ + _pico_ptr_free( ptr ); +} + +/* _pico_load_file: + * wrapper around the loadfile function pointer + */ +void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ) +{ + /* sanity checks */ + if( name == NULL ) + { + *bufSize = -1; + return; + } + if (_pico_ptr_load_file == NULL) + { + *bufSize = -1; + return; + } + /* do the actual call to read in the file; */ + /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */ + _pico_ptr_load_file( name,buffer,bufSize ); +} + +/* _pico_free_file: + * wrapper around the file free function pointer + */ +void _pico_free_file( void *buffer ) +{ + /* sanity checks */ + if( buffer == NULL ) + return; + + /* use default free */ + if( _pico_ptr_free_file == NULL ) + { + free( buffer ); + return; + } + /* free the allocated file */ + _pico_ptr_free_file( buffer ); +} + +/* _pico_printf: + * wrapper around the print function pointer -sea + */ +void _pico_printf( int level, const char *format, ...) +{ + char str[4096]; + va_list argptr; + + /* sanity checks */ + if( format == NULL ) + return; + if (_pico_ptr_print == NULL) + return; + + /* format string */ + va_start( argptr,format ); + vsprintf( str,format,argptr ); + va_end( argptr ); + + /* remove linefeeds */ + if (str[ strlen(str)-1 ] == '\n') + str[ strlen(str)-1 ] = '\0'; + + /* do the actual call */ + _pico_ptr_print( level,str ); +} + +/* _pico_strltrim: + * left trims the given string -sea + */ +char *_pico_strltrim( char *str ) +{ + char *str1 = str, *str2 = str; + + while (isspace(*str2)) str2++; + if( str2 != str ) + while( *str2 != '\0' ) /* fix: ydnar */ + *str1++ = *str2++; + return str; +} + +/* _pico_strrtrim: + * right trims the given string -sea + */ +char *_pico_strrtrim( char *str ) +{ + if (str && *str) + { + char *str1 = str; + int allspace = 1; + + while (*str1) + { + if (allspace && !isspace(*str1)) allspace = 0; + str1++; + } + if (allspace) *str = '\0'; + else { + str1--; + while ((isspace(*str1)) && (str1 >= str)) + *str1-- = '\0'; + } + } + return str; +} + +/* _pico_strlwr: + * pico internal string-to-lower routine. + */ +char *_pico_strlwr( char *str ) +{ + char *cp; + for (cp=str; *cp; ++cp) + { + if ('A' <= *cp && *cp <= 'Z') + { + *cp += ('a' - 'A'); + } + } + return str; +} + +/* _pico_strchcount: + * counts how often the given char appears in str. -sea + */ +int _pico_strchcount( char *str, int ch ) +{ + int count = 0; + while (*str++) if (*str == ch) count++; + return count; +} + +void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ) +{ + int i; + for (i=0; i<3; i++) + { + mins[i] = +999999; + maxs[i] = -999999; + } +} + +void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ) +{ + int i; + for (i=0; i<3; i++) + { + float value = p[i]; + if (value < mins[i]) mins[i] = value; + if (value > maxs[i]) maxs[i] = value; + } +} + +void _pico_zero_vec( picoVec3_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0; +} + +void _pico_zero_vec2( picoVec2_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = 0; +} + +void _pico_zero_vec4( picoVec4_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0; +} + +void _pico_set_vec( picoVec3_t v, float a, float b, float c ) +{ + v[ 0 ] = a; + v[ 1 ] = b; + v[ 2 ] = c; +} + +void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ) +{ + v[ 0 ] = a; + v[ 1 ] = b; + v[ 2 ] = c; + v[ 3 ] = d; +} + +void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; +} + +void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; +} + +void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; + dest[ 3 ] = src[ 3 ]; +} + +/* ydnar */ +picoVec_t _pico_normalize_vec( picoVec3_t vec ) +{ + double len, ilen; + + len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] ); + if( len == 0.0 ) return 0.0; + ilen = 1.0 / len; + vec[ 0 ] *= (picoVec_t) ilen; + vec[ 1 ] *= (picoVec_t) ilen; + vec[ 2 ] *= (picoVec_t) ilen; + return (picoVec_t) len; +} + +void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 0 ] + b[ 0 ]; + dest[ 1 ] = a[ 1 ] + b[ 1 ]; + dest[ 2 ] = a[ 2 ] + b[ 2 ]; +} + +void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 0 ] - b[ 0 ]; + dest[ 1 ] = a[ 1 ] - b[ 1 ]; + dest[ 2 ] = a[ 2 ] - b[ 2 ]; +} + +void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ) +{ + dest[ 0 ] = v[ 0 ] * scale; + dest[ 1 ] = v[ 1 ] * scale; + dest[ 2 ] = v[ 2 ] * scale; +} + +void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ) +{ + dest[ 0 ] = v[ 0 ] * scale; + dest[ 1 ] = v[ 1 ] * scale; + dest[ 2 ] = v[ 2 ] * scale; + dest[ 3 ] = v[ 3 ] * scale; +} + +picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ) +{ + return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; +} + +void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + 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 ]; +} + +picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ) +{ + picoVec3_t ba, ca; + + _pico_subtract_vec( b, a, ba ); + _pico_subtract_vec( c, a, ca ); + _pico_cross_vec( ca, ba, plane ); + plane[ 3 ] = _pico_dot_vec( a, plane ); + return _pico_normalize_vec( plane ); +} + +/* separate from _pico_set_vec4 */ +void _pico_set_color( picoColor_t c, int r, int g, int b, int a ) +{ + c[ 0 ] = r; + c[ 1 ] = g; + c[ 2 ] = b; + c[ 3 ] = a; +} + +void _pico_copy_color( picoColor_t src, picoColor_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; + dest[ 3 ] = src[ 3 ]; +} + +#ifdef __BIG_ENDIAN__ + +int _pico_big_long ( int src ) { return src; } +short _pico_big_short( short src ) { return src; } +float _pico_big_float( float src ) { return src; } + +int _pico_little_long( int src ) +{ + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); +} + +short _pico_little_short( short src ) +{ + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); +} + +float _pico_little_float( float src ) +{ + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; +} +#else /*__BIG_ENDIAN__*/ + +int _pico_little_long ( int src ) { return src; } +short _pico_little_short( short src ) { return src; } +float _pico_little_float( float src ) { return src; } + +int _pico_big_long( int src ) +{ + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); +} + +short _pico_big_short( short src ) +{ + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); +} + +float _pico_big_float( float src ) +{ + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; +} +#endif /*__BIG_ENDIAN__*/ + +/* _pico_stristr: + * case-insensitive strstr. -sea + */ +char *_pico_stristr( char *str, const char *substr ) +{ + const int sublen = strlen(substr); + while (*str) + { + if (!_pico_strnicmp(str,substr,sublen)) break; + str++; + } + if (!(*str)) str = NULL; + return str; +} + +/* +_pico_unixify() +changes dos \ style path separators to / +*/ + +void _pico_unixify( char *path ) +{ + if( path == NULL ) + return; + while( *path ) + { + if( *path == '\\' ) + *path = '/'; + path++; + } +} + +/* _pico_nofname: + * removes file name portion from given file path and converts + * the directory separators to un*x style. returns 1 on success + * or 0 when 'destSize' was exceeded. -sea + */ +int _pico_nofname( const char *path, char *dest, int destSize ) +{ + int left = destSize; + char *temp = dest; + + while ((*dest = *path) != '\0') + { + if (*dest == '/' || *dest == '\\') + { + temp = (dest + 1); + *dest = '/'; + } + dest++; path++; + + if (--left < 1) + { + *temp = '\0'; + return 0; + } + } + *temp = '\0'; + return 1; +} + +/* _pico_nopath: + * returns ptr to filename portion in given path or an empty + * string otherwise. given 'path' is not altered. -sea + */ +char *_pico_nopath( const char *path ) +{ + char *src; + src = (char *)path + (strlen(path) - 1); + + if (path == NULL) return (char *)""; + if (!strchr((char *)path,'/') && !strchr((char *)path,'\\')) + return ((char *)path); + + while ((src--) != path) + { + if (*src == '/' || *src == '\\') + return (++src); + } + return (char *)""; +} + +/* _pico_setfext: + * sets/changes the file extension for the given filename + * or filepath's filename portion. the given 'path' *is* + * altered. leave 'ext' empty to remove extension. -sea + */ +char *_pico_setfext( char *path, const char *ext ) +{ + char *src; + int remfext = 0; + + src = path + (strlen(path) - 1); + + if (ext == NULL) ext = ""; + if (strlen(ext ) < 1) remfext = 1; + if (strlen(path) < 1) + return path; + + while ((src--) != path) + { + if (*src == '/' || *src == '\\') + return path; + + if (*src == '.') + { + if (remfext) + { + *src = '\0'; + return path; + } + *(++src) = '\0'; + break; + } + } + strcat(path,ext); + return path; +} + +/* _pico_getline: + * extracts one line from the given buffer and stores it in dest. + * returns -1 on error or the length of the line on success. i've + * removed string trimming here. this can be done manually by the + * calling func. + */ +int _pico_getline( char *buf, int bufsize, char *dest, int destsize ) +{ + int pos; + + /* check output */ + if (dest == NULL || destsize < 1) return -1; + memset( dest,0,destsize ); + + /* check input */ + if (buf == NULL || bufsize < 1) + return -1; + + /* get next line */ + for (pos=0; poscursor == NULL) + return; + + /* skin white spaces */ + while( 1 ) + { + /* sanity checks */ + if (p->cursor < p->buffer || + p->cursor >= p->max) + { + return; + } + /* break for chars other than white spaces */ + if (*p->cursor > 0x20) break; + if (*p->cursor == 0x00) return; + + /* a bit of linefeed handling */ + if (*p->cursor == '\n') + { + *hasLFs = 1; + p->curLine++; + } + /* go to next character */ + p->cursor++; + } +} + +/* _pico_new_parser: + * allocates a new ascii parser object. + */ +picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ) +{ + picoParser_t *p; + + /* sanity check */ + if( buffer == NULL || bufSize <= 0 ) + return NULL; + + /* allocate reader */ + p = _pico_alloc( sizeof(picoParser_t) ); + if (p == NULL) return NULL; + memset( p,0,sizeof(picoParser_t) ); + + /* allocate token space */ + p->tokenSize = 0; + p->tokenMax = 1024; + p->token = _pico_alloc( p->tokenMax ); + if( p->token == NULL ) + { + _pico_free( p ); + return NULL; + } + /* setup */ + p->buffer = buffer; + p->cursor = buffer; + p->bufSize = bufSize; + p->max = p->buffer + bufSize; + p->curLine = 1; /* sea: new */ + + /* return ptr to parser */ + return p; +} + +/* _pico_free_parser: + * frees an existing pico parser object. + */ +void _pico_free_parser( picoParser_t *p ) +{ + /* sanity check */ + if (p == NULL) return; + + /* free the parser */ + if (p->token != NULL) + { + _pico_free( p->token ); + } + _pico_free( p ); +} + +/* _pico_parse_ex: + * reads the next token from given pico parser object. if param + * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when + * the EOF is reached. if 'allowLFs' is 0 it will return 0 when + * the EOL is reached. if 'handleQuoted' is 1 the parser function + * will handle "quoted" strings and return the data between the + * quotes as token. returns 0 on end/error or 1 on success. -sea + */ +int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ) +{ + int hasLFs = 0; + char *old; + + /* sanity checks */ + if( p == NULL || p->buffer == NULL || + p->cursor < p->buffer || + p->cursor >= p->max ) + { + return 0; + } + /* clear parser token */ + p->tokenSize = 0; + p->token[ 0 ] = '\0'; + old = p->cursor; + + /* skip whitespaces */ + while( p->cursor < p->max && *p->cursor <= 32 ) + { + if (*p->cursor == '\n') + { + p->curLine++; + hasLFs++; + } + p->cursor++; + } + /* return if we're not allowed to go beyond lfs */ + if ((hasLFs > 0) && !allowLFs) + { + p->cursor = old; + return 0; + } + /* get next quoted string */ + if (*p->cursor == '\"' && handleQuoted) + { + p->cursor++; + while (p->cursor < p->max && *p->cursor) + { + if (*p->cursor == '\\') + { + if (*(p->cursor+1) == '"') + { + p->cursor++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + continue; + } + else if (*p->cursor == '\"') + { + p->cursor++; + break; + } + else if (*p->cursor == '\n') + { + p->curLine++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + } + /* terminate token */ + p->token[ p->tokenSize ] = '\0'; + return 1; + } + /* otherwise get next word */ + while( p->cursor < p->max && *p->cursor > 32 ) + { + if (*p->cursor == '\n') + { + p->curLine++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + } + /* terminate token */ + p->token[ p->tokenSize ] = '\0'; + return 1; +} + +/* _pico_parse_first: + * reads the first token from the next line and returns + * a pointer to it. returns NULL on EOL or EOF. -sea + */ +char *_pico_parse_first( picoParser_t *p ) +{ + /* sanity check */ + if (p == NULL) return NULL; + + /* try to read next token (with lfs & quots) */ + if (!_pico_parse_ex( p,1,1 )) + return NULL; + + /* return ptr to the token string */ + return p->token; +} + +/* _pico_parse: + * reads the next token from the parser and returns a pointer + * to it. quoted strings are handled as usual. returns NULL + * on EOL or EOF. -sea + */ +char *_pico_parse( picoParser_t *p, int allowLFs ) +{ + /* sanity check */ + if (p == NULL) return NULL; + + /* try to read next token (with quots) */ + if (!_pico_parse_ex( p,allowLFs,1 )) + return NULL; + + /* return ptr to the token string */ + return p->token; +} + +/* _pico_parse_skip_rest: + * skips the rest of the current line in parser. + */ +void _pico_parse_skip_rest( picoParser_t *p ) +{ + while( _pico_parse_ex( p,0,0 ) ) ; +} + +/* _pico_parse_skip_braced: + * parses/skips over a braced section. returns 1 on success + * or 0 on error (when there was no closing bracket and the + * end of buffer was reached or when the opening bracket was + * missing). + */ +int _pico_parse_skip_braced( picoParser_t *p ) +{ + int firstToken = 1; + int level; + + /* sanity check */ + if (p == NULL) return 0; + + /* set the initial level for parsing */ + level = 0; + + /* skip braced section */ + while( 1 ) + { + /* read next token (lfs allowed) */ + if (!_pico_parse_ex( p,1,1 )) + { + /* end of parser buffer reached */ + return 0; + } + /* first token must be an opening bracket */ + if (firstToken && p->token[0] != '{') + { + /* opening bracket missing */ + return 0; + } + /* we only check this once */ + firstToken = 0; + + /* update level */ + if (p->token[1] == '\0') + { + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + } + /* break if we're back at our starting level */ + if (level == 0) break; + } + /* successfully skipped braced section */ + return 1; +} + +int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ) +{ + if (!_pico_parse_ex( p,allowLFs,1 )) + return 0; + if (!strcmp(p->token,str)) + return 1; + return 0; +} + +int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ) +{ + if (!_pico_parse_ex( p,allowLFs,1 )) + return 0; + if (!_pico_stricmp(p->token,str)) + return 1; + return 0; +} + +int _pico_parse_int( picoParser_t *p, int *out ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into an integer */ + *out = 0; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = atoi( token ); + + /* success */ + return 1; +} + +int _pico_parse_int_def( picoParser_t *p, int *out, int def ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into an integer */ + *out = def; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = atoi( token ); + + /* success */ + return 1; +} + +int _pico_parse_float( picoParser_t *p, float *out ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into a float */ + *out = 0.0f; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = (float) atof( token ); + + /* success */ + return 1; +} + +int _pico_parse_float_def( picoParser_t *p, float *out, float def ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into a float */ + *out = def; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = (float) atof( token ); + + /* success */ + return 1; +} + +int _pico_parse_vec( picoParser_t *p, picoVec3_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec( out ); + + /* parse three vector components */ + for (i=0; i<3; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec( def,out ); + + /* parse three vector components */ + for (i=0; i<3; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec2( out ); + + /* parse two vector components */ + for (i=0; i<2; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec2( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec2( def,out ); + + /* parse two vector components */ + for (i=0; i<2; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec2( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec4( out ); + + /* parse four vector components */ + for (i=0; i<4; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec4( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec4( def,out ); + + /* parse four vector components */ + for (i=0; i<4; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec4( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +/* _pico_new_memstream: + * allocates a new memorystream object. + */ +picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ) +{ + picoMemStream_t *s; + + /* sanity check */ + if( buffer == NULL || bufSize <= 0 ) + return NULL; + + /* allocate stream */ + s = _pico_alloc( sizeof(picoMemStream_t) ); + if (s == NULL) return NULL; + memset( s,0,sizeof(picoMemStream_t) ); + + /* setup */ + s->buffer = buffer; + s->curPos = buffer; + s->bufSize = bufSize; + s->flag = 0; + + /* return ptr to stream */ + return s; +} + +/* _pico_free_memstream: + * frees an existing pico memorystream object. + */ +void _pico_free_memstream( picoMemStream_t *s ) +{ + /* sanity check */ + if (s == NULL) return; + + /* free the stream */ + _pico_free( s ); +} + +/* _pico_memstream_read: + * reads data from a pico memorystream into a buffer. + */ +int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ) +{ + int ret = 1; + + /* sanity checks */ + if (s == NULL || buffer == NULL) + return 0; + + if (s->curPos + len > s->buffer + s->bufSize) + { + s->flag |= PICO_IOEOF; + len = s->buffer + s->bufSize - s->curPos; + ret = 0; + } + + /* read the data */ + memcpy( buffer, s->curPos, len ); + s->curPos += len; + return ret; +} + +/* _pico_memstream_read: + * reads a character from a pico memorystream + */ +int _pico_memstream_getc( picoMemStream_t *s ) +{ + int c = 0; + + /* sanity check */ + if (s == NULL) + return -1; + + /* read the character */ + if (_pico_memstream_read( s, &c, 1) == 0) + return -1; + + return c; +} + +/* _pico_memstream_seek: + * sets the current read position to a different location + */ +int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ) +{ + int overflow; + + /* sanity check */ + if (s == NULL) + return -1; + + if (origin == PICO_SEEK_SET) + { + s->curPos = s->buffer + offset; + overflow = s->curPos - ( s->buffer + s->bufSize ); + if (overflow > 0) + { + s->curPos = s->buffer + s->bufSize; + return offset - overflow; + } + return 0; + } + else if (origin == PICO_SEEK_CUR) + { + s->curPos += offset; + overflow = s->curPos - ( s->buffer + s->bufSize ); + if (overflow > 0) + { + s->curPos = s->buffer + s->bufSize; + return offset - overflow; + } + return 0; + } + else if (origin == PICO_SEEK_END) + { + s->curPos = ( s->buffer + s->bufSize ) - offset; + overflow = s->buffer - s->curPos; + if (overflow > 0) + { + s->curPos = s->buffer; + return offset - overflow; + } + return 0; + } + + return -1; +} + +/* _pico_memstream_tell: + * returns the current read position in the pico memorystream + */ +long _pico_memstream_tell( picoMemStream_t *s ) +{ + /* sanity check */ + if (s == NULL) + return -1; + + return s->curPos - s->buffer; +} diff --git a/libs/picomodel/picointernal.h b/libs/picomodel/picointernal.h new file mode 100644 index 00000000..37686ce1 --- /dev/null +++ b/libs/picomodel/picointernal.h @@ -0,0 +1,205 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef PICOINTERNAL_H +#define PICOINTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* dependencies */ +#include +#include +#include +#include +#include +#include + +#include "picomodel.h" + + +/* os dependant replacements */ +#if WIN32 || _WIN32 + #define _pico_stricmp stricmp + #define _pico_strnicmp strnicmp +#else + #define _pico_stricmp strcasecmp + #define _pico_strnicmp strncasecmp +#endif + + +/* constants */ +#define PICO_PI 3.14159265358979323846 + +#define PICO_SEEK_SET 0 +#define PICO_SEEK_CUR 1 +#define PICO_SEEK_END 2 + +#define PICO_IOEOF 1 +#define PICO_IOERR 2 + +/* types */ +typedef struct picoParser_s +{ + char *buffer; + int bufSize; + char *token; + int tokenSize; + int tokenMax; + char *cursor; + char *max; + int curLine; +} +picoParser_t; + +typedef struct picoMemStream_s +{ + picoByte_t *buffer; + int bufSize; + picoByte_t *curPos; + int flag; +} +picoMemStream_t; + + +/* variables */ +extern const picoModule_t *picoModules[]; + +extern void *(*_pico_ptr_malloc)( size_t ); +extern void (*_pico_ptr_free)( void* ); +extern void (*_pico_ptr_load_file)( char*, unsigned char**, int* ); +extern void (*_pico_ptr_free_file)( void* ); +extern void (*_pico_ptr_print)( int, const char* ); + + + +/* prototypes */ + +/* memory */ +void *_pico_alloc( size_t size ); +void *_pico_calloc( size_t num, size_t size ); +void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ); +char *_pico_clone_alloc( char *str, int size ); +void _pico_free( void *ptr ); + +/* files */ +void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ); +void _pico_free_file( void *buffer ); + +/* strings */ +char *_pico_strltrim( char *str ); +char *_pico_strrtrim( char *str ); +int _pico_strchcount( char *str, int ch ); +void _pico_printf( int level, const char *format, ... ); +char *_pico_stristr( char *str, const char *substr ); +void _pico_unixify( char *path ); +int _pico_nofname( const char *path, char *dest, int destSize ); +char *_pico_nopath( const char *path ); +char *_pico_setfext( char *path, const char *ext ); +int _pico_getline( char *buf, int bufsize, char *dest, int destsize ); +char *_pico_strlwr( char *str ); + +/* vectors */ +void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ); +void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ); +void _pico_zero_vec( picoVec3_t vec ); +void _pico_zero_vec2( picoVec2_t vec ); +void _pico_zero_vec4( picoVec4_t vec ); +void _pico_set_vec( picoVec3_t v, float a, float b, float c ); +void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ); +void _pico_set_color( picoColor_t c, int r, int g, int b, int a ); +void _pico_copy_color( picoColor_t src, picoColor_t dest ); +void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ); +void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ); +picoVec_t _pico_normalize_vec( picoVec3_t vec ); +void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ); +void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ); +void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ); +void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ); + +/* endian */ +int _pico_big_long( int src ); +short _pico_big_short( short src ); +float _pico_big_float( float src ); + +int _pico_little_long( int src ); +short _pico_little_short( short src ); +float _pico_little_float( float src ); + +/* pico ascii parser */ +picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ); +void _pico_free_parser( picoParser_t *p ); +int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ); +char *_pico_parse_first( picoParser_t *p ); +char *_pico_parse( picoParser_t *p, int allowLFs ); +void _pico_parse_skip_rest( picoParser_t *p ); +int _pico_parse_skip_braced( picoParser_t *p ); +int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ); +int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ); +int _pico_parse_int( picoParser_t *p, int *out ); +int _pico_parse_int_def( picoParser_t *p, int *out, int def ); +int _pico_parse_float( picoParser_t *p, float *out ); +int _pico_parse_float_def( picoParser_t *p, float *out, float def ); +int _pico_parse_vec( picoParser_t *p, picoVec3_t out); +int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def); +int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ); +int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ); +int _pico_parse_vec4( picoParser_t *p, picoVec4_t out); +int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def); + +/* pico memory stream */ +picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ); +void _pico_free_memstream( picoMemStream_t *s ); +int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ); +int _pico_memstream_getc( picoMemStream_t *s ); +int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ); +long _pico_memstream_tell( picoMemStream_t *s ); +#define _pico_memstream_eof( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOEOF) +#define _pico_memstream_error( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOERR) + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel/picomodel.c b/libs/picomodel/picomodel.c new file mode 100644 index 00000000..ed4f8b21 --- /dev/null +++ b/libs/picomodel/picomodel.c @@ -0,0 +1,1995 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOMODEL_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* +PicoInit() +initializes the picomodel library +*/ + +int PicoInit( void ) +{ + /* successfully initialized -sea */ + return 1; +} + + + +/* +PicoShutdown() +shuts the pico model library down +*/ + +void PicoShutdown( void ) +{ + /* do something interesting here in the future */ + return; +} + + + +/* +PicoError() +returns last picomodel error code (see PME_* defines) +*/ + +int PicoError( void ) +{ + /* todo: do something here */ + return 0; +} + + + +/* +PicoSetMallocFunc() +sets the ptr to the malloc function +*/ + +void PicoSetMallocFunc( void *(*func)( size_t ) ) +{ + if( func != NULL ) + _pico_ptr_malloc = func; +} + + + +/* +PicoSetFreeFunc() +sets the ptr to the free function +*/ + +void PicoSetFreeFunc( void (*func)( void* ) ) +{ + if( func != NULL ) + _pico_ptr_free = func; +} + + + +/* +PicoSetLoadFileFunc() +sets the ptr to the file load function +*/ + +void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ) +{ + if( func != NULL ) + _pico_ptr_load_file = func; +} + + + +/* +PicoSetFreeFileFunc() +sets the ptr to the free function +*/ + +void PicoSetFreeFileFunc( void (*func)( void* ) ) +{ + if( func != NULL ) + _pico_ptr_free_file = func; +} + + + +/* +PicoSetPrintFunc() +sets the ptr to the print function +*/ + +void PicoSetPrintFunc( void (*func)( int, const char* ) ) +{ + if( func != NULL ) + _pico_ptr_print = func; +} + + + +/* +PicoLoadModel() +the meat and potatoes function +*/ + +picoModel_t *PicoLoadModel( char *fileName, int frameNum ) +{ + const picoModule_t **modules, *pm; + picoModel_t *model; + picoByte_t *buffer; + int bufSize; + char *modelFileName, *remapFileName; + + + /* init */ + model = NULL; + + /* make sure we've got a file name */ + if( fileName == NULL ) + { + _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" ); + return NULL; + } + + /* load file data (buffer is allocated by host app) */ + _pico_load_file( fileName, &buffer, &bufSize ); + if( bufSize < 0 ) + { + _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName ); + return NULL; + } + + /* get ptr to list of supported modules */ + modules = PicoModuleList( NULL ); + + /* run it through the various loader functions and try */ + /* to find a loader that fits the given file data */ + for( ; *modules != NULL; modules++ ) + { + /* get module */ + pm = *modules; + + /* sanity check */ + if( pm == NULL) + break; + + /* module must be able to load */ + if( pm->canload == NULL || pm->load == NULL ) + continue; + + /* see whether this module can load the model file or not */ + if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) + { + /* use loader provided by module to read the model data */ + model = pm->load( fileName, frameNum, buffer, bufSize ); + if( model == NULL ) + { + _pico_free_file( buffer ); + return NULL; + } + + /* assign pointer to file format module */ + model->module = pm; + + /* get model file name */ + modelFileName = PicoGetModelFileName( model ); + + /* apply model remappings from .remap */ + if( strlen( modelFileName ) ) + { + /* alloc copy of model file name */ + remapFileName = _pico_alloc( strlen( modelFileName ) + 20 ); + if( remapFileName != NULL ) + { + /* copy model file name and change extension */ + strcpy( remapFileName, modelFileName ); + _pico_setfext( remapFileName, "remap" ); + + /* try to remap model; we don't handle the result */ + PicoRemapModel( model, remapFileName ); + + /* free the remap file name string */ + _pico_free( remapFileName ); + } + } + + /* model was loaded, so break out of loop */ + break; + } + } + + /* free memory used by file buffer */ + if( buffer) + _pico_free_file( buffer ); + + /* return */ + return model; +} + + + +/* ---------------------------------------------------------------------------- +models +---------------------------------------------------------------------------- */ + +/* +PicoNewModel() +creates a new pico model +*/ + +picoModel_t *PicoNewModel( void ) +{ + picoModel_t *model; + + /* allocate */ + model = _pico_alloc( sizeof(picoModel_t) ); + if( model == NULL ) + return NULL; + + /* clear */ + memset( model,0,sizeof(picoModel_t) ); + + /* model set up */ + _pico_zero_bounds( model->mins,model->maxs ); + + /* set initial frame count to 1 -sea */ + model->numFrames = 1; + + /* return ptr to new model */ + return model; +} + + + +/* +PicoFreeModel() +frees a model and all associated data +*/ + +void PicoFreeModel( picoModel_t *model ) +{ + int i; + + + /* sanity check */ + if( model == NULL ) + return; + + /* free bits */ + if( model->name ) + _pico_free( model->name ); + + /* free shaders */ + for( i = 0; i < model->numShaders; i++ ) + PicoFreeShader( model->shader[ i ] ); + free( model->shader ); + + /* free surfaces */ + for( i = 0; i < model->numSurfaces; i++ ) + PicoFreeSurface( model->surface[ i ] ); + free( model->surface ); + + /* free the model */ + _pico_free( model ); +} + + + +/* +PicoAdjustModel() +adjusts a models's memory allocations to handle the requested sizes. +will always grow, never shrink +*/ + +int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ) +{ + /* dummy check */ + if( model == NULL ) + return 0; + + /* bare minimums */ + /* sea: null surface/shader fix (1s=>0s) */ + if( numShaders < 0 ) + numShaders = 0; + if( numSurfaces < 0 ) + numSurfaces = 0; + + /* additional shaders? */ + while( numShaders > model->maxShaders ) + { + model->maxShaders += PICO_GROW_SHADERS; + if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) + return 0; + } + + /* set shader count to higher */ + if( numShaders > model->numShaders ) + model->numShaders = numShaders; + + /* additional surfaces? */ + while( numSurfaces > model->maxSurfaces ) + { + model->maxSurfaces += PICO_GROW_SURFACES; + if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) + return 0; + } + + /* set shader count to higher */ + if( numSurfaces > model->numSurfaces ) + model->numSurfaces = numSurfaces; + + /* return ok */ + return 1; +} + + + +/* ---------------------------------------------------------------------------- +shaders +---------------------------------------------------------------------------- */ + +/* +PicoNewShader() +creates a new pico shader and returns its index. -sea +*/ + +picoShader_t *PicoNewShader( picoModel_t *model ) +{ + picoShader_t *shader; + + + /* allocate and clear */ + shader = _pico_alloc( sizeof(picoShader_t) ); + if( shader == NULL ) + return NULL; + memset( shader, 0, sizeof(picoShader_t) ); + + /* attach it to the model */ + if( model != NULL ) + { + /* adjust model */ + if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) + { + _pico_free( shader ); + return NULL; + } + /* attach */ + model->shader[ model->numShaders - 1 ] = shader; + shader->model = model; + } + /* setup default shader colors */ + _pico_set_color( shader->ambientColor,0,0,0,0 ); + _pico_set_color( shader->diffuseColor,255,255,255,1 ); + _pico_set_color( shader->specularColor,0,0,0,0 ); + + /* no need to do this, but i do it anyway */ + shader->transparency = 0; + shader->shininess = 0; + + /* return the newly created shader */ + return shader; +} + + + +/* +PicoFreeShader() +frees a shader and all associated data -sea +*/ + +void PicoFreeShader( picoShader_t *shader ) +{ + /* dummy check */ + if( shader == NULL ) + return; + + /* free bits */ + if( shader->name ) + _pico_free( shader->name ); + if( shader->mapName ) + _pico_free( shader->mapName ); + + /* free the shader */ + _pico_free( shader ); +} + + + +/* +PicoFindShader() +finds a named shader in a model +*/ + +picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ) +{ + int i; + + + /* sanity checks */ + if( model == NULL || name == NULL ) /* sea: null name fix */ + return NULL; + + /* walk list */ + for( i = 0; i < model->numShaders; i++ ) + { + /* skip null shaders or shaders with null names */ + if( model->shader[ i ] == NULL || + model->shader[ i ]->name == NULL ) + continue; + + /* compare the shader name with name we're looking for */ + if( caseSensitive ) + { + if( !strcmp( name, model->shader[ i ]->name ) ) + return model->shader[ i ]; + } + else if( !_pico_stricmp( name, model->shader[ i ]->name ) ) + return model->shader[ i ]; + } + + /* named shader not found */ + return NULL; +} + + + +/* ---------------------------------------------------------------------------- +surfaces +---------------------------------------------------------------------------- */ + +/* +PicoNewSurface() +creates a new pico surface +*/ + +picoSurface_t *PicoNewSurface( picoModel_t *model ) +{ + picoSurface_t *surface; + char surfaceName[64]; + + /* allocate and clear */ + surface = _pico_alloc( sizeof( *surface ) ); + if( surface == NULL ) + return NULL; + memset( surface, 0, sizeof( *surface ) ); + + /* attach it to the model */ + if( model != NULL ) + { + /* adjust model */ + if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) + { + _pico_free( surface ); + return NULL; + } + + /* attach */ + model->surface[ model->numSurfaces - 1 ] = surface; + surface->model = model; + + /* set default name */ + sprintf( surfaceName, "Unnamed_%d", model->numSurfaces ); + PicoSetSurfaceName( surface, surfaceName ); + } + + /* return */ + return surface; +} + + + +/* +PicoFreeSurface() +frees a surface and all associated data +*/ +void PicoFreeSurface( picoSurface_t *surface ) +{ + int i; + + + /* dummy check */ + if( surface == NULL ) + return; + + /* free bits */ + _pico_free( surface->xyz ); + _pico_free( surface->normal ); + _pico_free( surface->index ); + _pico_free( surface->faceNormal ); + + /* free arrays */ + for( i = 0; i < surface->numSTArrays; i++ ) + _pico_free( surface->st[ i ] ); + free( surface->st ); + for( i = 0; i < surface->numColorArrays; i++ ) + _pico_free( surface->color[ i ] ); + free( surface->color ); + + /* free the surface */ + _pico_free( surface ); +} + + + +/* +PicoAdjustSurface() +adjusts a surface's memory allocations to handle the requested sizes. +will always grow, never shrink +*/ + +int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ) +{ + int i; + + + /* dummy check */ + if( surface == NULL ) + return 0; + + /* bare minimums */ + if( numVertexes < 1 ) + numVertexes = 1; + if( numSTArrays < 1 ) + numSTArrays = 1; + if( numColorArrays < 1 ) + numColorArrays = 1; + if( numIndexes < 1 ) + numIndexes = 1; + + /* additional vertexes? */ + while( numVertexes > surface->maxVertexes ) /* fix */ + { + surface->maxVertexes += PICO_GROW_VERTEXES; + if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) + return 0; + if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) + return 0; + for( i = 0; i < surface->numSTArrays; i++ ) + if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) + return 0; + for( i = 0; i < surface->numColorArrays; i++ ) + if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) + return 0; + } + + /* set vertex count to higher */ + if( numVertexes > surface->numVertexes ) + surface->numVertexes = numVertexes; + + /* additional st arrays? */ + while( numSTArrays > surface->maxSTArrays ) /* fix */ + { + surface->maxSTArrays += PICO_GROW_ARRAYS; + if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) + return 0; + while( surface->numSTArrays < numSTArrays ) + { + surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); + memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); + surface->numSTArrays++; + } + } + + /* additional color arrays? */ + while( numColorArrays > surface->maxColorArrays ) /* fix */ + { + surface->maxColorArrays += PICO_GROW_ARRAYS; + if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) + return 0; + while( surface->numColorArrays < numColorArrays ) + { + surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); + memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); + surface->numColorArrays++; + } + } + + /* additional indexes? */ + while( numIndexes > surface->maxIndexes ) /* fix */ + { + surface->maxIndexes += PICO_GROW_INDEXES; + if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) + return 0; + } + + /* set index count to higher */ + if( numIndexes > surface->numIndexes ) + surface->numIndexes = numIndexes; + + /* additional face normals? */ + while( numFaceNormals > surface->maxFaceNormals ) /* fix */ + { + surface->maxFaceNormals += PICO_GROW_FACES; + if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) + return 0; + } + + /* set face normal count to higher */ + if( numFaceNormals > surface->numFaceNormals ) + surface->numFaceNormals = numFaceNormals; + + /* return ok */ + return 1; +} + + +/* PicoFindSurface: + * Finds first matching named surface in a model. + */ +picoSurface_t *PicoFindSurface( + picoModel_t *model, char *name, int caseSensitive ) +{ + int i; + + /* sanity check */ + if( model == NULL || name == NULL ) + return NULL; + + /* walk list */ + for( i = 0; i < model->numSurfaces; i++ ) + { + /* skip null surfaces or surfaces with null names */ + if( model->surface[ i ] == NULL || + model->surface[ i ]->name == NULL ) + continue; + + /* compare the surface name with name we're looking for */ + if (caseSensitive) { + if( !strcmp(name,model->surface[ i ]->name) ) + return model->surface[ i ]; + } else { + if( !_pico_stricmp(name,model->surface[ i ]->name) ) + return model->surface[ i ]; + } + } + /* named surface not found */ + return NULL; +} + + + +/*---------------------------------------------------------------------------- + PicoSet*() Setter Functions +----------------------------------------------------------------------------*/ + +void PicoSetModelName( picoModel_t *model, char *name ) +{ + if( model == NULL || name == NULL ) + return; + if( model->name != NULL ) + _pico_free( model->name ); + + model->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetModelFileName( picoModel_t *model, char *fileName ) +{ + if( model == NULL || fileName == NULL ) + return; + if( model->fileName != NULL ) + _pico_free( model->fileName ); + + model->fileName = _pico_clone_alloc( fileName,-1 ); +} + + + +void PicoSetModelFrameNum( picoModel_t *model, int frameNum ) +{ + if( model == NULL ) + return; + model->frameNum = frameNum; +} + + + +void PicoSetModelNumFrames( picoModel_t *model, int numFrames ) +{ + if( model == NULL ) + return; + model->numFrames = numFrames; +} + + + +void PicoSetModelData( picoModel_t *model, void *data ) +{ + if( model == NULL ) + return; + model->data = data; +} + + + +void PicoSetShaderName( picoShader_t *shader, char *name ) +{ + if( shader == NULL || name == NULL ) + return; + if( shader->name != NULL ) + _pico_free( shader->name ); + + shader->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetShaderMapName( picoShader_t *shader, char *mapName ) +{ + if( shader == NULL || mapName == NULL ) + return; + if( shader->mapName != NULL ) + _pico_free( shader->mapName ); + + shader->mapName = _pico_clone_alloc( mapName,-1 ); +} + + + +void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->ambientColor[ 0 ] = color[ 0 ]; + shader->ambientColor[ 1 ] = color[ 1 ]; + shader->ambientColor[ 2 ] = color[ 2 ]; + shader->ambientColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->diffuseColor[ 0 ] = color[ 0 ]; + shader->diffuseColor[ 1 ] = color[ 1 ]; + shader->diffuseColor[ 2 ] = color[ 2 ]; + shader->diffuseColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->specularColor[ 0 ] = color[ 0 ]; + shader->specularColor[ 1 ] = color[ 1 ]; + shader->specularColor[ 2 ] = color[ 2 ]; + shader->specularColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderTransparency( picoShader_t *shader, float value ) +{ + if( shader == NULL ) + return; + shader->transparency = value; + + /* cap to 0..1 range */ + if (shader->transparency < 0.0) + shader->transparency = 0.0; + if (shader->transparency > 1.0) + shader->transparency = 1.0; +} + + + +void PicoSetShaderShininess( picoShader_t *shader, float value ) +{ + if( shader == NULL ) + return; + shader->shininess = value; + + /* cap to 0..127 range */ + if (shader->shininess < 0.0) + shader->shininess = 0.0; + if (shader->shininess > 127.0) + shader->shininess = 127.0; +} + + + +void PicoSetSurfaceData( picoSurface_t *surface, void *data ) +{ + if( surface == NULL ) + return; + surface->data = data; +} + + + +void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ) +{ + if( surface == NULL ) + return; + surface->type = type; +} + + + +void PicoSetSurfaceName( picoSurface_t *surface, char *name ) +{ + if( surface == NULL || name == NULL ) + return; + if( surface->name != NULL ) + _pico_free( surface->name ); + + surface->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ) +{ + if( surface == NULL ) + return; + surface->shader = shader; +} + + + +void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ) +{ + if( surface == NULL || num < 0 || xyz == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) + return; + _pico_copy_vec( xyz, surface->xyz[ num ] ); + if( surface->model != NULL ) + _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs ); +} + + + +void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) +{ + if( surface == NULL || num < 0 || normal == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) + return; + _pico_copy_vec( normal, surface->normal[ num ] ); +} + + + +void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ) +{ + if( surface == NULL || num < 0 || st == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) + return; + surface->st[ array ][ num ][ 0 ] = st[ 0 ]; + surface->st[ array ][ num ][ 1 ] = st[ 1 ]; +} + + + +void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ) +{ + if( surface == NULL || num < 0 || color == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) + return; + surface->color[ array ][ num ][ 0 ] = color[ 0 ]; + surface->color[ array ][ num ][ 1 ] = color[ 1 ]; + surface->color[ array ][ num ][ 2 ] = color[ 2 ]; + surface->color[ array ][ num ][ 3 ] = color[ 3 ]; +} + + + +void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ) +{ + if( surface == NULL || num < 0 ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) + return; + surface->index[ num ] = index; +} + + + +void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ) +{ + if( num < 0 || index == NULL || count < 1 ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) + return; + memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) ); +} + + + +void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) +{ + if( surface == NULL || num < 0 || normal == NULL ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) + return; + _pico_copy_vec( normal, surface->faceNormal[ num ] ); +} + + +void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ) +{ + if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) + return; + surface->special[ num ] = special; +} + + + +/*---------------------------------------------------------------------------- + PicoGet*() Getter Functions +----------------------------------------------------------------------------*/ + +char *PicoGetModelName( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + if( model->name == NULL) + return (char*) ""; + return model->name; +} + + + +char *PicoGetModelFileName( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + if( model->fileName == NULL) + return (char*) ""; + return model->fileName; +} + + + +int PicoGetModelFrameNum( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->frameNum; +} + + + +int PicoGetModelNumFrames( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numFrames; +} + + + +void *PicoGetModelData( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + return model->data; +} + + + +int PicoGetModelNumShaders( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numShaders; +} + + + +picoShader_t *PicoGetModelShader( picoModel_t *model, int num ) +{ + /* a few sanity checks */ + if( model == NULL ) + return NULL; + if( model->shader == NULL) + return NULL; + if( num < 0 || num >= model->numShaders ) + return NULL; + + /* return the shader */ + return model->shader[ num ]; +} + + + +int PicoGetModelNumSurfaces( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numSurfaces; +} + + + +picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ) +{ + /* a few sanity checks */ + if( model == NULL ) + return NULL; + if( model->surface == NULL) + return NULL; + if( num < 0 || num >= model->numSurfaces ) + return NULL; + + /* return the surface */ + return model->surface[ num ]; +} + + + +int PicoGetModelTotalVertexes( picoModel_t *model ) +{ + int i, count; + + + if( model == NULL ) + return 0; + if( model->surface == NULL ) + return 0; + + count = 0; + for( i = 0; i < model->numSurfaces; i++ ) + count += PicoGetSurfaceNumVertexes( model->surface[ i ] ); + + return count; +} + + + +int PicoGetModelTotalIndexes( picoModel_t *model ) +{ + int i, count; + + + if( model == NULL ) + return 0; + if( model->surface == NULL ) + return 0; + + count = 0; + for( i = 0; i < model->numSurfaces; i++ ) + count += PicoGetSurfaceNumIndexes( model->surface[ i ] ); + + return count; +} + + + +char *PicoGetShaderName( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + if( shader->name == NULL) + return (char*) ""; + return shader->name; +} + + + +char *PicoGetShaderMapName( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + if( shader->mapName == NULL) + return (char*) ""; + return shader->mapName; +} + + + +picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->ambientColor; +} + + + +picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->diffuseColor; +} + + + +picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->specularColor; +} + + + +float PicoGetShaderTransparency( picoShader_t *shader ) +{ + if( shader == NULL ) + return 0.0f; + return shader->transparency; +} + + + +float PicoGetShaderShininess( picoShader_t *shader ) +{ + if( shader == NULL ) + return 0.0f; + return shader->shininess; +} + + + +void *PicoGetSurfaceData( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + return surface->data; +} + + + +picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ) +{ + if( surface == NULL ) + return PICO_BAD; + return surface->type; +} + + + +char *PicoGetSurfaceName( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + if( surface->name == NULL ) + return (char*) ""; + return surface->name; +} + + + +picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + return surface->shader; +} + + + +int PicoGetSurfaceNumVertexes( picoSurface_t *surface ) +{ + if( surface == NULL ) + return 0; + return surface->numVertexes; +} + + + +picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->xyz[ num ]; +} + + + +picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->normal[ num ]; +} + + + +picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ) +{ + if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->st[ array ][ num ]; +} + + + +picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ) +{ + if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->color[ array ][ num ]; +} + + + +int PicoGetSurfaceNumIndexes( picoSurface_t *surface ) +{ + if( surface == NULL ) + return 0; + return surface->numIndexes; +} + + + +picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numIndexes ) + return 0; + return surface->index[ num ]; +} + + + +picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numIndexes ) + return NULL; + return &surface->index[ num ]; +} + + +picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numFaceNormals ) + return NULL; + return surface->faceNormal[ num ]; +} + + +int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) + return 0; + return surface->special[ num ]; +} + + + +/* ---------------------------------------------------------------------------- +hashtable related functions +---------------------------------------------------------------------------- */ + +/* hashtable code for faster vertex lookups */ +//#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */ +#define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */ + +int PicoGetHashTableSize( void ) +{ + return HASHTABLE_SIZE; +} + +#define HASH_USE_EPSILON + +#ifdef HASH_USE_EPSILON +#define HASH_XYZ_EPSILON 0.01f +#define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON +#define HASH_ST_EPSILON 0.0001f +#define HASH_NORMAL_EPSILON 0.02f +#endif + +unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ) +{ + unsigned int hash = 0; + +#ifndef HASH_USE_EPSILON + hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15); + hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10); + hash += (*((unsigned int*) &xyz[ 1 ]) << 3); + hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6); + hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11); + hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16); +#else + picoVec3_t xyz_epsilonspace; + + _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace ); + xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]); + xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]); + xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]); + + hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10); + hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6); + hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16); +#endif + + //hash = hash & (HASHTABLE_SIZE-1); + hash = hash % (HASHTABLE_SIZE); + return hash; +} + +picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ) +{ + picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); + + memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); + + return hashTable; +} + +void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ) +{ + int i; + picoVertexCombinationHash_t *vertexCombinationHash; + picoVertexCombinationHash_t *nextVertexCombinationHash; + + /* dummy check */ + if (hashTable == NULL) + return; + + for( i = 0; i < HASHTABLE_SIZE; i++ ) + { + if (hashTable[ i ]) + { + nextVertexCombinationHash = NULL; + + for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash ) + { + nextVertexCombinationHash = vertexCombinationHash->next; + if (vertexCombinationHash->data != NULL) + { + _pico_free( vertexCombinationHash->data ); + } + _pico_free( vertexCombinationHash ); + } + } + } + + _pico_free( hashTable ); +} + +picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ) +{ + unsigned int hash; + picoVertexCombinationHash_t *vertexCombinationHash; + + /* dumy check */ + if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) + return NULL; + + hash = PicoVertexCoordGenerateHash( xyz ); + + for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next ) + { +#ifndef HASH_USE_EPSILON + /* check xyz */ + if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) ) + continue; + + /* check normal */ + if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) ) + continue; + + /* check st */ + if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) + continue; +#else + /* check xyz */ + if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON || + ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON || + ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON ) + continue; + + /* check normal */ + if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON || + ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON || + ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON ) + continue; + + /* check st */ + if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON || + ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON ) + continue; +#endif + + /* check color */ + if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) ) + continue; + + /* gotcha */ + return vertexCombinationHash; + } + + return NULL; +} + +picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ) +{ + unsigned int hash; + picoVertexCombinationHash_t *vertexCombinationHash; + + /* dumy check */ + if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) + return NULL; + + vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) ); + + if (!vertexCombinationHash) + return NULL; + + hash = PicoVertexCoordGenerateHash( xyz ); + + _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz ); + _pico_copy_vec( normal, vertexCombinationHash->vcd.normal ); + _pico_copy_vec2( st, vertexCombinationHash->vcd.st ); + _pico_copy_color( color, vertexCombinationHash->vcd.color ); + vertexCombinationHash->index = index; + vertexCombinationHash->data = NULL; + vertexCombinationHash->next = hashTable[ hash ]; + hashTable[ hash ] = vertexCombinationHash; + + return vertexCombinationHash; +} + +/* ---------------------------------------------------------------------------- +specialized routines +---------------------------------------------------------------------------- */ + +/* +PicoFindSurfaceVertex() +finds a vertex matching the set parameters +fixme: needs non-naive algorithm +*/ + +int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ) +{ + int i, j; + + + /* dummy check */ + if( surface == NULL || surface->numVertexes <= 0 ) + return -1; + + /* walk vertex list */ + for( i = 0; i < surface->numVertexes; i++ ) + { + /* check xyz */ + if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) ) + continue; + + /* check normal */ + if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) ) + continue; + + /* check st */ + if( numSTs > 0 && st != NULL ) + { + for( j = 0; j < numSTs; j++ ) + { + if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) + break; + } + if( j != numSTs ) + continue; + } + + /* check color */ + if( numColors > 0 && color != NULL ) + { + for( j = 0; j < numSTs; j++ ) + { + if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) ) + break; + } + if( j != numColors ) + continue; + } + + /* vertex matches */ + return i; + } + + /* nada */ + return -1; +} + + + +/* +PicoFixSurfaceNormals() +fixes broken normals (certain formats bork normals) +*/ + +#define MAX_NORMAL_VOTES 128 +#define EQUAL_NORMAL_EPSILON 0.01 +#define BAD_NORMAL_EPSILON 0.5 + +void PicoFixSurfaceNormals( picoSurface_t *surface ) +{ + int i, j, k, a, b, c, numVotes, faceIndex; + picoVec3_t votes[ MAX_NORMAL_VOTES ]; + picoVec3_t *normals, diff; + picoVec4_t plane; + + + /* dummy check */ + if( surface == NULL || surface->numVertexes == 0 ) + return; + + /* fixme: handle other surface types */ + if( surface->type != PICO_TRIANGLES ) + return; + + /* allocate normal storage */ + normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) ); + if( normals == NULL ) + { + _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" ); + return; + } + + /* zero it out */ + memset( normals, 0, surface->numVertexes * sizeof( *normals ) ); + + /* walk vertex list */ + for( i = 0; i < surface->numVertexes; i++ ) + { + /* zero out votes */ + numVotes = 0; + + /* find all the triangles that reference this vertex */ + for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ ) + { + /* get triangle */ + a = surface->index[ j ]; + b = surface->index[ j + 1 ]; + c = surface->index[ j + 2 ]; + + /* ignore degenerate triangles */ + if( a == b || b == c || c == a ) + continue; + + /* ignore indexes out of range */ + if( a < 0 || a >= surface->numVertexes || + b < 0 || b >= surface->numVertexes || + c < 0 || c >= surface->numVertexes ) + continue; + + /* test triangle */ + if( a == i || b == i || c == i ) + { + /* if this surface has face normals */ + if( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) + { + _pico_copy_vec( surface->faceNormal[ faceIndex ], plane ); + if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) + { + /* if null normal, make plane from the 3 points */ + if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) + { + continue; + } + } + } + /* make a plane from the 3 points */ + else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) + { + continue; + } + + /* see if this normal has already been voted */ + for( k = 0; k < numVotes; k++ ) + { + _pico_subtract_vec( plane, votes[ k ], diff ); + if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) + break; + } + + /* add a new vote? */ + if( k == numVotes && numVotes < MAX_NORMAL_VOTES ) + { + _pico_copy_vec( plane, votes[ numVotes ] ); + numVotes++; + } + } + } + + /* tally votes */ + if( numVotes > 0 ) + { + /* create average normal */ + _pico_zero_vec( normals[ i ] ); + for( k = 0; k < numVotes; k++ ) + _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] ); + + /* normalize it */ + if( _pico_normalize_vec( normals[ i ] ) ) + { + /* test against actual normal */ + if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) + { + //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i, + //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ], + //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] ); + _pico_copy_vec( normals[ i ], surface->normal[ i ] ); + } + } + } + } + + /* free normal storage */ + _pico_free( normals ); +} + + + + +/* +PicoRemapModel() - sea +remaps model material/etc. information using the remappings +contained in the given 'remapFile' (full path to the ascii file to open) +returns 1 on success or 0 on error +*/ + +#define _prm_error_return \ +{ \ + _pico_free_parser( p ); \ + _pico_free_file( remapBuffer ); \ + return 0; \ +} + +int PicoRemapModel( picoModel_t *model, char *remapFile ) +{ + picoParser_t *p; + picoByte_t *remapBuffer; + int remapBufSize; + + + /* sanity checks */ + if( model == NULL || remapFile == NULL ) + return 0; + + /* load remap file contents */ + _pico_load_file( remapFile,&remapBuffer,&remapBufSize ); + + /* check result */ + if( remapBufSize == 0 ) + return 1; /* file is empty: no error */ + if( remapBufSize < 0 ) + return 0; /* load failed: error */ + + /* create a new pico parser */ + p = _pico_new_parser( remapBuffer, remapBufSize ); + if (p == NULL) + { + /* ram is really cheap nowadays... */ + _prm_error_return; + } + + /* doo teh parse */ + while( 1 ) + { + /* get next token in remap file */ + if (!_pico_parse( p,1 )) + break; + + /* skip over c++ style comment lines */ + if (!_pico_stricmp(p->token,"//")) + { + _pico_parse_skip_rest( p ); + continue; + } + + /* block for quick material shader name remapping */ + /* materials { "m" (=>|->|=) "s" } */ + if( !_pico_stricmp(p->token, "materials" ) ) + { + int level = 1; + + /* check bracket */ + if (!_pico_parse_check( p,1,"{" )) + _prm_error_return; + + /* process assignments */ + while( 1 ) + { + picoShader_t *shader; + char *materialName; + + + /* get material name */ + if (_pico_parse( p,1 ) == NULL) break; + if (!strlen(p->token)) continue; + materialName = _pico_clone_alloc( p->token,-1 ); + if (materialName == NULL) + _prm_error_return; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + /* get next token (assignment token or shader name) */ + if (!_pico_parse( p,0 )) + { + _pico_free( materialName ); + _prm_error_return; + } + /* skip assignment token (if present) */ + if (!strcmp(p->token,"=>") || + !strcmp(p->token,"->") || + !strcmp(p->token,"=")) + { + /* simply grab the next token */ + if (!_pico_parse( p,0 )) + { + _pico_free( materialName ); + _prm_error_return; + } + } + /* try to find material by name */ + shader = PicoFindShader( model,materialName,0 ); + + /* we've found a material matching the name */ + if (shader != NULL) + { + PicoSetShaderName( shader,p->token ); + } + /* free memory used by material name */ + _pico_free( materialName ); + + /* skip rest */ + _pico_parse_skip_rest( p ); + } + } + /* block for detailed single material remappings */ + /* materials[ "m" ] { key data... } */ + else if (!_pico_stricmp(p->token,"materials[")) + { + picoShader_t *shader; + char *tempMaterialName; + int level = 1; + + /* get material name */ + if (!_pico_parse( p,0 )) + _prm_error_return; + + /* temporary copy of material name */ + tempMaterialName = _pico_clone_alloc( p->token,-1 ); + if (tempMaterialName == NULL) + _prm_error_return; + + /* check square closing bracket */ + if (!_pico_parse_check( p,0,"]" )) + _prm_error_return; + + /* try to find material by name */ + shader = PicoFindShader( model,tempMaterialName,0 ); + + /* free memory used by temporary material name */ + _pico_free( tempMaterialName ); + + /* we haven't found a material matching the name */ + /* so we simply skip the braced section now and */ + /* continue parsing with the next main token */ + if (shader == NULL) + { + _pico_parse_skip_braced( p ); + continue; + } + /* check opening bracket */ + if (!_pico_parse_check( p,1,"{" )) + _prm_error_return; + + /* process material info keys */ + while( 1 ) + { + /* get key name */ + if (_pico_parse( p,1 ) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + /* remap shader name */ + if (!_pico_stricmp(p->token,"shader")) + { + if (!_pico_parse( p,0 )) _prm_error_return; + PicoSetShaderName( shader,p->token ); + } + /* remap shader map name */ + else if (!_pico_stricmp(p->token,"mapname")) + { + if (!_pico_parse( p,0 )) _prm_error_return; + PicoSetShaderMapName( shader,p->token ); + } + /* remap shader's ambient color */ + else if (!_pico_stricmp(p->token,"ambient")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderAmbientColor( shader,color ); + } + /* remap shader's diffuse color */ + else if (!_pico_stricmp(p->token,"diffuse")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderDiffuseColor( shader,color ); + } + /* remap shader's specular color */ + else if (!_pico_stricmp(p->token,"specular")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderSpecularColor( shader,color ); + } + /* skip rest */ + _pico_parse_skip_rest( p ); + } + } + /* end 'materials[' */ + } + + /* free both parser and file buffer */ + _pico_free_parser( p ); + _pico_free_file( remapBuffer ); + + /* return with success */ + return 1; +} + + +/* +PicoAddTriangleToModel() - jhefty +A nice way to add individual triangles to the model. +Chooses an appropriate surface based on the shader, or adds a new surface if necessary +*/ + +void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, + int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, + picoShader_t* shader ) +{ + int i,j; + int vertDataIndex; + picoSurface_t* workSurface = NULL; + + /* see if a surface already has the shader */ + for ( i = 0 ; i < model->numSurfaces ; i++ ) + { + workSurface = model->surface[i]; + if ( workSurface->shader == shader ) + { + break; + } + } + + /* no surface uses this shader yet, so create a new surface */ + if ( !workSurface || i >=model->numSurfaces ) + { + /* create a new surface in the model for the unique shader */ + workSurface = PicoNewSurface(model); + if ( !workSurface ) + { + _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" ); + return; + } + + /* do surface setup */ + PicoSetSurfaceType( workSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( workSurface, shader->name ); + PicoSetSurfaceShader( workSurface, shader ); + } + + /* add the triangle data to the surface */ + for ( i = 0 ; i < 3 ; i++ ) + { + /* get the next free spot in the index array */ + int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface ); + + /* get the index of the vertex that we're going to store at newVertIndex */ + vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]); + + /* the vertex wasn't found, so create a new vertex in the pool from the data we have */ + if ( vertDataIndex == -1 ) + { + /* find the next spot for a new vertex */ + vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface ); + + /* assign the data to it */ + PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] ); + PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] ); + + /* make sure to copy over all available ST's and colors for the vertex */ + for ( j = 0 ; j < numColors ; j++ ) + { + PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] ); + } + for ( j = 0 ; j < numSTs ; j++ ) + { + PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] ); + } + } + + /* add this vertex to the triangle */ + PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex ); + } +} diff --git a/libs/picomodel/picomodel.vcproj b/libs/picomodel/picomodel.vcproj new file mode 100644 index 00000000..bd3edb07 --- /dev/null +++ b/libs/picomodel/picomodel.vcproj @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/picomodel/picomodules.c b/libs/picomodel/picomodules.c new file mode 100644 index 00000000..060912f5 --- /dev/null +++ b/libs/picomodel/picomodules.c @@ -0,0 +1,92 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOMODULES_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* external modules */ +extern const picoModule_t picoModuleMD3; +extern const picoModule_t picoModule3DS; +extern const picoModule_t picoModuleASE; +extern const picoModule_t picoModuleOBJ; +extern const picoModule_t picoModuleMS3D; +extern const picoModule_t picoModuleMDC; +extern const picoModule_t picoModuleMD2; +extern const picoModule_t picoModuleFM; +extern const picoModule_t picoModuleLWO; + + + +/* list of all supported file format modules */ +const picoModule_t *picoModules[] = +{ + &picoModuleMD3, /* quake3 arena md3 */ + &picoModule3DS, /* autodesk 3ds */ + &picoModuleASE, /* autodesk ase */ + &picoModuleMS3D, /* milkshape3d */ + &picoModuleMDC, /* return to castle wolfenstein mdc */ + &picoModuleMD2, /* quake2 md2 */ + &picoModuleFM, /* heretic2 fm */ + &picoModuleOBJ, /* wavefront object */ + &picoModuleLWO, /* lightwave object */ + NULL /* arnold */ +}; + + + +/* +PicoModuleList() +returns a pointer to the module list and optionally stores +the number of supported modules in 'numModules'. Note that +this param can be NULL when the count is not needed. +*/ + +const picoModule_t **PicoModuleList( int *numModules ) +{ + /* get module count */ + if( numModules != NULL ) + for( (*numModules) = 0; picoModules[ *numModules ] != NULL; (*numModules)++ ); + + /* return list of modules */ + return (const picoModule_t**) picoModules; +} diff --git a/libs/picomodel/pm_3ds.c b/libs/picomodel/pm_3ds.c new file mode 100644 index 00000000..1ad95b1c --- /dev/null +++ b/libs/picomodel/pm_3ds.c @@ -0,0 +1,771 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_3DS_C + +/* dependencies */ +#include "picointernal.h" + +/* ydnar */ +static picoColor_t white = { 255,255,255,255 }; + +/* remarks: + * - 3ds file version is stored in pico special field 0 on load (ydnar: removed) + * todo: + * - sometimes there is one unnamed surface 0 having 0 verts as + * well as 0 faces. this error occurs since pm 0.6 (ydnar?) + */ +/* uncomment when debugging this module */ +/* #define DEBUG_PM_3DS +#define DEBUG_PM_3DS_EX */ + +/* structure holding persistent 3ds loader specific data used */ +/* to store formerly static vars to keep the module reentrant */ +/* safe. put everything that needs to be static in here. */ +typedef struct S3dsLoaderPers +{ + picoModel_t *model; /* ptr to output model */ + picoSurface_t *surface; /* ptr to current surface */ + picoShader_t *shader; /* ptr to current shader */ + picoByte_t *bufptr; /* ptr to raw data */ + char *basename; /* ptr to model base name (eg. jeep) */ + int cofs; + int maxofs; +} +T3dsLoaderPers; + +/* 3ds chunk types that we use */ +enum { + /* primary chunk */ + CHUNK_MAIN = 0x4D4D, + + /* main chunks */ + CHUNK_VERSION = 0x0002, + CHUNK_EDITOR_CONFIG = 0x3D3E, + CHUNK_EDITOR_DATA = 0x3D3D, + CHUNK_KEYFRAME_DATA = 0xB000, + + /* editor data sub chunks */ + CHUNK_MATERIAL = 0xAFFF, + CHUNK_OBJECT = 0x4000, + + /* material sub chunks */ + CHUNK_MATNAME = 0xA000, + CHUNK_MATDIFFUSE = 0xA020, + CHUNK_MATMAP = 0xA200, + CHUNK_MATMAPFILE = 0xA300, + + /* lets us know we're reading a new object */ + CHUNK_OBJECT_MESH = 0x4100, + + /* object mesh sub chunks */ + CHUNK_OBJECT_VERTICES = 0x4110, + CHUNK_OBJECT_FACES = 0x4120, + CHUNK_OBJECT_MATERIAL = 0x4130, + CHUNK_OBJECT_UV = 0x4140, +}; +#ifdef DEBUG_PM_3DS +static struct +{ + int id; + char *name; +} +debugChunkNames[] = +{ + { CHUNK_MAIN , "CHUNK_MAIN" }, + { CHUNK_VERSION , "CHUNK_VERSION" }, + { CHUNK_EDITOR_CONFIG , "CHUNK_EDITOR_CONFIG" }, + { CHUNK_EDITOR_DATA , "CHUNK_EDITOR_DATA" }, + { CHUNK_KEYFRAME_DATA , "CHUNK_KEYFRAME_DATA" }, + { CHUNK_MATERIAL , "CHUNK_MATERIAL" }, + { CHUNK_OBJECT , "CHUNK_OBJECT" }, + { CHUNK_MATNAME , "CHUNK_MATNAME" }, + { CHUNK_MATDIFFUSE , "CHUNK_MATDIFFUSE" }, + { CHUNK_MATMAP , "CHUNK_MATMAP" }, + { CHUNK_MATMAPFILE , "CHUNK_MATMAPFILE" }, + { CHUNK_OBJECT_MESH , "CHUNK_OBJECT_MESH" }, + { CHUNK_OBJECT_VERTICES , "CHUNK_OBJECT_VERTICES" }, + { CHUNK_OBJECT_FACES , "CHUNK_OBJECT_FACES" }, + { CHUNK_OBJECT_MATERIAL , "CHUNK_OBJECT_MATERIAL" }, + { CHUNK_OBJECT_UV , "CHUNK_OBJECT_UV" }, + { 0 , NULL } +}; +static char *DebugGetChunkName (int id) +{ + int i,max; /* imax? ;) */ + max = sizeof(debugChunkNames) / sizeof(debugChunkNames[0]); + + for (i=0; ilen)) + return PICO_PMV_ERROR_SIZE; + + /* check 3ds magic */ + if (_pico_little_short(chunk->id) != CHUNK_MAIN) + return PICO_PMV_ERROR_IDENT; + + /* file seems to be a valid 3ds */ + return PICO_PMV_OK; +} + +static T3dsChunk *GetChunk (T3dsLoaderPers *pers) +{ + T3dsChunk *chunk; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + +#ifdef DEBUG_PM_3DS +/* printf("GetChunk: pers->cofs %x\n",pers->cofs); */ +#endif + /* fill in pointer to chunk */ + chunk = (T3dsChunk *)&pers->bufptr[ pers->cofs ]; + if (!chunk) return NULL; + + chunk->id = _pico_little_short(chunk->id ); + chunk->len = _pico_little_long (chunk->len); + + /* advance in buffer */ + pers->cofs += sizeof(T3dsChunk); + + /* this means yay */ + return chunk; +} + +static int GetASCIIZ (T3dsLoaderPers *pers, char *dest, int max) +{ + int pos = 0; + int ch; + + for (;;) + { + ch = pers->bufptr[ pers->cofs++ ]; + if (ch == '\0') break; + if (pers->cofs >= pers->maxofs) + { + dest[ pos ] = '\0'; + return 0; + } + dest[ pos++ ] = ch; + if (pos >= max) break; + } + dest[ pos ] = '\0'; + return 1; +} + +static picoByte_t GetByte (T3dsLoaderPers *pers) +{ + picoByte_t *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (picoByte_t *)(pers->bufptr + pers->cofs); + pers->cofs += 1; + return *value; +} + +static int GetWord (T3dsLoaderPers *pers) +{ + unsigned short *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (unsigned short *)(pers->bufptr + pers->cofs); + pers->cofs += 2; + return _pico_little_short(*value); +} + +static float GetFloat (T3dsLoaderPers *pers) +{ + float *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (float *)(pers->bufptr + pers->cofs); + pers->cofs += 4; + return _pico_little_float(*value); +} + +static int GetMeshVertices (T3dsLoaderPers *pers) +{ + int numVerts; + int i; + + /* get number of verts for this surface */ + numVerts = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshVertices: numverts %d\n",numVerts); +#endif + /* read in vertices for current surface */ + for (i=0; isurface,i,v ); + PicoSetSurfaceColor( pers->surface,0,i,white ); /* ydnar */ + +#ifdef DEBUG_PM_3DS_EX + printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshFaces (T3dsLoaderPers *pers) +{ + int numFaces; + int i; + + /* get number of faces for this surface */ + numFaces = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshFaces: numfaces %d\n",numFaces); +#endif + /* read in vertex indices for current surface */ + for (i=0; isurface, (i * 3 + 0), (picoIndex_t)face.a ); + PicoSetSurfaceIndex( pers->surface, (i * 3 + 1), (picoIndex_t)face.b ); + PicoSetSurfaceIndex( pers->surface, (i * 3 + 2), (picoIndex_t)face.c ); + +#ifdef DEBUG_PM_3DS_EX + printf("Face: a: %d b: %d c: %d (%d)\n",face.a,face.b,face.c,face.visible); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshTexCoords (T3dsLoaderPers *pers) +{ + int numTexCoords; + int i; + + /* get number of uv coords for this surface */ + numTexCoords = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshTexCoords: numcoords %d\n",numTexCoords); +#endif + /* read in uv coords for current surface */ + for (i=0; isurface == NULL) + continue; + + /* add current uv */ + PicoSetSurfaceST( pers->surface,0,i,uv ); + +#ifdef DEBUG_PM_3DS_EX + printf("u: %f v: %f\n",uv[0],uv[1]); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshShader (T3dsLoaderPers *pers) +{ + char shaderName[255] = { 0 }; + picoShader_t *shader; + int numSharedVerts; + int setShaderName = 0; + int i; + + /* the shader is either the color or the texture map of the */ + /* object. it can also hold other information like the brightness, */ + /* shine, etc. stuff we don't really care about. we just want the */ + /* color, or the texture map file name really */ + + /* get in the shader name */ + if (!GetASCIIZ(pers,shaderName,sizeof(shaderName))) + return 0; + + /* now that we have the shader name we need to go through all of */ + /* the shaders and check the name against each shader. when we */ + /* find a shader in our shader list that matches this name we */ + /* just read in, then we assign the shader's id of the object to */ + /* that shader */ + + /* get shader id for shader name */ + shader = PicoFindShader( pers->model, shaderName, 1 ); + + /* we've found a matching shader */ + if ((shader != NULL) && pers->surface) + { + char mapName[1024+1]; + char *mapNamePtr; + memset( mapName,0,sizeof(mapName) ); + + /* get ptr to shader's map name */ + mapNamePtr = PicoGetShaderMapName( shader ); + + /* we have a valid map name ptr */ + if (mapNamePtr != NULL) + { + char temp[128]; + char *name; + + /* copy map name to local buffer */ + strcpy( mapName,mapNamePtr ); + + /* extract file name */ + name = _pico_nopath( mapName ); + strncpy( temp, name, sizeof(temp) ); + + /* remove file extension */ + /* name = _pico_setfext( name,"" ); */ + + /* assign default name if no name available */ + if (strlen(temp) < 1) + strcpy(temp,pers->basename); + + /* build shader name */ + _pico_strlwr( temp ); /* gaynux update -sea */ + sprintf( mapName,"models/mapobjects/%s/%s",pers->basename,temp ); + + /* set shader name */ + /* PicoSetShaderName( shader,mapName ); */ /* ydnar: this will screw up the named shader */ + + /* set surface's shader index */ + PicoSetSurfaceShader( pers->surface, shader ); + + setShaderName = 1; + } + } + /* we didn't set a shader name; throw out warning */ + if (!setShaderName) + { + _pico_printf( PICO_WARNING,"3DS mesh is missing shader name"); + } + /* we don't process the list of shared vertices here; there is a */ + /* short int that gives the number of faces of the mesh concerned */ + /* by this shader, then there is the list itself of these faces. */ + /* 0000 means the first face of the (4120) face list */ + + /* get number of shared verts */ + numSharedVerts = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshShader: uses shader '%s' (nsv %d)\n",shaderName,numSharedVerts); +#endif + /* skip list of shared verts */ + for (i=0; ishader ) + { + PicoSetShaderDiffuseColor( pers->shader,color ); + } +#ifdef DEBUG_PM_3DS + printf("GetDiffuseColor: %d %d %d\n",color[0],color[1],color[2]); +#endif + /* success (no errors occured) */ + return 1; +} + +static int DoNextEditorDataChunk (T3dsLoaderPers *pers, long endofs) +{ + T3dsChunk *chunk; + +#ifdef DEBUG_PM_3DS_EX + printf("DoNextEditorDataChunk: endofs %d\n",endofs); +#endif + while (pers->cofs < endofs) + { + long nextofs = pers->cofs; + if ((chunk = GetChunk(pers)) == NULL) return 0; + if (!chunk->len) return 0; + nextofs += chunk->len; + +#ifdef DEBUG_PM_3DS_EX + printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); +#endif + /*** meshes ***/ + if (chunk->id == CHUNK_OBJECT) + { + picoSurface_t *surface; + char surfaceName[ 0xff ] = { 0 }; + + /* read in surface name */ + if( !GetASCIIZ(pers,surfaceName,sizeof(surfaceName)) ) + return 0; /* this is bad */ + +//PicoGetSurfaceName + /* ignore NULL name surfaces */ +// if( surfaceName + + /* allocate a pico surface */ + surface = PicoNewSurface( pers->model ); + if( surface == NULL ) + { + pers->surface = NULL; + return 0; /* this is bad too */ + } + /* assign ptr to current surface */ + pers->surface = surface; + + /* 3ds models surfaces are all triangle meshes */ + PicoSetSurfaceType( pers->surface,PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( pers->surface,surfaceName ); + + /* continue mess with object's sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_OBJECT_MESH) + { + /* continue mess with mesh's sub chunks */ + if (!DoNextEditorDataChunk(pers,nextofs)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_VERTICES) + { + if (!GetMeshVertices(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_FACES) + { + if (!GetMeshFaces(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_UV) + { + if (!GetMeshTexCoords(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_MATERIAL) + { + if (!GetMeshShader(pers)) return 0; + continue; + } + /*** materials ***/ + if (chunk->id == CHUNK_MATERIAL) + { + /* new shader specific things should be */ + /* initialized right here */ + picoShader_t *shader; + + /* allocate a pico shader */ + shader = PicoNewShader( pers->model ); /* ydnar */ + if( shader == NULL ) + { + pers->shader = NULL; + return 0; /* this is bad too */ + } + + /* assign ptr to current shader */ + pers->shader = shader; + + /* continue and process the material's sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_MATNAME) + { + /* new material's names should be stored here. note that */ + /* GetMeshMaterial returns the name of the material that */ + /* is used by the mesh. new material names are set HERE. */ + /* but for now we skip the new material's name ... */ + if (pers->shader) + { + char *name = (char *)(pers->bufptr + pers->cofs); + PicoSetShaderName( pers->shader,name ); +#ifdef DEBUG_PM_3DS + printf("NewShader: '%s'\n",name); +#endif + } + } + if (chunk->id == CHUNK_MATDIFFUSE) + { + /* todo: color for last inserted new material should be */ + /* stored somewhere by GetDiffuseColor */ + if (!GetDiffuseColor(pers)) return 0; + + /* rest of chunk is skipped here */ + } + if (chunk->id == CHUNK_MATMAP) + { + /* continue and process the material map sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_MATMAPFILE) + { + /* map file name for last inserted new material should */ + /* be stored here. but for now we skip this too ... */ + if( pers->shader ) + { + char *name = (char *)(pers->bufptr + pers->cofs); + PicoSetShaderMapName( pers->shader,name ); +#ifdef DEBUG_PM_3DS + printf("NewShaderMapfile: '%s'\n",name); +#endif + } + } + /*** keyframes ***/ + if (chunk->id == CHUNK_KEYFRAME_DATA) + { + /* well umm, this is a bit too much since we don't really */ + /* need model animation sequences right now. we skip this */ +#ifdef DEBUG_PM_3DS + printf("KeyframeData: len %d\n",chunk->len); +#endif + } + /* skip unknown chunk */ + pers->cofs = nextofs; + if (pers->cofs >= pers->maxofs) break; + } + return 1; +} + +static int DoNextChunk (T3dsLoaderPers *pers, int endofs) +{ + T3dsChunk *chunk; + +#ifdef DEBUG_PM_3DS + printf("DoNextChunk: endofs %d\n",endofs); +#endif + while (pers->cofs < endofs) + { + long nextofs = pers->cofs; + if ((chunk = GetChunk(pers)) == NULL) return 0; + if (!chunk->len) return 0; + nextofs += chunk->len; + +#ifdef DEBUG_PM_3DS_EX + printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); +#endif + /*** version ***/ + if (chunk->id == CHUNK_VERSION) + { + /* at this point i get the 3ds file version. since there */ + /* might be new additions to the 3ds file format in 4.0 */ + /* it might be a good idea to store the version somewhere */ + /* for later handling or message displaying */ + + /* get the version */ + int version; + version = GetWord(pers); + GetWord(pers); +#ifdef DEBUG_PM_3DS + printf("FileVersion: %d\n",version); +#endif + + /* throw out a warning for version 4 models */ + if (version == 4) + { + _pico_printf( PICO_WARNING, + "3DS version is 4. Model might load incorrectly."); + } + /* store the 3ds file version in pico special field 0 */ + /* PicoSetSurfaceSpecial(pers->surface,0,version); */ /* ydnar: this was causing a crash accessing uninitialized surface */ + + /* rest of chunk is skipped here */ + } + /*** editor data ***/ + if (chunk->id == CHUNK_EDITOR_DATA) + { + if (!DoNextEditorDataChunk(pers,nextofs)) return 0; + continue; + } + /* skip unknown chunk */ + pers->cofs = nextofs; + if (pers->cofs >= pers->maxofs) break; + } + return 1; +} + +/* _3ds_load: + * loads an autodesk 3ds model file. +*/ +static picoModel_t *_3ds_load( PM_PARAMS_LOAD ) +{ + T3dsLoaderPers pers; + picoModel_t *model; + char basename[128]; + + /* create a new pico model */ + model = PicoNewModel(); + if (model == NULL) + { + /* user must have some serious ram problems ;) */ + return NULL; + } + /* get model's base name (eg. jeep from c:\models\jeep.3ds) */ + memset( basename,0,sizeof(basename) ); + strncpy( basename,_pico_nopath(fileName),sizeof(basename) ); + _pico_setfext( basename,"" ); + + /* initialize persistant vars (formerly static) */ + pers.model = model; + pers.bufptr = (picoByte_t *)buffer; + pers.basename = (char *)basename; + pers.maxofs = bufSize; + pers.cofs = 0L; + + /* do model setup */ + PicoSetModelFrameNum( model,frameNum ); + PicoSetModelName( model,fileName ); + PicoSetModelFileName( model,fileName ); + + /* skip first chunk in file (magic) */ + GetChunk(&pers); + + /* process chunks */ + if (!DoNextChunk(&pers,pers.maxofs)) + { + /* well, bleh i guess */ + PicoFreeModel(model); + return NULL; + } + /* return allocated pico model */ + return model; +} + +/* pico file format module definition */ +const picoModule_t picoModule3DS = +{ + "0.86-b", /* module version string */ + "Autodesk 3Dstudio", /* module display name */ + "seaw0lf", /* author's name */ + "2002 seaw0lf", /* module copyright */ + { + "3ds",NULL,NULL,NULL /* default extensions to use */ + }, + _3ds_canload, /* validation routine */ + _3ds_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_ase.c b/libs/picomodel/pm_ase.c new file mode 100644 index 00000000..e8c5751d --- /dev/null +++ b/libs/picomodel/pm_ase.c @@ -0,0 +1,1001 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other aseMaterialList provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + +/* marker */ +#define PM_ASE_C + +/* uncomment when debugging this module */ +//#define DEBUG_PM_ASE +//#define DEBUG_PM_ASE_EX + + +/* dependencies */ +#include "picointernal.h" + +#ifdef DEBUG_PM_ASE +#include "time.h" +#endif + +/* plain white */ +static picoColor_t white = { 255, 255, 255, 255 }; + +/* jhefty - multi-subobject material support */ + +/* Material/SubMaterial management */ +/* A material should have 1..n submaterials assigned to it */ + +typedef struct aseSubMaterial_s +{ + struct aseSubMaterial_s* next; + int subMtlId; + picoShader_t* shader; + +} aseSubMaterial_t; + +typedef struct aseMaterial_s +{ + struct aseMaterial_s* next; + struct aseSubMaterial_s* subMtls; + int mtlId; +} aseMaterial_t; + +/* Material/SubMaterial management functions */ +static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent ) +{ + aseMaterial_t* mtl = list; + + while ( mtl ) + { + if ( mtlIdParent == mtl->mtlId ) + { + break; + } + mtl = mtl->next; + } + return mtl; +} + +static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId ) +{ + aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent ); + aseSubMaterial_t* subMtl = NULL; + + if ( !parent ) + { + _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent ); + return NULL; + } + + subMtl = parent->subMtls; + while ( subMtl ) + { + if ( subMtlId == subMtl->subMtlId ) + { + break; + } + subMtl = subMtl->next; + } + return subMtl; +} + +static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ) +{ + aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) ); + mtl->mtlId = mtlIdParent; + mtl->subMtls = NULL; + mtl->next = *list; + *list = mtl; + + return mtl; +} + +static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ) +{ + aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent ); + aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) ); + + if ( !parent ) + { + parent = _ase_add_material ( list , mtlIdParent ); + } + + subMtl->shader = shader; + subMtl->subMtlId = subMtlId; + subMtl->next = parent->subMtls; + parent->subMtls = subMtl; + + return subMtl; +} + +static void _ase_free_materials( aseMaterial_t **list ) +{ + aseMaterial_t* mtl = *list; + aseSubMaterial_t* subMtl = NULL; + + aseMaterial_t* mtlTemp = NULL; + aseSubMaterial_t* subMtlTemp = NULL; + + while ( mtl ) + { + subMtl = mtl->subMtls; + while ( subMtl ) + { + subMtlTemp = subMtl->next; + _pico_free ( subMtl ); + subMtl = subMtlTemp; + } + mtlTemp = mtl->next; + _pico_free ( mtl ); + mtl = mtlTemp; + } + (*list) = NULL; +} + +#ifdef DEBUG_PM_ASE +static void _ase_print_materials( aseMaterial_t *list ) +{ + aseMaterial_t* mtl = list; + aseSubMaterial_t* subMtl = NULL; + + while ( mtl ) + { + _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId ); + subMtl = mtl->subMtls; + while ( subMtl ) + { + _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name ); + subMtl = subMtl->next; + } + mtl = mtl->next; + } +} +#endif //DEBUG_PM_ASE + +/* ASE Face management */ +/* These are used to keep an association between a submaterial and a face definition */ +/* They are kept in parallel with the current picoSurface, */ +/* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */ +typedef struct aseFace_s +{ + struct aseFace_s* next; + int mtlId; + int subMtlId; + int index[9]; +} aseFace_t; + +/* ASE Face management functions */ +void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace ) +{ + aseFace_t* face = *list; + aseFace_t* tempFace = NULL; + + /* insert as head of list */ + if ( !(*list) ) + { + *list = newFace; + } + else + { + (*tail)->next = newFace; + } + + *tail = newFace; + newFace->next = NULL; + + //tag the color indices so we can detect them and apply the default color to them + newFace->index[6] = -1; + newFace->index[7] = -1; + newFace->index[8] = -1; +} + +aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index ) +{ + int counter = 0; + aseFace_t* face = list; + + while ( counter < index ) + { + face = face->next; + counter++; + } + return face; +} +static void _ase_free_faces (aseFace_t** list, aseFace_t** tail ) +{ + aseFace_t* face = *list; + aseFace_t* tempFace = NULL; + + while ( face ) + { + tempFace = face->next; + _pico_free ( face ); + face = tempFace; + } + + (*list) = NULL; + (*tail) = NULL; +} + +/* todo: + * - apply material specific uv offsets to uv coordinates + */ + +/* _ase_canload: + * validates a 3dsmax ase model file. + */ +static int _ase_canload( PM_PARAMS_CANLOAD ) +{ + picoParser_t *p; + + + /* quick data length validation */ + if( bufSize < 80 ) + return PICO_PMV_ERROR_SIZE; + + /* keep the friggin compiler happy */ + *fileName = *fileName; + + /* create pico parser */ + p = _pico_new_parser( (picoByte_t*) buffer, bufSize ); + if( p == NULL ) + return PICO_PMV_ERROR_MEMORY; + + /* get first token */ + if( _pico_parse_first( p ) == NULL) + { + return PICO_PMV_ERROR_IDENT; + } + + /* check first token */ + if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) + { + _pico_free_parser( p ); + return PICO_PMV_ERROR_IDENT; + } + + /* free the pico parser object */ + _pico_free_parser( p ); + + /* file seems to be a valid ase file */ + return PICO_PMV_OK; +} + + + +/* _ase_submit_triangles - jhefty + use the surface and the current face list to look up material/submaterial IDs + and submit them to the model for proper processing + +The following still holds from ydnar's _ase_make_surface: + indexes 0 1 2 = vert indexes + indexes 3 4 5 = st indexes + indexes 6 7 8 = color indexes (new) +*/ + +static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces ) +{ + aseFace_t* face; + aseSubMaterial_t* subMtl; + picoVec3_t* xyz[3]; + picoVec3_t* normal[3]; + picoVec2_t* st[3]; + picoColor_t* color[3]; + int i; + + face = faces; + while ( face != NULL ) + { + /* look up the shader for the material/submaterial pair */ + subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId ); + if( subMtl == NULL ) + { + /* ydnar: trying default submaterial */ + subMtl = _ase_get_submaterial( materials, face->mtlId, 0 ); + if( subMtl == NULL ) + { + _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId ); + return; + } + } + + /* we pull the data from the surface using the facelist data */ + for ( i = 0 ; i < 3 ; i ++ ) + { + xyz[i] = (picoVec3_t*) PicoGetSurfaceXYZ ( surface, face->index[ i ] ); + normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] ); + st[i] = (picoVec2_t*) PicoGetSurfaceST ( surface, 0, face->index[ i + 3 ] ); + + if ( face->index [ i + 6] >= 0 ) + { + color[i] = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] ); + } + else + { + color[i] = &white; + } + + } + + /* submit the triangle to the model */ + PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader ); + + /* advance to the next face */ + face = face->next; + } +} + +/* _ase_load: + * loads a 3dsmax ase model file. +*/ +static picoModel_t *_ase_load( PM_PARAMS_LOAD ) +{ + picoModel_t *model; + picoSurface_t *surface = NULL; + picoParser_t *p; + char lastNodeName[ 1024 ]; + + aseFace_t* faces = NULL; + aseFace_t* facesTail = NULL; + aseMaterial_t* materials = NULL; + +#ifdef DEBUG_PM_ASE + clock_t start, finish; + double elapsed; + start = clock(); +#endif + + /* helper */ + #define _ase_error_return(m) \ + { \ + _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \ + _pico_free_parser( p ); \ + PicoFreeModel( model ); \ + return NULL; \ + } + /* create a new pico parser */ + p = _pico_new_parser( (picoByte_t *)buffer,bufSize ); + if (p == NULL) return NULL; + + /* create a new pico model */ + model = PicoNewModel(); + if (model == NULL) + { + _pico_free_parser( p ); + return NULL; + } + /* do model setup */ + PicoSetModelFrameNum( model, frameNum ); + PicoSetModelName( model, fileName ); + PicoSetModelFileName( model, fileName ); + + /* initialize some stuff */ + memset( lastNodeName,0,sizeof(lastNodeName) ); + + /* parse ase model file */ + while( 1 ) + { + /* get first token on line */ + if (_pico_parse_first( p ) == NULL) + break; + + /* we just skip empty lines */ + if (p->token == NULL || !strlen( p->token )) + continue; + + /* we skip invalid ase statements */ + if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}') + { + _pico_parse_skip_rest( p ); + continue; + } + /* remember node name */ + if (!_pico_stricmp(p->token,"*node_name")) + { + /* read node name */ + char *ptr = _pico_parse( p,0 ); + if (ptr == NULL) + _ase_error_return("Node name parse error"); + + /* remember node name */ + strncpy( lastNodeName,ptr,sizeof(lastNodeName) ); + } + /* model mesh (originally contained within geomobject) */ + else if (!_pico_stricmp(p->token,"*mesh")) + { + /* finish existing surface */ + //_ase_make_surface( model, &surface ); + _ase_submit_triangles (surface, model ,materials,faces); + _ase_free_faces (&faces,&facesTail); + + /* allocate new pico surface */ + surface = PicoNewSurface( NULL ); + if (surface == NULL) + { + PicoFreeModel( model ); + return NULL; + } + } + /* mesh material reference. this usually comes at the end of */ + /* geomobjects after the mesh blocks. we must assume that the */ + /* new mesh was already created so all we can do here is assign */ + /* the material reference id (shader index) now. */ + else if (!_pico_stricmp(p->token,"*material_ref")) + { + int mtlId; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + _ase_error_return("Missing mesh for material reference"); + + /* get the material ref (0..n) */ + if (!_pico_parse_int( p,&mtlId) ) + _ase_error_return("Missing material reference ID"); + + /* fix up all of the aseFaceList in the surface to point to the parent material */ + /* we've already saved off their subMtl */ + face = faces; + while ( face != NULL ) + { + face->mtlId = mtlId; + face = face->next; + } + } + /* model mesh vertex */ + else if (!_pico_stricmp(p->token,"*mesh_vertex")) + { + picoVec3_t v; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get vertex data (orig: index +y -x +z) */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Vertex parse error"); + if (!_pico_parse_vec( p,v )) + _ase_error_return("Vertex parse error"); + + /* set vertex */ + PicoSetSurfaceXYZ( surface,index,v ); + } + /* model mesh vertex normal */ + else if (!_pico_stricmp(p->token,"*mesh_vertexnormal")) + { + picoVec3_t v; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get vertex data (orig: index +y -x +z) */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Vertex parse error"); + if (!_pico_parse_vec( p,v )) + _ase_error_return("Vertex parse error"); + + /* set vertex */ + PicoSetSurfaceNormal( surface,index,v ); + } + /* model mesh face */ + else if (!_pico_stricmp(p->token,"*mesh_face")) + { + picoIndex_t indexes[3]; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Face parse error"); + + /* get 1st vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Face parse error"); + + /* get 2nd vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Face parse error"); + + /* get 3rd vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] ); + + /* parse to the subMaterial ID */ + while ( 1 ) + { + _pico_parse (p,0); + if (!_pico_stricmp (p->token,"*MESH_MTLID" )) + { + aseFace_t* newFace; + int subMtlId; + + _pico_parse_int ( p , &subMtlId ); + newFace = _pico_calloc ( 1 , sizeof ( aseFace_t )); + + /* we fix up the mtlId later when we parse the material_ref */ + newFace->mtlId = 0; + newFace->subMtlId = subMtlId; + newFace->index[0] = indexes[2]; + newFace->index[1] = indexes[1]; + newFace->index[2] = indexes[0]; + + _ase_add_face ( &faces,&facesTail,newFace ); + break; + } + } + + } + /* model texture vertex */ + else if (!_pico_stricmp(p->token,"*mesh_tvert")) + { + picoVec2_t uv; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get uv vertex index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("UV vertex parse error"); + + /* get uv vertex s */ + if (!_pico_parse_float( p,&uv[0] )) + _ase_error_return("UV vertex parse error"); + + /* get uv vertex t */ + if (!_pico_parse_float( p,&uv[1] )) + _ase_error_return("UV vertex parse error"); + + /* ydnar: invert t */ + uv[ 1 ] = 1.0f - uv[ 1 ]; + + /* set texture vertex */ + PicoSetSurfaceST( surface,0,index,uv ); + } + /* ydnar: model mesh texture face */ + else if( !_pico_stricmp( p->token, "*mesh_tface" ) ) + { + picoIndex_t indexes[3]; + int index; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Texture face parse error"); + + /* get 1st vertex index */ + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Texture face parse error"); + + /* get 2nd vertex index */ + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Texture face parse error"); + + /* get 3rd vertex index */ + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Texture face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] ); + + face = _ase_get_face_for_index(faces,index); + face->index[3] = indexes[2]; + face->index[4] = indexes[1]; + face->index[5] = indexes[0]; + } + /* model color vertex */ + else if (!_pico_stricmp(p->token,"*mesh_vertcol")) + { + picoColor_t color; + int index; + float colorInput; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get color vertex index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("UV vertex parse error"); + + /* get R component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[0] = (picoByte_t)(colorInput * 255); + + /* get G component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[1] = (picoByte_t)(colorInput * 255); + + /* get B component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[2] = (picoByte_t)(colorInput * 255); + + /* leave alpha alone since we don't get any data from the ASE format */ + color[3] = 255; + + /* set texture vertex */ + PicoSetSurfaceColor( surface,0,index,color ); + } + /* model color face */ + else if (!_pico_stricmp(p->token,"*mesh_cface")) + { + picoIndex_t indexes[3]; + int index; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Face parse error"); + + /* get 1st cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Face parse error"); + + /* get 2nd cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Face parse error"); + + /* get 3rd cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] ); + + face = _ase_get_face_for_index(faces,index); + face->index[6] = indexes[2]; + face->index[7] = indexes[1]; + face->index[8] = indexes[0]; + } + /* model material */ + else if( !_pico_stricmp( p->token, "*material" ) ) + { + aseSubMaterial_t* subMaterial = NULL; + picoShader_t *shader; + int level = 1, index; + char materialName[ 1024 ]; + float transValue = 0.0f, shineValue = 1.0f; + picoColor_t ambientColor, diffuseColor, specularColor; + char *mapname = NULL; + int subMtlId, subMaterialLevel = -1; + + + /* get material index */ + _pico_parse_int( p,&index ); + + /* check brace */ + if (!_pico_parse_check(p,1,"{")) + _ase_error_return("Material missing opening brace"); + + /* parse material block */ + while( 1 ) + { + /* get next token */ + if (_pico_parse(p,1) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + if( level == subMaterialLevel ) + { + /* set material name */ + PicoSetShaderName( shader, materialName); + + /* set shader's transparency */ + PicoSetShaderTransparency( shader,transValue ); + + /* set shader's ambient color */ + PicoSetShaderAmbientColor( shader,ambientColor ); + + /* set diffuse alpha to transparency */ + diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); + + /* set shader's diffuse color */ + PicoSetShaderDiffuseColor( shader,diffuseColor ); + + /* set shader's specular color */ + PicoSetShaderSpecularColor( shader,specularColor ); + + /* set shader's shininess */ + PicoSetShaderShininess( shader,shineValue ); + + /* set material map name */ + PicoSetShaderMapName( shader, mapname ); + + subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader ); + subMaterialLevel = -1; + } + + /* parse submaterial index */ + if (!_pico_stricmp(p->token,"*submaterial")) + { + /* allocate new pico shader */ + _pico_parse_int( p , &subMtlId ); + + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + subMaterialLevel = level; + } + /* parse material name */ + else if (!_pico_stricmp(p->token,"*material_name")) + { + char* name = _pico_parse(p,0); + if ( name == NULL) + _ase_error_return("Missing material name"); + + strcpy ( materialName , name ); + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse material transparency */ + else if (!_pico_stricmp(p->token,"*material_transparency")) + { + /* get transparency value from ase */ + if (!_pico_parse_float( p,&transValue )) + _ase_error_return("Material transparency parse error"); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse material shininess */ + else if (!_pico_stricmp(p->token,"*material_shine")) + { + /* remark: + * - not sure but instead of '*material_shine' i might + * need to use '*material_shinestrength' */ + + /* get shine value from ase */ + if (!_pico_parse_float( p,&shineValue )) + _ase_error_return("Material shine parse error"); + + /* scale ase shine range 0..1 to pico range 0..127 */ + shineValue *= 128.0; + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse ambient material color */ + else if (!_pico_stricmp(p->token,"*material_ambient")) + { + picoVec3_t vec; + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color values */ + ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); + ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); + ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); + ambientColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse diffuse material color */ + else if (!_pico_stricmp(p->token,"*material_diffuse")) + { + picoVec3_t vec; + + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color */ + diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); + diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); + diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); + diffuseColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse specular material color */ + else if (!_pico_stricmp(p->token,"*material_specular")) + { + picoVec3_t vec; + + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color */ + specularColor[ 0 ] = (int)( vec[ 0 ] * 255 ); + specularColor[ 1 ] = (int)( vec[ 1 ] * 255 ); + specularColor[ 2 ] = (int)( vec[ 2 ] * 255 ); + specularColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* material diffuse map */ + else if (!_pico_stricmp(p->token,"*map_diffuse") ) + { + int sublevel = 0; + + /* parse material block */ + while( 1 ) + { + /* get next token */ + if (_pico_parse(p,1) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') sublevel++; + if (p->token[0] == '}') sublevel--; + if (!sublevel) break; + + /* parse diffuse map bitmap */ + if (!_pico_stricmp(p->token,"*bitmap")) + { + char* name = _pico_parse(p,0); + if (name == NULL) + _ase_error_return("Missing material map bitmap name"); + mapname = _pico_alloc ( strlen ( name ) + 1 ); + strcpy ( mapname, name ); + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + } + } + /* end map_diffuse block */ + } + /* end material block */ + + if( subMaterial == NULL ) + { + /* allocate new pico shader */ + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + + /* set material name */ + PicoSetShaderName( shader,materialName ); + + /* set shader's transparency */ + PicoSetShaderTransparency( shader,transValue ); + + /* set shader's ambient color */ + PicoSetShaderAmbientColor( shader,ambientColor ); + + /* set diffuse alpha to transparency */ + diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); + + /* set shader's diffuse color */ + PicoSetShaderDiffuseColor( shader,diffuseColor ); + + /* set shader's specular color */ + PicoSetShaderSpecularColor( shader,specularColor ); + + /* set shader's shininess */ + PicoSetShaderShininess( shader,shineValue ); + + /* set material map name */ + PicoSetShaderMapName( shader, mapname ); + + /* this is just a material with 1 submaterial */ + subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); + } + + /* ydnar: free mapname */ + if( mapname != NULL ) + _pico_free( mapname ); + } // !_pico_stricmp ( "*material" ) + + /* skip unparsed rest of line and continue */ + _pico_parse_skip_rest( p ); + } + + /* ydnar: finish existing surface */ +// _ase_make_surface( model, &surface ); + _ase_submit_triangles (surface, model ,materials,faces); + _ase_free_faces (&faces,&facesTail); + +#ifdef DEBUG_PM_ASE + _ase_print_materials(materials); + finish = clock(); + elapsed = (double)(finish - start) / CLOCKS_PER_SEC; + _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed ); +#endif //DEBUG_PM_ASE + + _ase_free_materials(&materials); + + /* return allocated pico model */ + return model; +} + +/* pico file format module definition */ +const picoModule_t picoModuleASE = +{ + "1.0", /* module version string */ + "Autodesk 3DSMAX ASCII", /* module display name */ + "Jared Hefty, seaw0lf", /* author's name */ + "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */ + { + "ase",NULL,NULL,NULL /* default extensions to use */ + }, + _ase_canload, /* validation routine */ + _ase_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_fm.c b/libs/picomodel/pm_fm.c new file mode 100644 index 00000000..c6f8e538 --- /dev/null +++ b/libs/picomodel/pm_fm.c @@ -0,0 +1,670 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +/* +Nurail: Used pm_md3.c (Randy Reddig) as a template. +*/ + +/* marker */ +#define PM_FM_C + +/* dependencies */ +#include "pm_fm.h" + +//#define FM_VERBOSE_DBG 0 +#undef FM_VERBOSE_DBG +#undef FM_DBG + +typedef struct index_LUT_s +{ + short Vert; + short ST; + struct index_LUT_s *next; + +} index_LUT_t; + +typedef struct index_DUP_LUT_s +{ + short ST; + short OldVert; + +} index_DUP_LUT_t; + + +// _fm_canload() +static int _fm_canload( PM_PARAMS_CANLOAD ) +{ + fm_t fm; + unsigned char *bb; + int fm_file_pos; + + bb = (unsigned char *) buffer; + + // Header + fm.fm_header_hdr = (fm_chunk_header_t *) bb; + fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident ); +#endif + if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // Skin + fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident ); +#endif + if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // st + fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident ); +#endif + if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // tri + fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident ); +#endif + if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // frame + fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t); +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident ); +#endif + if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // file seems to be a valid fm + return PICO_PMV_OK; +} + + + +// _fm_load() loads a Heretic 2 model file. +static picoModel_t *_fm_load( PM_PARAMS_LOAD ) +{ + int i, j, dups, dup_index; + int fm_file_pos; + short tot_numVerts; + index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; + index_DUP_LUT_t *p_index_LUT_DUPS; + + fm_vert_normal_t *vert; + + char skinname[FM_SKINPATHSIZE]; + fm_t fm; + fm_header_t *fm_head; + fm_st_t *texCoord; + fm_xyz_st_t *tri_verts; + fm_xyz_st_t *triangle; + fm_frame_t *frame; + + picoByte_t *bb; + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + // fm loading + _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); + + bb = (picoByte_t*) buffer; + + // Header Header + fm.fm_header_hdr = (fm_chunk_header_t *) bb; + fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; + if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); + return NULL; + } + + // Skin Header + fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; + if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); + return NULL; + } + + // ST Header + fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; + if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); + return NULL; + } + + // Tris Header + fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; + if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); + return NULL; + } + + // Frame Header + fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t); + if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); + return NULL; + } + + // Header + fm_file_pos = sizeof(fm_chunk_header_t); + fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_header_hdr->size; + + // Skin + fm_file_pos += sizeof(fm_chunk_header_t); + fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_skin_hdr->size; + + // ST + fm_file_pos += sizeof(fm_chunk_header_t); + texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_st_hdr->size; + + // Tri + fm_file_pos += sizeof(fm_chunk_header_t); + tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_tri_hdr->size; + + // Frame + fm_file_pos += sizeof(fm_chunk_header_t); + frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos); + + // do frame check + if( fm_head->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); + return NULL; + } + + if( frameNum < 0 || frameNum >= fm_head->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" ); + return NULL; + } + + // swap fm + fm_head->skinWidth = _pico_little_long( fm_head->skinWidth ); + fm_head->skinHeight = _pico_little_long( fm_head->skinHeight ); + fm_head->frameSize = _pico_little_long( fm_head->frameSize ); + + fm_head->numSkins = _pico_little_long( fm_head->numSkins ); + fm_head->numXYZ = _pico_little_long( fm_head->numXYZ ); + fm_head->numST = _pico_little_long( fm_head->numST ); + fm_head->numTris = _pico_little_long( fm_head->numTris ); + fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds ); + fm_head->numFrames = _pico_little_long( fm_head->numFrames ); + + // swap frame scale and translation + for( i = 0; i < 3; i++ ) + { + frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] ); + frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] ); + } + + // swap triangles + triangle = tri_verts; + for( i = 0; i < fm_head->numTris; i++, triangle++ ) + { + for( j = 0; j < 3; j++ ) + { + triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); + triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); + } + } + + // swap st coords + for( i = 0; i < fm_head->numST; i++ ) + { + texCoord->s = _pico_little_short( texCoord[i].s ); + texCoord->t = _pico_little_short( texCoord[i].t ); + } + // set Skin Name + strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE ); + +#ifdef FM_VERBOSE_DBG + // Print out md2 values + _pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname ); +#endif + + // detox Skin name + _pico_setfext( skinname, "" ); + _pico_unixify( skinname ); + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + // allocate new pico surface + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + return NULL; + } + + + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( picoSurface, frame->header.name ); + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + PicoSetShaderName( picoShader, skinname ); + + // associate current surface with newly created shader + PicoSetSurfaceShader( picoSurface, picoShader ); + + // Init LUT for Verts + p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ); + for(i=0; inumXYZ; i++) + { + p_index_LUT[i].Vert = -1; + p_index_LUT[i].ST = -1; + p_index_LUT[i].next = NULL; + } + + // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. + tot_numVerts = fm_head->numXYZ; + dups = 0; + triangle = tri_verts; + + for(i=0; inumTris; i++) + { + for(j=0; j<3; j++) + { + if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry + p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j]; + + else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry + { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + continue; + } + else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry + { // Add first entry of LL from Main + p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT2 == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; + p_index_LUT2->Vert = dups; + p_index_LUT2->ST = triangle->index_st[j]; + p_index_LUT2->next = NULL; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]); +#endif + triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk + dups++; + } + else // Try to find in LL from Main Entry + { + p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next; + while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL + { + p_index_LUT3 = p_index_LUT2; + p_index_LUT2 = p_index_LUT2->next; + } + p_index_LUT2 = p_index_LUT3; + + if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it + { + triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + continue; + } + + if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. + { + // Add the Entry + p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT3 == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; + p_index_LUT3->Vert = dups; + p_index_LUT3->ST = triangle->index_st[j]; + p_index_LUT3->next = NULL; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]); +#endif + triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk + dups++; + } + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + } + triangle++; + } + + // malloc and build array for Dup STs + p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); + if (p_index_LUT_DUPS == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + + dup_index = 0; + for(i=0; inumXYZ; i++) + { + p_index_LUT2 = p_index_LUT[i].next; + while (p_index_LUT2 != NULL) + { + p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; + p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; + dup_index++; + p_index_LUT2 = p_index_LUT2->next; + } + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " Dups = %d\n", dups); + _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index); +#endif + for(i=0; inumXYZ; i++) + { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST); +#endif + if (p_index_LUT[i].next != NULL) + { + + p_index_LUT2 = p_index_LUT[i].next; + do { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST); +#endif + p_index_LUT2 = p_index_LUT2->next; + } while ( p_index_LUT2 != NULL); + + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "\n"); +#endif + } + + +#ifdef FM_VERBOSE_DBG + for(i=0; inumTris; i++) + { + for(j=0; j<3; j++) + _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); + _pico_printf( PICO_NORMAL, "\n"); + triangle++; + } +#endif + // Build Picomodel + triangle = tri_verts; + for( j = 0; j < fm_head->numTris; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); + PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); + PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); + } + + vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) ); + for(i=0; i< fm_head->numXYZ; i++, vert++) + { + /* set vertex origin */ + xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0]; + xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1]; + xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2]; + PicoSetSurfaceXYZ( picoSurface, i , xyz ); + + /* set normal */ + normal[ 0 ] = fm_normals[vert->lightnormalindex][0]; + normal[ 1 ] = fm_normals[vert->lightnormalindex][1]; + normal[ 2 ] = fm_normals[vert->lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i , st ); + } + + if (dups) + { + for(i=0; iverts[j].v[0] * frame->header.scale[0] + frame->header.translate[0]; + xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1]; + xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2]; + PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz ); + + /* set normal */ + normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0]; + normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1]; + normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st ); + } + } + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, 0, color ); + + // Free up malloc'ed LL entries + for(i=0; inumXYZ; i++) + { + if(p_index_LUT[i].next != NULL) + { + p_index_LUT2 = p_index_LUT[i].next; + do { + p_index_LUT3 = p_index_LUT2->next; + _pico_free(p_index_LUT2); + p_index_LUT2 = p_index_LUT3; + dups--; + } while (p_index_LUT2 != NULL); + } + } + + if (dups) + _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); + + // Free malloc'ed LUTs + _pico_free(p_index_LUT); + _pico_free(p_index_LUT_DUPS); + + /* return the new pico model */ + return picoModel; + +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleFM = +{ + "0.85", /* module version string */ + "Heretic 2 FM", /* module display name */ + "Nurail", /* author's name */ + "2003 Nurail", /* module copyright */ + { + "fm", NULL, NULL, NULL /* default extensions to use */ + }, + _fm_canload, /* validation routine */ + _fm_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_fm.h b/libs/picomodel/pm_fm.h new file mode 100644 index 00000000..ce43d334 --- /dev/null +++ b/libs/picomodel/pm_fm.h @@ -0,0 +1,367 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +// This header file is based from the following: + +/* + FlexModel.H - Header file for FlexModel file structure + + By Chris Burke + serotonin@earthlink.net +*/ + +#ifndef __PM_FM_H__ +#define __PM_FM_H__ + +#include "picointernal.h" + + +// +// Absolute limits (from QData / QMView source) +// +#define MAX_FM_TRIANGLES 2048 +#define MAX_FM_VERTS 2048 +#define MAX_FM_FRAMES 2048 +#define MAX_FM_SKINS 64 +#define MAX_FM_SKINNAME 64 +#define MAX_FM_MESH_NODES 16 + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +#define SKINPAGE_WIDTH 640 +#define SKINPAGE_HEIGHT 480 + +#define ENCODED_WIDTH_X 92 +#define ENCODED_WIDTH_Y 475 +#define ENCODED_HEIGHT_X 128 +#define ENCODED_HEIGHT_Y 475 + +#define SCALE_ADJUST_FACTOR 0.96 + +#define INFO_HEIGHT 5 +#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT) + +#ifndef byte + #define byte unsigned char +#endif + + +// +// Generic header on every chunk +// +#define FM_MAXCHUNKIDENT 32L +typedef struct +{ + char ident[FM_MAXCHUNKIDENT]; + unsigned int version; + unsigned int size; +} fm_chunk_header_t; + +// +// The format of the "header" chunk +// +#define FM_HEADERCHUNKNAME "header" +#define FM_HEADERCHUNKVER 2 +#define FM_HEADERCHUNKSIZE 40 +typedef struct +{ + int skinWidth; // in pixels + int skinHeight; // in pixels + int frameSize; // size of each frame (in bytes) + int numSkins; // number of skins + int numXYZ; // number of unique vertices in 3D space + int numST; // number of unique vertices in texture space + int numTris; // number of unique triangles + int numGLCmds; // # 32-bit elements in strip/fan command list + int numFrames; // number of animation frames + int numMeshNodes; // number of mesh nodes +} fm_header_t; + +// +// The format of an entry in the "skin" chunk. +// The number of entries is given in the fmheader chunk +// +#define FM_SKINCHUNKNAME "skin" +#define FM_SKINCHUNKVER 1 +#define FM_MAXPATHLENGTH 64L +#define FM_SKINPATHSIZE (FM_MAXPATHLENGTH) +typedef struct +{ + char path[FM_SKINPATHSIZE]; // path, relative to 'base' +} fm_skinpath_t; + +// +// The format of the "st coord" chunk. This is a list +// of unique skin texture (u, v) coordinates to be mapped +// to verteces of the model +// +#define FM_STCOORDCHUNKNAME "st coord" +#define FM_STCOORDCHUNKVER 1 +#define FM_STCOORDUVSIZE (2L + 2L) + +typedef struct +{ + short s; + short t; +} fm_st_t; + +// +// The format of the "tris" chunk. This is a list of vertex indeces +// in 3D space, and the corresponding vertex indeces in texture space. +// +#define FM_TRISCHUNKNAME "tris" +#define FM_TRISCHUNKVER 1 +#define FM_TRISINFOSIZE (2L*3 + 2L*3) + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} fm_xyz_st_t; + + +// +// The format of the "frames" chunk. This is a list of animation +// frames, each specifying the coordinates and "light normal" index +// of every vertex of the model in 3D space. +// +#define FM_FRAMESCHUNKNAME "frames" +#define FM_FRAMESCHUNKVER 1 + +#define FM_NUMVERTEXNORMALS 162 + +// Frame info +typedef struct +{ + byte v[3]; // scaled by header info + byte lightnormalindex; // index in canned table of closest vertex normal +} fm_vert_normal_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name +} fm_framehdr_t; + +typedef struct +{ + fm_framehdr_t header; // One header per frame + fm_vert_normal_t verts[1]; // variable number of these +} fm_frame_t; + +typedef struct +{ + fm_chunk_header_t *fm_header_hdr; + fm_header_t *fm_header; + fm_chunk_header_t *fm_skin_hdr; + fm_skinpath_t *fm_skin; + fm_chunk_header_t *fm_st_hdr; + fm_st_t *fm_st; + fm_chunk_header_t *fm_tri_hdr; + fm_xyz_st_t *fm_tri; + fm_chunk_header_t *fm_frame_hdr; + fm_frame_t *fm_frame; +} fm_t; + +float fm_normals[FM_NUMVERTEXNORMALS][3] = { + {-0.525731f, 0.000000f, 0.850651f}, + {-0.442863f, 0.238856f, 0.864188f}, + {-0.295242f, 0.000000f, 0.955423f}, + {-0.309017f, 0.500000f, 0.809017f}, + {-0.162460f, 0.262866f, 0.951056f}, + {0.000000f, 0.000000f, 1.000000f}, + {0.000000f, 0.850651f, 0.525731f}, + {-0.147621f, 0.716567f, 0.681718f}, + {0.147621f, 0.716567f, 0.681718f}, + {0.000000f, 0.525731f, 0.850651f}, + {0.309017f, 0.500000f, 0.809017f}, + {0.525731f, 0.000000f, 0.850651f}, + {0.295242f, 0.000000f, 0.955423f}, + {0.442863f, 0.238856f, 0.864188f}, + {0.162460f, 0.262866f, 0.951056f}, + {-0.681718f, 0.147621f, 0.716567f}, + {-0.809017f, 0.309017f, 0.500000f}, + {-0.587785f, 0.425325f, 0.688191f}, + {-0.850651f, 0.525731f, 0.000000f}, + {-0.864188f, 0.442863f, 0.238856f}, + {-0.716567f, 0.681718f, 0.147621f}, + {-0.688191f, 0.587785f, 0.425325f}, + {-0.500000f, 0.809017f, 0.309017f}, + {-0.238856f, 0.864188f, 0.442863f}, + {-0.425325f, 0.688191f, 0.587785f}, + {-0.716567f, 0.681718f, -0.147621f}, + {-0.500000f, 0.809017f, -0.309017f}, + {-0.525731f, 0.850651f, 0.000000f}, + {0.000000f, 0.850651f, -0.525731f}, + {-0.238856f, 0.864188f, -0.442863f}, + {0.000000f, 0.955423f, -0.295242f}, + {-0.262866f, 0.951056f, -0.162460f}, + {0.000000f, 1.000000f, 0.000000f}, + {0.000000f, 0.955423f, 0.295242f}, + {-0.262866f, 0.951056f, 0.162460f}, + {0.238856f, 0.864188f, 0.442863f}, + {0.262866f, 0.951056f, 0.162460f}, + {0.500000f, 0.809017f, 0.309017f}, + {0.238856f, 0.864188f, -0.442863f}, + {0.262866f, 0.951056f, -0.162460f}, + {0.500000f, 0.809017f, -0.309017f}, + {0.850651f, 0.525731f, 0.000000f}, + {0.716567f, 0.681718f, 0.147621f}, + {0.716567f, 0.681718f, -0.147621f}, + {0.525731f, 0.850651f, 0.000000f}, + {0.425325f, 0.688191f, 0.587785f}, + {0.864188f, 0.442863f, 0.238856f}, + {0.688191f, 0.587785f, 0.425325f}, + {0.809017f, 0.309017f, 0.500000f}, + {0.681718f, 0.147621f, 0.716567f}, + {0.587785f, 0.425325f, 0.688191f}, + {0.955423f, 0.295242f, 0.000000f}, + {1.000000f, 0.000000f, 0.000000f}, + {0.951056f, 0.162460f, 0.262866f}, + {0.850651f, -0.525731f, 0.000000f}, + {0.955423f, -0.295242f, 0.000000f}, + {0.864188f, -0.442863f, 0.238856f}, + {0.951056f, -0.162460f, 0.262866f}, + {0.809017f, -0.309017f, 0.500000f}, + {0.681718f, -0.147621f, 0.716567f}, + {0.850651f, 0.000000f, 0.525731f}, + {0.864188f, 0.442863f, -0.238856f}, + {0.809017f, 0.309017f, -0.500000f}, + {0.951056f, 0.162460f, -0.262866f}, + {0.525731f, 0.000000f, -0.850651f}, + {0.681718f, 0.147621f, -0.716567f}, + {0.681718f, -0.147621f, -0.716567f}, + {0.850651f, 0.000000f, -0.525731f}, + {0.809017f, -0.309017f, -0.500000f}, + {0.864188f, -0.442863f, -0.238856f}, + {0.951056f, -0.162460f, -0.262866f}, + {0.147621f, 0.716567f, -0.681718f}, + {0.309017f, 0.500000f, -0.809017f}, + {0.425325f, 0.688191f, -0.587785f}, + {0.442863f, 0.238856f, -0.864188f}, + {0.587785f, 0.425325f, -0.688191f}, + {0.688191f, 0.587785f, -0.425325f}, + {-0.147621f, 0.716567f, -0.681718f}, + {-0.309017f, 0.500000f, -0.809017f}, + {0.000000f, 0.525731f, -0.850651f}, + {-0.525731f, 0.000000f, -0.850651f}, + {-0.442863f, 0.238856f, -0.864188f}, + {-0.295242f, 0.000000f, -0.955423f}, + {-0.162460f, 0.262866f, -0.951056f}, + {0.000000f, 0.000000f, -1.000000f}, + {0.295242f, 0.000000f, -0.955423f}, + {0.162460f, 0.262866f, -0.951056f}, + {-0.442863f, -0.238856f, -0.864188f}, + {-0.309017f, -0.500000f, -0.809017f}, + {-0.162460f, -0.262866f, -0.951056f}, + {0.000000f, -0.850651f, -0.525731f}, + {-0.147621f, -0.716567f, -0.681718f}, + {0.147621f, -0.716567f, -0.681718f}, + {0.000000f, -0.525731f, -0.850651f}, + {0.309017f, -0.500000f, -0.809017f}, + {0.442863f, -0.238856f, -0.864188f}, + {0.162460f, -0.262866f, -0.951056f}, + {0.238856f, -0.864188f, -0.442863f}, + {0.500000f, -0.809017f, -0.309017f}, + {0.425325f, -0.688191f, -0.587785f}, + {0.716567f, -0.681718f, -0.147621f}, + {0.688191f, -0.587785f, -0.425325f}, + {0.587785f, -0.425325f, -0.688191f}, + {0.000000f, -0.955423f, -0.295242f}, + {0.000000f, -1.000000f, 0.000000f}, + {0.262866f, -0.951056f, -0.162460f}, + {0.000000f, -0.850651f, 0.525731f}, + {0.000000f, -0.955423f, 0.295242f}, + {0.238856f, -0.864188f, 0.442863f}, + {0.262866f, -0.951056f, 0.162460f}, + {0.500000f, -0.809017f, 0.309017f}, + {0.716567f, -0.681718f, 0.147621f}, + {0.525731f, -0.850651f, 0.000000f}, + {-0.238856f, -0.864188f, -0.442863f}, + {-0.500000f, -0.809017f, -0.309017f}, + {-0.262866f, -0.951056f, -0.162460f}, + {-0.850651f, -0.525731f, 0.000000f}, + {-0.716567f, -0.681718f, -0.147621f}, + {-0.716567f, -0.681718f, 0.147621f}, + {-0.525731f, -0.850651f, 0.000000f}, + {-0.500000f, -0.809017f, 0.309017f}, + {-0.238856f, -0.864188f, 0.442863f}, + {-0.262866f, -0.951056f, 0.162460f}, + {-0.864188f, -0.442863f, 0.238856f}, + {-0.809017f, -0.309017f, 0.500000f}, + {-0.688191f, -0.587785f, 0.425325f}, + {-0.681718f, -0.147621f, 0.716567f}, + {-0.442863f, -0.238856f, 0.864188f}, + {-0.587785f, -0.425325f, 0.688191f}, + {-0.309017f, -0.500000f, 0.809017f}, + {-0.147621f, -0.716567f, 0.681718f}, + {-0.425325f, -0.688191f, 0.587785f}, + {-0.162460f, -0.262866f, 0.951056f}, + {0.442863f, -0.238856f, 0.864188f}, + {0.162460f, -0.262866f, 0.951056f}, + {0.309017f, -0.500000f, 0.809017f}, + {0.147621f, -0.716567f, 0.681718f}, + {0.000000f, -0.525731f, 0.850651f}, + {0.425325f, -0.688191f, 0.587785f}, + {0.587785f, -0.425325f, 0.688191f}, + {0.688191f, -0.587785f, 0.425325f}, + {-0.955423f, 0.295242f, 0.000000f}, + {-0.951056f, 0.162460f, 0.262866f}, + {-1.000000f, 0.000000f, 0.000000f}, + {-0.850651f, 0.000000f, 0.525731f}, + {-0.955423f, -0.295242f, 0.000000f}, + {-0.951056f, -0.162460f, 0.262866f}, + {-0.864188f, 0.442863f, -0.238856f}, + {-0.951056f, 0.162460f, -0.262866f}, + {-0.809017f, 0.309017f, -0.500000f}, + {-0.864188f, -0.442863f, -0.238856f}, + {-0.951056f, -0.162460f, -0.262866f}, + {-0.809017f, -0.309017f, -0.500000f}, + {-0.681718f, 0.147621f, -0.716567f}, + {-0.681718f, -0.147621f, -0.716567f}, + {-0.850651f, 0.000000f, -0.525731f}, + {-0.688191f, 0.587785f, -0.425325f}, + {-0.587785f, 0.425325f, -0.688191f}, + {-0.425325f, 0.688191f, -0.587785f}, + {-0.425325f, -0.688191f, -0.587785f}, + {-0.587785f, -0.425325f, -0.688191f}, + {-0.688191f, -0.587785f, -0.425325f}, +}; + +#endif diff --git a/libs/picomodel/pm_lwo.c b/libs/picomodel/pm_lwo.c new file mode 100644 index 00000000..ba83ceb5 --- /dev/null +++ b/libs/picomodel/pm_lwo.c @@ -0,0 +1,430 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +/* marker */ +#define PM_LWO_C + +/* dependencies */ +#include "picointernal.h" +#include "lwo/lwo2.h" + +/* uncomment when debugging this module */ +/*#define DEBUG_PM_LWO*/ + +#ifdef DEBUG_PM_LWO +#include "time.h" +#endif + +/* helper functions */ +static const char *lwo_lwIDToStr( unsigned int lwID ) +{ + static char lwIDStr[5]; + + if (!lwID) + { + return "n/a"; + } + + lwIDStr[ 0 ] = (char)((lwID) >> 24); + lwIDStr[ 1 ] = (char)((lwID) >> 16); + lwIDStr[ 2 ] = (char)((lwID) >> 8); + lwIDStr[ 3 ] = (char)((lwID)); + lwIDStr[ 4 ] = '\0'; + + return lwIDStr; +} + +/* +_lwo_canload() +validates a LightWave Object model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ +static int _lwo_canload( PM_PARAMS_CANLOAD ) +{ + picoMemStream_t *s; + unsigned int failID = 0; + int failpos = -1; + int ret; + + /* create a new pico memorystream */ + s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); + if (s == NULL) + { + return PICO_PMV_ERROR_MEMORY; + } + + ret = lwValidateObject( fileName, s, &failID, &failpos ); + + _pico_free_memstream( s ); + + return ret; +} + +/* +_lwo_load() +loads a LightWave Object model file. +*/ +static picoModel_t *_lwo_load( PM_PARAMS_LOAD ) +{ + picoMemStream_t *s; + unsigned int failID = 0; + int failpos = -1; + lwObject *obj; + lwSurface *surface; + lwLayer *layer; + lwPoint *pt; + lwPolygon *pol; + lwPolVert *v; + lwVMapPt *vm; + char name[ 64 ]; + int i, j, k, numverts; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + int defaultSTAxis[ 2 ]; + picoVec2_t defaultXYZtoSTScale; + + picoVertexCombinationHash_t **hashTable; + picoVertexCombinationHash_t *vertexCombinationHash; + +#ifdef DEBUG_PM_LWO + clock_t load_start, load_finish, convert_start, convert_finish; + double load_elapsed, convert_elapsed; + + load_start = clock(); +#endif + + /* do frame check */ + if( frameNum < 0 || frameNum >= 1 ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range LWO frame specified" ); + return NULL; + } + + /* create a new pico memorystream */ + s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); + if (s == NULL) + { + return NULL; + } + + obj = lwGetObject( fileName, s, &failID, &failpos ); + + _pico_free_memstream( s ); + + if( !obj ) { + _pico_printf( PICO_ERROR, "Couldn't load LWO file, failed on ID '%s', position %d", lwo_lwIDToStr( failID ), failpos ); + return NULL; + } + +#ifdef DEBUG_PM_LWO + convert_start = load_finish = clock(); + load_elapsed = (double)(load_finish - load_start) / CLOCKS_PER_SEC; +#endif + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create a new pico model */ + picoModel = PicoNewModel(); + if (picoModel == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, 1 ); + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* create all polygons from layer[ 0 ] that belong to this surface */ + layer = &obj->layer[0]; + + /* warn the user that other layers are discarded */ + if (obj->nlayers > 1) + { + _pico_printf( PICO_WARNING, "LWO loader discards any geometry data not in Layer 1 (%d layers found)", obj->nlayers ); + } + + /* initialize dummy normal */ + normal[ 0 ] = normal[ 1 ] = normal[ 2 ] = 0.f; + + /* setup default st map */ + st[ 0 ] = st[ 1 ] = 0.f; /* st[0] holds max, st[1] holds max par one */ + defaultSTAxis[ 0 ] = 0; + defaultSTAxis[ 1 ] = 1; + for( i = 0; i < 3; i++ ) + { + float min = layer->bbox[ i ]; + float max = layer->bbox[ i + 3 ]; + float size = max - min; + + if (size > st[ 0 ]) + { + defaultSTAxis[ 1 ] = defaultSTAxis[ 0 ]; + defaultSTAxis[ 0 ] = i; + + st[ 1 ] = st[ 0 ]; + st[ 0 ] = size; + } + else if (size > st[ 1 ]) + { + defaultSTAxis[ 1 ] = i; + st[ 1 ] = size; + } + } + defaultXYZtoSTScale[ 0 ] = 4.f / st[ 0 ]; + defaultXYZtoSTScale[ 1 ] = 4.f / st[ 1 ]; + + /* LWO surfaces become pico surfaces */ + surface = obj->surf; + while (surface) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if (picoSurface == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* LWO model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader */ + picoShader = PicoNewShader( picoModel ); + if (picoShader == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* detox and set shader name */ + strncpy( name, surface->name, sizeof(name) ); + _pico_setfext( name, "" ); + _pico_unixify( name ); + PicoSetShaderName( picoShader, name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indices and vertex data */ + numverts = 0; + + hashTable = PicoNewVertexCombinationHashTable(); + + if (hashTable == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate hash table" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + for( i = 0, pol = layer->polygon.pol; i < layer->polygon.count; i++, pol++ ) + { + /* does this polygon belong to this surface? */ + if (pol->surf != surface) + continue; + + /* we only support polygons of the FACE type */ + if (pol->type != ID_FACE) + { + _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it's type != FACE (%s)", lwo_lwIDToStr( pol->type ) ); + continue; + } + + /* NOTE: LWO has support for non-convex polygons, do we want to store them as well? */ + if (pol->nverts != 3) + { + _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it has != 3 verts (%d)", pol->nverts ); + continue; + } + + for( j = 0, v = pol->v; j < 3; j++, v++ ) + { + pt = &layer->point.pt[ v->index ]; + + /* setup data */ + xyz[ 0 ] = pt->pos[ 0 ]; + xyz[ 1 ] = pt->pos[ 2 ]; + xyz[ 2 ] = pt->pos[ 1 ]; + + normal[ 0 ] = v->norm[ 0 ]; + normal[ 1 ] = v->norm[ 2 ]; + normal[ 2 ] = v->norm[ 1 ]; + + st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ]; + st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ]; + + color[ 0 ] = (picoByte_t)(surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = 0xFF; + + /* set from points */ + for( k = 0, vm = pt->vm; k < pt->nvmaps; k++, vm++ ) + { + if (vm->vmap->type == LWID_('T','X','U','V')) + { + /* set st coords */ + st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; + st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; + } + else if (vm->vmap->type == LWID_('R','G','B','A')) + { + /* set rgba */ + color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); + } + } + + /* override with polygon data */ + for( k = 0, vm = v->vm; k < v->nvmaps; k++, vm++ ) + { + if (vm->vmap->type == LWID_('T','X','U','V')) + { + /* set st coords */ + st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; + st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; + } + else if (vm->vmap->type == LWID_('R','G','B','A')) + { + /* set rgba */ + color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); + } + } + + /* find vertex in this surface and if we can't find it there create it */ + vertexCombinationHash = PicoFindVertexCombinationInHashTable( hashTable, xyz, normal, st, color ); + + if (vertexCombinationHash) + { + /* found an existing one */ + PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), vertexCombinationHash->index ); + } + else + { + /* it is a new one */ + vertexCombinationHash = PicoAddVertexCombinationToHashTable( hashTable, xyz, normal, st, color, (picoIndex_t) numverts ); + + if (vertexCombinationHash == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate hash bucket entry table" ); + PicoFreeVertexCombinationHashTable( hashTable ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* add the vertex to this surface */ + PicoSetSurfaceXYZ( picoSurface, numverts, xyz ); + + /* set dummy normal */ + PicoSetSurfaceNormal( picoSurface, numverts, normal ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, numverts, color ); + + /* set st coords */ + PicoSetSurfaceST( picoSurface, 0, numverts, st ); + + /* set index */ + PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), (picoIndex_t) numverts ); + + numverts++; + } + } + } + + /* free the hashtable */ + PicoFreeVertexCombinationHashTable( hashTable ); + + /* get next surface */ + surface = surface->next; + } + +#ifdef DEBUG_PM_LWO + load_start = convert_finish = clock(); +#endif + + lwFreeObject( obj ); + +#ifdef DEBUG_PM_LWO + load_finish = clock(); + load_elapsed += (double)(load_finish - load_start) / CLOCKS_PER_SEC; + convert_elapsed = (double)(convert_finish - convert_start) / CLOCKS_PER_SEC; + _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s) (loading: %-.2fs converting: %-.2fs)\n", load_elapsed + convert_elapsed, load_elapsed, convert_elapsed ); +#endif + + /* return the new pico model */ + return picoModel; +} + +/* pico file format module definition */ +const picoModule_t picoModuleLWO = +{ + "1.0", /* module version string */ + "LightWave Object", /* module display name */ + "Arnout van Meer", /* author's name */ + "2003 Arnout van Meer, 2000 Ernie Wright", /* module copyright */ + { + "lwo", NULL, NULL, NULL /* default extensions to use */ + }, + _lwo_canload, /* validation routine */ + _lwo_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_md2.c b/libs/picomodel/pm_md2.c new file mode 100644 index 00000000..2351ea58 --- /dev/null +++ b/libs/picomodel/pm_md2.c @@ -0,0 +1,670 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +/* +Nurail: Used pm_md3.c (Randy Reddig) as a template. +*/ + + +/* marker */ +#define PM_MD2_C + +/* dependencies */ +#include "picointernal.h" + + +/* md2 model format */ +#define MD2_MAGIC "IDP2" +#define MD2_VERSION 8 + +#define MD2_NUMVERTEXNORMALS 162 +#define MD2_MAX_SKINNAME 64 +#define MD2_MAX_TRIANGLES 4096 +#define MD2_MAX_VERTS 2048 +#define MD2_MAX_FRAMES 512 +#define MD2_MAX_MD2SKINS 32 +#define MD2_MAX_SKINNAME 64 + +#ifndef byte + #define byte unsigned char +#endif + +typedef struct index_LUT_s +{ + short Vert; + short ST; + struct index_LUT_s *next; + +} index_LUT_t; + +typedef struct index_DUP_LUT_s +{ + short ST; + short OldVert; + +} index_DUP_LUT_t; + +typedef struct +{ + short s; + short t; +} md2St_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} md2Triangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} md2XyzNormal_t; + +typedef struct md2Frame_s +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + md2XyzNormal_t verts[1]; // variable sized +} +md2Frame_t; + + +/* md2 model file md2 structure */ +typedef struct md2_s +{ + char magic[ 4 ]; + int version; + + int skinWidth; + int skinHeight; + int frameSize; + + int numSkins; + int numXYZ; + int numST; + int numTris; + int numGLCmds; + int numFrames; + + int ofsSkins; + int ofsST; + int ofsTris; + int ofsFrames; + int ofsGLCmds; + int ofsEnd; +} +md2_t; + +float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] = +{ + { -0.525731f, 0.000000f, 0.850651f }, + { -0.442863f, 0.238856f, 0.864188f }, + { -0.295242f, 0.000000f, 0.955423f }, + { -0.309017f, 0.500000f, 0.809017f }, + { -0.162460f, 0.262866f, 0.951056f }, + { 0.000000f, 0.000000f, 1.000000f }, + { 0.000000f, 0.850651f, 0.525731f }, + { -0.147621f, 0.716567f, 0.681718f }, + { 0.147621f, 0.716567f, 0.681718f }, + { 0.000000f, 0.525731f, 0.850651f }, + { 0.309017f, 0.500000f, 0.809017f }, + { 0.525731f, 0.000000f, 0.850651f }, + { 0.295242f, 0.000000f, 0.955423f }, + { 0.442863f, 0.238856f, 0.864188f }, + { 0.162460f, 0.262866f, 0.951056f }, + { -0.681718f, 0.147621f, 0.716567f }, + { -0.809017f, 0.309017f, 0.500000f }, + { -0.587785f, 0.425325f, 0.688191f }, + { -0.850651f, 0.525731f, 0.000000f }, + { -0.864188f, 0.442863f, 0.238856f }, + { -0.716567f, 0.681718f, 0.147621f }, + { -0.688191f, 0.587785f, 0.425325f }, + { -0.500000f, 0.809017f, 0.309017f }, + { -0.238856f, 0.864188f, 0.442863f }, + { -0.425325f, 0.688191f, 0.587785f }, + { -0.716567f, 0.681718f, -0.147621f }, + { -0.500000f, 0.809017f, -0.309017f }, + { -0.525731f, 0.850651f, 0.000000f }, + { 0.000000f, 0.850651f, -0.525731f }, + { -0.238856f, 0.864188f, -0.442863f }, + { 0.000000f, 0.955423f, -0.295242f }, + { -0.262866f, 0.951056f, -0.162460f }, + { 0.000000f, 1.000000f, 0.000000f }, + { 0.000000f, 0.955423f, 0.295242f }, + { -0.262866f, 0.951056f, 0.162460f }, + { 0.238856f, 0.864188f, 0.442863f }, + { 0.262866f, 0.951056f, 0.162460f }, + { 0.500000f, 0.809017f, 0.309017f }, + { 0.238856f, 0.864188f, -0.442863f }, + { 0.262866f, 0.951056f, -0.162460f }, + { 0.500000f, 0.809017f, -0.309017f }, + { 0.850651f, 0.525731f, 0.000000f }, + { 0.716567f, 0.681718f, 0.147621f }, + { 0.716567f, 0.681718f, -0.147621f }, + { 0.525731f, 0.850651f, 0.000000f }, + { 0.425325f, 0.688191f, 0.587785f }, + { 0.864188f, 0.442863f, 0.238856f }, + { 0.688191f, 0.587785f, 0.425325f }, + { 0.809017f, 0.309017f, 0.500000f }, + { 0.681718f, 0.147621f, 0.716567f }, + { 0.587785f, 0.425325f, 0.688191f }, + { 0.955423f, 0.295242f, 0.000000f }, + { 1.000000f, 0.000000f, 0.000000f }, + { 0.951056f, 0.162460f, 0.262866f }, + { 0.850651f, -0.525731f, 0.000000f }, + { 0.955423f, -0.295242f, 0.000000f }, + { 0.864188f, -0.442863f, 0.238856f }, + { 0.951056f, -0.162460f, 0.262866f }, + { 0.809017f, -0.309017f, 0.500000f }, + { 0.681718f, -0.147621f, 0.716567f }, + { 0.850651f, 0.000000f, 0.525731f }, + { 0.864188f, 0.442863f, -0.238856f }, + { 0.809017f, 0.309017f, -0.500000f }, + { 0.951056f, 0.162460f, -0.262866f }, + { 0.525731f, 0.000000f, -0.850651f }, + { 0.681718f, 0.147621f, -0.716567f }, + { 0.681718f, -0.147621f, -0.716567f }, + { 0.850651f, 0.000000f, -0.525731f }, + { 0.809017f, -0.309017f, -0.500000f }, + { 0.864188f, -0.442863f, -0.238856f }, + { 0.951056f, -0.162460f, -0.262866f }, + { 0.147621f, 0.716567f, -0.681718f }, + { 0.309017f, 0.500000f, -0.809017f }, + { 0.425325f, 0.688191f, -0.587785f }, + { 0.442863f, 0.238856f, -0.864188f }, + { 0.587785f, 0.425325f, -0.688191f }, + { 0.688191f, 0.587785f, -0.425325f }, + { -0.147621f, 0.716567f, -0.681718f }, + { -0.309017f, 0.500000f, -0.809017f }, + { 0.000000f, 0.525731f, -0.850651f }, + { -0.525731f, 0.000000f, -0.850651f }, + { -0.442863f, 0.238856f, -0.864188f }, + { -0.295242f, 0.000000f, -0.955423f }, + { -0.162460f, 0.262866f, -0.951056f }, + { 0.000000f, 0.000000f, -1.000000f }, + { 0.295242f, 0.000000f, -0.955423f }, + { 0.162460f, 0.262866f, -0.951056f }, + { -0.442863f, -0.238856f, -0.864188f }, + { -0.309017f, -0.500000f, -0.809017f }, + { -0.162460f, -0.262866f, -0.951056f }, + { 0.000000f, -0.850651f, -0.525731f }, + { -0.147621f, -0.716567f, -0.681718f }, + { 0.147621f, -0.716567f, -0.681718f }, + { 0.000000f, -0.525731f, -0.850651f }, + { 0.309017f, -0.500000f, -0.809017f }, + { 0.442863f, -0.238856f, -0.864188f }, + { 0.162460f, -0.262866f, -0.951056f }, + { 0.238856f, -0.864188f, -0.442863f }, + { 0.500000f, -0.809017f, -0.309017f }, + { 0.425325f, -0.688191f, -0.587785f }, + { 0.716567f, -0.681718f, -0.147621f }, + { 0.688191f, -0.587785f, -0.425325f }, + { 0.587785f, -0.425325f, -0.688191f }, + { 0.000000f, -0.955423f, -0.295242f }, + { 0.000000f, -1.000000f, 0.000000f }, + { 0.262866f, -0.951056f, -0.162460f }, + { 0.000000f, -0.850651f, 0.525731f }, + { 0.000000f, -0.955423f, 0.295242f }, + { 0.238856f, -0.864188f, 0.442863f }, + { 0.262866f, -0.951056f, 0.162460f }, + { 0.500000f, -0.809017f, 0.309017f }, + { 0.716567f, -0.681718f, 0.147621f }, + { 0.525731f, -0.850651f, 0.000000f }, + { -0.238856f, -0.864188f, -0.442863f }, + { -0.500000f, -0.809017f, -0.309017f }, + { -0.262866f, -0.951056f, -0.162460f }, + { -0.850651f, -0.525731f, 0.000000f }, + { -0.716567f, -0.681718f, -0.147621f }, + { -0.716567f, -0.681718f, 0.147621f }, + { -0.525731f, -0.850651f, 0.000000f }, + { -0.500000f, -0.809017f, 0.309017f }, + { -0.238856f, -0.864188f, 0.442863f }, + { -0.262866f, -0.951056f, 0.162460f }, + { -0.864188f, -0.442863f, 0.238856f }, + { -0.809017f, -0.309017f, 0.500000f }, + { -0.688191f, -0.587785f, 0.425325f }, + { -0.681718f, -0.147621f, 0.716567f }, + { -0.442863f, -0.238856f, 0.864188f }, + { -0.587785f, -0.425325f, 0.688191f }, + { -0.309017f, -0.500000f, 0.809017f }, + { -0.147621f, -0.716567f, 0.681718f }, + { -0.425325f, -0.688191f, 0.587785f }, + { -0.162460f, -0.262866f, 0.951056f }, + { 0.442863f, -0.238856f, 0.864188f }, + { 0.162460f, -0.262866f, 0.951056f }, + { 0.309017f, -0.500000f, 0.809017f }, + { 0.147621f, -0.716567f, 0.681718f }, + { 0.000000f, -0.525731f, 0.850651f }, + { 0.425325f, -0.688191f, 0.587785f }, + { 0.587785f, -0.425325f, 0.688191f }, + { 0.688191f, -0.587785f, 0.425325f }, + { -0.955423f, 0.295242f, 0.000000f }, + { -0.951056f, 0.162460f, 0.262866f }, + { -1.000000f, 0.000000f, 0.000000f }, + { -0.850651f, 0.000000f, 0.525731f }, + { -0.955423f, -0.295242f, 0.000000f }, + { -0.951056f, -0.162460f, 0.262866f }, + { -0.864188f, 0.442863f, -0.238856f }, + { -0.951056f, 0.162460f, -0.262866f }, + { -0.809017f, 0.309017f, -0.500000f }, + { -0.864188f, -0.442863f, -0.238856f }, + { -0.951056f, -0.162460f, -0.262866f }, + { -0.809017f, -0.309017f, -0.500000f }, + { -0.681718f, 0.147621f, -0.716567f }, + { -0.681718f, -0.147621f, -0.716567f }, + { -0.850651f, 0.000000f, -0.525731f }, + { -0.688191f, 0.587785f, -0.425325f }, + { -0.587785f, 0.425325f, -0.688191f }, + { -0.425325f, 0.688191f, -0.587785f }, + { -0.425325f, -0.688191f, -0.587785f }, + { -0.587785f, -0.425325f, -0.688191f }, + { -0.688191f, -0.587785f, -0.425325f }, +}; + + +// _md2_canload() + +static int _md2_canload( PM_PARAMS_CANLOAD ) +{ + md2_t *md2; + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *md2 ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as md2 */ + md2 = (md2_t*) buffer; + + /* check md2 magic */ + if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check md2 version */ + if( _pico_little_long( md2->version ) != MD2_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid md2 */ + return PICO_PMV_OK; +} + + + +// _md2_load() loads a quake2 md2 model file. + + +static picoModel_t *_md2_load( PM_PARAMS_LOAD ) +{ + int i, j, dups, dup_index; + short tot_numVerts; + index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; + index_DUP_LUT_t *p_index_LUT_DUPS; + md2Triangle_t *p_md2Triangle; + + char skinname[ MD2_MAX_SKINNAME ]; + md2_t *md2; + md2St_t *texCoord; + md2Frame_t *frame; + md2Triangle_t *triangle; + md2XyzNormal_t *vertex; + + picoByte_t *bb; + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + // md2 loading + _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); + + /* set as md2 */ + bb = (picoByte_t*) buffer; + md2 = (md2_t*) buffer; + + /* check ident and version */ + if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION ) + { + /* not an md2 file (todo: set error) */ + _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName ); + return NULL; + } + + // swap md2 + md2->version = _pico_little_long( md2->version ); + + md2->skinWidth = _pico_little_long( md2->skinWidth ); + md2->skinHeight = _pico_little_long( md2->skinHeight ); + md2->frameSize = _pico_little_long( md2->frameSize ); + + md2->numSkins = _pico_little_long( md2->numSkins ); + md2->numXYZ = _pico_little_long( md2->numXYZ ); + md2->numST = _pico_little_long( md2->numST ); + md2->numTris = _pico_little_long( md2->numTris ); + md2->numGLCmds = _pico_little_long( md2->numGLCmds ); + md2->numFrames = _pico_little_long( md2->numFrames ); + + md2->ofsSkins = _pico_little_long( md2->ofsSkins ); + md2->ofsST = _pico_little_long( md2->ofsST ); + md2->ofsTris = _pico_little_long( md2->ofsTris ); + md2->ofsFrames = _pico_little_long( md2->ofsFrames ); + md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds ); + md2->ofsEnd = _pico_little_long( md2->ofsEnd ); + + // do frame check + if( md2->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); + return NULL; + } + + if( frameNum < 0 || frameNum >= md2->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" ); + return NULL; + } + + // Setup Frame + frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum)); + + // swap frame scale and translation + for( i = 0; i < 3; i++ ) + { + frame->scale[ i ] = _pico_little_float( frame->scale[ i ] ); + frame->translate[ i ] = _pico_little_float( frame->translate[ i ] ); + } + + // swap triangles + triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); + for( i = 0; i < md2->numTris; i++, triangle++ ) + { + for( j = 0; j < 3; j++ ) + { + triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); + triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); + } + } + + // swap st coords + texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); + for( i = 0; i < md2->numST; i++, texCoord++ ) + { + texCoord->s = _pico_little_short( texCoord->s ); + texCoord->t = _pico_little_short( texCoord->t ); + } + + // set Skin Name + strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME ); + + // Print out md2 values + _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); + + // detox Skin name + _pico_setfext( skinname, "" ); + _pico_unixify( skinname ); + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + // allocate new pico surface + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + return NULL; + } + + + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( picoSurface, frame->name ); + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + PicoSetShaderName( picoShader, skinname ); + + // associate current surface with newly created shader + PicoSetSurfaceShader( picoSurface, picoShader ); + + // Init LUT for Verts + p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ); + for(i=0; inumXYZ; i++) + { + p_index_LUT[i].Vert = -1; + p_index_LUT[i].ST = -1; + p_index_LUT[i].next = NULL; + } + + // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. + tot_numVerts = md2->numXYZ; + dups = 0; + for(i=0; inumTris; i++) + { + p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i)); + for(j=0; j<3; j++) + { + if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry + p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j]; + + else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry + continue; + + else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry + { // Add first entry of LL from Main + p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT2 == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; + p_index_LUT2->Vert = dups; + p_index_LUT2->ST = p_md2Triangle->index_st[j]; + p_index_LUT2->next = NULL; + p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk + dups++; + } + else // Try to find in LL from Main Entry + { + p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next; + while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL + { + p_index_LUT3 = p_index_LUT2; + p_index_LUT2 = p_index_LUT2->next; + } + p_index_LUT2 = p_index_LUT3; + + if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it + { + p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk + continue; + } + + if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. + { + // Add the Entry + p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT3 == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; + p_index_LUT3->Vert = p_md2Triangle->index_xyz[j]; + p_index_LUT3->ST = p_md2Triangle->index_st[j]; + p_index_LUT3->next = NULL; + p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk + dups++; + } + } + } + } + + // malloc and build array for Dup STs + p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); + if (p_index_LUT_DUPS == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + + dup_index = 0; + for(i=0; inumXYZ; i++) + { + p_index_LUT2 = p_index_LUT[i].next; + while (p_index_LUT2 != NULL) + { + p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; + p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; + dup_index++; + p_index_LUT2 = p_index_LUT2->next; + } + } + + // Build Picomodel + triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); + texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); + vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) ); + for( j = 0; j < md2->numTris; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); + PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); + PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); + } + + for(i=0; i< md2->numXYZ; i++, vertex++) + { + /* set vertex origin */ + xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0]; + xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1]; + xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2]; + PicoSetSurfaceXYZ( picoSurface, i , xyz ); + + /* set normal */ + normal[ 0 ] = md2_normals[vertex->lightnormalindex][0]; + normal[ 1 ] = md2_normals[vertex->lightnormalindex][1]; + normal[ 2 ] = md2_normals[vertex->lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i , st ); + } + + if (dups) + { + for(i=0; iverts[j].v[0] * frame->scale[0] + frame->translate[0]; + xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1]; + xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2]; + PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz ); + + /* set normal */ + normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0]; + normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1]; + normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st ); + } + } + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, 0, color ); + + // Free up malloc'ed LL entries + for(i=0; inumXYZ; i++) + { + if(p_index_LUT[i].next != NULL) + { + p_index_LUT2 = p_index_LUT[i].next; + do { + p_index_LUT3 = p_index_LUT2->next; + _pico_free(p_index_LUT2); + p_index_LUT2 = p_index_LUT3; + dups--; + } while (p_index_LUT2 != NULL); + } + } + + if (dups) + _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); + + // Free malloc'ed LUTs + _pico_free(p_index_LUT); + _pico_free(p_index_LUT_DUPS); + + /* return the new pico model */ + return picoModel; + +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMD2 = +{ + "0.875", /* module version string */ + "Quake 2 MD2", /* module display name */ + "Nurail", /* author's name */ + "2003 Nurail", /* module copyright */ + { + "md2", NULL, NULL, NULL /* default extensions to use */ + }, + _md2_canload, /* validation routine */ + _md2_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_md3.c b/libs/picomodel/pm_md3.c new file mode 100644 index 00000000..6d87469d --- /dev/null +++ b/libs/picomodel/pm_md3.c @@ -0,0 +1,425 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MD3_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* md3 model format */ +#define MD3_MAGIC "IDP3" +#define MD3_VERSION 15 + +/* md3 vertex scale */ +#define MD3_SCALE (1.0f / 64.0f) + +/* md3 model frame information */ +typedef struct md3Frame_s +{ + float bounds[ 2 ][ 3 ]; + float localOrigin[ 3 ]; + float radius; + char creator[ 16 ]; +} +md3Frame_t; + +/* md3 model tag information */ +typedef struct md3Tag_s +{ + char name[ 64 ]; + float origin[ 3 ]; + float axis[ 3 ][ 3 ]; +} +md3Tag_t; + +/* md3 surface md3 (one object mesh) */ +typedef struct md3Surface_s +{ + char magic[ 4 ]; + char name[ 64 ]; /* polyset name */ + int flags; + int numFrames; /* all model surfaces should have the same */ + int numShaders; /* all model surfaces should have the same */ + int numVerts; + int numTriangles; + int ofsTriangles; + int ofsShaders; /* offset from start of md3Surface_t */ + int ofsSt; /* texture coords are common for all frames */ + int ofsVertexes; /* numVerts * numFrames */ + int ofsEnd; /* next surface follows */ +} +md3Surface_t; + +typedef struct md3Shader_s +{ + char name[ 64 ]; + int shaderIndex; /* for ingame use */ +} +md3Shader_t; + +typedef struct md3Triangle_s +{ + int indexes[ 3 ]; +} +md3Triangle_t; + +typedef struct md3TexCoord_s +{ + float st[ 2 ]; +} +md3TexCoord_t; + +typedef struct md3Vertex_s +{ + short xyz[ 3 ]; + short normal; +} +md3Vertex_t; + + +/* md3 model file md3 structure */ +typedef struct md3_s +{ + char magic[ 4 ]; /* MD3_MAGIC */ + int version; + char name[ 64 ]; /* model name */ + int flags; + int numFrames; + int numTags; + int numSurfaces; + int numSkins; /* number of skins for the mesh */ + int ofsFrames; /* offset for first frame */ + int ofsTags; /* numFrames * numTags */ + int ofsSurfaces; /* first surface, others follow */ + int ofsEnd; /* end of file */ +} +md3_t; + + + + +/* +_md3_canload() +validates a quake3 arena md3 model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ + +static int _md3_canload( PM_PARAMS_CANLOAD ) +{ + md3_t *md3; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *md3 ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as md3 */ + md3 = (md3_t*) buffer; + + /* check md3 magic */ + if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check md3 version */ + if( _pico_little_long( md3->version ) != MD3_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid md3 */ + return PICO_PMV_OK; +} + + + +/* +_md3_load() +loads a quake3 arena md3 model file. +*/ + +static picoModel_t *_md3_load( PM_PARAMS_LOAD ) +{ + int i, j; + picoByte_t *bb; + md3_t *md3; + md3Surface_t *surface; + md3Shader_t *shader; + md3TexCoord_t *texCoord; + md3Frame_t *frame; + md3Triangle_t *triangle; + md3Vertex_t *vertex; + double lat, lng; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + /* ------------------------------------------------- + md3 loading + ------------------------------------------------- */ + + + /* set as md3 */ + bb = (picoByte_t*) buffer; + md3 = (md3_t*) buffer; + + /* check ident and version */ + if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION ) + { + /* not an md3 file (todo: set error) */ + return NULL; + } + + /* swap md3; sea: swaps fixed */ + md3->version = _pico_little_long( md3->version ); + md3->numFrames = _pico_little_long( md3->numFrames ); + md3->numTags = _pico_little_long( md3->numTags ); + md3->numSurfaces = _pico_little_long( md3->numSurfaces ); + md3->numSkins = _pico_little_long( md3->numSkins ); + md3->ofsFrames = _pico_little_long( md3->ofsFrames ); + md3->ofsTags = _pico_little_long( md3->ofsTags ); + md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces ); + md3->ofsEnd = _pico_little_long( md3->ofsEnd ); + + /* do frame check */ + if( md3->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "MD3 with 0 frames" ); + return NULL; + } + + if( frameNum < 0 || frameNum >= md3->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" ); + return NULL; + } + + /* swap frames */ + frame = (md3Frame_t*) (bb + md3->ofsFrames ); + for( i = 0; i < md3->numFrames; i++, frame++ ) + { + frame->radius = _pico_little_float( frame->radius ); + for( j = 0; j < 3; j++ ) + { + frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); + frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); + frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); + } + } + + /* swap surfaces */ + surface = (md3Surface_t*) (bb + md3->ofsSurfaces); + for( i = 0; i < md3->numSurfaces; i++ ) + { + /* swap surface md3; sea: swaps fixed */ + surface->flags = _pico_little_long( surface->flags ); + surface->numFrames = _pico_little_long( surface->numFrames ); + surface->numShaders = _pico_little_long( surface->numShaders ); + surface->numTriangles = _pico_little_long( surface->numTriangles ); + surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); + surface->numVerts = _pico_little_long( surface->numVerts ); + surface->ofsShaders = _pico_little_long( surface->ofsShaders ); + surface->ofsSt = _pico_little_long( surface->ofsSt ); + surface->ofsVertexes = _pico_little_long( surface->ofsVertexes ); + surface->ofsEnd = _pico_little_long( surface->ofsEnd ); + + /* swap triangles */ + triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + /* sea: swaps fixed */ + triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); + triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); + triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); + } + + /* swap st coords */ + texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); + for( j = 0; j < surface->numVerts; j++, texCoord++ ) + { + texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); + texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); + } + + /* swap xyz/normals */ + vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes); + for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++) + { + vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); + vertex->normal = _pico_little_short( vertex->normal ); + } + + /* get next surface */ + surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* md3 surfaces become picomodel surfaces */ + surface = (md3Surface_t*) (bb + md3->ofsSurfaces); + + /* run through md3 surfaces */ + for( i = 0; i < md3->numSurfaces; i++ ) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); /* sea */ + return NULL; + } + + /* md3 model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader -sea */ + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + /* detox and set shader name */ + shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders); + _pico_setfext( shader->name, "" ); + _pico_unixify( shader->name ); + PicoSetShaderName( picoShader, shader->name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indexes */ + triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); + + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); + } + + /* copy vertexes */ + texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); + vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) ); + _pico_set_color( color, 255, 255, 255, 255 ); + + for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ ) + { + /* set vertex origin */ + xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ]; + xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ]; + xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ]; + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + /* decode lat/lng normal to 3 float normal */ + lat = (float) ((vertex->normal >> 8) & 0xff); + lng = (float) (vertex->normal & 0xff); + lat *= PICO_PI / 128; + lng *= PICO_PI / 128; + normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); + normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); + normal[ 2 ] = (picoVec_t) cos( lng ); + PicoSetSurfaceNormal( picoSurface, j, normal ); + + /* set st coords */ + st[ 0 ] = texCoord->st[ 0 ]; + st[ 1 ] = texCoord->st[ 1 ]; + PicoSetSurfaceST( picoSurface, 0, j, st ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, j, color ); + } + + /* get next surface */ + surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* return the new pico model */ + return picoModel; +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMD3 = +{ + "1.3", /* module version string */ + "Quake 3 Arena", /* module display name */ + "Randy Reddig", /* author's name */ + "2002 Randy Reddig", /* module copyright */ + { + "md3", NULL, NULL, NULL /* default extensions to use */ + }, + _md3_canload, /* validation routine */ + _md3_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_mdc.c b/libs/picomodel/pm_mdc.c new file mode 100644 index 00000000..3036d112 --- /dev/null +++ b/libs/picomodel/pm_mdc.c @@ -0,0 +1,750 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MDC_C + + + +/* dependencies */ +#include "picointernal.h" + +/* mdc model format */ +#define MDC_MAGIC "IDPC" +#define MDC_VERSION 2 + +/* mdc vertex scale */ +#define MDC_SCALE (1.0f / 64.0f) +#define MDC_MAX_OFS 127.0f +#define MDC_DIST_SCALE 0.05f + +/* mdc decoding normal table */ +double mdcNormals[ 256 ][ 3 ] = +{ + { 1.000000, 0.000000, 0.000000 }, + { 0.980785, 0.195090, 0.000000 }, + { 0.923880, 0.382683, 0.000000 }, + { 0.831470, 0.555570, 0.000000 }, + { 0.707107, 0.707107, 0.000000 }, + { 0.555570, 0.831470, 0.000000 }, + { 0.382683, 0.923880, 0.000000 }, + { 0.195090, 0.980785, 0.000000 }, + { -0.000000, 1.000000, 0.000000 }, + { -0.195090, 0.980785, 0.000000 }, + { -0.382683, 0.923880, 0.000000 }, + { -0.555570, 0.831470, 0.000000 }, + { -0.707107, 0.707107, 0.000000 }, + { -0.831470, 0.555570, 0.000000 }, + { -0.923880, 0.382683, 0.000000 }, + { -0.980785, 0.195090, 0.000000 }, + { -1.000000, -0.000000, 0.000000 }, + { -0.980785, -0.195090, 0.000000 }, + { -0.923880, -0.382683, 0.000000 }, + { -0.831470, -0.555570, 0.000000 }, + { -0.707107, -0.707107, 0.000000 }, + { -0.555570, -0.831469, 0.000000 }, + { -0.382684, -0.923880, 0.000000 }, + { -0.195090, -0.980785, 0.000000 }, + { 0.000000, -1.000000, 0.000000 }, + { 0.195090, -0.980785, 0.000000 }, + { 0.382684, -0.923879, 0.000000 }, + { 0.555570, -0.831470, 0.000000 }, + { 0.707107, -0.707107, 0.000000 }, + { 0.831470, -0.555570, 0.000000 }, + { 0.923880, -0.382683, 0.000000 }, + { 0.980785, -0.195090, 0.000000 }, + { 0.980785, 0.000000, -0.195090 }, + { 0.956195, 0.218245, -0.195090 }, + { 0.883657, 0.425547, -0.195090 }, + { 0.766809, 0.611510, -0.195090 }, + { 0.611510, 0.766809, -0.195090 }, + { 0.425547, 0.883657, -0.195090 }, + { 0.218245, 0.956195, -0.195090 }, + { -0.000000, 0.980785, -0.195090 }, + { -0.218245, 0.956195, -0.195090 }, + { -0.425547, 0.883657, -0.195090 }, + { -0.611510, 0.766809, -0.195090 }, + { -0.766809, 0.611510, -0.195090 }, + { -0.883657, 0.425547, -0.195090 }, + { -0.956195, 0.218245, -0.195090 }, + { -0.980785, -0.000000, -0.195090 }, + { -0.956195, -0.218245, -0.195090 }, + { -0.883657, -0.425547, -0.195090 }, + { -0.766809, -0.611510, -0.195090 }, + { -0.611510, -0.766809, -0.195090 }, + { -0.425547, -0.883657, -0.195090 }, + { -0.218245, -0.956195, -0.195090 }, + { 0.000000, -0.980785, -0.195090 }, + { 0.218245, -0.956195, -0.195090 }, + { 0.425547, -0.883657, -0.195090 }, + { 0.611510, -0.766809, -0.195090 }, + { 0.766809, -0.611510, -0.195090 }, + { 0.883657, -0.425547, -0.195090 }, + { 0.956195, -0.218245, -0.195090 }, + { 0.923880, 0.000000, -0.382683 }, + { 0.892399, 0.239118, -0.382683 }, + { 0.800103, 0.461940, -0.382683 }, + { 0.653281, 0.653281, -0.382683 }, + { 0.461940, 0.800103, -0.382683 }, + { 0.239118, 0.892399, -0.382683 }, + { -0.000000, 0.923880, -0.382683 }, + { -0.239118, 0.892399, -0.382683 }, + { -0.461940, 0.800103, -0.382683 }, + { -0.653281, 0.653281, -0.382683 }, + { -0.800103, 0.461940, -0.382683 }, + { -0.892399, 0.239118, -0.382683 }, + { -0.923880, -0.000000, -0.382683 }, + { -0.892399, -0.239118, -0.382683 }, + { -0.800103, -0.461940, -0.382683 }, + { -0.653282, -0.653281, -0.382683 }, + { -0.461940, -0.800103, -0.382683 }, + { -0.239118, -0.892399, -0.382683 }, + { 0.000000, -0.923880, -0.382683 }, + { 0.239118, -0.892399, -0.382683 }, + { 0.461940, -0.800103, -0.382683 }, + { 0.653281, -0.653282, -0.382683 }, + { 0.800103, -0.461940, -0.382683 }, + { 0.892399, -0.239117, -0.382683 }, + { 0.831470, 0.000000, -0.555570 }, + { 0.790775, 0.256938, -0.555570 }, + { 0.672673, 0.488726, -0.555570 }, + { 0.488726, 0.672673, -0.555570 }, + { 0.256938, 0.790775, -0.555570 }, + { -0.000000, 0.831470, -0.555570 }, + { -0.256938, 0.790775, -0.555570 }, + { -0.488726, 0.672673, -0.555570 }, + { -0.672673, 0.488726, -0.555570 }, + { -0.790775, 0.256938, -0.555570 }, + { -0.831470, -0.000000, -0.555570 }, + { -0.790775, -0.256938, -0.555570 }, + { -0.672673, -0.488726, -0.555570 }, + { -0.488725, -0.672673, -0.555570 }, + { -0.256938, -0.790775, -0.555570 }, + { 0.000000, -0.831470, -0.555570 }, + { 0.256938, -0.790775, -0.555570 }, + { 0.488725, -0.672673, -0.555570 }, + { 0.672673, -0.488726, -0.555570 }, + { 0.790775, -0.256938, -0.555570 }, + { 0.707107, 0.000000, -0.707107 }, + { 0.653281, 0.270598, -0.707107 }, + { 0.500000, 0.500000, -0.707107 }, + { 0.270598, 0.653281, -0.707107 }, + { -0.000000, 0.707107, -0.707107 }, + { -0.270598, 0.653282, -0.707107 }, + { -0.500000, 0.500000, -0.707107 }, + { -0.653281, 0.270598, -0.707107 }, + { -0.707107, -0.000000, -0.707107 }, + { -0.653281, -0.270598, -0.707107 }, + { -0.500000, -0.500000, -0.707107 }, + { -0.270598, -0.653281, -0.707107 }, + { 0.000000, -0.707107, -0.707107 }, + { 0.270598, -0.653281, -0.707107 }, + { 0.500000, -0.500000, -0.707107 }, + { 0.653282, -0.270598, -0.707107 }, + { 0.555570, 0.000000, -0.831470 }, + { 0.481138, 0.277785, -0.831470 }, + { 0.277785, 0.481138, -0.831470 }, + { -0.000000, 0.555570, -0.831470 }, + { -0.277785, 0.481138, -0.831470 }, + { -0.481138, 0.277785, -0.831470 }, + { -0.555570, -0.000000, -0.831470 }, + { -0.481138, -0.277785, -0.831470 }, + { -0.277785, -0.481138, -0.831470 }, + { 0.000000, -0.555570, -0.831470 }, + { 0.277785, -0.481138, -0.831470 }, + { 0.481138, -0.277785, -0.831470 }, + { 0.382683, 0.000000, -0.923880 }, + { 0.270598, 0.270598, -0.923880 }, + { -0.000000, 0.382683, -0.923880 }, + { -0.270598, 0.270598, -0.923880 }, + { -0.382683, -0.000000, -0.923880 }, + { -0.270598, -0.270598, -0.923880 }, + { 0.000000, -0.382683, -0.923880 }, + { 0.270598, -0.270598, -0.923880 }, + { 0.195090, 0.000000, -0.980785 }, + { -0.000000, 0.195090, -0.980785 }, + { -0.195090, -0.000000, -0.980785 }, + { 0.000000, -0.195090, -0.980785 }, + { 0.980785, 0.000000, 0.195090 }, + { 0.956195, 0.218245, 0.195090 }, + { 0.883657, 0.425547, 0.195090 }, + { 0.766809, 0.611510, 0.195090 }, + { 0.611510, 0.766809, 0.195090 }, + { 0.425547, 0.883657, 0.195090 }, + { 0.218245, 0.956195, 0.195090 }, + { -0.000000, 0.980785, 0.195090 }, + { -0.218245, 0.956195, 0.195090 }, + { -0.425547, 0.883657, 0.195090 }, + { -0.611510, 0.766809, 0.195090 }, + { -0.766809, 0.611510, 0.195090 }, + { -0.883657, 0.425547, 0.195090 }, + { -0.956195, 0.218245, 0.195090 }, + { -0.980785, -0.000000, 0.195090 }, + { -0.956195, -0.218245, 0.195090 }, + { -0.883657, -0.425547, 0.195090 }, + { -0.766809, -0.611510, 0.195090 }, + { -0.611510, -0.766809, 0.195090 }, + { -0.425547, -0.883657, 0.195090 }, + { -0.218245, -0.956195, 0.195090 }, + { 0.000000, -0.980785, 0.195090 }, + { 0.218245, -0.956195, 0.195090 }, + { 0.425547, -0.883657, 0.195090 }, + { 0.611510, -0.766809, 0.195090 }, + { 0.766809, -0.611510, 0.195090 }, + { 0.883657, -0.425547, 0.195090 }, + { 0.956195, -0.218245, 0.195090 }, + { 0.923880, 0.000000, 0.382683 }, + { 0.892399, 0.239118, 0.382683 }, + { 0.800103, 0.461940, 0.382683 }, + { 0.653281, 0.653281, 0.382683 }, + { 0.461940, 0.800103, 0.382683 }, + { 0.239118, 0.892399, 0.382683 }, + { -0.000000, 0.923880, 0.382683 }, + { -0.239118, 0.892399, 0.382683 }, + { -0.461940, 0.800103, 0.382683 }, + { -0.653281, 0.653281, 0.382683 }, + { -0.800103, 0.461940, 0.382683 }, + { -0.892399, 0.239118, 0.382683 }, + { -0.923880, -0.000000, 0.382683 }, + { -0.892399, -0.239118, 0.382683 }, + { -0.800103, -0.461940, 0.382683 }, + { -0.653282, -0.653281, 0.382683 }, + { -0.461940, -0.800103, 0.382683 }, + { -0.239118, -0.892399, 0.382683 }, + { 0.000000, -0.923880, 0.382683 }, + { 0.239118, -0.892399, 0.382683 }, + { 0.461940, -0.800103, 0.382683 }, + { 0.653281, -0.653282, 0.382683 }, + { 0.800103, -0.461940, 0.382683 }, + { 0.892399, -0.239117, 0.382683 }, + { 0.831470, 0.000000, 0.555570 }, + { 0.790775, 0.256938, 0.555570 }, + { 0.672673, 0.488726, 0.555570 }, + { 0.488726, 0.672673, 0.555570 }, + { 0.256938, 0.790775, 0.555570 }, + { -0.000000, 0.831470, 0.555570 }, + { -0.256938, 0.790775, 0.555570 }, + { -0.488726, 0.672673, 0.555570 }, + { -0.672673, 0.488726, 0.555570 }, + { -0.790775, 0.256938, 0.555570 }, + { -0.831470, -0.000000, 0.555570 }, + { -0.790775, -0.256938, 0.555570 }, + { -0.672673, -0.488726, 0.555570 }, + { -0.488725, -0.672673, 0.555570 }, + { -0.256938, -0.790775, 0.555570 }, + { 0.000000, -0.831470, 0.555570 }, + { 0.256938, -0.790775, 0.555570 }, + { 0.488725, -0.672673, 0.555570 }, + { 0.672673, -0.488726, 0.555570 }, + { 0.790775, -0.256938, 0.555570 }, + { 0.707107, 0.000000, 0.707107 }, + { 0.653281, 0.270598, 0.707107 }, + { 0.500000, 0.500000, 0.707107 }, + { 0.270598, 0.653281, 0.707107 }, + { -0.000000, 0.707107, 0.707107 }, + { -0.270598, 0.653282, 0.707107 }, + { -0.500000, 0.500000, 0.707107 }, + { -0.653281, 0.270598, 0.707107 }, + { -0.707107, -0.000000, 0.707107 }, + { -0.653281, -0.270598, 0.707107 }, + { -0.500000, -0.500000, 0.707107 }, + { -0.270598, -0.653281, 0.707107 }, + { 0.000000, -0.707107, 0.707107 }, + { 0.270598, -0.653281, 0.707107 }, + { 0.500000, -0.500000, 0.707107 }, + { 0.653282, -0.270598, 0.707107 }, + { 0.555570, 0.000000, 0.831470 }, + { 0.481138, 0.277785, 0.831470 }, + { 0.277785, 0.481138, 0.831470 }, + { -0.000000, 0.555570, 0.831470 }, + { -0.277785, 0.481138, 0.831470 }, + { -0.481138, 0.277785, 0.831470 }, + { -0.555570, -0.000000, 0.831470 }, + { -0.481138, -0.277785, 0.831470 }, + { -0.277785, -0.481138, 0.831470 }, + { 0.000000, -0.555570, 0.831470 }, + { 0.277785, -0.481138, 0.831470 }, + { 0.481138, -0.277785, 0.831470 }, + { 0.382683, 0.000000, 0.923880 }, + { 0.270598, 0.270598, 0.923880 }, + { -0.000000, 0.382683, 0.923880 }, + { -0.270598, 0.270598, 0.923880 }, + { -0.382683, -0.000000, 0.923880 }, + { -0.270598, -0.270598, 0.923880 }, + { 0.000000, -0.382683, 0.923880 }, + { 0.270598, -0.270598, 0.923880 }, + { 0.195090, 0.000000, 0.980785 }, + { -0.000000, 0.195090, 0.980785 }, + { -0.195090, -0.000000, 0.980785 }, + { 0.000000, -0.195090, 0.980785 } +}; + +/* mdc model frame information */ +typedef struct mdcFrame_s +{ + float bounds[ 2 ][ 3 ]; + float localOrigin[ 3 ]; + float radius; + char creator[ 16 ]; +} +mdcFrame_t; + +/* mdc model tag information */ +typedef struct mdcTag_s +{ + short xyz[3]; + short angles[3]; +} +mdcTag_t; + +/* mdc surface mdc (one object mesh) */ +typedef struct mdcSurface_s +{ + char magic[ 4 ]; + char name[ 64 ]; /* polyset name */ + int flags; + int numCompFrames; /* all surfaces in a model should have the same */ + int numBaseFrames; /* ditto */ + int numShaders; /* all model surfaces should have the same */ + int numVerts; + int numTriangles; + int ofsTriangles; + int ofsShaders; /* offset from start of mdcSurface_t */ + int ofsSt; /* texture coords are common for all frames */ + int ofsXyzNormals; /* numVerts * numBaseFrames */ + int ofsXyzCompressed; /* numVerts * numCompFrames */ + + int ofsFrameBaseFrames; /* numFrames */ + int ofsFrameCompFrames; /* numFrames */ + int ofsEnd; /* next surface follows */ +} +mdcSurface_t; + +typedef struct mdcShader_s +{ + char name[ 64 ]; + int shaderIndex; /* for ingame use */ +} +mdcShader_t; + +typedef struct mdcTriangle_s +{ + int indexes[ 3 ]; +} +mdcTriangle_t; + +typedef struct mdcTexCoord_s +{ + float st[ 2 ]; +} +mdcTexCoord_t; + +typedef struct mdcVertex_s +{ + short xyz[ 3 ]; + short normal; +} +mdcVertex_t; + +typedef struct mdcXyzCompressed_s +{ + unsigned int ofsVec; /* offset direction from the last base frame */ +} +mdcXyzCompressed_t; + + +/* mdc model file mdc structure */ +typedef struct mdc_s +{ + char magic[ 4 ]; /* MDC_MAGIC */ + int version; + char name[ 64 ]; /* model name */ + int flags; + int numFrames; + int numTags; + int numSurfaces; + int numSkins; /* number of skins for the mesh */ + int ofsFrames; /* offset for first frame */ + int ofsTagNames; /* numTags */ + int ofsTags; /* numFrames * numTags */ + int ofsSurfaces; /* first surface, others follow */ + int ofsEnd; /* end of file */ +} +mdc_t; + + + + +/* +_mdc_canload() +validates a Return to Castle Wolfenstein model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ + +static int _mdc_canload( PM_PARAMS_CANLOAD ) +{ + mdc_t *mdc; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *mdc ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as mdc */ + mdc = (mdc_t*) buffer; + + /* check mdc magic */ + if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check mdc version */ + if( _pico_little_long( mdc->version ) != MDC_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid mdc */ + return PICO_PMV_OK; +} + + + +/* +_mdc_load() +loads a Return to Castle Wolfenstein mdc model file. +*/ + +static picoModel_t *_mdc_load( PM_PARAMS_LOAD ) +{ + int i, j; + picoByte_t *bb; + mdc_t *mdc; + mdcSurface_t *surface; + mdcShader_t *shader; + mdcTexCoord_t *texCoord; + mdcFrame_t *frame; + mdcTriangle_t *triangle; + mdcVertex_t *vertex; + mdcXyzCompressed_t *vertexComp; + short *mdcShort, *mdcCompVert; + double lat, lng; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + /* ------------------------------------------------- + mdc loading + ------------------------------------------------- */ + + + /* set as mdc */ + bb = (picoByte_t*) buffer; + mdc = (mdc_t*) buffer; + + /* check ident and version */ + if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) || _pico_little_long( mdc->version ) != MDC_VERSION ) + { + /* not an mdc file (todo: set error) */ + return NULL; + } + + /* swap mdc */ + mdc->version = _pico_little_long( mdc->version ); + mdc->numFrames = _pico_little_long( mdc->numFrames ); + mdc->numTags = _pico_little_long( mdc->numTags ); + mdc->numSurfaces = _pico_little_long( mdc->numSurfaces ); + mdc->numSkins = _pico_little_long( mdc->numSkins ); + mdc->ofsFrames = _pico_little_long( mdc->ofsFrames ); + mdc->ofsTags = _pico_little_long( mdc->ofsTags ); + mdc->ofsTagNames = _pico_little_long( mdc->ofsTagNames ); + mdc->ofsSurfaces = _pico_little_long( mdc->ofsSurfaces ); + mdc->ofsEnd = _pico_little_long( mdc->ofsEnd ); + + /* do frame check */ + if( mdc->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "MDC with 0 frames" ); + return NULL; + } + + if( frameNum < 0 || frameNum >= mdc->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MDC frame specified" ); + return NULL; + } + + /* swap frames */ + frame = (mdcFrame_t*) (bb + mdc->ofsFrames ); + for( i = 0; i < mdc->numFrames; i++, frame++ ) + { + frame->radius = _pico_little_float( frame->radius ); + for( j = 0; j < 3; j++ ) + { + frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); + frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); + frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); + } + } + + /* swap surfaces */ + surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); + for( i = 0; i < mdc->numSurfaces; i++ ) + { + /* swap surface mdc */ + surface->flags = _pico_little_long( surface->flags ); + surface->numBaseFrames = _pico_little_long( surface->numBaseFrames ); + surface->numCompFrames = _pico_little_long( surface->numCompFrames ); + surface->numShaders = _pico_little_long( surface->numShaders ); + surface->numTriangles = _pico_little_long( surface->numTriangles ); + surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); + surface->numVerts = _pico_little_long( surface->numVerts ); + surface->ofsShaders = _pico_little_long( surface->ofsShaders ); + surface->ofsSt = _pico_little_long( surface->ofsSt ); + surface->ofsXyzNormals = _pico_little_long( surface->ofsXyzNormals ); + surface->ofsXyzCompressed = _pico_little_long( surface->ofsXyzCompressed ); + surface->ofsFrameBaseFrames = _pico_little_long( surface->ofsFrameBaseFrames ); + surface->ofsFrameCompFrames = _pico_little_long( surface->ofsFrameCompFrames ); + surface->ofsEnd = _pico_little_long( surface->ofsEnd ); + + /* swap triangles */ + triangle = (mdcTriangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + /* sea: swaps fixed */ + triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); + triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); + triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); + } + + /* swap st coords */ + texCoord = (mdcTexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); + for( j = 0; j < surface->numVerts; j++, texCoord++ ) + { + texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); + texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); + } + + /* swap xyz/normals */ + vertex = (mdcVertex_t*) ((picoByte_t*) surface + surface->ofsXyzNormals); + for( j = 0; j < (surface->numVerts * surface->numBaseFrames); j++, vertex++) + { + vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); + vertex->normal = _pico_little_short( vertex->normal ); + } + + /* swap xyz/compressed */ + vertexComp = (mdcXyzCompressed_t*) ((picoByte_t*) surface + surface->ofsXyzCompressed); + for( j = 0; j < (surface->numVerts * surface->numCompFrames); j++, vertexComp++) + { + vertexComp->ofsVec = _pico_little_long( vertexComp->ofsVec ); + } + + /* swap base frames */ + mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameBaseFrames); + for( j = 0; j < mdc->numFrames; j++, mdcShort++) + { + *mdcShort = _pico_little_short( *mdcShort ); + } + + /* swap compressed frames */ + mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameCompFrames); + for( j = 0; j < mdc->numFrames; j++, mdcShort++) + { + *mdcShort = _pico_little_short( *mdcShort ); + } + + /* get next surface */ + surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, mdc->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* mdc surfaces become picomodel surfaces */ + surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); + + /* run through mdc surfaces */ + for( i = 0; i < mdc->numSurfaces; i++ ) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); /* sea */ + return NULL; + } + + /* mdc model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader -sea */ + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + /* detox and set shader name */ + shader = (mdcShader_t*) ((picoByte_t*) surface + surface->ofsShaders); + _pico_setfext( shader->name, "" ); + _pico_unixify( shader->name ); + PicoSetShaderName( picoShader, shader->name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indexes */ + triangle = (mdcTriangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); + + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); + } + + /* copy vertexes */ + texCoord = (mdcTexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); + mdcShort = (short *) ((picoByte_t *) surface + surface->ofsXyzNormals) + ((int)*((short *) ((picoByte_t *) surface + surface->ofsFrameBaseFrames) + frameNum) * surface->numVerts * 4); + if( surface->numCompFrames > 0 ) + { + mdcCompVert = (short *) ((picoByte_t *) surface + surface->ofsFrameCompFrames) + frameNum; + if( *mdcCompVert >= 0 ) + vertexComp = (mdcXyzCompressed_t *) ((picoByte_t *) surface + surface->ofsXyzCompressed) + (*mdcCompVert * surface->numVerts); + } + _pico_set_color( color, 255, 255, 255, 255 ); + + for( j = 0; j < surface->numVerts; j++, texCoord++, mdcShort+=4 ) + { + /* set vertex origin */ + xyz[ 0 ] = MDC_SCALE * mdcShort[ 0 ]; + xyz[ 1 ] = MDC_SCALE * mdcShort[ 1 ]; + xyz[ 2 ] = MDC_SCALE * mdcShort[ 2 ]; + + /* add compressed ofsVec */ + if( surface->numCompFrames > 0 && *mdcCompVert >= 0 ) + { + xyz[ 0 ] += ((float) ((vertexComp->ofsVec) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + xyz[ 1 ] += ((float) ((vertexComp->ofsVec >> 8) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + xyz[ 2 ] += ((float) ((vertexComp->ofsVec >> 16) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + normal[ 0 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 0 ]; + normal[ 1 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 1 ]; + normal[ 2 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 2 ]; + PicoSetSurfaceNormal( picoSurface, j, normal ); + + vertexComp++; + } + else + { + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + /* decode lat/lng normal to 3 float normal */ + lat = (float) ((*(mdcShort + 3) >> 8) & 0xff); + lng = (float) (*(mdcShort + 3) & 0xff); + lat *= PICO_PI / 128; + lng *= PICO_PI / 128; + normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); + normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); + normal[ 2 ] = (picoVec_t) cos( lng ); + PicoSetSurfaceNormal( picoSurface, j, normal ); + } + + /* set st coords */ + st[ 0 ] = texCoord->st[ 0 ]; + st[ 1 ] = texCoord->st[ 1 ]; + PicoSetSurfaceST( picoSurface, 0, j, st ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, j, color ); + } + + /* get next surface */ + surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* return the new pico model */ + return picoModel; +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMDC = +{ + "1.3", /* module version string */ + "RtCW MDC", /* module display name */ + "Arnout van Meer", /* author's name */ + "2002 Arnout van Meer", /* module copyright */ + { + "mdc", NULL, NULL, NULL /* default extensions to use */ + }, + _mdc_canload, /* validation routine */ + _mdc_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_ms3d.c b/libs/picomodel/pm_ms3d.c new file mode 100644 index 00000000..4bbd9b38 --- /dev/null +++ b/libs/picomodel/pm_ms3d.c @@ -0,0 +1,494 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MS3D_C + +/* dependencies */ +#include "picointernal.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4100 ) /* unref param */ +#endif + +/* remarks: + * - loader seems stable + * todo: + * - fix uv coordinate problem + * - check for buffer overflows ('bufptr' accesses) + */ +/* uncomment when debugging this module */ + #define DEBUG_PM_MS3D + #define DEBUG_PM_MS3D_EX + +/* plain white */ +static picoColor_t white = { 255,255,255,255 }; + +/* ms3d limits */ +#define MS3D_MAX_VERTS 8192 +#define MS3D_MAX_TRIS 16384 +#define MS3D_MAX_GROUPS 128 +#define MS3D_MAX_MATERIALS 128 +#define MS3D_MAX_JOINTS 128 +#define MS3D_MAX_KEYFRAMES 216 + +/* ms3d flags */ +#define MS3D_SELECTED 1 +#define MS3D_HIDDEN 2 +#define MS3D_SELECTED2 4 +#define MS3D_DIRTY 8 + +/* this freaky loader needs byte alignment */ +#pragma pack(push, 1) + +/* ms3d header */ +typedef struct SMsHeader +{ + char magic[10]; + int version; +} +TMsHeader; + +/* ms3d vertex */ +typedef struct SMsVertex +{ + unsigned char flags; /* sel, sel2, or hidden */ + float xyz[3]; + char boneID; /* -1 means 'no bone' */ + unsigned char refCount; +} +TMsVertex; + +/* ms3d triangle */ +typedef struct SMsTriangle +{ + unsigned short flags; /* sel, sel2, or hidden */ + unsigned short vertexIndices[3]; + float vertexNormals[3][3]; + float s[3]; + float t[3]; + unsigned char smoothingGroup; /* 1 - 32 */ + unsigned char groupIndex; +} +TMsTriangle; + +/* ms3d material */ +typedef struct SMsMaterial +{ + char name[32]; + float ambient[4]; + float diffuse[4]; + float specular[4]; + float emissive[4]; + float shininess; /* range 0..128 */ + float transparency; /* range 0..1 */ + unsigned char mode; + char texture [128]; /* texture.bmp */ + char alphamap[128]; /* alpha.bmp */ +} +TMsMaterial; + +// ms3d group (static part) +// followed by a variable size block (see below) +typedef struct SMsGroup +{ + unsigned char flags; // sel, hidden + char name[32]; + unsigned short numTriangles; +/* + unsigned short triangleIndices[ numTriangles ]; + char materialIndex; // -1 means 'no material' +*/ +} +TMsGroup; + +// ms3d joint +typedef struct SMsJoint +{ + unsigned char flags; + char name[32]; + char parentName[32]; + float rotation[3]; + float translation[3]; + unsigned short numRotationKeyframes; + unsigned short numTranslationKeyframes; +} +TMsJoint; + +// ms3d keyframe +typedef struct SMsKeyframe +{ + float time; + float parameter[3]; +} +TMsKeyframe; + +/* restore previous data alignment */ +#pragma pack(pop) + +/* _ms3d_canload: + * validates a milkshape3d model file. + */ +static int _ms3d_canload( PM_PARAMS_CANLOAD ) +{ + TMsHeader *hdr; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if (bufSize < sizeof(TMsHeader)) + return PICO_PMV_ERROR_SIZE; + + /* get ms3d header */ + hdr = (TMsHeader *)buffer; + + /* check ms3d magic */ + if (strncmp(hdr->magic,"MS3D000000",10) != 0) + return PICO_PMV_ERROR_IDENT; + + /* check ms3d version */ + if (_pico_little_long(hdr->version) < 3 || + _pico_little_long(hdr->version) > 4) + { + _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." ); + return PICO_PMV_ERROR_VERSION; + } + /* file seems to be a valid ms3d */ + return PICO_PMV_OK; +} + +static unsigned char *GetWord( unsigned char *bufptr, int *out ) +{ + if (bufptr == NULL) return NULL; + *out = _pico_little_short( *(unsigned short *)bufptr ); + return( bufptr + 2 ); +} + +/* _ms3d_load: + * loads a milkshape3d model file. +*/ +static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ) +{ + picoModel_t *model; + unsigned char *bufptr; + int shaderRefs[ MS3D_MAX_GROUPS ]; + int numGroups; + int numMaterials; +// unsigned char *ptrToGroups; + int numVerts; + unsigned char *ptrToVerts; + int numTris; + unsigned char *ptrToTris; + int i,k,m; + + /* create new pico model */ + model = PicoNewModel(); + if (model == NULL) return NULL; + + /* do model setup */ + PicoSetModelFrameNum( model, frameNum ); + PicoSetModelName( model, fileName ); + PicoSetModelFileName( model, fileName ); + + /* skip header */ + bufptr = (unsigned char *)buffer + sizeof(TMsHeader); + + /* get number of vertices */ + bufptr = GetWord( bufptr,&numVerts ); + ptrToVerts = bufptr; + +#ifdef DEBUG_PM_MS3D + printf("NumVertices: %d\n",numVerts); +#endif + /* swap verts */ + for (i=0; ixyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] ); + +#ifdef DEBUG_PM_MS3D_EX_ + printf("Vertex: x: %f y: %f z: %f\n", + msvd[i]->vertex[0], + msvd[i]->vertex[1], + msvd[i]->vertex[2]); +#endif + } + /* get number of triangles */ + bufptr = GetWord( bufptr,&numTris ); + ptrToTris = bufptr; + +#ifdef DEBUG_PM_MS3D + printf("NumTriangles: %d\n",numTris); +#endif + /* swap tris */ + for (i=0; iflags = _pico_little_short( triangle->flags ); + + /* run through all tri verts */ + for (k=0; k<3; k++) + { + /* swap tex coords */ + triangle->s[ k ] = _pico_little_float( triangle->s[ k ] ); + triangle->t[ k ] = _pico_little_float( triangle->t[ k ] ); + + /* swap fields */ + triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] ); + triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] ); + triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] ); + triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] ); + + /* check for out of range indices */ + if (triangle->vertexIndices[ k ] >= numVerts) + { + _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts-1); + PicoFreeModel( model ); + return NULL; /* yuck */ + } + } + } + /* get number of groups */ + bufptr = GetWord( bufptr,&numGroups ); +// ptrToGroups = bufptr; + +#ifdef DEBUG_PM_MS3D + printf("NumGroups: %d\n",numGroups); +#endif + /* run through all groups in model */ + for (i=0; i

({RX16-Zk;7E4z5eH!R-~8q``QpF)%fGO} zw-k_Y+CTcEKl+D%_y;~>;Rd+w?c2B2b-7QD1gL)V8@cqq|NFmlkppY_pa1!v|Nig) z=CsQ0F)*(3>tFx+{~axV_jiBCdC)Lb2LK^l`oI3`zkdAVA3r=$F?lBvo>&v9iN8Py z3qSCwWK1;>V!;M+ne3tL%=l}uDJ;(!LW=_V3K~io9U>75ISeUbMB< zvL?&P$RolcFQkxYlD;=B55c`clRoudHv&2goR23WdXh9~r86$UHEFLI#dTH@a8eEY!NqesBC3BtS7Q9^rrXXMgs`fBeV46*GSC z_kIt%$6dfWF-_iLQosD=FEL_F?MFZQ5wP*AU;PRv0K3F$Ihf^x4?e(kc;k&XFm#NV z!xR*OH`qO2!OKBn9CzVw{^oBu9>c|scXxN$`TqOw^A=QKgNw4@TCj&N{`Ft~HTTTI zw|L7JUw!peejNKJVkckZfFJ$nhaAK4thr&d50%+*8z2_9^qb%O=6m1!-Yiav3@I#I8>~SKg%fZrfC_sppz<~FgMrra z5}2{4*IK1%6njK;=lQQQVHCFmM0w#@eQ;s4e`m0FyEZ-`UPzZZI2$peP-u+nYX=ZB znPA{g7Dn+iJg9HoEcN!QYgf|ktyHCz$~6kDjmE~Ma-mN0bL}xmfZ7&@ zZQVa+;1&Q0SQvnT-+(D|9@adM@e;5(90ESVYTtV6E%1X+`3imsV1OM1A-tW$4D49J z17^(vDgY#%PUkMnAkz8Ezx+!+1po+$xFQ!K>ftS?RY=2`zy0lRb8qYc2EaDDt8s<*j6gMbk?X#Jt!8qVP3}(_jX`p}N+dc%nMKRA0N)-?=u}y;kjS z*GC7<^-EZ@R%lfE8%D84$%8TFm?jiz=5>)vpwAO-1cnP{Feqepfw3CynI-4!vJ39h z@``)e-H2Z7Y+ljwEk+e-NmEN^MFnhp(AhkQ zn>omsa4BF{(6j>I0!jv>31Nd$bfwc|Y1zS;LS#Ux&OjAgbkIEFm&OwzZQw~H$Z(Km z4W&w2WfaRcy|J_}tU*@iQUpv<1dWYUx>%2!r9`?2U}*U|m|<3W@j|Caqs{nIv44;z zs3}!~$#kK=)jPN`=!+=$;{Y0;8Z&tG5=Y=+V7SU};8X-AgcUsR2?el7j2IkZzd8VG zChfsv`&-}o7CUXsAR~fHf!Ctk1u%mRQXqHv8DP)rufGlwu<%{Zra~2kRm!X20CoZu zyah-&GtwXk4lm5ly?W=473KU3Py`;-YBi4GW}tM~egnA;qGRG>WUd~5%)rTzH0aY3 zgQ%AR1Bp{44&i@z7y=J!{T$ARAc>?v*s1&y0SO6PEZ2ndd|meQ0yFS4SU>q>^Wb)} zG0brVa>H9zSCYr_RmH(v0DeVkS5MUCQZ+ z&MkXqmfW)|?ggiNW_gtWB$6(}epr>sBTo3-)HjfyK$8|S1li9-rjn`j+q*aYdKPaY zl`R=*rkE6~-L*n%kSvr#35|}Gn3jZtL4%2Omd-9P8i*>Z8kTJ7{LLXTj-P=Z7qbc& zh_*;)nLFSmP)ekIdM;6D1(OBJq_Iqyc_p;UQ6&L&0^u-X9uQsm0nKtdRj(JDBc{4! z8pBL;JzZ!bQ&t-6rCS^1WFuNCS#FQ^uaDO^C6zJy@;e%nn1S_Rf9z2U#;0sueiK$c zV=^`Y8+b^oIA!uMzN-QgERy4~Z2MC_B6WeqA)o8gKe8Ici56t;072ynP4Cuh#m-tI0A1b&9X3{Z_!2Nxn} z;$}F8g$)Ho46SkH%FT4-{gBNquXg({{Y52sNF~!;iNeLs0`Eb6*gy215u!MhT)Ciox(X=`leSG#H61%wW_sM6Xn-*`!~0 zu%GD+bA%zaah1@lx#14#$y%>8+9z{L4Mj7uiL6KtAsa`-leijR_63tt`HVmLlRqIG z00T&IszsGEIDp^5$6*HfQ`^r_hjAokN92Olf(qEZ{VU{DJoxX$3@%Cy1*pL8zx&M{s z)B$8f!K8;DGw?E0y3?|I5JQp^SUi|PqVu^44}+b+!}FFi!G>&Gd(;Ns;-$6~%*aWs zzE)g~@i>+$l6457ZX=R-0kks3!k~1=bVyc#Fgn~xn4wU^(VRHX2=b|OD0YXTKN)nQ zb|PlkAJ3wEU4r%6`896#XpihLuF&qK_Lpsx$U;K;AcQJg*Qf2BJ9pk zj0;iJ4JY&IfQj+V~Hj+^t_W8g#a4SG^%7~(u~rNR_*1wo3*uz#ol^xc#y1) z&Dwwga`gA+yBqo57NHGele~c#Xj-V$tpP<}e!#$*6=nb!n9f}brir6~XMlCyiy128 zN#fGBU4;!Ci9-PV@O4re3P{vP9I1?(>Ir*nKLgAF12B4SfCGqJ*dVfCKZcH1!CSxs zyC-0=+>F1&;jsM-PD@nP_2RUQ5}1G)QzBXAJU6=p`ymQdQ>RS21_KJU zD;Gj~(Ihp}6<_%L;>y(AB797y0nRaX7{jNpm1Jc&9!(dswO)1YQf=)DgH+O$2Ki7@ zCa9I?>wSY6j`@PeA40az7YxF|pnC+sfHF>(J=GIngRV6I2$fJWC5$KlkeFnm+RIqe zI*Xb(;Rh)V93BW3;Gfgau(%AAPcVZP6bNJa_8OQGHp>w`+ugri=*=nDNCXgye zWW-uFl*o9)FwHUyLEK=h8GqGlA3Epiul~!oR+xc#{l#DW1sOnW5!+&I*AcKG1six> zc5H&Z@+9WjtZbK)02S;cz47y({~W*|jX{8*>>gX^Q;xxWfB3^6@-0FMwiRYz+&CXx zj*UP6^FIeCD8T>{U<3J6u3}>b=f?q3o`Ie2WG4X#Z}|$h%Bk!#vj+&_>Kuc^L8!v1 zY|LN;B&f#CaL;x=1E>H<@IRPT_mKM;Br{;cTYiR>!6a893CzR%Ccpp^JZrIE6$Y@j zk%NfC#*gP1c`G>%P6Ffz(x~Ir0UY_t391iF4H45^b;xk>kc=H6V}TY0DaA1T7YsBc zkGbjwHcp+z-*8OL&d#iQ^kPfPwNd%=>v=t255!GIuQ5v56^gBTgR_eci$4+eM6@Zg zm2|Dq6%x^@VzhU!R@N^;&W5$kypa`3vY|+&vu1L_G*woO`2;BJpw9(y-eu|Fpq4?) z3EE$1jf-HH$AhjP7$#nb14N+mV&YZM@dn6=tau{D$?=eIT%uOlM0dKe^f)}ifEax}A@eSaC!|vRQ2@gl%s6ubvy;cT%u;vD z#KH)@8wU2h>h@B=BsM{lo4f*_l4P8kMlqZ!>(bncTg%kqW_8sQUT`yMEamdY035Ws z2~S9J&;a5HYJM#j&(x+Com5iL8Kx~IY*uSK*XiSkq{{TfGx%tQQYp%ut#Pi{G?2US zp%xrY#I?nR<+-_es$M_@6G+KMpexFVMkh?KP{bF3nC`>RU=KM^UpNsWx~ViNn$Tnh z3l;E#gdxrEMm7{ppfX71Mc0#hx`1||+1@mp>)F=OEcN=(P`bMjqo|?bQ9-w(PA-SG zIsBn~cat8I!`$a%kO0L%F|v>2XYdh7Kz4x&2*+TrUK?<$_pW@Ac5LiE#R+z!JKqfB1nTc5d8!pP(IG8p52e8CP#3t&Z zSUm0ykifz*ENYvx@kMoMAWA_CU*uEn0TALQITdd~8m7(?{WAlDY%H*W^TC=7DGLb1 zgG+fH4{dB>IT=qu8>eB{b~PYgJPjLETn$NAeC^q%E65nM$v@w%;RzPLY*A>BnQi5I+tx zus?hYVht5ya3q-q>{a0hzaI7wEMV4zA%qni35qDIRiE;8`~X}HpaS=TBk?(uyTAc9 zW?fspd20IBMcp{h0Aeu8#B~tfdnqZ*SRjI{pnACN_@e!xHJc_s5@8g1z{IZ z$9>}Ea859TpMo+9yl|E?XHNGAJ+KOBe{y^Az3^J_NR|D4(pKdFE*l z!h!_B6Wk7Vs!t(mfG&KbTng3-T9iuxHatfS)^b)r7k1j1VKD7D?D9(Xg2|=$0TDgJ zCius6>MF&)7ZStbc9H@$lQWrXB!2PP{h!4^?GlMUcCe^QF}aE zN15yKa4{_Nn#2q&hPTS-S>xmb4}bxSiYC~p4q%OOa{z7urAyZKVnc$mU5>nKQTtgd z%m6AdYy1_kVQ+7bgULXE0r(#*d~_FPeB5cdH$Ji#b*uKJ;fxXHD9pfR0buZG2~VIj zJ@wR+mj8a(EDvB{i#*65=GcVn=hK22xEddlGq89GL!K4}sNl!5PuZBkThPMtNTkGS z9q?fSLwOtEgkXkbMLxs~kYjtz6=ZNC=|T5eSBg48J@sRm7?C=z=ZO5%fxVK55S9ZXOF#Sx(aB&26n zd?YI~NpwZM@nBeI1PN`XWMJuw&)0kKH`$KR!yeTF{veJb3O*n^|0nNBS1NIn!^=3< zAby4;5Qb7p-h!kpoQzv_s+|fmKnq|4cpyK))%l2T5&i&F?BpX3V1qMr!cYBA0i@Y}2B+eusMc!7j~|C6 zEw+M)9r$5M0b((d7I^yUhZZwb_7lvo&`vPp&_$3QHU1~fY8HNo&%vMj{@84;48?nQPL3M!n8)nGVe z7LW+W)gYVU_Q#zhF1qV_xw9IGGgL92snFoBWy=Y}M7A6sgBEy$7Wi^!c=h%El{XDo zTg_pnvze)_>DfjUDdQ9vQ$%=!;m~Hem2VC@y&?4yadNFc&c`7_u`vUuT^T4gsum&w z9?UrHI2pJUkf2CBkQE?g;Mq?Gg3tg%C+k4Eg2TvI@R9m1D1wc`-ryH`udOT00A>Ir zuA(jkgrRH7Nkk;Jkgnj0?^_ucaFGBOv!JL*kOE+^20U26 z3>Gkh?k9dN&@~8Nc>9nn;$(mhf@`v2!N4IZ03=74Ax?*2#$iE(!v#xttMI_a3=oBv zf(O=CB2|15_2QQ^9@CjlR~ZqCNb&hXud=>IV*AV_;^zS5Ri>b_v6 z+HI^~-@g9s;qIMmd#ks1JKtE3r3wyz#1l?{8IU{(Tm0c9HqAgGw0%V%XVuMM09=`1 zL}#`uDi@Sv=yoksnuSV3M0O~d_yf#KV+uU9T^d;#syKCi8nQT2J~W&_3G;_FTGJS0 zL~w+126-1m%^{NEc6cHNfBJP%^{^9TH}ecAfBylZb|$5+DJXn9tX_8MyXR^uUIe-esTl$ zLi&LM1kZjBAmso^U_d3J^+Qd6+VYg8Aa6fGaRI@IQbM%$=|BMVu0@a<9b$ zD)=#6l!c8+st2wHpQ>BpQ*H^~1}C|Hkhtqe?vN5LE)f^HZ6#f}bAl@rCZHfN=oLSM zH4ESYU|?{VCLKf&U~VX`pe=u^-| zFawO?Q?<5$fjo!!B8Rbwg_rya_{d6l;Ai-mI|Lsh5T%!#!Uu^BPy}f_@IyBXnPL;s z90;6I+ypZZ+lsCe^l?z|M9*rtb*bIoV}Jo|B;iyM5;mNMcrvG<%9}7?b))IcW1hN( zlU8)UKvB8TM^HSLt!HZ;&O3{uCp$~EOre5$FI{GIt-3*pbUo!B&23es)|gfM-0W&WYSEFS@%tp(y1BJzEVXvawXD z)?PQVH5d<+GAOLz0?=U^is<=LJ82Z@MJ+XYg-SaTONC-76eiL|xZt%ysSRczVnJ-e zcr%*9AZ#MeNAn1m7_9H7^Nn0a`B*NP@?8t| z&65~gC)U8XV6Cza_z;s&@o~Q`&ZZCocZ8e=-zBKQlTcSt-@5CHcb)2!KfUYV`+Pfj zb-n_G;2T9EVawGJKLc8ZN^AfdDo6o2l$m0wEMGWga1RQ@xG^h#K>|ZyfEOEwm|^)1 z3N|FrvZ4}T1Mrx@3?Y3f@L>Hlt2q`Fk@E;%NO6{50WUBkmV(F-7Dj~;(DX#ETx9&f z`o+QSb-Z&5q#ke3S>$|rTxXEXePJKG60rYOpJ7QIOkoy6-XQ@Gn!7P%FT48YZf7< z7trnS`{+{3(BPlxtd}<~aIWtukqLyh*K98S0m2Ipi*_P)!n(gbK{L%YZy!A ztXk^|s-Fu>;u3@-a3|8SWHK73FQlxStFiWf#&vhzWB`#4M~~mUHqDN;;e~mG#hckBDc9pd-okXnlj*LF0^O7GlXl zX|P=wt-8CWh>PT@mwv{XV< zxf=KBVccu`fP^|HX$i20TqMW*PQY{TIUnF2A{2!EPMtc1W1#@!B?~q{4iob}Nh9fYqG=`)Y zX^&Tulxa>IGo%ebT5B2 z0cRb|(DF6mcNtkIAu=yMVZbaWQ33u%<7uLq`8w7~vX!$zmEc03`cx16 zi+CH^Y!<+vV_eD55Sy^5N{ZN@wP0}AD28h<|Hlpo*HwU_))Ht;yd-No;d!vl0l)*m zU}r4&2^2N}2G)N0RKgn;E0;>*6jCTVCoqH74w3ZDm#XbicYIJE9#ndJOjlNqsP6Q_VBE`QJ!h&Y2hq_IePM`>M$i^a=G=$R-9jY5N*CTJm}6FosD z#fz{voU%pey^#8K;v3iUQQ)>*DOKQ}i!%TzWCGrY`2ix^o1 z!4{TRW*6qqp`!tuIB;G3a7WPFaDi}s7#rzCuHg!&Xl#K;MkhOt5nb?nJrJc?H_fnw zpplQ~sz#*)Z!}x$GB`4!=Yx7SLH?t&m20lWQsqLmS8okAgqZPIFFgCP9_kb}U?|ui zpFvJSx$&Rn7X(g_Bf;B%^+~ky@W2K^3OD9(IOrc2ajKW_G-UQ5ivkZdF`ASh*kM_w z*zP29sO`@iLhiy093QORMh-Ttd;4%@ePks-#pmEiTo5v(61g0`1Rn56EYOfs@e^8b za(IB{XF!O6QH?}yxxZHGuBYpRTxaZw!NqdU69OPpF}F+~8!abPT&aIJ8CtfoN`8SN zDS3!gu9{30$!`W~xLV6iOg)lHvq`lDQg*4aT1Mf?>nV(%&M93?BbF zkq-J9NeUuD-A-iy3|yD-xSbpIcZI zkAq+Y(Bd{`7M94b(2h@&9M}VioF;v=N0|o;;|tjEGw`U;WQvL>mSn^l@Z}FhnFh}- zAR?G7G*aa@Wf%HWqGkzUE`Hc#t{OqKqga(u(4hq4UF>1{Nq;0+^oQi{_Y1iV#b5v` zh#l;xgiwMw1;Aj>1B8uh*RF9wd>4MwhbOVIvA*7EwJ7>S4pnv67ZJC^=Rk|wN^I~% zrp27adNfOFzyc0g*~Y4j`+>uTf(LbS8!FUW`_k%W?6(3HM+>*AJfx!?@?ZG@jxfUp z4;w=GA&)QvLM9^w0&ydeEk;r~RQPBXm59KJRGv&-XPhE3plTXBDFj|nB`{*@9i@63 zz)0uolwI%!LQ!&#g?xQD+P&Ev?b9)a6bG4xm_eg@0(CEr$d(%fK{V2Ga&jYDs*q(i z3Qg$wW^Huf_WHpKFatUl(6P7#0aW-ILeZd^c4-;FkiLDSJ{&H%9W>dJnx!IxawrKH zSfVb(Kf<~r$XG@#5EUL58Blm39snU%rJjOw1ob4Or30xVdDUnt4`-d5Bt3!?6pEXu z_Gsy>bYnfnkU^M0)e$16ib{YD+zXPP010jZluWf>!3I|T84aDwadNI=_qcu`FnRAq z$+!q?oICf@i_gEpM37@(1~u5{K@Nfx$O-@k8wxhCLg7tW3&w{PDtomp`+*||=eJKj zxnbjkeGlqL)&dT=7bGnv7JEOqp+G`l(DFjynzKiFAqqC&bU_y9IqmSc;bc2~%vhI7 zgwust!^cFpLJU+!usYy_@|Fk%hl6qjwg{=y7mSN!g^x~iT3Z9mcWsXM$9uQe_HQ!= zfZ_@BQDej)NrT1^=o(-~+|1Lw&Lt2a_Cd%<(L`FVjP{!wmnqFKB$-8!R7wL`LK(TOjZVHjaP< z@BlW(V@OkE8ojiBf(K|(Sdun0zeB;|1xQdV2?jzyiW6B+z++{Zq$tseFA#Ehm|5f} zW8q}N2z`ORP`cbIbvBygi}k^Ny3#9Ed+1eoqY0ktM!v@66k0xz)$)a4Ypr*U>>R#0J?vxnl0MWEM>WXAcq8RY%A2PmS@Gr%&s<%wM8 zR-C>#zC=A$s-PQemYY<0$aauNVLB5k=;TgdY{~F?{G?SH>SOfQIw6+IytgpDHb4vQ zabO1H)yDkke(JxpFU1#W95NFVPKa`y6cG_fI+;JhGK( zDhN@Q{a}3#8!hY&U|{lcHfAVz;C>XMOx~E( z{E*oZXM%La0xF!V4thb+sR1*Vq`Q>H^c5Fn5HFHjfk-%vDlnZWw!LX$|9cgEwfSx@w zb8c#G<~;d}b91xIRS{)D?#JOIHaTl?y(9_i@j%`H0LX#*6QU1>myjw{;<++fgV0B$ zmz9KUq2`Sl(PS=_uhC;Ca}YkQxOxc%woUoD3E`4-%x5RMcAq7_6ypN{RC*LyBqI_C2|wute=) z``(W}8EiP-KC^;{$ukHZSZs2LUh1WAMfM*p3QiQ6L)O-v12OWV3j54cPdo`xo4h7Z zY=Qu`Tuv7}Z^9DPurO}1Z#ux79zLDr={`SCrUPi9B_x1vV$H5h=sKhg$ewz-lrA(( zYcw)CT}%(5M=cnIXPRMTDlA**^b}LP z7pR{s%;Q+hlF1-%v9tsggPt`qq2wN@_tI#>nwl*Qc8GL^k||2Mw4|mRz3OmFOXZnN z5KHINwJuF4kj~NSpgIFPoC*tiWK4Yy8%20uwCoaaL2;!}Ou3lhC%vA<=6YN)13ZA9 z2_7gvgEa{ZVuwjoU|SudlA&M;{~fOtF~3z!?HZG2pHsHAn=g}&CW>^SKI2yyFU5^ zyLE6FX0aqx13UWvf$fC>TbbuZ!D~N1{NE=XMO+n7i(AE~$GT~%0Vdl+3 zLrYi5RWP6x&mX2INBaE%(hRhCgrYRX%jg2o1!5TGR+`KZ%wS&i*>h*lF?yExWM&56 z!V?HGQ$;2`&(6W|5;ZU{4QgHz7~T-#U_rRALy&?H4-@JMKnPW$W{$~7I6;uwVoX#C$Iv6kCCcVXJmi>cfz;0AAI@X4Z9U>g za3&~zDzZ4JKt2Q5P~HaC%mQX$-?pFepfCd|Ew1&jg(o71U`e$}0k+*GBELia5r(nP*Uw8BYL%kcDK% z>WUDq$T6VBg$B;b%8JMBjzmZpM8mqs-^4UCo2wYv3b_SuB!y0B)XX@8VW?j|f6!;? zaL}C2BcCpnXd;7XFtgSuhtgkoFgQ7W2DuHwBO)4Z zOeBt(@$B()+90D*@-R26U=re8TCQm1%eiuc=>(|kfJp>LxFwLgsLJxAAv&Jm>f}8W zwAducUXU#jdIwSf!5G8hv&AyQOhAaoGd2Mac+B&#rw5f^f=%eclo7)~K!+(OEMz$F zKUkEX@zz^!-4(oi3W(*>WLM#Lsr1RGIK$`t6-kL&ybb5_($vWlQ>RZ6s=RXSB~lx7 z!-5(lMHTrAguuf9H+Vz?9X5WjU)iPoIOnasja}XaD(v9^Wv{I5<&!aE^3zHDP+zyf zL!FtO>Xy`+8?YBXQU}{7vCbS!WMDe!g(ma`y0f5Lx}(~XCooG5gB)lOV+xSLK&BJP zKIAQ=(PLrJL#`keBQ)@n(|`?1yJ=MO1fn#!(%BJ+rWT#(>`?qf1PpqW0ZEfiR2onT zKyx2rd8*y;#ndYn4hp5{?0D%zUGUO2$^?P2C~*84GMnCrkxET1^pVig=y#IhdpY!8DT)K3L9L78EyaTC;R4_gV zfB`(SQE7+g_yS%u-{Pd|a z{JkDO^~%d9$!)y!;>&1n$m}4YZ}3txLD05>WeILjX8}h*5us9vzj25b;`&c4>g}W* zE3;M>uhx^O@LRWSi@$e6oz1=$Z`F;khi#7ksFUlthFR)XIw)ZF{IIVI)qK6f1U2R{ z6Bjs9;WLc5Zp5`D(JA+eX3vteyORB+ zyT3W!3!9awQPR?7;EJL4biB~~j(m?PisRL8uMd+4F9U7{tgg@L@9tqfE$#xL0l7%1 z62Jfpuz?Y)x+^$g0mmU=Se}NAU!P2MeCnT0;RM2g&_X};Nj}#vD$b5ofL-r&+N1%G zAA4!)L97gBH4@kihO@W0PIfgmQdX+{9$n`0)aQpGT` zB{-XyBc%$=lUaocE#(h{sCz=roMS4I3_4`cVwi4NNsky@&baUR@LQQIUo zaeH~plYyk6lo{EiH>4|M)=Ef*uue*pJhRhKx0zuUh^1gkkacuZTJeWD10A!Z5Fnh= z*%3}KZG?=c0d*8DFL;`2s3L1bc4&de#{e7fFgPuR*rnA~shcbvPBetT67|u8GI6d> z*_QJ^>EPrj!VlI8KPC-YZQG{*k-%`DJMELOp-y|BC!e220|W8|=EV>pa)_Zg zlxv;rr$u6rCJqXlK!x}hq!g^etkh*8XyOVu;eSVivACWlt7tMWl_H2MfI4`Hlp<6t z3?Eh%glsf6fFd%I40t9YfEh|%hEk{#i7khN*4M?A6$&FHGsu2Y5TPmy?+Zu(mw1s` zArcWHh{H*<$vLjRx++yx1c4$^ra?T35xDX;20u_sQj>jRajw7XW(1IxD<1k~=*6$M@KJu{1^GssKM;<)6^XwVaEYgJ< z)=XBB@&wjO`Cy*;%xL0x0~kGx@Ng#)@kJ4fi3O|{7nfmzLN^bF!_j!0p&@3zj6^Wm z3nm0G8kr^z2C5<1$r>5*M6PMphEcPO$`%l!rPA;%g+1zWFVh4^X2R)2Dg!?Q4Nzht zZ>LDxK$5xPhKGiDEv36)W5G~)-D@y3`W;*SU!SlZ$7Dgcb6nNFE$hBi|8Wq@Na zLOqAts|E_90aWX4*2jD0;hs@j%eJ@k&9y|X!cZm}U#axqfQRl|U|In$uI~1U8Nx!p1AO8qYtc;uO|+8`g_d>GLX8 z3jLhSs3M~uqKFl_s364(7Yeg;jZ*M}Gm2?|P;L$RR!S%Tm)CuO*CJo6 zV!B$j;&C}oQGk8!>&IVwK{6aKzCcx$mvT7BaG+4k%Sv^?==d6;3!cb}FEN)146!DQ zScwgg!-kCqiy0t{=S+0k;4|7bI`b^*b*3OtEw+fiSPc=o8(_Cvk{v+r|`TbGh%Km=4 z)k-Im&_?kmG-kl$Anif6gP4UqiiZB-hk6D8+zv!K;G+|=FiKS?GxRN(!N$>i1KZ=v z{ROY}Sv~Fg$MlE6fLe~NGme$tX>@&6dncE4tE-wk8L?I@<82@r&Tl^g7;CC8Wj#k) z6CQ>V(=slOEADl#9H*PIFkHS~44M_rBME0Zhy4*U=&IBiF@(PMSyQX zCIe0vY8EGq8N4){F0!kyIq&G1PxKb=M!>N@*x8|90_30uOG*P*<0Dp@+pb+@&qpZw zKnA;V<%6qNRrlNV>x3sHGg!b0y`lY#qnPnh(ZsCKLLX;uZ+LH?AOd}FDyxJc{E!n4 zFc7s?Z&hrM2!dt|@`+WKHufIET;NKvV$#nZX?Eu%u`H`vt>##WO4R!^%dohr)mCp1b_Oc3TR?LhlxhQe zt@cKDV{^E>gGX@?t!iwuWG^ONO**Lnj|9D^vtkm zHPd;M@dKvYbXvRZdtWq0|KN1*R|0|ppQbn5kt`Z}hJ~h2G%4*CS~^Qhi)^#dTFU{Q zMw7t;seAzvC`r#!g~_hPvO)~-q-c}A+#8Lu>9meh;E)oV{5B$xvWI#K5Q5u5*9rv{FoU`)m@#%Ta62@3jGc_P z0vp%n2sDt?p(w%6KTVy01mgh^!=bGe{2=40^u5=iXTjNEpb0b5TJX#1Od*-UKNKtE zPwS9L?Z$T5Y^JjnxEEEo?e`ygTaQb%9z-uUY(SxirIIiy@LfPD(yB;}GBV}v-4&=F z^r9iYMGFg>986WEcneue!x%0EUIh*W{sm}Ju2$(MgEyMbqJCa5%Iq^Ku_n`W*JT|q z0P4cl2K4d4kdvM8LrtvE2tlgz-jh|K#~46P=A3zVUIkY}_kF+vDZC;k9PDWh*rqi)ExWc8#nMOa5aDpR$Wgaase^G3|6wDfCk7h#tb%eR^#nr z#+^A-f|nMTDPMpL)vDrBQXGLZLGCf?_9WHF@4Jy@<|!3Y%dhnYWv`Vl**T+Z4=74Q7JhN-b`!_`uP%c{X`78pB0=8 z{Frz;g)#^ID+Y2MR73Lgg1D|Qur2C`N=`YHsPmtqWwyPdJZ(m@WOO|{Fnb0vC^acLu)t|!4ffKZ*!OS>I zfyqRR@FS*0e3FSoR64naZ-KV~Z0Jx0pM#ZtH=GRZTX4%lcrww?077P)u{i!{H|A9T z#+p*xp~%U+Bl<^d&*#D=7%^+iLJO)v!*aY_nl9G3+uX2PeS!IIw|dL5hX;{4`B-(SnD8o(JkbRnzSD zdVEomtC)DUzW7eA;4i=Yl3)FqG`Tut#Sqe=Y+8T?UZqND z`3=*n(^PH{j08oaxR+ZKKw`$58mz)`8RB$=S_Xdq{T) zfZ>Eax>u@>UvF>JTfLysB3rq%_=ngUH4vmr&>nEX!HTA}RbO0MB`Ywb~U@Q6k?7#PWXm9b<&XVBc(37UPhG-z(CF!#`M9NWbc zfVG8(K}dp1F%2UK3DRZH6(0jIl1loAsnAZ)a3NT@9w4zjq|bDh*p_v76s0l=1`qJ; z9uoedwMOZLg_dodofh}v=_&czTU^HwH5jQ%UkL{1?rR@%@&Pz9eJeD;>Ga8Ya56B& z_*{j?K^4!o%ujCKgaf8p+@fME5CUwF;ZW0xqD4c+QOp?c(P%Ng{q==D(>=rnO8&cC zK>&k#34TUI$jBmsMbH4XJDtfBo0J)ZR^M=%beco3Fw1tm%z%Ng&qVcFdypwwjAX~7 zsD-e${E}hC7+pYRBVSB2&OM*cWzv7Rb9-fZ38yB*Xr*+T@+`_6I2J$!?QkF$k%s9p zrfAsP9BdB;gng>V^vH7blw-GgLbT|o9DP)_XJP?>nF0zetcZ?tDZh!U8NfjPiy84~ zay%m+IFpa?P8@_27*s~xoSfdR-~ayOzxfE{V5P~M3#0P1@zzZR8&Oq-<`e(}z5=C6y+RU*Fj63?DZ7 zyG$*l-~yE!q9!iII-`n~siZFBYETzJMHCG`oD4KIXhxwd((G*YwuZwIO&==QP!&>H zPMHO`no$TPtAV#cqdJ}k4#(@fN6>;J5R&M2t}%GL&N0u}|LT}~d$aG_78?9yHI%D? zYLDtfxup72XrD(cP&LzEqA4~)5EZ1b;9)3gXP7jlA>EfLm?eb&JHzJozSkMn+FM?ypR3qqizd?04m-V_eLHB86rs1ws8(Qj zP}G2kL1q=WV4+aLL=r+3s-g^dHXWzGwM`hJa3V@v@U`P&oUt$eYB$jh<+!}Un>pqGLbSqyq6q`b$bwQsQBCv;Iha=ucw7cc z=&}bq*k%DR#wm^QB|h_wg9VjTSkI*kj18zV5)q*sn%b#vDrSc3WlIJ`Q34aoYuCaa zH4&rMhTmOfZb-Y!pv8J`8)#|w2bNbS=fQjs^s=ajtf9|ycZJ$WDnlhTlVA)&N(&Dg zp6B&9x1jo|YLlXB-e-;QLIC6Rp2Q#o=P!N+)mJX}@4x?^m<0e}|8p;T?Md)tHmKY} z5T{B)|0?AY`IUI?R~`Y!Lzqa=%K-^gHx$nthvSNZ5ZGUkMrm;)Q~@xKWhx!aT?(h@WuVk4(^2=ZXiz{O-}E$`a7M$$m?#> zcy3q@!;Y#7FpM}JMl_q5$p%104C=@FdZAFL)oT5IpA!d^h{{Wc2*IE8IZ5QXC(CJj z0#`f;@x>Qkklw)I`1$9bNktH1aNYB@!r{>Pp&>*+dAy$rIike)C_oPNTM97*COmrD zKI7?pKUf&#p#G@hkt3Q$9M}O>&{@B^xZ*SeNH9OERI=$US zd()_SMLIsJCJb+w+#HK;Gsdn)B7k>MwxEZs)#`9cMIoAw(^Ld^83s9U7r=m@e)SOe)xfEDw@MMC=g3O z{q)lp@lKw;5p>|Q>d&pe`=fxN_sk{{f4-^h(-?WcEA`Vtx2fz z$%IP*RZ~r6wwYnjHiL#8)X~qNdxUl|M6{SCK=&jRI8n3ymt@H!~3lH`adbId~ZTicf3s-o&0)&Y!~SEu)!l>`R92%Ta2 zmjn0%FlJ~TIh0sHEHKRiTyB5|(-Bb7U5KhDz(!OUI@2}fUbxg%Dp&5 z2qjdkDlbtj=Fn47s1sFm)xW5Tk;(-Dd+gt>V{-S?OF(D(+e50YVsWFBXBHgo(Ev?-lu&s*)J9l3%ofCfE>7Sxono) z1~u3*Y#hajaqyzy0rx_$PryTg#5lUq8$445I}y6zlmHld1w(l9U#_Myw0qO%G zc!XP?tZzBazg}Kd&8upq4Ib7N{phiHGO?ba-IZx-d8Ef(zi2v8K^X(USX5}C>xl$p z3qFki#_?aNJSrAA84Ku8#q<3_E>Ee5`+n|L2#>t!x@+xA1=UM=7gX#)1KW7}4O zLFspH|7Ky~8VSuPU;#yd1XeaazVW-8H*Vayb(7~XO5x7!Ta05?A~*3E5k(4Jtaa98 zDw(uQGYo>cxuuo(tvgG%nS8i(m%;1YE-tMu(}Gf_r=&&RlbP?X=R1xIb=9`4;b0(u z@m9_Sc~P;z%UWRUd_e7Q1VK>q7$+P0UVuC%Q%Ttl0`%^X`_Z@C+iDZVEBuv5k5C@` z#e!ryKr}a(Naq=J$Qbw4L@J)nGCp->WfeEW@&YoRw&fv34$~7}Cu4}v+9T!ivTt0T zFBT9BoQwsgl`wHWesTF9xf6LLihijV<(?c%nwXm_7&fAOOlPGr)pkRgPU7(doUX9Z zww=HaTDIe$%|~DYWefc*Vey^JmoKj(7I*~M zZ+Ciqw-zuJpxtf@V4RaPLO!Ng;CKuCDP>qeDpNv3i%BC0f2IpXH)w{azNiuA%Gi9y3EB^N=9b8#BThZGCEumuhlR@bvjtBIvm=C)=bgc?jG zF-_n1k%NvL3`t|WurcL{Vu5pD0d&W66$H2#tyrwsDoQa7W-8OLDo(~Z`1<7|iUnTU z0tX9ar(SFH+^|h1Bb(3D;f{Rt@kFqfeiiu#v4B|MtXSaRt}(xui6NGmKX)nYOJ&xAymS9%GiTBF7R7hy~7y1^)X&#SQ#s z*YSew!B9<1l|?Kd77zz~A0St*prdvuL5etX~lm-5Go(Tn;+k^dw zj82UfsjX@|$gNmFEHKFef4#I74J8o|W0G}bpIAUF@T>*q<`i*jtkrk_!5*tDVga#$ zSYV0;(sNTDklkVdv4B`$f(8Ehw-a{CF0p`EKrArD0tX9I9+2H)0kMEsV1fk%GbR{C zc8LYV0#hv@m@(Bf@_<-CEHJ?Wf*BKxBD=%_Vu7g^5X_ir8hJo0AQqTl0l|z3Mv+}& z0kObT3kYURHH|zV77z|*4fDb literal 0 HcmV?d00001 diff --git a/plugins/model/cpicomodel.cpp b/plugins/model/cpicomodel.cpp new file mode 100644 index 00000000..d02c5be4 --- /dev/null +++ b/plugins/model/cpicomodel.cpp @@ -0,0 +1,220 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "cpicomodel.h" +#include "cpicosurface.h" + +CPicoModel::CPicoModel(const PicoModelKey& key) +: m_refcount(1) +{ + load(key.first.GetBuffer(), key.second); +} + +CPicoModel::CPicoModel(const Str& name) +: m_refcount(1) +{ + load(name.GetBuffer(), 0); +} + +CPicoModel::CPicoModel(const Str& name, const int frame) +: m_refcount(1) +{ + load(name.GetBuffer(), frame); +} + +CPicoModel::CPicoModel(const char *name, const int frame) +: m_refcount(1) +{ + load(name, frame); +} + +void CPicoModel::load(const char *name, const int frame) +{ + CPicoSurface *surf; + picoSurface_t *pSurface; + int i; + + m_name= new char[strlen(name)+1]; + strcpy(m_name,name); + + m_frame = frame; + + if( !(m_pModel = PicoLoadModel(m_name, frame)) ) + { + int len = strlen(m_name); + + // Try loading an mdc if md3 fails and vice-versa (fixme: only do this for games with mdc support) + if( !strcmp( m_name + len - 4, ".md3" ) ) + { + m_name[len - 1] = 'c'; + m_pModel = PicoLoadModel(m_name, frame); + } else if( !strcmp( m_name + len - 4, ".mdc" ) ) + { + m_name[len - 1] = '3'; + m_pModel = PicoLoadModel(m_name, frame); + } + } + + if( m_pModel ) + { + m_children = g_ptr_array_new(); + aabb_clear(&m_BBox); + for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ ) + { + pSurface = PicoGetModelSurface(m_pModel,i); + surf = new CPicoSurface(pSurface); + g_ptr_array_add(m_children, surf); + aabb_extend_by_aabb(&m_BBox, surf->GetAABB()); + } + } + else + { + m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; + m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; + } + + m_parents = g_ptr_array_new(); +} + +CPicoModel::~CPicoModel() +{ + if( m_pModel ) { + for(unsigned int i=0; ilen; i++) + ((CPicoSurface*)m_children->pdata[i])->DecRef(); + g_ptr_array_free(m_children, FALSE); + } + g_ptr_array_free(m_parents, FALSE); + delete [] m_name; +} + +void CPicoModel::AddParent( CPicoParent *parent ) +{ + g_ptr_array_add(m_parents, parent); +} + +void CPicoModel::RemoveParent( CPicoParent *parent ) +{ + unsigned int i; + for(i=0; ilen; i++) { + if( parent == (CPicoParent*)m_parents->pdata[i] ) + g_ptr_array_remove_index_fast(m_parents, i); + } +} + +void CPicoModel::Reload( void ) +{ + CPicoSurface *surf; + picoSurface_t *pSurface; + int i; + unsigned int j; + + // Get rid of the old model + if( m_pModel ) { + for(j=0; jlen; j++) { + ((CPicoSurface*)m_children->pdata[j])->DecRef(); + g_ptr_array_remove_index_fast(m_children, j); + } + } + + // And reload it + m_pModel = PicoLoadModel(m_name, m_frame); + + if( m_pModel ) + { + m_children = g_ptr_array_new(); + aabb_clear(&m_BBox); + for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ ) + { + pSurface = PicoGetModelSurface(m_pModel,i); + surf = new CPicoSurface(pSurface); + g_ptr_array_add(m_children, surf); + aabb_extend_by_aabb(&m_BBox, surf->GetAABB()); + } + } + else + { + m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; + m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; + } + + for(j=0; jlen; j++) { + ((CPicoParent*)m_parents->pdata[j])->UpdateShaders(); + } +} + +void CPicoModel::Draw(int state, vector shaders, int rflags) const +{ + if( m_pModel ) { + for(unsigned int i=0; ilen; i++) + ((CPicoSurface*)m_children->pdata[i])->Draw(state, shaders[i], rflags); + } +} + +void CPicoModel::Draw(int state, int rflags) const +{ + if( m_pModel ) { + for(unsigned int i=0; ilen; i++) + ((CPicoSurface*)m_children->pdata[i])->Draw(state, rflags); + } +} + +bool CPicoModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t dist_start = *dist; + vec_t dist_local = *dist; + ray_t ray_local = *ray; + + if( !m_pModel ) { + return false; + } + + if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) + return false; + dist_local = dist_start; + + for(unsigned int i=0; ilen; i++) + { + if(((CPicoSurface*)m_children->pdata[i])->TestRay(&ray_local, &dist_local)) + { + *dist = dist_local; + } + } + + return *dist < dist_start; +} + +int CPicoModel::GetNumSurfaces( void ) +{ + if( !m_pModel ) { + return 0; + } + + return m_children->len; +} + +char *CPicoModel::GetShaderNameForSurface( const unsigned int surf ) +{ + if( !m_pModel || surf < 0 || surf >= m_children->len ) { + return 0; + } + + return ((CPicoSurface*)m_children->pdata[surf])->GetShaderName(); +} diff --git a/plugins/model/cpicomodel.h b/plugins/model/cpicomodel.h new file mode 100644 index 00000000..13ebfe1e --- /dev/null +++ b/plugins/model/cpicomodel.h @@ -0,0 +1,94 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CPICOMODEL_H_ +#define _CPICOMODEL_H_ + +#include "plugin.h" +#include "picomodel.h" + +#include "gtkr_vector.h" + +class CPicoParent +{ +public: + virtual void UpdateShaders( void ) = 0; +}; + +class CModelManager; // forward declaration + +//typedef std::pair PicoModelKey; +typedef pair PicoModelKey; + +class CPicoModel : public IRender, public ISelect +{ + friend class CModelManager; +public: + CPicoModel(const PicoModelKey& key); + CPicoModel(const Str& name); + CPicoModel(const Str& name, const int frame); + CPicoModel(const char *name, const int frame); + ~CPicoModel(); + void CPicoModel::load(const char *name, const int frame); + + void IncRef() + { + ++m_refcount; + } + void DecRef() + { + if(--m_refcount == 0) + delete this; + } + + void AddParent( CPicoParent *parent ); + void RemoveParent( CPicoParent *parent ); + + void Reload( void ); + + void Draw(int state, vector shaders, int rflags) const; + //IRender + virtual void Draw( int state, int rflags ) const; + virtual const aabb_t *GetAABB() const { return &m_BBox; } + + //ISelect + virtual bool TestRay( const ray_t *ray, vec_t *dist ) const; + + int GetNumSurfaces( void ); + char *GetShaderNameForSurface( const unsigned int surf ); + +private: + void AccumulateBBox(); + + char *m_name; + int m_frame; + picoModel_t *m_pModel; + unsigned int m_refcount; + aabb_t m_BBox; + GPtrArray *m_children; // array of CPicoSurface + GPtrArray *m_parents; // array of CPicoParent + + GPtrArray* m_shaders; + + bool m_bReloaded; // managed by CModelManager +}; + +#endif // _CPICOMODEL_H_ diff --git a/plugins/model/cpicosurface.cpp b/plugins/model/cpicosurface.cpp new file mode 100644 index 00000000..f3655246 --- /dev/null +++ b/plugins/model/cpicosurface.cpp @@ -0,0 +1,203 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "cpicosurface.h" + +// public + +CPicoSurface::CPicoSurface(picoSurface_t *pSurface) +{ + refCount = 1; + + m_pSurface = pSurface; + + // PicoFixSurfaceNormals( pSurface ); + + AccumulateBBox(); + + m_shader = QERApp_Shader_ForName(GetShaderName()); +} + +CPicoSurface::~CPicoSurface() +{ + m_shader->DecRef(); +} + +void CPicoSurface::Draw(int state, int rflags) +{ + Draw(state, m_shader, rflags); +} + +void CPicoSurface::Draw(int state, IShader *pShader, int rflags) +{ + int j; + + if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) ) + { + if(state & DRAW_GL_TEXTURE_2D) + { + g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); + if( (rflags & DRAW_RF_CAM) && (pShader->getFlags() & QER_ALPHAFUNC) ) { + int nFunc = 0; + float fRef = 0.f; + + g_QglTable.m_pfn_qglColor4f( 1.f, 1.f, 1.f, 1.f ); // identity + + g_QglTable.m_pfn_qglEnable( GL_ALPHA_TEST ); + + pShader->getAlphaFunc( &nFunc, &fRef ); + g_QglTable.m_pfn_qglAlphaFunc( nFunc, fRef ); + } + } + else + { + //g_QglTable.m_pfn_qglColor3fv( pShader->getTexture()->color ); +/* g_QglTable.m_pfn_qglEnableClientState(GL_COLOR_ARRAY);*/ + } + + if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) ) + { + if( pShader->getCull() == 2 ) + { + g_QglTable.m_pfn_qglDisable( GL_CULL_FACE ); + g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_FILL); + } + else // is 1 + { + g_QglTable.m_pfn_qglCullFace( GL_BACK ); + } + } + } + + switch( PicoGetSurfaceType(m_pSurface) ) + { + case PICO_TRIANGLES: g_QglTable.m_pfn_qglBegin(GL_TRIANGLES); + for (j=0; jgetFlags() & QER_ALPHAFUNC) ) { + g_QglTable.m_pfn_qglDisable( GL_ALPHA_TEST ); + } + +/* if(!(state & DRAW_GL_TEXTURE_2D)) { + g_QglTable.m_pfn_qglDisableClientState(GL_COLOR_ARRAY); + }*/ + + if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) ) + { + if( pShader->getCull() == 2 ) + { + g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_LINE); + g_QglTable.m_pfn_qglEnable( GL_CULL_FACE ); + } + else // is 1 + { + g_QglTable.m_pfn_qglCullFace( GL_FRONT ); + } + } + } +} + +// private + +void CPicoSurface::AccumulateBBox() +{ + int i; + picoVec_t *p; + aabb_clear(&m_BBox); + for (i=0; ishader); + } + +private: + int refCount; + aabb_t m_BBox; + picoSurface_t *m_pSurface; + IShader* m_shader; + + void AccumulateBBox(); // accumulate local bbox.. generally created from control handles +}; diff --git a/plugins/model/miscmodel.cpp b/plugins/model/miscmodel.cpp new file mode 100644 index 00000000..2a37bb54 --- /dev/null +++ b/plugins/model/miscmodel.cpp @@ -0,0 +1,451 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "entitymodel.h" + +extern CModelManager g_model_cache; + +// +// CEntityMiscModel implementation +// + +CEntityMiscModel::CEntityMiscModel () +{ + refCount = 1; + m_name = NULL; + m_model = NULL; + m_entity = NULL; + m_frame = 0; + m_remaps = g_ptr_array_new (); + m_shaders = g_ptr_array_new (); + VectorSet(m_translate, 0,0,0); + VectorSet(m_euler, 0,0,0); + VectorSet(m_scale, 1,1,1); + VectorSet(m_pivot, 0,0,0); + m4x4_identity(m_transform); + m4x4_identity(m_inverse_transform); +} + +typedef struct remap_s { + char m_key[64]; + char m_remapbuff[64+1024]; + char *m_remap[2]; +} remap_t; + +CEntityMiscModel::~CEntityMiscModel () +{ + unsigned int i; + + if(m_name && *m_name != '\0') { + if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) + m_model->RemoveParent( this ); + m_model = NULL; + delete [] m_name; + } + + for( i = 0; i < m_remaps->len; i++ ) + delete (remap_t*)m_remaps->pdata[i]; + g_ptr_array_free(m_remaps, FALSE); + + for( i = 0; i < m_shaders->len; i++ ) + { + (*(IShader**)m_shaders->pdata[i])->DecRef(); + delete (IShader**)m_shaders->pdata[i]; + } + g_ptr_array_free(m_shaders, FALSE); + + if(m_entity) { + // This might be just an evasion of the actual problem + m_entity->model.pRender = NULL; + m_entity->model.pSelect = NULL; + m_entity->model.pEdit = NULL; + } +} + +// IRender + +void CEntityMiscModel::Draw(int state, int rflags) const +{ + m4x4_t matrix; + vec3_t pivot; + + memcpy(matrix, m_transform, sizeof(m4x4_t)); + m4x4_transpose(matrix); + + VectorAdd(m_pivot, m_translate, pivot); + pivot_draw(pivot); + + // push the current modelview matrix + // FIXME: put in a check for stack recursion depth.. + // or avoid recursion of opengl matrix stack + g_QglTable.m_pfn_qglPushMatrix(); + // apply the parent-to-local transform + g_QglTable.m_pfn_qglMultMatrixf(matrix); + + // draw children + if(m_model) + m_model->Draw(state, m_shaders, rflags); + + g_QglTable.m_pfn_qglPopMatrix(); +} + +// ISelect + +bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t dist_start = *dist; + vec_t dist_local = *dist; + ray_t ray_local = *ray; + + if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) + return false; + + if(m_model){ + ray_transform(&ray_local, m_inverse_transform); + dist_local = dist_start; + if(m_model->TestRay(&ray_local, &dist_local)) + *dist = dist_local; + } else *dist = dist_local; + + return *dist < dist_start; +} + + +//IEdit + +void CEntityMiscModel::Translate(const vec3_t translation) +{ + VectorIncrement(translation, m_translate); + UpdateCachedData(); +} + +void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation) +{ + m4x4_t rotation_matrix; + + m4x4_identity(rotation_matrix); + m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, pivot); + m4x4_transform_point(rotation_matrix, m_translate); + + VectorIncrement(rotation, m_euler); + + UpdateCachedData(); +} + +void CEntityMiscModel::OnKeyChanged(entity_t *e, const char *key) +{ + const char *value; + + // FIXME: keys are case-sensitive? + + m_entity = e; + + if(strcmp(key,"model") == 0) + SetName(ValueForKey(e,"model")); + else if(strcmp(key,"_frame") == 0) + SetFrame(IntForKey(e,"_frame")); + else if(strcmp(key,"angle") == 0 || strcmp(key,"angles") == 0) + { + VectorSet(m_euler, 0.f, 0.f, 0.f); + m_euler[2] = FloatForKey(e,"angle"); + value = ValueForKey(e,"angles"); + if (value[0] != '\0') + sscanf (value, "%f %f %f", &m_euler[0], &m_euler[2], &m_euler[1]); + UpdateCachedData(); + } + else if(strcmp(key,"modelscale") == 0 || strcmp(key,"modelscale_vec") == 0) + { + VectorSet(m_scale, 1.f, 1.f, 1.f); + value = ValueForKey(e,"modelscale"); + if (value[0] != '\0') + { + float f = atof(value); + if( f != 0 ) + VectorSet(m_scale, f, f, f); + else + Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n"); + } + value = ValueForKey(e,"modelscale_vec"); + if (value[0] != '\0') + { + sscanf (value, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]); + if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0) + { + VectorSet(m_scale, 1,1,1); + Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n"); + } + } + UpdateCachedData(); + } + else if(strcmp(key,"origin") == 0) + { + value = ValueForKey(e,"origin"); + sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); + UpdateCachedData(); + } + else if(strncmp(key,"_remap",6) == 0) + { + unsigned int i; + remap_t *pRemap; + char *ch; + + value = ValueForKey(e,key); + + for(i=0; ilen; i++) + { + pRemap = (remap_t*)m_remaps->pdata[i]; + if(strcmp(key,pRemap->m_key) == 0) + break; + } + + if( i == m_remaps->len ) + { + if( value[0] == '\0' ) + return; + + pRemap = new remap_t; + g_ptr_array_add(m_remaps, pRemap); + } + else if( value[0] == '\0' ) + { + g_ptr_array_remove_index_fast(m_remaps, i); + delete pRemap; + + UpdateShaders(); + return; + } + + strncpy(pRemap->m_remapbuff,value,sizeof(pRemap->m_remapbuff)); + strncpy(pRemap->m_key,key,sizeof(pRemap->m_key)); + + pRemap->m_remap[0] = ch = pRemap->m_remapbuff; + + while( *ch && *ch != ';' ) + ch++; + + if( *ch == '\0' ) + { + // bad remap + Sys_FPrintf(SYS_WRN, "WARNING: Shader _remap key found in misc_model without a ; character\n" ); + g_ptr_array_remove_index_fast(m_remaps, i); + delete pRemap; + return; + } + else + { + *ch = '\0'; + pRemap->m_remap[1] = ch + 1; + } + + UpdateShaders(); + } +} + +// +// CEntityMiscModel +// + +// private: + +void CEntityMiscModel::SetName(const char *name) +{ + if(m_name && *m_name != '\0') { + if(strcmp(m_name, name) == 0) + return; + if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) + m_model->RemoveParent( this ); + delete [] m_name; + } + + m_model = NULL; + m_name = new char[strlen(name)+1]; + strcpy(m_name,name); + + if(*m_name != '\0') { + m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame); + m_model->AddParent( this ); + } + + UpdateCachedData(); + UpdateShaders(); +} + +void CEntityMiscModel::SetFrame(const int frame) +{ + if( m_frame == frame ) + return; + + if(m_name && *m_name != '\0') { + if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) + m_model->RemoveParent( this ); + } + + m_model = NULL; + + m_frame = frame; + + if(*m_name != '\0') { + m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame); + m_model->AddParent( this ); + } + + UpdateCachedData(); +} + +void CEntityMiscModel::UpdateCachedData() +{ + aabb_t aabb_temp; + bbox_t bbox_temp; + + m4x4_identity(m_transform); + m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, m_scale, m_pivot); + memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); + if(m4x4_invert(m_inverse_transform) == 1) { + Sys_Printf("ERROR: Singular Matrix, cannot invert"); + } + + aabb_clear(&aabb_temp); + + if(m_model) + aabb_extend_by_aabb(&aabb_temp, m_model->GetAABB()); + else + { + if (m_entity->eclass) + VectorSet(aabb_temp.extents, m_entity->eclass->maxs[0], m_entity->eclass->maxs[1], m_entity->eclass->maxs[2]); + else + VectorSet(aabb_temp.extents, 8, 8, 8); + } + + // create an oriented BBox in world-space + bbox_for_oriented_aabb(&bbox_temp, &aabb_temp, m_transform, m_euler, m_scale); + // create an axis aligned bbox in world-space + aabb_for_bbox(&m_BBox, &bbox_temp); + + aabb_update_radius(&m_BBox); +} + +void CEntityMiscModel::UpdateShaders() +{ + unsigned int i, j, numSurfaces; + remap_t *pRemap, *pGlobRemap = NULL; + char *surfShaderName; + IShader **pShader; + + if( !m_model ) + { + if( m_shaders->len ) + { + // free our shaders + for( i = 0; i < m_shaders->len; i++ ) + { + g_ptr_array_remove_index_fast(m_shaders, i); + (*(IShader**)m_shaders->pdata[i])->DecRef(); + delete (IShader**)m_shaders->pdata[i]; + } + } + return; + } + + numSurfaces = m_model->GetNumSurfaces(); + + if( numSurfaces < m_shaders->len ) + { + // free unneeded shader pointers + for( i = m_shaders->len - 1; i >= numSurfaces; i-- ) + { + g_ptr_array_remove_index_fast(m_shaders, i); + (*(IShader**)m_shaders->pdata[i])->DecRef(); + delete (IShader**)m_shaders->pdata[i]; + } + } + + // now go through our surface and find our shaders, remap if needed + for( j = 0; j < numSurfaces; j++ ) + { + surfShaderName = m_model->GetShaderNameForSurface(j); + + if( j < m_shaders->len ) + { + pShader = (IShader **)m_shaders->pdata[j]; + } + else + { + pShader = new (IShader *); + *pShader = NULL; + g_ptr_array_add(m_shaders, pShader); + } + + if( m_remaps->len ) + { + for( i = 0; i < m_remaps->len; i++ ) + { + pRemap = (remap_t*)m_remaps->pdata[i]; + if( stricmp(pRemap->m_remap[0],surfShaderName) == 0 ) + { + // only do the shader lookups if really needed + if( !(*pShader) || stricmp(pRemap->m_remap[1],(*pShader)->getName()) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(pRemap->m_remap[1]); + } + + pGlobRemap = NULL; + break; + } + else if( pRemap->m_remap[0][0] == '*' && pRemap->m_remap[0][1] == '\0' ) + pGlobRemap = pRemap; + } + + if( pGlobRemap ) + { + if( !(*pShader) || stricmp(pGlobRemap->m_remap[1],(*pShader)->getName()) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(pGlobRemap->m_remap[1]); + } + } + else if( i == m_remaps->len ) + { + // Back to the default one, if needed + if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(surfShaderName); + } + } + } + else + { + // Model specified shader, if needed + if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(surfShaderName); + } + } + } +} diff --git a/plugins/model/model.cpp b/plugins/model/model.cpp new file mode 100644 index 00000000..70ea078c --- /dev/null +++ b/plugins/model/model.cpp @@ -0,0 +1,88 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "plugin.h" +#include "picomodel.h" + +void pivot_draw(const vec3_t pivot) +{ + vec3_t vCenter, vMin, vMax; + VectorCopy(pivot, vCenter); + + g_QglTable.m_pfn_qglPointSize(4); + + g_QglTable.m_pfn_qglBegin(GL_POINTS); + g_QglTable.m_pfn_qglVertex3fv(vCenter); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINES); + vCenter[0] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[0] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[0] -= 8; + vCenter[1] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[1] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[1] -= 8; + vCenter[2] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[2] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[2] -= 8; + g_QglTable.m_pfn_qglEnd(); + + VectorCopy(vCenter, vMin); + VectorCopy(vCenter, vMax); + vMin[0] -= 4; + vMin[1] -= 4; + vMin[2] -= 4; + vMax[0] += 4; + vMax[1] += 4; + vMax[2] += 4; + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINES); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglEnd(); +} + diff --git a/plugins/model/model.def b/plugins/model/model.def new file mode 100644 index 00000000..fc23bd28 --- /dev/null +++ b/plugins/model/model.def @@ -0,0 +1,8 @@ +; model.def : Declares the module parameters for the DLL. + +LIBRARY "MODEL" +DESCRIPTION 'MODEL Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 \ No newline at end of file diff --git a/plugins/model/model.vcproj b/plugins/model/model.vcproj new file mode 100644 index 00000000..217912e9 --- /dev/null +++ b/plugins/model/model.vcproj @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/model/plugin.cpp b/plugins/model/plugin.cpp new file mode 100644 index 00000000..dc5da485 --- /dev/null +++ b/plugins/model/plugin.cpp @@ -0,0 +1,429 @@ + +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "plugin.h" + +#if 0 // stop using windowing systems in plugins - put the text in SynapseClient::GetInfo +// ============================================================================= +// Utility functions +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +int DoAboutBox( GtkWidget *parent ) +{ + GtkWidget *window, *w, *text, *vbox, *hbox, *hbox2, *frame; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + int ret, loop = 1; + char buf[2048]; + const picoModule_t **modules, *pm; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), "About..."); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent)); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + style = gtk_widget_get_style(window); + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + frame = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, FALSE, 2); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_widget_show (frame); + + if( g_FuncTable.m_pfnLoadBitmap( "picomodel.bmp", (void **)&pixmap, (void **)&mask ) ) { + w = gtk_pixmap_new (pixmap, mask); + gtk_container_add (GTK_CONTAINER (frame), w); + gtk_widget_show (w); + } + + w = gtk_label_new ("Model Module v1.0 for GtkRadiant\nby Arnout van Meer (rr2do2@splashdamage.com)\n\nBased on the MD3Model Module by SPoG\nPicoModel Library Copyright (c) 2002, Randy Reddig & seaw0lf" ); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(vbox), w, TRUE, TRUE, 2); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_widget_show(w); + + text = gtk_text_new(NULL, NULL); + gtk_text_set_editable(GTK_TEXT(text), FALSE); + gtk_container_add(GTK_CONTAINER(w), text); + + strcpy( buf, "#Supported Model Formats:\n" ); + gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1); + + for( modules = PicoModuleList( NULL ); *modules != NULL; modules++ ) + { + pm = *modules; + + if( pm == NULL) + break; + + sprintf( buf, "\n%s, version %s, (c) %s", pm->displayName, pm->version, pm->copyright ); + gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1); + } + + gtk_text_set_word_wrap(GTK_TEXT(text), FALSE); + gtk_widget_show(text); + + gtk_text_set_point(GTK_TEXT(text), 0); + gtk_text_forward_delete(GTK_TEXT(text), 1); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} +#endif + +// toolbar implementation + +class CFlushReloadSelectedToolbarButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + return "model_reload_entity.bmp"; + } + virtual const char* getText() const + { + return "Reload"; + } + virtual const char* getTooltip() const + { + return "Flush & Reload Selected Model"; + } + virtual void activate() const + { + DoFlushReloadSelected(); + } + virtual EType getType() const + { + return eButton; + } +}; + +CFlushReloadSelectedToolbarButton g_flushreloadselected; + +unsigned int ToolbarButtonCount() +{ + return 1; +} + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + return &g_flushreloadselected; +} + +// ============================================================================= +// Pico utility functions + +#include "picomodel.h" + +void PicoPrintFunc( int level, const char *str ) +{ + if( str == NULL ) + return; + switch( level ) + { + case PICO_NORMAL: + Sys_Printf( "%s\n", str ); + break; + + case PICO_VERBOSE: + Sys_FPrintf( SYS_VRB, "%s\n", str ); + break; + + case PICO_WARNING: + Sys_Printf( "WARNING: %s\n", str ); + break; + + case PICO_ERROR: + Sys_FPrintf( SYS_VRB, "ERROR: %s\n", str ); + break; + + case PICO_FATAL: + Sys_Printf( "ERROR: %s\n", str ); + break; + } +} + +void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ) +{ + *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 ); +} + +void PicoFreeFileFunc( void* file ) +{ + vfsFreeFile(file); +} + +static void initialise() +{ + PicoInit(); + PicoSetMallocFunc( malloc ); + PicoSetFreeFunc( free ); + PicoSetPrintFunc( PicoPrintFunc ); + PicoSetLoadFileFunc( PicoLoadFileFunc ); + PicoSetFreeFileFunc( PicoFreeFileFunc ); +} + +static void add_model_apis(CSynapseClient& client) +{ + const picoModule_t** modules = PicoModuleList( NULL ); + while(*modules != NULL) + { + const picoModule_t* module = *modules++; + if(module->canload && module->load) + for(unsigned int j = 0; module->defaultExts[j] != NULL; j++) + client.AddAPI(MODEL_MAJOR, module->defaultExts[j], sizeof(_QERPlugModelTable)); + } +} + +static bool model_is_supported(const char* extension) +{ + const picoModule_t** modules = PicoModuleList( NULL ); + while(*modules != NULL) + { + const picoModule_t* module = *modules++; + if(module->canload && module->load) + for(unsigned int j = 0; module->defaultExts[j] != NULL; j++) + if(strcmp(extension, module->defaultExts[j]) == 0) + return true; + } + return false; +} + +void init_filetypes() +{ + const picoModule_t **modules = PicoModuleList(NULL); + while(*modules != NULL) + { + const picoModule_t* module = *modules++; + if(module->canload && module->load) + { + for(char*const* ext = module->defaultExts; *ext != NULL; ++ext) + { + char buf[16]; + buf[0] = '*'; + buf[1] = '.'; + strcpy(buf+2, *ext); + GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t(module->displayName, buf)); + } + } + } +} + +// plugin implementation + +static const char *PLUGIN_NAME = "Model loading module"; +static const char *PLUGIN_COMMANDS = "Flush & Reload Models,Flush & Reload Selected"; +static const char *PLUGIN_ABOUT = "Model loading module"; + +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + init_filetypes(); + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetName () +{ + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList () +{ + return (char *) PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + if( !strcmp( p, "Flush & Reload Selected" ) ) + DoFlushReloadSelected(); + else if( !strcmp( p, "Flush & Reload Models" ) ) + DoFlushReloadAll(); +} + + +void DoFlushReloadSelected() { +} + +void DoFlushReloadAll() { + GetModelCache()->RefreshAll(); +} + +// ============================================================================= + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERShadersTable g_ShadersTable; +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientModel g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf( g_pSynapseServer->Get_Syn_Printf() ); + + initialise(); + + add_model_apis(g_SynapseClient); + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "model", sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "model", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + return &g_SynapseClient; +} + +bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, MODEL_MAJOR)) + { + _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable); + + if (model_is_supported(pAPI->minor_name)) + { + pTable->m_pfnLoadModel = &LoadModel; + return true; + } + } + else if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientModel::GetInfo() +{ + return "picomodel loader module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientModel::GetName() +{ + return "model"; +} diff --git a/plugins/model/plugin.h b/plugins/model/plugin.h new file mode 100644 index 00000000..06158646 --- /dev/null +++ b/plugins/model/plugin.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/*! +\todo need general notice about lib purpose etc. +and the external dependencies (such as GLib, STL, mathlib etc.) +*/ + +/*! +\todo not sure about what should be used for common data structures, GLib or STL +I think STL would be better since I intend on using STL in synapse +*/ + +#include + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "imodel.h" +#include "igl.h" +#include "ifilesystem.h" +#include "ishaders.h" +#include "itoolbar.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERShadersTable g_ShadersTable; +extern _QERFileSystemTable g_FileSystemTable; + +#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile +#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile +#define vfsBasePromptPath g_FileSystemTable.m_pfnBasePromptPath +#define QERApp_Shader_ForName g_ShadersTable.m_pfnShader_ForName + +void DoFlushReloadSelected(); +void DoFlushReloadAll(); + +void LoadModel(entity_interfaces_t *model, const char *name); + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientModel : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientModel() { } + virtual ~CSynapseClientModel() { } +}; + +#endif // _PLUGIN_H_ diff --git a/plugins/model/remap.cpp b/plugins/model/remap.cpp new file mode 100644 index 00000000..dbcef14f --- /dev/null +++ b/plugins/model/remap.cpp @@ -0,0 +1,318 @@ + +#include "cpicomodel.h" +#include "qertypes.h" + +#include +#include + +#define RADIANT_ASSERT(condition, message) if(!(condition)) { Sys_Printf("ASSERTION FAILURE: " message "\n"); } else + +template +class cache_element +{ +public: + inline cache_element() : m_count(0), m_value(NULL) {} + inline ~cache_element() + { + RADIANT_ASSERT(m_count == 0 , "destroyed a reference before it was released\n"); + if(m_count > 0) + destroy(); + } + inline value_type* capture(const key_type& key) + { + if(++m_count == 1) + construct(key); + return m_value; + } + inline void release() + { + RADIANT_ASSERT(!empty(), "failed to release reference - not found in cache\n"); + if(--m_count == 0) + destroy(); + } + inline bool empty() + { + return m_count == 0; + } + inline void refresh(const key_type& key) + { + m_value->refresh(key); + } +private: + inline void construct(const key_type& key) + { + m_value = new value_type(key); + } + inline void destroy() + { + delete m_value; + } + + unsigned int m_count; + value_type* m_value; +}; + +class ModelCache +{ + typedef CPicoModel value_type; + +public: + typedef PicoModelKey key_type; + typedef cache_element elem_type; + typedef map cache_type; + + value_type* capture(const key_type& key) + { + return m_cache[key].capture(key); + } + void release(const key_type& key) + { + m_cache[key].release(); + } + +private: + cache_type m_cache; +}; + +ModelCache g_model_cache; + + + +typedef struct remap_s { + char m_remapbuff[64+1024]; + char *original; + char *remap; +} remap_t; + +class RemapWrapper : public IRender, public ISelect +{ + unsigned int m_refcount; +public: + RemapWrapper(entity_interfaces_t* model, const char* name) + : m_refcount(1) + { + parse_namestr(name); + + m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), m_frame)); + + model->pRender = this; + model->pRender->IncRef(); + model->pEdit = NULL; + model->pSelect = this; + model->pSelect->IncRef(); + + construct_shaders(); + } + virtual ~RemapWrapper() + { + g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), m_frame)); + + for(shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) { + (*i)->DecRef(); + } + + for(remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j) + { + remap_t *pRemap = (*j); + delete pRemap; + } + m_remaps.clear(); + } + virtual void IncRef() + { + ++m_refcount; + } + virtual void DecRef() + { + if(--m_refcount == 0) + delete this; + } + virtual void Draw(int state, int rflags) const + { + m_model->Draw(state, m_shaders, rflags); + } + virtual const aabb_t *GetAABB() const + { + return m_model->GetAABB(); + } + virtual bool TestRay(const ray_t *ray, vec_t *dist) const + { + return m_model->TestRay(ray, dist); + } +private: + void add_remap(const char *remap) + { + const char *ch; + remap_t *pRemap; + + ch = remap; + + while( *ch && *ch != ';' ) + ch++; + + if( *ch == '\0' ) { + // bad remap + Sys_FPrintf( SYS_WRN, "WARNING: Shader _remap key found in a model entity without a ; character\n" ); + } else { + pRemap = new remap_t; + + strncpy( pRemap->m_remapbuff, remap, sizeof(pRemap->m_remapbuff) ); + + pRemap->m_remapbuff[ch - remap] = '\0'; + + pRemap->original = pRemap->m_remapbuff; + pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1; + + m_remaps.push_back( pRemap ); + } + } + + void parse_namestr(const char *name) + { + const char *ptr, *s; + char buf[1024]; + bool hasName, hasFrame; + + hasName = hasFrame = false; + + for( s = ptr = name; *ptr; ptr++ ) { + if( !hasName && *ptr == ':' ) { + // model name + hasName = true; + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + m_name = buf; + s = ptr + 1; + } else if( *ptr == '?' ) { + // model frame + hasFrame = true; + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + m_frame = atoi(buf); + s = ptr + 1; + } else if( *ptr == '&' ) { + // a remap + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + add_remap( buf ); + s = ptr + 1; + } + } + + if( !hasFrame ) { + // model frame + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + m_frame = atoi(buf); + } else { + // a remap + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + add_remap( buf ); + } + } + + void construct_shaders() + { + IShader* global_shader = shader_for_remap("*"); + + unsigned int numSurfaces = m_model->GetNumSurfaces(); + m_shaders.reserve(numSurfaces); + // now go through our surface and find our shaders, remap if needed + for(unsigned int j = 0; j < numSurfaces; j++ ) + { + const char* surfShaderName = m_model->GetShaderNameForSurface(j); + IShader* shader = shader_for_remap(surfShaderName); +// m_shaders.push_back((shader) ? shader : (global_shader) ? global_shader : QERApp_Shader_ForName(surfShaderName)); + if( shader ) { + m_shaders.push_back(shader); + } else if( global_shader ) { + m_shaders.push_back(global_shader); + } else { + m_shaders.push_back(QERApp_Shader_ForName(surfShaderName)); + } + } + } + + inline IShader* shader_for_remap(const char* remap) + { + remap_t *pRemap; + remaps_t::iterator i; + for(i = m_remaps.begin(); i != m_remaps.end(); ++i) + { + pRemap = (*i); + if( stricmp( remap, pRemap->original ) == 0 ) + break; + } + return (i != m_remaps.end()) ? QERApp_Shader_ForName(pRemap->remap) : NULL; + } + + Str m_name; + int m_frame; + CPicoModel* m_model; + + typedef vector remaps_t; + remaps_t m_remaps; + typedef vector shaders_t; + shaders_t m_shaders; +}; + +class ModelWrapper : public IRender, public ISelect +{ + unsigned int m_refcount; +public: + ModelWrapper(entity_interfaces_t* model, const char* name) + : m_refcount(1), m_name(name) + { + m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), 0)); + + model->pRender = this; + model->pRender->IncRef(); + model->pEdit = NULL; + model->pSelect = this; + model->pSelect->IncRef(); + } + virtual ~ModelWrapper() + { + g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), 0)); + } + + virtual void IncRef() + { + ++m_refcount; + } + virtual void DecRef() + { + if(--m_refcount == 0) + delete this; + } + virtual void Draw(int state, int rflags) const + { + m_model->Draw(state, rflags); + } + virtual const aabb_t *GetAABB() const + { + return m_model->GetAABB(); + } + virtual bool TestRay(const ray_t *ray, vec_t *dist) const + { + return m_model->TestRay(ray, dist); + } + + Str m_name; + CPicoModel* m_model; +}; + +void LoadModel(entity_interfaces_t* model, const char* name) +{ + if(strchr(name, ':') != NULL || strchr(name, '?') != NULL || strchr(name, '&') != NULL) + { + RemapWrapper* wrapper = new RemapWrapper(model, name); + wrapper->DecRef(); + } + else + { + ModelWrapper* wrapper = new ModelWrapper(model, name); + wrapper->DecRef(); + } +} diff --git a/plugins/model/surface.h b/plugins/model/surface.h new file mode 100644 index 00000000..33c5d2f7 --- /dev/null +++ b/plugins/model/surface.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +class CSurface : public ISurface +{ +public: + CSurface() { refCount = 0; aabb_clear(&m_BBox); m_pShader = NULL; } + ~CSurface() { if(m_pShader != NULL) m_pShader->DecRef(); } + void IncRef() { refCount++; } + void DecRef() { if ( --refCount <= 0 ) delete this; } + + const aabb_t *getBBox() const { return &m_BBox; } + IShader *getShader() const { return m_pShader; } + void setShader(const char *name) { if (getShader()) getShader()->DecRef(); m_pShader = QERApp_Shader_ForName(name); getShader()->IncRef(); } + +protected: + int refCount; + aabb_t m_BBox; + IShader *m_pShader; +}; \ No newline at end of file diff --git a/plugins/shaders/plugin.cpp b/plugins/shaders/plugin.cpp new file mode 100644 index 00000000..70af41bd --- /dev/null +++ b/plugins/shaders/plugin.cpp @@ -0,0 +1,98 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Shaders Plugin +// + +#include "plugin.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERAppDataTable g_DataTable; +_QERQglTable g_QglTable; +_QERAppShadersTable g_ShadersTable; +_QERFileSystemTable g_VFSTable; +_QERScripLibTable g_ScripLibTable; +_QERBrushTable g_BrushTable; + +static bool g_bInterfaceInitDone = false; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientShaders g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { + { SHADERS_MAJOR, SYN_PROVIDE, sizeof(_QERShadersTable), NULL }, + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_VFSTable), &g_VFSTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_DataTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(_QERScripLibTable), SYN_REQUIRE, &g_ScripLibTable); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(_QERBrushTable), SYN_REQUIRE, &g_BrushTable); + + return &g_SynapseClient; +} + +#include "version.h" + +const char* CSynapseClientShaders::GetInfo() +{ + return "Q3/Half-Life shaders module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientShaders::GetName() +{ + return "shaders"; +} diff --git a/plugins/shaders/plugin.h b/plugins/shaders/plugin.h new file mode 100644 index 00000000..6a4a547d --- /dev/null +++ b/plugins/shaders/plugin.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 "synapse.h" +#include "qerplugin.h" +#include "missing.h" +#include "igl.h" +#include "ishaders.h" +#include "idata.h" +#include "ifilesystem.h" +#include "iscriplib.h" +#define USE_BRUSHTABLE_DEFINE +#include "ibrush.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERAppDataTable g_DataTable; +extern _QERQglTable g_QglTable; +extern _QERAppShadersTable g_ShadersTable; +extern _QERFileSystemTable g_VFSTable; +extern _QERScripLibTable g_ScripLibTable; +extern _QERBrushTable g_BrushTable; + +#define vfsGetFileCount g_VFSTable.m_pfnGetFileCount +#define vfsLoadFile g_VFSTable.m_pfnLoadFile +#define vfsFreeFile g_VFSTable.m_pfnFreeFile +#define Sys_Printf g_FuncTable.m_pfnSysPrintf + +class CSynapseClientShaders : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientShaders() { } + virtual ~CSynapseClientShaders() { } +}; + +#endif // _PLUGIN_H_ diff --git a/plugins/shaders/shaders.cpp b/plugins/shaders/shaders.cpp new file mode 100644 index 00000000..b151c505 --- /dev/null +++ b/plugins/shaders/shaders.cpp @@ -0,0 +1,989 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Shaders Manager Plugin +// +// Leonardo Zide (leo@lokigames.com) +// + +// standard headers +#include +#include +#include "plugin.h" +#include "mathlib.h" +#include "missing.h" //++timo FIXME: this one is intended to go away some day, it's MFC compatibility classes +#include "shaders.h" + +// some forward declarations +IShader *WINAPI QERApp_Shader_ForName (const char *name); +qtexture_t *WINAPI QERApp_Try_Texture_ForName (const char *name); +qtexture_t *WINAPI QERApp_Texture_ForName2 (const char *filename); +IShader *WINAPI QERApp_ColorShader_ForName (const char *name); +void WINAPI QERApp_LoadShaderFile (const char *filename); + +//++timo TODO: use stl::map !! (I tried having a look to CMap but it obviously sucks) +CShaderArray g_Shaders; +// whenever a shader gets activated / deactivated this list is updated +// NOTE: make sure you don't add a shader that's already in +// NOTE: all shaders in this array are in the main g_Shaders +CShaderArray g_ActiveShaders; + +// clean a texture name to the qtexture_t name format we use internally +// NOTE: there are so many cases .. this may need to get updated to cover all of them +// we expect a "textures/" path on top, except if bAddTexture is set to true .. in case we add in needed +// NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case +// information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name, +// we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive. +//++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present +const char *WINAPI QERApp_CleanTextureName (const char *name, bool bAddTexture = false) +{ + static char stdName[QER_MAX_NAMELEN]; +#ifdef _DEBUG + if (strlen(name)>QER_MAX_NAMELEN) + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "WARNING: name exceeds QER_MAX_NAMELEN in CleanTextureName\n"); +#endif + + strcpy (stdName, name); + g_FuncTable.m_pfnQE_ConvertDOSToUnixName (stdName, stdName); + if (stdName[strlen (name) - 4] == '.') + // strip extension + stdName[strlen (stdName) - 4] = '\0'; + + if (bAddTexture) + { + char aux[QER_MAX_NAMELEN]; + sprintf (aux, "textures/%s", stdName); + strcpy (stdName, aux); + } + return stdName; +} + +int WINAPI QERApp_GetActiveShaderCount () +{ + return g_ActiveShaders.GetSize (); +} + +IShader *WINAPI QERApp_ActiveShader_ForIndex (int i) +{ + return static_cast < CShader * >(g_ActiveShaders.GetAt (i)); +} + +void CShaderArray::SortShaders () +{ + CPtrArray aux; + int i, icount; + int j, jcount; + CShader *pSort; + const char *sSort; + // dumb sort .. would it ever grow big enough so we would have to do something clever? noooo + icount = CPtrArray::GetSize (); + for (i = 0; i < icount; i++) + { + pSort = static_cast < CShader * >(GetAt (i)); + sSort = pSort->getName (); + jcount = aux.GetSize (); + for (j = 0; j < jcount; j++) + { + if (strcmp (sSort, static_cast < CShader * >(aux.GetAt (j))->getName ()) < 0) + break; + } + aux.InsertAt (j, pSort); + } + CPtrArray::RemoveAll (); + CPtrArray::InsertAt (0, &aux); +} + +// will sort the active shaders list by name +// NOTE: it would be easier if the thing would stay sorted by using a map thing +//++timo FIXME: would need to export that to allow external override? +void WINAPI QERApp_SortActiveShaders () +{ + g_ActiveShaders.SortShaders (); +} + +// NOTE: case sensitivity +// although we store shader names with case information, Radiant does case insensitive searches +// (we assume there's no case conflict with the names) +CShader *CShaderArray::Shader_ForName (const char *name) const +{ + int i; + for (i = 0; i < CPtrArray::GetSize (); i++) + { + CShader *pShader = static_cast < CShader * >(CPtrArray::GetAt (i)); + if (stricmp (pShader->getName (), name) == 0) + return pShader; + } + return NULL; +} + +void CShader::CreateDefault (const char *name) +{ + const char *stdName = QERApp_CleanTextureName (name); + m_strTextureName = stdName; + setName (name); +} + +CShader *CShaderArray::Shader_ForTextureName (const char *name) const +{ +#ifdef _DEBUG + // check we were given a texture name that fits the qtexture_t naming conventions + if (strcmp (name, QERApp_CleanTextureName (name)) != 0) + Sys_Printf + ("WARNING: texture name %s doesn't fit qtexture_t conventions in CShaderArray::Shader_ForTextureName\n", + name); +#endif + int i; + for (i = 0; i < CPtrArray::GetSize (); i++) + { + CShader *pShader = static_cast < CShader * >(CPtrArray::GetAt (i)); + if (strcmp (name, QERApp_CleanTextureName (pShader->getTextureName ())) == 0) + return pShader; + } + return NULL; +} + +IShader *WINAPI QERApp_ActiveShader_ForTextureName (char *name) +{ + return g_ActiveShaders.Shader_ForTextureName (name); +} + +void CShaderArray::AddSingle (void *lp) +{ + int i; + for (i = 0; i < CPtrArray::GetSize (); i++) + { + if (CPtrArray::GetAt (i) == lp) + return; + } + CPtrArray::Add (lp); + static_cast < CShader * >(CPtrArray::GetAt (i))->IncRef(); +} + +void CShaderArray::operator = (const class CShaderArray & src) +{ + int i; + +#ifdef _DEBUG + if (CPtrArray::GetSize () != 0) + Sys_Printf ("WARNING: CShaderArray::operator = expects an empty array\n"); +#endif + Copy (src); + // now go through and IncRef + for (i = 0; i < CPtrArray::GetSize (); i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->IncRef (); +} + +//++timo NOTE: for debugging we may need to keep track and tell wether everything has been properly unloaded +void CShaderArray::ReleaseAll () +{ + int i; + int count = CPtrArray::GetSize (); + // decref + for (i = 0; i < count; i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->DecRef (); + // get rid + CPtrArray::RemoveAll (); +} + +// NOTE TTimo: +// this was hacked to work a long time ago +// in Loki's fenris tracker as bug #104655 +// since that info is no longer available, and the hack has been there for so long, it's part of the code now +// don't remember the details, but basically across a flush and reload for the shaders +// we have to keep track of the patches texture names in a seperate entry +// not sure why anymore, but I know that doesn't happen with brushes +typedef struct patchEntry_s +{ + char name[QER_MAX_NAMELEN]; + patchMesh_t *p; +} patchEntry_t; + +CPtrArray PatchShaders; + +void PushPatch (patchMesh_t * patch) +{ + patchEntry_t *pEntry = new patchEntry_s; + pEntry->p = patch; + strcpy (pEntry->name, patch->pShader->getName ()); + PatchShaders.Add (pEntry); +} + +char *ShaderNameLookup (patchMesh_t * patch) +{ + int i; + int count = PatchShaders.GetSize (); + for (i = 0; i < count; i++) + { + if (static_cast < patchEntry_t * >(PatchShaders.GetAt (i))->p == patch) + return static_cast < patchEntry_t * >(PatchShaders.GetAt (i))->name; + } + Sys_Printf ("ERROR: failed to lookup name in ShaderNameLookup??\n"); + return SHADER_NOT_FOUND; +} +//++timo end clean + +// will free all GL binded qtextures and shaders +// NOTE: doesn't make much sense out of Radiant exit or called during a reload +void WINAPI QERApp_FreeShaders () +{ + int i; + brush_t *b; + brush_t *active_brushes; + brush_t *selected_brushes; + brush_t *filtered_brushes; + qtexture_t **d_qtextures; + + active_brushes = g_DataTable.m_pfnActiveBrushes (); + selected_brushes = g_DataTable.m_pfnSelectedBrushes (); + filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); + d_qtextures = g_ShadersTable.m_pfnQTextures (); + + // store the shader names used by the patches + for (i = 0; i < PatchShaders.GetSize (); i++) + delete static_cast < patchMesh_t * >(PatchShaders.GetAt (i)); + PatchShaders.RemoveAll (); + + for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) + { + if (b->patchBrush) + PushPatch (b->pPatch); + } + for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) + { + if (b->patchBrush) + PushPatch (b->pPatch); + } + for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) + { + if (b->patchBrush) + PushPatch (b->pPatch); + } + + // reload shaders + // empty the actives shaders list + g_ActiveShaders.ReleaseAll (); + g_Shaders.ReleaseAll (); + // empty the main g_qeglobals.d_qtextures list + // FIXME: when we reload later on, we need to have the shader names + // for brushes it's stored in the texdef + // but patches don't have texdef + // see bug 104655 for details + // so the solution, build an array of patchMesh_t* and their shader names +#ifdef _DEBUG + Sys_Printf ("FIXME: patch shader reload workaround (old fenris? bug 104655)\n"); +#endif + + //GtkWidget *widget = g_QglTable.m_pfn_GetQeglobalsGLWidget (); + GHashTable *texmap = g_ShadersTable.m_pfnQTexmap (); + + // NOTE: maybe before we'd like to set all qtexture_t in the shaders list to notex? + // NOTE: maybe there are some qtexture_t we don't want to erase? For plain color faces maybe? + while (*d_qtextures) + { + qtexture_t *pTex = *d_qtextures; + qtexture_t *pNextTex = pTex->next; + + //if (widget != NULL) + g_QglTable.m_pfn_qglDeleteTextures (1, &pTex->texture_number); + + g_hash_table_remove (texmap, pTex->name); + + // all qtexture_t should be manipulated with the glib alloc handlers for now + g_free (pTex); + *d_qtextures = pNextTex; + } + + g_QglTable.m_pfn_QE_CheckOpenGLForErrors (); +} + +// those functions are only used during a shader reload phase +// the patch one relies on ShaderNameLookup, a table that is being built only when a flush is performed +// so it's not something we want to expose publicly + +void SetShader (patchMesh_t * patch) +{ + // unhook current shader + patch->pShader->DecRef(); + // don't access this one! it has been deleted .. it's DEAD + patch->d_texture = NULL; + // hook the new one, increment the refcount + // NOTE TTimo this function increments the refcount, don't incref ourselves + patch->pShader = QERApp_Shader_ForName (ShaderNameLookup (patch)); + patch->d_texture = patch->pShader->getTexture (); +} + +void SetShader (face_t * f) +{ + // unhook current shader + f->pShader->DecRef(); + // don't access the texdef! it's DEAD + f->d_texture = NULL; + // hook + // NOTE TTimo this function increments the refcount, don't incref ourselves + f->pShader = QERApp_Shader_ForName (f->texdef.GetName()); + f->d_texture = f->pShader->getTexture (); +} + +void Brush_RefreshShader(brush_t *b) +{ + if (b->patchBrush) + SetShader(b->pPatch); + else if (b->owner->eclass->fixedsize) + { + /*eclass_t *eclass = HasModel(b); + if (eclass) + { + for(entitymodel *model = eclass->model; model!=NULL; model=model->pNext) + if(model && model->strSkin) + model->nTextureBind = g_FuncTable.m_pfnTexture_LoadSkin(((GString *)model->strSkin)->str, &model->nSkinWidth, &model->nSkinHeight); + }*/ + } + else + for (face_t *f=b->brush_faces ; f ; f=f->next) + SetShader(f); +} + +void WINAPI QERApp_ReloadShaders () +{ + brush_t *b; + brush_t *active_brushes; + brush_t *selected_brushes; + brush_t *filtered_brushes; + + QERApp_FreeShaders (); + + g_DataTable.m_pfnLstSkinCache()->RemoveAll(); //md3 skins + + active_brushes = g_DataTable.m_pfnActiveBrushes (); + selected_brushes = g_DataTable.m_pfnSelectedBrushes (); + filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); + + // now we must reload the shader information from shaderfiles + g_ShadersTable.m_pfnBuildShaderList(); + g_ShadersTable.m_pfnPreloadShaders(); + + // refresh the map visuals: replace our old shader objects by the new ones + // on brush faces we have the shader name in texdef.name + // on patches we have the shader name in PatchShaders + // while we walk through the map data, we DecRef the old shaders and push the new ones in + // if all goes well, most of our old shaders will get deleted on the way + + // FIXME: bug 104655, when we come accross a patch, we use the above array since the d_texture is lost + // NOTE: both face_t and patchMesh_t store pointers to the shader and qtexture_t + // in an ideal world they would only store shader and access the qtexture_t through it + // reassign all current shaders + for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) + Brush_RefreshShader(b); + for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) + Brush_RefreshShader(b); + // do that to the filtered brushes as well (we might have some region compiling going on) + for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) + Brush_RefreshShader(b); +} + +int WINAPI QERApp_LoadShadersFromDir (const char *path) +{ + int count = 0; + // scan g_Shaders, and call QERApp_Shader_ForName for each in the given path + // this will load the texture if needed and will set it in use.. + int nSize = g_Shaders.GetSize (); + for (int i = 0; i < nSize; i++) + { + CShader *pShader = reinterpret_cast < CShader * >(g_Shaders[i]); + if (strstr (pShader->getShaderFileName (), path) || strstr (pShader->getName (), path)) + { + count++; + // request the shader, this will load the texture if needed and set "inuse" + //++timo FIXME: should we put an Activate member on CShader? + // this QERApp_Shader_ForName call is a kind of hack + IShader *pFoo = QERApp_Shader_ForName (pShader->getName ()); +#ifdef _DEBUG + // check we activated the right shader + // NOTE: if there was something else loaded, the size of g_Shaders may have changed and strange behaviours are to be expected + if (pFoo != pShader) + Sys_Printf ("WARNING: unexpected pFoo != pShader in QERApp_LoadShadersFromDir\n"); +#else + pFoo = NULL; // leo: shut up the compiler +#endif + } + } + return count; +} + +bool CShader::Parse () +{ + char *token = g_ScripLibTable.m_pfnToken (); + + // the parsing needs to be taken out in another module +// Sys_Printf("TODO: CShader::Parse\n"); + + // token is shader name (full path with a "textures\") + // we remove the "textures\" part + //setName ((char *) &token[9])); + // no we don't + setName (token); + // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before) + const char *stdName = QERApp_CleanTextureName (token); + m_strTextureName = stdName; // FIXME: BC reports stdName is uninitialised? + g_ScripLibTable.m_pfnGetToken (true); + if (strcmp (token, "{")) + return false; + else + { + // we need to read until we hit a balanced } + int nMatch = 1; + while (nMatch > 0 && g_ScripLibTable.m_pfnGetToken (true)) + { + if (strcmp (token, "{") == 0) + { + nMatch++; + continue; + } + else if (strcmp (token, "}") == 0) + { + nMatch--; + continue; + } + if (nMatch > 1) continue; // ignore layers for now + if (strcmpi (token, "qer_nocarve") == 0) + { + m_nFlags |= QER_NOCARVE; + } + else if (strcmpi (token, "qer_trans") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + m_fTrans = (float) atof (token); + } + m_nFlags |= QER_TRANS; + } + else if (strcmpi (token, "qer_editorimage") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + // bAddTexture changed to false to allow editorimages in other locations than "textures/" + m_strTextureName = QERApp_CleanTextureName (token, false); + } + } + else if (strcmpi (token, "qer_alphafunc") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + + if(stricmp( token, "greater" ) == 0 ) + { + m_nAlphaFunc = GL_GREATER; + } + else if(stricmp( token, "less" ) == 0 ) + { + m_nAlphaFunc = GL_LESS; + } + else if(stricmp( token, "gequal" ) == 0 ) + { + m_nAlphaFunc = GL_GEQUAL; + } + + if( m_nAlphaFunc ) + m_nFlags |= QER_ALPHAFUNC; + } + if (g_ScripLibTable.m_pfnGetToken (true)) + { + m_fAlphaRef = (float) atof (token); + } + } + else if (strcmpi (token, "cull") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + if( stricmp( token, "none" ) == 0 || stricmp( token, "twosided" ) == 0 || stricmp( token, "disable" ) == 0 ) + { + m_nCull = 2; + } + else if( stricmp( token, "back" ) == 0 || stricmp( token, "backside" ) == 0 || stricmp( token, "backsided" ) == 0 ) + { + m_nCull = 1; + } + + if( m_nCull ) + m_nFlags |= QER_CULL; + } + } + else if (strcmpi (token, "surfaceparm") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + if (strcmpi (token, "fog") == 0) + { + m_nFlags |= QER_FOG; + if (m_fTrans == 1.0f) // has not been explicitly set by qer_trans + { + m_fTrans = 0.35f; + } + } + else if (strcmpi (token, "nodraw") == 0) + { + m_nFlags |= QER_NODRAW; + } + else if (strcmpi (token, "nonsolid") == 0) + { + m_nFlags |= QER_NONSOLID; + } + else if (strcmpi (token, "water") == 0) + { + m_nFlags |= QER_WATER; + } + else if (strcmpi (token, "lava") == 0) + { + m_nFlags |= QER_LAVA; + } + } + } + } + if (nMatch != 0) + return false; + } + return true; +} + +void CShader::RegisterActivate () +{ + // fill the qtexture_t with shader information + //++timo FIXME: a lot of that won't be necessary, will be stored at IShader* level +// strcpy (m_pTexture->shadername, m_Name); + // this flag is set only if we have a shaderfile name +// if (m_ShaderFileName[0] != '\0') +// m_pTexture->bFromShader = true; +// else +// m_pTexture->bFromShader = false; + //++timo FIXME: what do we do with that? + //m_pTexture->fTrans = pInfo->m_fTransValue; +// m_pTexture->fTrans = 1.0f; // if != 1.0 it's ot getting drawn in Cam_Draw +// m_pTexture->nShaderFlags = m_nFlags; + // store in the active shaders list (if necessary) + g_ActiveShaders.AddSingle (this); + // when you activate a shader, it gets displayed in the texture browser + m_bDisplayed = true; + IncRef (); +} + +void CShader::Try_Activate () +{ + m_pTexture = QERApp_Try_Texture_ForName (m_strTextureName.GetBuffer()); + if (m_pTexture) + RegisterActivate (); +} + +// Hydra: now returns false if the ORIGINAL shader could not be activated +// (missing texture, or incorrect shader script), true otherwise +// the shader is still activated in all cases. +bool CShader::Activate () +{ + Try_Activate (); + if (!m_pTexture) + { + m_pTexture = QERApp_Texture_ForName2 (SHADER_NOTEX); + RegisterActivate (); + return false; + } + return true; +} + +void WINAPI QERApp_LoadShaderFile (const char *filename) +{ + char *pBuff; + int nSize = vfsLoadFile (filename, reinterpret_cast < void **>(&pBuff), 0); + if (nSize > 0) + { + Sys_Printf ("Parsing shaderfile %s\n", filename); + g_ScripLibTable.m_pfnStartTokenParsing (pBuff); + while (g_ScripLibTable.m_pfnGetToken (true)) + { + // first token should be the path + name.. (from base) + CShader *pShader = new CShader (); + // we want the relative filename only, it's easier for later lookup .. see QERApp_ReloadShaderFile + char cTmp[1024]; + g_FuncTable.m_pfnQE_ConvertDOSToUnixName (cTmp, filename); + // given the vfs, we should not store the full path + //pShader->setShaderFileName( filename + strlen(ValueForKey(g_qeglobals.d_project_entity, "basepath"))); + pShader->setShaderFileName (filename); + if (pShader->Parse ()) + { + // do we already have this shader? + //++timo NOTE: this may a bit slow, we may need to use a map instead of a dumb list + if (g_Shaders.Shader_ForName (pShader->getName ()) != NULL) + { +#ifdef _DEBUG + Sys_Printf ("WARNING: shader %s is already in memory, definition in %s ignored.\n", + pShader->getName (), filename); +#endif + delete pShader; + } + else + { + pShader->IncRef (); + + g_Shaders.Add ((void *) pShader); + } + } + else + { + Sys_Printf ("Error parsing shader %s\n", pShader->getName ()); + delete pShader; + } + } + vfsFreeFile (pBuff); + } + else + { + Sys_Printf ("Unable to read shaderfile %s\n", filename); + } +} + +IShader *WINAPI QERApp_Try_Shader_ForName (const char *name) +{ + // look for the shader + CShader *pShader = g_Shaders.Shader_ForName (name); + if (!pShader) + // not found + return NULL; + // we may need to load the texture or use the "shader without texture" one + pShader->Activate (); + pShader->SetDisplayed (true); + return pShader; +} + +IShader *WINAPI QERApp_CreateShader_ForTextureName (const char *name) +{ + CShader *pShader; + pShader = new CShader; + // CreateDefault expects a texture / shader name relative to the "textures" directory + // (cause shader names are reletive to "textures/") + pShader->CreateDefault (name); + // hook it into the shader list + g_Shaders.Add ((void *) pShader); + pShader->IncRef (); + // if it can't find the texture, SHADER_NOT_FOUND will be used + // Hydra: display an error message, so the user can quickly find a list of missing + // textures by looking at the console. + if (!pShader->Activate ()) + { + Sys_Printf ("WARNING: Activate shader failed for %s\n",pShader->getName()); + } + pShader->SetDisplayed (true); + + return pShader; +} + +IShader *WINAPI QERApp_Shader_ForName (const char *name) +{ + if (name == NULL || strlen (name) == 0) + { + // Hydra: This error can occur if the user loaded a map with/dropped an entity that + // did not set a texture name "(r g b)" - check the entity definition loader + + g_FuncTable.m_pfnSysFPrintf (SYS_ERR, "FIXME: name == NULL || strlen(name) == 0 in QERApp_Shader_ForName\n"); + return QERApp_Shader_ForName (SHADER_NOT_FOUND); + } + // entities that should be represented with plain colors instead of textures + // request a texture name with (r g b) (it's stored in their class_t) + if (name[0] == '(') + { + return QERApp_ColorShader_ForName (name); + } + + CShader *pShader = static_cast < CShader * >(QERApp_Try_Shader_ForName (name)); + if (pShader) + { + pShader->SetDisplayed (true); + return pShader; + } + return QERApp_CreateShader_ForTextureName (name); +} + +qtexture_t *WINAPI QERApp_Try_Texture_ForName (const char *name) +{ + qtexture_t *q; +// char f1[1024], f2[1024]; + unsigned char *pPixels = NULL; + int nWidth, nHeight; + + // convert the texture name to the standard format we use in qtexture_t + const char *stdName = QERApp_CleanTextureName (name); + + // use the hash table + q = (qtexture_t*)g_hash_table_lookup (g_ShadersTable.m_pfnQTexmap (), stdName); + if (q) + return q; + +#ifdef QTEXMAP_DEBUG + for (q = g_qeglobals.d_qtextures; q; q = q->next) + { + if (!strcmp (stdName, q->name)) + { + Sys_Printf ("ERROR: %s is not in texture map, but was found in texture list\n"); + return q; + } + } +#endif + + g_FuncTable.m_pfnLoadImage (name, &pPixels, &nWidth, &nHeight); + + if (!pPixels) + return NULL; // we failed + else + Sys_Printf ("LOADED: %s\n", name); + + // instanciate a new qtexture_t + // NOTE: when called by a plugin we must make sure we have set Radiant's GL context before binding the texture + + // we'll be binding the GL texture now + // need to check we are using a right GL context + // with GL plugins that have their own window, the GL context may be the plugin's, in which case loading textures will bug + // g_QglTable.m_pfn_glwidget_make_current (g_QglTable.m_pfn_GetQeglobalsGLWidget ()); + q = g_FuncTable.m_pfnLoadTextureRGBA (pPixels, nWidth, nHeight); + if (!q) + return NULL; + g_free (pPixels); + + strcpy (q->name, name); + // only strip extension if extension there is! + if (q->name[strlen (q->name) - 4] == '.') + q->name[strlen (q->name) - 4] = '\0'; + // hook into the main qtexture_t list + qtexture_t **d_qtextures = g_ShadersTable.m_pfnQTextures (); + q->next = *d_qtextures; + *d_qtextures = q; + // push it in the map + g_hash_table_insert (g_ShadersTable.m_pfnQTexmap (), q->name, q); + return q; +} + +int WINAPI QERApp_HasShader (const char *pName) +{ + // mickey check the global shader array for existense of pName + CShader *pShader = g_Shaders.Shader_ForName (pName); + if (pShader) + return 1; + return 0; +} + +IShader *WINAPI QERApp_Shader_ForName_NoLoad (const char *pName) +{ + CShader *pShader = g_Shaders.Shader_ForName (pName); + return pShader; +} + +/*! +This should NEVER return NULL, it is the last-chance call in the load cascade +*/ +qtexture_t *WINAPI QERApp_Texture_ForName2 (const char *filename) +{ + qtexture_t *q; + q = QERApp_Try_Texture_ForName (filename); + if (q) + return q; + // not found? use "texture not found" + q = QERApp_Try_Texture_ForName (SHADER_NOT_FOUND); + if (q) + return q; + + // still not found? this is a fatal error + g_FuncTable.m_pfnError("Failed to load " SHADER_NOT_FOUND ". Looks like your installation is broken / missing some essential elements."); + return NULL; +} + +void CShader::CreateColor (const char *name) +{ + // parse + sscanf (name, "(%g %g %g)", m_vColor, m_vColor + 1, m_vColor + 2); + m_strTextureName = name; + setName ("color"); + // create the qtexture_t + qtexture_t *q1 = QERApp_Texture_ForName2 (SHADER_NOT_FOUND); + // copy this one + qtexture_t *q2 = new qtexture_t; + memcpy (q2, q1, sizeof (qtexture_t)); + strcpy (q2->name, m_strTextureName.GetBuffer ()); + VectorCopy (m_vColor, q2->color); + m_pTexture = q2; +} + +IShader *WINAPI QERApp_ColorShader_ForName (const char *name) +{ + CShader *pShader = new CShader (); + pShader->CreateColor (name); + // hook it into the shader list + pShader->IncRef (); + g_Shaders.Add ((void *) pShader); + return pShader; +} + +void CShaderArray::ReleaseForShaderFile (const char *name) +{ + int i; + // decref + for (i = 0; i < CPtrArray::GetSize (); i++) + { + IShader *pShader = static_cast < IShader * >(CPtrArray::GetAt (i)); + if (!strcmp (name, pShader->getShaderFileName ())) + { + pShader->DecRef (); + CPtrArray::RemoveAt (i); + i--; // get ready for next loop + } + } +} + +void WINAPI QERApp_ReloadShaderFile (const char *name) +{ + brush_t *b; + face_t *f; + brush_t *active_brushes; + brush_t *selected_brushes; + brush_t *filtered_brushes; + +// Sys_Printf("TODO: QERApp_ReloadShaderFile\n"); + + active_brushes = g_DataTable.m_pfnActiveBrushes (); + selected_brushes = g_DataTable.m_pfnSelectedBrushes (); + filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); + +#ifdef _DEBUG + // check the shader name is a reletive path + // I hacked together a few quick tests to make sure :-) + if (strstr (name, ":\\") || !strstr (name, "scripts")) + Sys_Printf ("WARNING: is %s a reletive path to a shader file? (QERApp_ReloadShaderFile\n"); +#endif + + // in the actives and global shaders lists, decref and unhook the shaders + //++timo NOTE: maybe we'd like to keep track of the shaders we are unhooking? + g_ActiveShaders.ReleaseForShaderFile (name); + g_Shaders.ReleaseForShaderFile (name); + // go through a reload of the shader file + QERApp_LoadShaderFile (name); + // scan all the brushes, replace all the old ones by refs to their new equivalents + for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) + { + if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) + SetShader (b->pPatch); + else + for (f = b->brush_faces; f; f = f->next) + if (!strcmp (f->pShader->getShaderFileName (), name)) + SetShader (f); + } + for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) + { + if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) + SetShader (b->pPatch); + else + for (f = b->brush_faces; f; f = f->next) + if (!strcmp (f->pShader->getShaderFileName (), name)) + SetShader (f); + } + // do that to the filtered brushes as well (we might have some region compiling going on) + for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) + { + if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) + SetShader (b->pPatch); + else + for (f = b->brush_faces; f; f = f->next) + if (!strcmp (f->pShader->getShaderFileName (), name)) + SetShader (f); + } + // call Texture_ShowInUse to clean and display only what's required + g_ShadersTable.m_pfnTexture_ShowInuse (); + QERApp_SortActiveShaders (); + g_FuncTable.m_pfnSysUpdateWindows (W_TEXTURE); +} + +void CShaderArray::SetDisplayed (bool b) +{ + int i, count; + count = CPtrArray::GetSize (); + for (i = 0; i < count; i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->SetDisplayed (b); +} + +void CShaderArray::SetInUse (bool b) +{ + int i, count; + count = CPtrArray::GetSize (); + for (i = 0; i < count; i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->SetInUse (b); +} + +// Set the IsDisplayed flag on all active shaders +void WINAPI QERApp_ActiveShaders_SetDisplayed (bool b) +{ + g_ActiveShaders.SetDisplayed (b); +} + +void WINAPI QERApp_ActiveShaders_SetInUse (bool b) +{ + g_ActiveShaders.SetInUse (b); +} + +// ============================================================================= +// SYNAPSE + +bool CSynapseClientShaders::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SHADERS_MAJOR)) + { + _QERShadersTable* pTable= static_cast<_QERShadersTable*>(pAPI->mpTable); + + pTable->m_pfnFreeShaders = QERApp_FreeShaders; + pTable->m_pfnReloadShaders = QERApp_ReloadShaders; + pTable->m_pfnLoadShadersFromDir = QERApp_LoadShadersFromDir; + pTable->m_pfnReloadShaderFile = QERApp_ReloadShaderFile; + pTable->m_pfnLoadShaderFile = QERApp_LoadShaderFile; + pTable->m_pfnHasShader = QERApp_HasShader; + pTable->m_pfnTry_Shader_ForName = QERApp_Try_Shader_ForName; + pTable->m_pfnShader_ForName = QERApp_Shader_ForName; + pTable->m_pfnTry_Texture_ForName = QERApp_Try_Texture_ForName; + pTable->m_pfnTexture_ForName = QERApp_Texture_ForName2; + pTable->m_pfnGetActiveShaderCount = QERApp_GetActiveShaderCount; + pTable->m_pfnColorShader_ForName = QERApp_ColorShader_ForName; + pTable->m_pfnShader_ForName_NoLoad = QERApp_Shader_ForName_NoLoad; + pTable->m_pfnActiveShaders_SetInUse = QERApp_ActiveShaders_SetInUse; + pTable->m_pfnSortActiveShaders = QERApp_SortActiveShaders; + pTable->m_pfnActiveShader_ForTextureName = QERApp_ActiveShader_ForTextureName; + pTable->m_pfnCreateShader_ForTextureName = QERApp_CreateShader_ForTextureName; + pTable->m_pfnActiveShaders_SetDisplayed = QERApp_ActiveShaders_SetDisplayed; + pTable->m_pfnActiveShader_ForIndex = QERApp_ActiveShader_ForIndex; + pTable->m_pfnCleanTextureName = QERApp_CleanTextureName; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} diff --git a/plugins/shaders/shaders.def b/plugins/shaders/shaders.def new file mode 100644 index 00000000..f542aff0 --- /dev/null +++ b/plugins/shaders/shaders.def @@ -0,0 +1,8 @@ +; shaders.def : Declares the module parameters for the DLL. + +LIBRARY "Shaders" +DESCRIPTION 'Shaders Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/shaders/shaders.h b/plugins/shaders/shaders.h new file mode 100644 index 00000000..04792a59 --- /dev/null +++ b/plugins/shaders/shaders.h @@ -0,0 +1,167 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// internal implementation of IShaders related stuff +// + +#ifndef __SHADERS_H_ +#define __SHADERS_H_ + +//++timo TODO: track all the calls to IncRef and look for not-called DecRef bugs +//++timo TODO: move all needed stuff into the IShader interface + +// Radiant's internal implementation of the IShader object +class CShader : public IShader +{ + int refCount; + qtexture_t *m_pTexture; + // name is shader / texture name (if not a real shader) reletive to "textures/" directory + char m_Name[QER_MAX_NAMELEN]; + char m_ShaderFileName[QER_MAX_NAMELEN]; + int m_nFlags; + float m_fTrans; + // the name of the texture file to be used to represent the shader + //++timo FIXME? + // must fit the qtexture_t convention or not? I think so .. + // ((old .. NOTE: may be a straight copy of the .shader file, doesn't fit the qtexture_t naming requirements)) + CString m_strTextureName; + bool m_bDisplayed; + bool m_bInUse; + // color stuff + bool m_bColor; + vec3_t m_vColor; + // alphafunc stuff + int m_nAlphaFunc; + float m_fAlphaRef; + // cull stuff + int m_nCull; + + // will hook itself in g_ActiveShaders and increment ref count + // will also update the underlying qtexture_t with some information about the shader name etc. + void RegisterActivate(); + +public: + CShader() { refCount = 0; m_pTexture = NULL; m_Name[0]='\0'; m_ShaderFileName[0]='\0'; m_nFlags = 0; m_bInUse = false; m_bDisplayed = false; m_bColor = false; m_fTrans = 1.0f; m_nAlphaFunc = 0; m_fAlphaRef = 0.f; m_nCull = 0; } + virtual ~CShader() { } + + // IShaders implementation ----------------- + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () + { if ( --refCount <= 0 ) + delete this; + } + // get/set the qtexture_t* Radiant uses to represent this shader object + qtexture_t* getTexture() const { return m_pTexture; } + void setTexture(qtexture_t *pTex) { m_pTexture = pTex; } + // get shader name + const char* getName() const { return m_Name; } + bool IsDisplayed() const { return m_bDisplayed; } + void SetDisplayed(bool b) { m_bDisplayed = b; } + // setting in use also sets the display flag on + bool IsInUse() const { return m_bInUse; } + void SetInUse(bool b) { m_bInUse = b; if (m_pTexture) m_pTexture->inuse = true; if (b) m_bDisplayed = true; } + // get the shader flags + int getFlags() { return m_nFlags; } + // get the transparency value + float getTrans() { return m_fTrans; } + // test if it's a true shader, or a default shader created to wrap around a texture + bool IsDefault() { return m_ShaderFileName[0] == '\0'; } + // test if it's a plain color shader, i.e. a shader we use on plain color stuff (like info_playerstart) + bool IsColor() { return m_bColor; } + // get the related color then! + void getColor( vec3_t v) { VectorCopy( m_vColor, v); } + // get the alphaFunc + void getAlphaFunc(int *func, float *ref) { *func = m_nAlphaFunc; *ref = m_fAlphaRef; }; + // get the cull type + int getCull() { return m_nCull; }; + // get/set shader file name (ie the file where this one is defined) + const char* getShaderFileName() const { return m_ShaderFileName; } + // ----------------------------------------- + + // parse yourself! + bool Parse(); + + // search / load the texture to be used when displaying the shader + // after a successfull call to one of these the shader will get displayed in the tex wnd + // if m_strTextureName could not be loaded will set m_pTexture to NULL + void Try_Activate(); + // if m_strTextureName could not be loaded will use a default qtexture + // FIXME TTimo: Activate forces activation, always true + bool Activate(); + + // set shader name + void setName(const char* name) { strcpy(m_Name, name); } + void setShaderFileName(const char* name) { strcpy(m_ShaderFileName, name); } + // create a default shader for a given texture name + // will not activate! + // NOTE: CreateDefault expects a texture name reletive to the base path. Adding a "textures/" may be needed + void CreateDefault(const char* name); + const char* getTextureName() { return m_strTextureName; } + + //++timo clean + // color stuff +// void setColor( vec3_t c ) { VectorCopy( c, m_vColor ); m_bColor = true; } + // create a color shader + void CreateColor(const char* name); +}; + +// the classical CPtrArray with some enhancements +class CShaderArray : public CPtrArray +{ +public: + CShaderArray() { } + virtual ~CShaderArray() { } + // look for a shader with a given name (may return NULL) + CShader* Shader_ForName( const char * ) const; + // look for a shader with a given texture name (may return NULL) + // NOTE: the texture name is supposed to fit qtexture_t naming conventions .. _DEBUG builds will check + CShader* Shader_ForTextureName( const char * ) const; + // will Add the given object if not already in + void AddSingle(void*); + // will copy / add another CShaderArray, and IncRef + void operator = (const class CShaderArray &); + // will empty the array, decreasing the refcount by 1 + void ReleaseAll(); + // will empty all shaders that match a given filename, decreasing the refcount by 1 + void ReleaseForShaderFile( const char * ); + // sort the array by shader name + void SortShaders(); + // set the IsDisplayed flag for all shaders stored + void SetDisplayed(bool b); + // set the InUse flag for all shaders stored + void SetInUse(bool b); +}; + +#endif diff --git a/plugins/shaders/shaders.proj b/plugins/shaders/shaders.proj new file mode 100644 index 0000000000000000000000000000000000000000..a3056b57e0b3f4151946d67ec3786d57112a5021 GIT binary patch literal 73728 zcmeHweQ+bmb>A#@Z+FS#0#YeSsmf8Mm%BcLToT0Kn^@hQc)R2to!vbi$@`FwX9xs_ zAZ`H+c4oj`n#IIXRqUinR<3L(rHU$wQe{V}BywDiDv50+rLyDLlC4DYmt;$pWLx>e zmLf|^l@lk9F2C13J=244?D4FVG}r|=czFH#_3PKKzh1xA&i>W1rfCsPJM$Zw_69s^ zGn#e^f9S29$NRMV_bmRNbHBgkl~-Q*0-jI(!`AU1;V-=ikA9z`FMpY@^PJVc%pAkK zLJ5Qt2qh3oAe2BTflvaW1VRaf5(p&_N+6WLx0eKFv~R?|8v9)A_hP>o`)KUvV*ft& z!Prm5-V=LwtcCY(?47aI*i1}|eKY#C=$}UaBi>()ekJavdNcYrqsi$1y72W2zjNVNFZ{}dpTF>P7yk8ye|2FQ?~TPduFE3t}QK zm5zKCJQEK=9Kk;ag9_2he6 zh-Vcpco1#DEl~L9bs+)L8qs1!-AP>%?M2u$Rc8o(j@xRX4?>sJdKYyq+aT%rdF{`= zb|>&pxjI9(QR=X;|3qKtiJ&9wznYhT3!0M7U-0%zX=Ohm@)iAy|152V&yQ@UlveO8 z$|Cz6N-Gw(r9P`PiGSJdh<{o#mvja_3;xgY_9DvlFeSu`Bs}cbTa~a-;urOqAoQK^=p`^T?V9#c8V>Y*odNW| z`zC~yF5HvIx0^@Ghw`P@AAqy?*FSOo%_uMBMX!t6uWBV@=50TKXECZI*vGUjz)A|N zqJ3QZk;=^5o(D|Qvm?Kz9Rl|D0PNSbCy@4?fcdXaXj#C@0QmX-SFMh;&-qB&o3#I? z{dM5&DzMYqC$)zGs{r;!7aq|*rD=dw6}&fTzoGqkb>?jbU@;edTKi4ye*m_J?|g?5 zf8V72miAe|YIuI-ZwtgXX}_&~9I$-__Rh%fXuk|t9WZIdH0{&c&ja>S0QMQ}Lx9}@ z3>%p4>vy%E1gwE?vb=WW_q6u{)(pTttNkcotpMzE+PeTV1F+xM?gG{hz&@|l0lN#> z1-$8HN4}ty0JHGy=lezNdBE%d><_eSfH{=Nd;Oud1X#!WP7i;ieNS~p+ppV>X&sg< z!vSge?Y?C|u<~2Qu?#~ysv3LcPQzgdyVbT{TC(@cRl~9q`muIUH}2WmQpdKI>a9wn zQ#Duu|CaX6rm^JIo90s6svndcW9f!-XR}y}Xg zQ*{FcyM-L<&(&L16FDTcUDMfLz#ADa-m~hCq3Hrvv&>H01zpl=)!oH=rgaCTw4PBDJj8Xxl%FO z&Z6y|L=c-jBuJ8e53HC3ZG;Ciac!m!tnZ`fsB@75&NROL!-ujp&CXKO6aHk$)O_ zIr5&!4@Hh5cI0m4#mGA%w+USr~dA# z2s(&!_&YuQZnx{YsC^gPA-A<^)m^ALZwho(5Sej_?qLR_DWcxhqrzq_*HKU-3ARc)8E486g_4~Y)RVa%eh7Z zjJ6G{X-oRNQK0!&yQ~NY1&j!XTvF|XD@!sLi}!^bc;gV}KwC8Kmn)8IDi)fCvu{>C z)3IQ~ur9XDO4&9fiu*08Rn3;^l&I8=@}Z{KO9)VdO(F^5XG{I5k11_8I<vCI8h32?8usxTUBkbp%kqFh8wWIk_v3J|D^)^XlqACweGN^ zy$*YNb#tZNF5NWC)h*sDQ1!4RlU+om-9Baly)SBfuQPYdD610DESbA6p$CvjjvThJ zcDuB_`uz4Yo2y%^+wK!GP$bqzEM5<@RF|CWOQL-##+_koH0$i>nkXOJG-}}1uvRJ# z@7Rv}m$n-%-mK3tm&T9+t2u3yE!!ACp8qx`&H4d5Dna^N6|3I9S>N5J9*{Ll?Y-6w z!`U|P7%j?We2EgBMtwKoi8MefUO$*)J^2kOGt|h}AG^Oe6@(Egvp0T0xD`4?Wj6hy z)Ky@7Z*E*_#|&L4S79O`bxmm^n?}QHBm)ZRwvYhkh|-D%^7M_H*VngJp18R>Nj=sY zezB=h_*90s2B}X^*BXi{mG0IWYi4b4B2`jZ;7TN^cuFKQ8LmHDhT}HRzNW|fd4x14 z&>fZYI(>Qdx>7M)WKU&@OE;cbzy6^0*-a-7;=?T51SRh=sJ@AP^)m3glr_veM4b+A zEehVK+U4EV271gA?A}_ZRT1jjS7ji;9?a47w+`*nhK1f|ufG}de;-Xta&Qyf&AOa1 z4VDGxHi$bak8y3=QoUMs%D%C1zrOm~t~7W@ff2-YWFTu}?2ahN6?Hi(rFf+=T;p$H zFr*r5`5oozvgY1chzz_oHh;Tzd(Sdab**Y*e^OzOk8iZgbs%EoXZ?R76PRqR4 zVoA+x8?92kwTBfLEMb%y^%iCktxoehZE7_6jLn?^@o9}R3sYAV+{sgL&eCtvAXZJo z&rkxP1VRaf5(p&_N+6U#D1lG{p#(w+gc1lP5K7=XSppF)0+*aWi@gG8ov3z1t^(}H zp&ceRKmO8@?QJj>bA{s4(hf6Qjl&&=joj)EbIct^J}Y(Oz}R7raOyiPxhjnf$D*Fr zi#u$GRrbr)4x1Mk?9m-oD+Ttz5`4>nZ-B+;cCL02$rLydA|(G2D@M7pPfVapJJ{wl zI}Px(3r@=Pl^kPs_%=FiVRutp?xAR7^AfAYactFMw-~Es3&?Ah3&63LzSmB;BxeEV zdG_#`OQwoD4squ4RJVObI1>!(z>UTZYnL5xey>iSV0LHL!M1kCGVGn5o!Pk{ueoFf zRBgk#jbg;(t|aFkiHl5LSl)SYt`93YByw@#Mnh?LNbc7fM!B^ua^nO&X8X{9kevG7 z4vRw|m1bMy$i=dA1U|bN)$_ooe?!uM32>3@PMU(6@T5k=2BQNA9FuSc5XcT9P*>Q# zYgi@P_qU+0gGo`b>0b{o-J~3=+_DD~N~c{yM66lb+vez03s@`N6KwTLJuRg;GJ9GA zhlf_PTpLoFjFhZk0yU}B{!o=5J-0fjjb0uzq>>{=WOul08C*%4gM~zGo0FnXrQTIp z@0qoM1oAp*I{l-Dw?~cFQ)$&Ez+FwYyDK}4T4N#s&Bm@k6Gj7mAy7$nlxEye>WPBR z@R6H-Edi-SD#P%xEOY4rq!Z~B!$)3XJOCh*$YmHlyj)(lfNUa_WcbL+(&iHBEXyS_ z$yWi$C$c)jhgX%~B0wRLDzHK#ot9-84OmX3lMEl8JVpcbB#8{4zRVsRq$kojrt67} zE_ue6lLMtVt&~dsBtg_{n4V5#QXcmw3CeKpGb;Bd3Cbq21*T^cIZt2k<@E_dD}|b% znfhvSlAt`=4Ab#h@apk_LA=fBYAeJSw9A2@W4I6T9)S7W0|ic-ATFdsS^+mXPn3ixVb)MX|1 zi>WN?@}O=xopOWmicv_fK}W9FtzdP~;D3%i%96o~&14Ipw6t{P3OVZs{O~N}ZU_GO zHp3u>9qif6bE-@v0(F|n<%&~E{_(CV%O(p&q#dX`_F#qs`D9at;uK!0?mV}$d3*i# zjUsmXjr(o5jv7_gUNcR0@ln>^;?ptk-K$(OPoZF{zT{z65(RJUqbIrmP@p^%$Tti< zfOJC7L!(lj>45IgU?}5tsXc&fB45BDq~Iyx$pSpRRcmRawqCncZg25P>9)DySOYXx zx(Snc!WqO*rI6ybirs_J({z0A76z z6wPR(FO<8qW~x)GZi%Lr3q{xIcwTxRuUJ<3uvqMyKF)j-4qDuP3s9gXrju#jm-KCk z?y7#}ax8vvoj@KIk&2g}Pi0V-9U~L9pc8u>GR0lP&ZL zIZmzsf359cI7uoqbvjZDt(Wcn9nWV3a3%AIhN zg3yvnw`S<6Owq56`7Yz!l{gjD3vwUhs^QlIExYBhW;8X0H8nRidYk^dfSkAXv}C!5 z!fbA=aVWyLKTCbM_--eN@^T@MQG?q@Sv+r6wg*sWB6g*Ly+Qf5(=p{jlck>TeSU#IC{D`oNXM|9rseSS8=i-8S5K76>;1;NTixm6!O^Xb(Wy5$?StG;ieC9( zakyAL00tIWh!s;wufV-D$2A9m;+EhLzutPr?zIYfy6-^0f9m+IX*SsITyVTiW)t=5 z@$A}w0VGE9PmPC+*Vu#QfY)tNhfz`nxS}bx45MnZGTS%JJ6JZyb^=zqxrwM6yPX== z$m!H6i=$t%j9RBrwpi1|(bl^2ebk?|46LOx9E`;HyDg2&6I&Y$PNo)4OTyKDdTe&d ztG1Yi*gXR$cq~_|oIkQ*7(JVepM7;%vswHd3@5i(BEeuVX%+wR$0x{Can3DbS+z$% zJaf=*;Iu8nK8tmD4+n3J@k^yK*)X{M>A#!H52IrWn%H z^&V+D7^eCY7$y|J#vx@^p}h%IBkhZDPFi5Xl_^`22ig3zV{?UNf8owd^R-m6TLzq? zee_~A6RKxI!49BcRM9lwa_EfK0vE=v0VTZKF>p?)%61Q_*WAwSO=S0`*5+w$!ub;+yZk|<33Fx={xo*8q7V=&3|u@-?amtg`RR` znmn4!xQ`PIq{f(oR`v~h5=QCNBK*LMdM3xU)aA4;I`mR$ee0RcwUukD8#kZ1v3|Ss zWQpzLpeMS2R5xuGF3=}hdZ&d}$&SQad7d9PxXRW^j`h~lZvVmN+g*TTb_eAUEu0GQ z_ye&{vk|O$2pOL!=U^NMR6V}kuP4HFDo?}eZ!O#E5Ku>t++{_mW^JcYEH=w+cJU&M zuVd?|jz&Uii`pvVP=K)SG?Qh!9R~)SnY*OZcH@xQoyr|M*ny{)M=Vb%r;U0CZdq(7 z_Fvoz9O>&#m`i2{By{IB#UelO*_$$tnb;Jx%N-jF9jh7+%%N+#_*gLUQoF|R#P-Y% z6qtzldYjAZlrpz^qVIxQyz=Ks^$mt&uf{g>Ew?E7O+;ivAf*_OkI_1R}Gf$UKzSVT}8EgxFE&=x7My<4%vi3 ztMAqub>|S>2o6TWwh^bo?Dz6HTXXI#;SC0SPG^;VLIv|fg#mzU4uRC}S*!q}dc0>A z47titAzuYpb+Tu?Jm_uEsbj?!1x1@dud|PF4O|hRJ!l^o{ZLmFI1&5!^d(pv9G;;S zK{`c;so*u}lmp+2XVhRZ%D+ql$U-Bws}EM#J32VR_Em9u5@J*iZD`_B5SG^9~u7bd=Zoc9s9A9#+Gz z-Vr$Qt2_qE@RNM@(rxj{vN$jYrxyR4he0C79294pC6=rnff8_pK^B4USEr}>(7smM z^@bPgt-5oaTF9ep4@EYBqplUX9q{dyTdTmB^`pHo!JW-+iPh`btNqeld+OG$mD|_1 zDDBFw*>Mty#MLK_Mw|X3$!k)3tM}WO(4nErszXI$Fl|^ZHhXQBj}_*<;a1?tDCT`f z(~R7ZIzWCTP_@SaBIFI@6Cok8I4#)EvwhV60)wEQt5>mDG0)n!aAZw<5#*aj6Z4X| zN`8SQ7noiDK?ANFT?#gbMH5mMPs`8__nyT7o^+DW>q}HgrDqWdVEw7vy~wRC&;{lI z@~8x_#Is$MihjkSqPPP>RM;>nK$Ns36%-=(F`A!K^k^iJYa)CF9eN!`OX^lPJ-%<^ zuhU?^1a$>>F{r=-CRPbi2?u2y7KDu~TeY@hk<e%~K-XLw5TTlOkM~hjUPN&ZcTld1P zmFGzrxq7YN-iF=7kbLV!AwZZ($zB%?^tA{z(m(?gOLo-T@MD{N_9MDt90V;lpqEw1 z1(fb#dV)ax;$Vd_3fUHDL3ZBSI<~B)wQu+gOVj?SvCG+ufnk28@ z${U`mR0Ya)io{6Sx(}1&8>slL z#+XNp+TGPW#WaxPgj}x>(z+f)HsxLF+gS=TfIV9AOdjLKB)57J z%gvcyc9#oR^!!M6-P)l28qP;Hvpg9e4;1ikq7Z+>*JQ=4Ef`9xUpPRDFi3iU&;d=< z{D^w;s7}PGh$Q#`xd>H2oeJLg;^y(VEV_wBZ9vr`hShar(mP^QZqJ@_!;Y0R?OS+=-q)EJtpN|$Io#RHN-o(MD7Hh>9& zpdcP94O=|$2Frirc7{LE(xv#dZMpcEXY-%R4Xi1ksZ!$ucQrnXqySQg!HDnpe+j63 z^~#-ulTX$z{DsAOriV$5xUt({FNnhfwEl&xP&E6pz_|=wQ9icgxPaLgMF!}%k1kWv zM=|4?Wsf|&bw+64erUZE&A_?Vt7feg3;hST3#eC zLE7f|4U6VA!diKKdY{mKCmD&VS@mN6aion0o+lRpilB@)G;wuP`B1M%XQlzAUhJ9&2pbppl*;; z3{ONm|5g9dr!+lv=|Nsd#+ODOIJxU{uu`p(-w!)#?c!Whjc$CxCbz$nZ?^f-cED(l zo=|z2*bA4D!0znc<4(WqGNq+0c^`|)`+`%y&r2@uzhsvsfkd0jgW;;Yma%JEIO+sS zIJuT&Y>_U`Y?1FC9DZrL-{m2WCC~-ok+cY3%Gy5NU^&;FDFbUF7h-@805-w2iY5HE zJfsBu4$kqP(!qg%{(ueP0f0)Uy5B8Z34V6a|AE$uXz%~>7Izh}*Th%02);U8RJZ7X zEjl8-M+hK{D{7@OTmaZ*Iy+BM|gE?4fj*)M`P&ZOcH8pGv$kW!T$1~9l-*#I

W6%y25Dp-&9^3wKbFF}R&iYKnU@=@?elsw-R(jzLZOQ@d$fhp3CrYthhr%CDr zRQNxYq^3!Gs@| zA*>R?+2tlrf-@RZQ|>c`SlFxAAZT2G)1!^J^AJA%{I@xgh-(}?PAfRQhwK_9IJ8V_AEG-`KbcLanpd@#^dWL=qSlxAVUIyU*Z~M^8{83^Yw%LYaqZ4tYG}o;KBOEGi8XhkwPGW`M2e zv9=0l9V>}!-)|8hPzw48zTeWWjoKbV8n`}N@!FA)0Fz|#RMkFg*Q z;X6_VFc=`aA`Q4Yj0T%>5MU6>$Uy*Md4mA@BI}MPf9(bVtH_EfrHk8vN=NuSjXOr+ z?2XsgQnF_d5M*c*^pX11#ybMFA(|#JPy)Lq{U(NSm-(LuV{p?LgF%7RhrzcGV$cHF zQ4Dr9PPD8Eg?p`osvK-DNVEc_*U~%>%P!lIYeu+WD;;MP+cMdZ=0_Qu?Zc53FOd4k z6{koC@CUMimNLF7ZlJ5=_GqZCdsw|Pd$wCL19)sxMw2ml2LAu2wKH#sYD)Zn*P~L2 zJtzY{c12wZbNK2{k2kDoNA*(m0z;(#v;gw)ssXs#8`xXLj!?{C~7N3Dl+f2uwmQ5rmSt6 ztw5;7g1(G!o4wL-*G}jNCcI`;$KO6IWhwA@7gM$yybxPe6cUp{t0Ay}C^SiwwzVD) zu(F&XGD_^vDuPO3!IgtmW{7k{RcIs7 z8lsK_hs(=Zy_aFj;E`~7C_>u3rzoFNc=cwxVPM5q_&9X2{p!Q6XDLwekXld=;PuyP zUC-p9cD?loF*mpd@4UyiPiO{bk zAs#1!0;WuOl4T`H4*)lPdodR~cg2;M2Quh`u}+h%PSUca?eTJ^bRblL9Ss#l)wtm}7xbxO6bd z=+o2t2M3`k;8G{tz~I#*zKjFH9Sv!gqAQ?eJ<^wM5Ds^NJoMTpKOP9WiZbHUFXID) zprzmopFXQ634;3K5)gcPDo0-)43tl#QY?i}uXWIuF+jLi4_Ns06AlM?w^Y#3aP+1N zzmN}`EMuP__fIv4S6Pc8_fB|~HLl(cud>GRm{NF^_0a3Kzx}SVp4Pq=`;*w`VxNuu zO6-?o|1x$rX2dG7b-X`-bpi1@jX(7KW7-GK{7lR_A3y(@bN}L@zjrQkZs(ydoqfYY zFQ0wu+5ddzYY%}G5sro}!J{c!Z%(f#O?(aTXS`k4zKzVPye#)T&@unYft z=C@{kX6EIYcg|#HW@f(h@JAnh@59c+Hy^(Iu=eohrvJnAPfRzapParttxbPs>cdk% zG388cOf5{Enfl`SkKm+2_zEQuN+6T~Nni@^H_`*0)}UoEjo)NspIXjmut1yEGg>)= zpJRkG?f_6Z1gcf8Tp?Q7LRwGePig5%Y5CC&JyM{S1u1P}zLc9aJYwlgQeQr$B_`&J zt}yGSl1WZnK0kPkB$m}28cU+3;Og>f6)1atn#mQ-k^?NS{kR+PU z;0ojn5iLwkGjMg8q$t^(oJSFF7)zuGoKH7rNs2y?*@<~nHgkK)X}O8%QRBkN1KdsG z@t4W!dSRJVSxZe!PsY#cWiB}}EfKrRrIg7g^QjcLnvry5FeOA<6gatbDyOGXP$?gW z-=)Ma8tTR&zesLBe3AB{q-oP0p1jqjo06vF=i>CCbk?WSma_Ia)-)Od34Y3La)*-T zPNq}(a#Af5t|r-|puLhxK9kNtIE7Q#=kaJr9EB3!Rk|LG@RB3BWuh zbx1&|3yI^=frWM@;OPf&s*M`I*;dM1Qu1V3v&>GrimNY7Tvz2{DaH#ywuCHIJS9(A zL{C<=hB*EpiRE(XTn5~Oc~4dzP9H+ZFF=cKtdX?xK4Sq|9H&1mpMM_d{cOE9!j1f4F9OQt)s>6m z=ZJn;G;IZkM?&{Yn9q3a$jhs0m1{nR&x|WW-mXQ(zy_FoF@0J=we~qu_;xGV=iApY z&t_HZzASm|tWs`vDSbMfO%;}*^jj3a@oYRxFr=TdmS8uy?i4I@zb9@2h zz2ec>lFNzXm2l9hSyvEq1$5DwJdJh~yUcL|*@~+H?wQsdT-2s5b!-c9S1OGTj?E_U zZ_I(I=B8N`;rkZFrEheA+}7N1>-Vt}zKD9iw@7i_H7}}W#jy-S%jn6ZuDM4+OE{rM z*GxgK--vxZ_QlxG#@-)$U+f>memHg%JB-z1@4$_KTQME)UyA-Q2|s*=5(p&_N+6U# zD1lG{p#(w+gc1lP5K17FKq!H42MM&w2lX1oMOw_TbW%^j2^XHX`v``W;7?VPUu4^9 z-D#26cT%J1N(g1OXKJ`PtZlutB)nm4t-32>=VL(tyH5ADOSpcog2-L8My|zMriLhK zPgs+tYGJ)%PHUO;m($m>No@;P=e9~~M7gx$l%8r;j1e1IVmBdpCt?Xfk5KT#60JXA z1>hyzkK6*qR;Q`GneYF9DfY40M`FJa`{~$+V*eOE0F_ud_I&J_*lq0QKOTD{_Vd3P z{YvytqQ4*g;Dx&vK1hp(;VYCtD1lG{p#(w+gc1lP5K17FKq!Gw0-*$63ke*FeQ}n> ziLm7qE8r|z4yPIM_dfn!$z-nR2;;(|_#IJza`zs}LaM;%eMFPfad(=PYnmB?MdP$w zI)U3}afH{vfmN$nZZPw}y5}H*Ij%Uj>py6)6iy27QFQC%F{;&PM^KBvX^{q21~ziaWl*eR5pT@a_11(`$qy zwH=yTU(#%Z@UHA*7O&Br=Vq&M2w=SisTtK0JOHY;c68*%Ugih0?PE5dpgnmA?Ff-- zJ>apoQx6{+qeXl5w!foq84hOha#~OO{@RgyZ6*t@RwVRe?VxVlv$aeD2OWuOwNr7t z{r}fOSwotk1VRaf5(p&_N+6U#D1lG{p#(w+gc1lP5K17F!0Sr_BK}{*jsJI)W;MFv zPfrxE(3B{6L0MiC0OIas5M0cUBh&-nfu-=_1;BX#0OE>ex`T_oJ^@&tNg}3M%8SQC zv3U@&ER&R>iXH%f5N0|;m}R}H{1yQa)dy>lh-f6sG8(WFm7@r387~MFzMLG0BD7JQHii62f~eV0oVH9#N}PhWofrsFt-yUo<^Ci=*+jNL zaoYUQd-(GD1ffwv5@@Ernw%sEVc-zW4W9+C9v>LQ+Z+!D=g}Gt@}h0=I9j8_ZS~w7 zL%wU>cbw?i6pvTh7dalMJ3r><8n(0e7@h5&yXwWm#7;mlpG*}G%zBjt@4NT!s^K}t z{p&;K`IdZ?N>{Yq|f*sz$ANhr|sd|R*dUz*( zy{#cHqCzp1MO_}$EvJKhAzm>GX?bl>pgP(({XU0#E0V#AMVJjWwyZ*hS;pN?-J;m! zh<|&)qy5Sw$caFmBC11iN=X^-Ql4zGP()z{>W;k3hxIZX$Onf~d8}eJZ0vI@o440* z-zc(93)k4<049R7w%1IPU3`?ay{N3Lr@myKLcvsh$-}H93f|ZU(OQE5C=h}aDu$s4 zkWT0ni#6q$4(JYzeKKB`+5m!95Ueg4+U#vCb-j39w%yttf+AHD8QuHdAS z6e78cJj1mkKABW94V1st2S=^_9IQU-LKy5Ok` zH*E2hjrG;r+naB9btFK4j>T`>?2vJ3z}tF(-MC3R<8@}0TQvh(G`5B1d8e~vR(nf< z%N|SZy;kXNt#KW3XdL4vGP8r-Og;m}S@uVL2>2WTAcQkQZX)!vFW%maMvIti-x|Le zbg#REFXX|z@_T&i?OUbQ&CLZi>u&11!QzW-4L8oiP$GIY;#0WBk**%tF7NgWLJyCE zWj9>6n>VNZ+~#f27Qy1->M$g5x2k1mE{GYcv@o4wU8fbfsAU*wq&8RAZalMoeG)}e zf=v|>#Qjoz4_9LEv64%wbbWPg{r2khv6Ux4PcL2qF}hxR2)&5bm_DuTBIe%fYh5Db zCX_%ZflvaW1VRaf5(p&_O5odH0!xUXbpS8or5nzjOp*H-7^%q`#oUp$*<6HFD=(S8;;1bz?zfOT= z+JQ3?1q-qqG|y15G9K2*8dXwdht`wgA&%A9RH{h6(pHPj;ud!j0@m6#5KgwViS{FP#wLKg*7g)Q+9wJs_{1txMR8#@DBZ>AheT*Ieu0cxE zy-40>UJn2}m9&84-_O(o$R_k8U3;YK-ge&W0+a(^1?*Jny0@_Sx&ZMzNbun;X7&KE z{ekld3PukAciZULh4j}6dH{4Tfp0ou=}m5+_W|jA|4PR#R36rA1o9SH-KI8pF-QCV D`>M#J literal 0 HcmV?d00001 diff --git a/plugins/shaders/shaders.vcproj b/plugins/shaders/shaders.vcproj new file mode 100644 index 00000000..3098d116 --- /dev/null +++ b/plugins/shaders/shaders.vcproj @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/shaders/shadershl.def b/plugins/shaders/shadershl.def new file mode 100644 index 00000000..2cea27cb --- /dev/null +++ b/plugins/shaders/shadershl.def @@ -0,0 +1,8 @@ +; shaders.def : Declares the module parameters for the DLL. + +LIBRARY "ShadersHL" +DESCRIPTION 'ShadersHL Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/spritemodel/plugin.cpp b/plugins/spritemodel/plugin.cpp new file mode 100644 index 00000000..0b3426fa --- /dev/null +++ b/plugins/spritemodel/plugin.cpp @@ -0,0 +1,274 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Sprite Model Plugin +// +// Code by Hydra aka Dominic Clifton +// +// Based on MD3Model source code by SPoG +// + +/* + Overview + ======== + + + Why ? + ----- + + It allows the user to see a graphical representation of the entity in the 3D view (maybe 2D views later) where the entity would just otherwise be a non-descriptive coloured box. + + It is designed to be used with the entity view set to WireFrame (as the sprite images are rendered in the middle of the entity's bbox). + + How ? + ----- + + Implemented as a model module, without any ISelect stuff. + + For an entity to use an image (instead of a model) you just update the entity defintion file so that the eclass_t's modelpath is filled in with a relative path and filename of an image file. + + e.g: + + baseq3/scripts/entities.def + =========================== + + \/\*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) SUSPENDED + ... + -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- + model="sprites/powerups/ammo/bfgam.bmp"\*\/ + + + valve/scripts/halflife.fgd + ========================== + + @PointClass iconsprite("sprites/lightbulb.spr") base(Target, Targetname, Light) = light : "Invisible lightsource" + [ + ... + ] + + What image formats are supported ? + ---------------------------------- + + This module can load any image format that there is an active image module for. For q3 this would be bmp, tga and jpg. For Half-Life this would be hlw and spr. + + Version History + =============== + + v0.1 - 27/May/2002 + - Created an inital implementation of a sprite model plugin. + According to the powers that be, it seems creating a model + plugin is hackish. + It works ok, but there is no way to attach models (sprites if you will) + to non-fixedsize entities (like func_bombtarget) + Also, I can't get the alpha map stuff right so I had to invert the alpha + mask in the spr loader so that 0xff = not drawn pixel. + + v0.2 - 10/March/2003 + - Updated to coincide with Radiant 1.3.5 test builds. Also, I made sure it worked + under quake3 and it does. + + v0.3 - 10/March/2003 + - Added about box. + + ToDo + ==== + + * make sprites always face the camera (is this done in camwindow.cpp ?) + but only if the entity model doesn't have "angle" keys. At the moment + it's better to rotate the model with the angles. + + * maybe add an option to scale the sprites in the prefs ? + + * maybe convert to a new kind of class not based on model. + + * allow sprites on non-fixedsize ents + + * fix reversed alpha map in spr loader + -> is this actually broken? + + * allow an entity to have multiple models (e.g .md3 and a sprite model) + and allow the user to toggle either models on or off. + + * dynamically add the api's depending on what image loading modules are + supported by radiant. + Currently, we hard code to the list in "supportedmodelformats" (see below) + but, all these extensions are stripped when the actual image is loaded. + current the bit of code that decided what model api to use needs reworking + as it decides by looking at the extension of the model name, when in fact + we don't even need an extension. + + Previously the code fell though to use this model as the default model + plugin, but that also has issues. + + what it means is, in the .def files you must specify an image filename + that has one of the extensions listed below, but in actual fact radiant + will use any available image module to load the image. + + + e.g. you could use a model name of "sprites/target_speaker.tga" and have + a file called sprites/target_speaker.png and it would be correctly loaded + even if it not listed below in "supportedmodelformats". + + So, currently in the .def files you can just use the name + "sprites/target_speaker.spr" and it will load the file + from "sprites/target_speaker.*" which is what I propose anyone creating image sets for Q3/Wolf/etc does. +*/ + +#include "plugin.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERShadersTable g_ShadersTable; + +// ============================================================================= +// plugin implementation + +static const char *PLUGIN_NAME = "Sprite Model loading module"; + +static const char *PLUGIN_COMMANDS = "About..."; + +static const char *PLUGIN_ABOUT = "Sprite Model loading module v0.2 for GTKRadiant\n\n" + "By Hydra!"; + +char *supportedmodelformats[] = {"spr","bmp","tga","jpg","hlw",NULL}; // NULL is list delimiter + +static void add_model_apis(CSynapseClient& client) +{ + char **ext; + for (ext = supportedmodelformats; *ext != NULL; ext++) + { + client.AddAPI(MODEL_MAJOR, *ext, sizeof(_QERPlugModelTable)); + } +} + +static bool model_is_supported(const char* extension) +{ + char **ext; + for (ext = supportedmodelformats; *ext != NULL; ext++) + { + if (stricmp(extension,*ext)==0) + return true; + } + return false; +} + +void init_filetypes() +{ + char **ext; + for (ext = supportedmodelformats; *ext != NULL; ext++) + { + GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t("sprite", *ext)); + } +} + +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + init_filetypes(); // see todo list above. + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetName () +{ + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList () +{ + return (char *) PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + // NOTE: this never happens in a module + if(!strcmp(p, "About...")) + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientModel g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + add_model_apis(g_SynapseClient); // see todo list above. + + g_SynapseClient.AddAPI( PLUGIN_MAJOR, "sprite", sizeof( _QERPluginTable ) ); + g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable ); + g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable ); + g_SynapseClient.AddAPI( SHADERS_MAJOR, "*", sizeof( g_ShadersTable ), SYN_REQUIRE, &g_ShadersTable ); + + return &g_SynapseClient; +} + +bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, MODEL_MAJOR)) + { + _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable); + + if (model_is_supported(pAPI->minor_name)) // see todo list above. + { + pTable->m_pfnLoadModel = &LoadSpriteModel; + return true; + } + } + else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientModel::GetInfo() +{ + return "Sprite Model module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientModel::GetName() +{ + return "sprite"; +} diff --git a/plugins/spritemodel/plugin.h b/plugins/spritemodel/plugin.h new file mode 100644 index 00000000..e8ebe054 --- /dev/null +++ b/plugins/spritemodel/plugin.h @@ -0,0 +1,78 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Sprite Model Plugin +// +// Code by Hydra aka Dominic Clifton +// +// Based on MD3Model source code by SPoG +// + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/*! +\todo need general notice about lib purpose etc. +and the external dependencies (such as GLib, STL, mathlib etc.) +*/ + +/*! +\todo not sure about what should be used for common data structures, GLib or STL +I think STL would be better since I intend on using STL in synapse +*/ + +#include + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "imodel.h" +#include "igl.h" +#include "ifilesystem.h" +#include "ishaders.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERShadersTable g_ShadersTable; + +#define QERApp_Shader_ForName g_ShadersTable.m_pfnShader_ForName +#define QERApp_Try_Shader_ForName g_ShadersTable.m_pfnTry_Shader_ForName + +void LoadSpriteModel(entity_interfaces_t *interfaces, const char *name); + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientModel : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientModel() { } + virtual ~CSynapseClientModel() { } +}; + + +#endif // _PLUGIN_H_ diff --git a/plugins/spritemodel/spritemodel.cpp b/plugins/spritemodel/spritemodel.cpp new file mode 100644 index 00000000..42487134 --- /dev/null +++ b/plugins/spritemodel/spritemodel.cpp @@ -0,0 +1,178 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Sprite Model Plugin +// +// Code by Hydra aka Dominic Clifton +// +// Based on MD3Model source code by SPoG +// + +#include "spritemodel.h" + +void LoadSpriteModel(entity_interfaces_t *interfaces, const char *name) +{ + IShader *pShader; + + pShader = QERApp_Shader_ForName(name); + + if (!pShader) + { + Sys_Printf("ERROR: can't find shader (or image) for: %s\n", name ); + return; + } + + CSpriteModel *model = new CSpriteModel(); + model->Construct(pShader); + interfaces->pRender = (IRender*)model; + interfaces->pRender->IncRef(); + //interfaces->pSelect = (ISelect*)model; + //interfaces->pSelect->IncRef(); + interfaces->pSelect = NULL; + interfaces->pEdit = NULL; + model->DecRef(); + +} + +void CSpriteModel::Construct(IShader *pShader) +{ + m_pShader = pShader; + aabb_clear(&m_BBox); + /* + md3Surface_t *pSurface = (md3Surface_t *)(((unsigned char *)pHeader) + pHeader->ofsSurfaces); + m_nSurfaces = pHeader->numSurfaces; + CMD3Surface* surfaces = new CMD3Surface[m_nSurfaces]; + for (int i = 0; i < m_nSurfaces; i++ ) + { + surfaces[i].Construct(pSurface); + pSurface = (md3Surface_t *) ((( char * ) pSurface) + pSurface->ofsEnd); + } + m_children = surfaces; + AccumulateBBox(); + */ +} + +CSpriteModel::CSpriteModel() +{ + refCount = 1; + //m_nSurfaces = 0; + //m_children = NULL; + m_pShader = NULL; +} + +CSpriteModel::~CSpriteModel() +{ + // if(m_children) delete[] m_children; + if (m_pShader) + m_pShader->DecRef(); +} + +void CSpriteModel::Draw(int state, int rflags) const +{ + +/* + // Draw a point in the middle of the bbox + vec3_t middle = {0,0,0}; + g_QglTable.m_pfn_qglPointSize (4); + g_QglTable.m_pfn_qglColor3f (0,1,0); + g_QglTable.m_pfn_qglBegin (GL_POINTS); + g_QglTable.m_pfn_qglVertex3fv (middle); + g_QglTable.m_pfn_qglEnd (); +*/ + + qtexture_t *q = m_pShader->getTexture(); + + // convert pixels to units and divide in half again so we draw in the middle + // of the bbox. + int h = q->height / 8; + int w = q->width / 8; + + // setup opengl stuff + + g_QglTable.m_pfn_qglPushAttrib (GL_ALL_ATTRIB_BITS); // GL_ENABLE_BIT + //g_QglTable.m_pfn_qglColor3f (1,1,1); //testing + //g_QglTable.m_pfn_qglColor4f (1,1,1,1); //testing + g_QglTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, q->texture_number); + + //g_QglTable.m_pfn_qglEnable (GL_TEXTURE_2D); // FIXME: ? this forces textures, even in wireframe mode, bad... ? + + g_QglTable.m_pfn_qglAlphaFunc (GL_LESS, 1); + g_QglTable.m_pfn_qglEnable (GL_ALPHA_TEST); + + // get rid of this when sprite always faces camera + g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + g_QglTable.m_pfn_qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + // draw the sprite + +#if 0 + // using x/y axis, it appears FLAT without the proper transform and rotation. + + g_QglTable.m_pfn_qglBegin(GL_QUADS); + g_QglTable.m_pfn_qglTexCoord2f (0,0); + g_QglTable.m_pfn_qglVertex3f (0-w,0-h, 0); + g_QglTable.m_pfn_qglTexCoord2f (1,0); + g_QglTable.m_pfn_qglVertex3f ( w,0-h, 0); + g_QglTable.m_pfn_qglTexCoord2f (1,1); + g_QglTable.m_pfn_qglVertex3f ( w, h, 0); + g_QglTable.m_pfn_qglTexCoord2f (0,1); + g_QglTable.m_pfn_qglVertex3f (0-w, h, 0); + g_QglTable.m_pfn_qglEnd (); +#else + + // so draw it using y/z instead. + g_QglTable.m_pfn_qglBegin(GL_QUADS); + g_QglTable.m_pfn_qglTexCoord2f (0,0); + g_QglTable.m_pfn_qglVertex3f (0,w,h); + g_QglTable.m_pfn_qglTexCoord2f (1,0); + g_QglTable.m_pfn_qglVertex3f (0,0-w,h); + g_QglTable.m_pfn_qglTexCoord2f (1,1); + g_QglTable.m_pfn_qglVertex3f (0,0-w,0-h); + g_QglTable.m_pfn_qglTexCoord2f (0,1); + g_QglTable.m_pfn_qglVertex3f (0,w,0-h); + g_QglTable.m_pfn_qglEnd (); +#endif + + g_QglTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); + g_QglTable.m_pfn_qglPopAttrib(); +} + +/* +bool CSpriteModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t depth_start = *dist; + vec_t depth_local = *dist; + + if (aabb_test_ray(&m_BBox, ray) == 0) + return false; + + for(int i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/surface/.cvsignore b/plugins/surface/.cvsignore new file mode 100644 index 00000000..af3ce37b --- /dev/null +++ b/plugins/surface/.cvsignore @@ -0,0 +1,11 @@ +*.d +*.o +*.so +Debug +Release +*.aps +*.plg +*.bak +*.BAK +*.opt +*.ncb diff --git a/plugins/surface/surface.def b/plugins/surface/surface.def new file mode 100644 index 00000000..23328e4a --- /dev/null +++ b/plugins/surface/surface.def @@ -0,0 +1,8 @@ +; surface.def : Declares the module parameters for the DLL. + +LIBRARY "SURFACE" +DESCRIPTION 'SURFACE Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/surface/surface.vcproj b/plugins/surface/surface.vcproj new file mode 100644 index 00000000..a18bf780 --- /dev/null +++ b/plugins/surface/surface.vcproj @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/surface/surfacedialog.cpp b/plugins/surface/surfacedialog.cpp new file mode 100644 index 00000000..dcd0ff76 --- /dev/null +++ b/plugins/surface/surfacedialog.cpp @@ -0,0 +1,1925 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Surface Dialog Module +// + +// +// Nurail: Implemented to Module from the main Radiant Surface Dialog code +// + + +#include +#include + +#include "surfdlg_plugin.h" + + + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +#include "gtkr_vector.h" + +vector g_texdef_face_vector; + +inline texdef_to_face_t* get_texdef_face_list() +{ + return &(*g_texdef_face_vector.begin()); +} + +inline unsigned int texdef_face_list_empty() +{ + return g_texdef_face_vector.empty(); +} + +inline unsigned int texdef_face_list_size() +{ + return g_texdef_face_vector.size(); +} + +// For different faces having different values +bool is_HShift_conflicting; +bool is_VShift_conflicting; +bool is_HScale_conflicting; +bool is_VScale_conflicting; +bool is_Rotate_conflicting; +bool is_TextureName_conflicting; + +void ShowDlg(); +void HideDlg(); +void SetTexMods(); +void GetTexMods(bool b_SetUndoPoint = FALSE); +void BuildDialog(); +void FitAll(); +void InitDefaultIncrement(texdef_t *); +void DoSnapTToGrid(float hscale, float vscale); +// called to perform a fitting from the outside (shortcut key) +void SurfaceDialogFitAll(); + + +// Dialog Data +int m_nHeight; +int m_nWidth; + +// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +int m_nUndoId; + + +texturewin_t *texturewin; +texdef_t *l_pIncrement; +texdef_t texdef_offset; +texdef_t texdef_SI_values; + +// For Texture Entry, activate only on entry change +char old_texture_entry[128]; + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; + +// when TRUE, this thing means the surface inspector is currently being displayed +bool g_surfwin = FALSE; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +GtkWidget* create_SurfaceInspector (void); +GtkWidget *SurfaceInspector = NULL; + +GtkWidget *m_pWidget; +GtkWidget *GetWidget () { return SurfaceInspector; } +GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } +void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } +GtkWidget *GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } + +// Spins for FitTexture +GtkWidget *spin_width; +GtkWidget *spin_height; + + +GtkWidget *texture_combo; +GtkWidget *texture_combo_entry; + +GtkWidget *match_grid_button; +GtkWidget *lock_valuechange_togglebutton; + +GtkObject *hshift_value_spinbutton_adj; +GtkWidget *hshift_value_spinbutton; +GtkObject *vshift_value_spinbutton_adj; +GtkWidget *vshift_value_spinbutton; +GtkObject *hscale_value_spinbutton_adj; +GtkWidget *hscale_value_spinbutton; +GtkObject *vscale_value_spinbutton_adj; +GtkWidget *vscale_value_spinbutton; +GtkObject *rotate_value_spinbutton_adj; +GtkWidget *rotate_value_spinbutton; + +GtkObject *hshift_offset_spinbutton_adj; +GtkWidget *hshift_offset_spinbutton; +GtkObject *vshift_offset_spinbutton_adj; +GtkWidget *vshift_offset_spinbutton; +GtkObject *hscale_offset_spinbutton_adj; +GtkWidget *hscale_offset_spinbutton; +GtkObject *vscale_offset_spinbutton_adj; +GtkWidget *vscale_offset_spinbutton; +GtkObject *rotate_offset_spinbutton_adj; +GtkWidget *rotate_offset_spinbutton; + +GtkObject *hshift_step_spinbutton_adj; +GtkWidget *hshift_step_spinbutton; +GtkObject *vshift_step_spinbutton_adj; +GtkWidget *vshift_step_spinbutton; +GtkObject *hscale_step_spinbutton_adj; +GtkWidget *hscale_step_spinbutton; +GtkObject *vscale_step_spinbutton_adj; +GtkWidget *vscale_step_spinbutton; +GtkObject *rotate_step_spinbutton_adj; +GtkWidget *rotate_step_spinbutton; + +GtkObject *fit_width_spinbutton_adj; +GtkWidget *fit_width_spinbutton; +GtkObject *fit_height_spinbutton_adj; +GtkWidget *fit_height_spinbutton; +GtkWidget *fit_button; +GtkWidget *axial_button; + +GtkWidget *done_button; +GtkWidget *apply_button; +GtkWidget *cancel_button; + +// Callbacks +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); + +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_button_clicked (GtkButton *button, gpointer user_data); +static void on_axial_button_clicked (GtkButton *button, gpointer user_data); + +static void on_done_button_clicked (GtkButton *button, gpointer user_data); +static void on_apply_button_clicked (GtkButton *button, gpointer user_data); +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + + +void IsFaceConflicting() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char buf[12]; + char texture_name[128]; + + if (texdef_face_list_empty()) + { + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); + return; + } + + g_bListenChanged = FALSE; + + tmp_texdef = &get_texdef_face_list()->texdef; + + strcpy(texture_name, tmp_texdef->GetName() ); + + texdef_SI_values.shift[0] = tmp_texdef->shift[0]; + texdef_SI_values.shift[1] = tmp_texdef->shift[1]; + texdef_SI_values.scale[0] = tmp_texdef->scale[0]; + texdef_SI_values.scale[1] = tmp_texdef->scale[1]; + texdef_SI_values.rotate = tmp_texdef->rotate; + texdef_SI_values.SetName( texture_name ); + + is_HShift_conflicting = FALSE; + is_VShift_conflicting = FALSE; + is_HScale_conflicting = FALSE; + is_VScale_conflicting = FALSE; + is_Rotate_conflicting = FALSE; + is_TextureName_conflicting = FALSE; + + if (texdef_face_list_size() > 1) + { + temp_texdef_face_list = get_texdef_face_list()->next; + + for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) + is_HShift_conflicting = TRUE; + + if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) + is_VShift_conflicting = TRUE; + + if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) + is_HScale_conflicting = TRUE; + + if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) + is_VScale_conflicting = TRUE; + + if ( texdef_SI_values.rotate != tmp_texdef->rotate ) + is_Rotate_conflicting = TRUE; + + if ( strcmp( texture_name, tmp_texdef->GetName() ) ) + is_TextureName_conflicting = TRUE; + } + } + + if(is_HShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); + + if(is_VShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); + + if(is_HScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); + + if(is_VScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); + + if(is_Rotate_conflicting) + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); + + g_bListenChanged = TRUE; +} + +#define MAX_NUM_LIST_ITEMS 15 +static void PopulateTextureComboList() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char blank[1]; + GList *items = NULL; + GList *tmp_item; + int num_of_list_items = 0; + + blank[0] = 0; + + if (texdef_face_list_empty()) + { + items = g_list_append (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + else if ( !is_TextureName_conflicting ) + { + temp_texdef_face_list = get_texdef_face_list(); + tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, tmp_texdef->GetName()); + } + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + // Need to do a string compare, hence the custom search + if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) + { + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + num_of_list_items++; + } + // Make sure the combo list isn't too long + if (num_of_list_items >= MAX_NUM_LIST_ITEMS) + break; + } + // If this isn't added last (to the top of the list), g_list_find freaks. + items = g_list_prepend (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); + g_list_free(items); + +} + +static void ZeroOffsetValues() +{ + texdef_offset.shift[0] = 0.0; + texdef_offset.shift[1] = 0.0; + texdef_offset.scale[0] = 0.0; + texdef_offset.scale[1] = 0.0; + texdef_offset.rotate = 0.0; +} + +static void GetTexdefInfo_from_Radiant() +{ + g_texdef_face_vector.clear(); + + unsigned int count = GetSelectedFaceCountfromBrushes(); + if(count == 0) + count = GetSelectedFaceCount(); + + g_texdef_face_vector.resize(count); + + if (!texdef_face_list_empty()) + { + texdef_to_face_t* p = get_texdef_face_list(); + GetSelFacesTexdef( get_texdef_face_list() ); + } + + IsFaceConflicting(); + PopulateTextureComboList(); + ZeroOffsetValues(); +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + HideDlg(); + return TRUE; +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + l_pIncrement = Get_SI_Inc(); + + if (hscale == 0.0f) + { + hscale = 0.5f; + } + if (vscale == 0.0f) + { + vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = GridSize() / hscale; + l_pIncrement->shift[1] = GridSize() / vscale; + // now some update work + // FIXME: doesn't look good here, seems to be called several times + SetTexMods(); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + if (!SurfaceInspector) + return; + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + if (g_surfwin) + { +#ifdef DBG_SI + Sys_Printf("UpdateSurfaceDialog\n"); +#endif + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } + +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + if (!SurfaceInspector) + create_SurfaceInspector (); + + ShowDlg(); + SetTexMods (); +} + +void ToggleSurface() +{ +#ifdef DBG_SI + Sys_Printf("ToggleSurface Module\n"); +#endif + if (!g_surfwin) + DoSurface (); + else + on_cancel_button_clicked(NULL, NULL); +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + DoSurface(); + FitAll(); +} + +// ============================================================================= +// SurfaceDialog class + +void ShowDlg() +{ + + if(!SurfaceInspector) + create_SurfaceInspector(); + else + gtk_widget_show (SurfaceInspector); + + GetTexdefInfo_from_Radiant(); + GetTexMods(TRUE); // Set Initial Undo Point + g_surfwin = TRUE; +} + +void HideDlg() +{ + g_surfwin = FALSE; + gtk_widget_hide (SurfaceInspector); +} + + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void BuildDialog () +{ + if ( !SurfaceInspector ) + create_SurfaceInspector(); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +=============== +*/ + +void SetTexMods() +{ + texdef_t *pt; + GtkSpinButton *spin; + GtkAdjustment *adjust; + + texturewin = Texturewin (); + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + pt = &texturewin->texdef; + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + texdef_offset.SetName(SHADER_NOT_FOUND); + + + spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); + + spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + + + spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); + + spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + + + spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); + + spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + + + spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); + + spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + + + spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.rotate); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); + + spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + + + g_bListenChanged = true; + + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = texturewin->texdef; +} + +/* +============== +GetTexMods + +Shows any changes to the main Radiant windows +=============== +*/ +void GetTexMods(bool b_SetUndoPoint) +{ + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg GetTexMods\n"); +#endif + + if ( !texdef_face_list_empty() ) + { + g_bListenUpdate=FALSE; + SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint, false ); + g_bListenUpdate=TRUE; + + if (b_SetUndoPoint) + m_nUndoId = Undo_GetUndoId(); + } +} + +void FitAll() +{ + on_fit_button_clicked(NULL, NULL); +} + + +//////////////////////////////////////////////////////////////////// +// +// GUI Section +// +//////////////////////////////////////////////////////////////////// + +GtkWidget* create_SurfaceInspector (void) +{ + + GtkWidget *label; + GtkWidget *hseparator; + GtkWidget *eventbox; + + GtkWidget *viewport8; + GtkWidget *viewport9; + GtkWidget *viewport2; + GtkWidget *viewport7; + GtkWidget *viewport5; + GtkWidget *viewport6; + GtkWidget *viewport10; + + GtkWidget *table1; + GtkWidget *table4; + GtkWidget *table5; + GtkWidget *table7; + + GtkWidget *alignment1; + GtkWidget *alignment2; + GtkWidget *alignment3; + + GtkWidget *vbox7; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hbox4; + + GtkWidget *image1; + GtkWidget *image2; + GtkWidget *image3; + + GtkWidget *hbuttonbox1; + + SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); + gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); + + SetWinPos_from_Prefs(SurfaceInspector); + + viewport8 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport8); + gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (viewport8), vbox7); + + viewport9 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport9); + gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (viewport9), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); + + label = gtk_label_new ("Texture: "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + texture_combo = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), + "KeepMeAround", texture_combo); + gtk_combo_disable_activate ( (GtkCombo*) texture_combo); + gtk_widget_show (texture_combo); + gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); + + texture_combo_entry = GTK_COMBO (texture_combo)->entry; + gtk_widget_show (texture_combo_entry); + gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport2); + gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); + + table1 = gtk_table_new (13, 4, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (viewport2), table1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Offset"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); + gtk_widget_show (match_grid_button); + gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); + + label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new (" H Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Rotate: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("H Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); + gtk_widget_show (lock_valuechange_togglebutton); + gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); + + // Value Spins + hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); + + vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); + + hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); + + vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); + + rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); + gtk_widget_show (rotate_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); + + // Offset Spins + hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (hshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + + vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (vshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + + hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (hscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + + vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (vscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + + rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); + gtk_widget_show (rotate_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + + // Step Spins + hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); + gtk_widget_show (rotate_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + viewport7 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport7); + gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); + + table4 = gtk_table_new (4, 7, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (viewport7), table4); + + viewport5 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport5); + gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); + + table5 = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (viewport5), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 2); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); + gtk_widget_show (fit_width_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); + + fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); + gtk_widget_show (fit_height_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 3, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 4, 0); + + fit_button = gtk_button_new_with_mnemonic (" Fit "); + gtk_widget_show (fit_button); + gtk_container_add (GTK_CONTAINER (eventbox), fit_button); + + viewport6 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport6); + gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); + + table7 = gtk_table_new (2, 1, FALSE); + gtk_widget_show (table7); + gtk_container_add (GTK_CONTAINER (viewport6), table7); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + axial_button = gtk_button_new_with_mnemonic ("Axial"); + gtk_widget_show (axial_button); + gtk_container_add (GTK_CONTAINER (eventbox), axial_button); + gtk_widget_set_size_request (axial_button, 56, 29); + gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); + + viewport10 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport10); + gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + + done_button = gtk_button_new (); + gtk_widget_show (done_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); + GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (done_button), alignment1); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (alignment1), hbox2); + + image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Done"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + apply_button = gtk_button_new (); + gtk_widget_show (apply_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); + GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); + + alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (apply_button), alignment3); + + hbox4 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (alignment3), hbox4); + + image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image3); + gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Apply"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + cancel_button = gtk_button_new (); + gtk_widget_show (cancel_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); + + hbox3 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (alignment2), hbox3); + + image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Cancel"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + + g_signal_connect ( (gpointer) SurfaceInspector, + "delete_event", + G_CALLBACK (delete_event_callback), + NULL ); + g_signal_connect ((gpointer) SurfaceInspector, "destroy", + G_CALLBACK (gtk_widget_destroy), + NULL); + + g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", + G_CALLBACK (on_texture_combo_entry_key_press_event), + NULL); + g_signal_connect ((gpointer) texture_combo_entry, "activate", + G_CALLBACK (on_texture_combo_entry_activate), + NULL); + + + g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_hshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_vshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_hscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_vscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", + G_CALLBACK (on_rotate_offset_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", + G_CALLBACK (on_hshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", + G_CALLBACK (on_vshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", + G_CALLBACK (on_hscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", + G_CALLBACK (on_vscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", + G_CALLBACK (on_rotate_value_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", + G_CALLBACK (on_hshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", + G_CALLBACK (on_vshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", + G_CALLBACK (on_hscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", + G_CALLBACK (on_vscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", + G_CALLBACK (on_rotate_step_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) match_grid_button, "clicked", + G_CALLBACK (on_match_grid_button_clicked), + NULL); + g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", + G_CALLBACK (on_lock_valuechange_togglebutton_toggled), + NULL); + + g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", + G_CALLBACK (on_fit_width_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", + G_CALLBACK (on_fit_height_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_button, "clicked", + G_CALLBACK (on_fit_button_clicked), + NULL); + + g_signal_connect ((gpointer) axial_button, "clicked", + G_CALLBACK (on_axial_button_clicked), + NULL); + + g_signal_connect ((gpointer) done_button, "clicked", + G_CALLBACK (on_done_button_clicked), + NULL); + g_signal_connect ((gpointer) apply_button, "clicked", + G_CALLBACK (on_apply_button_clicked), + NULL); + g_signal_connect ((gpointer) cancel_button, "clicked", + G_CALLBACK (on_cancel_button_clicked), + NULL); + + + return SurfaceInspector; +} + + +// Texture Combo +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + // Have Tab activate selection as well as Return + if (event->keyval == GDK_Tab) + g_signal_emit_by_name ( texture_combo_entry, "activate" ); + + return FALSE; +} + +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + char text[128] = { 0 }; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + // activate only on entry change + strcpy( text, gtk_entry_get_text(entry)); + if ( strcmp( old_texture_entry, text )) + { + // Check for spaces in shader name + if (text[0] <= ' ' || strchr(text, ' ')) + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + strcpy( old_texture_entry, text ); + tmp_texdef->SetName( text ); + } + GetTexMods(); + } + } + } +} + +// Offset Spins +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HShift_conflicting) + tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; + else + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + } + GetTexMods(); + } +} + +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VShift_conflicting) + tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; + else + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + } + GetTexMods(); + } + +} + +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HScale_conflicting) + tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; + else + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + } + GetTexMods(); + } + + +} + +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VScale_conflicting) + tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; + else + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + } + GetTexMods(); + } + +} + +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_Rotate_conflicting) + tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; + else + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + } + GetTexMods(); + } + +} + + +// Match Grid +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) +{ + float hscale, vscale; + + if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) + hscale = 0.0; + else + hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) + vscale = 0.0; + else + vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + DoSnapTToGrid (hscale, vscale); +} + + +// Lock out changes to Value +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) +{ + bool is_Locked; + + is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); + + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); +} + + +// Value Spins +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + is_HShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + is_VShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + is_HScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + is_VScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + is_Rotate_conflicting = FALSE; + } + GetTexMods(); + } +} + + +// Step Spins +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[0] = val; +} + +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged VShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[1] = val; +} + +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[0] = val; +} + +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[1] = val; +} + +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->rotate = val; +} + + +// Fit Texture +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); +} + +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); +} + +static void on_fit_button_clicked (GtkButton *button, gpointer user_data) +{ + FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); + Sys_UpdateWindows(W_ALL); +} + + +// Axial Button +static void on_axial_button_clicked (GtkButton *button, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_texdef->shift[0] = 0.0; + tmp_texdef->shift[1] = 0.0; + tmp_texdef->scale[0] = 0.5; + tmp_texdef->scale[1] = 0.5; + tmp_texdef->rotate = 0.0; + } + } + + SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); + Sys_UpdateWindows(W_ALL); +} + + +// Action Buttons +static void on_done_button_clicked (GtkButton *button, gpointer user_data) +{ + if ( !texdef_face_list_empty() ) + GetTexMods(TRUE); + HideDlg(); + Sys_UpdateWindows(W_ALL); +} + +static void on_apply_button_clicked (GtkButton *button, gpointer user_data) +{ + if (!g_bListenChanged) + return; + if ( !texdef_face_list_empty() ) + { + GetTexMods (TRUE); + Sys_UpdateWindows(W_CAMERA); + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } +} + +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) +{ + texturewin = Texturewin (); + texturewin->texdef = g_old_texdef; + // cancel the last do if we own it + if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(TRUE); + g_bListenUpdate = true; + m_nUndoId = 0; + } + HideDlg(); +} + + diff --git a/plugins/surface/surfacedialog.h b/plugins/surface/surfacedialog.h new file mode 100644 index 00000000..96ab3c79 --- /dev/null +++ b/plugins/surface/surfacedialog.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SURFACEDIALOG_H_ +#define _SURFACEDIALOG_H_ + +void UpdateSurfaceDialog (); +void DoSurface (); +void ToggleSurface (); +void SurfaceDlgFitAll (); +GtkWidget *Get_SI_Module_Widget (); + +#endif // _SURFACEDIALOG_H_ diff --git a/plugins/surface/surfdlg_plugin.cpp b/plugins/surface/surfdlg_plugin.cpp new file mode 100644 index 00000000..62569197 --- /dev/null +++ b/plugins/surface/surfdlg_plugin.cpp @@ -0,0 +1,122 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "surfdlg_plugin.h" +#include "surfacedialog.h" + +#include "synapse.h" + +class CSynapseClient_SurfDLG : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + bool OnActivate(); + + CSynapseClient_SurfDLG() { } + virtual ~CSynapseClient_SurfDLG() { } +}; + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; +_QERUndoTable g_UndoTable; +_QERAppSurfaceTable g_AppSurfaceTable; +_QERSelectedFaceTable g_SelectedFaceTable; +_QERShadersTable g_ShadersTable; +_QERAppShadersTable g_AppShadersTable; +_QERAppDataTable g_AppDataTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClient_SurfDLG g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(SURFACEDIALOG_MAJOR, "quake3", sizeof(_QERPlugSurfaceTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); + g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); + + return &g_SynapseClient; +} + +bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) + { + _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "quake3")) + { + pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; + pSurfDialogTable->m_pfnDoSurface = &DoSurface; + pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; + pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; + pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClient_SurfDLG::GetInfo() +{ + return "Surface Dialog (Quake 3) module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClient_SurfDLG::GetName() +{ + return "surface"; +} + +bool CSynapseClient_SurfDLG::OnActivate() +{ + return true; +} diff --git a/plugins/surface/surfdlg_plugin.h b/plugins/surface/surfdlg_plugin.h new file mode 100644 index 00000000..89129d45 --- /dev/null +++ b/plugins/surface/surfdlg_plugin.h @@ -0,0 +1,94 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _SURFDLG_PLUGIN_H_ +#define _SURFDLG_PLUGIN_H_ + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +#include "qerplugin.h" +#include "synapse.h" +#include "iselectedface.h" +#include "iundo.h" +#include "ishaders.h" +#include "mathlib.h" +#include "missing.h" +#include "idata.h" + +#include "isurfaceplugin.h" + +class SurfaceDialog : public IPluginTexdef +{ + int refCount; +public: + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () { if ( --refCount <= 0 ) delete this; } +}; + +extern _QERFuncTable_1 g_FuncTable; +extern _QERUndoTable g_UndoTable; +extern _QERAppSurfaceTable g_AppSurfaceTable; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERShadersTable g_ShadersTable; +extern _QERAppShadersTable g_AppShadersTable; +extern _QERAppDataTable g_AppDataTable; + +#define GetSelectedFaceCount g_SelectedFaceTable.m_pfnGetSelectedFaceCount + +#define Undo_Undo g_UndoTable.m_pfnUndo_Undo +#define Undo_GetUndoId g_UndoTable.m_pfnUndo_GetUndoId + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf +#define Sys_UpdateWindows g_FuncTable.m_pfnSysUpdateWindows + + +#define Select_FitTexture g_AppSurfaceTable.m_pfnSelect_FitTexture +#define Get_SI_Inc g_AppSurfaceTable.m_pfnQERApp_QeglobalsSavedinfo_SIInc +#define GridSize g_AppSurfaceTable.m_pfnQeglobalsGetGridSize +#define FaceList_FitTexture g_AppSurfaceTable.m_pfnFaceList_FitTexture +#define GetMainWindow g_AppSurfaceTable.m_pfnGetMainWindow +#define GetSelectedFaceCountfromBrushes g_AppSurfaceTable.m_pfnGetSelectedFaceCountfromBrushes +#define GetSelFacesTexdef g_AppSurfaceTable.m_pfnGetSelFacesTexdef +#define SetTexdef_FaceList g_AppSurfaceTable.m_pfnSetTexdef_FaceList +#define SetWinPos_from_Prefs g_AppSurfaceTable.m_pfnSetWinPos_From_Prefs + +#define Texturewin g_AppShadersTable.m_pfnQeglobalsTexturewin + +#endif // _SURFDLG_PLUGIN_H_ + diff --git a/plugins/surface_heretic2/surface_heretic2.def b/plugins/surface_heretic2/surface_heretic2.def new file mode 100644 index 00000000..382ffcb2 --- /dev/null +++ b/plugins/surface_heretic2/surface_heretic2.def @@ -0,0 +1,8 @@ +; surface_heretic2.def : Declares the module parameters for the DLL. + +LIBRARY "Surface_Heretic2" +DESCRIPTION 'Surface_Heretic2 Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/surface_heretic2/surface_heretic2.vcproj b/plugins/surface_heretic2/surface_heretic2.vcproj new file mode 100644 index 00000000..a8713dec --- /dev/null +++ b/plugins/surface_heretic2/surface_heretic2.vcproj @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/surface_heretic2/surfacedialog.cpp b/plugins/surface_heretic2/surfacedialog.cpp new file mode 100644 index 00000000..bd614564 --- /dev/null +++ b/plugins/surface_heretic2/surfacedialog.cpp @@ -0,0 +1,1940 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Surface Dialog Module +// + +// +// Nurail: Implemented to Module from the main Radiant Surface Dialog code +// + + +#include +#include + +#include "surfdlg_plugin.h" + + + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +#include "gtkr_vector.h" + +std::vector g_texdef_face_vector; + +inline texdef_to_face_t* get_texdef_face_list() +{ + return &(*g_texdef_face_vector.begin()); +} + +inline unsigned int texdef_face_list_empty() +{ + return g_texdef_face_vector.empty(); +} + +inline unsigned int texdef_face_list_size() +{ + return g_texdef_face_vector.size(); +} + +// For different faces having different values +bool is_HShift_conflicting; +bool is_VShift_conflicting; +bool is_HScale_conflicting; +bool is_VScale_conflicting; +bool is_Rotate_conflicting; +bool is_TextureName_conflicting; + +void ShowDlg(); +void HideDlg(); +void SetTexMods(); +void GetTexMods(bool b_SetUndoPoint = FALSE); +void BuildDialog(); +void FitAll(); +void InitDefaultIncrement(texdef_t *); +void DoSnapTToGrid(float hscale, float vscale); +// called to perform a fitting from the outside (shortcut key) +void SurfaceDialogFitAll(); + +// Heretic2 Flags Functions +void SetFlagButtons_Heretic2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty); +void SetChangeInFlags_Face_Heretic2 (texdef_to_face_t *texdef_face_list); +GtkWidget* Create_Heretic2FlagsDialog (GtkWidget* surfacedialog_widget); + + +// Dialog Data +int m_nHeight; +int m_nWidth; + +// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +int m_nUndoId; + + +texturewin_t *texturewin; +texdef_t *l_pIncrement; +texdef_t texdef_offset; +texdef_t texdef_SI_values; + +// For Texture Entry, activate only on entry change +char old_texture_entry[128]; + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; + +// when TRUE, this thing means the surface inspector is currently being displayed +bool g_surfwin = FALSE; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +GtkWidget* create_SurfaceInspector (void); +GtkWidget *SurfaceInspector = NULL; + +GtkWidget *m_pWidget; +GtkWidget *GetWidget () { return SurfaceInspector; } +GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } +void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } +GtkWidget *GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } + +// Spins for FitTexture +GtkWidget *spin_width; +GtkWidget *spin_height; + + +GtkWidget *texture_combo; +GtkWidget *texture_combo_entry; + +GtkWidget *match_grid_button; +GtkWidget *lock_valuechange_togglebutton; + +GtkObject *hshift_value_spinbutton_adj; +GtkWidget *hshift_value_spinbutton; +GtkObject *vshift_value_spinbutton_adj; +GtkWidget *vshift_value_spinbutton; +GtkObject *hscale_value_spinbutton_adj; +GtkWidget *hscale_value_spinbutton; +GtkObject *vscale_value_spinbutton_adj; +GtkWidget *vscale_value_spinbutton; +GtkObject *rotate_value_spinbutton_adj; +GtkWidget *rotate_value_spinbutton; + +GtkObject *hshift_offset_spinbutton_adj; +GtkWidget *hshift_offset_spinbutton; +GtkObject *vshift_offset_spinbutton_adj; +GtkWidget *vshift_offset_spinbutton; +GtkObject *hscale_offset_spinbutton_adj; +GtkWidget *hscale_offset_spinbutton; +GtkObject *vscale_offset_spinbutton_adj; +GtkWidget *vscale_offset_spinbutton; +GtkObject *rotate_offset_spinbutton_adj; +GtkWidget *rotate_offset_spinbutton; + +GtkObject *hshift_step_spinbutton_adj; +GtkWidget *hshift_step_spinbutton; +GtkObject *vshift_step_spinbutton_adj; +GtkWidget *vshift_step_spinbutton; +GtkObject *hscale_step_spinbutton_adj; +GtkWidget *hscale_step_spinbutton; +GtkObject *vscale_step_spinbutton_adj; +GtkWidget *vscale_step_spinbutton; +GtkObject *rotate_step_spinbutton_adj; +GtkWidget *rotate_step_spinbutton; + +GtkObject *fit_width_spinbutton_adj; +GtkWidget *fit_width_spinbutton; +GtkObject *fit_height_spinbutton_adj; +GtkWidget *fit_height_spinbutton; +GtkWidget *fit_button; +GtkWidget *axial_button; + +GtkWidget *done_button; +GtkWidget *apply_button; +GtkWidget *cancel_button; + +// Callbacks +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); + +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_button_clicked (GtkButton *button, gpointer user_data); +static void on_axial_button_clicked (GtkButton *button, gpointer user_data); + +static void on_done_button_clicked (GtkButton *button, gpointer user_data); +static void on_apply_button_clicked (GtkButton *button, gpointer user_data); +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + + +void IsFaceConflicting() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char buf[12]; + char texture_name[128]; + + if (texdef_face_list_empty()) + { + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); + return; + } + + g_bListenChanged = FALSE; + + tmp_texdef = &get_texdef_face_list()->texdef; + + strcpy(texture_name, tmp_texdef->GetName() ); + + texdef_SI_values.shift[0] = tmp_texdef->shift[0]; + texdef_SI_values.shift[1] = tmp_texdef->shift[1]; + texdef_SI_values.scale[0] = tmp_texdef->scale[0]; + texdef_SI_values.scale[1] = tmp_texdef->scale[1]; + texdef_SI_values.rotate = tmp_texdef->rotate; + texdef_SI_values.SetName( texture_name ); + + is_HShift_conflicting = FALSE; + is_VShift_conflicting = FALSE; + is_HScale_conflicting = FALSE; + is_VScale_conflicting = FALSE; + is_Rotate_conflicting = FALSE; + is_TextureName_conflicting = FALSE; + + if (texdef_face_list_size() > 1) + { + temp_texdef_face_list = get_texdef_face_list()->next; + + for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) + is_HShift_conflicting = TRUE; + + if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) + is_VShift_conflicting = TRUE; + + if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) + is_HScale_conflicting = TRUE; + + if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) + is_VScale_conflicting = TRUE; + + if ( texdef_SI_values.rotate != tmp_texdef->rotate ) + is_Rotate_conflicting = TRUE; + + if ( strcmp( texture_name, tmp_texdef->GetName() ) ) + is_TextureName_conflicting = TRUE; + } + } + + if(is_HShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); + + if(is_VShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); + + if(is_HScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); + + if(is_VScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); + + if(is_Rotate_conflicting) + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); + + g_bListenChanged = TRUE; +} + +#define MAX_NUM_LIST_ITEMS 15 +static void PopulateTextureComboList() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char blank[1]; + GList *items = NULL; + GList *tmp_item; + int num_of_list_items = 0; + + blank[0] = 0; + + if (texdef_face_list_empty()) + { + items = g_list_append (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + else if ( !is_TextureName_conflicting ) + { + temp_texdef_face_list = get_texdef_face_list(); + tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, tmp_texdef->GetName()); + } + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + // Need to do a string compare, hence the custom search + if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) + { + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + num_of_list_items++; + } + // Make sure the combo list isn't too long + if (num_of_list_items >= MAX_NUM_LIST_ITEMS) + break; + } + // If this isn't added last (to the top of the list), g_list_find freaks. + items = g_list_prepend (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); + g_list_free(items); + +} + +static void ZeroOffsetValues() +{ + texdef_offset.shift[0] = 0.0; + texdef_offset.shift[1] = 0.0; + texdef_offset.scale[0] = 0.0; + texdef_offset.scale[1] = 0.0; + texdef_offset.rotate = 0.0; +} + +static void GetTexdefInfo_from_Radiant() +{ + g_texdef_face_vector.clear(); + + unsigned int count = GetSelectedFaceCountfromBrushes(); + if(count == 0) + count = GetSelectedFaceCount(); + + g_texdef_face_vector.resize(count); + + if (!texdef_face_list_empty()) + { + texdef_to_face_t* p = get_texdef_face_list(); + GetSelFacesTexdef( get_texdef_face_list() ); + } + + IsFaceConflicting(); + PopulateTextureComboList(); + ZeroOffsetValues(); + if ( texdef_face_list_empty() ) + SetFlagButtons_Heretic2( get_texdef_face_list() , TRUE); + else + SetFlagButtons_Heretic2( get_texdef_face_list() , FALSE); + +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + HideDlg(); + return TRUE; +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + l_pIncrement = Get_SI_Inc(); + + if (hscale == 0.0f) + { + hscale = 0.5f; + } + if (vscale == 0.0f) + { + vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = GridSize() / hscale; + l_pIncrement->shift[1] = GridSize() / vscale; + // now some update work + // FIXME: doesn't look good here, seems to be called several times + SetTexMods(); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + if (!SurfaceInspector) + return; + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + if (g_surfwin) + { +#ifdef DBG_SI + Sys_Printf("UpdateSurfaceDialog\n"); +#endif + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } + +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + if (!SurfaceInspector) + create_SurfaceInspector (); + + ShowDlg(); + SetTexMods (); +} + +void ToggleSurface() +{ +#ifdef DBG_SI + Sys_Printf("ToggleSurface Module\n"); +#endif + if (!g_surfwin) + DoSurface (); + else + on_cancel_button_clicked(NULL, NULL); +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + DoSurface(); + FitAll(); +} + +// ============================================================================= +// SurfaceDialog class + +void ShowDlg() +{ + + if(!SurfaceInspector) + create_SurfaceInspector(); + else + gtk_widget_show (SurfaceInspector); + + GetTexdefInfo_from_Radiant(); + GetTexMods(TRUE); // Set Initial Undo Point + g_surfwin = TRUE; +} + +void HideDlg() +{ + g_surfwin = FALSE; + gtk_widget_hide (SurfaceInspector); +} + + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void BuildDialog () +{ + if ( !SurfaceInspector ) + create_SurfaceInspector(); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +=============== +*/ + +void SetTexMods() +{ + texdef_t *pt; + GtkSpinButton *spin; + GtkAdjustment *adjust; + + texturewin = Texturewin (); + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + pt = &texturewin->texdef; + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + texdef_offset.SetName(SHADER_NOT_FOUND); + + + spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); + + spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + + + spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); + + spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + + + spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); + + spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + + + spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); + + spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + + + spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.rotate); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); + + spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + + + g_bListenChanged = true; + + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = texturewin->texdef; +} + +/* +============== +GetTexMods + +Shows any changes to the main Radiant windows +=============== +*/ +void GetTexMods(bool b_SetUndoPoint) +{ + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg GetTexMods\n"); +#endif + + if ( !texdef_face_list_empty() ) + { + g_bListenUpdate=FALSE; + SetChangeInFlags_Face_Heretic2 ( get_texdef_face_list() ); + SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint ); + g_bListenUpdate=TRUE; + + if (b_SetUndoPoint) + m_nUndoId = Undo_GetUndoId(); + } +} + +void FitAll() +{ + on_fit_button_clicked(NULL, NULL); +} + + +//////////////////////////////////////////////////////////////////// +// +// GUI Section +// +//////////////////////////////////////////////////////////////////// + +GtkWidget* create_SurfaceInspector (void) +{ + + GtkWidget *label; + GtkWidget *hseparator; + GtkWidget *eventbox; + + GtkWidget *viewport8; + GtkWidget *viewport9; + GtkWidget *viewport2; + GtkWidget *viewport7; + GtkWidget *viewport5; + GtkWidget *viewport6; + GtkWidget *viewport10; + + GtkWidget *table1; + GtkWidget *table4; + GtkWidget *table5; + GtkWidget *table7; + + GtkWidget *alignment1; + GtkWidget *alignment2; + GtkWidget *alignment3; + + GtkWidget *vbox7; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hbox4; + + GtkWidget *image1; + GtkWidget *image2; + GtkWidget *image3; + + GtkWidget *hbuttonbox1; + + SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); + gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); + + SetWinPos_from_Prefs(SurfaceInspector); + + viewport8 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport8); + gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (viewport8), vbox7); + + viewport9 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport9); + gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (viewport9), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); + + label = gtk_label_new ("Texture: "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + texture_combo = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), + "KeepMeAround", texture_combo); + gtk_combo_disable_activate ( (GtkCombo*) texture_combo); + gtk_widget_show (texture_combo); + gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); + + texture_combo_entry = GTK_COMBO (texture_combo)->entry; + gtk_widget_show (texture_combo_entry); + gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport2); + gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); + + table1 = gtk_table_new (13, 4, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (viewport2), table1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Offset"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); + gtk_widget_show (match_grid_button); + gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); + + label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new (" H Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Rotate: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("H Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); + gtk_widget_show (lock_valuechange_togglebutton); + gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); + + // Value Spins + hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); + + vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); + + hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); + + vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); + + rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); + gtk_widget_show (rotate_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); + + // Offset Spins + hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (hshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + + vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (vshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + + hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (hscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + + vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (vscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + + rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); + gtk_widget_show (rotate_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + + // Step Spins + hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); + gtk_widget_show (rotate_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + viewport7 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport7); + gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); + + table4 = gtk_table_new (4, 7, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (viewport7), table4); + + viewport5 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport5); + gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); + + table5 = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (viewport5), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 2); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); + gtk_widget_show (fit_width_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); + + fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); + gtk_widget_show (fit_height_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 3, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 4, 0); + + fit_button = gtk_button_new_with_mnemonic (" Fit "); + gtk_widget_show (fit_button); + gtk_container_add (GTK_CONTAINER (eventbox), fit_button); + + viewport6 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport6); + gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); + + table7 = gtk_table_new (2, 1, FALSE); + gtk_widget_show (table7); + gtk_container_add (GTK_CONTAINER (viewport6), table7); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + axial_button = gtk_button_new_with_mnemonic ("Axial"); + gtk_widget_show (axial_button); + gtk_container_add (GTK_CONTAINER (eventbox), axial_button); + gtk_widget_set_size_request (axial_button, 56, 29); + gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); + + // Fit in Flags sub-dialog + Create_Heretic2FlagsDialog(vbox7); + + viewport10 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport10); + gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + + done_button = gtk_button_new (); + gtk_widget_show (done_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); + GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (done_button), alignment1); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (alignment1), hbox2); + + image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Done"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + apply_button = gtk_button_new (); + gtk_widget_show (apply_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); + GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); + + alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (apply_button), alignment3); + + hbox4 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (alignment3), hbox4); + + image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image3); + gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Apply"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + cancel_button = gtk_button_new (); + gtk_widget_show (cancel_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); + + hbox3 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (alignment2), hbox3); + + image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Cancel"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + + g_signal_connect ( (gpointer) SurfaceInspector, + "delete_event", + G_CALLBACK (delete_event_callback), + NULL ); + g_signal_connect ((gpointer) SurfaceInspector, "destroy", + G_CALLBACK (gtk_widget_destroy), + NULL); + + g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", + G_CALLBACK (on_texture_combo_entry_key_press_event), + NULL); + g_signal_connect ((gpointer) texture_combo_entry, "activate", + G_CALLBACK (on_texture_combo_entry_activate), + NULL); + + + g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_hshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_vshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_hscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_vscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", + G_CALLBACK (on_rotate_offset_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", + G_CALLBACK (on_hshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", + G_CALLBACK (on_vshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", + G_CALLBACK (on_hscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", + G_CALLBACK (on_vscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", + G_CALLBACK (on_rotate_value_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", + G_CALLBACK (on_hshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", + G_CALLBACK (on_vshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", + G_CALLBACK (on_hscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", + G_CALLBACK (on_vscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", + G_CALLBACK (on_rotate_step_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) match_grid_button, "clicked", + G_CALLBACK (on_match_grid_button_clicked), + NULL); + g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", + G_CALLBACK (on_lock_valuechange_togglebutton_toggled), + NULL); + + g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", + G_CALLBACK (on_fit_width_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", + G_CALLBACK (on_fit_height_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_button, "clicked", + G_CALLBACK (on_fit_button_clicked), + NULL); + + g_signal_connect ((gpointer) axial_button, "clicked", + G_CALLBACK (on_axial_button_clicked), + NULL); + + g_signal_connect ((gpointer) done_button, "clicked", + G_CALLBACK (on_done_button_clicked), + NULL); + g_signal_connect ((gpointer) apply_button, "clicked", + G_CALLBACK (on_apply_button_clicked), + NULL); + g_signal_connect ((gpointer) cancel_button, "clicked", + G_CALLBACK (on_cancel_button_clicked), + NULL); + + + return SurfaceInspector; +} + + +// Texture Combo +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + // Have Tab activate selection as well as Return + if (event->keyval == GDK_Tab) + g_signal_emit_by_name ( texture_combo_entry, "activate" ); + + return FALSE; +} + +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + char text[128] = { 0 }; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + // activate only on entry change + strcpy( text, gtk_entry_get_text(entry)); + if ( strcmp( old_texture_entry, text )) + { + // Check for spaces in shader name + if (text[0] <= ' ' || strchr(text, ' ')) + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + strcpy( old_texture_entry, text ); + tmp_texdef->SetName( text ); + } + GetTexMods(); + } + } + } +} + +// Offset Spins +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HShift_conflicting) + tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; + else + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + } + GetTexMods(); + } +} + +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VShift_conflicting) + tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; + else + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + } + GetTexMods(); + } + +} + +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HScale_conflicting) + tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; + else + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + } + GetTexMods(); + } + + +} + +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VScale_conflicting) + tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; + else + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + } + GetTexMods(); + } + +} + +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_Rotate_conflicting) + tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; + else + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + } + GetTexMods(); + } + +} + + +// Match Grid +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) +{ + float hscale, vscale; + + if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) + hscale = 0.0; + else + hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) + vscale = 0.0; + else + vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + DoSnapTToGrid (hscale, vscale); +} + + +// Lock out changes to Value +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) +{ + bool is_Locked; + + is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); + + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); +} + + +// Value Spins +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + is_HShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + is_VShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + is_HScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + is_VScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + is_Rotate_conflicting = FALSE; + } + GetTexMods(); + } +} + + +// Step Spins +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[0] = val; +} + +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged VShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[1] = val; +} + +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[0] = val; +} + +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[1] = val; +} + +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->rotate = val; +} + + +// Fit Texture +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); +} + +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); +} + +static void on_fit_button_clicked (GtkButton *button, gpointer user_data) +{ + FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); + Sys_UpdateWindows(W_ALL); +} + + +// Axial Button +static void on_axial_button_clicked (GtkButton *button, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_texdef->shift[0] = 0.0; + tmp_texdef->shift[1] = 0.0; + tmp_texdef->scale[0] = 0.5; + tmp_texdef->scale[1] = 0.5; + tmp_texdef->rotate = 0.0; + } + } + + SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); + Sys_UpdateWindows(W_ALL); +} + + +// Action Buttons +static void on_done_button_clicked (GtkButton *button, gpointer user_data) +{ + if ( !texdef_face_list_empty() ) + GetTexMods(TRUE); + HideDlg(); + Sys_UpdateWindows(W_ALL); +} + +static void on_apply_button_clicked (GtkButton *button, gpointer user_data) +{ + if (!g_bListenChanged) + return; + + if ( !texdef_face_list_empty() ) + { + GetTexMods (TRUE); + Sys_UpdateWindows(W_CAMERA); + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } +} + +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) +{ + texturewin = Texturewin (); + texturewin->texdef = g_old_texdef; + // cancel the last do if we own it + if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(TRUE); + g_bListenUpdate = true; + m_nUndoId = 0; + } + HideDlg(); +} + + diff --git a/plugins/surface_heretic2/surfacedialog.h b/plugins/surface_heretic2/surfacedialog.h new file mode 100644 index 00000000..96ab3c79 --- /dev/null +++ b/plugins/surface_heretic2/surfacedialog.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SURFACEDIALOG_H_ +#define _SURFACEDIALOG_H_ + +void UpdateSurfaceDialog (); +void DoSurface (); +void ToggleSurface (); +void SurfaceDlgFitAll (); +GtkWidget *Get_SI_Module_Widget (); + +#endif // _SURFACEDIALOG_H_ diff --git a/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp new file mode 100644 index 00000000..d56eaa3c --- /dev/null +++ b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp @@ -0,0 +1,1417 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include "surfdlg_plugin.h" + +#include "surfaceflagsdialog_heretic2.h" + + GtkWidget *surface_lightbutton; + GtkWidget *surface_slickbutton; + GtkWidget *surface_skybutton; + GtkWidget *surface_warpbutton; + GtkWidget *surface_trans33button; + GtkWidget *surface_trans66button; + GtkWidget *surface_flowingbutton; + GtkWidget *surface_nodrawbutton; + GtkWidget *surface_tallwallbutton; + GtkWidget *surface_alphatexbutton; + GtkWidget *surface_animspeedbutton; + GtkWidget *surface_undulatebutton; + + GtkWidget *surf_gravel_radiobutton; + GSList *surf_gravel_radiobutton_group = NULL; + GtkWidget *surf_metal_radiobutton; + GtkWidget *surf_stone_radiobutton; + GtkWidget *surf_wood_radiobutton; + + GtkWidget *surf_value_entry; + + GtkWidget *notebook1; + + GtkWidget *content_solidbutton; + GtkWidget *content_windowbutton; + GtkWidget *content_illusbutton; + GtkWidget *content_lavabutton; + GtkWidget *content_slimebutton; + GtkWidget *content_waterbutton; + GtkWidget *content_mistbutton; + GtkWidget *content_areaportalbutton; + GtkWidget *content_playerclipbutton; + GtkWidget *content_monsterclipbutton; + GtkWidget *content_current0button; + GtkWidget *content_current90button; + GtkWidget *content_current180button; + GtkWidget *content_current270button; + GtkWidget *content_currentUPbutton; + GtkWidget *content_currentDOWNbutton; + GtkWidget *content_originbutton; + GtkWidget *content_detailbutton; + GtkWidget *content_ladderbutton; + GtkWidget *content_camnoblockbutton; + + + gboolean setup_buttons = TRUE; + + int working_surface_flags; + int surface_mask; + int working_content_flags; + int content_mask; + int working_value; + gboolean surface_material_inconsistant = FALSE; + +inline void set_inconsistent(GtkWidget *toggle_button) +{ + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), TRUE); +} + +inline void clear_inconsistent(GtkWidget *toggle_button) +{ + if ( gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (toggle_button)) ) + { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), FALSE); + } + +} + +void clear_all_inconsistent(void) +{ + clear_inconsistent( surface_lightbutton ); + clear_inconsistent( surface_slickbutton ); + clear_inconsistent( surface_skybutton ); + clear_inconsistent( surface_warpbutton ); + clear_inconsistent( surface_trans33button ); + clear_inconsistent( surface_trans66button ); + clear_inconsistent( surface_flowingbutton ); + clear_inconsistent( surface_nodrawbutton ); + clear_inconsistent( surface_tallwallbutton ); + clear_inconsistent( surface_alphatexbutton ); + clear_inconsistent( surface_animspeedbutton ); + clear_inconsistent( surface_undulatebutton ); + + clear_inconsistent( surf_gravel_radiobutton ); + clear_inconsistent( surf_metal_radiobutton ); + clear_inconsistent( surf_stone_radiobutton ); + clear_inconsistent( surf_wood_radiobutton ); + + clear_inconsistent( content_solidbutton ); + clear_inconsistent( content_windowbutton ); + clear_inconsistent( content_illusbutton ); + clear_inconsistent( content_lavabutton ); + clear_inconsistent( content_slimebutton ); + clear_inconsistent( content_waterbutton ); + clear_inconsistent( content_mistbutton ); + clear_inconsistent( content_areaportalbutton ); + clear_inconsistent( content_playerclipbutton ); + clear_inconsistent( content_monsterclipbutton ); + clear_inconsistent( content_current0button ); + clear_inconsistent( content_current90button ); + clear_inconsistent( content_current180button ); + clear_inconsistent( content_current270button ); + clear_inconsistent( content_currentUPbutton ); + clear_inconsistent( content_currentDOWNbutton ); + clear_inconsistent( content_originbutton ); + clear_inconsistent( content_detailbutton ); + clear_inconsistent( content_ladderbutton ); + clear_inconsistent( content_camnoblockbutton ); +} + +void clear_all_buttons_and_values() +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_lightbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_slickbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_skybutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_warpbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_trans33button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_trans66button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_flowingbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_nodrawbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_tallwallbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_alphatexbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_animspeedbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_undulatebutton ), FALSE); + +// surface_material_inconsistant = TRUE; + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), FALSE); + set_inconsistent(surf_gravel_radiobutton); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), FALSE); + set_inconsistent(surf_metal_radiobutton); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), FALSE); + set_inconsistent(surf_stone_radiobutton); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), FALSE); + set_inconsistent(surf_wood_radiobutton); + + gtk_entry_set_text( (GtkEntry *)surf_value_entry, ""); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_solidbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_windowbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_illusbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_lavabutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_slimebutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_waterbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_mistbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_areaportalbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_playerclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_monsterclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current0button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current90button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current180button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current270button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_currentUPbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_currentDOWNbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_originbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_detailbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_ladderbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_camnoblockbutton ), FALSE); + +} + +void SetFlagButtons_Heretic2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty) +{ + int i; + int contents = 0; + int flags = 0; + int value = 0; + int diff_contents = 0; + int diff_flags = 0; + gboolean diff_value = FALSE; + char tex_buff[11]; + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + gboolean surface_which_material_inconsistant[4]; + int surface_iterator; + + setup_buttons = TRUE; + working_surface_flags = 0; + surface_mask = 0; + working_content_flags = 0; + content_mask = 0; + working_value = 0; + surface_material_inconsistant = FALSE; + surface_which_material_inconsistant[0] = FALSE; + surface_which_material_inconsistant[1] = FALSE; + surface_which_material_inconsistant[2] = FALSE; + surface_which_material_inconsistant[3] = FALSE; + + if(!b_isListEmpty) + { + tmp_texdef = &texdef_face_list->texdef; + contents = tmp_texdef->contents; + flags = tmp_texdef->flags; + value = tmp_texdef->value; + + surface_iterator = (tmp_texdef->flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; // Inconsistant Material? + surface_which_material_inconsistant[surface_iterator] = TRUE; + + for (temp_texdef_face_list = texdef_face_list->next; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + diff_contents |= contents ^ tmp_texdef->contents; // Figure out which buttons are inconsistent + diff_flags |= flags ^ tmp_texdef->flags; + if (tmp_texdef->value != value) + diff_value = TRUE; + + surface_iterator = (tmp_texdef->flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; // Inconsistant Material? + surface_which_material_inconsistant[surface_iterator] = TRUE; + + Sys_Printf("Diff_Flags: %d\t Surf_Iter: %d\n",diff_flags, surface_iterator); + + } + } + + + clear_all_inconsistent(); + + // If no faces/brushes are selected, clear everything and bail + if(b_isListEmpty) + { + clear_all_buttons_and_values(); + setup_buttons = FALSE; + return; + } + + // Set surface buttons to reflect brush/face flags, contents, and values + if(diff_flags & HERETIC2_SURF_LIGHT) + set_inconsistent(surface_lightbutton); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), (flags & HERETIC2_SURF_LIGHT)); + + if(diff_flags & HERETIC2_SURF_SLICK) + set_inconsistent(surface_slickbutton); + else if(flags & HERETIC2_SURF_SLICK) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_SKY) + set_inconsistent(surface_skybutton); + else if(flags & HERETIC2_SURF_SKY) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_WARP) + set_inconsistent(surface_warpbutton); + else if(flags & HERETIC2_SURF_WARP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_TRANS33) + set_inconsistent(surface_trans33button); + else if(flags & HERETIC2_SURF_TRANS33) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); + + if(diff_flags & HERETIC2_SURF_TRANS66) + set_inconsistent(surface_trans66button); + else if(flags & HERETIC2_SURF_TRANS66) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); + + if(diff_flags & HERETIC2_SURF_FLOWING) + set_inconsistent(surface_flowingbutton); + else if(flags & HERETIC2_SURF_FLOWING) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_NODRAW) + set_inconsistent(surface_nodrawbutton); + else if(flags & HERETIC2_SURF_NODRAW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_TALL_WALL) + set_inconsistent(surface_tallwallbutton); + else if(flags & HERETIC2_SURF_TALL_WALL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_tallwallbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_tallwallbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_ALPHA_TEXTURE) + set_inconsistent(surface_alphatexbutton); + else if(flags & HERETIC2_SURF_ALPHA_TEXTURE) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_alphatexbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_alphatexbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_ANIMSPEED) + set_inconsistent(surface_animspeedbutton); + else if(flags & HERETIC2_SURF_ANIMSPEED) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_animspeedbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_animspeedbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_UNDULATE) + set_inconsistent(surface_undulatebutton); + else if(flags & HERETIC2_SURF_UNDULATE) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_undulatebutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_undulatebutton ), FALSE); + + if(diff_flags & ~HERETIC2_SURF_MATERIAL_MASK) + { + Sys_Printf("--> %d\n", (diff_flags & ~HERETIC2_SURF_MATERIAL_MASK) ); + Sys_Printf("%d\t%d\t%d\t%d\n", surface_which_material_inconsistant[0], surface_which_material_inconsistant[1], surface_which_material_inconsistant[2], surface_which_material_inconsistant[3]); + + if (surface_which_material_inconsistant[0]) + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + set_inconsistent(surf_gravel_radiobutton); + } + if (surface_which_material_inconsistant[1]) + { + //if (!surface_material_inconsistant) + //{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + //} + set_inconsistent(surf_metal_radiobutton); + } + if (surface_which_material_inconsistant[2]) + { + //if (!surface_material_inconsistant) + //{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + //} + set_inconsistent(surf_stone_radiobutton); + } + if (surface_which_material_inconsistant[3]) + { + //if (!surface_material_inconsistant) + //{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + //} + set_inconsistent(surf_wood_radiobutton); + } + } + else + { + if(flags & ~HERETIC2_SURF_MATERIAL_MASK) + { + surface_iterator = (flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; + if( surface_iterator == 1) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), TRUE); + else if(surface_iterator == 2) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), TRUE); + else if(surface_iterator == 3) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), TRUE); + } + else + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), TRUE); + } + } + + // Set content buttons to reflect brush values + if(diff_contents & HERETIC2_CONTENTS_SOLID) + set_inconsistent(content_solidbutton); + else if(contents & HERETIC2_CONTENTS_SOLID) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_WINDOW) + set_inconsistent(content_windowbutton); + else if(contents & HERETIC2_CONTENTS_WINDOW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_ILLUSIONARY) + set_inconsistent(content_illusbutton); + else if(contents & HERETIC2_CONTENTS_ILLUSIONARY) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_illusbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_illusbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_LAVA) + set_inconsistent(content_lavabutton); + else if(contents & HERETIC2_CONTENTS_LAVA) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_SLIME) + set_inconsistent(content_slimebutton); + else if(contents & HERETIC2_CONTENTS_SLIME) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_WATER) + set_inconsistent(content_waterbutton); + else if(contents & HERETIC2_CONTENTS_WATER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_MIST) + set_inconsistent(content_mistbutton); + else if(contents & HERETIC2_CONTENTS_MIST) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_AREAPORTAL) + set_inconsistent(content_areaportalbutton); + else if(contents & HERETIC2_CONTENTS_AREAPORTAL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_PLAYERCLIP) + set_inconsistent(content_playerclipbutton); + else if(contents & HERETIC2_CONTENTS_PLAYERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_MONSTERCLIP) + set_inconsistent(content_monsterclipbutton); + else if(contents & HERETIC2_CONTENTS_MONSTERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_0) + set_inconsistent(content_current0button); + else if(contents & HERETIC2_CONTENTS_CURRENT_0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_90) + set_inconsistent(content_current90button); + else if(contents & HERETIC2_CONTENTS_CURRENT_90) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_180) + set_inconsistent(content_current180button); + else if(contents & HERETIC2_CONTENTS_CURRENT_180) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_270) + set_inconsistent(content_current270button); + else if(contents & HERETIC2_CONTENTS_CURRENT_270) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_UP) + set_inconsistent(content_currentUPbutton); + else if(contents & HERETIC2_CONTENTS_CURRENT_UP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_DOWN) + set_inconsistent(content_currentDOWNbutton); + else if(contents & HERETIC2_CONTENTS_CURRENT_DOWN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_ORIGIN) + set_inconsistent(content_originbutton); + else if(contents & HERETIC2_CONTENTS_ORIGIN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_DETAIL) + set_inconsistent(content_detailbutton); + else if(contents & HERETIC2_CONTENTS_DETAIL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_LADDER) + set_inconsistent(content_ladderbutton); + else if(contents & HERETIC2_CONTENTS_LADDER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CAMERANOBLOCK) + set_inconsistent(content_camnoblockbutton); + else if(contents & HERETIC2_CONTENTS_CAMERANOBLOCK) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_camnoblockbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_camnoblockbutton ), FALSE); + + // Set Value + if(diff_value) + gtk_entry_set_text( (GtkEntry *)surf_value_entry, ""); + else + { + working_value = value; + sprintf( tex_buff, "%d", value); + gtk_entry_set_text( (GtkEntry *)surf_value_entry, tex_buff); + } + + setup_buttons = FALSE; +} + +void SetChangeInFlags_Face_Heretic2 (texdef_to_face_t *texdef_face_list) +{ + texdef_to_face_t *temp_texdef_face_list; + texdef_t *tmp_texdef; + + for (temp_texdef_face_list = texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + tmp_texdef->flags = (tmp_texdef->flags & ~surface_mask) | working_surface_flags; + tmp_texdef->contents = (tmp_texdef->contents & ~content_mask) | working_content_flags; + tmp_texdef->value = working_value; + Sys_Printf("content_flag: %d content_mask: %d\n",working_content_flags,content_mask); + Sys_Printf("content: %d\n",tmp_texdef->contents); + } +} + +inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag) // For Material +{ + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + if (surface_material_inconsistant) + { + clear_inconsistent( surf_gravel_radiobutton ); + clear_inconsistent( surf_metal_radiobutton ); + clear_inconsistent( surf_stone_radiobutton ); + clear_inconsistent( surf_wood_radiobutton ); + } + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | sur_flag; + } +} + +inline void change_material (GtkWidget *togglebutton) +{ + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + if (surface_material_inconsistant) + { + clear_inconsistent( surf_gravel_radiobutton ); + clear_inconsistent( surf_metal_radiobutton ); + clear_inconsistent( surf_stone_radiobutton ); + clear_inconsistent( surf_wood_radiobutton ); + } + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_gravel_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_GRAVEL; + } + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_metal_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_METAL; + } + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_stone_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_STONE; + } + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_wood_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_WOOD; + } + } +} + +inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag, gboolean change_flag_to) +{ + + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) // Clear out inconsistent, if set + clear_inconsistent(GTK_WIDGET (togglebutton)); + + surface_mask |= sur_flag; + + if (change_flag_to) + working_surface_flags |= sur_flag; + else + working_surface_flags &= ~sur_flag; + } +} + +inline void change_contentflag (GtkWidget *togglebutton, int content_flag, gboolean change_flag_to) +{ + + if ( (!setup_buttons) ) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) + clear_inconsistent(togglebutton); + //if (g_ptrSelectedFaces.GetSize() == 0) // Only changing content flags on whole brushes, not faces. + //{ + content_mask |= content_flag; + + if (change_flag_to) + working_content_flags |= content_flag; + else + working_content_flags &= ~content_flag; + //} + } +} + +// Surface Flags Callbacks +void +on_surface_lightbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_lightbutton, HERETIC2_SURF_LIGHT, (GTK_TOGGLE_BUTTON (surface_lightbutton)->active)); +} + + +void +on_surface_slickbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_slickbutton, HERETIC2_SURF_SLICK, (GTK_TOGGLE_BUTTON (surface_slickbutton)->active)); +} + + +void +on_surface_skybutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_skybutton, HERETIC2_SURF_SKY, (GTK_TOGGLE_BUTTON (surface_skybutton)->active)); +} + + +void +on_surface_warpbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_warpbutton, HERETIC2_SURF_WARP, (GTK_TOGGLE_BUTTON (surface_warpbutton)->active)); +} + + +void +on_surface_trans33button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans33button, HERETIC2_SURF_TRANS33, (GTK_TOGGLE_BUTTON (surface_trans33button)->active)); +} + + +void +on_surface_trans66button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans66button, HERETIC2_SURF_TRANS66, (GTK_TOGGLE_BUTTON (surface_trans66button)->active)); +} + + +void +on_surface_flowingbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_flowingbutton, HERETIC2_SURF_FLOWING, (GTK_TOGGLE_BUTTON (surface_flowingbutton)->active)); +} + + +void +on_surface_nodrawbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_nodrawbutton, HERETIC2_SURF_NODRAW, (GTK_TOGGLE_BUTTON (surface_nodrawbutton)->active)); +} + + +void +on_surface_tallwallbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_tallwallbutton, HERETIC2_SURF_TALL_WALL, (GTK_TOGGLE_BUTTON (surface_tallwallbutton)->active)); +} + + +void +on_surface_alphatexbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_alphatexbutton, HERETIC2_SURF_ALPHA_TEXTURE, (GTK_TOGGLE_BUTTON (surface_alphatexbutton)->active)); +} + + +void +on_surface_animspeedbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_animspeedbutton, HERETIC2_SURF_ANIMSPEED, (GTK_TOGGLE_BUTTON (surface_animspeedbutton)->active)); +} + + +void +on_surface_undulatebutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_undulatebutton, HERETIC2_SURF_UNDULATE, (GTK_TOGGLE_BUTTON (surface_undulatebutton)->active)); +} + + +void +on_surf_gravel_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_gravel_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +void +on_surf_metal_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_metal_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +void +on_surf_stone_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_stone_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +void +on_surf_wood_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_wood_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +// Content Flags Callbacks +void +on_content_solidbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_solidbutton, HERETIC2_CONTENTS_SOLID, (GTK_TOGGLE_BUTTON (content_solidbutton)->active)); +} + + +void +on_content_windowbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_windowbutton, HERETIC2_CONTENTS_WINDOW, (GTK_TOGGLE_BUTTON (content_windowbutton)->active)); +} + + +void +on_content_illusbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_illusbutton, HERETIC2_CONTENTS_ILLUSIONARY, (GTK_TOGGLE_BUTTON (content_illusbutton)->active)); +} + + +void +on_content_lavabutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_lavabutton, HERETIC2_CONTENTS_LAVA, (GTK_TOGGLE_BUTTON (content_lavabutton)->active)); +} + + +void +on_content_slimebutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_slimebutton, HERETIC2_CONTENTS_SLIME, (GTK_TOGGLE_BUTTON (content_slimebutton)->active)); +} + + +void +on_content_waterbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_waterbutton, HERETIC2_CONTENTS_WATER, (GTK_TOGGLE_BUTTON (content_waterbutton)->active)); +} + + +void +on_content_mistbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_mistbutton, HERETIC2_CONTENTS_MIST, (GTK_TOGGLE_BUTTON (content_mistbutton)->active)); +} + + +void +on_content_areaportalbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_areaportalbutton, HERETIC2_CONTENTS_AREAPORTAL, (GTK_TOGGLE_BUTTON (content_areaportalbutton)->active)); +} + + +void +on_content_playerclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_playerclipbutton, HERETIC2_CONTENTS_PLAYERCLIP, (GTK_TOGGLE_BUTTON (content_playerclipbutton)->active)); +} + + +void +on_content_monsterclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_monsterclipbutton, HERETIC2_CONTENTS_MONSTERCLIP, (GTK_TOGGLE_BUTTON (content_monsterclipbutton)->active)); +} + + +void +on_content_current0button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current0button, HERETIC2_CONTENTS_CURRENT_0, (GTK_TOGGLE_BUTTON (content_current0button)->active)); +} + + +void +on_content_current90button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current90button, HERETIC2_CONTENTS_CURRENT_90, (GTK_TOGGLE_BUTTON (content_current90button)->active)); +} + + +void +on_content_current180button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current180button, HERETIC2_CONTENTS_CURRENT_180, (GTK_TOGGLE_BUTTON (content_current180button)->active)); +} + + +void +on_content_current270button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current270button, HERETIC2_CONTENTS_CURRENT_270, (GTK_TOGGLE_BUTTON (content_current270button)->active)); +} + + +void +on_content_currentUPbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentUPbutton, HERETIC2_CONTENTS_CURRENT_UP, (GTK_TOGGLE_BUTTON (content_currentUPbutton)->active)); +} + + +void +on_content_currentDOWNbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentDOWNbutton, HERETIC2_CONTENTS_CURRENT_DOWN, (GTK_TOGGLE_BUTTON (content_currentDOWNbutton)->active)); +} + + +void +on_content_originbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_originbutton, HERETIC2_CONTENTS_ORIGIN, (GTK_TOGGLE_BUTTON (content_originbutton)->active)); +} + + +void +on_content_detailbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_detailbutton, HERETIC2_CONTENTS_DETAIL, (GTK_TOGGLE_BUTTON (content_detailbutton)->active)); +} + + +void +on_content_ladderbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_ladderbutton, HERETIC2_CONTENTS_LADDER, (GTK_TOGGLE_BUTTON (content_ladderbutton)->active)); +} + + +void +on_content_camnoblockbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_camnoblockbutton, HERETIC2_CONTENTS_CAMERANOBLOCK, (GTK_TOGGLE_BUTTON (content_camnoblockbutton)->active)); +} + +// Value Entry Callback +void +on_surf_value_entry_changed (GtkEditable *editable, + gpointer user_data) +{ + if ( (!setup_buttons) ) // If we're setting up the buttons, don't change value + working_value = atoi( gtk_entry_get_text( (GtkEntry*)editable) ); +} + +void +on_surf_value_entry_insert_text (GtkEditable *editable, + gchar *new_text, + gint new_text_length, + gint *position, + gpointer user_data) +{ + int i, count=0; + gchar *result; + int entry_value; + texdef_t *pt; + brush_t *b; + face_t *f; + + // Limit input to digits, throwing out anything else + // Modified from Gtk FAQ for text filtering of GtkEntry + result = g_new (gchar, new_text_length); + + for (i=0; i < new_text_length; i++) { + if (!isdigit(new_text[i])) + continue; + result[count++] = new_text[i]; + } + + if (count > 0) { + gtk_signal_handler_block_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_surf_value_entry_insert_text), + user_data); + gtk_editable_insert_text (editable, result, count, position); + gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_surf_value_entry_insert_text), + user_data); + } + gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); + + g_free (result); +} + +#define HERETIC2_FLAG_BUTTON_BORDER 3 + +GtkWidget* Create_Heretic2FlagsDialog (GtkWidget* surfacedialog_widget) +{ + GtkWidget *frame1; + GtkWidget *notebook1; + GtkWidget *vbox3; + GtkWidget *table1; + GtkWidget *frame2; + GtkWidget *hbox4; + GtkWidget *label4; + GtkWidget *vbox4; + GtkWidget *table3; + GtkWidget *label5; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *label2; + GtkWidget *table2; + GtkWidget *label3; + + + frame1 = gtk_frame_new ("Brush/Face Flags"); + gtk_widget_show (frame1); + gtk_container_add (GTK_CONTAINER (surfacedialog_widget), frame1); + + notebook1 = gtk_notebook_new (); + gtk_widget_show (notebook1); + gtk_container_add (GTK_CONTAINER (frame1), notebook1); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox3); + gtk_container_add (GTK_CONTAINER (notebook1), vbox3); + + table1 = gtk_table_new (3, 4, TRUE); + gtk_widget_show (table1); + gtk_box_pack_start (GTK_BOX (vbox3), table1, TRUE, TRUE, 0); + + surface_lightbutton = gtk_toggle_button_new_with_mnemonic ("Light"); + gtk_widget_show (surface_lightbutton); + gtk_table_attach (GTK_TABLE (table1), surface_lightbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_slickbutton = gtk_toggle_button_new_with_mnemonic ("Slick"); + gtk_widget_show (surface_slickbutton); + gtk_table_attach (GTK_TABLE (table1), surface_slickbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_skybutton = gtk_toggle_button_new_with_mnemonic ("Sky"); + gtk_widget_show (surface_skybutton); + gtk_table_attach (GTK_TABLE (table1), surface_skybutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_warpbutton = gtk_toggle_button_new_with_mnemonic ("Warp"); + gtk_widget_show (surface_warpbutton); + gtk_table_attach (GTK_TABLE (table1), surface_warpbutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_trans33button = gtk_toggle_button_new_with_mnemonic ("Trans33"); + gtk_widget_show (surface_trans33button); + gtk_table_attach (GTK_TABLE (table1), surface_trans33button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_trans66button = gtk_toggle_button_new_with_mnemonic ("Trans66"); + gtk_widget_show (surface_trans66button); + gtk_table_attach (GTK_TABLE (table1), surface_trans66button, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_flowingbutton = gtk_toggle_button_new_with_mnemonic ("Flowing"); + gtk_widget_show (surface_flowingbutton); + gtk_table_attach (GTK_TABLE (table1), surface_flowingbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_nodrawbutton = gtk_toggle_button_new_with_mnemonic ("NoDraw"); + gtk_widget_show (surface_nodrawbutton); + gtk_table_attach (GTK_TABLE (table1), surface_nodrawbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_tallwallbutton = gtk_toggle_button_new_with_mnemonic ("TallWall"); + gtk_widget_show (surface_tallwallbutton); + gtk_table_attach (GTK_TABLE (table1), surface_tallwallbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_alphatexbutton = gtk_toggle_button_new_with_mnemonic ("AlphaTex"); + gtk_widget_show (surface_alphatexbutton); + gtk_table_attach (GTK_TABLE (table1), surface_alphatexbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_animspeedbutton = gtk_toggle_button_new_with_mnemonic ("AnimSpeed"); + gtk_widget_show (surface_animspeedbutton); + gtk_table_attach (GTK_TABLE (table1), surface_animspeedbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_undulatebutton = gtk_toggle_button_new_with_mnemonic ("Undulate"); + gtk_widget_show (surface_undulatebutton); + gtk_table_attach (GTK_TABLE (table1), surface_undulatebutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + frame2 = gtk_frame_new (NULL); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox3), frame2, FALSE, FALSE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_OUT); + gtk_container_set_border_width (GTK_CONTAINER (frame2), 4); + + hbox4 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (frame2), hbox4); + + surf_gravel_radiobutton = gtk_radio_button_new_with_mnemonic (NULL, "Gravel"); + gtk_widget_show (surf_gravel_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_gravel_radiobutton, TRUE, FALSE, 0); + + surf_metal_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_gravel_radiobutton), "Metal"); + gtk_widget_show (surf_metal_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_metal_radiobutton, TRUE, FALSE, 0); + + surf_stone_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_metal_radiobutton), "Stone"); + gtk_widget_show (surf_stone_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_stone_radiobutton, TRUE, FALSE, 0); + + surf_wood_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_stone_radiobutton), "Wood"); + gtk_widget_show (surf_wood_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_wood_radiobutton, TRUE, FALSE, 0); + + label4 = gtk_label_new ("Material"); + gtk_widget_show (label4); + gtk_frame_set_label_widget (GTK_FRAME (frame2), label4); + gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_LEFT); + + table3 = gtk_table_new (1, 4, FALSE); + gtk_widget_show (table3); + gtk_box_pack_start (GTK_BOX (vbox3), table3, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (table3), 3); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_table_attach (GTK_TABLE (table3), hbox1, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label5 = gtk_label_new ("Value: "); + gtk_widget_show (label5); + gtk_table_attach (GTK_TABLE (table3), label5, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label5), 0, 0); + gtk_label_set_justify (GTK_LABEL (label5), GTK_JUSTIFY_RIGHT); + + surf_value_entry = gtk_entry_new (); + gtk_widget_show (surf_value_entry); + gtk_table_attach (GTK_TABLE (table3), surf_value_entry, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table3), hbox2, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label2 = gtk_label_new ("Surface Flags"); + gtk_widget_show (label2); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label2); + gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT); + + table2 = gtk_table_new (5, 4, TRUE); + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (notebook1), table2); + + content_solidbutton = gtk_toggle_button_new_with_mnemonic ("Solid"); + gtk_widget_show (content_solidbutton); + gtk_table_attach (GTK_TABLE (table2), content_solidbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_windowbutton = gtk_toggle_button_new_with_mnemonic ("Window"); + gtk_widget_show (content_windowbutton); + gtk_table_attach (GTK_TABLE (table2), content_windowbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_illusbutton = gtk_toggle_button_new_with_mnemonic ("Illusion"); + gtk_widget_show (content_illusbutton); + gtk_table_attach (GTK_TABLE (table2), content_illusbutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_lavabutton = gtk_toggle_button_new_with_mnemonic ("Lava"); + gtk_widget_show (content_lavabutton); + gtk_table_attach (GTK_TABLE (table2), content_lavabutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_slimebutton = gtk_toggle_button_new_with_mnemonic ("Slime"); + gtk_widget_show (content_slimebutton); + gtk_table_attach (GTK_TABLE (table2), content_slimebutton, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_waterbutton = gtk_toggle_button_new_with_mnemonic ("Water"); + gtk_widget_show (content_waterbutton); + gtk_table_attach (GTK_TABLE (table2), content_waterbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_mistbutton = gtk_toggle_button_new_with_mnemonic ("Mist"); + gtk_widget_show (content_mistbutton); + gtk_table_attach (GTK_TABLE (table2), content_mistbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_areaportalbutton = gtk_toggle_button_new_with_mnemonic ("AreaPortal"); + gtk_widget_show (content_areaportalbutton); + gtk_table_attach (GTK_TABLE (table2), content_areaportalbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_playerclipbutton = gtk_toggle_button_new_with_mnemonic ("PlayerClip"); + gtk_widget_show (content_playerclipbutton); + gtk_table_attach (GTK_TABLE (table2), content_playerclipbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_monsterclipbutton = gtk_toggle_button_new_with_mnemonic ("MonsterClip"); + gtk_widget_show (content_monsterclipbutton); + gtk_table_attach (GTK_TABLE (table2), content_monsterclipbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current0button = gtk_toggle_button_new_with_mnemonic ("Current 0"); + gtk_widget_show (content_current0button); + gtk_table_attach (GTK_TABLE (table2), content_current0button, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current90button = gtk_toggle_button_new_with_mnemonic ("Current 90"); + gtk_widget_show (content_current90button); + gtk_table_attach (GTK_TABLE (table2), content_current90button, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current180button = gtk_toggle_button_new_with_mnemonic ("Current 180"); + gtk_widget_show (content_current180button); + gtk_table_attach (GTK_TABLE (table2), content_current180button, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current270button = gtk_toggle_button_new_with_mnemonic ("Current 270"); + gtk_widget_show (content_current270button); + gtk_table_attach (GTK_TABLE (table2), content_current270button, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_currentUPbutton = gtk_toggle_button_new_with_mnemonic ("Current UP"); + gtk_widget_show (content_currentUPbutton); + gtk_table_attach (GTK_TABLE (table2), content_currentUPbutton, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_currentDOWNbutton = gtk_toggle_button_new_with_mnemonic ("Current DOWN"); + gtk_widget_show (content_currentDOWNbutton); + gtk_table_attach (GTK_TABLE (table2), content_currentDOWNbutton, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_originbutton = gtk_toggle_button_new_with_mnemonic ("Origin"); + gtk_widget_show (content_originbutton); + gtk_table_attach (GTK_TABLE (table2), content_originbutton, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_detailbutton = gtk_toggle_button_new_with_mnemonic ("Detail"); + gtk_widget_show (content_detailbutton); + gtk_table_attach (GTK_TABLE (table2), content_detailbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_ladderbutton = gtk_toggle_button_new_with_mnemonic ("Ladder"); + gtk_widget_show (content_ladderbutton); + gtk_table_attach (GTK_TABLE (table2), content_ladderbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_camnoblockbutton = gtk_toggle_button_new_with_mnemonic ("Cam No Block"); + gtk_widget_show (content_camnoblockbutton); + gtk_table_attach (GTK_TABLE (table2), content_camnoblockbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label3 = gtk_label_new ("Content Flags"); + gtk_widget_show (label3); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label3); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + // Signal Connects + g_signal_connect ((gpointer) surface_lightbutton, "toggled", + G_CALLBACK (on_surface_lightbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_slickbutton, "toggled", + G_CALLBACK (on_surface_slickbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_skybutton, "toggled", + G_CALLBACK (on_surface_skybutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_warpbutton, "toggled", + G_CALLBACK (on_surface_warpbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_trans33button, "toggled", + G_CALLBACK (on_surface_trans33button_toggled), + NULL); + g_signal_connect ((gpointer) surface_trans66button, "toggled", + G_CALLBACK (on_surface_trans66button_toggled), + NULL); + g_signal_connect ((gpointer) surface_flowingbutton, "toggled", + G_CALLBACK (on_surface_flowingbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_nodrawbutton, "toggled", + G_CALLBACK (on_surface_nodrawbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_tallwallbutton, "toggled", + G_CALLBACK (on_surface_tallwallbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_alphatexbutton, "toggled", + G_CALLBACK (on_surface_alphatexbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_animspeedbutton, "toggled", + G_CALLBACK (on_surface_animspeedbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_undulatebutton, "toggled", + G_CALLBACK (on_surface_undulatebutton_toggled), + NULL); + + g_signal_connect ((gpointer) surf_gravel_radiobutton, "toggled", + G_CALLBACK (on_surf_gravel_radiobutton_toggled), + NULL); + g_signal_connect ((gpointer) surf_metal_radiobutton, "toggled", + G_CALLBACK (on_surf_metal_radiobutton_toggled), + NULL); + g_signal_connect ((gpointer) surf_stone_radiobutton, "toggled", + G_CALLBACK (on_surf_stone_radiobutton_toggled), + NULL); + g_signal_connect ((gpointer) surf_wood_radiobutton, "toggled", + G_CALLBACK (on_surf_wood_radiobutton_toggled), + NULL); + + g_signal_connect ((gpointer) surf_value_entry, "changed", + G_CALLBACK (on_surf_value_entry_changed), + NULL); + g_signal_connect ((gpointer) surf_value_entry, "insert_text", + G_CALLBACK (on_surf_value_entry_insert_text), + NULL); + g_signal_connect ((gpointer) content_solidbutton, "toggled", + G_CALLBACK (on_content_solidbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_windowbutton, "toggled", + G_CALLBACK (on_content_windowbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_illusbutton, "toggled", + G_CALLBACK (on_content_illusbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_lavabutton, "toggled", + G_CALLBACK (on_content_lavabutton_toggled), + NULL); + g_signal_connect ((gpointer) content_slimebutton, "toggled", + G_CALLBACK (on_content_slimebutton_toggled), + NULL); + g_signal_connect ((gpointer) content_waterbutton, "toggled", + G_CALLBACK (on_content_waterbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_mistbutton, "toggled", + G_CALLBACK (on_content_mistbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_areaportalbutton, "toggled", + G_CALLBACK (on_content_areaportalbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_playerclipbutton, "toggled", + G_CALLBACK (on_content_playerclipbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_monsterclipbutton, "toggled", + G_CALLBACK (on_content_monsterclipbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_current0button, "toggled", + G_CALLBACK (on_content_current0button_toggled), + NULL); + g_signal_connect ((gpointer) content_current90button, "toggled", + G_CALLBACK (on_content_current90button_toggled), + NULL); + g_signal_connect ((gpointer) content_current180button, "toggled", + G_CALLBACK (on_content_current180button_toggled), + NULL); + g_signal_connect ((gpointer) content_current270button, "toggled", + G_CALLBACK (on_content_current270button_toggled), + NULL); + g_signal_connect ((gpointer) content_currentUPbutton, "toggled", + G_CALLBACK (on_content_currentUPbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_currentDOWNbutton, "toggled", + G_CALLBACK (on_content_currentDOWNbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_originbutton, "toggled", + G_CALLBACK (on_content_originbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_detailbutton, "toggled", + G_CALLBACK (on_content_detailbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_ladderbutton, "toggled", + G_CALLBACK (on_content_ladderbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_camnoblockbutton, "toggled", + G_CALLBACK (on_content_camnoblockbutton_toggled), + NULL); + + + return frame1; +} + diff --git a/plugins/surface_heretic2/surfaceflagsdialog_heretic2.h b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.h new file mode 100644 index 00000000..1b00e1a3 --- /dev/null +++ b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SURFACEFLAGSDIALOG_HERETIC2_H + #define _SURFACEFLAGSDIALOG_HERETIC2_H + +// 12 +#define HERETIC2_SURF_LIGHT 0x1 +#define HERETIC2_SURF_SLICK 0x2 +#define HERETIC2_SURF_SKY 0x4 +#define HERETIC2_SURF_WARP 0x8 +#define HERETIC2_SURF_TRANS33 0x10 +#define HERETIC2_SURF_TRANS66 0x20 +#define HERETIC2_SURF_FLOWING 0x40 +#define HERETIC2_SURF_NODRAW 0x80 + +#define HERETIC2_SURF_TALL_WALL 0x400 +#define HERETIC2_SURF_ALPHA_TEXTURE 0x800 +#define HERETIC2_SURF_ANIMSPEED 0x1000 +#define HERETIC2_SURF_UNDULATE 0x2000 + +#define HERETIC2_SURF_TYPE_GRAVEL 0x00000000 +#define HERETIC2_SURF_TYPE_METAL 0x01000000 +#define HERETIC2_SURF_TYPE_STONE 0x02000000 +#define HERETIC2_SURF_TYPE_WOOD 0x03000000 + +#define HERETIC2_SURF_MATERIAL_MASK 0xFCFFFFFF + + +// 20 +#define HERETIC2_CONTENTS_SOLID 0x1 +#define HERETIC2_CONTENTS_WINDOW 0x2 +#define HERETIC2_CONTENTS_ILLUSIONARY 0x4 +#define HERETIC2_CONTENTS_LAVA 0x8 +#define HERETIC2_CONTENTS_SLIME 0x10 +#define HERETIC2_CONTENTS_WATER 0x20 +#define HERETIC2_CONTENTS_MIST 0x40 + +#define HERETIC2_CONTENTS_AREAPORTAL 0x8000 +#define HERETIC2_CONTENTS_PLAYERCLIP 0x10000 +#define HERETIC2_CONTENTS_MONSTERCLIP 0x20000 +#define HERETIC2_CONTENTS_CURRENT_0 0x40000 +#define HERETIC2_CONTENTS_CURRENT_90 0x80000 +#define HERETIC2_CONTENTS_CURRENT_180 0x100000 +#define HERETIC2_CONTENTS_CURRENT_270 0x200000 +#define HERETIC2_CONTENTS_CURRENT_UP 0x400000 +#define HERETIC2_CONTENTS_CURRENT_DOWN 0x800000 +#define HERETIC2_CONTENTS_ORIGIN 0x1000000 + +#define HERETIC2_CONTENTS_DETAIL 0x8000000 + +#define HERETIC2_CONTENTS_LADDER 0x20000000 + +#define HERETIC2_CONTENTS_CAMERANOBLOCK 0x40000000 + + + +#endif // _SURFACEFLAGSDIALOG_HERETIC2_H diff --git a/plugins/surface_heretic2/surfdlg_plugin.cpp b/plugins/surface_heretic2/surfdlg_plugin.cpp new file mode 100644 index 00000000..9ac7f19a --- /dev/null +++ b/plugins/surface_heretic2/surfdlg_plugin.cpp @@ -0,0 +1,122 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "surfdlg_plugin.h" +#include "surfacedialog.h" + +#include "synapse.h" + +class CSynapseClient_SurfDLG : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + bool OnActivate(); + + CSynapseClient_SurfDLG() { } + virtual ~CSynapseClient_SurfDLG() { } +}; + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; +_QERUndoTable g_UndoTable; +_QERAppSurfaceTable g_AppSurfaceTable; +_QERSelectedFaceTable g_SelectedFaceTable; +_QERShadersTable g_ShadersTable; +_QERAppShadersTable g_AppShadersTable; +_QERAppDataTable g_AppDataTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClient_SurfDLG g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(SURFACEDIALOG_MAJOR, "heretic2", sizeof(_QERPlugSurfaceTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); + g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "quake2", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); + + return &g_SynapseClient; +} + +bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) + { + _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "heretic2")) + { + pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; + pSurfDialogTable->m_pfnDoSurface = &DoSurface; + pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; + pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; + pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClient_SurfDLG::GetInfo() +{ + return "Surface Dialog (Heretic 2) module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClient_SurfDLG::GetName() +{ + return "surface"; +} + +bool CSynapseClient_SurfDLG::OnActivate() +{ + return true; +} diff --git a/plugins/surface_heretic2/surfdlg_plugin.h b/plugins/surface_heretic2/surfdlg_plugin.h new file mode 100644 index 00000000..89129d45 --- /dev/null +++ b/plugins/surface_heretic2/surfdlg_plugin.h @@ -0,0 +1,94 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _SURFDLG_PLUGIN_H_ +#define _SURFDLG_PLUGIN_H_ + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +#include "qerplugin.h" +#include "synapse.h" +#include "iselectedface.h" +#include "iundo.h" +#include "ishaders.h" +#include "mathlib.h" +#include "missing.h" +#include "idata.h" + +#include "isurfaceplugin.h" + +class SurfaceDialog : public IPluginTexdef +{ + int refCount; +public: + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () { if ( --refCount <= 0 ) delete this; } +}; + +extern _QERFuncTable_1 g_FuncTable; +extern _QERUndoTable g_UndoTable; +extern _QERAppSurfaceTable g_AppSurfaceTable; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERShadersTable g_ShadersTable; +extern _QERAppShadersTable g_AppShadersTable; +extern _QERAppDataTable g_AppDataTable; + +#define GetSelectedFaceCount g_SelectedFaceTable.m_pfnGetSelectedFaceCount + +#define Undo_Undo g_UndoTable.m_pfnUndo_Undo +#define Undo_GetUndoId g_UndoTable.m_pfnUndo_GetUndoId + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf +#define Sys_UpdateWindows g_FuncTable.m_pfnSysUpdateWindows + + +#define Select_FitTexture g_AppSurfaceTable.m_pfnSelect_FitTexture +#define Get_SI_Inc g_AppSurfaceTable.m_pfnQERApp_QeglobalsSavedinfo_SIInc +#define GridSize g_AppSurfaceTable.m_pfnQeglobalsGetGridSize +#define FaceList_FitTexture g_AppSurfaceTable.m_pfnFaceList_FitTexture +#define GetMainWindow g_AppSurfaceTable.m_pfnGetMainWindow +#define GetSelectedFaceCountfromBrushes g_AppSurfaceTable.m_pfnGetSelectedFaceCountfromBrushes +#define GetSelFacesTexdef g_AppSurfaceTable.m_pfnGetSelFacesTexdef +#define SetTexdef_FaceList g_AppSurfaceTable.m_pfnSetTexdef_FaceList +#define SetWinPos_from_Prefs g_AppSurfaceTable.m_pfnSetWinPos_From_Prefs + +#define Texturewin g_AppShadersTable.m_pfnQeglobalsTexturewin + +#endif // _SURFDLG_PLUGIN_H_ + diff --git a/plugins/surface_quake2/surface_quake2.def b/plugins/surface_quake2/surface_quake2.def new file mode 100644 index 00000000..0cec1f32 --- /dev/null +++ b/plugins/surface_quake2/surface_quake2.def @@ -0,0 +1,8 @@ +; surface_quake2.def : Declares the module parameters for the DLL. + +LIBRARY "SURFACE_QUAKE2" +DESCRIPTION 'SURFACE_QUAKE2 Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/surface_quake2/surface_quake2.vcproj b/plugins/surface_quake2/surface_quake2.vcproj new file mode 100644 index 00000000..9ad37f69 --- /dev/null +++ b/plugins/surface_quake2/surface_quake2.vcproj @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/surface_quake2/surfacedialog.cpp b/plugins/surface_quake2/surfacedialog.cpp new file mode 100644 index 00000000..bbf42271 --- /dev/null +++ b/plugins/surface_quake2/surfacedialog.cpp @@ -0,0 +1,1939 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Surface Dialog Module +// + +// +// Nurail: Implemented to Module from the main Radiant Surface Dialog code +// + + +#include +#include + +#include "surfdlg_plugin.h" + + + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +#include "gtkr_vector.h" + +std::vector g_texdef_face_vector; + +inline texdef_to_face_t* get_texdef_face_list() +{ + return &(*g_texdef_face_vector.begin()); +} + +inline unsigned int texdef_face_list_empty() +{ + return g_texdef_face_vector.empty(); +} + +inline unsigned int texdef_face_list_size() +{ + return g_texdef_face_vector.size(); +} + +// For different faces having different values +bool is_HShift_conflicting; +bool is_VShift_conflicting; +bool is_HScale_conflicting; +bool is_VScale_conflicting; +bool is_Rotate_conflicting; +bool is_TextureName_conflicting; + +void ShowDlg(); +void HideDlg(); +void SetTexMods(); +void GetTexMods(bool b_SetUndoPoint = FALSE); +void BuildDialog(); +void FitAll(); +void InitDefaultIncrement(texdef_t *); +void DoSnapTToGrid(float hscale, float vscale); +// called to perform a fitting from the outside (shortcut key) +void SurfaceDialogFitAll(); + +// Quake2 Flags Functions +void SetFlagButtons_Quake2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty); +void SetChangeInFlags_Face_Quake2 (texdef_to_face_t *texdef_face_list); +GtkWidget* Create_Quake2FlagsDialog (GtkWidget* surfacedialog_widget); + + +// Dialog Data +int m_nHeight; +int m_nWidth; + +// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +int m_nUndoId; + + +texturewin_t *texturewin; +texdef_t *l_pIncrement; +texdef_t texdef_offset; +texdef_t texdef_SI_values; + +// For Texture Entry, activate only on entry change +char old_texture_entry[128]; + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; + +// when TRUE, this thing means the surface inspector is currently being displayed +bool g_surfwin = FALSE; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +GtkWidget* create_SurfaceInspector (void); +GtkWidget *SurfaceInspector = NULL; + +GtkWidget *m_pWidget; +GtkWidget *GetWidget () { return SurfaceInspector; } +GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } +void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } +GtkWidget *GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } + +// Spins for FitTexture +GtkWidget *spin_width; +GtkWidget *spin_height; + + +GtkWidget *texture_combo; +GtkWidget *texture_combo_entry; + +GtkWidget *match_grid_button; +GtkWidget *lock_valuechange_togglebutton; + +GtkObject *hshift_value_spinbutton_adj; +GtkWidget *hshift_value_spinbutton; +GtkObject *vshift_value_spinbutton_adj; +GtkWidget *vshift_value_spinbutton; +GtkObject *hscale_value_spinbutton_adj; +GtkWidget *hscale_value_spinbutton; +GtkObject *vscale_value_spinbutton_adj; +GtkWidget *vscale_value_spinbutton; +GtkObject *rotate_value_spinbutton_adj; +GtkWidget *rotate_value_spinbutton; + +GtkObject *hshift_offset_spinbutton_adj; +GtkWidget *hshift_offset_spinbutton; +GtkObject *vshift_offset_spinbutton_adj; +GtkWidget *vshift_offset_spinbutton; +GtkObject *hscale_offset_spinbutton_adj; +GtkWidget *hscale_offset_spinbutton; +GtkObject *vscale_offset_spinbutton_adj; +GtkWidget *vscale_offset_spinbutton; +GtkObject *rotate_offset_spinbutton_adj; +GtkWidget *rotate_offset_spinbutton; + +GtkObject *hshift_step_spinbutton_adj; +GtkWidget *hshift_step_spinbutton; +GtkObject *vshift_step_spinbutton_adj; +GtkWidget *vshift_step_spinbutton; +GtkObject *hscale_step_spinbutton_adj; +GtkWidget *hscale_step_spinbutton; +GtkObject *vscale_step_spinbutton_adj; +GtkWidget *vscale_step_spinbutton; +GtkObject *rotate_step_spinbutton_adj; +GtkWidget *rotate_step_spinbutton; + +GtkObject *fit_width_spinbutton_adj; +GtkWidget *fit_width_spinbutton; +GtkObject *fit_height_spinbutton_adj; +GtkWidget *fit_height_spinbutton; +GtkWidget *fit_button; +GtkWidget *axial_button; + +GtkWidget *done_button; +GtkWidget *apply_button; +GtkWidget *cancel_button; + +// Callbacks +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); + +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_button_clicked (GtkButton *button, gpointer user_data); +static void on_axial_button_clicked (GtkButton *button, gpointer user_data); + +static void on_done_button_clicked (GtkButton *button, gpointer user_data); +static void on_apply_button_clicked (GtkButton *button, gpointer user_data); +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + + +void IsFaceConflicting() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char buf[12]; + char texture_name[128]; + + if (texdef_face_list_empty()) + { + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); + return; + } + + g_bListenChanged = FALSE; + + tmp_texdef = &get_texdef_face_list()->texdef; + + strcpy(texture_name, tmp_texdef->GetName() ); + + texdef_SI_values.shift[0] = tmp_texdef->shift[0]; + texdef_SI_values.shift[1] = tmp_texdef->shift[1]; + texdef_SI_values.scale[0] = tmp_texdef->scale[0]; + texdef_SI_values.scale[1] = tmp_texdef->scale[1]; + texdef_SI_values.rotate = tmp_texdef->rotate; + texdef_SI_values.SetName( texture_name ); + + is_HShift_conflicting = FALSE; + is_VShift_conflicting = FALSE; + is_HScale_conflicting = FALSE; + is_VScale_conflicting = FALSE; + is_Rotate_conflicting = FALSE; + is_TextureName_conflicting = FALSE; + + if (texdef_face_list_size() > 1) + { + temp_texdef_face_list = get_texdef_face_list()->next; + + for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) + is_HShift_conflicting = TRUE; + + if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) + is_VShift_conflicting = TRUE; + + if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) + is_HScale_conflicting = TRUE; + + if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) + is_VScale_conflicting = TRUE; + + if ( texdef_SI_values.rotate != tmp_texdef->rotate ) + is_Rotate_conflicting = TRUE; + + if ( strcmp( texture_name, tmp_texdef->GetName() ) ) + is_TextureName_conflicting = TRUE; + } + } + + if(is_HShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); + + if(is_VShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); + + if(is_HScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); + + if(is_VScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); + + if(is_Rotate_conflicting) + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); + + g_bListenChanged = TRUE; +} + +#define MAX_NUM_LIST_ITEMS 15 +static void PopulateTextureComboList() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char blank[1]; + GList *items = NULL; + GList *tmp_item; + int num_of_list_items = 0; + + blank[0] = 0; + + if (texdef_face_list_empty()) + { + items = g_list_append (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + else if ( !is_TextureName_conflicting ) + { + temp_texdef_face_list = get_texdef_face_list(); + tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, tmp_texdef->GetName()); + } + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + // Need to do a string compare, hence the custom search + if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) + { + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + num_of_list_items++; + } + // Make sure the combo list isn't too long + if (num_of_list_items >= MAX_NUM_LIST_ITEMS) + break; + } + // If this isn't added last (to the top of the list), g_list_find freaks. + items = g_list_prepend (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); + g_list_free(items); + +} + +static void ZeroOffsetValues() +{ + texdef_offset.shift[0] = 0.0; + texdef_offset.shift[1] = 0.0; + texdef_offset.scale[0] = 0.0; + texdef_offset.scale[1] = 0.0; + texdef_offset.rotate = 0.0; +} + +static void GetTexdefInfo_from_Radiant() +{ + g_texdef_face_vector.clear(); + + unsigned int count = GetSelectedFaceCountfromBrushes(); + if(count == 0) + count = GetSelectedFaceCount(); + + g_texdef_face_vector.resize(count); + + if (!texdef_face_list_empty()) + { + texdef_to_face_t* p = get_texdef_face_list(); + GetSelFacesTexdef( get_texdef_face_list() ); + } + + IsFaceConflicting(); + PopulateTextureComboList(); + ZeroOffsetValues(); + if ( texdef_face_list_empty() ) + SetFlagButtons_Quake2( get_texdef_face_list() , TRUE); + else + SetFlagButtons_Quake2( get_texdef_face_list() , FALSE); +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + HideDlg(); + return TRUE; +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + l_pIncrement = Get_SI_Inc(); + + if (hscale == 0.0f) + { + hscale = 0.5f; + } + if (vscale == 0.0f) + { + vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = GridSize() / hscale; + l_pIncrement->shift[1] = GridSize() / vscale; + // now some update work + // FIXME: doesn't look good here, seems to be called several times + SetTexMods(); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + if (!SurfaceInspector) + return; + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + if (g_surfwin) + { +#ifdef DBG_SI + Sys_Printf("UpdateSurfaceDialog\n"); +#endif + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } + +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + if (!SurfaceInspector) + create_SurfaceInspector (); + + ShowDlg(); + SetTexMods (); +} + +void ToggleSurface() +{ +#ifdef DBG_SI + Sys_Printf("ToggleSurface Module\n"); +#endif + if (!g_surfwin) + DoSurface (); + else + on_cancel_button_clicked(NULL, NULL); +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + DoSurface(); + FitAll(); +} + +// ============================================================================= +// SurfaceDialog class + +void ShowDlg() +{ + + if(!SurfaceInspector) + create_SurfaceInspector(); + else + gtk_widget_show (SurfaceInspector); + + GetTexdefInfo_from_Radiant(); + GetTexMods(TRUE); // Set Initial Undo Point + g_surfwin = TRUE; +} + +void HideDlg() +{ + g_surfwin = FALSE; + gtk_widget_hide (SurfaceInspector); +} + + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void BuildDialog () +{ + if ( !SurfaceInspector ) + create_SurfaceInspector(); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +=============== +*/ + +void SetTexMods() +{ + texdef_t *pt; + GtkSpinButton *spin; + GtkAdjustment *adjust; + + texturewin = Texturewin (); + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + pt = &texturewin->texdef; + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + texdef_offset.SetName(SHADER_NOT_FOUND); + + + spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); + + spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + + + spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); + + spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + + + spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); + + spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + + + spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); + + spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + + + spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.rotate); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); + + spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + + + g_bListenChanged = true; + + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = texturewin->texdef; +} + +/* +============== +GetTexMods + +Shows any changes to the main Radiant windows +=============== +*/ +void GetTexMods(bool b_SetUndoPoint) +{ + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg GetTexMods\n"); +#endif + + if ( !texdef_face_list_empty() ) + { + g_bListenUpdate=FALSE; + SetChangeInFlags_Face_Quake2 ( get_texdef_face_list() ); + SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint ); + g_bListenUpdate=TRUE; + + if (b_SetUndoPoint) + m_nUndoId = Undo_GetUndoId(); + } +} + +void FitAll() +{ + on_fit_button_clicked(NULL, NULL); +} + + +//////////////////////////////////////////////////////////////////// +// +// GUI Section +// +//////////////////////////////////////////////////////////////////// + +GtkWidget* create_SurfaceInspector (void) +{ + + GtkWidget *label; + GtkWidget *hseparator; + GtkWidget *eventbox; + + GtkWidget *viewport8; + GtkWidget *viewport9; + GtkWidget *viewport2; + GtkWidget *viewport7; + GtkWidget *viewport5; + GtkWidget *viewport6; + GtkWidget *viewport10; + + GtkWidget *table1; + GtkWidget *table4; + GtkWidget *table5; + GtkWidget *table7; + + GtkWidget *alignment1; + GtkWidget *alignment2; + GtkWidget *alignment3; + + GtkWidget *vbox7; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hbox4; + + GtkWidget *image1; + GtkWidget *image2; + GtkWidget *image3; + + GtkWidget *hbuttonbox1; + + SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); + gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); + + SetWinPos_from_Prefs(SurfaceInspector); + + viewport8 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport8); + gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (viewport8), vbox7); + + viewport9 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport9); + gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (viewport9), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); + + label = gtk_label_new ("Texture: "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + texture_combo = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), + "KeepMeAround", texture_combo); + gtk_combo_disable_activate ( (GtkCombo*) texture_combo); + gtk_widget_show (texture_combo); + gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); + + texture_combo_entry = GTK_COMBO (texture_combo)->entry; + gtk_widget_show (texture_combo_entry); + gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport2); + gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); + + table1 = gtk_table_new (13, 4, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (viewport2), table1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Offset"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); + gtk_widget_show (match_grid_button); + gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); + + label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new (" H Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Rotate: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("H Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); + gtk_widget_show (lock_valuechange_togglebutton); + gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); + + // Value Spins + hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); + + vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); + + hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); + + vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); + + rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); + gtk_widget_show (rotate_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); + + // Offset Spins + hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (hshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + + vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (vshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + + hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (hscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + + vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (vscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + + rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); + gtk_widget_show (rotate_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + + // Step Spins + hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); + gtk_widget_show (rotate_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + viewport7 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport7); + gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); + + table4 = gtk_table_new (4, 7, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (viewport7), table4); + + viewport5 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport5); + gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); + + table5 = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (viewport5), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 2); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); + gtk_widget_show (fit_width_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); + + fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); + gtk_widget_show (fit_height_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 3, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 4, 0); + + fit_button = gtk_button_new_with_mnemonic (" Fit "); + gtk_widget_show (fit_button); + gtk_container_add (GTK_CONTAINER (eventbox), fit_button); + + viewport6 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport6); + gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); + + table7 = gtk_table_new (2, 1, FALSE); + gtk_widget_show (table7); + gtk_container_add (GTK_CONTAINER (viewport6), table7); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + axial_button = gtk_button_new_with_mnemonic ("Axial"); + gtk_widget_show (axial_button); + gtk_container_add (GTK_CONTAINER (eventbox), axial_button); + gtk_widget_set_size_request (axial_button, 56, 29); + gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); + + // Fit in Flags sub-dialog + Create_Quake2FlagsDialog(vbox7); + + viewport10 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport10); + gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + + done_button = gtk_button_new (); + gtk_widget_show (done_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); + GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (done_button), alignment1); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (alignment1), hbox2); + + image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Done"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + apply_button = gtk_button_new (); + gtk_widget_show (apply_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); + GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); + + alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (apply_button), alignment3); + + hbox4 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (alignment3), hbox4); + + image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image3); + gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Apply"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + cancel_button = gtk_button_new (); + gtk_widget_show (cancel_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); + + hbox3 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (alignment2), hbox3); + + image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Cancel"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + + g_signal_connect ( (gpointer) SurfaceInspector, + "delete_event", + G_CALLBACK (delete_event_callback), + NULL ); + g_signal_connect ((gpointer) SurfaceInspector, "destroy", + G_CALLBACK (gtk_widget_destroy), + NULL); + + g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", + G_CALLBACK (on_texture_combo_entry_key_press_event), + NULL); + g_signal_connect ((gpointer) texture_combo_entry, "activate", + G_CALLBACK (on_texture_combo_entry_activate), + NULL); + + + g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_hshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_vshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_hscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_vscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", + G_CALLBACK (on_rotate_offset_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", + G_CALLBACK (on_hshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", + G_CALLBACK (on_vshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", + G_CALLBACK (on_hscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", + G_CALLBACK (on_vscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", + G_CALLBACK (on_rotate_value_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", + G_CALLBACK (on_hshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", + G_CALLBACK (on_vshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", + G_CALLBACK (on_hscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", + G_CALLBACK (on_vscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", + G_CALLBACK (on_rotate_step_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) match_grid_button, "clicked", + G_CALLBACK (on_match_grid_button_clicked), + NULL); + g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", + G_CALLBACK (on_lock_valuechange_togglebutton_toggled), + NULL); + + g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", + G_CALLBACK (on_fit_width_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", + G_CALLBACK (on_fit_height_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_button, "clicked", + G_CALLBACK (on_fit_button_clicked), + NULL); + + g_signal_connect ((gpointer) axial_button, "clicked", + G_CALLBACK (on_axial_button_clicked), + NULL); + + g_signal_connect ((gpointer) done_button, "clicked", + G_CALLBACK (on_done_button_clicked), + NULL); + g_signal_connect ((gpointer) apply_button, "clicked", + G_CALLBACK (on_apply_button_clicked), + NULL); + g_signal_connect ((gpointer) cancel_button, "clicked", + G_CALLBACK (on_cancel_button_clicked), + NULL); + + + return SurfaceInspector; +} + + +// Texture Combo +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + // Have Tab activate selection as well as Return + if (event->keyval == GDK_Tab) + g_signal_emit_by_name ( texture_combo_entry, "activate" ); + + return FALSE; +} + +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + char text[128] = { 0 }; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + // activate only on entry change + strcpy( text, gtk_entry_get_text(entry)); + if ( strcmp( old_texture_entry, text )) + { + // Check for spaces in shader name + if (text[0] <= ' ' || strchr(text, ' ')) + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + strcpy( old_texture_entry, text ); + tmp_texdef->SetName( text ); + } + GetTexMods(); + } + } + } +} + +// Offset Spins +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HShift_conflicting) + tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; + else + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + } + GetTexMods(); + } +} + +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VShift_conflicting) + tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; + else + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + } + GetTexMods(); + } + +} + +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HScale_conflicting) + tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; + else + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + } + GetTexMods(); + } + + +} + +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VScale_conflicting) + tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; + else + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + } + GetTexMods(); + } + +} + +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_Rotate_conflicting) + tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; + else + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + } + GetTexMods(); + } + +} + + +// Match Grid +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) +{ + float hscale, vscale; + + if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) + hscale = 0.0; + else + hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) + vscale = 0.0; + else + vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + DoSnapTToGrid (hscale, vscale); +} + + +// Lock out changes to Value +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) +{ + bool is_Locked; + + is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); + + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); +} + + +// Value Spins +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + is_HShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + is_VShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + is_HScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + is_VScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + is_Rotate_conflicting = FALSE; + } + GetTexMods(); + } +} + + +// Step Spins +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[0] = val; +} + +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged VShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[1] = val; +} + +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[0] = val; +} + +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[1] = val; +} + +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->rotate = val; +} + + +// Fit Texture +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); +} + +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); +} + +static void on_fit_button_clicked (GtkButton *button, gpointer user_data) +{ + FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); + Sys_UpdateWindows(W_ALL); +} + + +// Axial Button +static void on_axial_button_clicked (GtkButton *button, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_texdef->shift[0] = 0.0; + tmp_texdef->shift[1] = 0.0; + tmp_texdef->scale[0] = 0.5; + tmp_texdef->scale[1] = 0.5; + tmp_texdef->rotate = 0.0; + } + } + + SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); + Sys_UpdateWindows(W_ALL); +} + + +// Action Buttons +static void on_done_button_clicked (GtkButton *button, gpointer user_data) +{ + if ( !texdef_face_list_empty() ) + GetTexMods(TRUE); + HideDlg(); + Sys_UpdateWindows(W_ALL); +} + +static void on_apply_button_clicked (GtkButton *button, gpointer user_data) +{ + if (!g_bListenChanged) + return; + + if ( !texdef_face_list_empty() ) + { + GetTexMods (TRUE); + Sys_UpdateWindows(W_CAMERA); + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } +} + +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) +{ + texturewin = Texturewin (); + texturewin->texdef = g_old_texdef; + // cancel the last do if we own it + if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(TRUE); + g_bListenUpdate = true; + m_nUndoId = 0; + } + HideDlg(); +} + + diff --git a/plugins/surface_quake2/surfacedialog.h b/plugins/surface_quake2/surfacedialog.h new file mode 100644 index 00000000..96ab3c79 --- /dev/null +++ b/plugins/surface_quake2/surfacedialog.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SURFACEDIALOG_H_ +#define _SURFACEDIALOG_H_ + +void UpdateSurfaceDialog (); +void DoSurface (); +void ToggleSurface (); +void SurfaceDlgFitAll (); +GtkWidget *Get_SI_Module_Widget (); + +#endif // _SURFACEDIALOG_H_ diff --git a/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp b/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp new file mode 100644 index 00000000..6386d1e3 --- /dev/null +++ b/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp @@ -0,0 +1,1168 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include "surfdlg_plugin.h" + +#include "surfaceflagsdialog_quake2.h" + + GtkWidget *notebook1; + + GtkWidget *surface_lightbutton; + GtkWidget *surface_slickbutton; + GtkWidget *surface_skybutton; + GtkWidget *surface_warpbutton; + GtkWidget *surface_trans33button; + GtkWidget *surface_trans66button; + GtkWidget *surface_flowingbutton; + GtkWidget *surface_nodrawbutton; + GtkWidget *surface_hintbutton; + GtkWidget *surface_skipbutton; + + GtkWidget *content_solidbutton; + GtkWidget *content_windowbutton; + GtkWidget *content_auxbutton; + GtkWidget *content_lavabutton; + GtkWidget *content_slimebutton; + GtkWidget *content_waterbutton; + GtkWidget *content_mistbutton; + GtkWidget *content_areaportalbutton; + GtkWidget *content_playerclipbutton; + GtkWidget *content_monsterclipbutton; + GtkWidget *content_current0button; + GtkWidget *content_current90button; + GtkWidget *content_current180button; + GtkWidget *content_current270button; + GtkWidget *content_currentUPbutton; + GtkWidget *content_currentDOWNbutton; + GtkWidget *content_originbutton; + GtkWidget *content_detailbutton; + GtkWidget *content_translucentbutton; + GtkWidget *content_ladderbutton; + + GtkWidget *surfacebutton; + GtkWidget *contentbutton; + + GtkWidget *value_entry; + gboolean setup_buttons = TRUE; + + int working_surface_flags; + int surface_mask; + int working_content_flags; + int content_mask; + int working_value; + +inline void set_inconsistent(GtkWidget *toggle_button) +{ + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), TRUE); +} + +inline void clear_inconsistent(GtkWidget *toggle_button) +{ + GtkWidget *button_label; + + if ( gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (toggle_button)) ) + { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), FALSE); + } + +} + +void clear_all_inconsistent(void) +{ + clear_inconsistent( surface_lightbutton ); + clear_inconsistent( surface_slickbutton ); + clear_inconsistent( surface_skybutton ); + clear_inconsistent( surface_warpbutton ); + clear_inconsistent( surface_trans33button ); + clear_inconsistent( surface_trans66button ); + clear_inconsistent( surface_flowingbutton ); + clear_inconsistent( surface_nodrawbutton ); + clear_inconsistent( surface_hintbutton ); + clear_inconsistent( surface_skipbutton ); + + clear_inconsistent( content_solidbutton ); + clear_inconsistent( content_windowbutton ); + clear_inconsistent( content_auxbutton ); + clear_inconsistent( content_lavabutton ); + clear_inconsistent( content_slimebutton ); + clear_inconsistent( content_waterbutton ); + clear_inconsistent( content_mistbutton ); + clear_inconsistent( content_areaportalbutton ); + clear_inconsistent( content_playerclipbutton ); + clear_inconsistent( content_monsterclipbutton ); + clear_inconsistent( content_current0button ); + clear_inconsistent( content_current90button ); + clear_inconsistent( content_current180button ); + clear_inconsistent( content_current270button ); + clear_inconsistent( content_currentUPbutton ); + clear_inconsistent( content_currentDOWNbutton ); + clear_inconsistent( content_originbutton ); + clear_inconsistent( content_detailbutton ); + clear_inconsistent( content_translucentbutton ); + clear_inconsistent( content_ladderbutton ); +} + +void clear_all_buttons_and_values() +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_lightbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), FALSE); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); + + gtk_entry_set_text( (GtkEntry *)value_entry, ""); +} + +void SetFlagButtons_Quake2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty) +{ + int i; + int contents = 0; + int flags = 0; + int value = 0; + int diff_contents = 0; + int diff_flags = 0; + gboolean diff_value = FALSE; + char tex_buff[11]; + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + + + setup_buttons = TRUE; + working_surface_flags = 0; + surface_mask = 0; + working_content_flags = 0; + content_mask = 0; + working_value = 0; + + if(!b_isListEmpty) + { + tmp_texdef = &texdef_face_list->texdef; + contents = tmp_texdef->contents; + flags = tmp_texdef->flags; + value = tmp_texdef->value; + + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\ttmp_texdef\n",tmp_texdef->flags,tmp_texdef->contents,tmp_texdef->value); + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\n",flags,contents,value); + + for (temp_texdef_face_list = texdef_face_list->next; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + diff_contents |= contents ^ tmp_texdef->contents; // Figure out which buttons are inconsistent + diff_flags |= flags ^ tmp_texdef->flags; + if (tmp_texdef->value != value) + diff_value = TRUE; + + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\ttmp_texdef\n",tmp_texdef->flags,tmp_texdef->contents,tmp_texdef->value); + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\n",flags,contents,value); + + } + } + + + + clear_all_inconsistent(); + + // If no faces/brushes are selected, clear everything and bail + if(b_isListEmpty) + { + clear_all_buttons_and_values(); + setup_buttons = FALSE; + return; + } + + // Set surface buttons to reflect brush/face flags, contents, and values + if(diff_flags & QUAKE2_SURF_LIGHT) + set_inconsistent(surface_lightbutton); + else if(flags & QUAKE2_SURF_LIGHT) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), FALSE); + + if(diff_flags & QUAKE2_SURF_SLICK) + set_inconsistent(surface_slickbutton); + else if(flags & QUAKE2_SURF_SLICK) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_SKY) + set_inconsistent(surface_skybutton); + else if(flags & QUAKE2_SURF_SKY) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_WARP) + set_inconsistent(surface_warpbutton); + else if(flags & QUAKE2_SURF_WARP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_TRANS33) + set_inconsistent(surface_trans33button); + else if(flags & QUAKE2_SURF_TRANS33) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); + + if(diff_flags & QUAKE2_SURF_TRANS66) + set_inconsistent(surface_trans66button); + else if(flags & QUAKE2_SURF_TRANS66) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); + + if(diff_flags & QUAKE2_SURF_FLOWING) + set_inconsistent(surface_flowingbutton); + else if(flags & QUAKE2_SURF_FLOWING) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_NODRAW) + set_inconsistent(surface_nodrawbutton); + else if(flags & QUAKE2_SURF_NODRAW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_HINT) + set_inconsistent(surface_hintbutton); + else if(flags & QUAKE2_SURF_HINT) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_SKIP) + set_inconsistent(surface_skipbutton); + else if(flags & QUAKE2_SURF_SKIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), FALSE); + + // Set content buttons to reflect brush values + if(diff_contents & QUAKE2_CONTENTS_SOLID) + set_inconsistent(content_solidbutton); + else if(contents & QUAKE2_CONTENTS_SOLID) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_WINDOW) + set_inconsistent(content_windowbutton); + else if(contents & QUAKE2_CONTENTS_WINDOW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_AUX) + set_inconsistent(content_auxbutton); + else if(contents & QUAKE2_CONTENTS_AUX) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_LAVA) + set_inconsistent(content_lavabutton); + else if(contents & QUAKE2_CONTENTS_LAVA) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_SLIME) + set_inconsistent(content_slimebutton); + else if(contents & QUAKE2_CONTENTS_SLIME) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_WATER) + set_inconsistent(content_waterbutton); + else if(contents & QUAKE2_CONTENTS_WATER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_MIST) + set_inconsistent(content_mistbutton); + else if(contents & QUAKE2_CONTENTS_MIST) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_AREAPORTAL) + set_inconsistent(content_areaportalbutton); + else if(contents & QUAKE2_CONTENTS_AREAPORTAL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_PLAYERCLIP) + set_inconsistent(content_playerclipbutton); + else if(contents & QUAKE2_CONTENTS_PLAYERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_MONSTERCLIP) + set_inconsistent(content_monsterclipbutton); + else if(contents & QUAKE2_CONTENTS_MONSTERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_0) + set_inconsistent(content_current0button); + else if(contents & QUAKE2_CONTENTS_CURRENT_0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_90) + set_inconsistent(content_current90button); + else if(contents & QUAKE2_CONTENTS_CURRENT_90) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_180) + set_inconsistent(content_current180button); + else if(contents & QUAKE2_CONTENTS_CURRENT_180) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_270) + set_inconsistent(content_current270button); + else if(contents & QUAKE2_CONTENTS_CURRENT_270) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_UP) + set_inconsistent(content_currentUPbutton); + else if(contents & QUAKE2_CONTENTS_CURRENT_UP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_DOWN) + set_inconsistent(content_currentDOWNbutton); + else if(contents & QUAKE2_CONTENTS_CURRENT_DOWN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_ORIGIN) + set_inconsistent(content_originbutton); + else if(contents & QUAKE2_CONTENTS_ORIGIN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_DETAIL) + set_inconsistent(content_detailbutton); + else if(contents & QUAKE2_CONTENTS_DETAIL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_TRANSLUCENT) + set_inconsistent(content_translucentbutton); + else if(contents & QUAKE2_CONTENTS_TRANSLUCENT) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_LADDER) + set_inconsistent(content_ladderbutton); + else if(contents & QUAKE2_CONTENTS_LADDER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); + + // Set Value + if(diff_value) + gtk_entry_set_text( (GtkEntry *)value_entry, ""); + else + { + working_value = value; + sprintf( tex_buff, "%d", value); + gtk_entry_set_text( (GtkEntry *)value_entry, tex_buff); + } + + setup_buttons = FALSE; +} + +void SetChangeInFlags_Face_Quake2 (texdef_to_face_t *texdef_face_list) +{ + texdef_to_face_t *temp_texdef_face_list; + texdef_t *tmp_texdef; + + for (temp_texdef_face_list = texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + tmp_texdef->flags = (tmp_texdef->flags & ~surface_mask) | working_surface_flags; + tmp_texdef->contents = (tmp_texdef->contents & ~content_mask) | working_content_flags; + tmp_texdef->value = working_value; + Sys_Printf("content_flag: %d content_mask: %d\n",working_content_flags,content_mask); + Sys_Printf("content: %d\n",tmp_texdef->contents); + } +} + +inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag, gboolean change_flag_to) +{ + + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) // Clear out inconsistent, if set + clear_inconsistent(GTK_WIDGET (togglebutton)); + + surface_mask |= sur_flag; + + if (change_flag_to) + working_surface_flags |= sur_flag; + else + working_surface_flags &= ~sur_flag; + } +} + +inline void change_contentflag (GtkWidget *togglebutton, int content_flag, gboolean change_flag_to) +{ + + if ( (!setup_buttons) ) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) + clear_inconsistent(togglebutton); + //if (g_ptrSelectedFaces.GetSize() == 0) // Only changing content flags on whole brushes, not faces. + //{ + content_mask |= content_flag; + + if (change_flag_to) + working_content_flags |= content_flag; + else + working_content_flags &= ~content_flag; + //} + Sys_Printf("content_flag: %d content_mask: %d\n",content_flag,content_mask); + } +} + +// Surface Flags Callbacks +void +on_surface_lightbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_lightbutton, QUAKE2_SURF_LIGHT, (GTK_TOGGLE_BUTTON (surface_lightbutton)->active)); + +} + +void +on_surface_slickbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_slickbutton, QUAKE2_SURF_SLICK, (GTK_TOGGLE_BUTTON (surface_slickbutton)->active)); + +} + +void +on_surface_skybutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_skybutton, QUAKE2_SURF_SKY, (GTK_TOGGLE_BUTTON (surface_skybutton)->active)); +} + +void +on_surface_warpbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_warpbutton, QUAKE2_SURF_WARP, (GTK_TOGGLE_BUTTON (surface_warpbutton)->active)); +} + +void +on_surface_trans33button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans33button, QUAKE2_SURF_TRANS33, (GTK_TOGGLE_BUTTON (surface_trans33button)->active)); +} + +void +on_surface_trans66button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans66button, QUAKE2_SURF_TRANS66, (GTK_TOGGLE_BUTTON (surface_trans66button)->active)); +} + +void +on_surface_flowingbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_flowingbutton, QUAKE2_SURF_FLOWING, (GTK_TOGGLE_BUTTON (surface_flowingbutton)->active)); +} + +void +on_surface_nodrawbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_nodrawbutton, QUAKE2_SURF_NODRAW, (GTK_TOGGLE_BUTTON (surface_nodrawbutton)->active)); +} + +void +on_surface_hintbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_hintbutton, QUAKE2_SURF_HINT, (GTK_TOGGLE_BUTTON (surface_hintbutton)->active)); +} + +void +on_surface_skipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_skipbutton, QUAKE2_SURF_SKIP, (GTK_TOGGLE_BUTTON (surface_skipbutton)->active)); +} + +// Content Flags Callbacks +void +on_content_solidbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_solidbutton, QUAKE2_CONTENTS_SOLID, (GTK_TOGGLE_BUTTON (content_solidbutton)->active)); +} + +void +on_content_windowbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_windowbutton, QUAKE2_CONTENTS_WINDOW, (GTK_TOGGLE_BUTTON (content_windowbutton)->active)); +} + +void +on_content_auxbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_auxbutton, QUAKE2_CONTENTS_AUX, (GTK_TOGGLE_BUTTON (content_auxbutton)->active)); +} + +void +on_content_lavabutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_lavabutton, QUAKE2_CONTENTS_LAVA, (GTK_TOGGLE_BUTTON (content_lavabutton)->active)); +} + +void +on_content_slimebutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_slimebutton, QUAKE2_CONTENTS_SLIME, (GTK_TOGGLE_BUTTON (content_slimebutton)->active)); +} + +void +on_content_waterbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_waterbutton, QUAKE2_CONTENTS_WATER, (GTK_TOGGLE_BUTTON (content_waterbutton)->active)); +} + +void +on_content_mistbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_mistbutton, QUAKE2_CONTENTS_MIST, (GTK_TOGGLE_BUTTON (content_mistbutton)->active)); +} + +void +on_content_areaportalbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_areaportalbutton, QUAKE2_CONTENTS_AREAPORTAL, (GTK_TOGGLE_BUTTON (content_areaportalbutton)->active)); +} + +void +on_content_playerclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_playerclipbutton, QUAKE2_CONTENTS_PLAYERCLIP, (GTK_TOGGLE_BUTTON (content_playerclipbutton)->active)); +} + +void +on_content_monsterclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_monsterclipbutton, QUAKE2_CONTENTS_MONSTERCLIP, (GTK_TOGGLE_BUTTON (content_monsterclipbutton)->active)); +} + +void +on_content_current0button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current0button, QUAKE2_CONTENTS_CURRENT_0, (GTK_TOGGLE_BUTTON (content_current0button)->active)); +} + +void +on_content_current90button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current90button, QUAKE2_CONTENTS_CURRENT_90, (GTK_TOGGLE_BUTTON (content_current90button)->active)); +} + +void +on_content_current180button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current180button, QUAKE2_CONTENTS_CURRENT_180, (GTK_TOGGLE_BUTTON (content_current180button)->active)); +} + +void +on_content_current270button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current270button, QUAKE2_CONTENTS_CURRENT_270, (GTK_TOGGLE_BUTTON (content_current270button)->active)); +} + +void +on_content_currentUPbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentUPbutton, QUAKE2_CONTENTS_CURRENT_UP, (GTK_TOGGLE_BUTTON (content_currentUPbutton)->active)); +} + +void +on_content_currentDOWNbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentDOWNbutton, QUAKE2_CONTENTS_CURRENT_DOWN, (GTK_TOGGLE_BUTTON (content_currentDOWNbutton)->active)); +} + +void +on_content_originbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_originbutton, QUAKE2_CONTENTS_ORIGIN, (GTK_TOGGLE_BUTTON (content_originbutton)->active)); +} + +void +on_content_detailbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_detailbutton, QUAKE2_CONTENTS_DETAIL, (GTK_TOGGLE_BUTTON (content_detailbutton)->active)); +} + +void +on_content_translucentbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_translucentbutton, QUAKE2_CONTENTS_TRANSLUCENT, (GTK_TOGGLE_BUTTON (content_translucentbutton)->active)); +} + +void +on_content_ladderbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_ladderbutton, QUAKE2_CONTENTS_LADDER, (GTK_TOGGLE_BUTTON (content_ladderbutton)->active)); +} + +// Value Entry Callback +void +on_value_entry_changed (GtkEditable *editable, + gpointer user_data) +{ + if ( (!setup_buttons) ) // If we're setting up the buttons, don't change value + working_value = atoi( gtk_entry_get_text( (GtkEntry*)editable) ); +} + +void +on_value_entry_insert_text (GtkEditable *editable, + gchar *new_text, + gint new_text_length, + gint *position, + gpointer user_data) +{ + int i, count=0; + gchar *result; + int entry_value; + texdef_t *pt; + brush_t *b; + face_t *f; + + // Limit input to digits, throwing out anything else + // Modified from Gtk FAQ for text filtering of GtkEntry + result = g_new (gchar, new_text_length); + + for (i=0; i < new_text_length; i++) { + if (!isdigit(new_text[i])) + continue; + result[count++] = new_text[i]; + } + + if (count > 0) { + gtk_signal_handler_block_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_value_entry_insert_text), + user_data); + gtk_editable_insert_text (editable, result, count, position); + gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_value_entry_insert_text), + user_data); + } + gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); + + g_free (result); +} + +void +on_surfacebutton_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_notebook_set_page (GTK_NOTEBOOK(notebook1), 0); +} + +void +on_contentbutton_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_notebook_set_page (GTK_NOTEBOOK(notebook1), 1); +} + + +#define QUAKE2_FLAG_BUTTON_BORDER 3 + +GtkWidget* Create_Quake2FlagsDialog (GtkWidget* surfacedialog_widget) +{ + GtkWidget *frame1; + GtkWidget *vbox1; + GtkWidget *vbox2; + GtkWidget *vbox3; + GtkWidget *vbox4; + GtkWidget *table4; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hseparator1; + GtkWidget *value_label; + GtkWidget *label5; + GtkWidget *table3; + GtkWidget *label6; + GtkWidget *table1; + + + frame1 = gtk_frame_new ("Flags"); + gtk_widget_show (frame1); + gtk_container_add (GTK_CONTAINER (surfacedialog_widget), frame1); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (frame1), vbox1); + + notebook1 = gtk_notebook_new (); + gtk_widget_show (notebook1); + gtk_box_pack_start (GTK_BOX (vbox1), notebook1, TRUE, TRUE, 0); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook1), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (notebook1), 5); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (notebook1), vbox2); + + table4 = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table4); + gtk_box_pack_start (GTK_BOX (vbox2), table4, TRUE, TRUE, 0); + + surface_lightbutton = gtk_toggle_button_new_with_label ("Light"); + gtk_signal_connect (GTK_OBJECT (surface_lightbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_lightbutton_toggled), + NULL); + gtk_widget_show (surface_lightbutton); + gtk_table_attach (GTK_TABLE (table4), surface_lightbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_lightbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_slickbutton = gtk_toggle_button_new_with_label ("Slick"); + gtk_signal_connect (GTK_OBJECT (surface_slickbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_slickbutton_toggled), + NULL); + gtk_widget_show (surface_slickbutton); + gtk_table_attach (GTK_TABLE (table4), surface_slickbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_slickbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_skybutton = gtk_toggle_button_new_with_label ("Sky"); + gtk_signal_connect (GTK_OBJECT (surface_skybutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_skybutton_toggled), + NULL); + gtk_widget_show (surface_skybutton); + gtk_table_attach (GTK_TABLE (table4), surface_skybutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_skybutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_warpbutton = gtk_toggle_button_new_with_label ("Warp"); + gtk_signal_connect (GTK_OBJECT (surface_warpbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_warpbutton_toggled), + NULL); + gtk_widget_show (surface_warpbutton); + gtk_table_attach (GTK_TABLE (table4), surface_warpbutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_warpbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_trans33button = gtk_toggle_button_new_with_label ("Trans 33"); + gtk_signal_connect (GTK_OBJECT (surface_trans33button), "toggled", + GTK_SIGNAL_FUNC (on_surface_trans33button_toggled), + NULL); + gtk_widget_show (surface_trans33button); + gtk_table_attach (GTK_TABLE (table4), surface_trans33button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_trans33button), QUAKE2_FLAG_BUTTON_BORDER); + + surface_trans66button = gtk_toggle_button_new_with_label ("Trans 66"); + gtk_signal_connect (GTK_OBJECT (surface_trans66button), "toggled", + GTK_SIGNAL_FUNC (on_surface_trans66button_toggled), + NULL); + gtk_widget_show (surface_trans66button); + gtk_table_attach (GTK_TABLE (table4), surface_trans66button, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_trans66button), QUAKE2_FLAG_BUTTON_BORDER); + + surface_flowingbutton = gtk_toggle_button_new_with_label ("Flowing"); + gtk_signal_connect (GTK_OBJECT (surface_flowingbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_flowingbutton_toggled), + NULL); + gtk_widget_show (surface_flowingbutton); + gtk_table_attach (GTK_TABLE (table4), surface_flowingbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_flowingbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_nodrawbutton = gtk_toggle_button_new_with_label ("NoDraw"); + gtk_signal_connect (GTK_OBJECT (surface_nodrawbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_nodrawbutton_toggled), + NULL); + gtk_widget_show (surface_nodrawbutton); + gtk_table_attach (GTK_TABLE (table4), surface_nodrawbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_nodrawbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_hintbutton = gtk_toggle_button_new_with_label ("Hint"); + gtk_signal_connect (GTK_OBJECT (surface_hintbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_hintbutton_toggled), + NULL); + gtk_widget_show (surface_hintbutton); + gtk_table_attach (GTK_TABLE (table4), surface_hintbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_hintbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_skipbutton = gtk_toggle_button_new_with_label ("Skip"); + gtk_signal_connect (GTK_OBJECT (surface_skipbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_skipbutton_toggled), + NULL); + gtk_widget_show (surface_skipbutton); + gtk_table_attach (GTK_TABLE (table4), surface_skipbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_skipbutton), QUAKE2_FLAG_BUTTON_BORDER); + + hseparator1 = gtk_hseparator_new (); + gtk_widget_show (hseparator1); + gtk_box_pack_start (GTK_BOX (vbox2), hseparator1, FALSE, FALSE, 0); + gtk_widget_set_usize (hseparator1, -2, 5); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0); + + hbox3 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox3); + gtk_box_pack_start (GTK_BOX (hbox2), hbox3, TRUE, TRUE, 0); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_box_pack_start (GTK_BOX (hbox3), vbox4, TRUE, TRUE, 0); + + value_label = gtk_label_new (" Value: "); + gtk_widget_show (value_label); + gtk_box_pack_start (GTK_BOX (hbox3), value_label, FALSE, FALSE, 0); + + value_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (value_entry), "changed", + GTK_SIGNAL_FUNC (on_value_entry_changed), + NULL); + gtk_signal_connect (GTK_OBJECT (value_entry), "insert_text", + GTK_SIGNAL_FUNC (on_value_entry_insert_text), + NULL); + gtk_entry_set_max_length( (GtkEntry *)value_entry, 11); + gtk_widget_show (value_entry); + gtk_box_pack_start (GTK_BOX (hbox3), value_entry, TRUE, TRUE, 0); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox3); + gtk_box_pack_start (GTK_BOX (hbox3), vbox3, TRUE, TRUE, 0); + + label5 = gtk_label_new ("Surface Flags"); + gtk_widget_show (label5); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label5); + + table3 = gtk_table_new (5, 4, FALSE); + gtk_widget_show (table3); + gtk_container_add (GTK_CONTAINER (notebook1), table3); + + content_solidbutton = gtk_toggle_button_new_with_label ("Solid"); + gtk_signal_connect (GTK_OBJECT (content_solidbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_solidbutton_toggled), + NULL); + gtk_widget_show (content_solidbutton); + gtk_table_attach (GTK_TABLE (table3), content_solidbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_solidbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_windowbutton = gtk_toggle_button_new_with_label ("Window"); + gtk_signal_connect (GTK_OBJECT (content_windowbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_windowbutton_toggled), + NULL); + gtk_widget_show (content_windowbutton); + gtk_table_attach (GTK_TABLE (table3), content_windowbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_windowbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_auxbutton = gtk_toggle_button_new_with_label ("Aux"); + gtk_signal_connect (GTK_OBJECT (content_auxbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_auxbutton_toggled), + NULL); + gtk_widget_show (content_auxbutton); + gtk_table_attach (GTK_TABLE (table3), content_auxbutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_auxbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_lavabutton = gtk_toggle_button_new_with_label ("Lava"); + gtk_signal_connect (GTK_OBJECT (content_lavabutton), "toggled", + GTK_SIGNAL_FUNC (on_content_lavabutton_toggled), + NULL); + gtk_widget_show (content_lavabutton); + gtk_table_attach (GTK_TABLE (table3), content_lavabutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_lavabutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_slimebutton = gtk_toggle_button_new_with_label ("Slime"); + gtk_signal_connect (GTK_OBJECT (content_slimebutton), "toggled", + GTK_SIGNAL_FUNC (on_content_slimebutton_toggled), + NULL); + gtk_widget_show (content_slimebutton); + gtk_table_attach (GTK_TABLE (table3), content_slimebutton, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_slimebutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_waterbutton = gtk_toggle_button_new_with_label ("Water"); + gtk_signal_connect (GTK_OBJECT (content_waterbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_waterbutton_toggled), + NULL); + gtk_widget_show (content_waterbutton); + gtk_table_attach (GTK_TABLE (table3), content_waterbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_waterbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_mistbutton = gtk_toggle_button_new_with_label ("Mist"); + gtk_signal_connect (GTK_OBJECT (content_mistbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_mistbutton_toggled), + NULL); + gtk_widget_show (content_mistbutton); + gtk_table_attach (GTK_TABLE (table3), content_mistbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_mistbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_areaportalbutton = gtk_toggle_button_new_with_label ("AreaPortal"); + gtk_signal_connect (GTK_OBJECT (content_areaportalbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_areaportalbutton_toggled), + NULL); + gtk_widget_show (content_areaportalbutton); + gtk_table_attach (GTK_TABLE (table3), content_areaportalbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_areaportalbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_playerclipbutton = gtk_toggle_button_new_with_label ("PlayerClip"); + gtk_signal_connect (GTK_OBJECT (content_playerclipbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_playerclipbutton_toggled), + NULL); + gtk_widget_show (content_playerclipbutton); + gtk_table_attach (GTK_TABLE (table3), content_playerclipbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_playerclipbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_monsterclipbutton = gtk_toggle_button_new_with_label ("MonsterClip"); + gtk_signal_connect (GTK_OBJECT (content_monsterclipbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_monsterclipbutton_toggled), + NULL); + gtk_widget_show (content_monsterclipbutton); + gtk_table_attach (GTK_TABLE (table3), content_monsterclipbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_monsterclipbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_current0button = gtk_toggle_button_new_with_label ("Current 0"); + gtk_signal_connect (GTK_OBJECT (content_current0button), "toggled", + GTK_SIGNAL_FUNC (on_content_current0button_toggled), + NULL); + gtk_widget_show (content_current0button); + gtk_table_attach (GTK_TABLE (table3), content_current0button, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current0button), QUAKE2_FLAG_BUTTON_BORDER); + + content_current90button = gtk_toggle_button_new_with_label ("Current 90"); + gtk_signal_connect (GTK_OBJECT (content_current90button), "toggled", + GTK_SIGNAL_FUNC (on_content_current90button_toggled), + NULL); + gtk_widget_show (content_current90button); + gtk_table_attach (GTK_TABLE (table3), content_current90button, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current90button), QUAKE2_FLAG_BUTTON_BORDER); + + content_current180button = gtk_toggle_button_new_with_label ("Current 180"); + gtk_signal_connect (GTK_OBJECT (content_current180button), "toggled", + GTK_SIGNAL_FUNC (on_content_current180button_toggled), + NULL); + gtk_widget_show (content_current180button); + gtk_table_attach (GTK_TABLE (table3), content_current180button, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current180button), QUAKE2_FLAG_BUTTON_BORDER); + + content_current270button = gtk_toggle_button_new_with_label ("Current 270"); + gtk_signal_connect (GTK_OBJECT (content_current270button), "toggled", + GTK_SIGNAL_FUNC (on_content_current270button_toggled), + NULL); + gtk_widget_show (content_current270button); + gtk_table_attach (GTK_TABLE (table3), content_current270button, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current270button), QUAKE2_FLAG_BUTTON_BORDER); + + content_currentUPbutton = gtk_toggle_button_new_with_label ("Current UP"); + gtk_signal_connect (GTK_OBJECT (content_currentUPbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_currentUPbutton_toggled), + NULL); + gtk_widget_show (content_currentUPbutton); + gtk_table_attach (GTK_TABLE (table3), content_currentUPbutton, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_currentUPbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_currentDOWNbutton = gtk_toggle_button_new_with_label ("Current DOWN"); + gtk_signal_connect (GTK_OBJECT (content_currentDOWNbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_currentDOWNbutton_toggled), + NULL); + gtk_widget_show (content_currentDOWNbutton); + gtk_table_attach (GTK_TABLE (table3), content_currentDOWNbutton, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_currentDOWNbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_originbutton = gtk_toggle_button_new_with_label ("Origin"); + gtk_signal_connect (GTK_OBJECT (content_originbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_originbutton_toggled), + NULL); + gtk_widget_show (content_originbutton); + gtk_table_attach (GTK_TABLE (table3), content_originbutton, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_originbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_detailbutton = gtk_toggle_button_new_with_label ("Detail"); + gtk_signal_connect (GTK_OBJECT (content_detailbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_detailbutton_toggled), + NULL); + gtk_widget_show (content_detailbutton); + gtk_table_attach (GTK_TABLE (table3), content_detailbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_detailbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_translucentbutton = gtk_toggle_button_new_with_label ("Translucent"); + gtk_signal_connect (GTK_OBJECT (content_translucentbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_translucentbutton_toggled), + NULL); + gtk_widget_show (content_translucentbutton); + gtk_table_attach (GTK_TABLE (table3), content_translucentbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_translucentbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_ladderbutton = gtk_toggle_button_new_with_label ("Ladder"); + gtk_signal_connect (GTK_OBJECT (content_ladderbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_ladderbutton_toggled), + NULL); + gtk_widget_show (content_ladderbutton); + gtk_table_attach (GTK_TABLE (table3), content_ladderbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_ladderbutton), QUAKE2_FLAG_BUTTON_BORDER); + + label6 = gtk_label_new ("Content Flags"); + gtk_widget_show (label6); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label6); + + return frame1; +} + diff --git a/plugins/surface_quake2/surfaceflagsdialog_quake2.h b/plugins/surface_quake2/surfaceflagsdialog_quake2.h new file mode 100644 index 00000000..04e745f2 --- /dev/null +++ b/plugins/surface_quake2/surfaceflagsdialog_quake2.h @@ -0,0 +1,108 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SURFACEFLAGSDIALOG_QUAKE2_H + #define _SURFACEFLAGSDIALOG_QUAKE2_H + + +#define QUAKE2_SURF_LIGHT 0x1 +#define QUAKE2_SURF_SLICK 0x2 +#define QUAKE2_SURF_SKY 0x4 +#define QUAKE2_SURF_WARP 0x8 +#define QUAKE2_SURF_TRANS33 0x10 +#define QUAKE2_SURF_TRANS66 0x20 +#define QUAKE2_SURF_FLOWING 0x40 +#define QUAKE2_SURF_NODRAW 0x80 +#define QUAKE2_SURF_HINT 0x100 +#define QUAKE2_SURF_SKIP 0x200 + + +#define QUAKE2_CONTENTS_SOLID 0x1 +#define QUAKE2_CONTENTS_WINDOW 0x2 +#define QUAKE2_CONTENTS_AUX 0x4 +#define QUAKE2_CONTENTS_LAVA 0x8 +#define QUAKE2_CONTENTS_SLIME 0x10 +#define QUAKE2_CONTENTS_WATER 0x20 +#define QUAKE2_CONTENTS_MIST 0x40 + +#define QUAKE2_CONTENTS_AREAPORTAL 0x8000 +#define QUAKE2_CONTENTS_PLAYERCLIP 0x10000 +#define QUAKE2_CONTENTS_MONSTERCLIP 0x20000 +#define QUAKE2_CONTENTS_CURRENT_0 0x40000 +#define QUAKE2_CONTENTS_CURRENT_90 0x80000 +#define QUAKE2_CONTENTS_CURRENT_180 0x100000 +#define QUAKE2_CONTENTS_CURRENT_270 0x200000 +#define QUAKE2_CONTENTS_CURRENT_UP 0x400000 +#define QUAKE2_CONTENTS_CURRENT_DOWN 0x800000 +#define QUAKE2_CONTENTS_ORIGIN 0x1000000 + +#define QUAKE2_CONTENTS_DETAIL 0x8000000 +#define QUAKE2_CONTENTS_TRANSLUCENT 0x10000000 +#define QUAKE2_CONTENTS_LADDER 0x20000000 +/* +extern GtkWidget *notebook1; + +extern GtkWidget *surface_lightbutton; +extern GtkWidget *surface_slickbutton; +extern GtkWidget *surface_skybutton; +extern GtkWidget *surface_warpbutton; +extern GtkWidget *surface_trans33button; +extern GtkWidget *surface_trans66button; +extern GtkWidget *surface_flowingbutton; +extern GtkWidget *surface_nodrawbutton; +extern GtkWidget *surface_hintbutton; +extern GtkWidget *surface_skipbutton; + +extern GtkWidget *content_solidbutton; +extern GtkWidget *content_windowbutton; +extern GtkWidget *content_auxbutton; +extern GtkWidget *content_lavabutton; +extern GtkWidget *content_slimebutton; +extern GtkWidget *content_waterbutton; +extern GtkWidget *content_mistbutton; +extern GtkWidget *content_areaportalbutton; +extern GtkWidget *content_playerclipbutton; +extern GtkWidget *content_monsterclipbutton; +extern GtkWidget *content_current0button; +extern GtkWidget *content_current90button; +extern GtkWidget *content_current180button; +extern GtkWidget *content_current270button; +extern GtkWidget *content_currentUPbutton; +extern GtkWidget *content_currentDOWNbutton; +extern GtkWidget *content_originbutton; +extern GtkWidget *content_detailbutton; +extern GtkWidget *content_translucentbutton; +extern GtkWidget *content_ladderbutton; + +extern GtkWidget *surfacebutton; +extern GtkWidget *contentbutton; + +extern GtkWidget *value_entry; +extern gboolean setup_buttons; + +extern int working_surface_flags; +extern int surface_mask; +extern int working_content_flags; +extern int content_mask; +extern int working_value; +*/ + +#endif // _SURFACEFLAGSDIALOG_QUAKE2_H diff --git a/plugins/surface_quake2/surfdlg_plugin.cpp b/plugins/surface_quake2/surfdlg_plugin.cpp new file mode 100644 index 00000000..87034386 --- /dev/null +++ b/plugins/surface_quake2/surfdlg_plugin.cpp @@ -0,0 +1,122 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "surfdlg_plugin.h" +#include "surfacedialog.h" + +#include "synapse.h" + +class CSynapseClient_SurfDLG : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + bool OnActivate(); + + CSynapseClient_SurfDLG() { } + virtual ~CSynapseClient_SurfDLG() { } +}; + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; +_QERUndoTable g_UndoTable; +_QERAppSurfaceTable g_AppSurfaceTable; +_QERSelectedFaceTable g_SelectedFaceTable; +_QERShadersTable g_ShadersTable; +_QERAppShadersTable g_AppShadersTable; +_QERAppDataTable g_AppDataTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClient_SurfDLG g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(SURFACEDIALOG_MAJOR, "quake2", sizeof(_QERPlugSurfaceTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); + g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "quake2", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); + + return &g_SynapseClient; +} + +bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) + { + _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "quake2")) + { + pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; + pSurfDialogTable->m_pfnDoSurface = &DoSurface; + pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; + pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; + pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClient_SurfDLG::GetInfo() +{ + return "Surface Dialog (Quake 2) module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClient_SurfDLG::GetName() +{ + return "surface"; +} + +bool CSynapseClient_SurfDLG::OnActivate() +{ + return true; +} diff --git a/plugins/surface_quake2/surfdlg_plugin.h b/plugins/surface_quake2/surfdlg_plugin.h new file mode 100644 index 00000000..89129d45 --- /dev/null +++ b/plugins/surface_quake2/surfdlg_plugin.h @@ -0,0 +1,94 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _SURFDLG_PLUGIN_H_ +#define _SURFDLG_PLUGIN_H_ + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +#include "qerplugin.h" +#include "synapse.h" +#include "iselectedface.h" +#include "iundo.h" +#include "ishaders.h" +#include "mathlib.h" +#include "missing.h" +#include "idata.h" + +#include "isurfaceplugin.h" + +class SurfaceDialog : public IPluginTexdef +{ + int refCount; +public: + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () { if ( --refCount <= 0 ) delete this; } +}; + +extern _QERFuncTable_1 g_FuncTable; +extern _QERUndoTable g_UndoTable; +extern _QERAppSurfaceTable g_AppSurfaceTable; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERShadersTable g_ShadersTable; +extern _QERAppShadersTable g_AppShadersTable; +extern _QERAppDataTable g_AppDataTable; + +#define GetSelectedFaceCount g_SelectedFaceTable.m_pfnGetSelectedFaceCount + +#define Undo_Undo g_UndoTable.m_pfnUndo_Undo +#define Undo_GetUndoId g_UndoTable.m_pfnUndo_GetUndoId + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf +#define Sys_UpdateWindows g_FuncTable.m_pfnSysUpdateWindows + + +#define Select_FitTexture g_AppSurfaceTable.m_pfnSelect_FitTexture +#define Get_SI_Inc g_AppSurfaceTable.m_pfnQERApp_QeglobalsSavedinfo_SIInc +#define GridSize g_AppSurfaceTable.m_pfnQeglobalsGetGridSize +#define FaceList_FitTexture g_AppSurfaceTable.m_pfnFaceList_FitTexture +#define GetMainWindow g_AppSurfaceTable.m_pfnGetMainWindow +#define GetSelectedFaceCountfromBrushes g_AppSurfaceTable.m_pfnGetSelectedFaceCountfromBrushes +#define GetSelFacesTexdef g_AppSurfaceTable.m_pfnGetSelFacesTexdef +#define SetTexdef_FaceList g_AppSurfaceTable.m_pfnSetTexdef_FaceList +#define SetWinPos_from_Prefs g_AppSurfaceTable.m_pfnSetWinPos_From_Prefs + +#define Texturewin g_AppShadersTable.m_pfnQeglobalsTexturewin + +#endif // _SURFDLG_PLUGIN_H_ + diff --git a/plugins/textool/.cvsignore b/plugins/textool/.cvsignore new file mode 100644 index 00000000..5d257e72 --- /dev/null +++ b/plugins/textool/.cvsignore @@ -0,0 +1,13 @@ +*.d +*.o +*.so +Debug +Release +TexTool___Win32_Q3Debug +TexTool___Win32_Q3Release +*.aps +*.plg +*.bak +*.BAK +*.opt +*.ncb \ No newline at end of file diff --git a/plugins/textool/.cvswrappers b/plugins/textool/.cvswrappers new file mode 100644 index 00000000..21e5b0a3 --- /dev/null +++ b/plugins/textool/.cvswrappers @@ -0,0 +1,2 @@ +*.dsp -m 'COPY' -k 'b' +*.rc -m 'COPY' -k 'b' diff --git a/plugins/textool/2DView.cpp b/plugins/textool/2DView.cpp new file mode 100644 index 00000000..aab484e1 --- /dev/null +++ b/plugins/textool/2DView.cpp @@ -0,0 +1,202 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// a class to provide basic services for 2D view of a world +// window <-> local 2D space transforms +// snap to grid +// TODO: this one can be placed under an interface, and provided to the editor as a service + +#include "StdAfx.h" + +static void view_ZoomIn (GtkWidget* widget, gpointer data) +{ + ((C2DView*)data)->ZoomIn (); +} + +static void view_ZoomOut (GtkWidget* widget, gpointer data) +{ + ((C2DView*)data)->ZoomOut (); +} + +void C2DView::PreparePaint() +{ + g_QglTable.m_pfn_qglClearColor( 0, 0, 0, 0 ); + g_QglTable.m_pfn_qglViewport( 0, 0, m_rect.right, m_rect.bottom ); + g_QglTable.m_pfn_qglMatrixMode( GL_PROJECTION ); + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglOrtho( m_Mins[0], m_Maxs[0], m_Maxs[1], m_Mins[1], -1, 1 ); +} + +void C2DView::SpaceForWindow( float c[2], int x, int y) +{ + c[0] = ((float)(x))/((float)(m_rect.right-m_rect.left))*(m_Maxs[0]-m_Mins[0])+m_Mins[0]; + c[1] = ((float)(y))/((float)(m_rect.bottom-m_rect.top))*(m_Maxs[1]-m_Mins[1])+m_Mins[1]; +} + +void C2DView::GridForWindow( float c[2], int x, int y) +{ + SpaceForWindow( c, x, y ); + if ( !m_bDoGrid ) + return; + c[0] /= m_GridStep[0]; + c[1] /= m_GridStep[1]; + c[0] = (float)floor( c[0] + 0.5f ); + c[1] = (float)floor( c[1] + 0.5f ); + c[0] *= m_GridStep[0]; + c[1] *= m_GridStep[1]; +} + +void C2DView::WindowForSpace( int &x, int &y, const float c[2] ) +{ + x = m_rect.left + (int)( ((float)(m_rect.right-m_rect.left))*(c[0]-m_Mins[0])/(m_Maxs[0]-m_Mins[0]) ); + y = m_rect.top + (int)( ((float)(m_rect.bottom-m_rect.top))*(c[1]-m_Mins[1])/(m_Maxs[1]-m_Mins[1]) ); +} + +qboolean C2DView::DoesSelect( int x, int y, float c[2] ) +{ + int xc,yc; + WindowForSpace( xc, yc, c ); + if ( abs(xc-x)<=3 && abs(yc-y)<=3 ) + return true; + return false; +} + +void C2DView::ZoomIn() +{ + m_Mins[0] = 0.5f * ( m_Mins[0] - m_Center[0] ) + m_Center[0]; + m_Mins[1] = 0.5f * ( m_Mins[1] - m_Center[1] ) + m_Center[1]; + m_Maxs[0] = 0.5f * ( m_Maxs[0] - m_Center[0] ) + m_Center[0]; + m_Maxs[1] = 0.5f * ( m_Maxs[1] - m_Center[1] ) + m_Center[1]; + g_pToolWnd->Redraw (); +} + +void C2DView::ZoomOut() +{ + m_Mins[0] = 2.0f * ( m_Mins[0] - m_Center[0] ) + m_Center[0]; + m_Mins[1] = 2.0f * ( m_Mins[1] - m_Center[1] ) + m_Center[1]; + m_Maxs[0] = 2.0f * ( m_Maxs[0] - m_Center[0] ) + m_Center[0]; + m_Maxs[1] = 2.0f * ( m_Maxs[1] - m_Center[1] ) + m_Center[1]; + g_pToolWnd->Redraw (); +} + +bool C2DView::OnRButtonDown (int x, int y) +{ + if (ViewState == View_Idle) + { + m_xPosMove = x; // horizontal position of cursor + m_yPosMove = y; // vertical position of cursor + // store + m_MinsMove[0] = m_Mins[0]; m_MinsMove[1] = m_Mins[1]; + m_MaxsMove[0] = m_Maxs[0]; m_MaxsMove[1] = m_Maxs[1]; + ViewState = View_Move; + // set popup to true + m_bPopup = true; + return true; + } + return false; +} + +bool C2DView::OnRButtonUp (int x, int y) +{ + if (ViewState == View_Move) + { + // maybe it's time for popup menu + if (m_bPopup) + { + GtkWidget *menu, *item; + + menu = gtk_menu_new (); + + item = gtk_menu_item_new_with_label ("Validate (RETURN)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Textool_Validate), NULL); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Zoom in (INSERT)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (view_ZoomIn), this); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Zoom out (DELETE)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (view_ZoomOut), this); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Cancel (ESC)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Textool_Cancel), NULL); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); + } + + // back to Idle mode + ViewState = View_Idle; + return true; + } + return false; +} + +bool C2DView::OnMouseMove (int xPos, int yPos) +{ + if (ViewState == View_Move) + { + float V[2]; + // V is the offset + V[0] = ((float)( xPos - m_xPosMove )) * ( m_MaxsMove[0] - m_MinsMove[0] ) / ((float)( m_rect.left - m_rect.right )); + V[1] = ((float)( yPos - m_yPosMove )) * ( m_MaxsMove[1] - m_MinsMove[1] ) / ((float)( m_rect.top - m_rect.bottom )); + // update m_Mins m_Maxs and m_Center + m_Mins[0] = m_MinsMove[0] + V[0]; + m_Mins[1] = m_MinsMove[1] + V[1]; + m_Maxs[0] = m_MaxsMove[0] + V[0]; + m_Maxs[1] = m_MaxsMove[1] + V[1]; + m_Center[0] = 0.5f * ( m_Mins[0] + m_Maxs[0] ); + m_Center[1] = 0.5f * ( m_Mins[1] + m_Maxs[1] ); + // no popup menu if we moved + m_bPopup = false; + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool C2DView::OnKeyDown (char *s) +{ + if (ViewState == View_Idle) + { + if (!strcmp(s,"Insert")) + { + ZoomOut(); + return true; + } + if (!strcmp(s,"Delete")) + { + ZoomIn(); + return true; + } + } + return false; +} + diff --git a/plugins/textool/2DView.h b/plugins/textool/2DView.h new file mode 100644 index 00000000..4f8eac97 --- /dev/null +++ b/plugins/textool/2DView.h @@ -0,0 +1,70 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// a class to provide basic services for 2D view of a world +// window <-> local 2D space transforms +// snap to grid +// TODO: this one could be placed under an interface, and provided to the editor as a service + +#ifndef _2DVIEW_H_ +#define _2DVIEW_H_ + +class C2DView +{ + enum E2DViewState { View_Idle, View_Move } ViewState; + int m_xPosMove, m_yPosMove; + float m_MinsMove[2], m_MaxsMove[2]; + qboolean m_bDoGrid; + float m_GridStep[2]; + qboolean m_bPopup; +public: + RECT m_rect; + float m_Mins[2],m_Maxs[2],m_Center[2]; + C2DView() + { + ViewState = View_Idle; + m_bDoGrid = false; + m_bPopup = false; + } + ~C2DView() { } + void SetGrid( float xGridStep, float yGridStep ) + { m_bDoGrid = true; m_GridStep[0] = xGridStep; m_GridStep[1] = yGridStep; } + + // get window coordinates for space coordinates + void WindowForSpace( int &x, int &y, const float c[2]); + void SpaceForWindow( float c[2], int x, int y); + void GridForWindow( float c[2], int x, int y); + qboolean DoesSelect( int x, int y, float c[2] ); + void PreparePaint(); + + bool OnRButtonDown (int x, int y); + bool OnMouseMove (int x, int y); + bool OnRButtonUp (int x, int y); + bool OnKeyDown (char *s); + + void ZoomIn(); + void ZoomOut(); +}; + +#endif diff --git a/plugins/textool/ControlPointsManager.cpp b/plugins/textool/ControlPointsManager.cpp new file mode 100644 index 00000000..e91a6940 --- /dev/null +++ b/plugins/textool/ControlPointsManager.cpp @@ -0,0 +1,332 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// a class to handle control points in a 2D view +// TODO: this one can be placed under an interface, and provided to the editor as service +// + +#include "StdAfx.h" + +void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2], + _QERFaceData* pFaceData, _QERQglTable *pQglTable) +{ + ManagerState = Idle; + m_NumPoints = iPts; + m_pPts = Pts; + // store the initial config + memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) ); + // init TM + memset( m_TM, 0, sizeof( float[2][3] ) ); + m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f; + m_bGotAnchor = false; + m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f; + m_TexSize[0] = TexSize[0]; + m_TexSize[1] = TexSize[1]; + m_pFaceData = pFaceData; + + CControlPointsManager::Init( p2DView, pQglTable ); +} + +bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos) +{ + if (ManagerState == Idle) + { + int i; + + // scan the point list to see if we selected something + for ( i=0; iDoesSelect( xPos, yPos, m_pPts->data[i] ) ) + { + m_iDragPoint = i; + ManagerState = Drag; + if (m_bGotAnchor && i == m_iAnchorPoint) + { + // this means we selected the Anchor, so we'll translate + m_bGotAnchor = false; + } + // perhaps we won't use translation, but we can compute it anyway + ComputeTransOffset(i); + if (m_bGotAnchor) + { + // we have an Anchor and selected another point + m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0]; + m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1]; + } + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos) +{ + if (ManagerState == Drag) + { + if (m_bGotAnchor) + { + // there's an anchor, we are rotating the shape + // we need to work in XY space for orthonormality + float Pt[2]; + vec3_t V1,V2; + vec3_t cross; + float c,s; + // used in XY space + float XYTM[2][3]; + float XYRefAnchor[2]; + float XYAnchor[2]; + m_p2DView->GridForWindow( Pt, xPos, yPos ); + V2[0] = Pt[0] - m_Anchor[0]; + V2[1] = Pt[1] - m_Anchor[1]; + V2[2] = 0.0f; + V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0]; + V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1]; + V1[2] = 0.0f; + // compute transformation from V1 to V2 + // we need to work in XY orthonormal space + XYSpaceForSTSpace( V1, V1 ); + XYSpaceForSTSpace( V2, V2 ); + VectorNormalize( V2, V2 ); + VectorNormalize( V1, V1 ); + c = DotProduct( V1, V2 ); + CrossProduct( V1, V2, cross ); + s = VectorLength( cross ); + // we compute the transformation matrix in XY space + // reference position of the Anchor in XY space + XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] ); + // current position of the Anchor in XY space + XYSpaceForSTSpace( XYAnchor, m_Anchor ); + // compute transformation matrix + XYTM[0][0] = c; XYTM[1][1] = c; + if (cross[2]>0) + s *= -1.0f; + XYTM[0][1] = s; XYTM[1][0] = -s; + XYTM[0][2] = -c*XYRefAnchor[0] - s*XYRefAnchor[1] + XYAnchor[0]; + XYTM[1][2] = s*XYRefAnchor[0] - c*XYRefAnchor[1] + XYAnchor[1]; + // express this transformation matrix in ST space + m_TM[0][0] = XYTM[0][0]; + m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1]; + m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0]; + m_TM[1][1] = XYTM[1][1]; + m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0]; + m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1]; + // update all points + UpdateCtrlPts(); + } + else + { + // no Anchor point is defined, we translate all points + m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos ); + m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0]; + m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1]; + // update all points + UpdateCtrlPts(); + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + + return false; +} + +bool CControlPointsManagerBFace::OnLButtonUp (int x, int y) +{ + if (ManagerState == Drag) + { + // this button is gonna become our Anchor + m_bGotAnchor = true; + m_iAnchorPoint = m_iDragPoint; + // let's get out of Drag mode + ManagerState = Idle; + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +void CControlPointsManagerBFace::Render() +{ + int i; + + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + m_pQglTable->m_pfn_qglPointSize(6); + m_pQglTable->m_pfn_qglBegin( GL_POINTS ); + for ( i=0; im_pfn_qglColor3f(1, 0, 0); + else if ( m_bGotAnchor && i == m_iAnchorPoint ) + m_pQglTable->m_pfn_qglColor3f(0, 0, 1); + m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] ); + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + } + m_pQglTable->m_pfn_qglEnd(); +} + +void CControlPointsManagerBFace::UpdateCtrlPts() +{ + int i; + + // update all points + for ( i=0; idata[i][0] = m_RefPts.data[i][0]*m_TM[0][0]+m_RefPts.data[i][1]*m_TM[0][1]+m_TM[0][2]; + m_pPts->data[i][1] = m_RefPts.data[i][0]*m_TM[1][0]+m_RefPts.data[i][1]*m_TM[1][1]+m_TM[1][2]; + } + + if (g_bPrefsUpdateCameraView) + { + Commit(); + // tell Radiant to update + // NOTE: little speed optimisation, disable window updates, and only update camera view + g_FuncTable.m_pfnSetScreenUpdate( false ); + g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData ); + g_FuncTable.m_pfnSetScreenUpdate( true ); + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } +} + +//++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead +void CControlPointsManagerBFace::Commit( ) +{ + brushprimit_texdef_t aux; + aux.coords[0][0] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0]; + aux.coords[0][1] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1]; + aux.coords[0][2] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[0][2]; + aux.coords[1][0] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0]; + aux.coords[1][1] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1]; + aux.coords[1][2] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[1][2]; + memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t) ); +} + +void CControlPointsManagerBFace::ComputeTransOffset(int i) +{ + // compute the translation offset used to counteract rotation + m_TransOffset[0] = -m_TM[0][0]*m_RefPts.data[i][0] - m_TM[0][1]*m_RefPts.data[i][1]; + m_TransOffset[1] = -m_TM[1][0]*m_RefPts.data[i][0] - m_TM[1][1]*m_RefPts.data[i][1]; +} + +void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] ) +{ + xy[0] = st[0] * (float)m_TexSize[0]; + xy[1] = st[1] * (float)m_TexSize[1]; +} + +/* +====================================================================== +patch manager +====================================================================== +*/ + +void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch ) +{ + CControlPointsManager::Init( p2DView, pQglTable ); + m_pPatch = pPatch; + m_pWorkPatch = pWorkPatch; +} + +bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos) +{ + if (ManagerState == Idle) + { + int i,j; + + // scan the point list to see if we selected something + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) ) + { + m_iDragPoint[0] = i; + m_iDragPoint[1] = j; + ManagerState = Drag; + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos) +{ + if (ManagerState == Drag) + { + m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos ); + if (g_bPrefsUpdateCameraView) + { + Commit(); + // ask to rebuild the patch display data + m_pPatch->bDirty = true; + // send a repaint to the camera window as well + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool CControlPointsManagerPatch::OnLButtonUp (int x, int y) +{ + if (ManagerState == Drag) + { + ManagerState = Idle; + // send a repaint message + g_pToolWnd->Redraw (); + } + return false; +} + +void CControlPointsManagerPatch::Render() +{ + int i,j; + + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + m_pQglTable->m_pfn_qglPointSize(6); + m_pQglTable->m_pfn_qglBegin( GL_POINTS ); + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + { + if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] ) + m_pQglTable->m_pfn_qglColor3f(1, 0, 0); + m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] ); + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + } + m_pQglTable->m_pfn_qglEnd(); +} + +void CControlPointsManagerPatch::Commit() +{ + int i,j; + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + { + m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0]; + m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1]; + } +} diff --git a/plugins/textool/ControlPointsManager.h b/plugins/textool/ControlPointsManager.h new file mode 100644 index 00000000..00502c37 --- /dev/null +++ b/plugins/textool/ControlPointsManager.h @@ -0,0 +1,133 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// a class to handle control points in a 2D view +// TODO: this one can be placed under an interface, and provided to the editor as service +// +// NOTE: the C2DView *m_p2DView is the orthogonal mapping between window and ST space +// in Drag mode (for rotation) we need an orthonormal XY space +// we do ST <-> XY transformations using the texture size +// ( for translation-only moves, orthogonal is enough ) +// FIXME: is there a better way to deal between Window space <-> ST space <-> XY space ? +// +// NOTE: ControlPointsManagers are a bit different between brush faces and patches +// so there's a base virtual class, and we have two versions + +#ifndef _CONTROLPOINTSMANAGER_H_ +#define _CONTROLPOINTSMANAGER_H_ + +class CControlPointsManager +{ +protected: + // used by Render + _QERQglTable *m_pQglTable; + C2DView *m_p2DView; +public: + CControlPointsManager() { m_pQglTable = NULL; m_p2DView = NULL; } + virtual ~CControlPointsManager() { } + void Init( C2DView *p2DView, _QERQglTable *pQglTable ) { m_pQglTable = pQglTable; m_p2DView = p2DView; } + + virtual bool OnLButtonDown (int x, int y) = 0; + virtual bool OnMouseMove (int x, int y) = 0; + virtual bool OnLButtonUp (int x, int y) = 0; + + virtual void Render() = 0; + virtual void Commit() = 0; +}; + +// brush face manager +class CControlPointsManagerBFace : public CControlPointsManager +{ + enum EManagerState { Idle, Drag } ManagerState; + int m_NumPoints; + // initial geometry + CtrlPts_t m_RefPts; + // current geometry + CtrlPts_t *m_pPts; + // transform matrix ( 2DView is Window <-> ST ) + float m_TM[2][3]; + // texture size for ST <-> XY + int m_TexSize[2]; + // used when translating + float m_TransOffset[2]; + // dragged point index + int m_iDragPoint; + // do we have an anchor ? + bool m_bGotAnchor; + // anchor point index + int m_iAnchorPoint; + // coordinates of Anchor + float m_Anchor[2]; + // used for commit + _QERFaceData *m_pFaceData; + +public: + // construction / init ------------------------------------------------- + CControlPointsManagerBFace() { ManagerState = Idle; } + virtual ~CControlPointsManagerBFace() { } + // NOTE: pQglTable is sent to CControlPointsManager::Init + void Init(int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2], _QERFaceData* pFaceData, _QERQglTable *pQglTable); + // CControlPointsManager interface ------------------------------------- + + virtual bool OnLButtonDown (int x, int y); + virtual bool OnMouseMove (int x, int y); + virtual bool OnLButtonUp (int x, int y); + + virtual void Render(); + virtual void Commit(); + +private: + // internal members + void UpdateCtrlPts(); + void ComputeTransOffset(int i); + void XYSpaceForSTSpace( float xy[2], const float st[2] ); +}; + +// patch manager +class CControlPointsManagerPatch : public CControlPointsManager +{ + enum EManagerState { Idle, Drag } ManagerState; + // reference data, used for commits + patchMesh_t* m_pPatch; + // work patch, holds current data + patchMesh_t* m_pWorkPatch; + int m_iDragPoint[2]; + +public: + // construction / init ------------------------------------------------- + CControlPointsManagerPatch() { ManagerState = Idle; } + virtual ~CControlPointsManagerPatch() { } + // NOTE: pQglTable is sent to CControlPointsManager::Init + void Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch ); + // CControlPointsManager interface ------------------------------------- + + virtual bool OnLButtonDown (int x, int y); + virtual bool OnMouseMove (int x, int y); + virtual bool OnLButtonUp (int x, int y); + + virtual void Render(); + virtual void Commit(); +}; + +#endif diff --git a/plugins/textool/Doc/.cvswrappers b/plugins/textool/Doc/.cvswrappers new file mode 100644 index 00000000..89bb1f8b --- /dev/null +++ b/plugins/textool/Doc/.cvswrappers @@ -0,0 +1 @@ +*.jpg -m 'COPY' -k 'b' diff --git a/plugins/textool/Doc/Image2.jpg b/plugins/textool/Doc/Image2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e443d1e15b2556f2905680cc5b030b5a068023f GIT binary patch literal 50020 zcmd42WmH^C&^9_Sz+l1M-66QUySoO5U>RJ41qlr99^4_g1Of#2;O_43b~)$X_1^be z>-@R@?w&t;ukKy-^i$PUUA?E@=HJ!(f}wZD8Q%pAK+~XAOV1bfrW#GfrEpE z1A*Y+5z!D45fBiuP*9Q4aIx_4aItW32#Bdk2?!~PaB#?&$S7%O=^5zpNts!h=~$`h z=;{6u0tEtr5aAIq5fL%z2yh7K{y$%Dod9%rC-wG;Mm2%fpImIR2*jKoLw6iZ;Jrr_s-DhKy-izpy@j2UVHd%`wh^>fG~5* z!#tzEU0hr|Q|aV-U#XVQy-iuZjDt)ar_9FS4w_q$7pYfHoL{3o%s}$0*-qzEt#{b( zWMz;QyoA3CR&%Lv-NI05U{*{Rq&ZxACIHZrWSKj7*@4ZE7Y)43oO?IJRHVD44WVi7 zBmAbgT@Ds=YJV{fJPVZD6ozUJ2pG981S3bIlHHcV}guvsk&CW$MRVF*$HZi6)2j>!dPH zx7<)#g0gd^Yp4z&?V|Wt;AY&Ex3bU}S5oRpB_$ibh#i-`sGBPLReM1NL+T6L&O9jf zA=oMF(dotZvq@iNM_0weTG1O|Ho5Tm^FJd>T7CocWoNws)ZcHMV3q50uDruuushC} zHTAihCKlc6TMJ%X7o&!j+G~AlH!-mB4j;d1IYkho-8zYt2KM6Lv zNVTW@UT*yfBqIR`di03_IA*;q9)Cw&8W<3>Uusaqasd#f`C#YRn%9CvhhjMrV!5*( zeWV(vD(crckL>U(*5g;{DvN9>qlgoKB5Nt&(0z+<8S~Js)i=(s5?^(Sb21Hjeo zea(0S=B9M7q(Q8$mxt!)_Wz2;~(uhAmpV;oRf$O!$$?1+L1OH&Xs}7|% zKqa%n{Y=w6Cluqp|GiB48{p{ONE_>U#M~SwJ{nsh+l;15LZ>t&TW9_KyxrDzQjd0} zj~rs57aHa3?a8O>%fnpL7b({B-|rFg@x%_!^0`U=wh|1hWxsG4;V2yB8hB*OeRukx zfEJ7lz>j-EaT)u<3T5KjUyFZp=0GgZAGA`*?>%|G0*x9*{5M_v(|1C?E)Y!7*HYEa zpIj5kJqkqVOQOk-7Kj+Ls4(=DHmXbDZ9-WsQQ>m0z~vHC(Bd0Fp4-EYpM1@uw zcbY8Y@GTV#>G+R9C<|EZnP^_1V9}4eZOzeKfhS25l4|!8FGRL|;vpnzJ0@j9Y^o?l zM=UvW4IJ*P6Gb%;iURjWm(Ch#!1W3t+u$Hojo?!NK;?hWI|p}!%I87i-e-@-nzl4V{BAN@An&lZ#TCS* zQS7YjdN`l)Np)IJ_fxRTXED;w>5Tl=tskv2#mt;Wq?!}SlPlm>xrJiGk~I<(6;ot-@px5&B%4g$c`X!oC=A_J29_on=ei>Zh>DRfsSyZMOD-tHM!O= z`-mX4<^=ljPJPO;GW~RHnf%-dS#CptveBYBhz#LD7qJWln{WgUSoGf%A3m8LsBZMt zdxu#s%z64toD6dliBct8&pvf`%d6Y?m z30;QqBpx@0oC=mOg@~1M6@H*3Z14LdX`>L&y{TG8rBCr`6?L}%XYT|BN*ps5X3@cW z_%Fg;vIs%*t^S!ao zffN^gWP|$rl$TVe92^qssr!SS^*UDz@zBaxL1gjLVu(<2vrV>eIn%_j);8J14edRD zd(vn>GiUxl&Q<|<{GXx!*1JhoqI~`{?$^Jx(v;Gc)^kyD&)b<5V z(<3D&wxaix5|j6x%Kbn5+QL^kTV%UZa!p}^BoTl_na zMPD6)5623&HcgF}@QU%05==HI_~T}9Y=H`-b}w`bD;4`;d}CIQE}5^mrx_PHex|n_ zlTlfVW8p5DyHKfQ#4y5a6$mhtWjwv98|>Z9++omia7XasI5PB7(`q8K3%;hl>H}@1L?67Ye~K_7Y>)q zz4H#&HOSN9m-+7-Wql1I?KtT#Pz5uoCc3lNqju{1!z4L1Gn7I7s*dSFboWLH@o*kO- z+@o6EFTDvAm&}pnJ-+9UD?D4mk9H0xB6*cnXQ#Q-*VNgMQt>;_)-=+($<*T+6IjS7 z0*?uq84fED%IVhj?8@0i5jEY<`USL#P4SEdc2zOc#hUSkphPV6cs)dxsaTF!cCoxB z{heynC(#MV`T;IBC%eKmsyZXvChoFIszytIt+}Wi;xce)Evo|gKUp|h8xJmY$;ozA zyc>tCk*@q}s@VoGHbWn4#w5eARKwZuOj9*?PrR6N#Ty{m|90)9*t_YO(dX&v4Y0}u zH|v*oU3k)dK`c>(Z>WI#ScD7l5Y}ta40#-A(?U z#G_`cQI^oN{2j&Dc2l-xhquWd#`+y3_z2r?bCmY$l)IA(!}y|>f(pSu6)^8-Q4Qp*2-1dRVrmjG(5B<%lJ z0HetN^!fj*5`dpa^$nJv*u-G9>zdwZbyw~%*2MfL%CS*E@+Nm}l2Io^Z$3-FCVKc? zN@>&BiVk<-Wb34>ljRrR0sKe2jcrA?|3CbucijV`{ept!E{tAN|q~TUQE`#?lWy z&*4-GCSQ35NKh7(nZ-+5^5G5c5!XPb&334@*R) z9N%#}8yYV!i{diu`m>jxb~-eJ1nbz?pJGO-vX?4bd%Y=59%`A94?-!KQ=&HSM;?GX zgzoFn9@fH1BS$CJl`+o^FF2?Jl^sIS4KL}hk)Umznocl@&C@f!#{|Fr)|DJ>8~wz*(&Y{C!Cxx)lF{S{; zxVy*o$1HqYk~pgTRM?)?yWF=V7Xe@Os>711|B!5%d~_{9w1vj=?NBEkI|YU0&*Vop zeAg)K8)hC=h5OB@(_{(Ep9z1+11%OSJV*}9P^kdCRdggXt>ZxcfmcSwCEdDi45!~K>{`z;v5crx2SJ$9(jfuOk14L6Q73{7pD^;;DTCAb;}IR#VEaO8 zm`D}QQ61ytQzSn-(KP)PNYL%XbQk*xogk!Z%URAL+fA)Mys!DMkLJ|L#Ncv^Ufq)w5eFtt$|q%^Uz?4S^Dg-KC?DS8Qw%=9O{O$yLghJ1vZh?h;2>Lt$U%$b zg%p+c9(7zkt&^HC5~uJgn&+#>j$4yQPLVhRRNEDkr;q>0e*^d*^5RgAw7&v-yYmH% zH!t<58!e~Kz*r$;T0Zus{TZ8#EFY=k4XliW@6crpcXS&2h`fGNG?(}&9iA;X?f-q1 za(LKv^Eht0w(+M(0rq&Mbab{^@N?9k{>N+iFTSmfrNsv|`?DSw!zB4YLo8Fm=d=uq z4LokGHd)nYl=T& z7hB0{t2jRb!2#n^D_gcugbtG~E_JAL7w1vh-XeqykS7QBVv1j4Ke%g-5Z_~HZ)DvX zy}<6HTvXBiI`jsRj=W?vJ)tb;eFHH3`$T`vB$MXzjMO)^KQ_|bmMrIx=K8cOMedSh zyo3kdy^k3FFK)R^Y+khecTDy#zDn5(<-6&S{@?dRNa(vU?{v5cLyjZ=INAKU$hz>>N8oE$f1oC$9`l~$e! z6YFmK8=pRPFA;wg4z}$@f!rk`{UnhBV{f zsLG|~&-vPuj}UP;?AFEvjcoh^o5dOQ&hs5hl_EV-vk*}t2Y{Ch52}ry+7tZ?$;ZKW z&t@qWxy*S7K@{M)iMrPVIkrW^9KbN%2d|6!CaN@}~%j>^9AO$ymkhzW}$0xji#kqXR97S*q-7uovf4V2;GUW>WtCBtc zQ>nj2M{4Ay&AMj{`#Ud~|4IY@mo%(HKN0mA{;Q%J0R@96I|D*uaePNrnN7(ncu7m_ zCTQOZFIeBUJzl}RhxS90g^#-w&*|50XX>wm{%pA06P*{tIvt&0ek0PR!3loLs`_>k z`v$i|!i<6HYHHi9Wa`%DfN{1ctu8I`3HFaER-L{@>_18rDoM*V#M_m~8w51G+&+J* zZ_QR{vCq9gG~_T8+*w$}8Pr{Y#-`wAzK)WMZaY+2Al;>WPG7q6nD(y~8IgJSC+e@| zYwL#UF)}BYCc@(<{5c9U4W?DPhd^bYa7TMH{_;ac_;Y5B|TRA2ZHs5-p4kJ`yZ@JIE_xfs1=yd zWO-cr=sIGEYq_MH->y5p3|5&FyG)z>i;|6x`du4Hvo?J-Up*k*{w)n0i>|_=nS`?ty9|DP-QO!qyRs3PM z5)Y|w0GcLZhiQ>o(vkju=i2*R;Ml_Q7IBI{vlFfmLb&oZ;Z>=mDHaUfyj_>PT5MPj zvrQ&bw4Xhx$5N}Kv@yzu;#{GuP*EFOY>2K#32`!$s^Iqi+189QqF7VdGfecOSrgx# znuj=^mXKk5v|9D+fIkQ6_AE-nA@UpG&p&FpRFCZ?jizFR+h$s^QI_+SR%q)CTgu%& zp2pVB)E|8>ZjID3K(N$vxIRi-JvA_7is-GPP8zNYg(MnMIFNf_7;SrJP8oMnMh_jp zqc|V3jX3`JqEe2y3pJbm@V=||2KYzG&m$rKn>WA}+pCfcO!bVME>-{c=U=JG4J*5=m!wE^+J{^=c-^g6s9??zj9THLn3z~tcC zV!YoUNE#kYD|`tSb49hvGPSiP@*topTX(sh$T|FM&);qI;`cn_zhZz=H3$D9^gQ`h zNf`8RbR+%If%K9xP^`AkpQ3`Kl3h8PGql6ni9Z8@VATMCnSkQ#mG;e0i9f9vntOuY z1b(v~E+z*?_+Zahs&OCT-A?=-^}x=pzZ%qwME9BCu4;x#9%c35727A0UV^d;N;UhL zH-O9EjM&n5bo3u8sDyqB?2$#xk96tMkFAy2^~Rcx2*a^T1^zr8gfvV)YIVhv z5%%DHTFC2_-Q)&E%e1DOke&bRzL>OAEB&hHWzT zpk;4O^!ImO@}dM*^6tmP6v9TLxcd_6%J*n8JA)WVkxWH$KR`OoxWe6w{k~imye#mg zn+cCsOp6jD3L%P-pMwec5Y-H#%A7r3+7hmi0r6JC1X8F9_OIxpaW;nsX+rjY7pv50!_r$JlC?^#7Xf32|UqA19PCyc?>7(yux_NR5PN9zV4MB`wP|yK4zmGYml!HD$dGmFibsMT+z*(Xo?Z zl|kl~%Y?+rbk1JyB+DBi8yAmjRUYooXs;4B82ItXApDBEGHSYal^$XQnQk8Nb0Ay4 zerS4*cr+GL85j`=eMsc8H00q)w)I}OZRHnl?;lOxBYjF7bb~LjLOWO#AUocZZ`^ul zHT2GSMivNdN&0lk=vJ<{Quc#VW#T=nm7R2S7g$WkSzONVKk2*yhALZL9aBh(x6RH^ zt{AnB87B_34bw-PRcNyEA*l1i{sYAX+Ql$)s{Jf!`K*p_fbAvl8z892-^NzV>dV*e zXbg4t7M;?Q@uv%e>ZdmVwOh5a>zd-K6n^u;3HcyU7pdzhfLS zq9;(P$^MnISmneBF^QPBYweoGFGHPeY>}bxm=UZElOD{-vP4YTLAg8ZG*Fn|Zas`d zObd81$zZ;Jb!^RXn!4o3=^DIZEL-tkdwE}%JXKh9$izYwACQr%WH`J5C^CHud0&8q zz?}Id|AE5((g(aYq8#=*?4RYro4R>5Ryf|OIbRlq9hy$w0A`s@L7d?`4=9PWWLH=A zq;cXWi(jQxg5r0z7?)mNv0LAlAMa#z-02Y*ZcMcKFw=+AlK$V!WghWp&o;)Tx}MNm zkhxs>g5ChIMD96pk)7}0&<#F+vN%)dByETTl45O?xj~L z;de*qUALSLqy2|&M*+m7!SYs0OuNEU7^qjJf6+BW8l#spCAS)|9)ERgBE6^Entq0; z)a^`1#>g*xmgNs@lZX^zD#7m`ec#xM(*}t>uaxx=JjqXPgPQi~!fxoQ>}3`|bK=;F zJrQUerza67#;G9A>*yV<5KrNvV|e>3GQTf!O->7)_&EyKzy18n*$M97cY8eyxy=iX zb^|&6b*d>VwjbCIG^jLu{Yx?B8cFNGBRfTzLWcSmOnRiDHKO0%8IBXCMD-r_-8!~4 zx?c+O!*w8}M`n!fQu4}UvOwdB{f3NW)epbZQ9MO>3|^&p`6~u@?2I^@I(F|xC|W&F zL@3!d60XpDPZ`1Lo^JHSV%(1&Z-Axs=LoQ!_arMbTqdSqPR9GAuXj$|_gl^9f$+J! zB7KL246S57=Ih-iz`G@ByB@G+PhV}$k|@Gd&g%vqexvx`(QVZ~L$a|&*eT5#OWPZk zeTW7vi@9+{3UW#BZLrcWnf(FAybPr*CBFB@6k&&szNwwszj;d2Ox>Ki zeH0lzce%4KG%#pY6^>N7{}&4HjtC{~H>Fo9RN@eOdiO(t#MrF#ubtqSe{e2-ElB}& zhpFJb0nX9BN)b8dB!$71?utVvVrhuYWgn?VPQFX+j!W7`cZU! zKYJtw-5~Ci-WG+>m&l{M0dniVj?HGe&{sQutCsOTI2-X$zIv7V*?-3PGD9+V?SME+ z)K#cUueR2y@nRN{^SMMl`rX)=q;*L}$3^W!*mkCiS)UhAChah#oIZS0B`5nh@QLqf z$SS=_)dT_8-ksV{W`OKDVn57jsuY_VRQl}~T%P+_jGd{xRFw&OM|Tb5DK{(XGgg8A z&D3u}0rc$dZPr&Q9irlGi*tr-S1QH{<-Tf{SZ+OwH^4ofKSg5OjH6j2q>ri1Y&j;j zd+D{8g-2y*&@WhHEL6du+EmKv1|e^1BObdJlYRR&D6Hcp!mj9WP6dslFrleqTQ%lT z-q$fFE}`?YNMD$rLf{WqWlvJ(=GU>$w(PiOE;%9CN7|US?RZP*Vr`ixQP440?2iCI z5#mJhqTzQCgWt^6{P(*gYOc{nKN^A@H+jxAs+40+n*u375bhM;W}?l!w7aE|KRVWd z#3vAb*Y$2q5>b4?xoq#Jv2Q$47gX|t%clc^>g!aPq%=U6wFbNO?Yk~g#EGGV`VKO0 z#Lpwjo1t|5ljMW6LQfieCwJ04Tkfmup2cFCJ<_uG&-6$!?89jIoo5kd(+H+8kyQr$ ztlgN=u(F&PNCnN!(X(ca%_y3Xz=OE^eWk>VhNlmmnb5+IX*R}kyATv)FVIGu-qpuA zxWixW4b#UP5)jEH&ztvX?;ungAsf$rOoTl^4vuMTJK7X>Yq&D~rZm24yOX+P{<*3^ zBy5!T6xFnE68b6-GUXQ1WQpe?=pEsP9`nfz6-1GcHk09OY9JJ2RYoO-ElWKHCxTv$ z$vJdi1iIb}58D0%Xk+Jc+qSv^a3!!*k^-=f1u zb%+d2L?3NrcD<{PNzShk$(h^aQL|JbHyy8wfS7jE$epUQ+h=)xq94B#c6)4R1(d&UY4 z@6UZ}?yQLmT4GT^i633!UD@cOoTV}12UPb2r`jnbn7n9(HTqY?9+OWBeyPeN5(rJn zQ^gFAY2H53CrZ&88Y{;`i&f^TqQMxlcoom#Jj~FjLH1_T*bsLRwn^nhxw91b7Qw;2 zT*=+4S&~Q8kAApkB680MhtzjP|2|Nfh%^AnBQG3^0D2=(mAyxm)!ZH zcMay9V=UQYWe0mHud*hU9AQ+@b<`4W=S&WTu#1hL)n}RB0HY<1`G0XzU+B_^_8d%^ zd?FfT37EKEkAs9jE|(ebCaZZB^D2LX4q&JAaT9vS zl8+THSl=>HTny)?=Nv>dh1y$_=a=ISjM%2RHH<=a`>~ND^FApQW&Zh1Nun$;tyWc{ zomdc2sx%W6L4WVMbg%<0V2et8p|VumAiK3Zph>zsb5ZCzBojo5_eAgDq7uTK#{JPr z%m}l820U&@iMR11t0i+)uD%6bR*dnqaCS#8^b4bLS-q!sv}lKB133W}Rr6-Mx5gQL zsT;2)QJoE$feZBVgdUZD`d?4xdX#I-KQ0&p72G+B6Zq8xLdYJpaP^YI(x^W(pGy;X zZ+24-3q)uGYdV3C2cdyvKEc0^tT}zk$a*0k#=h`A?Jpake<`sBVvvb+DI!C275TIbFtB4Q&9W%#j ztb4TyjF?i2+}{6HzM{(+w;?p0m-*$v_?Ef;5KE<@yrI6Y6^oF=vKGY1nZ< zs7IY=(QhW;f<+gO$Q*kTyg#vI@DS^MgRSMGH#N7-^f!R;i=d7qTZ6!SpZj#5uBU|~ zwGZs#y{JDkZ?w@wY;o}FH+{)n*n!>f&WzWh*wPJRtPeTzblbflFe9mk-GWtMpnZWPqAEZ@k07 zYocG%jy*a|qg%>0LnFa;RC~v*9NOHbGfr&f$jE473ZXL3-xHg-W1mpExouLMM73^lcT9lI8bOqOwt9EZbH#4~rhsTq>V3*jW&oyj*9mGVld%Vm0?gqFBir zU(-|t+jGUN0*j<#*XOD9BY(8#$re*hje2*Z?aS|^62rmpllNqo714D3NVAGC5{YhIgvM4~>LT z<6DpMkxr{zXP65jjkEk=YPcqXdWI^NX z9#raNI@);s_H(%-yW4ovR0-Q`jv+xI00QhnWqoZGv0j0hYCX=9Y2*iRI`I^wYMsPj zIz11;Nv}>O&(+`~@<-a&A$`0_geom$YRjd2krk=d6D`*&h&G8y@^IW6pf)*ZWnf}_ zQyhn6z$IGdX09@M&?fF_i==+md@ov>(BmV63STA6aVBHVS2{)W zG)E%r59q4GkCPif_SOw&XVJ5ZLYz~+zzeJ(ICj)Z&Zs7lNm;z?QOH+*g1?}@rdo~L zu|AVLlp}-!7JOYK4F%yt#aTbzJ(k*|zuww|uYgsm&f)L_Yv7JspRn*_rp=So@k2j6 z_`X*{x57xJu!p;ro;k-Dtlmx|?uHPs?ZCIyM2Rif?*N};*hf8A8E{;)N9x6?n5fsr zsw{f!N1vkEZ2Y59zyl{d07SGsHQ4z8j+0?(CVOdHzvzD0;_2TMMZQDj`)>ePSNp#qHeK_84!@&^67iZ2!NAP&TfgHEeIX@^T{dd+Y|N1+6Zuf(_fhUX-I4rFVlTdb()@U>q ziMXshVgHA>rn&C^Da6FKoy`eXZvViRCaa|FZxk`Mg{6<`x1w=2!VD0IFvfo3v}DpX zinieFq}5-cVTw8P%*LS-wze*H8HWMOVjU_c;7$vlXl+{mOO!&U^CALhH69{kv5j=zLmRm&pTuG&9mTUs>c=5}i;n0`G@jO1sY?VLd>J@~@o&*|e z3%_hDFMnLI3?_k*2-H1_(%-V9nk>cZOy!&0s%&u8G=p>>rb#un==u)!{B zWwAKl!WVvwmCV@qkV$gGT8{rq(z$4>Wm9I;;{9XNqIhu&fgkyeBKcZ18};J{|!atnD~ALujJ46CR2@?xIKbej3^H|il;&+IGCh+wk%3Ea=4Pu}W}vrHEloZpIOJI9 zTB58dUe=*&1KjzvZ=B|CKAnmtdxK?Nj_llR^S2aeCHr&`9%hIX%y%Jo-U09_ofgpD zQ5LP-l|~Q3jgcR~{fq-_qA5;&zQ85ab#t!(Axo$_lzl!Srjp-n&k6C4X?!~9wsmk>l}bI2vJE6@(WR`2<9i)AyAz}t2Fl{!e>nPLm zQwDk{JkY|}-@u$Xx#fid|LjRIk-BNDPVOL?Ee$?)`ZF6eO)_0r3eBkbC^lg%@L$Dt zKOXUSXxR+MZWVGz3~8g6!UIhF*inYRxD#QpDN`}TV!P~NmrKM5BT%8(?Z?pYG|Na? zW~gbJ52!O5=T0Tl-~(O!sePtq&#nUO&FPdVt7R_+davTna&1s`a>;%=CD>k4QQin9 zmpE*+P-r;H`mJ0YXfPA(^3^{iOI_XT!R7rX#5aT*vw;d}*@DUH-;i?cVJ^`Rc>^d~ zrIx*rBeO+N7j}e|8U*nnqc9SzZN(KZXAysxWPpJen&H5kXJx>iNb_;CC(=ycePQ0} z;;m*xrH1Dod#q`z2wNrS`0~M);+r8`}q~T>Dp}I5r5Nwc-)fUj8-WDxGe;}MF==-hnTI2Y23V6*#yyaoGMY9(d8Yy zn~3xi=iB6?r1B^UrO24%$L4oliOVjum!eknt}8$EPzEqn2kM-u7ylhlDJcW$1c;Rz za(sdGOm==eCGL%!P5;S$GN?V+ClcQ%H`ZxX3*TA6Kw}HwgKl8uATBF_#jkd88IO)s zS6~irp4^I!#UdMDlHi2LU`#9M`{Joj?jGM?*a>&?3si~t*YR1PN!#!TCx*h~EW+9K zYGed9v%uA5FeJ0cW>_KjpskbdPpeH^)f1?eLq2IfqTX>9|o z;@xs!D5HXi59H>desZr1frE3v6-u48-IvK+_;aR2X5V;nCl_~?9Zt*(GMVm` zI5fsSeev=U?#35!6FgeL*^+3XBSMC~$|rxU^+sd(Sm~CXM%#dr)M8-dD}$3&k`MRS zDL8)AE~>u)3lru$8PmnFPc#3HuIjTAi%dt=5n=g6;sQ}Q`Je_hEe1cZbb-y z=d4blQ}N2&cQLx*;Z2W}nRb(TlR1`AcH40mt_@mc75yj$2b=X#IMw9B}`N2*0v z6nT&6>fe!TZ5Uc8I6>e$t$5hUt*B}qzJZnCM#v2#8Ctm5V)@bS-w&{gK1;vx;&K|J z?9{`8C_8=Ke-Ji9zdl%;n`$u(d2O|S{#z%Lb#L;8tL;L1Y)T}l-_!s*O3NVm4x+xC zt3+v>BAVFh73u=fOnRwVZVgYyCCMx;aeHYtgS5e&oEN-GQvy9SV%u;dH&#Tfcqfq;>kmmHFve*hE54&Lic9p5#}D z1GjWb44*N4Nl1*zSiHM{%PAMfZM7-+RDtId7{;n}ST@mMkN7Gsq79Zot5jb>Lr_WX zk2m{9-ECAWTFW@mU*V!dkz~mpi1lQ72ABym1%D}e`c@D5mqhjlcbU2asTI67&DGtr z>nelb9C}pGl{|_8kk9 z^n=%2P4ad9UX3kYAy0jQ9+tv43iS(biLIG1B}k7Ah1M*&T?W9BL&%K7iIz$$Ko(I-;<2o!O&yp$eNlc8xzCTP9YJzeL0j|7 z6PGHtm+0?HUMp(Rfbfvl|At`URKWddq0z{7OvT}Lr zzmHsefFFU;H%5ndd6yeC{d~EzR|AyuF0qXBGx!P?r(BgpO!NwzvZcma*r^rH8J6r0 zAW}qEmXuBqUQ*18QbAYKqL9EO?Ewkd@6c8VPQkcVVCZ+?nHC|OSFcPx-X>4PczlId zFXk+A?fwJ~m1H?2#t(F`{(d3=CT{*Ol9|$ph~4#^9L#`8vOJu>PkcVVQ9{Lc@|){Y z+N30k%;FU;K`p^r+@=1@Je{Iu!khbV8tBPvfE86V7Hh`C+rA<$D=TBt?)FDYun zDDKX>hnHLPtsKco^W>H2DRU%K#eY2%a>0#B@z8N4gHr{FIKa0=$QG~#bvDgftjGL( zRC6WBqO3CNTb<>X`!oJ+ic4@81WKtpW=pu!$gxRaTH*5^AOfWRlPcrA(dZjnJP3Vs z4``8uF%_q;Qi({6$A9*ztSGnt7>mDtSqj(?hlEK>+)!PUy;oc9m2L6MaB*L&iQDN{ z0##sZ5qR$=7oTT$@TCQ%iOd^#CN^mRgcJS?qFps%Njvie)uneDSZjoJkS{)Qy&wHK zmONK+zW4-6Y+ew?D+~1{MJT$^aa{JpWX99;X$osWkrGXXq30DD93fxG_T?@)p0wQL z>UUOgeIIcq%6w)pnHY*+>t5PYBTc~0tfAV>vGxA8s9Ctt?I_T4UFEC9r&+Lt`B_~p zYhgOwa6*5vnCuJv!3-vCoF;Qly`DCgUKr&vz11y*?@!ZaH3Qbsl%6?e%TQw0(nrGb zk}6XM*^}tc$+v~Y{hJ60F#Yjh#ogN&I+I)zo*qpFt-~l8&9vSDh`8U3TE5Y!Qn{{r z78fp7-#*aGAX;FO23rp`74wi$dZoc2Tge*$Ib}{3gy=NZ%VaR?R+QBI=%f^W6#WHo z2OGy5;+V$@F{3j)aDPF))JS2FT~z7k%v$+@CQY+_%HJ}U!9bJ4?=LAp!zHom z1g#l(X2MDY8kf7vVCbig0Es-XG6s4>Ph~!dRtA`0+F{0c7Tvi#r+Jhm12@t+TuBTt zNHSs(@K7t*?Ua z{pi~a#(1)YrZ2$+L>4cqQp&;84(w;+q1=J8-Q?1rmY?4%08Z2-=4heo73K)}o-5_W zm^i_GtY{@^%C2n}ot3N}_rKL-Xl#ZJd53od95FETT`LKzMUATyIiE0sV})QnXU=aZ zwWcFl*5nI_uq=kx_9X8jq#r#UHz@Vt`QFtr18@NKd>nQor@`t3q&~wtFpSW~g0i$g_2|ivg@&HNnZ8^)acW=J-m@m(t ziHpwPo}r@b5I6I2PHer%#{0?qNwI3m#wa*O26sCY@=(#Qe-o8P+-nhTkk!U-$iN`& ziLIg93JgB4Kp%2!8(Vq`(&$)I(L~Ub`wG~RA+_Pmls`5PbJzK4rYy6z`i;hm2|r{w zjs*@eZfQgHsHE+KoIE+>z|tvRX`D9Gst51bNhc&7RJyqNqECAn_ltIuesxRyk%~N@ zWk4%QWmdSkc$n-W5ksq{e%;!m`iZ_M`tY_;vDtD=Gn#&;vuPt~M=sI7Fi^hBT{wP2 z7KxlKnXi*5=B#K_)Cr4wcHZMtrav{gGja_ojuou$nrw!A@Wl;weqATEv?{Uuv81sf z>FwXxrDk!~vS?Fw`!VsFm6%YUDT8lbR7`k@;~?VSi{g{#Xh%YIRbD%?T_mBIKSEX- zF*1J93&w;97-po<{N%5AQaT8FoQ-yr&MHaWCKhonEB`(Bh0f7=`{9ciUe^F09^Z_) zhGXnBT%DJl#}{YplM1Rj)!&5cSn)Dcd&2fxv21+`QO>8_w>6W>IKDJ#rF*Qrg6%n` zket@A8}2%ma`RcVp@K>bDA!73P=mdM-x@S2kTXaFLq#+=P-xwaux2 zg+*>?l;$hI-0>;TNi|=Y(aL40GMkl@{cHg=#ixrx0v^BW=88H^FqZ2V5a<(m@2gwJ~c<}f@AZA zA3sv%Z2w5z38N_^L|29E^C;KKA-5?En{TMxNT;>2FPtb|KUwnE$8Tl*vS~PyzU(Hs zQH4X`^5Cc;iItxMD1TkN*?vEM*&2SNU{jmAo@CVSo;}UP-`5S^cDbEgF~VVKd{D*O z2p_!Ht`YCd>TlZrU3^-PH?|68!ESkx&#{`3hvcIr>2j_*#HP^wDf3aEFal{{=}z!8=ap4VcFmqKbv95R@3h+VDJ*x zR@6MQIE_!7RG{qV5~xujGebJdb?@2RO`KSU)@I{v^#s`x!F;@el}2Vp$TvD5@}&@1 zf2byan@#xfi#|FgX97hI_|z89ms>4cXrXX~$qtbcjvb@ccu0_ z8)Ce{`d3IZ(d`?6i}?eFCnSJH7e$y0Lq7#%VR2sXv`Z~_4MSiFc5%W(SJpxpoAlhx zG3|2=TiT=1Ow}v%s7e8f@Iw*(xVX5yqq$mjU^u--i$r ztLv1e_aY5ar5Ew@)9RTYa0WkKy&P}3OFYQWHan#RDWAH+S(baxd=JK#QMbq~D=%Ay z%AIL}_ipbrzg@|mg_!C(_O)--z~O+7VH6UmtoW79(!IY$g>2gSR-w5{mWQLY>9@Gd ziXPX^NX3uwdGio#`LbQfU;M>1-vy%nhVOJ~Z8h^^*Yh9|<*Lxf{9kmvRa6{Iw5{6& z3mV*=#x1xLv}xSk-Q6L$L*s#9K^vC@cY-&rjk`MpCy?a7oOAEPec1cG9%_slHCEM{ zbAGFKphWYWI4!Ki_$EA)LN_ZnrpEKoWd|RUZ153vZAKs+4MhU4wI-zTO-{dwYI%D8*`G4cQu{xiRiPWc1-gyMl%#h2BNJD$RDP z$(~V)>?@yQA&us8RsjV(PtoZ+JFy&FPqgeghqo=mr_B(Nt97dHM=}?Brw`^td}ob} zplrBSfCPmN>C?TjXp`xFJ&t4*C$`mJ%JTmTWXz`MwszQ9pX+aWIl+8xn zVoZf%UUDxJWo|lzhwbTn)9)~GAD3P@BgF*l#{dr8laU?ub|RZw+Zqd51;O{Ya6Z8v zm0k(>Q;jYq=K4LN!L82O5z&V+YAka47$U*QnU$IMmJ@@e6?SFuOzZCgrj{}UF&2-yQY9veLcV36U0=}Q@8cVLZP)1spU771@7k99o31!CS4B*{X+|r6Ps0J! zDjVP}la0W|PlW#g^h4)pZ|$GXB$A5y?x)P>eefUF03mC61v%Y_G;Moz^rv|hUOhRI zPw0yJy>T3};XhSP>drRBMyC+~#5?Fgp?seC4@eKY)O(o94^dwWsV3>DX8Z7VSJCpo<~6uXLFpd3(^8qySA7X;43*9f~UyYM2-$|zj{%t_UT&hXAvp@P@8x2CY0v5x;r_^L{xtiwx~U-#sogPl2qB(?L3Ta>aHUXs4&CY) zL@e|Hi-bzIFI*lj0!Ir!U=;`twUdU%47>Cl;2gdm#fn!W+NvX1B)12(tc$B|t-+M% z-4^lY*{AsMca%hb7p8_(-;ngP`Vy0DIpIBNbg3a${UP7k`24fyAhdHkZEt_#FhfFT zt&YkM^(U`!?Ydwu%b@o#ye6X~tPS7*N=Gk`fwG~Kw+%-QnqSDKx*B*~dmIk1 zlW7Ep3sC{>GOvn$Y~+|DX2@VCd8L%vdtFZ{JKrZ>N*oDaaB_0g<9utB9wzmCFGQc# zPY3xk-kBR7jHyd(`c>cuvb=a$I{!c=ML?-K2wP`tbl#LH&96ik1A1oh!w@s*&T!*| zc=;m_-(1PdrL*>b0F9Hs(zEp@Hqm#D`q?}`{sUMXP*xyWTcgW$n(k_`UMXA;v#<2V zIcS`Xy5?8~Rme07)6o*_b4dFHo7()y9*r_)-ofp!A-K=nnmz5#4{A^^_hTz$VV~U&-uv3AFTHT-JLc$HxH&btNt=RaLmcFedCNN)V!hfW+*ICH`af zC}vLiElp|uw_juax&mB6G-*37-pPS|QplV{K{s&mA;tQl)PfLSURp6ZvO zRdBoxJQgse32#dKlLq z))V>iJ}!yO_V}~x9~CCfw90x+7nD!O+9RB~?Y<0N!|a><{wSa`u0%B@#47`IGS#Ax zrvAe4^11tm#g=np(m5ziu}ZyEVdGqN(pOG_3o}_ zZuar-R9lK(l6y;K#LH>&1FcB56`eB*W_iTgnR|d>i-b7uCsi<0hPxoWnCm{_qN-1$ z*tr(zNP$h}iSk1>iT78Tp%q_2Kj6XZe)hbQ18IZqsB&Q1R_56=6=&wjsI>%s;(Chm z{+NJJk>$YdrrNYH%-m|^Q&wB_hE~>*3Up28qy!WDc#QH1KZ0e5$6%P~)Ox+G-D2#O zC2syOlpAigA(=w@&yWzF#-Hyy{zSzy(e*9Q1M)e9pI_o!#9i-t|1I)@pfp_!*2o(F z$UCwx$>mnhWLB0j8D!G|<=D+~2I4jq##*QuRd9X1myN4V;6Vwf7u4kTb$&rcc_fhr zBAB^5WB?dXG=*qpL%43o?n$nces3vPfX&v9%PM=xf2Rr008W#%9Vy0+8#jKNr7w9k(?gAlcM< z*~t7ylx(!q#CN76%jlH6D=#`VpP9d3e_ehC8DloT_r?(Wv;05%c|y#bKQp zDyFy0%9;jkuGE0G{rU@$;5CULs^w6wg=e{kOEUc0Af3k`*EC~tKBI}ea$KHHcAhmg zQgwOZT;?xfXlqmJ=V)KG6*Jc90cXAJ=Ff3sC;y_*t3)!^2>*m^+)w10etQe*GGb8$ zIq?Nk`OALAzG-gUf$cpjBC#IO6Vi{z(t95Tn?C8BCg!dG2VfuYXywYQcm9Lh5T`bW zU}}sfpFoHhS^~v2VanGInftE6Xyf*A6Ov$5Y!khsoo65SQmB~pD&3BU!=1%3Y^TaQ zY+qUHM>2N(tC(Pd@pm&goSLHzGi2*idiI}Ed5DJ(?(3AU#;Vyy%r^y51&#vv(v?EK zGffQYd}8u&8{uPSM(ZKTYZJKVU*SG-x-8($>#von=Htf24%<}2+PD}T8b5BeCrk`e zDdR!;Eo(>d1g-nt{F5+ph79tusF@oB(_ue;sT$shv3X(ahgB6}Sk!y#n(<#yyy%r& zgCxu{WwVcgPyZB4H2)d-*<_AAc^UYGdhYnkQwJ-7YXnT^P3`-A>kfdy&9x%Q@kk*` z+3~NAi7_uWVXn@-Y@-#Owja{v+ck;|R(@J8^Etf#z$d?(YkZcAL5L!&mHb*$$jQ$_ z2l=ttuA3EDHdN}J3=)6PWqcIjXmLT=hR7Vo)5evkC zEUQw2(VE-Y+=t6EP#b0lQm?!>3?Czm-sv~3|NN&tSi@Q5!mi>xKH9g#q4{HF?A9%_ zZn-OI@ngjA?Xq1wJa;VM0=bGSs5!6wVCma3M9{6bj=9&#i7)-k-_qGS=32WvS?MeT z42?$mCn8+`r~GVhUT6Z@eymTTqndFz9Jt1knihbD*ve~|xCx}dXzzOsy{#V5zh>vj zs2nR6q&xO~UJWbq0n=WprQLI@l1`&U)rn5Kd{`59`_e56b}@1`856(wT*)@NFR(K_ zd{g_qFhmPf-75iOwnDp-NEs&x5?@-b%1RXHkh>&T=7RpsA zK<_X7&_m@N=Q?49@VdxLPG|^zqXM-@v^)|n4V|b{fG2|$+d-iAsmFOokX%5?bKce& zHB2?80}Ar38sML`)QrNKTx9syAsa6fEFYqX_4 zFQ-r8awn}FeJbjc71eeqHLme+jRM_d(fDqUZwu}Mz2KphQH*iWIze6|-0`VVMDFT> zOo3zHeyF;u>i`ENg$l=!LUNay(h?8;Tz+Q-xs{|VxVLQzEk9$cP-E_Hlnwqd^Huvn z^n>@9uqb#M#Y;JGK`Bwc(0APK!gR-k5?ecC=6!9GVWQr28D8s?@9LFnJNU7;y0TN>0R>6Zkm~Z`$nEg zk8{0lPi3tN1;knG#We!utL=Y)#6+{>smVOB+e*Qp-=$2OxkVPa=b~fmqB~@_=UV9m z<5!px1W))Kv)jTa?7N?}&63YHAHJb%2Bf{0II8z;U1Z|Up&X;1FECc~;4e(1&qVT= zW^Rep{0|Uoe7e_RU^P>@`F5d&V@+qXe={UXT>J+(G#;xk=IKHykSbUe(~ftxX$^PH zI`$1lJj!seAE|%j*y`$vca}{hv|sfa)}`d~O{r?C|7g@gy~t(g`mK#C{WF(g#Qhwb z7jPU*I!Y*erTVw>^4E*f0KG%^*H<)NjjlWvDLiP_ft9GI*PkzD-*cuj=cYD$4Fn%~ z;31kBDQ$twJN#{44$^<(%H1cS@BJ1O(2x+H zQn-5Y6s=Qmr3_Fdg8CA%xe)H5Hlj(-NJl`CSBp$m^0aa4)=6CN3nRa8nv< zO`!`C8i?V8*sx8VL%17Kp0!r~5}dUom}ip|9+6yQG2Fy{BWA;MCRVX+WH@TG?ZgTx z7<$pt&X;{n#Tkp766(1FeNae6L*Q8{Id(zhQp!2oIm6mBcIqPxEF-@$qrpek&4qcR=-gJP(ol zEcEEEo%~Vgk7?$D+Er=a8@;cOLDq< z(=OkXns9jk;l(Sa^Y^uJc=o|5bS2RPfm(Zjg>@E{__^h$Bxn2PeO zXtzu-AN1RjN8XK%J+^@=bMAWfk#|IR*zyQ|ET_}J;+ld{YORg z7c1{8$zr@_`-Kd~psWhdH9`%bIWpzBW&5Fa1|atRcy1Um_o1pTLg@;V- z9-3H#m1Dtb*@(+s3v92wzK7nch@It5Z%Xg&@~!(g<&C5OYFQ?bf##y_@dX&29}M->q(`192mpk#7_G1mKs;9ug&3<~0&|(Iq+G$QysQV_Iu(s4FZ+^uM7YePAT5aI7bO->z7c8o15;CMbu*Z*JuBAB=F7#4aq~L zNZ`@?$&ai=eDLd}N`7Iq*jZ)lMB4jz$~P)6nB8Pw=||};9z9HbWY>K#0)$Ddlx~r} zcW^Z>uKh#PGC?`{(%(JesbDUu#7>QvFM7tZNj-vl!f|!glo6U!rUyX`N*|*R;8A z*T2LcM?792%{cM&qDAUEzw{{JiM2RNHgk$(Hg%twwefdb@5TFeW`Xab*T9oe z=8;DLcV^S7lFf4-$<_*cBy(*WO{Z}PW?>ECON(wnh4)t;B^|R?8{%T=a@1c z<*S=vdP8y{p@Rq~;$+^xk%~7ao@EPI-7r-MSfRJ5e5H!jd3TcEA5znuHF;Fo#$4o% z0-H`XJ#`Ifj(j8f+?k2Wz9*V&F=bFsfY@yfb^-YZ>Pev>;s%lZ2yt;%8zwddXTCb0 z$)v4^>~x-nD&c*gw(Z%$#v~A!|1``N1f8lF)!g;$*p0PPfip{}dj{RDb)HINoF$j@ zdaf2I{JIjlR%Lg^caO0h;1{sUDD<(`K+QDJ={F%Y@hk$Ld-r+??b^dCjOJO zoD36}qo+@s9A(RFJ3~#KIX=^%)Lft~Z+vkMWKfi|v!7Wr7GgFaqGsHc)Klx75nYH@ z?ietM{ejDF#fs^wA~;lJqG(gh@ejgaDed%__-m%j?) z?+F|FJYm{m8JqItoT%}q@_a%|VqE15ThZsC<&jOUgMka1A}ZsgYNA-kuBeMHnGY=V zTK!@RpI8UR2Qe#Jh3i~xGwUn3(;Klz(%Ow9&Yr~$du&lx=%wLYT z4fx7FL+!R@>bWE`Be*U7h4;dXx_==o3qMCnV-}e+$ zP?jy$Mz>Lf$*;*-#Ki`v49zEMWLedV_?~id>?0l1FF~o0LQfWh=NhkC;xljGqtt>s zAo!5IZV2$M_IuiiZqm2qkFGVWMsE>!!kMjwmNW@y)|_>!`#^n2)wc+R=EAUg&$BTN zpGWpBU$KS3-Y5L}(cGVM)RWeY@5duI3fPth$97}GN_K>?Jf`Ui5FBt%cvzTZ7g z0;-HdN%hB6k9SS;W7&C=;o~cjbm`!ygwNpd-DG45$rR4Csh^GHf!qU<%Hk`6Z;-R3LCG0ND73_L$?uK5|TON^wJ@d~1wWuNrRa zF8Pvx$?KaNSM0D3;1fUi0lUl%Q#X*mZqiH2f?RBVq(4ik>RpaLZhka++B;~CzY%Pi zpYKt;is8T$>Jl42aJ)Sn@C}+9QQ1N1FOV?-KdJFf){nFj)4itfD7NgWDu^2zjya~w zS}e5bKul&MQ4t9~>>yX9)-_6{wl^H|&GnvyA(B+T-{7CfDco|Lcr0U1pNfLU_0RC@ z_Op%wST}1_C-gKcpKSeM)d>{wI=ctfc8I%*>j0bvS6&s`wOFxZu^qoM<+ypwcQq+K zfnVhb>ni2q(mr<_wWb77hT*9ZWcDH{9UT+&bob)0f5@kZR3<8|&(GXhWJt8ULTDex zSjO0NOf9WKubXDBPfV+9o?JYgLd2lNccwH=MZxaABwNMEH$aM#DD

=O?W*tNZ_m;rk!IC$(4uXF& zXDk|ZZLO`+h6*%dtmq)jZERHX%Tn< z(<=BaXA?C>d`;cI_&J2V8mI4xWXFIPHne*ap1wR+eVb{+Xh|hTv&(5~rbB`OiF#5e zUvW1ibDs40PTU=y411dHA6}-|qwG|>Z4!1va0~EU&x%;^xTom=IuG;d_yqoz@`Ss4 z*PzZ|HO1&^EvI7MU-UDsa4y4d9J|hdkIb_Y((a<##5HyvnC*NGnq#UH*(W2nT`X?) zWUvYTpD6SldbADKl^dSUKAHhfOKU@ExYxhR%010Y zMasJ8+I@^|taeg@IrJAAQpB9+(Qxy&-oPTaIZlET793Hj?;3>6rFLVuH-hhvRRgwW zpQ{B~fXOJ#OzO=Ud{iu;mmwG78OQNvFR5~0bIO{Lt)G48I_H8;9>`y0JFceIN^OrE z>Y5YLx*J&5*k(A4WS*STEY8@p#no!szNWmwJVUlS`!#*qxqoT68vUU4T92_kJ5nno9#cs;a>{CA+zJ$I%arvJW z@cdWVOs3O`d8BY(^Z(EMtM$Jv4FYA_o!0D=qy}&w|Gz$A-3o*W6OdK1djmzf$94E zZc8cH(aTAy5}M{tY_zkb;!by|$&{$OFetX=R+fA{6ZN^MzamQ7FC^EezzN3k`8k#j z?svxyzLz+bZOi-R#G-^xc&~Vr;~>5mC)o5FV9}V&!ebywXgdIIJC01Cv?&|5MuPxC z#(hb`!`GSyH8VxWjT+BX6vxHl3Uxot37P62RbdoBx__Rbxw(>LuSC>9EIXz5M%W^h zn1Qdu0xDQ&qmmM9!=M(H4ms1q?o7Hb9fa6lXNj(99Ma-n?MF&yAK%=^rII9=ce-`G zg#?IgbP+y?fMo6wp^~-$61zM&%fXk%VG3AXR`b$9B*~gP_izA)u7{s#x7ts zmF`j0BoV);8vm8WalsesfEGN+8Zj^Oh*t)P#OND^Fpz@U5DRNS41;Q}iy~iZl_uSU z@||7Uuwz`RsKVs3^0+&10?VR$NL1{&NBGRPv^TT0ic~3OEYq$gc1;#va|HjG5a}Q9 zA&{??1N(=8M!BsbE5uL98J$1%B+$8XBpT{6fME(xvlx|DlBY8Tz_pb=8s8d}g;f!U zQ6DEeYAzl7%MU{Ft6-kDG-3`ixc@^-(_ugEMG0y*oQ$vUMHvqkO$B`oBL%)7=p9xW zz*${?sk=Y~gMU(|)CFMsFz71rcT%2xR5zq(^1DdbW3(~&nL0OPC(hxskQNsL@1#y%BW$2hUb;>Q$cF>wfsD~x8Xq(jhy z=r$GQxIZXnBynD%cpqn%2A7`d1#YOg*sp_j6kuKRQ71hJi9QMHD}Yo4`Bm?VLVcA2bmT|YI1suq0Zq}+J<6jw`dd07KGp6A`yp|~!t`?I=IBE#yA*z9K4rOzt_jG+C?P??i)esd=JL1^$uPh^A0a&BG~sq@ zc_c@RetLy3O7rW4@7M)%Os?;?5w@qXu8&O?)>|qCn!`WW^A%RT#>;DUGn=HhGT5h( z9LjuuRNtF~>@th5dEBCaKaKF6?#sD~ttR|B-vK6%pYchQd_r_RVBR8bgL`LjnXtF6 z_SAPCOm+rV(90aZX6SOYnh4g~78+sokcdXQ5U2tc3>1`o(e+@*LD(Hpc-7x$`i;7Q zI?^z-du~O)x%}E2`@!D)42#*v%x_mzeE z+}z-X+eN_*-~IU^jq_KW4R^+iEqtAdFsmRq}Cl_#HJDzrr3Xo06>aBC}(QjeMQA zNlRH(Isro1jAI4oq5XqH$%Rf_ea@NQ3n^+jme)~>eXLP|1_VX8u1liy+U6a%`wKw~ zj%Y^yFP0eyVVH%=F&)2o)Xi2t>3%LpbvunG_`AuK`&GnR%GiQpvZ{>B)9g1)QU;EE z>&J?~%;pS-hBt<5X|COZhR7xl6=ARnk1n)g?Y;KtzZ7hW@Bl%y?LY7q3bHTNQug&5 z`=qWY;)@*TU!(c1lI+M!h`pXj|ANfaT1%&wE?LFYBh=jSbL}N>g1n`;jiO~n41Sjz zmV!?S(u<|h_G#V@bT55LQmY>+`3-eO`?-Ng^T*T7&M#IQit!OR>l3fm){qoZGtnd8kDpHAFm19-L+YvyjUGwa-2vS-R^X+bQ(*&2@LASg! z-!~PT5IH}8oRnw#x3;R0z#CkwbB`#IwE&p$aIF=+;z$oAWbP!R2iADShaIru|Ap)9 zaiGvA#T%Pbv3Y~+mD3bu-ubcNpueGqH|2c@lwi6}9!_iwU2UnO&-q345Gv7|f8%;X zpKI~$LSQJ;Va=Mg(*4sqt+ApiZQ{$Rzs;C+2xTEwZaQnv)5h43@ zaXzLsE_L_A2ajoH@??dWb#DpSWYzzFZ(G;gD^$aTJ}Kg3`xRV9GS0-P>Mh^$0qL>m zuQKtljoh%rsXim_wQ-a-ZAyisjZqGDXOiKboHr))7K=xJ(k(7KIp{OGWX^>?I?k0oL8|3_sSr?`T=Tq6)aiXa&i;m@IG4VR=$>#m zW5c(A5aeR0!&|3ci=(_d3Fa{~(hB&3b>fJ+poh0Pu{R1sUEsG^kGwS(_fU+s(`lLY zVX0gjwChY>^;1Y`UOKIm-Ju*LBsr_1GhO;n5tx3>AhlQ z8T%@6pQc1_myqy4)nTcj&QQg9-9~efu(~>Jg27ft=rD6>m>OO- z(&Je->Ix_Gx#LL|D*dYmbO{1Br2XVW-)x&yuKnn=@qdX7IVPbR4ec9g2+#6MWg@|S zks#@tSfEFtB2Mc~ey<6w zhqzGU2S-!B>mvxQva(57WD+vZCcQt(Zl!DLr;@3TcGDDhP;y@poem!PW;RUWE-i&= zwy7%OIZwVR$#5Lk`mt2aj}8Z2w!0OL1bc(dF5;qesY2?OJ=Au#KBp8qgy2&tY%Njq zEitaVVt*MPz1Didac|a{cA-H>7hKuBdHxEwTw1m#6Nh4#08lLsK%B4p zK2@H9+!)=NBJ{MJB)GZkDqsAeI=6u@_eiJ%sOeNW^yl3tN}ZP!qcy%L;CYIw0~?2{ z((g=5ujT?(C*eKD7ANU_MNy_IM`$8%z+Ejph+Z_tE#THXs?g+> zQDP^vv0~ZA&7fFti5=cf;bc+RY@Dk?@KTNPm>{da>4sSLez~PDs!;2~Qs-uJMS~4w zond5VslQ`oeXW{~MrSO+`S1}mTHGUBTwx8t@d684Cl7r1;&2Bhch|3`1lnJn)1er{ zD`XOE7LGz>ZN;IpU~>h=40Zq@Umfs8y8azEtd4k|P_@+AXl@u26Ojnw)6(POorGSDrj9scuv=cIZ(s{SdNug!NA+-*@$^-wdQm5>Kdp10+ zkTCx^*1`j)w_a{~RNb5Q$b7*}`!uWDwf%s$0l(O)yMw1G*q@jF9H)=mxG%?wr293G|T{0MynMN#&+ z$qF$YepG!J3Z6kkT0auJ;%(yw;Z!33L?(t*f}c;cDu|!-&#R<<9lWv?J}_n+D^(sK zMf}k@hLa8Fx5BKe)w=iD zXw7%md#Mq6NyZ~rXco~}smvLq^UK)lI>9=zOv`-6=6W4BoLEhu2_n$Ep3v(l%cY^9 zZL*+Oeo|j0thYdfhWWI;hRT0hf-b$2lU@RGT*rFw-7%8auv*c70B)$Q2Q!1>_b!^f zd?F!wQt=U|2_fa%lIC4?+6OGTa$a zI&|QN4E}Wo+b?^|5h#b%CyrpG76q50q|QE9B$A_kTOUc(TmT}b^20aI2o^1@^jz5_^{a7H_K(+)2^->{p->Mf%gOd zM<^bZ|Gz@9cpuE80L%7&iP{F2C^vZ@p3}I$vzms)o++G2R`UqE)m(Qg!MTgp-b9f2 z6KA>Z1ZoHR))0bEmHP=s?SJTWPRu{C%g!^((kJPGIwL!>YdR5#ekT*u&Rcw_nrm42s<0a?Gu ziFqjq&Jx){1nW2E18-SE%+EywT(bQ$M#nci;Yx}LQZ*o?q$aUDFpEKcgus5)7-rE}1rO<`xhm+jl%GW$ZN#rZ=NG&g=- z(kG#;g2{w!6M`349_FO0K1gZ2mFRJ{X1#>oXmsb_r6= zx2a3UoO1ARD9_sS^&0)Ic=Rp^A4a$b11cTO@L&Bx*mCDyt7Ef|b3Mvi6ZKJtrSq^F zKRHmV3?+p1zQ0tzALO}9%gt;Y$>r7+%Ak@-9tm%mOgYhPZX$ByT>gaV1?r4E#badG zx9YVw{faWLP0?VLq1F;Mo<>iBX&Ejc&uN}~HQN+Ll`*x>AtP3VDAB zB+n8`=}1#*=tt$rG{^jGn@FIW#8~4U&k>!-HP;z~uR1=$oD;16g`p|DLEp|pU3O#o z$>zAdJ3Od{#Wv9J znTmFXiT}tq|6e9{g)X+p5&I>UT8soi?+@sJJByM91vj$RG@IWlD^L0d!Y>YQ;|OSL z3YR^j9;;I*^C8&66pzE&ttFOSe?X}1$35O^%_f9y-lu6_>3{B3Q*vOk?Q~JpJDE-v z&Yt$n6>xsiOc(sIbS2x1nf?i}*I}u+Qi0Dx2LEaHv`*HJ#yVGn#&=B*q6e)Sd1`=t z%NwdSW<&q=u8m!a9x>s*$qtzRdahuggaz@^1$&iV5&8%NGg1j4g^k${g!@X>FNH?GRG8T;?9uP zTW|%U+g>py!VR^AxxIM{iNVMXBl=`)$%8Qh>ru!4c zi)M$UFvn5a52jr1U(V>6h68KFDm~4&Kc~rBH&0+wge8|gqsM>FFDzEWqHr@)^*WIu zye4A|FFzJsw2e(gs72&@v@b{wCwQt~Y{G@q!8TRfy)9L56MvB6H{0ItBLSUOH4rYU z0XkG+2&W1Rvm_NNFq*}TQ?wL`@=oe9oVW~h$E=e&A*D)L=rLBB30Bb>LpMwNBjK*) z+Ykt);*(hemJKl!I@mx_un9hib>F2{`6VOsKsE{vil%VYj}7ZtzM>-O%cZE z^p9of2qOFf3v<$jb9&z#q$T`qVLDGD&_5rs???a5@dyvTBn%g3y85p7fqAh!XHb_D z-$JP6&4c|F_;w@7ZWY*?3P29bmZEVOkedW!`k^lUr~A5nWJ<`!I*;{Vth7|M&Ta?v zxG#7hc|yn;Ze&KGT6BP`;B;7ez_qrb9z*BUS$Qm`N0BYsRS~5iix&mNH~;PwRrphkHP@V%iN9!8ncKN2aiZej3_Id7)9j zZ-?$2U3qSvA4sm6+S1^qW)6S>wbLw4_(>r)XPrHRtfJ zC#W8pj5|Nxm0nQ*MAf+`)k{DM?Igh8VE)5y+#GafJI~LnJBTXZAUoNMvEOM97AnPr z9uW?7VZa^FfPad57$35>n2_z%4>&;zVhJvYl3!_29zYLQs2dK=8BAd(>9HGrgqCP( zv4p(^U57}V_;4~AJ9(%7*(PC*1DBj{EAr75N8Z^&zC?yJD{qyD9aorD07f z6BbJNKGv}VCXn~kA6kDX&Wn1qI4#F3vqZd+DS=0zeb;xdJx*{#`skVl1?YzXL|C9~ zBqUSlX~`nx%=fz_nmeCC$S6p`{DV z9tk%$lVPJZmnX~v76@H{=a^uXs=fPNe3=|F?y~q4s}`}fTXKWolD*ls6}*kE1#UO0 zBC{2XOxUi z!BNuqn_VD<*80ZpIbE0>I*lS$L$=?RAwCA(ojCmBp>(pWE8@&y!ttM-It%95t ze@IndzkR_?_DSg}bWEdHyR04CWaHg?lsr?snnRgfJ+5Zr8OjDD{{mJQn;l=FqYeWH zv^B-qF>(P(tH@t9UyEO|2IeORZ=*K2&vg(IBb!o@X=1<~NjYi*9o+ghhSQG?J!Grc zsp2XqJWR&HEyqVC8-DE?Ps^g8tItVpwr_Ip4vF>u1Bf$9EEtEpGqoxmf))Gw2pT## z+0IS*;aH8ZeuH1p6P7WC%G#| zYs@&VfN`;R$DnccjW~!I&o%0eL_2tLehT?jjux1(hOv9-2D7;}t?-qT%dj=pN{XW5 z)#8;E&6Q@bgYB8lSDLrMz76M-isHnqX|G{S zu!@Zyf;vuUeLl`OHo-B$7NK-h6|6JG-m%)1zos(XC|GC+57lJMLlnPJkop8CUDP9j zo-LF8y&>eu;6DKHR7MuiGM4H3J?=ikE}fl921F&fnS5+RbAdEm%0B;bO_JcnsiUkj zJz(>wK$rcRmVJ8Ypn)kpgg>0%N@&D>BM8qlda!=*qvLmy<7UfVMR4w+TxQf`!aGesvV18)+$F-${7N z(bEc?d>?qgBQhyG`P7C>L^{?hXZnI}KF)%p;V58&wQV)~t6Z0%2yV#yR4~jn>elH4 z*#OaI7R&mk6nku}50Ji*%qt+6qcszU=~vLpf;gFVPKf&El)W`LaLo*{qLT-N6y042 zv3n4<_uMjhM}apU`c4u6E5kpRyp3dpXyVc#sa5R}VRPTRl_XcoJc$*C{%{W`pYR2(bQnzcsIL3^ZA_CRphJd@2 z)1=f7oh~EQH*4$@!Z3&H6p4d60k&`o1-g^4%CNS@*qEE4!ht&}L5(>8I{?<1h-mi} zb*N+fay6qF`%_k0jIJyPpEA90-;ARv3u4?;{d>w8D^(&LACo!%yrBFY^>+xXC6=m} z$8dGYE+3}bO7wB}knvRI$r-#axHoB$Z~Ou*k_@9l--|11xIM|OXK~^%(ZYWK(HOjn4eet4EkTXS2=7TANFJ!ZWJS8Zq|l{JAa5l59!Js7x2DsIqG^6& zCLfP^>22>XKmTOQ%F|uQX`h)t;6dM<=Noy1&J*mRInpB~O=>7?pp$xaG1w#AD)=!B z!$xRi3#Ky#jj#WVsJ?p$X|aTr{mHlgO_Y_%u{~WMk=${C zeIxw<&zKEYX_;tWUxO(K8T`t%t;p}&xqS?d;R!i2T2mPpR64^4oW+we1@chg$*hFy zT6!+)u7hm+lBC=_s1cRyHJV#J{P&p#k0oAQs}xWtErdls*2T@IA=-)0TZ`j)!@XK?&9t=~dY6+9if zR&fX_^Vs?n2#@nAY0L@w(rMH7&VnwOd6QuxFJvrk)pC9$P7wcZO>3F6v)^WrXegeh z0_pOT*TV=~rlxWQtbH_5EgjHW^v6@ul@nGjw{q9^g7VfGf33q&o~RX9B{%#DQoA5S zb#FT3v(9d38|?St6t}^KE_eiu-On!EfU?89XGDcx@Wy5Q$A&1`(zgC5wii3iqNfo+ zS?@5HdU2~Zq8~~I%|Tka1i_c(U!$MX-#O6w@o>_)7u}@us_R$XFc=e!QbxN_sE|sK z9xMR6z<>{Q$4i+eARe7`x$(IgsUo?{@-X`G_qtDW>v8lMvb1pDz2fB_seqthBuz#R zD`TR*gV!^uyRt4LdE&UPnYW5wT#WB$?!qZdw`d)YLc98>*-5)it@!p<{!?;ve}J1? z)p+f=iB^aNLEE(E)csA>+D~mNueV1aLxAH_qbql0ij2yoO)f@UMO)@>fiNO8t#t{6 zN)sWBL~S_NqO=J*lkve#LS01iE1y@Qar>0^fdYP{LTIZDszWJH`d!q@uD*ZFW*^?p z^yJW?YkZewN%7Vu!73{#E1j~i=c41@Je^#}yWKSF=Ne7jV>SMyW+3WQysBNs{={nJf z(d7e0I=`wqvVT^B&bOeDItUOod!6}~TqU;I=ppBYlR*#yqx9B%&iZRXbEQo2xbzdO z6qnu>gT?)WEUX^=)hkI;3~%&dME-pcHjjI6I}{6!D4YorKWcGW!41PEmpGHrJ7I2c zOO2l14q=%T=rDn$NgpqgG0-uZbR1}{@Pnx~P*UHC&WA+P2H?=F#r_u6RK0?{OBX+W zW8Kt#o6FCA8x#%9G~Lsol?PyIZ`5G?$5Iq8pDXspcAvDieDBqkvzR3J~pOU|8lFeG>xMLoP7yEQ_k+)s6Jutm-1VUZ&R z9GQax*g+qP}nwrzFU>auOyRbB34 z-*2BY`_7rUd*6sVF%vWMXGLVjO03K`GuMlJ9`tNou{vZf%P2`?H8~b)u1OqFM(n53 zgQdbw!TUWa?>Dt{EH&m1Mv}@WoMP!UpI9xfXSA5RVH0Rv774s?pEsrN7XgX)k}2>` zv~Hc@MoD|jZ@XynbNPy@fYZ76b1nst0iK?dsr_J$F_^KslizDuEJ8$VkdM(EjA6M@9n=m5wQR12ptqgAgrjg??*{bsu zRUC#q6iJfw+I~L^)yq=(T=@lG9Hl&+jL*_>?NMtg_#jAyi&s`n(T_x@mXglTo#JZ9 zPTjOKfKK3+Lb8o)wS{zxw?)Z<3QNpy2(f0?M7tZK5mM|ms-BT@dsa)-F}TB43)Qqj zdwaeWU1{;BYGqn9xhfdU$azgbMR)t*b(9r~XF?vf7|#rkIqQR7%JyUZ4+$Zq)i!~# zWPevncx`k^XLiHAc=)6Eo1(ph4W<1=MOcne;E(e<)}sg}zuyq$%i;ca{;7mjFw>W3~czg}76%2IBkv2W?49QX~wNG$#HxJ;j63lo%{~6@p4? zi0!T$O=+4#@E1KEB3~9UdMknyF`p?p^ds}@7o|YJY%ERLd~AU^WJ-H`XM6PJP<9+_ z=(lN$l?%7Rl*1Ur(Yr;Eo~x)hLM*OPpEpUvwzBq5v zt}Cdw3&%0b)bO&yAT~B@GooST4ZR>pU3wDUrTHs$*2TPyZW3>(ys469s6mt+(S3m5M-)XlUvVx{BLVH;sjqx18g@+S7- zT~v(}x|7__t|{-scMpqo8$)%XRSA$poeM&WQ;WS>QrcZgeDmuXY3<7}Q0+)JH*5nY zOJ6}>h;A#n1C^il@|>k8rg5e^EH}K466R9>#%WsLyq;v2vXrU%n}iezk6J*SvJf=W zTC1lyZ`n)DH0}?XmRV^#Tgt>JqXpzLb=sdje6M-C>NEm%X;;x)V|R%RSs)3l`lACP z*R7n?c`;`fPmcCd^}W(LxUw%X&rja&#kh>7qz%q;8|-C=s;$Hq)%?{g*AfZRP~mHv z&*pTQGqujx0)?nXkefPpVYxh+QF*VXlLj2^_9@Rq^zmmkoT3y%66Lr*7(9NlVSp*4 zEq;=o*7J%3E^QZ`RSraXovFp)-Vh?>-?-~APZLp3GP-H&;%hBNb&+s;cqTfCuO<9O z5vUcAeiJ(E{APsokF=E=Fwkm&96oA2K~!j5t#ba(YB1*!n!$K3l&nQAkMiFXu@#WY zOVtC^TFn?S{C}yB9(}a}*%VFG^MyUNEjm8OsuATfV&X`k2x6&nzvD~6gi2QU<`dSG zMn2Lm$0D0-P<}?OiQ7%S$qHPl##4mAdoWe-RZ8<`fifQy3{$Q*_(z6EJ<`kqZYMUy zpav`jYY-tCjlXQQV;9x#ZBeQ!|EM7*La+axZ`!1&eD-PuhER@G=22xJuT%nA&6-gt z9MUW#K8JOz7c4HrA_4V=XHRMqH1$I$k_PmDGCZp9smG1q3bYsmuNy-znP}H4NHA0%4BT18<$kttPZn1-HWB*0WpaoO(9|TBi5Gyj)rPscr-iXzQrSch zO%%`%S;sf_#1E3C1xkIWm0d6VtO@YRgdyy`@J5Wpw+?F)o5ki&ogFkjG3y0R$8NzG z$@=%d0G4jISl}L9=dL?+a^$?V65q6*4mT7}1Iyv`Q)(7J&SW zZ`Mg=sLN$GwVo?=;n)&EDZeRgj-2`2s}3NPs1!>HR_p1Js2_>N_;8Cn817C| z!tv!qEsCJ(t<>I9?_SaATA8TA)(He@QJ=@~A?-992F#2vWxfJ@tu-Dlk1@Df&&T%P zev(AFxp105J#te(mHz1Bl2)f+i?)`=So_@vxh_c5Q9{ms&yEYeeY2@XJO^~bRUEVs zFaum2LCtq8;>}B&Gd$Yn>aPz1u^_kkUg5Np?bkLbKNHp9b@|W(UNHpuQ!gKXu`?r6 z&Ml;ykNQkmW1OjHL`JMzWASwdrNZDM+AQX8!Tww=D~`4!R$3}~gQkv$5mEVl)@xG_ zd{vAJ$BAyv|BV_VAZ)B9o(Q5^X|`Z-iu%7T8kQdNQ+hq^2`Y6!kcOqHrq>IS|m zs7EgS9FUtLx}8w*CeF&lxFr^v8H;!?aLu=)5=wt9nwBBHCBAWIN_-c-{IeNj&!BuL z@>jzz3~Z?P%Od7U^!kQi&ull;NMlWqC@y8s+Z@Ix<$bgiG*Y^;Qyj%0gzrQ&A=t)v zsa++TuWwdEC#^~JQ}^+BJSk$Y0v^|rv*ZU6<)%)vae^a= ze9J8t%_h7o{YKGa(s#3de2>#NwxsZt45vnL?ARc`(RJuJ(en8Cx{r}y28uN z-x%RMjBp;_7P4&BgiMg!v3x&1yi;P)+lr?VQ-IjuK>2jZD@NSrE`w+IrQ-yG|3O92 zT`mM2+Y)PgO)WX?^V9?wlel0POjtuH(A#88L5&U^1$cA7_%a3iNC z;?rKtNvibOzDeStgSWXIq#sX%yuMt7X-Z7uh5VOFiQ=f;*fhRSBY+HPSTr!uzRu)3 zS*G6Qh?8GC*Fl_>fW#%S5<0-=TBzmqB=1~UjMShXa%|uMmdtitGo&PUa=^f|Yyo3^ z{@>6EpkHjJvh%Y*fsly+1DgAt*8+u~{pkS_xja+#@9drK_% zdmNAtx|L77%9fU&>EKK{L4FfBD^-gud%y7#rOpgIEZPqTc@?6FcDx0b%#tk<6~6~a z#VBFDU{U))>^oBY-jR(M4sNuBuVHd}W~=G4dzRS%l# zSJTb{h98}%NL?7svvjx{C8phFQ5whNbRy`pS)mp2)9B)TMYcu|D&`;|yUPA5(lx>4 zVWZG6cZBf@z8uByWApLe&SjEsST#2uLrRZb>db?bG zBlx%X98o2&UPoVu`3R7fO`@krUy_)4GDg*HD&5hD!WF9ZP!nF(h8;gZ?7K{wrn}x8 z;|^nSIvvkJxTd%G@`hMEBH)x)MU6J1sFevG=k8Jlg(6OP%*p#C8pL?u8cO4ici`E) z54%#VxR$?s(P8}CB(k$AnXf#owojY}f5Njt%lDt@L+9R3A$!3}*`}ltRe|SSK96? z&Dv$&TNh!xfGn3fn1}oq=G8jqO%uQR<0%UY8%N;)C2>GY>KS{Dly;4I8nNccZ7j9* z@@j;j8aR?vNP0`FxaInvJ=C_)>{9m|y6sR$D$-J2jD?9@6U%LhC{)Z1fN;*WY;0{8t-Sx8`f&t zJ(g?f>F;3MBeKK}RH!$@tm%f&cygiVOIXcYY5h(^r_KNxy+vwBE$vC&xD>nj}V$~QV>##HeFB9JxZ z>QG#}m^UsZ^Ka(e{HN9HnJMwa6r2n$87}upuXZ2+yTWxl7#&~l6|WF0 z*a>_e2ujmc4yPljHFS^_lIgMjE9&Aw*v7^q#yYA#;s%C~6`e?TapD)VymGaju|k{x z%2m+nlb*I$sZs0pJ@D#m?jMd}+F zQ7mM_uh@rK0K2bb2Q^X3ZNW(feGB)r>0p-Eo;{`Ty4y^V%oMNZ3ec*t!p!t|Um8et zyg;x|G$n!YWYx>}S4nwv~lXMWbR$hAN*dXIwl+3|$RGrank$-#Q?BRN?qWGluM|{%!mMj~Jv`ugJ z)zh7D2lRo+*ZLM*;(ets$-EFdtJVl>JL!6kdeM00!5C&{LZgF1>l;Q@A4 zn0VGUoG@CfNBg|!pDEC?ZF@v{uir%Mcs z`Na#?A?lxFubbu)_rBezpx2mpY3csQ-mH2&8@y$Z;PZBAf(XE(Q9izBsm zEzMcnei9VeolzkCa*lA#1RNz#c&$xxHK+%;`$29lqoUgAG;a8yZI{2RX>V`^2Hl43 zecE5ZjkdtDL?Omt1!F)7A<%%{?hj85eh(?xU(R&a8AHR%1J}qWBE0@prRtI^n2u1k zjpX=S8>mMx{Ag(zo+4kOrsMJQ48`bHjT0qK>Wfg@n2D`oo1&nnd6U7|675QS3jY-| zU3>vaIg;;60jbW+BoK`bF{!R~$;TpZML_G++W9Aro<~s(p<4K2#7 z!#@B(fTzA+bB<3L9X!KtX!Jv|4NtjEL@ExAvC?_PHfAsC#j#6l<$(>02Ai-a(T*%7 z{fq&!)slq7Ykh_}&ho4!L_4$CK=O9b<|uY;$KV{tXGKG=NS>nMfl2RJw$|3j8?tl* zct@$;J1Tgddjy-{L5Ogik~-x_UQ6}{IC=W!$|ndoEIP-XEbNJZKeJqHG-qkkZ|R)6 zTWZ*u6FK;arQ|r1)W_vb+T)2@mim^D{lmQW=4cfgb!+bsdKg;3c1nuSdtVoa6 zQ>qQ9Qc~i^rII`vrB7>VjLElbEE2!s*tCS@5QnM6XZHSp_iz!H)kxTl16^RQyJgZqp0>HY_?d9@8^IV zJ=W{mIdF`P(WRELjCJQ9m;1p62;vh-=@HC?J3ZGX$tJO+?nN0IKzv3GRtS+604h&v zv?*h~lmHQ2P*B^71j4KtLz4Y^T$MB#hI7|T5?zA4-j$F62$-TtlFqU3V_#a|mT6>5 zXmUTk3%MZAx{?OC+4FurI#(7uo5IEQ8|8+)5WndVLQOan4;hY^&ozEkAHP>yTR?ZR zAW<1#Ug~Yr1+YWeIZzpk@GQq2LigKlL6^fvgBwsCG>h(_Cpd5UQ0w4mgP)?Oj+V|E zsCD=jB;KGK%bi7kN=8>>FTDW?Krszzh`|ZAJ|Of7XTj}FFn(&aJEoRPmSS}*3L{s# zO)LnQC6gSNIDM6acH5h+LPR1CJzvolVo8ewDyF?Ul@KMaZ|me9&|4E*rFiG3xKBl_ z*?*$J-YQ2fUBf@89nAW^Z+YQ?AO_uAvmL$AEmndKgJIKKn zj>C3MvnG#~1di2iFCQAlVCpEN^a*bIglkw^SK#7hs2(P9p;wb4LK8m|#~8)y&@t=x z*1O}|TN>S61un7316{!EL}%BM_;>&50+udmfnm_KWt`aIW&WeKFg0b`76Wo5l6Z6& zY7=^Dp(IKFS$HGi63yumA#EFNargh~-^Se>}ZBpL?is%f;1L zGcd{Xq%AM4t$W)|KH>^eZ`aN|PAp9mWw__TG^0$Cqwy{& z&Xzj6UNSJx`e7gqIlHdA!iU0z9qCu6^2~O%AXWkT8ehxUkOpx?6vw0dy=$1} z^8C*^f>-3a))20y3Vd>w#)J?}x0iZ#M#@7onr8FJ*xKRJd*$UAnzZ9}Z=_?Ttppe4 zO8n;g_b!K8-a7F&PV|TMLokmpxy>%sTWfRlJ8A_U^<=Fcb;VzZD?F78W&2qYg=Ei; zTuOzTL_jiyXIFnz%r-g=#4Xsf`Yfz%$!#rBYZNlr;gz9b-Nt2Z`i)UCeV3a;Q-@tn zhGD1}{DogkA^5iITg!ph>=zWBuiSff4}LVkG$p~aF@#U&hE@|TY}ELv1(nk!-mDR0 z?Lzq?mwMV7Rb3JnES~kC8QUsx--l7->GBLb>WYyRn|^gk?d8l>+AQp<(UTcZ6)(h( z5<@J96XwI(dZRmSi(NTzqQhrcp^`ivx5o++VnG&j!__2${n2Z-S52a7&Jd4)MlmY( zWvvsthgR|^gd%ZX#yvmJ;HFg5D9_m3kq-&{)v*m;JwS%^>tzAxcrV#)(AvGL_zPeN z@K&8Y(Jr}neq+(UI;#2#g7bfP%zmcT{$e9KUh(rw_8YeLA1VImte~X=-TnBa_>5Zl z3y2kebf|+MAmQC&_41S^syPhTj1Ak$i^ANb_ zHKvhYu2?4^^me{2k);Wxij1N2Q%~)GFsb2xVL`U$vhU2)bU-b%#&`+>sAjDs=sezq z8S8k=vgNrWVYom%0V|6XFPzwbJ);&NLvY>wo!EkL0>Y1S?9Wr9L&#^b2P>NKfcE}J z^atT3J)TWha4H-8tk@k5YqeMLMpCHu*%xJMBBeNKM>0libv+qnJqDPzEXKsMmDZT}C-U7;y!b~^ z=WuPENzeMWh|xi{iRHh5WfSNUviHku?kMf-naU(Mi;NQ6Nuzq0CnHm8Cz9Tj6or`3 zHij8!)@})%bpCMQ*|yRnP`NDuD$M@=@WbrvS`52wOau0bGP)GYW)$5*wl-jXYL@CY z_@L#DUmi1k*|d(LabX&$XApq&Tu@KTfM8{a7_hoRO<(ikeoh;!ay zizURpU`>JD;Y#ys@5z}>>vqmPRBvL>oNG2yO`7-W(!;db#V`*?r4`~PTJyLdV>@h~(PN~SXyke@$sf6T? z1k}}2l^;qgN|5Bsa^$tu)uu*Ar1Y2uRsYKpnB*cGTr?XAiN+i5W|NNPf>ZL=BxX)o zlCZ-K4N6n&XqJ0N5gsHA?~!7*UObRed>GaTr0}gSkv*mK)NKoqwv)5UDNUnC&Qmc< zGm8aO7sMviqFMADO>p|zmV0nGVy)rwj==Qz z`T4drW_V{lSepih(-6NWXGK1V-iD*+?13oNe1fonUV?(7Vp6tYzl%blc@ zOL-ey5F*7nd8f56P9SL{0w#rBeqENd6aK4UF<{3gPqNlC=^5stfqJ2K6`{SLOp7IA z50;Pmt7!3K7sUim`2CDOnb|Tb=8!+ABH*+Ib9W(^V)yGGXF>&n{AbB9SuX7Y^H9t^ z-uTZd7Ww({bA|fs`aaFAzX0&vZ3z*r3D*bLmrI`fz3lgDe!JdJbLS5;)BI&d9SuP>OC%BCDL6Kx+StAp#b^dIHB-gt_AVS zm)sf2H*Su_DN6X5cr8Zeb1DyS%6vu5@hy{t%=nttl(*qo*&`C--0<@|g96-<<8#eG z`cHe9%~TVUF9F_B(?aBFlE3&@?La77SOR5y_$9CNV-aF$Lu|)b81_f@M|ag{g|s&R z0J^1|ph^{1?rxLFaR?1RUFUo;3vCYw+A)rR_`Bn1ZE!ET!RbA0mM-Ba#IrY|Vo!uo zk%2?7{-12dBjO><8ti#^7&*TiyvmK1&2sZf1j?G(e_|VkK4Q?t29371CIHIqsBx=Q zQptfRqTn@y;e)j{stEZh-$l6S3x{+L^H60TmA!#U=eq7u5So4ZVPpxA%u3#P9yhEZ=HCSIPggooayk=t@{=DW)d_7*vl5qQ&h(Putt+Mej4KB4@hr|%S`t!mptA5NBjX;cQ5F04pDrZAvoLX$Ig3!` zbnzeCSAks170`TC@ZVVK&=>MNyTd!p3?$$)RsW)ASh!dg3j7}9h9UjV5L46ChTo%) zD~?jZw%=ZJvj5d$#l?TI+NH@tAF1rwgiIh`s&-+t3gDU%6Ss0K zd+c^h!2A~YyYe&`W#kG?%0{6>mB^vaVxPXu79rP`eJMVdfk)a;5Q^}kvZrRPX2YA+ z7#><+QeCb(5o=rJwt4)A8zp~@KwX)?s09`1TV)$bX>(h0zfN$LFKA5?`pg28wlRH;V3 zwOw2@h*Thgm+f(TUQzC4w$^JL@Ue$c81|vMHF%UQSPO@Y6&rzP2Mu+%a$+fuNsK$u zO|7rQ2&lQcAfiu*=`Ec~YGmLa)cKMOYYOm=%1nMS2C#Q$O0g0b@xmordZCv7^A-}D zb{$YLu!$}wNh=E1jxlbPa>$=HzK=QWZ~>xhAyG-TTe=Ue5f6Sww2HRQ5=rmGIn#nM~Qyw9$46LDU>{#$*q}k}f;>66rhuuze+$C~{6%q>)CU7CBDP z#yHH48FdC#-QE=8&a@52WQlgDs8f2q@q-JvfMObrth1Z{;O)*TnWQLn6XT%EsJ?m? zKp_*OCzoY1(1(z89Oh0#Xb4xw8F7@k(Ma`q!AP7^Vgk}qL3qpTX%&prx?PrxRDVU3 z5wP!PTY@y^bVYaOjz?fHP4LIA9AJ6@;0^G*NcJ=8RDW(M@<)!ow*aAYB@AGE>eY1p3mBAFe*2O57ciwR^|jJ0 ze}LjAYkopo>Tj(@c?aD`QG$^ILi920Qh#mz~3&Mn%w@ zE7gw6>!!j-X#Xe2XWhR(GvvMQMcd~YV4=W5|2N`nDzMbIP(4bUL(&$sbM2;m@I)|b zk=gcx%qJ&tgq=kyn;fHjm-8rEOQbN3z<`|_D%u24kIcF)ka5=Wl*kAhqX>DY=QboJ zVZoy)EcWOk=x-(g&}hpODjlQJgDFJQ1QL4P}QFHi>5$%gRsFzB2^dW zku8lt(VOpHg#AX2Hmer)UQS*bPq>!ss)ZYNP{+H&hZSeER?0|lWk25Uwd$cb8HJi} zmd*H=fJk7x)F2Ecm(nZVi_d`d+rU)Y`>43;s_5{J9<<>d;Nn7DZeRy>0EbMN|1r@!dM} z&S*QI60eoT!2{fJawk%)B+q10Urj)~W}5u~WsU-G%_5Ty5YS_!$nFLkZEKOtEYj!4 z6%dV2^jA_$Jb#l?w#C{e50hX!x-b2NQ1rMMTosL(Z5B}kdC zb@tuvD%x@tRkV@`EbvdouIgCRfZ0T#gq#I?f|2#l!5J`vgIL$^VZVP!sH*yJO5otP zN3IaB_48Gar9;c(J8S9dv&N%CvcRGx>#<5HpdMbKXRHjpub1|l8?+yfI;#)oL_@UG z2_7!3QfOXs;L>$nH~KnIHF+zplz=kBM-{I|Jy3>M;?_B+cWlDWIVdJ`b11B$vWVS@ zKq=YUfOVe&RH2+#xRWaqBZ-%03mHw8CMFr2hn)_n)k^X2&6cW^vnSDYJAX_&fpPA= zDQEv8R`Oo7g*IY4Tu5ILn8tNT*6_J?NRlg!D9QaXug|N5&)`v{ru8=V7jVi#Q}rC` z^$bx*vL84?182I@Hc26N9q>}~^O061+!In&s(J5zoIuFkAsxj8CC6Enqd5b-)rkUx zI9SNWw{Yq%RGn)W;R3PPyIs=k=uIseNlRHN#qHa2S+U7jcTM82v0V){Y{a>DXW-o# z-|u01z)M4M=PQbMNF)zYFCBzNbN-9Z_4mI=gA}rC>uAPZAbY7wR9^7YEquSTM>Hsn83*O%W1C(VuL#l>KSY5L0%o{=%y)`J~8%7 zg`pUvSP6Sq);1YCd>`v{o6lma4HG|fW{JZcX6bT$tCtHO!HLni)pU413rg(bR@KTj zH~lsO;i@gk{u}C<%o<6bcU1={@RN>r(F^Ix$)g~fqa4-U1?pC^v6BwksuZ(=os-97 z*r;=~czA3PL}(0x)fTlT1?2!FHVVZ@sCcP>r})=MfnAI;7CGi9o$;b%cjHaDQgu~+ z3Yg;7&JyP#AZg1KcfQK@x_&nbS_mh)zWC*P24`+meyq}<5phb4E&Cc3YK!utLdQ0+sYqqjBo0^sWA;0q@1QQ5>&ZI zn`7@hD|l{ZG*|%mm1xq)|Q5>etv?3c%Sjs4!h>@{81cIdY*2zltrpT-Xx*UYJ_k%^`|RN#S(& zgcAtV>aJ+^2H(rxIWE(v&oJfj66r=U7OPVwxkTb$z%sP@ zvv`U`+G6vgUladPLxJdT-=YhmpKk(0pG)}%O5z)Gr3VHU8~@oUUw5e&lxOua{U>5{2d6D6|1e= zc_I5jE7*CsEW zGQ@sJYOA^USg+cg_-9*SerC!oXxeoY{B7fdk2>Z}UTNcU1y|^NC-GJE3T;blpbj)N zVgwt16D+?Jh}AR7c}RSts_rjISAax)n`MdngPbaA*moB<1gke*Mvjn>D_u&%SKHXrWfxPVEZE^{#F~OrG3s{MjeZY9P zXWDRT`;&103wWHh^|~vbb~H5kIRbji(Fpio0O^Hw5UD2*TLk@(c__TEV>2_Dh?1zu zc~CDl4pfdJAL91O63Q>nK_sc4FH^ya!7;y$(} zCFxEX#HLFwBZr}M=d}{Iq2!@6KaI={nQI}IIF+eT6w@|qe3BbXg8vBOto)T*g+-Vu zF};F&lj#W2TgV}IcFofC!tXULpHXm*l z{w>=-1>oG$Wt2;YUa97aHlNHZmBYfS*2csd9RN-EwzFIk`$KaN@uW_cRBEZE%h0jN za%a|+)*k(rX;XWii8@?+C9RE^V{qI@@J0hGfp2Hfp(Fw0e9;Lu@JEK9Q>igC=5x>)H;sXG)$5TMbn>K9%W>AY_Q|1f^QI&B8eYgh%j^& zKvQHaFsrWjjhw?r|x;oa9pv%I9M3{Vhw<^#G647TDN{-aw+eG6}KyA>`ygnl{a zSRH*~o<+6~*Q(Kj+c}$Il;>C=LRXR_RB)*TzbIsqsPFig^?s^~x+>qzT6LP9eUZCGHi; z-n&GKNihlFc4rrJr?HEEOg&26;n@>WM?m47dc%wJ38M`KGhE{ zL?f|KjV(`vn2yaBR2#3C24{R#!Xlx&b_!G;TC6^B%o}^#;%~(Z`)dJL`y)4p&N}wO zru4aoNb4MF-ZgN@Z1{FkN23R&Ivd^C3$<8tH|Pi`(BN_SFVx-`aWS!ZVFP>mnoTTL zk3I!XZHpgG&mJkC+6EWG_4J=U%N5SEc+)y@I+niWS!C#Khr(fnx8wI?=a=X}KsC%T zOB!6mr&Ax;-5PMT=(0$%uFFWLL9K49OxJL>?IYfd)N#FqSGZDzPq+5)ENPF&`q_GK zwr9zf{4q1M-KQnwbk~7|_}RT!%TealcrvqNofmU1%Ws*PvZ>Qt_G835W6zWeE}xbV zdWLJ*kZECXc(|*`dNo!pH;V6@2L%f?Y24EJcD~(5&VzbL55dwvF~XuQx^yd~pYra1 z?0&RF#hsbBYq7z)tdlkS}j() z?2Rs+NBlhBk-xPMNy^Zv{M`54?W*LsX_|G_Hez{R-_ezea-q)jT&}9k1?BNYtk7+P zy=CDI?QJ!0C$)4{`blaQkX_!%wqw3lns>^zp}n$68G6OyhYcR!PHT-5;~-JP+hswv zCw%}<1m8wcn@cKrp({5xZM)b*lK4?|Fcoec;66x~*l@6RgobCliamxOaQ7x&g%$nBPDx$2E_otjSJy!V}k6s>CaRPfv8LM<^);JUr{IWzUwD6Yq zjFhtG0;FW^hgcpibKk1mg>MuajkX&uHsW)P37jF)*>OD%SFp_D7;8px^oM`=G3n`6 zg~^EIK>WW;rk<}3dezd*PPhs)4a!8Kb@G6YigJ~Wy9g!0Fr>G?#o2si+Z@YvvtLZl z3)~eeCpI^OOr*`@eH9 zMF-&_K+f^kQt&59^dCaTA@(M~BgUQYzUzO@bQ5?Ja}f|M7Q7DvUj<>Fsm2>Grsbkw zRcL>jhMr3;2$c#>@PLfsXtr*Zja}%3k$;paCt6>L2Eu~A^^h)JK64TM1;hokKWrG= zpCcyO`yTDSkX4Z5T=Z7p{C zHST{6d+_gYgV=8WY@PiDyfp#ICi~1a>-|Sg#eqJqtn$xyZa~8J&X9TIHwNA&RA+nQ zPuWpIJ?|y$e{D0U%)LF&M%s;kwpWz({^H;k_^MeJxLu!vfLm#U-u=4PK>Z{d=P+Z( z`6ST<_C|anb3^2#>6!`u$Ub@>0OmhY_k4age82mez7SZ^e;b|4e_G1_=)4br z)BP92q+D6=gJea3;$~a7u_ECL2SybbAgN1|2?7Nk)VlBt1rC46#`eEbAxGtnvA+!g z97)Z9ald3s-&jewuPdXI2t{TG)P*jH%PUw~>40QEu^uFQ2? zY~)hw{GC8-U;EdcJ!>Dv2UDGJ(3l*HbA0m>?r90P-0DV8ZMBPA*oIzl>7T^%X)Ac8 zO^E~fB4&eIEQi;?*|~cj+%`sknKi!;|0b^}>)pGK`M-cCGvJLHznK6Wt6Y#d4#i=+ zPrMQ`@)JNStM z-_!F}6PVZjf0EF}>fJ?lqCTRloyM2P>G0dpca8$cw*PUSpAas*Gj=zjgvY9xG_G8Q z2MQhJM1Ss~q`f!YRv!OTnicAR;F58A0e=C7R(;F%f~Z|xYcbD1$VbzR>tE3&A9DYPxL1gbB(yx3b4P`^de=Dj~^4F&XMN;WdOK9Iecqe<7J73|<_i zrirlM%^>{eqj91jbN4P-S~N6DHrNm zp!!i4l%C5t>jbaCk(KU#m~>5uP<^^B00dBZ+AEF@;``{j<&MSOTHWgU>eu76gB5T( zhT_8*ygLZ!$qDo=|&ODi}}DpDELtC_(x<{ z#Fj7T9MesUJ-c%2g8MkNLR-W3i7R+BLWu%8)-EbxybTBOY&OTUU5BuD(Z(ef6^?*r zVq;{25o@rmHPR^dJ9^2!3V=mYz>*bY+;7GIknrUz)c(^+MXgltzor6M8XFt`*B%0Y G*Z&)7PHANT literal 0 HcmV?d00001 diff --git a/plugins/textool/Doc/TexTool.html b/plugins/textool/Doc/TexTool.html new file mode 100644 index 00000000..d8590034 --- /dev/null +++ b/plugins/textool/Doc/TexTool.html @@ -0,0 +1,123 @@ + + + TexTool plugin for Q3Radiant - documentation +
+ + +TexTool plugin for Q3Radiant
+
Introduction +

TexTool is a set of texture tools for Q3Radiant. It was designed to help fine-tuning texture placement +on brushes and patches.

+Warning: +

The plugin needs brush primitives texture coordinates to operate. If this feature is not enabled in your project +settings you'll only be able to edit patches.

+
Basic use +

It's a "drag-n-drop control points" interface. Select a single face on a brush ( with shift+ctrl+left mouse clic), +or a patch, and do Plugins > Q3 Texture Tools > Go.... You can select points and move them... if you are editing +a brush face, you can rotate the shape by clicking on an anchor point first, then dragging another point.

+
+ + + + + +TexTool screenshot + +
+ +

There are also a few misc keys to help you. You can + +right clic + move the mouse to change the point of view +and use + +Inser and + +Suppr to zoom in/out. + + + + + +
+ +


+Appendix: keyboard shortcuts +

You can use the following keyboard shortcuts:

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + KEY
+
+ + usage
+
ESC
+
cancel the changes and hide TexTool window
+
RETURN
+
validate changes into the editor (also resets the view)
+
INSERT
+
zoom in
+
SUPPR
+
zoom out
+
RIGHT CLIC+MOVE
+
move the view
+
LEFT CLIC+MOVE
+
grab a control point and move it
+
RIGHT CLIC
+
drop down menu
+

+

Feedback, enhancements bugs etc. to timo@qeradiant.com

+

+ + + diff --git a/plugins/textool/StdAfx.cpp b/plugins/textool/StdAfx.cpp new file mode 100644 index 00000000..c6ef9354 --- /dev/null +++ b/plugins/textool/StdAfx.cpp @@ -0,0 +1,28 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/textool/StdAfx.h b/plugins/textool/StdAfx.h new file mode 100644 index 00000000..2a2da9c3 --- /dev/null +++ b/plugins/textool/StdAfx.h @@ -0,0 +1,154 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// stdafx.h +// precompiled headers + +// standard headers +#include +#include +#include +#include + +#if defined(__linux__) || defined(__APPLE__) + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L + + +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L + +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND + +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 + +typedef struct tagRECT +{ + long left; + long top; + long right; + long bottom; +} RECT, *PRECT, *LPRECT; + +#endif // __linux__ + +// plugin +// FIXME TTimo: drop this +extern "C" void Sys_Printf (char *text, ...); + +#include "synapse.h" +#include "iplugin.h" +#include "qerplugin.h" +#include "mathlib.h" +#include "igl.h" +#include "iselectedface.h" +#include "isurfaceplugin.h" +#include "iui.h" + +// internals +// the implementation of a IWindowListener interface to use with the native UI +// TODO: move in it's own set of files? +// NOTE: I'm not too sure about the bool flags being any use.. they are supposed to tell if we handle the event or not +class CWindowListener : public IWindowListener +{ + int refCount; +public: + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () { if ( --refCount <= 0 ) delete this; } + // IWindowListener --------------------------------------- + bool OnLButtonDown(guint32 nFlags, double x, double y); + bool OnMButtonDown(guint32 nFlags, double x, double y) { return false; } + bool OnRButtonDown(guint32 nFlags, double x, double y); + bool OnLButtonUp(guint32 nFlags, double x, double y); + bool OnMButtonUp(guint32 nFlags, double x, double y) { return false; } + bool OnRButtonUp(guint32 nFlags, double x, double y); + bool OnMouseMove(guint32 nFlags, double x, double y); + bool OnKeyPressed(char *s); + bool Paint(); + void Close(); +}; + +#include "2DView.h" +typedef struct +{ + float data[MAX_POINTS_ON_WINDING][2]; +} CtrlPts_t; +#include "ControlPointsManager.h" + +extern _QERQglTable g_QglTable; +extern _QERFuncTable_1 g_FuncTable; +// prefs globals +// NOTE: these are used by the CControlPointsManager classes, not very C++ish +extern bool g_bPrefsUpdateCameraView; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERFaceData g_CancelFaceData; + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf + +// call to validate the current changes into the editor +extern void Textool_Validate(); +extern void Textool_Cancel(); + +class CSynapseClientTexTool : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientTexTool() { } + virtual ~CSynapseClientTexTool() { } +}; + +extern IWindow *g_pToolWnd; diff --git a/plugins/textool/TexTool.cpp b/plugins/textool/TexTool.cpp new file mode 100644 index 00000000..01d88901 --- /dev/null +++ b/plugins/textool/TexTool.cpp @@ -0,0 +1,962 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// main plugin implementation +// texturing tools for Radiant +// + +#include "StdAfx.h" + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) +{ + GtkWidget *window, *w, *vbox, *hbox; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// Radiant function table +_QERFuncTable_1 g_FuncTable; + +// plugin name +const char *PLUGIN_NAME = "Q3 Texture Tools"; + +// commands in the menu +const char *PLUGIN_COMMANDS = "About...;Go..."; + +// cast to GtkWidget* +void *g_pMainWnd; +IWindow *g_pToolWnd = NULL; // handle to the window +CWindowListener g_Listen; + +// plugin interfaces --------------------------- +bool g_bQglInitDone = false; +_QERQglTable g_QglTable; +bool g_bSelectedFaceInitDone = false; +_QERSelectedFaceTable g_SelectedFaceTable; +bool g_bUITable = false; +_QERUITable g_UITable; + +// selected face ------------------------------- +// we use this one to commit / read with Radiant +_QERFaceData g_SelectedFaceData; +// g_pSelectedFaceWindings gets allocated with MAX_POINTS_ON_WINDING at plugin startup ( QERPlug_Init ) +winding_t *g_pSelectedFaceWinding = NULL; +const float g_ViewportRatio = 1.2f; +// usefull class to manage the 2D view +C2DView g_2DView; +// control points to move the polygon +CControlPointsManagerBFace g_ControlPointsBFace; +// tells if a face is selected and we have something to render in the TexWindow +bool g_bTexViewReady = false; +// data for texture work +int g_NumPoints; +CtrlPts_t g_WorkWinding; +// reference _QERFaceData we use on Cancel, and for Commit +_QERFaceData g_CancelFaceData; + +// patches ------------------------------------- +bool g_bPatch = false; +//++timo we use this one to grab selected patchMesh_t +// FIXME: update when there's a real interface to read/write patches +bool g_bSurfaceTableInitDone = false; +_QERAppSurfaceTable g_SurfaceTable; +CControlPointsManagerPatch g_ControlPointsPatch; +// data for texture work +patchMesh_t* g_pPatch; +// we only use ctrl[][].st in this one +patchMesh_t g_WorkPatch; +// copy of initial g_pPatch for Cancel situation +patchMesh_t g_CancelPatch; + +// --------------------------------------------- +// holds the manager we are currently using +CControlPointsManager *g_pManager = NULL; + +// --------------------------------------------- +// globals flags for user preferences +//++timo TODO: this should be retrieved from the Editor's .INI prefs in a dedicated interface +// update camera view during manipulation ? +bool g_bPrefsUpdateCameraView = true; + +// misc ---------------------------------------- +bool g_bHelp = false; +//++timo FIXME: used to close the plugin window if InitTexView fails +// it's dirty, only use is to prevent infinite loop in DialogProc +bool g_bClosing = false; + +const char *PLUGIN_ABOUT = "Texture Tools for Radiant\n\n" + "Gtk port by Leonardo Zide (leo@lokigames.com)\n" + "Original version by Timothee \"TTimo\" Besset (timo@qeradiant.com)"; + +extern "C" void* WINAPI QERPlug_GetFuncTable () +{ + return &g_FuncTable; +} + +const char* QERPlug_Init (void* hApp, void *pWidget) +{ + int size; + GtkWidget* pMainWidget = static_cast(pWidget); + + g_pMainWnd = pMainWidget; + memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); + g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); + size = (int)((winding_t *)0)->points[MAX_POINTS_ON_WINDING]; + g_pSelectedFaceWinding = (winding_t *)malloc( size ); + memset( g_pSelectedFaceWinding, 0, size ); + return "Texture tools for Radiant"; +} + +const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +char *TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; igetHeight(); + g_2DView.m_rect.right = hwndDlg->getWidth(); + + // we need to draw this area, now compute a bigger area so the texture scale is the same along X and Y + // compute box shape in XY space, let's say X <-> S we'll get a ratio for Y: + if (!g_bPatch) + { + g_SelectedFaceTable.m_pfnGetTextureSize( 0, TexSize ); + } + else + { + TexSize[0] = g_pPatch->d_texture->width; + TexSize[1] = g_pPatch->d_texture->height; + } + // we want a texture with the same X / Y ratio + // compute XY space / window size ratio + float SSize = (float)fabs( g_2DView.m_Maxs[0] - g_2DView.m_Mins[0] ); + float TSize = (float)fabs( g_2DView.m_Maxs[1] - g_2DView.m_Mins[1] ); + float XSize = TexSize[0] * SSize; + float YSize = TexSize[1] * TSize; + float RatioX = XSize / (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ); + float RatioY = YSize / (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ); + if ( RatioX > RatioY ) + { + YSize = (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ) * RatioX; + TSize = YSize / (float)TexSize[1]; + } + else + { + XSize = (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ) * RatioY; + SSize = XSize / (float)TexSize[0]; + } + g_2DView.m_Mins[0] = g_2DView.m_Center[0] - 0.5f * SSize; + g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + 0.5f * SSize; + g_2DView.m_Mins[1] = g_2DView.m_Center[1] - 0.5f * TSize; + g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + 0.5f * TSize; +} + +// call this one each time we need to re-init +//++timo TODO: re-init objects state, g_2DView and g_ControlPointsManager +void InitTexView( IWindow* hwndDlg ) +{ + // size of the texture we are working on + int TexSize[2]; + g_bTexViewReady = false; + if (g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 0) + { + g_SelectedFaceTable.m_pfnGetFaceInfo( 0, &g_SelectedFaceData, g_pSelectedFaceWinding ); + g_bPatch = false; + int i; + // we have something selected + // setup: compute BBox for the winding ( in ST space ) + //++timo FIXME: move this in a C2DView member ? used as well for patches + g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f; + g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f; + for ( i=0; inumpoints; i++ ) + { + if ( g_pSelectedFaceWinding->points[i][3] < g_2DView.m_Mins[0] ) + g_2DView.m_Mins[0] = g_pSelectedFaceWinding->points[i][3]; + if ( g_pSelectedFaceWinding->points[i][3] > g_2DView.m_Maxs[0] ) + g_2DView.m_Maxs[0] = g_pSelectedFaceWinding->points[i][3]; + if ( g_pSelectedFaceWinding->points[i][4] < g_2DView.m_Mins[1] ) + g_2DView.m_Mins[1] = g_pSelectedFaceWinding->points[i][4]; + if ( g_pSelectedFaceWinding->points[i][4] > g_2DView.m_Maxs[1] ) + g_2DView.m_Maxs[1] = g_pSelectedFaceWinding->points[i][4]; + } + // NOTE: FitView will read and init TexSize + FitView( hwndDlg, TexSize ); + // now init the work tables + g_NumPoints = g_pSelectedFaceWinding->numpoints; + for ( i=0; ipoints[i][3]; + g_WorkWinding.data[i][1] = g_pSelectedFaceWinding->points[i][4]; + } + g_ControlPointsBFace.Init( g_NumPoints, &g_WorkWinding, &g_2DView, TexSize, &g_SelectedFaceData, &g_QglTable ); + // init snap-to-grid + float fTexStep[2]; + fTexStep[0] = 1.0f / float(TexSize[0]); + fTexStep[1] = 1.0f / float(TexSize[1]); + g_2DView.SetGrid( fTexStep[0], fTexStep[1] ); + g_pManager = &g_ControlPointsBFace; + // prepare the "Cancel" data + memcpy( &g_CancelFaceData, &g_SelectedFaceData, sizeof(_QERFaceData) ); + // we are done + g_bTexViewReady = true; + } + else if ( g_SurfaceTable.m_pfnAnyPatchesSelected()) + { + g_pPatch = g_SurfaceTable.m_pfnGetSelectedPatch(); + g_bPatch = true; + int i,j; + // compute BBox for all patch points + g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f; + g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f; + for ( i=0; iwidth; i++ ) + { + for ( j=0; jheight; j++ ) + { + if ( g_pPatch->ctrl[i][j].st[0] < g_2DView.m_Mins[0] ) + g_2DView.m_Mins[0] = g_pPatch->ctrl[i][j].st[0]; + if ( g_pPatch->ctrl[i][j].st[0] > g_2DView.m_Maxs[0] ) + g_2DView.m_Maxs[0] = g_pPatch->ctrl[i][j].st[0]; + if ( g_pPatch->ctrl[i][j].st[1] < g_2DView.m_Mins[1] ) + g_2DView.m_Mins[1] = g_pPatch->ctrl[i][j].st[1]; + if ( g_pPatch->ctrl[i][j].st[1] > g_2DView.m_Maxs[1] ) + g_2DView.m_Maxs[1] = g_pPatch->ctrl[i][j].st[1]; + } + } + FitView( hwndDlg, TexSize); + // init the work tables + g_WorkPatch = *g_pPatch; + g_ControlPointsPatch.Init( &g_WorkPatch, &g_2DView, &g_QglTable, g_pPatch ); + // init snap-to-grid + float fTexStep[2]; + fTexStep[0] = 1.0f / float(TexSize[0]); + fTexStep[1] = 1.0f / float(TexSize[1]); + g_2DView.SetGrid( fTexStep[0], fTexStep[1] ); + g_pManager = &g_ControlPointsPatch; + // prepare the "cancel" data + g_CancelPatch = *g_pPatch; + // we are done + g_bTexViewReady = true; + } +} + +void Textool_Validate() +{ + // validate current situation into the main view + g_pManager->Commit( ); + // for a brush face we have an aditionnal step + if (!g_bPatch) + { + // tell Radiant to update (will also send update windows messages ) + g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_SelectedFaceData ); + } + else + { + // ask to rebuild the patch display data + g_pPatch->bDirty = true; + // send a repaint to the camera window as well + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } + // we'll need to update after that as well: + g_bTexViewReady = false; + // send a repaint message + g_pToolWnd->Redraw (); +} + +void Textool_Cancel() +{ + if (!g_bPatch) + { + // tell Radiant to update (will also send update windows messages ) + g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_CancelFaceData ); + } + else + { + *g_pPatch = g_CancelPatch; + g_pPatch->bDirty = true; + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } + // do not call destroy, decref it + g_pToolWnd->DecRef(); + g_pToolWnd = NULL; +} + +static void DoExpose () +{ + int i,j; + + g_2DView.PreparePaint(); + g_QglTable.m_pfn_qglColor3f(1, 1, 1); + // draw the texture background + g_QglTable.m_pfn_qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + if (!g_bPatch) + { + g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_SelectedFaceTable.m_pfnGetTextureNumber(0) ); + } + else + { + g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_pPatch->d_texture->texture_number ); + } + + g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D ); + g_QglTable.m_pfn_qglBegin( GL_QUADS ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglEnd(); + g_QglTable.m_pfn_qglDisable( GL_TEXTURE_2D ); + + if (!g_bPatch) + { + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + { + if ( i < g_pPatch->width-1 ) + { + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] ); + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i+1][j].st[0], g_WorkPatch.ctrl[i+1][j].st[1] ); + } + + if ( j < g_pPatch->height-1 ) + { + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] ); + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j+1].st[0], g_WorkPatch.ctrl[i][j+1].st[1] ); + } + } + g_QglTable.m_pfn_qglEnd(); + } + + // let the control points manager render + g_pManager->Render( ); +} + +static bool CanProcess () +{ + if (!g_bTexViewReady && !g_bClosing) + { + InitTexView (g_pToolWnd); + + if (!g_bTexViewReady) + { + g_bClosing = true; + DoMessageBox ("You must have brush primitives activated in your project settings and\n" + "have a patch or a single face selected to use the TexTool plugin.\n" + "See plugins/TexToolHelp for documentation.", "TexTool plugin", MB_ICONERROR | MB_OK); + // decref, this will destroy + g_pToolWnd->DecRef(); + g_pToolWnd = NULL; + return 0; + } + else + g_bClosing = false; + } + else if (!g_bTexViewReady && g_bClosing) + { + return 0; + } + + return 1; +} + +#if 0 +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (CanProcess ()) + { + switch (event->button) + { + case 1: + g_pManager->OnLButtonDown (event->x, event->y); break; + case 3: + g_2DView.OnRButtonDown (event->x, event->y); break; + } + } +} + +static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (CanProcess ()) + { + switch (event->button) + { + case 1: + g_pManager->OnLButtonUp (event->x, event->y); break; + case 3: + g_2DView.OnRButtonUp (event->x, event->y); break; + } + } +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + if (CanProcess ()) + { + if (g_2DView.OnMouseMove (event->x, event->y)) + return; + + if (g_pManager->OnMouseMove (event->x, event->y)) + return; + } +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + if (!CanProcess ()) + return TRUE; + + if (g_bTexViewReady) + { + g_2DView.m_rect.bottom = widget->allocation.height; + g_2DView.m_rect.right = widget->allocation.width; + + if (!g_QglTable.m_pfn_glwidget_make_current (g_pToolWidget)) + { + Sys_Printf("TexTool: glMakeCurrent failed\n"); + return TRUE; + } + + DoExpose (); + + g_QglTable.m_pfn_glwidget_swap_buffers (g_pToolWidget); + } + + return TRUE; +} + +static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper(event->keyval); + + if (code == GDK_Escape) + { + gtk_widget_destroy (g_pToolWnd); + g_pToolWnd = NULL; + return TRUE; + } + + if (CanProcess ()) + { + if (g_2DView.OnKeyDown (code)) + return FALSE; + + if (code == GDK_Return) + { + Textool_Validate(); + return FALSE; + } + } + + return TRUE; +} + +static gint close (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + gtk_widget_destroy (widget); + g_pToolWnd = NULL; + + return TRUE; +} + +static GtkWidget* CreateOpenGLWidget () +{ + g_pToolWidget = g_QglTable.m_pfn_glwidget_new (FALSE, g_QglTable.m_pfn_GetQeglobalsGLWidget ()); + + gtk_widget_set_events (g_pToolWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); + + // Connect signal handlers + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "motion_notify_event", + GTK_SIGNAL_FUNC (motion), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_release_event", + GTK_SIGNAL_FUNC (button_release), NULL); + + gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "delete_event", GTK_SIGNAL_FUNC (close), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "key_press_event", + GTK_SIGNAL_FUNC (keypress), NULL); + + return g_pToolWidget; +} +#endif + +#if 0 +static void DoPaint () +{ + if (!CanProcess ()) + return; + + if (g_bTexViewReady) + { + g_2DView.m_rect.bottom = g_pToolWnd->getHeight(); + g_2DView.m_rect.right = g_pToolWnd->getWidth(); + + // set GL_PROJECTION + g_2DView.PreparePaint(); + // render the objects + // the master is not rendered the same way, draw over a unified texture background + g_2DView.TextureBackground(g_DrawObjects[0].pObject->getTextureNumber()); + if (g_nDrawObjects >= 1) + { + int i; + for (i=1;iPrepareModelView(g_DrawObjects[i].pTopo); + g_DrawObjects[i].pObject->RenderAuxiliary(); + } + } + // draw the polygon outline and control points + g_DrawObjects[0].pObject->PrepareModelView(NULL); + g_DrawObjects[0].pObject->RenderUI(); + } +} +#endif + +bool CWindowListener::OnLButtonDown(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_pManager->OnLButtonDown((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnRButtonDown(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_2DView.OnRButtonDown ((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnLButtonUp(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_pManager->OnLButtonUp((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnRButtonUp(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_2DView.OnRButtonUp ((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnMouseMove(guint32 nFlags, double x, double y) +{ + if (CanProcess ()) + { + if (g_2DView.OnMouseMove ((int)x, (int)y)) + return true; + + g_pManager->OnMouseMove((int)x, (int)y); + return true; + } + return false; +} + +// the widget is closing +void CWindowListener::Close() +{ + g_pToolWnd = NULL; +} + +bool CWindowListener::Paint() +{ + if (!CanProcess ()) + return false; + + if (g_bTexViewReady) + DoExpose(); + + return true; +} + +bool CWindowListener::OnKeyPressed(char *s) +{ + if (!strcmp(s,"Escape")) + { + Textool_Cancel(); + return TRUE; + } + if (CanProcess ()) + { + if (g_2DView.OnKeyDown (s)) + return TRUE; + + if (!strcmp(s,"Return")) + { + Textool_Validate(); + return TRUE; + } + } + return FALSE; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + #if 0 + // if it's the first call, perhaps we need some additional init steps + if (!g_bQglInitDone) + { + g_QglTable.m_nSize = sizeof(_QERQglTable); + if ( g_FuncTable.m_pfnRequestInterface( QERQglTable_GUID, static_cast(&g_QglTable) ) ) + { + g_bQglInitDone = true; + } + else + { + Sys_Printf("TexTool plugin: _QERQglTable interface request failed\n"); + return; + } + } + + if (!g_bSelectedFaceInitDone) + { + g_SelectedFaceTable.m_nSize = sizeof(_QERSelectedFaceTable); + if (g_FuncTable.m_pfnRequestInterface (QERSelectedFaceTable_GUID, + static_cast(&g_SelectedFaceTable))) + { + g_bSelectedFaceInitDone = true; + } + else + { + Sys_Printf("TexTool plugin: _QERSelectedFaceTable interface request failed\n"); + return; + } + } + + if (!g_bSurfaceTableInitDone) + { + g_SurfaceTable.m_nSize = sizeof(_QERAppSurfaceTable); + if ( g_FuncTable.m_pfnRequestInterface( QERAppSurfaceTable_GUID, static_cast(&g_SurfaceTable) ) ) + { + g_bSurfaceTableInitDone = true; + } + else + { + Sys_Printf("TexTool plugin: _QERAppSurfaceTable interface request failed\n"); + return; + } + } + + if (!g_bUITable) + { + g_UITable.m_nSize = sizeof(_QERUITable); + if ( g_FuncTable.m_pfnRequestInterface( QERUI_GUID, static_cast(&g_UITable) ) ) + { + g_bUITable = true; + } + else + { + Sys_Printf("TexTool plugin: _QERUITable interface request failed\n"); + return; + } + } + #endif + + if (!strcmp(p, "About...")) + { + DoMessageBox (PLUGIN_ABOUT, "About ...", MB_OK ); + } + else if (!strcmp(p, "Go...")) + { + if (!g_pToolWnd) + { + g_pToolWnd = g_UITable.m_pfnCreateGLWindow(); + g_pToolWnd->setSizeParm(300,300); + g_pToolWnd->setName("TexTool"); + // g_Listener is a static class, we need to bump the refCount to avoid premature release problems + g_Listen.IncRef(); + // setListener will incRef on the listener too + g_pToolWnd->setListener(&g_Listen); + if (!g_pToolWnd->Show()) + { + DoMessageBox ("Error creating texture tools window!", "TexTool plugin", MB_ICONERROR | MB_OK); + return; + } + } + + g_bTexViewReady = false; + g_bClosing = false; + } + else if (!strcmp(p, "Help...")) + { + if (!g_bHelp) + DoMessageBox ("Select a brush face (ctrl+shift+left mouse) or a patch, and hit Go...\n" + "See tutorials for more", "TexTool plugin", MB_OK ); + else + DoMessageBox ("Are you kidding me ?", "TexTool plugin", MB_OK ); + g_bHelp = true; + } +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientTexTool g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "textool", sizeof(_QERPluginTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + + return &g_SynapseClient; +} + +bool CSynapseClientTexTool::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable); + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientTexTool::GetInfo() +{ + return "Texture Tools plugin built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/textool/TexTool.def b/plugins/textool/TexTool.def new file mode 100644 index 00000000..d992fe0e --- /dev/null +++ b/plugins/textool/TexTool.def @@ -0,0 +1,12 @@ +; TexTool.def : Declares the module parameters for the DLL. + +LIBRARY "TexTool" +DESCRIPTION 'TexTool Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + QERPlug_Init @1 + QERPlug_GetName @2 + QERPlug_GetCommandList @3 + QERPlug_Dispatch @4 + QERPlug_GetFuncTable @5 diff --git a/plugins/textool/TexTool.rc b/plugins/textool/TexTool.rc new file mode 100644 index 00000000..02394880 --- /dev/null +++ b/plugins/textool/TexTool.rc @@ -0,0 +1,136 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG2 DIALOGEX 0, 0, 290, 206 +STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW +FONT 8, "MS Sans Serif" +BEGIN +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 283 + TOPMARGIN, 7 + BOTTOMMARGIN, 199 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_DROP_MENU MENU DISCARDABLE +BEGIN + POPUP "Drop" + BEGIN + MENUITEM "Validate (RETURN)", ID_DROP_VALIDATE + MENUITEM "Zoom in (INSERT)", ID_DROP_ZOOMIN + MENUITEM "Zoom out (SUPPR)", ID_DROP_ZOOMOUT + MENUITEM "Cancel (ESC)", ID_DROP_CANCEL + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/textool/TexTool.vcproj b/plugins/textool/TexTool.vcproj new file mode 100644 index 00000000..4a7c8e85 --- /dev/null +++ b/plugins/textool/TexTool.vcproj @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/textool/changelog.txt b/plugins/textool/changelog.txt new file mode 100644 index 00000000..ff5dcb28 --- /dev/null +++ b/plugins/textool/changelog.txt @@ -0,0 +1,8 @@ +11/19/99 +first usable version +here is the TODO-list for next release, ( most certainly a wish list ) + +- TODO: add hooks with the selected face and selected patch data. tell the plugin when selected face +or selected patch has changed. +the hooks should use a generic interface inside Radiant for "observers" +- TODO: add other usefull texturing tools, if designers come up with good ideas \ No newline at end of file diff --git a/plugins/textool/resource.h b/plugins/textool/resource.h new file mode 100644 index 00000000..22f6e86c --- /dev/null +++ b/plugins/textool/resource.h @@ -0,0 +1,23 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by TexTool.rc +// +#define IDUNDO 3 +#define IDD_DIALOG 101 +#define IDD_DIALOG2 102 +#define IDR_DROP_MENU 103 +#define ID_DROP_VALIDATE 40001 +#define ID_DROP_ZOOMIN 40002 +#define ID_DROP_ZOOMOUT 40003 +#define ID_DROP_CANCEL 40004 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40005 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/vfspak/vfs.cpp b/plugins/vfspak/vfs.cpp new file mode 100644 index 00000000..09484c50 --- /dev/null +++ b/plugins/vfspak/vfs.cpp @@ -0,0 +1,803 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Rules: +// +// - Directories should be searched in the following order: ~/.q3a/baseq3, +// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). +// +// - Pak files are searched first inside the directories. +// - Case insensitive. +// - Unix-style slashes (/) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include +#if defined __linux__ || defined (__APPLE__) + #include + #include + #define WINAPI +#else + #include + #include + #define R_OK 04 + #define S_ISDIR(mode) (mode & _S_IFDIR) +#endif + +#include "str.h" +#include +#include +#include "vfs.h" +#include "vfspak.h" + +typedef struct +{ + char magic[4]; // Name of the new WAD format ("PACK") + gint32 diroffset; // Position of WAD directory from start of file + gint32 dirsize; // Number of entries * 0x40 (64 char) +} pakheader_t; + +typedef struct +{ + char filename[0x38]; // Name of the file, Unix style, with extension, 50 chars, padded with '\0'. + gint32 offset; // Position of the entry in PACK file + gint32 size; // Size of the entry in PACK file +} pakentry_t; + +typedef struct +{ + char* name; + pakentry_t entry; + FILE *pak; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_unzFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; +static bool g_bUsePak = true; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +static void vfsInitPakFile (const char *filename) +{ + pakheader_t header; + FILE *f; + long i; + + f = fopen (filename, "rb"); + if (f == NULL) + return; + + // read header + fread (header.magic, 1, 4, f); + fread (&header.diroffset, 1, 4, f); + fread (&header.dirsize, 1, 4, f); + + // fix endianess + header.diroffset = GINT32_FROM_LE (header.diroffset); + header.dirsize = GINT32_FROM_LE (header.dirsize); + + // check that the magic header + if (strncmp (header.magic, "PACK", 4)) + { + fclose (f); + return; + } + + g_FuncTable.m_pfnSysPrintf(" pak file: %s\n", filename); + + g_unzFiles = g_slist_append (g_unzFiles, f); + fseek (f, header.diroffset, SEEK_SET); + + for (i = 0; i < (long)(header.dirsize/sizeof (pakentry_t)); i++) + { + VFS_PAKFILE* file; + + file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + fread (file->entry.filename, 1, sizeof (file->entry.filename), f); + fread (&file->entry.offset, 1, sizeof (file->entry.offset), f); + fread (&file->entry.size, 1, sizeof (file->entry.size), f); + file->pak = f; + + // fix endianess + file->entry.offset = GINT32_FROM_LE (file->entry.offset); + file->entry.size = GINT32_FROM_LE (file->entry.size); + + // fix filename + vfsFixDOSName (file->entry.filename); + g_strdown (file->entry.filename); + //g_FuncTable.m_pfnSysPrintf("vfs file from pak: %s\n", file->entry.filename); + } +} + +static GSList* vfsGetListInternal (const char *dir, const char *ext, bool directories) +{ + GSList *lst, *lst_aux, *files = NULL; + char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; + int dirlen; + char *ptr; + //struct dirent *dirlist; + char *dirlist; + struct stat st; + GDir *diskdir; + int i; + + dirname[0] = '\0'; + if (dir != NULL) + { + strcat (dirname, dir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + Sys_Printf("vfs dirname_1: %s\n", dirname); + } + //else + // dirname[0] = '\0'; + dirlen = strlen (dirname); + + if (ext != NULL) + strcpy (extension, ext); + else + extension[0] = '\0'; + g_strdown (extension); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + gboolean found = FALSE; + ptr = file->entry.filename; + + // check that the file name begins with dirname + for (i = 0; (*ptr && i < dirlen); i++, ptr++) + if (*ptr != dirname[i]) + break; + + if (i != dirlen) + continue; + + if (directories) + { + char *sep = strchr (ptr, '/'); + if (sep == NULL) + continue; + + i = sep-ptr; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strncmp ((char*)lst_aux->data, ptr, i) == 0) + { + found = TRUE; + break; + } + + if (!found) + { + char *name = g_strndup (ptr, i+1); + name[i] = '\0'; + files = g_slist_append (files, name); + } + } + else + { + // check extension + if ((ext != NULL) && (strstr (ptr, extension) == NULL)) + continue; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, ptr) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (ptr)); + } + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (dirname, g_strDirs[i]); + strcat (dirname, dir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + + diskdir = g_dir_open (dirname, 0, NULL); + + if (diskdir != NULL) + { + while (1) + { + const char* name = g_dir_read_name(diskdir); + if(name == NULL) + break; + + if (directories && (name[0] == '.')) + continue; + + sprintf (filename, "%s%s", dirname, name); + stat (filename, &st); + Sys_Printf("vfs FileName: %s\n", filename); + + if ((S_ISDIR (st.st_mode) != 0) != directories) + continue; + + gboolean found = FALSE; + + dirlist = g_strdup(name); + + g_strdown (dirlist); + + char *ptr_ext = strrchr (dirlist, '.'); + if(ext == NULL + || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) + { + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, dirlist) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (dirlist)); + } + + g_free(dirlist); + } + g_dir_close (diskdir); + } + } + + return files; +} + +/*! +This behaves identically to -stricmp(a,b), except that ASCII chars +[\]^`_ come AFTER alphabet chars instead of before. This is because +it effectively converts all alphabet chars to uppercase before comparison, +while stricmp converts them to lowercase. +*/ +//!\todo Analyse the code in rtcw/q3 to see how it behaves. +static int vfsPakSort (const void *a, const void *b) +{ + char *s1, *s2; + int c1, c2; + + s1 = (char*)a; + s2 = (char*)b; + + do { + c1 = *s1++; + c2 = *s2++; + + if (c1 >= 'a' && c1 <= 'z') + { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') + { + c2 -= ('a' - 'A'); + } + + if ( c1 == '\\' || c1 == ':' ) + { + c1 = '/'; + } + if ( c2 == '\\' || c2 == ':' ) + { + c2 = '/'; + } + + // Arnout: note - sort pakfiles in reverse order. This ensures that + // later pakfiles override earlier ones. This because the vfs module + // returns a filehandle to the first file it can find (while it should + // return the filehandle to the file in the most overriding pakfile, the + // last one in the list that is). + if (c1 < c2) + { + //return -1; // strings not equal + return 1; // strings not equal + } + if (c1 > c2) + { + //return 1; + return -1; + } + } while (c1); + + return 0; // strings are equal +} + +// ============================================================================= +// Global functions + +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + //struct dirent *direntry; + GDir *dir; + //GSList *dirlistptr; + GSList *dirlist = NULL; + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + + if (g_bUsePak) + { + dir = g_dir_open (path, 0, NULL); + if (dir != NULL) + { + g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); + + for(;;) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + char *ext = strrchr (name, '.'); + if ((ext == NULL) || (strcasecmp (ext, ".pak") != 0)) + continue; + + char* direntry = g_strdup(name); + dirlist = g_slist_append (dirlist, direntry); + } + + g_dir_close (dir); + + + // sort them + dirlist = g_slist_sort (dirlist, vfsPakSort); + + // add the entries to the vfs and free the list + while (dirlist) + { + GSList *cur = dirlist; + char* name = (char*)cur->data; + + sprintf (filename, "%s/%s", path, name); + vfsInitPakFile (filename); + + g_free (name); + dirlist = g_slist_remove (cur, name); + } + } else + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); + + } +} + + +// frees all memory that we allocated +void vfsShutdown () +{ + while (g_unzFiles) + { + fclose ((FILE*)g_unzFiles->data); + g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); + } + + while (g_pakFiles) + { + g_free (g_pakFiles->data); + g_pakFiles = g_slist_remove (g_pakFiles, g_pakFiles->data); + } +} + +GSList* vfsGetFileList (const char *dir, const char *ext) +{ + return vfsGetListInternal (dir, ext, false); +} + +GSList* vfsGetDirList (const char *dir) +{ + return vfsGetListInternal (dir, NULL, true); +} + +void vfsClearFileDirList (GSList **lst) +{ + while (*lst) + { + g_free ((*lst)->data); + *lst = g_slist_remove (*lst, (*lst)->data); + } +} + +// return the number of files that match +int vfsGetFileCount (const char *filename, int flag) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->entry.filename, fixed) == 0) + count++; + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + + return count; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + long len; + FILE *f; + + f = fopen (tmp, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; + } + + count++; + } + } + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->entry.filename, fixed) != 0) + continue; + + if (count == index) + { + fseek (file->pak, file->entry.offset, SEEK_SET); + + *bufferptr = malloc (file->entry.size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->entry.size] = 0; + + return fread (*bufferptr, 1, file->entry.size, file->pak); + } + + count++; + } + + return -1; +} + +void vfsFreeFile (void *p) +{ + g_free(p); +} + +// open a full path file +int vfsLoadFullPathFile (const char *filename, void **bufferptr) +{ + FILE *f; + long len; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; +} + +void vfsCleanFileName(char *in) +{ + strlwr(in); + vfsFixDOSName(in); + int n = strlen(in); + if (in[n-1] == '/') + in[n-1] = '\0'; +} + +const char* vfsBasePromptPath() +{ +#ifdef _WIN32 + static char* path = "C:"; +#else + static char* path = "/"; +#endif + return path; +} + +/*! +\param shorten will try to match against the short version +http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 +recent switch back to short path names in project settings has broken some stuff +with shorten == true, we will convert in to short version before looking for root +FIXME WAAA .. the stuff below is much more simple on linux .. add appropriate #ifdef +*/ +char* vfsExtractRelativePath_short(const char *in, bool shorten) +{ + int i; + char l_in[PATH_MAX]; + char check[PATH_MAX]; + static char out[PATH_MAX]; + out[0] = 0; + +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: %s\n", in); +#endif + +#ifdef _WIN32 + if (shorten) + { + // make it short + if (GetShortPathName(in, l_in, PATH_MAX) == 0) + { +#ifdef DBG_RLTPATH + Sys_Printf("GetShortPathName failed\n"); +#endif + return NULL; + } + } + else + { + strcpy(l_in,in); + } + vfsCleanFileName(l_in); +#else + strcpy(l_in, in); + vfsCleanFileName(l_in); +#endif // ifdef WIN32 + + +#ifdef DBG_RLTPATH + Sys_Printf("cleaned path: %s\n", l_in); +#endif + + for (i = 0; i < g_numDirs; i++) + { + strcpy(check,g_strDirs[i]); + vfsCleanFileName(check); +#ifdef DBG_RLTPATH + Sys_Printf("Matching against %s\n", check); +#endif + + // try to find a match + if (strstr(l_in, check)) + { + strcpy(out,l_in+strlen(check)+1); + break; + } + + } + if (out[0]!=0) + { +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: success\n"); +#endif + return out; + } +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: failed\n"); +#endif + return NULL; +} + +// HYDRA: this now searches VFS/PAK files in addition to the filesystem +// if FLAG is unspecified then ONLY dirs are searched. +// PAK's are searched before DIRs to mimic engine behaviour +// index is ignored when searching PAK files. +// see ifilesystem.h +char* vfsGetFullPath(const char *in, int index, int flag) +{ + int count = 0; + static char out[PATH_MAX]; + char tmp[NAME_MAX]; + int i; + + if (flag & VFS_SEARCH_PAK) + { + char fixed[NAME_MAX]; + GSList *lst; + + strcpy (fixed, in); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + char *ptr,*lastptr; + lastptr = file->name; + + while (ptr = strchr(lastptr,'/')) + lastptr = ptr+1; + + if (strcmp (lastptr, fixed) == 0) + { + strncpy(out,file->name,PATH_MAX); + return out; + } + } + + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, in); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + strcpy (out, tmp); + return out; + } + count++; + } + } + } + return NULL; +} + +// FIXME TTimo: this and the above should be merged at some point +char* vfsExtractRelativePath(const char *in) +{ + static char out[PATH_MAX]; + unsigned int i, count; + char *chunk, *backup = NULL; // those point to out stuff + char *ret = vfsExtractRelativePath_short(in, false); + if (!ret) + { +#ifdef DBG_RLTPATH + Sys_Printf("trying with a short version\n"); +#endif + ret = vfsExtractRelativePath_short(in, true); + if (ret) + { + // ok, but we have a relative short version now + // hack the long relative version out of here + count = 0; + for(i=0;i +#include "vfspak.h" +#include "vfs.h" + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientVFS g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(VFS_MAJOR, "pak", sizeof(_QERFileSystemTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + return &g_SynapseClient; +} + +bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, VFS_MAJOR)) + { + _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); + pTable->m_pfnInitDirectory = &vfsInitDirectory; + pTable->m_pfnShutdown = &vfsShutdown; + pTable->m_pfnFreeFile = &vfsFreeFile; + pTable->m_pfnGetDirList = &vfsGetDirList; + pTable->m_pfnGetFileList = &vfsGetFileList; + pTable->m_pfnClearFileDirList = &vfsClearFileDirList; + pTable->m_pfnGetFileCount = &vfsGetFileCount; + pTable->m_pfnLoadFile = &vfsLoadFile; + pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; + pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; + pTable->m_pfnGetFullPath = &vfsGetFullPath; + pTable->m_pfnBasePromptPath = &vfsBasePromptPath; + return true; + } + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientVFS::GetInfo() +{ + return "PAK VFS module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientVFS::GetName() +{ + return "VFS"; +} + + diff --git a/plugins/vfspak/vfspak.def b/plugins/vfspak/vfspak.def new file mode 100644 index 00000000..5172d2d8 --- /dev/null +++ b/plugins/vfspak/vfspak.def @@ -0,0 +1,8 @@ +; vfspak.def : Declares the module parameters for the DLL. + +LIBRARY "VFSPAK" +DESCRIPTION 'VFSPAK Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/vfspak/vfspak.h b/plugins/vfspak/vfspak.h new file mode 100644 index 00000000..4676ac37 --- /dev/null +++ b/plugins/vfspak/vfspak.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _VFSPAK_H_ +#define _VFSPAK_H_ + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" + +extern _QERFuncTable_1 g_FuncTable; +extern CSynapseServer* g_pSynapseServer; + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf + +class CSynapseClientVFS : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientVFS() { } + virtual ~CSynapseClientVFS() { } +}; + +#endif // _VFSPAK_H_ diff --git a/plugins/vfspak/vfspak.vcproj b/plugins/vfspak/vfspak.vcproj new file mode 100644 index 00000000..a6817fb8 --- /dev/null +++ b/plugins/vfspak/vfspak.vcproj @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/vfspk3/.cvsignore b/plugins/vfspk3/.cvsignore new file mode 100644 index 00000000..af3ce37b --- /dev/null +++ b/plugins/vfspk3/.cvsignore @@ -0,0 +1,11 @@ +*.d +*.o +*.so +Debug +Release +*.aps +*.plg +*.bak +*.BAK +*.opt +*.ncb diff --git a/plugins/vfspk3/unzip-vfspk3.h b/plugins/vfspk3/unzip-vfspk3.h new file mode 100644 index 00000000..930de283 --- /dev/null +++ b/plugins/vfspk3/unzip-vfspk3.h @@ -0,0 +1,299 @@ +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef void* unzFile; +#endif + + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + unsigned long number_entry; /* total number of entries in the central dir on this disk */ + unsigned long size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + unsigned long version; /* version made by 2 unsigned chars */ + unsigned long version_needed; /* version needed to extract 2 unsigned chars */ + unsigned long flag; /* general purpose bit flag 2 unsigned chars */ + unsigned long compression_method; /* compression method 2 unsigned chars */ + unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ + unsigned long crc; /* crc-32 4 unsigned chars */ + unsigned long compressed_size; /* compressed size 4 unsigned chars */ + unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ + unsigned long size_filename; /* filename length 2 unsigned chars */ + unsigned long size_file_extra; /* extra field length 2 unsigned chars */ + unsigned long size_file_comment; /* file comment length 2 unsigned chars */ + + unsigned long disk_num_start; /* disk number start 2 unsigned chars */ + unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ + unsigned long external_fa; /* external file attributes 4 unsigned chars */ + + tm_unz tmu_date; +} unz_file_info; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ +} unz_file_info_internal; + +typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void* opaque, void* address); + +struct internal_state; + +typedef struct z_stream_s { + unsigned char *next_in; /* next input unsigned char */ + unsigned int avail_in; /* number of unsigned chars available at next_in */ + unsigned long total_in; /* total nb of input unsigned chars read so */ + + unsigned char *next_out; /* next output unsigned char should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total nb of unsigned chars output so */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + unsigned char* opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ + unsigned long stream_initialised; /* flag set if stream structure is initialised*/ + + unsigned long offset_local_extrafield;/* offset of the static extra field */ + unsigned int size_local_extrafield;/* size of the static extra field */ + unsigned long pos_local_extrafield; /* position in the static extra field in read*/ + + unsigned long crc32; /* crc32 of all data uncompressed */ + unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ + unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ + unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + unsigned long compression_method; /* compression method (0==store) */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ + unsigned long num_file; /* number of the current file in the zipfile*/ + unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ + unsigned long current_file_ok; /* flag about the usability of the current file*/ + unsigned long central_pos; /* position of the beginning of the central dir*/ + + unsigned long size_central_dir; /* size of the central directory */ + unsigned long offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_CASESENSITIVE 1 +#define UNZ_NOTCASESENSITIVE 2 +#define UNZ_OSDEFAULTCASE 0 + +extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + +extern unzFile unzOpen (const char *path); +extern unzFile unzReOpen (const char* path, unzFile file); + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int unzClose (unzFile file); + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of unsigned char copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int unzGoToFirstFile (unzFile file); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int unzGoToNextFile (unzFile file); + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); + +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int unzOpenCurrentFile (unzFile file); + +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int unzCloseCurrentFile (unzFile file); + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); + +/* + Read unsigned chars from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of unsigned char copied if somes unsigned chars are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern long unztell(unzFile file); + +/* + Give the current position in uncompressed data +*/ + +extern int unzeof (unzFile file); + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of unsigned chars copied in buf, or (if <0) + the error code +*/ diff --git a/plugins/vfspk3/unzip.cpp b/plugins/vfspk3/unzip.cpp new file mode 100644 index 00000000..42f0ccac --- /dev/null +++ b/plugins/vfspk3/unzip.cpp @@ -0,0 +1,4537 @@ +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * + *****************************************************************************/ + +#include +#include +#include +#include "unzip-vfspk3.h" + +typedef unsigned char byte; + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + 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. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + 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. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +int deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +int deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +int gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +// private stuff to not include cmdlib.h +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short __LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __BigShort (short l) +{ + return l; +} + + +int __LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __BigLong (int l) +{ + return l; +} + + +float __LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __BigFloat (float l) +{ + return l; +} + + +#else + + +short __BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __LittleShort (short l) +{ + return l; +} + + +int __BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __LittleLong (int l) +{ + return l; +} + +float __BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __LittleFloat (float l) +{ + return l; +} + + + +#endif + + + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +const char * zError OF((int err)); +int inflateSyncPoint OF((z_streamp z)); +const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#define zmemcpy memcpy +#define zmemcmp memcmp +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +static uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)malloc(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)malloc(sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + free(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + malloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + free(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + free(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + free(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifdef DYNAMIC_CRC_TABLE + +static int crc_table_empty = 1; +static uLong crc_table[256]; +static void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLong * get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLong *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong crc32(uLong crc, const Byte *buf, uInt len) +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} + + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} + + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} + +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidp)malloc(items*size); +} + +void zcfree (voidp opaque, voidp ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + diff --git a/plugins/vfspk3/vfs.cpp b/plugins/vfspk3/vfs.cpp new file mode 100644 index 00000000..c2afbefd --- /dev/null +++ b/plugins/vfspk3/vfs.cpp @@ -0,0 +1,854 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Rules: +// +// - Directories should be searched in the following order: ~/.q3a/baseq3, +// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). +// +// - Pak files are searched first inside the directories. +// - Case insensitive. +// - Unix-style slashes (/) (windows is backwards .. everyone knows that) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include + +#if defined (__linux__) || defined (__APPLE__) + #include + #include +#else + #include + #include + #define R_OK 04 + #define S_ISDIR(mode) (mode & _S_IFDIR) +#endif + +// TTimo: String functions +// see http://www.qeradiant.com/faq/index.cgi?file=175 +#include "str.h" + +#include +#include + +#include "vfspk3.h" +#include "vfs.h" +#include "unzip-vfspk3.h" + +typedef struct +{ + char* name; + unz_s zipinfo; + unzFile zipfile; + guint32 size; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_unzFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; +static bool g_bUsePak = true; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +static void vfsInitPakFile (const char *filename) +{ + unz_global_info gi; + unzFile uf; + guint32 i; + int err; + + uf = unzOpen (filename); + if (uf == NULL) + { + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " failed to init pak file %s\n", filename); + return; + } + g_FuncTable.m_pfnSysPrintf(" pak file: %s\n", filename); + + g_unzFiles = g_slist_append (g_unzFiles, uf); + + err = unzGetGlobalInfo (uf,&gi); + if (err != UNZ_OK) + return; + unzGoToFirstFile(uf); + + for (i = 0; i < gi.number_entry; i++) + { + char filename_inzip[NAME_MAX]; + unz_file_info file_info; + VFS_PAKFILE* file; + + err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) + break; + + file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + vfsFixDOSName (filename_inzip); + g_strdown (filename_inzip); + + file->name = g_strdup (filename_inzip); + file->size = file_info.uncompressed_size; + file->zipfile = uf; + memcpy (&file->zipinfo, uf, sizeof (unz_s)); + + if ((i+1) < gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err!=UNZ_OK) + break; + } + } +} + +static GSList* vfsGetListInternal (const char *refdir, const char *ext, bool directories) +{ + GSList *lst, *lst_aux, *files = NULL; + char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; + char basedir[NAME_MAX]; + int dirlen; + char *ptr; + char *dirlist; + struct stat st; + GDir *diskdir; + int i; + + if (refdir != NULL) + { + strcpy (dirname, refdir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + } else + dirname[0] = '\0'; + dirlen = strlen (dirname); + + if (ext != NULL) + strcpy (extension, ext); + else + extension[0] = '\0'; + g_strdown (extension); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + gboolean found = FALSE; + ptr = file->name; + + // check that the file name begins with dirname + for (i = 0; (*ptr && i < dirlen); i++, ptr++) + if (*ptr != dirname[i]) + break; + + if (i != dirlen) + continue; + + if (directories) + { + char *sep = strchr (ptr, '/'); + if (sep == NULL) + continue; + + i = sep-ptr; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strncmp ((char*)lst_aux->data, ptr, i) == 0) + { + found = TRUE; + break; + } + + if (!found) + { + char *name = g_strndup (ptr, i+1); + name[i] = '\0'; + files = g_slist_append (files, name); + } + } else + { + // check extension + char *ptr_ext = strrchr (ptr, '.'); + if ((ext != NULL) && ((ptr_ext == NULL) || (strcmp (ptr_ext+1, extension) != 0))) + continue; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, ptr) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (ptr)); + } + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (basedir, g_strDirs[i]); + strcat (basedir, dirname); + + diskdir = g_dir_open (basedir, 0, NULL); + + if (diskdir != NULL) + { + while (1) + { + const char* name = g_dir_read_name(diskdir); + if(name == NULL) + break; + + if (directories && (name[0] == '.')) + continue; + + sprintf (filename, "%s%s", basedir, name); + stat (filename, &st); + + if ((S_ISDIR (st.st_mode) != 0) != directories) + continue; + + gboolean found = FALSE; + + dirlist = g_strdup(name); + + g_strdown (dirlist); + + char *ptr_ext = strrchr (dirlist, '.'); + if(ext == NULL + || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) + { + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, dirlist) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (dirlist)); + } + + g_free(dirlist); + } + g_dir_close (diskdir); + } + } + + return files; +} + +/*! +This behaves identically to -stricmp(a,b), except that ASCII chars +[\]^`_ come AFTER alphabet chars instead of before. This is because +it effectively converts all alphabet chars to uppercase before comparison, +while stricmp converts them to lowercase. +*/ +//!\todo Analyse the code in rtcw/q3 to see how it behaves. +static int vfsPakSort (const void *a, const void *b) +{ + char *s1, *s2; + int c1, c2; + + s1 = (char*)a; + s2 = (char*)b; + + do { + c1 = *s1++; + c2 = *s2++; + + if (c1 >= 'a' && c1 <= 'z') + { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') + { + c2 -= ('a' - 'A'); + } + + if ( c1 == '\\' || c1 == ':' ) + { + c1 = '/'; + } + if ( c2 == '\\' || c2 == ':' ) + { + c2 = '/'; + } + + // Arnout: note - sort pakfiles in reverse order. This ensures that + // later pakfiles override earlier ones. This because the vfs module + // returns a filehandle to the first file it can find (while it should + // return the filehandle to the file in the most overriding pakfile, the + // last one in the list that is). + if (c1 < c2) + { + //return -1; // strings not equal + return 1; // strings not equal + } + if (c1 > c2) + { + //return 1; + return -1; + } + } while (c1); + + return 0; // strings are equal +} + +// ============================================================================= +// Global functions + +// reads all pak files from a dir +/*! +The gamemode hacks in here will do undefined things with files called zz_*. +This is simple to fix by cleaning up the hacks, but may be better left alone +if the engine code does the same thing. +*/ +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + GDir *dir; + GSList *dirlistptr, *dirlist = NULL; + int iGameMode; // 0: no filtering 1: SP 2: MP + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + // See if we are in "sp" or "mp" mapping mode + const char* gamemode = g_FuncTable.m_pfnReadProjectKey("gamemode"); + + if (gamemode) + { + if (strcmp (gamemode, "sp") == 0) + iGameMode = 1; + else if (strcmp (gamemode, "mp") == 0) + iGameMode = 2; + else + iGameMode = 0; + } else + iGameMode = 0; + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + + if (g_bUsePak) + { + dir = g_dir_open (path, 0, NULL); + + if (dir != NULL) + { + g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); + + for(;;) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + char *ext = (char*)strrchr(name, '.'); + if ((ext == NULL) || (strcasecmp (ext, ".pk3") != 0)) + continue; + + char* direntry = g_strdup(name); + + // using the same kludge as in engine to ensure consistency + switch (iGameMode) + { + case 1: // SP + if (strncmp(direntry,"sp_",3) == 0) + memcpy(direntry,"zz",2); + break; + case 2: // MP + if (strncmp(direntry,"mp_",3) == 0) + memcpy(direntry,"zz",2); + break; + } + + dirlist = g_slist_append (dirlist, direntry); + } + + g_dir_close (dir); + + // sort them + dirlist = g_slist_sort (dirlist, vfsPakSort); + + // add the entries to the vfs and free the list + while (dirlist) + { + GSList *cur = dirlist; + char* name = (char*)cur->data; + + switch (iGameMode) + { + case 1: // SP + if (strncmp(name,"mp_",3) == 0) + { + g_free (name); + dirlist = g_slist_remove (cur, name); + continue; + } else if (strncmp(name,"zz_",3) == 0) + memcpy(name,"sp",2); + break; + case 2: // MP + if (strncmp(name,"sp_",3) == 0) + { + g_free (name); + dirlist = g_slist_remove (cur, name); + continue; + } else if (strncmp(name,"zz_",3) == 0) + memcpy(name,"mp",2); + break; + } + + sprintf (filename, "%s/%s", path, name); + vfsInitPakFile (filename); + + g_free (name); + dirlist = g_slist_remove (cur, name); + } + } + else + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); + } +} + +// frees all memory that we allocated +// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant? +// (for instance when modifying the project settings) +void vfsShutdown () +{ + while (g_unzFiles) + { + unzClose ((unzFile)g_unzFiles->data); + g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); + } + + // avoid dangling pointer operation (makes BC hangry) + GSList *cur = g_pakFiles; + GSList *next = cur; + while (next) + { + cur = next; + VFS_PAKFILE* file = (VFS_PAKFILE*)cur->data; + g_free (file->name); + g_free (file); + next = g_slist_remove (cur, file); + } + g_pakFiles = NULL; +} + +void vfsFreeFile (void *p) +{ + g_free(p); +} + +GSList* vfsGetFileList (const char *dir, const char *ext) +{ + return vfsGetListInternal (dir, ext, false); +} + +GSList* vfsGetDirList (const char *dir) +{ + return vfsGetListInternal (dir, NULL, true); +} + +void vfsClearFileDirList (GSList **lst) +{ + while (*lst) + { + g_free ((*lst)->data); + *lst = g_slist_remove (*lst, (*lst)->data); + } +} + +int vfsGetFileCount (const char *filename, int flag) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + if (!flag || (flag & VFS_SEARCH_PAK)) + { + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) == 0) + count++; + } + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + } + + return count; +} + +// open a full path file +int vfsLoadFullPathFile (const char *filename, void **bufferptr) +{ + FILE *f; + long len; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + return vfsLoadFullPathFile(tmp,bufferptr); + } + + count++; + } + } + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) != 0) + continue; + + if (count == index) + { + memcpy (file->zipfile, &file->zipinfo, sizeof (unz_s)); + + if (unzOpenCurrentFile (file->zipfile) != UNZ_OK) + return -1; + + *bufferptr = g_malloc (file->size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->size] = 0; + + i = unzReadCurrentFile (file->zipfile , *bufferptr, file->size); + unzCloseCurrentFile (file->zipfile); + if (i > 0) + return file->size; + else + return -1; + } + + count++; + } + + return -1; +} + +//#ifdef _DEBUG +#if 1 + #define DBG_RLTPATH +#endif + +/*! +\param shorten will try to match against the short version +http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 +recent switch back to short path names in project settings has broken some stuff +with shorten == true, we will convert in to short version before looking for root +FIXME WAAA .. the stuff below is much more simple on linux .. add appropriate #ifdef +*/ +char* vfsExtractRelativePath_short(const char *in, bool shorten) +{ + int i; + char l_in[PATH_MAX]; + char check[PATH_MAX]; + static char out[PATH_MAX]; + out[0] = 0; + +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: %s\n", in); +#endif + +#ifdef _WIN32 + if (shorten) + { + // make it short + if (GetShortPathName(in, l_in, PATH_MAX) == 0) + { +#ifdef DBG_RLTPATH + Sys_Printf("GetShortPathName failed\n"); +#endif + return NULL; + } + } + else + { + strcpy(l_in,in); + } + vfsCleanFileName(l_in); +#else + strcpy(l_in, in); + vfsCleanFileName(l_in); +#endif // ifdef WIN32 + + +#ifdef DBG_RLTPATH + Sys_Printf("cleaned path: %s\n", l_in); +#endif + + for (i = 0; i < g_numDirs; i++) + { + strcpy(check,g_strDirs[i]); + vfsCleanFileName(check); +#ifdef DBG_RLTPATH + Sys_Printf("Matching against %s\n", check); +#endif + + // try to find a match + if (strstr(l_in, check)) + { + strcpy(out,l_in+strlen(check)+1); + break; + } + + } + if (out[0]!=0) + { +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: success\n"); +#endif + return out; + } +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: failed\n"); +#endif + return NULL; +} + + +// FIXME TTimo: this and the above should be merged at some point +char* vfsExtractRelativePath(const char *in) +{ + static char out[PATH_MAX]; + unsigned int i, count; + char *chunk, *backup = NULL; // those point to out stuff + char *ret = vfsExtractRelativePath_short(in, false); + if (!ret) + { +#ifdef DBG_RLTPATH + Sys_Printf("trying with a short version\n"); +#endif + ret = vfsExtractRelativePath_short(in, true); + if (ret) + { + // ok, but we have a relative short version now + // hack the long relative version out of here + count = 0; + for(i=0;idata; + + char *ptr,*lastptr; + lastptr = file->name; + + while (ptr = strchr(lastptr,'/')) + lastptr = ptr+1; + + if (strcmp (lastptr, fixed) == 0) + { + strncpy(out,file->name,PATH_MAX); + return out; + } + } + + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, in); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + strcpy (out, tmp); + return out; + } + count++; + } + } + } + return NULL; +} + + +// TODO TTimo on linux the base prompt is ~/.q3a/ +// given the file dialog, we could push the strFSBasePath and ~/.q3a into the directory shortcuts +// FIXME TTimo is this really a VFS functionality? +// actually .. this should be the decision of the core isn't it? +// or .. add an API so that the base prompt can be set during VFS init +const char* vfsBasePromptPath() +{ +#ifdef _WIN32 + static char* path = "C:"; +#else + static char* path = "/"; +#endif + return path; +} + diff --git a/plugins/vfspk3/vfs.h b/plugins/vfspk3/vfs.h new file mode 100644 index 00000000..8ab7cddd --- /dev/null +++ b/plugins/vfspk3/vfs.h @@ -0,0 +1,68 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _VFS_H_ +#define _VFS_H_ + +#define VFS_MAXDIRS 8 + +void vfsInitDirectory (const char *path); +void vfsShutdown (); +void vfsFreeFile (void *p); +GSList* vfsGetFileList (const char *dir, const char *ext); +GSList* vfsGetDirList (const char *dir); +void vfsClearFileDirList (GSList **lst); +int vfsGetFileCount (const char *filename, int flag); +int vfsLoadFile (const char *filename, void **buffer, int index = 0); +int vfsLoadFullPathFile (const char *filename, void **buffer); + +// some useful functions +// clean a file name to a unique representation +// very usefull if you have to do some weird manips on the files +// works on regular files and dirs +// will convert to lowercase, unix path ('/' filename seperator) +// on win32, will build the short path name +// directories will be cleaned, no ending filename seperator +// we modify the entry directly, the size of the string can only go down +void vfsCleanFileName(char *); +// these return a static char*, doesn't need to be freed or anything +// get the base path to use when raising file dialogs +// we manually add "maps/" or "sounds/" or "mapobjects/models/" etc. +const char* vfsBasePromptPath(); +// extract the relative path from a full path +// will match against any of the base paths we have +// returns NULL if not found +char* vfsExtractRelativePath(const char *in); +// returns the full path (in a static buff) to a file given it's relative path +// returns the first file in the list or NULL if not found +// see ifilesystem.h for more notes +char* vfsGetFullPath(const char*, int index = 0, int flag = 0); + +#endif // _VFS_H_ diff --git a/plugins/vfspk3/vfspk3.cpp b/plugins/vfspk3/vfspk3.cpp new file mode 100644 index 00000000..c4aee9a7 --- /dev/null +++ b/plugins/vfspk3/vfspk3.cpp @@ -0,0 +1,99 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Quake 3 Virtual FileSystem - reads files from different dirs and inside pak files +// +// Leonardo Zide (leo@lokigames.com) +// + +#ifdef _WIN32 +#include +#endif + +#include +#include "vfspk3.h" +#include "vfs.h" + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientVFS g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(VFS_MAJOR, "pk3", sizeof(_QERFileSystemTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + return &g_SynapseClient; +} + +bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, VFS_MAJOR)) + { + _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); + pTable->m_pfnInitDirectory = &vfsInitDirectory; + pTable->m_pfnShutdown = &vfsShutdown; + pTable->m_pfnFreeFile = &vfsFreeFile; + pTable->m_pfnGetDirList = &vfsGetDirList; + pTable->m_pfnGetFileList = &vfsGetFileList; + pTable->m_pfnClearFileDirList = &vfsClearFileDirList; + pTable->m_pfnGetFileCount = &vfsGetFileCount; + pTable->m_pfnLoadFile = &vfsLoadFile; + pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; + pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; + pTable->m_pfnGetFullPath = &vfsGetFullPath; + pTable->m_pfnBasePromptPath = &vfsBasePromptPath; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientVFS::GetInfo() +{ + return "PK3 VFS module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/vfspk3/vfspk3.def b/plugins/vfspk3/vfspk3.def new file mode 100644 index 00000000..c9e249d4 --- /dev/null +++ b/plugins/vfspk3/vfspk3.def @@ -0,0 +1,8 @@ +; vfspk3.def : Declares the module parameters for the DLL. + +LIBRARY "VFSPK3" +DESCRIPTION 'VFSPK3 Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/vfspk3/vfspk3.h b/plugins/vfspk3/vfspk3.h new file mode 100644 index 00000000..1462656f --- /dev/null +++ b/plugins/vfspk3/vfspk3.h @@ -0,0 +1,63 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _VFSPK3_H_ +#define _VFSPK3_H_ + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" + +extern _QERFuncTable_1 g_FuncTable; +extern CSynapseServer* g_pSynapseServer; + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf + +class CSynapseClientVFS : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientVFS() { } + virtual ~CSynapseClientVFS() { } +}; + +#endif // _VFSPK3_H_ diff --git a/plugins/vfspk3/vfspk3.proj b/plugins/vfspk3/vfspk3.proj new file mode 100644 index 0000000000000000000000000000000000000000..558e2e3b9100c365f843aa2175e1621c9c19a921 GIT binary patch literal 16384 zcmeHLZEPGz8Gdm>vuoeo5?PgkAkw4}mE+{jcju49iHMxgCPZyWnuIj{LAQImbM_|t z<()m-m&0mRAxe-cJ|xuqtg29nA604L4+v2N6hfPpG_({_NK(pYp%4|RQh(6!zWZU{ zrnTcsP(`Yp)85QHGw*ynJ2U&d12^2L0YDeP@-qM*!6f7WK7%>bbEyqip!!3%`VqW4&4%whT@~4`MoED`UJ1UI0MM zXsg!?XW(rkH^vcDVtg6=3f@4hj`{GW1LIzJ5ne%T9MhNXjVkuSOYjV06K&W%UB8B> z5i=3%iK^lM%kX`~4yUl+z+;FVK`fkVSogPZ0x=8I$$UlESvZcEox)y$2N82p*ze$e z#M~72dzeJbOJV20L~IhVJU$de*LhG8^D#Z&?*%x7m`Gu-!lw`m$Y?J70R|9j%;hQZ z8hi|~sTB4{xB;>06!s^06W`_06!vF0k60^({RK`T_W2a{S9l7snKrB!{st!yYqnv_ z;C1*K-cFrfxq6HqDoQS(zIv}bc3eLvPh$D1n}l={%PIf!u7|s%+h1C}mhSQ171q8BSsL)s6#x$-r}QN2Y7LwO75CuX*u;n9 zX4b$jU_WAN8>YiE@BqHcLx|z42!rT)7Mh6NmBLQJcC@`GsuKTa=SFsJ&{DXzbK@>t zc%R0#OAocyes1*r%&H%DoYDjDr+TYi*w`mLuwM%8!()R!Q z+;|lSx(Yd^Cp$MXy>Y$i4cbdgSv^J%?XC86V=s!rL$uMql^Yv7c9V49*1yY7$L9vc zRMcrmY!=$zG#(1qm)>Yin~vd5v%%pqs}2vbO@mc7GBQl@494pRhlbWyMn~DW&pqa8 z<9wDSCL?S(te2`^USDS1Fay@2%B&TpH&r(=dRleU;%s2TwfR6`+U|hon^RiA2X+QW z_GyNxIl+MG1l+G{Iv+5pwrGlg+ocKSxq?+Ir7{x%S}@1;ZOvltls_G?G7GetFpqLp zWp2GLI6|`+V0Xg`%sayw3MfO(4JJ0=!+lYl_RWApCBnvix8cRmS{OHK#c9_+VwgU( zTH7p(g(I0|{j3BL=4G!aFhuwswRUElmW} z%|Ju=ICb4>7@U>xw|G-?BtdLb6mG-Uc@f*D=*}JmiuAu z+quVckL2tgwdd}heLZ*d+|skIdsX+1-OIY)k>8Xr%ID=L#`vq zl=sM6Li&pIpme`obl(lJR2zmVykgWspW`~3&DTK`hYi4R8TRX% z#IicV7C(Ii6OfP}i{7*Mp@W@h1dEdj02A8XmF zS9f;uU91b%|k<*8QZ(#GwQ(|`*+@YV8@<)ySE)+aY%Qvr91Lp zO1kH5-Z+YOjClvhAu4W7*JPh$H_wf2OE(Jm!N`rQlr{~rN@;Xs_d-CmgnOV`8Y*|s zqFFfCblZLX>t-2heJWDxzH29L$n2a}r=oeSj(*a7Mn|^`IgI>N-F4U*tGH;($j|X^J)xLV;y@oc&F7*ny6Ar7E>EMoc8aBkc zk=8Vy30>JMY>zhTYQn?Uh$D3jboQ6LiVZE$I;qb+&Gbbl7R2n_CB%})HEwm%hs}l1 z@NQtd6Qk&CK~LTc(A)3CQs}~n5Q_*;muD1P;vsIi<{^(4FAE) m!z^SBWDH~sWDH~sWDH~sWDH~sWDH~sWDH~sWDI<;8Tc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/vfswad/unwad.cpp b/plugins/vfswad/unwad.cpp new file mode 100644 index 00000000..e6c36b7e --- /dev/null +++ b/plugins/vfswad/unwad.cpp @@ -0,0 +1,251 @@ +#include +#include +#include + +#include "unwad.h" + + +wadFile_t *wadCleanup(wadFile_t *wf) +{ + if (wf) + { + if (wf->fin) fclose(wf->fin); + if (wf->lpHeader) free(wf->lpHeader); + if (wf->lpLump) free(wf->lpLump); + if (wf->lpMip) free(wf->lpMip); + if (wf->wadfilename) free(wf->wadfilename); + free (wf); + wf = NULL; + } + return wf; +} + +int wadGetCurrentFileInfo ( wadFile_t *wf, char *szFileName, unsigned long fileNameBufferSize, unsigned long *filesize) +{ + /* returns 0 if error, or 1 for sucess */ + // if this fails you'll need to re-position the fileposition + // before attempting any other calls. e.g. call wadGoToFirstFile() + + if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) + return 0; + strncpy(szFileName, wf->lpLump->name, fileNameBufferSize); + szFileName[fileNameBufferSize-1] = 0; // null terminate + + *filesize = wf->lpLump->size; + + return 1; +} + +int wadGoToFile(wadFile_t *wf, unsigned long filenum) +{ + if (!wf) + return 0; + + if (!wf->fin) + return 0; + + if (filenum >= wf->lpHeader->numlumps) + return 0; + + if (fseek(wf->fin,wf->lpHeader->infotableofs + (filenum * sizeof(WAD3_LUMP)),SEEK_SET) != 0) + return 0; + + wf->currentfile = filenum; + + return 1; +} + +int wadGoToNextFile(wadFile_t *wf) +{ + return(wadGoToFile(wf, wf->currentfile + 1)); +} + +int wadGoToFirstFile(wadFile_t *wf) +{ + /* returns 0 if error, or 1 for sucess */ + + if (!wf) + return 0; + + if (!wf->fin) + return 0; + + if (fseek(wf->fin,wf->lpHeader->infotableofs,SEEK_SET) != 0) + return 0; + + wf->currentfile = 0; + + return 1; +} + +wadFile_t *wadOpen(const char* path) +{ + + wadFile_t *wf = NULL; + + if (!path) + return NULL; + + wf = new wadFile_s; + memset (wf, 0, sizeof(*wf)); + + if (!wf) + return NULL; + + wf->fin=fopen(path,"rb"); + if (wf->fin==NULL) + return wadCleanup(wf); + + // get the file size + if (fseek(wf->fin,0,SEEK_END) != 0) + return wadCleanup(wf); + + wf->FileSize = ftell( wf->fin ); + + // Make sure it's at least big enough to manipulate the header + if (wf->FileSize < sizeof(WAD3_HEADER)) + { + // WAD3 file is malformed. + return wadCleanup(wf); + } + + // go back to the start + if (fseek(wf->fin,0,SEEK_SET)!=0) + return wadCleanup(wf); + + // allocate buffers + wf->lpHeader = (LPWAD3_HEADER) malloc(sizeof(WAD3_HEADER)); + wf->lpLump = (LPWAD3_LUMP) malloc(sizeof(WAD3_LUMP)); + wf->lpMip = (LPWAD3_MIP) malloc(sizeof(WAD3_MIP)); + + if (!(wf->lpHeader) || !(wf->lpLump) || !(wf->lpMip)) + return wadCleanup(wf); + + // read the header. + if (fread(wf->lpHeader,sizeof(WAD3_HEADER),1,wf->fin)!=1) + return wadCleanup(wf); + + if (wf->lpHeader->identification != WAD2_ID && wf->lpHeader->identification != WAD3_ID) + { + // Invalid WAD3 header id. + return wadCleanup(wf); + } + + // Make sure our table is really there + if ( ((wf->lpHeader->numlumps * sizeof(WAD3_LUMP)) + wf->lpHeader->infotableofs) > wf->FileSize) + { + // WAD3 file is malformed. + return wadCleanup(wf); + } + + // Store the name of the wadfile + if (!(wf->wadfilename = strdup(path))) + return wadCleanup(wf); + + return wf; +} + +int wadOpenCurrentFileByNum (wadFile_t *wf, unsigned long filenumber) +{ + /* returns 0 if error, or 1 for sucess */ + return(wadGoToFile(wf, filenumber)); +} + +void wadCloseCurrentFile (wadFile_t *wf) +{ + // nothing to do really... +} + +unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size) +{ + // returns 0 if error, or the amount of data read into the buffer + if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) + return 0; + + // dunno how to handle any other image types but this (yet) + if (wf->lpLump->type != WAD2_TYPE_MIP && wf->lpLump->type != WAD3_TYPE_MIP) + return 0; + + // go to first mip + if (fseek(wf->fin, wf->lpLump->filepos, SEEK_SET) != 0) + return 0; + + if (fread(bufferptr,size,1,wf->fin) == 1) + return (size); + else + return 0; +} + +/* + +.. or we could do it the long way, and process the file as we go.. + + +*/ +/* +unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size) +{ + // returns 0 if error, or the amount of data read into the buffer + unsigned long bufferpos; + unsigned long mipdatasize; + WORD palettesize; + + if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) + return 0; + + if (wf->lpLump->type == WAD3_TYPE_MIP) // can we handle it ? + { + + // bounds check. + if (wf->lpLump->filepos >= wf->FileSize) + return 0; // malformed wad3 + + // go to first mip + if (fseek(wf->fin, wf->lpLump->filepos, SEEK_SET) != 0) + return 0; + + // and read it + if (fread(wf->lpMip,sizeof(WAD3_MIP),1,wf->fin)!=1) + return 0; + + // store in buffer. + memcpy(bufferptr, wf->lpMip, sizeof(WAD3_MIP)); + bufferpos = sizeof(WAD3_MIP); + + // now read the MIP data. + // mip data + if (fseek(wf->fin, wf->lpLump->filepos + wf->lpMip->offsets[0], SEEK_SET) != 0) + return 0; + + mipdatasize = GET_MIP_DATA_SIZE(wf->lpMip->width,wf->lpMip->height); + + if (fread(bufferptr+bufferpos, mipdatasize, 1, wf->fin)!=1) + return 0; + + bufferpos += mipdatasize; + + // ok, that's the mip data itself, now grab the palette size. + if (fread(bufferptr+bufferpos,sizeof(WORD),1,wf->fin)!=1) + return 0; + + palettesize = *(WORD *)(bufferptr+bufferpos); + + bufferpos += sizeof(WORD); + + // grab the palette itself + if (fread(bufferptr+bufferpos,palettesize*3,1,wf->fin)!=1) + return 0; + + bufferpos += palettesize*3; + + // and finally the one-word padding. + if (fread(bufferptr+bufferpos,sizeof(WORD),1,wf->fin)!=1) + return 0; + + bufferpos += sizeof(WORD); + + return(bufferpos); // return the amount of bytes read. + } + return 0; +} +*/ diff --git a/plugins/vfswad/unwad.h b/plugins/vfswad/unwad.h new file mode 100644 index 00000000..e1170531 --- /dev/null +++ b/plugins/vfswad/unwad.h @@ -0,0 +1,111 @@ + +#ifndef _WAD3_H_ +#define _WAD3_H_ + +// WAD3 (Half-Life) Header and mip structs +// WAD2 (Quake) Header and mip structs added by LordHavoc + +#define WADBUFSIZE 32768 + +#define WAD2_TYPE_MIP 0x44 +#define WAD2_ID ('W' | 'A' << 8 | 'D' << 16 | '2' << 24) +#define WAD3_TYPE_MIP 0x43 +#define WAD3_ID ('W' | 'A' << 8 | 'D' << 16 | '3' << 24) +#define GET_MIP_DATA_SIZE(WIDTH, HEIGHT) ((WIDTH * HEIGHT) + (WIDTH * HEIGHT / 4) + (WIDTH * HEIGHT / 16) + (WIDTH * HEIGHT / 64)) + +/* + + WAD3 pseudo-structure: + + WAD3 Header + Mip section + First mip + Mip header + First mip (width * height) + Second mip (width * height / 4) + Third mip (width * height / 16) + Fourth mip (width * height / 64) + Palette size (WORD) + Palette (Palette size * 3) + Padding (WORD) + [...] + Last mip + Lump table + First lump entry + Lump header + [...] + Last lump entry + + WAD2 pseudo-structure: + + WAD2 Header + Mip section + First mip + Mip header + First mip (width * height) + Second mip (width * height / 4) + Third mip (width * height / 16) + Fourth mip (width * height / 64) + [...] + Last mip + Lump table + First lump entry + Lump header + [...] + Last lump entry +*/ + +#define DWORD unsigned int +#define BYTE unsigned char +#define WORD unsigned short int + +typedef struct +{ + DWORD identification; + DWORD numlumps; + DWORD infotableofs; // Lump table +} WAD3_HEADER, *LPWAD3_HEADER; + +typedef struct +{ + DWORD filepos; + DWORD disksize; + DWORD size; // uncompressed + BYTE type; + BYTE compression; + BYTE pad1, pad2; + char name[16]; // must be null terminated +} WAD3_LUMP, *LPWAD3_LUMP; + +typedef struct +{ + char name[16]; + DWORD width, height; + DWORD offsets[4]; // four mip maps stored +} WAD3_MIP, *LPWAD3_MIP; + + +typedef struct wadFile_s +{ + FILE * fin; + LPWAD3_HEADER lpHeader; + LPWAD3_LUMP lpLump; + LPWAD3_MIP lpMip; + + DWORD FileSize; + unsigned long currentfile; + char *wadfilename; +} wadFile_t; + + +wadFile_t *wadOpen(const char* path); +wadFile_t *wadCleanup(wadFile_t *wf); +int wadGoToFirstFile(wadFile_t *wf); +int wadGetCurrentFileInfo ( wadFile_t *wf, char *szFileName, unsigned long fileNameBufferSize, unsigned long *filesize); +int wadGoToNextFile(wadFile_t *wf); + +int wadOpenCurrentFileByNum (wadFile_t *wf, unsigned long filenumber); +void wadCloseCurrentFile (wadFile_t *wf); +unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size); + +#endif // #ifndef _WAD3_H_ diff --git a/plugins/vfswad/vfs.cpp b/plugins/vfswad/vfs.cpp new file mode 100644 index 00000000..5a1ab58c --- /dev/null +++ b/plugins/vfswad/vfs.cpp @@ -0,0 +1,759 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Rules: +// +// - Directories should be searched in the following order: ~/.q3a/baseq3, +// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). +// +// - Pak files are searched first inside the directories. +// - Case insensitive. +// - Unix-style slashes (/) (windows is backwards .. everyone knows that) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include + +#if defined (__linux__) || defined (__APPLE__) + #include + #include +#else + #include + #include + #define R_OK 04 + #define S_ISDIR(mode) (mode & _S_IFDIR) +#endif + +// TTimo: String functions +// see http://www.qeradiant.com/faq/index.cgi?file=175 +#include "str.h" + +#include +#include + +#include "vfswad.h" +#include "vfs.h" +#include "unwad.h" + +typedef struct +{ + char* name; + WAD3_LUMP wadlump; + wadFile_t *wadfile; + unsigned long filenumber; + unsigned long size; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_wadFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +//FIXME: STUPID short filenames.. get RID of it asap +// copied verbatim from qe3.cpp +int vfsBuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) +{ +#ifdef _WIN32 + char *pFile = NULL; + int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); + nResult = GetShortPathName(pPath, pBuffer, nBufferLen); + if (nResult == 0) + strcpy(pBuffer, pPath); // Use long filename + return nResult; +#endif + +#if defined (__linux__) || defined (__APPLE__) + + // remove /../ from directories + const char *scr = pPath; char *dst = pBuffer; + for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) + { + if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') + { + scr += 3; + while (dst != pBuffer && *(--dst) != '/') + { + i--; + } + } + + *dst = *scr; + + scr++; dst++; + } + *dst = 0; + + return strlen (pBuffer); +#endif +} + +static void vfsInitPakFile (const char *filename) +{ + wadFile_t *wf; + unsigned int i; + int err; + char *wadnameptr; + char wadname[NAME_MAX]; + + wf = wadOpen (filename); + if (wf == NULL) + { + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " failed to init wad file %s\n", filename); + return; + } + g_FuncTable.m_pfnSysPrintf(" wad file: %s\n", filename); + + for (i = strlen(filename)-1 ; i >= 0 && filename[i] != '\\' && filename[i] != '/' ; i --) + wadnameptr = (char *)filename + i; + + strcpy(wadname,wadnameptr); + wadname[strlen(wadname)-4] = 0; // ditch the .wad so everthing looks nice! + + g_wadFiles = g_slist_append (g_wadFiles, wf); // store the wadfile handle + + wadGoToFirstFile(wf); + + for (i = 0; i < wf->lpHeader->numlumps; i++) + { + char filename_inwad[NAME_MAX]; + char filename_inwadfixed[NAME_MAX]; + unsigned long filesize; + VFS_PAKFILE* file; + + err = wadGetCurrentFileInfo (wf, filename_inwad, sizeof(filename_inwad) - 5, &filesize); // -5 for extension + null terminator + if (err != 1) + break; + + file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + vfsFixDOSName (filename_inwad); + g_strdown (filename_inwad); + + // texturenames in wad files don't have an extensions or paths, so we must add them! + if (wf->lpLump->type == WAD2_TYPE_MIP) + { + sprintf(filename_inwadfixed,"textures/%s/%s.mip",wadname,filename_inwad); + }else { + sprintf(filename_inwadfixed,"textures/%s/%s.hlw",wadname,filename_inwad); + } + + //g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " scanned %s\\%s\n", filename,filename_inwad); + + file->name = g_strdup (filename_inwadfixed); + file->size = filesize; + file->filenumber = wf->currentfile; + file->wadfile = wf; + memcpy(&file->wadlump, wf->lpLump, sizeof(WAD3_LUMP)); + + err = wadGoToNextFile(wf); + if (err != 1) + break; + } +} + +static GSList* vfsGetListInternal (const char *refdir, const char *ext, bool directories) +{ + GSList *lst, *lst_aux, *files = NULL; + char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; + char basedir[NAME_MAX]; + int dirlen; + char *ptr; + struct stat st; + int i; + + if (refdir != NULL) + { + strcpy (dirname, refdir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + } else + dirname[0] = '\0'; + dirlen = strlen (dirname); + + if (ext != NULL) + strcpy (extension, ext); + else + extension[0] = '\0'; + g_strdown (extension); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + gboolean found = FALSE; + ptr = file->name; + + // check that the file name begins with dirname + for (i = 0; (*ptr && i < dirlen); i++, ptr++) + if (*ptr != dirname[i]) + break; + + if (i != dirlen) + continue; + + if (directories) + { + char *sep = strchr (ptr, '/'); + if (sep == NULL) + continue; + + i = sep-ptr; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strncmp ((char*)lst_aux->data, ptr, i) == 0) + { + found = TRUE; + break; + } + + if (!found) + { + char *name = g_strndup (ptr, i+1); + name[i] = '\0'; + files = g_slist_append (files, name); + } + } else + { + // check extension + char *ptr_ext = strrchr (ptr, '.'); + if ((ext != NULL) && ((ptr_ext == NULL) || (strcmp (ptr_ext+1, extension) != 0))) + continue; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, ptr) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (ptr)); + } + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (basedir, g_strDirs[i]); + strcat (basedir, dirname); + + GDir* dir = g_dir_open (basedir, 0, NULL); + + if (dir != NULL) + { + for(;;) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + if (directories && (name[0] == '.')) + continue; + + sprintf (filename, "%s%s", basedir, name); + stat (filename, &st); + + if ((S_ISDIR (st.st_mode) != 0) != directories) + continue; + + gboolean found = FALSE; + + char* direntry = g_strdup(name); + + g_strdown (direntry); + + char *ptr_ext = strrchr (direntry, '.'); + + if(ext == NULL + || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) + { + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, direntry) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (direntry)); + } + + g_free(direntry); + } + g_dir_close(dir); + } + } + + return files; +} + +// ============================================================================= +// Global functions + +// reads all pak files from a dir +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + +// if (g_PrefsDlg.m_bPAK) + // TODO: can't read prefs from a module, bah.. + if (1) + { + GDir* dir = g_dir_open (path, 0, NULL); + if (dir != NULL) + { + g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); + while (1) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + char *ext = strrchr (name, '.'); + if ((ext == NULL) || (strcmp (ext, ".wad") != 0)) + continue; + + sprintf (filename, "%s/%s", path, name); + vfsInitPakFile (filename); + } + g_dir_close (dir); + } else + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); + } +} + +// frees all memory that we allocated +// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant? +// (for instance when modifying the project settings) +void vfsShutdown () +{ + wadFile_t *tmpptr; + + while (g_wadFiles) + { + wadCleanup((wadFile_t *)g_wadFiles->data); + g_wadFiles = g_slist_remove (g_wadFiles, g_wadFiles->data); + } + + // avoid dangling pointer operation (makes BC hangry) + GSList *cur = g_pakFiles; + GSList *next = cur; + while (next) + { + cur = next; + VFS_PAKFILE* file = (VFS_PAKFILE*)cur->data; + g_free (file->name); + g_free (file); + next = g_slist_remove (cur, file); + } + g_pakFiles = NULL; +} + +void vfsFreeFile (void *p) +{ + g_free(p); +} + +GSList* vfsGetFileList (const char *dir, const char *ext) +{ + return vfsGetListInternal (dir, ext, false); +} + +GSList* vfsGetDirList (const char *dir) +{ + return vfsGetListInternal (dir, NULL, true); +} + +void vfsClearFileDirList (GSList **lst) +{ + while (*lst) + { + g_free ((*lst)->data); + *lst = g_slist_remove (*lst, (*lst)->data); + } +} + +// return the number of files that match +int vfsGetFileCount (const char *filename, int flag) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + if (!flag || (flag & VFS_SEARCH_PAK)) + { + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) == 0) + count++; + } + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + } + + return count; +} + +// open a full path file +int vfsLoadFullPathFile (const char *filename, void **bufferptr) +{ + FILE *f; + long len; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + return vfsLoadFullPathFile(tmp,bufferptr); + /* + long len; + FILE *f; + + f = fopen (tmp, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; + */ + } + + count++; + } + } + + + // Textures in HalfLife wads don't have paths, but in the list of files + // we store the actual full paths of the files and what WAD they're in. + // so what we have to do is strip the paths and just compare filenames. + + // Hydra: well, we did do this, but now we don't, as the map loader now + // fills in the correct paths for each texture. + + /* + char *searchname; + char *fixedptr; + + fixedptr = fixed; + + for (i = strlen(fixed)-1 ; i >= 0 && fixed[i] != '\\' && fixed[i] != '/' ; i --) + fixedptr = (char *)fixed + i; + */ + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + + /* + searchname = file->name; + for (i = strlen(file->name)-1 ; i >= 0 && file->name[i] != '\\' && file->name[i] != '/' ; i --) + searchname = (char *)file->name + i; + if (strcmp (searchname, fixedptr) != 0) + continue; + */ + + if (strcmp (file->name, fixed) != 0) + continue; + + if (count == index) + { + // Useful for debugging + //Sys_Printf("VFSWAD: reading from %s\n",file->wadfile->wadfilename); + + if (wadOpenCurrentFileByNum (file->wadfile, file->filenumber) != 1) + return -1; + + *bufferptr = g_malloc (file->size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->size] = 0; + + i = wadReadCurrentFile (file->wadfile , (char *)*bufferptr, file->size); + wadCloseCurrentFile (file->wadfile); + if (i > 0) + return file->size; + else + return -1; + } + + count++; + } + + return -1; +} + +//#ifdef _DEBUG +#if 0 + #define DBG_RLTPATH +#endif + +char* vfsExtractRelativePath(const char *in) +{ + int i; + char l_in[PATH_MAX]; + char check[PATH_MAX]; + static char out[PATH_MAX]; + out[0] = 0; + +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: %s\n", in); +#endif + + strcpy(l_in,in); + vfsCleanFileName(l_in); + +#ifdef DBG_RLTPATH + Sys_Printf("cleaned path: %s\n", l_in); +#endif + + for (i = 0; i < g_numDirs; i++) + { + strcpy(check,g_strDirs[i]); + vfsCleanFileName(check); +#ifdef DBG_RLTPATH + Sys_Printf("Matching against %s\n", check); +#endif + + // try to find a match + if (strstr(l_in, check)) + { + strcpy(out,l_in+strlen(check)+1); + break; + } + } + if (out[0]!=0) + { +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: success\n"); +#endif + return out; + } +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: failed\n"); +#endif + return NULL; +} + +// removed CString usage +void vfsCleanFileName(char *in) +{ + char str[PATH_MAX]; + vfsBuildShortPathName (in, str, PATH_MAX); + strlwr(str); + vfsFixDOSName(str); + int n = strlen(str); + if (str[n-1] == '/') + str[n-1] = '\0'; + strcpy (in, str); +} + +// HYDRA: this now searches VFS/PAK files in addition to the filesystem +// if FLAG is unspecified then ONLY dirs are searched. +// PAK's are searched before DIRs to mimic engine behaviour +// index is ignored when searching PAK files. +// see ifilesystem.h +char* vfsGetFullPath(const char *in, int index, int flag) +{ + int count = 0; + static char out[PATH_MAX]; + char tmp[NAME_MAX]; + int i; + + if (flag & VFS_SEARCH_PAK) + { + char fixed[NAME_MAX]; + GSList *lst; + + strcpy (fixed, in); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + char *ptr,*lastptr; + lastptr = file->name; + + while (ptr = strchr(lastptr,'/')) + lastptr = ptr+1; + + if (strcmp (lastptr, fixed) == 0) + { + strncpy(out,file->name,PATH_MAX); + return out; + } + } + + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, in); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + strcpy (out, tmp); + return out; + } + count++; + } + } + } + return NULL; +} + +// TODO TTimo on linux the base prompt is ~/.q3a/ +// given the file dialog, we could push the strFSBasePath and ~/.q3a into the directory shortcuts +// FIXME TTimo is this really a VFS functionality? +// actually .. this should be the decision of the core isn't it? +// or .. add an API so that the base prompt can be set during VFS init +const char* vfsBasePromptPath() +{ +#ifdef _WIN32 + static char* path = "C:"; +#else + static char* path = "/"; +#endif + return path; +} + diff --git a/plugins/vfswad/vfs.h b/plugins/vfswad/vfs.h new file mode 100644 index 00000000..155e993d --- /dev/null +++ b/plugins/vfswad/vfs.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _VFS_H_ +#define _VFS_H_ + +#define VFS_MAXDIRS 8 + +void vfsInitDirectory (const char *path); +void vfsShutdown (); +void vfsFreeFile (void *p); +GSList* vfsGetFileList (const char *dir, const char *ext); +GSList* vfsGetDirList (const char *dir); +void vfsClearFileDirList (GSList **lst); +int vfsGetFileCount (const char *filename, int flag); +int vfsLoadFile (const char *filename, void **buffer, int index = 0); +int vfsLoadFullPathFile (const char *filename, void **buffer); + +// some useful functions +// clean a file name to a unique representation +// very usefull if you have to do some weird manips on the files +// works on regular files and dirs +// will convert to lowercase, unix path ('/' filename seperator) +// on win32, will build the short path name +// directories will be cleaned, no ending filename seperator +// we modify the entry directly, the size of the string can only go down +void vfsCleanFileName(char *); +// these return a static char*, doesn't need to be freed or anything +// get the base path to use when raising file dialogs +// we manually add "maps/" or "sounds/" or "mapobjects/models/" etc. +const char* vfsBasePromptPath(); +// extract the relative path from a full path +// will match against any of the base paths we have +// returns NULL if not found +char* vfsExtractRelativePath(const char *in); +// returns the full path (in a static buff) to a file given it's relative path +// returns the first file in the list or NULL if not found +// see ifilesystem.h for more notes +char* vfsGetFullPath(const char*, int index = 0, int flag = 0); + + +#endif // _VFS_H_ diff --git a/plugins/vfswad/vfswad.cpp b/plugins/vfswad/vfswad.cpp new file mode 100644 index 00000000..95dbf875 --- /dev/null +++ b/plugins/vfswad/vfswad.cpp @@ -0,0 +1,101 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// HalfLife Virtual FileSystem - reads files from different dirs and inside wad files +// +// Coding by Dominic Clifton - Hydra - hydra@hydras-world.com +// +// based on code by Leonardo Zide (leo@lokigames.com) +// + +#ifdef _WIN32 +#include +#endif + +#include +#include "vfswad.h" +#include "vfs.h" + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientVFS g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(_QERFileSystemTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + return &g_SynapseClient; +} + +bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, VFS_MAJOR)) + { + _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); + pTable->m_pfnInitDirectory = &vfsInitDirectory; + pTable->m_pfnShutdown = &vfsShutdown; + pTable->m_pfnFreeFile = &vfsFreeFile; + pTable->m_pfnGetDirList = &vfsGetDirList; + pTable->m_pfnGetFileList = &vfsGetFileList; + pTable->m_pfnClearFileDirList = &vfsClearFileDirList; + pTable->m_pfnGetFileCount = &vfsGetFileCount; + pTable->m_pfnLoadFile = &vfsLoadFile; + pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; + pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; + pTable->m_pfnGetFullPath = &vfsGetFullPath; + pTable->m_pfnBasePromptPath = &vfsBasePromptPath; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientVFS::GetInfo() +{ + return "WAD VFS module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/vfswad/vfswad.def b/plugins/vfswad/vfswad.def new file mode 100644 index 00000000..45fa85c7 --- /dev/null +++ b/plugins/vfswad/vfswad.def @@ -0,0 +1,8 @@ +; vfswad.def : Declares the module parameters for the DLL. + +LIBRARY "vfswad" +DESCRIPTION 'vfswad Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/plugins/vfswad/vfswad.h b/plugins/vfswad/vfswad.h new file mode 100644 index 00000000..7e8cbb85 --- /dev/null +++ b/plugins/vfswad/vfswad.h @@ -0,0 +1,63 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _VFSWAD_H_ +#define _VFSWAD_H_ + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" + +extern _QERFuncTable_1 g_FuncTable; +extern CSynapseServer* g_pSynapseServer; + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf + +class CSynapseClientVFS : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientVFS() { } + virtual ~CSynapseClientVFS() { } +}; + +#endif // _VFSWAD_H_ diff --git a/plugins/vfswad/vfswad.txt b/plugins/vfswad/vfswad.txt new file mode 100644 index 00000000..a5afa599 --- /dev/null +++ b/plugins/vfswad/vfswad.txt @@ -0,0 +1,30 @@ +VFSWAD +====== + +Coding by Dominic Clifton - Hydra - hydra@hydras-world.com + +What is it ? +------------ + +This GTKRadiant 1.2+ plugin handles the extracting of files from .WAD files. +I'll refer to these files as .HLW files, even though they don't have any +extension when they're stored in the .WAD file itself. + +You need an image plugin to go with this plugin that can read .HLW files +My ImageHL plugin does just this. + +Developer Notes +--------------- + +The project file will copy the compiled DLL file and this .TXT file to +"$(HLRADIANTDIR)\modules" so make sure you have that environment variable +defined. + +For my GTKRadiant 1.2 HalfLife game pack files I use the directory: +"E:\games\HalfLife\Tools\GTKR12N\". Under which there are the directories +"modules" and "plugins" + +Credits +------- +Thanks to the guys that made Wally for releasing an example WAD loader. +without it this would not have been possible. diff --git a/plugins/vfswad/vfswad.vcproj b/plugins/vfswad/vfswad.vcproj new file mode 100644 index 00000000..7758c6a4 --- /dev/null +++ b/plugins/vfswad/vfswad.vcproj @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/radiant.sln b/radiant.sln new file mode 100644 index 00000000..bea3312f --- /dev/null +++ b/radiant.sln @@ -0,0 +1,168 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "radiant", "radiant\radiant.vcproj", "{65D02375-63EE-4A8A-9F8E-504B1D5A1D02}" + ProjectSection(ProjectDependencies) = postProject + {3886C418-A41E-4AFF-BBD1-8E1E508920C9} = {3886C418-A41E-4AFF-BBD1-8E1E508920C9} + {0B522841-BDCC-493A-BA5C-604AE2CD5756} = {0B522841-BDCC-493A-BA5C-604AE2CD5756} + {DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01} = {DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01} + {5DCC8086-830E-42E6-B080-5A287F8FF5DC} = {5DCC8086-830E-42E6-B080-5A287F8FF5DC} + {B1684CA7-AB7C-46A8-92A0-D621406FE041} = {B1684CA7-AB7C-46A8-92A0-D621406FE041} + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} = {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8} = {320CF5DE-0DFD-4C3F-B558-5F4098E111C8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "synapse", "libs\synapse\synapse.vcproj", "{E13CCFB0-A366-4EF3-A66F-C374B563E4DF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmdlib", "libs\cmdlib\cmdlib.vcproj", "{0B522841-BDCC-493A-BA5C-604AE2CD5756}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddslib", "libs\ddslib\ddslib.vcproj", "{5DCC8086-830E-42E6-B080-5A287F8FF5DC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg6", "libs\jpeg6\jpeg6.vcproj", "{B1684CA7-AB7C-46A8-92A0-D621406FE041}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "l_net", "libs\l_net\l_net.vcproj", "{3886C418-A41E-4AFF-BBD1-8E1E508920C9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathlib", "libs\mathlib\mathlib.vcproj", "{320CF5DE-0DFD-4C3F-B558-5F4098E111C8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md5lib", "libs\md5lib\md5lib.vcproj", "{DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "picomodel", "libs\picomodel\picomodel.vcproj", "{444E6FDA-83BD-49F1-89A4-7CF716F742A8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "camera", "contrib\camera\camera.vcproj", "{A43B5811-4BCC-483A-BDAC-F5721DCF9B4A}" + ProjectSection(ProjectDependencies) = postProject + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} = {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} + {6C1116CE-D99E-4629-9E69-A9329335D706} = {6C1116CE-D99E-4629-9E69-A9329335D706} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "entity", "plugins\entity\entity.vcproj", "{17DD38AA-4842-45BC-9304-2ADC1A12B4F4}" + ProjectSection(ProjectDependencies) = postProject + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8} = {320CF5DE-0DFD-4C3F-B558-5F4098E111C8} + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} = {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "image", "plugins\image\image.vcproj", "{1F9977F6-216F-4AE1-9928-59B72CF31C46}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagepng", "plugins\imagepng\imagepng.vcproj", "{43C01E60-21CC-49F5-8A11-F460BC866A31}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map", "plugins\map\map.vcproj", "{1B0E70B0-ED20-4021-9BBE-5168CB8DAE90}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapxml", "plugins\mapxml\mapxml.vcproj", "{DDBF170A-42DF-4836-9006-816422E08493}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "model", "plugins\model\model.vcproj", "{83C877DA-17B2-4863-B085-06AE9A8D68F3}" + ProjectSection(ProjectDependencies) = postProject + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} = {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} + {444E6FDA-83BD-49F1-89A4-7CF716F742A8} = {444E6FDA-83BD-49F1-89A4-7CF716F742A8} + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8} = {320CF5DE-0DFD-4C3F-B558-5F4098E111C8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders", "plugins\shaders\shaders.vcproj", "{AEBCB950-AB67-48BB-9AF5-FCFB042824E8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "surface", "plugins\surface\surface.vcproj", "{6FDF6CFE-52FF-4E8C-A6F6-C0392DAE4DB7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vfspk3", "plugins\vfspk3\vfspk3.vcproj", "{DEFCF433-3A47-40EB-BBF7-861211C3A941}" + ProjectSection(ProjectDependencies) = postProject + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} = {E13CCFB0-A366-4EF3-A66F-C374B563E4DF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Splines", "libs\splines\Splines.vcproj", "{6C1116CE-D99E-4629-9E69-A9329335D706}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3map2", "tools\quake3\q3map2\q3map2.vcproj", "{F5D0509C-80E0-49B7-B033-885D8253063A}" + ProjectSection(ProjectDependencies) = postProject + {B1684CA7-AB7C-46A8-92A0-D621406FE041} = {B1684CA7-AB7C-46A8-92A0-D621406FE041} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {65D02375-63EE-4A8A-9F8E-504B1D5A1D02}.Debug|Win32.ActiveCfg = Debug|Win32 + {65D02375-63EE-4A8A-9F8E-504B1D5A1D02}.Debug|Win32.Build.0 = Debug|Win32 + {65D02375-63EE-4A8A-9F8E-504B1D5A1D02}.Release|Win32.ActiveCfg = Release|Win32 + {65D02375-63EE-4A8A-9F8E-504B1D5A1D02}.Release|Win32.Build.0 = Release|Win32 + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF}.Debug|Win32.ActiveCfg = Debug|Win32 + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF}.Debug|Win32.Build.0 = Debug|Win32 + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF}.Release|Win32.ActiveCfg = Release|Win32 + {E13CCFB0-A366-4EF3-A66F-C374B563E4DF}.Release|Win32.Build.0 = Release|Win32 + {0B522841-BDCC-493A-BA5C-604AE2CD5756}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B522841-BDCC-493A-BA5C-604AE2CD5756}.Debug|Win32.Build.0 = Debug|Win32 + {0B522841-BDCC-493A-BA5C-604AE2CD5756}.Release|Win32.ActiveCfg = Release|Win32 + {0B522841-BDCC-493A-BA5C-604AE2CD5756}.Release|Win32.Build.0 = Release|Win32 + {5DCC8086-830E-42E6-B080-5A287F8FF5DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {5DCC8086-830E-42E6-B080-5A287F8FF5DC}.Debug|Win32.Build.0 = Debug|Win32 + {5DCC8086-830E-42E6-B080-5A287F8FF5DC}.Release|Win32.ActiveCfg = Release|Win32 + {5DCC8086-830E-42E6-B080-5A287F8FF5DC}.Release|Win32.Build.0 = Release|Win32 + {B1684CA7-AB7C-46A8-92A0-D621406FE041}.Debug|Win32.ActiveCfg = Debug|Win32 + {B1684CA7-AB7C-46A8-92A0-D621406FE041}.Debug|Win32.Build.0 = Debug|Win32 + {B1684CA7-AB7C-46A8-92A0-D621406FE041}.Release|Win32.ActiveCfg = Release|Win32 + {B1684CA7-AB7C-46A8-92A0-D621406FE041}.Release|Win32.Build.0 = Release|Win32 + {3886C418-A41E-4AFF-BBD1-8E1E508920C9}.Debug|Win32.ActiveCfg = Debug|Win32 + {3886C418-A41E-4AFF-BBD1-8E1E508920C9}.Debug|Win32.Build.0 = Debug|Win32 + {3886C418-A41E-4AFF-BBD1-8E1E508920C9}.Release|Win32.ActiveCfg = Release|Win32 + {3886C418-A41E-4AFF-BBD1-8E1E508920C9}.Release|Win32.Build.0 = Release|Win32 + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8}.Debug|Win32.Build.0 = Debug|Win32 + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8}.Release|Win32.ActiveCfg = Release|Win32 + {320CF5DE-0DFD-4C3F-B558-5F4098E111C8}.Release|Win32.Build.0 = Release|Win32 + {DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01}.Debug|Win32.ActiveCfg = Debug|Win32 + {DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01}.Debug|Win32.Build.0 = Debug|Win32 + {DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01}.Release|Win32.ActiveCfg = Release|Win32 + {DC2F2B6B-2596-4B90-88CE-2FDE4C2FFB01}.Release|Win32.Build.0 = Release|Win32 + {444E6FDA-83BD-49F1-89A4-7CF716F742A8}.Debug|Win32.ActiveCfg = Debug|Win32 + {444E6FDA-83BD-49F1-89A4-7CF716F742A8}.Debug|Win32.Build.0 = Debug|Win32 + {444E6FDA-83BD-49F1-89A4-7CF716F742A8}.Release|Win32.ActiveCfg = Release|Win32 + {444E6FDA-83BD-49F1-89A4-7CF716F742A8}.Release|Win32.Build.0 = Release|Win32 + {A43B5811-4BCC-483A-BDAC-F5721DCF9B4A}.Debug|Win32.ActiveCfg = Debug|Win32 + {A43B5811-4BCC-483A-BDAC-F5721DCF9B4A}.Debug|Win32.Build.0 = Debug|Win32 + {A43B5811-4BCC-483A-BDAC-F5721DCF9B4A}.Release|Win32.ActiveCfg = Release|Win32 + {A43B5811-4BCC-483A-BDAC-F5721DCF9B4A}.Release|Win32.Build.0 = Release|Win32 + {17DD38AA-4842-45BC-9304-2ADC1A12B4F4}.Debug|Win32.ActiveCfg = Debug|Win32 + {17DD38AA-4842-45BC-9304-2ADC1A12B4F4}.Debug|Win32.Build.0 = Debug|Win32 + {17DD38AA-4842-45BC-9304-2ADC1A12B4F4}.Release|Win32.ActiveCfg = Release|Win32 + {17DD38AA-4842-45BC-9304-2ADC1A12B4F4}.Release|Win32.Build.0 = Release|Win32 + {1F9977F6-216F-4AE1-9928-59B72CF31C46}.Debug|Win32.ActiveCfg = Debug|Win32 + {1F9977F6-216F-4AE1-9928-59B72CF31C46}.Debug|Win32.Build.0 = Debug|Win32 + {1F9977F6-216F-4AE1-9928-59B72CF31C46}.Release|Win32.ActiveCfg = Release|Win32 + {1F9977F6-216F-4AE1-9928-59B72CF31C46}.Release|Win32.Build.0 = Release|Win32 + {43C01E60-21CC-49F5-8A11-F460BC866A31}.Debug|Win32.ActiveCfg = Debug|Win32 + {43C01E60-21CC-49F5-8A11-F460BC866A31}.Debug|Win32.Build.0 = Debug|Win32 + {43C01E60-21CC-49F5-8A11-F460BC866A31}.Release|Win32.ActiveCfg = Release|Win32 + {43C01E60-21CC-49F5-8A11-F460BC866A31}.Release|Win32.Build.0 = Release|Win32 + {1B0E70B0-ED20-4021-9BBE-5168CB8DAE90}.Debug|Win32.ActiveCfg = Debug|Win32 + {1B0E70B0-ED20-4021-9BBE-5168CB8DAE90}.Debug|Win32.Build.0 = Debug|Win32 + {1B0E70B0-ED20-4021-9BBE-5168CB8DAE90}.Release|Win32.ActiveCfg = Release|Win32 + {1B0E70B0-ED20-4021-9BBE-5168CB8DAE90}.Release|Win32.Build.0 = Release|Win32 + {DDBF170A-42DF-4836-9006-816422E08493}.Debug|Win32.ActiveCfg = Debug|Win32 + {DDBF170A-42DF-4836-9006-816422E08493}.Debug|Win32.Build.0 = Debug|Win32 + {DDBF170A-42DF-4836-9006-816422E08493}.Release|Win32.ActiveCfg = Release|Win32 + {DDBF170A-42DF-4836-9006-816422E08493}.Release|Win32.Build.0 = Release|Win32 + {83C877DA-17B2-4863-B085-06AE9A8D68F3}.Debug|Win32.ActiveCfg = Debug|Win32 + {83C877DA-17B2-4863-B085-06AE9A8D68F3}.Debug|Win32.Build.0 = Debug|Win32 + {83C877DA-17B2-4863-B085-06AE9A8D68F3}.Release|Win32.ActiveCfg = Release|Win32 + {83C877DA-17B2-4863-B085-06AE9A8D68F3}.Release|Win32.Build.0 = Release|Win32 + {AEBCB950-AB67-48BB-9AF5-FCFB042824E8}.Debug|Win32.ActiveCfg = Debug|Win32 + {AEBCB950-AB67-48BB-9AF5-FCFB042824E8}.Debug|Win32.Build.0 = Debug|Win32 + {AEBCB950-AB67-48BB-9AF5-FCFB042824E8}.Release|Win32.ActiveCfg = Release|Win32 + {AEBCB950-AB67-48BB-9AF5-FCFB042824E8}.Release|Win32.Build.0 = Release|Win32 + {6FDF6CFE-52FF-4E8C-A6F6-C0392DAE4DB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6FDF6CFE-52FF-4E8C-A6F6-C0392DAE4DB7}.Debug|Win32.Build.0 = Debug|Win32 + {6FDF6CFE-52FF-4E8C-A6F6-C0392DAE4DB7}.Release|Win32.ActiveCfg = Release|Win32 + {6FDF6CFE-52FF-4E8C-A6F6-C0392DAE4DB7}.Release|Win32.Build.0 = Release|Win32 + {DEFCF433-3A47-40EB-BBF7-861211C3A941}.Debug|Win32.ActiveCfg = Debug|Win32 + {DEFCF433-3A47-40EB-BBF7-861211C3A941}.Debug|Win32.Build.0 = Debug|Win32 + {DEFCF433-3A47-40EB-BBF7-861211C3A941}.Release|Win32.ActiveCfg = Release|Win32 + {DEFCF433-3A47-40EB-BBF7-861211C3A941}.Release|Win32.Build.0 = Release|Win32 + {6C1116CE-D99E-4629-9E69-A9329335D706}.Debug|Win32.ActiveCfg = Debug|Win32 + {6C1116CE-D99E-4629-9E69-A9329335D706}.Debug|Win32.Build.0 = Debug|Win32 + {6C1116CE-D99E-4629-9E69-A9329335D706}.Release|Win32.ActiveCfg = Release|Win32 + {6C1116CE-D99E-4629-9E69-A9329335D706}.Release|Win32.Build.0 = Release|Win32 + {F5D0509C-80E0-49B7-B033-885D8253063A}.Debug|Win32.ActiveCfg = Debug|Win32 + {F5D0509C-80E0-49B7-B033-885D8253063A}.Debug|Win32.Build.0 = Debug|Win32 + {F5D0509C-80E0-49B7-B033-885D8253063A}.Release|Win32.ActiveCfg = Release|Win32 + {F5D0509C-80E0-49B7-B033-885D8253063A}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/radiant.sln.ref b/radiant.sln.ref new file mode 100644 index 00000000..61d6fb2c --- /dev/null +++ b/radiant.sln.ref @@ -0,0 +1,1174 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GtkRadiant", "radiant\GtkRadiant.vcproj", "{8B4BF693-2EDC-4102-AD6E-236081F6B108}" + ProjectSection(ProjectDependencies) = postProject + {07F4CA3B-F38B-45F9-90EB-63BE0207509C} = {07F4CA3B-F38B-45F9-90EB-63BE0207509C} + {3646D8A8-8054-45AF-AAD0-981E287E3AD0} = {3646D8A8-8054-45AF-AAD0-981E287E3AD0} + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {7C304AF9-A9DF-47F6-9856-65E8D815BE18} = {7C304AF9-A9DF-47F6-9856-65E8D815BE18} + {511245E6-1A00-4C24-B528-DF1202CC9A8A} = {511245E6-1A00-4C24-B528-DF1202CC9A8A} + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76} = {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76} + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675} = {DD7D35A8-77B0-4A80-B301-A6ADDC10F675} + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD} = {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD} + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE} = {4EDCB80E-093D-4C69-AA08-E2968F8F07FE} + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + {FDF3762B-398F-47CC-96B6-9F355C408798} = {FDF3762B-398F-47CC-96B6-9F355C408798} + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} = {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} + {14C1D466-31E6-4A74-9D45-D41ACB8E2857} = {14C1D466-31E6-4A74-9D45-D41ACB8E2857} + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4} = {88D28E9E-74E7-434D-B182-8E0D93A5DCB4} + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE} = {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE} + {4C41B124-B378-4849-812C-1AE36103850D} = {4C41B124-B378-4849-812C-1AE36103850D} + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229} = {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229} + {7F443DE2-FA15-4D9A-8641-B307561D4F3A} = {7F443DE2-FA15-4D9A-8641-B307561D4F3A} + {032F4468-26AC-4EFC-8E57-EA31921BA200} = {032F4468-26AC-4EFC-8E57-EA31921BA200} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrtView", "contrib\prtview\PrtView.vcproj", "{C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}" + ProjectSection(ProjectDependencies) = postProject + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76} = {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76} + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Splines", "libs\splines\Splines.vcproj", "{7C304AF9-A9DF-47F6-9856-65E8D815BE18}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bobToolz_gtk", "contrib\bobtoolz\bobToolz_gtk.vcproj", "{6F711EA0-4EA8-46E0-9623-0774ADA64BFF}" + ProjectSection(ProjectDependencies) = postProject + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {7F443DE2-FA15-4D9A-8641-B307561D4F3A} = {7F443DE2-FA15-4D9A-8641-B307561D4F3A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "camera", "contrib\camera\camera.vcproj", "{032F4468-26AC-4EFC-8E57-EA31921BA200}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {7C304AF9-A9DF-47F6-9856-65E8D815BE18} = {7C304AF9-A9DF-47F6-9856-65E8D815BE18} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmdlib", "libs\cmdlib\cmdlib.vcproj", "{7F443DE2-FA15-4D9A-8641-B307561D4F3A}" + ProjectSection(ProjectDependencies) = postProject + {7C304AF9-A9DF-47F6-9856-65E8D815BE18} = {7C304AF9-A9DF-47F6-9856-65E8D815BE18} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddslib", "libs\ddslib\ddslib.vcproj", "{0CFFBFAB-92DF-4882-A528-701587142A85}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "entity", "plugins\entity\entity.vcproj", "{B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fgd", "plugins\eclassfgd\fgd.vcproj", "{929A0B03-4F92-44E1-AAB3-D32F40540634}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gen", "gen.vcproj", "{4C41B124-B378-4849-812C-1AE36103850D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtkgensurf", "contrib\gtkgensurf\gtkgensurf.vcproj", "{6B1A3D69-C0FB-47C9-ADA4-D64370A82723}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hydratoolz", "contrib\hydratoolz\hydratoolz.vcproj", "{22200A84-00D4-44B7-B044-64111BDD94EC}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "image", "plugins\image\image.vcproj", "{63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {14C1D466-31E6-4A74-9D45-D41ACB8E2857} = {14C1D466-31E6-4A74-9D45-D41ACB8E2857} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagehl", "plugins\imagehl\imagehl.vcproj", "{45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagem8", "plugins\imagem8\imagem8.vcproj", "{BBDE9008-7972-4727-80EB-E9575F2FBFE8}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagepng", "plugins\imagepng\imagepng.vcproj", "{88D28E9E-74E7-434D-B182-8E0D93A5DCB4}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagewal", "plugins\imagewal\imagewal.vcproj", "{49769BB7-A293-4B03-B28E-16212E03A742}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg6", "libs\jpeg6\jpeg6.vcproj", "{14C1D466-31E6-4A74-9D45-D41ACB8E2857}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "l_net", "libs\l_net\l_net.vcproj", "{90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapq3", "plugins\map\map.vcproj", "{FDF3762B-398F-47CC-96B6-9F355C408798}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {7F443DE2-FA15-4D9A-8641-B307561D4F3A} = {7F443DE2-FA15-4D9A-8641-B307561D4F3A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapxml", "plugins\mapxml\mapxml.vcproj", "{D1E7F1DE-8489-452C-B176-D0CAC410FA6E}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {7F443DE2-FA15-4D9A-8641-B307561D4F3A} = {7F443DE2-FA15-4D9A-8641-B307561D4F3A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathlib", "libs\mathlib\mathlib.vcproj", "{ADF8E361-1045-4603-9586-ACB5494BC96C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md5lib", "libs\md5lib\md5lib.vcproj", "{63D4D041-B5FE-4B85-882C-94EF70595055}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "model", "plugins\model\model.vcproj", "{4EDCB80E-093D-4C69-AA08-E2968F8F07FE}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD} = {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD} + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "picomodel", "libs\picomodel\picomodel.vcproj", "{E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q2map", "tools\quake2\q2map\q2map.vcproj", "{ECEF63AC-6D19-400E-A220-7D66ADA62A06}" + ProjectSection(ProjectDependencies) = postProject + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} = {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3data", "tools\quake3\q3data\q3data.vcproj", "{DD7D35A8-77B0-4A80-B301-A6ADDC10F675}" + ProjectSection(ProjectDependencies) = postProject + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} = {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3map2", "tools\quake3\q3map2\q3map2.vcproj", "{005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}" + ProjectSection(ProjectDependencies) = postProject + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD} = {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD} + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} = {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} + {14C1D466-31E6-4A74-9D45-D41ACB8E2857} = {14C1D466-31E6-4A74-9D45-D41ACB8E2857} + {0CFFBFAB-92DF-4882-A528-701587142A85} = {0CFFBFAB-92DF-4882-A528-701587142A85} + {63D4D041-B5FE-4B85-882C-94EF70595055} = {63D4D041-B5FE-4B85-882C-94EF70595055} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qdata3", "tools\quake2\qdata\qdata3.vcproj", "{202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}" + ProjectSection(ProjectDependencies) = postProject + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} = {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qdata3_heretic2", "tools\quake2\qdata_heretic2\qdata3_heretic2.vcproj", "{EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}" + ProjectSection(ProjectDependencies) = postProject + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} = {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders", "plugins\shaders\shaders.vcproj", "{511245E6-1A00-4C24-B528-DF1202CC9A8A}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spritemodel", "plugins\spritemodel\spritemodel.vcproj", "{7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + {ADF8E361-1045-4603-9586-ACB5494BC96C} = {ADF8E361-1045-4603-9586-ACB5494BC96C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "surface", "plugins\surface\surface.vcproj", "{07F4CA3B-F38B-45F9-90EB-63BE0207509C}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "surface_heretic2", "plugins\SURFACE_HERETIC2\surface_heretic2.vcproj", "{916A982C-D2C1-4A40-9488-CF5A9985B2FF}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "surface_quake2", "plugins\surface_quake2\surface_quake2.vcproj", "{1E5C7743-ACA0-4423-B40C-0A0E01365A2D}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "synapse", "libs\synapse\synapse.vcproj", "{6D64135F-A762-4B15-9CE7-68B606F68CAE}" + ProjectSection(ProjectDependencies) = postProject + {4C41B124-B378-4849-812C-1AE36103850D} = {4C41B124-B378-4849-812C-1AE36103850D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vfspak", "plugins\vfspak\vfspak.vcproj", "{9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vfspk3", "plugins\vfspk3\vfspk3.vcproj", "{3646D8A8-8054-45AF-AAD0-981E287E3AD0}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vfswad", "plugins\vfswad\vfswad.vcproj", "{F709400A-3B59-4508-843B-01105460A1F4}" + ProjectSection(ProjectDependencies) = postProject + {6D64135F-A762-4B15-9CE7-68B606F68CAE} = {6D64135F-A762-4B15-9CE7-68B606F68CAE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bkgrnd2d", "contrib\bkgrnd2d\bkgrnd2d.vcproj", "{356A36AA-1F10-48A0-BF63-227DFB46F208}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug (Q3Map2)|Win32 = Debug (Q3Map2)|Win32 + Debug|Win32 = Debug|Win32 + DLL ASM Debug|Win32 = DLL ASM Debug|Win32 + DLL ASM Release|Win32 = DLL ASM Release|Win32 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Release|Win32 = DLL Release|Win32 + DLL VB|Win32 = DLL VB|Win32 + LIB ASM Debug|Win32 = LIB ASM Debug|Win32 + LIB ASM Release|Win32 = LIB ASM Release|Win32 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Release|Win32 = LIB Release|Win32 + Release (Q3Map2)|Win32 = Release (Q3Map2)|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.Debug|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.Debug|Win32.Build.0 = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL Debug|Win32.Build.0 = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL Release|Win32.ActiveCfg = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL Release|Win32.Build.0 = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.DLL VB|Win32.Build.0 = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB Debug|Win32.Build.0 = Debug|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB Release|Win32.ActiveCfg = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.LIB Release|Win32.Build.0 = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.Release|Win32.ActiveCfg = Release|Win32 + {8B4BF693-2EDC-4102-AD6E-236081F6B108}.Release|Win32.Build.0 = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.Debug|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL Debug|Win32.Build.0 = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL Release|Win32.ActiveCfg = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL Release|Win32.Build.0 = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.DLL VB|Win32.Build.0 = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB Debug|Win32.Build.0 = Debug|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB Release|Win32.ActiveCfg = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.LIB Release|Win32.Build.0 = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {C403CC21-8ECF-4D99-9C6B-BDBFA61012DD}.Release|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.Debug|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.Debug|Win32.Build.0 = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL Debug|Win32.Build.0 = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL Release|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL Release|Win32.Build.0 = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.DLL VB|Win32.Build.0 = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB Debug|Win32.Build.0 = Debug|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB Release|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.LIB Release|Win32.Build.0 = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.Release|Win32.ActiveCfg = Release|Win32 + {7C304AF9-A9DF-47F6-9856-65E8D815BE18}.Release|Win32.Build.0 = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL Debug|Win32.Build.0 = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL Release|Win32.ActiveCfg = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL Release|Win32.Build.0 = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.DLL VB|Win32.Build.0 = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB Debug|Win32.Build.0 = Debug|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB Release|Win32.ActiveCfg = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.LIB Release|Win32.Build.0 = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {6F711EA0-4EA8-46E0-9623-0774ADA64BFF}.Release|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.Debug|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.Debug|Win32.Build.0 = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL Debug|Win32.Build.0 = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL Release|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL Release|Win32.Build.0 = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.DLL VB|Win32.Build.0 = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB Debug|Win32.Build.0 = Debug|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB Release|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.LIB Release|Win32.Build.0 = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.Release|Win32.ActiveCfg = Release|Win32 + {032F4468-26AC-4EFC-8E57-EA31921BA200}.Release|Win32.Build.0 = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.Debug|Win32.Build.0 = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL Debug|Win32.Build.0 = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL Release|Win32.ActiveCfg = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL Release|Win32.Build.0 = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.DLL VB|Win32.Build.0 = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB Debug|Win32.Build.0 = Debug|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB Release|Win32.ActiveCfg = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.LIB Release|Win32.Build.0 = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.Release|Win32.ActiveCfg = Release|Win32 + {7F443DE2-FA15-4D9A-8641-B307561D4F3A}.Release|Win32.Build.0 = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Debug|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Debug|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL Debug|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL Release|Win32.ActiveCfg = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL Release|Win32.Build.0 = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.DLL VB|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB Debug|Win32.Build.0 = Debug|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB Release|Win32.ActiveCfg = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.LIB Release|Win32.Build.0 = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Release|Win32.ActiveCfg = Release|Win32 + {0CFFBFAB-92DF-4882-A528-701587142A85}.Release|Win32.Build.0 = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.Debug|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.Debug|Win32.Build.0 = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL Debug|Win32.Build.0 = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL Release|Win32.ActiveCfg = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL Release|Win32.Build.0 = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.DLL VB|Win32.Build.0 = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB Debug|Win32.Build.0 = Debug|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB Release|Win32.ActiveCfg = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.LIB Release|Win32.Build.0 = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.Release|Win32.ActiveCfg = Release|Win32 + {B31BD7A8-8B32-4631-ADDF-BA81C6C3E229}.Release|Win32.Build.0 = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.Debug|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL Debug|Win32.Build.0 = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL Release|Win32.ActiveCfg = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL Release|Win32.Build.0 = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.DLL VB|Win32.Build.0 = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB Debug|Win32.Build.0 = Debug|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB Release|Win32.ActiveCfg = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.LIB Release|Win32.Build.0 = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {929A0B03-4F92-44E1-AAB3-D32F40540634}.Release|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.Debug|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.Debug|Win32.Build.0 = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL Debug|Win32.Build.0 = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL Release|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL Release|Win32.Build.0 = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.DLL VB|Win32.Build.0 = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB Debug|Win32.Build.0 = Debug|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB Release|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.LIB Release|Win32.Build.0 = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.Release|Win32.ActiveCfg = Release|Win32 + {4C41B124-B378-4849-812C-1AE36103850D}.Release|Win32.Build.0 = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL Debug|Win32.Build.0 = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL Release|Win32.ActiveCfg = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL Release|Win32.Build.0 = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.DLL VB|Win32.Build.0 = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB Debug|Win32.Build.0 = Debug|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB Release|Win32.ActiveCfg = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.LIB Release|Win32.Build.0 = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {6B1A3D69-C0FB-47C9-ADA4-D64370A82723}.Release|Win32.ActiveCfg = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.Debug|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL Debug|Win32.Build.0 = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL Release|Win32.ActiveCfg = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL Release|Win32.Build.0 = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.DLL VB|Win32.Build.0 = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB Debug|Win32.Build.0 = Debug|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB Release|Win32.ActiveCfg = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.LIB Release|Win32.Build.0 = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {22200A84-00D4-44B7-B044-64111BDD94EC}.Release|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.Debug|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.Debug|Win32.Build.0 = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL Debug|Win32.Build.0 = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL Release|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL Release|Win32.Build.0 = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.DLL VB|Win32.Build.0 = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB Debug|Win32.Build.0 = Debug|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB Release|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.LIB Release|Win32.Build.0 = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.Release|Win32.ActiveCfg = Release|Win32 + {63D8BE69-F5D8-4D29-BD25-0FFA63DCCABE}.Release|Win32.Build.0 = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.Debug|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL Debug|Win32.Build.0 = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL Release|Win32.ActiveCfg = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL Release|Win32.Build.0 = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.DLL VB|Win32.Build.0 = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB Debug|Win32.Build.0 = Debug|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB Release|Win32.ActiveCfg = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.LIB Release|Win32.Build.0 = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {45DAB3CC-7E9F-4607-9902-A9F6BD9A731F}.Release|Win32.ActiveCfg = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.Debug|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL Debug|Win32.Build.0 = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL Release|Win32.ActiveCfg = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL Release|Win32.Build.0 = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.DLL VB|Win32.Build.0 = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB Debug|Win32.Build.0 = Debug|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB Release|Win32.ActiveCfg = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.LIB Release|Win32.Build.0 = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {BBDE9008-7972-4727-80EB-E9575F2FBFE8}.Release|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.Debug|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.Debug|Win32.Build.0 = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL Debug|Win32.Build.0 = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL Release|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL Release|Win32.Build.0 = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.DLL VB|Win32.Build.0 = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB Debug|Win32.Build.0 = Debug|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB Release|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.LIB Release|Win32.Build.0 = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.Release|Win32.ActiveCfg = Release|Win32 + {88D28E9E-74E7-434D-B182-8E0D93A5DCB4}.Release|Win32.Build.0 = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.Debug|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL Debug|Win32.Build.0 = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL Release|Win32.ActiveCfg = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL Release|Win32.Build.0 = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.DLL VB|Win32.Build.0 = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB Debug|Win32.Build.0 = Debug|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB Release|Win32.ActiveCfg = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.LIB Release|Win32.Build.0 = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {49769BB7-A293-4B03-B28E-16212E03A742}.Release|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Debug|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Debug|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL Debug|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL Release|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL Release|Win32.Build.0 = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.DLL VB|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB Debug|Win32.Build.0 = Debug|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB Release|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.LIB Release|Win32.Build.0 = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Release|Win32.ActiveCfg = Release|Win32 + {14C1D466-31E6-4A74-9D45-D41ACB8E2857}.Release|Win32.Build.0 = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Debug|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Debug|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL Debug|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL Release|Win32.ActiveCfg = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL Release|Win32.Build.0 = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.DLL VB|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB Debug|Win32.Build.0 = Debug|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB Release|Win32.ActiveCfg = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.LIB Release|Win32.Build.0 = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Release|Win32.ActiveCfg = Release|Win32 + {90CAE4F3-7CA7-4337-9AC0-46C7CCC48CFE}.Release|Win32.Build.0 = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.Debug|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.Debug|Win32.Build.0 = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL Debug|Win32.Build.0 = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL Release|Win32.ActiveCfg = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL Release|Win32.Build.0 = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.DLL VB|Win32.Build.0 = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB Debug|Win32.Build.0 = Debug|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB Release|Win32.ActiveCfg = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.LIB Release|Win32.Build.0 = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.Release|Win32.ActiveCfg = Release|Win32 + {FDF3762B-398F-47CC-96B6-9F355C408798}.Release|Win32.Build.0 = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.Debug|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.Debug|Win32.Build.0 = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL Debug|Win32.Build.0 = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL Release|Win32.ActiveCfg = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL Release|Win32.Build.0 = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.DLL VB|Win32.Build.0 = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB Debug|Win32.Build.0 = Debug|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB Release|Win32.ActiveCfg = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.LIB Release|Win32.Build.0 = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.Release|Win32.ActiveCfg = Release|Win32 + {D1E7F1DE-8489-452C-B176-D0CAC410FA6E}.Release|Win32.Build.0 = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Debug|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL Debug|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL Release|Win32.ActiveCfg = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL Release|Win32.Build.0 = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.DLL VB|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB Debug|Win32.Build.0 = Debug|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB Release|Win32.ActiveCfg = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.LIB Release|Win32.Build.0 = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Release|Win32.ActiveCfg = Release|Win32 + {ADF8E361-1045-4603-9586-ACB5494BC96C}.Release|Win32.Build.0 = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Debug|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Debug|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL Debug|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL Release|Win32.ActiveCfg = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL Release|Win32.Build.0 = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.DLL VB|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB Debug|Win32.Build.0 = Debug|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB Release|Win32.ActiveCfg = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.LIB Release|Win32.Build.0 = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Release|Win32.ActiveCfg = Release|Win32 + {63D4D041-B5FE-4B85-882C-94EF70595055}.Release|Win32.Build.0 = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.Debug|Win32.Build.0 = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL Debug|Win32.Build.0 = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL Release|Win32.ActiveCfg = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL Release|Win32.Build.0 = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.DLL VB|Win32.Build.0 = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB Debug|Win32.Build.0 = Debug|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB Release|Win32.ActiveCfg = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.LIB Release|Win32.Build.0 = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.Release|Win32.ActiveCfg = Release|Win32 + {4EDCB80E-093D-4C69-AA08-E2968F8F07FE}.Release|Win32.Build.0 = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Debug|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL Debug|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL Release|Win32.ActiveCfg = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL Release|Win32.Build.0 = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.DLL VB|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB Debug|Win32.Build.0 = Debug|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB Release|Win32.ActiveCfg = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.LIB Release|Win32.Build.0 = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Release|Win32.ActiveCfg = Release|Win32 + {E9AF9076-F5DC-4E3E-AEFD-C6EFCDC51ACD}.Release|Win32.Build.0 = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.Debug|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL Debug|Win32.Build.0 = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL Release|Win32.ActiveCfg = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL Release|Win32.Build.0 = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.DLL VB|Win32.Build.0 = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB Debug|Win32.Build.0 = Debug|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB Release|Win32.ActiveCfg = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.LIB Release|Win32.Build.0 = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {ECEF63AC-6D19-400E-A220-7D66ADA62A06}.Release|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.Debug|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.Debug|Win32.Build.0 = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL Debug|Win32.Build.0 = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL Release|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL Release|Win32.Build.0 = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.DLL VB|Win32.Build.0 = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB Debug|Win32.Build.0 = Debug|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB Release|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.LIB Release|Win32.Build.0 = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.Release|Win32.ActiveCfg = Release|Win32 + {DD7D35A8-77B0-4A80-B301-A6ADDC10F675}.Release|Win32.Build.0 = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Debug (Q3Map2)|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Debug|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Debug|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL Debug|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL Release|Win32.ActiveCfg = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL Release|Win32.Build.0 = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.DLL VB|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB Debug|Win32.Build.0 = Debug|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB Release|Win32.ActiveCfg = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.LIB Release|Win32.Build.0 = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Release (Q3Map2)|Win32.Build.0 = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Release|Win32.ActiveCfg = Release|Win32 + {005E1AE8-2A4D-44F9-A9A4-55A5E4EFFD76}.Release|Win32.Build.0 = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.Debug|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL Debug|Win32.Build.0 = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL Release|Win32.ActiveCfg = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL Release|Win32.Build.0 = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.DLL VB|Win32.Build.0 = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB Debug|Win32.Build.0 = Debug|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB Release|Win32.ActiveCfg = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.LIB Release|Win32.Build.0 = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {202F4F4A-9317-4CBD-9F48-9EFE9C65DE5B}.Release|Win32.ActiveCfg = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.Debug|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL Debug|Win32.Build.0 = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL Release|Win32.ActiveCfg = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL Release|Win32.Build.0 = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.DLL VB|Win32.Build.0 = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB Debug|Win32.Build.0 = Debug|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB Release|Win32.ActiveCfg = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.LIB Release|Win32.Build.0 = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {EE940EE3-582C-4D3F-B0E3-6BA2BDB12BF1}.Release|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.Debug|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.Debug|Win32.Build.0 = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL Debug|Win32.Build.0 = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL Release|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL Release|Win32.Build.0 = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.DLL VB|Win32.Build.0 = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB Debug|Win32.Build.0 = Debug|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB Release|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.LIB Release|Win32.Build.0 = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.Release|Win32.ActiveCfg = Release|Win32 + {511245E6-1A00-4C24-B528-DF1202CC9A8A}.Release|Win32.Build.0 = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL Debug|Win32.Build.0 = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL Release|Win32.ActiveCfg = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL Release|Win32.Build.0 = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.DLL VB|Win32.Build.0 = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB Debug|Win32.Build.0 = Debug|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB Release|Win32.ActiveCfg = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.LIB Release|Win32.Build.0 = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {7F30EE07-9FDF-42FD-954D-99C7C8D6A0E0}.Release|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.Debug|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.Debug|Win32.Build.0 = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL Debug|Win32.Build.0 = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL Release|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL Release|Win32.Build.0 = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.DLL VB|Win32.Build.0 = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB Debug|Win32.Build.0 = Debug|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB Release|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.LIB Release|Win32.Build.0 = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.Release|Win32.ActiveCfg = Release|Win32 + {07F4CA3B-F38B-45F9-90EB-63BE0207509C}.Release|Win32.Build.0 = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL Debug|Win32.Build.0 = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL Release|Win32.ActiveCfg = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL Release|Win32.Build.0 = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.DLL VB|Win32.Build.0 = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB Debug|Win32.Build.0 = Debug|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB Release|Win32.ActiveCfg = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.LIB Release|Win32.Build.0 = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {916A982C-D2C1-4A40-9488-CF5A9985B2FF}.Release|Win32.ActiveCfg = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.Debug|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL Debug|Win32.Build.0 = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL Release|Win32.ActiveCfg = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL Release|Win32.Build.0 = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.DLL VB|Win32.Build.0 = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB Debug|Win32.Build.0 = Debug|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB Release|Win32.ActiveCfg = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.LIB Release|Win32.Build.0 = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {1E5C7743-ACA0-4423-B40C-0A0E01365A2D}.Release|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.Debug|Win32.Build.0 = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL Debug|Win32.Build.0 = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL Release|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL Release|Win32.Build.0 = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.DLL VB|Win32.Build.0 = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB Debug|Win32.Build.0 = Debug|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB Release|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.LIB Release|Win32.Build.0 = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.Release|Win32.ActiveCfg = Release|Win32 + {6D64135F-A762-4B15-9CE7-68B606F68CAE}.Release|Win32.Build.0 = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.Debug|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL Debug|Win32.Build.0 = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL Release|Win32.ActiveCfg = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL Release|Win32.Build.0 = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.DLL VB|Win32.Build.0 = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB Debug|Win32.Build.0 = Debug|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB Release|Win32.ActiveCfg = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.LIB Release|Win32.Build.0 = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {9FB5C1FD-DA07-470A-AECC-BDA2F2F65A15}.Release|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.Debug|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.Debug|Win32.Build.0 = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL Debug|Win32.Build.0 = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL Release|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL Release|Win32.Build.0 = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.DLL VB|Win32.Build.0 = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB Debug|Win32.Build.0 = Debug|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB Release|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.LIB Release|Win32.Build.0 = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.Release|Win32.ActiveCfg = Release|Win32 + {3646D8A8-8054-45AF-AAD0-981E287E3AD0}.Release|Win32.Build.0 = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.Debug|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL Debug|Win32.Build.0 = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL Release|Win32.ActiveCfg = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL Release|Win32.Build.0 = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.DLL VB|Win32.Build.0 = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB Debug|Win32.Build.0 = Debug|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB Release|Win32.ActiveCfg = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.LIB Release|Win32.Build.0 = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {F709400A-3B59-4508-843B-01105460A1F4}.Release|Win32.ActiveCfg = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.Debug (Q3Map2)|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.Debug|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL ASM Debug|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL ASM Debug|Win32.Build.0 = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL ASM Release|Win32.ActiveCfg = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL ASM Release|Win32.Build.0 = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL Debug|Win32.Build.0 = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL Release|Win32.ActiveCfg = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL Release|Win32.Build.0 = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL VB|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.DLL VB|Win32.Build.0 = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB ASM Debug|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB ASM Debug|Win32.Build.0 = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB ASM Release|Win32.ActiveCfg = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB ASM Release|Win32.Build.0 = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB Debug|Win32.Build.0 = Debug|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB Release|Win32.ActiveCfg = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.LIB Release|Win32.Build.0 = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.Release (Q3Map2)|Win32.ActiveCfg = Release|Win32 + {356A36AA-1F10-48A0-BF63-227DFB46F208}.Release|Win32.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/radiant.xcode/apple.pbxuser b/radiant.xcode/apple.pbxuser new file mode 100644 index 00000000..7e5d5832 --- /dev/null +++ b/radiant.xcode/apple.pbxuser @@ -0,0 +1,496 @@ +// !$*UTF8*$! +{ + 1865048206253BC4005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1736, 11689}}"; + sepNavSelRange = "{27154, 0}"; + sepNavVisRect = "{{0, 9653}, {699, 833}}"; + sepNavWindowFrame = "{{15, 128}, {759, 895}}"; + }; + }; + 1865048306253BC4005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {728, 4157}}"; + sepNavSelRange = "{509, 0}"; + sepNavVisRect = "{{0, 3371}, {720, 786}}"; + }; + }; + 18650B1A06253BD4005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 1763}}"; + sepNavSelRange = "{3427, 0}"; + sepNavVisRect = "{{0, 837}, {699, 833}}"; + }; + }; + 18650B8806253BD5005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {720, 786}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRect = "{{0, 0}, {720, 786}}"; + }; + }; + 18650B8906253BD5005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1532, 833}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRect = "{{0, 0}, {699, 833}}"; + }; + }; + 1865158D06253D50005AB5DA = { + activeExec = 0; + }; + 186515AC06255F40005AB5DA = { + activeExec = 0; + }; + 1865EBCC06253B29005AB5DA = { + activeBuildStyle = 1865EBCA06253B29005AB5DA; + activeTarget = 186515AC06255F40005AB5DA; + addToTargets = ( + ); + codeSenseManager = 1865EBCE06253B29005AB5DA; + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 190, + 20, + 39, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 167, + 41, + 20, + 41, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 103238153; + PBXPrepackagedSmartGroups_v2 = ( + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + activationKey = OldTargetSmartGroup; + clz = PBXTargetSmartGroup; + description = "Displays all targets of the project."; + globalID = 1C37FABC04509CD000000102; + name = Targets; + preferences = { + image = Targets; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXTargetSmartGroup2; + description = "Displays all targets of the project as well as nested build phases."; + globalID = 1C37FBAC04509CD000000102; + name = Targets; + preferences = { + image = Targets; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXExecutablesSmartGroup; + description = "Displays all executables of the project."; + globalID = 1C37FAAC04509CD000000102; + name = Executables; + preferences = { + image = Executable; + }; + }, + { + " PBXTransientLocationAtTop " = bottom; + absolutePathToBundle = ""; + clz = PBXErrorsWarningsSmartGroup; + description = "Displays files with errors or warnings."; + globalID = 1C08E77C0454961000C914BD; + name = "Errors and Warnings"; + preferences = { + fnmatch = ""; + image = WarningsErrors; + recursive = 1; + regex = ""; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter."; + globalID = 1CC0EA4004350EF90044410B; + name = "Implementation Files"; + preferences = { + canSave = 1; + fnmatch = ""; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = "?*\\.[mcMC]"; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "This group displays Interface Builder NIB Files."; + globalID = 1CC0EA4004350EF90041110B; + name = "NIB Files"; + preferences = { + canSave = 1; + fnmatch = "*.nib"; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = ""; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = no; + absolutePathToBundle = ""; + clz = PBXFindSmartGroup; + description = "Displays Find Results."; + globalID = 1C37FABC05509CD000000102; + name = "Find Results"; + preferences = { + image = spyglass; + }; + }, + { + PBXTransientLocationAtTop = no; + absolutePathToBundle = ""; + clz = PBXBookmarksSmartGroup; + description = "Displays Project Bookmarks."; + globalID = 1C37FABC05539CD112110102; + name = Bookmarks; + preferences = { + image = Bookmarks; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = XCSCMSmartGroup; + description = "Displays files with interesting SCM status."; + globalID = E2644B35053B69B200211256; + name = SCM; + preferences = { + image = PBXRepository; + isLeaf = 0; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXSymbolsSmartGroup; + description = "Displays all symbols for the project."; + globalID = 1C37FABC04509CD000100104; + name = "Project Symbols"; + preferences = { + image = ProjectSymbols; + isLeaf = 1; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter."; + globalID = PBXTemplateMarker; + name = "Simple Filter SmartGroup"; + preferences = { + canSave = 1; + fnmatch = "*.nib"; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = ""; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter."; + globalID = PBXTemplateMarker; + name = "Simple Regular Expression SmartGroup"; + preferences = { + canSave = 1; + fnmatch = ""; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = "?*\\.[mcMC]"; + root = ""; + }; + }, + ); + PBXWorkspaceContents = ( + { + PBXProjectWorkspaceModule_StateKey_Rev39 = { + PBXProjectWorkspaceModule_DataSourceSelectionKey_Rev6 = { + BoundsStr = "{{0, 0}, {288, 284}}"; + Rows = ( + 0, + ); + VisibleRectStr = "{{0, 0}, {288, 284}}"; + }; + PBXProjectWorkspaceModule_EditorOpen = false; + PBXProjectWorkspaceModule_EmbeddedNavigatorGroup = { + PBXSplitModuleInNavigatorKey = { + SplitCount = 1; + }; + }; + PBXProjectWorkspaceModule_GeometryKey_Rev15 = { + PBXProjectWorkspaceModule_SGTM_Geometry = { + _collapsingFrameDimension = 0; + _indexOfCollapsedView = 0; + _percentageOfCollapsedView = 0; + sizes = ( + "{{0, 0}, {297, 301}}", + "{{297, 0}, {303, 301}}", + ); + }; + }; + PBXProjectWorkspaceModule_OldDetailFrame = "{{0, 0}, {303, 301}}"; + PBXProjectWorkspaceModule_OldEditorFrame = "{{0, 0}, {750, 480}}"; + PBXProjectWorkspaceModule_OldSuperviewFrame = "{{297, 0}, {303, 301}}"; + PBXProjectWorkspaceModule_SGTM = { + PBXBottomSmartGroupGIDs = ( + 1C37FBAC04509CD000000102, + 1C37FAAC04509CD000000102, + 1C08E77C0454961000C914BD, + 1CC0EA4004350EF90044410B, + 1CC0EA4004350EF90041110B, + 1C37FABC05509CD000000102, + 1C37FABC05539CD112110102, + E2644B35053B69B200211256, + 1C37FABC04509CD000100104, + ); + PBXSmartGroupTreeModuleColumnData = { + PBXSmartGroupTreeModuleColumnWidthsKey = ( + 280, + ); + PBXSmartGroupTreeModuleColumnsKey_v4 = ( + MainColumn, + ); + }; + PBXSmartGroupTreeModuleOutlineStateKey_v7 = { + PBXSmartGroupTreeModuleOutlineStateExpansionKey = ( + 1865EBC806253B29005AB5DA, + 1865EBD506253B76005AB5DA, + 1865048406253BC4005AB5DA, + 186504B506253BC5005AB5DA, + 186504CA06253BC5005AB5DA, + 18650A2106253BD1005AB5DA, + 18650ACA06253BD3005AB5DA, + 18650ADE06253BD3005AB5DA, + 18650B7006253BD5005AB5DA, + 1C37FBAC04509CD000000102, + ); + PBXSmartGroupTreeModuleOutlineStateSelectionKey = ( + ( + 84, + 81, + 42, + 1, + 0, + ), + ); + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey = "{{0, 1273}, {280, 283}}"; + }; + PBXTopSmartGroupGIDs = ( + ); + }; + }; + }, + ); + "PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXBuildResultsModule" = { + }; + "PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXDebugCLIModule" = { + }; + "PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXNavigatorGroup" = { + PBXSplitModuleInNavigatorKey = { + SplitCount = 1; + }; + }; + "PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXProjectWorkspaceModule" = { + PBXProjectWorkspaceModule_StateKey_Rev39 = { + PBXProjectWorkspaceModule_DataSourceSelectionKey_Rev6 = { + BoundsStr = "{{0, 0}, {403, 284}}"; + Rows = ( + 0, + ); + VisibleRectStr = "{{0, 0}, {403, 284}}"; + }; + PBXProjectWorkspaceModule_EditorOpen = false; + PBXProjectWorkspaceModule_EmbeddedNavigatorGroup = { + PBXSplitModuleInNavigatorKey = { + SplitCount = 1; + }; + }; + PBXProjectWorkspaceModule_GeometryKey_Rev15 = { + PBXProjectWorkspaceModule_SGTM_Geometry = { + _collapsingFrameDimension = 0; + _indexOfCollapsedView = 0; + _percentageOfCollapsedView = 0; + sizes = ( + "{{0, 0}, {182, 301}}", + "{{182, 0}, {418, 301}}", + ); + }; + }; + PBXProjectWorkspaceModule_OldDetailFrame = "{{0, 0}, {418, 301}}"; + PBXProjectWorkspaceModule_OldEditorFrame = "{{0, 0}, {750, 480}}"; + PBXProjectWorkspaceModule_OldSuperviewFrame = "{{182, 0}, {418, 301}}"; + PBXProjectWorkspaceModule_SGTM = { + PBXBottomSmartGroupGIDs = ( + 1C37FBAC04509CD000000102, + 1C37FAAC04509CD000000102, + 1C08E77C0454961000C914BD, + 1CC0EA4004350EF90044410B, + 1CC0EA4004350EF90041110B, + 1C37FABC05509CD000000102, + 1C37FABC05539CD112110102, + E2644B35053B69B200211256, + 1C37FABC04509CD000100104, + ); + PBXSmartGroupTreeModuleColumnData = { + PBXSmartGroupTreeModuleColumnWidthsKey = ( + 165, + ); + PBXSmartGroupTreeModuleColumnsKey_v4 = ( + MainColumn, + ); + }; + PBXSmartGroupTreeModuleOutlineStateKey_v7 = { + PBXSmartGroupTreeModuleOutlineStateExpansionKey = ( + 1865EBC806253B29005AB5DA, + 1865EBD506253B76005AB5DA, + 1865048406253BC4005AB5DA, + 18650B7006253BD5005AB5DA, + 1C37FBAC04509CD000000102, + 186E28A30625621E00080878, + ); + PBXSmartGroupTreeModuleOutlineStateSelectionKey = ( + ( + 53, + 51, + 42, + 1, + 0, + ), + ); + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey = "{{0, 733}, {165, 283}}"; + }; + PBXTopSmartGroupGIDs = ( + ); + }; + }; + }; + PBXWorkspaceGeometries = ( + { + Frame = "{{0, 0}, {600, 301}}"; + PBXProjectWorkspaceModule_GeometryKey_Rev15 = { + }; + RubberWindowFrame = "864 615 600 343 0 0 1680 1028 "; + }, + ); + "PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXBuildResultsModule" = { + Frame = "{{0, 0}, {643, 462}}"; + PBXModuleWindowStatusBarHidden = YES; + RubberWindowFrame = "600 374 643 483 0 0 1680 1028 "; + }; + "PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXDebugCLIModule" = { + Frame = "{{0, 0}, {400, 201}}"; + PBXModuleWindowStatusBarHidden = YES; + RubberWindowFrame = "50 1000 400 222 0 0 1680 1028 "; + }; + "PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXNavigatorGroup" = { + Frame = "{{0, 0}, {741, 869}}"; + PBXModuleWindowStatusBarHidden = YES; + RubberWindowFrame = "15 133 741 890 0 0 1680 1028 "; + }; + "PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXProjectWorkspaceModule" = { + Frame = "{{0, 0}, {600, 301}}"; + PBXProjectWorkspaceModule_GeometryKey_Rev15 = { + PBXProjectWorkspaceModule_BuildResultsWindowVisible = true; + PBXProjectWorkspaceModule_PinnedFile = /Users/apple/GtkRadiant/setup/osx/build.sh; + }; + RubberWindowFrame = "864 615 600 343 0 0 1680 1028 "; + }; + PBXWorkspaceStateSaveDate = 103238153; + }; + sourceControlManager = 1865EBCD06253B29005AB5DA; + userBuildSettings = { + }; + }; + 1865EBCD06253B29005AB5DA = { + isa = PBXSourceControlManager; + scmConfiguration = { + }; + scmType = ""; + }; + 1865EBCE06253B29005AB5DA = { + indexTemplatePath = ""; + isa = PBXCodeSenseManager; + usesDefaults = 1; + wantsCodeCompletion = 1; + wantsCodeCompletionAutoPopup = 0; + wantsCodeCompletionAutoSuggestions = 0; + wantsCodeCompletionCaseSensitivity = 1; + wantsCodeCompletionOnlyMatchingItems = 1; + wantsCodeCompletionParametersIncluded = 1; + wantsCodeCompletionPlaceholdersInserted = 1; + wantsCodeCompletionTabCompletes = 1; + wantsIndex = 1; + }; + 1865F17706253B81005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {2762, 78581}}"; + sepNavSelRange = "{187, 0}"; + sepNavVisRect = "{{0, 0}, {699, 833}}"; + }; + }; + 1865FCB706253BAF005AB5DA = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1118, 833}}"; + sepNavSelRange = "{1196, 0}"; + sepNavVisRect = "{{0, 0}, {699, 833}}"; + }; + }; +} diff --git a/radiant.xcode/project.pbxproj b/radiant.xcode/project.pbxproj new file mode 100644 index 00000000..4157860b --- /dev/null +++ b/radiant.xcode/project.pbxproj @@ -0,0 +1,95793 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + 1865000006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865000106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865000206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865000306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865000406253BB8005AB5DA = { + children = ( + 1865000506253BB8005AB5DA, + 1865000606253BB8005AB5DA, + 1865000706253BB8005AB5DA, + 1865000806253BB8005AB5DA, + 1865000906253BB8005AB5DA, + 1865000A06253BB8005AB5DA, + 1865000B06253BB8005AB5DA, + 1865000C06253BB8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865000506253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000606253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000706253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000806253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000A06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000B06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000C06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865000D06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865000E06253BB8005AB5DA = { + children = ( + 1865000F06253BB8005AB5DA, + 1865001006253BB8005AB5DA, + 1865001106253BB8005AB5DA, + 1865001206253BB8005AB5DA, + 1865001306253BB8005AB5DA, + 1865001406253BB8005AB5DA, + 1865001506253BB8005AB5DA, + 1865001606253BB8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865000F06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "surface_quake2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001406253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001506253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001606253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865001706253BB8005AB5DA = { + children = ( + 1865001806253BB8005AB5DA, + 1865001906253BB8005AB5DA, + 1865001A06253BB8005AB5DA, + 1865001B06253BB8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865001806253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865001906253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865001A06253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865001B06253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865001C06253BB8005AB5DA = { + children = ( + 1865001D06253BB8005AB5DA, + 1865001E06253BB8005AB5DA, + 1865001F06253BB8005AB5DA, + 1865002006253BB8005AB5DA, + 1865002106253BB8005AB5DA, + 1865002206253BB8005AB5DA, + 1865002306253BB8005AB5DA, + 1865002406253BB8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865001D06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865001E06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865001F06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865002006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865002106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865002206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_quake2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865002306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865002406253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865002506253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = surface_quake2.def; + refType = 4; + sourceTree = ""; + }; + 1865002606253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = surface_quake2.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865002706253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfacedialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865002806253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfacedialog.h; + refType = 4; + sourceTree = ""; + }; + 1865002906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfaceflagsdialog_quake2.cpp; + refType = 4; + sourceTree = ""; + }; + 1865002A06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfaceflagsdialog_quake2.h; + refType = 4; + sourceTree = ""; + }; + 1865002B06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfdlg_plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865002C06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfdlg_plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865002D06253BB8005AB5DA = { + children = ( + 1865002E06253BB8005AB5DA, + 1865002F06253BB8005AB5DA, + 1865003006253BB8005AB5DA, + 1865007706253BB9005AB5DA, + 1865007806253BB9005AB5DA, + 1865007906253BB9005AB5DA, + 1865007A06253BB9005AB5DA, + 1865007B06253BB9005AB5DA, + 1865007C06253BB9005AB5DA, + 1865009B06253BB9005AB5DA, + 1865009C06253BB9005AB5DA, + 1865009D06253BB9005AB5DA, + 1865009E06253BB9005AB5DA, + 1865009F06253BB9005AB5DA, + 186500A006253BB9005AB5DA, + 186500A106253BB9005AB5DA, + ); + isa = PBXGroup; + path = textool; + refType = 4; + sourceTree = ""; + }; + 1865002E06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865002F06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvswrappers; + refType = 4; + sourceTree = ""; + }; + 1865003006253BB8005AB5DA = { + children = ( + 1865003106253BB8005AB5DA, + 1865003206253BB8005AB5DA, + 1865003306253BB8005AB5DA, + 1865003406253BB8005AB5DA, + 1865003506253BB8005AB5DA, + 1865004406253BB8005AB5DA, + 1865005306253BB8005AB5DA, + 1865005406253BB8005AB5DA, + 1865006306253BB8005AB5DA, + 1865006806253BB9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865003106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865003206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865003306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865003406253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865003506253BB8005AB5DA = { + children = ( + 1865003606253BB8005AB5DA, + 1865003706253BB8005AB5DA, + 1865003806253BB8005AB5DA, + 1865003906253BB8005AB5DA, + 1865003A06253BB8005AB5DA, + 1865003B06253BB8005AB5DA, + 1865003C06253BB8005AB5DA, + 1865003D06253BB8005AB5DA, + 1865003E06253BB8005AB5DA, + 1865003F06253BB8005AB5DA, + 1865004006253BB8005AB5DA, + 1865004106253BB8005AB5DA, + 1865004206253BB8005AB5DA, + 1865004306253BB8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865003606253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003706253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003806253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003A06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003B06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003C06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003D06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003E06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865003F06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865004006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865004106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865004206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865004306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865004406253BB8005AB5DA = { + children = ( + 1865004506253BB8005AB5DA, + 1865004606253BB8005AB5DA, + 1865004706253BB8005AB5DA, + 1865004806253BB8005AB5DA, + 1865004906253BB8005AB5DA, + 1865004A06253BB8005AB5DA, + 1865004B06253BB8005AB5DA, + 1865004C06253BB8005AB5DA, + 1865004D06253BB8005AB5DA, + 1865004E06253BB8005AB5DA, + 1865004F06253BB8005AB5DA, + 1865005006253BB8005AB5DA, + 1865005106253BB8005AB5DA, + 1865005206253BB8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865004506253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004606253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004706253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004806253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004A06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004B06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004C06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004D06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004E06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865004F06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865005006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865005106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865005206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865005306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865005406253BB8005AB5DA = { + children = ( + 1865005506253BB8005AB5DA, + 1865005606253BB8005AB5DA, + 1865005706253BB8005AB5DA, + 1865005806253BB8005AB5DA, + 1865005906253BB8005AB5DA, + 1865005A06253BB8005AB5DA, + 1865005B06253BB8005AB5DA, + 1865005C06253BB8005AB5DA, + 1865005D06253BB8005AB5DA, + 1865005E06253BB8005AB5DA, + 1865005F06253BB8005AB5DA, + 1865006006253BB8005AB5DA, + 1865006106253BB8005AB5DA, + 1865006206253BB8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865005506253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005606253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005706253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005806253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005A06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005B06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005C06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005D06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005E06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865005F06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865006006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865006106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865006206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "TexTool.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865006306253BB8005AB5DA = { + children = ( + 1865006406253BB8005AB5DA, + 1865006506253BB8005AB5DA, + 1865006606253BB8005AB5DA, + 1865006706253BB9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865006406253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865006506253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865006606253BB8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865006706253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865006806253BB9005AB5DA = { + children = ( + 1865006906253BB9005AB5DA, + 1865006A06253BB9005AB5DA, + 1865006B06253BB9005AB5DA, + 1865006C06253BB9005AB5DA, + 1865006D06253BB9005AB5DA, + 1865006E06253BB9005AB5DA, + 1865006F06253BB9005AB5DA, + 1865007006253BB9005AB5DA, + 1865007106253BB9005AB5DA, + 1865007206253BB9005AB5DA, + 1865007306253BB9005AB5DA, + 1865007406253BB9005AB5DA, + 1865007506253BB9005AB5DA, + 1865007606253BB9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865006906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865006A06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865006B06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865006C06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "2DView.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865006D06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865006E06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865006F06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ControlPointsManager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007006253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007106253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007206253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007306253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865007706253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = 2DView.cpp; + refType = 4; + sourceTree = ""; + }; + 1865007806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = 2DView.h; + refType = 4; + sourceTree = ""; + }; + 1865007906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = changelog.txt; + refType = 4; + sourceTree = ""; + }; + 1865007A06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = ControlPointsManager.cpp; + refType = 4; + sourceTree = ""; + }; + 1865007B06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ControlPointsManager.h; + refType = 4; + sourceTree = ""; + }; + 1865007C06253BB9005AB5DA = { + children = ( + 1865007D06253BB9005AB5DA, + 1865007E06253BB9005AB5DA, + 1865009906253BB9005AB5DA, + 1865009A06253BB9005AB5DA, + ); + isa = PBXGroup; + path = Doc; + refType = 4; + sourceTree = ""; + }; + 1865007D06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvswrappers; + refType = 4; + sourceTree = ""; + }; + 1865007E06253BB9005AB5DA = { + children = ( + 1865007F06253BB9005AB5DA, + 1865008006253BB9005AB5DA, + 1865008106253BB9005AB5DA, + 1865008206253BB9005AB5DA, + 1865008306253BB9005AB5DA, + 1865008706253BB9005AB5DA, + 1865008B06253BB9005AB5DA, + 1865008C06253BB9005AB5DA, + 1865009006253BB9005AB5DA, + 1865009506253BB9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865007F06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865008006253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865008106253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865008206253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865008306253BB9005AB5DA = { + children = ( + 1865008406253BB9005AB5DA, + 1865008506253BB9005AB5DA, + 1865008606253BB9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865008406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865008506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image2.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865008606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865008706253BB9005AB5DA = { + children = ( + 1865008806253BB9005AB5DA, + 1865008906253BB9005AB5DA, + 1865008A06253BB9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865008806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865008906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image2.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865008A06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865008B06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865008C06253BB9005AB5DA = { + children = ( + 1865008D06253BB9005AB5DA, + 1865008E06253BB9005AB5DA, + 1865008F06253BB9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865008D06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865008E06253BB9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "Image2.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865008F06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865009006253BB9005AB5DA = { + children = ( + 1865009106253BB9005AB5DA, + 1865009206253BB9005AB5DA, + 1865009306253BB9005AB5DA, + 1865009406253BB9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865009106253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865009206253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865009306253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865009406253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865009506253BB9005AB5DA = { + children = ( + 1865009606253BB9005AB5DA, + 1865009706253BB9005AB5DA, + 1865009806253BB9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865009606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865009706253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image2.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865009806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865009906253BB9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = Image2.jpg; + refType = 4; + sourceTree = ""; + }; + 1865009A06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = TexTool.html; + refType = 4; + sourceTree = ""; + }; + 1865009B06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = resource.h; + refType = 4; + sourceTree = ""; + }; + 1865009C06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = StdAfx.cpp; + refType = 4; + sourceTree = ""; + }; + 1865009D06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = StdAfx.h; + refType = 4; + sourceTree = ""; + }; + 1865009E06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = TexTool.cpp; + refType = 4; + sourceTree = ""; + }; + 1865009F06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TexTool.def; + refType = 4; + sourceTree = ""; + }; + 186500A006253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TexTool.rc; + refType = 4; + sourceTree = ""; + }; + 186500A106253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = TexTool.vcproj; + refType = 4; + sourceTree = ""; + }; + 186500A206253BB9005AB5DA = { + children = ( + 186500A306253BB9005AB5DA, + 186500CA06253BB9005AB5DA, + 186500CB06253BB9005AB5DA, + 186500CC06253BB9005AB5DA, + 186500CD06253BB9005AB5DA, + 186500CE06253BB9005AB5DA, + 186500CF06253BB9005AB5DA, + ); + isa = PBXGroup; + path = vfspak; + refType = 4; + sourceTree = ""; + }; + 186500A306253BB9005AB5DA = { + children = ( + 186500A406253BB9005AB5DA, + 186500A506253BB9005AB5DA, + 186500A606253BB9005AB5DA, + 186500A706253BB9005AB5DA, + 186500A806253BB9005AB5DA, + 186500AF06253BB9005AB5DA, + 186500B606253BB9005AB5DA, + 186500B706253BB9005AB5DA, + 186500BE06253BB9005AB5DA, + 186500C306253BB9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186500A406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186500A506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186500A606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186500A706253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186500A806253BB9005AB5DA = { + children = ( + 186500A906253BB9005AB5DA, + 186500AA06253BB9005AB5DA, + 186500AB06253BB9005AB5DA, + 186500AC06253BB9005AB5DA, + 186500AD06253BB9005AB5DA, + 186500AE06253BB9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186500A906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500AA06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500AB06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500AC06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500AD06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500AE06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500AF06253BB9005AB5DA = { + children = ( + 186500B006253BB9005AB5DA, + 186500B106253BB9005AB5DA, + 186500B206253BB9005AB5DA, + 186500B306253BB9005AB5DA, + 186500B406253BB9005AB5DA, + 186500B506253BB9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186500B006253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500B106253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500B206253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500B306253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500B406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500B506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500B606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186500B706253BB9005AB5DA = { + children = ( + 186500B806253BB9005AB5DA, + 186500B906253BB9005AB5DA, + 186500BA06253BB9005AB5DA, + 186500BB06253BB9005AB5DA, + 186500BC06253BB9005AB5DA, + 186500BD06253BB9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186500B806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500B906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500BA06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500BB06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500BC06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500BD06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "vfspak.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500BE06253BB9005AB5DA = { + children = ( + 186500BF06253BB9005AB5DA, + 186500C006253BB9005AB5DA, + 186500C106253BB9005AB5DA, + 186500C206253BB9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186500BF06253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186500C006253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186500C106253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186500C206253BB9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186500C306253BB9005AB5DA = { + children = ( + 186500C406253BB9005AB5DA, + 186500C506253BB9005AB5DA, + 186500C606253BB9005AB5DA, + 186500C706253BB9005AB5DA, + 186500C806253BB9005AB5DA, + 186500C906253BB9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186500C406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500C506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500C606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500C706253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500C806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500C906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspak.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500CA06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vfs.cpp; + refType = 4; + sourceTree = ""; + }; + 186500CB06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfs.h; + refType = 4; + sourceTree = ""; + }; + 186500CC06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vfspak.cpp; + refType = 4; + sourceTree = ""; + }; + 186500CD06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = vfspak.def; + refType = 4; + sourceTree = ""; + }; + 186500CE06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfspak.h; + refType = 4; + sourceTree = ""; + }; + 186500CF06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = vfspak.vcproj; + refType = 4; + sourceTree = ""; + }; + 186500D006253BB9005AB5DA = { + children = ( + 186500D106253BB9005AB5DA, + 186500D206253BB9005AB5DA, + 1865010906253BBA005AB5DA, + 1865010A06253BBA005AB5DA, + 1865010B06253BBA005AB5DA, + 1865010C06253BBA005AB5DA, + 1865010D06253BBA005AB5DA, + 1865010E06253BBA005AB5DA, + 1865010F06253BBA005AB5DA, + 1865011006253BBA005AB5DA, + 1865011106253BBA005AB5DA, + ); + isa = PBXGroup; + path = vfspk3; + refType = 4; + sourceTree = ""; + }; + 186500D106253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 186500D206253BB9005AB5DA = { + children = ( + 186500D306253BB9005AB5DA, + 186500D406253BB9005AB5DA, + 186500D506253BB9005AB5DA, + 186500D606253BB9005AB5DA, + 186500D706253BB9005AB5DA, + 186500E206253BB9005AB5DA, + 186500ED06253BB9005AB5DA, + 186500EE06253BBA005AB5DA, + 186500F906253BBA005AB5DA, + 186500FE06253BBA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186500D306253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186500D406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186500D506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186500D606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186500D706253BB9005AB5DA = { + children = ( + 186500D806253BB9005AB5DA, + 186500D906253BB9005AB5DA, + 186500DA06253BB9005AB5DA, + 186500DB06253BB9005AB5DA, + 186500DC06253BB9005AB5DA, + 186500DD06253BB9005AB5DA, + 186500DE06253BB9005AB5DA, + 186500DF06253BB9005AB5DA, + 186500E006253BB9005AB5DA, + 186500E106253BB9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186500D806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500D906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip-vfspk3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500DA06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500DB06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500DC06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500DD06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500DE06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500DF06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500E006253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.proj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500E106253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500E206253BB9005AB5DA = { + children = ( + 186500E306253BB9005AB5DA, + 186500E406253BB9005AB5DA, + 186500E506253BB9005AB5DA, + 186500E606253BB9005AB5DA, + 186500E706253BB9005AB5DA, + 186500E806253BB9005AB5DA, + 186500E906253BB9005AB5DA, + 186500EA06253BB9005AB5DA, + 186500EB06253BB9005AB5DA, + 186500EC06253BB9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186500E306253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500E406253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip-vfspk3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500E506253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500E606253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500E706253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500E806253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500E906253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500EA06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500EB06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.proj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500EC06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186500ED06253BB9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186500EE06253BBA005AB5DA = { + children = ( + 186500EF06253BBA005AB5DA, + 186500F006253BBA005AB5DA, + 186500F106253BBA005AB5DA, + 186500F206253BBA005AB5DA, + 186500F306253BBA005AB5DA, + 186500F406253BBA005AB5DA, + 186500F506253BBA005AB5DA, + 186500F606253BBA005AB5DA, + 186500F706253BBA005AB5DA, + 186500F806253BBA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186500EF06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F006253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip-vfspk3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F106253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F206253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F306253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F606253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F706253BBA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "vfspk3.proj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F806253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "vfspk3.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186500F906253BBA005AB5DA = { + children = ( + 186500FA06253BBA005AB5DA, + 186500FB06253BBA005AB5DA, + 186500FC06253BBA005AB5DA, + 186500FD06253BBA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186500FA06253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186500FB06253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186500FC06253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186500FD06253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186500FE06253BBA005AB5DA = { + children = ( + 186500FF06253BBA005AB5DA, + 1865010006253BBA005AB5DA, + 1865010106253BBA005AB5DA, + 1865010206253BBA005AB5DA, + 1865010306253BBA005AB5DA, + 1865010406253BBA005AB5DA, + 1865010506253BBA005AB5DA, + 1865010606253BBA005AB5DA, + 1865010706253BBA005AB5DA, + 1865010806253BBA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186500FF06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010006253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip-vfspk3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010106253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010206253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010306253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010606253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010706253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.proj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010806253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865010906253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "unzip-vfspk3.h"; + refType = 4; + sourceTree = ""; + }; + 1865010A06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = unzip.cpp; + refType = 4; + sourceTree = ""; + }; + 1865010B06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vfs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865010C06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfs.h; + refType = 4; + sourceTree = ""; + }; + 1865010D06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vfspk3.cpp; + refType = 4; + sourceTree = ""; + }; + 1865010E06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = vfspk3.def; + refType = 4; + sourceTree = ""; + }; + 1865010F06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfspk3.h; + refType = 4; + sourceTree = ""; + }; + 1865011006253BBA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = vfspk3.proj; + refType = 4; + sourceTree = ""; + }; + 1865011106253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = vfspk3.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865011206253BBA005AB5DA = { + children = ( + 1865011306253BBA005AB5DA, + 1865014606253BBA005AB5DA, + 1865014706253BBA005AB5DA, + 1865014806253BBA005AB5DA, + 1865014906253BBA005AB5DA, + 1865014A06253BBA005AB5DA, + 1865014B06253BBA005AB5DA, + 1865014C06253BBA005AB5DA, + 1865014D06253BBA005AB5DA, + 1865014E06253BBA005AB5DA, + ); + isa = PBXGroup; + path = vfswad; + refType = 4; + sourceTree = ""; + }; + 1865011306253BBA005AB5DA = { + children = ( + 1865011406253BBA005AB5DA, + 1865011506253BBA005AB5DA, + 1865011606253BBA005AB5DA, + 1865011706253BBA005AB5DA, + 1865011806253BBA005AB5DA, + 1865012206253BBA005AB5DA, + 1865012C06253BBA005AB5DA, + 1865012D06253BBA005AB5DA, + 1865013706253BBA005AB5DA, + 1865013C06253BBA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865011406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865011506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865011606253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865011706253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865011806253BBA005AB5DA = { + children = ( + 1865011906253BBA005AB5DA, + 1865011A06253BBA005AB5DA, + 1865011B06253BBA005AB5DA, + 1865011C06253BBA005AB5DA, + 1865011D06253BBA005AB5DA, + 1865011E06253BBA005AB5DA, + 1865011F06253BBA005AB5DA, + 1865012006253BBA005AB5DA, + 1865012106253BBA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865011906253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865011A06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865011B06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865011C06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865011D06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865011E06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865011F06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865012006253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865012106253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865012206253BBA005AB5DA = { + children = ( + 1865012306253BBA005AB5DA, + 1865012406253BBA005AB5DA, + 1865012506253BBA005AB5DA, + 1865012606253BBA005AB5DA, + 1865012706253BBA005AB5DA, + 1865012806253BBA005AB5DA, + 1865012906253BBA005AB5DA, + 1865012A06253BBA005AB5DA, + 1865012B06253BBA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865012306253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012606253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012706253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012806253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012906253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012A06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012B06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865012C06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865012D06253BBA005AB5DA = { + children = ( + 1865012E06253BBA005AB5DA, + 1865012F06253BBA005AB5DA, + 1865013006253BBA005AB5DA, + 1865013106253BBA005AB5DA, + 1865013206253BBA005AB5DA, + 1865013306253BBA005AB5DA, + 1865013406253BBA005AB5DA, + 1865013506253BBA005AB5DA, + 1865013606253BBA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865012E06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865012F06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013006253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013106253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013206253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013306253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013606253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "vfswad.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865013706253BBA005AB5DA = { + children = ( + 1865013806253BBA005AB5DA, + 1865013906253BBA005AB5DA, + 1865013A06253BBA005AB5DA, + 1865013B06253BBA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865013806253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865013906253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865013A06253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865013B06253BBA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865013C06253BBA005AB5DA = { + children = ( + 1865013D06253BBA005AB5DA, + 1865013E06253BBA005AB5DA, + 1865013F06253BBA005AB5DA, + 1865014006253BBA005AB5DA, + 1865014106253BBA005AB5DA, + 1865014206253BBA005AB5DA, + 1865014306253BBA005AB5DA, + 1865014406253BBA005AB5DA, + 1865014506253BBA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865013D06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865013E06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unwad.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865013F06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014006253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014106253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014206253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014306253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfswad.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865014606253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = unwad.cpp; + refType = 4; + sourceTree = ""; + }; + 1865014706253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = unwad.h; + refType = 4; + sourceTree = ""; + }; + 1865014806253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vfs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865014906253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfs.h; + refType = 4; + sourceTree = ""; + }; + 1865014A06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vfswad.cpp; + refType = 4; + sourceTree = ""; + }; + 1865014B06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = vfswad.def; + refType = 4; + sourceTree = ""; + }; + 1865014C06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfswad.h; + refType = 4; + sourceTree = ""; + }; + 1865014D06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = vfswad.txt; + refType = 4; + sourceTree = ""; + }; + 1865014E06253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = vfswad.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865014F06253BBA005AB5DA = { + children = ( + 1865015006253BBA005AB5DA, + 1865015106253BBA005AB5DA, + 1865030C06253BC1005AB5DA, + 1865041106253BC3005AB5DA, + 1865041206253BC3005AB5DA, + 1865041306253BC3005AB5DA, + 1865041406253BC3005AB5DA, + 1865041506253BC3005AB5DA, + 1865041606253BC3005AB5DA, + 1865041706253BC3005AB5DA, + 1865041806253BC3005AB5DA, + 1865041906253BC3005AB5DA, + 1865041A06253BC3005AB5DA, + 1865041B06253BC3005AB5DA, + 1865041C06253BC3005AB5DA, + 1865041D06253BC3005AB5DA, + 1865041E06253BC3005AB5DA, + 1865041F06253BC3005AB5DA, + 1865042006253BC3005AB5DA, + 1865042106253BC3005AB5DA, + 1865042206253BC3005AB5DA, + 1865042306253BC3005AB5DA, + 1865042406253BC3005AB5DA, + 1865042506253BC3005AB5DA, + 1865042606253BC3005AB5DA, + 1865042706253BC3005AB5DA, + 1865042806253BC3005AB5DA, + 1865042906253BC3005AB5DA, + 1865042A06253BC3005AB5DA, + 1865042B06253BC3005AB5DA, + 1865042C06253BC3005AB5DA, + 1865042D06253BC4005AB5DA, + 1865042E06253BC4005AB5DA, + 1865042F06253BC4005AB5DA, + 1865043006253BC4005AB5DA, + 1865043106253BC4005AB5DA, + 1865043206253BC4005AB5DA, + 1865043306253BC4005AB5DA, + 1865043406253BC4005AB5DA, + 1865043506253BC4005AB5DA, + 1865043606253BC4005AB5DA, + 1865043706253BC4005AB5DA, + 1865043806253BC4005AB5DA, + 1865043906253BC4005AB5DA, + 1865043A06253BC4005AB5DA, + 1865043B06253BC4005AB5DA, + 1865043C06253BC4005AB5DA, + 1865043D06253BC4005AB5DA, + 1865043E06253BC4005AB5DA, + 1865043F06253BC4005AB5DA, + 1865044006253BC4005AB5DA, + 1865044106253BC4005AB5DA, + 1865044206253BC4005AB5DA, + 1865044306253BC4005AB5DA, + 1865044406253BC4005AB5DA, + 1865044506253BC4005AB5DA, + 1865044606253BC4005AB5DA, + 1865044706253BC4005AB5DA, + 1865044806253BC4005AB5DA, + 1865044906253BC4005AB5DA, + 1865044A06253BC4005AB5DA, + 1865044B06253BC4005AB5DA, + 1865044C06253BC4005AB5DA, + 1865044D06253BC4005AB5DA, + 1865044E06253BC4005AB5DA, + 1865044F06253BC4005AB5DA, + 1865045006253BC4005AB5DA, + 1865045106253BC4005AB5DA, + 1865045206253BC4005AB5DA, + 1865045306253BC4005AB5DA, + 1865045406253BC4005AB5DA, + 1865045506253BC4005AB5DA, + 1865045606253BC4005AB5DA, + 1865045706253BC4005AB5DA, + 1865045806253BC4005AB5DA, + 1865045906253BC4005AB5DA, + 1865045A06253BC4005AB5DA, + 1865045B06253BC4005AB5DA, + 1865045C06253BC4005AB5DA, + 1865045D06253BC4005AB5DA, + 1865045E06253BC4005AB5DA, + 1865045F06253BC4005AB5DA, + 1865046006253BC4005AB5DA, + 1865046106253BC4005AB5DA, + 1865046206253BC4005AB5DA, + 1865046306253BC4005AB5DA, + 1865046406253BC4005AB5DA, + 1865046506253BC4005AB5DA, + 1865046606253BC4005AB5DA, + 1865046706253BC4005AB5DA, + 1865046806253BC4005AB5DA, + 1865046906253BC4005AB5DA, + 1865046A06253BC4005AB5DA, + 1865046B06253BC4005AB5DA, + 1865046C06253BC4005AB5DA, + 1865046D06253BC4005AB5DA, + 1865046E06253BC4005AB5DA, + 1865046F06253BC4005AB5DA, + 1865047006253BC4005AB5DA, + 1865047106253BC4005AB5DA, + 1865047206253BC4005AB5DA, + 1865047306253BC4005AB5DA, + 1865047406253BC4005AB5DA, + 1865047506253BC4005AB5DA, + 1865047606253BC4005AB5DA, + 1865047706253BC4005AB5DA, + 1865047806253BC4005AB5DA, + 1865047906253BC4005AB5DA, + 1865047A06253BC4005AB5DA, + ); + isa = PBXGroup; + path = radiant; + refType = 4; + sourceTree = ""; + }; + 1865015006253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865015106253BBA005AB5DA = { + children = ( + 1865015206253BBA005AB5DA, + 1865015306253BBA005AB5DA, + 1865015406253BBA005AB5DA, + 1865015506253BBA005AB5DA, + 1865015606253BBA005AB5DA, + 186501C206253BBC005AB5DA, + 1865022E06253BBD005AB5DA, + 1865022F06253BBD005AB5DA, + 1865029B06253BBF005AB5DA, + 186502A006253BBF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865015206253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865015306253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865015406253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865015506253BBA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865015606253BBA005AB5DA = { + children = ( + 1865015706253BBB005AB5DA, + 1865015806253BBB005AB5DA, + 1865015906253BBB005AB5DA, + 1865015A06253BBB005AB5DA, + 1865015B06253BBB005AB5DA, + 1865015C06253BBB005AB5DA, + 1865015D06253BBB005AB5DA, + 1865015E06253BBB005AB5DA, + 1865015F06253BBB005AB5DA, + 1865016006253BBB005AB5DA, + 1865016106253BBB005AB5DA, + 1865016206253BBB005AB5DA, + 1865016306253BBB005AB5DA, + 1865016406253BBB005AB5DA, + 1865016506253BBB005AB5DA, + 1865016606253BBB005AB5DA, + 1865016706253BBB005AB5DA, + 1865016806253BBB005AB5DA, + 1865016906253BBB005AB5DA, + 1865016A06253BBB005AB5DA, + 1865016B06253BBB005AB5DA, + 1865016C06253BBB005AB5DA, + 1865016D06253BBB005AB5DA, + 1865016E06253BBB005AB5DA, + 1865016F06253BBB005AB5DA, + 1865017006253BBB005AB5DA, + 1865017106253BBB005AB5DA, + 1865017206253BBB005AB5DA, + 1865017306253BBB005AB5DA, + 1865017406253BBB005AB5DA, + 1865017506253BBB005AB5DA, + 1865017606253BBB005AB5DA, + 1865017706253BBB005AB5DA, + 1865017806253BBB005AB5DA, + 1865017906253BBB005AB5DA, + 1865017A06253BBB005AB5DA, + 1865017B06253BBB005AB5DA, + 1865017C06253BBB005AB5DA, + 1865017D06253BBB005AB5DA, + 1865017E06253BBB005AB5DA, + 1865017F06253BBB005AB5DA, + 1865018006253BBB005AB5DA, + 1865018106253BBB005AB5DA, + 1865018206253BBB005AB5DA, + 1865018306253BBB005AB5DA, + 1865018406253BBB005AB5DA, + 1865018506253BBB005AB5DA, + 1865018606253BBB005AB5DA, + 1865018706253BBB005AB5DA, + 1865018806253BBB005AB5DA, + 1865018906253BBB005AB5DA, + 1865018A06253BBB005AB5DA, + 1865018B06253BBB005AB5DA, + 1865018C06253BBB005AB5DA, + 1865018D06253BBB005AB5DA, + 1865018E06253BBB005AB5DA, + 1865018F06253BBB005AB5DA, + 1865019006253BBB005AB5DA, + 1865019106253BBB005AB5DA, + 1865019206253BBB005AB5DA, + 1865019306253BBB005AB5DA, + 1865019406253BBB005AB5DA, + 1865019506253BBB005AB5DA, + 1865019606253BBB005AB5DA, + 1865019706253BBB005AB5DA, + 1865019806253BBB005AB5DA, + 1865019906253BBB005AB5DA, + 1865019A06253BBB005AB5DA, + 1865019B06253BBB005AB5DA, + 1865019C06253BBB005AB5DA, + 1865019D06253BBC005AB5DA, + 1865019E06253BBC005AB5DA, + 1865019F06253BBC005AB5DA, + 186501A006253BBC005AB5DA, + 186501A106253BBC005AB5DA, + 186501A206253BBC005AB5DA, + 186501A306253BBC005AB5DA, + 186501A406253BBC005AB5DA, + 186501A506253BBC005AB5DA, + 186501A606253BBC005AB5DA, + 186501A706253BBC005AB5DA, + 186501A806253BBC005AB5DA, + 186501A906253BBC005AB5DA, + 186501AA06253BBC005AB5DA, + 186501AB06253BBC005AB5DA, + 186501AC06253BBC005AB5DA, + 186501AD06253BBC005AB5DA, + 186501AE06253BBC005AB5DA, + 186501AF06253BBC005AB5DA, + 186501B006253BBC005AB5DA, + 186501B106253BBC005AB5DA, + 186501B206253BBC005AB5DA, + 186501B306253BBC005AB5DA, + 186501B406253BBC005AB5DA, + 186501B506253BBC005AB5DA, + 186501B606253BBC005AB5DA, + 186501B706253BBC005AB5DA, + 186501B806253BBC005AB5DA, + 186501B906253BBC005AB5DA, + 186501BA06253BBC005AB5DA, + 186501BB06253BBC005AB5DA, + 186501BC06253BBC005AB5DA, + 186501BD06253BBC005AB5DA, + 186501BE06253BBC005AB5DA, + 186501BF06253BBC005AB5DA, + 186501C006253BBC005AB5DA, + 186501C106253BBC005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865015706253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015806253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bp_dlg.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015906253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015A06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015B06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015C06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushscript.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015D06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015E06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865015F06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016006253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016106253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016206253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016306253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialoginfo.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016406253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "drag.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016506253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016606253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016706253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016806253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "error.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016906253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016A06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016B06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016C06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016D06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016E06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865016F06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017006253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017106253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glinterface.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017206253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017306253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017406253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017506253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017606253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017706253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017806253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017906253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017A06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017B06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017C06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017D06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017E06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865017F06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018006253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018106253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018206253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018306253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018406253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018506253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Makefile.mac.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018606253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018706253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018806253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018906253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018A06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018B06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018C06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018D06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018E06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginentities.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865018F06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019006253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019106253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pmesh.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019206253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019306253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019406253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019506253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019606253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "profile.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019706253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019806253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019906253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qedefs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019A06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019B06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl-mac.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019C06253BBB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019D06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019E06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl_ext.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865019F06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "queuedraw.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A006253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.ico.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A106253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A206253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A306253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A406253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A506253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selectedface.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A606253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A706253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A806253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501A906253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501AA06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501AB06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501AC06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "targetname.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501AD06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501AE06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501AF06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B006253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B106253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B206253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B306253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B406253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B506253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B606253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vertsel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B706253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B806253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501B906253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501BA06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501BB06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlstuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501BC06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501BD06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501BE06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501BF06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501C006253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501C106253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186501C206253BBC005AB5DA = { + children = ( + 186501C306253BBC005AB5DA, + 186501C406253BBC005AB5DA, + 186501C506253BBC005AB5DA, + 186501C606253BBC005AB5DA, + 186501C706253BBC005AB5DA, + 186501C806253BBC005AB5DA, + 186501C906253BBC005AB5DA, + 186501CA06253BBC005AB5DA, + 186501CB06253BBC005AB5DA, + 186501CC06253BBC005AB5DA, + 186501CD06253BBC005AB5DA, + 186501CE06253BBC005AB5DA, + 186501CF06253BBC005AB5DA, + 186501D006253BBC005AB5DA, + 186501D106253BBC005AB5DA, + 186501D206253BBC005AB5DA, + 186501D306253BBC005AB5DA, + 186501D406253BBC005AB5DA, + 186501D506253BBC005AB5DA, + 186501D606253BBC005AB5DA, + 186501D706253BBC005AB5DA, + 186501D806253BBC005AB5DA, + 186501D906253BBC005AB5DA, + 186501DA06253BBC005AB5DA, + 186501DB06253BBC005AB5DA, + 186501DC06253BBC005AB5DA, + 186501DD06253BBC005AB5DA, + 186501DE06253BBC005AB5DA, + 186501DF06253BBC005AB5DA, + 186501E006253BBC005AB5DA, + 186501E106253BBC005AB5DA, + 186501E206253BBC005AB5DA, + 186501E306253BBC005AB5DA, + 186501E406253BBC005AB5DA, + 186501E506253BBC005AB5DA, + 186501E606253BBC005AB5DA, + 186501E706253BBC005AB5DA, + 186501E806253BBC005AB5DA, + 186501E906253BBC005AB5DA, + 186501EA06253BBD005AB5DA, + 186501EB06253BBD005AB5DA, + 186501EC06253BBD005AB5DA, + 186501ED06253BBD005AB5DA, + 186501EE06253BBD005AB5DA, + 186501EF06253BBD005AB5DA, + 186501F006253BBD005AB5DA, + 186501F106253BBD005AB5DA, + 186501F206253BBD005AB5DA, + 186501F306253BBD005AB5DA, + 186501F406253BBD005AB5DA, + 186501F506253BBD005AB5DA, + 186501F606253BBD005AB5DA, + 186501F706253BBD005AB5DA, + 186501F806253BBD005AB5DA, + 186501F906253BBD005AB5DA, + 186501FA06253BBD005AB5DA, + 186501FB06253BBD005AB5DA, + 186501FC06253BBD005AB5DA, + 186501FD06253BBD005AB5DA, + 186501FE06253BBD005AB5DA, + 186501FF06253BBD005AB5DA, + 1865020006253BBD005AB5DA, + 1865020106253BBD005AB5DA, + 1865020206253BBD005AB5DA, + 1865020306253BBD005AB5DA, + 1865020406253BBD005AB5DA, + 1865020506253BBD005AB5DA, + 1865020606253BBD005AB5DA, + 1865020706253BBD005AB5DA, + 1865020806253BBD005AB5DA, + 1865020906253BBD005AB5DA, + 1865020A06253BBD005AB5DA, + 1865020B06253BBD005AB5DA, + 1865020C06253BBD005AB5DA, + 1865020D06253BBD005AB5DA, + 1865020E06253BBD005AB5DA, + 1865020F06253BBD005AB5DA, + 1865021006253BBD005AB5DA, + 1865021106253BBD005AB5DA, + 1865021206253BBD005AB5DA, + 1865021306253BBD005AB5DA, + 1865021406253BBD005AB5DA, + 1865021506253BBD005AB5DA, + 1865021606253BBD005AB5DA, + 1865021706253BBD005AB5DA, + 1865021806253BBD005AB5DA, + 1865021906253BBD005AB5DA, + 1865021A06253BBD005AB5DA, + 1865021B06253BBD005AB5DA, + 1865021C06253BBD005AB5DA, + 1865021D06253BBD005AB5DA, + 1865021E06253BBD005AB5DA, + 1865021F06253BBD005AB5DA, + 1865022006253BBD005AB5DA, + 1865022106253BBD005AB5DA, + 1865022206253BBD005AB5DA, + 1865022306253BBD005AB5DA, + 1865022406253BBD005AB5DA, + 1865022506253BBD005AB5DA, + 1865022606253BBD005AB5DA, + 1865022706253BBD005AB5DA, + 1865022806253BBD005AB5DA, + 1865022906253BBD005AB5DA, + 1865022A06253BBD005AB5DA, + 1865022B06253BBD005AB5DA, + 1865022C06253BBD005AB5DA, + 1865022D06253BBD005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186501C306253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501C406253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bp_dlg.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501C506253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501C606253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501C706253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501C806253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushscript.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501C906253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501CA06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501CB06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501CC06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501CD06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501CE06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501CF06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialoginfo.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D006253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "drag.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D106253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D206253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D306253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D406253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "error.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D506253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D606253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D706253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D806253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501D906253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501DA06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501DB06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501DC06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501DD06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glinterface.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501DE06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501DF06253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E006253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E106253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E206253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E306253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E406253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E506253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E606253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E706253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E806253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501E906253BBC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501EA06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501EB06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501EC06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501ED06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501EE06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501EF06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F006253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F106253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Makefile.mac.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F206253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F306253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F406253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F506253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F606253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F706253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F806253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501F906253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501FA06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginentities.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501FB06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501FC06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501FD06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pmesh.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501FE06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186501FF06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020006253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020106253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020206253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "profile.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020306253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020406253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020506253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qedefs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020606253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020706253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl-mac.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020806253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020906253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020A06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl_ext.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020B06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "queuedraw.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020C06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.ico.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020D06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020E06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865020F06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021006253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021106253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selectedface.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021206253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021306253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021406253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021506253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021606253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021706253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021806253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "targetname.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021906253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021A06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021B06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021C06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021D06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021E06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865021F06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022006253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022106253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022206253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vertsel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022306253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022406253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022506253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022606253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022706253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlstuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022806253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022906253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022A06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022B06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022C06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022D06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865022E06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865022F06253BBD005AB5DA = { + children = ( + 1865023006253BBD005AB5DA, + 1865023106253BBD005AB5DA, + 1865023206253BBD005AB5DA, + 1865023306253BBD005AB5DA, + 1865023406253BBD005AB5DA, + 1865023506253BBD005AB5DA, + 1865023606253BBD005AB5DA, + 1865023706253BBD005AB5DA, + 1865023806253BBD005AB5DA, + 1865023906253BBD005AB5DA, + 1865023A06253BBD005AB5DA, + 1865023B06253BBD005AB5DA, + 1865023C06253BBD005AB5DA, + 1865023D06253BBD005AB5DA, + 1865023E06253BBD005AB5DA, + 1865023F06253BBD005AB5DA, + 1865024006253BBD005AB5DA, + 1865024106253BBD005AB5DA, + 1865024206253BBD005AB5DA, + 1865024306253BBD005AB5DA, + 1865024406253BBD005AB5DA, + 1865024506253BBD005AB5DA, + 1865024606253BBD005AB5DA, + 1865024706253BBD005AB5DA, + 1865024806253BBD005AB5DA, + 1865024906253BBD005AB5DA, + 1865024A06253BBD005AB5DA, + 1865024B06253BBE005AB5DA, + 1865024C06253BBE005AB5DA, + 1865024D06253BBE005AB5DA, + 1865024E06253BBE005AB5DA, + 1865024F06253BBE005AB5DA, + 1865025006253BBE005AB5DA, + 1865025106253BBE005AB5DA, + 1865025206253BBE005AB5DA, + 1865025306253BBE005AB5DA, + 1865025406253BBE005AB5DA, + 1865025506253BBE005AB5DA, + 1865025606253BBE005AB5DA, + 1865025706253BBE005AB5DA, + 1865025806253BBE005AB5DA, + 1865025906253BBE005AB5DA, + 1865025A06253BBE005AB5DA, + 1865025B06253BBE005AB5DA, + 1865025C06253BBE005AB5DA, + 1865025D06253BBE005AB5DA, + 1865025E06253BBE005AB5DA, + 1865025F06253BBE005AB5DA, + 1865026006253BBE005AB5DA, + 1865026106253BBE005AB5DA, + 1865026206253BBE005AB5DA, + 1865026306253BBE005AB5DA, + 1865026406253BBE005AB5DA, + 1865026506253BBE005AB5DA, + 1865026606253BBE005AB5DA, + 1865026706253BBE005AB5DA, + 1865026806253BBF005AB5DA, + 1865026906253BBF005AB5DA, + 1865026A06253BBF005AB5DA, + 1865026B06253BBF005AB5DA, + 1865026C06253BBF005AB5DA, + 1865026D06253BBF005AB5DA, + 1865026E06253BBF005AB5DA, + 1865026F06253BBF005AB5DA, + 1865027006253BBF005AB5DA, + 1865027106253BBF005AB5DA, + 1865027206253BBF005AB5DA, + 1865027306253BBF005AB5DA, + 1865027406253BBF005AB5DA, + 1865027506253BBF005AB5DA, + 1865027606253BBF005AB5DA, + 1865027706253BBF005AB5DA, + 1865027806253BBF005AB5DA, + 1865027906253BBF005AB5DA, + 1865027A06253BBF005AB5DA, + 1865027B06253BBF005AB5DA, + 1865027C06253BBF005AB5DA, + 1865027D06253BBF005AB5DA, + 1865027E06253BBF005AB5DA, + 1865027F06253BBF005AB5DA, + 1865028006253BBF005AB5DA, + 1865028106253BBF005AB5DA, + 1865028206253BBF005AB5DA, + 1865028306253BBF005AB5DA, + 1865028406253BBF005AB5DA, + 1865028506253BBF005AB5DA, + 1865028606253BBF005AB5DA, + 1865028706253BBF005AB5DA, + 1865028806253BBF005AB5DA, + 1865028906253BBF005AB5DA, + 1865028A06253BBF005AB5DA, + 1865028B06253BBF005AB5DA, + 1865028C06253BBF005AB5DA, + 1865028D06253BBF005AB5DA, + 1865028E06253BBF005AB5DA, + 1865028F06253BBF005AB5DA, + 1865029006253BBF005AB5DA, + 1865029106253BBF005AB5DA, + 1865029206253BBF005AB5DA, + 1865029306253BBF005AB5DA, + 1865029406253BBF005AB5DA, + 1865029506253BBF005AB5DA, + 1865029606253BBF005AB5DA, + 1865029706253BBF005AB5DA, + 1865029806253BBF005AB5DA, + 1865029906253BBF005AB5DA, + 1865029A06253BBF005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865023006253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023106253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bp_dlg.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023206253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023306253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023406253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023506253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushscript.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023606253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023706253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023806253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023906253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023A06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023B06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023C06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialoginfo.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023D06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "drag.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023E06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865023F06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024006253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024106253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "error.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024206253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024306253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024406253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024506253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024606253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024706253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024806253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024906253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024A06253BBD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glinterface.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024B06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024C06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024D06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024E06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865024F06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025006253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025106253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025206253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025306253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025406253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025506253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025606253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025706253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025806253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025906253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025A06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "GtkRadiant.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025B06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025C06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025D06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025E06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Makefile.mac.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865025F06253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026006253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026106253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026206253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026306253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026406253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026506253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026606253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026706253BBE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginentities.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026806253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026906253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026A06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pmesh.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026B06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026C06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026D06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026E06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865026F06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "profile.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027006253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027106253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027206253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qedefs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027306253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027406253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl-mac.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027506253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027606253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027706253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl_ext.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027806253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "queuedraw.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027906253BBF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "radiant.ico.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027A06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027B06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027C06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027D06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027E06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selectedface.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865027F06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028006253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028106253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028206253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028306253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028406253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028506253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "targetname.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028606253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028706253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028806253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028906253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028A06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028B06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028C06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028D06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028E06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865028F06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vertsel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029006253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029106253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029206253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029306253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029406253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlstuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029506253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029606253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029706253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029806253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029906253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029A06253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865029B06253BBF005AB5DA = { + children = ( + 1865029C06253BBF005AB5DA, + 1865029D06253BBF005AB5DA, + 1865029E06253BBF005AB5DA, + 1865029F06253BBF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865029C06253BBF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865029D06253BBF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865029E06253BBF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865029F06253BBF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186502A006253BBF005AB5DA = { + children = ( + 186502A106253BBF005AB5DA, + 186502A206253BBF005AB5DA, + 186502A306253BBF005AB5DA, + 186502A406253BBF005AB5DA, + 186502A506253BBF005AB5DA, + 186502A606253BBF005AB5DA, + 186502A706253BBF005AB5DA, + 186502A806253BBF005AB5DA, + 186502A906253BC0005AB5DA, + 186502AA06253BC0005AB5DA, + 186502AB06253BC0005AB5DA, + 186502AC06253BC0005AB5DA, + 186502AD06253BC0005AB5DA, + 186502AE06253BC0005AB5DA, + 186502AF06253BC0005AB5DA, + 186502B006253BC0005AB5DA, + 186502B106253BC0005AB5DA, + 186502B206253BC0005AB5DA, + 186502B306253BC0005AB5DA, + 186502B406253BC0005AB5DA, + 186502B506253BC0005AB5DA, + 186502B606253BC0005AB5DA, + 186502B706253BC0005AB5DA, + 186502B806253BC0005AB5DA, + 186502B906253BC0005AB5DA, + 186502BA06253BC0005AB5DA, + 186502BB06253BC0005AB5DA, + 186502BC06253BC0005AB5DA, + 186502BD06253BC0005AB5DA, + 186502BE06253BC0005AB5DA, + 186502BF06253BC0005AB5DA, + 186502C006253BC0005AB5DA, + 186502C106253BC0005AB5DA, + 186502C206253BC0005AB5DA, + 186502C306253BC0005AB5DA, + 186502C406253BC0005AB5DA, + 186502C506253BC0005AB5DA, + 186502C606253BC0005AB5DA, + 186502C706253BC0005AB5DA, + 186502C806253BC0005AB5DA, + 186502C906253BC0005AB5DA, + 186502CA06253BC0005AB5DA, + 186502CB06253BC0005AB5DA, + 186502CC06253BC0005AB5DA, + 186502CD06253BC0005AB5DA, + 186502CE06253BC0005AB5DA, + 186502CF06253BC0005AB5DA, + 186502D006253BC0005AB5DA, + 186502D106253BC0005AB5DA, + 186502D206253BC0005AB5DA, + 186502D306253BC0005AB5DA, + 186502D406253BC0005AB5DA, + 186502D506253BC0005AB5DA, + 186502D606253BC0005AB5DA, + 186502D706253BC0005AB5DA, + 186502D806253BC0005AB5DA, + 186502D906253BC0005AB5DA, + 186502DA06253BC0005AB5DA, + 186502DB06253BC0005AB5DA, + 186502DC06253BC0005AB5DA, + 186502DD06253BC0005AB5DA, + 186502DE06253BC0005AB5DA, + 186502DF06253BC0005AB5DA, + 186502E006253BC0005AB5DA, + 186502E106253BC0005AB5DA, + 186502E206253BC1005AB5DA, + 186502E306253BC1005AB5DA, + 186502E406253BC1005AB5DA, + 186502E506253BC1005AB5DA, + 186502E606253BC1005AB5DA, + 186502E706253BC1005AB5DA, + 186502E806253BC1005AB5DA, + 186502E906253BC1005AB5DA, + 186502EA06253BC1005AB5DA, + 186502EB06253BC1005AB5DA, + 186502EC06253BC1005AB5DA, + 186502ED06253BC1005AB5DA, + 186502EE06253BC1005AB5DA, + 186502EF06253BC1005AB5DA, + 186502F006253BC1005AB5DA, + 186502F106253BC1005AB5DA, + 186502F206253BC1005AB5DA, + 186502F306253BC1005AB5DA, + 186502F406253BC1005AB5DA, + 186502F506253BC1005AB5DA, + 186502F606253BC1005AB5DA, + 186502F706253BC1005AB5DA, + 186502F806253BC1005AB5DA, + 186502F906253BC1005AB5DA, + 186502FA06253BC1005AB5DA, + 186502FB06253BC1005AB5DA, + 186502FC06253BC1005AB5DA, + 186502FD06253BC1005AB5DA, + 186502FE06253BC1005AB5DA, + 186502FF06253BC1005AB5DA, + 1865030006253BC1005AB5DA, + 1865030106253BC1005AB5DA, + 1865030206253BC1005AB5DA, + 1865030306253BC1005AB5DA, + 1865030406253BC1005AB5DA, + 1865030506253BC1005AB5DA, + 1865030606253BC1005AB5DA, + 1865030706253BC1005AB5DA, + 1865030806253BC1005AB5DA, + 1865030906253BC1005AB5DA, + 1865030A06253BC1005AB5DA, + 1865030B06253BC1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186502A106253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A206253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bp_dlg.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A306253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A406253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A506253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A606253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushscript.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A706253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A806253BBF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502A906253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502AA06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502AB06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502AC06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502AD06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialoginfo.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502AE06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "drag.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502AF06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B006253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B106253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclass_def.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B206253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "error.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B306253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B406253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "feedback.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B506253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B606253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B706253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B806253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "filters.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502B906253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502BA06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "findtexturedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502BB06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glinterface.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502BC06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502BD06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwidget.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502BE06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502BF06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C006253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C106253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "groupdialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C206253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C306253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C406253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-darwin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C506253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C606253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel-linux.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C706253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C806253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkfilesel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502C906253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502CA06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkmisc.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502CB06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502CC06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502CD06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502CE06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mainframe.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502CF06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Makefile.mac.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D006253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D106253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D206253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D306253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D406253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D506253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D606253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patchdialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D706253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D806253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginentities.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502D906253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502DA06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pluginmanager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502DB06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pmesh.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502DC06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502DD06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "points.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502DE06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502DF06253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preferences.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E006253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "profile.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E106253BC0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E206253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qe3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E306253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qedefs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E406253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E506253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl-mac.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E606253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E706253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E806253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qgl_ext.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502E906253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "queuedraw.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502EA06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.ico.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502EB06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502EC06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502ED06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502EE06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502EF06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selectedface.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F006253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F106253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F206253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F306253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F406253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F506253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F606253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "targetname.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F706253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F806253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texmanip.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502F906253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502FA06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502FB06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "texwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502FC06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502FD06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ui.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502FE06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186502FF06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "undo.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030006253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vertsel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030106253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030206253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "watchbsp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030306253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030406253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "winding.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030506253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlstuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030606253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030706253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xywindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030806253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030906253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "z.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030A06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030B06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "zwindow.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865030C06253BC1005AB5DA = { + children = ( + 1865030D06253BC1005AB5DA, + 186503E006253BC3005AB5DA, + 186503E106253BC3005AB5DA, + 186503E206253BC3005AB5DA, + 186503E306253BC3005AB5DA, + 186503E406253BC3005AB5DA, + 186503E506253BC3005AB5DA, + 186503E606253BC3005AB5DA, + 186503E706253BC3005AB5DA, + 186503E806253BC3005AB5DA, + 186503E906253BC3005AB5DA, + 186503EA06253BC3005AB5DA, + 186503EB06253BC3005AB5DA, + 186503EC06253BC3005AB5DA, + 186503ED06253BC3005AB5DA, + 186503EE06253BC3005AB5DA, + 186503EF06253BC3005AB5DA, + 186503F006253BC3005AB5DA, + 186503F106253BC3005AB5DA, + 186503F206253BC3005AB5DA, + 186503F306253BC3005AB5DA, + 186503F406253BC3005AB5DA, + 186503F506253BC3005AB5DA, + 186503F606253BC3005AB5DA, + 186503F706253BC3005AB5DA, + 186503F806253BC3005AB5DA, + 186503F906253BC3005AB5DA, + 186503FA06253BC3005AB5DA, + 186503FB06253BC3005AB5DA, + 186503FC06253BC3005AB5DA, + 186503FD06253BC3005AB5DA, + 186503FE06253BC3005AB5DA, + 186503FF06253BC3005AB5DA, + 1865040006253BC3005AB5DA, + 1865040106253BC3005AB5DA, + 1865040206253BC3005AB5DA, + 1865040306253BC3005AB5DA, + 1865040406253BC3005AB5DA, + 1865040506253BC3005AB5DA, + 1865040606253BC3005AB5DA, + 1865040706253BC3005AB5DA, + 1865040806253BC3005AB5DA, + 1865040906253BC3005AB5DA, + 1865040A06253BC3005AB5DA, + 1865040B06253BC3005AB5DA, + 1865040C06253BC3005AB5DA, + 1865040D06253BC3005AB5DA, + 1865040E06253BC3005AB5DA, + 1865040F06253BC3005AB5DA, + 1865041006253BC3005AB5DA, + ); + isa = PBXGroup; + path = bitmaps; + refType = 4; + sourceTree = ""; + }; + 1865030D06253BC1005AB5DA = { + children = ( + 1865030E06253BC1005AB5DA, + 1865030F06253BC1005AB5DA, + 1865031006253BC1005AB5DA, + 1865031106253BC1005AB5DA, + 1865031206253BC1005AB5DA, + 1865034406253BC2005AB5DA, + 1865037606253BC2005AB5DA, + 1865037706253BC2005AB5DA, + 186503A906253BC3005AB5DA, + 186503AE06253BC3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865030E06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865030F06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865031006253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865031106253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865031206253BC1005AB5DA = { + children = ( + 1865031306253BC1005AB5DA, + 1865031406253BC1005AB5DA, + 1865031506253BC1005AB5DA, + 1865031606253BC1005AB5DA, + 1865031706253BC1005AB5DA, + 1865031806253BC1005AB5DA, + 1865031906253BC1005AB5DA, + 1865031A06253BC1005AB5DA, + 1865031B06253BC1005AB5DA, + 1865031C06253BC1005AB5DA, + 1865031D06253BC1005AB5DA, + 1865031E06253BC1005AB5DA, + 1865031F06253BC1005AB5DA, + 1865032006253BC1005AB5DA, + 1865032106253BC1005AB5DA, + 1865032206253BC1005AB5DA, + 1865032306253BC1005AB5DA, + 1865032406253BC1005AB5DA, + 1865032506253BC1005AB5DA, + 1865032606253BC1005AB5DA, + 1865032706253BC1005AB5DA, + 1865032806253BC1005AB5DA, + 1865032906253BC1005AB5DA, + 1865032A06253BC1005AB5DA, + 1865032B06253BC1005AB5DA, + 1865032C06253BC1005AB5DA, + 1865032D06253BC1005AB5DA, + 1865032E06253BC1005AB5DA, + 1865032F06253BC1005AB5DA, + 1865033006253BC1005AB5DA, + 1865033106253BC1005AB5DA, + 1865033206253BC1005AB5DA, + 1865033306253BC1005AB5DA, + 1865033406253BC1005AB5DA, + 1865033506253BC1005AB5DA, + 1865033606253BC1005AB5DA, + 1865033706253BC1005AB5DA, + 1865033806253BC1005AB5DA, + 1865033906253BC1005AB5DA, + 1865033A06253BC1005AB5DA, + 1865033B06253BC1005AB5DA, + 1865033C06253BC1005AB5DA, + 1865033D06253BC1005AB5DA, + 1865033E06253BC1005AB5DA, + 1865033F06253BC1005AB5DA, + 1865034006253BC2005AB5DA, + 1865034106253BC2005AB5DA, + 1865034206253BC2005AB5DA, + 1865034306253BC2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865031306253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipx.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031406253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipy.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031506253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipz.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031606253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatex.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031706253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatey.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031806253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatez.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031906253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_bevel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031A06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_endcap.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031B06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_ibevel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031C06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_iendcap.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031D06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "curve_cap.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031E06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dontselectcurve.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865031F06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dontselectmodel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032006253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file_open.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032106253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file_save.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032206253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icon.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032306253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "logo.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032406253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_bend.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032506253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_drilldown.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032606253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_insdel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032706253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_showboundingbox.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032806253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_weld.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032906253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_wireframe.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032A06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "popup_selection.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032B06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelockx.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032C06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelocky.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032D06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelockz.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032E06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select_mouserotate.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865032F06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select_mousescale.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033006253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_csgmerge.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033106253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_csgsubtract.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033206253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_makehollow.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033306253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectcompletetall.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033406253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectinside.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033506253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectpartialtall.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033606253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selecttouching.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033706253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "show_entities.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033806253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033906253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures_popup.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033A06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cameratoggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033B06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cameraupdate.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033C06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_change.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033D06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_clipper.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033E06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cubicclipping.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865033F06253BC1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_entity.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865034006253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window1.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865034106253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window2.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865034206253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window3.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865034306253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window4.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865034406253BC2005AB5DA = { + children = ( + 1865034506253BC2005AB5DA, + 1865034606253BC2005AB5DA, + 1865034706253BC2005AB5DA, + 1865034806253BC2005AB5DA, + 1865034906253BC2005AB5DA, + 1865034A06253BC2005AB5DA, + 1865034B06253BC2005AB5DA, + 1865034C06253BC2005AB5DA, + 1865034D06253BC2005AB5DA, + 1865034E06253BC2005AB5DA, + 1865034F06253BC2005AB5DA, + 1865035006253BC2005AB5DA, + 1865035106253BC2005AB5DA, + 1865035206253BC2005AB5DA, + 1865035306253BC2005AB5DA, + 1865035406253BC2005AB5DA, + 1865035506253BC2005AB5DA, + 1865035606253BC2005AB5DA, + 1865035706253BC2005AB5DA, + 1865035806253BC2005AB5DA, + 1865035906253BC2005AB5DA, + 1865035A06253BC2005AB5DA, + 1865035B06253BC2005AB5DA, + 1865035C06253BC2005AB5DA, + 1865035D06253BC2005AB5DA, + 1865035E06253BC2005AB5DA, + 1865035F06253BC2005AB5DA, + 1865036006253BC2005AB5DA, + 1865036106253BC2005AB5DA, + 1865036206253BC2005AB5DA, + 1865036306253BC2005AB5DA, + 1865036406253BC2005AB5DA, + 1865036506253BC2005AB5DA, + 1865036606253BC2005AB5DA, + 1865036706253BC2005AB5DA, + 1865036806253BC2005AB5DA, + 1865036906253BC2005AB5DA, + 1865036A06253BC2005AB5DA, + 1865036B06253BC2005AB5DA, + 1865036C06253BC2005AB5DA, + 1865036D06253BC2005AB5DA, + 1865036E06253BC2005AB5DA, + 1865036F06253BC2005AB5DA, + 1865037006253BC2005AB5DA, + 1865037106253BC2005AB5DA, + 1865037206253BC2005AB5DA, + 1865037306253BC2005AB5DA, + 1865037406253BC2005AB5DA, + 1865037506253BC2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865034506253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipx.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034606253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipy.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034706253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipz.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034806253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatex.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034906253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatey.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034A06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatez.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034B06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_bevel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034C06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_endcap.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034D06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_ibevel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034E06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_iendcap.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865034F06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "curve_cap.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035006253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dontselectcurve.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035106253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dontselectmodel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035206253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file_open.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035306253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file_save.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035406253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icon.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035506253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "logo.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035606253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_bend.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035706253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_drilldown.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035806253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_insdel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035906253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_showboundingbox.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035A06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_weld.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035B06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_wireframe.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035C06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "popup_selection.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035D06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelockx.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035E06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelocky.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865035F06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelockz.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036006253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select_mouserotate.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036106253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select_mousescale.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036206253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_csgmerge.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036306253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_csgsubtract.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036406253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_makehollow.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036506253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectcompletetall.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036606253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectinside.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036706253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectpartialtall.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036806253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selecttouching.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036906253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "show_entities.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036A06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036B06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures_popup.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036C06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cameratoggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036D06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cameraupdate.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036E06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_change.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865036F06253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_clipper.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037006253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cubicclipping.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037106253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_entity.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037206253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window1.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037306253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window2.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037406253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window3.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037506253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window4.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865037606253BC2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865037706253BC2005AB5DA = { + children = ( + 1865037806253BC2005AB5DA, + 1865037906253BC2005AB5DA, + 1865037A06253BC2005AB5DA, + 1865037B06253BC2005AB5DA, + 1865037C06253BC2005AB5DA, + 1865037D06253BC2005AB5DA, + 1865037E06253BC2005AB5DA, + 1865037F06253BC2005AB5DA, + 1865038006253BC2005AB5DA, + 1865038106253BC2005AB5DA, + 1865038206253BC2005AB5DA, + 1865038306253BC2005AB5DA, + 1865038406253BC2005AB5DA, + 1865038506253BC2005AB5DA, + 1865038606253BC2005AB5DA, + 1865038706253BC2005AB5DA, + 1865038806253BC2005AB5DA, + 1865038906253BC2005AB5DA, + 1865038A06253BC2005AB5DA, + 1865038B06253BC2005AB5DA, + 1865038C06253BC2005AB5DA, + 1865038D06253BC2005AB5DA, + 1865038E06253BC2005AB5DA, + 1865038F06253BC2005AB5DA, + 1865039006253BC2005AB5DA, + 1865039106253BC2005AB5DA, + 1865039206253BC2005AB5DA, + 1865039306253BC2005AB5DA, + 1865039406253BC2005AB5DA, + 1865039506253BC2005AB5DA, + 1865039606253BC2005AB5DA, + 1865039706253BC2005AB5DA, + 1865039806253BC2005AB5DA, + 1865039906253BC2005AB5DA, + 1865039A06253BC2005AB5DA, + 1865039B06253BC2005AB5DA, + 1865039C06253BC2005AB5DA, + 1865039D06253BC2005AB5DA, + 1865039E06253BC2005AB5DA, + 1865039F06253BC2005AB5DA, + 186503A006253BC2005AB5DA, + 186503A106253BC2005AB5DA, + 186503A206253BC2005AB5DA, + 186503A306253BC2005AB5DA, + 186503A406253BC2005AB5DA, + 186503A506253BC2005AB5DA, + 186503A606253BC2005AB5DA, + 186503A706253BC2005AB5DA, + 186503A806253BC2005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865037806253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "brush_flipx.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037906253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "brush_flipy.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037A06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "brush_flipz.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037B06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "brush_rotatex.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037C06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "brush_rotatey.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037D06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "brush_rotatez.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037E06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "cap_bevel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865037F06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "cap_endcap.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038006253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "cap_ibevel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038106253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "cap_iendcap.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038206253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "curve_cap.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038306253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "dontselectcurve.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038406253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "dontselectmodel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038506253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "file_open.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038606253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "file_save.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038706253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "icon.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038806253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "logo.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038906253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "patch_bend.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038A06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "patch_drilldown.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038B06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "patch_insdel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038C06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "patch_showboundingbox.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038D06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "patch_weld.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038E06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "patch_wireframe.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865038F06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "popup_selection.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039006253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "scalelockx.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039106253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "scalelocky.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039206253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "scalelockz.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039306253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "select_mouserotate.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039406253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "select_mousescale.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039506253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_csgmerge.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039606253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_csgsubtract.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039706253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_makehollow.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039806253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_selectcompletetall.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039906253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_selectinside.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039A06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_selectpartialtall.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039B06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "selection_selecttouching.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039C06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "show_entities.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039D06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "splash.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039E06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "textures_popup.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865039F06253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "view_cameratoggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A006253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "view_cameraupdate.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A106253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "view_change.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A206253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "view_clipper.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A306253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "view_cubicclipping.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A406253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "view_entity.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A506253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "window1.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A606253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "window2.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A706253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "window3.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A806253BC2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "window4.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186503A906253BC3005AB5DA = { + children = ( + 186503AA06253BC3005AB5DA, + 186503AB06253BC3005AB5DA, + 186503AC06253BC3005AB5DA, + 186503AD06253BC3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186503AA06253BC3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186503AB06253BC3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186503AC06253BC3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186503AD06253BC3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186503AE06253BC3005AB5DA = { + children = ( + 186503AF06253BC3005AB5DA, + 186503B006253BC3005AB5DA, + 186503B106253BC3005AB5DA, + 186503B206253BC3005AB5DA, + 186503B306253BC3005AB5DA, + 186503B406253BC3005AB5DA, + 186503B506253BC3005AB5DA, + 186503B606253BC3005AB5DA, + 186503B706253BC3005AB5DA, + 186503B806253BC3005AB5DA, + 186503B906253BC3005AB5DA, + 186503BA06253BC3005AB5DA, + 186503BB06253BC3005AB5DA, + 186503BC06253BC3005AB5DA, + 186503BD06253BC3005AB5DA, + 186503BE06253BC3005AB5DA, + 186503BF06253BC3005AB5DA, + 186503C006253BC3005AB5DA, + 186503C106253BC3005AB5DA, + 186503C206253BC3005AB5DA, + 186503C306253BC3005AB5DA, + 186503C406253BC3005AB5DA, + 186503C506253BC3005AB5DA, + 186503C606253BC3005AB5DA, + 186503C706253BC3005AB5DA, + 186503C806253BC3005AB5DA, + 186503C906253BC3005AB5DA, + 186503CA06253BC3005AB5DA, + 186503CB06253BC3005AB5DA, + 186503CC06253BC3005AB5DA, + 186503CD06253BC3005AB5DA, + 186503CE06253BC3005AB5DA, + 186503CF06253BC3005AB5DA, + 186503D006253BC3005AB5DA, + 186503D106253BC3005AB5DA, + 186503D206253BC3005AB5DA, + 186503D306253BC3005AB5DA, + 186503D406253BC3005AB5DA, + 186503D506253BC3005AB5DA, + 186503D606253BC3005AB5DA, + 186503D706253BC3005AB5DA, + 186503D806253BC3005AB5DA, + 186503D906253BC3005AB5DA, + 186503DA06253BC3005AB5DA, + 186503DB06253BC3005AB5DA, + 186503DC06253BC3005AB5DA, + 186503DD06253BC3005AB5DA, + 186503DE06253BC3005AB5DA, + 186503DF06253BC3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186503AF06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipx.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B006253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipy.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B106253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_flipz.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B206253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatex.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B306253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatey.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B406253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_rotatez.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B506253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_bevel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B606253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_endcap.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B706253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_ibevel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B806253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cap_iendcap.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503B906253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "curve_cap.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503BA06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dontselectcurve.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503BB06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dontselectmodel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503BC06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file_open.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503BD06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "file_save.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503BE06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icon.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503BF06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "logo.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C006253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_bend.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C106253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_drilldown.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C206253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_insdel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C306253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_showboundingbox.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C406253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_weld.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C506253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch_wireframe.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C606253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "popup_selection.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C706253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelockx.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C806253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelocky.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503C906253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scalelockz.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503CA06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select_mouserotate.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503CB06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "select_mousescale.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503CC06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_csgmerge.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503CD06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_csgsubtract.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503CE06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_makehollow.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503CF06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectcompletetall.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D006253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectinside.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D106253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selectpartialtall.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D206253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "selection_selecttouching.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D306253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "show_entities.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D406253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D506253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures_popup.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D606253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cameratoggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D706253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cameraupdate.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D806253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_change.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503D906253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_clipper.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503DA06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_cubicclipping.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503DB06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view_entity.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503DC06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window1.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503DD06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window2.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503DE06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window3.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503DF06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "window4.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186503E006253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = brush_flipx.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E106253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = brush_flipy.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E206253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = brush_flipz.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E306253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = brush_rotatex.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E406253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = brush_rotatey.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E506253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = brush_rotatez.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E606253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = cap_bevel.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E706253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = cap_endcap.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E806253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = cap_ibevel.bmp; + refType = 4; + sourceTree = ""; + }; + 186503E906253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = cap_iendcap.bmp; + refType = 4; + sourceTree = ""; + }; + 186503EA06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = curve_cap.bmp; + refType = 4; + sourceTree = ""; + }; + 186503EB06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = dontselectcurve.bmp; + refType = 4; + sourceTree = ""; + }; + 186503EC06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = dontselectmodel.bmp; + refType = 4; + sourceTree = ""; + }; + 186503ED06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = file_open.bmp; + refType = 4; + sourceTree = ""; + }; + 186503EE06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = file_save.bmp; + refType = 4; + sourceTree = ""; + }; + 186503EF06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = icon.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F006253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = logo.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F106253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = patch_bend.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F206253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = patch_drilldown.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F306253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = patch_insdel.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F406253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = patch_showboundingbox.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F506253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = patch_weld.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F606253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = patch_wireframe.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F706253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = popup_selection.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F806253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = scalelockx.bmp; + refType = 4; + sourceTree = ""; + }; + 186503F906253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = scalelocky.bmp; + refType = 4; + sourceTree = ""; + }; + 186503FA06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = scalelockz.bmp; + refType = 4; + sourceTree = ""; + }; + 186503FB06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = select_mouserotate.bmp; + refType = 4; + sourceTree = ""; + }; + 186503FC06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = select_mousescale.bmp; + refType = 4; + sourceTree = ""; + }; + 186503FD06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_csgmerge.bmp; + refType = 4; + sourceTree = ""; + }; + 186503FE06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_csgsubtract.bmp; + refType = 4; + sourceTree = ""; + }; + 186503FF06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_makehollow.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040006253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_selectcompletetall.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040106253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_selectinside.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040206253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_selectpartialtall.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040306253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = selection_selecttouching.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040406253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = show_entities.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040506253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = splash.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040606253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = textures_popup.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040706253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = view_cameratoggle.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040806253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = view_cameraupdate.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040906253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = view_change.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040A06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = view_clipper.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040B06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = view_cubicclipping.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040C06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = view_entity.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040D06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = window1.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040E06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = window2.bmp; + refType = 4; + sourceTree = ""; + }; + 1865040F06253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = window3.bmp; + refType = 4; + sourceTree = ""; + }; + 1865041006253BC3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = window4.bmp; + refType = 4; + sourceTree = ""; + }; + 1865041106253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = bp_dlg.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041206253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = brush.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041306253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = brush.h; + refType = 4; + sourceTree = ""; + }; + 1865041406253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = brush_primit.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041506253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = brushscript.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041606253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = camera.h; + refType = 4; + sourceTree = ""; + }; + 1865041706253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = camwindow.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041806253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = camwindow.h; + refType = 4; + sourceTree = ""; + }; + 1865041906253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = csg.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041A06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = dialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041B06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = dialog.h; + refType = 4; + sourceTree = ""; + }; + 1865041C06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = dialoginfo.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041D06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = drag.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041E06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = eclass.cpp; + refType = 4; + sourceTree = ""; + }; + 1865041F06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = eclass_def.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042006253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = eclass_def.h; + refType = 4; + sourceTree = ""; + }; + 1865042106253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = error.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042206253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = feedback.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042306253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = feedback.h; + refType = 4; + sourceTree = ""; + }; + 1865042406253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = file.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042506253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = file.h; + refType = 4; + sourceTree = ""; + }; + 1865042606253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = filters.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042706253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = filters.h; + refType = 4; + sourceTree = ""; + }; + 1865042806253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = findtexturedialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042906253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = findtexturedialog.h; + refType = 4; + sourceTree = ""; + }; + 1865042A06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = glinterface.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042B06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = glwidget.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042C06253BC3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = glwidget.h; + refType = 4; + sourceTree = ""; + }; + 1865042D06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = glwindow.cpp; + refType = 4; + sourceTree = ""; + }; + 1865042E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = glwindow.h; + refType = 4; + sourceTree = ""; + }; + 1865042F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = groupdialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865043006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = groupdialog.h; + refType = 4; + sourceTree = ""; + }; + 1865043106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = gtkdlgs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865043206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = "gtkfilesel-darwin.c"; + refType = 4; + sourceTree = ""; + }; + 1865043306253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "gtkfilesel-darwin.h"; + refType = 4; + sourceTree = ""; + }; + 1865043406253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = "gtkfilesel-linux.c"; + refType = 4; + sourceTree = ""; + }; + 1865043506253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "gtkfilesel-linux.h"; + refType = 4; + sourceTree = ""; + }; + 1865043606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = gtkfilesel.c; + refType = 4; + sourceTree = ""; + }; + 1865043706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gtkfilesel.h; + refType = 4; + sourceTree = ""; + }; + 1865043806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = gtkmisc.cpp; + refType = 4; + sourceTree = ""; + }; + 1865043906253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gtkmisc.h; + refType = 4; + sourceTree = ""; + }; + 1865043A06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = GtkRadiant.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865043B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = main.cpp; + refType = 4; + sourceTree = ""; + }; + 1865043C06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = mainframe.cpp; + refType = 4; + sourceTree = ""; + }; + 1865043D06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = mainframe.h; + refType = 4; + sourceTree = ""; + }; + 1865043E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Makefile.mac; + refType = 4; + sourceTree = ""; + }; + 1865043F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = map.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = map.h; + refType = 4; + sourceTree = ""; + }; + 1865044106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = missing.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = parse.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044306253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = parse.h; + refType = 4; + sourceTree = ""; + }; + 1865044406253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = patchdialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044506253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = patchdialog.h; + refType = 4; + sourceTree = ""; + }; + 1865044606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865044706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = pluginentities.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = pluginmanager.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044906253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = pluginmanager.h; + refType = 4; + sourceTree = ""; + }; + 1865044A06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = pmesh.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = points.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044C06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = points.h; + refType = 4; + sourceTree = ""; + }; + 1865044D06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = preferences.cpp; + refType = 4; + sourceTree = ""; + }; + 1865044E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = preferences.h; + refType = 4; + sourceTree = ""; + }; + 1865044F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = profile.cpp; + refType = 4; + sourceTree = ""; + }; + 1865045006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = qe3.cpp; + refType = 4; + sourceTree = ""; + }; + 1865045106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qe3.h; + refType = 4; + sourceTree = ""; + }; + 1865045206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qedefs.h; + refType = 4; + sourceTree = ""; + }; + 1865045306253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qfiles.h; + refType = 4; + sourceTree = ""; + }; + 1865045406253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = "qgl-mac.c"; + refType = 4; + sourceTree = ""; + }; + 1865045506253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qgl.c; + refType = 4; + sourceTree = ""; + }; + 1865045606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qgl.h; + refType = 4; + sourceTree = ""; + }; + 1865045706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = qgl_ext.cpp; + refType = 4; + sourceTree = ""; + }; + 1865045806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = queuedraw.cpp; + refType = 4; + sourceTree = ""; + }; + 1865045906253BC4005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.ico; + path = radiant.ico; + refType = 4; + sourceTree = ""; + }; + 1865045A06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = radiant.rc; + refType = 4; + sourceTree = ""; + }; + 1865045B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = resource.h; + refType = 4; + sourceTree = ""; + }; + 1865045C06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = select.cpp; + refType = 4; + sourceTree = ""; + }; + 1865045D06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = select.h; + refType = 4; + sourceTree = ""; + }; + 1865045E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = selectedface.cpp; + refType = 4; + sourceTree = ""; + }; + 1865045F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = stdafx.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = stdafx.h; + refType = 4; + sourceTree = ""; + }; + 1865046106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfacedialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfacedialog.h; + refType = 4; + sourceTree = ""; + }; + 1865046306253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfaceplugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046406253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfaceplugin.h; + refType = 4; + sourceTree = ""; + }; + 1865046506253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = targetname.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = texmanip.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = texmanip.h; + refType = 4; + sourceTree = ""; + }; + 1865046806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = textures.h; + refType = 4; + sourceTree = ""; + }; + 1865046906253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = texwindow.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046A06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = texwindow.h; + refType = 4; + sourceTree = ""; + }; + 1865046B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = ui.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046C06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ui.h; + refType = 4; + sourceTree = ""; + }; + 1865046D06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = undo.cpp; + refType = 4; + sourceTree = ""; + }; + 1865046E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = undo.h; + refType = 4; + sourceTree = ""; + }; + 1865046F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = vertsel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865047006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = watchbsp.cpp; + refType = 4; + sourceTree = ""; + }; + 1865047106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = watchbsp.h; + refType = 4; + sourceTree = ""; + }; + 1865047206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = winding.cpp; + refType = 4; + sourceTree = ""; + }; + 1865047306253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = winding.h; + refType = 4; + sourceTree = ""; + }; + 1865047406253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = xmlstuff.h; + refType = 4; + sourceTree = ""; + }; + 1865047506253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = xywindow.cpp; + refType = 4; + sourceTree = ""; + }; + 1865047606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = xywindow.h; + refType = 4; + sourceTree = ""; + }; + 1865047706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = z.cpp; + refType = 4; + sourceTree = ""; + }; + 1865047806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = z.h; + refType = 4; + sourceTree = ""; + }; + 1865047906253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = zwindow.cpp; + refType = 4; + sourceTree = ""; + }; + 1865047A06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = zwindow.h; + refType = 4; + sourceTree = ""; + }; + 1865047B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = radiant.sln; + refType = 4; + sourceTree = ""; + }; + 1865047C06253BC4005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "wrapper.pb-project"; + path = radiant.xcode; + refType = 4; + sourceTree = ""; + }; + 1865047D06253BC4005AB5DA = { + children = ( + ); + isa = PBXGroup; + name = Products; + refType = 4; + sourceTree = ""; + }; + 1865047E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + 1865047F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.doxygen; + refType = 4; + sourceTree = ""; + }; + 1865048006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = run_python.bat; + refType = 4; + sourceTree = ""; + }; + 1865048106253BC4005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = scons.signatures; + refType = 4; + sourceTree = ""; + }; + 1865048206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = SConscript; + refType = 4; + sourceTree = ""; + }; + 1865048306253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = SConstruct; + refType = 4; + sourceTree = ""; + }; + 1865048406253BC4005AB5DA = { + children = ( + 1865048506253BC4005AB5DA, + 186504B406253BC5005AB5DA, + 186504B506253BC5005AB5DA, + 186504CA06253BC5005AB5DA, + 18650A1006253BD1005AB5DA, + 18650A2006253BD1005AB5DA, + 18650A2106253BD1005AB5DA, + 18650B6F06253BD5005AB5DA, + 18650B7006253BD5005AB5DA, + 18650B8A06253BD5005AB5DA, + 18650BB306253BD5005AB5DA, + 18650BB406253BD5005AB5DA, + 18650BB506253BD5005AB5DA, + 18650BB606253BD5005AB5DA, + 18650BB706253BD5005AB5DA, + 18650BB806253BD5005AB5DA, + ); + isa = PBXGroup; + path = setup; + refType = 4; + sourceTree = ""; + }; + 1865048506253BC4005AB5DA = { + children = ( + 1865048606253BC4005AB5DA, + 1865048706253BC4005AB5DA, + 1865048806253BC4005AB5DA, + 1865048906253BC4005AB5DA, + 1865048A06253BC4005AB5DA, + 1865049306253BC4005AB5DA, + 1865049C06253BC4005AB5DA, + 1865049D06253BC4005AB5DA, + 186504A606253BC5005AB5DA, + 186504AB06253BC5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865048606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865048706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865048806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865048906253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865048A06253BC4005AB5DA = { + children = ( + 1865048B06253BC4005AB5DA, + 1865048C06253BC4005AB5DA, + 1865048D06253BC4005AB5DA, + 1865048E06253BC4005AB5DA, + 1865048F06253BC4005AB5DA, + 1865049006253BC4005AB5DA, + 1865049106253BC4005AB5DA, + 1865049206253BC4005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865048B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865048C06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865048D06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "openurl.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865048E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "quickstart.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865048F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiantgtkrc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865049006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865049106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.patch.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865049206253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865049306253BC4005AB5DA = { + children = ( + 1865049406253BC4005AB5DA, + 1865049506253BC4005AB5DA, + 1865049606253BC4005AB5DA, + 1865049706253BC4005AB5DA, + 1865049806253BC4005AB5DA, + 1865049906253BC4005AB5DA, + 1865049A06253BC4005AB5DA, + 1865049B06253BC4005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865049406253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049506253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049606253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "openurl.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049706253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "quickstart.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049806253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiantgtkrc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049906253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049A06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.patch.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049B06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865049C06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865049D06253BC4005AB5DA = { + children = ( + 1865049E06253BC4005AB5DA, + 1865049F06253BC4005AB5DA, + 186504A006253BC4005AB5DA, + 186504A106253BC4005AB5DA, + 186504A206253BC5005AB5DA, + 186504A306253BC5005AB5DA, + 186504A406253BC5005AB5DA, + 186504A506253BC5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865049E06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865049F06253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A006253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "openurl.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A106253BC4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "quickstart.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A206253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiantgtkrc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A306253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "setup.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A406253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.patch.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A506253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504A606253BC5005AB5DA = { + children = ( + 186504A706253BC5005AB5DA, + 186504A806253BC5005AB5DA, + 186504A906253BC5005AB5DA, + 186504AA06253BC5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186504A706253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504A806253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504A906253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504AA06253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504AB06253BC5005AB5DA = { + children = ( + 186504AC06253BC5005AB5DA, + 186504AD06253BC5005AB5DA, + 186504AE06253BC5005AB5DA, + 186504AF06253BC5005AB5DA, + 186504B006253BC5005AB5DA, + 186504B106253BC5005AB5DA, + 186504B206253BC5005AB5DA, + 186504B306253BC5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504AC06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504AD06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504AE06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "openurl.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504AF06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "quickstart.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504B006253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiantgtkrc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504B106253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504B206253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.patch.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504B306253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504B406253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = changelog.txt; + refType = 4; + sourceTree = ""; + }; + 186504B506253BC5005AB5DA = { + children = ( + 186504B606253BC5005AB5DA, + 186504C906253BC5005AB5DA, + ); + isa = PBXGroup; + path = common; + refType = 4; + sourceTree = ""; + }; + 186504B606253BC5005AB5DA = { + children = ( + 186504B706253BC5005AB5DA, + 186504B806253BC5005AB5DA, + 186504B906253BC5005AB5DA, + 186504BA06253BC5005AB5DA, + 186504BB06253BC5005AB5DA, + 186504BD06253BC5005AB5DA, + 186504BF06253BC5005AB5DA, + 186504C006253BC5005AB5DA, + 186504C206253BC5005AB5DA, + 186504C706253BC5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186504B706253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186504B806253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186504B906253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186504BA06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186504BB06253BC5005AB5DA = { + children = ( + 186504BC06253BC5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504BC06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504BD06253BC5005AB5DA = { + children = ( + 186504BE06253BC5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504BE06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504BF06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186504C006253BC5005AB5DA = { + children = ( + 186504C106253BC5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504C106253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504C206253BC5005AB5DA = { + children = ( + 186504C306253BC5005AB5DA, + 186504C406253BC5005AB5DA, + 186504C506253BC5005AB5DA, + 186504C606253BC5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186504C306253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504C406253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504C506253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504C606253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504C706253BC5005AB5DA = { + children = ( + 186504C806253BC5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504C806253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504C906253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.perl; + path = setup.pm; + refType = 4; + sourceTree = ""; + }; + 186504CA06253BC5005AB5DA = { + children = ( + 186504CB06253BC5005AB5DA, + 186504DA06253BC5005AB5DA, + 1865087506253BCD005AB5DA, + 186509C306253BD1005AB5DA, + ); + isa = PBXGroup; + path = data; + refType = 4; + sourceTree = ""; + }; + 186504CB06253BC5005AB5DA = { + children = ( + 186504CC06253BC5005AB5DA, + 186504CD06253BC5005AB5DA, + 186504CE06253BC5005AB5DA, + 186504CF06253BC5005AB5DA, + 186504D006253BC5005AB5DA, + 186504D106253BC5005AB5DA, + 186504D206253BC5005AB5DA, + 186504D306253BC5005AB5DA, + 186504D406253BC5005AB5DA, + 186504D906253BC5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186504CC06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186504CD06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186504CE06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186504CF06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186504D006253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504D106253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504D206253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186504D306253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504D406253BC5005AB5DA = { + children = ( + 186504D506253BC5005AB5DA, + 186504D606253BC5005AB5DA, + 186504D706253BC5005AB5DA, + 186504D806253BC5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186504D506253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504D606253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504D706253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504D806253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504D906253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504DA06253BC5005AB5DA = { + children = ( + 186504DB06253BC5005AB5DA, + 186504F606253BC5005AB5DA, + 186504F706253BC5005AB5DA, + 186504F806253BC5005AB5DA, + 186504F906253BC5005AB5DA, + 1865052206253BC6005AB5DA, + 1865077106253BCB005AB5DA, + 1865081C06253BCC005AB5DA, + ); + isa = PBXGroup; + path = baseq3; + refType = 4; + sourceTree = ""; + }; + 186504DB06253BC5005AB5DA = { + children = ( + 186504DC06253BC5005AB5DA, + 186504DD06253BC5005AB5DA, + 186504DE06253BC5005AB5DA, + 186504DF06253BC5005AB5DA, + 186504E006253BC5005AB5DA, + 186504E406253BC5005AB5DA, + 186504E806253BC5005AB5DA, + 186504E906253BC5005AB5DA, + 186504ED06253BC5005AB5DA, + 186504F206253BC5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186504DC06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186504DD06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186504DE06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186504DF06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186504E006253BC5005AB5DA = { + children = ( + 186504E106253BC5005AB5DA, + 186504E206253BC5005AB5DA, + 186504E306253BC5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504E106253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common-spog.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504E206253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "curry.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504E306253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapmedia.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504E406253BC5005AB5DA = { + children = ( + 186504E506253BC5005AB5DA, + 186504E606253BC5005AB5DA, + 186504E706253BC5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504E506253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common-spog.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504E606253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "curry.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504E706253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapmedia.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504E806253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186504E906253BC5005AB5DA = { + children = ( + 186504EA06253BC5005AB5DA, + 186504EB06253BC5005AB5DA, + 186504EC06253BC5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504EA06253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "common-spog.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504EB06253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "curry.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504EC06253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "mapmedia.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186504ED06253BC5005AB5DA = { + children = ( + 186504EE06253BC5005AB5DA, + 186504EF06253BC5005AB5DA, + 186504F006253BC5005AB5DA, + 186504F106253BC5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186504EE06253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186504EF06253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186504F006253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186504F106253BC5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504F206253BC5005AB5DA = { + children = ( + 186504F306253BC5005AB5DA, + 186504F406253BC5005AB5DA, + 186504F506253BC5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186504F306253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common-spog.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504F406253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "curry.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504F506253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapmedia.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186504F606253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "common-spog.pk3"; + refType = 4; + sourceTree = ""; + }; + 186504F706253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = curry.pk3; + refType = 4; + sourceTree = ""; + }; + 186504F806253BC5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = mapmedia.pk3; + refType = 4; + sourceTree = ""; + }; + 186504F906253BC5005AB5DA = { + children = ( + 186504FA06253BC5005AB5DA, + 1865051D06253BC6005AB5DA, + 1865051E06253BC6005AB5DA, + 1865051F06253BC6005AB5DA, + 1865052006253BC6005AB5DA, + 1865052106253BC6005AB5DA, + ); + isa = PBXGroup; + path = maps; + refType = 4; + sourceTree = ""; + }; + 186504FA06253BC5005AB5DA = { + children = ( + 186504FB06253BC5005AB5DA, + 186504FC06253BC5005AB5DA, + 186504FD06253BC5005AB5DA, + 186504FE06253BC5005AB5DA, + 186504FF06253BC5005AB5DA, + 1865050506253BC6005AB5DA, + 1865050B06253BC6005AB5DA, + 1865050C06253BC6005AB5DA, + 1865051206253BC6005AB5DA, + 1865051706253BC6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186504FB06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186504FC06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186504FD06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186504FE06253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186504FF06253BC5005AB5DA = { + children = ( + 1865050006253BC5005AB5DA, + 1865050106253BC5005AB5DA, + 1865050206253BC6005AB5DA, + 1865050306253BC6005AB5DA, + 1865050406253BC6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865050006253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050106253BC5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm17sample.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050206253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm1sample.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050306253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm7sample.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050406253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050506253BC6005AB5DA = { + children = ( + 1865050606253BC6005AB5DA, + 1865050706253BC6005AB5DA, + 1865050806253BC6005AB5DA, + 1865050906253BC6005AB5DA, + 1865050A06253BC6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865050606253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865050706253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm17sample.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865050806253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm1sample.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865050906253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm7sample.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865050A06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865050B06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865050C06253BC6005AB5DA = { + children = ( + 1865050D06253BC6005AB5DA, + 1865050E06253BC6005AB5DA, + 1865050F06253BC6005AB5DA, + 1865051006253BC6005AB5DA, + 1865051106253BC6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865050D06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050E06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm17sample.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865050F06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm1sample.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865051006253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm7sample.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865051106253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865051206253BC6005AB5DA = { + children = ( + 1865051306253BC6005AB5DA, + 1865051406253BC6005AB5DA, + 1865051506253BC6005AB5DA, + 1865051606253BC6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865051306253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865051406253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865051506253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865051606253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865051706253BC6005AB5DA = { + children = ( + 1865051806253BC6005AB5DA, + 1865051906253BC6005AB5DA, + 1865051A06253BC6005AB5DA, + 1865051B06253BC6005AB5DA, + 1865051C06253BC6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865051806253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865051906253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm17sample.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865051A06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm1sample.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865051B06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3dm7sample.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865051C06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865051D06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = museum.map; + refType = 4; + sourceTree = ""; + }; + 1865051E06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3dm17sample.map; + refType = 4; + sourceTree = ""; + }; + 1865051F06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3dm1sample.map; + refType = 4; + sourceTree = ""; + }; + 1865052006253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3dm7sample.map; + refType = 4; + sourceTree = ""; + }; + 1865052106253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = terrademoQ3.map; + refType = 4; + sourceTree = ""; + }; + 1865052206253BC6005AB5DA = { + children = ( + 1865052306253BC6005AB5DA, + 1865053206253BC6005AB5DA, + ); + isa = PBXGroup; + path = models; + refType = 4; + sourceTree = ""; + }; + 1865052306253BC6005AB5DA = { + children = ( + 1865052406253BC6005AB5DA, + 1865052506253BC6005AB5DA, + 1865052606253BC6005AB5DA, + 1865052706253BC6005AB5DA, + 1865052806253BC6005AB5DA, + 1865052906253BC6005AB5DA, + 1865052A06253BC6005AB5DA, + 1865052B06253BC6005AB5DA, + 1865052C06253BC6005AB5DA, + 1865053106253BC6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865052406253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865052506253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865052606253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865052706253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865052806253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865052906253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865052A06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865052B06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865052C06253BC6005AB5DA = { + children = ( + 1865052D06253BC6005AB5DA, + 1865052E06253BC6005AB5DA, + 1865052F06253BC6005AB5DA, + 1865053006253BC6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865052D06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865052E06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865052F06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865053006253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865053106253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865053206253BC6005AB5DA = { + children = ( + 1865053306253BC6005AB5DA, + 1865055606253BC6005AB5DA, + 1865056B06253BC6005AB5DA, + 1865058506253BC7005AB5DA, + 1865059F06253BC7005AB5DA, + 186505B906253BC7005AB5DA, + 186505BA06253BC7005AB5DA, + 186505D906253BC7005AB5DA, + 186505EE06253BC8005AB5DA, + 1865060306253BC8005AB5DA, + 1865060406253BC8005AB5DA, + 1865061906253BC8005AB5DA, + 1865063306253BC8005AB5DA, + 1865064806253BC8005AB5DA, + 1865065D06253BC8005AB5DA, + 1865068606253BC9005AB5DA, + 186506A506253BC9005AB5DA, + 186506BA06253BC9005AB5DA, + 186506BB06253BC9005AB5DA, + 186506DA06253BC9005AB5DA, + 186506EF06253BC9005AB5DA, + 1865070406253BC9005AB5DA, + 1865075006253BCA005AB5DA, + 1865075106253BCA005AB5DA, + 1865077006253BCA005AB5DA, + ); + isa = PBXGroup; + path = mapobjects; + refType = 4; + sourceTree = ""; + }; + 1865053306253BC6005AB5DA = { + children = ( + 1865053406253BC6005AB5DA, + 1865053506253BC6005AB5DA, + 1865053606253BC6005AB5DA, + 1865053706253BC6005AB5DA, + 1865053806253BC6005AB5DA, + 1865053E06253BC6005AB5DA, + 1865054406253BC6005AB5DA, + 1865054506253BC6005AB5DA, + 1865054B06253BC6005AB5DA, + 1865055006253BC6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865053406253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865053506253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865053606253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865053706253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865053806253BC6005AB5DA = { + children = ( + 1865053906253BC6005AB5DA, + 1865053A06253BC6005AB5DA, + 1865053B06253BC6005AB5DA, + 1865053C06253BC6005AB5DA, + 1865053D06253BC6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865053906253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gargoyle1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865053A06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "kmlamp1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865053B06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "statue_major.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865053C06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visor_posed.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865053D06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "walllamp3.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865053E06253BC6005AB5DA = { + children = ( + 1865053F06253BC6005AB5DA, + 1865054006253BC6005AB5DA, + 1865054106253BC6005AB5DA, + 1865054206253BC6005AB5DA, + 1865054306253BC6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865053F06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gargoyle1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865054006253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "kmlamp1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865054106253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "statue_major.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865054206253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visor_posed.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865054306253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "walllamp3.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865054406253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865054506253BC6005AB5DA = { + children = ( + 1865054606253BC6005AB5DA, + 1865054706253BC6005AB5DA, + 1865054806253BC6005AB5DA, + 1865054906253BC6005AB5DA, + 1865054A06253BC6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865054606253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "gargoyle1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865054706253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "kmlamp1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865054806253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "statue_major.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865054906253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "visor_posed.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865054A06253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "walllamp3.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865054B06253BC6005AB5DA = { + children = ( + 1865054C06253BC6005AB5DA, + 1865054D06253BC6005AB5DA, + 1865054E06253BC6005AB5DA, + 1865054F06253BC6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865054C06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865054D06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865054E06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865054F06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865055006253BC6005AB5DA = { + children = ( + 1865055106253BC6005AB5DA, + 1865055206253BC6005AB5DA, + 1865055306253BC6005AB5DA, + 1865055406253BC6005AB5DA, + 1865055506253BC6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865055106253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gargoyle1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865055206253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "kmlamp1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865055306253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "statue_major.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865055406253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visor_posed.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865055506253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "walllamp3.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865055606253BC6005AB5DA = { + children = ( + 1865055706253BC6005AB5DA, + 1865056A06253BC6005AB5DA, + ); + isa = PBXGroup; + path = banner; + refType = 4; + sourceTree = ""; + }; + 1865055706253BC6005AB5DA = { + children = ( + 1865055806253BC6005AB5DA, + 1865055906253BC6005AB5DA, + 1865055A06253BC6005AB5DA, + 1865055B06253BC6005AB5DA, + 1865055C06253BC6005AB5DA, + 1865055E06253BC6005AB5DA, + 1865056006253BC6005AB5DA, + 1865056106253BC6005AB5DA, + 1865056306253BC6005AB5DA, + 1865056806253BC6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865055806253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865055906253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865055A06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865055B06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865055C06253BC6005AB5DA = { + children = ( + 1865055D06253BC6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865055D06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "banner5.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865055E06253BC6005AB5DA = { + children = ( + 1865055F06253BC6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865055F06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "banner5.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865056006253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865056106253BC6005AB5DA = { + children = ( + 1865056206253BC6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865056206253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "banner5.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865056306253BC6005AB5DA = { + children = ( + 1865056406253BC6005AB5DA, + 1865056506253BC6005AB5DA, + 1865056606253BC6005AB5DA, + 1865056706253BC6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865056406253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865056506253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865056606253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865056706253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865056806253BC6005AB5DA = { + children = ( + 1865056906253BC6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865056906253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "banner5.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865056A06253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = banner5.md3; + refType = 4; + sourceTree = ""; + }; + 1865056B06253BC6005AB5DA = { + children = ( + 1865056C06253BC6005AB5DA, + 1865058306253BC7005AB5DA, + 1865058406253BC7005AB5DA, + ); + isa = PBXGroup; + path = baph; + refType = 4; + sourceTree = ""; + }; + 1865056C06253BC6005AB5DA = { + children = ( + 1865056D06253BC6005AB5DA, + 1865056E06253BC6005AB5DA, + 1865056F06253BC6005AB5DA, + 1865057006253BC6005AB5DA, + 1865057106253BC6005AB5DA, + 1865057406253BC6005AB5DA, + 1865057706253BC6005AB5DA, + 1865057806253BC6005AB5DA, + 1865057B06253BC6005AB5DA, + 1865058006253BC6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865056D06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865056E06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865056F06253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865057006253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865057106253BC6005AB5DA = { + children = ( + 1865057206253BC6005AB5DA, + 1865057306253BC6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865057206253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "baphomet_gold.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865057306253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lil_baphomet.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865057406253BC6005AB5DA = { + children = ( + 1865057506253BC6005AB5DA, + 1865057606253BC6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865057506253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "baphomet_gold.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865057606253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lil_baphomet.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865057706253BC6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865057806253BC6005AB5DA = { + children = ( + 1865057906253BC6005AB5DA, + 1865057A06253BC6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865057906253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "baphomet_gold.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865057A06253BC6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "lil_baphomet.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865057B06253BC6005AB5DA = { + children = ( + 1865057C06253BC6005AB5DA, + 1865057D06253BC6005AB5DA, + 1865057E06253BC6005AB5DA, + 1865057F06253BC6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865057C06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865057D06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865057E06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865057F06253BC6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865058006253BC6005AB5DA = { + children = ( + 1865058106253BC7005AB5DA, + 1865058206253BC7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865058106253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "baphomet_gold.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865058206253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lil_baphomet.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865058306253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = baphomet_gold.md3; + refType = 4; + sourceTree = ""; + }; + 1865058406253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = lil_baphomet.md3; + refType = 4; + sourceTree = ""; + }; + 1865058506253BC7005AB5DA = { + children = ( + 1865058606253BC7005AB5DA, + 1865059D06253BC7005AB5DA, + 1865059E06253BC7005AB5DA, + ); + isa = PBXGroup; + path = bitch; + refType = 4; + sourceTree = ""; + }; + 1865058606253BC7005AB5DA = { + children = ( + 1865058706253BC7005AB5DA, + 1865058806253BC7005AB5DA, + 1865058906253BC7005AB5DA, + 1865058A06253BC7005AB5DA, + 1865058B06253BC7005AB5DA, + 1865058E06253BC7005AB5DA, + 1865059106253BC7005AB5DA, + 1865059206253BC7005AB5DA, + 1865059506253BC7005AB5DA, + 1865059A06253BC7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865058706253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865058806253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865058906253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865058A06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865058B06253BC7005AB5DA = { + children = ( + 1865058C06253BC7005AB5DA, + 1865058D06253BC7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865058C06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fembot.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865058D06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fembotbig.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865058E06253BC7005AB5DA = { + children = ( + 1865058F06253BC7005AB5DA, + 1865059006253BC7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865058F06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fembot.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865059006253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fembotbig.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865059106253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865059206253BC7005AB5DA = { + children = ( + 1865059306253BC7005AB5DA, + 1865059406253BC7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865059306253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "fembot.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865059406253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "fembotbig.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865059506253BC7005AB5DA = { + children = ( + 1865059606253BC7005AB5DA, + 1865059706253BC7005AB5DA, + 1865059806253BC7005AB5DA, + 1865059906253BC7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865059606253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865059706253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865059806253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865059906253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865059A06253BC7005AB5DA = { + children = ( + 1865059B06253BC7005AB5DA, + 1865059C06253BC7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865059B06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fembot.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865059C06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fembotbig.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865059D06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = fembot.md3; + refType = 4; + sourceTree = ""; + }; + 1865059E06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = fembotbig.md3; + refType = 4; + sourceTree = ""; + }; + 1865059F06253BC7005AB5DA = { + children = ( + 186505A006253BC7005AB5DA, + 186505B706253BC7005AB5DA, + 186505B806253BC7005AB5DA, + ); + isa = PBXGroup; + path = corpse; + refType = 4; + sourceTree = ""; + }; + 186505A006253BC7005AB5DA = { + children = ( + 186505A106253BC7005AB5DA, + 186505A206253BC7005AB5DA, + 186505A306253BC7005AB5DA, + 186505A406253BC7005AB5DA, + 186505A506253BC7005AB5DA, + 186505A806253BC7005AB5DA, + 186505AB06253BC7005AB5DA, + 186505AC06253BC7005AB5DA, + 186505AF06253BC7005AB5DA, + 186505B406253BC7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186505A106253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186505A206253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186505A306253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186505A406253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186505A506253BC7005AB5DA = { + children = ( + 186505A606253BC7005AB5DA, + 186505A706253BC7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505A606253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "corpse.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505A706253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "torso.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505A806253BC7005AB5DA = { + children = ( + 186505A906253BC7005AB5DA, + 186505AA06253BC7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505A906253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "corpse.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505AA06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "torso.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505AB06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186505AC06253BC7005AB5DA = { + children = ( + 186505AD06253BC7005AB5DA, + 186505AE06253BC7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505AD06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "corpse.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505AE06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "torso.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505AF06253BC7005AB5DA = { + children = ( + 186505B006253BC7005AB5DA, + 186505B106253BC7005AB5DA, + 186505B206253BC7005AB5DA, + 186505B306253BC7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186505B006253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505B106253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505B206253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505B306253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186505B406253BC7005AB5DA = { + children = ( + 186505B506253BC7005AB5DA, + 186505B606253BC7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186505B506253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "corpse.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505B606253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "torso.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505B706253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = corpse.md3; + refType = 4; + sourceTree = ""; + }; + 186505B806253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = torso.md3; + refType = 4; + sourceTree = ""; + }; + 186505B906253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = gargoyle1.md3; + refType = 4; + sourceTree = ""; + }; + 186505BA06253BC7005AB5DA = { + children = ( + 186505BB06253BC7005AB5DA, + 186505D606253BC7005AB5DA, + 186505D706253BC7005AB5DA, + 186505D806253BC7005AB5DA, + ); + isa = PBXGroup; + path = gratelamp; + refType = 4; + sourceTree = ""; + }; + 186505BB06253BC7005AB5DA = { + children = ( + 186505BC06253BC7005AB5DA, + 186505BD06253BC7005AB5DA, + 186505BE06253BC7005AB5DA, + 186505BF06253BC7005AB5DA, + 186505C006253BC7005AB5DA, + 186505C406253BC7005AB5DA, + 186505C806253BC7005AB5DA, + 186505C906253BC7005AB5DA, + 186505CD06253BC7005AB5DA, + 186505D206253BC7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186505BC06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186505BD06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186505BE06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186505BF06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186505C006253BC7005AB5DA = { + children = ( + 186505C106253BC7005AB5DA, + 186505C206253BC7005AB5DA, + 186505C306253BC7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505C106253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratelamp.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505C206253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratetorch.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505C306253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratetorchbig.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505C406253BC7005AB5DA = { + children = ( + 186505C506253BC7005AB5DA, + 186505C606253BC7005AB5DA, + 186505C706253BC7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505C506253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratelamp.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505C606253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratetorch.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505C706253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratetorchbig.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505C806253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186505C906253BC7005AB5DA = { + children = ( + 186505CA06253BC7005AB5DA, + 186505CB06253BC7005AB5DA, + 186505CC06253BC7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505CA06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "gratelamp.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505CB06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "gratetorch.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505CC06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "gratetorchbig.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505CD06253BC7005AB5DA = { + children = ( + 186505CE06253BC7005AB5DA, + 186505CF06253BC7005AB5DA, + 186505D006253BC7005AB5DA, + 186505D106253BC7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186505CE06253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505CF06253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505D006253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505D106253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186505D206253BC7005AB5DA = { + children = ( + 186505D306253BC7005AB5DA, + 186505D406253BC7005AB5DA, + 186505D506253BC7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186505D306253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratelamp.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505D406253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratetorch.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505D506253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gratetorchbig.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505D606253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = gratelamp.md3; + refType = 4; + sourceTree = ""; + }; + 186505D706253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = gratetorch.md3; + refType = 4; + sourceTree = ""; + }; + 186505D806253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = gratetorchbig.md3; + refType = 4; + sourceTree = ""; + }; + 186505D906253BC7005AB5DA = { + children = ( + 186505DA06253BC7005AB5DA, + 186505ED06253BC7005AB5DA, + ); + isa = PBXGroup; + path = jesus; + refType = 4; + sourceTree = ""; + }; + 186505DA06253BC7005AB5DA = { + children = ( + 186505DB06253BC7005AB5DA, + 186505DC06253BC7005AB5DA, + 186505DD06253BC7005AB5DA, + 186505DE06253BC7005AB5DA, + 186505DF06253BC7005AB5DA, + 186505E106253BC7005AB5DA, + 186505E306253BC7005AB5DA, + 186505E406253BC7005AB5DA, + 186505E606253BC7005AB5DA, + 186505EB06253BC7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186505DB06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186505DC06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186505DD06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186505DE06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186505DF06253BC7005AB5DA = { + children = ( + 186505E006253BC7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505E006253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jesus.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505E106253BC7005AB5DA = { + children = ( + 186505E206253BC7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505E206253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jesus.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505E306253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186505E406253BC7005AB5DA = { + children = ( + 186505E506253BC7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505E506253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "jesus.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505E606253BC7005AB5DA = { + children = ( + 186505E706253BC7005AB5DA, + 186505E806253BC7005AB5DA, + 186505E906253BC7005AB5DA, + 186505EA06253BC7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186505E706253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505E806253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505E906253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505EA06253BC7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186505EB06253BC7005AB5DA = { + children = ( + 186505EC06253BC7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186505EC06253BC7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jesus.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505ED06253BC7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = jesus.md3; + refType = 4; + sourceTree = ""; + }; + 186505EE06253BC8005AB5DA = { + children = ( + 186505EF06253BC8005AB5DA, + 1865060206253BC8005AB5DA, + ); + isa = PBXGroup; + path = jets; + refType = 4; + sourceTree = ""; + }; + 186505EF06253BC8005AB5DA = { + children = ( + 186505F006253BC8005AB5DA, + 186505F106253BC8005AB5DA, + 186505F206253BC8005AB5DA, + 186505F306253BC8005AB5DA, + 186505F406253BC8005AB5DA, + 186505F606253BC8005AB5DA, + 186505F806253BC8005AB5DA, + 186505F906253BC8005AB5DA, + 186505FB06253BC8005AB5DA, + 1865060006253BC8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186505F006253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186505F106253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186505F206253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186505F306253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186505F406253BC8005AB5DA = { + children = ( + 186505F506253BC8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505F506253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jets01.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505F606253BC8005AB5DA = { + children = ( + 186505F706253BC8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505F706253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jets01.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186505F806253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186505F906253BC8005AB5DA = { + children = ( + 186505FA06253BC8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505FA06253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "jets01.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186505FB06253BC8005AB5DA = { + children = ( + 186505FC06253BC8005AB5DA, + 186505FD06253BC8005AB5DA, + 186505FE06253BC8005AB5DA, + 186505FF06253BC8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186505FC06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186505FD06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186505FE06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186505FF06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865060006253BC8005AB5DA = { + children = ( + 1865060106253BC8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865060106253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jets01.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865060206253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = jets01.md3; + refType = 4; + sourceTree = ""; + }; + 1865060306253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = kmlamp1.md3; + refType = 4; + sourceTree = ""; + }; + 1865060406253BC8005AB5DA = { + children = ( + 1865060506253BC8005AB5DA, + 1865061806253BC8005AB5DA, + ); + isa = PBXGroup; + path = lamps; + refType = 4; + sourceTree = ""; + }; + 1865060506253BC8005AB5DA = { + children = ( + 1865060606253BC8005AB5DA, + 1865060706253BC8005AB5DA, + 1865060806253BC8005AB5DA, + 1865060906253BC8005AB5DA, + 1865060A06253BC8005AB5DA, + 1865060C06253BC8005AB5DA, + 1865060E06253BC8005AB5DA, + 1865060F06253BC8005AB5DA, + 1865061106253BC8005AB5DA, + 1865061606253BC8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865060606253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865060706253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865060806253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865060906253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865060A06253BC8005AB5DA = { + children = ( + 1865060B06253BC8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865060B06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bot_lamp2.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865060C06253BC8005AB5DA = { + children = ( + 1865060D06253BC8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865060D06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bot_lamp2.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865060E06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865060F06253BC8005AB5DA = { + children = ( + 1865061006253BC8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865061006253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bot_lamp2.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865061106253BC8005AB5DA = { + children = ( + 1865061206253BC8005AB5DA, + 1865061306253BC8005AB5DA, + 1865061406253BC8005AB5DA, + 1865061506253BC8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865061206253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865061306253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865061406253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865061506253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865061606253BC8005AB5DA = { + children = ( + 1865061706253BC8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865061706253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bot_lamp2.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865061806253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = bot_lamp2.md3; + refType = 4; + sourceTree = ""; + }; + 1865061906253BC8005AB5DA = { + children = ( + 1865061A06253BC8005AB5DA, + 1865063106253BC8005AB5DA, + 1865063206253BC8005AB5DA, + ); + isa = PBXGroup; + path = pipe; + refType = 4; + sourceTree = ""; + }; + 1865061A06253BC8005AB5DA = { + children = ( + 1865061B06253BC8005AB5DA, + 1865061C06253BC8005AB5DA, + 1865061D06253BC8005AB5DA, + 1865061E06253BC8005AB5DA, + 1865061F06253BC8005AB5DA, + 1865062206253BC8005AB5DA, + 1865062506253BC8005AB5DA, + 1865062606253BC8005AB5DA, + 1865062906253BC8005AB5DA, + 1865062E06253BC8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865061B06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865061C06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865061D06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865061E06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865061F06253BC8005AB5DA = { + children = ( + 1865062006253BC8005AB5DA, + 1865062106253BC8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865062006253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pipe02.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865062106253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pipe02b.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865062206253BC8005AB5DA = { + children = ( + 1865062306253BC8005AB5DA, + 1865062406253BC8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865062306253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pipe02.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865062406253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pipe02b.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865062506253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865062606253BC8005AB5DA = { + children = ( + 1865062706253BC8005AB5DA, + 1865062806253BC8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865062706253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "pipe02.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865062806253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "pipe02b.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865062906253BC8005AB5DA = { + children = ( + 1865062A06253BC8005AB5DA, + 1865062B06253BC8005AB5DA, + 1865062C06253BC8005AB5DA, + 1865062D06253BC8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865062A06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865062B06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865062C06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865062D06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865062E06253BC8005AB5DA = { + children = ( + 1865062F06253BC8005AB5DA, + 1865063006253BC8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865062F06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pipe02.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865063006253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pipe02b.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865063106253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pipe02.md3; + refType = 4; + sourceTree = ""; + }; + 1865063206253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pipe02b.md3; + refType = 4; + sourceTree = ""; + }; + 1865063306253BC8005AB5DA = { + children = ( + 1865063406253BC8005AB5DA, + 1865064706253BC8005AB5DA, + ); + isa = PBXGroup; + path = podium; + refType = 4; + sourceTree = ""; + }; + 1865063406253BC8005AB5DA = { + children = ( + 1865063506253BC8005AB5DA, + 1865063606253BC8005AB5DA, + 1865063706253BC8005AB5DA, + 1865063806253BC8005AB5DA, + 1865063906253BC8005AB5DA, + 1865063B06253BC8005AB5DA, + 1865063D06253BC8005AB5DA, + 1865063E06253BC8005AB5DA, + 1865064006253BC8005AB5DA, + 1865064506253BC8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865063506253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865063606253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865063706253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865063806253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865063906253BC8005AB5DA = { + children = ( + 1865063A06253BC8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865063A06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "podium4.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865063B06253BC8005AB5DA = { + children = ( + 1865063C06253BC8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865063C06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "podium4.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865063D06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865063E06253BC8005AB5DA = { + children = ( + 1865063F06253BC8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865063F06253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "podium4.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865064006253BC8005AB5DA = { + children = ( + 1865064106253BC8005AB5DA, + 1865064206253BC8005AB5DA, + 1865064306253BC8005AB5DA, + 1865064406253BC8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865064106253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865064206253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865064306253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865064406253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865064506253BC8005AB5DA = { + children = ( + 1865064606253BC8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865064606253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "podium4.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865064706253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = podium4.md3; + refType = 4; + sourceTree = ""; + }; + 1865064806253BC8005AB5DA = { + children = ( + 1865064906253BC8005AB5DA, + 1865065C06253BC8005AB5DA, + ); + isa = PBXGroup; + path = portal_2; + refType = 4; + sourceTree = ""; + }; + 1865064906253BC8005AB5DA = { + children = ( + 1865064A06253BC8005AB5DA, + 1865064B06253BC8005AB5DA, + 1865064C06253BC8005AB5DA, + 1865064D06253BC8005AB5DA, + 1865064E06253BC8005AB5DA, + 1865065006253BC8005AB5DA, + 1865065206253BC8005AB5DA, + 1865065306253BC8005AB5DA, + 1865065506253BC8005AB5DA, + 1865065A06253BC8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865064A06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865064B06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865064C06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865064D06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865064E06253BC8005AB5DA = { + children = ( + 1865064F06253BC8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865064F06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portal_2.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865065006253BC8005AB5DA = { + children = ( + 1865065106253BC8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865065106253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portal_2.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865065206253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865065306253BC8005AB5DA = { + children = ( + 1865065406253BC8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865065406253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "portal_2.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865065506253BC8005AB5DA = { + children = ( + 1865065606253BC8005AB5DA, + 1865065706253BC8005AB5DA, + 1865065806253BC8005AB5DA, + 1865065906253BC8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865065606253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865065706253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865065806253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865065906253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865065A06253BC8005AB5DA = { + children = ( + 1865065B06253BC8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865065B06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portal_2.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865065C06253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = portal_2.md3; + refType = 4; + sourceTree = ""; + }; + 1865065D06253BC8005AB5DA = { + children = ( + 1865065E06253BC8005AB5DA, + 1865068106253BC9005AB5DA, + 1865068206253BC9005AB5DA, + 1865068306253BC9005AB5DA, + 1865068406253BC9005AB5DA, + 1865068506253BC9005AB5DA, + ); + isa = PBXGroup; + path = skel; + refType = 4; + sourceTree = ""; + }; + 1865065E06253BC8005AB5DA = { + children = ( + 1865065F06253BC8005AB5DA, + 1865066006253BC8005AB5DA, + 1865066106253BC8005AB5DA, + 1865066206253BC8005AB5DA, + 1865066306253BC8005AB5DA, + 1865066906253BC8005AB5DA, + 1865066F06253BC8005AB5DA, + 1865067006253BC8005AB5DA, + 1865067606253BC8005AB5DA, + 1865067B06253BC8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865065F06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865066006253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865066106253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865066206253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865066306253BC8005AB5DA = { + children = ( + 1865066406253BC8005AB5DA, + 1865066506253BC8005AB5DA, + 1865066606253BC8005AB5DA, + 1865066706253BC8005AB5DA, + 1865066806253BC8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865066406253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel01.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865066506253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel02mid.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865066606253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel_ribs.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865066706253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xray.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865066806253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xraybig.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865066906253BC8005AB5DA = { + children = ( + 1865066A06253BC8005AB5DA, + 1865066B06253BC8005AB5DA, + 1865066C06253BC8005AB5DA, + 1865066D06253BC8005AB5DA, + 1865066E06253BC8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865066A06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel01.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865066B06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel02mid.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865066C06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel_ribs.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865066D06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xray.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865066E06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xraybig.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865066F06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865067006253BC8005AB5DA = { + children = ( + 1865067106253BC8005AB5DA, + 1865067206253BC8005AB5DA, + 1865067306253BC8005AB5DA, + 1865067406253BC8005AB5DA, + 1865067506253BC8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865067106253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "skel01.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865067206253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "skel02mid.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865067306253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "skel_ribs.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865067406253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "xray.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865067506253BC8005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "xraybig.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865067606253BC8005AB5DA = { + children = ( + 1865067706253BC8005AB5DA, + 1865067806253BC8005AB5DA, + 1865067906253BC8005AB5DA, + 1865067A06253BC8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865067706253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865067806253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865067906253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865067A06253BC8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865067B06253BC8005AB5DA = { + children = ( + 1865067C06253BC8005AB5DA, + 1865067D06253BC8005AB5DA, + 1865067E06253BC8005AB5DA, + 1865067F06253BC8005AB5DA, + 1865068006253BC9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865067C06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel01.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865067D06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel02mid.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865067E06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skel_ribs.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865067F06253BC8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xray.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865068006253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xraybig.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865068106253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = skel01.md3; + refType = 4; + sourceTree = ""; + }; + 1865068206253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = skel02mid.md3; + refType = 4; + sourceTree = ""; + }; + 1865068306253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = skel_ribs.md3; + refType = 4; + sourceTree = ""; + }; + 1865068406253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = xray.md3; + refType = 4; + sourceTree = ""; + }; + 1865068506253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = xraybig.md3; + refType = 4; + sourceTree = ""; + }; + 1865068606253BC9005AB5DA = { + children = ( + 1865068706253BC9005AB5DA, + 186506A206253BC9005AB5DA, + 186506A306253BC9005AB5DA, + 186506A406253BC9005AB5DA, + ); + isa = PBXGroup; + path = skull; + refType = 4; + sourceTree = ""; + }; + 1865068706253BC9005AB5DA = { + children = ( + 1865068806253BC9005AB5DA, + 1865068906253BC9005AB5DA, + 1865068A06253BC9005AB5DA, + 1865068B06253BC9005AB5DA, + 1865068C06253BC9005AB5DA, + 1865069006253BC9005AB5DA, + 1865069406253BC9005AB5DA, + 1865069506253BC9005AB5DA, + 1865069906253BC9005AB5DA, + 1865069E06253BC9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865068806253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865068906253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865068A06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865068B06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865068C06253BC9005AB5DA = { + children = ( + 1865068D06253BC9005AB5DA, + 1865068E06253BC9005AB5DA, + 1865068F06253BC9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865068D06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "monkeyface.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865068E06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skull.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865068F06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skull_tilt1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865069006253BC9005AB5DA = { + children = ( + 1865069106253BC9005AB5DA, + 1865069206253BC9005AB5DA, + 1865069306253BC9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865069106253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "monkeyface.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865069206253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skull.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865069306253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skull_tilt1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865069406253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865069506253BC9005AB5DA = { + children = ( + 1865069606253BC9005AB5DA, + 1865069706253BC9005AB5DA, + 1865069806253BC9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865069606253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "monkeyface.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865069706253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "skull.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865069806253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "skull_tilt1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865069906253BC9005AB5DA = { + children = ( + 1865069A06253BC9005AB5DA, + 1865069B06253BC9005AB5DA, + 1865069C06253BC9005AB5DA, + 1865069D06253BC9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865069A06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865069B06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865069C06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865069D06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865069E06253BC9005AB5DA = { + children = ( + 1865069F06253BC9005AB5DA, + 186506A006253BC9005AB5DA, + 186506A106253BC9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865069F06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "monkeyface.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506A006253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skull.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506A106253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skull_tilt1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506A206253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = monkeyface.md3; + refType = 4; + sourceTree = ""; + }; + 186506A306253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = skull.md3; + refType = 4; + sourceTree = ""; + }; + 186506A406253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = skull_tilt1.md3; + refType = 4; + sourceTree = ""; + }; + 186506A506253BC9005AB5DA = { + children = ( + 186506A606253BC9005AB5DA, + 186506B906253BC9005AB5DA, + ); + isa = PBXGroup; + path = spotlamp; + refType = 4; + sourceTree = ""; + }; + 186506A606253BC9005AB5DA = { + children = ( + 186506A706253BC9005AB5DA, + 186506A806253BC9005AB5DA, + 186506A906253BC9005AB5DA, + 186506AA06253BC9005AB5DA, + 186506AB06253BC9005AB5DA, + 186506AD06253BC9005AB5DA, + 186506AF06253BC9005AB5DA, + 186506B006253BC9005AB5DA, + 186506B206253BC9005AB5DA, + 186506B706253BC9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186506A706253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186506A806253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186506A906253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186506AA06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186506AB06253BC9005AB5DA = { + children = ( + 186506AC06253BC9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506AC06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spotlamp.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506AD06253BC9005AB5DA = { + children = ( + 186506AE06253BC9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506AE06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spotlamp.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506AF06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186506B006253BC9005AB5DA = { + children = ( + 186506B106253BC9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506B106253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "spotlamp.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506B206253BC9005AB5DA = { + children = ( + 186506B306253BC9005AB5DA, + 186506B406253BC9005AB5DA, + 186506B506253BC9005AB5DA, + 186506B606253BC9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186506B306253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506B406253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506B506253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506B606253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186506B706253BC9005AB5DA = { + children = ( + 186506B806253BC9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186506B806253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spotlamp.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506B906253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = spotlamp.md3; + refType = 4; + sourceTree = ""; + }; + 186506BA06253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = statue_major.md3; + refType = 4; + sourceTree = ""; + }; + 186506BB06253BC9005AB5DA = { + children = ( + 186506BC06253BC9005AB5DA, + 186506D706253BC9005AB5DA, + 186506D806253BC9005AB5DA, + 186506D906253BC9005AB5DA, + ); + isa = PBXGroup; + path = storch; + refType = 4; + sourceTree = ""; + }; + 186506BC06253BC9005AB5DA = { + children = ( + 186506BD06253BC9005AB5DA, + 186506BE06253BC9005AB5DA, + 186506BF06253BC9005AB5DA, + 186506C006253BC9005AB5DA, + 186506C106253BC9005AB5DA, + 186506C506253BC9005AB5DA, + 186506C906253BC9005AB5DA, + 186506CA06253BC9005AB5DA, + 186506CE06253BC9005AB5DA, + 186506D306253BC9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186506BD06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186506BE06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186506BF06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186506C006253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186506C106253BC9005AB5DA = { + children = ( + 186506C206253BC9005AB5DA, + 186506C306253BC9005AB5DA, + 186506C406253BC9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506C206253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "storch.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506C306253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "storchx.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506C406253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tall_torch.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506C506253BC9005AB5DA = { + children = ( + 186506C606253BC9005AB5DA, + 186506C706253BC9005AB5DA, + 186506C806253BC9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506C606253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "storch.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506C706253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "storchx.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506C806253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tall_torch.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506C906253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186506CA06253BC9005AB5DA = { + children = ( + 186506CB06253BC9005AB5DA, + 186506CC06253BC9005AB5DA, + 186506CD06253BC9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506CB06253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "storch.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506CC06253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "storchx.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506CD06253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tall_torch.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506CE06253BC9005AB5DA = { + children = ( + 186506CF06253BC9005AB5DA, + 186506D006253BC9005AB5DA, + 186506D106253BC9005AB5DA, + 186506D206253BC9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186506CF06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506D006253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506D106253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506D206253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186506D306253BC9005AB5DA = { + children = ( + 186506D406253BC9005AB5DA, + 186506D506253BC9005AB5DA, + 186506D606253BC9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186506D406253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "storch.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506D506253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "storchx.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506D606253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tall_torch.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506D706253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = storch.md3; + refType = 4; + sourceTree = ""; + }; + 186506D806253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = storchx.md3; + refType = 4; + sourceTree = ""; + }; + 186506D906253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tall_torch.md3; + refType = 4; + sourceTree = ""; + }; + 186506DA06253BC9005AB5DA = { + children = ( + 186506DB06253BC9005AB5DA, + 186506EE06253BC9005AB5DA, + ); + isa = PBXGroup; + path = teleporter; + refType = 4; + sourceTree = ""; + }; + 186506DB06253BC9005AB5DA = { + children = ( + 186506DC06253BC9005AB5DA, + 186506DD06253BC9005AB5DA, + 186506DE06253BC9005AB5DA, + 186506DF06253BC9005AB5DA, + 186506E006253BC9005AB5DA, + 186506E206253BC9005AB5DA, + 186506E406253BC9005AB5DA, + 186506E506253BC9005AB5DA, + 186506E706253BC9005AB5DA, + 186506EC06253BC9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186506DC06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186506DD06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186506DE06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186506DF06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186506E006253BC9005AB5DA = { + children = ( + 186506E106253BC9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506E106253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "teleporter.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506E206253BC9005AB5DA = { + children = ( + 186506E306253BC9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506E306253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "teleporter.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506E406253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186506E506253BC9005AB5DA = { + children = ( + 186506E606253BC9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506E606253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "teleporter.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506E706253BC9005AB5DA = { + children = ( + 186506E806253BC9005AB5DA, + 186506E906253BC9005AB5DA, + 186506EA06253BC9005AB5DA, + 186506EB06253BC9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186506E806253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506E906253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506EA06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506EB06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186506EC06253BC9005AB5DA = { + children = ( + 186506ED06253BC9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186506ED06253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "teleporter.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506EE06253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = teleporter.md3; + refType = 4; + sourceTree = ""; + }; + 186506EF06253BC9005AB5DA = { + children = ( + 186506F006253BC9005AB5DA, + 1865070306253BC9005AB5DA, + ); + isa = PBXGroup; + path = timlamp; + refType = 4; + sourceTree = ""; + }; + 186506F006253BC9005AB5DA = { + children = ( + 186506F106253BC9005AB5DA, + 186506F206253BC9005AB5DA, + 186506F306253BC9005AB5DA, + 186506F406253BC9005AB5DA, + 186506F506253BC9005AB5DA, + 186506F706253BC9005AB5DA, + 186506F906253BC9005AB5DA, + 186506FA06253BC9005AB5DA, + 186506FC06253BC9005AB5DA, + 1865070106253BC9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186506F106253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186506F206253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186506F306253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186506F406253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186506F506253BC9005AB5DA = { + children = ( + 186506F606253BC9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506F606253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "timlamp.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506F706253BC9005AB5DA = { + children = ( + 186506F806253BC9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506F806253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "timlamp.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186506F906253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186506FA06253BC9005AB5DA = { + children = ( + 186506FB06253BC9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186506FB06253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "timlamp.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186506FC06253BC9005AB5DA = { + children = ( + 186506FD06253BC9005AB5DA, + 186506FE06253BC9005AB5DA, + 186506FF06253BC9005AB5DA, + 1865070006253BC9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186506FD06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186506FE06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186506FF06253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865070006253BC9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865070106253BC9005AB5DA = { + children = ( + 1865070206253BC9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865070206253BC9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "timlamp.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865070306253BC9005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = timlamp.md3; + refType = 4; + sourceTree = ""; + }; + 1865070406253BC9005AB5DA = { + children = ( + 1865070506253BC9005AB5DA, + 1865074406253BCA005AB5DA, + 1865074506253BCA005AB5DA, + 1865074606253BCA005AB5DA, + 1865074706253BCA005AB5DA, + 1865074806253BCA005AB5DA, + 1865074906253BCA005AB5DA, + 1865074A06253BCA005AB5DA, + 1865074B06253BCA005AB5DA, + 1865074C06253BCA005AB5DA, + 1865074D06253BCA005AB5DA, + 1865074E06253BCA005AB5DA, + 1865074F06253BCA005AB5DA, + ); + isa = PBXGroup; + path = tree2; + refType = 4; + sourceTree = ""; + }; + 1865070506253BC9005AB5DA = { + children = ( + 1865070606253BCA005AB5DA, + 1865070706253BCA005AB5DA, + 1865070806253BCA005AB5DA, + 1865070906253BCA005AB5DA, + 1865070A06253BCA005AB5DA, + 1865071706253BCA005AB5DA, + 1865072406253BCA005AB5DA, + 1865072506253BCA005AB5DA, + 1865073206253BCA005AB5DA, + 1865073706253BCA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865070606253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865070706253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865070806253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865070906253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865070A06253BCA005AB5DA = { + children = ( + 1865070B06253BCA005AB5DA, + 1865070C06253BCA005AB5DA, + 1865070D06253BCA005AB5DA, + 1865070E06253BCA005AB5DA, + 1865070F06253BCA005AB5DA, + 1865071006253BCA005AB5DA, + 1865071106253BCA005AB5DA, + 1865071206253BCA005AB5DA, + 1865071306253BCA005AB5DA, + 1865071406253BCA005AB5DA, + 1865071506253BCA005AB5DA, + 1865071606253BCA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865070B06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "branch2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865070C06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865070D06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree10.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865070E06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree2.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865070F06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree3.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071006253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree4.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071106253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree5.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071206253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree6.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071306253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree7.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071406253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree8.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071506253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree9.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071606253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trunk2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865071706253BCA005AB5DA = { + children = ( + 1865071806253BCA005AB5DA, + 1865071906253BCA005AB5DA, + 1865071A06253BCA005AB5DA, + 1865071B06253BCA005AB5DA, + 1865071C06253BCA005AB5DA, + 1865071D06253BCA005AB5DA, + 1865071E06253BCA005AB5DA, + 1865071F06253BCA005AB5DA, + 1865072006253BCA005AB5DA, + 1865072106253BCA005AB5DA, + 1865072206253BCA005AB5DA, + 1865072306253BCA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865071806253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "branch2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071906253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071A06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree10.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071B06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree2.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071C06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree3.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071D06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree4.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071E06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree5.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865071F06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree6.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865072006253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree7.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865072106253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree8.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865072206253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree9.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865072306253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trunk2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865072406253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865072506253BCA005AB5DA = { + children = ( + 1865072606253BCA005AB5DA, + 1865072706253BCA005AB5DA, + 1865072806253BCA005AB5DA, + 1865072906253BCA005AB5DA, + 1865072A06253BCA005AB5DA, + 1865072B06253BCA005AB5DA, + 1865072C06253BCA005AB5DA, + 1865072D06253BCA005AB5DA, + 1865072E06253BCA005AB5DA, + 1865072F06253BCA005AB5DA, + 1865073006253BCA005AB5DA, + 1865073106253BCA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865072606253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "branch2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072706253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree1.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072806253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree10.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072906253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree2.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072A06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree3.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072B06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree4.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072C06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree5.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072D06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree6.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072E06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree7.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865072F06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree8.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865073006253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "tree9.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865073106253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "trunk2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865073206253BCA005AB5DA = { + children = ( + 1865073306253BCA005AB5DA, + 1865073406253BCA005AB5DA, + 1865073506253BCA005AB5DA, + 1865073606253BCA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865073306253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865073406253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865073506253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865073606253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865073706253BCA005AB5DA = { + children = ( + 1865073806253BCA005AB5DA, + 1865073906253BCA005AB5DA, + 1865073A06253BCA005AB5DA, + 1865073B06253BCA005AB5DA, + 1865073C06253BCA005AB5DA, + 1865073D06253BCA005AB5DA, + 1865073E06253BCA005AB5DA, + 1865073F06253BCA005AB5DA, + 1865074006253BCA005AB5DA, + 1865074106253BCA005AB5DA, + 1865074206253BCA005AB5DA, + 1865074306253BCA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865073806253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "branch2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073906253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree1.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073A06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree10.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073B06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree2.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073C06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree3.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073D06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree4.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073E06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree5.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865073F06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree6.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865074006253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree7.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865074106253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree8.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865074206253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree9.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865074306253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trunk2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865074406253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = branch2.tga; + refType = 4; + sourceTree = ""; + }; + 1865074506253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree1.md3; + refType = 4; + sourceTree = ""; + }; + 1865074606253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree10.md3; + refType = 4; + sourceTree = ""; + }; + 1865074706253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree2.md3; + refType = 4; + sourceTree = ""; + }; + 1865074806253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree3.md3; + refType = 4; + sourceTree = ""; + }; + 1865074906253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree4.md3; + refType = 4; + sourceTree = ""; + }; + 1865074A06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree5.md3; + refType = 4; + sourceTree = ""; + }; + 1865074B06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree6.md3; + refType = 4; + sourceTree = ""; + }; + 1865074C06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree7.md3; + refType = 4; + sourceTree = ""; + }; + 1865074D06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree8.md3; + refType = 4; + sourceTree = ""; + }; + 1865074E06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = tree9.md3; + refType = 4; + sourceTree = ""; + }; + 1865074F06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = trunk2.tga; + refType = 4; + sourceTree = ""; + }; + 1865075006253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = visor_posed.md3; + refType = 4; + sourceTree = ""; + }; + 1865075106253BCA005AB5DA = { + children = ( + 1865075206253BCA005AB5DA, + 1865076D06253BCA005AB5DA, + 1865076E06253BCA005AB5DA, + 1865076F06253BCA005AB5DA, + ); + isa = PBXGroup; + path = wallhead; + refType = 4; + sourceTree = ""; + }; + 1865075206253BCA005AB5DA = { + children = ( + 1865075306253BCA005AB5DA, + 1865075406253BCA005AB5DA, + 1865075506253BCA005AB5DA, + 1865075606253BCA005AB5DA, + 1865075706253BCA005AB5DA, + 1865075B06253BCA005AB5DA, + 1865075F06253BCA005AB5DA, + 1865076006253BCA005AB5DA, + 1865076406253BCA005AB5DA, + 1865076906253BCA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865075306253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865075406253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865075506253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865075606253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865075706253BCA005AB5DA = { + children = ( + 1865075806253BCA005AB5DA, + 1865075906253BCA005AB5DA, + 1865075A06253BCA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865075806253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "femhead.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865075906253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lion.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865075A06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wallhead02.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865075B06253BCA005AB5DA = { + children = ( + 1865075C06253BCA005AB5DA, + 1865075D06253BCA005AB5DA, + 1865075E06253BCA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865075C06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "femhead.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865075D06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lion.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865075E06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wallhead02.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865075F06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865076006253BCA005AB5DA = { + children = ( + 1865076106253BCA005AB5DA, + 1865076206253BCA005AB5DA, + 1865076306253BCA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865076106253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "femhead.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865076206253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "lion.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865076306253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "wallhead02.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865076406253BCA005AB5DA = { + children = ( + 1865076506253BCA005AB5DA, + 1865076606253BCA005AB5DA, + 1865076706253BCA005AB5DA, + 1865076806253BCA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865076506253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865076606253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865076706253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865076806253BCA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865076906253BCA005AB5DA = { + children = ( + 1865076A06253BCA005AB5DA, + 1865076B06253BCA005AB5DA, + 1865076C06253BCA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865076A06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "femhead.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865076B06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lion.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865076C06253BCA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wallhead02.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865076D06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = femhead.md3; + refType = 4; + sourceTree = ""; + }; + 1865076E06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = lion.md3; + refType = 4; + sourceTree = ""; + }; + 1865076F06253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = wallhead02.md3; + refType = 4; + sourceTree = ""; + }; + 1865077006253BCA005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = walllamp3.md3; + refType = 4; + sourceTree = ""; + }; + 1865077106253BCB005AB5DA = { + children = ( + 1865077206253BCB005AB5DA, + 186507FD06253BCC005AB5DA, + 186507FE06253BCC005AB5DA, + 186507FF06253BCC005AB5DA, + 1865080006253BCC005AB5DA, + 1865080106253BCC005AB5DA, + 1865080206253BCC005AB5DA, + 1865080306253BCC005AB5DA, + 1865080406253BCC005AB5DA, + 1865080506253BCC005AB5DA, + 1865080606253BCC005AB5DA, + 1865080706253BCC005AB5DA, + 1865080806253BCC005AB5DA, + 1865080906253BCC005AB5DA, + 1865080A06253BCC005AB5DA, + 1865080B06253BCC005AB5DA, + 1865080C06253BCC005AB5DA, + 1865080D06253BCC005AB5DA, + 1865080E06253BCC005AB5DA, + 1865080F06253BCC005AB5DA, + 1865081006253BCC005AB5DA, + 1865081106253BCC005AB5DA, + 1865081206253BCC005AB5DA, + 1865081306253BCC005AB5DA, + 1865081406253BCC005AB5DA, + 1865081506253BCC005AB5DA, + 1865081606253BCC005AB5DA, + 1865081706253BCC005AB5DA, + 1865081806253BCC005AB5DA, + 1865081906253BCC005AB5DA, + 1865081A06253BCC005AB5DA, + 1865081B06253BCC005AB5DA, + ); + isa = PBXGroup; + path = scripts; + refType = 4; + sourceTree = ""; + }; + 1865077206253BCB005AB5DA = { + children = ( + 1865077306253BCB005AB5DA, + 1865077406253BCB005AB5DA, + 1865077506253BCB005AB5DA, + 1865077606253BCB005AB5DA, + 1865077706253BCB005AB5DA, + 1865079706253BCB005AB5DA, + 186507B706253BCB005AB5DA, + 186507B806253BCB005AB5DA, + 186507D806253BCC005AB5DA, + 186507DD06253BCC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865077306253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865077406253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865077506253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865077606253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865077706253BCB005AB5DA = { + children = ( + 1865077806253BCB005AB5DA, + 1865077906253BCB005AB5DA, + 1865077A06253BCB005AB5DA, + 1865077B06253BCB005AB5DA, + 1865077C06253BCB005AB5DA, + 1865077D06253BCB005AB5DA, + 1865077E06253BCB005AB5DA, + 1865077F06253BCB005AB5DA, + 1865078006253BCB005AB5DA, + 1865078106253BCB005AB5DA, + 1865078206253BCB005AB5DA, + 1865078306253BCB005AB5DA, + 1865078406253BCB005AB5DA, + 1865078506253BCB005AB5DA, + 1865078606253BCB005AB5DA, + 1865078706253BCB005AB5DA, + 1865078806253BCB005AB5DA, + 1865078906253BCB005AB5DA, + 1865078A06253BCB005AB5DA, + 1865078B06253BCB005AB5DA, + 1865078C06253BCB005AB5DA, + 1865078D06253BCB005AB5DA, + 1865078E06253BCB005AB5DA, + 1865078F06253BCB005AB5DA, + 1865079006253BCB005AB5DA, + 1865079106253BCB005AB5DA, + 1865079206253BCB005AB5DA, + 1865079306253BCB005AB5DA, + 1865079406253BCB005AB5DA, + 1865079506253BCB005AB5DA, + 1865079606253BCB005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865077806253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_button.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077906253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_door.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077A06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077B06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077C06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_object.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077D06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_support.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077E06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_trim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865077F06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078006253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078106253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078206253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "default_project.proj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078306253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078406253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gfx.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078506253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_block.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078606253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_button.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078706253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_door.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078806253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_floor.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078906253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_light.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078A06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078B06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078C06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hell.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078D06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078E06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865078F06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079006253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "organics.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079106253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079206253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079306253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079406253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skin.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079506253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079606253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865079706253BCB005AB5DA = { + children = ( + 1865079806253BCB005AB5DA, + 1865079906253BCB005AB5DA, + 1865079A06253BCB005AB5DA, + 1865079B06253BCB005AB5DA, + 1865079C06253BCB005AB5DA, + 1865079D06253BCB005AB5DA, + 1865079E06253BCB005AB5DA, + 1865079F06253BCB005AB5DA, + 186507A006253BCB005AB5DA, + 186507A106253BCB005AB5DA, + 186507A206253BCB005AB5DA, + 186507A306253BCB005AB5DA, + 186507A406253BCB005AB5DA, + 186507A506253BCB005AB5DA, + 186507A606253BCB005AB5DA, + 186507A706253BCB005AB5DA, + 186507A806253BCB005AB5DA, + 186507A906253BCB005AB5DA, + 186507AA06253BCB005AB5DA, + 186507AB06253BCB005AB5DA, + 186507AC06253BCB005AB5DA, + 186507AD06253BCB005AB5DA, + 186507AE06253BCB005AB5DA, + 186507AF06253BCB005AB5DA, + 186507B006253BCB005AB5DA, + 186507B106253BCB005AB5DA, + 186507B206253BCB005AB5DA, + 186507B306253BCB005AB5DA, + 186507B406253BCB005AB5DA, + 186507B506253BCB005AB5DA, + 186507B606253BCB005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865079806253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_button.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079906253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_door.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079A06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079B06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079C06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_object.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079D06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_support.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079E06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_trim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865079F06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A006253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A106253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A206253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "default_project.proj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A306253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A406253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gfx.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A506253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_block.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A606253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_button.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A706253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_door.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A806253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_floor.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507A906253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_light.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507AA06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507AB06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507AC06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hell.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507AD06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507AE06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507AF06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B006253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "organics.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B106253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B206253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B306253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B406253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skin.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B506253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B606253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507B706253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186507B806253BCB005AB5DA = { + children = ( + 186507B906253BCB005AB5DA, + 186507BA06253BCB005AB5DA, + 186507BB06253BCB005AB5DA, + 186507BC06253BCB005AB5DA, + 186507BD06253BCB005AB5DA, + 186507BE06253BCB005AB5DA, + 186507BF06253BCB005AB5DA, + 186507C006253BCB005AB5DA, + 186507C106253BCB005AB5DA, + 186507C206253BCB005AB5DA, + 186507C306253BCC005AB5DA, + 186507C406253BCC005AB5DA, + 186507C506253BCC005AB5DA, + 186507C606253BCC005AB5DA, + 186507C706253BCC005AB5DA, + 186507C806253BCC005AB5DA, + 186507C906253BCC005AB5DA, + 186507CA06253BCC005AB5DA, + 186507CB06253BCC005AB5DA, + 186507CC06253BCC005AB5DA, + 186507CD06253BCC005AB5DA, + 186507CE06253BCC005AB5DA, + 186507CF06253BCC005AB5DA, + 186507D006253BCC005AB5DA, + 186507D106253BCC005AB5DA, + 186507D206253BCC005AB5DA, + 186507D306253BCC005AB5DA, + 186507D406253BCC005AB5DA, + 186507D506253BCC005AB5DA, + 186507D606253BCC005AB5DA, + 186507D706253BCC005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186507B906253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_button.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507BA06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_door.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507BB06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507BC06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507BD06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_object.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507BE06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_support.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507BF06253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_trim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C006253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C106253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C206253BCB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "default_project.proj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gfx.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_block.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C706253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_button.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C806253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_door.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507C906253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_floor.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507CA06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_light.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507CB06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507CC06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507CD06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hell.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507CE06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507CF06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "organics.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D206253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skin.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D706253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186507D806253BCC005AB5DA = { + children = ( + 186507D906253BCC005AB5DA, + 186507DA06253BCC005AB5DA, + 186507DB06253BCC005AB5DA, + 186507DC06253BCC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186507D906253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186507DA06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186507DB06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186507DC06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186507DD06253BCC005AB5DA = { + children = ( + 186507DE06253BCC005AB5DA, + 186507DF06253BCC005AB5DA, + 186507E006253BCC005AB5DA, + 186507E106253BCC005AB5DA, + 186507E206253BCC005AB5DA, + 186507E306253BCC005AB5DA, + 186507E406253BCC005AB5DA, + 186507E506253BCC005AB5DA, + 186507E606253BCC005AB5DA, + 186507E706253BCC005AB5DA, + 186507E806253BCC005AB5DA, + 186507E906253BCC005AB5DA, + 186507EA06253BCC005AB5DA, + 186507EB06253BCC005AB5DA, + 186507EC06253BCC005AB5DA, + 186507ED06253BCC005AB5DA, + 186507EE06253BCC005AB5DA, + 186507EF06253BCC005AB5DA, + 186507F006253BCC005AB5DA, + 186507F106253BCC005AB5DA, + 186507F206253BCC005AB5DA, + 186507F306253BCC005AB5DA, + 186507F406253BCC005AB5DA, + 186507F506253BCC005AB5DA, + 186507F606253BCC005AB5DA, + 186507F706253BCC005AB5DA, + 186507F806253BCC005AB5DA, + 186507F906253BCC005AB5DA, + 186507FA06253BCC005AB5DA, + 186507FB06253BCC005AB5DA, + 186507FC06253BCC005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186507DE06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_button.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507DF06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_door.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E206253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_object.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_support.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_trim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E706253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E806253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "default_project.proj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507E906253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507EA06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gfx.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507EB06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_block.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507EC06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_button.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507ED06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_door.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507EE06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_floor.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507EF06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_light.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F206253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hell.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "organics.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F706253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F806253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507F906253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507FA06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skin.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507FB06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademoQ3.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507FC06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186507FD06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_button.shader; + refType = 4; + sourceTree = ""; + }; + 186507FE06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_door.shader; + refType = 4; + sourceTree = ""; + }; + 186507FF06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_floor.shader; + refType = 4; + sourceTree = ""; + }; + 1865080006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_light.shader; + refType = 4; + sourceTree = ""; + }; + 1865080106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_object.shader; + refType = 4; + sourceTree = ""; + }; + 1865080206253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_support.shader; + refType = 4; + sourceTree = ""; + }; + 1865080306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_trim.shader; + refType = 4; + sourceTree = ""; + }; + 1865080406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_wall.shader; + refType = 4; + sourceTree = ""; + }; + 1865080506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = common.shader; + refType = 4; + sourceTree = ""; + }; + 1865080606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ctf.shader; + refType = 4; + sourceTree = ""; + }; + 1865080706253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = default_project.proj; + refType = 4; + sourceTree = ""; + }; + 1865080806253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = entities.def; + refType = 4; + sourceTree = ""; + }; + 1865080906253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gfx.shader; + refType = 4; + sourceTree = ""; + }; + 1865080A06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_block.shader; + refType = 4; + sourceTree = ""; + }; + 1865080B06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_button.shader; + refType = 4; + sourceTree = ""; + }; + 1865080C06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_door.shader; + refType = 4; + sourceTree = ""; + }; + 1865080D06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_floor.shader; + refType = 4; + sourceTree = ""; + }; + 1865080E06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_light.shader; + refType = 4; + sourceTree = ""; + }; + 1865080F06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_trim.shader; + refType = 4; + sourceTree = ""; + }; + 1865081006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_wall.shader; + refType = 4; + sourceTree = ""; + }; + 1865081106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = hell.shader; + refType = 4; + sourceTree = ""; + }; + 1865081206253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = liquids.shader; + refType = 4; + sourceTree = ""; + }; + 1865081306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = models.shader; + refType = 4; + sourceTree = ""; + }; + 1865081406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = museum.shader; + refType = 4; + sourceTree = ""; + }; + 1865081506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = organics.shader; + refType = 4; + sourceTree = ""; + }; + 1865081606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = sfx.shader; + refType = 4; + sourceTree = ""; + }; + 1865081706253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shaderlist.txt; + refType = 4; + sourceTree = ""; + }; + 1865081806253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = skies.shader; + refType = 4; + sourceTree = ""; + }; + 1865081906253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = skin.shader; + refType = 4; + sourceTree = ""; + }; + 1865081A06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = terrademoQ3.shader; + refType = 4; + sourceTree = ""; + }; + 1865081B06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = test.shader; + refType = 4; + sourceTree = ""; + }; + 1865081C06253BCC005AB5DA = { + children = ( + 1865081D06253BCC005AB5DA, + 1865082C06253BCC005AB5DA, + 1865084106253BCC005AB5DA, + 1865085606253BCD005AB5DA, + ); + isa = PBXGroup; + path = textures; + refType = 4; + sourceTree = ""; + }; + 1865081D06253BCC005AB5DA = { + children = ( + 1865081E06253BCC005AB5DA, + 1865081F06253BCC005AB5DA, + 1865082006253BCC005AB5DA, + 1865082106253BCC005AB5DA, + 1865082206253BCC005AB5DA, + 1865082306253BCC005AB5DA, + 1865082406253BCC005AB5DA, + 1865082506253BCC005AB5DA, + 1865082606253BCC005AB5DA, + 1865082B06253BCC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865081E06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865081F06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865082006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865082106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865082206253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865082306253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865082406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865082506253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865082606253BCC005AB5DA = { + children = ( + 1865082706253BCC005AB5DA, + 1865082806253BCC005AB5DA, + 1865082906253BCC005AB5DA, + 1865082A06253BCC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865082706253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865082806253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865082906253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865082A06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865082B06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865082C06253BCC005AB5DA = { + children = ( + 1865082D06253BCC005AB5DA, + 1865084006253BCC005AB5DA, + ); + isa = PBXGroup; + path = proto2; + refType = 4; + sourceTree = ""; + }; + 1865082D06253BCC005AB5DA = { + children = ( + 1865082E06253BCC005AB5DA, + 1865082F06253BCC005AB5DA, + 1865083006253BCC005AB5DA, + 1865083106253BCC005AB5DA, + 1865083206253BCC005AB5DA, + 1865083406253BCC005AB5DA, + 1865083606253BCC005AB5DA, + 1865083706253BCC005AB5DA, + 1865083906253BCC005AB5DA, + 1865083E06253BCC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865082E06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865082F06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865083006253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865083106253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865083206253BCC005AB5DA = { + children = ( + 1865083306253BCC005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865083306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pj_terralpha01.pcx.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865083406253BCC005AB5DA = { + children = ( + 1865083506253BCC005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865083506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pj_terralpha01.pcx.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865083606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865083706253BCC005AB5DA = { + children = ( + 1865083806253BCC005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865083806253BCC005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "pj_terralpha01.pcx.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865083906253BCC005AB5DA = { + children = ( + 1865083A06253BCC005AB5DA, + 1865083B06253BCC005AB5DA, + 1865083C06253BCC005AB5DA, + 1865083D06253BCC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865083A06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865083B06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865083C06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865083D06253BCC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865083E06253BCC005AB5DA = { + children = ( + 1865083F06253BCC005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865083F06253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pj_terralpha01.pcx.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865084006253BCC005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pj_terralpha01.pcx; + refType = 4; + sourceTree = ""; + }; + 1865084106253BCC005AB5DA = { + children = ( + 1865084206253BCC005AB5DA, + 1865085506253BCD005AB5DA, + ); + isa = PBXGroup; + path = skies2; + refType = 4; + sourceTree = ""; + }; + 1865084206253BCC005AB5DA = { + children = ( + 1865084306253BCC005AB5DA, + 1865084406253BCC005AB5DA, + 1865084506253BCC005AB5DA, + 1865084606253BCC005AB5DA, + 1865084706253BCC005AB5DA, + 1865084906253BCD005AB5DA, + 1865084B06253BCD005AB5DA, + 1865084C06253BCD005AB5DA, + 1865084E06253BCD005AB5DA, + 1865085306253BCD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865084306253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865084406253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865084506253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865084606253BCC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865084706253BCC005AB5DA = { + children = ( + 1865084806253BCD005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865084806253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clouds.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865084906253BCD005AB5DA = { + children = ( + 1865084A06253BCD005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865084A06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clouds.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865084B06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865084C06253BCD005AB5DA = { + children = ( + 1865084D06253BCD005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865084D06253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "clouds.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865084E06253BCD005AB5DA = { + children = ( + 1865084F06253BCD005AB5DA, + 1865085006253BCD005AB5DA, + 1865085106253BCD005AB5DA, + 1865085206253BCD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865084F06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865085006253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865085106253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865085206253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865085306253BCD005AB5DA = { + children = ( + 1865085406253BCD005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865085406253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clouds.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865085506253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = clouds.tga; + refType = 4; + sourceTree = ""; + }; + 1865085606253BCD005AB5DA = { + children = ( + 1865085706253BCD005AB5DA, + 1865087206253BCD005AB5DA, + 1865087306253BCD005AB5DA, + 1865087406253BCD005AB5DA, + ); + isa = PBXGroup; + path = stone; + refType = 4; + sourceTree = ""; + }; + 1865085706253BCD005AB5DA = { + children = ( + 1865085806253BCD005AB5DA, + 1865085906253BCD005AB5DA, + 1865085A06253BCD005AB5DA, + 1865085B06253BCD005AB5DA, + 1865085C06253BCD005AB5DA, + 1865086006253BCD005AB5DA, + 1865086406253BCD005AB5DA, + 1865086506253BCD005AB5DA, + 1865086906253BCD005AB5DA, + 1865086E06253BCD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865085806253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865085906253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865085A06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865085B06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865085C06253BCD005AB5DA = { + children = ( + 1865085D06253BCD005AB5DA, + 1865085E06253BCD005AB5DA, + 1865085F06253BCD005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865085D06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock10b_2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865085E06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock12b_2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865085F06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock9b_2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865086006253BCD005AB5DA = { + children = ( + 1865086106253BCD005AB5DA, + 1865086206253BCD005AB5DA, + 1865086306253BCD005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865086106253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock10b_2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865086206253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock12b_2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865086306253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock9b_2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865086406253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865086506253BCD005AB5DA = { + children = ( + 1865086606253BCD005AB5DA, + 1865086706253BCD005AB5DA, + 1865086806253BCD005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865086606253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "pjrock10b_2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865086706253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "pjrock12b_2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865086806253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "pjrock9b_2.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865086906253BCD005AB5DA = { + children = ( + 1865086A06253BCD005AB5DA, + 1865086B06253BCD005AB5DA, + 1865086C06253BCD005AB5DA, + 1865086D06253BCD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865086A06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865086B06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865086C06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865086D06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865086E06253BCD005AB5DA = { + children = ( + 1865086F06253BCD005AB5DA, + 1865087006253BCD005AB5DA, + 1865087106253BCD005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865086F06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock10b_2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865087006253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock12b_2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865087106253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pjrock9b_2.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865087206253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pjrock10b_2.tga; + refType = 4; + sourceTree = ""; + }; + 1865087306253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pjrock12b_2.tga; + refType = 4; + sourceTree = ""; + }; + 1865087406253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pjrock9b_2.tga; + refType = 4; + sourceTree = ""; + }; + 1865087506253BCD005AB5DA = { + children = ( + 1865087606253BCD005AB5DA, + 1865088D06253BCD005AB5DA, + 1865088E06253BCD005AB5DA, + 186508DB06253BCE005AB5DA, + 1865091506253BCF005AB5DA, + 1865099D06253BD0005AB5DA, + 1865099E06253BD0005AB5DA, + ); + isa = PBXGroup; + path = missionpack; + refType = 4; + sourceTree = ""; + }; + 1865087606253BCD005AB5DA = { + children = ( + 1865087706253BCD005AB5DA, + 1865087806253BCD005AB5DA, + 1865087906253BCD005AB5DA, + 1865087A06253BCD005AB5DA, + 1865087B06253BCD005AB5DA, + 1865087E06253BCD005AB5DA, + 1865088106253BCD005AB5DA, + 1865088206253BCD005AB5DA, + 1865088506253BCD005AB5DA, + 1865088A06253BCD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865087706253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865087806253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865087906253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865087A06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865087B06253BCD005AB5DA = { + children = ( + 1865087C06253BCD005AB5DA, + 1865087D06253BCD005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865087C06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapmedia-TA.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865087D06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo-README.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865087E06253BCD005AB5DA = { + children = ( + 1865087F06253BCD005AB5DA, + 1865088006253BCD005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865087F06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapmedia-TA.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865088006253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo-README.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865088106253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865088206253BCD005AB5DA = { + children = ( + 1865088306253BCD005AB5DA, + 1865088406253BCD005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865088306253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "mapmedia-TA.pk3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865088406253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo-README.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865088506253BCD005AB5DA = { + children = ( + 1865088606253BCD005AB5DA, + 1865088706253BCD005AB5DA, + 1865088806253BCD005AB5DA, + 1865088906253BCD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865088606253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865088706253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865088806253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865088906253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865088A06253BCD005AB5DA = { + children = ( + 1865088B06253BCD005AB5DA, + 1865088C06253BCD005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865088B06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapmedia-TA.pk3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865088C06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo-README.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865088D06253BCD005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "mapmedia-TA.pk3"; + refType = 4; + sourceTree = ""; + }; + 1865088E06253BCD005AB5DA = { + children = ( + 1865088F06253BCD005AB5DA, + 186508A206253BCD005AB5DA, + 186508DA06253BCE005AB5DA, + ); + isa = PBXGroup; + path = maps; + refType = 4; + sourceTree = ""; + }; + 1865088F06253BCD005AB5DA = { + children = ( + 1865089006253BCD005AB5DA, + 1865089106253BCD005AB5DA, + 1865089206253BCD005AB5DA, + 1865089306253BCD005AB5DA, + 1865089406253BCD005AB5DA, + 1865089606253BCD005AB5DA, + 1865089806253BCD005AB5DA, + 1865089906253BCD005AB5DA, + 1865089B06253BCD005AB5DA, + 186508A006253BCD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865089006253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865089106253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865089206253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865089306253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865089406253BCD005AB5DA = { + children = ( + 1865089506253BCD005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865089506253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865089606253BCD005AB5DA = { + children = ( + 1865089706253BCD005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865089706253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865089806253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865089906253BCD005AB5DA = { + children = ( + 1865089A06253BCD005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865089A06253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865089B06253BCD005AB5DA = { + children = ( + 1865089C06253BCD005AB5DA, + 1865089D06253BCD005AB5DA, + 1865089E06253BCD005AB5DA, + 1865089F06253BCD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865089C06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865089D06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865089E06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865089F06253BCD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508A006253BCD005AB5DA = { + children = ( + 186508A106253BCD005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508A106253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508A206253BCD005AB5DA = { + children = ( + 186508A306253BCD005AB5DA, + 186508D206253BCE005AB5DA, + 186508D306253BCE005AB5DA, + 186508D406253BCE005AB5DA, + 186508D506253BCE005AB5DA, + 186508D606253BCE005AB5DA, + 186508D706253BCE005AB5DA, + 186508D806253BCE005AB5DA, + 186508D906253BCE005AB5DA, + ); + isa = PBXGroup; + path = "Team Arena Prefabs"; + refType = 4; + sourceTree = ""; + }; + 186508A306253BCD005AB5DA = { + children = ( + 186508A406253BCD005AB5DA, + 186508A506253BCD005AB5DA, + 186508A606253BCD005AB5DA, + 186508A706253BCD005AB5DA, + 186508A806253BCD005AB5DA, + 186508B106253BCE005AB5DA, + 186508BA06253BCE005AB5DA, + 186508BB06253BCE005AB5DA, + 186508C406253BCE005AB5DA, + 186508C906253BCE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186508A406253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186508A506253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186508A606253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186508A706253BCD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186508A806253BCD005AB5DA = { + children = ( + 186508A906253BCE005AB5DA, + 186508AA06253BCE005AB5DA, + 186508AB06253BCE005AB5DA, + 186508AC06253BCE005AB5DA, + 186508AD06253BCE005AB5DA, + 186508AE06253BCE005AB5DA, + 186508AF06253BCE005AB5DA, + 186508B006253BCE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186508A906253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_blue.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508AA06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_neutral.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508AB06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_red.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508AC06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_blue.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508AD06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_red.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508AE06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_blue.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508AF06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_neutral.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508B006253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_red.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508B106253BCE005AB5DA = { + children = ( + 186508B206253BCE005AB5DA, + 186508B306253BCE005AB5DA, + 186508B406253BCE005AB5DA, + 186508B506253BCE005AB5DA, + 186508B606253BCE005AB5DA, + 186508B706253BCE005AB5DA, + 186508B806253BCE005AB5DA, + 186508B906253BCE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186508B206253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_blue.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B306253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_neutral.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B406253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_red.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B506253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_blue.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B606253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_red.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B706253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_blue.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B806253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_neutral.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508B906253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_red.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508BA06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186508BB06253BCE005AB5DA = { + children = ( + 186508BC06253BCE005AB5DA, + 186508BD06253BCE005AB5DA, + 186508BE06253BCE005AB5DA, + 186508BF06253BCE005AB5DA, + 186508C006253BCE005AB5DA, + 186508C106253BCE005AB5DA, + 186508C206253BCE005AB5DA, + 186508C306253BCE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186508BC06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_blue.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508BD06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_neutral.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508BE06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_red.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508BF06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_blue.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508C006253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_red.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508C106253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_blue.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508C206253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_neutral.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508C306253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_red.pfb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186508C406253BCE005AB5DA = { + children = ( + 186508C506253BCE005AB5DA, + 186508C606253BCE005AB5DA, + 186508C706253BCE005AB5DA, + 186508C806253BCE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186508C506253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186508C606253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186508C706253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186508C806253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508C906253BCE005AB5DA = { + children = ( + 186508CA06253BCE005AB5DA, + 186508CB06253BCE005AB5DA, + 186508CC06253BCE005AB5DA, + 186508CD06253BCE005AB5DA, + 186508CE06253BCE005AB5DA, + 186508CF06253BCE005AB5DA, + 186508D006253BCE005AB5DA, + 186508D106253BCE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508CA06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_blue.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508CB06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_neutral.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508CC06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "armorpad_red.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508CD06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_blue.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508CE06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA_banner_red.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508CF06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_blue.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508D006253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_neutral.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508D106253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "weaponpad_red.pfb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186508D206253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = armorpad_blue.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D306253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = armorpad_neutral.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D406253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = armorpad_red.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D506253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TA_banner_blue.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D606253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TA_banner_red.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D706253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = weaponpad_blue.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D806253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = weaponpad_neutral.pfb; + refType = 4; + sourceTree = ""; + }; + 186508D906253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = weaponpad_red.pfb; + refType = 4; + sourceTree = ""; + }; + 186508DA06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = terrademo.map; + refType = 4; + sourceTree = ""; + }; + 186508DB06253BCE005AB5DA = { + children = ( + 186508DC06253BCE005AB5DA, + 186508EB06253BCE005AB5DA, + ); + isa = PBXGroup; + path = models; + refType = 4; + sourceTree = ""; + }; + 186508DC06253BCE005AB5DA = { + children = ( + 186508DD06253BCE005AB5DA, + 186508DE06253BCE005AB5DA, + 186508DF06253BCE005AB5DA, + 186508E006253BCE005AB5DA, + 186508E106253BCE005AB5DA, + 186508E206253BCE005AB5DA, + 186508E306253BCE005AB5DA, + 186508E406253BCE005AB5DA, + 186508E506253BCE005AB5DA, + 186508EA06253BCE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186508DD06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186508DE06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186508DF06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186508E006253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186508E106253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186508E206253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186508E306253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186508E406253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186508E506253BCE005AB5DA = { + children = ( + 186508E606253BCE005AB5DA, + 186508E706253BCE005AB5DA, + 186508E806253BCE005AB5DA, + 186508E906253BCE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186508E606253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186508E706253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186508E806253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186508E906253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508EA06253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508EB06253BCE005AB5DA = { + children = ( + 186508EC06253BCE005AB5DA, + 186508FB06253BCE005AB5DA, + ); + isa = PBXGroup; + path = mapobjects; + refType = 4; + sourceTree = ""; + }; + 186508EC06253BCE005AB5DA = { + children = ( + 186508ED06253BCE005AB5DA, + 186508EE06253BCE005AB5DA, + 186508EF06253BCE005AB5DA, + 186508F006253BCE005AB5DA, + 186508F106253BCE005AB5DA, + 186508F206253BCE005AB5DA, + 186508F306253BCE005AB5DA, + 186508F406253BCE005AB5DA, + 186508F506253BCE005AB5DA, + 186508FA06253BCE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186508ED06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186508EE06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186508EF06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186508F006253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186508F106253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186508F206253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186508F306253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186508F406253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186508F506253BCE005AB5DA = { + children = ( + 186508F606253BCE005AB5DA, + 186508F706253BCE005AB5DA, + 186508F806253BCE005AB5DA, + 186508F906253BCE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186508F606253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186508F706253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186508F806253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186508F906253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508FA06253BCE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186508FB06253BCE005AB5DA = { + children = ( + 186508FC06253BCE005AB5DA, + 1865091306253BCF005AB5DA, + 1865091406253BCF005AB5DA, + ); + isa = PBXGroup; + path = spawn; + refType = 4; + sourceTree = ""; + }; + 186508FC06253BCE005AB5DA = { + children = ( + 186508FD06253BCE005AB5DA, + 186508FE06253BCF005AB5DA, + 186508FF06253BCF005AB5DA, + 1865090006253BCF005AB5DA, + 1865090106253BCF005AB5DA, + 1865090406253BCF005AB5DA, + 1865090706253BCF005AB5DA, + 1865090806253BCF005AB5DA, + 1865090B06253BCF005AB5DA, + 1865091006253BCF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186508FD06253BCE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186508FE06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186508FF06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865090006253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865090106253BCF005AB5DA = { + children = ( + 1865090206253BCF005AB5DA, + 1865090306253BCF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865090206253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spawn.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865090306253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spawn_r.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865090406253BCF005AB5DA = { + children = ( + 1865090506253BCF005AB5DA, + 1865090606253BCF005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865090506253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spawn.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865090606253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spawn_r.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865090706253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865090806253BCF005AB5DA = { + children = ( + 1865090906253BCF005AB5DA, + 1865090A06253BCF005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865090906253BCF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "spawn.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865090A06253BCF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "spawn_r.md3.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865090B06253BCF005AB5DA = { + children = ( + 1865090C06253BCF005AB5DA, + 1865090D06253BCF005AB5DA, + 1865090E06253BCF005AB5DA, + 1865090F06253BCF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865090C06253BCF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865090D06253BCF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865090E06253BCF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865090F06253BCF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865091006253BCF005AB5DA = { + children = ( + 1865091106253BCF005AB5DA, + 1865091206253BCF005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865091106253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spawn.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865091206253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spawn_r.md3.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865091306253BCF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = spawn.md3; + refType = 4; + sourceTree = ""; + }; + 1865091406253BCF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = spawn_r.md3; + refType = 4; + sourceTree = ""; + }; + 1865091506253BCF005AB5DA = { + children = ( + 1865091606253BCF005AB5DA, + 1865098506253BD0005AB5DA, + 1865098606253BD0005AB5DA, + 1865098706253BD0005AB5DA, + 1865098806253BD0005AB5DA, + 1865098906253BD0005AB5DA, + 1865098A06253BD0005AB5DA, + 1865098B06253BD0005AB5DA, + 1865098C06253BD0005AB5DA, + 1865098D06253BD0005AB5DA, + 1865098E06253BD0005AB5DA, + 1865098F06253BD0005AB5DA, + 1865099006253BD0005AB5DA, + 1865099106253BD0005AB5DA, + 1865099206253BD0005AB5DA, + 1865099306253BD0005AB5DA, + 1865099406253BD0005AB5DA, + 1865099506253BD0005AB5DA, + 1865099606253BD0005AB5DA, + 1865099706253BD0005AB5DA, + 1865099806253BD0005AB5DA, + 1865099906253BD0005AB5DA, + 1865099A06253BD0005AB5DA, + 1865099B06253BD0005AB5DA, + 1865099C06253BD0005AB5DA, + ); + isa = PBXGroup; + path = scripts; + refType = 4; + sourceTree = ""; + }; + 1865091606253BCF005AB5DA = { + children = ( + 1865091706253BCF005AB5DA, + 1865091806253BCF005AB5DA, + 1865091906253BCF005AB5DA, + 1865091A06253BCF005AB5DA, + 1865091B06253BCF005AB5DA, + 1865093406253BCF005AB5DA, + 1865094D06253BD0005AB5DA, + 1865094E06253BD0005AB5DA, + 1865096706253BD0005AB5DA, + 1865096C06253BD0005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865091706253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865091806253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865091906253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865091A06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865091B06253BCF005AB5DA = { + children = ( + 1865091C06253BCF005AB5DA, + 1865091D06253BCF005AB5DA, + 1865091E06253BCF005AB5DA, + 1865091F06253BCF005AB5DA, + 1865092006253BCF005AB5DA, + 1865092106253BCF005AB5DA, + 1865092206253BCF005AB5DA, + 1865092306253BCF005AB5DA, + 1865092406253BCF005AB5DA, + 1865092506253BCF005AB5DA, + 1865092606253BCF005AB5DA, + 1865092706253BCF005AB5DA, + 1865092806253BCF005AB5DA, + 1865092906253BCF005AB5DA, + 1865092A06253BCF005AB5DA, + 1865092B06253BCF005AB5DA, + 1865092C06253BCF005AB5DA, + 1865092D06253BCF005AB5DA, + 1865092E06253BCF005AB5DA, + 1865092F06253BCF005AB5DA, + 1865093006253BCF005AB5DA, + 1865093106253BCF005AB5DA, + 1865093206253BCF005AB5DA, + 1865093306253BCF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865091C06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865091D06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865091E06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865091F06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092006253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092106253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092206253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092306253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092406253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities-ta.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092506253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092606253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092706253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092806253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092906253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092A06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "proto2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092B06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092C06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092D06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092E06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865092F06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865093006253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stone2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865093106253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865093206253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865093306253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865093406253BCF005AB5DA = { + children = ( + 1865093506253BCF005AB5DA, + 1865093606253BCF005AB5DA, + 1865093706253BCF005AB5DA, + 1865093806253BCF005AB5DA, + 1865093906253BCF005AB5DA, + 1865093A06253BCF005AB5DA, + 1865093B06253BCF005AB5DA, + 1865093C06253BCF005AB5DA, + 1865093D06253BCF005AB5DA, + 1865093E06253BCF005AB5DA, + 1865093F06253BCF005AB5DA, + 1865094006253BCF005AB5DA, + 1865094106253BCF005AB5DA, + 1865094206253BCF005AB5DA, + 1865094306253BD0005AB5DA, + 1865094406253BD0005AB5DA, + 1865094506253BD0005AB5DA, + 1865094606253BD0005AB5DA, + 1865094706253BD0005AB5DA, + 1865094806253BD0005AB5DA, + 1865094906253BD0005AB5DA, + 1865094A06253BD0005AB5DA, + 1865094B06253BD0005AB5DA, + 1865094C06253BD0005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865093506253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093606253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093706253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093806253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093906253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093A06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093B06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093C06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093D06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities-ta.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093E06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865093F06253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094006253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094106253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094206253BCF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "proto2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094406253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094506253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094706253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094806253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094906253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stone2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094A06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094B06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094C06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865094D06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865094E06253BD0005AB5DA = { + children = ( + 1865094F06253BD0005AB5DA, + 1865095006253BD0005AB5DA, + 1865095106253BD0005AB5DA, + 1865095206253BD0005AB5DA, + 1865095306253BD0005AB5DA, + 1865095406253BD0005AB5DA, + 1865095506253BD0005AB5DA, + 1865095606253BD0005AB5DA, + 1865095706253BD0005AB5DA, + 1865095806253BD0005AB5DA, + 1865095906253BD0005AB5DA, + 1865095A06253BD0005AB5DA, + 1865095B06253BD0005AB5DA, + 1865095C06253BD0005AB5DA, + 1865095D06253BD0005AB5DA, + 1865095E06253BD0005AB5DA, + 1865095F06253BD0005AB5DA, + 1865096006253BD0005AB5DA, + 1865096106253BD0005AB5DA, + 1865096206253BD0005AB5DA, + 1865096306253BD0005AB5DA, + 1865096406253BD0005AB5DA, + 1865096506253BD0005AB5DA, + 1865096606253BD0005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865094F06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095006253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095106253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095206253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095406253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095506253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095706253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities-ta.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095806253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095906253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095A06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095B06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095C06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095D06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "proto2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095E06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865095F06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096006253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096106253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096206253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stone2.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096406253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096506253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tim.shader.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865096706253BD0005AB5DA = { + children = ( + 1865096806253BD0005AB5DA, + 1865096906253BD0005AB5DA, + 1865096A06253BD0005AB5DA, + 1865096B06253BD0005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865096806253BD0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865096906253BD0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865096A06253BD0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865096B06253BD0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865096C06253BD0005AB5DA = { + children = ( + 1865096D06253BD0005AB5DA, + 1865096E06253BD0005AB5DA, + 1865096F06253BD0005AB5DA, + 1865097006253BD0005AB5DA, + 1865097106253BD0005AB5DA, + 1865097206253BD0005AB5DA, + 1865097306253BD0005AB5DA, + 1865097406253BD0005AB5DA, + 1865097506253BD0005AB5DA, + 1865097606253BD0005AB5DA, + 1865097706253BD0005AB5DA, + 1865097806253BD0005AB5DA, + 1865097906253BD0005AB5DA, + 1865097A06253BD0005AB5DA, + 1865097B06253BD0005AB5DA, + 1865097C06253BD0005AB5DA, + 1865097D06253BD0005AB5DA, + 1865097E06253BD0005AB5DA, + 1865097F06253BD0005AB5DA, + 1865098006253BD0005AB5DA, + 1865098106253BD0005AB5DA, + 1865098206253BD0005AB5DA, + 1865098306253BD0005AB5DA, + 1865098406253BD0005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865096D06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865096E06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_floor2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865096F06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_light.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097006253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097106253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "base_wall2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097206253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "common.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097406253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097506253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities-ta.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_trim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097706253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gothic_wall.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097806253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097906253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "liquids2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097A06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "museum.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097B06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "proto2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097C06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097D06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sfx2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097E06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865097F06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865098006253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skies2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865098106253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stone2.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865098206253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865098306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865098406253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tim.shader.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865098506253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_floor.shader; + refType = 4; + sourceTree = ""; + }; + 1865098606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_floor2.shader; + refType = 4; + sourceTree = ""; + }; + 1865098706253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_light.shader; + refType = 4; + sourceTree = ""; + }; + 1865098806253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_wall.shader; + refType = 4; + sourceTree = ""; + }; + 1865098906253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = base_wall2.shader; + refType = 4; + sourceTree = ""; + }; + 1865098A06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = common.shader; + refType = 4; + sourceTree = ""; + }; + 1865098B06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ctf.shader; + refType = 4; + sourceTree = ""; + }; + 1865098C06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ctf2.shader; + refType = 4; + sourceTree = ""; + }; + 1865098D06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entities-ta.def"; + refType = 4; + sourceTree = ""; + }; + 1865098E06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_trim.shader; + refType = 4; + sourceTree = ""; + }; + 1865098F06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gothic_wall.shader; + refType = 4; + sourceTree = ""; + }; + 1865099006253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = liquids.shader; + refType = 4; + sourceTree = ""; + }; + 1865099106253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = liquids2.shader; + refType = 4; + sourceTree = ""; + }; + 1865099206253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = museum.shader; + refType = 4; + sourceTree = ""; + }; + 1865099306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = proto2.shader; + refType = 4; + sourceTree = ""; + }; + 1865099406253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = sfx.shader; + refType = 4; + sourceTree = ""; + }; + 1865099506253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = sfx2.shader; + refType = 4; + sourceTree = ""; + }; + 1865099606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shaderlist.txt; + refType = 4; + sourceTree = ""; + }; + 1865099706253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = skies.shader; + refType = 4; + sourceTree = ""; + }; + 1865099806253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = skies2.shader; + refType = 4; + sourceTree = ""; + }; + 1865099906253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = stone2.shader; + refType = 4; + sourceTree = ""; + }; + 1865099A06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = team.shader; + refType = 4; + sourceTree = ""; + }; + 1865099B06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = terrain.shader; + refType = 4; + sourceTree = ""; + }; + 1865099C06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = tim.shader; + refType = 4; + sourceTree = ""; + }; + 1865099D06253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrademo-README.txt"; + refType = 4; + sourceTree = ""; + }; + 1865099E06253BD0005AB5DA = { + children = ( + 1865099F06253BD0005AB5DA, + 186509AE06253BD1005AB5DA, + ); + isa = PBXGroup; + path = textures; + refType = 4; + sourceTree = ""; + }; + 1865099F06253BD0005AB5DA = { + children = ( + 186509A006253BD0005AB5DA, + 186509A106253BD0005AB5DA, + 186509A206253BD0005AB5DA, + 186509A306253BD0005AB5DA, + 186509A406253BD0005AB5DA, + 186509A506253BD0005AB5DA, + 186509A606253BD0005AB5DA, + 186509A706253BD1005AB5DA, + 186509A806253BD1005AB5DA, + 186509AD06253BD1005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186509A006253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186509A106253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186509A206253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186509A306253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186509A406253BD0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509A506253BD0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509A606253BD0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186509A706253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509A806253BD1005AB5DA = { + children = ( + 186509A906253BD1005AB5DA, + 186509AA06253BD1005AB5DA, + 186509AB06253BD1005AB5DA, + 186509AC06253BD1005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186509A906253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509AA06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509AB06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509AC06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186509AD06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186509AE06253BD1005AB5DA = { + children = ( + 186509AF06253BD1005AB5DA, + 186509C206253BD1005AB5DA, + ); + isa = PBXGroup; + path = base_wall2; + refType = 4; + sourceTree = ""; + }; + 186509AF06253BD1005AB5DA = { + children = ( + 186509B006253BD1005AB5DA, + 186509B106253BD1005AB5DA, + 186509B206253BD1005AB5DA, + 186509B306253BD1005AB5DA, + 186509B406253BD1005AB5DA, + 186509B606253BD1005AB5DA, + 186509B806253BD1005AB5DA, + 186509B906253BD1005AB5DA, + 186509BB06253BD1005AB5DA, + 186509C006253BD1005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186509B006253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186509B106253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186509B206253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186509B306253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186509B406253BD1005AB5DA = { + children = ( + 186509B506253BD1005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509B506253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "techfloor_kc_blue.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509B606253BD1005AB5DA = { + children = ( + 186509B706253BD1005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509B706253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "techfloor_kc_blue.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509B806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186509B906253BD1005AB5DA = { + children = ( + 186509BA06253BD1005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509BA06253BD1005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "techfloor_kc_blue.tga.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509BB06253BD1005AB5DA = { + children = ( + 186509BC06253BD1005AB5DA, + 186509BD06253BD1005AB5DA, + 186509BE06253BD1005AB5DA, + 186509BF06253BD1005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186509BC06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509BD06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509BE06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509BF06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186509C006253BD1005AB5DA = { + children = ( + 186509C106253BD1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186509C106253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "techfloor_kc_blue.tga.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509C206253BD1005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = techfloor_kc_blue.tga; + refType = 4; + sourceTree = ""; + }; + 186509C306253BD1005AB5DA = { + children = ( + 186509C406253BD1005AB5DA, + 186509EF06253BD1005AB5DA, + 186509F006253BD1005AB5DA, + 18650A0A06253BD1005AB5DA, + 18650A0B06253BD1005AB5DA, + 18650A0C06253BD1005AB5DA, + 18650A0D06253BD1005AB5DA, + 18650A0E06253BD1005AB5DA, + 18650A0F06253BD1005AB5DA, + ); + isa = PBXGroup; + path = tools; + refType = 4; + sourceTree = ""; + }; + 186509C406253BD1005AB5DA = { + children = ( + 186509C506253BD1005AB5DA, + 186509C606253BD1005AB5DA, + 186509C706253BD1005AB5DA, + 186509C806253BD1005AB5DA, + 186509C906253BD1005AB5DA, + 186509D106253BD1005AB5DA, + 186509D906253BD1005AB5DA, + 186509DA06253BD1005AB5DA, + 186509E206253BD1005AB5DA, + 186509E706253BD1005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186509C506253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186509C606253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186509C706253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186509C806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186509C906253BD1005AB5DA = { + children = ( + 186509CA06253BD1005AB5DA, + 186509CB06253BD1005AB5DA, + 186509CC06253BD1005AB5DA, + 186509CD06253BD1005AB5DA, + 186509CE06253BD1005AB5DA, + 186509CF06253BD1005AB5DA, + 186509D006253BD1005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509CA06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "credits.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509CB06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game.xlink.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509CC06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "global.xlink.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509CD06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "links.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509CE06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.qdt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509CF06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509D006253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.config.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509D106253BD1005AB5DA = { + children = ( + 186509D206253BD1005AB5DA, + 186509D306253BD1005AB5DA, + 186509D406253BD1005AB5DA, + 186509D506253BD1005AB5DA, + 186509D606253BD1005AB5DA, + 186509D706253BD1005AB5DA, + 186509D806253BD1005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509D206253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "credits.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D306253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game.xlink.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D406253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "global.xlink.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D506253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "links.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D606253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.qdt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D706253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.config.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509D906253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186509DA06253BD1005AB5DA = { + children = ( + 186509DB06253BD1005AB5DA, + 186509DC06253BD1005AB5DA, + 186509DD06253BD1005AB5DA, + 186509DE06253BD1005AB5DA, + 186509DF06253BD1005AB5DA, + 186509E006253BD1005AB5DA, + 186509E106253BD1005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509DB06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "credits.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509DC06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "game.xlink.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509DD06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "global.xlink.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509DE06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "links.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509DF06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.qdt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509E006253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509E106253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "synapse.config.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509E206253BD1005AB5DA = { + children = ( + 186509E306253BD1005AB5DA, + 186509E406253BD1005AB5DA, + 186509E506253BD1005AB5DA, + 186509E606253BD1005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186509E306253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509E406253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509E506253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509E606253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186509E706253BD1005AB5DA = { + children = ( + 186509E806253BD1005AB5DA, + 186509E906253BD1005AB5DA, + 186509EA06253BD1005AB5DA, + 186509EB06253BD1005AB5DA, + 186509EC06253BD1005AB5DA, + 186509ED06253BD1005AB5DA, + 186509EE06253BD1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186509E806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "credits.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509E906253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game.xlink.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509EA06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "global.xlink.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509EB06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "links.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509EC06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.qdt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509ED06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shortcuts.ini.sample.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509EE06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.config.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509EF06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = credits.html; + refType = 4; + sourceTree = ""; + }; + 186509F006253BD1005AB5DA = { + children = ( + 186509F106253BD1005AB5DA, + 18650A0806253BD1005AB5DA, + 18650A0906253BD1005AB5DA, + ); + isa = PBXGroup; + path = dtds; + refType = 4; + sourceTree = ""; + }; + 186509F106253BD1005AB5DA = { + children = ( + 186509F206253BD1005AB5DA, + 186509F306253BD1005AB5DA, + 186509F406253BD1005AB5DA, + 186509F506253BD1005AB5DA, + 186509F606253BD1005AB5DA, + 186509F906253BD1005AB5DA, + 186509FC06253BD1005AB5DA, + 186509FD06253BD1005AB5DA, + 18650A0006253BD1005AB5DA, + 18650A0506253BD1005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186509F206253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186509F306253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186509F406253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186509F506253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186509F606253BD1005AB5DA = { + children = ( + 186509F706253BD1005AB5DA, + 186509F806253BD1005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186509F706253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapq3.dtd.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509F806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "project.dtd.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509F906253BD1005AB5DA = { + children = ( + 186509FA06253BD1005AB5DA, + 186509FB06253BD1005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186509FA06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapq3.dtd.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509FB06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "project.dtd.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186509FC06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186509FD06253BD1005AB5DA = { + children = ( + 186509FE06253BD1005AB5DA, + 186509FF06253BD1005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186509FE06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapq3.dtd.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186509FF06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "project.dtd.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A0006253BD1005AB5DA = { + children = ( + 18650A0106253BD1005AB5DA, + 18650A0206253BD1005AB5DA, + 18650A0306253BD1005AB5DA, + 18650A0406253BD1005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650A0106253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A0206253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A0306253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A0406253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A0506253BD1005AB5DA = { + children = ( + 18650A0606253BD1005AB5DA, + 18650A0706253BD1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A0606253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapq3.dtd.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A0706253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "project.dtd.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A0806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = mapq3.dtd; + refType = 4; + sourceTree = ""; + }; + 18650A0906253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = project.dtd; + refType = 4; + sourceTree = ""; + }; + 18650A0A06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = game.xlink; + refType = 4; + sourceTree = ""; + }; + 18650A0B06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = global.xlink; + refType = 4; + sourceTree = ""; + }; + 18650A0C06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = links.htm; + refType = 4; + sourceTree = ""; + }; + 18650A0D06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3data.qdt; + refType = 4; + sourceTree = ""; + }; + 18650A0E06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shortcuts.ini.sample; + refType = 4; + sourceTree = ""; + }; + 18650A0F06253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = synapse.config; + refType = 4; + sourceTree = ""; + }; + 18650A1006253BD1005AB5DA = { + children = ( + 18650A1106253BD1005AB5DA, + ); + isa = PBXGroup; + path = deb; + refType = 4; + sourceTree = ""; + }; + 18650A1106253BD1005AB5DA = { + children = ( + 18650A1206253BD1005AB5DA, + 18650A1306253BD1005AB5DA, + 18650A1406253BD1005AB5DA, + 18650A1506253BD1005AB5DA, + 18650A1606253BD1005AB5DA, + 18650A1706253BD1005AB5DA, + 18650A1806253BD1005AB5DA, + 18650A1906253BD1005AB5DA, + 18650A1A06253BD1005AB5DA, + 18650A1F06253BD1005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650A1206253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650A1306253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650A1406253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650A1506253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650A1606253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A1706253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A1806253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650A1906253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A1A06253BD1005AB5DA = { + children = ( + 18650A1B06253BD1005AB5DA, + 18650A1C06253BD1005AB5DA, + 18650A1D06253BD1005AB5DA, + 18650A1E06253BD1005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650A1B06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A1C06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A1D06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A1E06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A1F06253BD1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A2006253BD1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = license.txt; + refType = 4; + sourceTree = ""; + }; + 18650A2106253BD1005AB5DA = { + children = ( + 18650A2206253BD2005AB5DA, + 18650A4D06253BD2005AB5DA, + 18650A4E06253BD2005AB5DA, + 18650A4F06253BD2005AB5DA, + 18650A6406253BD2005AB5DA, + 18650A9306253BD3005AB5DA, + 18650AC606253BD3005AB5DA, + 18650AC706253BD3005AB5DA, + 18650AC806253BD3005AB5DA, + 18650AC906253BD3005AB5DA, + 18650ACA06253BD3005AB5DA, + 18650B1D06253BD4005AB5DA, + 18650B6E06253BD5005AB5DA, + ); + isa = PBXGroup; + path = linux; + refType = 4; + sourceTree = ""; + }; + 18650A2206253BD2005AB5DA = { + children = ( + 18650A2306253BD2005AB5DA, + 18650A2406253BD2005AB5DA, + 18650A2506253BD2005AB5DA, + 18650A2606253BD2005AB5DA, + 18650A2706253BD2005AB5DA, + 18650A2F06253BD2005AB5DA, + 18650A3706253BD2005AB5DA, + 18650A3806253BD2005AB5DA, + 18650A4006253BD2005AB5DA, + 18650A4506253BD2005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650A2306253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650A2406253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650A2506253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650A2606253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650A2706253BD2005AB5DA = { + children = ( + 18650A2806253BD2005AB5DA, + 18650A2906253BD2005AB5DA, + 18650A2A06253BD2005AB5DA, + 18650A2B06253BD2005AB5DA, + 18650A2C06253BD2005AB5DA, + 18650A2D06253BD2005AB5DA, + 18650A2E06253BD2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2806253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2906253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2A06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2B06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2C06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2D06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2E06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A2F06253BD2005AB5DA = { + children = ( + 18650A3006253BD2005AB5DA, + 18650A3106253BD2005AB5DA, + 18650A3206253BD2005AB5DA, + 18650A3306253BD2005AB5DA, + 18650A3406253BD2005AB5DA, + 18650A3506253BD2005AB5DA, + 18650A3606253BD2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A3006253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3106253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3206253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3306253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3406253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3506253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3606253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A3706253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650A3806253BD2005AB5DA = { + children = ( + 18650A3906253BD2005AB5DA, + 18650A3A06253BD2005AB5DA, + 18650A3B06253BD2005AB5DA, + 18650A3C06253BD2005AB5DA, + 18650A3D06253BD2005AB5DA, + 18650A3E06253BD2005AB5DA, + 18650A3F06253BD2005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3906253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3A06253BD2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bspc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3B06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3C06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3D06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3E06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "setup.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A3F06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A4006253BD2005AB5DA = { + children = ( + 18650A4106253BD2005AB5DA, + 18650A4206253BD2005AB5DA, + 18650A4306253BD2005AB5DA, + 18650A4406253BD2005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650A4106253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A4206253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A4306253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A4406253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A4506253BD2005AB5DA = { + children = ( + 18650A4606253BD2005AB5DA, + 18650A4706253BD2005AB5DA, + 18650A4806253BD2005AB5DA, + 18650A4906253BD2005AB5DA, + 18650A4A06253BD2005AB5DA, + 18650A4B06253BD2005AB5DA, + 18650A4C06253BD2005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A4606253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4706253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4806253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4906253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4A06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4B06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4C06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A4D06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = all.cf; + refType = 4; + sourceTree = ""; + }; + 18650A4E06253BD2005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = bspc; + refType = 4; + sourceTree = ""; + }; + 18650A4F06253BD2005AB5DA = { + children = ( + 18650A5006253BD2005AB5DA, + 18650A6306253BD2005AB5DA, + ); + isa = PBXGroup; + path = bug750; + refType = 4; + sourceTree = ""; + }; + 18650A5006253BD2005AB5DA = { + children = ( + 18650A5106253BD2005AB5DA, + 18650A5206253BD2005AB5DA, + 18650A5306253BD2005AB5DA, + 18650A5406253BD2005AB5DA, + 18650A5506253BD2005AB5DA, + 18650A5706253BD2005AB5DA, + 18650A5906253BD2005AB5DA, + 18650A5A06253BD2005AB5DA, + 18650A5C06253BD2005AB5DA, + 18650A6106253BD2005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650A5106253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650A5206253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650A5306253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650A5406253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650A5506253BD2005AB5DA = { + children = ( + 18650A5606253BD2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A5606253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "loki_setup.patch.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A5706253BD2005AB5DA = { + children = ( + 18650A5806253BD2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A5806253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "loki_setup.patch.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A5906253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650A5A06253BD2005AB5DA = { + children = ( + 18650A5B06253BD2005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A5B06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "loki_setup.patch.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A5C06253BD2005AB5DA = { + children = ( + 18650A5D06253BD2005AB5DA, + 18650A5E06253BD2005AB5DA, + 18650A5F06253BD2005AB5DA, + 18650A6006253BD2005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650A5D06253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A5E06253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A5F06253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A6006253BD2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A6106253BD2005AB5DA = { + children = ( + 18650A6206253BD2005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A6206253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "loki_setup.patch.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A6306253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = loki_setup.patch; + refType = 4; + sourceTree = ""; + }; + 18650A6406253BD2005AB5DA = { + children = ( + 18650A6506253BD2005AB5DA, + 18650A7C06253BD3005AB5DA, + 18650A9106253BD3005AB5DA, + 18650A9206253BD3005AB5DA, + ); + isa = PBXGroup; + path = Help; + refType = 4; + sourceTree = ""; + }; + 18650A6506253BD2005AB5DA = { + children = ( + 18650A6606253BD2005AB5DA, + 18650A6706253BD2005AB5DA, + 18650A6806253BD2005AB5DA, + 18650A6906253BD2005AB5DA, + 18650A6A06253BD2005AB5DA, + 18650A6D06253BD2005AB5DA, + 18650A7006253BD2005AB5DA, + 18650A7106253BD2005AB5DA, + 18650A7406253BD3005AB5DA, + 18650A7906253BD3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650A6606253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650A6706253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650A6806253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650A6906253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650A6A06253BD2005AB5DA = { + children = ( + 18650A6B06253BD2005AB5DA, + 18650A6C06253BD2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A6B06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A6C06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3A_EULA.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A6D06253BD2005AB5DA = { + children = ( + 18650A6E06253BD2005AB5DA, + 18650A6F06253BD2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A6E06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A6F06253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3A_EULA.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A7006253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650A7106253BD2005AB5DA = { + children = ( + 18650A7206253BD2005AB5DA, + 18650A7306253BD3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A7206253BD2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A7306253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3A_EULA.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A7406253BD3005AB5DA = { + children = ( + 18650A7506253BD3005AB5DA, + 18650A7606253BD3005AB5DA, + 18650A7706253BD3005AB5DA, + 18650A7806253BD3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650A7506253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A7606253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A7706253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A7806253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A7906253BD3005AB5DA = { + children = ( + 18650A7A06253BD3005AB5DA, + 18650A7B06253BD3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A7A06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A7B06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3A_EULA.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A7C06253BD3005AB5DA = { + children = ( + 18650A7D06253BD3005AB5DA, + 18650A9006253BD3005AB5DA, + ); + isa = PBXGroup; + path = DocsArt; + refType = 4; + sourceTree = ""; + }; + 18650A7D06253BD3005AB5DA = { + children = ( + 18650A7E06253BD3005AB5DA, + 18650A7F06253BD3005AB5DA, + 18650A8006253BD3005AB5DA, + 18650A8106253BD3005AB5DA, + 18650A8206253BD3005AB5DA, + 18650A8406253BD3005AB5DA, + 18650A8606253BD3005AB5DA, + 18650A8706253BD3005AB5DA, + 18650A8906253BD3005AB5DA, + 18650A8E06253BD3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650A7E06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650A7F06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650A8006253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650A8106253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650A8206253BD3005AB5DA = { + children = ( + 18650A8306253BD3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A8306253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "toolback.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A8406253BD3005AB5DA = { + children = ( + 18650A8506253BD3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A8506253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "toolback.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A8606253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650A8706253BD3005AB5DA = { + children = ( + 18650A8806253BD3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A8806253BD3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "toolback.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A8906253BD3005AB5DA = { + children = ( + 18650A8A06253BD3005AB5DA, + 18650A8B06253BD3005AB5DA, + 18650A8C06253BD3005AB5DA, + 18650A8D06253BD3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650A8A06253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A8B06253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650A8C06253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650A8D06253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A8E06253BD3005AB5DA = { + children = ( + 18650A8F06253BD3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650A8F06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "toolback.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650A9006253BD3005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = toolback.jpg; + refType = 4; + sourceTree = ""; + }; + 18650A9106253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = Index.html; + refType = 4; + sourceTree = ""; + }; + 18650A9206253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Q3A_EULA.txt; + refType = 4; + sourceTree = ""; + }; + 18650A9306253BD3005AB5DA = { + children = ( + 18650A9406253BD3005AB5DA, + 18650ABF06253BD3005AB5DA, + 18650AC006253BD3005AB5DA, + 18650AC106253BD3005AB5DA, + 18650AC206253BD3005AB5DA, + 18650AC306253BD3005AB5DA, + 18650AC406253BD3005AB5DA, + 18650AC506253BD3005AB5DA, + ); + isa = PBXGroup; + path = makeself; + refType = 4; + sourceTree = ""; + }; + 18650A9406253BD3005AB5DA = { + children = ( + 18650A9506253BD3005AB5DA, + 18650A9606253BD3005AB5DA, + 18650A9706253BD3005AB5DA, + 18650A9806253BD3005AB5DA, + 18650A9906253BD3005AB5DA, + 18650AA106253BD3005AB5DA, + 18650AA906253BD3005AB5DA, + 18650AAA06253BD3005AB5DA, + 18650AB206253BD3005AB5DA, + 18650AB706253BD3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650A9506253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650A9606253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650A9706253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650A9806253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650A9906253BD3005AB5DA = { + children = ( + 18650A9A06253BD3005AB5DA, + 18650A9B06253BD3005AB5DA, + 18650A9C06253BD3005AB5DA, + 18650A9D06253BD3005AB5DA, + 18650A9E06253BD3005AB5DA, + 18650A9F06253BD3005AB5DA, + 18650AA006253BD3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650A9A06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COPYING.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A9B06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself-header.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A9C06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.lsm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A9D06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A9E06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650A9F06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AA006253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "update-readme.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AA106253BD3005AB5DA = { + children = ( + 18650AA206253BD3005AB5DA, + 18650AA306253BD3005AB5DA, + 18650AA406253BD3005AB5DA, + 18650AA506253BD3005AB5DA, + 18650AA606253BD3005AB5DA, + 18650AA706253BD3005AB5DA, + 18650AA806253BD3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650AA206253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COPYING.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA306253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself-header.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA406253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.lsm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA506253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA606253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA706253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA806253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "update-readme.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AA906253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650AAA06253BD3005AB5DA = { + children = ( + 18650AAB06253BD3005AB5DA, + 18650AAC06253BD3005AB5DA, + 18650AAD06253BD3005AB5DA, + 18650AAE06253BD3005AB5DA, + 18650AAF06253BD3005AB5DA, + 18650AB006253BD3005AB5DA, + 18650AB106253BD3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650AAB06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COPYING.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AAC06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself-header.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AAD06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.lsm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AAE06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "makeself.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AAF06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AB006253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AB106253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "update-readme.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AB206253BD3005AB5DA = { + children = ( + 18650AB306253BD3005AB5DA, + 18650AB406253BD3005AB5DA, + 18650AB506253BD3005AB5DA, + 18650AB606253BD3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650AB306253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650AB406253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650AB506253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650AB606253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650AB706253BD3005AB5DA = { + children = ( + 18650AB806253BD3005AB5DA, + 18650AB906253BD3005AB5DA, + 18650ABA06253BD3005AB5DA, + 18650ABB06253BD3005AB5DA, + 18650ABC06253BD3005AB5DA, + 18650ABD06253BD3005AB5DA, + 18650ABE06253BD3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650AB806253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COPYING.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AB906253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself-header.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ABA06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.lsm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ABB06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeself.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ABC06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ABD06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ABE06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "update-readme.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ABF06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = COPYING; + refType = 4; + sourceTree = ""; + }; + 18650AC006253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "makeself-header.sh"; + refType = 4; + sourceTree = ""; + }; + 18650AC106253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = makeself.lsm; + refType = 4; + sourceTree = ""; + }; + 18650AC206253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = makeself.sh; + refType = 4; + sourceTree = ""; + }; + 18650AC306253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + 18650AC406253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TODO; + refType = 4; + sourceTree = ""; + }; + 18650AC506253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "update-readme"; + refType = 4; + sourceTree = ""; + }; + 18650AC606253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = nightly.cf; + refType = 4; + sourceTree = ""; + }; + 18650AC706253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3.cf; + refType = 4; + sourceTree = ""; + }; + 18650AC806253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + 18650AC906253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = setup.sh; + refType = 4; + sourceTree = ""; + }; + 18650ACA06253BD3005AB5DA = { + children = ( + 18650ACB06253BD3005AB5DA, + 18650ADE06253BD3005AB5DA, + 18650B1C06253BD4005AB5DA, + ); + isa = PBXGroup; + path = setup_image; + refType = 4; + sourceTree = ""; + }; + 18650ACB06253BD3005AB5DA = { + children = ( + 18650ACC06253BD3005AB5DA, + 18650ACD06253BD3005AB5DA, + 18650ACE06253BD3005AB5DA, + 18650ACF06253BD3005AB5DA, + 18650AD006253BD3005AB5DA, + 18650AD206253BD3005AB5DA, + 18650AD406253BD3005AB5DA, + 18650AD506253BD3005AB5DA, + 18650AD706253BD3005AB5DA, + 18650ADC06253BD3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650ACC06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650ACD06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650ACE06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650ACF06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650AD006253BD3005AB5DA = { + children = ( + 18650AD106253BD3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650AD106253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AD206253BD3005AB5DA = { + children = ( + 18650AD306253BD3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650AD306253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AD406253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650AD506253BD3005AB5DA = { + children = ( + 18650AD606253BD3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650AD606253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AD706253BD3005AB5DA = { + children = ( + 18650AD806253BD3005AB5DA, + 18650AD906253BD3005AB5DA, + 18650ADA06253BD3005AB5DA, + 18650ADB06253BD3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650AD806253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650AD906253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650ADA06253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650ADB06253BD3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650ADC06253BD3005AB5DA = { + children = ( + 18650ADD06253BD3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650ADD06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.sh.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650ADE06253BD3005AB5DA = { + children = ( + 18650ADF06253BD3005AB5DA, + 18650B0606253BD4005AB5DA, + 18650B1606253BD4005AB5DA, + 18650B1706253BD4005AB5DA, + 18650B1806253BD4005AB5DA, + 18650B1906253BD4005AB5DA, + 18650B1A06253BD4005AB5DA, + 18650B1B06253BD4005AB5DA, + ); + isa = PBXGroup; + path = setup.data; + refType = 4; + sourceTree = ""; + }; + 18650ADF06253BD3005AB5DA = { + children = ( + 18650AE006253BD3005AB5DA, + 18650AE106253BD3005AB5DA, + 18650AE206253BD3005AB5DA, + 18650AE306253BD3005AB5DA, + 18650AE406253BD3005AB5DA, + 18650AEB06253BD4005AB5DA, + 18650AF206253BD4005AB5DA, + 18650AF306253BD4005AB5DA, + 18650AFA06253BD4005AB5DA, + 18650AFF06253BD4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650AE006253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650AE106253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650AE206253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650AE306253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650AE406253BD3005AB5DA = { + children = ( + 18650AE506253BD3005AB5DA, + 18650AE606253BD3005AB5DA, + 18650AE706253BD3005AB5DA, + 18650AE806253BD3005AB5DA, + 18650AE906253BD3005AB5DA, + 18650AEA06253BD3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650AE506253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.games.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AE606253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.sh.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AE706253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "postinstall.sh.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AE806253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.glade.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AE906253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.xml.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AEA06253BD3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.xpm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AEB06253BD4005AB5DA = { + children = ( + 18650AEC06253BD4005AB5DA, + 18650AED06253BD4005AB5DA, + 18650AEE06253BD4005AB5DA, + 18650AEF06253BD4005AB5DA, + 18650AF006253BD4005AB5DA, + 18650AF106253BD4005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650AEC06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.games.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AED06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.sh.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AEE06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "postinstall.sh.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AEF06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.glade.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AF006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.xml.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AF106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.xpm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650AF206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650AF306253BD4005AB5DA = { + children = ( + 18650AF406253BD4005AB5DA, + 18650AF506253BD4005AB5DA, + 18650AF606253BD4005AB5DA, + 18650AF706253BD4005AB5DA, + 18650AF806253BD4005AB5DA, + 18650AF906253BD4005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650AF406253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "config.games.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AF506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.sh.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AF606253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "postinstall.sh.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AF706253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "setup.glade.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AF806253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "setup.xml.in.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AF906253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.xpm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650AFA06253BD4005AB5DA = { + children = ( + 18650AFB06253BD4005AB5DA, + 18650AFC06253BD4005AB5DA, + 18650AFD06253BD4005AB5DA, + 18650AFE06253BD4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650AFB06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650AFC06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650AFD06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650AFE06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650AFF06253BD4005AB5DA = { + children = ( + 18650B0006253BD4005AB5DA, + 18650B0106253BD4005AB5DA, + 18650B0206253BD4005AB5DA, + 18650B0306253BD4005AB5DA, + 18650B0406253BD4005AB5DA, + 18650B0506253BD4005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B0006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.games.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B0106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.sh.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B0206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "postinstall.sh.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B0306253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.glade.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B0406253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.xml.in.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B0506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splash.xpm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B0606253BD4005AB5DA = { + children = ( + 18650B0706253BD4005AB5DA, + ); + isa = PBXGroup; + path = bin; + refType = 4; + sourceTree = ""; + }; + 18650B0706253BD4005AB5DA = { + children = ( + 18650B0806253BD4005AB5DA, + 18650B0906253BD4005AB5DA, + 18650B0A06253BD4005AB5DA, + 18650B0B06253BD4005AB5DA, + 18650B0C06253BD4005AB5DA, + 18650B0D06253BD4005AB5DA, + 18650B0E06253BD4005AB5DA, + 18650B0F06253BD4005AB5DA, + 18650B1006253BD4005AB5DA, + 18650B1506253BD4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B0806253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B0906253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B0A06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B0B06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B0C06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B0D06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B0E06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B0F06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B1006253BD4005AB5DA = { + children = ( + 18650B1106253BD4005AB5DA, + 18650B1206253BD4005AB5DA, + 18650B1306253BD4005AB5DA, + 18650B1406253BD4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B1106253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B1206253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B1306253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B1406253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B1506253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B1606253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = config.games.sh; + refType = 4; + sourceTree = ""; + }; + 18650B1706253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = config.sh.in; + refType = 4; + sourceTree = ""; + }; + 18650B1806253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = postinstall.sh.in; + refType = 4; + sourceTree = ""; + }; + 18650B1906253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = setup.glade; + refType = 4; + sourceTree = ""; + }; + 18650B1A06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = setup.xml.in; + refType = 4; + sourceTree = ""; + }; + 18650B1B06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = splash.xpm; + refType = 4; + sourceTree = ""; + }; + 18650B1C06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = setup.sh.in; + refType = 4; + sourceTree = ""; + }; + 18650B1D06253BD4005AB5DA = { + children = ( + 18650B1E06253BD4005AB5DA, + 18650B2D06253BD4005AB5DA, + ); + isa = PBXGroup; + path = setup_image.Linux; + refType = 4; + sourceTree = ""; + }; + 18650B1E06253BD4005AB5DA = { + children = ( + 18650B1F06253BD4005AB5DA, + 18650B2006253BD4005AB5DA, + 18650B2106253BD4005AB5DA, + 18650B2206253BD4005AB5DA, + 18650B2306253BD4005AB5DA, + 18650B2406253BD4005AB5DA, + 18650B2506253BD4005AB5DA, + 18650B2606253BD4005AB5DA, + 18650B2706253BD4005AB5DA, + 18650B2C06253BD4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B1F06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B2006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B2106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B2206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B2306253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B2406253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B2506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B2606253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B2706253BD4005AB5DA = { + children = ( + 18650B2806253BD4005AB5DA, + 18650B2906253BD4005AB5DA, + 18650B2A06253BD4005AB5DA, + 18650B2B06253BD4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B2806253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B2906253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B2A06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B2B06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B2C06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B2D06253BD4005AB5DA = { + children = ( + 18650B2E06253BD4005AB5DA, + 18650B3D06253BD4005AB5DA, + ); + isa = PBXGroup; + path = setup.data; + refType = 4; + sourceTree = ""; + }; + 18650B2E06253BD4005AB5DA = { + children = ( + 18650B2F06253BD4005AB5DA, + 18650B3006253BD4005AB5DA, + 18650B3106253BD4005AB5DA, + 18650B3206253BD4005AB5DA, + 18650B3306253BD4005AB5DA, + 18650B3406253BD4005AB5DA, + 18650B3506253BD4005AB5DA, + 18650B3606253BD4005AB5DA, + 18650B3706253BD4005AB5DA, + 18650B3C06253BD4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B2F06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B3006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B3106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B3206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B3306253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B3406253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B3506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B3606253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B3706253BD4005AB5DA = { + children = ( + 18650B3806253BD4005AB5DA, + 18650B3906253BD4005AB5DA, + 18650B3A06253BD4005AB5DA, + 18650B3B06253BD4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B3806253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B3906253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B3A06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B3B06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B3C06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B3D06253BD4005AB5DA = { + children = ( + 18650B3E06253BD4005AB5DA, + 18650B4D06253BD4005AB5DA, + ); + isa = PBXGroup; + path = bin; + refType = 4; + sourceTree = ""; + }; + 18650B3E06253BD4005AB5DA = { + children = ( + 18650B3F06253BD4005AB5DA, + 18650B4006253BD4005AB5DA, + 18650B4106253BD4005AB5DA, + 18650B4206253BD4005AB5DA, + 18650B4306253BD4005AB5DA, + 18650B4406253BD4005AB5DA, + 18650B4506253BD4005AB5DA, + 18650B4606253BD4005AB5DA, + 18650B4706253BD4005AB5DA, + 18650B4C06253BD4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B3F06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B4006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B4106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B4206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B4306253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B4406253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B4506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B4606253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B4706253BD4005AB5DA = { + children = ( + 18650B4806253BD4005AB5DA, + 18650B4906253BD4005AB5DA, + 18650B4A06253BD4005AB5DA, + 18650B4B06253BD4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B4806253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B4906253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B4A06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B4B06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B4C06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B4D06253BD4005AB5DA = { + children = ( + 18650B4E06253BD4005AB5DA, + 18650B5D06253BD4005AB5DA, + ); + isa = PBXGroup; + path = Linux; + refType = 4; + sourceTree = ""; + }; + 18650B4E06253BD4005AB5DA = { + children = ( + 18650B4F06253BD4005AB5DA, + 18650B5006253BD4005AB5DA, + 18650B5106253BD4005AB5DA, + 18650B5206253BD4005AB5DA, + 18650B5306253BD4005AB5DA, + 18650B5406253BD4005AB5DA, + 18650B5506253BD4005AB5DA, + 18650B5606253BD4005AB5DA, + 18650B5706253BD4005AB5DA, + 18650B5C06253BD4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B4F06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B5006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B5106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B5206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B5306253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B5406253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B5506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B5606253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B5706253BD4005AB5DA = { + children = ( + 18650B5806253BD4005AB5DA, + 18650B5906253BD4005AB5DA, + 18650B5A06253BD4005AB5DA, + 18650B5B06253BD4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B5806253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B5906253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B5A06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B5B06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B5C06253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B5D06253BD4005AB5DA = { + children = ( + 18650B5E06253BD4005AB5DA, + 18650B6D06253BD5005AB5DA, + ); + isa = PBXGroup; + path = x86; + refType = 4; + sourceTree = ""; + }; + 18650B5E06253BD4005AB5DA = { + children = ( + 18650B5F06253BD4005AB5DA, + 18650B6006253BD4005AB5DA, + 18650B6106253BD4005AB5DA, + 18650B6206253BD4005AB5DA, + 18650B6306253BD4005AB5DA, + 18650B6406253BD4005AB5DA, + 18650B6506253BD4005AB5DA, + 18650B6606253BD4005AB5DA, + 18650B6706253BD4005AB5DA, + 18650B6C06253BD5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B5F06253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B6006253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B6106253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B6206253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B6306253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B6406253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B6506253BD4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B6606253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B6706253BD4005AB5DA = { + children = ( + 18650B6806253BD4005AB5DA, + 18650B6906253BD4005AB5DA, + 18650B6A06253BD5005AB5DA, + 18650B6B06253BD5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B6806253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B6906253BD4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B6A06253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B6B06253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B6C06253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B6D06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.man; + path = "glibc-2.1"; + refType = 4; + sourceTree = ""; + }; + 18650B6E06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = wolf.cf; + refType = 4; + sourceTree = ""; + }; + 18650B6F06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = openurl.sh; + refType = 4; + sourceTree = ""; + }; + 18650B7006253BD5005AB5DA = { + children = ( + 18650B7106253BD5005AB5DA, + 18650B8806253BD5005AB5DA, + 18650B8906253BD5005AB5DA, + ); + isa = PBXGroup; + path = osx; + refType = 4; + sourceTree = ""; + }; + 18650B7106253BD5005AB5DA = { + children = ( + 18650B7206253BD5005AB5DA, + 18650B7306253BD5005AB5DA, + 18650B7406253BD5005AB5DA, + 18650B7506253BD5005AB5DA, + 18650B7606253BD5005AB5DA, + 18650B7906253BD5005AB5DA, + 18650B7C06253BD5005AB5DA, + 18650B7D06253BD5005AB5DA, + 18650B8006253BD5005AB5DA, + 18650B8506253BD5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B7206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B7306253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B7406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B7506253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B7606253BD5005AB5DA = { + children = ( + 18650B7706253BD5005AB5DA, + 18650B7806253BD5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B7706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "build.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B7806253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.info.m4.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B7906253BD5005AB5DA = { + children = ( + 18650B7A06253BD5005AB5DA, + 18650B7B06253BD5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B7A06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "build.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B7B06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.info.m4.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B7C06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B7D06253BD5005AB5DA = { + children = ( + 18650B7E06253BD5005AB5DA, + 18650B7F06253BD5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B7E06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "build.sh.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B7F06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.info.m4.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B8006253BD5005AB5DA = { + children = ( + 18650B8106253BD5005AB5DA, + 18650B8206253BD5005AB5DA, + 18650B8306253BD5005AB5DA, + 18650B8406253BD5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650B8106253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B8206253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B8306253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B8406253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B8506253BD5005AB5DA = { + children = ( + 18650B8606253BD5005AB5DA, + 18650B8706253BD5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650B8606253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "build.sh.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B8706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.info.m4.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B8806253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = build.sh; + refType = 4; + sourceTree = ""; + }; + 18650B8906253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = radiant.info.m4; + refType = 4; + sourceTree = ""; + }; + 18650B8A06253BD5005AB5DA = { + children = ( + 18650B8B06253BD5005AB5DA, + 18650BAE06253BD5005AB5DA, + 18650BAF06253BD5005AB5DA, + 18650BB006253BD5005AB5DA, + 18650BB106253BD5005AB5DA, + 18650BB206253BD5005AB5DA, + ); + isa = PBXGroup; + path = PluginSDK; + refType = 4; + sourceTree = ""; + }; + 18650B8B06253BD5005AB5DA = { + children = ( + 18650B8C06253BD5005AB5DA, + 18650B8D06253BD5005AB5DA, + 18650B8E06253BD5005AB5DA, + 18650B8F06253BD5005AB5DA, + 18650B9006253BD5005AB5DA, + 18650B9606253BD5005AB5DA, + 18650B9C06253BD5005AB5DA, + 18650B9D06253BD5005AB5DA, + 18650BA306253BD5005AB5DA, + 18650BA806253BD5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650B8C06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650B8D06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650B8E06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650B8F06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650B9006253BD5005AB5DA = { + children = ( + 18650B9106253BD5005AB5DA, + 18650B9206253BD5005AB5DA, + 18650B9306253BD5005AB5DA, + 18650B9406253BD5005AB5DA, + 18650B9506253BD5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildGtkSrc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildSDK.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9306253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildZip.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9506253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9606253BD5005AB5DA = { + children = ( + 18650B9706253BD5005AB5DA, + 18650B9806253BD5005AB5DA, + 18650B9906253BD5005AB5DA, + 18650B9A06253BD5005AB5DA, + 18650B9B06253BD5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650B9706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildGtkSrc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B9806253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildSDK.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B9906253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildZip.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B9A06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B9B06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650B9C06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650B9D06253BD5005AB5DA = { + children = ( + 18650B9E06253BD5005AB5DA, + 18650B9F06253BD5005AB5DA, + 18650BA006253BD5005AB5DA, + 18650BA106253BD5005AB5DA, + 18650BA206253BD5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9E06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "BuildGtkSrc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650B9F06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "BuildSDK.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BA006253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "BuildZip.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BA106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BA206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BA306253BD5005AB5DA = { + children = ( + 18650BA406253BD5005AB5DA, + 18650BA506253BD5005AB5DA, + 18650BA606253BD5005AB5DA, + 18650BA706253BD5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650BA406253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650BA506253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650BA606253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650BA706253BD5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650BA806253BD5005AB5DA = { + children = ( + 18650BA906253BD5005AB5DA, + 18650BAA06253BD5005AB5DA, + 18650BAB06253BD5005AB5DA, + 18650BAC06253BD5005AB5DA, + 18650BAD06253BD5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650BA906253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildGtkSrc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BAA06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildSDK.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BAB06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BuildZip.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BAC06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BAD06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BAE06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = BuildGtkSrc; + refType = 4; + sourceTree = ""; + }; + 18650BAF06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = BuildSDK; + refType = 4; + sourceTree = ""; + }; + 18650BB006253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = BuildZip; + refType = 4; + sourceTree = ""; + }; + 18650BB106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = README.html; + refType = 4; + sourceTree = ""; + }; + 18650BB206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TODO; + refType = 4; + sourceTree = ""; + }; + 18650BB306253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = quickstart.txt; + refType = 4; + sourceTree = ""; + }; + 18650BB406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = radiantgtkrc; + refType = 4; + sourceTree = ""; + }; + 18650BB506253BD5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = setup.bmp; + refType = 4; + sourceTree = ""; + }; + 18650BB606253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = setup.patch; + refType = 4; + sourceTree = ""; + }; + 18650BB706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shortcuts.ini.sample; + refType = 4; + sourceTree = ""; + }; + 18650BB806253BD5005AB5DA = { + children = ( + 18650BB906253BD5005AB5DA, + 18650C1806253BD6005AB5DA, + 18650C1906253BD6005AB5DA, + 18650C3806253BD6005AB5DA, + 18650C3906253BD6005AB5DA, + 18650C3A06253BD6005AB5DA, + 18650C3B06253BD6005AB5DA, + 18650C3C06253BD6005AB5DA, + 18650C3D06253BD6005AB5DA, + 18650C3E06253BD6005AB5DA, + 18650C3F06253BD6005AB5DA, + 18650C4006253BD6005AB5DA, + 18650C4106253BD6005AB5DA, + 18650C4206253BD6005AB5DA, + 18650C4306253BD6005AB5DA, + 18650C4406253BD6005AB5DA, + 18650C4506253BD6005AB5DA, + 18650C4606253BD6005AB5DA, + 18650C4706253BD6005AB5DA, + 18650C4806253BD6005AB5DA, + 18650C4906253BD6005AB5DA, + 18650F9906253BDE005AB5DA, + 18650F9A06253BDE005AB5DA, + ); + isa = PBXGroup; + path = win32; + refType = 4; + sourceTree = ""; + }; + 18650BB906253BD5005AB5DA = { + children = ( + 18650BBA06253BD5005AB5DA, + 18650BBB06253BD5005AB5DA, + 18650BBC06253BD5005AB5DA, + 18650BBD06253BD5005AB5DA, + 18650BBE06253BD5005AB5DA, + 18650BD306253BD5005AB5DA, + 18650BE806253BD5005AB5DA, + 18650BE906253BD5005AB5DA, + 18650BFE06253BD6005AB5DA, + 18650C0306253BD6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650BBA06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650BBB06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650BBC06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650BBD06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650BBE06253BD5005AB5DA = { + children = ( + 18650BBF06253BD5005AB5DA, + 18650BC006253BD5005AB5DA, + 18650BC106253BD5005AB5DA, + 18650BC206253BD5005AB5DA, + 18650BC306253BD5005AB5DA, + 18650BC406253BD5005AB5DA, + 18650BC506253BD5005AB5DA, + 18650BC606253BD5005AB5DA, + 18650BC706253BD5005AB5DA, + 18650BC806253BD5005AB5DA, + 18650BC906253BD5005AB5DA, + 18650BCA06253BD5005AB5DA, + 18650BCB06253BD5005AB5DA, + 18650BCC06253BD5005AB5DA, + 18650BCD06253BD5005AB5DA, + 18650BCE06253BD5005AB5DA, + 18650BCF06253BD5005AB5DA, + 18650BD006253BD5005AB5DA, + 18650BD106253BD5005AB5DA, + 18650BD206253BD5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650BBF06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC006253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classic.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "et.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "halflife.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC306253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic2.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HOWTO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC506253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "id-hl.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC606253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ja.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jk2.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC806253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BC906253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BCA06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolf.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BCB06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolfet.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BCC06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven-hl.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BCD06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BCE06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BCF06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sof2.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BD006253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stvef.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BD106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BD206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BD306253BD5005AB5DA = { + children = ( + 18650BD406253BD5005AB5DA, + 18650BD506253BD5005AB5DA, + 18650BD606253BD5005AB5DA, + 18650BD706253BD5005AB5DA, + 18650BD806253BD5005AB5DA, + 18650BD906253BD5005AB5DA, + 18650BDA06253BD5005AB5DA, + 18650BDB06253BD5005AB5DA, + 18650BDC06253BD5005AB5DA, + 18650BDD06253BD5005AB5DA, + 18650BDE06253BD5005AB5DA, + 18650BDF06253BD5005AB5DA, + 18650BE006253BD5005AB5DA, + 18650BE106253BD5005AB5DA, + 18650BE206253BD5005AB5DA, + 18650BE306253BD5005AB5DA, + 18650BE406253BD5005AB5DA, + 18650BE506253BD5005AB5DA, + 18650BE606253BD5005AB5DA, + 18650BE706253BD5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650BD406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BD506253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classic.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BD606253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "et.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BD706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "halflife.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BD806253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic2.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BD906253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HOWTO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BDA06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "id-hl.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BDB06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ja.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BDC06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jk2.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BDD06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BDE06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BDF06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolf.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE006253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolfet.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven-hl.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE306253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sof2.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE506253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stvef.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE606253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE706253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650BE806253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650BE906253BD5005AB5DA = { + children = ( + 18650BEA06253BD5005AB5DA, + 18650BEB06253BD5005AB5DA, + 18650BEC06253BD5005AB5DA, + 18650BED06253BD5005AB5DA, + 18650BEE06253BD5005AB5DA, + 18650BEF06253BD5005AB5DA, + 18650BF006253BD5005AB5DA, + 18650BF106253BD5005AB5DA, + 18650BF206253BD5005AB5DA, + 18650BF306253BD5005AB5DA, + 18650BF406253BD5005AB5DA, + 18650BF506253BD5005AB5DA, + 18650BF606253BD5005AB5DA, + 18650BF706253BD6005AB5DA, + 18650BF806253BD6005AB5DA, + 18650BF906253BD6005AB5DA, + 18650BFA06253BD6005AB5DA, + 18650BFB06253BD6005AB5DA, + 18650BFC06253BD6005AB5DA, + 18650BFD06253BD6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650BEA06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BEB06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classic.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BEC06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "et.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BED06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "halflife.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BEE06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic2.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BEF06253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HOWTO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF006253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "id-hl.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF106253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ja.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF206253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jk2.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF306253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF406253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF506253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolf.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF606253BD5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolfet.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF706253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven-hl.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF806253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BF906253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BFA06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sof2.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BFB06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stvef.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BFC06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BFD06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650BFE06253BD6005AB5DA = { + children = ( + 18650BFF06253BD6005AB5DA, + 18650C0006253BD6005AB5DA, + 18650C0106253BD6005AB5DA, + 18650C0206253BD6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650BFF06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C0006253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C0106253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C0206253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C0306253BD6005AB5DA = { + children = ( + 18650C0406253BD6005AB5DA, + 18650C0506253BD6005AB5DA, + 18650C0606253BD6005AB5DA, + 18650C0706253BD6005AB5DA, + 18650C0806253BD6005AB5DA, + 18650C0906253BD6005AB5DA, + 18650C0A06253BD6005AB5DA, + 18650C0B06253BD6005AB5DA, + 18650C0C06253BD6005AB5DA, + 18650C0D06253BD6005AB5DA, + 18650C0E06253BD6005AB5DA, + 18650C0F06253BD6005AB5DA, + 18650C1006253BD6005AB5DA, + 18650C1106253BD6005AB5DA, + 18650C1206253BD6005AB5DA, + 18650C1306253BD6005AB5DA, + 18650C1406253BD6005AB5DA, + 18650C1506253BD6005AB5DA, + 18650C1606253BD6005AB5DA, + 18650C1706253BD6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C0406253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "all.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0506253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classic.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0606253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "et.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0706253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "halflife.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0806253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic2.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0906253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HOWTO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0A06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "id-hl.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0B06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ja.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0C06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jk2.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0D06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nightly.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0E06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C0F06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolf.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1006253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3wolfet.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1106253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven-hl.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1206253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1306253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "setup.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1406253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sof2.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1506253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stvef.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1606253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1706253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wolf.cf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C1806253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = all.cf; + refType = 4; + sourceTree = ""; + }; + 18650C1906253BD6005AB5DA = { + children = ( + 18650C1A06253BD6005AB5DA, + 18650C3506253BD6005AB5DA, + 18650C3606253BD6005AB5DA, + 18650C3706253BD6005AB5DA, + ); + isa = PBXGroup; + path = bin; + refType = 4; + sourceTree = ""; + }; + 18650C1A06253BD6005AB5DA = { + children = ( + 18650C1B06253BD6005AB5DA, + 18650C1C06253BD6005AB5DA, + 18650C1D06253BD6005AB5DA, + 18650C1E06253BD6005AB5DA, + 18650C1F06253BD6005AB5DA, + 18650C2306253BD6005AB5DA, + 18650C2706253BD6005AB5DA, + 18650C2806253BD6005AB5DA, + 18650C2C06253BD6005AB5DA, + 18650C3106253BD6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650C1B06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650C1C06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650C1D06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650C1E06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650C1F06253BD6005AB5DA = { + children = ( + 18650C2006253BD6005AB5DA, + 18650C2106253BD6005AB5DA, + 18650C2206253BD6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2006253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.exe.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2106253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "msvcp70.dll.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2206253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "msvcr70.dll.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2306253BD6005AB5DA = { + children = ( + 18650C2406253BD6005AB5DA, + 18650C2506253BD6005AB5DA, + 18650C2606253BD6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C2406253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.exe.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C2506253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "msvcp70.dll.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C2606253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "msvcr70.dll.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C2706253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650C2806253BD6005AB5DA = { + children = ( + 18650C2906253BD6005AB5DA, + 18650C2A06253BD6005AB5DA, + 18650C2B06253BD6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2906253BD6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bspc.exe.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2A06253BD6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "msvcp70.dll.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2B06253BD6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "msvcr70.dll.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2C06253BD6005AB5DA = { + children = ( + 18650C2D06253BD6005AB5DA, + 18650C2E06253BD6005AB5DA, + 18650C2F06253BD6005AB5DA, + 18650C3006253BD6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650C2D06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C2E06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C2F06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C3006253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C3106253BD6005AB5DA = { + children = ( + 18650C3206253BD6005AB5DA, + 18650C3306253BD6005AB5DA, + 18650C3406253BD6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C3206253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.exe.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C3306253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "msvcp70.dll.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C3406253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "msvcr70.dll.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C3506253BD6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = bspc.exe; + refType = 4; + sourceTree = ""; + }; + 18650C3606253BD6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = msvcp70.dll; + refType = 4; + sourceTree = ""; + }; + 18650C3706253BD6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = msvcr70.dll; + refType = 4; + sourceTree = ""; + }; + 18650C3806253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = classic.cf; + refType = 4; + sourceTree = ""; + }; + 18650C3906253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = et.cf; + refType = 4; + sourceTree = ""; + }; + 18650C3A06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = halflife.cf; + refType = 4; + sourceTree = ""; + }; + 18650C3B06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = heretic2.cf; + refType = 4; + sourceTree = ""; + }; + 18650C3C06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = HOWTO; + refType = 4; + sourceTree = ""; + }; + 18650C3D06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "id-hl.cf"; + refType = 4; + sourceTree = ""; + }; + 18650C3E06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ja.cf; + refType = 4; + sourceTree = ""; + }; + 18650C3F06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = jk2.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4006253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = nightly.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4106253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4206253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3wolf.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4306253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3wolfet.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4406253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "raven-hl.cf"; + refType = 4; + sourceTree = ""; + }; + 18650C4506253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = raven.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4606253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.perl; + path = setup.pl; + refType = 4; + sourceTree = ""; + }; + 18650C4706253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = sof2.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4806253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = stvef.cf; + refType = 4; + sourceTree = ""; + }; + 18650C4906253BD6005AB5DA = { + children = ( + 18650C4A06253BD6005AB5DA, + 18650C5D06253BD6005AB5DA, + 18650C7706253BD7005AB5DA, + 18650D7C06253BD9005AB5DA, + 18650D7D06253BD9005AB5DA, + 18650DE206253BDA005AB5DA, + 18650DF706253BDA005AB5DA, + 18650E1106253BDB005AB5DA, + 18650F4006253BDE005AB5DA, + 18650F5506253BDE005AB5DA, + 18650F7F06253BDE005AB5DA, + ); + isa = PBXGroup; + path = template; + refType = 4; + sourceTree = ""; + }; + 18650C4A06253BD6005AB5DA = { + children = ( + 18650C4B06253BD6005AB5DA, + 18650C4C06253BD6005AB5DA, + 18650C4D06253BD6005AB5DA, + 18650C4E06253BD6005AB5DA, + 18650C4F06253BD6005AB5DA, + 18650C5106253BD6005AB5DA, + 18650C5306253BD6005AB5DA, + 18650C5406253BD6005AB5DA, + 18650C5606253BD6005AB5DA, + 18650C5B06253BD6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650C4B06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650C4C06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650C4D06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650C4E06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650C4F06253BD6005AB5DA = { + children = ( + 18650C5006253BD6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C5006253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.ipr.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C5106253BD6005AB5DA = { + children = ( + 18650C5206253BD6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C5206253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.ipr.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C5306253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650C5406253BD6005AB5DA = { + children = ( + 18650C5506253BD6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C5506253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.ipr.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C5606253BD6005AB5DA = { + children = ( + 18650C5706253BD6005AB5DA, + 18650C5806253BD6005AB5DA, + 18650C5906253BD6005AB5DA, + 18650C5A06253BD6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650C5706253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C5806253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C5906253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C5A06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C5B06253BD6005AB5DA = { + children = ( + 18650C5C06253BD6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C5C06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.ipr.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C5D06253BD6005AB5DA = { + children = ( + 18650C5E06253BD6005AB5DA, + 18650C7506253BD7005AB5DA, + 18650C7606253BD7005AB5DA, + ); + isa = PBXGroup; + path = "Component Definitions"; + refType = 4; + sourceTree = ""; + }; + 18650C5E06253BD6005AB5DA = { + children = ( + 18650C5F06253BD6005AB5DA, + 18650C6006253BD6005AB5DA, + 18650C6106253BD6005AB5DA, + 18650C6206253BD6005AB5DA, + 18650C6306253BD6005AB5DA, + 18650C6606253BD6005AB5DA, + 18650C6906253BD6005AB5DA, + 18650C6A06253BD6005AB5DA, + 18650C6D06253BD6005AB5DA, + 18650C7206253BD6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650C5F06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650C6006253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650C6106253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650C6206253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650C6306253BD6005AB5DA = { + children = ( + 18650C6406253BD6005AB5DA, + 18650C6506253BD6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6406253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.cdf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6506253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6606253BD6005AB5DA = { + children = ( + 18650C6706253BD6005AB5DA, + 18650C6806253BD6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C6706253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.cdf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C6806253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C6906253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650C6A06253BD6005AB5DA = { + children = ( + 18650C6B06253BD6005AB5DA, + 18650C6C06253BD6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6B06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.cdf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6C06253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6D06253BD6005AB5DA = { + children = ( + 18650C6E06253BD6005AB5DA, + 18650C6F06253BD6005AB5DA, + 18650C7006253BD6005AB5DA, + 18650C7106253BD6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650C6E06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C6F06253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650C7006253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650C7106253BD6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C7206253BD6005AB5DA = { + children = ( + 18650C7306253BD6005AB5DA, + 18650C7406253BD7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650C7306253BD6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.cdf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C7406253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650C7506253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.cdf; + refType = 4; + sourceTree = ""; + }; + 18650C7606253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.fgl; + refType = 4; + sourceTree = ""; + }; + 18650C7706253BD7005AB5DA = { + children = ( + 18650C7806253BD7005AB5DA, + 18650D4B06253BD9005AB5DA, + 18650D4C06253BD9005AB5DA, + 18650D4D06253BD9005AB5DA, + 18650D4E06253BD9005AB5DA, + 18650D4F06253BD9005AB5DA, + 18650D5006253BD9005AB5DA, + 18650D5106253BD9005AB5DA, + 18650D5206253BD9005AB5DA, + 18650D5306253BD9005AB5DA, + 18650D5406253BD9005AB5DA, + 18650D5506253BD9005AB5DA, + 18650D5606253BD9005AB5DA, + 18650D5706253BD9005AB5DA, + 18650D5806253BD9005AB5DA, + 18650D5906253BD9005AB5DA, + 18650D5A06253BD9005AB5DA, + 18650D5B06253BD9005AB5DA, + 18650D5C06253BD9005AB5DA, + 18650D5D06253BD9005AB5DA, + 18650D5E06253BD9005AB5DA, + 18650D5F06253BD9005AB5DA, + 18650D6006253BD9005AB5DA, + 18650D6106253BD9005AB5DA, + 18650D6206253BD9005AB5DA, + 18650D6306253BD9005AB5DA, + 18650D6406253BD9005AB5DA, + 18650D6506253BD9005AB5DA, + 18650D6606253BD9005AB5DA, + 18650D6706253BD9005AB5DA, + 18650D6806253BD9005AB5DA, + 18650D6906253BD9005AB5DA, + 18650D6A06253BD9005AB5DA, + 18650D6B06253BD9005AB5DA, + 18650D6C06253BD9005AB5DA, + 18650D6D06253BD9005AB5DA, + 18650D6E06253BD9005AB5DA, + 18650D6F06253BD9005AB5DA, + 18650D7006253BD9005AB5DA, + 18650D7106253BD9005AB5DA, + 18650D7206253BD9005AB5DA, + 18650D7306253BD9005AB5DA, + 18650D7406253BD9005AB5DA, + 18650D7506253BD9005AB5DA, + 18650D7606253BD9005AB5DA, + 18650D7706253BD9005AB5DA, + 18650D7806253BD9005AB5DA, + 18650D7906253BD9005AB5DA, + 18650D7A06253BD9005AB5DA, + 18650D7B06253BD9005AB5DA, + ); + isa = PBXGroup; + path = "File Groups"; + refType = 4; + sourceTree = ""; + }; + 18650C7806253BD7005AB5DA = { + children = ( + 18650C7906253BD7005AB5DA, + 18650C7A06253BD7005AB5DA, + 18650C7B06253BD7005AB5DA, + 18650C7C06253BD7005AB5DA, + 18650C7D06253BD7005AB5DA, + 18650CAF06253BD7005AB5DA, + 18650CE106253BD8005AB5DA, + 18650CE206253BD8005AB5DA, + 18650D1406253BD8005AB5DA, + 18650D1906253BD8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650C7906253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650C7A06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650C7B06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650C7C06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650C7D06253BD7005AB5DA = { + children = ( + 18650C7E06253BD7005AB5DA, + 18650C7F06253BD7005AB5DA, + 18650C8006253BD7005AB5DA, + 18650C8106253BD7005AB5DA, + 18650C8206253BD7005AB5DA, + 18650C8306253BD7005AB5DA, + 18650C8406253BD7005AB5DA, + 18650C8506253BD7005AB5DA, + 18650C8606253BD7005AB5DA, + 18650C8706253BD7005AB5DA, + 18650C8806253BD7005AB5DA, + 18650C8906253BD7005AB5DA, + 18650C8A06253BD7005AB5DA, + 18650C8B06253BD7005AB5DA, + 18650C8C06253BD7005AB5DA, + 18650C8D06253BD7005AB5DA, + 18650C8E06253BD7005AB5DA, + 18650C8F06253BD7005AB5DA, + 18650C9006253BD7005AB5DA, + 18650C9106253BD7005AB5DA, + 18650C9206253BD7005AB5DA, + 18650C9306253BD7005AB5DA, + 18650C9406253BD7005AB5DA, + 18650C9506253BD7005AB5DA, + 18650C9606253BD7005AB5DA, + 18650C9706253BD7005AB5DA, + 18650C9806253BD7005AB5DA, + 18650C9906253BD7005AB5DA, + 18650C9A06253BD7005AB5DA, + 18650C9B06253BD7005AB5DA, + 18650C9C06253BD7005AB5DA, + 18650C9D06253BD7005AB5DA, + 18650C9E06253BD7005AB5DA, + 18650C9F06253BD7005AB5DA, + 18650CA006253BD7005AB5DA, + 18650CA106253BD7005AB5DA, + 18650CA206253BD7005AB5DA, + 18650CA306253BD7005AB5DA, + 18650CA406253BD7005AB5DA, + 18650CA506253BD7005AB5DA, + 18650CA606253BD7005AB5DA, + 18650CA706253BD7005AB5DA, + 18650CA806253BD7005AB5DA, + 18650CA906253BD7005AB5DA, + 18650CAA06253BD7005AB5DA, + 18650CAB06253BD7005AB5DA, + 18650CAC06253BD7005AB5DA, + 18650CAD06253BD7005AB5DA, + 18650CAE06253BD7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650C7E06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Compile Manual.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C7F06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fdf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8006253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8106253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8206253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Example Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8306253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8406253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8506253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8606253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8706253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8806253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8906253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8A06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8B06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Model Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8C06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - bkgrnd2d.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8D06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - BobToolz.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8E06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3 Wolf.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C8F06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9006253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9106253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - GTK GenSurf.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9206253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Pk3Man.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9306253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - PrtView.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9406253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - TexTool.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9506253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLL Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9606253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLLs.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9706253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9806253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Misc Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9906253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9A06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9B06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Default Project.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9C06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Editor Images - SPoG pk3.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9D06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9E06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Misc Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650C9F06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Sample Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA006253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA106253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Shader Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA206253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist-ta.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA306253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA406253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA506253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA606253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA706253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA806253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CA906253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Sample Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CAA06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Teams Manual.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CAB06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Terrain Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CAC06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool Help.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CAD06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Exectuable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CAE06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CAF06253BD7005AB5DA = { + children = ( + 18650CB006253BD7005AB5DA, + 18650CB106253BD7005AB5DA, + 18650CB206253BD7005AB5DA, + 18650CB306253BD7005AB5DA, + 18650CB406253BD7005AB5DA, + 18650CB506253BD7005AB5DA, + 18650CB606253BD7005AB5DA, + 18650CB706253BD7005AB5DA, + 18650CB806253BD7005AB5DA, + 18650CB906253BD7005AB5DA, + 18650CBA06253BD7005AB5DA, + 18650CBB06253BD7005AB5DA, + 18650CBC06253BD7005AB5DA, + 18650CBD06253BD7005AB5DA, + 18650CBE06253BD7005AB5DA, + 18650CBF06253BD7005AB5DA, + 18650CC006253BD7005AB5DA, + 18650CC106253BD7005AB5DA, + 18650CC206253BD7005AB5DA, + 18650CC306253BD7005AB5DA, + 18650CC406253BD7005AB5DA, + 18650CC506253BD8005AB5DA, + 18650CC606253BD8005AB5DA, + 18650CC706253BD8005AB5DA, + 18650CC806253BD8005AB5DA, + 18650CC906253BD8005AB5DA, + 18650CCA06253BD8005AB5DA, + 18650CCB06253BD8005AB5DA, + 18650CCC06253BD8005AB5DA, + 18650CCD06253BD8005AB5DA, + 18650CCE06253BD8005AB5DA, + 18650CCF06253BD8005AB5DA, + 18650CD006253BD8005AB5DA, + 18650CD106253BD8005AB5DA, + 18650CD206253BD8005AB5DA, + 18650CD306253BD8005AB5DA, + 18650CD406253BD8005AB5DA, + 18650CD506253BD8005AB5DA, + 18650CD606253BD8005AB5DA, + 18650CD706253BD8005AB5DA, + 18650CD806253BD8005AB5DA, + 18650CD906253BD8005AB5DA, + 18650CDA06253BD8005AB5DA, + 18650CDB06253BD8005AB5DA, + 18650CDC06253BD8005AB5DA, + 18650CDD06253BD8005AB5DA, + 18650CDE06253BD8005AB5DA, + 18650CDF06253BD8005AB5DA, + 18650CE006253BD8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650CB006253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Compile Manual.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB106253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fdf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB206253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB306253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB406253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Example Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB506253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB606253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB706253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB806253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CB906253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CBA06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CBB06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CBC06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CBD06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Model Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CBE06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - bkgrnd2d.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CBF06253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - BobToolz.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC006253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3 Wolf.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC106253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC206253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC306253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - GTK GenSurf.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC406253BD7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Pk3Man.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - PrtView.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC606253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - TexTool.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC706253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLL Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC806253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLLs.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CC906253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CCA06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Misc Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CCB06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CCC06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CCD06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Default Project.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CCE06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Editor Images - SPoG pk3.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CCF06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Misc Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Sample Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD206253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Shader Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD406253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist-ta.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD606253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD706253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD806253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CD906253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CDA06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CDB06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Sample Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CDC06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Teams Manual.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CDD06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Terrain Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CDE06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool Help.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CDF06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Exectuable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CE006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650CE106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650CE206253BD8005AB5DA = { + children = ( + 18650CE306253BD8005AB5DA, + 18650CE406253BD8005AB5DA, + 18650CE506253BD8005AB5DA, + 18650CE606253BD8005AB5DA, + 18650CE706253BD8005AB5DA, + 18650CE806253BD8005AB5DA, + 18650CE906253BD8005AB5DA, + 18650CEA06253BD8005AB5DA, + 18650CEB06253BD8005AB5DA, + 18650CEC06253BD8005AB5DA, + 18650CED06253BD8005AB5DA, + 18650CEE06253BD8005AB5DA, + 18650CEF06253BD8005AB5DA, + 18650CF006253BD8005AB5DA, + 18650CF106253BD8005AB5DA, + 18650CF206253BD8005AB5DA, + 18650CF306253BD8005AB5DA, + 18650CF406253BD8005AB5DA, + 18650CF506253BD8005AB5DA, + 18650CF606253BD8005AB5DA, + 18650CF706253BD8005AB5DA, + 18650CF806253BD8005AB5DA, + 18650CF906253BD8005AB5DA, + 18650CFA06253BD8005AB5DA, + 18650CFB06253BD8005AB5DA, + 18650CFC06253BD8005AB5DA, + 18650CFD06253BD8005AB5DA, + 18650CFE06253BD8005AB5DA, + 18650CFF06253BD8005AB5DA, + 18650D0006253BD8005AB5DA, + 18650D0106253BD8005AB5DA, + 18650D0206253BD8005AB5DA, + 18650D0306253BD8005AB5DA, + 18650D0406253BD8005AB5DA, + 18650D0506253BD8005AB5DA, + 18650D0606253BD8005AB5DA, + 18650D0706253BD8005AB5DA, + 18650D0806253BD8005AB5DA, + 18650D0906253BD8005AB5DA, + 18650D0A06253BD8005AB5DA, + 18650D0B06253BD8005AB5DA, + 18650D0C06253BD8005AB5DA, + 18650D0D06253BD8005AB5DA, + 18650D0E06253BD8005AB5DA, + 18650D0F06253BD8005AB5DA, + 18650D1006253BD8005AB5DA, + 18650D1106253BD8005AB5DA, + 18650D1206253BD8005AB5DA, + 18650D1306253BD8005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Compile Manual.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE406253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fdf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE606253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE706253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Example Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE806253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CE906253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CEA06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CEB06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CEC06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CED06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CEE06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CEF06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Model Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - bkgrnd2d.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF206253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - BobToolz.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3 Wolf.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF406253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF606253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - GTK GenSurf.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF706253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Pk3Man.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF806253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - PrtView.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CF906253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - TexTool.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CFA06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLL Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CFB06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLLs.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CFC06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CFD06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Misc Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CFE06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650CFF06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Default Project.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Editor Images - SPoG pk3.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0206253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Misc Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0406253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Sample Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0606253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Shader Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0706253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist-ta.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0806253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0906253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0A06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0B06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Executable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0C06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0D06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0E06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Sample Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D0F06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Teams Manual.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Terrain Manual Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool Help.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1206253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Exectuable Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Media Files.fgl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1406253BD8005AB5DA = { + children = ( + 18650D1506253BD8005AB5DA, + 18650D1606253BD8005AB5DA, + 18650D1706253BD8005AB5DA, + 18650D1806253BD8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650D1506253BD8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1606253BD8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650D1706253BD8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650D1806253BD8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650D1906253BD8005AB5DA = { + children = ( + 18650D1A06253BD8005AB5DA, + 18650D1B06253BD8005AB5DA, + 18650D1C06253BD8005AB5DA, + 18650D1D06253BD8005AB5DA, + 18650D1E06253BD8005AB5DA, + 18650D1F06253BD8005AB5DA, + 18650D2006253BD8005AB5DA, + 18650D2106253BD8005AB5DA, + 18650D2206253BD8005AB5DA, + 18650D2306253BD8005AB5DA, + 18650D2406253BD8005AB5DA, + 18650D2506253BD8005AB5DA, + 18650D2606253BD8005AB5DA, + 18650D2706253BD8005AB5DA, + 18650D2806253BD8005AB5DA, + 18650D2906253BD8005AB5DA, + 18650D2A06253BD8005AB5DA, + 18650D2B06253BD8005AB5DA, + 18650D2C06253BD8005AB5DA, + 18650D2D06253BD8005AB5DA, + 18650D2E06253BD8005AB5DA, + 18650D2F06253BD8005AB5DA, + 18650D3006253BD8005AB5DA, + 18650D3106253BD8005AB5DA, + 18650D3206253BD8005AB5DA, + 18650D3306253BD8005AB5DA, + 18650D3406253BD8005AB5DA, + 18650D3506253BD8005AB5DA, + 18650D3606253BD9005AB5DA, + 18650D3706253BD9005AB5DA, + 18650D3806253BD9005AB5DA, + 18650D3906253BD9005AB5DA, + 18650D3A06253BD9005AB5DA, + 18650D3B06253BD9005AB5DA, + 18650D3C06253BD9005AB5DA, + 18650D3D06253BD9005AB5DA, + 18650D3E06253BD9005AB5DA, + 18650D3F06253BD9005AB5DA, + 18650D4006253BD9005AB5DA, + 18650D4106253BD9005AB5DA, + 18650D4206253BD9005AB5DA, + 18650D4306253BD9005AB5DA, + 18650D4406253BD9005AB5DA, + 18650D4506253BD9005AB5DA, + 18650D4606253BD9005AB5DA, + 18650D4706253BD9005AB5DA, + 18650D4806253BD9005AB5DA, + 18650D4906253BD9005AB5DA, + 18650D4A06253BD9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650D1A06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Compile Manual.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D1B06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.fdf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D1C06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D1D06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D1E06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Example Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D1F06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2206253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2406253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2606253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2706253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Model Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2806253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - bkgrnd2d.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2906253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - BobToolz.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2A06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3 Wolf.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2B06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2C06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2D06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - GTK GenSurf.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2E06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Pk3Man.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D2F06253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - PrtView.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3006253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - TexTool.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3106253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLL Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3206253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLLs.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3306253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3406253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Misc Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3506253BD8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3606253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3706253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Default Project.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3806253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Editor Images - SPoG pk3.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3906253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3A06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Misc Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3B06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Sample Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3C06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3D06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Shader Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3E06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist-ta.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D3F06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4006253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4106253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4206253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Executable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4306253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4406253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4506253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Sample Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4606253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Teams Manual.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4706253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Terrain Manual Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4806253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool Help.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4906253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Exectuable Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4A06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Media Files.fgl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D4B06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Compile Manual.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D4C06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.fdf; + refType = 4; + sourceTree = ""; + }; + 18650D4D06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D4E06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ET Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D4F06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Example Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5006253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5106253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Halflife Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5206253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5306253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Heretic2 Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5406253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5506253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JA Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5606253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5706253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "JKII Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5806253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Model Manual Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5906253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - bkgrnd2d.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5A06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - BobToolz.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5B06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3 Wolf.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5C06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry pk3.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5D06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Curry.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5E06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - GTK GenSurf.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D5F06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - Pk3Man.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6006253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - PrtView.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6106253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Plugins - TexTool.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6206253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLL Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6306253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program DLLs.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6406253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6506253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Program Misc Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6606253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6706253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q2 Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6806253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Default Project.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6906253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Editor Images - SPoG pk3.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6A06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6B06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Misc Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6C06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Q3 Sample Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6D06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant Manual Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6E06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Shader Manual Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D6F06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaderlist-ta.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7006253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shaderlist.fgl; + refType = 4; + sourceTree = ""; + }; + 18650D7106253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7206253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SOF2 Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7306253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Executable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7406253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STVEF Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7506253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Manual Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7606253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Sample Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7706253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TA Teams Manual.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7806253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Terrain Manual Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7906253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TexTool Help.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7A06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Exectuable Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7B06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Wolf Media Files.fgl"; + refType = 4; + sourceTree = ""; + }; + 18650D7C06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = GtkRadiant.ipr; + refType = 4; + sourceTree = ""; + }; + 18650D7D06253BD9005AB5DA = { + children = ( + 18650D7E06253BD9005AB5DA, + 18650D8D06253BDA005AB5DA, + ); + isa = PBXGroup; + path = Media; + refType = 4; + sourceTree = ""; + }; + 18650D7E06253BD9005AB5DA = { + children = ( + 18650D7F06253BD9005AB5DA, + 18650D8006253BD9005AB5DA, + 18650D8106253BD9005AB5DA, + 18650D8206253BD9005AB5DA, + 18650D8306253BD9005AB5DA, + 18650D8406253BD9005AB5DA, + 18650D8506253BD9005AB5DA, + 18650D8606253BDA005AB5DA, + 18650D8706253BDA005AB5DA, + 18650D8C06253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650D7F06253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650D8006253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650D8106253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650D8206253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650D8306253BD9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650D8406253BD9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650D8506253BD9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650D8606253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650D8706253BDA005AB5DA = { + children = ( + 18650D8806253BDA005AB5DA, + 18650D8906253BDA005AB5DA, + 18650D8A06253BDA005AB5DA, + 18650D8B06253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650D8806253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650D8906253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650D8A06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650D8B06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650D8C06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650D8D06253BDA005AB5DA = { + children = ( + 18650D8E06253BDA005AB5DA, + 18650DA106253BDA005AB5DA, + 18650DA206253BDA005AB5DA, + 18650DC206253BDA005AB5DA, + 18650DD206253BDA005AB5DA, + ); + isa = PBXGroup; + path = GtkRadiant; + refType = 4; + sourceTree = ""; + }; + 18650D8E06253BDA005AB5DA = { + children = ( + 18650D8F06253BDA005AB5DA, + 18650D9006253BDA005AB5DA, + 18650D9106253BDA005AB5DA, + 18650D9206253BDA005AB5DA, + 18650D9306253BDA005AB5DA, + 18650D9506253BDA005AB5DA, + 18650D9706253BDA005AB5DA, + 18650D9806253BDA005AB5DA, + 18650D9A06253BDA005AB5DA, + 18650D9F06253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650D8F06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650D9006253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650D9106253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650D9206253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650D9306253BDA005AB5DA = { + children = ( + 18650D9406253BDA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650D9406253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.mda.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D9506253BDA005AB5DA = { + children = ( + 18650D9606253BDA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650D9606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.mda.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650D9706253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650D9806253BDA005AB5DA = { + children = ( + 18650D9906253BDA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650D9906253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.mda.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650D9A06253BDA005AB5DA = { + children = ( + 18650D9B06253BDA005AB5DA, + 18650D9C06253BDA005AB5DA, + 18650D9D06253BDA005AB5DA, + 18650D9E06253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650D9B06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650D9C06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650D9D06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650D9E06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650D9F06253BDA005AB5DA = { + children = ( + 18650DA006253BDA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DA006253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.mda.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650DA106253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.mda; + refType = 4; + sourceTree = ""; + }; + 18650DA206253BDA005AB5DA = { + children = ( + 18650DA306253BDA005AB5DA, + 18650DB206253BDA005AB5DA, + ); + isa = PBXGroup; + path = "Disk Images"; + refType = 4; + sourceTree = ""; + }; + 18650DA306253BDA005AB5DA = { + children = ( + 18650DA406253BDA005AB5DA, + 18650DA506253BDA005AB5DA, + 18650DA606253BDA005AB5DA, + 18650DA706253BDA005AB5DA, + 18650DA806253BDA005AB5DA, + 18650DA906253BDA005AB5DA, + 18650DAA06253BDA005AB5DA, + 18650DAB06253BDA005AB5DA, + 18650DAC06253BDA005AB5DA, + 18650DB106253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650DA406253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650DA506253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650DA606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650DA706253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650DA806253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DA906253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DAA06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650DAB06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DAC06253BDA005AB5DA = { + children = ( + 18650DAD06253BDA005AB5DA, + 18650DAE06253BDA005AB5DA, + 18650DAF06253BDA005AB5DA, + 18650DB006253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650DAD06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DAE06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DAF06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DB006253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DB106253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DB206253BDA005AB5DA = { + children = ( + 18650DB306253BDA005AB5DA, + ); + isa = PBXGroup; + path = Disk1; + refType = 4; + sourceTree = ""; + }; + 18650DB306253BDA005AB5DA = { + children = ( + 18650DB406253BDA005AB5DA, + 18650DB506253BDA005AB5DA, + 18650DB606253BDA005AB5DA, + 18650DB706253BDA005AB5DA, + 18650DB806253BDA005AB5DA, + 18650DB906253BDA005AB5DA, + 18650DBA06253BDA005AB5DA, + 18650DBB06253BDA005AB5DA, + 18650DBC06253BDA005AB5DA, + 18650DC106253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650DB406253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650DB506253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650DB606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650DB706253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650DB806253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DB906253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DBA06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650DBB06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DBC06253BDA005AB5DA = { + children = ( + 18650DBD06253BDA005AB5DA, + 18650DBE06253BDA005AB5DA, + 18650DBF06253BDA005AB5DA, + 18650DC006253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650DBD06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DBE06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DBF06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DC006253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DC106253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DC206253BDA005AB5DA = { + children = ( + 18650DC306253BDA005AB5DA, + ); + isa = PBXGroup; + path = "Log Files"; + refType = 4; + sourceTree = ""; + }; + 18650DC306253BDA005AB5DA = { + children = ( + 18650DC406253BDA005AB5DA, + 18650DC506253BDA005AB5DA, + 18650DC606253BDA005AB5DA, + 18650DC706253BDA005AB5DA, + 18650DC806253BDA005AB5DA, + 18650DC906253BDA005AB5DA, + 18650DCA06253BDA005AB5DA, + 18650DCB06253BDA005AB5DA, + 18650DCC06253BDA005AB5DA, + 18650DD106253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650DC406253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650DC506253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650DC606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650DC706253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650DC806253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DC906253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DCA06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650DCB06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DCC06253BDA005AB5DA = { + children = ( + 18650DCD06253BDA005AB5DA, + 18650DCE06253BDA005AB5DA, + 18650DCF06253BDA005AB5DA, + 18650DD006253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650DCD06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DCE06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DCF06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DD006253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DD106253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DD206253BDA005AB5DA = { + children = ( + 18650DD306253BDA005AB5DA, + ); + isa = PBXGroup; + path = "Report Files"; + refType = 4; + sourceTree = ""; + }; + 18650DD306253BDA005AB5DA = { + children = ( + 18650DD406253BDA005AB5DA, + 18650DD506253BDA005AB5DA, + 18650DD606253BDA005AB5DA, + 18650DD706253BDA005AB5DA, + 18650DD806253BDA005AB5DA, + 18650DD906253BDA005AB5DA, + 18650DDA06253BDA005AB5DA, + 18650DDB06253BDA005AB5DA, + 18650DDC06253BDA005AB5DA, + 18650DE106253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650DD406253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650DD506253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650DD606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650DD706253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650DD806253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DD906253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DDA06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650DDB06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DDC06253BDA005AB5DA = { + children = ( + 18650DDD06253BDA005AB5DA, + 18650DDE06253BDA005AB5DA, + 18650DDF06253BDA005AB5DA, + 18650DE006253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650DDD06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DDE06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DDF06253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DE006253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DE106253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DE206253BDA005AB5DA = { + children = ( + 18650DE306253BDA005AB5DA, + 18650DF606253BDA005AB5DA, + ); + isa = PBXGroup; + path = "Registry Entries"; + refType = 4; + sourceTree = ""; + }; + 18650DE306253BDA005AB5DA = { + children = ( + 18650DE406253BDA005AB5DA, + 18650DE506253BDA005AB5DA, + 18650DE606253BDA005AB5DA, + 18650DE706253BDA005AB5DA, + 18650DE806253BDA005AB5DA, + 18650DEA06253BDA005AB5DA, + 18650DEC06253BDA005AB5DA, + 18650DED06253BDA005AB5DA, + 18650DEF06253BDA005AB5DA, + 18650DF406253BDA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650DE406253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650DE506253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650DE606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650DE706253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650DE806253BDA005AB5DA = { + children = ( + 18650DE906253BDA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DE906253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.rge.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650DEA06253BDA005AB5DA = { + children = ( + 18650DEB06253BDA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DEB06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.rge.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650DEC06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650DED06253BDA005AB5DA = { + children = ( + 18650DEE06253BDA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DEE06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.rge.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650DEF06253BDA005AB5DA = { + children = ( + 18650DF006253BDA005AB5DA, + 18650DF106253BDA005AB5DA, + 18650DF206253BDA005AB5DA, + 18650DF306253BDA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650DF006253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DF106253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650DF206253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650DF306253BDA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DF406253BDA005AB5DA = { + children = ( + 18650DF506253BDA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650DF506253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.rge.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650DF606253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.rge; + refType = 4; + sourceTree = ""; + }; + 18650DF706253BDA005AB5DA = { + children = ( + 18650DF806253BDA005AB5DA, + 18650E0F06253BDB005AB5DA, + 18650E1006253BDB005AB5DA, + ); + isa = PBXGroup; + path = "Script Files"; + refType = 4; + sourceTree = ""; + }; + 18650DF806253BDA005AB5DA = { + children = ( + 18650DF906253BDA005AB5DA, + 18650DFA06253BDA005AB5DA, + 18650DFB06253BDA005AB5DA, + 18650DFC06253BDA005AB5DA, + 18650DFD06253BDA005AB5DA, + 18650E0006253BDB005AB5DA, + 18650E0306253BDB005AB5DA, + 18650E0406253BDB005AB5DA, + 18650E0706253BDB005AB5DA, + 18650E0C06253BDB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650DF906253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650DFA06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650DFB06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650DFC06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650DFD06253BDA005AB5DA = { + children = ( + 18650DFE06253BDA005AB5DA, + 18650DFF06253BDB005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650DFE06253BDA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650DFF06253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.rul.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E0006253BDB005AB5DA = { + children = ( + 18650E0106253BDB005AB5DA, + 18650E0206253BDB005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E0106253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E0206253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.rul.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E0306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E0406253BDB005AB5DA = { + children = ( + 18650E0506253BDB005AB5DA, + 18650E0606253BDB005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E0506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E0606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.rul.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E0706253BDB005AB5DA = { + children = ( + 18650E0806253BDB005AB5DA, + 18650E0906253BDB005AB5DA, + 18650E0A06253BDB005AB5DA, + 18650E0B06253BDB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E0806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E0906253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E0A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E0B06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E0C06253BDB005AB5DA = { + children = ( + 18650E0D06253BDB005AB5DA, + 18650E0E06253BDB005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E0D06253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E0E06253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.rul.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E0F06253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Setup.map; + refType = 4; + sourceTree = ""; + }; + 18650E1006253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Setup.rul; + refType = 4; + sourceTree = ""; + }; + 18650E1106253BDB005AB5DA = { + children = ( + 18650E1206253BDB005AB5DA, + 18650E2106253BDB005AB5DA, + 18650EA006253BDC005AB5DA, + ); + isa = PBXGroup; + path = "Setup Files"; + refType = 4; + sourceTree = ""; + }; + 18650E1206253BDB005AB5DA = { + children = ( + 18650E1306253BDB005AB5DA, + 18650E1406253BDB005AB5DA, + 18650E1506253BDB005AB5DA, + 18650E1606253BDB005AB5DA, + 18650E1706253BDB005AB5DA, + 18650E1806253BDB005AB5DA, + 18650E1906253BDB005AB5DA, + 18650E1A06253BDB005AB5DA, + 18650E1B06253BDB005AB5DA, + 18650E2006253BDB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E1306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E1406253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E1506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E1606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E1706253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E1806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E1906253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E1A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E1B06253BDB005AB5DA = { + children = ( + 18650E1C06253BDB005AB5DA, + 18650E1D06253BDB005AB5DA, + 18650E1E06253BDB005AB5DA, + 18650E1F06253BDB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E1C06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E1D06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E1E06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E1F06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E2006253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E2106253BDB005AB5DA = { + children = ( + 18650E2206253BDB005AB5DA, + 18650E3106253BDB005AB5DA, + 18650E6106253BDB005AB5DA, + ); + isa = PBXGroup; + path = "Compressed Files"; + refType = 4; + sourceTree = ""; + }; + 18650E2206253BDB005AB5DA = { + children = ( + 18650E2306253BDB005AB5DA, + 18650E2406253BDB005AB5DA, + 18650E2506253BDB005AB5DA, + 18650E2606253BDB005AB5DA, + 18650E2706253BDB005AB5DA, + 18650E2806253BDB005AB5DA, + 18650E2906253BDB005AB5DA, + 18650E2A06253BDB005AB5DA, + 18650E2B06253BDB005AB5DA, + 18650E3006253BDB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E2306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E2406253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E2506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E2606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E2706253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E2806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E2906253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E2A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E2B06253BDB005AB5DA = { + children = ( + 18650E2C06253BDB005AB5DA, + 18650E2D06253BDB005AB5DA, + 18650E2E06253BDB005AB5DA, + 18650E2F06253BDB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E2C06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E2D06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E2E06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E2F06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E3006253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E3106253BDB005AB5DA = { + children = ( + 18650E3206253BDB005AB5DA, + 18650E4106253BDB005AB5DA, + 18650E5106253BDB005AB5DA, + ); + isa = PBXGroup; + path = "0009-English"; + refType = 4; + sourceTree = ""; + }; + 18650E3206253BDB005AB5DA = { + children = ( + 18650E3306253BDB005AB5DA, + 18650E3406253BDB005AB5DA, + 18650E3506253BDB005AB5DA, + 18650E3606253BDB005AB5DA, + 18650E3706253BDB005AB5DA, + 18650E3806253BDB005AB5DA, + 18650E3906253BDB005AB5DA, + 18650E3A06253BDB005AB5DA, + 18650E3B06253BDB005AB5DA, + 18650E4006253BDB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E3306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E3406253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E3506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E3606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E3706253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E3806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E3906253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E3A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E3B06253BDB005AB5DA = { + children = ( + 18650E3C06253BDB005AB5DA, + 18650E3D06253BDB005AB5DA, + 18650E3E06253BDB005AB5DA, + 18650E3F06253BDB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E3C06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E3D06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E3E06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E3F06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E4006253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E4106253BDB005AB5DA = { + children = ( + 18650E4206253BDB005AB5DA, + ); + isa = PBXGroup; + path = "Intel 32"; + refType = 4; + sourceTree = ""; + }; + 18650E4206253BDB005AB5DA = { + children = ( + 18650E4306253BDB005AB5DA, + 18650E4406253BDB005AB5DA, + 18650E4506253BDB005AB5DA, + 18650E4606253BDB005AB5DA, + 18650E4706253BDB005AB5DA, + 18650E4806253BDB005AB5DA, + 18650E4906253BDB005AB5DA, + 18650E4A06253BDB005AB5DA, + 18650E4B06253BDB005AB5DA, + 18650E5006253BDB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E4306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E4406253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E4506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E4606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E4706253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E4806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E4906253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E4A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E4B06253BDB005AB5DA = { + children = ( + 18650E4C06253BDB005AB5DA, + 18650E4D06253BDB005AB5DA, + 18650E4E06253BDB005AB5DA, + 18650E4F06253BDB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E4C06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E4D06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E4E06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E4F06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E5006253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E5106253BDB005AB5DA = { + children = ( + 18650E5206253BDB005AB5DA, + ); + isa = PBXGroup; + path = "OS Independent"; + refType = 4; + sourceTree = ""; + }; + 18650E5206253BDB005AB5DA = { + children = ( + 18650E5306253BDB005AB5DA, + 18650E5406253BDB005AB5DA, + 18650E5506253BDB005AB5DA, + 18650E5606253BDB005AB5DA, + 18650E5706253BDB005AB5DA, + 18650E5806253BDB005AB5DA, + 18650E5906253BDB005AB5DA, + 18650E5A06253BDB005AB5DA, + 18650E5B06253BDB005AB5DA, + 18650E6006253BDB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E5306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E5406253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E5506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E5606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E5706253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E5806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E5906253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E5A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E5B06253BDB005AB5DA = { + children = ( + 18650E5C06253BDB005AB5DA, + 18650E5D06253BDB005AB5DA, + 18650E5E06253BDB005AB5DA, + 18650E5F06253BDB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E5C06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E5D06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E5E06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E5F06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E6006253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E6106253BDB005AB5DA = { + children = ( + 18650E6206253BDB005AB5DA, + 18650E7106253BDC005AB5DA, + 18650E8106253BDC005AB5DA, + ); + isa = PBXGroup; + path = "Language Independent"; + refType = 4; + sourceTree = ""; + }; + 18650E6206253BDB005AB5DA = { + children = ( + 18650E6306253BDB005AB5DA, + 18650E6406253BDB005AB5DA, + 18650E6506253BDB005AB5DA, + 18650E6606253BDB005AB5DA, + 18650E6706253BDB005AB5DA, + 18650E6806253BDB005AB5DA, + 18650E6906253BDB005AB5DA, + 18650E6A06253BDB005AB5DA, + 18650E6B06253BDC005AB5DA, + 18650E7006253BDC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E6306253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E6406253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E6506253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E6606253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E6706253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E6806253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E6906253BDB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E6A06253BDB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E6B06253BDC005AB5DA = { + children = ( + 18650E6C06253BDC005AB5DA, + 18650E6D06253BDC005AB5DA, + 18650E6E06253BDC005AB5DA, + 18650E6F06253BDC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E6C06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E6D06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E6E06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E6F06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E7006253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E7106253BDC005AB5DA = { + children = ( + 18650E7206253BDC005AB5DA, + ); + isa = PBXGroup; + path = "Intel 32"; + refType = 4; + sourceTree = ""; + }; + 18650E7206253BDC005AB5DA = { + children = ( + 18650E7306253BDC005AB5DA, + 18650E7406253BDC005AB5DA, + 18650E7506253BDC005AB5DA, + 18650E7606253BDC005AB5DA, + 18650E7706253BDC005AB5DA, + 18650E7806253BDC005AB5DA, + 18650E7906253BDC005AB5DA, + 18650E7A06253BDC005AB5DA, + 18650E7B06253BDC005AB5DA, + 18650E8006253BDC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E7306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E7406253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E7506253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E7606253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E7706253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E7806253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E7906253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E7A06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E7B06253BDC005AB5DA = { + children = ( + 18650E7C06253BDC005AB5DA, + 18650E7D06253BDC005AB5DA, + 18650E7E06253BDC005AB5DA, + 18650E7F06253BDC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E7C06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E7D06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E7E06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E7F06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E8006253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E8106253BDC005AB5DA = { + children = ( + 18650E8206253BDC005AB5DA, + 18650E9D06253BDC005AB5DA, + 18650E9E06253BDC005AB5DA, + 18650E9F06253BDC005AB5DA, + ); + isa = PBXGroup; + path = "OS Independent"; + refType = 4; + sourceTree = ""; + }; + 18650E8206253BDC005AB5DA = { + children = ( + 18650E8306253BDC005AB5DA, + 18650E8406253BDC005AB5DA, + 18650E8506253BDC005AB5DA, + 18650E8606253BDC005AB5DA, + 18650E8706253BDC005AB5DA, + 18650E8B06253BDC005AB5DA, + 18650E8F06253BDC005AB5DA, + 18650E9006253BDC005AB5DA, + 18650E9406253BDC005AB5DA, + 18650E9906253BDC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650E8306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650E8406253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650E8506253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650E8606253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650E8706253BDC005AB5DA = { + children = ( + 18650E8806253BDC005AB5DA, + 18650E8906253BDC005AB5DA, + 18650E8A06253BDC005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E8806253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "_IsUser.dll.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E8906253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "infolist.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E8A06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E8B06253BDC005AB5DA = { + children = ( + 18650E8C06253BDC005AB5DA, + 18650E8D06253BDC005AB5DA, + 18650E8E06253BDC005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E8C06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "_IsUser.dll.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E8D06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "infolist.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E8E06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E8F06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650E9006253BDC005AB5DA = { + children = ( + 18650E9106253BDC005AB5DA, + 18650E9206253BDC005AB5DA, + 18650E9306253BDC005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E9106253BDC005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "_IsUser.dll.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E9206253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "infolist.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E9306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650E9406253BDC005AB5DA = { + children = ( + 18650E9506253BDC005AB5DA, + 18650E9606253BDC005AB5DA, + 18650E9706253BDC005AB5DA, + 18650E9806253BDC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650E9506253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650E9606253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650E9706253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650E9806253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E9906253BDC005AB5DA = { + children = ( + 18650E9A06253BDC005AB5DA, + 18650E9B06253BDC005AB5DA, + 18650E9C06253BDC005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650E9A06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "_IsUser.dll.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E9B06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "infolist.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E9C06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "license.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650E9D06253BDC005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = _IsUser.dll; + refType = 4; + sourceTree = ""; + }; + 18650E9E06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = infolist.txt; + refType = 4; + sourceTree = ""; + }; + 18650E9F06253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = license.txt; + refType = 4; + sourceTree = ""; + }; + 18650EA006253BDC005AB5DA = { + children = ( + 18650EA106253BDC005AB5DA, + 18650EB006253BDC005AB5DA, + 18650EE006253BDD005AB5DA, + 18650EF006253BDD005AB5DA, + 18650F2006253BDE005AB5DA, + 18650F3006253BDE005AB5DA, + ); + isa = PBXGroup; + path = "Uncompressed Files"; + refType = 4; + sourceTree = ""; + }; + 18650EA106253BDC005AB5DA = { + children = ( + 18650EA206253BDC005AB5DA, + 18650EA306253BDC005AB5DA, + 18650EA406253BDC005AB5DA, + 18650EA506253BDC005AB5DA, + 18650EA606253BDC005AB5DA, + 18650EA706253BDC005AB5DA, + 18650EA806253BDC005AB5DA, + 18650EA906253BDC005AB5DA, + 18650EAA06253BDC005AB5DA, + 18650EAF06253BDC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650EA206253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650EA306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650EA406253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650EA506253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650EA606253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EA706253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EA806253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650EA906253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EAA06253BDC005AB5DA = { + children = ( + 18650EAB06253BDC005AB5DA, + 18650EAC06253BDC005AB5DA, + 18650EAD06253BDC005AB5DA, + 18650EAE06253BDC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650EAB06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EAC06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EAD06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EAE06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EAF06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EB006253BDC005AB5DA = { + children = ( + 18650EB106253BDC005AB5DA, + 18650EC006253BDC005AB5DA, + 18650ED006253BDC005AB5DA, + ); + isa = PBXGroup; + path = "0009-English"; + refType = 4; + sourceTree = ""; + }; + 18650EB106253BDC005AB5DA = { + children = ( + 18650EB206253BDC005AB5DA, + 18650EB306253BDC005AB5DA, + 18650EB406253BDC005AB5DA, + 18650EB506253BDC005AB5DA, + 18650EB606253BDC005AB5DA, + 18650EB706253BDC005AB5DA, + 18650EB806253BDC005AB5DA, + 18650EB906253BDC005AB5DA, + 18650EBA06253BDC005AB5DA, + 18650EBF06253BDC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650EB206253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650EB306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650EB406253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650EB506253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650EB606253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EB706253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EB806253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650EB906253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EBA06253BDC005AB5DA = { + children = ( + 18650EBB06253BDC005AB5DA, + 18650EBC06253BDC005AB5DA, + 18650EBD06253BDC005AB5DA, + 18650EBE06253BDC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650EBB06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EBC06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EBD06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EBE06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EBF06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EC006253BDC005AB5DA = { + children = ( + 18650EC106253BDC005AB5DA, + ); + isa = PBXGroup; + path = "Intel 32"; + refType = 4; + sourceTree = ""; + }; + 18650EC106253BDC005AB5DA = { + children = ( + 18650EC206253BDC005AB5DA, + 18650EC306253BDC005AB5DA, + 18650EC406253BDC005AB5DA, + 18650EC506253BDC005AB5DA, + 18650EC606253BDC005AB5DA, + 18650EC706253BDC005AB5DA, + 18650EC806253BDC005AB5DA, + 18650EC906253BDC005AB5DA, + 18650ECA06253BDC005AB5DA, + 18650ECF06253BDC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650EC206253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650EC306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650EC406253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650EC506253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650EC606253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EC706253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EC806253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650EC906253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650ECA06253BDC005AB5DA = { + children = ( + 18650ECB06253BDC005AB5DA, + 18650ECC06253BDC005AB5DA, + 18650ECD06253BDC005AB5DA, + 18650ECE06253BDC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650ECB06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650ECC06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650ECD06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650ECE06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650ECF06253BDC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650ED006253BDC005AB5DA = { + children = ( + 18650ED106253BDC005AB5DA, + ); + isa = PBXGroup; + path = "OS Independent"; + refType = 4; + sourceTree = ""; + }; + 18650ED106253BDC005AB5DA = { + children = ( + 18650ED206253BDC005AB5DA, + 18650ED306253BDC005AB5DA, + 18650ED406253BDC005AB5DA, + 18650ED506253BDD005AB5DA, + 18650ED606253BDD005AB5DA, + 18650ED706253BDD005AB5DA, + 18650ED806253BDD005AB5DA, + 18650ED906253BDD005AB5DA, + 18650EDA06253BDD005AB5DA, + 18650EDF06253BDD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650ED206253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650ED306253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650ED406253BDC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650ED506253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650ED606253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650ED706253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650ED806253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650ED906253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EDA06253BDD005AB5DA = { + children = ( + 18650EDB06253BDD005AB5DA, + 18650EDC06253BDD005AB5DA, + 18650EDD06253BDD005AB5DA, + 18650EDE06253BDD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650EDB06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EDC06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EDD06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EDE06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EDF06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EE006253BDD005AB5DA = { + children = ( + 18650EE106253BDD005AB5DA, + ); + isa = PBXGroup; + path = Disk1; + refType = 4; + sourceTree = ""; + }; + 18650EE106253BDD005AB5DA = { + children = ( + 18650EE206253BDD005AB5DA, + 18650EE306253BDD005AB5DA, + 18650EE406253BDD005AB5DA, + 18650EE506253BDD005AB5DA, + 18650EE606253BDD005AB5DA, + 18650EE706253BDD005AB5DA, + 18650EE806253BDD005AB5DA, + 18650EE906253BDD005AB5DA, + 18650EEA06253BDD005AB5DA, + 18650EEF06253BDD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650EE206253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650EE306253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650EE406253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650EE506253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650EE606253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EE706253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EE806253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650EE906253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EEA06253BDD005AB5DA = { + children = ( + 18650EEB06253BDD005AB5DA, + 18650EEC06253BDD005AB5DA, + 18650EED06253BDD005AB5DA, + 18650EEE06253BDD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650EEB06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EEC06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EED06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EEE06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EEF06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EF006253BDD005AB5DA = { + children = ( + 18650EF106253BDD005AB5DA, + 18650F0006253BDD005AB5DA, + 18650F1006253BDD005AB5DA, + ); + isa = PBXGroup; + path = "Language Independent"; + refType = 4; + sourceTree = ""; + }; + 18650EF106253BDD005AB5DA = { + children = ( + 18650EF206253BDD005AB5DA, + 18650EF306253BDD005AB5DA, + 18650EF406253BDD005AB5DA, + 18650EF506253BDD005AB5DA, + 18650EF606253BDD005AB5DA, + 18650EF706253BDD005AB5DA, + 18650EF806253BDD005AB5DA, + 18650EF906253BDD005AB5DA, + 18650EFA06253BDD005AB5DA, + 18650EFF06253BDD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650EF206253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650EF306253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650EF406253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650EF506253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650EF606253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EF706253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EF806253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650EF906253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EFA06253BDD005AB5DA = { + children = ( + 18650EFB06253BDD005AB5DA, + 18650EFC06253BDD005AB5DA, + 18650EFD06253BDD005AB5DA, + 18650EFE06253BDD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650EFB06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650EFC06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650EFD06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650EFE06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650EFF06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F0006253BDD005AB5DA = { + children = ( + 18650F0106253BDD005AB5DA, + ); + isa = PBXGroup; + path = "Intel 32"; + refType = 4; + sourceTree = ""; + }; + 18650F0106253BDD005AB5DA = { + children = ( + 18650F0206253BDD005AB5DA, + 18650F0306253BDD005AB5DA, + 18650F0406253BDD005AB5DA, + 18650F0506253BDD005AB5DA, + 18650F0606253BDD005AB5DA, + 18650F0706253BDD005AB5DA, + 18650F0806253BDD005AB5DA, + 18650F0906253BDD005AB5DA, + 18650F0A06253BDD005AB5DA, + 18650F0F06253BDD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F0206253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F0306253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F0406253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F0506253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F0606253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F0706253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F0806253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F0906253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F0A06253BDD005AB5DA = { + children = ( + 18650F0B06253BDD005AB5DA, + 18650F0C06253BDD005AB5DA, + 18650F0D06253BDD005AB5DA, + 18650F0E06253BDD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F0B06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F0C06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F0D06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F0E06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F0F06253BDD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F1006253BDD005AB5DA = { + children = ( + 18650F1106253BDD005AB5DA, + ); + isa = PBXGroup; + path = "OS Independent"; + refType = 4; + sourceTree = ""; + }; + 18650F1106253BDD005AB5DA = { + children = ( + 18650F1206253BDD005AB5DA, + 18650F1306253BDE005AB5DA, + 18650F1406253BDE005AB5DA, + 18650F1506253BDE005AB5DA, + 18650F1606253BDE005AB5DA, + 18650F1706253BDE005AB5DA, + 18650F1806253BDE005AB5DA, + 18650F1906253BDE005AB5DA, + 18650F1A06253BDE005AB5DA, + 18650F1F06253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F1206253BDD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F1306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F1406253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F1506253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F1606253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F1706253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F1806253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F1906253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F1A06253BDE005AB5DA = { + children = ( + 18650F1B06253BDE005AB5DA, + 18650F1C06253BDE005AB5DA, + 18650F1D06253BDE005AB5DA, + 18650F1E06253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F1B06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F1C06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F1D06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F1E06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F1F06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F2006253BDE005AB5DA = { + children = ( + 18650F2106253BDE005AB5DA, + ); + isa = PBXGroup; + path = LastDisk; + refType = 4; + sourceTree = ""; + }; + 18650F2106253BDE005AB5DA = { + children = ( + 18650F2206253BDE005AB5DA, + 18650F2306253BDE005AB5DA, + 18650F2406253BDE005AB5DA, + 18650F2506253BDE005AB5DA, + 18650F2606253BDE005AB5DA, + 18650F2706253BDE005AB5DA, + 18650F2806253BDE005AB5DA, + 18650F2906253BDE005AB5DA, + 18650F2A06253BDE005AB5DA, + 18650F2F06253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F2206253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F2306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F2406253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F2506253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F2606253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F2706253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F2806253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F2906253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F2A06253BDE005AB5DA = { + children = ( + 18650F2B06253BDE005AB5DA, + 18650F2C06253BDE005AB5DA, + 18650F2D06253BDE005AB5DA, + 18650F2E06253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F2B06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F2C06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F2D06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F2E06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F2F06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F3006253BDE005AB5DA = { + children = ( + 18650F3106253BDE005AB5DA, + ); + isa = PBXGroup; + path = Other; + refType = 4; + sourceTree = ""; + }; + 18650F3106253BDE005AB5DA = { + children = ( + 18650F3206253BDE005AB5DA, + 18650F3306253BDE005AB5DA, + 18650F3406253BDE005AB5DA, + 18650F3506253BDE005AB5DA, + 18650F3606253BDE005AB5DA, + 18650F3706253BDE005AB5DA, + 18650F3806253BDE005AB5DA, + 18650F3906253BDE005AB5DA, + 18650F3A06253BDE005AB5DA, + 18650F3F06253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F3206253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F3306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F3406253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F3506253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F3606253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F3706253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F3806253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F3906253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F3A06253BDE005AB5DA = { + children = ( + 18650F3B06253BDE005AB5DA, + 18650F3C06253BDE005AB5DA, + 18650F3D06253BDE005AB5DA, + 18650F3E06253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F3B06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F3C06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F3D06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F3E06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F3F06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F4006253BDE005AB5DA = { + children = ( + 18650F4106253BDE005AB5DA, + 18650F5406253BDE005AB5DA, + ); + isa = PBXGroup; + path = "Shell Objects"; + refType = 4; + sourceTree = ""; + }; + 18650F4106253BDE005AB5DA = { + children = ( + 18650F4206253BDE005AB5DA, + 18650F4306253BDE005AB5DA, + 18650F4406253BDE005AB5DA, + 18650F4506253BDE005AB5DA, + 18650F4606253BDE005AB5DA, + 18650F4806253BDE005AB5DA, + 18650F4A06253BDE005AB5DA, + 18650F4B06253BDE005AB5DA, + 18650F4D06253BDE005AB5DA, + 18650F5206253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F4206253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F4306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F4406253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F4506253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F4606253BDE005AB5DA = { + children = ( + 18650F4706253BDE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F4706253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F4806253BDE005AB5DA = { + children = ( + 18650F4906253BDE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F4906253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F4A06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F4B06253BDE005AB5DA = { + children = ( + 18650F4C06253BDE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F4C06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F4D06253BDE005AB5DA = { + children = ( + 18650F4E06253BDE005AB5DA, + 18650F4F06253BDE005AB5DA, + 18650F5006253BDE005AB5DA, + 18650F5106253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F4E06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F4F06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F5006253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F5106253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F5206253BDE005AB5DA = { + children = ( + 18650F5306253BDE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F5306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F5406253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.shl; + refType = 4; + sourceTree = ""; + }; + 18650F5506253BDE005AB5DA = { + children = ( + 18650F5606253BDE005AB5DA, + 18650F6906253BDE005AB5DA, + 18650F7E06253BDE005AB5DA, + ); + isa = PBXGroup; + path = "String Tables"; + refType = 4; + sourceTree = ""; + }; + 18650F5606253BDE005AB5DA = { + children = ( + 18650F5706253BDE005AB5DA, + 18650F5806253BDE005AB5DA, + 18650F5906253BDE005AB5DA, + 18650F5A06253BDE005AB5DA, + 18650F5B06253BDE005AB5DA, + 18650F5D06253BDE005AB5DA, + 18650F5F06253BDE005AB5DA, + 18650F6006253BDE005AB5DA, + 18650F6206253BDE005AB5DA, + 18650F6706253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F5706253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F5806253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F5906253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F5A06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F5B06253BDE005AB5DA = { + children = ( + 18650F5C06253BDE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F5C06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F5D06253BDE005AB5DA = { + children = ( + 18650F5E06253BDE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F5E06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F5F06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F6006253BDE005AB5DA = { + children = ( + 18650F6106253BDE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F6106253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F6206253BDE005AB5DA = { + children = ( + 18650F6306253BDE005AB5DA, + 18650F6406253BDE005AB5DA, + 18650F6506253BDE005AB5DA, + 18650F6606253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F6306253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F6406253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F6506253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F6606253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F6706253BDE005AB5DA = { + children = ( + 18650F6806253BDE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F6806253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Default.shl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F6906253BDE005AB5DA = { + children = ( + 18650F6A06253BDE005AB5DA, + 18650F7D06253BDE005AB5DA, + ); + isa = PBXGroup; + path = "0009-English"; + refType = 4; + sourceTree = ""; + }; + 18650F6A06253BDE005AB5DA = { + children = ( + 18650F6B06253BDE005AB5DA, + 18650F6C06253BDE005AB5DA, + 18650F6D06253BDE005AB5DA, + 18650F6E06253BDE005AB5DA, + 18650F6F06253BDE005AB5DA, + 18650F7106253BDE005AB5DA, + 18650F7306253BDE005AB5DA, + 18650F7406253BDE005AB5DA, + 18650F7606253BDE005AB5DA, + 18650F7B06253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F6B06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F6C06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F6D06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F6E06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F6F06253BDE005AB5DA = { + children = ( + 18650F7006253BDE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F7006253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "value.shl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F7106253BDE005AB5DA = { + children = ( + 18650F7206253BDE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F7206253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "value.shl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F7306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F7406253BDE005AB5DA = { + children = ( + 18650F7506253BDE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F7506253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "value.shl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F7606253BDE005AB5DA = { + children = ( + 18650F7706253BDE005AB5DA, + 18650F7806253BDE005AB5DA, + 18650F7906253BDE005AB5DA, + 18650F7A06253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F7706253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F7806253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F7906253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F7A06253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F7B06253BDE005AB5DA = { + children = ( + 18650F7C06253BDE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F7C06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "value.shl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F7D06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = value.shl; + refType = 4; + sourceTree = ""; + }; + 18650F7E06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Default.shl; + refType = 4; + sourceTree = ""; + }; + 18650F7F06253BDE005AB5DA = { + children = ( + 18650F8006253BDE005AB5DA, + 18650F9706253BDE005AB5DA, + 18650F9806253BDE005AB5DA, + ); + isa = PBXGroup; + path = "Text Substitutions"; + refType = 4; + sourceTree = ""; + }; + 18650F8006253BDE005AB5DA = { + children = ( + 18650F8106253BDE005AB5DA, + 18650F8206253BDE005AB5DA, + 18650F8306253BDE005AB5DA, + 18650F8406253BDE005AB5DA, + 18650F8506253BDE005AB5DA, + 18650F8806253BDE005AB5DA, + 18650F8B06253BDE005AB5DA, + 18650F8C06253BDE005AB5DA, + 18650F8F06253BDE005AB5DA, + 18650F9406253BDE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F8106253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F8206253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650F8306253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650F8406253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650F8506253BDE005AB5DA = { + children = ( + 18650F8606253BDE005AB5DA, + 18650F8706253BDE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F8606253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Build.tsb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F8706253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.tsb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F8806253BDE005AB5DA = { + children = ( + 18650F8906253BDE005AB5DA, + 18650F8A06253BDE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F8906253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Build.tsb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F8A06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.tsb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F8B06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650F8C06253BDE005AB5DA = { + children = ( + 18650F8D06253BDE005AB5DA, + 18650F8E06253BDE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F8D06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Build.tsb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F8E06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.tsb.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650F8F06253BDE005AB5DA = { + children = ( + 18650F9006253BDE005AB5DA, + 18650F9106253BDE005AB5DA, + 18650F9206253BDE005AB5DA, + 18650F9306253BDE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650F9006253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650F9106253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650F9206253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650F9306253BDE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F9406253BDE005AB5DA = { + children = ( + 18650F9506253BDE005AB5DA, + 18650F9606253BDE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650F9506253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Build.tsb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F9606253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Setup.tsb.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650F9706253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Build.tsb; + refType = 4; + sourceTree = ""; + }; + 18650F9806253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Setup.tsb; + refType = 4; + sourceTree = ""; + }; + 18650F9906253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TODO; + refType = 4; + sourceTree = ""; + }; + 18650F9A06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = wolf.cf; + refType = 4; + sourceTree = ""; + }; + 18650F9B06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = site.conf; + refType = 4; + sourceTree = ""; + }; + 18650F9C06253BDE005AB5DA = { + children = ( + 18650F9D06253BDE005AB5DA, + 18650FAC06253BDF005AB5DA, + 1865129206253BE7005AB5DA, + ); + isa = PBXGroup; + path = tools; + refType = 4; + sourceTree = ""; + }; + 18650F9D06253BDE005AB5DA = { + children = ( + 18650F9E06253BDE005AB5DA, + 18650F9F06253BDE005AB5DA, + 18650FA006253BDE005AB5DA, + 18650FA106253BDE005AB5DA, + 18650FA206253BDF005AB5DA, + 18650FA306253BDF005AB5DA, + 18650FA406253BDF005AB5DA, + 18650FA506253BDF005AB5DA, + 18650FA606253BDF005AB5DA, + 18650FAB06253BDF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650F9E06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650F9F06253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650FA006253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650FA106253BDE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650FA206253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650FA306253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650FA406253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650FA506253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650FA606253BDF005AB5DA = { + children = ( + 18650FA706253BDF005AB5DA, + 18650FA806253BDF005AB5DA, + 18650FA906253BDF005AB5DA, + 18650FAA06253BDF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650FA706253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650FA806253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650FA906253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650FAA06253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650FAB06253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650FAC06253BDF005AB5DA = { + children = ( + 18650FAD06253BDF005AB5DA, + 18650FBC06253BDF005AB5DA, + 1865103F06253BE1005AB5DA, + 186510D106253BE3005AB5DA, + 1865111306253BE3005AB5DA, + ); + isa = PBXGroup; + path = quake2; + refType = 4; + sourceTree = ""; + }; + 18650FAD06253BDF005AB5DA = { + children = ( + 18650FAE06253BDF005AB5DA, + 18650FAF06253BDF005AB5DA, + 18650FB006253BDF005AB5DA, + 18650FB106253BDF005AB5DA, + 18650FB206253BDF005AB5DA, + 18650FB306253BDF005AB5DA, + 18650FB406253BDF005AB5DA, + 18650FB506253BDF005AB5DA, + 18650FB606253BDF005AB5DA, + 18650FBB06253BDF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650FAE06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650FAF06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650FB006253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650FB106253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650FB206253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650FB306253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650FB406253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650FB506253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650FB606253BDF005AB5DA = { + children = ( + 18650FB706253BDF005AB5DA, + 18650FB806253BDF005AB5DA, + 18650FB906253BDF005AB5DA, + 18650FBA06253BDF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 18650FB706253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650FB806253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650FB906253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650FBA06253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650FBB06253BDF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 18650FBC06253BDF005AB5DA = { + children = ( + 18650FBD06253BDF005AB5DA, + 1865102806253BE1005AB5DA, + 1865102906253BE1005AB5DA, + 1865102A06253BE1005AB5DA, + 1865102B06253BE1005AB5DA, + 1865102C06253BE1005AB5DA, + 1865102D06253BE1005AB5DA, + 1865102E06253BE1005AB5DA, + 1865102F06253BE1005AB5DA, + 1865103006253BE1005AB5DA, + 1865103106253BE1005AB5DA, + 1865103206253BE1005AB5DA, + 1865103306253BE1005AB5DA, + 1865103406253BE1005AB5DA, + 1865103506253BE1005AB5DA, + 1865103606253BE1005AB5DA, + 1865103706253BE1005AB5DA, + 1865103806253BE1005AB5DA, + 1865103906253BE1005AB5DA, + 1865103A06253BE1005AB5DA, + 1865103B06253BE1005AB5DA, + 1865103C06253BE1005AB5DA, + 1865103D06253BE1005AB5DA, + 1865103E06253BE1005AB5DA, + ); + isa = PBXGroup; + path = common; + refType = 4; + sourceTree = ""; + }; + 18650FBD06253BDF005AB5DA = { + children = ( + 18650FBE06253BDF005AB5DA, + 18650FBF06253BDF005AB5DA, + 18650FC006253BDF005AB5DA, + 18650FC106253BDF005AB5DA, + 18650FC206253BDF005AB5DA, + 18650FDA06253BDF005AB5DA, + 18650FF206253BE0005AB5DA, + 18650FF306253BE0005AB5DA, + 1865100B06253BE0005AB5DA, + 1865101006253BE0005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 18650FBE06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 18650FBF06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 18650FC006253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 18650FC106253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 18650FC206253BDF005AB5DA = { + children = ( + 18650FC306253BDF005AB5DA, + 18650FC406253BDF005AB5DA, + 18650FC506253BDF005AB5DA, + 18650FC606253BDF005AB5DA, + 18650FC706253BDF005AB5DA, + 18650FC806253BDF005AB5DA, + 18650FC906253BDF005AB5DA, + 18650FCA06253BDF005AB5DA, + 18650FCB06253BDF005AB5DA, + 18650FCC06253BDF005AB5DA, + 18650FCD06253BDF005AB5DA, + 18650FCE06253BDF005AB5DA, + 18650FCF06253BDF005AB5DA, + 18650FD006253BDF005AB5DA, + 18650FD106253BDF005AB5DA, + 18650FD206253BDF005AB5DA, + 18650FD306253BDF005AB5DA, + 18650FD406253BDF005AB5DA, + 18650FD506253BDF005AB5DA, + 18650FD606253BDF005AB5DA, + 18650FD706253BDF005AB5DA, + 18650FD806253BDF005AB5DA, + 18650FD906253BDF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC306253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC406253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC506253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC606253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC706253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC806253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FC906253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FCA06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FCB06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FCC06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FCD06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FCE06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FCF06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD006253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD106253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD206253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD306253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_threads.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD406253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD506253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD606253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD706253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD806253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FD906253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FDA06253BDF005AB5DA = { + children = ( + 18650FDB06253BDF005AB5DA, + 18650FDC06253BDF005AB5DA, + 18650FDD06253BE0005AB5DA, + 18650FDE06253BE0005AB5DA, + 18650FDF06253BE0005AB5DA, + 18650FE006253BE0005AB5DA, + 18650FE106253BE0005AB5DA, + 18650FE206253BE0005AB5DA, + 18650FE306253BE0005AB5DA, + 18650FE406253BE0005AB5DA, + 18650FE506253BE0005AB5DA, + 18650FE606253BE0005AB5DA, + 18650FE706253BE0005AB5DA, + 18650FE806253BE0005AB5DA, + 18650FE906253BE0005AB5DA, + 18650FEA06253BE0005AB5DA, + 18650FEB06253BE0005AB5DA, + 18650FEC06253BE0005AB5DA, + 18650FED06253BE0005AB5DA, + 18650FEE06253BE0005AB5DA, + 18650FEF06253BE0005AB5DA, + 18650FF006253BE0005AB5DA, + 18650FF106253BE0005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 18650FDB06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FDC06253BDF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FDD06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FDE06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FDF06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE006253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE106253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE206253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE306253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE406253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE506253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE606253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE706253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE806253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FE906253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FEA06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FEB06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_threads.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FEC06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FED06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FEE06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FEF06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FF006253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FF106253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 18650FF206253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 18650FF306253BE0005AB5DA = { + children = ( + 18650FF406253BE0005AB5DA, + 18650FF506253BE0005AB5DA, + 18650FF606253BE0005AB5DA, + 18650FF706253BE0005AB5DA, + 18650FF806253BE0005AB5DA, + 18650FF906253BE0005AB5DA, + 18650FFA06253BE0005AB5DA, + 18650FFB06253BE0005AB5DA, + 18650FFC06253BE0005AB5DA, + 18650FFD06253BE0005AB5DA, + 18650FFE06253BE0005AB5DA, + 18650FFF06253BE0005AB5DA, + 1865100006253BE0005AB5DA, + 1865100106253BE0005AB5DA, + 1865100206253BE0005AB5DA, + 1865100306253BE0005AB5DA, + 1865100406253BE0005AB5DA, + 1865100506253BE0005AB5DA, + 1865100606253BE0005AB5DA, + 1865100706253BE0005AB5DA, + 1865100806253BE0005AB5DA, + 1865100906253BE0005AB5DA, + 1865100A06253BE0005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 18650FF406253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FF506253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FF606253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FF706253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FF806253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FF906253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FFA06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FFB06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FFC06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FFD06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FFE06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 18650FFF06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100006253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100106253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100206253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100306253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100406253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_threads.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100506253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100606253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100706253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100806253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100906253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100A06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865100B06253BE0005AB5DA = { + children = ( + 1865100C06253BE0005AB5DA, + 1865100D06253BE0005AB5DA, + 1865100E06253BE0005AB5DA, + 1865100F06253BE0005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865100C06253BE0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865100D06253BE0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865100E06253BE0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865100F06253BE0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865101006253BE0005AB5DA = { + children = ( + 1865101106253BE0005AB5DA, + 1865101206253BE0005AB5DA, + 1865101306253BE0005AB5DA, + 1865101406253BE0005AB5DA, + 1865101506253BE0005AB5DA, + 1865101606253BE0005AB5DA, + 1865101706253BE0005AB5DA, + 1865101806253BE0005AB5DA, + 1865101906253BE0005AB5DA, + 1865101A06253BE0005AB5DA, + 1865101B06253BE0005AB5DA, + 1865101C06253BE0005AB5DA, + 1865101D06253BE0005AB5DA, + 1865101E06253BE0005AB5DA, + 1865101F06253BE0005AB5DA, + 1865102006253BE0005AB5DA, + 1865102106253BE0005AB5DA, + 1865102206253BE0005AB5DA, + 1865102306253BE0005AB5DA, + 1865102406253BE0005AB5DA, + 1865102506253BE0005AB5DA, + 1865102606253BE1005AB5DA, + 1865102706253BE1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865101106253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101206253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101306253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101406253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101506253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101606253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101706253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101806253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101906253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101A06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101B06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101C06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101D06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101E06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865101F06253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102006253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102106253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_threads.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102206253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102306253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102406253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102506253BE0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102606253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102706253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865102806253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bspfile.c; + refType = 4; + sourceTree = ""; + }; + 1865102906253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bspfile.h; + refType = 4; + sourceTree = ""; + }; + 1865102A06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = cmdlib.c; + refType = 4; + sourceTree = ""; + }; + 1865102B06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = cmdlib.h; + refType = 4; + sourceTree = ""; + }; + 1865102C06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = inout.c; + refType = 4; + sourceTree = ""; + }; + 1865102D06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = inout.h; + refType = 4; + sourceTree = ""; + }; + 1865102E06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = l3dslib.c; + refType = 4; + sourceTree = ""; + }; + 1865102F06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = l3dslib.h; + refType = 4; + sourceTree = ""; + }; + 1865103006253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lbmlib.c; + refType = 4; + sourceTree = ""; + }; + 1865103106253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = lbmlib.h; + refType = 4; + sourceTree = ""; + }; + 1865103206253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = mathlib.c; + refType = 4; + sourceTree = ""; + }; + 1865103306253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = mathlib.h; + refType = 4; + sourceTree = ""; + }; + 1865103406253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = md4.c; + refType = 4; + sourceTree = ""; + }; + 1865103506253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = path_init.c; + refType = 4; + sourceTree = ""; + }; + 1865103606253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = polylib.c; + refType = 4; + sourceTree = ""; + }; + 1865103706253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = polylib.h; + refType = 4; + sourceTree = ""; + }; + 1865103806253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q2_threads.h; + refType = 4; + sourceTree = ""; + }; + 1865103906253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qfiles.h; + refType = 4; + sourceTree = ""; + }; + 1865103A06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = scriplib.c; + refType = 4; + sourceTree = ""; + }; + 1865103B06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = scriplib.h; + refType = 4; + sourceTree = ""; + }; + 1865103C06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = threads.c; + refType = 4; + sourceTree = ""; + }; + 1865103D06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = trilib.c; + refType = 4; + sourceTree = ""; + }; + 1865103E06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = trilib.h; + refType = 4; + sourceTree = ""; + }; + 1865103F06253BE1005AB5DA = { + children = ( + 1865104006253BE1005AB5DA, + 186510B706253BE3005AB5DA, + 186510B806253BE3005AB5DA, + 186510B906253BE3005AB5DA, + 186510BA06253BE3005AB5DA, + 186510BB06253BE3005AB5DA, + 186510BC06253BE3005AB5DA, + 186510BD06253BE3005AB5DA, + 186510BE06253BE3005AB5DA, + 186510BF06253BE3005AB5DA, + 186510C006253BE3005AB5DA, + 186510C106253BE3005AB5DA, + 186510C206253BE3005AB5DA, + 186510C306253BE3005AB5DA, + 186510C406253BE3005AB5DA, + 186510C506253BE3005AB5DA, + 186510C606253BE3005AB5DA, + 186510C706253BE3005AB5DA, + 186510C806253BE3005AB5DA, + 186510C906253BE3005AB5DA, + 186510CA06253BE3005AB5DA, + 186510CB06253BE3005AB5DA, + 186510CC06253BE3005AB5DA, + 186510CD06253BE3005AB5DA, + 186510CE06253BE3005AB5DA, + 186510CF06253BE3005AB5DA, + 186510D006253BE3005AB5DA, + ); + isa = PBXGroup; + path = q2map; + refType = 4; + sourceTree = ""; + }; + 1865104006253BE1005AB5DA = { + children = ( + 1865104106253BE1005AB5DA, + 1865104206253BE1005AB5DA, + 1865104306253BE1005AB5DA, + 1865104406253BE1005AB5DA, + 1865104506253BE1005AB5DA, + 1865106006253BE2005AB5DA, + 1865107B06253BE2005AB5DA, + 1865107C06253BE2005AB5DA, + 1865109706253BE2005AB5DA, + 1865109C06253BE2005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865104106253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865104206253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865104306253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865104406253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865104506253BE1005AB5DA = { + children = ( + 1865104606253BE1005AB5DA, + 1865104706253BE1005AB5DA, + 1865104806253BE1005AB5DA, + 1865104906253BE1005AB5DA, + 1865104A06253BE1005AB5DA, + 1865104B06253BE1005AB5DA, + 1865104C06253BE1005AB5DA, + 1865104D06253BE1005AB5DA, + 1865104E06253BE1005AB5DA, + 1865104F06253BE1005AB5DA, + 1865105006253BE1005AB5DA, + 1865105106253BE1005AB5DA, + 1865105206253BE1005AB5DA, + 1865105306253BE1005AB5DA, + 1865105406253BE1005AB5DA, + 1865105506253BE1005AB5DA, + 1865105606253BE1005AB5DA, + 1865105706253BE1005AB5DA, + 1865105806253BE1005AB5DA, + 1865105906253BE1005AB5DA, + 1865105A06253BE1005AB5DA, + 1865105B06253BE1005AB5DA, + 1865105C06253BE2005AB5DA, + 1865105D06253BE2005AB5DA, + 1865105E06253BE2005AB5DA, + 1865105F06253BE2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865104606253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushbsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104706253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104806253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "faces.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104906253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flow.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104A06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gldraw.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104B06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104C06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104D06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmap.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104E06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865104F06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105006253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nodraw.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105106253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patches.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105206253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105306253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105406253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105506253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105606253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105706253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105806253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105906253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105A06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105B06253BE1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105C06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105D06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trace.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105E06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865105F06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865106006253BE2005AB5DA = { + children = ( + 1865106106253BE2005AB5DA, + 1865106206253BE2005AB5DA, + 1865106306253BE2005AB5DA, + 1865106406253BE2005AB5DA, + 1865106506253BE2005AB5DA, + 1865106606253BE2005AB5DA, + 1865106706253BE2005AB5DA, + 1865106806253BE2005AB5DA, + 1865106906253BE2005AB5DA, + 1865106A06253BE2005AB5DA, + 1865106B06253BE2005AB5DA, + 1865106C06253BE2005AB5DA, + 1865106D06253BE2005AB5DA, + 1865106E06253BE2005AB5DA, + 1865106F06253BE2005AB5DA, + 1865107006253BE2005AB5DA, + 1865107106253BE2005AB5DA, + 1865107206253BE2005AB5DA, + 1865107306253BE2005AB5DA, + 1865107406253BE2005AB5DA, + 1865107506253BE2005AB5DA, + 1865107606253BE2005AB5DA, + 1865107706253BE2005AB5DA, + 1865107806253BE2005AB5DA, + 1865107906253BE2005AB5DA, + 1865107A06253BE2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865106106253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushbsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106206253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106306253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "faces.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106406253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flow.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106506253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gldraw.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106606253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106706253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106806253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmap.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106906253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106A06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106B06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nodraw.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106C06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patches.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106D06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106E06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865106F06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107006253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107106253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107206253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107306253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107406253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107506253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107606253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107706253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107806253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trace.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107906253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107A06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865107B06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865107C06253BE2005AB5DA = { + children = ( + 1865107D06253BE2005AB5DA, + 1865107E06253BE2005AB5DA, + 1865107F06253BE2005AB5DA, + 1865108006253BE2005AB5DA, + 1865108106253BE2005AB5DA, + 1865108206253BE2005AB5DA, + 1865108306253BE2005AB5DA, + 1865108406253BE2005AB5DA, + 1865108506253BE2005AB5DA, + 1865108606253BE2005AB5DA, + 1865108706253BE2005AB5DA, + 1865108806253BE2005AB5DA, + 1865108906253BE2005AB5DA, + 1865108A06253BE2005AB5DA, + 1865108B06253BE2005AB5DA, + 1865108C06253BE2005AB5DA, + 1865108D06253BE2005AB5DA, + 1865108E06253BE2005AB5DA, + 1865108F06253BE2005AB5DA, + 1865109006253BE2005AB5DA, + 1865109106253BE2005AB5DA, + 1865109206253BE2005AB5DA, + 1865109306253BE2005AB5DA, + 1865109406253BE2005AB5DA, + 1865109506253BE2005AB5DA, + 1865109606253BE2005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865107D06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushbsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865107E06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865107F06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "faces.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108006253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flow.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108106253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gldraw.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108206253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108306253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108406253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmap.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108506253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108606253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108706253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nodraw.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108806253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patches.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108906253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108A06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108B06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108C06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "q2map.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108D06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108E06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865108F06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109006253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109106253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109206253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109306253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109406253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trace.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109506253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109606253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865109706253BE2005AB5DA = { + children = ( + 1865109806253BE2005AB5DA, + 1865109906253BE2005AB5DA, + 1865109A06253BE2005AB5DA, + 1865109B06253BE2005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865109806253BE2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865109906253BE2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865109A06253BE2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865109B06253BE2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865109C06253BE2005AB5DA = { + children = ( + 1865109D06253BE2005AB5DA, + 1865109E06253BE2005AB5DA, + 1865109F06253BE2005AB5DA, + 186510A006253BE2005AB5DA, + 186510A106253BE2005AB5DA, + 186510A206253BE2005AB5DA, + 186510A306253BE2005AB5DA, + 186510A406253BE2005AB5DA, + 186510A506253BE2005AB5DA, + 186510A606253BE2005AB5DA, + 186510A706253BE3005AB5DA, + 186510A806253BE3005AB5DA, + 186510A906253BE3005AB5DA, + 186510AA06253BE3005AB5DA, + 186510AB06253BE3005AB5DA, + 186510AC06253BE3005AB5DA, + 186510AD06253BE3005AB5DA, + 186510AE06253BE3005AB5DA, + 186510AF06253BE3005AB5DA, + 186510B006253BE3005AB5DA, + 186510B106253BE3005AB5DA, + 186510B206253BE3005AB5DA, + 186510B306253BE3005AB5DA, + 186510B406253BE3005AB5DA, + 186510B506253BE3005AB5DA, + 186510B606253BE3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865109D06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushbsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865109E06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "csg.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865109F06253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "faces.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A006253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flow.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A106253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gldraw.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A206253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A306253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A406253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmap.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A506253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A606253BE2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "nodraw.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patches.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510A906253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510AA06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510AB06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510AC06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2map.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510AD06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510AE06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qbsp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510AF06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qrad.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B106253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B206253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qvis.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B306253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textures.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B406253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trace.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510B706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = brushbsp.c; + refType = 4; + sourceTree = ""; + }; + 186510B806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = csg.c; + refType = 4; + sourceTree = ""; + }; + 186510B906253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = faces.c; + refType = 4; + sourceTree = ""; + }; + 186510BA06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = flow.c; + refType = 4; + sourceTree = ""; + }; + 186510BB06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = gldraw.c; + refType = 4; + sourceTree = ""; + }; + 186510BC06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = glfile.c; + refType = 4; + sourceTree = ""; + }; + 186510BD06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = leakfile.c; + refType = 4; + sourceTree = ""; + }; + 186510BE06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lightmap.c; + refType = 4; + sourceTree = ""; + }; + 186510BF06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = main.c; + refType = 4; + sourceTree = ""; + }; + 186510C006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = map.c; + refType = 4; + sourceTree = ""; + }; + 186510C106253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = nodraw.c; + refType = 4; + sourceTree = ""; + }; + 186510C206253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = patches.c; + refType = 4; + sourceTree = ""; + }; + 186510C306253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = portals.c; + refType = 4; + sourceTree = ""; + }; + 186510C406253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = prtfile.c; + refType = 4; + sourceTree = ""; + }; + 186510C506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q2map.h; + refType = 4; + sourceTree = ""; + }; + 186510C606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = q2map.vcproj; + refType = 4; + sourceTree = ""; + }; + 186510C706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qbsp.c; + refType = 4; + sourceTree = ""; + }; + 186510C806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qbsp.h; + refType = 4; + sourceTree = ""; + }; + 186510C906253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qrad.c; + refType = 4; + sourceTree = ""; + }; + 186510CA06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qrad.h; + refType = 4; + sourceTree = ""; + }; + 186510CB06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qvis.c; + refType = 4; + sourceTree = ""; + }; + 186510CC06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qvis.h; + refType = 4; + sourceTree = ""; + }; + 186510CD06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = textures.c; + refType = 4; + sourceTree = ""; + }; + 186510CE06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = trace.c; + refType = 4; + sourceTree = ""; + }; + 186510CF06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = tree.c; + refType = 4; + sourceTree = ""; + }; + 186510D006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = writebsp.c; + refType = 4; + sourceTree = ""; + }; + 186510D106253BE3005AB5DA = { + children = ( + 186510D206253BE3005AB5DA, + 1865110906253BE3005AB5DA, + 1865110A06253BE3005AB5DA, + 1865110B06253BE3005AB5DA, + 1865110C06253BE3005AB5DA, + 1865110D06253BE3005AB5DA, + 1865110E06253BE3005AB5DA, + 1865110F06253BE3005AB5DA, + 1865111006253BE3005AB5DA, + 1865111106253BE3005AB5DA, + 1865111206253BE3005AB5DA, + ); + isa = PBXGroup; + path = qdata; + refType = 4; + sourceTree = ""; + }; + 186510D206253BE3005AB5DA = { + children = ( + 186510D306253BE3005AB5DA, + 186510D406253BE3005AB5DA, + 186510D506253BE3005AB5DA, + 186510D606253BE3005AB5DA, + 186510D706253BE3005AB5DA, + 186510E206253BE3005AB5DA, + 186510ED06253BE3005AB5DA, + 186510EE06253BE3005AB5DA, + 186510F906253BE3005AB5DA, + 186510FE06253BE3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186510D306253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186510D406253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186510D506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186510D606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186510D706253BE3005AB5DA = { + children = ( + 186510D806253BE3005AB5DA, + 186510D906253BE3005AB5DA, + 186510DA06253BE3005AB5DA, + 186510DB06253BE3005AB5DA, + 186510DC06253BE3005AB5DA, + 186510DD06253BE3005AB5DA, + 186510DE06253BE3005AB5DA, + 186510DF06253BE3005AB5DA, + 186510E006253BE3005AB5DA, + 186510E106253BE3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186510D806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510D906253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510DA06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makefile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510DB06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510DC06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510DD06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510DE06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata3.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510DF06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510E006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510E106253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510E206253BE3005AB5DA = { + children = ( + 186510E306253BE3005AB5DA, + 186510E406253BE3005AB5DA, + 186510E506253BE3005AB5DA, + 186510E606253BE3005AB5DA, + 186510E706253BE3005AB5DA, + 186510E806253BE3005AB5DA, + 186510E906253BE3005AB5DA, + 186510EA06253BE3005AB5DA, + 186510EB06253BE3005AB5DA, + 186510EC06253BE3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186510E306253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510E406253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510E506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makefile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510E606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510E706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510E806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510E906253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata3.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510EA06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510EB06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510EC06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186510ED06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186510EE06253BE3005AB5DA = { + children = ( + 186510EF06253BE3005AB5DA, + 186510F006253BE3005AB5DA, + 186510F106253BE3005AB5DA, + 186510F206253BE3005AB5DA, + 186510F306253BE3005AB5DA, + 186510F406253BE3005AB5DA, + 186510F506253BE3005AB5DA, + 186510F606253BE3005AB5DA, + 186510F706253BE3005AB5DA, + 186510F806253BE3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186510EF06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F106253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makefile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F206253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F306253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F406253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "qdata3.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186510F906253BE3005AB5DA = { + children = ( + 186510FA06253BE3005AB5DA, + 186510FB06253BE3005AB5DA, + 186510FC06253BE3005AB5DA, + 186510FD06253BE3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186510FA06253BE3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186510FB06253BE3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186510FC06253BE3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186510FD06253BE3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186510FE06253BE3005AB5DA = { + children = ( + 186510FF06253BE3005AB5DA, + 1865110006253BE3005AB5DA, + 1865110106253BE3005AB5DA, + 1865110206253BE3005AB5DA, + 1865110306253BE3005AB5DA, + 1865110406253BE3005AB5DA, + 1865110506253BE3005AB5DA, + 1865110606253BE3005AB5DA, + 1865110706253BE3005AB5DA, + 1865110806253BE3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186510FF06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110106253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makefile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110206253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110306253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110406253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata3.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865110906253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = anorms.h; + refType = 4; + sourceTree = ""; + }; + 1865110A06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = images.c; + refType = 4; + sourceTree = ""; + }; + 1865110B06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.make; + path = makefile; + refType = 4; + sourceTree = ""; + }; + 1865110C06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = models.c; + refType = 4; + sourceTree = ""; + }; + 1865110D06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qdata.c; + refType = 4; + sourceTree = ""; + }; + 1865110E06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qdata.h; + refType = 4; + sourceTree = ""; + }; + 1865110F06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = qdata3.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865111006253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = sprites.c; + refType = 4; + sourceTree = ""; + }; + 1865111106253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = tables.c; + refType = 4; + sourceTree = ""; + }; + 1865111206253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = video.c; + refType = 4; + sourceTree = ""; + }; + 1865111306253BE3005AB5DA = { + children = ( + 1865111406253BE3005AB5DA, + 1865118F06253BE5005AB5DA, + 1865119006253BE5005AB5DA, + 1865119106253BE5005AB5DA, + 1865119206253BE5005AB5DA, + 1865119306253BE5005AB5DA, + 1865119406253BE5005AB5DA, + 1865122606253BE7005AB5DA, + 1865122706253BE7005AB5DA, + 1865122806253BE7005AB5DA, + 1865122906253BE7005AB5DA, + 1865122A06253BE7005AB5DA, + 1865122B06253BE7005AB5DA, + 1865122C06253BE7005AB5DA, + 1865122D06253BE7005AB5DA, + 1865122E06253BE7005AB5DA, + 1865128406253BE7005AB5DA, + 1865128506253BE7005AB5DA, + 1865128606253BE7005AB5DA, + 1865128706253BE7005AB5DA, + 1865128806253BE7005AB5DA, + 1865128906253BE7005AB5DA, + 1865128A06253BE7005AB5DA, + 1865128B06253BE7005AB5DA, + 1865128C06253BE7005AB5DA, + 1865128D06253BE7005AB5DA, + 1865128E06253BE7005AB5DA, + 1865128F06253BE7005AB5DA, + 1865129006253BE7005AB5DA, + 1865129106253BE7005AB5DA, + ); + isa = PBXGroup; + path = qdata_heretic2; + refType = 4; + sourceTree = ""; + }; + 1865111406253BE3005AB5DA = { + children = ( + 1865111506253BE3005AB5DA, + 1865111606253BE3005AB5DA, + 1865111706253BE3005AB5DA, + 1865111806253BE3005AB5DA, + 1865111906253BE3005AB5DA, + 1865113506253BE4005AB5DA, + 1865115106253BE5005AB5DA, + 1865115206253BE5005AB5DA, + 1865116E06253BE5005AB5DA, + 1865117306253BE5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865111506253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865111606253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865111706253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865111806253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865111906253BE3005AB5DA = { + children = ( + 1865111A06253BE3005AB5DA, + 1865111B06253BE4005AB5DA, + 1865111C06253BE4005AB5DA, + 1865111D06253BE4005AB5DA, + 1865111E06253BE4005AB5DA, + 1865111F06253BE4005AB5DA, + 1865112006253BE4005AB5DA, + 1865112106253BE4005AB5DA, + 1865112206253BE4005AB5DA, + 1865112306253BE4005AB5DA, + 1865112406253BE4005AB5DA, + 1865112506253BE4005AB5DA, + 1865112606253BE4005AB5DA, + 1865112706253BE4005AB5DA, + 1865112806253BE4005AB5DA, + 1865112906253BE4005AB5DA, + 1865112A06253BE4005AB5DA, + 1865112B06253BE4005AB5DA, + 1865112C06253BE4005AB5DA, + 1865112D06253BE4005AB5DA, + 1865112E06253BE4005AB5DA, + 1865112F06253BE4005AB5DA, + 1865113006253BE4005AB5DA, + 1865113106253BE4005AB5DA, + 1865113206253BE4005AB5DA, + 1865113306253BE4005AB5DA, + 1865113406253BE4005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865111A06253BE3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adpcm.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865111B06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865111C06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865111D06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865111E06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "book.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865111F06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodels.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112006253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icon1.ico.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112106253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112206253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112306253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112406253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "joints.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112506253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112606253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pics.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112706253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_fmodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112806253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112906253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112A06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112B06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112C06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata3_heretic2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112D06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112E06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.aps.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865112F06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865113006253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865113106253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "svdcmp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865113206253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865113306253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tmix.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865113406253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865113506253BE4005AB5DA = { + children = ( + 1865113606253BE4005AB5DA, + 1865113706253BE4005AB5DA, + 1865113806253BE4005AB5DA, + 1865113906253BE4005AB5DA, + 1865113A06253BE4005AB5DA, + 1865113B06253BE4005AB5DA, + 1865113C06253BE4005AB5DA, + 1865113D06253BE4005AB5DA, + 1865113E06253BE4005AB5DA, + 1865113F06253BE4005AB5DA, + 1865114006253BE4005AB5DA, + 1865114106253BE4005AB5DA, + 1865114206253BE4005AB5DA, + 1865114306253BE4005AB5DA, + 1865114406253BE4005AB5DA, + 1865114506253BE4005AB5DA, + 1865114606253BE4005AB5DA, + 1865114706253BE4005AB5DA, + 1865114806253BE4005AB5DA, + 1865114906253BE4005AB5DA, + 1865114A06253BE4005AB5DA, + 1865114B06253BE4005AB5DA, + 1865114C06253BE5005AB5DA, + 1865114D06253BE5005AB5DA, + 1865114E06253BE5005AB5DA, + 1865114F06253BE5005AB5DA, + 1865115006253BE5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865113606253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adpcm.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113706253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113806253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113906253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113A06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "book.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113B06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodels.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113C06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icon1.ico.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113D06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113E06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865113F06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114006253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "joints.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114106253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114206253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pics.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114306253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_fmodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114406253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114506253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114606253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114706253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114806253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata3_heretic2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114906253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114A06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.aps.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114B06253BE4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114C06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114D06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "svdcmp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114E06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865114F06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tmix.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865115006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865115106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865115206253BE5005AB5DA = { + children = ( + 1865115306253BE5005AB5DA, + 1865115406253BE5005AB5DA, + 1865115506253BE5005AB5DA, + 1865115606253BE5005AB5DA, + 1865115706253BE5005AB5DA, + 1865115806253BE5005AB5DA, + 1865115906253BE5005AB5DA, + 1865115A06253BE5005AB5DA, + 1865115B06253BE5005AB5DA, + 1865115C06253BE5005AB5DA, + 1865115D06253BE5005AB5DA, + 1865115E06253BE5005AB5DA, + 1865115F06253BE5005AB5DA, + 1865116006253BE5005AB5DA, + 1865116106253BE5005AB5DA, + 1865116206253BE5005AB5DA, + 1865116306253BE5005AB5DA, + 1865116406253BE5005AB5DA, + 1865116506253BE5005AB5DA, + 1865116606253BE5005AB5DA, + 1865116706253BE5005AB5DA, + 1865116806253BE5005AB5DA, + 1865116906253BE5005AB5DA, + 1865116A06253BE5005AB5DA, + 1865116B06253BE5005AB5DA, + 1865116C06253BE5005AB5DA, + 1865116D06253BE5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865115306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adpcm.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115506253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "book.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodels.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115906253BE5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "icon1.ico.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115A06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115B06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115C06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115D06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "joints.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115E06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865115F06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pics.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_fmodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116206253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116506253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "qdata3_heretic2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116706253BE5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "script1.aps.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116906253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116A06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "svdcmp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116B06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116C06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tmix.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116D06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865116E06253BE5005AB5DA = { + children = ( + 1865116F06253BE5005AB5DA, + 1865117006253BE5005AB5DA, + 1865117106253BE5005AB5DA, + 1865117206253BE5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865116F06253BE5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865117006253BE5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865117106253BE5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865117206253BE5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865117306253BE5005AB5DA = { + children = ( + 1865117406253BE5005AB5DA, + 1865117506253BE5005AB5DA, + 1865117606253BE5005AB5DA, + 1865117706253BE5005AB5DA, + 1865117806253BE5005AB5DA, + 1865117906253BE5005AB5DA, + 1865117A06253BE5005AB5DA, + 1865117B06253BE5005AB5DA, + 1865117C06253BE5005AB5DA, + 1865117D06253BE5005AB5DA, + 1865117E06253BE5005AB5DA, + 1865117F06253BE5005AB5DA, + 1865118006253BE5005AB5DA, + 1865118106253BE5005AB5DA, + 1865118206253BE5005AB5DA, + 1865118306253BE5005AB5DA, + 1865118406253BE5005AB5DA, + 1865118506253BE5005AB5DA, + 1865118606253BE5005AB5DA, + 1865118706253BE5005AB5DA, + 1865118806253BE5005AB5DA, + 1865118906253BE5005AB5DA, + 1865118A06253BE5005AB5DA, + 1865118B06253BE5005AB5DA, + 1865118C06253BE5005AB5DA, + 1865118D06253BE5005AB5DA, + 1865118E06253BE5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865117406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adpcm.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117506253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "animcomp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "anorms.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "book.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117906253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodels.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117A06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icon1.ico.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117B06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117C06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117D06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jointed.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117E06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "joints.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865117F06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pics.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_fmodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118206253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qd_skeletons.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118506253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qdata3_heretic2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.aps.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118906253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "script1.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118A06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sprites.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118B06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "svdcmp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118C06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tables.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118D06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tmix.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118E06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865118F06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = adpcm.h; + refType = 4; + sourceTree = ""; + }; + 1865119006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = animcomp.c; + refType = 4; + sourceTree = ""; + }; + 1865119106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = animcomp.h; + refType = 4; + sourceTree = ""; + }; + 1865119206253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = anorms.h; + refType = 4; + sourceTree = ""; + }; + 1865119306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = book.c; + refType = 4; + sourceTree = ""; + }; + 1865119406253BE5005AB5DA = { + children = ( + 1865119506253BE5005AB5DA, + 1865120C06253BE6005AB5DA, + 1865120D06253BE6005AB5DA, + 1865120E06253BE6005AB5DA, + 1865120F06253BE6005AB5DA, + 1865121006253BE6005AB5DA, + 1865121106253BE6005AB5DA, + 1865121206253BE6005AB5DA, + 1865121306253BE6005AB5DA, + 1865121406253BE6005AB5DA, + 1865121506253BE6005AB5DA, + 1865121606253BE6005AB5DA, + 1865121706253BE6005AB5DA, + 1865121806253BE6005AB5DA, + 1865121906253BE6005AB5DA, + 1865121A06253BE6005AB5DA, + 1865121B06253BE7005AB5DA, + 1865121C06253BE7005AB5DA, + 1865121D06253BE7005AB5DA, + 1865121E06253BE7005AB5DA, + 1865121F06253BE7005AB5DA, + 1865122006253BE7005AB5DA, + 1865122106253BE7005AB5DA, + 1865122206253BE7005AB5DA, + 1865122306253BE7005AB5DA, + 1865122406253BE7005AB5DA, + 1865122506253BE7005AB5DA, + ); + isa = PBXGroup; + path = common; + refType = 4; + sourceTree = ""; + }; + 1865119506253BE5005AB5DA = { + children = ( + 1865119606253BE5005AB5DA, + 1865119706253BE5005AB5DA, + 1865119806253BE5005AB5DA, + 1865119906253BE5005AB5DA, + 1865119A06253BE5005AB5DA, + 186511B506253BE5005AB5DA, + 186511D006253BE6005AB5DA, + 186511D106253BE6005AB5DA, + 186511EC06253BE6005AB5DA, + 186511F106253BE6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865119606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865119706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865119806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865119906253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865119A06253BE5005AB5DA = { + children = ( + 1865119B06253BE5005AB5DA, + 1865119C06253BE5005AB5DA, + 1865119D06253BE5005AB5DA, + 1865119E06253BE5005AB5DA, + 1865119F06253BE5005AB5DA, + 186511A006253BE5005AB5DA, + 186511A106253BE5005AB5DA, + 186511A206253BE5005AB5DA, + 186511A306253BE5005AB5DA, + 186511A406253BE5005AB5DA, + 186511A506253BE5005AB5DA, + 186511A606253BE5005AB5DA, + 186511A706253BE5005AB5DA, + 186511A806253BE5005AB5DA, + 186511A906253BE5005AB5DA, + 186511AA06253BE5005AB5DA, + 186511AB06253BE5005AB5DA, + 186511AC06253BE5005AB5DA, + 186511AD06253BE5005AB5DA, + 186511AE06253BE5005AB5DA, + 186511AF06253BE5005AB5DA, + 186511B006253BE5005AB5DA, + 186511B106253BE5005AB5DA, + 186511B206253BE5005AB5DA, + 186511B306253BE5005AB5DA, + 186511B406253BE5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865119B06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865119C06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865119D06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865119E06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865119F06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "her2_threads.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A206253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A506253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511A906253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511AA06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511AB06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511AC06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511AD06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511AE06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511AF06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511B006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511B106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511B206253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511B306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511B406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511B506253BE5005AB5DA = { + children = ( + 186511B606253BE5005AB5DA, + 186511B706253BE5005AB5DA, + 186511B806253BE5005AB5DA, + 186511B906253BE5005AB5DA, + 186511BA06253BE5005AB5DA, + 186511BB06253BE5005AB5DA, + 186511BC06253BE5005AB5DA, + 186511BD06253BE5005AB5DA, + 186511BE06253BE5005AB5DA, + 186511BF06253BE5005AB5DA, + 186511C006253BE5005AB5DA, + 186511C106253BE5005AB5DA, + 186511C206253BE5005AB5DA, + 186511C306253BE5005AB5DA, + 186511C406253BE5005AB5DA, + 186511C506253BE5005AB5DA, + 186511C606253BE5005AB5DA, + 186511C706253BE5005AB5DA, + 186511C806253BE6005AB5DA, + 186511C906253BE6005AB5DA, + 186511CA06253BE6005AB5DA, + 186511CB06253BE6005AB5DA, + 186511CC06253BE6005AB5DA, + 186511CD06253BE6005AB5DA, + 186511CE06253BE6005AB5DA, + 186511CF06253BE6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186511B606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511B706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511B806253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511B906253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511BA06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "her2_threads.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511BB06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511BC06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511BD06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511BE06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511BF06253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C006253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C106253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C206253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C306253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C406253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C506253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C606253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C706253BE5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C806253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511C906253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511CA06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511CB06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511CC06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511CD06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511CE06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511CF06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511D006253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186511D106253BE6005AB5DA = { + children = ( + 186511D206253BE6005AB5DA, + 186511D306253BE6005AB5DA, + 186511D406253BE6005AB5DA, + 186511D506253BE6005AB5DA, + 186511D606253BE6005AB5DA, + 186511D706253BE6005AB5DA, + 186511D806253BE6005AB5DA, + 186511D906253BE6005AB5DA, + 186511DA06253BE6005AB5DA, + 186511DB06253BE6005AB5DA, + 186511DC06253BE6005AB5DA, + 186511DD06253BE6005AB5DA, + 186511DE06253BE6005AB5DA, + 186511DF06253BE6005AB5DA, + 186511E006253BE6005AB5DA, + 186511E106253BE6005AB5DA, + 186511E206253BE6005AB5DA, + 186511E306253BE6005AB5DA, + 186511E406253BE6005AB5DA, + 186511E506253BE6005AB5DA, + 186511E606253BE6005AB5DA, + 186511E706253BE6005AB5DA, + 186511E806253BE6005AB5DA, + 186511E906253BE6005AB5DA, + 186511EA06253BE6005AB5DA, + 186511EB06253BE6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186511D206253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D306253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D406253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D506253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D606253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "her2_threads.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D706253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D806253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511D906253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511DA06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511DB06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511DC06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511DD06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511DE06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511DF06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E006253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E106253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E206253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E306253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E406253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E506253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E606253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E706253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E806253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511E906253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511EA06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511EB06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186511EC06253BE6005AB5DA = { + children = ( + 186511ED06253BE6005AB5DA, + 186511EE06253BE6005AB5DA, + 186511EF06253BE6005AB5DA, + 186511F006253BE6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186511ED06253BE6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186511EE06253BE6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186511EF06253BE6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186511F006253BE6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186511F106253BE6005AB5DA = { + children = ( + 186511F206253BE6005AB5DA, + 186511F306253BE6005AB5DA, + 186511F406253BE6005AB5DA, + 186511F506253BE6005AB5DA, + 186511F606253BE6005AB5DA, + 186511F706253BE6005AB5DA, + 186511F806253BE6005AB5DA, + 186511F906253BE6005AB5DA, + 186511FA06253BE6005AB5DA, + 186511FB06253BE6005AB5DA, + 186511FC06253BE6005AB5DA, + 186511FD06253BE6005AB5DA, + 186511FE06253BE6005AB5DA, + 186511FF06253BE6005AB5DA, + 1865120006253BE6005AB5DA, + 1865120106253BE6005AB5DA, + 1865120206253BE6005AB5DA, + 1865120306253BE6005AB5DA, + 1865120406253BE6005AB5DA, + 1865120506253BE6005AB5DA, + 1865120606253BE6005AB5DA, + 1865120706253BE6005AB5DA, + 1865120806253BE6005AB5DA, + 1865120906253BE6005AB5DA, + 1865120A06253BE6005AB5DA, + 1865120B06253BE6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186511F206253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F306253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F406253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F506253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F606253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "her2_threads.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F706253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F806253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511F906253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511FA06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511FB06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511FC06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511FD06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511FE06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186511FF06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120006253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120106253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120206253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120306253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120406253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120506253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120606253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120706253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120806253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120906253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "token.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120A06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120B06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865120C06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bspfile.c; + refType = 4; + sourceTree = ""; + }; + 1865120D06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bspfile.h; + refType = 4; + sourceTree = ""; + }; + 1865120E06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = cmdlib.c; + refType = 4; + sourceTree = ""; + }; + 1865120F06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = cmdlib.h; + refType = 4; + sourceTree = ""; + }; + 1865121006253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = her2_threads.h; + refType = 4; + sourceTree = ""; + }; + 1865121106253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = inout.c; + refType = 4; + sourceTree = ""; + }; + 1865121206253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = inout.h; + refType = 4; + sourceTree = ""; + }; + 1865121306253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = l3dslib.c; + refType = 4; + sourceTree = ""; + }; + 1865121406253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = l3dslib.h; + refType = 4; + sourceTree = ""; + }; + 1865121506253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lbmlib.c; + refType = 4; + sourceTree = ""; + }; + 1865121606253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = lbmlib.h; + refType = 4; + sourceTree = ""; + }; + 1865121706253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = mathlib.c; + refType = 4; + sourceTree = ""; + }; + 1865121806253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = mathlib.h; + refType = 4; + sourceTree = ""; + }; + 1865121906253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = md4.c; + refType = 4; + sourceTree = ""; + }; + 1865121A06253BE6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = path_init.c; + refType = 4; + sourceTree = ""; + }; + 1865121B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = polylib.c; + refType = 4; + sourceTree = ""; + }; + 1865121C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = polylib.h; + refType = 4; + sourceTree = ""; + }; + 1865121D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qfiles.c; + refType = 4; + sourceTree = ""; + }; + 1865121E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qfiles.h; + refType = 4; + sourceTree = ""; + }; + 1865121F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = scriplib.c; + refType = 4; + sourceTree = ""; + }; + 1865122006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = scriplib.h; + refType = 4; + sourceTree = ""; + }; + 1865122106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = threads.c; + refType = 4; + sourceTree = ""; + }; + 1865122206253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = token.c; + refType = 4; + sourceTree = ""; + }; + 1865122306253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = token.h; + refType = 4; + sourceTree = ""; + }; + 1865122406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = trilib.c; + refType = 4; + sourceTree = ""; + }; + 1865122506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = trilib.h; + refType = 4; + sourceTree = ""; + }; + 1865122606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = fmodels.c; + refType = 4; + sourceTree = ""; + }; + 1865122706253BE7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.ico; + path = icon1.ico; + refType = 4; + sourceTree = ""; + }; + 1865122806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = images.c; + refType = 4; + sourceTree = ""; + }; + 1865122906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = jointed.c; + refType = 4; + sourceTree = ""; + }; + 1865122A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jointed.h; + refType = 4; + sourceTree = ""; + }; + 1865122B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = joints.h; + refType = 4; + sourceTree = ""; + }; + 1865122C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = models.c; + refType = 4; + sourceTree = ""; + }; + 1865122D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pics.c; + refType = 4; + sourceTree = ""; + }; + 1865122E06253BE7005AB5DA = { + children = ( + 1865122F06253BE7005AB5DA, + 1865127606253BE7005AB5DA, + 1865127706253BE7005AB5DA, + 1865127806253BE7005AB5DA, + 1865127906253BE7005AB5DA, + 1865127A06253BE7005AB5DA, + 1865127B06253BE7005AB5DA, + 1865127C06253BE7005AB5DA, + 1865127D06253BE7005AB5DA, + 1865127E06253BE7005AB5DA, + 1865127F06253BE7005AB5DA, + 1865128006253BE7005AB5DA, + 1865128106253BE7005AB5DA, + 1865128206253BE7005AB5DA, + 1865128306253BE7005AB5DA, + ); + isa = PBXGroup; + path = qcommon; + refType = 4; + sourceTree = ""; + }; + 1865122F06253BE7005AB5DA = { + children = ( + 1865123006253BE7005AB5DA, + 1865123106253BE7005AB5DA, + 1865123206253BE7005AB5DA, + 1865123306253BE7005AB5DA, + 1865123406253BE7005AB5DA, + 1865124306253BE7005AB5DA, + 1865125206253BE7005AB5DA, + 1865125306253BE7005AB5DA, + 1865126206253BE7005AB5DA, + 1865126706253BE7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865123006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865123106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865123206253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865123306253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865123406253BE7005AB5DA = { + children = ( + 1865123506253BE7005AB5DA, + 1865123606253BE7005AB5DA, + 1865123706253BE7005AB5DA, + 1865123806253BE7005AB5DA, + 1865123906253BE7005AB5DA, + 1865123A06253BE7005AB5DA, + 1865123B06253BE7005AB5DA, + 1865123C06253BE7005AB5DA, + 1865123D06253BE7005AB5DA, + 1865123E06253BE7005AB5DA, + 1865123F06253BE7005AB5DA, + 1865124006253BE7005AB5DA, + 1865124106253BE7005AB5DA, + 1865124206253BE7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865123506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "angles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "arrayedlist.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flex.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "h2common.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "placement.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_typedef.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865123F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865124006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865124106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865124206253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865124306253BE7005AB5DA = { + children = ( + 1865124406253BE7005AB5DA, + 1865124506253BE7005AB5DA, + 1865124606253BE7005AB5DA, + 1865124706253BE7005AB5DA, + 1865124806253BE7005AB5DA, + 1865124906253BE7005AB5DA, + 1865124A06253BE7005AB5DA, + 1865124B06253BE7005AB5DA, + 1865124C06253BE7005AB5DA, + 1865124D06253BE7005AB5DA, + 1865124E06253BE7005AB5DA, + 1865124F06253BE7005AB5DA, + 1865125006253BE7005AB5DA, + 1865125106253BE7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865124406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "angles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "arrayedlist.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flex.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "h2common.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "placement.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_typedef.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865124F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865125006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865125106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865125206253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865125306253BE7005AB5DA = { + children = ( + 1865125406253BE7005AB5DA, + 1865125506253BE7005AB5DA, + 1865125606253BE7005AB5DA, + 1865125706253BE7005AB5DA, + 1865125806253BE7005AB5DA, + 1865125906253BE7005AB5DA, + 1865125A06253BE7005AB5DA, + 1865125B06253BE7005AB5DA, + 1865125C06253BE7005AB5DA, + 1865125D06253BE7005AB5DA, + 1865125E06253BE7005AB5DA, + 1865125F06253BE7005AB5DA, + 1865126006253BE7005AB5DA, + 1865126106253BE7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865125406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "angles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "arrayedlist.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flex.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "h2common.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "placement.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_typedef.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865125F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865126006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865126106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865126206253BE7005AB5DA = { + children = ( + 1865126306253BE7005AB5DA, + 1865126406253BE7005AB5DA, + 1865126506253BE7005AB5DA, + 1865126606253BE7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865126306253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865126406253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865126506253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865126606253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865126706253BE7005AB5DA = { + children = ( + 1865126806253BE7005AB5DA, + 1865126906253BE7005AB5DA, + 1865126A06253BE7005AB5DA, + 1865126B06253BE7005AB5DA, + 1865126C06253BE7005AB5DA, + 1865126D06253BE7005AB5DA, + 1865126E06253BE7005AB5DA, + 1865126F06253BE7005AB5DA, + 1865127006253BE7005AB5DA, + 1865127106253BE7005AB5DA, + 1865127206253BE7005AB5DA, + 1865127306253BE7005AB5DA, + 1865127406253BE7005AB5DA, + 1865127506253BE7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865126806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "angles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "arrayedlist.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "flex.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fmodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "h2common.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "placement.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_typedef.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865126F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127206253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127306253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resourcemanager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "skeletons.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865127606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = angles.h; + refType = 4; + sourceTree = ""; + }; + 1865127706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = arrayedlist.h; + refType = 4; + sourceTree = ""; + }; + 1865127806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = flex.h; + refType = 4; + sourceTree = ""; + }; + 1865127906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = fmodel.h; + refType = 4; + sourceTree = ""; + }; + 1865127A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = h2common.h; + refType = 4; + sourceTree = ""; + }; + 1865127B06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = placement.h; + refType = 4; + sourceTree = ""; + }; + 1865127C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q_typedef.h; + refType = 4; + sourceTree = ""; + }; + 1865127D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qfiles.h; + refType = 4; + sourceTree = ""; + }; + 1865127E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = reference.c; + refType = 4; + sourceTree = ""; + }; + 1865127F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = reference.h; + refType = 4; + sourceTree = ""; + }; + 1865128006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = resourcemanager.c; + refType = 4; + sourceTree = ""; + }; + 1865128106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = resourcemanager.h; + refType = 4; + sourceTree = ""; + }; + 1865128206253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = skeletons.c; + refType = 4; + sourceTree = ""; + }; + 1865128306253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = skeletons.h; + refType = 4; + sourceTree = ""; + }; + 1865128406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qd_fmodel.h; + refType = 4; + sourceTree = ""; + }; + 1865128506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qd_skeletons.c; + refType = 4; + sourceTree = ""; + }; + 1865128606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qd_skeletons.h; + refType = 4; + sourceTree = ""; + }; + 1865128706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = qdata.c; + refType = 4; + sourceTree = ""; + }; + 1865128806253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qdata.h; + refType = 4; + sourceTree = ""; + }; + 1865128906253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = qdata3_heretic2.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865128A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = resource.h; + refType = 4; + sourceTree = ""; + }; + 1865128B06253BE7005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = script1.aps; + refType = 4; + sourceTree = ""; + }; + 1865128C06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = script1.rc; + refType = 4; + sourceTree = ""; + }; + 1865128D06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = sprites.c; + refType = 4; + sourceTree = ""; + }; + 1865128E06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = svdcmp.c; + refType = 4; + sourceTree = ""; + }; + 1865128F06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = tables.c; + refType = 4; + sourceTree = ""; + }; + 1865129006253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = tmix.c; + refType = 4; + sourceTree = ""; + }; + 1865129106253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = video.c; + refType = 4; + sourceTree = ""; + }; + 1865129206253BE7005AB5DA = { + children = ( + 1865129306253BE7005AB5DA, + 186512A206253BE7005AB5DA, + 186512B206253BE8005AB5DA, + 1865135806253BEA005AB5DA, + 186513C206253BEB005AB5DA, + 186513E206253BEB005AB5DA, + ); + isa = PBXGroup; + path = quake3; + refType = 4; + sourceTree = ""; + }; + 1865129306253BE7005AB5DA = { + children = ( + 1865129406253BE7005AB5DA, + 1865129506253BE7005AB5DA, + 1865129606253BE7005AB5DA, + 1865129706253BE7005AB5DA, + 1865129806253BE7005AB5DA, + 1865129906253BE7005AB5DA, + 1865129A06253BE7005AB5DA, + 1865129B06253BE7005AB5DA, + 1865129C06253BE7005AB5DA, + 186512A106253BE7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865129406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865129506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865129606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865129706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865129806253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865129906253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865129A06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865129B06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865129C06253BE7005AB5DA = { + children = ( + 1865129D06253BE7005AB5DA, + 1865129E06253BE7005AB5DA, + 1865129F06253BE7005AB5DA, + 186512A006253BE7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865129D06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865129E06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865129F06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186512A006253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186512A106253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186512A206253BE7005AB5DA = { + children = ( + 186512A306253BE7005AB5DA, + ); + isa = PBXGroup; + path = code; + refType = 4; + sourceTree = ""; + }; + 186512A306253BE7005AB5DA = { + children = ( + 186512A406253BE7005AB5DA, + 186512A506253BE7005AB5DA, + 186512A606253BE7005AB5DA, + 186512A706253BE7005AB5DA, + 186512A806253BE7005AB5DA, + 186512A906253BE7005AB5DA, + 186512AA06253BE7005AB5DA, + 186512AB06253BE7005AB5DA, + 186512AC06253BE7005AB5DA, + 186512B106253BE8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186512A406253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186512A506253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186512A606253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186512A706253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186512A806253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186512A906253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186512AA06253BE7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186512AB06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186512AC06253BE7005AB5DA = { + children = ( + 186512AD06253BE7005AB5DA, + 186512AE06253BE7005AB5DA, + 186512AF06253BE8005AB5DA, + 186512B006253BE8005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186512AD06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186512AE06253BE7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186512AF06253BE8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186512B006253BE8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186512B106253BE8005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186512B206253BE8005AB5DA = { + children = ( + 186512B306253BE8005AB5DA, + 1865133A06253BE9005AB5DA, + 1865133B06253BE9005AB5DA, + 1865133C06253BE9005AB5DA, + 1865133D06253BE9005AB5DA, + 1865133E06253BE9005AB5DA, + 1865133F06253BE9005AB5DA, + 1865134006253BE9005AB5DA, + 1865134106253BE9005AB5DA, + 1865134206253BE9005AB5DA, + 1865134306253BE9005AB5DA, + 1865134406253BE9005AB5DA, + 1865134506253BE9005AB5DA, + 1865134606253BE9005AB5DA, + 1865134706253BE9005AB5DA, + 1865134806253BE9005AB5DA, + 1865134906253BEA005AB5DA, + 1865134A06253BEA005AB5DA, + 1865134B06253BEA005AB5DA, + 1865134C06253BEA005AB5DA, + 1865134D06253BEA005AB5DA, + 1865134E06253BEA005AB5DA, + 1865134F06253BEA005AB5DA, + 1865135006253BEA005AB5DA, + 1865135106253BEA005AB5DA, + 1865135206253BEA005AB5DA, + 1865135306253BEA005AB5DA, + 1865135406253BEA005AB5DA, + 1865135506253BEA005AB5DA, + 1865135606253BEA005AB5DA, + 1865135706253BEA005AB5DA, + ); + isa = PBXGroup; + path = common; + refType = 4; + sourceTree = ""; + }; + 186512B306253BE8005AB5DA = { + children = ( + 186512B406253BE8005AB5DA, + 186512B506253BE8005AB5DA, + 186512B606253BE8005AB5DA, + 186512B706253BE8005AB5DA, + 186512B806253BE8005AB5DA, + 186512D706253BE8005AB5DA, + 186512F606253BE9005AB5DA, + 186512F706253BE9005AB5DA, + 1865131606253BE9005AB5DA, + 1865131B06253BE9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186512B406253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186512B506253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186512B606253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186512B706253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186512B806253BE8005AB5DA = { + children = ( + 186512B906253BE8005AB5DA, + 186512BA06253BE8005AB5DA, + 186512BB06253BE8005AB5DA, + 186512BC06253BE8005AB5DA, + 186512BD06253BE8005AB5DA, + 186512BE06253BE8005AB5DA, + 186512BF06253BE8005AB5DA, + 186512C006253BE8005AB5DA, + 186512C106253BE8005AB5DA, + 186512C206253BE8005AB5DA, + 186512C306253BE8005AB5DA, + 186512C406253BE8005AB5DA, + 186512C506253BE8005AB5DA, + 186512C606253BE8005AB5DA, + 186512C706253BE8005AB5DA, + 186512C806253BE8005AB5DA, + 186512C906253BE8005AB5DA, + 186512CA06253BE8005AB5DA, + 186512CB06253BE8005AB5DA, + 186512CC06253BE8005AB5DA, + 186512CD06253BE8005AB5DA, + 186512CE06253BE8005AB5DA, + 186512CF06253BE8005AB5DA, + 186512D006253BE8005AB5DA, + 186512D106253BE8005AB5DA, + 186512D206253BE8005AB5DA, + 186512D306253BE8005AB5DA, + 186512D406253BE8005AB5DA, + 186512D506253BE8005AB5DA, + 186512D606253BE8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186512B906253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512BA06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512BB06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512BC06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512BD06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512BE06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512BF06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C006253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C106253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C206253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C306253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C406253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C506253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C606253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C706253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C806253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512C906253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512CA06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512CB06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512CC06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qthreads.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512CD06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512CE06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512CF06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflags.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D006253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D106253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D206253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D306253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D406253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D506253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D606253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512D706253BE8005AB5DA = { + children = ( + 186512D806253BE8005AB5DA, + 186512D906253BE8005AB5DA, + 186512DA06253BE8005AB5DA, + 186512DB06253BE8005AB5DA, + 186512DC06253BE8005AB5DA, + 186512DD06253BE8005AB5DA, + 186512DE06253BE8005AB5DA, + 186512DF06253BE8005AB5DA, + 186512E006253BE8005AB5DA, + 186512E106253BE8005AB5DA, + 186512E206253BE8005AB5DA, + 186512E306253BE8005AB5DA, + 186512E406253BE8005AB5DA, + 186512E506253BE8005AB5DA, + 186512E606253BE8005AB5DA, + 186512E706253BE8005AB5DA, + 186512E806253BE8005AB5DA, + 186512E906253BE8005AB5DA, + 186512EA06253BE8005AB5DA, + 186512EB06253BE8005AB5DA, + 186512EC06253BE8005AB5DA, + 186512ED06253BE8005AB5DA, + 186512EE06253BE8005AB5DA, + 186512EF06253BE8005AB5DA, + 186512F006253BE8005AB5DA, + 186512F106253BE8005AB5DA, + 186512F206253BE8005AB5DA, + 186512F306253BE9005AB5DA, + 186512F406253BE9005AB5DA, + 186512F506253BE9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186512D806253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512D906253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512DA06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512DB06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512DC06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512DD06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512DE06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512DF06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E006253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E106253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E206253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E306253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E406253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E506253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E606253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E706253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E806253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512E906253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512EA06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512EB06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qthreads.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512EC06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512ED06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512EE06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflags.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512EF06253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F006253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F106253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F206253BE8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F306253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F406253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F506253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186512F606253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186512F706253BE9005AB5DA = { + children = ( + 186512F806253BE9005AB5DA, + 186512F906253BE9005AB5DA, + 186512FA06253BE9005AB5DA, + 186512FB06253BE9005AB5DA, + 186512FC06253BE9005AB5DA, + 186512FD06253BE9005AB5DA, + 186512FE06253BE9005AB5DA, + 186512FF06253BE9005AB5DA, + 1865130006253BE9005AB5DA, + 1865130106253BE9005AB5DA, + 1865130206253BE9005AB5DA, + 1865130306253BE9005AB5DA, + 1865130406253BE9005AB5DA, + 1865130506253BE9005AB5DA, + 1865130606253BE9005AB5DA, + 1865130706253BE9005AB5DA, + 1865130806253BE9005AB5DA, + 1865130906253BE9005AB5DA, + 1865130A06253BE9005AB5DA, + 1865130B06253BE9005AB5DA, + 1865130C06253BE9005AB5DA, + 1865130D06253BE9005AB5DA, + 1865130E06253BE9005AB5DA, + 1865130F06253BE9005AB5DA, + 1865131006253BE9005AB5DA, + 1865131106253BE9005AB5DA, + 1865131206253BE9005AB5DA, + 1865131306253BE9005AB5DA, + 1865131406253BE9005AB5DA, + 1865131506253BE9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186512F806253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512F906253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512FA06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512FB06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512FC06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512FD06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512FE06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186512FF06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130006253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130106253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130206253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130306253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130406253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130506253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130606253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130706253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130806253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130906253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130A06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130B06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qthreads.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130C06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130D06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130E06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflags.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865130F06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131006253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131106253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131206253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131306253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131406253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131506253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865131606253BE9005AB5DA = { + children = ( + 1865131706253BE9005AB5DA, + 1865131806253BE9005AB5DA, + 1865131906253BE9005AB5DA, + 1865131A06253BE9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865131706253BE9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865131806253BE9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865131906253BE9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865131A06253BE9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865131B06253BE9005AB5DA = { + children = ( + 1865131C06253BE9005AB5DA, + 1865131D06253BE9005AB5DA, + 1865131E06253BE9005AB5DA, + 1865131F06253BE9005AB5DA, + 1865132006253BE9005AB5DA, + 1865132106253BE9005AB5DA, + 1865132206253BE9005AB5DA, + 1865132306253BE9005AB5DA, + 1865132406253BE9005AB5DA, + 1865132506253BE9005AB5DA, + 1865132606253BE9005AB5DA, + 1865132706253BE9005AB5DA, + 1865132806253BE9005AB5DA, + 1865132906253BE9005AB5DA, + 1865132A06253BE9005AB5DA, + 1865132B06253BE9005AB5DA, + 1865132C06253BE9005AB5DA, + 1865132D06253BE9005AB5DA, + 1865132E06253BE9005AB5DA, + 1865132F06253BE9005AB5DA, + 1865133006253BE9005AB5DA, + 1865133106253BE9005AB5DA, + 1865133206253BE9005AB5DA, + 1865133306253BE9005AB5DA, + 1865133406253BE9005AB5DA, + 1865133506253BE9005AB5DA, + 1865133606253BE9005AB5DA, + 1865133706253BE9005AB5DA, + 1865133806253BE9005AB5DA, + 1865133906253BE9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865131C06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865131D06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aselib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865131E06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865131F06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132006253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132106253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132206253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132306253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagelib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132406253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132506253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inout.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132606253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132706253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132806253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132906253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132A06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mutex.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132B06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132C06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polylib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132D06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132E06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qfiles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865132F06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qthreads.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133006253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133106253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "scriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133206253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflags.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133306253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "threads.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133406253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133506253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "trilib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133606253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133706253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133806253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133906253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865133A06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = aselib.c; + refType = 4; + sourceTree = ""; + }; + 1865133B06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = aselib.h; + refType = 4; + sourceTree = ""; + }; + 1865133C06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bspfile.c; + refType = 4; + sourceTree = ""; + }; + 1865133D06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bspfile.h; + refType = 4; + sourceTree = ""; + }; + 1865133E06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = cmdlib.c; + refType = 4; + sourceTree = ""; + }; + 1865133F06253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = cmdlib.h; + refType = 4; + sourceTree = ""; + }; + 1865134006253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = imagelib.c; + refType = 4; + sourceTree = ""; + }; + 1865134106253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imagelib.h; + refType = 4; + sourceTree = ""; + }; + 1865134206253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = inout.c; + refType = 4; + sourceTree = ""; + }; + 1865134306253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = inout.h; + refType = 4; + sourceTree = ""; + }; + 1865134406253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = l3dslib.c; + refType = 4; + sourceTree = ""; + }; + 1865134506253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = l3dslib.h; + refType = 4; + sourceTree = ""; + }; + 1865134606253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = md4.c; + refType = 4; + sourceTree = ""; + }; + 1865134706253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = mutex.c; + refType = 4; + sourceTree = ""; + }; + 1865134806253BE9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = mutex.h; + refType = 4; + sourceTree = ""; + }; + 1865134906253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = polylib.c; + refType = 4; + sourceTree = ""; + }; + 1865134A06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = polylib.h; + refType = 4; + sourceTree = ""; + }; + 1865134B06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = polyset.h; + refType = 4; + sourceTree = ""; + }; + 1865134C06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qfiles.h; + refType = 4; + sourceTree = ""; + }; + 1865134D06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qthreads.h; + refType = 4; + sourceTree = ""; + }; + 1865134E06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = scriplib.c; + refType = 4; + sourceTree = ""; + }; + 1865134F06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = scriplib.h; + refType = 4; + sourceTree = ""; + }; + 1865135006253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfaceflags.h; + refType = 4; + sourceTree = ""; + }; + 1865135106253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = threads.c; + refType = 4; + sourceTree = ""; + }; + 1865135206253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = trilib.c; + refType = 4; + sourceTree = ""; + }; + 1865135306253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = trilib.h; + refType = 4; + sourceTree = ""; + }; + 1865135406253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = unzip.c; + refType = 4; + sourceTree = ""; + }; + 1865135506253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = unzip.h; + refType = 4; + sourceTree = ""; + }; + 1865135606253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = vfs.c; + refType = 4; + sourceTree = ""; + }; + 1865135706253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = vfs.h; + refType = 4; + sourceTree = ""; + }; + 1865135806253BEA005AB5DA = { + children = ( + 1865135906253BEA005AB5DA, + 1865135A06253BEA005AB5DA, + 1865135B06253BEA005AB5DA, + 186513B206253BEB005AB5DA, + 186513B306253BEB005AB5DA, + 186513B406253BEB005AB5DA, + 186513B506253BEB005AB5DA, + 186513B606253BEB005AB5DA, + 186513B706253BEB005AB5DA, + 186513B806253BEB005AB5DA, + 186513B906253BEB005AB5DA, + 186513BA06253BEB005AB5DA, + 186513BB06253BEB005AB5DA, + 186513BC06253BEB005AB5DA, + 186513BD06253BEB005AB5DA, + 186513BE06253BEB005AB5DA, + 186513BF06253BEB005AB5DA, + 186513C006253BEB005AB5DA, + 186513C106253BEB005AB5DA, + ); + isa = PBXGroup; + path = q3data; + refType = 4; + sourceTree = ""; + }; + 1865135906253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865135A06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvswrappers; + refType = 4; + sourceTree = ""; + }; + 1865135B06253BEA005AB5DA = { + children = ( + 1865135C06253BEA005AB5DA, + 1865135D06253BEA005AB5DA, + 1865135E06253BEA005AB5DA, + 1865135F06253BEA005AB5DA, + 1865136006253BEA005AB5DA, + 1865137306253BEA005AB5DA, + 1865138606253BEA005AB5DA, + 1865138706253BEA005AB5DA, + 1865139A06253BEA005AB5DA, + 1865139F06253BEB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865135C06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865135D06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865135E06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865135F06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865136006253BEA005AB5DA = { + children = ( + 1865136106253BEA005AB5DA, + 1865136206253BEA005AB5DA, + 1865136306253BEA005AB5DA, + 1865136406253BEA005AB5DA, + 1865136506253BEA005AB5DA, + 1865136606253BEA005AB5DA, + 1865136706253BEA005AB5DA, + 1865136806253BEA005AB5DA, + 1865136906253BEA005AB5DA, + 1865136A06253BEA005AB5DA, + 1865136B06253BEA005AB5DA, + 1865136C06253BEA005AB5DA, + 1865136D06253BEA005AB5DA, + 1865136E06253BEA005AB5DA, + 1865136F06253BEA005AB5DA, + 1865137006253BEA005AB5DA, + 1865137106253BEA005AB5DA, + 1865137206253BEA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865136106253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136206253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136306253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136406253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136506253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "compress.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136606253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136706253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136806253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136906253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136A06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "oldstuff.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136B06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136C06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136D06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136E06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865136F06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865137006253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865137106253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stripper.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865137206253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865137306253BEA005AB5DA = { + children = ( + 1865137406253BEA005AB5DA, + 1865137506253BEA005AB5DA, + 1865137606253BEA005AB5DA, + 1865137706253BEA005AB5DA, + 1865137806253BEA005AB5DA, + 1865137906253BEA005AB5DA, + 1865137A06253BEA005AB5DA, + 1865137B06253BEA005AB5DA, + 1865137C06253BEA005AB5DA, + 1865137D06253BEA005AB5DA, + 1865137E06253BEA005AB5DA, + 1865137F06253BEA005AB5DA, + 1865138006253BEA005AB5DA, + 1865138106253BEA005AB5DA, + 1865138206253BEA005AB5DA, + 1865138306253BEA005AB5DA, + 1865138406253BEA005AB5DA, + 1865138506253BEA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865137406253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137506253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137606253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137706253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137806253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "compress.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137906253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137A06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137B06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137C06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137D06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "oldstuff.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137E06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865137F06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138006253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138106253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138206253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138306253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138406253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stripper.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138506253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865138606253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865138706253BEA005AB5DA = { + children = ( + 1865138806253BEA005AB5DA, + 1865138906253BEA005AB5DA, + 1865138A06253BEA005AB5DA, + 1865138B06253BEA005AB5DA, + 1865138C06253BEA005AB5DA, + 1865138D06253BEA005AB5DA, + 1865138E06253BEA005AB5DA, + 1865138F06253BEA005AB5DA, + 1865139006253BEA005AB5DA, + 1865139106253BEA005AB5DA, + 1865139206253BEA005AB5DA, + 1865139306253BEA005AB5DA, + 1865139406253BEA005AB5DA, + 1865139506253BEA005AB5DA, + 1865139606253BEA005AB5DA, + 1865139706253BEA005AB5DA, + 1865139806253BEA005AB5DA, + 1865139906253BEA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865138806253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138906253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138A06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138B06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138C06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "compress.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138D06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138E06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865138F06253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139006253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139106253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "oldstuff.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139206253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139306253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139406253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139506253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139606253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139706253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "q3data.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139806253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stripper.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139906253BEA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865139A06253BEA005AB5DA = { + children = ( + 1865139B06253BEA005AB5DA, + 1865139C06253BEA005AB5DA, + 1865139D06253BEA005AB5DA, + 1865139E06253BEA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865139B06253BEA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865139C06253BEA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865139D06253BEA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865139E06253BEA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865139F06253BEB005AB5DA = { + children = ( + 186513A006253BEB005AB5DA, + 186513A106253BEB005AB5DA, + 186513A206253BEB005AB5DA, + 186513A306253BEB005AB5DA, + 186513A406253BEB005AB5DA, + 186513A506253BEB005AB5DA, + 186513A606253BEB005AB5DA, + 186513A706253BEB005AB5DA, + 186513A806253BEB005AB5DA, + 186513A906253BEB005AB5DA, + 186513AA06253BEB005AB5DA, + 186513AB06253BEB005AB5DA, + 186513AC06253BEB005AB5DA, + 186513AD06253BEB005AB5DA, + 186513AE06253BEB005AB5DA, + 186513AF06253BEB005AB5DA, + 186513B006253BEB005AB5DA, + 186513B106253BEB005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186513A006253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A106253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A206253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A306253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "3dslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "compress.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "images.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3lib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A806253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "models.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513A906253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "oldstuff.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513AA06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513AB06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "p3dlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513AC06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "polyset.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513AD06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513AE06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513AF06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3data.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513B006253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stripper.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513B106253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "video.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186513B206253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = 3dslib.c; + refType = 4; + sourceTree = ""; + }; + 186513B306253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = 3dslib.h; + refType = 4; + sourceTree = ""; + }; + 186513B406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = compress.c; + refType = 4; + sourceTree = ""; + }; + 186513B506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = images.c; + refType = 4; + sourceTree = ""; + }; + 186513B606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = md3lib.c; + refType = 4; + sourceTree = ""; + }; + 186513B706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = md3lib.h; + refType = 4; + sourceTree = ""; + }; + 186513B806253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = models.c; + refType = 4; + sourceTree = ""; + }; + 186513B906253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = oldstuff.c; + refType = 4; + sourceTree = ""; + }; + 186513BA06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = p3dlib.c; + refType = 4; + sourceTree = ""; + }; + 186513BB06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = p3dlib.h; + refType = 4; + sourceTree = ""; + }; + 186513BC06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = polyset.c; + refType = 4; + sourceTree = ""; + }; + 186513BD06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = q3data.c; + refType = 4; + sourceTree = ""; + }; + 186513BE06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q3data.h; + refType = 4; + sourceTree = ""; + }; + 186513BF06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = q3data.vcproj; + refType = 4; + sourceTree = ""; + }; + 186513C006253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = stripper.c; + refType = 4; + sourceTree = ""; + }; + 186513C106253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = video.c; + refType = 4; + sourceTree = ""; + }; + 186513C206253BEB005AB5DA = { + children = ( + 186513C306253BEB005AB5DA, + 186513D206253BEB005AB5DA, + ); + isa = PBXGroup; + path = q3map; + refType = 4; + sourceTree = ""; + }; + 186513C306253BEB005AB5DA = { + children = ( + 186513C406253BEB005AB5DA, + 186513C506253BEB005AB5DA, + 186513C606253BEB005AB5DA, + 186513C706253BEB005AB5DA, + 186513C806253BEB005AB5DA, + 186513C906253BEB005AB5DA, + 186513CA06253BEB005AB5DA, + 186513CB06253BEB005AB5DA, + 186513CC06253BEB005AB5DA, + 186513D106253BEB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186513C406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186513C506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186513C606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186513C706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186513C806253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186513C906253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186513CA06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186513CB06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186513CC06253BEB005AB5DA = { + children = ( + 186513CD06253BEB005AB5DA, + 186513CE06253BEB005AB5DA, + 186513CF06253BEB005AB5DA, + 186513D006253BEB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186513CD06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186513CE06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186513CF06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186513D006253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186513D106253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186513D206253BEB005AB5DA = { + children = ( + 186513D306253BEB005AB5DA, + ); + isa = PBXGroup; + path = NetTest; + refType = 4; + sourceTree = ""; + }; + 186513D306253BEB005AB5DA = { + children = ( + 186513D406253BEB005AB5DA, + 186513D506253BEB005AB5DA, + 186513D606253BEB005AB5DA, + 186513D706253BEB005AB5DA, + 186513D806253BEB005AB5DA, + 186513D906253BEB005AB5DA, + 186513DA06253BEB005AB5DA, + 186513DB06253BEB005AB5DA, + 186513DC06253BEB005AB5DA, + 186513E106253BEB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186513D406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186513D506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186513D606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186513D706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186513D806253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186513D906253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186513DA06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 186513DB06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186513DC06253BEB005AB5DA = { + children = ( + 186513DD06253BEB005AB5DA, + 186513DE06253BEB005AB5DA, + 186513DF06253BEB005AB5DA, + 186513E006253BEB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 186513DD06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186513DE06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 186513DF06253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 186513E006253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186513E106253BEB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 186513E206253BEB005AB5DA = { + children = ( + 186513E306253BEB005AB5DA, + 186513E406253BEB005AB5DA, + 186514D306253BEE005AB5DA, + 186514D406253BEE005AB5DA, + 186514D506253BEE005AB5DA, + 186514D606253BEE005AB5DA, + 186514D706253BEE005AB5DA, + 186514D806253BEE005AB5DA, + 186514D906253BEE005AB5DA, + 186514DA06253BEE005AB5DA, + 186514DB06253BEE005AB5DA, + 186514DC06253BEE005AB5DA, + 186514DD06253BEE005AB5DA, + 186514DE06253BEE005AB5DA, + 186514DF06253BEE005AB5DA, + 186514E006253BEE005AB5DA, + 186514E106253BEE005AB5DA, + 186514E206253BEE005AB5DA, + 186514E306253BEE005AB5DA, + 186514E406253BEE005AB5DA, + 186514E506253BEE005AB5DA, + 186514E606253BEE005AB5DA, + 186514E706253BEE005AB5DA, + 186514E806253BEE005AB5DA, + 186514E906253BEE005AB5DA, + 186514EA06253BEE005AB5DA, + 186514EB06253BEE005AB5DA, + 186514EC06253BEE005AB5DA, + 186514ED06253BEE005AB5DA, + 186514EE06253BEE005AB5DA, + 186514EF06253BEE005AB5DA, + 186514F006253BEE005AB5DA, + 186514F106253BEE005AB5DA, + 186514F206253BEE005AB5DA, + 186514F306253BEE005AB5DA, + 186514F406253BEE005AB5DA, + 186514F506253BEE005AB5DA, + 186514F606253BEE005AB5DA, + 186514F706253BEE005AB5DA, + 186514F806253BEE005AB5DA, + 186514F906253BEE005AB5DA, + 186514FA06253BEE005AB5DA, + 186514FB06253BEE005AB5DA, + 186514FC06253BEE005AB5DA, + 186514FD06253BEE005AB5DA, + 186514FE06253BEE005AB5DA, + 186514FF06253BEE005AB5DA, + 1865150006253BEE005AB5DA, + 1865150106253BEE005AB5DA, + 1865150206253BEE005AB5DA, + 1865150306253BEE005AB5DA, + 1865150406253BEE005AB5DA, + 1865150506253BEE005AB5DA, + 1865150606253BEE005AB5DA, + 1865150706253BEE005AB5DA, + 1865150806253BEE005AB5DA, + 1865150906253BEE005AB5DA, + ); + isa = PBXGroup; + path = q3map2; + refType = 4; + sourceTree = ""; + }; + 186513E306253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 186513E406253BEB005AB5DA = { + children = ( + 186513E506253BEB005AB5DA, + 186513E606253BEB005AB5DA, + 186513E706253BEB005AB5DA, + 186513E806253BEB005AB5DA, + 186513E906253BEB005AB5DA, + 1865142206253BEC005AB5DA, + 1865145B06253BEC005AB5DA, + 1865145C06253BEC005AB5DA, + 1865149506253BED005AB5DA, + 1865149A06253BED005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 186513E506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 186513E606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 186513E706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 186513E806253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 186513E906253BEB005AB5DA = { + children = ( + 186513EA06253BEB005AB5DA, + 186513EB06253BEB005AB5DA, + 186513EC06253BEB005AB5DA, + 186513ED06253BEB005AB5DA, + 186513EE06253BEB005AB5DA, + 186513EF06253BEB005AB5DA, + 186513F006253BEB005AB5DA, + 186513F106253BEB005AB5DA, + 186513F206253BEB005AB5DA, + 186513F306253BEB005AB5DA, + 186513F406253BEB005AB5DA, + 186513F506253BEB005AB5DA, + 186513F606253BEB005AB5DA, + 186513F706253BEB005AB5DA, + 186513F806253BEB005AB5DA, + 186513F906253BEB005AB5DA, + 186513FA06253BEB005AB5DA, + 186513FB06253BEB005AB5DA, + 186513FC06253BEB005AB5DA, + 186513FD06253BEB005AB5DA, + 186513FE06253BEB005AB5DA, + 186513FF06253BEB005AB5DA, + 1865140006253BEB005AB5DA, + 1865140106253BEB005AB5DA, + 1865140206253BEB005AB5DA, + 1865140306253BEB005AB5DA, + 1865140406253BEB005AB5DA, + 1865140506253BEB005AB5DA, + 1865140606253BEB005AB5DA, + 1865140706253BEB005AB5DA, + 1865140806253BEB005AB5DA, + 1865140906253BEB005AB5DA, + 1865140A06253BEB005AB5DA, + 1865140B06253BEB005AB5DA, + 1865140C06253BEB005AB5DA, + 1865140D06253BEB005AB5DA, + 1865140E06253BEB005AB5DA, + 1865140F06253BEB005AB5DA, + 1865141006253BEB005AB5DA, + 1865141106253BEB005AB5DA, + 1865141206253BEB005AB5DA, + 1865141306253BEB005AB5DA, + 1865141406253BEB005AB5DA, + 1865141506253BEB005AB5DA, + 1865141606253BEB005AB5DA, + 1865141706253BEB005AB5DA, + 1865141806253BEB005AB5DA, + 1865141906253BEB005AB5DA, + 1865141A06253BEB005AB5DA, + 1865141B06253BEB005AB5DA, + 1865141C06253BEB005AB5DA, + 1865141D06253BEB005AB5DA, + 1865141E06253BEB005AB5DA, + 1865141F06253BEB005AB5DA, + 1865142006253BEC005AB5DA, + 1865142106253BEC005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 186513EA06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513EB06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513EC06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513ED06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513EE06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_abstract.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513EF06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_ibsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F006253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_rbsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F106253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map1.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F206253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map2.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F306253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_ase.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_map.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "decals.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "facebsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fog.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F806253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ef.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513F906253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ja.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513FA06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_jk2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513FB06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_quake3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513FC06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_sof2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513FD06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_t.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513FE06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_tenebrae.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 186513FF06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolf.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140006253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolfet.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140106253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140206253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140306253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_bounce.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_shadows.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_trace.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_ydnar.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140806253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140906253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps_ydnar.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140A06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listen.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140B06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140C06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140D06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mesh.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140E06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865140F06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141006253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141106253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141206253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141306253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141406253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.ico.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141506253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141606253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141706253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141806253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141906253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_extra.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141A06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_foliage.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141B06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_fur.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141C06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_meta.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141D06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tjunction.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141E06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865141F06253BEB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vis.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865142006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visflow.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865142106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865142206253BEC005AB5DA = { + children = ( + 1865142306253BEC005AB5DA, + 1865142406253BEC005AB5DA, + 1865142506253BEC005AB5DA, + 1865142606253BEC005AB5DA, + 1865142706253BEC005AB5DA, + 1865142806253BEC005AB5DA, + 1865142906253BEC005AB5DA, + 1865142A06253BEC005AB5DA, + 1865142B06253BEC005AB5DA, + 1865142C06253BEC005AB5DA, + 1865142D06253BEC005AB5DA, + 1865142E06253BEC005AB5DA, + 1865142F06253BEC005AB5DA, + 1865143006253BEC005AB5DA, + 1865143106253BEC005AB5DA, + 1865143206253BEC005AB5DA, + 1865143306253BEC005AB5DA, + 1865143406253BEC005AB5DA, + 1865143506253BEC005AB5DA, + 1865143606253BEC005AB5DA, + 1865143706253BEC005AB5DA, + 1865143806253BEC005AB5DA, + 1865143906253BEC005AB5DA, + 1865143A06253BEC005AB5DA, + 1865143B06253BEC005AB5DA, + 1865143C06253BEC005AB5DA, + 1865143D06253BEC005AB5DA, + 1865143E06253BEC005AB5DA, + 1865143F06253BEC005AB5DA, + 1865144006253BEC005AB5DA, + 1865144106253BEC005AB5DA, + 1865144206253BEC005AB5DA, + 1865144306253BEC005AB5DA, + 1865144406253BEC005AB5DA, + 1865144506253BEC005AB5DA, + 1865144606253BEC005AB5DA, + 1865144706253BEC005AB5DA, + 1865144806253BEC005AB5DA, + 1865144906253BEC005AB5DA, + 1865144A06253BEC005AB5DA, + 1865144B06253BEC005AB5DA, + 1865144C06253BEC005AB5DA, + 1865144D06253BEC005AB5DA, + 1865144E06253BEC005AB5DA, + 1865144F06253BEC005AB5DA, + 1865145006253BEC005AB5DA, + 1865145106253BEC005AB5DA, + 1865145206253BEC005AB5DA, + 1865145306253BEC005AB5DA, + 1865145406253BEC005AB5DA, + 1865145506253BEC005AB5DA, + 1865145606253BEC005AB5DA, + 1865145706253BEC005AB5DA, + 1865145806253BEC005AB5DA, + 1865145906253BEC005AB5DA, + 1865145A06253BEC005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865142306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142406253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142506253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142606253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142706253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_abstract.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142806253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_ibsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142906253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_rbsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142A06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map1.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142B06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map2.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142C06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_ase.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142D06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_map.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142E06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "decals.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865142F06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "facebsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fog.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ef.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143206253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ja.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_jk2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143406253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_quake3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143506253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_sof2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143606253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_t.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143706253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_tenebrae.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143806253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolf.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143906253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolfet.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143A06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143B06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143C06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143D06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_bounce.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143E06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_shadows.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865143F06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_trace.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_ydnar.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144206253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps_ydnar.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listen.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144406253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144506253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144606253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mesh.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144706253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144806253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144906253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144A06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144B06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144C06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144D06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.ico.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144E06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865144F06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145206253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_extra.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_foliage.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145406253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_fur.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145506253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_meta.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145606253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tjunction.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145706253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145806253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vis.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145906253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visflow.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145A06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865145B06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865145C06253BEC005AB5DA = { + children = ( + 1865145D06253BEC005AB5DA, + 1865145E06253BEC005AB5DA, + 1865145F06253BEC005AB5DA, + 1865146006253BEC005AB5DA, + 1865146106253BEC005AB5DA, + 1865146206253BEC005AB5DA, + 1865146306253BEC005AB5DA, + 1865146406253BEC005AB5DA, + 1865146506253BEC005AB5DA, + 1865146606253BEC005AB5DA, + 1865146706253BEC005AB5DA, + 1865146806253BEC005AB5DA, + 1865146906253BEC005AB5DA, + 1865146A06253BEC005AB5DA, + 1865146B06253BEC005AB5DA, + 1865146C06253BEC005AB5DA, + 1865146D06253BEC005AB5DA, + 1865146E06253BEC005AB5DA, + 1865146F06253BEC005AB5DA, + 1865147006253BEC005AB5DA, + 1865147106253BEC005AB5DA, + 1865147206253BEC005AB5DA, + 1865147306253BEC005AB5DA, + 1865147406253BEC005AB5DA, + 1865147506253BEC005AB5DA, + 1865147606253BEC005AB5DA, + 1865147706253BEC005AB5DA, + 1865147806253BEC005AB5DA, + 1865147906253BEC005AB5DA, + 1865147A06253BEC005AB5DA, + 1865147B06253BEC005AB5DA, + 1865147C06253BEC005AB5DA, + 1865147D06253BEC005AB5DA, + 1865147E06253BEC005AB5DA, + 1865147F06253BEC005AB5DA, + 1865148006253BEC005AB5DA, + 1865148106253BEC005AB5DA, + 1865148206253BEC005AB5DA, + 1865148306253BEC005AB5DA, + 1865148406253BED005AB5DA, + 1865148506253BED005AB5DA, + 1865148606253BED005AB5DA, + 1865148706253BED005AB5DA, + 1865148806253BED005AB5DA, + 1865148906253BED005AB5DA, + 1865148A06253BED005AB5DA, + 1865148B06253BED005AB5DA, + 1865148C06253BED005AB5DA, + 1865148D06253BED005AB5DA, + 1865148E06253BED005AB5DA, + 1865148F06253BED005AB5DA, + 1865149006253BED005AB5DA, + 1865149106253BED005AB5DA, + 1865149206253BED005AB5DA, + 1865149306253BED005AB5DA, + 1865149406253BED005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865145D06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865145E06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865145F06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_abstract.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146206253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_ibsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_rbsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146406253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map1.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146506253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map2.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146606253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_ase.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146706253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_map.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146806253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "decals.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146906253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "facebsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146A06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fog.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146B06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ef.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146C06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ja.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146D06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_jk2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146E06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_quake3.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865146F06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_sof2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_t.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_tenebrae.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147206253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolf.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolfet.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147406253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147506253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147606253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147706253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_bounce.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147806253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_shadows.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147906253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_trace.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147A06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_ydnar.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147B06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147C06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps_ydnar.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147D06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.perl; + path = "listen.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147E06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865147F06253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148006253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mesh.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148106253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148206253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148306253BEC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148406253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148506253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148606253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148706253BED005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "q3map2.ico.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148806253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148906253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "q3map2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148A06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148B06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148C06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_extra.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148D06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_foliage.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148E06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_fur.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865148F06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_meta.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865149006253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tjunction.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865149106253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865149206253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vis.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865149306253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visflow.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865149406253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865149506253BED005AB5DA = { + children = ( + 1865149606253BED005AB5DA, + 1865149706253BED005AB5DA, + 1865149806253BED005AB5DA, + 1865149906253BED005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865149606253BED005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865149706253BED005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865149806253BED005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865149906253BED005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865149A06253BED005AB5DA = { + children = ( + 1865149B06253BED005AB5DA, + 1865149C06253BED005AB5DA, + 1865149D06253BED005AB5DA, + 1865149E06253BED005AB5DA, + 1865149F06253BED005AB5DA, + 186514A006253BED005AB5DA, + 186514A106253BED005AB5DA, + 186514A206253BED005AB5DA, + 186514A306253BED005AB5DA, + 186514A406253BED005AB5DA, + 186514A506253BED005AB5DA, + 186514A606253BED005AB5DA, + 186514A706253BED005AB5DA, + 186514A806253BED005AB5DA, + 186514A906253BED005AB5DA, + 186514AA06253BED005AB5DA, + 186514AB06253BED005AB5DA, + 186514AC06253BED005AB5DA, + 186514AD06253BED005AB5DA, + 186514AE06253BED005AB5DA, + 186514AF06253BED005AB5DA, + 186514B006253BED005AB5DA, + 186514B106253BED005AB5DA, + 186514B206253BED005AB5DA, + 186514B306253BED005AB5DA, + 186514B406253BED005AB5DA, + 186514B506253BED005AB5DA, + 186514B606253BED005AB5DA, + 186514B706253BED005AB5DA, + 186514B806253BED005AB5DA, + 186514B906253BED005AB5DA, + 186514BA06253BED005AB5DA, + 186514BB06253BED005AB5DA, + 186514BC06253BED005AB5DA, + 186514BD06253BED005AB5DA, + 186514BE06253BED005AB5DA, + 186514BF06253BED005AB5DA, + 186514C006253BED005AB5DA, + 186514C106253BED005AB5DA, + 186514C206253BED005AB5DA, + 186514C306253BED005AB5DA, + 186514C406253BED005AB5DA, + 186514C506253BED005AB5DA, + 186514C606253BED005AB5DA, + 186514C706253BED005AB5DA, + 186514C806253BED005AB5DA, + 186514C906253BEE005AB5DA, + 186514CA06253BEE005AB5DA, + 186514CB06253BEE005AB5DA, + 186514CC06253BEE005AB5DA, + 186514CD06253BEE005AB5DA, + 186514CE06253BEE005AB5DA, + 186514CF06253BEE005AB5DA, + 186514D006253BEE005AB5DA, + 186514D106253BEE005AB5DA, + 186514D206253BEE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865149B06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865149C06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865149D06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brush_primit.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865149E06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865149F06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_abstract.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A006253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_ibsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A106253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspfile_rbsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A206253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map1.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A306253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.q3map2.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A406253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_ase.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A506253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "convert_map.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A606253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "decals.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A706253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "facebsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A806253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fog.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514A906253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ef.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514AA06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_ja.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514AB06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_jk2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514AC06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_quake3.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514AD06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_sof2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514AE06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_t.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514AF06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_tenebrae.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B006253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolf.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B106253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "game_wolfet.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B206253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B306253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "leakfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B406253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B506253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_bounce.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B606253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_shadows.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B706253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_trace.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B806253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light_ydnar.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514B906253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514BA06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lightmaps_ydnar.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514BB06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listen.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514BC06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "main.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514BD06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514BE06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mesh.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514BF06253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C006253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "patch.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C106253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "path_init.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C206253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C306253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtfile.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C406253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C506253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.ico.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C606253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C706253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C806253BED005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514C906253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514CA06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_extra.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514CB06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_foliage.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514CC06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_fur.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514CD06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_meta.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514CE06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tjunction.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514CF06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tree.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514D006253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vis.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514D106253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visflow.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514D206253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "writebsp.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 186514D306253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = brush.c; + refType = 4; + sourceTree = ""; + }; + 186514D406253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = brush_primit.c; + refType = 4; + sourceTree = ""; + }; + 186514D506253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bsp.c; + refType = 4; + sourceTree = ""; + }; + 186514D606253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bspfile_abstract.c; + refType = 4; + sourceTree = ""; + }; + 186514D706253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bspfile_ibsp.c; + refType = 4; + sourceTree = ""; + }; + 186514D806253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bspfile_rbsp.c; + refType = 4; + sourceTree = ""; + }; + 186514D906253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = changelog.q3map1; + refType = 4; + sourceTree = ""; + }; + 186514DA06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = changelog.q3map2.txt; + refType = 4; + sourceTree = ""; + }; + 186514DB06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = convert_ase.c; + refType = 4; + sourceTree = ""; + }; + 186514DC06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = convert_map.c; + refType = 4; + sourceTree = ""; + }; + 186514DD06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = decals.c; + refType = 4; + sourceTree = ""; + }; + 186514DE06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = facebsp.c; + refType = 4; + sourceTree = ""; + }; + 186514DF06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = fog.c; + refType = 4; + sourceTree = ""; + }; + 186514E006253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_ef.h; + refType = 4; + sourceTree = ""; + }; + 186514E106253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_ja.h; + refType = 4; + sourceTree = ""; + }; + 186514E206253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_jk2.h; + refType = 4; + sourceTree = ""; + }; + 186514E306253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_quake3.h; + refType = 4; + sourceTree = ""; + }; + 186514E406253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_sof2.h; + refType = 4; + sourceTree = ""; + }; + 186514E506253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_t.h; + refType = 4; + sourceTree = ""; + }; + 186514E606253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_tenebrae.h; + refType = 4; + sourceTree = ""; + }; + 186514E706253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_wolf.h; + refType = 4; + sourceTree = ""; + }; + 186514E806253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = game_wolfet.h; + refType = 4; + sourceTree = ""; + }; + 186514E906253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = image.c; + refType = 4; + sourceTree = ""; + }; + 186514EA06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = leakfile.c; + refType = 4; + sourceTree = ""; + }; + 186514EB06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = light.c; + refType = 4; + sourceTree = ""; + }; + 186514EC06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = light_bounce.c; + refType = 4; + sourceTree = ""; + }; + 186514ED06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = light_shadows.c; + refType = 4; + sourceTree = ""; + }; + 186514EE06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = light_trace.c; + refType = 4; + sourceTree = ""; + }; + 186514EF06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = light_ydnar.c; + refType = 4; + sourceTree = ""; + }; + 186514F006253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lightmaps.c; + refType = 4; + sourceTree = ""; + }; + 186514F106253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lightmaps_ydnar.c; + refType = 4; + sourceTree = ""; + }; + 186514F206253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.perl; + path = listen.pl; + refType = 4; + sourceTree = ""; + }; + 186514F306253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = main.c; + refType = 4; + sourceTree = ""; + }; + 186514F406253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = map.c; + refType = 4; + sourceTree = ""; + }; + 186514F506253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = mesh.c; + refType = 4; + sourceTree = ""; + }; + 186514F606253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = model.c; + refType = 4; + sourceTree = ""; + }; + 186514F706253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = patch.c; + refType = 4; + sourceTree = ""; + }; + 186514F806253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = path_init.c; + refType = 4; + sourceTree = ""; + }; + 186514F906253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = portals.c; + refType = 4; + sourceTree = ""; + }; + 186514FA06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = prtfile.c; + refType = 4; + sourceTree = ""; + }; + 186514FB06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q3map2.h; + refType = 4; + sourceTree = ""; + }; + 186514FC06253BEE005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.ico; + path = q3map2.ico; + refType = 4; + sourceTree = ""; + }; + 186514FD06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3map2.rc; + refType = 4; + sourceTree = ""; + }; + 186514FE06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = q3map2.vcproj; + refType = 4; + sourceTree = ""; + }; + 186514FF06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = shaders.c; + refType = 4; + sourceTree = ""; + }; + 1865150006253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = surface.c; + refType = 4; + sourceTree = ""; + }; + 1865150106253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = surface_extra.c; + refType = 4; + sourceTree = ""; + }; + 1865150206253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = surface_foliage.c; + refType = 4; + sourceTree = ""; + }; + 1865150306253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = surface_fur.c; + refType = 4; + sourceTree = ""; + }; + 1865150406253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = surface_meta.c; + refType = 4; + sourceTree = ""; + }; + 1865150506253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = tjunction.c; + refType = 4; + sourceTree = ""; + }; + 1865150606253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = tree.c; + refType = 4; + sourceTree = ""; + }; + 1865150706253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = vis.c; + refType = 4; + sourceTree = ""; + }; + 1865150806253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = visflow.c; + refType = 4; + sourceTree = ""; + }; + 1865150906253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = writebsp.c; + refType = 4; + sourceTree = ""; + }; + 1865150A06253BEE005AB5DA = { + children = ( + 1865150B06253BEE005AB5DA, + ); + isa = PBXGroup; + path = vslick; + refType = 4; + sourceTree = ""; + }; + 1865150B06253BEE005AB5DA = { + children = ( + 1865150C06253BEE005AB5DA, + 1865150D06253BEE005AB5DA, + 1865150E06253BEE005AB5DA, + 1865150F06253BEE005AB5DA, + 1865151006253BEE005AB5DA, + 1865152006253BEE005AB5DA, + 1865153006253BEF005AB5DA, + 1865153106253BEF005AB5DA, + 1865154106253BEF005AB5DA, + 1865154606253BEF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865150C06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865150D06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865150E06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865150F06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865151006253BEE005AB5DA = { + children = ( + 1865151106253BEE005AB5DA, + 1865151206253BEE005AB5DA, + 1865151306253BEE005AB5DA, + 1865151406253BEE005AB5DA, + 1865151506253BEE005AB5DA, + 1865151606253BEE005AB5DA, + 1865151706253BEE005AB5DA, + 1865151806253BEE005AB5DA, + 1865151906253BEE005AB5DA, + 1865151A06253BEE005AB5DA, + 1865151B06253BEE005AB5DA, + 1865151C06253BEE005AB5DA, + 1865151D06253BEE005AB5DA, + 1865151E06253BEE005AB5DA, + 1865151F06253BEE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865151106253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151206253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151306253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151406253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151506253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151606253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151706253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151806253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3model.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151906253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pak.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151A06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pk3man.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151B06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151C06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151D06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151E06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textool.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865151F06253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865152006253BEE005AB5DA = { + children = ( + 1865152106253BEE005AB5DA, + 1865152206253BEF005AB5DA, + 1865152306253BEF005AB5DA, + 1865152406253BEF005AB5DA, + 1865152506253BEF005AB5DA, + 1865152606253BEF005AB5DA, + 1865152706253BEF005AB5DA, + 1865152806253BEF005AB5DA, + 1865152906253BEF005AB5DA, + 1865152A06253BEF005AB5DA, + 1865152B06253BEF005AB5DA, + 1865152C06253BEF005AB5DA, + 1865152D06253BEF005AB5DA, + 1865152E06253BEF005AB5DA, + 1865152F06253BEF005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865152106253BEE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152206253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152306253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152406253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152506253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152606253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152706253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152806253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3model.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152906253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pak.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152A06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pk3man.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152B06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152C06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152D06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152E06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textool.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865152F06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865153006253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865153106253BEF005AB5DA = { + children = ( + 1865153206253BEF005AB5DA, + 1865153306253BEF005AB5DA, + 1865153406253BEF005AB5DA, + 1865153506253BEF005AB5DA, + 1865153606253BEF005AB5DA, + 1865153706253BEF005AB5DA, + 1865153806253BEF005AB5DA, + 1865153906253BEF005AB5DA, + 1865153A06253BEF005AB5DA, + 1865153B06253BEF005AB5DA, + 1865153C06253BEF005AB5DA, + 1865153D06253BEF005AB5DA, + 1865153E06253BEF005AB5DA, + 1865153F06253BEF005AB5DA, + 1865154006253BEF005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865153206253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153306253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153406253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153506253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153606253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153706253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153806253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153906253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3model.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153A06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pak.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153B06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pk3man.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153C06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153D06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153E06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865153F06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textool.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865154006253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vpj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865154106253BEF005AB5DA = { + children = ( + 1865154206253BEF005AB5DA, + 1865154306253BEF005AB5DA, + 1865154406253BEF005AB5DA, + 1865154506253BEF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865154206253BEF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865154306253BEF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865154406253BEF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865154506253BEF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865154606253BEF005AB5DA = { + children = ( + 1865154706253BEF005AB5DA, + 1865154806253BEF005AB5DA, + 1865154906253BEF005AB5DA, + 1865154A06253BEF005AB5DA, + 1865154B06253BEF005AB5DA, + 1865154C06253BEF005AB5DA, + 1865154D06253BEF005AB5DA, + 1865154E06253BEF005AB5DA, + 1865154F06253BEF005AB5DA, + 1865155006253BEF005AB5DA, + 1865155106253BEF005AB5DA, + 1865155206253BEF005AB5DA, + 1865155306253BEF005AB5DA, + 1865155406253BEF005AB5DA, + 1865155506253BEF005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865154706253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154806253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154906253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154A06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154B06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154C06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154D06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154E06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md3model.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865154F06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pak.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155006253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pk3man.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155106253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155206253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Radiant.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155306253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155406253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "textool.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155506253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vfspk3.vpj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865155606253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.python; + path = win32_install.py; + refType = 4; + sourceTree = ""; + }; + 1865155706253BEF005AB5DA = { + children = ( + 1865155806253BEF005AB5DA, + 1865158306253BF0005AB5DA, + 1865158406253BF0005AB5DA, + 1865158506253BF0005AB5DA, + 1865158606253BF0005AB5DA, + 1865158706253BF0005AB5DA, + 1865158806253BF0005AB5DA, + 1865158906253BF0005AB5DA, + ); + isa = PBXGroup; + path = www; + refType = 4; + sourceTree = ""; + }; + 1865155806253BEF005AB5DA = { + children = ( + 1865155906253BEF005AB5DA, + 1865155A06253BEF005AB5DA, + 1865155B06253BEF005AB5DA, + 1865155C06253BEF005AB5DA, + 1865155D06253BEF005AB5DA, + 1865156506253BEF005AB5DA, + 1865156D06253BEF005AB5DA, + 1865156E06253BEF005AB5DA, + 1865157606253BF0005AB5DA, + 1865157B06253BF0005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865155906253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865155A06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865155B06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865155C06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865155D06253BEF005AB5DA = { + children = ( + 1865155E06253BEF005AB5DA, + 1865155F06253BEF005AB5DA, + 1865156006253BEF005AB5DA, + 1865156106253BEF005AB5DA, + 1865156206253BEF005AB5DA, + 1865156306253BEF005AB5DA, + 1865156406253BEF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865155E06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bug.shtml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865155F06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "coding.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865156006253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865156106253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkradiant.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865156206253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hosted.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865156306253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865156406253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reviews.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865156506253BEF005AB5DA = { + children = ( + 1865156606253BEF005AB5DA, + 1865156706253BEF005AB5DA, + 1865156806253BEF005AB5DA, + 1865156906253BEF005AB5DA, + 1865156A06253BEF005AB5DA, + 1865156B06253BEF005AB5DA, + 1865156C06253BEF005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865156606253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bug.shtml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156706253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "coding.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156806253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156906253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkradiant.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156A06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hosted.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156B06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156C06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reviews.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865156D06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865156E06253BEF005AB5DA = { + children = ( + 1865156F06253BEF005AB5DA, + 1865157006253BF0005AB5DA, + 1865157106253BF0005AB5DA, + 1865157206253BF0005AB5DA, + 1865157306253BF0005AB5DA, + 1865157406253BF0005AB5DA, + 1865157506253BF0005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865156F06253BEF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bug.shtml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157006253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "coding.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157106253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157206253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkradiant.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157306253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hosted.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157406253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157506253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reviews.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865157606253BF0005AB5DA = { + children = ( + 1865157706253BF0005AB5DA, + 1865157806253BF0005AB5DA, + 1865157906253BF0005AB5DA, + 1865157A06253BF0005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865157706253BF0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865157806253BF0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865157906253BF0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865157A06253BF0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865157B06253BF0005AB5DA = { + children = ( + 1865157C06253BF0005AB5DA, + 1865157D06253BF0005AB5DA, + 1865157E06253BF0005AB5DA, + 1865157F06253BF0005AB5DA, + 1865158006253BF0005AB5DA, + 1865158106253BF0005AB5DA, + 1865158206253BF0005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865157C06253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bug.shtml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865157D06253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "coding.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865157E06253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865157F06253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkradiant.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865158006253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hosted.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865158106253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865158206253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reviews.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865158306253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html.other; + path = bug.shtml; + refType = 4; + sourceTree = ""; + }; + 1865158406253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = coding.html; + refType = 4; + sourceTree = ""; + }; + 1865158506253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = files.html; + refType = 4; + sourceTree = ""; + }; + 1865158606253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = gtkradiant.html; + refType = 4; + sourceTree = ""; + }; + 1865158706253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = hosted.html; + refType = 4; + sourceTree = ""; + }; + 1865158806253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = index.html; + refType = 4; + sourceTree = ""; + }; + 1865158906253BF0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = reviews.html; + refType = 4; + sourceTree = ""; + }; + 1865158C06253D50005AB5DA = { + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + isa = PBXShellScriptBuildPhase; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "source /sw/bin/init.sh\nscons"; + }; + 1865158D06253D50005AB5DA = { + buildPhases = ( + 1865158C06253D50005AB5DA, + ); + buildSettings = { + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = radiant; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + ); + isa = PBXAggregateTarget; + name = radiant; + productName = radiant; + }; + 186515AB06255F40005AB5DA = { + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + isa = PBXShellScriptBuildPhase; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "source /sw/bin/init.sh\nscons BUILD=info"; + }; + 186515AC06255F40005AB5DA = { + buildPhases = ( + 186515AB06255F40005AB5DA, + ); + buildSettings = { + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = setup; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + ); + isa = PBXAggregateTarget; + name = setup; + productName = setup; + }; + 1865EBC806253B29005AB5DA = { + children = ( + 1865EBD506253B76005AB5DA, + ); + isa = PBXGroup; + refType = 4; + sourceTree = ""; + }; + 1865EBCA06253B29005AB5DA = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = NO; + }; + isa = PBXBuildStyle; + name = Development; + }; + 1865EBCB06253B29005AB5DA = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = YES; + }; + isa = PBXBuildStyle; + name = Deployment; + }; + 1865EBCC06253B29005AB5DA = { + buildSettings = { + }; + buildStyles = ( + 1865EBCA06253B29005AB5DA, + 1865EBCB06253B29005AB5DA, + ); + hasScannedForEncodings = 1; + isa = PBXProject; + mainGroup = 1865EBC806253B29005AB5DA; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 1865047D06253BC4005AB5DA; + ProjectRef = 1865047C06253BC4005AB5DA; + }, + ); + targets = ( + 1865158D06253D50005AB5DA, + 186515AC06255F40005AB5DA, + ); + }; + 1865EBD506253B76005AB5DA = { + children = ( + 1865EBD606253B76005AB5DA, + 1865EBD706253B76005AB5DA, + 1865EC5206253B77005AB5DA, + 1865EC5306253B77005AB5DA, + 1865EC7006253B77005AB5DA, + 1865EC7106253B77005AB5DA, + 1865EC7206253B77005AB5DA, + 1865F11706253B80005AB5DA, + 1865F11806253B80005AB5DA, + 1865F11906253B80005AB5DA, + 1865F11A06253B80005AB5DA, + 1865F73306253B98005AB5DA, + 1865F73406253B98005AB5DA, + 1865F73506253B98005AB5DA, + 1865F75506253B99005AB5DA, + 1865F85206253B9D005AB5DA, + 1865F85306253B9D005AB5DA, + 1865F85406253B9D005AB5DA, + 1865F85506253B9D005AB5DA, + 1865F85606253B9E005AB5DA, + 1865F85706253B9E005AB5DA, + 1865F91B06253BA2005AB5DA, + 1865F91C06253BA2005AB5DA, + 1865F91D06253BA2005AB5DA, + 1865FCB306253BAF005AB5DA, + 1865FCB406253BAF005AB5DA, + 1865FCB506253BAF005AB5DA, + 1865FCB606253BAF005AB5DA, + 1865FCB706253BAF005AB5DA, + 1865FCB806253BAF005AB5DA, + 1865FCB906253BAF005AB5DA, + 1865014F06253BBA005AB5DA, + 1865047B06253BC4005AB5DA, + 1865047C06253BC4005AB5DA, + 1865047E06253BC4005AB5DA, + 1865047F06253BC4005AB5DA, + 1865048006253BC4005AB5DA, + 1865048106253BC4005AB5DA, + 1865048206253BC4005AB5DA, + 1865048306253BC4005AB5DA, + 1865048406253BC4005AB5DA, + 18650F9B06253BDE005AB5DA, + 18650F9C06253BDE005AB5DA, + 1865150A06253BEE005AB5DA, + 1865155606253BEF005AB5DA, + 1865155706253BEF005AB5DA, + ); + isa = PBXGroup; + name = GtkRadiant; + path = ""; + refType = 4; + sourceTree = ""; + }; + 1865EBD606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865EBD706253B76005AB5DA = { + children = ( + 1865EBD806253B76005AB5DA, + 1865EBD906253B76005AB5DA, + 1865EBDA06253B76005AB5DA, + 1865EBDB06253B76005AB5DA, + 1865EBDC06253B76005AB5DA, + 1865EBF806253B76005AB5DA, + 1865EC1406253B76005AB5DA, + 1865EC1506253B76005AB5DA, + 1865EC3106253B76005AB5DA, + 1865EC3606253B76005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EBD806253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EBD906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EBDA06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EBDB06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EBDC06253B76005AB5DA = { + children = ( + 1865EBDD06253B76005AB5DA, + 1865EBDE06253B76005AB5DA, + 1865EBDF06253B76005AB5DA, + 1865EBE006253B76005AB5DA, + 1865EBE106253B76005AB5DA, + 1865EBE206253B76005AB5DA, + 1865EBE306253B76005AB5DA, + 1865EBE406253B76005AB5DA, + 1865EBE506253B76005AB5DA, + 1865EBE606253B76005AB5DA, + 1865EBE706253B76005AB5DA, + 1865EBE806253B76005AB5DA, + 1865EBE906253B76005AB5DA, + 1865EBEA06253B76005AB5DA, + 1865EBEB06253B76005AB5DA, + 1865EBEC06253B76005AB5DA, + 1865EBED06253B76005AB5DA, + 1865EBEE06253B76005AB5DA, + 1865EBEF06253B76005AB5DA, + 1865EBF006253B76005AB5DA, + 1865EBF106253B76005AB5DA, + 1865EBF206253B76005AB5DA, + 1865EBF306253B76005AB5DA, + 1865EBF406253B76005AB5DA, + 1865EBF506253B76005AB5DA, + 1865EBF606253B76005AB5DA, + 1865EBF706253B76005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBDD06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBDE06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BSD.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBDF06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES-MACOS.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COMPILING.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE106253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTOR_AGREEMENT.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE206253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTORS.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE306253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DarwinCompileInfo.rtf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE406253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoxyConfig.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE506253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.readme.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE806253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendox.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBE906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GPL.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBEA06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.prj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBEB06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INSTALL.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBEC06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LGPL.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBED06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBEE06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE_ID.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBEF06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeversion.py.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "osx_setup.py.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF106253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.sln.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF206253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.doxygen.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF306253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF406253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "run_python.bat.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF506253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConscript.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConstruct.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "win32_install.py.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EBF806253B76005AB5DA = { + children = ( + 1865EBF906253B76005AB5DA, + 1865EBFA06253B76005AB5DA, + 1865EBFB06253B76005AB5DA, + 1865EBFC06253B76005AB5DA, + 1865EBFD06253B76005AB5DA, + 1865EBFE06253B76005AB5DA, + 1865EBFF06253B76005AB5DA, + 1865EC0006253B76005AB5DA, + 1865EC0106253B76005AB5DA, + 1865EC0206253B76005AB5DA, + 1865EC0306253B76005AB5DA, + 1865EC0406253B76005AB5DA, + 1865EC0506253B76005AB5DA, + 1865EC0606253B76005AB5DA, + 1865EC0706253B76005AB5DA, + 1865EC0806253B76005AB5DA, + 1865EC0906253B76005AB5DA, + 1865EC0A06253B76005AB5DA, + 1865EC0B06253B76005AB5DA, + 1865EC0C06253B76005AB5DA, + 1865EC0D06253B76005AB5DA, + 1865EC0E06253B76005AB5DA, + 1865EC0F06253B76005AB5DA, + 1865EC1006253B76005AB5DA, + 1865EC1106253B76005AB5DA, + 1865EC1206253B76005AB5DA, + 1865EC1306253B76005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EBF906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EBFA06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BSD.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EBFB06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES-MACOS.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EBFC06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COMPILING.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EBFD06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTOR_AGREEMENT.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EBFE06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTORS.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EBFF06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DarwinCompileInfo.rtf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoxyConfig.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0106253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0206253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.readme.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0306253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0406253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendox.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0506253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GPL.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.prj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INSTALL.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0806253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LGPL.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0A06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE_ID.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0B06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeversion.py.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0C06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "osx_setup.py.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0D06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.sln.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0E06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.doxygen.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC0F06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC1006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "run_python.bat.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC1106253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConscript.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC1206253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConstruct.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC1306253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "win32_install.py.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC1406253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EC1506253B76005AB5DA = { + children = ( + 1865EC1606253B76005AB5DA, + 1865EC1706253B76005AB5DA, + 1865EC1806253B76005AB5DA, + 1865EC1906253B76005AB5DA, + 1865EC1A06253B76005AB5DA, + 1865EC1B06253B76005AB5DA, + 1865EC1C06253B76005AB5DA, + 1865EC1D06253B76005AB5DA, + 1865EC1E06253B76005AB5DA, + 1865EC1F06253B76005AB5DA, + 1865EC2006253B76005AB5DA, + 1865EC2106253B76005AB5DA, + 1865EC2206253B76005AB5DA, + 1865EC2306253B76005AB5DA, + 1865EC2406253B76005AB5DA, + 1865EC2506253B76005AB5DA, + 1865EC2606253B76005AB5DA, + 1865EC2706253B76005AB5DA, + 1865EC2806253B76005AB5DA, + 1865EC2906253B76005AB5DA, + 1865EC2A06253B76005AB5DA, + 1865EC2B06253B76005AB5DA, + 1865EC2C06253B76005AB5DA, + 1865EC2D06253B76005AB5DA, + 1865EC2E06253B76005AB5DA, + 1865EC2F06253B76005AB5DA, + 1865EC3006253B76005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BSD.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1806253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES-MACOS.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COMPILING.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1A06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTOR_AGREEMENT.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1B06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTORS.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1C06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DarwinCompileInfo.rtf.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1D06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoxyConfig.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1E06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC1F06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.readme.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "gen.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2106253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "gendox.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2206253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GPL.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2306253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.prj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2406253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INSTALL.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2506253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LGPL.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE_ID.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2806253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeversion.py.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "osx_setup.py.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2A06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.sln.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2B06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.doxygen.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2C06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2D06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "run_python.bat.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2E06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConscript.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC2F06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConstruct.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC3006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "win32_install.py.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC3106253B76005AB5DA = { + children = ( + 1865EC3206253B76005AB5DA, + 1865EC3306253B76005AB5DA, + 1865EC3406253B76005AB5DA, + 1865EC3506253B76005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EC3206253B76005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC3306253B76005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EC3406253B76005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC3506253B76005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EC3606253B76005AB5DA = { + children = ( + 1865EC3706253B76005AB5DA, + 1865EC3806253B76005AB5DA, + 1865EC3906253B76005AB5DA, + 1865EC3A06253B76005AB5DA, + 1865EC3B06253B76005AB5DA, + 1865EC3C06253B76005AB5DA, + 1865EC3D06253B76005AB5DA, + 1865EC3E06253B76005AB5DA, + 1865EC3F06253B76005AB5DA, + 1865EC4006253B76005AB5DA, + 1865EC4106253B76005AB5DA, + 1865EC4206253B76005AB5DA, + 1865EC4306253B76005AB5DA, + 1865EC4406253B76005AB5DA, + 1865EC4506253B76005AB5DA, + 1865EC4606253B76005AB5DA, + 1865EC4706253B76005AB5DA, + 1865EC4806253B77005AB5DA, + 1865EC4906253B77005AB5DA, + 1865EC4A06253B77005AB5DA, + 1865EC4B06253B77005AB5DA, + 1865EC4C06253B77005AB5DA, + 1865EC4D06253B77005AB5DA, + 1865EC4E06253B77005AB5DA, + 1865EC4F06253B77005AB5DA, + 1865EC5006253B77005AB5DA, + 1865EC5106253B77005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EC3706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3806253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BSD.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3906253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES-MACOS.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3A06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "COMPILING.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3B06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTOR_AGREEMENT.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3C06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CONTRIBUTORS.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3D06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DarwinCompileInfo.rtf.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3E06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoxyConfig.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC3F06253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4006253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.readme.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4106253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gen.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4206253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendox.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4306253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GPL.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4406253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "GtkRadiant.prj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4506253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INSTALL.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4606253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LGPL.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4706253B76005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4806253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LICENSE_ID.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4906253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "makeversion.py.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4A06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "osx_setup.py.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4B06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant.sln.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4C06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.doxygen.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4D06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4E06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "run_python.bat.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC4F06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConscript.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC5006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "SConstruct.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC5106253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "win32_install.py.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC5206253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = BSD; + refType = 4; + sourceTree = ""; + }; + 1865EC5306253B77005AB5DA = { + children = ( + 1865EC5406253B77005AB5DA, + 1865EC6206253B77005AB5DA, + ); + isa = PBXGroup; + path = build; + refType = 4; + sourceTree = ""; + }; + 1865EC5406253B77005AB5DA = { + children = ( + 1865EC5506253B77005AB5DA, + 1865EC5E06253B77005AB5DA, + ); + isa = PBXGroup; + path = debug; + refType = 4; + sourceTree = ""; + }; + 1865EC5506253B77005AB5DA = { + children = ( + 1865EC5606253B77005AB5DA, + 1865EC5A06253B77005AB5DA, + ); + isa = PBXGroup; + path = contrib; + refType = 4; + sourceTree = ""; + }; + 1865EC5606253B77005AB5DA = { + children = ( + 1865EC5706253B77005AB5DA, + 1865EC5806253B77005AB5DA, + 1865EC5906253B77005AB5DA, + ); + isa = PBXGroup; + path = bkgrnd2d; + refType = 4; + sourceTree = ""; + }; + 1865EC5706253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.objfile"; + path = bkgrnd2d.os; + refType = 4; + sourceTree = ""; + }; + 1865EC5806253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.objfile"; + path = dialog.os; + refType = 4; + sourceTree = ""; + }; + 1865EC5906253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.objfile"; + path = plugin.os; + refType = 4; + sourceTree = ""; + }; + 1865EC5A06253B77005AB5DA = { + children = ( + 1865EC5B06253B77005AB5DA, + 1865EC5C06253B77005AB5DA, + ); + isa = PBXGroup; + path = bobtoolz; + refType = 4; + sourceTree = ""; + }; + 1865EC5B06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.objfile"; + path = "bobToolz-GTK.os"; + refType = 4; + sourceTree = ""; + }; + 1865EC5C06253B77005AB5DA = { + children = ( + 1865EC5D06253B77005AB5DA, + ); + isa = PBXGroup; + path = dialogs; + refType = 4; + sourceTree = ""; + }; + 1865EC5D06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.objfile"; + path = "dialogs-gtk.os"; + refType = 4; + sourceTree = ""; + }; + 1865EC5E06253B77005AB5DA = { + children = ( + 1865EC5F06253B77005AB5DA, + 1865EC6006253B77005AB5DA, + ); + isa = PBXGroup; + path = libs; + refType = 4; + sourceTree = ""; + }; + 1865EC5F06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = archive.ar; + path = libsynapse.a; + refType = 4; + sourceTree = ""; + }; + 1865EC6006253B77005AB5DA = { + children = ( + 1865EC6106253B77005AB5DA, + ); + isa = PBXGroup; + path = synapse; + refType = 4; + sourceTree = ""; + }; + 1865EC6106253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.objfile"; + path = synapse.o; + refType = 4; + sourceTree = ""; + }; + 1865EC6206253B77005AB5DA = { + children = ( + 1865EC6306253B77005AB5DA, + ); + isa = PBXGroup; + path = radiant.build; + refType = 4; + sourceTree = ""; + }; + 1865EC6306253B77005AB5DA = { + children = ( + 1865EC6406253B77005AB5DA, + 1865EC6506253B77005AB5DA, + 1865EC6606253B77005AB5DA, + 1865EC6706253B77005AB5DA, + 1865EC6806253B77005AB5DA, + 1865EC6906253B77005AB5DA, + 1865EC6A06253B77005AB5DA, + 1865EC6B06253B77005AB5DA, + 1865EC6C06253B77005AB5DA, + 1865EC6F06253B77005AB5DA, + ); + isa = PBXGroup; + path = radiant.pbxindex; + refType = 4; + sourceTree = ""; + }; + 1865EC6406253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = categories.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6506253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = cdecls.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6606253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = decls.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6706253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = files.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6806253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = imports.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6906253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = pbxindex.header; + refType = 4; + sourceTree = ""; + }; + 1865EC6A06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = protocols.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6B06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = refs.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC6C06253B77005AB5DA = { + children = ( + 1865EC6D06253B77005AB5DA, + 1865EC6E06253B77005AB5DA, + ); + isa = PBXGroup; + path = strings.pbxstrings; + refType = 4; + sourceTree = ""; + }; + 1865EC6D06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = control; + refType = 4; + sourceTree = ""; + }; + 1865EC6E06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = strings; + refType = 4; + sourceTree = ""; + }; + 1865EC6F06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = subclasses.pbxbtree; + refType = 4; + sourceTree = ""; + }; + 1865EC7006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES-MACOS"; + refType = 4; + sourceTree = ""; + }; + 1865EC7106253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = COMPILING; + refType = 4; + sourceTree = ""; + }; + 1865EC7206253B77005AB5DA = { + children = ( + 1865EC7306253B77005AB5DA, + 1865EC8206253B77005AB5DA, + 1865ECE306253B77005AB5DA, + 1865EF5B06253B7C005AB5DA, + 1865EFCB06253B7D005AB5DA, + 1865F03506253B7E005AB5DA, + 1865F05906253B7E005AB5DA, + 1865F08906253B7E005AB5DA, + ); + isa = PBXGroup; + path = contrib; + refType = 4; + sourceTree = ""; + }; + 1865EC7306253B77005AB5DA = { + children = ( + 1865EC7406253B77005AB5DA, + 1865EC7506253B77005AB5DA, + 1865EC7606253B77005AB5DA, + 1865EC7706253B77005AB5DA, + 1865EC7806253B77005AB5DA, + 1865EC7906253B77005AB5DA, + 1865EC7A06253B77005AB5DA, + 1865EC7B06253B77005AB5DA, + 1865EC7C06253B77005AB5DA, + 1865EC8106253B77005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EC7406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EC7506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EC7606253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EC7706253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EC7806253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC7906253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EC7A06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EC7B06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC7C06253B77005AB5DA = { + children = ( + 1865EC7D06253B77005AB5DA, + 1865EC7E06253B77005AB5DA, + 1865EC7F06253B77005AB5DA, + 1865EC8006253B77005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EC7D06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC7E06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EC7F06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8006253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EC8106253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EC8206253B77005AB5DA = { + children = ( + 1865EC8306253B77005AB5DA, + 1865ECB606253B77005AB5DA, + 1865ECDA06253B77005AB5DA, + 1865ECDB06253B77005AB5DA, + 1865ECDC06253B77005AB5DA, + 1865ECDD06253B77005AB5DA, + 1865ECDE06253B77005AB5DA, + 1865ECDF06253B77005AB5DA, + 1865ECE006253B77005AB5DA, + 1865ECE106253B77005AB5DA, + 1865ECE206253B77005AB5DA, + ); + isa = PBXGroup; + path = bkgrnd2d; + refType = 4; + sourceTree = ""; + }; + 1865EC8306253B77005AB5DA = { + children = ( + 1865EC8406253B77005AB5DA, + 1865EC8506253B77005AB5DA, + 1865EC8606253B77005AB5DA, + 1865EC8706253B77005AB5DA, + 1865EC8806253B77005AB5DA, + 1865EC9206253B77005AB5DA, + 1865EC9C06253B77005AB5DA, + 1865EC9D06253B77005AB5DA, + 1865ECA706253B77005AB5DA, + 1865ECAC06253B77005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EC8406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EC8506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EC8606253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EC8706253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EC8806253B77005AB5DA = { + children = ( + 1865EC8906253B77005AB5DA, + 1865EC8A06253B77005AB5DA, + 1865EC8B06253B77005AB5DA, + 1865EC8C06253B77005AB5DA, + 1865EC8D06253B77005AB5DA, + 1865EC8E06253B77005AB5DA, + 1865EC8F06253B77005AB5DA, + 1865EC9006253B77005AB5DA, + 1865EC9106253B77005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8906253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8A06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8B06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8C06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8D06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8E06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC8F06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC9006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC9106253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme_bkgrnd2d-b0.25.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC9206253B77005AB5DA = { + children = ( + 1865EC9306253B77005AB5DA, + 1865EC9406253B77005AB5DA, + 1865EC9506253B77005AB5DA, + 1865EC9606253B77005AB5DA, + 1865EC9706253B77005AB5DA, + 1865EC9806253B77005AB5DA, + 1865EC9906253B77005AB5DA, + 1865EC9A06253B77005AB5DA, + 1865EC9B06253B77005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EC9306253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9606253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9706253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9806253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9906253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9A06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9B06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme_bkgrnd2d-b0.25.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EC9C06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EC9D06253B77005AB5DA = { + children = ( + 1865EC9E06253B77005AB5DA, + 1865EC9F06253B77005AB5DA, + 1865ECA006253B77005AB5DA, + 1865ECA106253B77005AB5DA, + 1865ECA206253B77005AB5DA, + 1865ECA306253B77005AB5DA, + 1865ECA406253B77005AB5DA, + 1865ECA506253B77005AB5DA, + 1865ECA606253B77005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC9E06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EC9F06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA106253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "bkgrnd2d.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA206253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA306253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA606253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme_bkgrnd2d-b0.25.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA706253B77005AB5DA = { + children = ( + 1865ECA806253B77005AB5DA, + 1865ECA906253B77005AB5DA, + 1865ECAA06253B77005AB5DA, + 1865ECAB06253B77005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865ECA806253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECA906253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865ECAA06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECAB06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865ECAC06253B77005AB5DA = { + children = ( + 1865ECAD06253B77005AB5DA, + 1865ECAE06253B77005AB5DA, + 1865ECAF06253B77005AB5DA, + 1865ECB006253B77005AB5DA, + 1865ECB106253B77005AB5DA, + 1865ECB206253B77005AB5DA, + 1865ECB306253B77005AB5DA, + 1865ECB406253B77005AB5DA, + 1865ECB506253B77005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865ECAD06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECAE06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECAF06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB106253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB206253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB306253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme_bkgrnd2d-b0.25.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECB606253B77005AB5DA = { + children = ( + 1865ECB706253B77005AB5DA, + 1865ECD606253B77005AB5DA, + 1865ECD706253B77005AB5DA, + 1865ECD806253B77005AB5DA, + 1865ECD906253B77005AB5DA, + ); + isa = PBXGroup; + path = bitmaps; + refType = 4; + sourceTree = ""; + }; + 1865ECB706253B77005AB5DA = { + children = ( + 1865ECB806253B77005AB5DA, + 1865ECB906253B77005AB5DA, + 1865ECBA06253B77005AB5DA, + 1865ECBB06253B77005AB5DA, + 1865ECBC06253B77005AB5DA, + 1865ECC106253B77005AB5DA, + 1865ECC606253B77005AB5DA, + 1865ECC706253B77005AB5DA, + 1865ECCC06253B77005AB5DA, + 1865ECD106253B77005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865ECB806253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865ECB906253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865ECBA06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865ECBB06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865ECBC06253B77005AB5DA = { + children = ( + 1865ECBD06253B77005AB5DA, + 1865ECBE06253B77005AB5DA, + 1865ECBF06253B77005AB5DA, + 1865ECC006253B77005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECBD06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_conf.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECBE06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_xy_toggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECBF06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_xz_toggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECC006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_yz_toggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECC106253B77005AB5DA = { + children = ( + 1865ECC206253B77005AB5DA, + 1865ECC306253B77005AB5DA, + 1865ECC406253B77005AB5DA, + 1865ECC506253B77005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865ECC206253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_conf.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECC306253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_xy_toggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECC406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_xz_toggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECC506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_yz_toggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECC606253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865ECC706253B77005AB5DA = { + children = ( + 1865ECC806253B77005AB5DA, + 1865ECC906253B77005AB5DA, + 1865ECCA06253B77005AB5DA, + 1865ECCB06253B77005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECC806253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bkgrnd2d_conf.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECC906253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bkgrnd2d_xy_toggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECCA06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bkgrnd2d_xz_toggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECCB06253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bkgrnd2d_yz_toggle.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECCC06253B77005AB5DA = { + children = ( + 1865ECCD06253B77005AB5DA, + 1865ECCE06253B77005AB5DA, + 1865ECCF06253B77005AB5DA, + 1865ECD006253B77005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865ECCD06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECCE06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865ECCF06253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECD006253B77005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865ECD106253B77005AB5DA = { + children = ( + 1865ECD206253B77005AB5DA, + 1865ECD306253B77005AB5DA, + 1865ECD406253B77005AB5DA, + 1865ECD506253B77005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865ECD206253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_conf.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECD306253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_xy_toggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECD406253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_xz_toggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECD506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bkgrnd2d_yz_toggle.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ECD606253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bkgrnd2d_conf.bmp; + refType = 4; + sourceTree = ""; + }; + 1865ECD706253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bkgrnd2d_xy_toggle.bmp; + refType = 4; + sourceTree = ""; + }; + 1865ECD806253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bkgrnd2d_xz_toggle.bmp; + refType = 4; + sourceTree = ""; + }; + 1865ECD906253B77005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bkgrnd2d_yz_toggle.bmp; + refType = 4; + sourceTree = ""; + }; + 1865ECDA06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = bkgrnd2d.cpp; + refType = 4; + sourceTree = ""; + }; + 1865ECDB06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = bkgrnd2d.def; + refType = 4; + sourceTree = ""; + }; + 1865ECDC06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bkgrnd2d.h; + refType = 4; + sourceTree = ""; + }; + 1865ECDD06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = bkgrnd2d.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865ECDE06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = dialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865ECDF06253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = dialog.h; + refType = 4; + sourceTree = ""; + }; + 1865ECE006253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865ECE106253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865ECE206253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme_bkgrnd2d-b0.25.txt"; + refType = 4; + sourceTree = ""; + }; + 1865ECE306253B77005AB5DA = { + children = ( + 1865ECE406253B77005AB5DA, + 1865EDE306253B7A005AB5DA, + 1865EE2006253B7A005AB5DA, + 1865EE2106253B7A005AB5DA, + 1865EE2206253B7A005AB5DA, + 1865EE2306253B7A005AB5DA, + 1865EE2406253B7A005AB5DA, + 1865EE2506253B7A005AB5DA, + 1865EE2606253B7A005AB5DA, + 1865EE2706253B7A005AB5DA, + 1865EE2806253B7A005AB5DA, + 1865EE5B06253B7B005AB5DA, + 1865EE5C06253B7B005AB5DA, + 1865EE5D06253B7B005AB5DA, + 1865EE5E06253B7B005AB5DA, + 1865EE5F06253B7B005AB5DA, + 1865EE6006253B7B005AB5DA, + 1865EE6106253B7B005AB5DA, + 1865EE6206253B7B005AB5DA, + 1865EE6306253B7B005AB5DA, + 1865EE6406253B7B005AB5DA, + 1865EE6506253B7B005AB5DA, + 1865EE6606253B7B005AB5DA, + 1865EE6706253B7B005AB5DA, + 1865EE6806253B7B005AB5DA, + 1865EE6906253B7B005AB5DA, + 1865EEF106253B7C005AB5DA, + 1865EEF206253B7C005AB5DA, + 1865EEF306253B7C005AB5DA, + 1865EEF406253B7C005AB5DA, + 1865EEF506253B7C005AB5DA, + 1865EEF606253B7C005AB5DA, + 1865EEF706253B7C005AB5DA, + 1865EEF806253B7C005AB5DA, + 1865EEF906253B7C005AB5DA, + 1865EEFA06253B7C005AB5DA, + 1865EEFB06253B7C005AB5DA, + 1865EEFC06253B7C005AB5DA, + 1865EEFD06253B7C005AB5DA, + 1865EEFE06253B7C005AB5DA, + 1865EEFF06253B7C005AB5DA, + 1865EF0006253B7C005AB5DA, + 1865EF0106253B7C005AB5DA, + 1865EF0206253B7C005AB5DA, + 1865EF0306253B7C005AB5DA, + 1865EF0406253B7C005AB5DA, + 1865EF0506253B7C005AB5DA, + 1865EF0606253B7C005AB5DA, + 1865EF0706253B7C005AB5DA, + 1865EF0806253B7C005AB5DA, + 1865EF0906253B7C005AB5DA, + 1865EF1E06253B7C005AB5DA, + 1865EF1F06253B7C005AB5DA, + 1865EF2006253B7C005AB5DA, + 1865EF2106253B7C005AB5DA, + 1865EF2206253B7C005AB5DA, + 1865EF3706253B7C005AB5DA, + 1865EF3806253B7C005AB5DA, + 1865EF3906253B7C005AB5DA, + 1865EF3A06253B7C005AB5DA, + 1865EF3B06253B7C005AB5DA, + 1865EF3C06253B7C005AB5DA, + 1865EF3D06253B7C005AB5DA, + 1865EF3E06253B7C005AB5DA, + 1865EF3F06253B7C005AB5DA, + 1865EF5906253B7C005AB5DA, + 1865EF5A06253B7C005AB5DA, + ); + isa = PBXGroup; + path = bobtoolz; + refType = 4; + sourceTree = ""; + }; + 1865ECE406253B77005AB5DA = { + children = ( + 1865ECE506253B77005AB5DA, + 1865ECE606253B77005AB5DA, + 1865ECE706253B77005AB5DA, + 1865ECE806253B77005AB5DA, + 1865ECE906253B77005AB5DA, + 1865ED2606253B78005AB5DA, + 1865ED6306253B79005AB5DA, + 1865ED6406253B79005AB5DA, + 1865EDA106253B79005AB5DA, + 1865EDA606253B79005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865ECE506253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865ECE606253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865ECE706253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865ECE806253B77005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865ECE906253B77005AB5DA = { + children = ( + 1865ECEA06253B78005AB5DA, + 1865ECEB06253B78005AB5DA, + 1865ECEC06253B78005AB5DA, + 1865ECED06253B78005AB5DA, + 1865ECEE06253B78005AB5DA, + 1865ECEF06253B78005AB5DA, + 1865ECF006253B78005AB5DA, + 1865ECF106253B78005AB5DA, + 1865ECF206253B78005AB5DA, + 1865ECF306253B78005AB5DA, + 1865ECF406253B78005AB5DA, + 1865ECF506253B78005AB5DA, + 1865ECF606253B78005AB5DA, + 1865ECF706253B78005AB5DA, + 1865ECF806253B78005AB5DA, + 1865ECF906253B78005AB5DA, + 1865ECFA06253B78005AB5DA, + 1865ECFB06253B78005AB5DA, + 1865ECFC06253B78005AB5DA, + 1865ECFD06253B78005AB5DA, + 1865ECFE06253B78005AB5DA, + 1865ECFF06253B78005AB5DA, + 1865ED0006253B78005AB5DA, + 1865ED0106253B78005AB5DA, + 1865ED0206253B78005AB5DA, + 1865ED0306253B78005AB5DA, + 1865ED0406253B78005AB5DA, + 1865ED0506253B78005AB5DA, + 1865ED0606253B78005AB5DA, + 1865ED0706253B78005AB5DA, + 1865ED0806253B78005AB5DA, + 1865ED0906253B78005AB5DA, + 1865ED0A06253B78005AB5DA, + 1865ED0B06253B78005AB5DA, + 1865ED0C06253B78005AB5DA, + 1865ED0D06253B78005AB5DA, + 1865ED0E06253B78005AB5DA, + 1865ED0F06253B78005AB5DA, + 1865ED1006253B78005AB5DA, + 1865ED1106253B78005AB5DA, + 1865ED1206253B78005AB5DA, + 1865ED1306253B78005AB5DA, + 1865ED1406253B78005AB5DA, + 1865ED1506253B78005AB5DA, + 1865ED1606253B78005AB5DA, + 1865ED1706253B78005AB5DA, + 1865ED1806253B78005AB5DA, + 1865ED1906253B78005AB5DA, + 1865ED1A06253B78005AB5DA, + 1865ED1B06253B78005AB5DA, + 1865ED1C06253B78005AB5DA, + 1865ED1D06253B78005AB5DA, + 1865ED1E06253B78005AB5DA, + 1865ED1F06253B78005AB5DA, + 1865ED2006253B78005AB5DA, + 1865ED2106253B78005AB5DA, + 1865ED2206253B78005AB5DA, + 1865ED2306253B78005AB5DA, + 1865ED2406253B78005AB5DA, + 1865ED2506253B78005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECEA06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECEB06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz-gtk.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECEC06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECED06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECEE06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECEF06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz_gtk.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cportals.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CPortals.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF506253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF606253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfToolz-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF706253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctftoolz.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF806253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECF906253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECFA06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECFB06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECFC06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECFD06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECFE06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ECFF06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0506253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0606253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0706253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0806253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0906253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0A06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0B06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0C06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0D06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0E06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED0F06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-ctf-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1506253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1606253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1706253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1806253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1906253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1A06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1B06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1C06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource-gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1D06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1E06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED1F06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2506253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED2606253B78005AB5DA = { + children = ( + 1865ED2706253B78005AB5DA, + 1865ED2806253B78005AB5DA, + 1865ED2906253B78005AB5DA, + 1865ED2A06253B78005AB5DA, + 1865ED2B06253B78005AB5DA, + 1865ED2C06253B78005AB5DA, + 1865ED2D06253B78005AB5DA, + 1865ED2E06253B78005AB5DA, + 1865ED2F06253B78005AB5DA, + 1865ED3006253B78005AB5DA, + 1865ED3106253B78005AB5DA, + 1865ED3206253B78005AB5DA, + 1865ED3306253B78005AB5DA, + 1865ED3406253B78005AB5DA, + 1865ED3506253B78005AB5DA, + 1865ED3606253B78005AB5DA, + 1865ED3706253B78005AB5DA, + 1865ED3806253B78005AB5DA, + 1865ED3906253B78005AB5DA, + 1865ED3A06253B78005AB5DA, + 1865ED3B06253B78005AB5DA, + 1865ED3C06253B78005AB5DA, + 1865ED3D06253B78005AB5DA, + 1865ED3E06253B78005AB5DA, + 1865ED3F06253B78005AB5DA, + 1865ED4006253B78005AB5DA, + 1865ED4106253B78005AB5DA, + 1865ED4206253B78005AB5DA, + 1865ED4306253B78005AB5DA, + 1865ED4406253B78005AB5DA, + 1865ED4506253B78005AB5DA, + 1865ED4606253B78005AB5DA, + 1865ED4706253B78005AB5DA, + 1865ED4806253B78005AB5DA, + 1865ED4906253B78005AB5DA, + 1865ED4A06253B78005AB5DA, + 1865ED4B06253B78005AB5DA, + 1865ED4C06253B78005AB5DA, + 1865ED4D06253B78005AB5DA, + 1865ED4E06253B78005AB5DA, + 1865ED4F06253B78005AB5DA, + 1865ED5006253B78005AB5DA, + 1865ED5106253B78005AB5DA, + 1865ED5206253B78005AB5DA, + 1865ED5306253B78005AB5DA, + 1865ED5406253B78005AB5DA, + 1865ED5506253B79005AB5DA, + 1865ED5606253B79005AB5DA, + 1865ED5706253B79005AB5DA, + 1865ED5806253B79005AB5DA, + 1865ED5906253B79005AB5DA, + 1865ED5A06253B79005AB5DA, + 1865ED5B06253B79005AB5DA, + 1865ED5C06253B79005AB5DA, + 1865ED5D06253B79005AB5DA, + 1865ED5E06253B79005AB5DA, + 1865ED5F06253B79005AB5DA, + 1865ED6006253B79005AB5DA, + 1865ED6106253B79005AB5DA, + 1865ED6206253B79005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865ED2706253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2806253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz-gtk.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2906253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2A06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2B06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2C06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz_gtk.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2D06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2E06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED2F06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cportals.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CPortals.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfToolz-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctftoolz.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3506253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3606253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3706253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3806253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3906253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3A06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3B06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3C06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3D06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3E06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED3F06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4506253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4606253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4706253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4806253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4906253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4A06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4B06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4C06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4D06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4E06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED4F06253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5006253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5106253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-ctf-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5206253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5306253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5406253B78005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5506253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5606253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5706253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5806253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5906253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource-gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5A06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5B06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5C06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5D06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5E06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED5F06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED6006253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED6106253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED6206253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865ED6306253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865ED6406253B79005AB5DA = { + children = ( + 1865ED6506253B79005AB5DA, + 1865ED6606253B79005AB5DA, + 1865ED6706253B79005AB5DA, + 1865ED6806253B79005AB5DA, + 1865ED6906253B79005AB5DA, + 1865ED6A06253B79005AB5DA, + 1865ED6B06253B79005AB5DA, + 1865ED6C06253B79005AB5DA, + 1865ED6D06253B79005AB5DA, + 1865ED6E06253B79005AB5DA, + 1865ED6F06253B79005AB5DA, + 1865ED7006253B79005AB5DA, + 1865ED7106253B79005AB5DA, + 1865ED7206253B79005AB5DA, + 1865ED7306253B79005AB5DA, + 1865ED7406253B79005AB5DA, + 1865ED7506253B79005AB5DA, + 1865ED7606253B79005AB5DA, + 1865ED7706253B79005AB5DA, + 1865ED7806253B79005AB5DA, + 1865ED7906253B79005AB5DA, + 1865ED7A06253B79005AB5DA, + 1865ED7B06253B79005AB5DA, + 1865ED7C06253B79005AB5DA, + 1865ED7D06253B79005AB5DA, + 1865ED7E06253B79005AB5DA, + 1865ED7F06253B79005AB5DA, + 1865ED8006253B79005AB5DA, + 1865ED8106253B79005AB5DA, + 1865ED8206253B79005AB5DA, + 1865ED8306253B79005AB5DA, + 1865ED8406253B79005AB5DA, + 1865ED8506253B79005AB5DA, + 1865ED8606253B79005AB5DA, + 1865ED8706253B79005AB5DA, + 1865ED8806253B79005AB5DA, + 1865ED8906253B79005AB5DA, + 1865ED8A06253B79005AB5DA, + 1865ED8B06253B79005AB5DA, + 1865ED8C06253B79005AB5DA, + 1865ED8D06253B79005AB5DA, + 1865ED8E06253B79005AB5DA, + 1865ED8F06253B79005AB5DA, + 1865ED9006253B79005AB5DA, + 1865ED9106253B79005AB5DA, + 1865ED9206253B79005AB5DA, + 1865ED9306253B79005AB5DA, + 1865ED9406253B79005AB5DA, + 1865ED9506253B79005AB5DA, + 1865ED9606253B79005AB5DA, + 1865ED9706253B79005AB5DA, + 1865ED9806253B79005AB5DA, + 1865ED9906253B79005AB5DA, + 1865ED9A06253B79005AB5DA, + 1865ED9B06253B79005AB5DA, + 1865ED9C06253B79005AB5DA, + 1865ED9D06253B79005AB5DA, + 1865ED9E06253B79005AB5DA, + 1865ED9F06253B79005AB5DA, + 1865EDA006253B79005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6506253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6606253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz-gtk.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6706253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6806253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6906253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6A06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "bobToolz_gtk.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6B06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6C06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6D06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cportals.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6E06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CPortals.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED6F06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7006253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7106253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfToolz-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7206253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctftoolz.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7306253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7406253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7506253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7606253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7706253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7806253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7906253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7A06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7B06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7C06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7D06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7E06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED7F06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8006253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8106253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8206253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8306253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8406253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8506253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8606253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8706253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8806253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8906253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8A06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8B06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8C06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8D06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8E06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED8F06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-ctf-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9006253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-GTK.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9106253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9206253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9306253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9406253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9506253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9606253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9706253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource-gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9806253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9906253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9A06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9B06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9C06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9D06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9E06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865ED9F06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDA006253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDA106253B79005AB5DA = { + children = ( + 1865EDA206253B79005AB5DA, + 1865EDA306253B79005AB5DA, + 1865EDA406253B79005AB5DA, + 1865EDA506253B79005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EDA206253B79005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDA306253B79005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EDA406253B79005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDA506253B79005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EDA606253B79005AB5DA = { + children = ( + 1865EDA706253B79005AB5DA, + 1865EDA806253B79005AB5DA, + 1865EDA906253B79005AB5DA, + 1865EDAA06253B79005AB5DA, + 1865EDAB06253B79005AB5DA, + 1865EDAC06253B79005AB5DA, + 1865EDAD06253B79005AB5DA, + 1865EDAE06253B79005AB5DA, + 1865EDAF06253B79005AB5DA, + 1865EDB006253B7A005AB5DA, + 1865EDB106253B7A005AB5DA, + 1865EDB206253B7A005AB5DA, + 1865EDB306253B7A005AB5DA, + 1865EDB406253B7A005AB5DA, + 1865EDB506253B7A005AB5DA, + 1865EDB606253B7A005AB5DA, + 1865EDB706253B7A005AB5DA, + 1865EDB806253B7A005AB5DA, + 1865EDB906253B7A005AB5DA, + 1865EDBA06253B7A005AB5DA, + 1865EDBB06253B7A005AB5DA, + 1865EDBC06253B7A005AB5DA, + 1865EDBD06253B7A005AB5DA, + 1865EDBE06253B7A005AB5DA, + 1865EDBF06253B7A005AB5DA, + 1865EDC006253B7A005AB5DA, + 1865EDC106253B7A005AB5DA, + 1865EDC206253B7A005AB5DA, + 1865EDC306253B7A005AB5DA, + 1865EDC406253B7A005AB5DA, + 1865EDC506253B7A005AB5DA, + 1865EDC606253B7A005AB5DA, + 1865EDC706253B7A005AB5DA, + 1865EDC806253B7A005AB5DA, + 1865EDC906253B7A005AB5DA, + 1865EDCA06253B7A005AB5DA, + 1865EDCB06253B7A005AB5DA, + 1865EDCC06253B7A005AB5DA, + 1865EDCD06253B7A005AB5DA, + 1865EDCE06253B7A005AB5DA, + 1865EDCF06253B7A005AB5DA, + 1865EDD006253B7A005AB5DA, + 1865EDD106253B7A005AB5DA, + 1865EDD206253B7A005AB5DA, + 1865EDD306253B7A005AB5DA, + 1865EDD406253B7A005AB5DA, + 1865EDD506253B7A005AB5DA, + 1865EDD606253B7A005AB5DA, + 1865EDD706253B7A005AB5DA, + 1865EDD806253B7A005AB5DA, + 1865EDD906253B7A005AB5DA, + 1865EDDA06253B7A005AB5DA, + 1865EDDB06253B7A005AB5DA, + 1865EDDC06253B7A005AB5DA, + 1865EDDD06253B7A005AB5DA, + 1865EDDE06253B7A005AB5DA, + 1865EDDF06253B7A005AB5DA, + 1865EDE006253B7A005AB5DA, + 1865EDE106253B7A005AB5DA, + 1865EDE206253B7A005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EDA706253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDA806253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz-gtk.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDA906253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDAA06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDAB06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDAC06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobToolz_gtk.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDAD06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDAE06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bsploader.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDAF06253B79005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cportals.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CPortals.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfresource_gtk.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctfToolz-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctftoolz.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBobView.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB806253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DBrush.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDB906253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDBA06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEntity.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDBB06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDBC06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DEPair.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDBD06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDBE06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DListener.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDBF06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DMap.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPatch.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPlane.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DPoint.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC806253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DShape.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDC906253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDCA06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTrainDrawer.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDCB06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDCC06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DTreePlanter.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDCD06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDCE06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DVisDrawer.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDCF06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DWinding.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-ctf-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers-GTK.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lists.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD806253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDD906253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource-gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDDA06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDDB06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDDC06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ScriptParser.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDDD06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDDE06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shapes.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDDF06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDE006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDE106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDE206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "visfind.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDE306253B7A005AB5DA = { + children = ( + 1865EDE406253B7A005AB5DA, + 1865EE1706253B7A005AB5DA, + 1865EE1806253B7A005AB5DA, + 1865EE1906253B7A005AB5DA, + 1865EE1A06253B7A005AB5DA, + 1865EE1B06253B7A005AB5DA, + 1865EE1C06253B7A005AB5DA, + 1865EE1D06253B7A005AB5DA, + 1865EE1E06253B7A005AB5DA, + 1865EE1F06253B7A005AB5DA, + ); + isa = PBXGroup; + path = bitmaps; + refType = 4; + sourceTree = ""; + }; + 1865EDE406253B7A005AB5DA = { + children = ( + 1865EDE506253B7A005AB5DA, + 1865EDE606253B7A005AB5DA, + 1865EDE706253B7A005AB5DA, + 1865EDE806253B7A005AB5DA, + 1865EDE906253B7A005AB5DA, + 1865EDF306253B7A005AB5DA, + 1865EDFD06253B7A005AB5DA, + 1865EDFE06253B7A005AB5DA, + 1865EE0806253B7A005AB5DA, + 1865EE0D06253B7A005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EDE506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EDE606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EDE706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EDE806253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EDE906253B7A005AB5DA = { + children = ( + 1865EDEA06253B7A005AB5DA, + 1865EDEB06253B7A005AB5DA, + 1865EDEC06253B7A005AB5DA, + 1865EDED06253B7A005AB5DA, + 1865EDEE06253B7A005AB5DA, + 1865EDEF06253B7A005AB5DA, + 1865EDF006253B7A005AB5DA, + 1865EDF106253B7A005AB5DA, + 1865EDF206253B7A005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDEA06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_caulk.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDEB06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_cleanup.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDEC06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_dropent.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDED06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_merge.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDEE06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_poly.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDEF06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_split.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDF006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_trainpathplot.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDF106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_treeplanter.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDF206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_turnedge.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDF306253B7A005AB5DA = { + children = ( + 1865EDF406253B7A005AB5DA, + 1865EDF506253B7A005AB5DA, + 1865EDF606253B7A005AB5DA, + 1865EDF706253B7A005AB5DA, + 1865EDF806253B7A005AB5DA, + 1865EDF906253B7A005AB5DA, + 1865EDFA06253B7A005AB5DA, + 1865EDFB06253B7A005AB5DA, + 1865EDFC06253B7A005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EDF406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_caulk.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDF506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_cleanup.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDF606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_dropent.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDF706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_merge.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDF806253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_poly.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDF906253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_split.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDFA06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_trainpathplot.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDFB06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_treeplanter.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDFC06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_turnedge.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EDFD06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EDFE06253B7A005AB5DA = { + children = ( + 1865EDFF06253B7A005AB5DA, + 1865EE0006253B7A005AB5DA, + 1865EE0106253B7A005AB5DA, + 1865EE0206253B7A005AB5DA, + 1865EE0306253B7A005AB5DA, + 1865EE0406253B7A005AB5DA, + 1865EE0506253B7A005AB5DA, + 1865EE0606253B7A005AB5DA, + 1865EE0706253B7A005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EDFF06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_caulk.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0006253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_cleanup.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0106253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_dropent.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0206253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_merge.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0306253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_poly.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0406253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_split.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0506253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_trainpathplot.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0606253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_treeplanter.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0706253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "bobtoolz_turnedge.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0806253B7A005AB5DA = { + children = ( + 1865EE0906253B7A005AB5DA, + 1865EE0A06253B7A005AB5DA, + 1865EE0B06253B7A005AB5DA, + 1865EE0C06253B7A005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EE0906253B7A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0A06253B7A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EE0B06253B7A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE0C06253B7A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EE0D06253B7A005AB5DA = { + children = ( + 1865EE0E06253B7A005AB5DA, + 1865EE0F06253B7A005AB5DA, + 1865EE1006253B7A005AB5DA, + 1865EE1106253B7A005AB5DA, + 1865EE1206253B7A005AB5DA, + 1865EE1306253B7A005AB5DA, + 1865EE1406253B7A005AB5DA, + 1865EE1506253B7A005AB5DA, + 1865EE1606253B7A005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EE0E06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_caulk.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE0F06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_cleanup.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_dropent.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_merge.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_poly.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_split.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_trainpathplot.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_treeplanter.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz_turnedge.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE1706253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_caulk.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1806253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_cleanup.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1906253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_dropent.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1A06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_merge.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1B06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_poly.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1C06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_split.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1D06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_trainpathplot.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1E06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_treeplanter.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE1F06253B7A005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = bobtoolz_turnedge.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EE2006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = "bobToolz-GTK.cpp"; + refType = 4; + sourceTree = ""; + }; + 1865EE2106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bobtoolz-gtk.rc"; + refType = 4; + sourceTree = ""; + }; + 1865EE2206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = bobToolz.def; + refType = 4; + sourceTree = ""; + }; + 1865EE2306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bobToolz.h; + refType = 4; + sourceTree = ""; + }; + 1865EE2406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = bobToolz.rc; + refType = 4; + sourceTree = ""; + }; + 1865EE2506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = bobToolz_gtk.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865EE2606253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = bsploader.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EE2706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bsploader.h; + refType = 4; + sourceTree = ""; + }; + 1865EE2806253B7A005AB5DA = { + children = ( + 1865EE2906253B7A005AB5DA, + 1865EE5406253B7B005AB5DA, + 1865EE5506253B7B005AB5DA, + 1865EE5606253B7B005AB5DA, + 1865EE5706253B7B005AB5DA, + 1865EE5806253B7B005AB5DA, + 1865EE5906253B7B005AB5DA, + 1865EE5A06253B7B005AB5DA, + ); + isa = PBXGroup; + path = bt; + refType = 4; + sourceTree = ""; + }; + 1865EE2906253B7A005AB5DA = { + children = ( + 1865EE2A06253B7A005AB5DA, + 1865EE2B06253B7A005AB5DA, + 1865EE2C06253B7A005AB5DA, + 1865EE2D06253B7A005AB5DA, + 1865EE2E06253B7A005AB5DA, + 1865EE3606253B7A005AB5DA, + 1865EE3E06253B7A005AB5DA, + 1865EE3F06253B7A005AB5DA, + 1865EE4706253B7B005AB5DA, + 1865EE4C06253B7B005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EE2A06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EE2B06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EE2C06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EE2D06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EE2E06253B7A005AB5DA = { + children = ( + 1865EE2F06253B7A005AB5DA, + 1865EE3006253B7A005AB5DA, + 1865EE3106253B7A005AB5DA, + 1865EE3206253B7A005AB5DA, + 1865EE3306253B7A005AB5DA, + 1865EE3406253B7A005AB5DA, + 1865EE3506253B7A005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE2F06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el1.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el2.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-blue.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-red.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex-trim.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3406253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3506253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tp_ent.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE3606253B7A005AB5DA = { + children = ( + 1865EE3706253B7A005AB5DA, + 1865EE3806253B7A005AB5DA, + 1865EE3906253B7A005AB5DA, + 1865EE3A06253B7A005AB5DA, + 1865EE3B06253B7A005AB5DA, + 1865EE3C06253B7A005AB5DA, + 1865EE3D06253B7A005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EE3706253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el1.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3806253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el2.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3906253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-blue.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3A06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-red.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3B06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex-trim.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3C06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3D06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tp_ent.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE3E06253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EE3F06253B7A005AB5DA = { + children = ( + 1865EE4006253B7A005AB5DA, + 1865EE4106253B7A005AB5DA, + 1865EE4206253B7A005AB5DA, + 1865EE4306253B7A005AB5DA, + 1865EE4406253B7B005AB5DA, + 1865EE4506253B7B005AB5DA, + 1865EE4606253B7B005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4006253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el1.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4106253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el2.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4206253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-blue.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4306253B7A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-red.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex-trim.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tp_ent.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4706253B7B005AB5DA = { + children = ( + 1865EE4806253B7B005AB5DA, + 1865EE4906253B7B005AB5DA, + 1865EE4A06253B7B005AB5DA, + 1865EE4B06253B7B005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EE4806253B7B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4906253B7B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EE4A06253B7B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE4B06253B7B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EE4C06253B7B005AB5DA = { + children = ( + 1865EE4D06253B7B005AB5DA, + 1865EE4E06253B7B005AB5DA, + 1865EE4F06253B7B005AB5DA, + 1865EE5006253B7B005AB5DA, + 1865EE5106253B7B005AB5DA, + 1865EE5206253B7B005AB5DA, + 1865EE5306253B7B005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EE4D06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el1.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE4E06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el2.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE4F06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-blue.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE5006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-red.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE5106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex-trim.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE5206253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE5306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tp_ent.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE5406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el1.txt"; + refType = 4; + sourceTree = ""; + }; + 1865EE5506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bt-el2.txt"; + refType = 4; + sourceTree = ""; + }; + 1865EE5606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-blue.txt"; + refType = 4; + sourceTree = ""; + }; + 1865EE5706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ctf-red.txt"; + refType = 4; + sourceTree = ""; + }; + 1865EE5806253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex-trim.txt"; + refType = 4; + sourceTree = ""; + }; + 1865EE5906253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "door-tex.txt"; + refType = 4; + sourceTree = ""; + }; + 1865EE5A06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = tp_ent.txt; + refType = 4; + sourceTree = ""; + }; + 1865EE5B06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = cportals.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EE5C06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = CPortals.h; + refType = 4; + sourceTree = ""; + }; + 1865EE5D06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ctfresource_gtk.h; + refType = 4; + sourceTree = ""; + }; + 1865EE5E06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ctfresource_gtk.rc; + refType = 4; + sourceTree = ""; + }; + 1865EE5F06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = "ctfToolz-GTK.cpp"; + refType = 4; + sourceTree = ""; + }; + 1865EE6006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ctftoolz.def; + refType = 4; + sourceTree = ""; + }; + 1865EE6106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DBobView.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EE6206253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DBobView.h; + refType = 4; + sourceTree = ""; + }; + 1865EE6306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DBrush.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EE6406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DBrush.h; + refType = 4; + sourceTree = ""; + }; + 1865EE6506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DEntity.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EE6606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DEntity.h; + refType = 4; + sourceTree = ""; + }; + 1865EE6706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DEPair.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EE6806253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DEPair.h; + refType = 4; + sourceTree = ""; + }; + 1865EE6906253B7B005AB5DA = { + children = ( + 1865EE6A06253B7B005AB5DA, + 1865EED906253B7C005AB5DA, + 1865EEDA06253B7C005AB5DA, + 1865EEDB06253B7C005AB5DA, + 1865EEDC06253B7C005AB5DA, + 1865EEDD06253B7C005AB5DA, + 1865EEDE06253B7C005AB5DA, + 1865EEDF06253B7C005AB5DA, + 1865EEE006253B7C005AB5DA, + 1865EEE106253B7C005AB5DA, + 1865EEE206253B7C005AB5DA, + 1865EEE306253B7C005AB5DA, + 1865EEE406253B7C005AB5DA, + 1865EEE506253B7C005AB5DA, + 1865EEE606253B7C005AB5DA, + 1865EEE706253B7C005AB5DA, + 1865EEE806253B7C005AB5DA, + 1865EEE906253B7C005AB5DA, + 1865EEEA06253B7C005AB5DA, + 1865EEEB06253B7C005AB5DA, + 1865EEEC06253B7C005AB5DA, + 1865EEED06253B7C005AB5DA, + 1865EEEE06253B7C005AB5DA, + 1865EEEF06253B7C005AB5DA, + 1865EEF006253B7C005AB5DA, + ); + isa = PBXGroup; + path = dialogs; + refType = 4; + sourceTree = ""; + }; + 1865EE6A06253B7B005AB5DA = { + children = ( + 1865EE6B06253B7B005AB5DA, + 1865EE6C06253B7B005AB5DA, + 1865EE6D06253B7B005AB5DA, + 1865EE6E06253B7B005AB5DA, + 1865EE6F06253B7B005AB5DA, + 1865EE8806253B7B005AB5DA, + 1865EEA106253B7B005AB5DA, + 1865EEA206253B7B005AB5DA, + 1865EEBB06253B7C005AB5DA, + 1865EEC006253B7C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EE6B06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EE6C06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EE6D06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EE6E06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EE6F06253B7B005AB5DA = { + children = ( + 1865EE7006253B7B005AB5DA, + 1865EE7106253B7B005AB5DA, + 1865EE7206253B7B005AB5DA, + 1865EE7306253B7B005AB5DA, + 1865EE7406253B7B005AB5DA, + 1865EE7506253B7B005AB5DA, + 1865EE7606253B7B005AB5DA, + 1865EE7706253B7B005AB5DA, + 1865EE7806253B7B005AB5DA, + 1865EE7906253B7B005AB5DA, + 1865EE7A06253B7B005AB5DA, + 1865EE7B06253B7B005AB5DA, + 1865EE7C06253B7B005AB5DA, + 1865EE7D06253B7B005AB5DA, + 1865EE7E06253B7B005AB5DA, + 1865EE7F06253B7B005AB5DA, + 1865EE8006253B7B005AB5DA, + 1865EE8106253B7B005AB5DA, + 1865EE8206253B7B005AB5DA, + 1865EE8306253B7B005AB5DA, + 1865EE8406253B7B005AB5DA, + 1865EE8506253B7B005AB5DA, + 1865EE8606253B7B005AB5DA, + 1865EE8706253B7B005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7206253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushcheckdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BrushCheckDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7806253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7906253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7A06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7B06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7C06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7D06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7E06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE7F06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8206253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EE8806253B7B005AB5DA = { + children = ( + 1865EE8906253B7B005AB5DA, + 1865EE8A06253B7B005AB5DA, + 1865EE8B06253B7B005AB5DA, + 1865EE8C06253B7B005AB5DA, + 1865EE8D06253B7B005AB5DA, + 1865EE8E06253B7B005AB5DA, + 1865EE8F06253B7B005AB5DA, + 1865EE9006253B7B005AB5DA, + 1865EE9106253B7B005AB5DA, + 1865EE9206253B7B005AB5DA, + 1865EE9306253B7B005AB5DA, + 1865EE9406253B7B005AB5DA, + 1865EE9506253B7B005AB5DA, + 1865EE9606253B7B005AB5DA, + 1865EE9706253B7B005AB5DA, + 1865EE9806253B7B005AB5DA, + 1865EE9906253B7B005AB5DA, + 1865EE9A06253B7B005AB5DA, + 1865EE9B06253B7B005AB5DA, + 1865EE9C06253B7B005AB5DA, + 1865EE9D06253B7B005AB5DA, + 1865EE9E06253B7B005AB5DA, + 1865EE9F06253B7B005AB5DA, + 1865EEA006253B7B005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EE8906253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE8A06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE8B06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE8C06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE8D06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE8E06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE8F06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushcheckdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BrushCheckDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9206253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9806253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9906253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9A06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9B06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9C06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9D06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9E06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EE9F06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEA006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEA106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EEA206253B7B005AB5DA = { + children = ( + 1865EEA306253B7B005AB5DA, + 1865EEA406253B7B005AB5DA, + 1865EEA506253B7B005AB5DA, + 1865EEA606253B7B005AB5DA, + 1865EEA706253B7B005AB5DA, + 1865EEA806253B7B005AB5DA, + 1865EEA906253B7B005AB5DA, + 1865EEAA06253B7B005AB5DA, + 1865EEAB06253B7B005AB5DA, + 1865EEAC06253B7B005AB5DA, + 1865EEAD06253B7B005AB5DA, + 1865EEAE06253B7B005AB5DA, + 1865EEAF06253B7B005AB5DA, + 1865EEB006253B7B005AB5DA, + 1865EEB106253B7B005AB5DA, + 1865EEB206253B7B005AB5DA, + 1865EEB306253B7B005AB5DA, + 1865EEB406253B7B005AB5DA, + 1865EEB506253B7B005AB5DA, + 1865EEB606253B7B005AB5DA, + 1865EEB706253B7B005AB5DA, + 1865EEB806253B7C005AB5DA, + 1865EEB906253B7C005AB5DA, + 1865EEBA06253B7C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA806253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEA906253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushcheckdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEAA06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BrushCheckDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEAB06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEAC06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEAD06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEAE06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEAF06253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB006253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB106253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB206253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB306253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB406253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB506253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB606253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB706253B7B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEB906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEBA06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEBB06253B7C005AB5DA = { + children = ( + 1865EEBC06253B7C005AB5DA, + 1865EEBD06253B7C005AB5DA, + 1865EEBE06253B7C005AB5DA, + 1865EEBF06253B7C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EEBC06253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEBD06253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EEBE06253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EEBF06253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EEC006253B7C005AB5DA = { + children = ( + 1865EEC106253B7C005AB5DA, + 1865EEC206253B7C005AB5DA, + 1865EEC306253B7C005AB5DA, + 1865EEC406253B7C005AB5DA, + 1865EEC506253B7C005AB5DA, + 1865EEC606253B7C005AB5DA, + 1865EEC706253B7C005AB5DA, + 1865EEC806253B7C005AB5DA, + 1865EEC906253B7C005AB5DA, + 1865EECA06253B7C005AB5DA, + 1865EECB06253B7C005AB5DA, + 1865EECC06253B7C005AB5DA, + 1865EECD06253B7C005AB5DA, + 1865EECE06253B7C005AB5DA, + 1865EECF06253B7C005AB5DA, + 1865EED006253B7C005AB5DA, + 1865EED106253B7C005AB5DA, + 1865EED206253B7C005AB5DA, + 1865EED306253B7C005AB5DA, + 1865EED406253B7C005AB5DA, + 1865EED506253B7C005AB5DA, + 1865EED606253B7C005AB5DA, + 1865EED706253B7C005AB5DA, + 1865EED806253B7C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EEC106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AutoCaulkStartDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "brushcheckdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "BrushCheckDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EEC906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EECA06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs-gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EECB06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EECC06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DoorDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EECD06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EECE06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EECF06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IntersectInfoDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pathplotterdialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PolygonDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StairDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TextureResetDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EED906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = AboutDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEDA06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = AboutDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEDB06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = AutoCaulkDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEDC06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = AutoCaulkDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEDD06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = AutoCaulkStartDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEDE06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = AutoCaulkStartDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEDF06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = brushcheckdialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEE006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = BrushCheckDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEE106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = "dialogs-gtk.cpp"; + refType = 4; + sourceTree = ""; + }; + 1865EEE206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "dialogs-gtk.h"; + refType = 4; + sourceTree = ""; + }; + 1865EEE306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DoorDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEE406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DoorDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEE506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = IntersectDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEE606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = IntersectDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEE706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = IntersectInfoDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEE806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = IntersectInfoDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEE906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = pathplotterdialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEEA06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = pathplotterdialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEEB06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = PolygonDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEEC06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = PolygonDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEED06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = StairDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEEE06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = StairDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEEF06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = TextureResetDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEF006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = TextureResetDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865EEF106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DListener.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEF206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DListener.h; + refType = 4; + sourceTree = ""; + }; + 1865EEF306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DMap.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEF406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DMap.h; + refType = 4; + sourceTree = ""; + }; + 1865EEF506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DPatch.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEF606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DPatch.h; + refType = 4; + sourceTree = ""; + }; + 1865EEF706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DPlane.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEF806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DPlane.h; + refType = 4; + sourceTree = ""; + }; + 1865EEF906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DPoint.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEFA06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DPoint.h; + refType = 4; + sourceTree = ""; + }; + 1865EEFB06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DShape.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEFC06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DShape.h; + refType = 4; + sourceTree = ""; + }; + 1865EEFD06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DTrainDrawer.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EEFE06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DTrainDrawer.h; + refType = 4; + sourceTree = ""; + }; + 1865EEFF06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DTreePlanter.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF0006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DTreePlanter.h; + refType = 4; + sourceTree = ""; + }; + 1865EF0106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DVisDrawer.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF0206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DVisDrawer.h; + refType = 4; + sourceTree = ""; + }; + 1865EF0306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = DWinding.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF0406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = DWinding.h; + refType = 4; + sourceTree = ""; + }; + 1865EF0506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = "funchandlers-ctf-GTK.cpp"; + refType = 4; + sourceTree = ""; + }; + 1865EF0606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = "funchandlers-GTK.cpp"; + refType = 4; + sourceTree = ""; + }; + 1865EF0706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = funchandlers.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF0806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = funchandlers.h; + refType = 4; + sourceTree = ""; + }; + 1865EF0906253B7C005AB5DA = { + children = ( + 1865EF0A06253B7C005AB5DA, + 1865EF1D06253B7C005AB5DA, + ); + isa = PBXGroup; + path = interfaces; + refType = 4; + sourceTree = ""; + }; + 1865EF0A06253B7C005AB5DA = { + children = ( + 1865EF0B06253B7C005AB5DA, + 1865EF0C06253B7C005AB5DA, + 1865EF0D06253B7C005AB5DA, + 1865EF0E06253B7C005AB5DA, + 1865EF0F06253B7C005AB5DA, + 1865EF1106253B7C005AB5DA, + 1865EF1306253B7C005AB5DA, + 1865EF1406253B7C005AB5DA, + 1865EF1606253B7C005AB5DA, + 1865EF1B06253B7C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EF0B06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EF0C06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EF0D06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EF0E06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EF0F06253B7C005AB5DA = { + children = ( + 1865EF1006253B7C005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF1006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IScriptParser.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF1106253B7C005AB5DA = { + children = ( + 1865EF1206253B7C005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF1206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IScriptParser.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF1306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EF1406253B7C005AB5DA = { + children = ( + 1865EF1506253B7C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF1506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IScriptParser.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF1606253B7C005AB5DA = { + children = ( + 1865EF1706253B7C005AB5DA, + 1865EF1806253B7C005AB5DA, + 1865EF1906253B7C005AB5DA, + 1865EF1A06253B7C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EF1706253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF1806253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF1906253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF1A06253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF1B06253B7C005AB5DA = { + children = ( + 1865EF1C06253B7C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF1C06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "IScriptParser.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF1D06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = IScriptParser.h; + refType = 4; + sourceTree = ""; + }; + 1865EF1E06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = lists.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF1F06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = lists.h; + refType = 4; + sourceTree = ""; + }; + 1865EF2006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = misc.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF2106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = misc.h; + refType = 4; + sourceTree = ""; + }; + 1865EF2206253B7C005AB5DA = { + children = ( + 1865EF2306253B7C005AB5DA, + 1865EF3606253B7C005AB5DA, + ); + isa = PBXGroup; + path = res; + refType = 4; + sourceTree = ""; + }; + 1865EF2306253B7C005AB5DA = { + children = ( + 1865EF2406253B7C005AB5DA, + 1865EF2506253B7C005AB5DA, + 1865EF2606253B7C005AB5DA, + 1865EF2706253B7C005AB5DA, + 1865EF2806253B7C005AB5DA, + 1865EF2A06253B7C005AB5DA, + 1865EF2C06253B7C005AB5DA, + 1865EF2D06253B7C005AB5DA, + 1865EF2F06253B7C005AB5DA, + 1865EF3406253B7C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EF2406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EF2506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EF2606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EF2706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EF2806253B7C005AB5DA = { + children = ( + 1865EF2906253B7C005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF2906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.rc2.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF2A06253B7C005AB5DA = { + children = ( + 1865EF2B06253B7C005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF2B06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.rc2.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF2C06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EF2D06253B7C005AB5DA = { + children = ( + 1865EF2E06253B7C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF2E06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.rc2.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF2F06253B7C005AB5DA = { + children = ( + 1865EF3006253B7C005AB5DA, + 1865EF3106253B7C005AB5DA, + 1865EF3206253B7C005AB5DA, + 1865EF3306253B7C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EF3006253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF3106253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF3206253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF3306253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF3406253B7C005AB5DA = { + children = ( + 1865EF3506253B7C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF3506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.rc2.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF3606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = plugin.rc2; + refType = 4; + sourceTree = ""; + }; + 1865EF3706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "resource-gtk.h"; + refType = 4; + sourceTree = ""; + }; + 1865EF3806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = resource.h; + refType = 4; + sourceTree = ""; + }; + 1865EF3906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = ScriptParser.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF3A06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ScriptParser.h; + refType = 4; + sourceTree = ""; + }; + 1865EF3B06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = shapes.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF3C06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = shapes.h; + refType = 4; + sourceTree = ""; + }; + 1865EF3D06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = StdAfx.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF3E06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = StdAfx.h; + refType = 4; + sourceTree = ""; + }; + 1865EF3F06253B7C005AB5DA = { + children = ( + 1865EF4006253B7C005AB5DA, + 1865EF5706253B7C005AB5DA, + 1865EF5806253B7C005AB5DA, + ); + isa = PBXGroup; + path = txt; + refType = 4; + sourceTree = ""; + }; + 1865EF4006253B7C005AB5DA = { + children = ( + 1865EF4106253B7C005AB5DA, + 1865EF4206253B7C005AB5DA, + 1865EF4306253B7C005AB5DA, + 1865EF4406253B7C005AB5DA, + 1865EF4506253B7C005AB5DA, + 1865EF4806253B7C005AB5DA, + 1865EF4B06253B7C005AB5DA, + 1865EF4C06253B7C005AB5DA, + 1865EF4F06253B7C005AB5DA, + 1865EF5406253B7C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EF4106253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EF4206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EF4306253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EF4406253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EF4506253B7C005AB5DA = { + children = ( + 1865EF4606253B7C005AB5DA, + 1865EF4706253B7C005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF4606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF4706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF4806253B7C005AB5DA = { + children = ( + 1865EF4906253B7C005AB5DA, + 1865EF4A06253B7C005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF4906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF4A06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF4B06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EF4C06253B7C005AB5DA = { + children = ( + 1865EF4D06253B7C005AB5DA, + 1865EF4E06253B7C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF4D06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF4E06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF4F06253B7C005AB5DA = { + children = ( + 1865EF5006253B7C005AB5DA, + 1865EF5106253B7C005AB5DA, + 1865EF5206253B7C005AB5DA, + 1865EF5306253B7C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EF5006253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF5106253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF5206253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF5306253B7C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF5406253B7C005AB5DA = { + children = ( + 1865EF5506253B7C005AB5DA, + 1865EF5606253B7C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF5506253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changelog.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF5606253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "readme.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF5706253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = changelog.txt; + refType = 4; + sourceTree = ""; + }; + 1865EF5806253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = readme.txt; + refType = 4; + sourceTree = ""; + }; + 1865EF5906253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = visfind.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EF5A06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = visfind.h; + refType = 4; + sourceTree = ""; + }; + 1865EF5B06253B7C005AB5DA = { + children = ( + 1865EF5C06253B7C005AB5DA, + 1865EFA706253B7D005AB5DA, + 1865EFBC06253B7D005AB5DA, + 1865EFBD06253B7D005AB5DA, + 1865EFBE06253B7D005AB5DA, + 1865EFBF06253B7D005AB5DA, + 1865EFC006253B7D005AB5DA, + 1865EFC106253B7D005AB5DA, + 1865EFC206253B7D005AB5DA, + 1865EFC306253B7D005AB5DA, + 1865EFC406253B7D005AB5DA, + 1865EFC506253B7D005AB5DA, + 1865EFC606253B7D005AB5DA, + 1865EFC706253B7D005AB5DA, + 1865EFC806253B7D005AB5DA, + 1865EFC906253B7D005AB5DA, + 1865EFCA06253B7D005AB5DA, + ); + isa = PBXGroup; + path = camera; + refType = 4; + sourceTree = ""; + }; + 1865EF5C06253B7C005AB5DA = { + children = ( + 1865EF5D06253B7C005AB5DA, + 1865EF5E06253B7C005AB5DA, + 1865EF5F06253B7C005AB5DA, + 1865EF6006253B7C005AB5DA, + 1865EF6106253B7C005AB5DA, + 1865EF7106253B7D005AB5DA, + 1865EF8106253B7D005AB5DA, + 1865EF8206253B7D005AB5DA, + 1865EF9206253B7D005AB5DA, + 1865EF9706253B7D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EF5D06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EF5E06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EF5F06253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EF6006253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EF6106253B7C005AB5DA = { + children = ( + 1865EF6206253B7C005AB5DA, + 1865EF6306253B7D005AB5DA, + 1865EF6406253B7D005AB5DA, + 1865EF6506253B7D005AB5DA, + 1865EF6606253B7D005AB5DA, + 1865EF6706253B7D005AB5DA, + 1865EF6806253B7D005AB5DA, + 1865EF6906253B7D005AB5DA, + 1865EF6A06253B7D005AB5DA, + 1865EF6B06253B7D005AB5DA, + 1865EF6C06253B7D005AB5DA, + 1865EF6D06253B7D005AB5DA, + 1865EF6E06253B7D005AB5DA, + 1865EF6F06253B7D005AB5DA, + 1865EF7006253B7D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6206253B7C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6306253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6406253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6506253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6606253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6706253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6806253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs_common.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6A06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6B06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6C06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6D06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6E06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF6F06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF7006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF7106253B7D005AB5DA = { + children = ( + 1865EF7206253B7D005AB5DA, + 1865EF7306253B7D005AB5DA, + 1865EF7406253B7D005AB5DA, + 1865EF7506253B7D005AB5DA, + 1865EF7606253B7D005AB5DA, + 1865EF7706253B7D005AB5DA, + 1865EF7806253B7D005AB5DA, + 1865EF7906253B7D005AB5DA, + 1865EF7A06253B7D005AB5DA, + 1865EF7B06253B7D005AB5DA, + 1865EF7C06253B7D005AB5DA, + 1865EF7D06253B7D005AB5DA, + 1865EF7E06253B7D005AB5DA, + 1865EF7F06253B7D005AB5DA, + 1865EF8006253B7D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF7206253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7306253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7406253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7506253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7606253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7706253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7806253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs_common.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7A06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7B06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7C06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7D06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7E06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF7F06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF8006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF8106253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EF8206253B7D005AB5DA = { + children = ( + 1865EF8306253B7D005AB5DA, + 1865EF8406253B7D005AB5DA, + 1865EF8506253B7D005AB5DA, + 1865EF8606253B7D005AB5DA, + 1865EF8706253B7D005AB5DA, + 1865EF8806253B7D005AB5DA, + 1865EF8906253B7D005AB5DA, + 1865EF8A06253B7D005AB5DA, + 1865EF8B06253B7D005AB5DA, + 1865EF8C06253B7D005AB5DA, + 1865EF8D06253B7D005AB5DA, + 1865EF8E06253B7D005AB5DA, + 1865EF8F06253B7D005AB5DA, + 1865EF9006253B7D005AB5DA, + 1865EF9106253B7D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8306253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8406253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8506253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8606253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "camera.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8706253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8806253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs_common.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8A06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8B06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8C06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8D06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8E06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF8F06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF9006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF9106253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF9206253B7D005AB5DA = { + children = ( + 1865EF9306253B7D005AB5DA, + 1865EF9406253B7D005AB5DA, + 1865EF9506253B7D005AB5DA, + 1865EF9606253B7D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EF9306253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF9406253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EF9506253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EF9606253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF9706253B7D005AB5DA = { + children = ( + 1865EF9806253B7D005AB5DA, + 1865EF9906253B7D005AB5DA, + 1865EF9A06253B7D005AB5DA, + 1865EF9B06253B7D005AB5DA, + 1865EF9C06253B7D005AB5DA, + 1865EF9D06253B7D005AB5DA, + 1865EF9E06253B7D005AB5DA, + 1865EF9F06253B7D005AB5DA, + 1865EFA006253B7D005AB5DA, + 1865EFA106253B7D005AB5DA, + 1865EFA206253B7D005AB5DA, + 1865EFA306253B7D005AB5DA, + 1865EFA406253B7D005AB5DA, + 1865EFA506253B7D005AB5DA, + 1865EFA606253B7D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EF9806253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9A06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9B06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9C06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9D06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9E06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dialogs_common.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EF9F06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "funchandlers.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA106253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA206253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "listener.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA306253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA406253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA506253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA606253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "renderer.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFA706253B7D005AB5DA = { + children = ( + 1865EFA806253B7D005AB5DA, + 1865EFBB06253B7D005AB5DA, + ); + isa = PBXGroup; + path = bitmaps; + refType = 4; + sourceTree = ""; + }; + 1865EFA806253B7D005AB5DA = { + children = ( + 1865EFA906253B7D005AB5DA, + 1865EFAA06253B7D005AB5DA, + 1865EFAB06253B7D005AB5DA, + 1865EFAC06253B7D005AB5DA, + 1865EFAD06253B7D005AB5DA, + 1865EFAF06253B7D005AB5DA, + 1865EFB106253B7D005AB5DA, + 1865EFB206253B7D005AB5DA, + 1865EFB406253B7D005AB5DA, + 1865EFB906253B7D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EFA906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EFAA06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EFAB06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EFAC06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EFAD06253B7D005AB5DA = { + children = ( + 1865EFAE06253B7D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFAE06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera_insp.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFAF06253B7D005AB5DA = { + children = ( + 1865EFB006253B7D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EFB006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera_insp.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFB106253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EFB206253B7D005AB5DA = { + children = ( + 1865EFB306253B7D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFB306253B7D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "camera_insp.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFB406253B7D005AB5DA = { + children = ( + 1865EFB506253B7D005AB5DA, + 1865EFB606253B7D005AB5DA, + 1865EFB706253B7D005AB5DA, + 1865EFB806253B7D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865EFB506253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFB606253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EFB706253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFB806253B7D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EFB906253B7D005AB5DA = { + children = ( + 1865EFBA06253B7D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865EFBA06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "camera_insp.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFBB06253B7D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = camera_insp.bmp; + refType = 4; + sourceTree = ""; + }; + 1865EFBC06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = camera.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFBD06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = camera.def; + refType = 4; + sourceTree = ""; + }; + 1865EFBE06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = camera.h; + refType = 4; + sourceTree = ""; + }; + 1865EFBF06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = camera.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865EFC006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = dialogs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFC106253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = dialogs.h; + refType = 4; + sourceTree = ""; + }; + 1865EFC206253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = dialogs_common.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFC306253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = funchandlers.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFC406253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = funchandlers.h; + refType = 4; + sourceTree = ""; + }; + 1865EFC506253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = listener.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFC606253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = listener.h; + refType = 4; + sourceTree = ""; + }; + 1865EFC706253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = misc.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFC806253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = misc.h; + refType = 4; + sourceTree = ""; + }; + 1865EFC906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = renderer.cpp; + refType = 4; + sourceTree = ""; + }; + 1865EFCA06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = renderer.h; + refType = 4; + sourceTree = ""; + }; + 1865EFCB06253B7D005AB5DA = { + children = ( + 1865EFCC06253B7D005AB5DA, + 1865EFCD06253B7D005AB5DA, + 1865F02406253B7E005AB5DA, + 1865F02506253B7E005AB5DA, + 1865F02606253B7E005AB5DA, + 1865F02706253B7E005AB5DA, + 1865F02806253B7E005AB5DA, + 1865F02906253B7E005AB5DA, + 1865F02A06253B7E005AB5DA, + 1865F02B06253B7E005AB5DA, + 1865F02C06253B7E005AB5DA, + 1865F02D06253B7E005AB5DA, + 1865F02E06253B7E005AB5DA, + 1865F02F06253B7E005AB5DA, + 1865F03006253B7E005AB5DA, + 1865F03106253B7E005AB5DA, + 1865F03206253B7E005AB5DA, + 1865F03306253B7E005AB5DA, + 1865F03406253B7E005AB5DA, + ); + isa = PBXGroup; + path = gtkgensurf; + refType = 4; + sourceTree = ""; + }; + 1865EFCC06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865EFCD06253B7D005AB5DA = { + children = ( + 1865EFCE06253B7D005AB5DA, + 1865EFCF06253B7D005AB5DA, + 1865EFD006253B7D005AB5DA, + 1865EFD106253B7D005AB5DA, + 1865EFD206253B7D005AB5DA, + 1865EFE506253B7E005AB5DA, + 1865EFF806253B7E005AB5DA, + 1865EFF906253B7E005AB5DA, + 1865F00C06253B7E005AB5DA, + 1865F01106253B7E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865EFCE06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865EFCF06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865EFD006253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865EFD106253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865EFD206253B7D005AB5DA = { + children = ( + 1865EFD306253B7D005AB5DA, + 1865EFD406253B7D005AB5DA, + 1865EFD506253B7D005AB5DA, + 1865EFD606253B7D005AB5DA, + 1865EFD706253B7D005AB5DA, + 1865EFD806253B7D005AB5DA, + 1865EFD906253B7D005AB5DA, + 1865EFDA06253B7D005AB5DA, + 1865EFDB06253B7D005AB5DA, + 1865EFDC06253B7D005AB5DA, + 1865EFDD06253B7E005AB5DA, + 1865EFDE06253B7E005AB5DA, + 1865EFDF06253B7E005AB5DA, + 1865EFE006253B7E005AB5DA, + 1865EFE106253B7E005AB5DA, + 1865EFE206253B7E005AB5DA, + 1865EFE306253B7E005AB5DA, + 1865EFE406253B7E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD306253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD406253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bitmap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD506253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD606253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dec.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD706253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "face.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD806253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "font.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFD906253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFDA06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFDB06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genmap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFDC06253B7D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFDD06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFDE06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFDF06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkgensurf.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFE006253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFE106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFE206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFE306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFE406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFE506253B7E005AB5DA = { + children = ( + 1865EFE606253B7E005AB5DA, + 1865EFE706253B7E005AB5DA, + 1865EFE806253B7E005AB5DA, + 1865EFE906253B7E005AB5DA, + 1865EFEA06253B7E005AB5DA, + 1865EFEB06253B7E005AB5DA, + 1865EFEC06253B7E005AB5DA, + 1865EFED06253B7E005AB5DA, + 1865EFEE06253B7E005AB5DA, + 1865EFEF06253B7E005AB5DA, + 1865EFF006253B7E005AB5DA, + 1865EFF106253B7E005AB5DA, + 1865EFF206253B7E005AB5DA, + 1865EFF306253B7E005AB5DA, + 1865EFF406253B7E005AB5DA, + 1865EFF506253B7E005AB5DA, + 1865EFF606253B7E005AB5DA, + 1865EFF706253B7E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865EFE606253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFE706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bitmap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFE806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFE906253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dec.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFEA06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "face.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFEB06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "font.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFEC06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFED06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFEE06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genmap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFEF06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF006253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkgensurf.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF506253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF606253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865EFF806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865EFF906253B7E005AB5DA = { + children = ( + 1865EFFA06253B7E005AB5DA, + 1865EFFB06253B7E005AB5DA, + 1865EFFC06253B7E005AB5DA, + 1865EFFD06253B7E005AB5DA, + 1865EFFE06253B7E005AB5DA, + 1865EFFF06253B7E005AB5DA, + 1865F00006253B7E005AB5DA, + 1865F00106253B7E005AB5DA, + 1865F00206253B7E005AB5DA, + 1865F00306253B7E005AB5DA, + 1865F00406253B7E005AB5DA, + 1865F00506253B7E005AB5DA, + 1865F00606253B7E005AB5DA, + 1865F00706253B7E005AB5DA, + 1865F00806253B7E005AB5DA, + 1865F00906253B7E005AB5DA, + 1865F00A06253B7E005AB5DA, + 1865F00B06253B7E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFFA06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFFB06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bitmap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFFC06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFFD06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dec.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFFE06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "face.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865EFFF06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "font.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00006253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genmap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00506253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00606253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "gtkgensurf.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00906253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00A06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00B06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00C06253B7E005AB5DA = { + children = ( + 1865F00D06253B7E005AB5DA, + 1865F00E06253B7E005AB5DA, + 1865F00F06253B7E005AB5DA, + 1865F01006253B7E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F00D06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F00E06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F00F06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F01006253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F01106253B7E005AB5DA = { + children = ( + 1865F01206253B7E005AB5DA, + 1865F01306253B7E005AB5DA, + 1865F01406253B7E005AB5DA, + 1865F01506253B7E005AB5DA, + 1865F01606253B7E005AB5DA, + 1865F01706253B7E005AB5DA, + 1865F01806253B7E005AB5DA, + 1865F01906253B7E005AB5DA, + 1865F01A06253B7E005AB5DA, + 1865F01B06253B7E005AB5DA, + 1865F01C06253B7E005AB5DA, + 1865F01D06253B7E005AB5DA, + 1865F01E06253B7E005AB5DA, + 1865F01F06253B7E005AB5DA, + 1865F02006253B7E005AB5DA, + 1865F02106253B7E005AB5DA, + 1865F02206253B7E005AB5DA, + 1865F02306253B7E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F01206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bitmap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01506253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dec.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01606253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "face.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "font.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01906253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendlgs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01A06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genmap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01B06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01C06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01D06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gensurf.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01E06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkgensurf.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F01F06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "heretic.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F02006253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F02106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F02206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "triangle.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F02306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "view.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F02406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = bitmap.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02506253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = CHANGES; + refType = 4; + sourceTree = ""; + }; + 1865F02606253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = dec.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = face.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = font.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02906253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = gendlgs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02A06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gendlgs.h; + refType = 4; + sourceTree = ""; + }; + 1865F02B06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = genmap.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02C06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = gensurf.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F02D06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gensurf.def; + refType = 4; + sourceTree = ""; + }; + 1865F02E06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gensurf.h; + refType = 4; + sourceTree = ""; + }; + 1865F02F06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = gtkgensurf.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865F03006253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = heretic.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F03106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F03206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = triangle.c; + refType = 4; + sourceTree = ""; + }; + 1865F03306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = triangle.h; + refType = 4; + sourceTree = ""; + }; + 1865F03406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = view.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F03506253B7E005AB5DA = { + children = ( + 1865F03606253B7E005AB5DA, + 1865F05506253B7E005AB5DA, + 1865F05606253B7E005AB5DA, + 1865F05706253B7E005AB5DA, + 1865F05806253B7E005AB5DA, + ); + isa = PBXGroup; + path = hydratoolz; + refType = 4; + sourceTree = ""; + }; + 1865F03606253B7E005AB5DA = { + children = ( + 1865F03706253B7E005AB5DA, + 1865F03806253B7E005AB5DA, + 1865F03906253B7E005AB5DA, + 1865F03A06253B7E005AB5DA, + 1865F03B06253B7E005AB5DA, + 1865F04006253B7E005AB5DA, + 1865F04506253B7E005AB5DA, + 1865F04606253B7E005AB5DA, + 1865F04B06253B7E005AB5DA, + 1865F05006253B7E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F03706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F03806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F03906253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F03A06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F03B06253B7E005AB5DA = { + children = ( + 1865F03C06253B7E005AB5DA, + 1865F03D06253B7E005AB5DA, + 1865F03E06253B7E005AB5DA, + 1865F03F06253B7E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F03C06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F03D06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F03E06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F03F06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04006253B7E005AB5DA = { + children = ( + 1865F04106253B7E005AB5DA, + 1865F04206253B7E005AB5DA, + 1865F04306253B7E005AB5DA, + 1865F04406253B7E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F04106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F04206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F04306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F04406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F04506253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F04606253B7E005AB5DA = { + children = ( + 1865F04706253B7E005AB5DA, + 1865F04806253B7E005AB5DA, + 1865F04906253B7E005AB5DA, + 1865F04A06253B7E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "hydratoolz.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04906253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04A06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04B06253B7E005AB5DA = { + children = ( + 1865F04C06253B7E005AB5DA, + 1865F04D06253B7E005AB5DA, + 1865F04E06253B7E005AB5DA, + 1865F04F06253B7E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F04C06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04D06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F04E06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F04F06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F05006253B7E005AB5DA = { + children = ( + 1865F05106253B7E005AB5DA, + 1865F05206253B7E005AB5DA, + 1865F05306253B7E005AB5DA, + 1865F05406253B7E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F05106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F05206253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "hydratoolz.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F05306253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F05406253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F05506253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = hydratoolz.def; + refType = 4; + sourceTree = ""; + }; + 1865F05606253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = hydratoolz.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865F05706253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F05806253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865F05906253B7E005AB5DA = { + children = ( + 1865F05A06253B7E005AB5DA, + 1865F06906253B7E005AB5DA, + ); + isa = PBXGroup; + path = patches; + refType = 4; + sourceTree = ""; + }; + 1865F05A06253B7E005AB5DA = { + children = ( + 1865F05B06253B7E005AB5DA, + 1865F05C06253B7E005AB5DA, + 1865F05D06253B7E005AB5DA, + 1865F05E06253B7E005AB5DA, + 1865F05F06253B7E005AB5DA, + 1865F06006253B7E005AB5DA, + 1865F06106253B7E005AB5DA, + 1865F06206253B7E005AB5DA, + 1865F06306253B7E005AB5DA, + 1865F06806253B7E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F05B06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F05C06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F05D06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F05E06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F05F06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F06006253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F06106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F06206253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F06306253B7E005AB5DA = { + children = ( + 1865F06406253B7E005AB5DA, + 1865F06506253B7E005AB5DA, + 1865F06606253B7E005AB5DA, + 1865F06706253B7E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F06406253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F06506253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F06606253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F06706253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F06806253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F06906253B7E005AB5DA = { + children = ( + 1865F06A06253B7E005AB5DA, + 1865F07906253B7E005AB5DA, + ); + isa = PBXGroup; + path = Gtk; + refType = 4; + sourceTree = ""; + }; + 1865F06A06253B7E005AB5DA = { + children = ( + 1865F06B06253B7E005AB5DA, + 1865F06C06253B7E005AB5DA, + 1865F06D06253B7E005AB5DA, + 1865F06E06253B7E005AB5DA, + 1865F06F06253B7E005AB5DA, + 1865F07006253B7E005AB5DA, + 1865F07106253B7E005AB5DA, + 1865F07206253B7E005AB5DA, + 1865F07306253B7E005AB5DA, + 1865F07806253B7E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F06B06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F06C06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F06D06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F06E06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F06F06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F07006253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F07106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F07206253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F07306253B7E005AB5DA = { + children = ( + 1865F07406253B7E005AB5DA, + 1865F07506253B7E005AB5DA, + 1865F07606253B7E005AB5DA, + 1865F07706253B7E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F07406253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F07506253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F07606253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F07706253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F07806253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F07906253B7E005AB5DA = { + children = ( + 1865F07A06253B7E005AB5DA, + ); + isa = PBXGroup; + path = fileselect; + refType = 4; + sourceTree = ""; + }; + 1865F07A06253B7E005AB5DA = { + children = ( + 1865F07B06253B7E005AB5DA, + 1865F07C06253B7E005AB5DA, + 1865F07D06253B7E005AB5DA, + 1865F07E06253B7E005AB5DA, + 1865F07F06253B7E005AB5DA, + 1865F08006253B7E005AB5DA, + 1865F08106253B7E005AB5DA, + 1865F08206253B7E005AB5DA, + 1865F08306253B7E005AB5DA, + 1865F08806253B7E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F07B06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F07C06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F07D06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F07E06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F07F06253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F08006253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F08106253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F08206253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F08306253B7E005AB5DA = { + children = ( + 1865F08406253B7E005AB5DA, + 1865F08506253B7E005AB5DA, + 1865F08606253B7E005AB5DA, + 1865F08706253B7E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F08406253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F08506253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F08606253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F08706253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F08806253B7E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F08906253B7E005AB5DA = { + children = ( + 1865F08A06253B7E005AB5DA, + 1865F08B06253B7E005AB5DA, + 1865F0EE06253B7F005AB5DA, + 1865F0EF06253B7F005AB5DA, + 1865F0F006253B7F005AB5DA, + 1865F0F106253B7F005AB5DA, + 1865F0F206253B7F005AB5DA, + 1865F0F306253B7F005AB5DA, + 1865F0F406253B7F005AB5DA, + 1865F0F506253B7F005AB5DA, + 1865F0F606253B80005AB5DA, + 1865F0F706253B80005AB5DA, + 1865F0F806253B80005AB5DA, + 1865F0F906253B80005AB5DA, + 1865F0FA06253B80005AB5DA, + 1865F0FB06253B80005AB5DA, + 1865F0FC06253B80005AB5DA, + 1865F0FD06253B80005AB5DA, + 1865F0FE06253B80005AB5DA, + 1865F0FF06253B80005AB5DA, + 1865F11406253B80005AB5DA, + 1865F11506253B80005AB5DA, + 1865F11606253B80005AB5DA, + ); + isa = PBXGroup; + path = prtview; + refType = 4; + sourceTree = ""; + }; + 1865F08A06253B7E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865F08B06253B7E005AB5DA = { + children = ( + 1865F08C06253B7F005AB5DA, + 1865F08D06253B7F005AB5DA, + 1865F08E06253B7F005AB5DA, + 1865F08F06253B7F005AB5DA, + 1865F09006253B7F005AB5DA, + 1865F0A606253B7F005AB5DA, + 1865F0BC06253B7F005AB5DA, + 1865F0BD06253B7F005AB5DA, + 1865F0D306253B7F005AB5DA, + 1865F0D806253B7F005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F08C06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F08D06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F08E06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F08F06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F09006253B7F005AB5DA = { + children = ( + 1865F09106253B7F005AB5DA, + 1865F09206253B7F005AB5DA, + 1865F09306253B7F005AB5DA, + 1865F09406253B7F005AB5DA, + 1865F09506253B7F005AB5DA, + 1865F09606253B7F005AB5DA, + 1865F09706253B7F005AB5DA, + 1865F09806253B7F005AB5DA, + 1865F09906253B7F005AB5DA, + 1865F09A06253B7F005AB5DA, + 1865F09B06253B7F005AB5DA, + 1865F09C06253B7F005AB5DA, + 1865F09D06253B7F005AB5DA, + 1865F09E06253B7F005AB5DA, + 1865F09F06253B7F005AB5DA, + 1865F0A006253B7F005AB5DA, + 1865F0A106253B7F005AB5DA, + 1865F0A206253B7F005AB5DA, + 1865F0A306253B7F005AB5DA, + 1865F0A406253B7F005AB5DA, + 1865F0A506253B7F005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09306253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09406253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09506253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09606253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09706253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09806253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09906253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09A06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09B06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09C06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.aps.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09D06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09E06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F09F06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A006253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A306253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A406253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A506253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0A606253B7F005AB5DA = { + children = ( + 1865F0A706253B7F005AB5DA, + 1865F0A806253B7F005AB5DA, + 1865F0A906253B7F005AB5DA, + 1865F0AA06253B7F005AB5DA, + 1865F0AB06253B7F005AB5DA, + 1865F0AC06253B7F005AB5DA, + 1865F0AD06253B7F005AB5DA, + 1865F0AE06253B7F005AB5DA, + 1865F0AF06253B7F005AB5DA, + 1865F0B006253B7F005AB5DA, + 1865F0B106253B7F005AB5DA, + 1865F0B206253B7F005AB5DA, + 1865F0B306253B7F005AB5DA, + 1865F0B406253B7F005AB5DA, + 1865F0B506253B7F005AB5DA, + 1865F0B606253B7F005AB5DA, + 1865F0B706253B7F005AB5DA, + 1865F0B806253B7F005AB5DA, + 1865F0B906253B7F005AB5DA, + 1865F0BA06253B7F005AB5DA, + 1865F0BB06253B7F005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F0A706253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0A806253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0A906253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0AA06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0AB06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0AC06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0AD06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0AE06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0AF06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B006253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.aps.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B306253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B406253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B506253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B606253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B706253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B806253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0B906253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0BA06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0BB06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0BC06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F0BD06253B7F005AB5DA = { + children = ( + 1865F0BE06253B7F005AB5DA, + 1865F0BF06253B7F005AB5DA, + 1865F0C006253B7F005AB5DA, + 1865F0C106253B7F005AB5DA, + 1865F0C206253B7F005AB5DA, + 1865F0C306253B7F005AB5DA, + 1865F0C406253B7F005AB5DA, + 1865F0C506253B7F005AB5DA, + 1865F0C606253B7F005AB5DA, + 1865F0C706253B7F005AB5DA, + 1865F0C806253B7F005AB5DA, + 1865F0C906253B7F005AB5DA, + 1865F0CA06253B7F005AB5DA, + 1865F0CB06253B7F005AB5DA, + 1865F0CC06253B7F005AB5DA, + 1865F0CD06253B7F005AB5DA, + 1865F0CE06253B7F005AB5DA, + 1865F0CF06253B7F005AB5DA, + 1865F0D006253B7F005AB5DA, + 1865F0D106253B7F005AB5DA, + 1865F0D206253B7F005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0BE06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0BF06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C006253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C306253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C406253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C506253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C606253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C706253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C806253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0C906253B7F005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "PrtView.aps.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0CA06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0CB06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0CC06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0CD06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0CE06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0CF06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "PrtView.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0D006253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0D106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0D206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0D306253B7F005AB5DA = { + children = ( + 1865F0D406253B7F005AB5DA, + 1865F0D506253B7F005AB5DA, + 1865F0D606253B7F005AB5DA, + 1865F0D706253B7F005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F0D406253B7F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0D506253B7F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F0D606253B7F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F0D706253B7F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F0D806253B7F005AB5DA = { + children = ( + 1865F0D906253B7F005AB5DA, + 1865F0DA06253B7F005AB5DA, + 1865F0DB06253B7F005AB5DA, + 1865F0DC06253B7F005AB5DA, + 1865F0DD06253B7F005AB5DA, + 1865F0DE06253B7F005AB5DA, + 1865F0DF06253B7F005AB5DA, + 1865F0E006253B7F005AB5DA, + 1865F0E106253B7F005AB5DA, + 1865F0E206253B7F005AB5DA, + 1865F0E306253B7F005AB5DA, + 1865F0E406253B7F005AB5DA, + 1865F0E506253B7F005AB5DA, + 1865F0E606253B7F005AB5DA, + 1865F0E706253B7F005AB5DA, + 1865F0E806253B7F005AB5DA, + 1865F0E906253B7F005AB5DA, + 1865F0EA06253B7F005AB5DA, + 1865F0EB06253B7F005AB5DA, + 1865F0EC06253B7F005AB5DA, + 1865F0ED06253B7F005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F0D906253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0DA06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0DB06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "AboutDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0DC06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0DD06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ConfigDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0DE06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0DF06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkdlgs.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E006253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "LoadPortalFileDialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E306253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "portals.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E406253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.aps.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E506253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E606253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E706253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "prtview.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E806253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0E906253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0EA06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0EB06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "resource.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0EC06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0ED06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stdafx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F0EE06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = AboutDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F0EF06253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = AboutDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865F0F006253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = ConfigDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F0F106253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ConfigDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865F0F206253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = gtkdlgs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F0F306253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gtkdlgs.h; + refType = 4; + sourceTree = ""; + }; + 1865F0F406253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = LoadPortalFileDialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F0F506253B7F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = LoadPortalFileDialog.h; + refType = 4; + sourceTree = ""; + }; + 1865F0F606253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = portals.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F0F706253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = portals.h; + refType = 4; + sourceTree = ""; + }; + 1865F0F806253B80005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = PrtView.aps; + refType = 4; + sourceTree = ""; + }; + 1865F0F906253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = prtview.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F0FA06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = PrtView.def; + refType = 4; + sourceTree = ""; + }; + 1865F0FB06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = prtview.h; + refType = 4; + sourceTree = ""; + }; + 1865F0FC06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = PrtView.rc; + refType = 4; + sourceTree = ""; + }; + 1865F0FD06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = PrtView.txt; + refType = 4; + sourceTree = ""; + }; + 1865F0FE06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = PrtView.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865F0FF06253B80005AB5DA = { + children = ( + 1865F10006253B80005AB5DA, + 1865F11306253B80005AB5DA, + ); + isa = PBXGroup; + path = res; + refType = 4; + sourceTree = ""; + }; + 1865F10006253B80005AB5DA = { + children = ( + 1865F10106253B80005AB5DA, + 1865F10206253B80005AB5DA, + 1865F10306253B80005AB5DA, + 1865F10406253B80005AB5DA, + 1865F10506253B80005AB5DA, + 1865F10706253B80005AB5DA, + 1865F10906253B80005AB5DA, + 1865F10A06253B80005AB5DA, + 1865F10C06253B80005AB5DA, + 1865F11106253B80005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F10106253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F10206253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F10306253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F10406253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F10506253B80005AB5DA = { + children = ( + 1865F10606253B80005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F10606253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc2.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F10706253B80005AB5DA = { + children = ( + 1865F10806253B80005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F10806253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc2.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F10906253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F10A06253B80005AB5DA = { + children = ( + 1865F10B06253B80005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F10B06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc2.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F10C06253B80005AB5DA = { + children = ( + 1865F10D06253B80005AB5DA, + 1865F10E06253B80005AB5DA, + 1865F10F06253B80005AB5DA, + 1865F11006253B80005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F10D06253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F10E06253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F10F06253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F11006253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F11106253B80005AB5DA = { + children = ( + 1865F11206253B80005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F11206253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PrtView.rc2.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F11306253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = PrtView.rc2; + refType = 4; + sourceTree = ""; + }; + 1865F11406253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = resource.h; + refType = 4; + sourceTree = ""; + }; + 1865F11506253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = stdafx.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F11606253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = stdafx.h; + refType = 4; + sourceTree = ""; + }; + 1865F11706253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = CONTRIBUTOR_AGREEMENT; + refType = 4; + sourceTree = ""; + }; + 1865F11806253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = CONTRIBUTORS; + refType = 4; + sourceTree = ""; + }; + 1865F11906253B80005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = text.rtf; + path = DarwinCompileInfo.rtf; + refType = 4; + sourceTree = ""; + }; + 1865F11A06253B80005AB5DA = { + children = ( + 1865F11B06253B80005AB5DA, + 1865F12A06253B80005AB5DA, + 1865F25206253B84005AB5DA, + ); + isa = PBXGroup; + path = docs; + refType = 4; + sourceTree = ""; + }; + 1865F11B06253B80005AB5DA = { + children = ( + 1865F11C06253B80005AB5DA, + 1865F11D06253B80005AB5DA, + 1865F11E06253B80005AB5DA, + 1865F11F06253B80005AB5DA, + 1865F12006253B80005AB5DA, + 1865F12106253B80005AB5DA, + 1865F12206253B80005AB5DA, + 1865F12306253B80005AB5DA, + 1865F12406253B80005AB5DA, + 1865F12906253B80005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F11C06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F11D06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F11E06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F11F06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F12006253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F12106253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F12206253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F12306253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F12406253B80005AB5DA = { + children = ( + 1865F12506253B80005AB5DA, + 1865F12606253B80005AB5DA, + 1865F12706253B80005AB5DA, + 1865F12806253B80005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F12506253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F12606253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F12706253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F12806253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F12906253B80005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F12A06253B80005AB5DA = { + children = ( + 1865F12B06253B80005AB5DA, + 1865F12C06253B80005AB5DA, + 1865F17706253B81005AB5DA, + 1865F17806253B81005AB5DA, + 1865F17906253B81005AB5DA, + 1865F17A06253B81005AB5DA, + 1865F17B06253B81005AB5DA, + 1865F17C06253B81005AB5DA, + 1865F17D06253B81005AB5DA, + 1865F17E06253B81005AB5DA, + 1865F1B606253B82005AB5DA, + 1865F1B706253B82005AB5DA, + 1865F1E006253B82005AB5DA, + 1865F1E106253B82005AB5DA, + 1865F1E206253B82005AB5DA, + 1865F21006253B83005AB5DA, + 1865F22506253B83005AB5DA, + 1865F22606253B83005AB5DA, + 1865F22706253B83005AB5DA, + 1865F22806253B83005AB5DA, + 1865F22906253B83005AB5DA, + ); + isa = PBXGroup; + path = developer; + refType = 4; + sourceTree = ""; + }; + 1865F12B06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865F12C06253B80005AB5DA = { + children = ( + 1865F12D06253B80005AB5DA, + 1865F12E06253B80005AB5DA, + 1865F12F06253B80005AB5DA, + 1865F13006253B80005AB5DA, + 1865F13106253B80005AB5DA, + 1865F14106253B80005AB5DA, + 1865F15106253B81005AB5DA, + 1865F15206253B81005AB5DA, + 1865F16206253B81005AB5DA, + 1865F16706253B81005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F12D06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F12E06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F12F06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F13006253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F13106253B80005AB5DA = { + children = ( + 1865F13206253B80005AB5DA, + 1865F13306253B80005AB5DA, + 1865F13406253B80005AB5DA, + 1865F13506253B80005AB5DA, + 1865F13606253B80005AB5DA, + 1865F13706253B80005AB5DA, + 1865F13806253B80005AB5DA, + 1865F13906253B80005AB5DA, + 1865F13A06253B80005AB5DA, + 1865F13B06253B80005AB5DA, + 1865F13C06253B80005AB5DA, + 1865F13D06253B80005AB5DA, + 1865F13E06253B80005AB5DA, + 1865F13F06253B80005AB5DA, + 1865F14006253B80005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13206253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13306253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changes.201.202.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13406253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13506253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "d2u.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13606253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "data-driven-design.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13706253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DRAFT.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13806253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "frp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13906253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HEAP.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13A06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3mapfeedback.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13B06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TESTERS.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13C06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13D06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32BETA.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13E06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32SETUP.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F13F06253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XML.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F14006253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLmap.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F14106253B80005AB5DA = { + children = ( + 1865F14206253B80005AB5DA, + 1865F14306253B80005AB5DA, + 1865F14406253B80005AB5DA, + 1865F14506253B80005AB5DA, + 1865F14606253B81005AB5DA, + 1865F14706253B81005AB5DA, + 1865F14806253B81005AB5DA, + 1865F14906253B81005AB5DA, + 1865F14A06253B81005AB5DA, + 1865F14B06253B81005AB5DA, + 1865F14C06253B81005AB5DA, + 1865F14D06253B81005AB5DA, + 1865F14E06253B81005AB5DA, + 1865F14F06253B81005AB5DA, + 1865F15006253B81005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F14206253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14306253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changes.201.202.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14406253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14506253B80005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "d2u.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14606253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "data-driven-design.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14706253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DRAFT.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14806253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "frp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14906253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HEAP.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14A06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3mapfeedback.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14B06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TESTERS.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14C06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14D06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32BETA.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14E06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32SETUP.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F14F06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XML.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F15006253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLmap.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F15106253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F15206253B81005AB5DA = { + children = ( + 1865F15306253B81005AB5DA, + 1865F15406253B81005AB5DA, + 1865F15506253B81005AB5DA, + 1865F15606253B81005AB5DA, + 1865F15706253B81005AB5DA, + 1865F15806253B81005AB5DA, + 1865F15906253B81005AB5DA, + 1865F15A06253B81005AB5DA, + 1865F15B06253B81005AB5DA, + 1865F15C06253B81005AB5DA, + 1865F15D06253B81005AB5DA, + 1865F15E06253B81005AB5DA, + 1865F15F06253B81005AB5DA, + 1865F16006253B81005AB5DA, + 1865F16106253B81005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15306253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15406253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changes.201.202.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15506253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15606253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "d2u.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15706253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "data-driven-design.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15806253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DRAFT.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15906253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "frp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15A06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HEAP.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15B06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3mapfeedback.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15C06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TESTERS.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15D06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15E06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32BETA.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F15F06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32SETUP.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F16006253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XML.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F16106253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLmap.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F16206253B81005AB5DA = { + children = ( + 1865F16306253B81005AB5DA, + 1865F16406253B81005AB5DA, + 1865F16506253B81005AB5DA, + 1865F16606253B81005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F16306253B81005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F16406253B81005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F16506253B81005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F16606253B81005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F16706253B81005AB5DA = { + children = ( + 1865F16806253B81005AB5DA, + 1865F16906253B81005AB5DA, + 1865F16A06253B81005AB5DA, + 1865F16B06253B81005AB5DA, + 1865F16C06253B81005AB5DA, + 1865F16D06253B81005AB5DA, + 1865F16E06253B81005AB5DA, + 1865F16F06253B81005AB5DA, + 1865F17006253B81005AB5DA, + 1865F17106253B81005AB5DA, + 1865F17206253B81005AB5DA, + 1865F17306253B81005AB5DA, + 1865F17406253B81005AB5DA, + 1865F17506253B81005AB5DA, + 1865F17606253B81005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F16806253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16906253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "changes.201.202.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16A06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CHANGES.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16B06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "d2u.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16C06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "data-driven-design.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16D06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "DRAFT.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16E06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "frp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F16F06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "HEAP.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17006253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3mapfeedback.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17106253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TESTERS.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17206253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "TODO.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17306253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32BETA.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17406253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "WIN32SETUP.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17506253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XML.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17606253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLmap.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F17706253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = CHANGES; + refType = 4; + sourceTree = ""; + }; + 1865F17806253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = changes.201.202; + refType = 4; + sourceTree = ""; + }; + 1865F17906253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = d2u; + refType = 4; + sourceTree = ""; + }; + 1865F17A06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "data-driven-design.txt"; + refType = 4; + sourceTree = ""; + }; + 1865F17B06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = DRAFT; + refType = 4; + sourceTree = ""; + }; + 1865F17C06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = frp; + refType = 4; + sourceTree = ""; + }; + 1865F17D06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = HEAP; + refType = 4; + sourceTree = ""; + }; + 1865F17E06253B81005AB5DA = { + children = ( + 1865F17F06253B81005AB5DA, + 1865F1AE06253B82005AB5DA, + 1865F1AF06253B82005AB5DA, + 1865F1B006253B82005AB5DA, + 1865F1B106253B82005AB5DA, + 1865F1B206253B82005AB5DA, + 1865F1B306253B82005AB5DA, + 1865F1B406253B82005AB5DA, + 1865F1B506253B82005AB5DA, + ); + isa = PBXGroup; + path = Inspector; + refType = 4; + sourceTree = ""; + }; + 1865F17F06253B81005AB5DA = { + children = ( + 1865F18006253B81005AB5DA, + 1865F18106253B81005AB5DA, + 1865F18206253B81005AB5DA, + 1865F18306253B81005AB5DA, + 1865F18406253B81005AB5DA, + 1865F18D06253B81005AB5DA, + 1865F19606253B82005AB5DA, + 1865F19706253B82005AB5DA, + 1865F1A006253B82005AB5DA, + 1865F1A506253B82005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F18006253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F18106253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F18206253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F18306253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F18406253B81005AB5DA = { + children = ( + 1865F18506253B81005AB5DA, + 1865F18606253B81005AB5DA, + 1865F18706253B81005AB5DA, + 1865F18806253B81005AB5DA, + 1865F18906253B81005AB5DA, + 1865F18A06253B81005AB5DA, + 1865F18B06253B81005AB5DA, + 1865F18C06253B81005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18506253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classdiagram1.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18606253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "collaborationdiagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18706253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inspector.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18806253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors.argo.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18906253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors.xmi.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18A06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_classdiagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18B06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_collaborationdiagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18C06253B81005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_usecasediagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F18D06253B81005AB5DA = { + children = ( + 1865F18E06253B82005AB5DA, + 1865F18F06253B82005AB5DA, + 1865F19006253B82005AB5DA, + 1865F19106253B82005AB5DA, + 1865F19206253B82005AB5DA, + 1865F19306253B82005AB5DA, + 1865F19406253B82005AB5DA, + 1865F19506253B82005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F18E06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classdiagram1.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F18F06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "collaborationdiagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19006253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inspector.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19106253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors.argo.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19206253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors.xmi.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19306253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_classdiagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19406253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_collaborationdiagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19506253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_usecasediagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F19606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F19706253B82005AB5DA = { + children = ( + 1865F19806253B82005AB5DA, + 1865F19906253B82005AB5DA, + 1865F19A06253B82005AB5DA, + 1865F19B06253B82005AB5DA, + 1865F19C06253B82005AB5DA, + 1865F19D06253B82005AB5DA, + 1865F19E06253B82005AB5DA, + 1865F19F06253B82005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19806253B82005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "classdiagram1.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "collaborationdiagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19A06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inspector.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19B06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "Inspectors.argo.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19C06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "Inspectors.xmi.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19D06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "Inspectors_classdiagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19E06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "Inspectors_collaborationdiagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F19F06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "Inspectors_usecasediagram1.pgml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1A006253B82005AB5DA = { + children = ( + 1865F1A106253B82005AB5DA, + 1865F1A206253B82005AB5DA, + 1865F1A306253B82005AB5DA, + 1865F1A406253B82005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F1A106253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1A206253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F1A306253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1A406253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F1A506253B82005AB5DA = { + children = ( + 1865F1A606253B82005AB5DA, + 1865F1A706253B82005AB5DA, + 1865F1A806253B82005AB5DA, + 1865F1A906253B82005AB5DA, + 1865F1AA06253B82005AB5DA, + 1865F1AB06253B82005AB5DA, + 1865F1AC06253B82005AB5DA, + 1865F1AD06253B82005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F1A606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classdiagram1.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1A706253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "collaborationdiagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1A806253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "inspector.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1A906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors.argo.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1AA06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors.xmi.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1AB06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_classdiagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1AC06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_collaborationdiagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1AD06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Inspectors_usecasediagram1.pgml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1AE06253B82005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = classdiagram1.gif; + refType = 4; + sourceTree = ""; + }; + 1865F1AF06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = collaborationdiagram1.pgml; + refType = 4; + sourceTree = ""; + }; + 1865F1B006253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = inspector.txt; + refType = 4; + sourceTree = ""; + }; + 1865F1B106253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = Inspectors.argo; + refType = 4; + sourceTree = ""; + }; + 1865F1B206253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = Inspectors.xmi; + refType = 4; + sourceTree = ""; + }; + 1865F1B306253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = Inspectors_classdiagram1.pgml; + refType = 4; + sourceTree = ""; + }; + 1865F1B406253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = Inspectors_collaborationdiagram1.pgml; + refType = 4; + sourceTree = ""; + }; + 1865F1B506253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = Inspectors_usecasediagram1.pgml; + refType = 4; + sourceTree = ""; + }; + 1865F1B606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3mapfeedback.txt; + refType = 4; + sourceTree = ""; + }; + 1865F1B706253B82005AB5DA = { + children = ( + 1865F1B806253B82005AB5DA, + 1865F1DB06253B82005AB5DA, + 1865F1DC06253B82005AB5DA, + 1865F1DD06253B82005AB5DA, + 1865F1DE06253B82005AB5DA, + 1865F1DF06253B82005AB5DA, + ); + isa = PBXGroup; + path = RegExp; + refType = 4; + sourceTree = ""; + }; + 1865F1B806253B82005AB5DA = { + children = ( + 1865F1B906253B82005AB5DA, + 1865F1BA06253B82005AB5DA, + 1865F1BB06253B82005AB5DA, + 1865F1BC06253B82005AB5DA, + 1865F1BD06253B82005AB5DA, + 1865F1C306253B82005AB5DA, + 1865F1C906253B82005AB5DA, + 1865F1CA06253B82005AB5DA, + 1865F1D006253B82005AB5DA, + 1865F1D506253B82005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F1B906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F1BA06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F1BB06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F1BC06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F1BD06253B82005AB5DA = { + children = ( + 1865F1BE06253B82005AB5DA, + 1865F1BF06253B82005AB5DA, + 1865F1C006253B82005AB5DA, + 1865F1C106253B82005AB5DA, + 1865F1C206253B82005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1BE06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.cleaned.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1BF06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1C006253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pattern.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1C106253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "replace.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1C206253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tstscrpt.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1C306253B82005AB5DA = { + children = ( + 1865F1C406253B82005AB5DA, + 1865F1C506253B82005AB5DA, + 1865F1C606253B82005AB5DA, + 1865F1C706253B82005AB5DA, + 1865F1C806253B82005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F1C406253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.cleaned.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1C506253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1C606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pattern.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1C706253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "replace.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1C806253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tstscrpt.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1C906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F1CA06253B82005AB5DA = { + children = ( + 1865F1CB06253B82005AB5DA, + 1865F1CC06253B82005AB5DA, + 1865F1CD06253B82005AB5DA, + 1865F1CE06253B82005AB5DA, + 1865F1CF06253B82005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1CB06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.cleaned.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1CC06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1CD06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pattern.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1CE06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "replace.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1CF06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tstscrpt.pl.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1D006253B82005AB5DA = { + children = ( + 1865F1D106253B82005AB5DA, + 1865F1D206253B82005AB5DA, + 1865F1D306253B82005AB5DA, + 1865F1D406253B82005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F1D106253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1D206253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F1D306253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1D406253B82005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F1D506253B82005AB5DA = { + children = ( + 1865F1D606253B82005AB5DA, + 1865F1D706253B82005AB5DA, + 1865F1D806253B82005AB5DA, + 1865F1D906253B82005AB5DA, + 1865F1DA06253B82005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F1D606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.cleaned.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1D706253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Go.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1D806253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pattern.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1D906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "replace.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1DA06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "tstscrpt.pl.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1DB06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Go; + refType = 4; + sourceTree = ""; + }; + 1865F1DC06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Go.cleaned; + refType = 4; + sourceTree = ""; + }; + 1865F1DD06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = pattern; + refType = 4; + sourceTree = ""; + }; + 1865F1DE06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.perl; + path = replace.pl; + refType = 4; + sourceTree = ""; + }; + 1865F1DF06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.perl; + path = tstscrpt.pl; + refType = 4; + sourceTree = ""; + }; + 1865F1E006253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TESTERS; + refType = 4; + sourceTree = ""; + }; + 1865F1E106253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = TODO; + refType = 4; + sourceTree = ""; + }; + 1865F1E206253B82005AB5DA = { + children = ( + 1865F1E306253B82005AB5DA, + 1865F20A06253B83005AB5DA, + 1865F20B06253B83005AB5DA, + 1865F20C06253B83005AB5DA, + 1865F20D06253B83005AB5DA, + 1865F20E06253B83005AB5DA, + 1865F20F06253B83005AB5DA, + ); + isa = PBXGroup; + path = TstMaps; + refType = 4; + sourceTree = ""; + }; + 1865F1E306253B82005AB5DA = { + children = ( + 1865F1E406253B82005AB5DA, + 1865F1E506253B82005AB5DA, + 1865F1E606253B82005AB5DA, + 1865F1E706253B82005AB5DA, + 1865F1E806253B82005AB5DA, + 1865F1EF06253B82005AB5DA, + 1865F1F606253B82005AB5DA, + 1865F1F706253B82005AB5DA, + 1865F1FE06253B83005AB5DA, + 1865F20306253B83005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F1E406253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F1E506253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F1E606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F1E706253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F1E806253B82005AB5DA = { + children = ( + 1865F1E906253B82005AB5DA, + 1865F1EA06253B82005AB5DA, + 1865F1EB06253B82005AB5DA, + 1865F1EC06253B82005AB5DA, + 1865F1ED06253B82005AB5DA, + 1865F1EE06253B82005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1E906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Desktop_pb_leaf.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1EA06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "komap1.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1EB06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "realloc.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1EC06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sput.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1ED06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ttq3dm3.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1EE06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "western.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1EF06253B82005AB5DA = { + children = ( + 1865F1F006253B82005AB5DA, + 1865F1F106253B82005AB5DA, + 1865F1F206253B82005AB5DA, + 1865F1F306253B82005AB5DA, + 1865F1F406253B82005AB5DA, + 1865F1F506253B82005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F1F006253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Desktop_pb_leaf.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1F106253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "komap1.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1F206253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "realloc.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1F306253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sput.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1F406253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ttq3dm3.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1F506253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "western.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F1F606253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F1F706253B82005AB5DA = { + children = ( + 1865F1F806253B82005AB5DA, + 1865F1F906253B82005AB5DA, + 1865F1FA06253B82005AB5DA, + 1865F1FB06253B82005AB5DA, + 1865F1FC06253B83005AB5DA, + 1865F1FD06253B83005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1F806253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Desktop_pb_leaf.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1F906253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "komap1.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1FA06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "realloc.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1FB06253B82005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sput.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1FC06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ttq3dm3.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1FD06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "western.map.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F1FE06253B83005AB5DA = { + children = ( + 1865F1FF06253B83005AB5DA, + 1865F20006253B83005AB5DA, + 1865F20106253B83005AB5DA, + 1865F20206253B83005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F1FF06253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F20006253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F20106253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F20206253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F20306253B83005AB5DA = { + children = ( + 1865F20406253B83005AB5DA, + 1865F20506253B83005AB5DA, + 1865F20606253B83005AB5DA, + 1865F20706253B83005AB5DA, + 1865F20806253B83005AB5DA, + 1865F20906253B83005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F20406253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Desktop_pb_leaf.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F20506253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "komap1.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F20606253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "realloc.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F20706253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sput.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F20806253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ttq3dm3.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F20906253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "western.map.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F20A06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Desktop_pb_leaf.map; + refType = 4; + sourceTree = ""; + }; + 1865F20B06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = komap1.map; + refType = 4; + sourceTree = ""; + }; + 1865F20C06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = realloc.map; + refType = 4; + sourceTree = ""; + }; + 1865F20D06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = sput.map; + refType = 4; + sourceTree = ""; + }; + 1865F20E06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ttq3dm3.map; + refType = 4; + sourceTree = ""; + }; + 1865F20F06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = western.map; + refType = 4; + sourceTree = ""; + }; + 1865F21006253B83005AB5DA = { + children = ( + 1865F21106253B83005AB5DA, + 1865F22406253B83005AB5DA, + ); + isa = PBXGroup; + path = UML; + refType = 4; + sourceTree = ""; + }; + 1865F21106253B83005AB5DA = { + children = ( + 1865F21206253B83005AB5DA, + 1865F21306253B83005AB5DA, + 1865F21406253B83005AB5DA, + 1865F21506253B83005AB5DA, + 1865F21606253B83005AB5DA, + 1865F21806253B83005AB5DA, + 1865F21A06253B83005AB5DA, + 1865F21B06253B83005AB5DA, + 1865F21D06253B83005AB5DA, + 1865F22206253B83005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F21206253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F21306253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F21406253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F21506253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F21606253B83005AB5DA = { + children = ( + 1865F21706253B83005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F21706253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modules.zargo.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F21806253B83005AB5DA = { + children = ( + 1865F21906253B83005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F21906253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modules.zargo.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F21A06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F21B06253B83005AB5DA = { + children = ( + 1865F21C06253B83005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F21C06253B83005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "modules.zargo.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F21D06253B83005AB5DA = { + children = ( + 1865F21E06253B83005AB5DA, + 1865F21F06253B83005AB5DA, + 1865F22006253B83005AB5DA, + 1865F22106253B83005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F21E06253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F21F06253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F22006253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F22106253B83005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F22206253B83005AB5DA = { + children = ( + 1865F22306253B83005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F22306253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modules.zargo.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F22406253B83005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = modules.zargo; + refType = 4; + sourceTree = ""; + }; + 1865F22506253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = WIN32BETA; + refType = 4; + sourceTree = ""; + }; + 1865F22606253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = WIN32SETUP; + refType = 4; + sourceTree = ""; + }; + 1865F22706253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = XML.txt; + refType = 4; + sourceTree = ""; + }; + 1865F22806253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = XMLmap.txt; + refType = 4; + sourceTree = ""; + }; + 1865F22906253B83005AB5DA = { + children = ( + 1865F22A06253B83005AB5DA, + 1865F24D06253B84005AB5DA, + 1865F24E06253B84005AB5DA, + 1865F24F06253B84005AB5DA, + 1865F25006253B84005AB5DA, + 1865F25106253B84005AB5DA, + ); + isa = PBXGroup; + path = XMLPush; + refType = 4; + sourceTree = ""; + }; + 1865F22A06253B83005AB5DA = { + children = ( + 1865F22B06253B83005AB5DA, + 1865F22C06253B83005AB5DA, + 1865F22D06253B83005AB5DA, + 1865F22E06253B83005AB5DA, + 1865F22F06253B83005AB5DA, + 1865F23506253B83005AB5DA, + 1865F23B06253B84005AB5DA, + 1865F23C06253B84005AB5DA, + 1865F24206253B84005AB5DA, + 1865F24706253B84005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F22B06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F22C06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F22D06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F22E06253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F22F06253B83005AB5DA = { + children = ( + 1865F23006253B83005AB5DA, + 1865F23106253B83005AB5DA, + 1865F23206253B83005AB5DA, + 1865F23306253B83005AB5DA, + 1865F23406253B83005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23006253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ReadMe.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23106253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23206253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23306253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLDump.xml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23406253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLPush.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23506253B83005AB5DA = { + children = ( + 1865F23606253B83005AB5DA, + 1865F23706253B83005AB5DA, + 1865F23806253B83005AB5DA, + 1865F23906253B83005AB5DA, + 1865F23A06253B84005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F23606253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ReadMe.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F23706253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F23806253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F23906253B83005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLDump.xml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F23A06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLPush.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F23B06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F23C06253B84005AB5DA = { + children = ( + 1865F23D06253B84005AB5DA, + 1865F23E06253B84005AB5DA, + 1865F23F06253B84005AB5DA, + 1865F24006253B84005AB5DA, + 1865F24106253B84005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23D06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ReadMe.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23E06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F23F06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F24006253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "XMLDump.xml.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F24106253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLPush.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F24206253B84005AB5DA = { + children = ( + 1865F24306253B84005AB5DA, + 1865F24406253B84005AB5DA, + 1865F24506253B84005AB5DA, + 1865F24606253B84005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F24306253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F24406253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F24506253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F24606253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F24706253B84005AB5DA = { + children = ( + 1865F24806253B84005AB5DA, + 1865F24906253B84005AB5DA, + 1865F24A06253B84005AB5DA, + 1865F24B06253B84005AB5DA, + 1865F24C06253B84005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F24806253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ReadMe.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F24906253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F24A06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "StdAfx.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F24B06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLDump.xml.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F24C06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "XMLPush.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F24D06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ReadMe.txt; + refType = 4; + sourceTree = ""; + }; + 1865F24E06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = StdAfx.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F24F06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = StdAfx.h; + refType = 4; + sourceTree = ""; + }; + 1865F25006253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = XMLDump.xml; + refType = 4; + sourceTree = ""; + }; + 1865F25106253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = XMLPush.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F25206253B84005AB5DA = { + children = ( + 1865F25306253B84005AB5DA, + 1865F26206253B84005AB5DA, + 1865F47606253B8C005AB5DA, + ); + isa = PBXGroup; + path = manual; + refType = 4; + sourceTree = ""; + }; + 1865F25306253B84005AB5DA = { + children = ( + 1865F25406253B84005AB5DA, + 1865F25506253B84005AB5DA, + 1865F25606253B84005AB5DA, + 1865F25706253B84005AB5DA, + 1865F25806253B84005AB5DA, + 1865F25906253B84005AB5DA, + 1865F25A06253B84005AB5DA, + 1865F25B06253B84005AB5DA, + 1865F25C06253B84005AB5DA, + 1865F26106253B84005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F25406253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F25506253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F25606253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F25706253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F25806253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F25906253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F25A06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F25B06253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F25C06253B84005AB5DA = { + children = ( + 1865F25D06253B84005AB5DA, + 1865F25E06253B84005AB5DA, + 1865F25F06253B84005AB5DA, + 1865F26006253B84005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F25D06253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F25E06253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F25F06253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F26006253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F26106253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F26206253B84005AB5DA = { + children = ( + 1865F26306253B84005AB5DA, + 1865F27606253B85005AB5DA, + 1865F2D106253B86005AB5DA, + 1865F2EB06253B86005AB5DA, + 1865F30006253B87005AB5DA, + 1865F31506253B87005AB5DA, + 1865F32A06253B87005AB5DA, + 1865F33F06253B87005AB5DA, + 1865F35406253B88005AB5DA, + 1865F36906253B88005AB5DA, + 1865F37E06253B88005AB5DA, + 1865F39306253B89005AB5DA, + 1865F3A806253B89005AB5DA, + 1865F3BD06253B89005AB5DA, + 1865F3D206253B8A005AB5DA, + 1865F3E706253B8A005AB5DA, + 1865F3E806253B8A005AB5DA, + 1865F46106253B8C005AB5DA, + ); + isa = PBXGroup; + path = Q3Rad_Manual; + refType = 4; + sourceTree = ""; + }; + 1865F26306253B84005AB5DA = { + children = ( + 1865F26406253B84005AB5DA, + 1865F26506253B84005AB5DA, + 1865F26606253B84005AB5DA, + 1865F26706253B84005AB5DA, + 1865F26806253B84005AB5DA, + 1865F26A06253B84005AB5DA, + 1865F26C06253B84005AB5DA, + 1865F26D06253B84005AB5DA, + 1865F26F06253B84005AB5DA, + 1865F27406253B84005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F26406253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F26506253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F26606253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F26706253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F26806253B84005AB5DA = { + children = ( + 1865F26906253B84005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F26906253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F26A06253B84005AB5DA = { + children = ( + 1865F26B06253B84005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F26B06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F26C06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F26D06253B84005AB5DA = { + children = ( + 1865F26E06253B84005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F26E06253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F26F06253B84005AB5DA = { + children = ( + 1865F27006253B84005AB5DA, + 1865F27106253B84005AB5DA, + 1865F27206253B84005AB5DA, + 1865F27306253B84005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F27006253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F27106253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F27206253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F27306253B84005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F27406253B84005AB5DA = { + children = ( + 1865F27506253B84005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F27506253B84005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F27606253B85005AB5DA = { + children = ( + 1865F27706253B85005AB5DA, + 1865F2C206253B86005AB5DA, + 1865F2C306253B86005AB5DA, + 1865F2C406253B86005AB5DA, + 1865F2C506253B86005AB5DA, + 1865F2C606253B86005AB5DA, + 1865F2C706253B86005AB5DA, + 1865F2C806253B86005AB5DA, + 1865F2C906253B86005AB5DA, + 1865F2CA06253B86005AB5DA, + 1865F2CB06253B86005AB5DA, + 1865F2CC06253B86005AB5DA, + 1865F2CD06253B86005AB5DA, + 1865F2CE06253B86005AB5DA, + 1865F2CF06253B86005AB5DA, + 1865F2D006253B86005AB5DA, + ); + isa = PBXGroup; + path = appndx; + refType = 4; + sourceTree = ""; + }; + 1865F27706253B85005AB5DA = { + children = ( + 1865F27806253B85005AB5DA, + 1865F27906253B85005AB5DA, + 1865F27A06253B85005AB5DA, + 1865F27B06253B85005AB5DA, + 1865F27C06253B85005AB5DA, + 1865F28C06253B85005AB5DA, + 1865F29C06253B85005AB5DA, + 1865F29D06253B85005AB5DA, + 1865F2AD06253B85005AB5DA, + 1865F2B206253B85005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F27806253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F27906253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F27A06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F27B06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F27C06253B85005AB5DA = { + children = ( + 1865F27D06253B85005AB5DA, + 1865F27E06253B85005AB5DA, + 1865F27F06253B85005AB5DA, + 1865F28006253B85005AB5DA, + 1865F28106253B85005AB5DA, + 1865F28206253B85005AB5DA, + 1865F28306253B85005AB5DA, + 1865F28406253B85005AB5DA, + 1865F28506253B85005AB5DA, + 1865F28606253B85005AB5DA, + 1865F28706253B85005AB5DA, + 1865F28806253B85005AB5DA, + 1865F28906253B85005AB5DA, + 1865F28A06253B85005AB5DA, + 1865F28B06253B85005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F27D06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_a.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F27E06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F27F06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_2.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28006253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_3.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28106253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_4.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28206253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_5.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28306253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_6.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28406253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_7.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28506253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_8.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28606253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_9.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28706253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_c.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28806253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_d.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28906253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_e.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28A06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_f.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28B06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sskey_dl.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F28C06253B85005AB5DA = { + children = ( + 1865F28D06253B85005AB5DA, + 1865F28E06253B85005AB5DA, + 1865F28F06253B85005AB5DA, + 1865F29006253B85005AB5DA, + 1865F29106253B85005AB5DA, + 1865F29206253B85005AB5DA, + 1865F29306253B85005AB5DA, + 1865F29406253B85005AB5DA, + 1865F29506253B85005AB5DA, + 1865F29606253B85005AB5DA, + 1865F29706253B85005AB5DA, + 1865F29806253B85005AB5DA, + 1865F29906253B85005AB5DA, + 1865F29A06253B85005AB5DA, + 1865F29B06253B85005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F28D06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_a.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F28E06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F28F06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_2.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29006253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_3.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29106253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_4.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29206253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_5.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29306253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_6.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29406253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_7.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29506253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_8.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29606253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_9.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29706253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_c.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29806253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_d.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29906253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_e.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29A06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_f.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29B06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sskey_dl.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F29C06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F29D06253B85005AB5DA = { + children = ( + 1865F29E06253B85005AB5DA, + 1865F29F06253B85005AB5DA, + 1865F2A006253B85005AB5DA, + 1865F2A106253B85005AB5DA, + 1865F2A206253B85005AB5DA, + 1865F2A306253B85005AB5DA, + 1865F2A406253B85005AB5DA, + 1865F2A506253B85005AB5DA, + 1865F2A606253B85005AB5DA, + 1865F2A706253B85005AB5DA, + 1865F2A806253B85005AB5DA, + 1865F2A906253B85005AB5DA, + 1865F2AA06253B85005AB5DA, + 1865F2AB06253B85005AB5DA, + 1865F2AC06253B85005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F29E06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_a.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F29F06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A006253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_2.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A106253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_3.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A206253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_4.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A306253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_5.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A406253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_6.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A506253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_7.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A606253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_8.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A706253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_9.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A806253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_c.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2A906253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_d.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2AA06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_e.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2AB06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_f.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2AC06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sskey_dl.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2AD06253B85005AB5DA = { + children = ( + 1865F2AE06253B85005AB5DA, + 1865F2AF06253B85005AB5DA, + 1865F2B006253B85005AB5DA, + 1865F2B106253B85005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F2AE06253B85005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2AF06253B85005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F2B006253B85005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2B106253B85005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F2B206253B85005AB5DA = { + children = ( + 1865F2B306253B85005AB5DA, + 1865F2B406253B85005AB5DA, + 1865F2B506253B85005AB5DA, + 1865F2B606253B85005AB5DA, + 1865F2B706253B85005AB5DA, + 1865F2B806253B85005AB5DA, + 1865F2B906253B85005AB5DA, + 1865F2BA06253B85005AB5DA, + 1865F2BB06253B85005AB5DA, + 1865F2BC06253B85005AB5DA, + 1865F2BD06253B85005AB5DA, + 1865F2BE06253B86005AB5DA, + 1865F2BF06253B86005AB5DA, + 1865F2C006253B86005AB5DA, + 1865F2C106253B86005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F2B306253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_a.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2B406253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2B506253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_2.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2B606253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_3.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2B706253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_4.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2B806253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_5.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2B906253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_6.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2BA06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_7.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2BB06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_8.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2BC06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_b_9.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2BD06253B85005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_c.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2BE06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_d.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2BF06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_e.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2C006253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appn_f.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2C106253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "sskey_dl.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2C206253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_a.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C306253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C406253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_2.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C506253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_3.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C606253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_4.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C706253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_5.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C806253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_6.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2C906253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_7.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2CA06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_8.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2CB06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_b_9.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2CC06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_c.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2CD06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_d.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2CE06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_e.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2CF06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appn_f.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2D006253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = sskey_dl.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2D106253B86005AB5DA = { + children = ( + 1865F2D206253B86005AB5DA, + 1865F2E906253B86005AB5DA, + 1865F2EA06253B86005AB5DA, + ); + isa = PBXGroup; + path = ch01; + refType = 4; + sourceTree = ""; + }; + 1865F2D206253B86005AB5DA = { + children = ( + 1865F2D306253B86005AB5DA, + 1865F2D406253B86005AB5DA, + 1865F2D506253B86005AB5DA, + 1865F2D606253B86005AB5DA, + 1865F2D706253B86005AB5DA, + 1865F2DA06253B86005AB5DA, + 1865F2DD06253B86005AB5DA, + 1865F2DE06253B86005AB5DA, + 1865F2E106253B86005AB5DA, + 1865F2E606253B86005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F2D306253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F2D406253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F2D506253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F2D606253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F2D706253B86005AB5DA = { + children = ( + 1865F2D806253B86005AB5DA, + 1865F2D906253B86005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2D806253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2D906253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_2.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2DA06253B86005AB5DA = { + children = ( + 1865F2DB06253B86005AB5DA, + 1865F2DC06253B86005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F2DB06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2DC06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_2.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2DD06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F2DE06253B86005AB5DA = { + children = ( + 1865F2DF06253B86005AB5DA, + 1865F2E006253B86005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2DF06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2E006253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_2.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2E106253B86005AB5DA = { + children = ( + 1865F2E206253B86005AB5DA, + 1865F2E306253B86005AB5DA, + 1865F2E406253B86005AB5DA, + 1865F2E506253B86005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F2E206253B86005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2E306253B86005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F2E406253B86005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2E506253B86005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F2E606253B86005AB5DA = { + children = ( + 1865F2E706253B86005AB5DA, + 1865F2E806253B86005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F2E706253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2E806253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_2.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2E906253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg1_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2EA06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg1_2.htm; + refType = 4; + sourceTree = ""; + }; + 1865F2EB06253B86005AB5DA = { + children = ( + 1865F2EC06253B86005AB5DA, + 1865F2FF06253B87005AB5DA, + ); + isa = PBXGroup; + path = ch02; + refType = 4; + sourceTree = ""; + }; + 1865F2EC06253B86005AB5DA = { + children = ( + 1865F2ED06253B86005AB5DA, + 1865F2EE06253B86005AB5DA, + 1865F2EF06253B86005AB5DA, + 1865F2F006253B86005AB5DA, + 1865F2F106253B86005AB5DA, + 1865F2F306253B87005AB5DA, + 1865F2F506253B87005AB5DA, + 1865F2F606253B87005AB5DA, + 1865F2F806253B87005AB5DA, + 1865F2FD06253B87005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F2ED06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F2EE06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F2EF06253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F2F006253B86005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F2F106253B86005AB5DA = { + children = ( + 1865F2F206253B87005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2F206253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2F306253B87005AB5DA = { + children = ( + 1865F2F406253B87005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F2F406253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2F506253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F2F606253B87005AB5DA = { + children = ( + 1865F2F706253B87005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2F706253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2F806253B87005AB5DA = { + children = ( + 1865F2F906253B87005AB5DA, + 1865F2FA06253B87005AB5DA, + 1865F2FB06253B87005AB5DA, + 1865F2FC06253B87005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F2F906253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2FA06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F2FB06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F2FC06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F2FD06253B87005AB5DA = { + children = ( + 1865F2FE06253B87005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F2FE06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F2FF06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg2_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F30006253B87005AB5DA = { + children = ( + 1865F30106253B87005AB5DA, + 1865F31406253B87005AB5DA, + ); + isa = PBXGroup; + path = ch03; + refType = 4; + sourceTree = ""; + }; + 1865F30106253B87005AB5DA = { + children = ( + 1865F30206253B87005AB5DA, + 1865F30306253B87005AB5DA, + 1865F30406253B87005AB5DA, + 1865F30506253B87005AB5DA, + 1865F30606253B87005AB5DA, + 1865F30806253B87005AB5DA, + 1865F30A06253B87005AB5DA, + 1865F30B06253B87005AB5DA, + 1865F30D06253B87005AB5DA, + 1865F31206253B87005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F30206253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F30306253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F30406253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F30506253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F30606253B87005AB5DA = { + children = ( + 1865F30706253B87005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F30706253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F30806253B87005AB5DA = { + children = ( + 1865F30906253B87005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F30906253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F30A06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F30B06253B87005AB5DA = { + children = ( + 1865F30C06253B87005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F30C06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F30D06253B87005AB5DA = { + children = ( + 1865F30E06253B87005AB5DA, + 1865F30F06253B87005AB5DA, + 1865F31006253B87005AB5DA, + 1865F31106253B87005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F30E06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F30F06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F31006253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F31106253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F31206253B87005AB5DA = { + children = ( + 1865F31306253B87005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F31306253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F31406253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg3_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F31506253B87005AB5DA = { + children = ( + 1865F31606253B87005AB5DA, + 1865F32906253B87005AB5DA, + ); + isa = PBXGroup; + path = ch04; + refType = 4; + sourceTree = ""; + }; + 1865F31606253B87005AB5DA = { + children = ( + 1865F31706253B87005AB5DA, + 1865F31806253B87005AB5DA, + 1865F31906253B87005AB5DA, + 1865F31A06253B87005AB5DA, + 1865F31B06253B87005AB5DA, + 1865F31D06253B87005AB5DA, + 1865F31F06253B87005AB5DA, + 1865F32006253B87005AB5DA, + 1865F32206253B87005AB5DA, + 1865F32706253B87005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F31706253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F31806253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F31906253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F31A06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F31B06253B87005AB5DA = { + children = ( + 1865F31C06253B87005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F31C06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F31D06253B87005AB5DA = { + children = ( + 1865F31E06253B87005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F31E06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F31F06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F32006253B87005AB5DA = { + children = ( + 1865F32106253B87005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F32106253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F32206253B87005AB5DA = { + children = ( + 1865F32306253B87005AB5DA, + 1865F32406253B87005AB5DA, + 1865F32506253B87005AB5DA, + 1865F32606253B87005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F32306253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F32406253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F32506253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F32606253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F32706253B87005AB5DA = { + children = ( + 1865F32806253B87005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F32806253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F32906253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg4_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F32A06253B87005AB5DA = { + children = ( + 1865F32B06253B87005AB5DA, + 1865F33E06253B87005AB5DA, + ); + isa = PBXGroup; + path = ch05; + refType = 4; + sourceTree = ""; + }; + 1865F32B06253B87005AB5DA = { + children = ( + 1865F32C06253B87005AB5DA, + 1865F32D06253B87005AB5DA, + 1865F32E06253B87005AB5DA, + 1865F32F06253B87005AB5DA, + 1865F33006253B87005AB5DA, + 1865F33206253B87005AB5DA, + 1865F33406253B87005AB5DA, + 1865F33506253B87005AB5DA, + 1865F33706253B87005AB5DA, + 1865F33C06253B87005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F32C06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F32D06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F32E06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F32F06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F33006253B87005AB5DA = { + children = ( + 1865F33106253B87005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F33106253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F33206253B87005AB5DA = { + children = ( + 1865F33306253B87005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F33306253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F33406253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F33506253B87005AB5DA = { + children = ( + 1865F33606253B87005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F33606253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F33706253B87005AB5DA = { + children = ( + 1865F33806253B87005AB5DA, + 1865F33906253B87005AB5DA, + 1865F33A06253B87005AB5DA, + 1865F33B06253B87005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F33806253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F33906253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F33A06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F33B06253B87005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F33C06253B87005AB5DA = { + children = ( + 1865F33D06253B87005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F33D06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F33E06253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg5_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F33F06253B87005AB5DA = { + children = ( + 1865F34006253B87005AB5DA, + 1865F35306253B88005AB5DA, + ); + isa = PBXGroup; + path = ch06; + refType = 4; + sourceTree = ""; + }; + 1865F34006253B87005AB5DA = { + children = ( + 1865F34106253B87005AB5DA, + 1865F34206253B87005AB5DA, + 1865F34306253B87005AB5DA, + 1865F34406253B88005AB5DA, + 1865F34506253B88005AB5DA, + 1865F34706253B88005AB5DA, + 1865F34906253B88005AB5DA, + 1865F34A06253B88005AB5DA, + 1865F34C06253B88005AB5DA, + 1865F35106253B88005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F34106253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F34206253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F34306253B87005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F34406253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F34506253B88005AB5DA = { + children = ( + 1865F34606253B88005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F34606253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F34706253B88005AB5DA = { + children = ( + 1865F34806253B88005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F34806253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F34906253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F34A06253B88005AB5DA = { + children = ( + 1865F34B06253B88005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F34B06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F34C06253B88005AB5DA = { + children = ( + 1865F34D06253B88005AB5DA, + 1865F34E06253B88005AB5DA, + 1865F34F06253B88005AB5DA, + 1865F35006253B88005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F34D06253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F34E06253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F34F06253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F35006253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F35106253B88005AB5DA = { + children = ( + 1865F35206253B88005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F35206253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F35306253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg6_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F35406253B88005AB5DA = { + children = ( + 1865F35506253B88005AB5DA, + 1865F36806253B88005AB5DA, + ); + isa = PBXGroup; + path = ch07; + refType = 4; + sourceTree = ""; + }; + 1865F35506253B88005AB5DA = { + children = ( + 1865F35606253B88005AB5DA, + 1865F35706253B88005AB5DA, + 1865F35806253B88005AB5DA, + 1865F35906253B88005AB5DA, + 1865F35A06253B88005AB5DA, + 1865F35C06253B88005AB5DA, + 1865F35E06253B88005AB5DA, + 1865F35F06253B88005AB5DA, + 1865F36106253B88005AB5DA, + 1865F36606253B88005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F35606253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F35706253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F35806253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F35906253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F35A06253B88005AB5DA = { + children = ( + 1865F35B06253B88005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F35B06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg7_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F35C06253B88005AB5DA = { + children = ( + 1865F35D06253B88005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F35D06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg7_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F35E06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F35F06253B88005AB5DA = { + children = ( + 1865F36006253B88005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F36006253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg7_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F36106253B88005AB5DA = { + children = ( + 1865F36206253B88005AB5DA, + 1865F36306253B88005AB5DA, + 1865F36406253B88005AB5DA, + 1865F36506253B88005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F36206253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F36306253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F36406253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F36506253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F36606253B88005AB5DA = { + children = ( + 1865F36706253B88005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F36706253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg7_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F36806253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg7_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F36906253B88005AB5DA = { + children = ( + 1865F36A06253B88005AB5DA, + 1865F37D06253B88005AB5DA, + ); + isa = PBXGroup; + path = ch08; + refType = 4; + sourceTree = ""; + }; + 1865F36A06253B88005AB5DA = { + children = ( + 1865F36B06253B88005AB5DA, + 1865F36C06253B88005AB5DA, + 1865F36D06253B88005AB5DA, + 1865F36E06253B88005AB5DA, + 1865F36F06253B88005AB5DA, + 1865F37106253B88005AB5DA, + 1865F37306253B88005AB5DA, + 1865F37406253B88005AB5DA, + 1865F37606253B88005AB5DA, + 1865F37B06253B88005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F36B06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F36C06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F36D06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F36E06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F36F06253B88005AB5DA = { + children = ( + 1865F37006253B88005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F37006253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg8_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F37106253B88005AB5DA = { + children = ( + 1865F37206253B88005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F37206253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg8_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F37306253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F37406253B88005AB5DA = { + children = ( + 1865F37506253B88005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F37506253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg8_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F37606253B88005AB5DA = { + children = ( + 1865F37706253B88005AB5DA, + 1865F37806253B88005AB5DA, + 1865F37906253B88005AB5DA, + 1865F37A06253B88005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F37706253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F37806253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F37906253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F37A06253B88005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F37B06253B88005AB5DA = { + children = ( + 1865F37C06253B88005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F37C06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg8_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F37D06253B88005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg8_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F37E06253B88005AB5DA = { + children = ( + 1865F37F06253B89005AB5DA, + 1865F39206253B89005AB5DA, + ); + isa = PBXGroup; + path = ch09; + refType = 4; + sourceTree = ""; + }; + 1865F37F06253B89005AB5DA = { + children = ( + 1865F38006253B89005AB5DA, + 1865F38106253B89005AB5DA, + 1865F38206253B89005AB5DA, + 1865F38306253B89005AB5DA, + 1865F38406253B89005AB5DA, + 1865F38606253B89005AB5DA, + 1865F38806253B89005AB5DA, + 1865F38906253B89005AB5DA, + 1865F38B06253B89005AB5DA, + 1865F39006253B89005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F38006253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F38106253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F38206253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F38306253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F38406253B89005AB5DA = { + children = ( + 1865F38506253B89005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F38506253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg9_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F38606253B89005AB5DA = { + children = ( + 1865F38706253B89005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F38706253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg9_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F38806253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F38906253B89005AB5DA = { + children = ( + 1865F38A06253B89005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F38A06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg9_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F38B06253B89005AB5DA = { + children = ( + 1865F38C06253B89005AB5DA, + 1865F38D06253B89005AB5DA, + 1865F38E06253B89005AB5DA, + 1865F38F06253B89005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F38C06253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F38D06253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F38E06253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F38F06253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F39006253B89005AB5DA = { + children = ( + 1865F39106253B89005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F39106253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg9_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F39206253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg9_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F39306253B89005AB5DA = { + children = ( + 1865F39406253B89005AB5DA, + 1865F3A706253B89005AB5DA, + ); + isa = PBXGroup; + path = ch10; + refType = 4; + sourceTree = ""; + }; + 1865F39406253B89005AB5DA = { + children = ( + 1865F39506253B89005AB5DA, + 1865F39606253B89005AB5DA, + 1865F39706253B89005AB5DA, + 1865F39806253B89005AB5DA, + 1865F39906253B89005AB5DA, + 1865F39B06253B89005AB5DA, + 1865F39D06253B89005AB5DA, + 1865F39E06253B89005AB5DA, + 1865F3A006253B89005AB5DA, + 1865F3A506253B89005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F39506253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F39606253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F39706253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F39806253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F39906253B89005AB5DA = { + children = ( + 1865F39A06253B89005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F39A06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg10_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F39B06253B89005AB5DA = { + children = ( + 1865F39C06253B89005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F39C06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg10_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F39D06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F39E06253B89005AB5DA = { + children = ( + 1865F39F06253B89005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F39F06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg10_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3A006253B89005AB5DA = { + children = ( + 1865F3A106253B89005AB5DA, + 1865F3A206253B89005AB5DA, + 1865F3A306253B89005AB5DA, + 1865F3A406253B89005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F3A106253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3A206253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3A306253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3A406253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3A506253B89005AB5DA = { + children = ( + 1865F3A606253B89005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3A606253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg10_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3A706253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg10_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F3A806253B89005AB5DA = { + children = ( + 1865F3A906253B89005AB5DA, + 1865F3BC06253B89005AB5DA, + ); + isa = PBXGroup; + path = ch11; + refType = 4; + sourceTree = ""; + }; + 1865F3A906253B89005AB5DA = { + children = ( + 1865F3AA06253B89005AB5DA, + 1865F3AB06253B89005AB5DA, + 1865F3AC06253B89005AB5DA, + 1865F3AD06253B89005AB5DA, + 1865F3AE06253B89005AB5DA, + 1865F3B006253B89005AB5DA, + 1865F3B206253B89005AB5DA, + 1865F3B306253B89005AB5DA, + 1865F3B506253B89005AB5DA, + 1865F3BA06253B89005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F3AA06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F3AB06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F3AC06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F3AD06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F3AE06253B89005AB5DA = { + children = ( + 1865F3AF06253B89005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3AF06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg11_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3B006253B89005AB5DA = { + children = ( + 1865F3B106253B89005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3B106253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg11_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3B206253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F3B306253B89005AB5DA = { + children = ( + 1865F3B406253B89005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3B406253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg11_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3B506253B89005AB5DA = { + children = ( + 1865F3B606253B89005AB5DA, + 1865F3B706253B89005AB5DA, + 1865F3B806253B89005AB5DA, + 1865F3B906253B89005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F3B606253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3B706253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3B806253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3B906253B89005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3BA06253B89005AB5DA = { + children = ( + 1865F3BB06253B89005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3BB06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg11_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3BC06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg11_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F3BD06253B89005AB5DA = { + children = ( + 1865F3BE06253B89005AB5DA, + 1865F3D106253B8A005AB5DA, + ); + isa = PBXGroup; + path = ch12; + refType = 4; + sourceTree = ""; + }; + 1865F3BE06253B89005AB5DA = { + children = ( + 1865F3BF06253B89005AB5DA, + 1865F3C006253B89005AB5DA, + 1865F3C106253B89005AB5DA, + 1865F3C206253B89005AB5DA, + 1865F3C306253B89005AB5DA, + 1865F3C506253B89005AB5DA, + 1865F3C706253B89005AB5DA, + 1865F3C806253B8A005AB5DA, + 1865F3CA06253B8A005AB5DA, + 1865F3CF06253B8A005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F3BF06253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F3C006253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F3C106253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F3C206253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F3C306253B89005AB5DA = { + children = ( + 1865F3C406253B89005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3C406253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg12_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3C506253B89005AB5DA = { + children = ( + 1865F3C606253B89005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3C606253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg12_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3C706253B89005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F3C806253B8A005AB5DA = { + children = ( + 1865F3C906253B8A005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3C906253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg12_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3CA06253B8A005AB5DA = { + children = ( + 1865F3CB06253B8A005AB5DA, + 1865F3CC06253B8A005AB5DA, + 1865F3CD06253B8A005AB5DA, + 1865F3CE06253B8A005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F3CB06253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3CC06253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3CD06253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3CE06253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3CF06253B8A005AB5DA = { + children = ( + 1865F3D006253B8A005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3D006253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg12_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3D106253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg12_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F3D206253B8A005AB5DA = { + children = ( + 1865F3D306253B8A005AB5DA, + 1865F3E606253B8A005AB5DA, + ); + isa = PBXGroup; + path = gtkrad; + refType = 4; + sourceTree = ""; + }; + 1865F3D306253B8A005AB5DA = { + children = ( + 1865F3D406253B8A005AB5DA, + 1865F3D506253B8A005AB5DA, + 1865F3D606253B8A005AB5DA, + 1865F3D706253B8A005AB5DA, + 1865F3D806253B8A005AB5DA, + 1865F3DA06253B8A005AB5DA, + 1865F3DC06253B8A005AB5DA, + 1865F3DD06253B8A005AB5DA, + 1865F3DF06253B8A005AB5DA, + 1865F3E406253B8A005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F3D406253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F3D506253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F3D606253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F3D706253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F3D806253B8A005AB5DA = { + children = ( + 1865F3D906253B8A005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3D906253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3DA06253B8A005AB5DA = { + children = ( + 1865F3DB06253B8A005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3DB06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3DC06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F3DD06253B8A005AB5DA = { + children = ( + 1865F3DE06253B8A005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3DE06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3DF06253B8A005AB5DA = { + children = ( + 1865F3E006253B8A005AB5DA, + 1865F3E106253B8A005AB5DA, + 1865F3E206253B8A005AB5DA, + 1865F3E306253B8A005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F3E006253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3E106253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F3E206253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3E306253B8A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3E406253B8A005AB5DA = { + children = ( + 1865F3E506253B8A005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F3E506253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F3E606253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg1_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F3E706253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = index.htm; + refType = 4; + sourceTree = ""; + }; + 1865F3E806253B8A005AB5DA = { + children = ( + 1865F3E906253B8A005AB5DA, + 1865F44C06253B8B005AB5DA, + 1865F44D06253B8B005AB5DA, + 1865F44E06253B8B005AB5DA, + 1865F44F06253B8B005AB5DA, + 1865F45006253B8B005AB5DA, + 1865F45106253B8B005AB5DA, + 1865F45206253B8B005AB5DA, + 1865F45306253B8B005AB5DA, + 1865F45406253B8B005AB5DA, + 1865F45506253B8B005AB5DA, + 1865F45606253B8B005AB5DA, + 1865F45706253B8B005AB5DA, + 1865F45806253B8B005AB5DA, + 1865F45906253B8B005AB5DA, + 1865F45A06253B8B005AB5DA, + 1865F45B06253B8B005AB5DA, + 1865F45C06253B8B005AB5DA, + 1865F45D06253B8B005AB5DA, + 1865F45E06253B8B005AB5DA, + 1865F45F06253B8B005AB5DA, + 1865F46006253B8C005AB5DA, + ); + isa = PBXGroup; + path = Q3Rad_Manual_files; + refType = 4; + sourceTree = ""; + }; + 1865F3E906253B8A005AB5DA = { + children = ( + 1865F3EA06253B8A005AB5DA, + 1865F3EB06253B8A005AB5DA, + 1865F3EC06253B8A005AB5DA, + 1865F3ED06253B8A005AB5DA, + 1865F3EE06253B8A005AB5DA, + 1865F40406253B8A005AB5DA, + 1865F41A06253B8B005AB5DA, + 1865F41B06253B8B005AB5DA, + 1865F43106253B8B005AB5DA, + 1865F43606253B8B005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F3EA06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F3EB06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F3EC06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F3ED06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F3EE06253B8A005AB5DA = { + children = ( + 1865F3EF06253B8A005AB5DA, + 1865F3F006253B8A005AB5DA, + 1865F3F106253B8A005AB5DA, + 1865F3F206253B8A005AB5DA, + 1865F3F306253B8A005AB5DA, + 1865F3F406253B8A005AB5DA, + 1865F3F506253B8A005AB5DA, + 1865F3F606253B8A005AB5DA, + 1865F3F706253B8A005AB5DA, + 1865F3F806253B8A005AB5DA, + 1865F3F906253B8A005AB5DA, + 1865F3FA06253B8A005AB5DA, + 1865F3FB06253B8A005AB5DA, + 1865F3FC06253B8A005AB5DA, + 1865F3FD06253B8A005AB5DA, + 1865F3FE06253B8A005AB5DA, + 1865F3FF06253B8A005AB5DA, + 1865F40006253B8A005AB5DA, + 1865F40106253B8A005AB5DA, + 1865F40206253B8A005AB5DA, + 1865F40306253B8A005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3EF06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image002.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F006253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image003.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F106253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image004.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F206253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image006.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F306253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image008.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F406253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image010.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F506253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image012.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F606253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image014.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F706253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image016.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F806253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image018.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3F906253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image020.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3FA06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image022.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3FB06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image024.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3FC06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image026.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3FD06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image028.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3FE06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image030.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F3FF06253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image032.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F40006253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image034.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F40106253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image035.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F40206253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image038.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F40306253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image040.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F40406253B8A005AB5DA = { + children = ( + 1865F40506253B8A005AB5DA, + 1865F40606253B8A005AB5DA, + 1865F40706253B8B005AB5DA, + 1865F40806253B8B005AB5DA, + 1865F40906253B8B005AB5DA, + 1865F40A06253B8B005AB5DA, + 1865F40B06253B8B005AB5DA, + 1865F40C06253B8B005AB5DA, + 1865F40D06253B8B005AB5DA, + 1865F40E06253B8B005AB5DA, + 1865F40F06253B8B005AB5DA, + 1865F41006253B8B005AB5DA, + 1865F41106253B8B005AB5DA, + 1865F41206253B8B005AB5DA, + 1865F41306253B8B005AB5DA, + 1865F41406253B8B005AB5DA, + 1865F41506253B8B005AB5DA, + 1865F41606253B8B005AB5DA, + 1865F41706253B8B005AB5DA, + 1865F41806253B8B005AB5DA, + 1865F41906253B8B005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F40506253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image002.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40606253B8A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image003.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40706253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image004.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40806253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image006.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40906253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image008.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40A06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image010.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40B06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image012.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40C06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image014.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40D06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image016.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40E06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image018.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F40F06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image020.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41006253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image022.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41106253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image024.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41206253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image026.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41306253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image028.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41406253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image030.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41506253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image032.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41606253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image034.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41706253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image035.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41806253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image038.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41906253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image040.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F41A06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F41B06253B8B005AB5DA = { + children = ( + 1865F41C06253B8B005AB5DA, + 1865F41D06253B8B005AB5DA, + 1865F41E06253B8B005AB5DA, + 1865F41F06253B8B005AB5DA, + 1865F42006253B8B005AB5DA, + 1865F42106253B8B005AB5DA, + 1865F42206253B8B005AB5DA, + 1865F42306253B8B005AB5DA, + 1865F42406253B8B005AB5DA, + 1865F42506253B8B005AB5DA, + 1865F42606253B8B005AB5DA, + 1865F42706253B8B005AB5DA, + 1865F42806253B8B005AB5DA, + 1865F42906253B8B005AB5DA, + 1865F42A06253B8B005AB5DA, + 1865F42B06253B8B005AB5DA, + 1865F42C06253B8B005AB5DA, + 1865F42D06253B8B005AB5DA, + 1865F42E06253B8B005AB5DA, + 1865F42F06253B8B005AB5DA, + 1865F43006253B8B005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F41C06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image002.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F41D06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image003.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F41E06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image004.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F41F06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image006.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42006253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image008.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42106253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image010.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42206253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image012.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42306253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image014.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42406253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image016.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42506253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image018.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42606253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image020.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42706253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image022.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42806253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image024.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42906253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image026.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42A06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image028.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42B06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image030.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42C06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image032.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42D06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image034.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42E06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image035.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F42F06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image038.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F43006253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image040.png.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F43106253B8B005AB5DA = { + children = ( + 1865F43206253B8B005AB5DA, + 1865F43306253B8B005AB5DA, + 1865F43406253B8B005AB5DA, + 1865F43506253B8B005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F43206253B8B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F43306253B8B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F43406253B8B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F43506253B8B005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F43606253B8B005AB5DA = { + children = ( + 1865F43706253B8B005AB5DA, + 1865F43806253B8B005AB5DA, + 1865F43906253B8B005AB5DA, + 1865F43A06253B8B005AB5DA, + 1865F43B06253B8B005AB5DA, + 1865F43C06253B8B005AB5DA, + 1865F43D06253B8B005AB5DA, + 1865F43E06253B8B005AB5DA, + 1865F43F06253B8B005AB5DA, + 1865F44006253B8B005AB5DA, + 1865F44106253B8B005AB5DA, + 1865F44206253B8B005AB5DA, + 1865F44306253B8B005AB5DA, + 1865F44406253B8B005AB5DA, + 1865F44506253B8B005AB5DA, + 1865F44606253B8B005AB5DA, + 1865F44706253B8B005AB5DA, + 1865F44806253B8B005AB5DA, + 1865F44906253B8B005AB5DA, + 1865F44A06253B8B005AB5DA, + 1865F44B06253B8B005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F43706253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image002.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43806253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image003.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43906253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image004.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43A06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image006.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43B06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image008.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43C06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image010.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43D06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image012.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43E06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image014.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F43F06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image016.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44006253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image018.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44106253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image020.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44206253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image022.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44306253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image024.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44406253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image026.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44506253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image028.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44606253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image030.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44706253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image032.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44806253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image034.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44906253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image035.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44A06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image038.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44B06253B8B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image040.png.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F44C06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image002.png; + refType = 4; + sourceTree = ""; + }; + 1865F44D06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image003.png; + refType = 4; + sourceTree = ""; + }; + 1865F44E06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image004.png; + refType = 4; + sourceTree = ""; + }; + 1865F44F06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image006.png; + refType = 4; + sourceTree = ""; + }; + 1865F45006253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image008.png; + refType = 4; + sourceTree = ""; + }; + 1865F45106253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image010.png; + refType = 4; + sourceTree = ""; + }; + 1865F45206253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image012.png; + refType = 4; + sourceTree = ""; + }; + 1865F45306253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image014.png; + refType = 4; + sourceTree = ""; + }; + 1865F45406253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image016.png; + refType = 4; + sourceTree = ""; + }; + 1865F45506253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image018.png; + refType = 4; + sourceTree = ""; + }; + 1865F45606253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image020.png; + refType = 4; + sourceTree = ""; + }; + 1865F45706253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image022.png; + refType = 4; + sourceTree = ""; + }; + 1865F45806253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image024.png; + refType = 4; + sourceTree = ""; + }; + 1865F45906253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image026.png; + refType = 4; + sourceTree = ""; + }; + 1865F45A06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image028.png; + refType = 4; + sourceTree = ""; + }; + 1865F45B06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image030.png; + refType = 4; + sourceTree = ""; + }; + 1865F45C06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image032.png; + refType = 4; + sourceTree = ""; + }; + 1865F45D06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image034.png; + refType = 4; + sourceTree = ""; + }; + 1865F45E06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image035.png; + refType = 4; + sourceTree = ""; + }; + 1865F45F06253B8B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image038.png; + refType = 4; + sourceTree = ""; + }; + 1865F46006253B8C005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.png; + path = image040.png; + refType = 4; + sourceTree = ""; + }; + 1865F46106253B8C005AB5DA = { + children = ( + 1865F46206253B8C005AB5DA, + 1865F47506253B8C005AB5DA, + ); + isa = PBXGroup; + path = styles; + refType = 4; + sourceTree = ""; + }; + 1865F46206253B8C005AB5DA = { + children = ( + 1865F46306253B8C005AB5DA, + 1865F46406253B8C005AB5DA, + 1865F46506253B8C005AB5DA, + 1865F46606253B8C005AB5DA, + 1865F46706253B8C005AB5DA, + 1865F46906253B8C005AB5DA, + 1865F46B06253B8C005AB5DA, + 1865F46C06253B8C005AB5DA, + 1865F46E06253B8C005AB5DA, + 1865F47306253B8C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F46306253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F46406253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F46506253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F46606253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F46706253B8C005AB5DA = { + children = ( + 1865F46806253B8C005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F46806253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F46906253B8C005AB5DA = { + children = ( + 1865F46A06253B8C005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F46A06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F46B06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F46C06253B8C005AB5DA = { + children = ( + 1865F46D06253B8C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F46D06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F46E06253B8C005AB5DA = { + children = ( + 1865F46F06253B8C005AB5DA, + 1865F47006253B8C005AB5DA, + 1865F47106253B8C005AB5DA, + 1865F47206253B8C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F46F06253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F47006253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F47106253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F47206253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F47306253B8C005AB5DA = { + children = ( + 1865F47406253B8C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F47406253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F47506253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3rad.css; + refType = 4; + sourceTree = ""; + }; + 1865F47606253B8C005AB5DA = { + children = ( + 1865F47706253B8C005AB5DA, + 1865F48606253B8C005AB5DA, + 1865F4B406253B8C005AB5DA, + 1865F4DE06253B8D005AB5DA, + 1865F4F306253B8D005AB5DA, + 1865F5C506253B8F005AB5DA, + 1865F65406253B92005AB5DA, + ); + isa = PBXGroup; + path = quake3; + refType = 4; + sourceTree = ""; + }; + 1865F47706253B8C005AB5DA = { + children = ( + 1865F47806253B8C005AB5DA, + 1865F47906253B8C005AB5DA, + 1865F47A06253B8C005AB5DA, + 1865F47B06253B8C005AB5DA, + 1865F47C06253B8C005AB5DA, + 1865F47D06253B8C005AB5DA, + 1865F47E06253B8C005AB5DA, + 1865F47F06253B8C005AB5DA, + 1865F48006253B8C005AB5DA, + 1865F48506253B8C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F47806253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F47906253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F47A06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F47B06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F47C06253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F47D06253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F47E06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F47F06253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F48006253B8C005AB5DA = { + children = ( + 1865F48106253B8C005AB5DA, + 1865F48206253B8C005AB5DA, + 1865F48306253B8C005AB5DA, + 1865F48406253B8C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F48106253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F48206253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F48306253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F48406253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F48506253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F48606253B8C005AB5DA = { + children = ( + 1865F48706253B8C005AB5DA, + 1865F4AE06253B8C005AB5DA, + 1865F4AF06253B8C005AB5DA, + 1865F4B006253B8C005AB5DA, + 1865F4B106253B8C005AB5DA, + 1865F4B206253B8C005AB5DA, + 1865F4B306253B8C005AB5DA, + ); + isa = PBXGroup; + path = Compile_Manual; + refType = 4; + sourceTree = ""; + }; + 1865F48706253B8C005AB5DA = { + children = ( + 1865F48806253B8C005AB5DA, + 1865F48906253B8C005AB5DA, + 1865F48A06253B8C005AB5DA, + 1865F48B06253B8C005AB5DA, + 1865F48C06253B8C005AB5DA, + 1865F49306253B8C005AB5DA, + 1865F49A06253B8C005AB5DA, + 1865F49B06253B8C005AB5DA, + 1865F4A206253B8C005AB5DA, + 1865F4A706253B8C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F48806253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F48906253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F48A06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F48B06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F48C06253B8C005AB5DA = { + children = ( + 1865F48D06253B8C005AB5DA, + 1865F48E06253B8C005AB5DA, + 1865F48F06253B8C005AB5DA, + 1865F49006253B8C005AB5DA, + 1865F49106253B8C005AB5DA, + 1865F49206253B8C005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F48D06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F48E06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cfgq3.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F48F06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "headskins.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49006253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49106253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modelskins.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49206253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49306253B8C005AB5DA = { + children = ( + 1865F49406253B8C005AB5DA, + 1865F49506253B8C005AB5DA, + 1865F49606253B8C005AB5DA, + 1865F49706253B8C005AB5DA, + 1865F49806253B8C005AB5DA, + 1865F49906253B8C005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F49406253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F49506253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cfgq3.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F49606253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "headskins.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F49706253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F49806253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modelskins.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F49906253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F49A06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F49B06253B8C005AB5DA = { + children = ( + 1865F49C06253B8C005AB5DA, + 1865F49D06253B8C005AB5DA, + 1865F49E06253B8C005AB5DA, + 1865F49F06253B8C005AB5DA, + 1865F4A006253B8C005AB5DA, + 1865F4A106253B8C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49C06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49D06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cfgq3.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49E06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "headskins.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F49F06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4A006253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modelskins.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4A106253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4A206253B8C005AB5DA = { + children = ( + 1865F4A306253B8C005AB5DA, + 1865F4A406253B8C005AB5DA, + 1865F4A506253B8C005AB5DA, + 1865F4A606253B8C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F4A306253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4A406253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4A506253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4A606253B8C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4A706253B8C005AB5DA = { + children = ( + 1865F4A806253B8C005AB5DA, + 1865F4A906253B8C005AB5DA, + 1865F4AA06253B8C005AB5DA, + 1865F4AB06253B8C005AB5DA, + 1865F4AC06253B8C005AB5DA, + 1865F4AD06253B8C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4A806253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bspc.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4A906253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cfgq3.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4AA06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "headskins.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4AB06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4AC06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "modelskins.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4AD06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3map.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4AE06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = bspc.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4AF06253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = cfgq3.c; + refType = 4; + sourceTree = ""; + }; + 1865F4B006253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = headskins.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4B106253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = index.html; + refType = 4; + sourceTree = ""; + }; + 1865F4B206253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = modelskins.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4B306253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = q3map.html; + refType = 4; + sourceTree = ""; + }; + 1865F4B406253B8C005AB5DA = { + children = ( + 1865F4B506253B8C005AB5DA, + 1865F4C806253B8D005AB5DA, + 1865F4C906253B8D005AB5DA, + ); + isa = PBXGroup; + path = Model_Manual; + refType = 4; + sourceTree = ""; + }; + 1865F4B506253B8C005AB5DA = { + children = ( + 1865F4B606253B8C005AB5DA, + 1865F4B706253B8C005AB5DA, + 1865F4B806253B8C005AB5DA, + 1865F4B906253B8C005AB5DA, + 1865F4BA06253B8D005AB5DA, + 1865F4BC06253B8D005AB5DA, + 1865F4BE06253B8D005AB5DA, + 1865F4BF06253B8D005AB5DA, + 1865F4C106253B8D005AB5DA, + 1865F4C606253B8D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F4B606253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F4B706253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F4B806253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F4B906253B8C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F4BA06253B8D005AB5DA = { + children = ( + 1865F4BB06253B8D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4BB06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_manual.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4BC06253B8D005AB5DA = { + children = ( + 1865F4BD06253B8D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4BD06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_manual.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4BE06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4BF06253B8D005AB5DA = { + children = ( + 1865F4C006253B8D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4C006253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_manual.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4C106253B8D005AB5DA = { + children = ( + 1865F4C206253B8D005AB5DA, + 1865F4C306253B8D005AB5DA, + 1865F4C406253B8D005AB5DA, + 1865F4C506253B8D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F4C206253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4C306253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4C406253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4C506253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4C606253B8D005AB5DA = { + children = ( + 1865F4C706253B8D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4C706253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_manual.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4C806253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = model_manual.htm; + refType = 4; + sourceTree = ""; + }; + 1865F4C906253B8D005AB5DA = { + children = ( + 1865F4CA06253B8D005AB5DA, + 1865F4DD06253B8D005AB5DA, + ); + isa = PBXGroup; + path = styles; + refType = 4; + sourceTree = ""; + }; + 1865F4CA06253B8D005AB5DA = { + children = ( + 1865F4CB06253B8D005AB5DA, + 1865F4CC06253B8D005AB5DA, + 1865F4CD06253B8D005AB5DA, + 1865F4CE06253B8D005AB5DA, + 1865F4CF06253B8D005AB5DA, + 1865F4D106253B8D005AB5DA, + 1865F4D306253B8D005AB5DA, + 1865F4D406253B8D005AB5DA, + 1865F4D606253B8D005AB5DA, + 1865F4DB06253B8D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F4CB06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F4CC06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F4CD06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F4CE06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F4CF06253B8D005AB5DA = { + children = ( + 1865F4D006253B8D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4D006253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4D106253B8D005AB5DA = { + children = ( + 1865F4D206253B8D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4D206253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4D306253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4D406253B8D005AB5DA = { + children = ( + 1865F4D506253B8D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4D506253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4D606253B8D005AB5DA = { + children = ( + 1865F4D706253B8D005AB5DA, + 1865F4D806253B8D005AB5DA, + 1865F4D906253B8D005AB5DA, + 1865F4DA06253B8D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F4D706253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4D806253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4D906253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4DA06253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4DB06253B8D005AB5DA = { + children = ( + 1865F4DC06253B8D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4DC06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4DD06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3rad.css; + refType = 4; + sourceTree = ""; + }; + 1865F4DE06253B8D005AB5DA = { + children = ( + 1865F4DF06253B8D005AB5DA, + 1865F4F206253B8D005AB5DA, + ); + isa = PBXGroup; + path = New_Teams_For_Q3TA; + refType = 4; + sourceTree = ""; + }; + 1865F4DF06253B8D005AB5DA = { + children = ( + 1865F4E006253B8D005AB5DA, + 1865F4E106253B8D005AB5DA, + 1865F4E206253B8D005AB5DA, + 1865F4E306253B8D005AB5DA, + 1865F4E406253B8D005AB5DA, + 1865F4E606253B8D005AB5DA, + 1865F4E806253B8D005AB5DA, + 1865F4E906253B8D005AB5DA, + 1865F4EB06253B8D005AB5DA, + 1865F4F006253B8D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F4E006253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F4E106253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F4E206253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F4E306253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F4E406253B8D005AB5DA = { + children = ( + 1865F4E506253B8D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4E506253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4E606253B8D005AB5DA = { + children = ( + 1865F4E706253B8D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4E706253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4E806253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4E906253B8D005AB5DA = { + children = ( + 1865F4EA06253B8D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4EA06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4EB06253B8D005AB5DA = { + children = ( + 1865F4EC06253B8D005AB5DA, + 1865F4ED06253B8D005AB5DA, + 1865F4EE06253B8D005AB5DA, + 1865F4EF06253B8D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F4EC06253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4ED06253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4EE06253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4EF06253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4F006253B8D005AB5DA = { + children = ( + 1865F4F106253B8D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F4F106253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4F206253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = index.html; + refType = 4; + sourceTree = ""; + }; + 1865F4F306253B8D005AB5DA = { + children = ( + 1865F4F406253B8D005AB5DA, + 1865F50706253B8D005AB5DA, + 1865F51C06253B8D005AB5DA, + 1865F53106253B8E005AB5DA, + 1865F54606253B8E005AB5DA, + 1865F55B06253B8E005AB5DA, + 1865F57006253B8E005AB5DA, + 1865F58506253B8E005AB5DA, + 1865F59A06253B8F005AB5DA, + 1865F59B06253B8F005AB5DA, + 1865F5B006253B8F005AB5DA, + ); + isa = PBXGroup; + path = Q3AShader_Manual; + refType = 4; + sourceTree = ""; + }; + 1865F4F406253B8D005AB5DA = { + children = ( + 1865F4F506253B8D005AB5DA, + 1865F4F606253B8D005AB5DA, + 1865F4F706253B8D005AB5DA, + 1865F4F806253B8D005AB5DA, + 1865F4F906253B8D005AB5DA, + 1865F4FB06253B8D005AB5DA, + 1865F4FD06253B8D005AB5DA, + 1865F4FE06253B8D005AB5DA, + 1865F50006253B8D005AB5DA, + 1865F50506253B8D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F4F506253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F4F606253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F4F706253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F4F806253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F4F906253B8D005AB5DA = { + children = ( + 1865F4FA06253B8D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4FA06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4FB06253B8D005AB5DA = { + children = ( + 1865F4FC06253B8D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F4FC06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F4FD06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F4FE06253B8D005AB5DA = { + children = ( + 1865F4FF06253B8D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F4FF06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F50006253B8D005AB5DA = { + children = ( + 1865F50106253B8D005AB5DA, + 1865F50206253B8D005AB5DA, + 1865F50306253B8D005AB5DA, + 1865F50406253B8D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F50106253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F50206253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F50306253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F50406253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F50506253B8D005AB5DA = { + children = ( + 1865F50606253B8D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F50606253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F50706253B8D005AB5DA = { + children = ( + 1865F50806253B8D005AB5DA, + 1865F51B06253B8D005AB5DA, + ); + isa = PBXGroup; + path = appendix; + refType = 4; + sourceTree = ""; + }; + 1865F50806253B8D005AB5DA = { + children = ( + 1865F50906253B8D005AB5DA, + 1865F50A06253B8D005AB5DA, + 1865F50B06253B8D005AB5DA, + 1865F50C06253B8D005AB5DA, + 1865F50D06253B8D005AB5DA, + 1865F50F06253B8D005AB5DA, + 1865F51106253B8D005AB5DA, + 1865F51206253B8D005AB5DA, + 1865F51406253B8D005AB5DA, + 1865F51906253B8D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F50906253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F50A06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F50B06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F50C06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F50D06253B8D005AB5DA = { + children = ( + 1865F50E06253B8D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F50E06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appA.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F50F06253B8D005AB5DA = { + children = ( + 1865F51006253B8D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F51006253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appA.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F51106253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F51206253B8D005AB5DA = { + children = ( + 1865F51306253B8D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F51306253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appA.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F51406253B8D005AB5DA = { + children = ( + 1865F51506253B8D005AB5DA, + 1865F51606253B8D005AB5DA, + 1865F51706253B8D005AB5DA, + 1865F51806253B8D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F51506253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F51606253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F51706253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F51806253B8D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F51906253B8D005AB5DA = { + children = ( + 1865F51A06253B8D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F51A06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "appA.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F51B06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = appA.html; + refType = 4; + sourceTree = ""; + }; + 1865F51C06253B8D005AB5DA = { + children = ( + 1865F51D06253B8D005AB5DA, + 1865F53006253B8E005AB5DA, + ); + isa = PBXGroup; + path = ch01; + refType = 4; + sourceTree = ""; + }; + 1865F51D06253B8D005AB5DA = { + children = ( + 1865F51E06253B8D005AB5DA, + 1865F51F06253B8D005AB5DA, + 1865F52006253B8D005AB5DA, + 1865F52106253B8D005AB5DA, + 1865F52206253B8D005AB5DA, + 1865F52406253B8E005AB5DA, + 1865F52606253B8E005AB5DA, + 1865F52706253B8E005AB5DA, + 1865F52906253B8E005AB5DA, + 1865F52E06253B8E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F51E06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F51F06253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F52006253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F52106253B8D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F52206253B8D005AB5DA = { + children = ( + 1865F52306253B8E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F52306253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F52406253B8E005AB5DA = { + children = ( + 1865F52506253B8E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F52506253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F52606253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F52706253B8E005AB5DA = { + children = ( + 1865F52806253B8E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F52806253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F52906253B8E005AB5DA = { + children = ( + 1865F52A06253B8E005AB5DA, + 1865F52B06253B8E005AB5DA, + 1865F52C06253B8E005AB5DA, + 1865F52D06253B8E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F52A06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F52B06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F52C06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F52D06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F52E06253B8E005AB5DA = { + children = ( + 1865F52F06253B8E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F52F06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg1_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F53006253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg1_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F53106253B8E005AB5DA = { + children = ( + 1865F53206253B8E005AB5DA, + 1865F54506253B8E005AB5DA, + ); + isa = PBXGroup; + path = ch02; + refType = 4; + sourceTree = ""; + }; + 1865F53206253B8E005AB5DA = { + children = ( + 1865F53306253B8E005AB5DA, + 1865F53406253B8E005AB5DA, + 1865F53506253B8E005AB5DA, + 1865F53606253B8E005AB5DA, + 1865F53706253B8E005AB5DA, + 1865F53906253B8E005AB5DA, + 1865F53B06253B8E005AB5DA, + 1865F53C06253B8E005AB5DA, + 1865F53E06253B8E005AB5DA, + 1865F54306253B8E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F53306253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F53406253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F53506253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F53606253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F53706253B8E005AB5DA = { + children = ( + 1865F53806253B8E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F53806253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F53906253B8E005AB5DA = { + children = ( + 1865F53A06253B8E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F53A06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F53B06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F53C06253B8E005AB5DA = { + children = ( + 1865F53D06253B8E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F53D06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F53E06253B8E005AB5DA = { + children = ( + 1865F53F06253B8E005AB5DA, + 1865F54006253B8E005AB5DA, + 1865F54106253B8E005AB5DA, + 1865F54206253B8E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F53F06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F54006253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F54106253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F54206253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F54306253B8E005AB5DA = { + children = ( + 1865F54406253B8E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F54406253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg2_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F54506253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg2_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F54606253B8E005AB5DA = { + children = ( + 1865F54706253B8E005AB5DA, + 1865F55A06253B8E005AB5DA, + ); + isa = PBXGroup; + path = ch03; + refType = 4; + sourceTree = ""; + }; + 1865F54706253B8E005AB5DA = { + children = ( + 1865F54806253B8E005AB5DA, + 1865F54906253B8E005AB5DA, + 1865F54A06253B8E005AB5DA, + 1865F54B06253B8E005AB5DA, + 1865F54C06253B8E005AB5DA, + 1865F54E06253B8E005AB5DA, + 1865F55006253B8E005AB5DA, + 1865F55106253B8E005AB5DA, + 1865F55306253B8E005AB5DA, + 1865F55806253B8E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F54806253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F54906253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F54A06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F54B06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F54C06253B8E005AB5DA = { + children = ( + 1865F54D06253B8E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F54D06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F54E06253B8E005AB5DA = { + children = ( + 1865F54F06253B8E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F54F06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F55006253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F55106253B8E005AB5DA = { + children = ( + 1865F55206253B8E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F55206253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F55306253B8E005AB5DA = { + children = ( + 1865F55406253B8E005AB5DA, + 1865F55506253B8E005AB5DA, + 1865F55606253B8E005AB5DA, + 1865F55706253B8E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F55406253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F55506253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F55606253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F55706253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F55806253B8E005AB5DA = { + children = ( + 1865F55906253B8E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F55906253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg3_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F55A06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg3_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F55B06253B8E005AB5DA = { + children = ( + 1865F55C06253B8E005AB5DA, + 1865F56F06253B8E005AB5DA, + ); + isa = PBXGroup; + path = ch04; + refType = 4; + sourceTree = ""; + }; + 1865F55C06253B8E005AB5DA = { + children = ( + 1865F55D06253B8E005AB5DA, + 1865F55E06253B8E005AB5DA, + 1865F55F06253B8E005AB5DA, + 1865F56006253B8E005AB5DA, + 1865F56106253B8E005AB5DA, + 1865F56306253B8E005AB5DA, + 1865F56506253B8E005AB5DA, + 1865F56606253B8E005AB5DA, + 1865F56806253B8E005AB5DA, + 1865F56D06253B8E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F55D06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F55E06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F55F06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F56006253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F56106253B8E005AB5DA = { + children = ( + 1865F56206253B8E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F56206253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F56306253B8E005AB5DA = { + children = ( + 1865F56406253B8E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F56406253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F56506253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F56606253B8E005AB5DA = { + children = ( + 1865F56706253B8E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F56706253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F56806253B8E005AB5DA = { + children = ( + 1865F56906253B8E005AB5DA, + 1865F56A06253B8E005AB5DA, + 1865F56B06253B8E005AB5DA, + 1865F56C06253B8E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F56906253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F56A06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F56B06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F56C06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F56D06253B8E005AB5DA = { + children = ( + 1865F56E06253B8E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F56E06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg4_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F56F06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg4_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F57006253B8E005AB5DA = { + children = ( + 1865F57106253B8E005AB5DA, + 1865F58406253B8E005AB5DA, + ); + isa = PBXGroup; + path = ch05; + refType = 4; + sourceTree = ""; + }; + 1865F57106253B8E005AB5DA = { + children = ( + 1865F57206253B8E005AB5DA, + 1865F57306253B8E005AB5DA, + 1865F57406253B8E005AB5DA, + 1865F57506253B8E005AB5DA, + 1865F57606253B8E005AB5DA, + 1865F57806253B8E005AB5DA, + 1865F57A06253B8E005AB5DA, + 1865F57B06253B8E005AB5DA, + 1865F57D06253B8E005AB5DA, + 1865F58206253B8E005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F57206253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F57306253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F57406253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F57506253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F57606253B8E005AB5DA = { + children = ( + 1865F57706253B8E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F57706253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F57806253B8E005AB5DA = { + children = ( + 1865F57906253B8E005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F57906253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F57A06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F57B06253B8E005AB5DA = { + children = ( + 1865F57C06253B8E005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F57C06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F57D06253B8E005AB5DA = { + children = ( + 1865F57E06253B8E005AB5DA, + 1865F57F06253B8E005AB5DA, + 1865F58006253B8E005AB5DA, + 1865F58106253B8E005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F57E06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F57F06253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F58006253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F58106253B8E005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F58206253B8E005AB5DA = { + children = ( + 1865F58306253B8E005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F58306253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg5_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F58406253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg5_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F58506253B8E005AB5DA = { + children = ( + 1865F58606253B8E005AB5DA, + 1865F59906253B8F005AB5DA, + ); + isa = PBXGroup; + path = ch06; + refType = 4; + sourceTree = ""; + }; + 1865F58606253B8E005AB5DA = { + children = ( + 1865F58706253B8E005AB5DA, + 1865F58806253B8E005AB5DA, + 1865F58906253B8E005AB5DA, + 1865F58A06253B8E005AB5DA, + 1865F58B06253B8F005AB5DA, + 1865F58D06253B8F005AB5DA, + 1865F58F06253B8F005AB5DA, + 1865F59006253B8F005AB5DA, + 1865F59206253B8F005AB5DA, + 1865F59706253B8F005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F58706253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F58806253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F58906253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F58A06253B8E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F58B06253B8F005AB5DA = { + children = ( + 1865F58C06253B8F005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F58C06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F58D06253B8F005AB5DA = { + children = ( + 1865F58E06253B8F005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F58E06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F58F06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F59006253B8F005AB5DA = { + children = ( + 1865F59106253B8F005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F59106253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F59206253B8F005AB5DA = { + children = ( + 1865F59306253B8F005AB5DA, + 1865F59406253B8F005AB5DA, + 1865F59506253B8F005AB5DA, + 1865F59606253B8F005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F59306253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F59406253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F59506253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F59606253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F59706253B8F005AB5DA = { + children = ( + 1865F59806253B8F005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F59806253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pg6_1.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F59906253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pg6_1.htm; + refType = 4; + sourceTree = ""; + }; + 1865F59A06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = index.htm; + refType = 4; + sourceTree = ""; + }; + 1865F59B06253B8F005AB5DA = { + children = ( + 1865F59C06253B8F005AB5DA, + 1865F5AF06253B8F005AB5DA, + ); + isa = PBXGroup; + path = q3ashader_manual_files; + refType = 4; + sourceTree = ""; + }; + 1865F59C06253B8F005AB5DA = { + children = ( + 1865F59D06253B8F005AB5DA, + 1865F59E06253B8F005AB5DA, + 1865F59F06253B8F005AB5DA, + 1865F5A006253B8F005AB5DA, + 1865F5A106253B8F005AB5DA, + 1865F5A306253B8F005AB5DA, + 1865F5A506253B8F005AB5DA, + 1865F5A606253B8F005AB5DA, + 1865F5A806253B8F005AB5DA, + 1865F5AD06253B8F005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F59D06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F59E06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F59F06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F5A006253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F5A106253B8F005AB5DA = { + children = ( + 1865F5A206253B8F005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5A206253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image002.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5A306253B8F005AB5DA = { + children = ( + 1865F5A406253B8F005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5A406253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image002.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5A506253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F5A606253B8F005AB5DA = { + children = ( + 1865F5A706253B8F005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5A706253B8F005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "image002.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5A806253B8F005AB5DA = { + children = ( + 1865F5A906253B8F005AB5DA, + 1865F5AA06253B8F005AB5DA, + 1865F5AB06253B8F005AB5DA, + 1865F5AC06253B8F005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F5A906253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5AA06253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5AB06253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5AC06253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F5AD06253B8F005AB5DA = { + children = ( + 1865F5AE06253B8F005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F5AE06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image002.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5AF06253B8F005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = image002.jpg; + refType = 4; + sourceTree = ""; + }; + 1865F5B006253B8F005AB5DA = { + children = ( + 1865F5B106253B8F005AB5DA, + 1865F5C406253B8F005AB5DA, + ); + isa = PBXGroup; + path = styles; + refType = 4; + sourceTree = ""; + }; + 1865F5B106253B8F005AB5DA = { + children = ( + 1865F5B206253B8F005AB5DA, + 1865F5B306253B8F005AB5DA, + 1865F5B406253B8F005AB5DA, + 1865F5B506253B8F005AB5DA, + 1865F5B606253B8F005AB5DA, + 1865F5B806253B8F005AB5DA, + 1865F5BA06253B8F005AB5DA, + 1865F5BB06253B8F005AB5DA, + 1865F5BD06253B8F005AB5DA, + 1865F5C206253B8F005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F5B206253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F5B306253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F5B406253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F5B506253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F5B606253B8F005AB5DA = { + children = ( + 1865F5B706253B8F005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5B706253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5B806253B8F005AB5DA = { + children = ( + 1865F5B906253B8F005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5B906253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5BA06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F5BB06253B8F005AB5DA = { + children = ( + 1865F5BC06253B8F005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5BC06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5BD06253B8F005AB5DA = { + children = ( + 1865F5BE06253B8F005AB5DA, + 1865F5BF06253B8F005AB5DA, + 1865F5C006253B8F005AB5DA, + 1865F5C106253B8F005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F5BE06253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5BF06253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5C006253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5C106253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F5C206253B8F005AB5DA = { + children = ( + 1865F5C306253B8F005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F5C306253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q3rad.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5C406253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = q3rad.css; + refType = 4; + sourceTree = ""; + }; + 1865F5C506253B8F005AB5DA = { + children = ( + 1865F5C606253B8F005AB5DA, + 1865F5D906253B8F005AB5DA, + 1865F61B06253B91005AB5DA, + 1865F65306253B92005AB5DA, + ); + isa = PBXGroup; + path = Team_Arena_Mapping_Help; + refType = 4; + sourceTree = ""; + }; + 1865F5C606253B8F005AB5DA = { + children = ( + 1865F5C706253B8F005AB5DA, + 1865F5C806253B8F005AB5DA, + 1865F5C906253B8F005AB5DA, + 1865F5CA06253B8F005AB5DA, + 1865F5CB06253B8F005AB5DA, + 1865F5CD06253B8F005AB5DA, + 1865F5CF06253B8F005AB5DA, + 1865F5D006253B8F005AB5DA, + 1865F5D206253B8F005AB5DA, + 1865F5D706253B8F005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F5C706253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F5C806253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F5C906253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F5CA06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F5CB06253B8F005AB5DA = { + children = ( + 1865F5CC06253B8F005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5CC06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5CD06253B8F005AB5DA = { + children = ( + 1865F5CE06253B8F005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5CE06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5CF06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F5D006253B8F005AB5DA = { + children = ( + 1865F5D106253B8F005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5D106253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5D206253B8F005AB5DA = { + children = ( + 1865F5D306253B8F005AB5DA, + 1865F5D406253B8F005AB5DA, + 1865F5D506253B8F005AB5DA, + 1865F5D606253B8F005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F5D306253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5D406253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5D506253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5D606253B8F005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F5D706253B8F005AB5DA = { + children = ( + 1865F5D806253B8F005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F5D806253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5D906253B8F005AB5DA = { + children = ( + 1865F5DA06253B8F005AB5DA, + 1865F61106253B90005AB5DA, + 1865F61206253B90005AB5DA, + 1865F61306253B90005AB5DA, + 1865F61406253B90005AB5DA, + 1865F61506253B90005AB5DA, + 1865F61606253B90005AB5DA, + 1865F61706253B90005AB5DA, + 1865F61806253B90005AB5DA, + 1865F61906253B90005AB5DA, + 1865F61A06253B90005AB5DA, + ); + isa = PBXGroup; + path = pages; + refType = 4; + sourceTree = ""; + }; + 1865F5DA06253B8F005AB5DA = { + children = ( + 1865F5DB06253B8F005AB5DA, + 1865F5DC06253B8F005AB5DA, + 1865F5DD06253B8F005AB5DA, + 1865F5DE06253B8F005AB5DA, + 1865F5DF06253B8F005AB5DA, + 1865F5EA06253B90005AB5DA, + 1865F5F506253B90005AB5DA, + 1865F5F606253B90005AB5DA, + 1865F60106253B90005AB5DA, + 1865F60606253B90005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F5DB06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F5DC06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F5DD06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F5DE06253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F5DF06253B8F005AB5DA = { + children = ( + 1865F5E006253B8F005AB5DA, + 1865F5E106253B8F005AB5DA, + 1865F5E206253B8F005AB5DA, + 1865F5E306253B8F005AB5DA, + 1865F5E406253B8F005AB5DA, + 1865F5E506253B8F005AB5DA, + 1865F5E606253B8F005AB5DA, + 1865F5E706253B8F005AB5DA, + 1865F5E806253B90005AB5DA, + 1865F5E906253B90005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E006253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design_tips.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E106253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map_converters_checklist.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E206253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preface.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E306253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E406253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ta_game_types.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E506253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E606253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_entity_definitions.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E706253B8F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_prefabs.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E806253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_powerup_bases.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5E906253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "using_new_game_entities.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5EA06253B90005AB5DA = { + children = ( + 1865F5EB06253B90005AB5DA, + 1865F5EC06253B90005AB5DA, + 1865F5ED06253B90005AB5DA, + 1865F5EE06253B90005AB5DA, + 1865F5EF06253B90005AB5DA, + 1865F5F006253B90005AB5DA, + 1865F5F106253B90005AB5DA, + 1865F5F206253B90005AB5DA, + 1865F5F306253B90005AB5DA, + 1865F5F406253B90005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F5EB06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design_tips.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5EC06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map_converters_checklist.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5ED06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preface.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5EE06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5EF06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ta_game_types.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5F006253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5F106253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_entity_definitions.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5F206253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_prefabs.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5F306253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_powerup_bases.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5F406253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "using_new_game_entities.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F5F506253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F5F606253B90005AB5DA = { + children = ( + 1865F5F706253B90005AB5DA, + 1865F5F806253B90005AB5DA, + 1865F5F906253B90005AB5DA, + 1865F5FA06253B90005AB5DA, + 1865F5FB06253B90005AB5DA, + 1865F5FC06253B90005AB5DA, + 1865F5FD06253B90005AB5DA, + 1865F5FE06253B90005AB5DA, + 1865F5FF06253B90005AB5DA, + 1865F60006253B90005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5F706253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design_tips.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5F806253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map_converters_checklist.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5F906253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preface.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5FA06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5FB06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ta_game_types.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5FC06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.htm.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5FD06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_entity_definitions.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5FE06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_prefabs.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F5FF06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_powerup_bases.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F60006253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "using_new_game_entities.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F60106253B90005AB5DA = { + children = ( + 1865F60206253B90005AB5DA, + 1865F60306253B90005AB5DA, + 1865F60406253B90005AB5DA, + 1865F60506253B90005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F60206253B90005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F60306253B90005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F60406253B90005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F60506253B90005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F60606253B90005AB5DA = { + children = ( + 1865F60706253B90005AB5DA, + 1865F60806253B90005AB5DA, + 1865F60906253B90005AB5DA, + 1865F60A06253B90005AB5DA, + 1865F60B06253B90005AB5DA, + 1865F60C06253B90005AB5DA, + 1865F60D06253B90005AB5DA, + 1865F60E06253B90005AB5DA, + 1865F60F06253B90005AB5DA, + 1865F61006253B90005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F60706253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design_tips.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60806253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map_converters_checklist.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60906253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "preface.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60A06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60B06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ta_game_types.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60C06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.htm.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60D06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_entity_definitions.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60E06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_arena_prefabs.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F60F06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "team_powerup_bases.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F61006253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "using_new_game_entities.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F61106253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = design_tips.html; + refType = 4; + sourceTree = ""; + }; + 1865F61206253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = map_converters_checklist.html; + refType = 4; + sourceTree = ""; + }; + 1865F61306253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = preface.html; + refType = 4; + sourceTree = ""; + }; + 1865F61406253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = related_links.html; + refType = 4; + sourceTree = ""; + }; + 1865F61506253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = ta_game_types.html; + refType = 4; + sourceTree = ""; + }; + 1865F61606253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = table_of_contents.htm; + refType = 4; + sourceTree = ""; + }; + 1865F61706253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = team_arena_entity_definitions.html; + refType = 4; + sourceTree = ""; + }; + 1865F61806253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = team_arena_prefabs.html; + refType = 4; + sourceTree = ""; + }; + 1865F61906253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = team_powerup_bases.html; + refType = 4; + sourceTree = ""; + }; + 1865F61A06253B90005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = using_new_game_entities.html; + refType = 4; + sourceTree = ""; + }; + 1865F61B06253B91005AB5DA = { + children = ( + 1865F61C06253B91005AB5DA, + 1865F64B06253B92005AB5DA, + 1865F64C06253B92005AB5DA, + 1865F64D06253B92005AB5DA, + 1865F64E06253B92005AB5DA, + 1865F64F06253B92005AB5DA, + 1865F65006253B92005AB5DA, + 1865F65106253B92005AB5DA, + 1865F65206253B92005AB5DA, + ); + isa = PBXGroup; + path = pics; + refType = 4; + sourceTree = ""; + }; + 1865F61C06253B91005AB5DA = { + children = ( + 1865F61D06253B91005AB5DA, + 1865F61E06253B91005AB5DA, + 1865F61F06253B91005AB5DA, + 1865F62006253B91005AB5DA, + 1865F62106253B91005AB5DA, + 1865F62A06253B91005AB5DA, + 1865F63306253B91005AB5DA, + 1865F63406253B91005AB5DA, + 1865F63D06253B91005AB5DA, + 1865F64206253B91005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F61D06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F61E06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F61F06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F62006253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F62106253B91005AB5DA = { + children = ( + 1865F62206253B91005AB5DA, + 1865F62306253B91005AB5DA, + 1865F62406253B91005AB5DA, + 1865F62506253B91005AB5DA, + 1865F62606253B91005AB5DA, + 1865F62706253B91005AB5DA, + 1865F62806253B91005AB5DA, + 1865F62906253B91005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62206253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CRUSADER.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62306253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INTRUDER.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62406253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "logo.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62506253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "MAINPOP.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62606253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "MENUBACKgif.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62706253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PAGANs.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62806253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STROGGS.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62906253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "THEFALLEN.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F62A06253B91005AB5DA = { + children = ( + 1865F62B06253B91005AB5DA, + 1865F62C06253B91005AB5DA, + 1865F62D06253B91005AB5DA, + 1865F62E06253B91005AB5DA, + 1865F62F06253B91005AB5DA, + 1865F63006253B91005AB5DA, + 1865F63106253B91005AB5DA, + 1865F63206253B91005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F62B06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CRUSADER.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F62C06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INTRUDER.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F62D06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "logo.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F62E06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "MAINPOP.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F62F06253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "MENUBACKgif.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F63006253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PAGANs.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F63106253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STROGGS.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F63206253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "THEFALLEN.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F63306253B91005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F63406253B91005AB5DA = { + children = ( + 1865F63506253B91005AB5DA, + 1865F63606253B91005AB5DA, + 1865F63706253B91005AB5DA, + 1865F63806253B91005AB5DA, + 1865F63906253B91005AB5DA, + 1865F63A06253B91005AB5DA, + 1865F63B06253B91005AB5DA, + 1865F63C06253B91005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63506253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "CRUSADER.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63606253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "INTRUDER.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63706253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "logo.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63806253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "MAINPOP.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63906253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "MENUBACKgif.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63A06253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "PAGANs.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63B06253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "STROGGS.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63C06253B91005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "THEFALLEN.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63D06253B91005AB5DA = { + children = ( + 1865F63E06253B91005AB5DA, + 1865F63F06253B91005AB5DA, + 1865F64006253B91005AB5DA, + 1865F64106253B91005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F63E06253B91005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F63F06253B91005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F64006253B91005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F64106253B91005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F64206253B91005AB5DA = { + children = ( + 1865F64306253B92005AB5DA, + 1865F64406253B92005AB5DA, + 1865F64506253B92005AB5DA, + 1865F64606253B92005AB5DA, + 1865F64706253B92005AB5DA, + 1865F64806253B92005AB5DA, + 1865F64906253B92005AB5DA, + 1865F64A06253B92005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F64306253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "CRUSADER.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64406253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "INTRUDER.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64506253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "logo.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64606253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "MAINPOP.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64706253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "MENUBACKgif.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64806253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "PAGANs.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64906253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "STROGGS.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64A06253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "THEFALLEN.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F64B06253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = CRUSADER.gif; + refType = 4; + sourceTree = ""; + }; + 1865F64C06253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = INTRUDER.gif; + refType = 4; + sourceTree = ""; + }; + 1865F64D06253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = logo.gif; + refType = 4; + sourceTree = ""; + }; + 1865F64E06253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = MAINPOP.gif; + refType = 4; + sourceTree = ""; + }; + 1865F64F06253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = MENUBACKgif.gif; + refType = 4; + sourceTree = ""; + }; + 1865F65006253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = PAGANs.gif; + refType = 4; + sourceTree = ""; + }; + 1865F65106253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = STROGGS.gif; + refType = 4; + sourceTree = ""; + }; + 1865F65206253B92005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = THEFALLEN.gif; + refType = 4; + sourceTree = ""; + }; + 1865F65306253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = start.html; + refType = 4; + sourceTree = ""; + }; + 1865F65406253B92005AB5DA = { + children = ( + 1865F65506253B92005AB5DA, + 1865F66806253B93005AB5DA, + 1865F71306253B97005AB5DA, + 1865F73206253B98005AB5DA, + ); + isa = PBXGroup; + path = Terrain_Manual; + refType = 4; + sourceTree = ""; + }; + 1865F65506253B92005AB5DA = { + children = ( + 1865F65606253B92005AB5DA, + 1865F65706253B92005AB5DA, + 1865F65806253B92005AB5DA, + 1865F65906253B92005AB5DA, + 1865F65A06253B92005AB5DA, + 1865F65C06253B92005AB5DA, + 1865F65E06253B92005AB5DA, + 1865F65F06253B92005AB5DA, + 1865F66106253B92005AB5DA, + 1865F66606253B93005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F65606253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F65706253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F65806253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F65906253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F65A06253B92005AB5DA = { + children = ( + 1865F65B06253B92005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F65B06253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F65C06253B92005AB5DA = { + children = ( + 1865F65D06253B92005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F65D06253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F65E06253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F65F06253B92005AB5DA = { + children = ( + 1865F66006253B92005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F66006253B92005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F66106253B92005AB5DA = { + children = ( + 1865F66206253B93005AB5DA, + 1865F66306253B93005AB5DA, + 1865F66406253B93005AB5DA, + 1865F66506253B93005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F66206253B93005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F66306253B93005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F66406253B93005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F66506253B93005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F66606253B93005AB5DA = { + children = ( + 1865F66706253B93005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F66706253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F66806253B93005AB5DA = { + children = ( + 1865F66906253B93005AB5DA, + 1865F6F406253B96005AB5DA, + 1865F6F506253B96005AB5DA, + 1865F6F606253B96005AB5DA, + 1865F6F706253B96005AB5DA, + 1865F6F806253B96005AB5DA, + 1865F6F906253B96005AB5DA, + 1865F6FA06253B96005AB5DA, + 1865F6FB06253B96005AB5DA, + 1865F6FC06253B96005AB5DA, + 1865F6FD06253B96005AB5DA, + 1865F6FE06253B96005AB5DA, + 1865F6FF06253B96005AB5DA, + 1865F70006253B96005AB5DA, + 1865F70106253B96005AB5DA, + 1865F70206253B97005AB5DA, + 1865F70306253B97005AB5DA, + 1865F70406253B97005AB5DA, + 1865F70506253B97005AB5DA, + 1865F70606253B97005AB5DA, + 1865F70706253B97005AB5DA, + 1865F70806253B97005AB5DA, + 1865F70906253B97005AB5DA, + 1865F70A06253B97005AB5DA, + 1865F70B06253B97005AB5DA, + 1865F70C06253B97005AB5DA, + 1865F70D06253B97005AB5DA, + 1865F70E06253B97005AB5DA, + 1865F70F06253B97005AB5DA, + 1865F71006253B97005AB5DA, + 1865F71106253B97005AB5DA, + 1865F71206253B97005AB5DA, + ); + isa = PBXGroup; + path = pages; + refType = 4; + sourceTree = ""; + }; + 1865F66906253B93005AB5DA = { + children = ( + 1865F66A06253B93005AB5DA, + 1865F66B06253B93005AB5DA, + 1865F66C06253B93005AB5DA, + 1865F66D06253B93005AB5DA, + 1865F66E06253B93005AB5DA, + 1865F68E06253B94005AB5DA, + 1865F6AE06253B94005AB5DA, + 1865F6AF06253B94005AB5DA, + 1865F6CF06253B95005AB5DA, + 1865F6D406253B96005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F66A06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F66B06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F66C06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F66D06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F66E06253B93005AB5DA = { + children = ( + 1865F66F06253B93005AB5DA, + 1865F67006253B93005AB5DA, + 1865F67106253B93005AB5DA, + 1865F67206253B93005AB5DA, + 1865F67306253B93005AB5DA, + 1865F67406253B93005AB5DA, + 1865F67506253B93005AB5DA, + 1865F67606253B93005AB5DA, + 1865F67706253B93005AB5DA, + 1865F67806253B93005AB5DA, + 1865F67906253B93005AB5DA, + 1865F67A06253B93005AB5DA, + 1865F67B06253B93005AB5DA, + 1865F67C06253B93005AB5DA, + 1865F67D06253B93005AB5DA, + 1865F67E06253B93005AB5DA, + 1865F67F06253B93005AB5DA, + 1865F68006253B93005AB5DA, + 1865F68106253B93005AB5DA, + 1865F68206253B93005AB5DA, + 1865F68306253B93005AB5DA, + 1865F68406253B93005AB5DA, + 1865F68506253B93005AB5DA, + 1865F68606253B93005AB5DA, + 1865F68706253B93005AB5DA, + 1865F68806253B93005AB5DA, + 1865F68906253B93005AB5DA, + 1865F68A06253B93005AB5DA, + 1865F68B06253B94005AB5DA, + 1865F68C06253B94005AB5DA, + 1865F68D06253B94005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F66F06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_bots.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67006253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_buildings_to_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67106253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "art_tools.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67206253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "blocking_vis.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67306253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "boxing_in_the_world.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67406253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clipping_the_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67506253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_alphamap.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67606253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67706253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_keys_and_values.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67806253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glossary.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67906253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_map_into_terrain_mesh.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67A06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_maps.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67B06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image3.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67C06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image4.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67D06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image5.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67E06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image6.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F67F06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "introduction.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68006253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "key_changes.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68106253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lighting_the_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68206253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "manipulating_the_terrain_mesh.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68306253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapping_the_textures.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68406253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "new_or_revised_q3map_shader_comm.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68506253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "other_possible_height_map_tools.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68606253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68706253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "suggested_gensurf_settings.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68806253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68906253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_entity.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68A06253B93005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_mesh_into_terrain_entity.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68B06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_related_worldspawn_features.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68C06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_texture.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68D06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "the_meta_shader.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F68E06253B94005AB5DA = { + children = ( + 1865F68F06253B94005AB5DA, + 1865F69006253B94005AB5DA, + 1865F69106253B94005AB5DA, + 1865F69206253B94005AB5DA, + 1865F69306253B94005AB5DA, + 1865F69406253B94005AB5DA, + 1865F69506253B94005AB5DA, + 1865F69606253B94005AB5DA, + 1865F69706253B94005AB5DA, + 1865F69806253B94005AB5DA, + 1865F69906253B94005AB5DA, + 1865F69A06253B94005AB5DA, + 1865F69B06253B94005AB5DA, + 1865F69C06253B94005AB5DA, + 1865F69D06253B94005AB5DA, + 1865F69E06253B94005AB5DA, + 1865F69F06253B94005AB5DA, + 1865F6A006253B94005AB5DA, + 1865F6A106253B94005AB5DA, + 1865F6A206253B94005AB5DA, + 1865F6A306253B94005AB5DA, + 1865F6A406253B94005AB5DA, + 1865F6A506253B94005AB5DA, + 1865F6A606253B94005AB5DA, + 1865F6A706253B94005AB5DA, + 1865F6A806253B94005AB5DA, + 1865F6A906253B94005AB5DA, + 1865F6AA06253B94005AB5DA, + 1865F6AB06253B94005AB5DA, + 1865F6AC06253B94005AB5DA, + 1865F6AD06253B94005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F68F06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_bots.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69006253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_buildings_to_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69106253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "art_tools.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69206253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "blocking_vis.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69306253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "boxing_in_the_world.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69406253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clipping_the_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69506253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_alphamap.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69606253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69706253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_keys_and_values.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69806253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glossary.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69906253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_map_into_terrain_mesh.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69A06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_maps.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69B06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image3.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69C06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image4.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69D06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image5.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69E06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image6.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F69F06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "introduction.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A006253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "key_changes.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A106253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lighting_the_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A206253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "manipulating_the_terrain_mesh.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A306253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapping_the_textures.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A406253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "new_or_revised_q3map_shader_comm.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A506253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "other_possible_height_map_tools.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A606253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A706253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "suggested_gensurf_settings.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A806253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6A906253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_entity.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6AA06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_mesh_into_terrain_entity.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6AB06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_related_worldspawn_features.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6AC06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_texture.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6AD06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "the_meta_shader.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6AE06253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F6AF06253B94005AB5DA = { + children = ( + 1865F6B006253B94005AB5DA, + 1865F6B106253B95005AB5DA, + 1865F6B206253B95005AB5DA, + 1865F6B306253B95005AB5DA, + 1865F6B406253B95005AB5DA, + 1865F6B506253B95005AB5DA, + 1865F6B606253B95005AB5DA, + 1865F6B706253B95005AB5DA, + 1865F6B806253B95005AB5DA, + 1865F6B906253B95005AB5DA, + 1865F6BA06253B95005AB5DA, + 1865F6BB06253B95005AB5DA, + 1865F6BC06253B95005AB5DA, + 1865F6BD06253B95005AB5DA, + 1865F6BE06253B95005AB5DA, + 1865F6BF06253B95005AB5DA, + 1865F6C006253B95005AB5DA, + 1865F6C106253B95005AB5DA, + 1865F6C206253B95005AB5DA, + 1865F6C306253B95005AB5DA, + 1865F6C406253B95005AB5DA, + 1865F6C506253B95005AB5DA, + 1865F6C606253B95005AB5DA, + 1865F6C706253B95005AB5DA, + 1865F6C806253B95005AB5DA, + 1865F6C906253B95005AB5DA, + 1865F6CA06253B95005AB5DA, + 1865F6CB06253B95005AB5DA, + 1865F6CC06253B95005AB5DA, + 1865F6CD06253B95005AB5DA, + 1865F6CE06253B95005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B006253B94005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_bots.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B106253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_buildings_to_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B206253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "art_tools.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B306253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "blocking_vis.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B406253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "boxing_in_the_world.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B506253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clipping_the_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B606253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_alphamap.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B706253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B806253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_keys_and_values.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6B906253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glossary.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6BA06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_map_into_terrain_mesh.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6BB06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_maps.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6BC06253B95005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "Image3.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6BD06253B95005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "Image4.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6BE06253B95005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "Image5.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6BF06253B95005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "Image6.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C006253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "introduction.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C106253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "key_changes.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C206253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lighting_the_terrain.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C306253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "manipulating_the_terrain_mesh.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C406253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapping_the_textures.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C506253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "new_or_revised_q3map_shader_comm.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C606253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "other_possible_height_map_tools.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C706253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C806253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "suggested_gensurf_settings.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6C906253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6CA06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_entity.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6CB06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_mesh_into_terrain_entity.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6CC06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_related_worldspawn_features.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6CD06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_texture.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6CE06253B95005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "the_meta_shader.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6CF06253B95005AB5DA = { + children = ( + 1865F6D006253B95005AB5DA, + 1865F6D106253B96005AB5DA, + 1865F6D206253B96005AB5DA, + 1865F6D306253B96005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F6D006253B95005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6D106253B96005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F6D206253B96005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F6D306253B96005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F6D406253B96005AB5DA = { + children = ( + 1865F6D506253B96005AB5DA, + 1865F6D606253B96005AB5DA, + 1865F6D706253B96005AB5DA, + 1865F6D806253B96005AB5DA, + 1865F6D906253B96005AB5DA, + 1865F6DA06253B96005AB5DA, + 1865F6DB06253B96005AB5DA, + 1865F6DC06253B96005AB5DA, + 1865F6DD06253B96005AB5DA, + 1865F6DE06253B96005AB5DA, + 1865F6DF06253B96005AB5DA, + 1865F6E006253B96005AB5DA, + 1865F6E106253B96005AB5DA, + 1865F6E206253B96005AB5DA, + 1865F6E306253B96005AB5DA, + 1865F6E406253B96005AB5DA, + 1865F6E506253B96005AB5DA, + 1865F6E606253B96005AB5DA, + 1865F6E706253B96005AB5DA, + 1865F6E806253B96005AB5DA, + 1865F6E906253B96005AB5DA, + 1865F6EA06253B96005AB5DA, + 1865F6EB06253B96005AB5DA, + 1865F6EC06253B96005AB5DA, + 1865F6ED06253B96005AB5DA, + 1865F6EE06253B96005AB5DA, + 1865F6EF06253B96005AB5DA, + 1865F6F006253B96005AB5DA, + 1865F6F106253B96005AB5DA, + 1865F6F206253B96005AB5DA, + 1865F6F306253B96005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F6D506253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_bots.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6D606253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "adding_buildings_to_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6D706253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "art_tools.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6D806253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "blocking_vis.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6D906253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "boxing_in_the_world.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6DA06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clipping_the_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6DB06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_alphamap.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6DC06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "creating_the_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6DD06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_keys_and_values.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6DE06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "glossary.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6DF06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_map_into_terrain_mesh.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E006253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "height_maps.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E106253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image3.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E206253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image4.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E306253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image5.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E406253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Image6.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E506253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "introduction.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E606253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "key_changes.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E706253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lighting_the_terrain.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E806253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "manipulating_the_terrain_mesh.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6E906253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapping_the_textures.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6EA06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "new_or_revised_q3map_shader_comm.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6EB06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "other_possible_height_map_tools.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6EC06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "related_links.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6ED06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "suggested_gensurf_settings.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6EE06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "table_of_contents.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6EF06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_entity.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6F006253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_mesh_into_terrain_entity.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6F106253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_related_worldspawn_features.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6F206253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain_texture.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6F306253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "the_meta_shader.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F6F406253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = adding_bots.html; + refType = 4; + sourceTree = ""; + }; + 1865F6F506253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = adding_buildings_to_terrain.html; + refType = 4; + sourceTree = ""; + }; + 1865F6F606253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = art_tools.html; + refType = 4; + sourceTree = ""; + }; + 1865F6F706253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = blocking_vis.html; + refType = 4; + sourceTree = ""; + }; + 1865F6F806253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = boxing_in_the_world.html; + refType = 4; + sourceTree = ""; + }; + 1865F6F906253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = clipping_the_terrain.html; + refType = 4; + sourceTree = ""; + }; + 1865F6FA06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = creating_the_alphamap.html; + refType = 4; + sourceTree = ""; + }; + 1865F6FB06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = creating_the_terrain.html; + refType = 4; + sourceTree = ""; + }; + 1865F6FC06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = entity_keys_and_values.html; + refType = 4; + sourceTree = ""; + }; + 1865F6FD06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = glossary.html; + refType = 4; + sourceTree = ""; + }; + 1865F6FE06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = height_map_into_terrain_mesh.html; + refType = 4; + sourceTree = ""; + }; + 1865F6FF06253B96005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = height_maps.html; + refType = 4; + sourceTree = ""; + }; + 1865F70006253B96005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = Image3.gif; + refType = 4; + sourceTree = ""; + }; + 1865F70106253B96005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = Image4.gif; + refType = 4; + sourceTree = ""; + }; + 1865F70206253B97005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = Image5.gif; + refType = 4; + sourceTree = ""; + }; + 1865F70306253B97005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = Image6.gif; + refType = 4; + sourceTree = ""; + }; + 1865F70406253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = introduction.html; + refType = 4; + sourceTree = ""; + }; + 1865F70506253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = key_changes.html; + refType = 4; + sourceTree = ""; + }; + 1865F70606253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = lighting_the_terrain.html; + refType = 4; + sourceTree = ""; + }; + 1865F70706253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = manipulating_the_terrain_mesh.html; + refType = 4; + sourceTree = ""; + }; + 1865F70806253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = mapping_the_textures.html; + refType = 4; + sourceTree = ""; + }; + 1865F70906253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = new_or_revised_q3map_shader_comm.html; + refType = 4; + sourceTree = ""; + }; + 1865F70A06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = other_possible_height_map_tools.html; + refType = 4; + sourceTree = ""; + }; + 1865F70B06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = related_links.html; + refType = 4; + sourceTree = ""; + }; + 1865F70C06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = suggested_gensurf_settings.html; + refType = 4; + sourceTree = ""; + }; + 1865F70D06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = table_of_contents.html; + refType = 4; + sourceTree = ""; + }; + 1865F70E06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = terrain_entity.html; + refType = 4; + sourceTree = ""; + }; + 1865F70F06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = terrain_mesh_into_terrain_entity.html; + refType = 4; + sourceTree = ""; + }; + 1865F71006253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = terrain_related_worldspawn_features.html; + refType = 4; + sourceTree = ""; + }; + 1865F71106253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = terrain_texture.html; + refType = 4; + sourceTree = ""; + }; + 1865F71206253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = the_meta_shader.html; + refType = 4; + sourceTree = ""; + }; + 1865F71306253B97005AB5DA = { + children = ( + 1865F71406253B97005AB5DA, + 1865F72F06253B98005AB5DA, + 1865F73006253B98005AB5DA, + 1865F73106253B98005AB5DA, + ); + isa = PBXGroup; + path = pics; + refType = 4; + sourceTree = ""; + }; + 1865F71406253B97005AB5DA = { + children = ( + 1865F71506253B97005AB5DA, + 1865F71606253B97005AB5DA, + 1865F71706253B97005AB5DA, + 1865F71806253B97005AB5DA, + 1865F71906253B97005AB5DA, + 1865F71D06253B97005AB5DA, + 1865F72106253B98005AB5DA, + 1865F72206253B98005AB5DA, + 1865F72606253B98005AB5DA, + 1865F72B06253B98005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F71506253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F71606253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F71706253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F71806253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F71906253B97005AB5DA = { + children = ( + 1865F71A06253B97005AB5DA, + 1865F71B06253B97005AB5DA, + 1865F71C06253B97005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F71A06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "background.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F71B06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F71C06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F71D06253B97005AB5DA = { + children = ( + 1865F71E06253B97005AB5DA, + 1865F71F06253B97005AB5DA, + 1865F72006253B98005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F71E06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "background.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F71F06253B97005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F72006253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F72106253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F72206253B98005AB5DA = { + children = ( + 1865F72306253B98005AB5DA, + 1865F72406253B98005AB5DA, + 1865F72506253B98005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F72306253B98005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "background.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F72406253B98005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "start.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F72506253B98005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "terrain.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F72606253B98005AB5DA = { + children = ( + 1865F72706253B98005AB5DA, + 1865F72806253B98005AB5DA, + 1865F72906253B98005AB5DA, + 1865F72A06253B98005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F72706253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F72806253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F72906253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F72A06253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F72B06253B98005AB5DA = { + children = ( + 1865F72C06253B98005AB5DA, + 1865F72D06253B98005AB5DA, + 1865F72E06253B98005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F72C06253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "background.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F72D06253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "start.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F72E06253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "terrain.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F72F06253B98005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = background.jpg; + refType = 4; + sourceTree = ""; + }; + 1865F73006253B98005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = start.gif; + refType = 4; + sourceTree = ""; + }; + 1865F73106253B98005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = terrain.jpg; + refType = 4; + sourceTree = ""; + }; + 1865F73206253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = start.html; + refType = 4; + sourceTree = ""; + }; + 1865F73306253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = DoxyConfig; + refType = 4; + sourceTree = ""; + }; + 1865F73406253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Doxyfile; + refType = 4; + sourceTree = ""; + }; + 1865F73506253B98005AB5DA = { + children = ( + 1865F73606253B98005AB5DA, + 1865F74506253B99005AB5DA, + ); + isa = PBXGroup; + path = "doxygen-out"; + refType = 4; + sourceTree = ""; + }; + 1865F73606253B98005AB5DA = { + children = ( + 1865F73706253B98005AB5DA, + 1865F73806253B98005AB5DA, + 1865F73906253B98005AB5DA, + 1865F73A06253B98005AB5DA, + 1865F73B06253B98005AB5DA, + 1865F73C06253B98005AB5DA, + 1865F73D06253B98005AB5DA, + 1865F73E06253B98005AB5DA, + 1865F73F06253B98005AB5DA, + 1865F74406253B98005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F73706253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F73806253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F73906253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F73A06253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F73B06253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F73C06253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F73D06253B98005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F73E06253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F73F06253B98005AB5DA = { + children = ( + 1865F74006253B98005AB5DA, + 1865F74106253B98005AB5DA, + 1865F74206253B98005AB5DA, + 1865F74306253B98005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F74006253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F74106253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F74206253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F74306253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F74406253B98005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F74506253B99005AB5DA = { + children = ( + 1865F74606253B99005AB5DA, + ); + isa = PBXGroup; + path = images; + refType = 4; + sourceTree = ""; + }; + 1865F74606253B99005AB5DA = { + children = ( + 1865F74706253B99005AB5DA, + 1865F74806253B99005AB5DA, + 1865F74906253B99005AB5DA, + 1865F74A06253B99005AB5DA, + 1865F74B06253B99005AB5DA, + 1865F74C06253B99005AB5DA, + 1865F74D06253B99005AB5DA, + 1865F74E06253B99005AB5DA, + 1865F74F06253B99005AB5DA, + 1865F75406253B99005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F74706253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F74806253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F74906253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F74A06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F74B06253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F74C06253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F74D06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F74E06253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F74F06253B99005AB5DA = { + children = ( + 1865F75006253B99005AB5DA, + 1865F75106253B99005AB5DA, + 1865F75206253B99005AB5DA, + 1865F75306253B99005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F75006253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F75106253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F75206253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F75306253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F75406253B99005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F75506253B99005AB5DA = { + children = ( + 1865F75606253B99005AB5DA, + 1865F79106253B9A005AB5DA, + 1865F79206253B9A005AB5DA, + 1865F79306253B9A005AB5DA, + 1865F79406253B9A005AB5DA, + 1865F79506253B9A005AB5DA, + 1865F79606253B9A005AB5DA, + 1865F79706253B9A005AB5DA, + 1865F79806253B9A005AB5DA, + 1865F79906253B9A005AB5DA, + 1865F7F906253B9D005AB5DA, + 1865F7FA06253B9D005AB5DA, + 1865F7FB06253B9D005AB5DA, + 1865F85106253B9D005AB5DA, + ); + isa = PBXGroup; + path = Doxygen_files; + refType = 4; + sourceTree = ""; + }; + 1865F75606253B99005AB5DA = { + children = ( + 1865F75706253B99005AB5DA, + 1865F75806253B99005AB5DA, + 1865F75906253B99005AB5DA, + 1865F75A06253B99005AB5DA, + 1865F75B06253B99005AB5DA, + 1865F76706253B99005AB5DA, + 1865F77306253B9A005AB5DA, + 1865F77406253B9A005AB5DA, + 1865F78006253B9A005AB5DA, + 1865F78506253B9A005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F75706253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F75806253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F75906253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F75A06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F75B06253B99005AB5DA = { + children = ( + 1865F75C06253B99005AB5DA, + 1865F75D06253B99005AB5DA, + 1865F75E06253B99005AB5DA, + 1865F75F06253B99005AB5DA, + 1865F76006253B99005AB5DA, + 1865F76106253B99005AB5DA, + 1865F76206253B99005AB5DA, + 1865F76306253B99005AB5DA, + 1865F76406253B99005AB5DA, + 1865F76506253B99005AB5DA, + 1865F76606253B99005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F75C06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxy_mainpage.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F75D06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F75E06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F75F06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_foot.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76006253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_head.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76106253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76206253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_foot.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76306253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_head.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76406253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendoxfunctions.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76506253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genDoxyfile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76606253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference1.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F76706253B99005AB5DA = { + children = ( + 1865F76806253B99005AB5DA, + 1865F76906253B99005AB5DA, + 1865F76A06253B99005AB5DA, + 1865F76B06253B99005AB5DA, + 1865F76C06253B99005AB5DA, + 1865F76D06253B99005AB5DA, + 1865F76E06253B99005AB5DA, + 1865F76F06253B99005AB5DA, + 1865F77006253B9A005AB5DA, + 1865F77106253B9A005AB5DA, + 1865F77206253B9A005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F76806253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxy_mainpage.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76906253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76A06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76B06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_foot.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76C06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_head.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76D06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76E06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_foot.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F76F06253B99005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_head.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F77006253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendoxfunctions.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F77106253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genDoxyfile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F77206253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference1.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F77306253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F77406253B9A005AB5DA = { + children = ( + 1865F77506253B9A005AB5DA, + 1865F77606253B9A005AB5DA, + 1865F77706253B9A005AB5DA, + 1865F77806253B9A005AB5DA, + 1865F77906253B9A005AB5DA, + 1865F77A06253B9A005AB5DA, + 1865F77B06253B9A005AB5DA, + 1865F77C06253B9A005AB5DA, + 1865F77D06253B9A005AB5DA, + 1865F77E06253B9A005AB5DA, + 1865F77F06253B9A005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77506253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxy_mainpage.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77606253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77706253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77806253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_foot.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77906253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_head.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77A06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77B06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_foot.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77C06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_head.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77D06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "gendoxfunctions.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77E06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genDoxyfile.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F77F06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference1.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F78006253B9A005AB5DA = { + children = ( + 1865F78106253B9A005AB5DA, + 1865F78206253B9A005AB5DA, + 1865F78306253B9A005AB5DA, + 1865F78406253B9A005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F78106253B9A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F78206253B9A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F78306253B9A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F78406253B9A005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F78506253B9A005AB5DA = { + children = ( + 1865F78606253B9A005AB5DA, + 1865F78706253B9A005AB5DA, + 1865F78806253B9A005AB5DA, + 1865F78906253B9A005AB5DA, + 1865F78A06253B9A005AB5DA, + 1865F78B06253B9A005AB5DA, + 1865F78C06253B9A005AB5DA, + 1865F78D06253B9A005AB5DA, + 1865F78E06253B9A005AB5DA, + 1865F78F06253B9A005AB5DA, + 1865F79006253B9A005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F78606253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxy_mainpage.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78706253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Doxyfile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78806253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78906253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_foot.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78A06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant_head.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78B06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78C06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_foot.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78D06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_reference_head.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78E06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gendoxfunctions.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F78F06253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "genDoxyfile.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F79006253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "reference1.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F79106253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = doxy_mainpage.h; + refType = 4; + sourceTree = ""; + }; + 1865F79206253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Doxyfile; + refType = 4; + sourceTree = ""; + }; + 1865F79306253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = doxygen_gtkradiant.css; + refType = 4; + sourceTree = ""; + }; + 1865F79406253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = doxygen_gtkradiant_foot.html; + refType = 4; + sourceTree = ""; + }; + 1865F79506253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = doxygen_gtkradiant_head.html; + refType = 4; + sourceTree = ""; + }; + 1865F79606253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = doxygen_index.html; + refType = 4; + sourceTree = ""; + }; + 1865F79706253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = doxygen_reference_foot.html; + refType = 4; + sourceTree = ""; + }; + 1865F79806253B9A005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = doxygen_reference_head.html; + refType = 4; + sourceTree = ""; + }; + 1865F79906253B9A005AB5DA = { + children = ( + 1865F79A06253B9B005AB5DA, + 1865F7E906253B9C005AB5DA, + 1865F7EA06253B9C005AB5DA, + 1865F7EB06253B9C005AB5DA, + 1865F7EC06253B9D005AB5DA, + 1865F7ED06253B9D005AB5DA, + 1865F7EE06253B9D005AB5DA, + 1865F7EF06253B9D005AB5DA, + 1865F7F006253B9D005AB5DA, + 1865F7F106253B9D005AB5DA, + 1865F7F206253B9D005AB5DA, + 1865F7F306253B9D005AB5DA, + 1865F7F406253B9D005AB5DA, + 1865F7F506253B9D005AB5DA, + 1865F7F606253B9D005AB5DA, + 1865F7F706253B9D005AB5DA, + 1865F7F806253B9D005AB5DA, + ); + isa = PBXGroup; + path = example; + refType = 4; + sourceTree = ""; + }; + 1865F79A06253B9B005AB5DA = { + children = ( + 1865F79B06253B9B005AB5DA, + 1865F79C06253B9B005AB5DA, + 1865F79D06253B9B005AB5DA, + 1865F79E06253B9B005AB5DA, + 1865F79F06253B9B005AB5DA, + 1865F7B006253B9B005AB5DA, + 1865F7C106253B9B005AB5DA, + 1865F7C206253B9B005AB5DA, + 1865F7D306253B9C005AB5DA, + 1865F7D806253B9C005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F79B06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F79C06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F79D06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F79E06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F79F06253B9B005AB5DA = { + children = ( + 1865F7A006253B9B005AB5DA, + 1865F7A106253B9B005AB5DA, + 1865F7A206253B9B005AB5DA, + 1865F7A306253B9B005AB5DA, + 1865F7A406253B9B005AB5DA, + 1865F7A506253B9B005AB5DA, + 1865F7A606253B9B005AB5DA, + 1865F7A706253B9B005AB5DA, + 1865F7A806253B9B005AB5DA, + 1865F7A906253B9B005AB5DA, + 1865F7AA06253B9B005AB5DA, + 1865F7AB06253B9B005AB5DA, + 1865F7AC06253B9B005AB5DA, + 1865F7AD06253B9B005AB5DA, + 1865F7AE06253B9B005AB5DA, + 1865F7AF06253B9B005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A006253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "annotated.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A106253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classes.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A206253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair-members.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A306253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A406253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A506253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A606253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A706253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "functions.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A806253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.dot.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7A906253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7AA06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7AB06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7AC06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pages.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7AD06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c-source.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7AE06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7AF06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "todo.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7B006253B9B005AB5DA = { + children = ( + 1865F7B106253B9B005AB5DA, + 1865F7B206253B9B005AB5DA, + 1865F7B306253B9B005AB5DA, + 1865F7B406253B9B005AB5DA, + 1865F7B506253B9B005AB5DA, + 1865F7B606253B9B005AB5DA, + 1865F7B706253B9B005AB5DA, + 1865F7B806253B9B005AB5DA, + 1865F7B906253B9B005AB5DA, + 1865F7BA06253B9B005AB5DA, + 1865F7BB06253B9B005AB5DA, + 1865F7BC06253B9B005AB5DA, + 1865F7BD06253B9B005AB5DA, + 1865F7BE06253B9B005AB5DA, + 1865F7BF06253B9B005AB5DA, + 1865F7C006253B9B005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F7B106253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "annotated.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B206253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classes.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B306253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair-members.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B406253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B506253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B606253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B706253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B806253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "functions.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7B906253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.dot.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7BA06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7BB06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7BC06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7BD06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pages.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7BE06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c-source.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7BF06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7C006253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "todo.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7C106253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F7C206253B9B005AB5DA = { + children = ( + 1865F7C306253B9B005AB5DA, + 1865F7C406253B9B005AB5DA, + 1865F7C506253B9B005AB5DA, + 1865F7C606253B9B005AB5DA, + 1865F7C706253B9B005AB5DA, + 1865F7C806253B9B005AB5DA, + 1865F7C906253B9B005AB5DA, + 1865F7CA06253B9B005AB5DA, + 1865F7CB06253B9B005AB5DA, + 1865F7CC06253B9B005AB5DA, + 1865F7CD06253B9B005AB5DA, + 1865F7CE06253B9C005AB5DA, + 1865F7CF06253B9C005AB5DA, + 1865F7D006253B9C005AB5DA, + 1865F7D106253B9C005AB5DA, + 1865F7D206253B9C005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C306253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "annotated.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C406253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classes.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C506253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair-members.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C606253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C706253B9B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "doxygen.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C806253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7C906253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7CA06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "functions.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7CB06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.dot.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7CC06253B9B005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "graph_legend.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7CD06253B9B005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7CE06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7CF06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pages.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7D006253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c-source.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7D106253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7D206253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "todo.html.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7D306253B9C005AB5DA = { + children = ( + 1865F7D406253B9C005AB5DA, + 1865F7D506253B9C005AB5DA, + 1865F7D606253B9C005AB5DA, + 1865F7D706253B9C005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F7D406253B9C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7D506253B9C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F7D606253B9C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F7D706253B9C005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F7D806253B9C005AB5DA = { + children = ( + 1865F7D906253B9C005AB5DA, + 1865F7DA06253B9C005AB5DA, + 1865F7DB06253B9C005AB5DA, + 1865F7DC06253B9C005AB5DA, + 1865F7DD06253B9C005AB5DA, + 1865F7DE06253B9C005AB5DA, + 1865F7DF06253B9C005AB5DA, + 1865F7E006253B9C005AB5DA, + 1865F7E106253B9C005AB5DA, + 1865F7E206253B9C005AB5DA, + 1865F7E306253B9C005AB5DA, + 1865F7E406253B9C005AB5DA, + 1865F7E506253B9C005AB5DA, + 1865F7E606253B9C005AB5DA, + 1865F7E706253B9C005AB5DA, + 1865F7E806253B9C005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F7D906253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "annotated.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7DA06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classes.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7DB06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair-members.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7DC06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "classIEpair.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7DD06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7DE06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "doxygen_gtkradiant.css.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7DF06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "files.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E006253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "functions.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E106253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.dot.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E206253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E306253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "graph_legend.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E406253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "index.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E506253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pages.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E606253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c-source.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E706253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "test_8c.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E806253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "todo.html.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F7E906253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = annotated.html; + refType = 4; + sourceTree = ""; + }; + 1865F7EA06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = classes.html; + refType = 4; + sourceTree = ""; + }; + 1865F7EB06253B9C005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = "classIEpair-members.html"; + refType = 4; + sourceTree = ""; + }; + 1865F7EC06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = classIEpair.html; + refType = 4; + sourceTree = ""; + }; + 1865F7ED06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = doxygen.gif; + refType = 4; + sourceTree = ""; + }; + 1865F7EE06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = doxygen_gtkradiant.css; + refType = 4; + sourceTree = ""; + }; + 1865F7EF06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = files.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F006253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = functions.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F106253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = graph_legend.dot; + refType = 4; + sourceTree = ""; + }; + 1865F7F206253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = graph_legend.gif; + refType = 4; + sourceTree = ""; + }; + 1865F7F306253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = graph_legend.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F406253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = index.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F506253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = pages.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F606253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = "test_8c-source.html"; + refType = 4; + sourceTree = ""; + }; + 1865F7F706253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = test_8c.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F806253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = todo.html; + refType = 4; + sourceTree = ""; + }; + 1865F7F906253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = gendoxfunctions; + refType = 4; + sourceTree = ""; + }; + 1865F7FA06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = genDoxyfile; + refType = 4; + sourceTree = ""; + }; + 1865F7FB06253B9D005AB5DA = { + children = ( + 1865F7FC06253B9D005AB5DA, + 1865F84306253B9D005AB5DA, + 1865F84406253B9D005AB5DA, + 1865F84506253B9D005AB5DA, + 1865F84606253B9D005AB5DA, + 1865F84706253B9D005AB5DA, + 1865F84806253B9D005AB5DA, + 1865F84906253B9D005AB5DA, + 1865F84A06253B9D005AB5DA, + 1865F84B06253B9D005AB5DA, + 1865F84C06253B9D005AB5DA, + 1865F84D06253B9D005AB5DA, + 1865F84E06253B9D005AB5DA, + 1865F84F06253B9D005AB5DA, + 1865F85006253B9D005AB5DA, + ); + isa = PBXGroup; + path = images; + refType = 4; + sourceTree = ""; + }; + 1865F7FC06253B9D005AB5DA = { + children = ( + 1865F7FD06253B9D005AB5DA, + 1865F7FE06253B9D005AB5DA, + 1865F7FF06253B9D005AB5DA, + 1865F80006253B9D005AB5DA, + 1865F80106253B9D005AB5DA, + 1865F81006253B9D005AB5DA, + 1865F81F06253B9D005AB5DA, + 1865F82006253B9D005AB5DA, + 1865F82F06253B9D005AB5DA, + 1865F83406253B9D005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F7FD06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F7FE06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F7FF06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F80006253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F80106253B9D005AB5DA = { + children = ( + 1865F80206253B9D005AB5DA, + 1865F80306253B9D005AB5DA, + 1865F80406253B9D005AB5DA, + 1865F80506253B9D005AB5DA, + 1865F80606253B9D005AB5DA, + 1865F80706253B9D005AB5DA, + 1865F80806253B9D005AB5DA, + 1865F80906253B9D005AB5DA, + 1865F80A06253B9D005AB5DA, + 1865F80B06253B9D005AB5DA, + 1865F80C06253B9D005AB5DA, + 1865F80D06253B9D005AB5DA, + 1865F80E06253B9D005AB5DA, + 1865F80F06253B9D005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80206253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-left-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80306253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-left.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80406253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-right.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80506253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80606253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-right-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80706253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-left.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80806253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-right.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80906253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80A06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_splash.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80B06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_splash_sm.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80C06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "history_id_logo.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80D06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-right.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80E06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F80F06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-title.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F81006253B9D005AB5DA = { + children = ( + 1865F81106253B9D005AB5DA, + 1865F81206253B9D005AB5DA, + 1865F81306253B9D005AB5DA, + 1865F81406253B9D005AB5DA, + 1865F81506253B9D005AB5DA, + 1865F81606253B9D005AB5DA, + 1865F81706253B9D005AB5DA, + 1865F81806253B9D005AB5DA, + 1865F81906253B9D005AB5DA, + 1865F81A06253B9D005AB5DA, + 1865F81B06253B9D005AB5DA, + 1865F81C06253B9D005AB5DA, + 1865F81D06253B9D005AB5DA, + 1865F81E06253B9D005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F81106253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-left-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81206253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-left.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81306253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-right.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81406253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81506253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-right-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81606253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-left.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81706253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-right.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81806253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81906253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_splash.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81A06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_splash_sm.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81B06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "history_id_logo.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81C06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-right.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81D06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81E06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-title.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F81F06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F82006253B9D005AB5DA = { + children = ( + 1865F82106253B9D005AB5DA, + 1865F82206253B9D005AB5DA, + 1865F82306253B9D005AB5DA, + 1865F82406253B9D005AB5DA, + 1865F82506253B9D005AB5DA, + 1865F82606253B9D005AB5DA, + 1865F82706253B9D005AB5DA, + 1865F82806253B9D005AB5DA, + 1865F82906253B9D005AB5DA, + 1865F82A06253B9D005AB5DA, + 1865F82B06253B9D005AB5DA, + 1865F82C06253B9D005AB5DA, + 1865F82D06253B9D005AB5DA, + 1865F82E06253B9D005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82106253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-left-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82206253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-lower-left.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82306253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-lower-right.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82406253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-lower-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82506253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-right-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82606253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-upper-left.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82706253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-upper-right.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82806253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "body-upper-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82906253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "gtkr_splash.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82A06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "gtkr_splash_sm.jpg.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82B06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "history_id_logo.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82C06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "top-right.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82D06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "top-tile.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82E06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "top-title.gif.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F82F06253B9D005AB5DA = { + children = ( + 1865F83006253B9D005AB5DA, + 1865F83106253B9D005AB5DA, + 1865F83206253B9D005AB5DA, + 1865F83306253B9D005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F83006253B9D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F83106253B9D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F83206253B9D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F83306253B9D005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F83406253B9D005AB5DA = { + children = ( + 1865F83506253B9D005AB5DA, + 1865F83606253B9D005AB5DA, + 1865F83706253B9D005AB5DA, + 1865F83806253B9D005AB5DA, + 1865F83906253B9D005AB5DA, + 1865F83A06253B9D005AB5DA, + 1865F83B06253B9D005AB5DA, + 1865F83C06253B9D005AB5DA, + 1865F83D06253B9D005AB5DA, + 1865F83E06253B9D005AB5DA, + 1865F83F06253B9D005AB5DA, + 1865F84006253B9D005AB5DA, + 1865F84106253B9D005AB5DA, + 1865F84206253B9D005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F83506253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-left-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83606253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-left.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83706253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-right.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83806253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-lower-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83906253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-right-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83A06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-left.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83B06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-right.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83C06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "body-upper-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83D06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_splash.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83E06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_splash_sm.jpg.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F83F06253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "history_id_logo.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F84006253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-right.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F84106253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-tile.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F84206253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "top-title.gif.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F84306253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-left-tile.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84406253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-lower-left.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84506253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-lower-right.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84606253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-lower-tile.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84706253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-right-tile.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84806253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-upper-left.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84906253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-upper-right.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84A06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "body-upper-tile.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84B06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = gtkr_splash.jpg; + refType = 4; + sourceTree = ""; + }; + 1865F84C06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.jpeg; + path = gtkr_splash_sm.jpg; + refType = 4; + sourceTree = ""; + }; + 1865F84D06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = history_id_logo.gif; + refType = 4; + sourceTree = ""; + }; + 1865F84E06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "top-right.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F84F06253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "top-tile.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F85006253B9D005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.gif; + path = "top-title.gif"; + refType = 4; + sourceTree = ""; + }; + 1865F85106253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.html; + path = reference1.html; + refType = 4; + sourceTree = ""; + }; + 1865F85206253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = gen.readme; + refType = 4; + sourceTree = ""; + }; + 1865F85306253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = gen.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865F85406253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = gendox; + refType = 4; + sourceTree = ""; + }; + 1865F85506253B9D005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = GPL; + refType = 4; + sourceTree = ""; + }; + 1865F85606253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = GtkRadiant.prj; + refType = 4; + sourceTree = ""; + }; + 1865F85706253B9E005AB5DA = { + children = ( + 1865F85806253B9E005AB5DA, + 1865F85906253B9E005AB5DA, + 1865F8F406253BA1005AB5DA, + 1865F8F506253BA1005AB5DA, + 1865F8F606253BA1005AB5DA, + 1865F8F706253BA1005AB5DA, + 1865F8F806253BA1005AB5DA, + 1865F8F906253BA1005AB5DA, + 1865F8FA06253BA1005AB5DA, + 1865F8FB06253BA1005AB5DA, + 1865F8FC06253BA1005AB5DA, + 1865F8FD06253BA1005AB5DA, + 1865F8FE06253BA1005AB5DA, + 1865F8FF06253BA1005AB5DA, + 1865F90006253BA1005AB5DA, + 1865F90106253BA1005AB5DA, + 1865F90206253BA1005AB5DA, + 1865F90306253BA1005AB5DA, + 1865F90406253BA1005AB5DA, + 1865F90506253BA1005AB5DA, + 1865F90606253BA1005AB5DA, + 1865F90706253BA2005AB5DA, + 1865F90806253BA2005AB5DA, + 1865F90906253BA2005AB5DA, + 1865F90A06253BA2005AB5DA, + 1865F90B06253BA2005AB5DA, + 1865F90C06253BA2005AB5DA, + 1865F90D06253BA2005AB5DA, + 1865F90E06253BA2005AB5DA, + 1865F90F06253BA2005AB5DA, + 1865F91006253BA2005AB5DA, + 1865F91106253BA2005AB5DA, + 1865F91206253BA2005AB5DA, + 1865F91306253BA2005AB5DA, + 1865F91406253BA2005AB5DA, + 1865F91506253BA2005AB5DA, + 1865F91606253BA2005AB5DA, + 1865F91706253BA2005AB5DA, + 1865F91806253BA2005AB5DA, + 1865F91906253BA2005AB5DA, + 1865F91A06253BA2005AB5DA, + ); + isa = PBXGroup; + path = include; + refType = 4; + sourceTree = ""; + }; + 1865F85806253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865F85906253B9E005AB5DA = { + children = ( + 1865F85A06253B9E005AB5DA, + 1865F85B06253B9E005AB5DA, + 1865F85C06253B9E005AB5DA, + 1865F85D06253B9E005AB5DA, + 1865F85E06253B9E005AB5DA, + 1865F88206253B9E005AB5DA, + 1865F8A606253B9F005AB5DA, + 1865F8A706253B9F005AB5DA, + 1865F8CB06253BA0005AB5DA, + 1865F8D006253BA0005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F85A06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F85B06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F85C06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F85D06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F85E06253B9E005AB5DA = { + children = ( + 1865F85F06253B9E005AB5DA, + 1865F86006253B9E005AB5DA, + 1865F86106253B9E005AB5DA, + 1865F86206253B9E005AB5DA, + 1865F86306253B9E005AB5DA, + 1865F86406253B9E005AB5DA, + 1865F86506253B9E005AB5DA, + 1865F86606253B9E005AB5DA, + 1865F86706253B9E005AB5DA, + 1865F86806253B9E005AB5DA, + 1865F86906253B9E005AB5DA, + 1865F86A06253B9E005AB5DA, + 1865F86B06253B9E005AB5DA, + 1865F86C06253B9E005AB5DA, + 1865F86D06253B9E005AB5DA, + 1865F86E06253B9E005AB5DA, + 1865F86F06253B9E005AB5DA, + 1865F87006253B9E005AB5DA, + 1865F87106253B9E005AB5DA, + 1865F87206253B9E005AB5DA, + 1865F87306253B9E005AB5DA, + 1865F87406253B9E005AB5DA, + 1865F87506253B9E005AB5DA, + 1865F87606253B9E005AB5DA, + 1865F87706253B9E005AB5DA, + 1865F87806253B9E005AB5DA, + 1865F87906253B9E005AB5DA, + 1865F87A06253B9E005AB5DA, + 1865F87B06253B9E005AB5DA, + 1865F87C06253B9E005AB5DA, + 1865F87D06253B9E005AB5DA, + 1865F87E06253B9E005AB5DA, + 1865F87F06253B9E005AB5DA, + 1865F88006253B9E005AB5DA, + 1865F88106253B9E005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F85F06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86006253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aboutmsg.default.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86106253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_list.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86206253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_vector.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86306253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibrush.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86406253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibspfrontend.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86506253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icamera.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86606253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idata.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86706253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idatastream.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86806253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ieclass.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86906253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ientity.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86A06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ifilesystem.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86B06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86C06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iimage.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86D06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imap.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86E06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F86F06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ipatch.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87006253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87106253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "irefcount.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87206253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iscriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87306253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iselectedface.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87406253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishaders.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87506253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishadersmanager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87606253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "isurfaceplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87706253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "itoolbar.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87806253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87906253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui_gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87A06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iundo.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87B06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc_def.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87C06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qerplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87D06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qertypes.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87E06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qsysprintf.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F87F06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stl_check.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F88006253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stream_version.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F88106253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "version.default.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F88206253B9E005AB5DA = { + children = ( + 1865F88306253B9E005AB5DA, + 1865F88406253B9E005AB5DA, + 1865F88506253B9E005AB5DA, + 1865F88606253B9E005AB5DA, + 1865F88706253B9E005AB5DA, + 1865F88806253B9E005AB5DA, + 1865F88906253B9E005AB5DA, + 1865F88A06253B9E005AB5DA, + 1865F88B06253B9E005AB5DA, + 1865F88C06253B9E005AB5DA, + 1865F88D06253B9E005AB5DA, + 1865F88E06253B9E005AB5DA, + 1865F88F06253B9E005AB5DA, + 1865F89006253B9E005AB5DA, + 1865F89106253B9E005AB5DA, + 1865F89206253B9E005AB5DA, + 1865F89306253B9E005AB5DA, + 1865F89406253B9E005AB5DA, + 1865F89506253B9E005AB5DA, + 1865F89606253B9E005AB5DA, + 1865F89706253B9F005AB5DA, + 1865F89806253B9F005AB5DA, + 1865F89906253B9F005AB5DA, + 1865F89A06253B9F005AB5DA, + 1865F89B06253B9F005AB5DA, + 1865F89C06253B9F005AB5DA, + 1865F89D06253B9F005AB5DA, + 1865F89E06253B9F005AB5DA, + 1865F89F06253B9F005AB5DA, + 1865F8A006253B9F005AB5DA, + 1865F8A106253B9F005AB5DA, + 1865F8A206253B9F005AB5DA, + 1865F8A306253B9F005AB5DA, + 1865F8A406253B9F005AB5DA, + 1865F8A506253B9F005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F88306253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88406253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aboutmsg.default.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88506253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_list.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88606253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_vector.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88706253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibrush.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88806253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibspfrontend.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88906253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icamera.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88A06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idata.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88B06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idatastream.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88C06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ieclass.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88D06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ientity.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88E06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ifilesystem.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F88F06253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89006253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iimage.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89106253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imap.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89206253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89306253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ipatch.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89406253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89506253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "irefcount.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89606253B9E005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iscriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89706253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iselectedface.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89806253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishaders.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89906253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishadersmanager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89A06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "isurfaceplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89B06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "itoolbar.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89C06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89D06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui_gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89E06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iundo.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F89F06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc_def.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A006253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qerplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A106253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qertypes.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A206253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qsysprintf.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A306253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stl_check.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A406253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stream_version.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A506253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "version.default.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8A606253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F8A706253B9F005AB5DA = { + children = ( + 1865F8A806253B9F005AB5DA, + 1865F8A906253B9F005AB5DA, + 1865F8AA06253B9F005AB5DA, + 1865F8AB06253B9F005AB5DA, + 1865F8AC06253B9F005AB5DA, + 1865F8AD06253B9F005AB5DA, + 1865F8AE06253B9F005AB5DA, + 1865F8AF06253B9F005AB5DA, + 1865F8B006253B9F005AB5DA, + 1865F8B106253B9F005AB5DA, + 1865F8B206253B9F005AB5DA, + 1865F8B306253B9F005AB5DA, + 1865F8B406253B9F005AB5DA, + 1865F8B506253B9F005AB5DA, + 1865F8B606253B9F005AB5DA, + 1865F8B706253B9F005AB5DA, + 1865F8B806253B9F005AB5DA, + 1865F8B906253B9F005AB5DA, + 1865F8BA06253B9F005AB5DA, + 1865F8BB06253B9F005AB5DA, + 1865F8BC06253B9F005AB5DA, + 1865F8BD06253B9F005AB5DA, + 1865F8BE06253B9F005AB5DA, + 1865F8BF06253B9F005AB5DA, + 1865F8C006253B9F005AB5DA, + 1865F8C106253B9F005AB5DA, + 1865F8C206253B9F005AB5DA, + 1865F8C306253B9F005AB5DA, + 1865F8C406253B9F005AB5DA, + 1865F8C506253B9F005AB5DA, + 1865F8C606253B9F005AB5DA, + 1865F8C706253B9F005AB5DA, + 1865F8C806253BA0005AB5DA, + 1865F8C906253BA0005AB5DA, + 1865F8CA06253BA0005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8A806253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8A906253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aboutmsg.default.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8AA06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_list.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8AB06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_vector.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8AC06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibrush.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8AD06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibspfrontend.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8AE06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icamera.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8AF06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idata.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B006253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idatastream.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B106253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ieclass.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B206253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ientity.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B306253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ifilesystem.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B406253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B506253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iimage.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B606253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imap.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B706253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B806253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ipatch.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8B906253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8BA06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "irefcount.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8BB06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iscriplib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8BC06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iselectedface.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8BD06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishaders.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8BE06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishadersmanager.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8BF06253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "isurfaceplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C006253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "itoolbar.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C106253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C206253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui_gtk.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C306253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iundo.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C406253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc_def.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C506253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qerplugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C606253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qertypes.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C706253B9F005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qsysprintf.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C806253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stl_check.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8C906253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stream_version.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8CA06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "version.default.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8CB06253BA0005AB5DA = { + children = ( + 1865F8CC06253BA0005AB5DA, + 1865F8CD06253BA0005AB5DA, + 1865F8CE06253BA0005AB5DA, + 1865F8CF06253BA0005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F8CC06253BA0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8CD06253BA0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F8CE06253BA0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F8CF06253BA0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F8D006253BA0005AB5DA = { + children = ( + 1865F8D106253BA0005AB5DA, + 1865F8D206253BA0005AB5DA, + 1865F8D306253BA0005AB5DA, + 1865F8D406253BA0005AB5DA, + 1865F8D506253BA0005AB5DA, + 1865F8D606253BA0005AB5DA, + 1865F8D706253BA0005AB5DA, + 1865F8D806253BA0005AB5DA, + 1865F8D906253BA0005AB5DA, + 1865F8DA06253BA0005AB5DA, + 1865F8DB06253BA0005AB5DA, + 1865F8DC06253BA0005AB5DA, + 1865F8DD06253BA0005AB5DA, + 1865F8DE06253BA0005AB5DA, + 1865F8DF06253BA0005AB5DA, + 1865F8E006253BA0005AB5DA, + 1865F8E106253BA0005AB5DA, + 1865F8E206253BA0005AB5DA, + 1865F8E306253BA0005AB5DA, + 1865F8E406253BA0005AB5DA, + 1865F8E506253BA0005AB5DA, + 1865F8E606253BA0005AB5DA, + 1865F8E706253BA0005AB5DA, + 1865F8E806253BA0005AB5DA, + 1865F8E906253BA0005AB5DA, + 1865F8EA06253BA0005AB5DA, + 1865F8EB06253BA0005AB5DA, + 1865F8EC06253BA0005AB5DA, + 1865F8ED06253BA0005AB5DA, + 1865F8EE06253BA0005AB5DA, + 1865F8EF06253BA0005AB5DA, + 1865F8F006253BA0005AB5DA, + 1865F8F106253BA0005AB5DA, + 1865F8F206253BA0005AB5DA, + 1865F8F306253BA1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F8D106253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D206253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "aboutmsg.default.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D306253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_list.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D406253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "gtkr_vector.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D506253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibrush.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D606253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ibspfrontend.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D706253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "icamera.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D806253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idata.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8D906253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "idatastream.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8DA06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ieclass.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8DB06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ientity.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8DC06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ifilesystem.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8DD06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8DE06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iimage.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8DF06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imap.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E006253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E106253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ipatch.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E206253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E306253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "irefcount.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E406253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iscriplib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E506253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iselectedface.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E606253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishaders.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E706253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ishadersmanager.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E806253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "isurfaceplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8E906253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "itoolbar.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8EA06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8EB06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iui_gtk.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8EC06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "iundo.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8ED06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "misc_def.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8EE06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qerplugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8EF06253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qertypes.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8F006253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "qsysprintf.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8F106253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stl_check.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8F206253BA0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "stream_version.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8F306253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "version.default.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F8F406253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = aboutmsg.default; + refType = 4; + sourceTree = ""; + }; + 1865F8F506253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = aboutmsg.h; + refType = 4; + sourceTree = ""; + }; + 1865F8F606253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gtkr_list.h; + refType = 4; + sourceTree = ""; + }; + 1865F8F706253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = gtkr_vector.h; + refType = 4; + sourceTree = ""; + }; + 1865F8F806253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ibrush.h; + refType = 4; + sourceTree = ""; + }; + 1865F8F906253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ibspfrontend.h; + refType = 4; + sourceTree = ""; + }; + 1865F8FA06253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = icamera.h; + refType = 4; + sourceTree = ""; + }; + 1865F8FB06253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = idata.h; + refType = 4; + sourceTree = ""; + }; + 1865F8FC06253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = idatastream.h; + refType = 4; + sourceTree = ""; + }; + 1865F8FD06253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ieclass.h; + refType = 4; + sourceTree = ""; + }; + 1865F8FE06253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ientity.h; + refType = 4; + sourceTree = ""; + }; + 1865F8FF06253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ifilesystem.h; + refType = 4; + sourceTree = ""; + }; + 1865F90006253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = igl.h; + refType = 4; + sourceTree = ""; + }; + 1865F90106253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iimage.h; + refType = 4; + sourceTree = ""; + }; + 1865F90206253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imap.h; + refType = 4; + sourceTree = ""; + }; + 1865F90306253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imodel.h; + refType = 4; + sourceTree = ""; + }; + 1865F90406253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ipatch.h; + refType = 4; + sourceTree = ""; + }; + 1865F90506253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iplugin.h; + refType = 4; + sourceTree = ""; + }; + 1865F90606253BA1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = irefcount.h; + refType = 4; + sourceTree = ""; + }; + 1865F90706253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iscriplib.h; + refType = 4; + sourceTree = ""; + }; + 1865F90806253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iselectedface.h; + refType = 4; + sourceTree = ""; + }; + 1865F90906253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ishaders.h; + refType = 4; + sourceTree = ""; + }; + 1865F90A06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ishadersmanager.h; + refType = 4; + sourceTree = ""; + }; + 1865F90B06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = isurfaceplugin.h; + refType = 4; + sourceTree = ""; + }; + 1865F90C06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = itoolbar.h; + refType = 4; + sourceTree = ""; + }; + 1865F90D06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iui.h; + refType = 4; + sourceTree = ""; + }; + 1865F90E06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iui_gtk.h; + refType = 4; + sourceTree = ""; + }; + 1865F90F06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iundo.h; + refType = 4; + sourceTree = ""; + }; + 1865F91006253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = misc_def.h; + refType = 4; + sourceTree = ""; + }; + 1865F91106253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qerplugin.h; + refType = 4; + sourceTree = ""; + }; + 1865F91206253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qertypes.h; + refType = 4; + sourceTree = ""; + }; + 1865F91306253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = qsysprintf.h; + refType = 4; + sourceTree = ""; + }; + 1865F91406253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = RADIANT_MAJOR; + refType = 4; + sourceTree = ""; + }; + 1865F91506253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = RADIANT_MINOR; + refType = 4; + sourceTree = ""; + }; + 1865F91606253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = stl_check.h; + refType = 4; + sourceTree = ""; + }; + 1865F91706253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = stream_version.h; + refType = 4; + sourceTree = ""; + }; + 1865F91806253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = version; + refType = 4; + sourceTree = ""; + }; + 1865F91906253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = version.default; + refType = 4; + sourceTree = ""; + }; + 1865F91A06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = version.h; + refType = 4; + sourceTree = ""; + }; + 1865F91B06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = INSTALL.txt; + refType = 4; + sourceTree = ""; + }; + 1865F91C06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = LGPL; + refType = 4; + sourceTree = ""; + }; + 1865F91D06253BA2005AB5DA = { + children = ( + 1865F91E06253BA2005AB5DA, + 1865F91F06253BA2005AB5DA, + 1865F96A06253BA5005AB5DA, + 1865F96B06253BA5005AB5DA, + 1865F98F06253BA6005AB5DA, + 1865F99006253BA6005AB5DA, + 1865F9AA06253BA7005AB5DA, + 1865F9AB06253BA7005AB5DA, + 1865F9AC06253BA7005AB5DA, + 1865FA6B06253BA9005AB5DA, + 1865FA6C06253BA9005AB5DA, + 1865FA9F06253BA9005AB5DA, + 1865FAEF06253BAA005AB5DA, + 1865FB1D06253BAA005AB5DA, + 1865FB1E06253BAA005AB5DA, + 1865FB3D06253BAB005AB5DA, + 1865FB3E06253BAB005AB5DA, + 1865FB3F06253BAB005AB5DA, + 1865FB4006253BAB005AB5DA, + 1865FB6906253BAB005AB5DA, + 1865FB6A06253BAB005AB5DA, + 1865FC0C06253BAD005AB5DA, + 1865FC0D06253BAD005AB5DA, + 1865FC0E06253BAD005AB5DA, + 1865FC7806253BAE005AB5DA, + 1865FC7906253BAE005AB5DA, + 1865FCB206253BAF005AB5DA, + ); + isa = PBXGroup; + path = libs; + refType = 4; + sourceTree = ""; + }; + 1865F91E06253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865F91F06253BA2005AB5DA = { + children = ( + 1865F92006253BA2005AB5DA, + 1865F92106253BA2005AB5DA, + 1865F92206253BA3005AB5DA, + 1865F92306253BA3005AB5DA, + 1865F92406253BA3005AB5DA, + 1865F93406253BA3005AB5DA, + 1865F94406253BA3005AB5DA, + 1865F94506253BA4005AB5DA, + 1865F95506253BA4005AB5DA, + 1865F95A06253BA4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F92006253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F92106253BA2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F92206253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F92306253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F92406253BA3005AB5DA = { + children = ( + 1865F92506253BA3005AB5DA, + 1865F92606253BA3005AB5DA, + 1865F92706253BA3005AB5DA, + 1865F92806253BA3005AB5DA, + 1865F92906253BA3005AB5DA, + 1865F92A06253BA3005AB5DA, + 1865F92B06253BA3005AB5DA, + 1865F92C06253BA3005AB5DA, + 1865F92D06253BA3005AB5DA, + 1865F92E06253BA3005AB5DA, + 1865F92F06253BA3005AB5DA, + 1865F93006253BA3005AB5DA, + 1865F93106253BA3005AB5DA, + 1865F93206253BA3005AB5DA, + 1865F93306253BA3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92506253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92606253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bytebool.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92706253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92806253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92906253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl_to_qgl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92A06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeglib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92B06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92C06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92D06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92E06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "multimon.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F92F06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F93006253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F93106253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant_jpeglib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F93206253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "str.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F93306253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F93406253BA3005AB5DA = { + children = ( + 1865F93506253BA3005AB5DA, + 1865F93606253BA3005AB5DA, + 1865F93706253BA3005AB5DA, + 1865F93806253BA3005AB5DA, + 1865F93906253BA3005AB5DA, + 1865F93A06253BA3005AB5DA, + 1865F93B06253BA3005AB5DA, + 1865F93C06253BA3005AB5DA, + 1865F93D06253BA3005AB5DA, + 1865F93E06253BA3005AB5DA, + 1865F93F06253BA3005AB5DA, + 1865F94006253BA3005AB5DA, + 1865F94106253BA3005AB5DA, + 1865F94206253BA3005AB5DA, + 1865F94306253BA3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F93506253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93606253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bytebool.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93706253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93806253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93906253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl_to_qgl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93A06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeglib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93B06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93C06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93D06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93E06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "multimon.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F93F06253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F94006253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F94106253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant_jpeglib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F94206253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "str.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F94306253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F94406253BA3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F94506253BA4005AB5DA = { + children = ( + 1865F94606253BA4005AB5DA, + 1865F94706253BA4005AB5DA, + 1865F94806253BA4005AB5DA, + 1865F94906253BA4005AB5DA, + 1865F94A06253BA4005AB5DA, + 1865F94B06253BA4005AB5DA, + 1865F94C06253BA4005AB5DA, + 1865F94D06253BA4005AB5DA, + 1865F94E06253BA4005AB5DA, + 1865F94F06253BA4005AB5DA, + 1865F95006253BA4005AB5DA, + 1865F95106253BA4005AB5DA, + 1865F95206253BA4005AB5DA, + 1865F95306253BA4005AB5DA, + 1865F95406253BA4005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94606253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94706253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bytebool.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94806253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94906253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94A06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl_to_qgl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94B06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeglib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94C06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94D06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94E06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F94F06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "multimon.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95006253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95106253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95206253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant_jpeglib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95306253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "str.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95406253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95506253BA4005AB5DA = { + children = ( + 1865F95606253BA4005AB5DA, + 1865F95706253BA4005AB5DA, + 1865F95806253BA4005AB5DA, + 1865F95906253BA4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F95606253BA4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95706253BA4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F95806253BA4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F95906253BA4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F95A06253BA4005AB5DA = { + children = ( + 1865F95B06253BA4005AB5DA, + 1865F95C06253BA4005AB5DA, + 1865F95D06253BA4005AB5DA, + 1865F95E06253BA4005AB5DA, + 1865F95F06253BA4005AB5DA, + 1865F96006253BA4005AB5DA, + 1865F96106253BA4005AB5DA, + 1865F96206253BA4005AB5DA, + 1865F96306253BA4005AB5DA, + 1865F96406253BA4005AB5DA, + 1865F96506253BA4005AB5DA, + 1865F96606253BA5005AB5DA, + 1865F96706253BA5005AB5DA, + 1865F96806253BA5005AB5DA, + 1865F96906253BA5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F95B06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F95C06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bytebool.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F95D06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F95E06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F95F06253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "igl_to_qgl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96006253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeglib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96106253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96206253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96306253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "missing.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96406253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "multimon.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96506253BA4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96606253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96706253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "radiant_jpeglib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96806253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "str.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96906253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F96A06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bytebool.h; + refType = 4; + sourceTree = ""; + }; + 1865F96B06253BA5005AB5DA = { + children = ( + 1865F96C06253BA5005AB5DA, + 1865F96D06253BA5005AB5DA, + 1865F96E06253BA5005AB5DA, + 1865F98D06253BA6005AB5DA, + 1865F98E06253BA6005AB5DA, + ); + isa = PBXGroup; + path = cmdlib; + refType = 4; + sourceTree = ""; + }; + 1865F96C06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865F96D06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvswrappers; + refType = 4; + sourceTree = ""; + }; + 1865F96E06253BA5005AB5DA = { + children = ( + 1865F96F06253BA5005AB5DA, + 1865F97006253BA5005AB5DA, + 1865F97106253BA5005AB5DA, + 1865F97206253BA5005AB5DA, + 1865F97306253BA5005AB5DA, + 1865F97806253BA5005AB5DA, + 1865F97D06253BA5005AB5DA, + 1865F97E06253BA5005AB5DA, + 1865F98306253BA5005AB5DA, + 1865F98806253BA6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F96F06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F97006253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F97106253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F97206253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F97306253BA5005AB5DA = { + children = ( + 1865F97406253BA5005AB5DA, + 1865F97506253BA5005AB5DA, + 1865F97606253BA5005AB5DA, + 1865F97706253BA5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F97406253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F97506253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F97606253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F97706253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F97806253BA5005AB5DA = { + children = ( + 1865F97906253BA5005AB5DA, + 1865F97A06253BA5005AB5DA, + 1865F97B06253BA5005AB5DA, + 1865F97C06253BA5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F97906253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F97A06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F97B06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F97C06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F97D06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F97E06253BA5005AB5DA = { + children = ( + 1865F97F06253BA5005AB5DA, + 1865F98006253BA5005AB5DA, + 1865F98106253BA5005AB5DA, + 1865F98206253BA5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F97F06253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F98006253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F98106253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F98206253BA5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "cmdlib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F98306253BA5005AB5DA = { + children = ( + 1865F98406253BA5005AB5DA, + 1865F98506253BA5005AB5DA, + 1865F98606253BA5005AB5DA, + 1865F98706253BA5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F98406253BA5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F98506253BA5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F98606253BA5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F98706253BA5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F98806253BA6005AB5DA = { + children = ( + 1865F98906253BA6005AB5DA, + 1865F98A06253BA6005AB5DA, + 1865F98B06253BA6005AB5DA, + 1865F98C06253BA6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F98906253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F98A06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F98B06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F98C06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cmdlib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F98D06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = cmdlib.cpp; + refType = 4; + sourceTree = ""; + }; + 1865F98E06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = cmdlib.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865F98F06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = cmdlib.h; + refType = 4; + sourceTree = ""; + }; + 1865F99006253BA6005AB5DA = { + children = ( + 1865F99106253BA6005AB5DA, + 1865F9A806253BA6005AB5DA, + 1865F9A906253BA7005AB5DA, + ); + isa = PBXGroup; + path = ddslib; + refType = 4; + sourceTree = ""; + }; + 1865F99106253BA6005AB5DA = { + children = ( + 1865F99206253BA6005AB5DA, + 1865F99306253BA6005AB5DA, + 1865F99406253BA6005AB5DA, + 1865F99506253BA6005AB5DA, + 1865F99606253BA6005AB5DA, + 1865F99906253BA6005AB5DA, + 1865F99C06253BA6005AB5DA, + 1865F99D06253BA6005AB5DA, + 1865F9A006253BA6005AB5DA, + 1865F9A506253BA6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F99206253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F99306253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F99406253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F99506253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F99606253BA6005AB5DA = { + children = ( + 1865F99706253BA6005AB5DA, + 1865F99806253BA6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F99706253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F99806253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F99906253BA6005AB5DA = { + children = ( + 1865F99A06253BA6005AB5DA, + 1865F99B06253BA6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F99A06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F99B06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F99C06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F99D06253BA6005AB5DA = { + children = ( + 1865F99E06253BA6005AB5DA, + 1865F99F06253BA6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F99E06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F99F06253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "ddslib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9A006253BA6005AB5DA = { + children = ( + 1865F9A106253BA6005AB5DA, + 1865F9A206253BA6005AB5DA, + 1865F9A306253BA6005AB5DA, + 1865F9A406253BA6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865F9A106253BA6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9A206253BA6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F9A306253BA6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9A406253BA6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F9A506253BA6005AB5DA = { + children = ( + 1865F9A606253BA6005AB5DA, + 1865F9A706253BA6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865F9A606253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9A706253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ddslib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9A806253BA6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = ddslib.c; + refType = 4; + sourceTree = ""; + }; + 1865F9A906253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = ddslib.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865F9AA06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = ddslib.h; + refType = 4; + sourceTree = ""; + }; + 1865F9AB06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = igl_to_qgl.h; + refType = 4; + sourceTree = ""; + }; + 1865F9AC06253BA7005AB5DA = { + children = ( + 1865F9AD06253BA7005AB5DA, + 1865F9AE06253BA7005AB5DA, + 1865F9AF06253BA7005AB5DA, + 1865FA4A06253BA9005AB5DA, + 1865FA4B06253BA9005AB5DA, + 1865FA4C06253BA9005AB5DA, + 1865FA4D06253BA9005AB5DA, + 1865FA4E06253BA9005AB5DA, + 1865FA4F06253BA9005AB5DA, + 1865FA5006253BA9005AB5DA, + 1865FA5106253BA9005AB5DA, + 1865FA5206253BA9005AB5DA, + 1865FA5306253BA9005AB5DA, + 1865FA5406253BA9005AB5DA, + 1865FA5506253BA9005AB5DA, + 1865FA5606253BA9005AB5DA, + 1865FA5706253BA9005AB5DA, + 1865FA5806253BA9005AB5DA, + 1865FA5906253BA9005AB5DA, + 1865FA5A06253BA9005AB5DA, + 1865FA5B06253BA9005AB5DA, + 1865FA5C06253BA9005AB5DA, + 1865FA5D06253BA9005AB5DA, + 1865FA5E06253BA9005AB5DA, + 1865FA5F06253BA9005AB5DA, + 1865FA6006253BA9005AB5DA, + 1865FA6106253BA9005AB5DA, + 1865FA6206253BA9005AB5DA, + 1865FA6306253BA9005AB5DA, + 1865FA6406253BA9005AB5DA, + 1865FA6506253BA9005AB5DA, + 1865FA6606253BA9005AB5DA, + 1865FA6706253BA9005AB5DA, + 1865FA6806253BA9005AB5DA, + 1865FA6906253BA9005AB5DA, + 1865FA6A06253BA9005AB5DA, + ); + isa = PBXGroup; + path = jpeg6; + refType = 4; + sourceTree = ""; + }; + 1865F9AD06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865F9AE06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvswrappers; + refType = 4; + sourceTree = ""; + }; + 1865F9AF06253BA7005AB5DA = { + children = ( + 1865F9B006253BA7005AB5DA, + 1865F9B106253BA7005AB5DA, + 1865F9B206253BA7005AB5DA, + 1865F9B306253BA7005AB5DA, + 1865F9B406253BA7005AB5DA, + 1865F9D806253BA8005AB5DA, + 1865F9FC06253BA8005AB5DA, + 1865F9FD06253BA8005AB5DA, + 1865FA2106253BA9005AB5DA, + 1865FA2606253BA9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865F9B006253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865F9B106253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865F9B206253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865F9B306253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865F9B406253BA7005AB5DA = { + children = ( + 1865F9B506253BA7005AB5DA, + 1865F9B606253BA7005AB5DA, + 1865F9B706253BA7005AB5DA, + 1865F9B806253BA7005AB5DA, + 1865F9B906253BA7005AB5DA, + 1865F9BA06253BA7005AB5DA, + 1865F9BB06253BA7005AB5DA, + 1865F9BC06253BA7005AB5DA, + 1865F9BD06253BA7005AB5DA, + 1865F9BE06253BA7005AB5DA, + 1865F9BF06253BA7005AB5DA, + 1865F9C006253BA7005AB5DA, + 1865F9C106253BA7005AB5DA, + 1865F9C206253BA7005AB5DA, + 1865F9C306253BA7005AB5DA, + 1865F9C406253BA7005AB5DA, + 1865F9C506253BA7005AB5DA, + 1865F9C606253BA7005AB5DA, + 1865F9C706253BA7005AB5DA, + 1865F9C806253BA7005AB5DA, + 1865F9C906253BA8005AB5DA, + 1865F9CA06253BA8005AB5DA, + 1865F9CB06253BA8005AB5DA, + 1865F9CC06253BA8005AB5DA, + 1865F9CD06253BA8005AB5DA, + 1865F9CE06253BA8005AB5DA, + 1865F9CF06253BA8005AB5DA, + 1865F9D006253BA8005AB5DA, + 1865F9D106253BA8005AB5DA, + 1865F9D206253BA8005AB5DA, + 1865F9D306253BA8005AB5DA, + 1865F9D406253BA8005AB5DA, + 1865F9D506253BA8005AB5DA, + 1865F9D606253BA8005AB5DA, + 1865F9D706253BA8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9B506253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9B606253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9B706253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jchuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9B806253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jcomapi.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9B906253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jconfig.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9BA06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapimin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9BB06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapistd.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9BC06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdatasrc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9BD06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcoefct.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9BE06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcolor.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9BF06253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdct.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C006253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jddctmgr.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C106253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C206253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C306253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdinput.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C406253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmainct.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C506253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmarker.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C606253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmaster.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C706253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdpostct.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C806253BA7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdsample.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9C906253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdtrans.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9CA06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9CB06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9CC06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jfdctflt.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9CD06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jidctflt.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9CE06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jinclude.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9CF06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemmgr.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D006253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemnobs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D106253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemsys.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D206253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmorecfg.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D306253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D406253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpegint.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D506253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpgload.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D606253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jutils.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D706253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jversion.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9D806253BA8005AB5DA = { + children = ( + 1865F9D906253BA8005AB5DA, + 1865F9DA06253BA8005AB5DA, + 1865F9DB06253BA8005AB5DA, + 1865F9DC06253BA8005AB5DA, + 1865F9DD06253BA8005AB5DA, + 1865F9DE06253BA8005AB5DA, + 1865F9DF06253BA8005AB5DA, + 1865F9E006253BA8005AB5DA, + 1865F9E106253BA8005AB5DA, + 1865F9E206253BA8005AB5DA, + 1865F9E306253BA8005AB5DA, + 1865F9E406253BA8005AB5DA, + 1865F9E506253BA8005AB5DA, + 1865F9E606253BA8005AB5DA, + 1865F9E706253BA8005AB5DA, + 1865F9E806253BA8005AB5DA, + 1865F9E906253BA8005AB5DA, + 1865F9EA06253BA8005AB5DA, + 1865F9EB06253BA8005AB5DA, + 1865F9EC06253BA8005AB5DA, + 1865F9ED06253BA8005AB5DA, + 1865F9EE06253BA8005AB5DA, + 1865F9EF06253BA8005AB5DA, + 1865F9F006253BA8005AB5DA, + 1865F9F106253BA8005AB5DA, + 1865F9F206253BA8005AB5DA, + 1865F9F306253BA8005AB5DA, + 1865F9F406253BA8005AB5DA, + 1865F9F506253BA8005AB5DA, + 1865F9F606253BA8005AB5DA, + 1865F9F706253BA8005AB5DA, + 1865F9F806253BA8005AB5DA, + 1865F9F906253BA8005AB5DA, + 1865F9FA06253BA8005AB5DA, + 1865F9FB06253BA8005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865F9D906253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9DA06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9DB06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jchuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9DC06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jcomapi.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9DD06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jconfig.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9DE06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapimin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9DF06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapistd.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E006253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdatasrc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E106253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcoefct.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E206253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcolor.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E306253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdct.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E406253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jddctmgr.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E506253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E606253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E706253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdinput.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E806253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmainct.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9E906253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmarker.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9EA06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmaster.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9EB06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdpostct.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9EC06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdsample.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9ED06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdtrans.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9EE06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9EF06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F006253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jfdctflt.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F106253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jidctflt.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F206253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jinclude.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F306253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemmgr.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F406253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemnobs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F506253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemsys.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F606253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmorecfg.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F706253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F806253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpegint.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9F906253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpgload.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9FA06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jutils.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9FB06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jversion.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865F9FC06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865F9FD06253BA8005AB5DA = { + children = ( + 1865F9FE06253BA8005AB5DA, + 1865F9FF06253BA8005AB5DA, + 1865FA0006253BA8005AB5DA, + 1865FA0106253BA8005AB5DA, + 1865FA0206253BA8005AB5DA, + 1865FA0306253BA8005AB5DA, + 1865FA0406253BA8005AB5DA, + 1865FA0506253BA8005AB5DA, + 1865FA0606253BA8005AB5DA, + 1865FA0706253BA8005AB5DA, + 1865FA0806253BA8005AB5DA, + 1865FA0906253BA8005AB5DA, + 1865FA0A06253BA8005AB5DA, + 1865FA0B06253BA8005AB5DA, + 1865FA0C06253BA8005AB5DA, + 1865FA0D06253BA8005AB5DA, + 1865FA0E06253BA8005AB5DA, + 1865FA0F06253BA8005AB5DA, + 1865FA1006253BA8005AB5DA, + 1865FA1106253BA8005AB5DA, + 1865FA1206253BA8005AB5DA, + 1865FA1306253BA8005AB5DA, + 1865FA1406253BA8005AB5DA, + 1865FA1506253BA8005AB5DA, + 1865FA1606253BA8005AB5DA, + 1865FA1706253BA8005AB5DA, + 1865FA1806253BA8005AB5DA, + 1865FA1906253BA8005AB5DA, + 1865FA1A06253BA8005AB5DA, + 1865FA1B06253BA8005AB5DA, + 1865FA1C06253BA8005AB5DA, + 1865FA1D06253BA8005AB5DA, + 1865FA1E06253BA9005AB5DA, + 1865FA1F06253BA9005AB5DA, + 1865FA2006253BA9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9FE06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865F9FF06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0006253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jchuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0106253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jcomapi.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0206253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jconfig.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0306253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapimin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0406253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapistd.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0506253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdatasrc.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0606253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcoefct.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0706253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcolor.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0806253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdct.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0906253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jddctmgr.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0A06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0B06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0C06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdinput.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0D06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmainct.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0E06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmarker.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA0F06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmaster.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1006253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdpostct.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1106253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdsample.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1206253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdtrans.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1306253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1406253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1506253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jfdctflt.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1606253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jidctflt.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1706253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jinclude.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1806253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemmgr.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1906253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemnobs.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1A06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemsys.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1B06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmorecfg.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1C06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "jpeg6.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1D06253BA8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpegint.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpgload.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA1F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jutils.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA2006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jversion.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA2106253BA9005AB5DA = { + children = ( + 1865FA2206253BA9005AB5DA, + 1865FA2306253BA9005AB5DA, + 1865FA2406253BA9005AB5DA, + 1865FA2506253BA9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FA2206253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA2306253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FA2406253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA2506253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FA2606253BA9005AB5DA = { + children = ( + 1865FA2706253BA9005AB5DA, + 1865FA2806253BA9005AB5DA, + 1865FA2906253BA9005AB5DA, + 1865FA2A06253BA9005AB5DA, + 1865FA2B06253BA9005AB5DA, + 1865FA2C06253BA9005AB5DA, + 1865FA2D06253BA9005AB5DA, + 1865FA2E06253BA9005AB5DA, + 1865FA2F06253BA9005AB5DA, + 1865FA3006253BA9005AB5DA, + 1865FA3106253BA9005AB5DA, + 1865FA3206253BA9005AB5DA, + 1865FA3306253BA9005AB5DA, + 1865FA3406253BA9005AB5DA, + 1865FA3506253BA9005AB5DA, + 1865FA3606253BA9005AB5DA, + 1865FA3706253BA9005AB5DA, + 1865FA3806253BA9005AB5DA, + 1865FA3906253BA9005AB5DA, + 1865FA3A06253BA9005AB5DA, + 1865FA3B06253BA9005AB5DA, + 1865FA3C06253BA9005AB5DA, + 1865FA3D06253BA9005AB5DA, + 1865FA3E06253BA9005AB5DA, + 1865FA3F06253BA9005AB5DA, + 1865FA4006253BA9005AB5DA, + 1865FA4106253BA9005AB5DA, + 1865FA4206253BA9005AB5DA, + 1865FA4306253BA9005AB5DA, + 1865FA4406253BA9005AB5DA, + 1865FA4506253BA9005AB5DA, + 1865FA4606253BA9005AB5DA, + 1865FA4706253BA9005AB5DA, + 1865FA4806253BA9005AB5DA, + 1865FA4906253BA9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FA2706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jchuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jcomapi.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jconfig.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2C06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapimin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdapistd.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdatasrc.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA2F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcoefct.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdcolor.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3106253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdct.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jddctmgr.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3306253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3406253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdhuff.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdinput.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmainct.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmarker.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdmaster.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdpostct.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdsample.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jdtrans.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3C06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jerror.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jfdctflt.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA3F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jidctflt.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jinclude.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4106253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemmgr.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemnobs.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4306253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmemsys.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4406253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jmorecfg.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg6.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpegint.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpgload.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jutils.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jversion.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA4A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jchuff.h; + refType = 4; + sourceTree = ""; + }; + 1865FA4B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jcomapi.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA4C06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jconfig.h; + refType = 4; + sourceTree = ""; + }; + 1865FA4D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdapimin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA4E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdapistd.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA4F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdatasrc.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdcoefct.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5106253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdcolor.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jdct.h; + refType = 4; + sourceTree = ""; + }; + 1865FA5306253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jddctmgr.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5406253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdhuff.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jdhuff.h; + refType = 4; + sourceTree = ""; + }; + 1865FA5606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdinput.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdmainct.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdmarker.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdmaster.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdpostct.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdsample.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5C06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jdtrans.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jerror.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA5E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jerror.h; + refType = 4; + sourceTree = ""; + }; + 1865FA5F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jfdctflt.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA6006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jidctflt.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA6106253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jinclude.h; + refType = 4; + sourceTree = ""; + }; + 1865FA6206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jmemmgr.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA6306253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jmemnobs.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA6406253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jmemsys.h; + refType = 4; + sourceTree = ""; + }; + 1865FA6506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jmorecfg.h; + refType = 4; + sourceTree = ""; + }; + 1865FA6606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = jpeg6.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FA6706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jpegint.h; + refType = 4; + sourceTree = ""; + }; + 1865FA6806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jpgload.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA6906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jutils.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FA6A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jversion.h; + refType = 4; + sourceTree = ""; + }; + 1865FA6B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = jpeglib.h; + refType = 4; + sourceTree = ""; + }; + 1865FA6C06253BA9005AB5DA = { + children = ( + 1865FA6D06253BA9005AB5DA, + 1865FA6E06253BA9005AB5DA, + 1865FA9906253BA9005AB5DA, + 1865FA9A06253BA9005AB5DA, + 1865FA9B06253BA9005AB5DA, + 1865FA9C06253BA9005AB5DA, + 1865FA9D06253BA9005AB5DA, + 1865FA9E06253BA9005AB5DA, + ); + isa = PBXGroup; + path = l_net; + refType = 4; + sourceTree = ""; + }; + 1865FA6D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865FA6E06253BA9005AB5DA = { + children = ( + 1865FA6F06253BA9005AB5DA, + 1865FA7006253BA9005AB5DA, + 1865FA7106253BA9005AB5DA, + 1865FA7206253BA9005AB5DA, + 1865FA7306253BA9005AB5DA, + 1865FA7B06253BA9005AB5DA, + 1865FA8306253BA9005AB5DA, + 1865FA8406253BA9005AB5DA, + 1865FA8C06253BA9005AB5DA, + 1865FA9106253BA9005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FA6F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FA7006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FA7106253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FA7206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FA7306253BA9005AB5DA = { + children = ( + 1865FA7406253BA9005AB5DA, + 1865FA7506253BA9005AB5DA, + 1865FA7606253BA9005AB5DA, + 1865FA7706253BA9005AB5DA, + 1865FA7806253BA9005AB5DA, + 1865FA7906253BA9005AB5DA, + 1865FA7A06253BA9005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7406253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_berkley.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA7B06253BA9005AB5DA = { + children = ( + 1865FA7C06253BA9005AB5DA, + 1865FA7D06253BA9005AB5DA, + 1865FA7E06253BA9005AB5DA, + 1865FA7F06253BA9005AB5DA, + 1865FA8006253BA9005AB5DA, + 1865FA8106253BA9005AB5DA, + 1865FA8206253BA9005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FA7C06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA7D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA7E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA7F06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA8006253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_berkley.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA8106253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA8206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA8306253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FA8406253BA9005AB5DA = { + children = ( + 1865FA8506253BA9005AB5DA, + 1865FA8606253BA9005AB5DA, + 1865FA8706253BA9005AB5DA, + 1865FA8806253BA9005AB5DA, + 1865FA8906253BA9005AB5DA, + 1865FA8A06253BA9005AB5DA, + 1865FA8B06253BA9005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "l_net.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_berkley.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8C06253BA9005AB5DA = { + children = ( + 1865FA8D06253BA9005AB5DA, + 1865FA8E06253BA9005AB5DA, + 1865FA8F06253BA9005AB5DA, + 1865FA9006253BA9005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FA8D06253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA8E06253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FA8F06253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FA9006253BA9005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FA9106253BA9005AB5DA = { + children = ( + 1865FA9206253BA9005AB5DA, + 1865FA9306253BA9005AB5DA, + 1865FA9406253BA9005AB5DA, + 1865FA9506253BA9005AB5DA, + 1865FA9606253BA9005AB5DA, + 1865FA9706253BA9005AB5DA, + 1865FA9806253BA9005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FA9206253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9306253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9406253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9506253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9606253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_berkley.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9706253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9806253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "l_net_wins.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FA9906253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = l_net.c; + refType = 4; + sourceTree = ""; + }; + 1865FA9A06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = l_net.h; + refType = 4; + sourceTree = ""; + }; + 1865FA9B06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = l_net.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FA9C06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = l_net_berkley.c; + refType = 4; + sourceTree = ""; + }; + 1865FA9D06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = l_net_wins.c; + refType = 4; + sourceTree = ""; + }; + 1865FA9E06253BA9005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = l_net_wins.h; + refType = 4; + sourceTree = ""; + }; + 1865FA9F06253BA9005AB5DA = { + children = ( + 1865FAA006253BA9005AB5DA, + 1865FAAF06253BAA005AB5DA, + 1865FABF06253BAA005AB5DA, + 1865FACF06253BAA005AB5DA, + 1865FADF06253BAA005AB5DA, + ); + isa = PBXGroup; + path = libxml2; + refType = 4; + sourceTree = ""; + }; + 1865FAA006253BA9005AB5DA = { + children = ( + 1865FAA106253BAA005AB5DA, + 1865FAA206253BAA005AB5DA, + 1865FAA306253BAA005AB5DA, + 1865FAA406253BAA005AB5DA, + 1865FAA506253BAA005AB5DA, + 1865FAA606253BAA005AB5DA, + 1865FAA706253BAA005AB5DA, + 1865FAA806253BAA005AB5DA, + 1865FAA906253BAA005AB5DA, + 1865FAAE06253BAA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FAA106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FAA206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FAA306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FAA406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FAA506253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAA606253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAA706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FAA806253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAA906253BAA005AB5DA = { + children = ( + 1865FAAA06253BAA005AB5DA, + 1865FAAB06253BAA005AB5DA, + 1865FAAC06253BAA005AB5DA, + 1865FAAD06253BAA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FAAA06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAAB06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAAC06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAAD06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FAAE06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FAAF06253BAA005AB5DA = { + children = ( + 1865FAB006253BAA005AB5DA, + ); + isa = PBXGroup; + path = doc; + refType = 4; + sourceTree = ""; + }; + 1865FAB006253BAA005AB5DA = { + children = ( + 1865FAB106253BAA005AB5DA, + 1865FAB206253BAA005AB5DA, + 1865FAB306253BAA005AB5DA, + 1865FAB406253BAA005AB5DA, + 1865FAB506253BAA005AB5DA, + 1865FAB606253BAA005AB5DA, + 1865FAB706253BAA005AB5DA, + 1865FAB806253BAA005AB5DA, + 1865FAB906253BAA005AB5DA, + 1865FABE06253BAA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FAB106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FAB206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FAB306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FAB406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FAB506253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAB606253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAB706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FAB806253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAB906253BAA005AB5DA = { + children = ( + 1865FABA06253BAA005AB5DA, + 1865FABB06253BAA005AB5DA, + 1865FABC06253BAA005AB5DA, + 1865FABD06253BAA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FABA06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FABB06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FABC06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FABD06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FABE06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FABF06253BAA005AB5DA = { + children = ( + 1865FAC006253BAA005AB5DA, + ); + isa = PBXGroup; + path = example; + refType = 4; + sourceTree = ""; + }; + 1865FAC006253BAA005AB5DA = { + children = ( + 1865FAC106253BAA005AB5DA, + 1865FAC206253BAA005AB5DA, + 1865FAC306253BAA005AB5DA, + 1865FAC406253BAA005AB5DA, + 1865FAC506253BAA005AB5DA, + 1865FAC606253BAA005AB5DA, + 1865FAC706253BAA005AB5DA, + 1865FAC806253BAA005AB5DA, + 1865FAC906253BAA005AB5DA, + 1865FACE06253BAA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FAC106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FAC206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FAC306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FAC406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FAC506253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAC606253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAC706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FAC806253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAC906253BAA005AB5DA = { + children = ( + 1865FACA06253BAA005AB5DA, + 1865FACB06253BAA005AB5DA, + 1865FACC06253BAA005AB5DA, + 1865FACD06253BAA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FACA06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FACB06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FACC06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FACD06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FACE06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FACF06253BAA005AB5DA = { + children = ( + 1865FAD006253BAA005AB5DA, + ); + isa = PBXGroup; + path = libxml; + refType = 4; + sourceTree = ""; + }; + 1865FAD006253BAA005AB5DA = { + children = ( + 1865FAD106253BAA005AB5DA, + 1865FAD206253BAA005AB5DA, + 1865FAD306253BAA005AB5DA, + 1865FAD406253BAA005AB5DA, + 1865FAD506253BAA005AB5DA, + 1865FAD606253BAA005AB5DA, + 1865FAD706253BAA005AB5DA, + 1865FAD806253BAA005AB5DA, + 1865FAD906253BAA005AB5DA, + 1865FADE06253BAA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FAD106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FAD206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FAD306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FAD406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FAD506253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAD606253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAD706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FAD806253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAD906253BAA005AB5DA = { + children = ( + 1865FADA06253BAA005AB5DA, + 1865FADB06253BAA005AB5DA, + 1865FADC06253BAA005AB5DA, + 1865FADD06253BAA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FADA06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FADB06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FADC06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FADD06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FADE06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FADF06253BAA005AB5DA = { + children = ( + 1865FAE006253BAA005AB5DA, + ); + isa = PBXGroup; + path = MSDev; + refType = 4; + sourceTree = ""; + }; + 1865FAE006253BAA005AB5DA = { + children = ( + 1865FAE106253BAA005AB5DA, + 1865FAE206253BAA005AB5DA, + 1865FAE306253BAA005AB5DA, + 1865FAE406253BAA005AB5DA, + 1865FAE506253BAA005AB5DA, + 1865FAE606253BAA005AB5DA, + 1865FAE706253BAA005AB5DA, + 1865FAE806253BAA005AB5DA, + 1865FAE906253BAA005AB5DA, + 1865FAEE06253BAA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FAE106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FAE206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FAE306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FAE406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FAE506253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAE606253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAE706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FAE806253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAE906253BAA005AB5DA = { + children = ( + 1865FAEA06253BAA005AB5DA, + 1865FAEB06253BAA005AB5DA, + 1865FAEC06253BAA005AB5DA, + 1865FAED06253BAA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FAEA06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAEB06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAEC06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAED06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FAEE06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FAEF06253BAA005AB5DA = { + children = ( + 1865FAF006253BAA005AB5DA, + 1865FB1706253BAA005AB5DA, + 1865FB1806253BAA005AB5DA, + 1865FB1906253BAA005AB5DA, + 1865FB1A06253BAA005AB5DA, + 1865FB1B06253BAA005AB5DA, + 1865FB1C06253BAA005AB5DA, + ); + isa = PBXGroup; + path = mathlib; + refType = 4; + sourceTree = ""; + }; + 1865FAF006253BAA005AB5DA = { + children = ( + 1865FAF106253BAA005AB5DA, + 1865FAF206253BAA005AB5DA, + 1865FAF306253BAA005AB5DA, + 1865FAF406253BAA005AB5DA, + 1865FAF506253BAA005AB5DA, + 1865FAFC06253BAA005AB5DA, + 1865FB0306253BAA005AB5DA, + 1865FB0406253BAA005AB5DA, + 1865FB0B06253BAA005AB5DA, + 1865FB1006253BAA005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FAF106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FAF206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FAF306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FAF406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FAF506253BAA005AB5DA = { + children = ( + 1865FAF606253BAA005AB5DA, + 1865FAF706253BAA005AB5DA, + 1865FAF806253BAA005AB5DA, + 1865FAF906253BAA005AB5DA, + 1865FAFA06253BAA005AB5DA, + 1865FAFB06253BAA005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAF606253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bbox.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAF706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "linear.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAF806253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m4x4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAF906253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAFA06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAFB06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ray.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FAFC06253BAA005AB5DA = { + children = ( + 1865FAFD06253BAA005AB5DA, + 1865FAFE06253BAA005AB5DA, + 1865FAFF06253BAA005AB5DA, + 1865FB0006253BAA005AB5DA, + 1865FB0106253BAA005AB5DA, + 1865FB0206253BAA005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FAFD06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bbox.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FAFE06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "linear.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FAFF06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m4x4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB0006253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB0106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB0206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ray.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB0306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FB0406253BAA005AB5DA = { + children = ( + 1865FB0506253BAA005AB5DA, + 1865FB0606253BAA005AB5DA, + 1865FB0706253BAA005AB5DA, + 1865FB0806253BAA005AB5DA, + 1865FB0906253BAA005AB5DA, + 1865FB0A06253BAA005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0506253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bbox.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0606253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "linear.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m4x4.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0806253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0906253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "mathlib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0A06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ray.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0B06253BAA005AB5DA = { + children = ( + 1865FB0C06253BAA005AB5DA, + 1865FB0D06253BAA005AB5DA, + 1865FB0E06253BAA005AB5DA, + 1865FB0F06253BAA005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FB0C06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0D06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FB0E06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB0F06253BAA005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FB1006253BAA005AB5DA = { + children = ( + 1865FB1106253BAA005AB5DA, + 1865FB1206253BAA005AB5DA, + 1865FB1306253BAA005AB5DA, + 1865FB1406253BAA005AB5DA, + 1865FB1506253BAA005AB5DA, + 1865FB1606253BAA005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FB1106253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bbox.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB1206253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "linear.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB1306253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m4x4.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB1406253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB1506253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mathlib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB1606253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "ray.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB1706253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = bbox.c; + refType = 4; + sourceTree = ""; + }; + 1865FB1806253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = linear.c; + refType = 4; + sourceTree = ""; + }; + 1865FB1906253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = m4x4.c; + refType = 4; + sourceTree = ""; + }; + 1865FB1A06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = mathlib.c; + refType = 4; + sourceTree = ""; + }; + 1865FB1B06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = mathlib.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FB1C06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = ray.c; + refType = 4; + sourceTree = ""; + }; + 1865FB1D06253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = mathlib.h; + refType = 4; + sourceTree = ""; + }; + 1865FB1E06253BAA005AB5DA = { + children = ( + 1865FB1F06253BAA005AB5DA, + 1865FB3A06253BAB005AB5DA, + 1865FB3B06253BAB005AB5DA, + 1865FB3C06253BAB005AB5DA, + ); + isa = PBXGroup; + path = md5lib; + refType = 4; + sourceTree = ""; + }; + 1865FB1F06253BAA005AB5DA = { + children = ( + 1865FB2006253BAA005AB5DA, + 1865FB2106253BAB005AB5DA, + 1865FB2206253BAB005AB5DA, + 1865FB2306253BAB005AB5DA, + 1865FB2406253BAB005AB5DA, + 1865FB2806253BAB005AB5DA, + 1865FB2C06253BAB005AB5DA, + 1865FB2D06253BAB005AB5DA, + 1865FB3106253BAB005AB5DA, + 1865FB3606253BAB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FB2006253BAA005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FB2106253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FB2206253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FB2306253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FB2406253BAB005AB5DA = { + children = ( + 1865FB2506253BAB005AB5DA, + 1865FB2606253BAB005AB5DA, + 1865FB2706253BAB005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB2506253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Conscript.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB2606253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB2706253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB2806253BAB005AB5DA = { + children = ( + 1865FB2906253BAB005AB5DA, + 1865FB2A06253BAB005AB5DA, + 1865FB2B06253BAB005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FB2906253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Conscript.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB2A06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB2B06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB2C06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FB2D06253BAB005AB5DA = { + children = ( + 1865FB2E06253BAB005AB5DA, + 1865FB2F06253BAB005AB5DA, + 1865FB3006253BAB005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB2E06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Conscript.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB2F06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB3006253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "md5lib.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB3106253BAB005AB5DA = { + children = ( + 1865FB3206253BAB005AB5DA, + 1865FB3306253BAB005AB5DA, + 1865FB3406253BAB005AB5DA, + 1865FB3506253BAB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FB3206253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB3306253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FB3406253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB3506253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FB3606253BAB005AB5DA = { + children = ( + 1865FB3706253BAB005AB5DA, + 1865FB3806253BAB005AB5DA, + 1865FB3906253BAB005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FB3706253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Conscript.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB3806253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB3906253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "md5lib.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB3A06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = Conscript; + refType = 4; + sourceTree = ""; + }; + 1865FB3B06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = md5lib.c; + refType = 4; + sourceTree = ""; + }; + 1865FB3C06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = md5lib.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FB3D06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = md5lib.h; + refType = 4; + sourceTree = ""; + }; + 1865FB3E06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = missing.h; + refType = 4; + sourceTree = ""; + }; + 1865FB3F06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = multimon.h; + refType = 4; + sourceTree = ""; + }; + 1865FB4006253BAB005AB5DA = { + children = ( + 1865FB4106253BAB005AB5DA, + 1865FB4206253BAB005AB5DA, + 1865FB4306253BAB005AB5DA, + 1865FB6606253BAB005AB5DA, + 1865FB6706253BAB005AB5DA, + 1865FB6806253BAB005AB5DA, + ); + isa = PBXGroup; + path = pak; + refType = 4; + sourceTree = ""; + }; + 1865FB4106253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865FB4206253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvswrappers; + refType = 4; + sourceTree = ""; + }; + 1865FB4306253BAB005AB5DA = { + children = ( + 1865FB4406253BAB005AB5DA, + 1865FB4506253BAB005AB5DA, + 1865FB4606253BAB005AB5DA, + 1865FB4706253BAB005AB5DA, + 1865FB4806253BAB005AB5DA, + 1865FB4E06253BAB005AB5DA, + 1865FB5406253BAB005AB5DA, + 1865FB5506253BAB005AB5DA, + 1865FB5B06253BAB005AB5DA, + 1865FB6006253BAB005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FB4406253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FB4506253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FB4606253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FB4706253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FB4806253BAB005AB5DA = { + children = ( + 1865FB4906253BAB005AB5DA, + 1865FB4A06253BAB005AB5DA, + 1865FB4B06253BAB005AB5DA, + 1865FB4C06253BAB005AB5DA, + 1865FB4D06253BAB005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB4906253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB4A06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB4B06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB4C06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB4D06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB4E06253BAB005AB5DA = { + children = ( + 1865FB4F06253BAB005AB5DA, + 1865FB5006253BAB005AB5DA, + 1865FB5106253BAB005AB5DA, + 1865FB5206253BAB005AB5DA, + 1865FB5306253BAB005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FB4F06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB5006253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB5106253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB5206253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB5306253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB5406253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FB5506253BAB005AB5DA = { + children = ( + 1865FB5606253BAB005AB5DA, + 1865FB5706253BAB005AB5DA, + 1865FB5806253BAB005AB5DA, + 1865FB5906253BAB005AB5DA, + 1865FB5A06253BAB005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5606253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5706253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5806253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5906253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5A06253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5B06253BAB005AB5DA = { + children = ( + 1865FB5C06253BAB005AB5DA, + 1865FB5D06253BAB005AB5DA, + 1865FB5E06253BAB005AB5DA, + 1865FB5F06253BAB005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FB5C06253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5D06253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FB5E06253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB5F06253BAB005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FB6006253BAB005AB5DA = { + children = ( + 1865FB6106253BAB005AB5DA, + 1865FB6206253BAB005AB5DA, + 1865FB6306253BAB005AB5DA, + 1865FB6406253BAB005AB5DA, + 1865FB6506253BAB005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FB6106253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB6206253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvswrappers.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB6306253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pakstuff.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB6406253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB6506253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unzip.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB6606253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = pakstuff.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FB6706253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = unzip.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FB6806253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = unzip.h; + refType = 4; + sourceTree = ""; + }; + 1865FB6906253BAB005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = pakstuff.h; + refType = 4; + sourceTree = ""; + }; + 1865FB6A06253BAB005AB5DA = { + children = ( + 1865FB6B06253BAB005AB5DA, + 1865FBB606253BAC005AB5DA, + 1865FBFD06253BAD005AB5DA, + 1865FBFE06253BAD005AB5DA, + 1865FBFF06253BAD005AB5DA, + 1865FC0006253BAD005AB5DA, + 1865FC0106253BAD005AB5DA, + 1865FC0206253BAD005AB5DA, + 1865FC0306253BAD005AB5DA, + 1865FC0406253BAD005AB5DA, + 1865FC0506253BAD005AB5DA, + 1865FC0606253BAD005AB5DA, + 1865FC0706253BAD005AB5DA, + 1865FC0806253BAD005AB5DA, + 1865FC0906253BAD005AB5DA, + 1865FC0A06253BAD005AB5DA, + 1865FC0B06253BAD005AB5DA, + ); + isa = PBXGroup; + path = picomodel; + refType = 4; + sourceTree = ""; + }; + 1865FB6B06253BAB005AB5DA = { + children = ( + 1865FB6C06253BAC005AB5DA, + 1865FB6D06253BAC005AB5DA, + 1865FB6E06253BAC005AB5DA, + 1865FB6F06253BAC005AB5DA, + 1865FB7006253BAC005AB5DA, + 1865FB8006253BAC005AB5DA, + 1865FB9006253BAC005AB5DA, + 1865FB9106253BAC005AB5DA, + 1865FBA106253BAC005AB5DA, + 1865FBA606253BAC005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FB6C06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FB6D06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FB6E06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FB6F06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FB7006253BAC005AB5DA = { + children = ( + 1865FB7106253BAC005AB5DA, + 1865FB7206253BAC005AB5DA, + 1865FB7306253BAC005AB5DA, + 1865FB7406253BAC005AB5DA, + 1865FB7506253BAC005AB5DA, + 1865FB7606253BAC005AB5DA, + 1865FB7706253BAC005AB5DA, + 1865FB7806253BAC005AB5DA, + 1865FB7906253BAC005AB5DA, + 1865FB7A06253BAC005AB5DA, + 1865FB7B06253BAC005AB5DA, + 1865FB7C06253BAC005AB5DA, + 1865FB7D06253BAC005AB5DA, + 1865FB7E06253BAC005AB5DA, + 1865FB7F06253BAC005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7106253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7206253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7306253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7406253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7506253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodules.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7606253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_3ds.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7706253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ase.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7806253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7A06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_lwo.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7B06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md2.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7C06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md3.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7D06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_mdc.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7E06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ms3d.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB7F06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_obj.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB8006253BAC005AB5DA = { + children = ( + 1865FB8106253BAC005AB5DA, + 1865FB8206253BAC005AB5DA, + 1865FB8306253BAC005AB5DA, + 1865FB8406253BAC005AB5DA, + 1865FB8506253BAC005AB5DA, + 1865FB8606253BAC005AB5DA, + 1865FB8706253BAC005AB5DA, + 1865FB8806253BAC005AB5DA, + 1865FB8906253BAC005AB5DA, + 1865FB8A06253BAC005AB5DA, + 1865FB8B06253BAC005AB5DA, + 1865FB8C06253BAC005AB5DA, + 1865FB8D06253BAC005AB5DA, + 1865FB8E06253BAC005AB5DA, + 1865FB8F06253BAC005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FB8106253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8206253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8306253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8406253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8506253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodules.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8606253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_3ds.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8706253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ase.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8806253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8A06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_lwo.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8B06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md2.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8C06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md3.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8D06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_mdc.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8E06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ms3d.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB8F06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_obj.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FB9006253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FB9106253BAC005AB5DA = { + children = ( + 1865FB9206253BAC005AB5DA, + 1865FB9306253BAC005AB5DA, + 1865FB9406253BAC005AB5DA, + 1865FB9506253BAC005AB5DA, + 1865FB9606253BAC005AB5DA, + 1865FB9706253BAC005AB5DA, + 1865FB9806253BAC005AB5DA, + 1865FB9906253BAC005AB5DA, + 1865FB9A06253BAC005AB5DA, + 1865FB9B06253BAC005AB5DA, + 1865FB9C06253BAC005AB5DA, + 1865FB9D06253BAC005AB5DA, + 1865FB9E06253BAC005AB5DA, + 1865FB9F06253BAC005AB5DA, + 1865FBA006253BAC005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9206253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9306253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9406253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9506253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "picomodel.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9606253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodules.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9706253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_3ds.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9806253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ase.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9A06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9B06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_lwo.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9C06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md2.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9D06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md3.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9E06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_mdc.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FB9F06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ms3d.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBA006253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_obj.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBA106253BAC005AB5DA = { + children = ( + 1865FBA206253BAC005AB5DA, + 1865FBA306253BAC005AB5DA, + 1865FBA406253BAC005AB5DA, + 1865FBA506253BAC005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FBA206253BAC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBA306253BAC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FBA406253BAC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBA506253BAC005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FBA606253BAC005AB5DA = { + children = ( + 1865FBA706253BAC005AB5DA, + 1865FBA806253BAC005AB5DA, + 1865FBA906253BAC005AB5DA, + 1865FBAA06253BAC005AB5DA, + 1865FBAB06253BAC005AB5DA, + 1865FBAC06253BAC005AB5DA, + 1865FBAD06253BAC005AB5DA, + 1865FBAE06253BAC005AB5DA, + 1865FBAF06253BAC005AB5DA, + 1865FBB006253BAC005AB5DA, + 1865FBB106253BAC005AB5DA, + 1865FBB206253BAC005AB5DA, + 1865FBB306253BAC005AB5DA, + 1865FBB406253BAC005AB5DA, + 1865FBB506253BAC005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FBA706253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBA806253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picointernal.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBA906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBAA06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBAB06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodules.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBAC06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_3ds.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBAD06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ase.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBAE06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBAF06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_fm.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB006253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_lwo.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB106253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md2.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB206253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_md3.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB306253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_mdc.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB406253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_ms3d.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB506253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pm_obj.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBB606253BAC005AB5DA = { + children = ( + 1865FBB706253BAC005AB5DA, + 1865FBF206253BAD005AB5DA, + 1865FBF306253BAD005AB5DA, + 1865FBF406253BAD005AB5DA, + 1865FBF506253BAD005AB5DA, + 1865FBF606253BAD005AB5DA, + 1865FBF706253BAD005AB5DA, + 1865FBF806253BAD005AB5DA, + 1865FBF906253BAD005AB5DA, + 1865FBFA06253BAD005AB5DA, + 1865FBFB06253BAD005AB5DA, + 1865FBFC06253BAD005AB5DA, + ); + isa = PBXGroup; + path = lwo; + refType = 4; + sourceTree = ""; + }; + 1865FBB706253BAC005AB5DA = { + children = ( + 1865FBB806253BAC005AB5DA, + 1865FBB906253BAC005AB5DA, + 1865FBBA06253BAC005AB5DA, + 1865FBBB06253BAC005AB5DA, + 1865FBBC06253BAC005AB5DA, + 1865FBC806253BAC005AB5DA, + 1865FBD406253BAC005AB5DA, + 1865FBD506253BAC005AB5DA, + 1865FBE106253BAD005AB5DA, + 1865FBE606253BAD005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FBB806253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FBB906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FBBA06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FBBB06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FBBC06253BAC005AB5DA = { + children = ( + 1865FBBD06253BAC005AB5DA, + 1865FBBE06253BAC005AB5DA, + 1865FBBF06253BAC005AB5DA, + 1865FBC006253BAC005AB5DA, + 1865FBC106253BAC005AB5DA, + 1865FBC206253BAC005AB5DA, + 1865FBC306253BAC005AB5DA, + 1865FBC406253BAC005AB5DA, + 1865FBC506253BAC005AB5DA, + 1865FBC606253BAC005AB5DA, + 1865FBC706253BAC005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBBD06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clip.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBBE06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "envelope.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBBF06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "list.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC006253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwio.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC106253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC206253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC306253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwob.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC406253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pntspols.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC506253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC606253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vecmath.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC706253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vmap.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBC806253BAC005AB5DA = { + children = ( + 1865FBC906253BAC005AB5DA, + 1865FBCA06253BAC005AB5DA, + 1865FBCB06253BAC005AB5DA, + 1865FBCC06253BAC005AB5DA, + 1865FBCD06253BAC005AB5DA, + 1865FBCE06253BAC005AB5DA, + 1865FBCF06253BAC005AB5DA, + 1865FBD006253BAC005AB5DA, + 1865FBD106253BAC005AB5DA, + 1865FBD206253BAC005AB5DA, + 1865FBD306253BAC005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FBC906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clip.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBCA06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "envelope.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBCB06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "list.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBCC06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwio.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBCD06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBCE06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBCF06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwob.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBD006253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pntspols.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBD106253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBD206253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vecmath.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBD306253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vmap.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBD406253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FBD506253BAC005AB5DA = { + children = ( + 1865FBD606253BAC005AB5DA, + 1865FBD706253BAC005AB5DA, + 1865FBD806253BAC005AB5DA, + 1865FBD906253BAC005AB5DA, + 1865FBDA06253BAC005AB5DA, + 1865FBDB06253BAC005AB5DA, + 1865FBDC06253BAC005AB5DA, + 1865FBDD06253BAD005AB5DA, + 1865FBDE06253BAD005AB5DA, + 1865FBDF06253BAD005AB5DA, + 1865FBE006253BAD005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBD606253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clip.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBD706253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "envelope.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBD806253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "list.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBD906253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwio.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBDA06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBDB06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBDC06253BAC005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwob.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBDD06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pntspols.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBDE06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBDF06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vecmath.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBE006253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vmap.c.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBE106253BAD005AB5DA = { + children = ( + 1865FBE206253BAD005AB5DA, + 1865FBE306253BAD005AB5DA, + 1865FBE406253BAD005AB5DA, + 1865FBE506253BAD005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FBE206253BAD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBE306253BAD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FBE406253BAD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FBE506253BAD005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FBE606253BAD005AB5DA = { + children = ( + 1865FBE706253BAD005AB5DA, + 1865FBE806253BAD005AB5DA, + 1865FBE906253BAD005AB5DA, + 1865FBEA06253BAD005AB5DA, + 1865FBEB06253BAD005AB5DA, + 1865FBEC06253BAD005AB5DA, + 1865FBED06253BAD005AB5DA, + 1865FBEE06253BAD005AB5DA, + 1865FBEF06253BAD005AB5DA, + 1865FBF006253BAD005AB5DA, + 1865FBF106253BAD005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FBE706253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "clip.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBE806253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "envelope.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBE906253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "list.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBEA06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwio.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBEB06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBEC06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwo2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBED06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lwob.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBEE06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "pntspols.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBEF06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBF006253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vecmath.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBF106253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "vmap.c.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FBF206253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = clip.c; + refType = 4; + sourceTree = ""; + }; + 1865FBF306253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = envelope.c; + refType = 4; + sourceTree = ""; + }; + 1865FBF406253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = list.c; + refType = 4; + sourceTree = ""; + }; + 1865FBF506253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lwio.c; + refType = 4; + sourceTree = ""; + }; + 1865FBF606253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lwo2.c; + refType = 4; + sourceTree = ""; + }; + 1865FBF706253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = lwo2.h; + refType = 4; + sourceTree = ""; + }; + 1865FBF806253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = lwob.c; + refType = 4; + sourceTree = ""; + }; + 1865FBF906253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pntspols.c; + refType = 4; + sourceTree = ""; + }; + 1865FBFA06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = surface.c; + refType = 4; + sourceTree = ""; + }; + 1865FBFB06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = vecmath.c; + refType = 4; + sourceTree = ""; + }; + 1865FBFC06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = vmap.c; + refType = 4; + sourceTree = ""; + }; + 1865FBFD06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = picointernal.c; + refType = 4; + sourceTree = ""; + }; + 1865FBFE06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = picointernal.h; + refType = 4; + sourceTree = ""; + }; + 1865FBFF06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = picomodel.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0006253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = picomodel.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FC0106253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = picomodules.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0206253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_3ds.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0306253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_ase.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0406253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_fm.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0506253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = pm_fm.h; + refType = 4; + sourceTree = ""; + }; + 1865FC0606253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_lwo.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0706253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_md2.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0806253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_md3.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0906253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_mdc.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0A06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_ms3d.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0B06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + path = pm_obj.c; + refType = 4; + sourceTree = ""; + }; + 1865FC0C06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = picomodel.h; + refType = 4; + sourceTree = ""; + }; + 1865FC0D06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = radiant_jpeglib.h; + refType = 4; + sourceTree = ""; + }; + 1865FC0E06253BAD005AB5DA = { + children = ( + 1865FC0F06253BAD005AB5DA, + 1865FC1006253BAD005AB5DA, + 1865FC6706253BAE005AB5DA, + 1865FC6806253BAE005AB5DA, + 1865FC6906253BAE005AB5DA, + 1865FC6A06253BAE005AB5DA, + 1865FC6B06253BAE005AB5DA, + 1865FC6C06253BAE005AB5DA, + 1865FC6D06253BAE005AB5DA, + 1865FC6E06253BAE005AB5DA, + 1865FC6F06253BAE005AB5DA, + 1865FC7006253BAE005AB5DA, + 1865FC7106253BAE005AB5DA, + 1865FC7206253BAE005AB5DA, + 1865FC7306253BAE005AB5DA, + 1865FC7406253BAE005AB5DA, + 1865FC7506253BAE005AB5DA, + 1865FC7606253BAE005AB5DA, + 1865FC7706253BAE005AB5DA, + ); + isa = PBXGroup; + path = splines; + refType = 4; + sourceTree = ""; + }; + 1865FC0F06253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865FC1006253BAD005AB5DA = { + children = ( + 1865FC1106253BAD005AB5DA, + 1865FC1206253BAD005AB5DA, + 1865FC1306253BAD005AB5DA, + 1865FC1406253BAD005AB5DA, + 1865FC1506253BAD005AB5DA, + 1865FC2806253BAE005AB5DA, + 1865FC3B06253BAE005AB5DA, + 1865FC3C06253BAE005AB5DA, + 1865FC4F06253BAE005AB5DA, + 1865FC5406253BAE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FC1106253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FC1206253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FC1306253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FC1406253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FC1506253BAD005AB5DA = { + children = ( + 1865FC1606253BAD005AB5DA, + 1865FC1706253BAD005AB5DA, + 1865FC1806253BAD005AB5DA, + 1865FC1906253BAE005AB5DA, + 1865FC1A06253BAE005AB5DA, + 1865FC1B06253BAE005AB5DA, + 1865FC1C06253BAE005AB5DA, + 1865FC1D06253BAE005AB5DA, + 1865FC1E06253BAE005AB5DA, + 1865FC1F06253BAE005AB5DA, + 1865FC2006253BAE005AB5DA, + 1865FC2106253BAE005AB5DA, + 1865FC2206253BAE005AB5DA, + 1865FC2306253BAE005AB5DA, + 1865FC2406253BAE005AB5DA, + 1865FC2506253BAE005AB5DA, + 1865FC2606253BAE005AB5DA, + 1865FC2706253BAE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1606253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1706253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1806253BAD005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1906253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1A06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1C06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC1F06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_parse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2106253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2206253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2306253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2406253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Splines.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_list.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2606253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC2806253BAE005AB5DA = { + children = ( + 1865FC2906253BAE005AB5DA, + 1865FC2A06253BAE005AB5DA, + 1865FC2B06253BAE005AB5DA, + 1865FC2C06253BAE005AB5DA, + 1865FC2D06253BAE005AB5DA, + 1865FC2E06253BAE005AB5DA, + 1865FC2F06253BAE005AB5DA, + 1865FC3006253BAE005AB5DA, + 1865FC3106253BAE005AB5DA, + 1865FC3206253BAE005AB5DA, + 1865FC3306253BAE005AB5DA, + 1865FC3406253BAE005AB5DA, + 1865FC3506253BAE005AB5DA, + 1865FC3606253BAE005AB5DA, + 1865FC3706253BAE005AB5DA, + 1865FC3806253BAE005AB5DA, + 1865FC3906253BAE005AB5DA, + 1865FC3A06253BAE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FC2906253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC2A06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC2B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC2C06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC2D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC2E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC2F06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3106253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3206253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_parse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3306253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3406253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3606253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Splines.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3806253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_list.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3906253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3A06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC3B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FC3C06253BAE005AB5DA = { + children = ( + 1865FC3D06253BAE005AB5DA, + 1865FC3E06253BAE005AB5DA, + 1865FC3F06253BAE005AB5DA, + 1865FC4006253BAE005AB5DA, + 1865FC4106253BAE005AB5DA, + 1865FC4206253BAE005AB5DA, + 1865FC4306253BAE005AB5DA, + 1865FC4406253BAE005AB5DA, + 1865FC4506253BAE005AB5DA, + 1865FC4606253BAE005AB5DA, + 1865FC4706253BAE005AB5DA, + 1865FC4806253BAE005AB5DA, + 1865FC4906253BAE005AB5DA, + 1865FC4A06253BAE005AB5DA, + 1865FC4B06253BAE005AB5DA, + 1865FC4C06253BAE005AB5DA, + 1865FC4D06253BAE005AB5DA, + 1865FC4E06253BAE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC3D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC3E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC3F06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4106253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4206253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4306253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4406253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4606253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_parse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4806253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4906253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4A06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "Splines.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4C06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_list.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC4F06253BAE005AB5DA = { + children = ( + 1865FC5006253BAE005AB5DA, + 1865FC5106253BAE005AB5DA, + 1865FC5206253BAE005AB5DA, + 1865FC5306253BAE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FC5006253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC5106253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FC5206253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC5306253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FC5406253BAE005AB5DA = { + children = ( + 1865FC5506253BAE005AB5DA, + 1865FC5606253BAE005AB5DA, + 1865FC5706253BAE005AB5DA, + 1865FC5806253BAE005AB5DA, + 1865FC5906253BAE005AB5DA, + 1865FC5A06253BAE005AB5DA, + 1865FC5B06253BAE005AB5DA, + 1865FC5C06253BAE005AB5DA, + 1865FC5D06253BAE005AB5DA, + 1865FC5E06253BAE005AB5DA, + 1865FC5F06253BAE005AB5DA, + 1865FC6006253BAE005AB5DA, + 1865FC6106253BAE005AB5DA, + 1865FC6206253BAE005AB5DA, + 1865FC6306253BAE005AB5DA, + 1865FC6406253BAE005AB5DA, + 1865FC6506253BAE005AB5DA, + 1865FC6606253BAE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FC5506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5606253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_angles.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5806253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5906253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_matrix.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5A06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_quaternion.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5C06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "math_vector.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_parse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC5F06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q_shared.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6106253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6206253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "splines.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6306253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "Splines.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6406253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_list.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6606253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "util_str.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC6706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = math_angles.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC6806253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = math_angles.h; + refType = 4; + sourceTree = ""; + }; + 1865FC6906253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = math_matrix.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC6A06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = math_matrix.h; + refType = 4; + sourceTree = ""; + }; + 1865FC6B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = math_quaternion.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC6C06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = math_quaternion.h; + refType = 4; + sourceTree = ""; + }; + 1865FC6D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = math_vector.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC6E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = math_vector.h; + refType = 4; + sourceTree = ""; + }; + 1865FC6F06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = q_parse.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC7006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = q_shared.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC7106253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q_shared.h; + refType = 4; + sourceTree = ""; + }; + 1865FC7206253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = splines.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC7306253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = splines.h; + refType = 4; + sourceTree = ""; + }; + 1865FC7406253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = Splines.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FC7506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = util_list.h; + refType = 4; + sourceTree = ""; + }; + 1865FC7606253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = util_str.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FC7706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = util_str.h; + refType = 4; + sourceTree = ""; + }; + 1865FC7806253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = str.h; + refType = 4; + sourceTree = ""; + }; + 1865FC7906253BAE005AB5DA = { + children = ( + 1865FC7A06253BAE005AB5DA, + 1865FC9106253BAE005AB5DA, + 1865FCB006253BAF005AB5DA, + 1865FCB106253BAF005AB5DA, + ); + isa = PBXGroup; + path = synapse; + refType = 4; + sourceTree = ""; + }; + 1865FC7A06253BAE005AB5DA = { + children = ( + 1865FC7B06253BAE005AB5DA, + 1865FC7C06253BAE005AB5DA, + 1865FC7D06253BAE005AB5DA, + 1865FC7E06253BAE005AB5DA, + 1865FC7F06253BAE005AB5DA, + 1865FC8206253BAE005AB5DA, + 1865FC8506253BAE005AB5DA, + 1865FC8606253BAE005AB5DA, + 1865FC8906253BAE005AB5DA, + 1865FC8E06253BAE005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FC7B06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FC7C06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FC7D06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FC7E06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FC7F06253BAE005AB5DA = { + children = ( + 1865FC8006253BAE005AB5DA, + 1865FC8106253BAE005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8106253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8206253BAE005AB5DA = { + children = ( + 1865FC8306253BAE005AB5DA, + 1865FC8406253BAE005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FC8306253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC8406253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC8506253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FC8606253BAE005AB5DA = { + children = ( + 1865FC8706253BAE005AB5DA, + 1865FC8806253BAE005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8706253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8806253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "synapse.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8906253BAE005AB5DA = { + children = ( + 1865FC8A06253BAE005AB5DA, + 1865FC8B06253BAE005AB5DA, + 1865FC8C06253BAE005AB5DA, + 1865FC8D06253BAE005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FC8A06253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8B06253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FC8C06253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC8D06253BAE005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FC8E06253BAE005AB5DA = { + children = ( + 1865FC8F06253BAE005AB5DA, + 1865FC9006253BAE005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FC8F06253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC9006253BAE005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "synapse.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC9106253BAE005AB5DA = { + children = ( + 1865FC9206253BAE005AB5DA, + 1865FCAD06253BAF005AB5DA, + 1865FCAE06253BAF005AB5DA, + 1865FCAF06253BAF005AB5DA, + ); + isa = PBXGroup; + path = doc; + refType = 4; + sourceTree = ""; + }; + 1865FC9206253BAE005AB5DA = { + children = ( + 1865FC9306253BAF005AB5DA, + 1865FC9406253BAF005AB5DA, + 1865FC9506253BAF005AB5DA, + 1865FC9606253BAF005AB5DA, + 1865FC9706253BAF005AB5DA, + 1865FC9B06253BAF005AB5DA, + 1865FC9F06253BAF005AB5DA, + 1865FCA006253BAF005AB5DA, + 1865FCA406253BAF005AB5DA, + 1865FCA906253BAF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FC9306253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FC9406253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FC9506253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FC9606253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FC9706253BAF005AB5DA = { + children = ( + 1865FC9806253BAF005AB5DA, + 1865FC9906253BAF005AB5DA, + 1865FC9A06253BAF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC9806253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC9906253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "runtime.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC9A06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unload.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FC9B06253BAF005AB5DA = { + children = ( + 1865FC9C06253BAF005AB5DA, + 1865FC9D06253BAF005AB5DA, + 1865FC9E06253BAF005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FC9C06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC9D06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "runtime.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC9E06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unload.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FC9F06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCA006253BAF005AB5DA = { + children = ( + 1865FCA106253BAF005AB5DA, + 1865FCA206253BAF005AB5DA, + 1865FCA306253BAF005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCA106253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCA206253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "runtime.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCA306253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unload.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCA406253BAF005AB5DA = { + children = ( + 1865FCA506253BAF005AB5DA, + 1865FCA606253BAF005AB5DA, + 1865FCA706253BAF005AB5DA, + 1865FCA806253BAF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FCA506253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCA606253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCA706253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCA806253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCA906253BAF005AB5DA = { + children = ( + 1865FCAA06253BAF005AB5DA, + 1865FCAB06253BAF005AB5DA, + 1865FCAC06253BAF005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCAA06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "design.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCAB06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "runtime.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCAC06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "unload.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCAD06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = design.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCAE06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = runtime.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCAF06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = unload.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCB006253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = synapse.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FCB106253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = synapse.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FCB206253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = synapse.h; + refType = 4; + sourceTree = ""; + }; + 1865FCB306253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = LICENSE; + refType = 4; + sourceTree = ""; + }; + 1865FCB406253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = LICENSE_ID; + refType = 4; + sourceTree = ""; + }; + 1865FCB506253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.python; + path = makeversion.py; + refType = 4; + sourceTree = ""; + }; + 1865FCB606253BAF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = makeversion.pyc; + refType = 4; + sourceTree = ""; + }; + 1865FCB706253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.script.python; + path = osx_setup.py; + refType = 4; + sourceTree = ""; + }; + 1865FCB806253BAF005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = osx_setup.pyc; + refType = 4; + sourceTree = ""; + }; + 1865FCB906253BAF005AB5DA = { + children = ( + 1865FCBA06253BAF005AB5DA, + 1865FCCD06253BAF005AB5DA, + 1865FCDD06253BAF005AB5DA, + 1865FCDE06253BAF005AB5DA, + 1865FD0206253BB0005AB5DA, + 1865FD4E06253BB1005AB5DA, + 1865FD9006253BB1005AB5DA, + 1865FDC306253BB2005AB5DA, + 1865FDFB06253BB3005AB5DA, + 1865FE1F06253BB3005AB5DA, + 1865FE5206253BB3005AB5DA, + 1865FE8006253BB4005AB5DA, + 1865FEAE06253BB4005AB5DA, + 1865FF1406253BB5005AB5DA, + 1865FF2406253BB5005AB5DA, + 1865FF5C06253BB6005AB5DA, + 1865FF8A06253BB7005AB5DA, + 1865FFBD06253BB7005AB5DA, + 1865FFF506253BB8005AB5DA, + 1865002D06253BB8005AB5DA, + 186500A206253BB9005AB5DA, + 186500D006253BB9005AB5DA, + 1865011206253BBA005AB5DA, + ); + isa = PBXGroup; + path = plugins; + refType = 4; + sourceTree = ""; + }; + 1865FCBA06253BAF005AB5DA = { + children = ( + 1865FCBB06253BAF005AB5DA, + 1865FCBC06253BAF005AB5DA, + 1865FCBD06253BAF005AB5DA, + 1865FCBE06253BAF005AB5DA, + 1865FCBF06253BAF005AB5DA, + 1865FCC106253BAF005AB5DA, + 1865FCC306253BAF005AB5DA, + 1865FCC406253BAF005AB5DA, + 1865FCC606253BAF005AB5DA, + 1865FCCB06253BAF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FCBB06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FCBC06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FCBD06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FCBE06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FCBF06253BAF005AB5DA = { + children = ( + 1865FCC006253BAF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCC006253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.mk.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCC106253BAF005AB5DA = { + children = ( + 1865FCC206253BAF005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCC206253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.mk.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCC306253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCC406253BAF005AB5DA = { + children = ( + 1865FCC506253BAF005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCC506253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.mk.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCC606253BAF005AB5DA = { + children = ( + 1865FCC706253BAF005AB5DA, + 1865FCC806253BAF005AB5DA, + 1865FCC906253BAF005AB5DA, + 1865FCCA06253BAF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FCC706253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCC806253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCC906253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCCA06253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCCB06253BAF005AB5DA = { + children = ( + 1865FCCC06253BAF005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCCC06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "config.mk.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCCD06253BAF005AB5DA = { + children = ( + 1865FCCE06253BAF005AB5DA, + ); + isa = PBXGroup; + path = archivewad; + refType = 4; + sourceTree = ""; + }; + 1865FCCE06253BAF005AB5DA = { + children = ( + 1865FCCF06253BAF005AB5DA, + 1865FCD006253BAF005AB5DA, + 1865FCD106253BAF005AB5DA, + 1865FCD206253BAF005AB5DA, + 1865FCD306253BAF005AB5DA, + 1865FCD406253BAF005AB5DA, + 1865FCD506253BAF005AB5DA, + 1865FCD606253BAF005AB5DA, + 1865FCD706253BAF005AB5DA, + 1865FCDC06253BAF005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FCCF06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FCD006253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FCD106253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FCD206253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FCD306253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCD406253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCD506253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCD606253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCD706253BAF005AB5DA = { + children = ( + 1865FCD806253BAF005AB5DA, + 1865FCD906253BAF005AB5DA, + 1865FCDA06253BAF005AB5DA, + 1865FCDB06253BAF005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FCD806253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCD906253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCDA06253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCDB06253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCDC06253BAF005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCDD06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = config.mk; + refType = 4; + sourceTree = ""; + }; + 1865FCDE06253BAF005AB5DA = { + children = ( + 1865FCDF06253BAF005AB5DA, + 1865FCFE06253BB0005AB5DA, + 1865FCFF06253BB0005AB5DA, + 1865FD0006253BB0005AB5DA, + 1865FD0106253BB0005AB5DA, + ); + isa = PBXGroup; + path = eclassfgd; + refType = 4; + sourceTree = ""; + }; + 1865FCDF06253BAF005AB5DA = { + children = ( + 1865FCE006253BAF005AB5DA, + 1865FCE106253BAF005AB5DA, + 1865FCE206253BAF005AB5DA, + 1865FCE306253BAF005AB5DA, + 1865FCE406253BAF005AB5DA, + 1865FCE906253BAF005AB5DA, + 1865FCEE06253BAF005AB5DA, + 1865FCEF06253BAF005AB5DA, + 1865FCF406253BAF005AB5DA, + 1865FCF906253BB0005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FCE006253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FCE106253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FCE206253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FCE306253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FCE406253BAF005AB5DA = { + children = ( + 1865FCE506253BAF005AB5DA, + 1865FCE606253BAF005AB5DA, + 1865FCE706253BAF005AB5DA, + 1865FCE806253BAF005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCE506253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCE606253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCE706253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCE806253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCE906253BAF005AB5DA = { + children = ( + 1865FCEA06253BAF005AB5DA, + 1865FCEB06253BAF005AB5DA, + 1865FCEC06253BAF005AB5DA, + 1865FCED06253BAF005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCEA06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCEB06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCEC06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCED06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCEE06253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FCEF06253BAF005AB5DA = { + children = ( + 1865FCF006253BAF005AB5DA, + 1865FCF106253BAF005AB5DA, + 1865FCF206253BAF005AB5DA, + 1865FCF306253BAF005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF006253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF106253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "fgd.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF206253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF306253BAF005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF406253BAF005AB5DA = { + children = ( + 1865FCF506253BB0005AB5DA, + 1865FCF606253BB0005AB5DA, + 1865FCF706253BB0005AB5DA, + 1865FCF806253BB0005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FCF506253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF606253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FCF706253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FCF806253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCF906253BB0005AB5DA = { + children = ( + 1865FCFA06253BB0005AB5DA, + 1865FCFB06253BB0005AB5DA, + 1865FCFC06253BB0005AB5DA, + 1865FCFD06253BB0005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FCFA06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCFB06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "fgd.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCFC06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCFD06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FCFE06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = fgd.def; + refType = 4; + sourceTree = ""; + }; + 1865FCFF06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = fgd.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FD0006253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD0106253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FD0206253BB0005AB5DA = { + children = ( + 1865FD0306253BB0005AB5DA, + 1865FD4206253BB0005AB5DA, + 1865FD4306253BB0005AB5DA, + 1865FD4406253BB0005AB5DA, + 1865FD4506253BB0005AB5DA, + 1865FD4606253BB0005AB5DA, + 1865FD4706253BB0005AB5DA, + 1865FD4806253BB0005AB5DA, + 1865FD4906253BB0005AB5DA, + 1865FD4A06253BB0005AB5DA, + 1865FD4B06253BB0005AB5DA, + 1865FD4C06253BB0005AB5DA, + 1865FD4D06253BB1005AB5DA, + ); + isa = PBXGroup; + path = entity; + refType = 4; + sourceTree = ""; + }; + 1865FD0306253BB0005AB5DA = { + children = ( + 1865FD0406253BB0005AB5DA, + 1865FD0506253BB0005AB5DA, + 1865FD0606253BB0005AB5DA, + 1865FD0706253BB0005AB5DA, + 1865FD0806253BB0005AB5DA, + 1865FD1506253BB0005AB5DA, + 1865FD2206253BB0005AB5DA, + 1865FD2306253BB0005AB5DA, + 1865FD3006253BB0005AB5DA, + 1865FD3506253BB0005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FD0406253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FD0506253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FD0606253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FD0706253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FD0806253BB0005AB5DA = { + children = ( + 1865FD0906253BB0005AB5DA, + 1865FD0A06253BB0005AB5DA, + 1865FD0B06253BB0005AB5DA, + 1865FD0C06253BB0005AB5DA, + 1865FD0D06253BB0005AB5DA, + 1865FD0E06253BB0005AB5DA, + 1865FD0F06253BB0005AB5DA, + 1865FD1006253BB0005AB5DA, + 1865FD1106253BB0005AB5DA, + 1865FD1206253BB0005AB5DA, + 1865FD1306253BB0005AB5DA, + 1865FD1406253BB0005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0906253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclassmodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0A06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0B06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0C06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0D06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0E06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD0F06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD1006253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD1106253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD1206253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD1306253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD1406253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD1506253BB0005AB5DA = { + children = ( + 1865FD1606253BB0005AB5DA, + 1865FD1706253BB0005AB5DA, + 1865FD1806253BB0005AB5DA, + 1865FD1906253BB0005AB5DA, + 1865FD1A06253BB0005AB5DA, + 1865FD1B06253BB0005AB5DA, + 1865FD1C06253BB0005AB5DA, + 1865FD1D06253BB0005AB5DA, + 1865FD1E06253BB0005AB5DA, + 1865FD1F06253BB0005AB5DA, + 1865FD2006253BB0005AB5DA, + 1865FD2106253BB0005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FD1606253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclassmodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1706253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1806253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1906253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1A06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1B06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1C06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1D06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1E06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD1F06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD2006253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD2106253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD2206253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FD2306253BB0005AB5DA = { + children = ( + 1865FD2406253BB0005AB5DA, + 1865FD2506253BB0005AB5DA, + 1865FD2606253BB0005AB5DA, + 1865FD2706253BB0005AB5DA, + 1865FD2806253BB0005AB5DA, + 1865FD2906253BB0005AB5DA, + 1865FD2A06253BB0005AB5DA, + 1865FD2B06253BB0005AB5DA, + 1865FD2C06253BB0005AB5DA, + 1865FD2D06253BB0005AB5DA, + 1865FD2E06253BB0005AB5DA, + 1865FD2F06253BB0005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2406253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclassmodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2506253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2606253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2706253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2806253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "entity.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2906253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2A06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2B06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2C06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2D06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2E06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD2F06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD3006253BB0005AB5DA = { + children = ( + 1865FD3106253BB0005AB5DA, + 1865FD3206253BB0005AB5DA, + 1865FD3306253BB0005AB5DA, + 1865FD3406253BB0005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FD3106253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD3206253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FD3306253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD3406253BB0005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FD3506253BB0005AB5DA = { + children = ( + 1865FD3606253BB0005AB5DA, + 1865FD3706253BB0005AB5DA, + 1865FD3806253BB0005AB5DA, + 1865FD3906253BB0005AB5DA, + 1865FD3A06253BB0005AB5DA, + 1865FD3B06253BB0005AB5DA, + 1865FD3C06253BB0005AB5DA, + 1865FD3D06253BB0005AB5DA, + 1865FD3E06253BB0005AB5DA, + 1865FD3F06253BB0005AB5DA, + 1865FD4006253BB0005AB5DA, + 1865FD4106253BB0005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FD3606253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "eclassmodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3706253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3806253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3906253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3A06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3B06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3C06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "entity_entitymodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3D06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3E06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "light.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD3F06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD4006253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD4106253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD4206253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = eclassmodel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD4306253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = entity.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD4406253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = entity.def; + refType = 4; + sourceTree = ""; + }; + 1865FD4506253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = entity.h; + refType = 4; + sourceTree = ""; + }; + 1865FD4606253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entity.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FD4706253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = entity_entitymodel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD4806253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = entity_entitymodel.h; + refType = 4; + sourceTree = ""; + }; + 1865FD4906253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = light.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD4A06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = light.h; + refType = 4; + sourceTree = ""; + }; + 1865FD4B06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = miscmodel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD4C06253BB0005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD4D06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FD4E06253BB1005AB5DA = { + children = ( + 1865FD4F06253BB1005AB5DA, + 1865FD5006253BB1005AB5DA, + 1865FD8706253BB1005AB5DA, + 1865FD8806253BB1005AB5DA, + 1865FD8906253BB1005AB5DA, + 1865FD8A06253BB1005AB5DA, + 1865FD8B06253BB1005AB5DA, + 1865FD8C06253BB1005AB5DA, + 1865FD8D06253BB1005AB5DA, + 1865FD8E06253BB1005AB5DA, + 1865FD8F06253BB1005AB5DA, + ); + isa = PBXGroup; + path = image; + refType = 4; + sourceTree = ""; + }; + 1865FD4F06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865FD5006253BB1005AB5DA = { + children = ( + 1865FD5106253BB1005AB5DA, + 1865FD5206253BB1005AB5DA, + 1865FD5306253BB1005AB5DA, + 1865FD5406253BB1005AB5DA, + 1865FD5506253BB1005AB5DA, + 1865FD6006253BB1005AB5DA, + 1865FD6B06253BB1005AB5DA, + 1865FD6C06253BB1005AB5DA, + 1865FD7706253BB1005AB5DA, + 1865FD7C06253BB1005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FD5106253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FD5206253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FD5306253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FD5406253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FD5506253BB1005AB5DA = { + children = ( + 1865FD5606253BB1005AB5DA, + 1865FD5706253BB1005AB5DA, + 1865FD5806253BB1005AB5DA, + 1865FD5906253BB1005AB5DA, + 1865FD5A06253BB1005AB5DA, + 1865FD5B06253BB1005AB5DA, + 1865FD5C06253BB1005AB5DA, + 1865FD5D06253BB1005AB5DA, + 1865FD5E06253BB1005AB5DA, + 1865FD5F06253BB1005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5606253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5706253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5806253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5906253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5A06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5B06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5C06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5D06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5E06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD5F06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD6006253BB1005AB5DA = { + children = ( + 1865FD6106253BB1005AB5DA, + 1865FD6206253BB1005AB5DA, + 1865FD6306253BB1005AB5DA, + 1865FD6406253BB1005AB5DA, + 1865FD6506253BB1005AB5DA, + 1865FD6606253BB1005AB5DA, + 1865FD6706253BB1005AB5DA, + 1865FD6806253BB1005AB5DA, + 1865FD6906253BB1005AB5DA, + 1865FD6A06253BB1005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FD6106253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6206253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6306253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6406253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6506253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6606253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6706253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6806253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6906253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6A06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD6B06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FD6C06253BB1005AB5DA = { + children = ( + 1865FD6D06253BB1005AB5DA, + 1865FD6E06253BB1005AB5DA, + 1865FD6F06253BB1005AB5DA, + 1865FD7006253BB1005AB5DA, + 1865FD7106253BB1005AB5DA, + 1865FD7206253BB1005AB5DA, + 1865FD7306253BB1005AB5DA, + 1865FD7406253BB1005AB5DA, + 1865FD7506253BB1005AB5DA, + 1865FD7606253BB1005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD6D06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD6E06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD6F06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7006253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7106253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7206253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7306253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "image.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7406253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7506253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7606253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7706253BB1005AB5DA = { + children = ( + 1865FD7806253BB1005AB5DA, + 1865FD7906253BB1005AB5DA, + 1865FD7A06253BB1005AB5DA, + 1865FD7B06253BB1005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FD7806253BB1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7906253BB1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FD7A06253BB1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD7B06253BB1005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FD7C06253BB1005AB5DA = { + children = ( + 1865FD7D06253BB1005AB5DA, + 1865FD7E06253BB1005AB5DA, + 1865FD7F06253BB1005AB5DA, + 1865FD8006253BB1005AB5DA, + 1865FD8106253BB1005AB5DA, + 1865FD8206253BB1005AB5DA, + 1865FD8306253BB1005AB5DA, + 1865FD8406253BB1005AB5DA, + 1865FD8506253BB1005AB5DA, + 1865FD8606253BB1005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FD7D06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD7E06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD7F06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "bmp.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8006253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8106253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8206253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8306253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "image.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8406253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "jpeg.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8506253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8606253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FD8706253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = bmp.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD8806253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = bmp.h; + refType = 4; + sourceTree = ""; + }; + 1865FD8906253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = image.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD8A06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = image.def; + refType = 4; + sourceTree = ""; + }; + 1865FD8B06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = image.h; + refType = 4; + sourceTree = ""; + }; + 1865FD8C06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = image.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FD8D06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = jpeg.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD8E06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = lbmlib.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FD8F06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = lbmlib.h; + refType = 4; + sourceTree = ""; + }; + 1865FD9006253BB1005AB5DA = { + children = ( + 1865FD9106253BB1005AB5DA, + 1865FDBC06253BB2005AB5DA, + 1865FDBD06253BB2005AB5DA, + 1865FDBE06253BB2005AB5DA, + 1865FDBF06253BB2005AB5DA, + 1865FDC006253BB2005AB5DA, + 1865FDC106253BB2005AB5DA, + 1865FDC206253BB2005AB5DA, + ); + isa = PBXGroup; + path = imagehl; + refType = 4; + sourceTree = ""; + }; + 1865FD9106253BB1005AB5DA = { + children = ( + 1865FD9206253BB1005AB5DA, + 1865FD9306253BB1005AB5DA, + 1865FD9406253BB1005AB5DA, + 1865FD9506253BB1005AB5DA, + 1865FD9606253BB1005AB5DA, + 1865FD9E06253BB2005AB5DA, + 1865FDA606253BB2005AB5DA, + 1865FDA706253BB2005AB5DA, + 1865FDAF06253BB2005AB5DA, + 1865FDB406253BB2005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FD9206253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FD9306253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FD9406253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FD9506253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FD9606253BB1005AB5DA = { + children = ( + 1865FD9706253BB1005AB5DA, + 1865FD9806253BB1005AB5DA, + 1865FD9906253BB1005AB5DA, + 1865FD9A06253BB1005AB5DA, + 1865FD9B06253BB1005AB5DA, + 1865FD9C06253BB2005AB5DA, + 1865FD9D06253BB2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9706253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9806253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9906253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9A06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9B06253BB1005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9C06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9D06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FD9E06253BB2005AB5DA = { + children = ( + 1865FD9F06253BB2005AB5DA, + 1865FDA006253BB2005AB5DA, + 1865FDA106253BB2005AB5DA, + 1865FDA206253BB2005AB5DA, + 1865FDA306253BB2005AB5DA, + 1865FDA406253BB2005AB5DA, + 1865FDA506253BB2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FD9F06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA006253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA106253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA206253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA306253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA406253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA506253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDA606253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FDA706253BB2005AB5DA = { + children = ( + 1865FDA806253BB2005AB5DA, + 1865FDA906253BB2005AB5DA, + 1865FDAA06253BB2005AB5DA, + 1865FDAB06253BB2005AB5DA, + 1865FDAC06253BB2005AB5DA, + 1865FDAD06253BB2005AB5DA, + 1865FDAE06253BB2005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDA806253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDA906253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDAA06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDAB06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.txt.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDAC06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "imagehl.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDAD06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDAE06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDAF06253BB2005AB5DA = { + children = ( + 1865FDB006253BB2005AB5DA, + 1865FDB106253BB2005AB5DA, + 1865FDB206253BB2005AB5DA, + 1865FDB306253BB2005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FDB006253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDB106253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FDB206253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDB306253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FDB406253BB2005AB5DA = { + children = ( + 1865FDB506253BB2005AB5DA, + 1865FDB606253BB2005AB5DA, + 1865FDB706253BB2005AB5DA, + 1865FDB806253BB2005AB5DA, + 1865FDB906253BB2005AB5DA, + 1865FDBA06253BB2005AB5DA, + 1865FDBB06253BB2005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FDB506253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDB606253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDB706253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDB806253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.txt.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDB906253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagehl.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDBA06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDBB06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "lbmlib.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDBC06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = imagehl.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FDBD06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = imagehl.def; + refType = 4; + sourceTree = ""; + }; + 1865FDBE06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imagehl.h; + refType = 4; + sourceTree = ""; + }; + 1865FDBF06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = imagehl.txt; + refType = 4; + sourceTree = ""; + }; + 1865FDC006253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = imagehl.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FDC106253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = lbmlib.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FDC206253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = lbmlib.h; + refType = 4; + sourceTree = ""; + }; + 1865FDC306253BB2005AB5DA = { + children = ( + 1865FDC406253BB2005AB5DA, + 1865FDF306253BB3005AB5DA, + 1865FDF406253BB3005AB5DA, + 1865FDF506253BB3005AB5DA, + 1865FDF606253BB3005AB5DA, + 1865FDF706253BB3005AB5DA, + 1865FDF806253BB3005AB5DA, + 1865FDF906253BB3005AB5DA, + 1865FDFA06253BB3005AB5DA, + ); + isa = PBXGroup; + path = imagem8; + refType = 4; + sourceTree = ""; + }; + 1865FDC406253BB2005AB5DA = { + children = ( + 1865FDC506253BB2005AB5DA, + 1865FDC606253BB2005AB5DA, + 1865FDC706253BB2005AB5DA, + 1865FDC806253BB2005AB5DA, + 1865FDC906253BB2005AB5DA, + 1865FDD206253BB2005AB5DA, + 1865FDDB06253BB2005AB5DA, + 1865FDDC06253BB2005AB5DA, + 1865FDE506253BB2005AB5DA, + 1865FDEA06253BB2005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FDC506253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FDC606253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FDC706253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FDC806253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FDC906253BB2005AB5DA = { + children = ( + 1865FDCA06253BB2005AB5DA, + 1865FDCB06253BB2005AB5DA, + 1865FDCC06253BB2005AB5DA, + 1865FDCD06253BB2005AB5DA, + 1865FDCE06253BB2005AB5DA, + 1865FDCF06253BB2005AB5DA, + 1865FDD006253BB2005AB5DA, + 1865FDD106253BB2005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDCA06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDCB06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDCC06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDCD06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDCE06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDCF06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDD006253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDD106253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDD206253BB2005AB5DA = { + children = ( + 1865FDD306253BB2005AB5DA, + 1865FDD406253BB2005AB5DA, + 1865FDD506253BB2005AB5DA, + 1865FDD606253BB2005AB5DA, + 1865FDD706253BB2005AB5DA, + 1865FDD806253BB2005AB5DA, + 1865FDD906253BB2005AB5DA, + 1865FDDA06253BB2005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FDD306253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDD406253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDD506253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDD606253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDD706253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDD806253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDD906253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDDA06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDDB06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FDDC06253BB2005AB5DA = { + children = ( + 1865FDDD06253BB2005AB5DA, + 1865FDDE06253BB2005AB5DA, + 1865FDDF06253BB2005AB5DA, + 1865FDE006253BB2005AB5DA, + 1865FDE106253BB2005AB5DA, + 1865FDE206253BB2005AB5DA, + 1865FDE306253BB2005AB5DA, + 1865FDE406253BB2005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDDD06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDDE06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDDF06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE006253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "imagem8.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE106253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE206253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE306253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE406253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE506253BB2005AB5DA = { + children = ( + 1865FDE606253BB2005AB5DA, + 1865FDE706253BB2005AB5DA, + 1865FDE806253BB2005AB5DA, + 1865FDE906253BB2005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FDE606253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE706253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FDE806253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FDE906253BB2005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FDEA06253BB2005AB5DA = { + children = ( + 1865FDEB06253BB2005AB5DA, + 1865FDEC06253BB2005AB5DA, + 1865FDED06253BB2005AB5DA, + 1865FDEE06253BB2005AB5DA, + 1865FDEF06253BB2005AB5DA, + 1865FDF006253BB2005AB5DA, + 1865FDF106253BB2005AB5DA, + 1865FDF206253BB3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FDEB06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDEC06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDED06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDEE06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagem8.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDEF06253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDF006253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m32.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDF106253BB2005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDF206253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "m8.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FDF306253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = imagem8.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FDF406253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = imagem8.def; + refType = 4; + sourceTree = ""; + }; + 1865FDF506253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imagem8.h; + refType = 4; + sourceTree = ""; + }; + 1865FDF606253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = imagem8.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FDF706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = m32.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FDF806253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = m32.h; + refType = 4; + sourceTree = ""; + }; + 1865FDF906253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = m8.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FDFA06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = m8.h; + refType = 4; + sourceTree = ""; + }; + 1865FDFB06253BB3005AB5DA = { + children = ( + 1865FDFC06253BB3005AB5DA, + 1865FE1B06253BB3005AB5DA, + 1865FE1C06253BB3005AB5DA, + 1865FE1D06253BB3005AB5DA, + 1865FE1E06253BB3005AB5DA, + ); + isa = PBXGroup; + path = imagepng; + refType = 4; + sourceTree = ""; + }; + 1865FDFC06253BB3005AB5DA = { + children = ( + 1865FDFD06253BB3005AB5DA, + 1865FDFE06253BB3005AB5DA, + 1865FDFF06253BB3005AB5DA, + 1865FE0006253BB3005AB5DA, + 1865FE0106253BB3005AB5DA, + 1865FE0606253BB3005AB5DA, + 1865FE0B06253BB3005AB5DA, + 1865FE0C06253BB3005AB5DA, + 1865FE1106253BB3005AB5DA, + 1865FE1606253BB3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FDFD06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FDFE06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FDFF06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FE0006253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FE0106253BB3005AB5DA = { + children = ( + 1865FE0206253BB3005AB5DA, + 1865FE0306253BB3005AB5DA, + 1865FE0406253BB3005AB5DA, + 1865FE0506253BB3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0206253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0306253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0406253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0506253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0606253BB3005AB5DA = { + children = ( + 1865FE0706253BB3005AB5DA, + 1865FE0806253BB3005AB5DA, + 1865FE0906253BB3005AB5DA, + 1865FE0A06253BB3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE0706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE0806253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE0906253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE0A06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE0B06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FE0C06253BB3005AB5DA = { + children = ( + 1865FE0D06253BB3005AB5DA, + 1865FE0E06253BB3005AB5DA, + 1865FE0F06253BB3005AB5DA, + 1865FE1006253BB3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0D06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0E06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "imagepng.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE0F06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE1006253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE1106253BB3005AB5DA = { + children = ( + 1865FE1206253BB3005AB5DA, + 1865FE1306253BB3005AB5DA, + 1865FE1406253BB3005AB5DA, + 1865FE1506253BB3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FE1206253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE1306253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE1406253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE1506253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FE1606253BB3005AB5DA = { + children = ( + 1865FE1706253BB3005AB5DA, + 1865FE1806253BB3005AB5DA, + 1865FE1906253BB3005AB5DA, + 1865FE1A06253BB3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FE1706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE1806253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagepng.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE1906253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE1A06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE1B06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = imagepng.def; + refType = 4; + sourceTree = ""; + }; + 1865FE1C06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = imagepng.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FE1D06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FE1E06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FE1F06253BB3005AB5DA = { + children = ( + 1865FE2006253BB3005AB5DA, + 1865FE4B06253BB3005AB5DA, + 1865FE4C06253BB3005AB5DA, + 1865FE4D06253BB3005AB5DA, + 1865FE4E06253BB3005AB5DA, + 1865FE4F06253BB3005AB5DA, + 1865FE5006253BB3005AB5DA, + 1865FE5106253BB3005AB5DA, + ); + isa = PBXGroup; + path = imagewal; + refType = 4; + sourceTree = ""; + }; + 1865FE2006253BB3005AB5DA = { + children = ( + 1865FE2106253BB3005AB5DA, + 1865FE2206253BB3005AB5DA, + 1865FE2306253BB3005AB5DA, + 1865FE2406253BB3005AB5DA, + 1865FE2506253BB3005AB5DA, + 1865FE2D06253BB3005AB5DA, + 1865FE3506253BB3005AB5DA, + 1865FE3606253BB3005AB5DA, + 1865FE3E06253BB3005AB5DA, + 1865FE4306253BB3005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FE2106253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FE2206253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FE2306253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FE2406253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FE2506253BB3005AB5DA = { + children = ( + 1865FE2606253BB3005AB5DA, + 1865FE2706253BB3005AB5DA, + 1865FE2806253BB3005AB5DA, + 1865FE2906253BB3005AB5DA, + 1865FE2A06253BB3005AB5DA, + 1865FE2B06253BB3005AB5DA, + 1865FE2C06253BB3005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2606253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2806253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2906253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2A06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_palette.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2B06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2C06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE2D06253BB3005AB5DA = { + children = ( + 1865FE2E06253BB3005AB5DA, + 1865FE2F06253BB3005AB5DA, + 1865FE3006253BB3005AB5DA, + 1865FE3106253BB3005AB5DA, + 1865FE3206253BB3005AB5DA, + 1865FE3306253BB3005AB5DA, + 1865FE3406253BB3005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE2E06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE2F06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE3006253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE3106253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE3206253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_palette.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE3306253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE3406253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE3506253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FE3606253BB3005AB5DA = { + children = ( + 1865FE3706253BB3005AB5DA, + 1865FE3806253BB3005AB5DA, + 1865FE3906253BB3005AB5DA, + 1865FE3A06253BB3005AB5DA, + 1865FE3B06253BB3005AB5DA, + 1865FE3C06253BB3005AB5DA, + 1865FE3D06253BB3005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3806253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3906253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3A06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "imagewal.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3B06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_palette.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3C06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3D06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE3E06253BB3005AB5DA = { + children = ( + 1865FE3F06253BB3005AB5DA, + 1865FE4006253BB3005AB5DA, + 1865FE4106253BB3005AB5DA, + 1865FE4206253BB3005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FE3F06253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE4006253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE4106253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE4206253BB3005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FE4306253BB3005AB5DA = { + children = ( + 1865FE4406253BB3005AB5DA, + 1865FE4506253BB3005AB5DA, + 1865FE4606253BB3005AB5DA, + 1865FE4706253BB3005AB5DA, + 1865FE4806253BB3005AB5DA, + 1865FE4906253BB3005AB5DA, + 1865FE4A06253BB3005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FE4406253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4506253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4606253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "imagewal.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4806253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "q2_palette.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4906253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4A06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "wal.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE4B06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = imagewal.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FE4C06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = imagewal.def; + refType = 4; + sourceTree = ""; + }; + 1865FE4D06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imagewal.h; + refType = 4; + sourceTree = ""; + }; + 1865FE4E06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = imagewal.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FE4F06253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = q2_palette.h; + refType = 4; + sourceTree = ""; + }; + 1865FE5006253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = wal.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FE5106253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = wal.h; + refType = 4; + sourceTree = ""; + }; + 1865FE5206253BB3005AB5DA = { + children = ( + 1865FE5306253BB3005AB5DA, + 1865FE7A06253BB4005AB5DA, + 1865FE7B06253BB4005AB5DA, + 1865FE7C06253BB4005AB5DA, + 1865FE7D06253BB4005AB5DA, + 1865FE7E06253BB4005AB5DA, + 1865FE7F06253BB4005AB5DA, + ); + isa = PBXGroup; + path = map; + refType = 4; + sourceTree = ""; + }; + 1865FE5306253BB3005AB5DA = { + children = ( + 1865FE5406253BB3005AB5DA, + 1865FE5506253BB3005AB5DA, + 1865FE5606253BB3005AB5DA, + 1865FE5706253BB3005AB5DA, + 1865FE5806253BB3005AB5DA, + 1865FE5F06253BB4005AB5DA, + 1865FE6606253BB4005AB5DA, + 1865FE6706253BB4005AB5DA, + 1865FE6E06253BB4005AB5DA, + 1865FE7306253BB4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FE5406253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FE5506253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FE5606253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FE5706253BB3005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FE5806253BB3005AB5DA = { + children = ( + 1865FE5906253BB4005AB5DA, + 1865FE5A06253BB4005AB5DA, + 1865FE5B06253BB4005AB5DA, + 1865FE5C06253BB4005AB5DA, + 1865FE5D06253BB4005AB5DA, + 1865FE5E06253BB4005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5906253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5A06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5B06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5C06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5D06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5E06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "write.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE5F06253BB4005AB5DA = { + children = ( + 1865FE6006253BB4005AB5DA, + 1865FE6106253BB4005AB5DA, + 1865FE6206253BB4005AB5DA, + 1865FE6306253BB4005AB5DA, + 1865FE6406253BB4005AB5DA, + 1865FE6506253BB4005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE6006253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE6106253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE6206253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE6306253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE6406253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE6506253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "write.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE6606253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FE6706253BB4005AB5DA = { + children = ( + 1865FE6806253BB4005AB5DA, + 1865FE6906253BB4005AB5DA, + 1865FE6A06253BB4005AB5DA, + 1865FE6B06253BB4005AB5DA, + 1865FE6C06253BB4005AB5DA, + 1865FE6D06253BB4005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6806253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6906253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "map.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6A06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6B06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6C06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6D06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "write.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE6E06253BB4005AB5DA = { + children = ( + 1865FE6F06253BB4005AB5DA, + 1865FE7006253BB4005AB5DA, + 1865FE7106253BB4005AB5DA, + 1865FE7206253BB4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FE6F06253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE7006253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE7106253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE7206253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FE7306253BB4005AB5DA = { + children = ( + 1865FE7406253BB4005AB5DA, + 1865FE7506253BB4005AB5DA, + 1865FE7606253BB4005AB5DA, + 1865FE7706253BB4005AB5DA, + 1865FE7806253BB4005AB5DA, + 1865FE7906253BB4005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FE7406253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE7506253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "map.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE7606253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "parse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE7706253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE7806253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE7906253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "write.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE7A06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = map.def; + refType = 4; + sourceTree = ""; + }; + 1865FE7B06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = map.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FE7C06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = parse.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FE7D06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FE7E06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FE7F06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = write.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FE8006253BB4005AB5DA = { + children = ( + 1865FE8106253BB4005AB5DA, + 1865FEA806253BB4005AB5DA, + 1865FEA906253BB4005AB5DA, + 1865FEAA06253BB4005AB5DA, + 1865FEAB06253BB4005AB5DA, + 1865FEAC06253BB4005AB5DA, + 1865FEAD06253BB4005AB5DA, + ); + isa = PBXGroup; + path = mapxml; + refType = 4; + sourceTree = ""; + }; + 1865FE8106253BB4005AB5DA = { + children = ( + 1865FE8206253BB4005AB5DA, + 1865FE8306253BB4005AB5DA, + 1865FE8406253BB4005AB5DA, + 1865FE8506253BB4005AB5DA, + 1865FE8606253BB4005AB5DA, + 1865FE8D06253BB4005AB5DA, + 1865FE9406253BB4005AB5DA, + 1865FE9506253BB4005AB5DA, + 1865FE9C06253BB4005AB5DA, + 1865FEA106253BB4005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FE8206253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FE8306253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FE8406253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FE8506253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FE8606253BB4005AB5DA = { + children = ( + 1865FE8706253BB4005AB5DA, + 1865FE8806253BB4005AB5DA, + 1865FE8906253BB4005AB5DA, + 1865FE8A06253BB4005AB5DA, + 1865FE8B06253BB4005AB5DA, + 1865FE8C06253BB4005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8706253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8806253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8906253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8A06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8B06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlparse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8C06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlwrite.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE8D06253BB4005AB5DA = { + children = ( + 1865FE8E06253BB4005AB5DA, + 1865FE8F06253BB4005AB5DA, + 1865FE9006253BB4005AB5DA, + 1865FE9106253BB4005AB5DA, + 1865FE9206253BB4005AB5DA, + 1865FE9306253BB4005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE8E06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE8F06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE9006253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE9106253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE9206253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlparse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE9306253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlwrite.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FE9406253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FE9506253BB4005AB5DA = { + children = ( + 1865FE9606253BB4005AB5DA, + 1865FE9706253BB4005AB5DA, + 1865FE9806253BB4005AB5DA, + 1865FE9906253BB4005AB5DA, + 1865FE9A06253BB4005AB5DA, + 1865FE9B06253BB4005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9606253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9706253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "mapxml.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9806253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9906253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9A06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlparse.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9B06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlwrite.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9C06253BB4005AB5DA = { + children = ( + 1865FE9D06253BB4005AB5DA, + 1865FE9E06253BB4005AB5DA, + 1865FE9F06253BB4005AB5DA, + 1865FEA006253BB4005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FE9D06253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FE9E06253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FE9F06253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEA006253BB4005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FEA106253BB4005AB5DA = { + children = ( + 1865FEA206253BB4005AB5DA, + 1865FEA306253BB4005AB5DA, + 1865FEA406253BB4005AB5DA, + 1865FEA506253BB4005AB5DA, + 1865FEA606253BB4005AB5DA, + 1865FEA706253BB4005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FEA206253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEA306253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "mapxml.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEA406253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEA506253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEA606253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlparse.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEA706253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "xmlwrite.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEA806253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = mapxml.def; + refType = 4; + sourceTree = ""; + }; + 1865FEA906253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = mapxml.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FEAA06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FEAB06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FEAC06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = xmlparse.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FEAD06253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = xmlwrite.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FEAE06253BB4005AB5DA = { + children = ( + 1865FEAF06253BB4005AB5DA, + 1865FEEE06253BB5005AB5DA, + 1865FF0806253BB5005AB5DA, + 1865FF0906253BB5005AB5DA, + 1865FF0A06253BB5005AB5DA, + 1865FF0B06253BB5005AB5DA, + 1865FF0C06253BB5005AB5DA, + 1865FF0D06253BB5005AB5DA, + 1865FF0E06253BB5005AB5DA, + 1865FF0F06253BB5005AB5DA, + 1865FF1006253BB5005AB5DA, + 1865FF1106253BB5005AB5DA, + 1865FF1206253BB5005AB5DA, + 1865FF1306253BB5005AB5DA, + ); + isa = PBXGroup; + path = model; + refType = 4; + sourceTree = ""; + }; + 1865FEAF06253BB4005AB5DA = { + children = ( + 1865FEB006253BB4005AB5DA, + 1865FEB106253BB4005AB5DA, + 1865FEB206253BB4005AB5DA, + 1865FEB306253BB4005AB5DA, + 1865FEB406253BB4005AB5DA, + 1865FEC106253BB5005AB5DA, + 1865FECE06253BB5005AB5DA, + 1865FECF06253BB5005AB5DA, + 1865FEDC06253BB5005AB5DA, + 1865FEE106253BB5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FEB006253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FEB106253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FEB206253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FEB306253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FEB406253BB4005AB5DA = { + children = ( + 1865FEB506253BB4005AB5DA, + 1865FEB606253BB5005AB5DA, + 1865FEB706253BB5005AB5DA, + 1865FEB806253BB5005AB5DA, + 1865FEB906253BB5005AB5DA, + 1865FEBA06253BB5005AB5DA, + 1865FEBB06253BB5005AB5DA, + 1865FEBC06253BB5005AB5DA, + 1865FEBD06253BB5005AB5DA, + 1865FEBE06253BB5005AB5DA, + 1865FEBF06253BB5005AB5DA, + 1865FEC006253BB5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEB506253BB4005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEB606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEB706253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEB806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEB906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEBA06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEBB06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEBC06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEBD06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEBE06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEBF06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "remap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEC006253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEC106253BB5005AB5DA = { + children = ( + 1865FEC206253BB5005AB5DA, + 1865FEC306253BB5005AB5DA, + 1865FEC406253BB5005AB5DA, + 1865FEC506253BB5005AB5DA, + 1865FEC606253BB5005AB5DA, + 1865FEC706253BB5005AB5DA, + 1865FEC806253BB5005AB5DA, + 1865FEC906253BB5005AB5DA, + 1865FECA06253BB5005AB5DA, + 1865FECB06253BB5005AB5DA, + 1865FECC06253BB5005AB5DA, + 1865FECD06253BB5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FEC206253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC306253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC406253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC506253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC706253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEC906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FECA06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FECB06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FECC06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "remap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FECD06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FECE06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FECF06253BB5005AB5DA = { + children = ( + 1865FED006253BB5005AB5DA, + 1865FED106253BB5005AB5DA, + 1865FED206253BB5005AB5DA, + 1865FED306253BB5005AB5DA, + 1865FED406253BB5005AB5DA, + 1865FED506253BB5005AB5DA, + 1865FED606253BB5005AB5DA, + 1865FED706253BB5005AB5DA, + 1865FED806253BB5005AB5DA, + 1865FED906253BB5005AB5DA, + 1865FEDA06253BB5005AB5DA, + 1865FEDB06253BB5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED006253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED106253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED206253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED306253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED406253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED506253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED706253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "model.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FED906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEDA06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "remap.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEDB06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEDC06253BB5005AB5DA = { + children = ( + 1865FEDD06253BB5005AB5DA, + 1865FEDE06253BB5005AB5DA, + 1865FEDF06253BB5005AB5DA, + 1865FEE006253BB5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FEDD06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEDE06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FEDF06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEE006253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FEE106253BB5005AB5DA = { + children = ( + 1865FEE206253BB5005AB5DA, + 1865FEE306253BB5005AB5DA, + 1865FEE406253BB5005AB5DA, + 1865FEE506253BB5005AB5DA, + 1865FEE606253BB5005AB5DA, + 1865FEE706253BB5005AB5DA, + 1865FEE806253BB5005AB5DA, + 1865FEE906253BB5005AB5DA, + 1865FEEA06253BB5005AB5DA, + 1865FEEB06253BB5005AB5DA, + 1865FEEC06253BB5005AB5DA, + 1865FEED06253BB5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FEE206253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE306253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicomodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE406253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE506253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "cpicosurface.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "miscmodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE706253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEE906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEEA06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEEB06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEEC06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "remap.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEED06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEEE06253BB5005AB5DA = { + children = ( + 1865FEEF06253BB5005AB5DA, + 1865FF0606253BB5005AB5DA, + 1865FF0706253BB5005AB5DA, + ); + isa = PBXGroup; + path = bitmaps; + refType = 4; + sourceTree = ""; + }; + 1865FEEF06253BB5005AB5DA = { + children = ( + 1865FEF006253BB5005AB5DA, + 1865FEF106253BB5005AB5DA, + 1865FEF206253BB5005AB5DA, + 1865FEF306253BB5005AB5DA, + 1865FEF406253BB5005AB5DA, + 1865FEF706253BB5005AB5DA, + 1865FEFA06253BB5005AB5DA, + 1865FEFB06253BB5005AB5DA, + 1865FEFE06253BB5005AB5DA, + 1865FF0306253BB5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FEF006253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FEF106253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FEF206253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FEF306253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FEF406253BB5005AB5DA = { + children = ( + 1865FEF506253BB5005AB5DA, + 1865FEF606253BB5005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEF506253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_reload_entity.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEF606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEF706253BB5005AB5DA = { + children = ( + 1865FEF806253BB5005AB5DA, + 1865FEF906253BB5005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FEF806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_reload_entity.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEF906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FEFA06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FEFB06253BB5005AB5DA = { + children = ( + 1865FEFC06253BB5005AB5DA, + 1865FEFD06253BB5005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEFC06253BB5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "model_reload_entity.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEFD06253BB5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "picomodel.bmp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FEFE06253BB5005AB5DA = { + children = ( + 1865FEFF06253BB5005AB5DA, + 1865FF0006253BB5005AB5DA, + 1865FF0106253BB5005AB5DA, + 1865FF0206253BB5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FEFF06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF0006253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF0106253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF0206253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF0306253BB5005AB5DA = { + children = ( + 1865FF0406253BB5005AB5DA, + 1865FF0506253BB5005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF0406253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "model_reload_entity.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF0506253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "picomodel.bmp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF0606253BB5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = model_reload_entity.bmp; + refType = 4; + sourceTree = ""; + }; + 1865FF0706253BB5005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = image.bmp; + path = picomodel.bmp; + refType = 4; + sourceTree = ""; + }; + 1865FF0806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = cpicomodel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF0906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = cpicomodel.h; + refType = 4; + sourceTree = ""; + }; + 1865FF0A06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = cpicosurface.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF0B06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = cpicosurface.h; + refType = 4; + sourceTree = ""; + }; + 1865FF0C06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = miscmodel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF0D06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = model.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF0E06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = model.def; + refType = 4; + sourceTree = ""; + }; + 1865FF0F06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = model.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FF1006253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF1106253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FF1206253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = remap.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF1306253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surface.h; + refType = 4; + sourceTree = ""; + }; + 1865FF1406253BB5005AB5DA = { + children = ( + 1865FF1506253BB5005AB5DA, + ); + isa = PBXGroup; + path = sample; + refType = 4; + sourceTree = ""; + }; + 1865FF1506253BB5005AB5DA = { + children = ( + 1865FF1606253BB5005AB5DA, + 1865FF1706253BB5005AB5DA, + 1865FF1806253BB5005AB5DA, + 1865FF1906253BB5005AB5DA, + 1865FF1A06253BB5005AB5DA, + 1865FF1B06253BB5005AB5DA, + 1865FF1C06253BB5005AB5DA, + 1865FF1D06253BB5005AB5DA, + 1865FF1E06253BB5005AB5DA, + 1865FF2306253BB5005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FF1606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FF1706253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FF1806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FF1906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FF1A06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF1B06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF1C06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FF1D06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF1E06253BB5005AB5DA = { + children = ( + 1865FF1F06253BB5005AB5DA, + 1865FF2006253BB5005AB5DA, + 1865FF2106253BB5005AB5DA, + 1865FF2206253BB5005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FF1F06253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2006253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF2106253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2206253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF2306253BB5005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF2406253BB5005AB5DA = { + children = ( + 1865FF2506253BB5005AB5DA, + 1865FF5406253BB6005AB5DA, + 1865FF5506253BB6005AB5DA, + 1865FF5606253BB6005AB5DA, + 1865FF5706253BB6005AB5DA, + 1865FF5806253BB6005AB5DA, + 1865FF5906253BB6005AB5DA, + 1865FF5A06253BB6005AB5DA, + 1865FF5B06253BB6005AB5DA, + ); + isa = PBXGroup; + path = shaders; + refType = 4; + sourceTree = ""; + }; + 1865FF2506253BB5005AB5DA = { + children = ( + 1865FF2606253BB5005AB5DA, + 1865FF2706253BB5005AB5DA, + 1865FF2806253BB5005AB5DA, + 1865FF2906253BB5005AB5DA, + 1865FF2A06253BB5005AB5DA, + 1865FF3306253BB6005AB5DA, + 1865FF3C06253BB6005AB5DA, + 1865FF3D06253BB6005AB5DA, + 1865FF4606253BB6005AB5DA, + 1865FF4B06253BB6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FF2606253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FF2706253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FF2806253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FF2906253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FF2A06253BB5005AB5DA = { + children = ( + 1865FF2B06253BB5005AB5DA, + 1865FF2C06253BB5005AB5DA, + 1865FF2D06253BB5005AB5DA, + 1865FF2E06253BB5005AB5DA, + 1865FF2F06253BB5005AB5DA, + 1865FF3006253BB6005AB5DA, + 1865FF3106253BB6005AB5DA, + 1865FF3206253BB6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2B06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2C06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2D06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2E06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF2F06253BB5005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF3006253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.proj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF3106253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF3206253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shadershl.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF3306253BB6005AB5DA = { + children = ( + 1865FF3406253BB6005AB5DA, + 1865FF3506253BB6005AB5DA, + 1865FF3606253BB6005AB5DA, + 1865FF3706253BB6005AB5DA, + 1865FF3806253BB6005AB5DA, + 1865FF3906253BB6005AB5DA, + 1865FF3A06253BB6005AB5DA, + 1865FF3B06253BB6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF3406253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3506253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3606253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3706253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3806253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3906253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.proj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3A06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3B06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shadershl.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF3C06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FF3D06253BB6005AB5DA = { + children = ( + 1865FF3E06253BB6005AB5DA, + 1865FF3F06253BB6005AB5DA, + 1865FF4006253BB6005AB5DA, + 1865FF4106253BB6005AB5DA, + 1865FF4206253BB6005AB5DA, + 1865FF4306253BB6005AB5DA, + 1865FF4406253BB6005AB5DA, + 1865FF4506253BB6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF3E06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF3F06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4006253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4106253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4206253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4306253BB6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "shaders.proj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4406253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "shaders.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4506253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shadershl.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4606253BB6005AB5DA = { + children = ( + 1865FF4706253BB6005AB5DA, + 1865FF4806253BB6005AB5DA, + 1865FF4906253BB6005AB5DA, + 1865FF4A06253BB6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FF4706253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4806253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF4906253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF4A06253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF4B06253BB6005AB5DA = { + children = ( + 1865FF4C06253BB6005AB5DA, + 1865FF4D06253BB6005AB5DA, + 1865FF4E06253BB6005AB5DA, + 1865FF4F06253BB6005AB5DA, + 1865FF5006253BB6005AB5DA, + 1865FF5106253BB6005AB5DA, + 1865FF5206253BB6005AB5DA, + 1865FF5306253BB6005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF4C06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF4D06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF4E06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF4F06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF5006253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF5106253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.proj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF5206253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shaders.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF5306253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "shadershl.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF5406253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF5506253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FF5606253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = shaders.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF5706253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shaders.def; + refType = 4; + sourceTree = ""; + }; + 1865FF5806253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = shaders.h; + refType = 4; + sourceTree = ""; + }; + 1865FF5906253BB6005AB5DA = { + isa = PBXFileReference; + lastKnownFileType = file; + path = shaders.proj; + refType = 4; + sourceTree = ""; + }; + 1865FF5A06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = shaders.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FF5B06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = shadershl.def; + refType = 4; + sourceTree = ""; + }; + 1865FF5C06253BB6005AB5DA = { + children = ( + 1865FF5D06253BB6005AB5DA, + 1865FF8406253BB7005AB5DA, + 1865FF8506253BB7005AB5DA, + 1865FF8606253BB7005AB5DA, + 1865FF8706253BB7005AB5DA, + 1865FF8806253BB7005AB5DA, + 1865FF8906253BB7005AB5DA, + ); + isa = PBXGroup; + path = spritemodel; + refType = 4; + sourceTree = ""; + }; + 1865FF5D06253BB6005AB5DA = { + children = ( + 1865FF5E06253BB6005AB5DA, + 1865FF5F06253BB6005AB5DA, + 1865FF6006253BB6005AB5DA, + 1865FF6106253BB6005AB5DA, + 1865FF6206253BB6005AB5DA, + 1865FF6906253BB6005AB5DA, + 1865FF7006253BB6005AB5DA, + 1865FF7106253BB6005AB5DA, + 1865FF7806253BB6005AB5DA, + 1865FF7D06253BB6005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FF5E06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FF5F06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FF6006253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FF6106253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FF6206253BB6005AB5DA = { + children = ( + 1865FF6306253BB6005AB5DA, + 1865FF6406253BB6005AB5DA, + 1865FF6506253BB6005AB5DA, + 1865FF6606253BB6005AB5DA, + 1865FF6706253BB6005AB5DA, + 1865FF6806253BB6005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6306253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6406253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6506253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6606253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6706253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6806253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF6906253BB6005AB5DA = { + children = ( + 1865FF6A06253BB6005AB5DA, + 1865FF6B06253BB6005AB5DA, + 1865FF6C06253BB6005AB5DA, + 1865FF6D06253BB6005AB5DA, + 1865FF6E06253BB6005AB5DA, + 1865FF6F06253BB6005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF6A06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF6B06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF6C06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF6D06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF6E06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF6F06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF7006253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FF7106253BB6005AB5DA = { + children = ( + 1865FF7206253BB6005AB5DA, + 1865FF7306253BB6005AB5DA, + 1865FF7406253BB6005AB5DA, + 1865FF7506253BB6005AB5DA, + 1865FF7606253BB6005AB5DA, + 1865FF7706253BB6005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7206253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7306253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7406253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7506253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7606253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7706253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "spritemodel.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7806253BB6005AB5DA = { + children = ( + 1865FF7906253BB6005AB5DA, + 1865FF7A06253BB6005AB5DA, + 1865FF7B06253BB6005AB5DA, + 1865FF7C06253BB6005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FF7906253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7A06253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF7B06253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF7C06253BB6005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF7D06253BB6005AB5DA = { + children = ( + 1865FF7E06253BB6005AB5DA, + 1865FF7F06253BB6005AB5DA, + 1865FF8006253BB6005AB5DA, + 1865FF8106253BB6005AB5DA, + 1865FF8206253BB7005AB5DA, + 1865FF8306253BB7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FF7E06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF7F06253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF8006253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF8106253BB6005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF8206253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF8306253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "spritemodel.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF8406253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF8506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FF8606253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = spritemodel.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FF8706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = spritemodel.def; + refType = 4; + sourceTree = ""; + }; + 1865FF8806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = spritemodel.h; + refType = 4; + sourceTree = ""; + }; + 1865FF8906253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = spritemodel.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FF8A06253BB7005AB5DA = { + children = ( + 1865FF8B06253BB7005AB5DA, + 1865FF8C06253BB7005AB5DA, + 1865FFB706253BB7005AB5DA, + 1865FFB806253BB7005AB5DA, + 1865FFB906253BB7005AB5DA, + 1865FFBA06253BB7005AB5DA, + 1865FFBB06253BB7005AB5DA, + 1865FFBC06253BB7005AB5DA, + ); + isa = PBXGroup; + path = surface; + refType = 4; + sourceTree = ""; + }; + 1865FF8B06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + 1865FF8C06253BB7005AB5DA = { + children = ( + 1865FF8D06253BB7005AB5DA, + 1865FF8E06253BB7005AB5DA, + 1865FF8F06253BB7005AB5DA, + 1865FF9006253BB7005AB5DA, + 1865FF9106253BB7005AB5DA, + 1865FF9906253BB7005AB5DA, + 1865FFA106253BB7005AB5DA, + 1865FFA206253BB7005AB5DA, + 1865FFAA06253BB7005AB5DA, + 1865FFAF06253BB7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FF8D06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FF8E06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FF8F06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FF9006253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FF9106253BB7005AB5DA = { + children = ( + 1865FF9206253BB7005AB5DA, + 1865FF9306253BB7005AB5DA, + 1865FF9406253BB7005AB5DA, + 1865FF9506253BB7005AB5DA, + 1865FF9606253BB7005AB5DA, + 1865FF9706253BB7005AB5DA, + 1865FF9806253BB7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9206253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9306253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9406253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9606253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FF9906253BB7005AB5DA = { + children = ( + 1865FF9A06253BB7005AB5DA, + 1865FF9B06253BB7005AB5DA, + 1865FF9C06253BB7005AB5DA, + 1865FF9D06253BB7005AB5DA, + 1865FF9E06253BB7005AB5DA, + 1865FF9F06253BB7005AB5DA, + 1865FFA006253BB7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FF9A06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF9B06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF9C06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF9D06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF9E06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FF9F06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFA006253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFA106253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FFA206253BB7005AB5DA = { + children = ( + 1865FFA306253BB7005AB5DA, + 1865FFA406253BB7005AB5DA, + 1865FFA506253BB7005AB5DA, + 1865FFA606253BB7005AB5DA, + 1865FFA706253BB7005AB5DA, + 1865FFA806253BB7005AB5DA, + 1865FFA906253BB7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA306253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA406253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "surface.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA606253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFA906253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFAA06253BB7005AB5DA = { + children = ( + 1865FFAB06253BB7005AB5DA, + 1865FFAC06253BB7005AB5DA, + 1865FFAD06253BB7005AB5DA, + 1865FFAE06253BB7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FFAB06253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFAC06253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FFAD06253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFAE06253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FFAF06253BB7005AB5DA = { + children = ( + 1865FFB006253BB7005AB5DA, + 1865FFB106253BB7005AB5DA, + 1865FFB206253BB7005AB5DA, + 1865FFB306253BB7005AB5DA, + 1865FFB406253BB7005AB5DA, + 1865FFB506253BB7005AB5DA, + 1865FFB606253BB7005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FFB006253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = ".cvsignore.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB106253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB206253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB306253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB406253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB606253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFB706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = surface.def; + refType = 4; + sourceTree = ""; + }; + 1865FFB806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = surface.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FFB906253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfacedialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FFBA06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfacedialog.h; + refType = 4; + sourceTree = ""; + }; + 1865FFBB06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfdlg_plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FFBC06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfdlg_plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FFBD06253BB7005AB5DA = { + children = ( + 1865FFBE06253BB7005AB5DA, + 1865FFED06253BB8005AB5DA, + 1865FFEE06253BB8005AB5DA, + 1865FFEF06253BB8005AB5DA, + 1865FFF006253BB8005AB5DA, + 1865FFF106253BB8005AB5DA, + 1865FFF206253BB8005AB5DA, + 1865FFF306253BB8005AB5DA, + 1865FFF406253BB8005AB5DA, + ); + isa = PBXGroup; + path = surface_heretic2; + refType = 4; + sourceTree = ""; + }; + 1865FFBE06253BB7005AB5DA = { + children = ( + 1865FFBF06253BB7005AB5DA, + 1865FFC006253BB7005AB5DA, + 1865FFC106253BB7005AB5DA, + 1865FFC206253BB7005AB5DA, + 1865FFC306253BB7005AB5DA, + 1865FFCC06253BB7005AB5DA, + 1865FFD506253BB7005AB5DA, + 1865FFD606253BB7005AB5DA, + 1865FFDF06253BB7005AB5DA, + 1865FFE406253BB7005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FFBF06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FFC006253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FFC106253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FFC206253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FFC306253BB7005AB5DA = { + children = ( + 1865FFC406253BB7005AB5DA, + 1865FFC506253BB7005AB5DA, + 1865FFC606253BB7005AB5DA, + 1865FFC706253BB7005AB5DA, + 1865FFC806253BB7005AB5DA, + 1865FFC906253BB7005AB5DA, + 1865FFCA06253BB7005AB5DA, + 1865FFCB06253BB7005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFC406253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFC506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFC606253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFC706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFC806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFC906253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFCA06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFCB06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFCC06253BB7005AB5DA = { + children = ( + 1865FFCD06253BB7005AB5DA, + 1865FFCE06253BB7005AB5DA, + 1865FFCF06253BB7005AB5DA, + 1865FFD006253BB7005AB5DA, + 1865FFD106253BB7005AB5DA, + 1865FFD206253BB7005AB5DA, + 1865FFD306253BB7005AB5DA, + 1865FFD406253BB7005AB5DA, + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FFCD06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFCE06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFCF06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFD006253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFD106253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFD206253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFD306253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFD406253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFD506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = README.txt; + refType = 4; + sourceTree = ""; + }; + 1865FFD606253BB7005AB5DA = { + children = ( + 1865FFD706253BB7005AB5DA, + 1865FFD806253BB7005AB5DA, + 1865FFD906253BB7005AB5DA, + 1865FFDA06253BB7005AB5DA, + 1865FFDB06253BB7005AB5DA, + 1865FFDC06253BB7005AB5DA, + 1865FFDD06253BB7005AB5DA, + 1865FFDE06253BB7005AB5DA, + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFD706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFD806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = "surface_heretic2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFD906253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFDA06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFDB06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFDC06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFDD06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFDE06253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFDF06253BB7005AB5DA = { + children = ( + 1865FFE006253BB7005AB5DA, + 1865FFE106253BB7005AB5DA, + 1865FFE206253BB7005AB5DA, + 1865FFE306253BB7005AB5DA, + ); + isa = PBXGroup; + path = tmp; + refType = 4; + sourceTree = ""; + }; + 1865FFE006253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFE106253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = props; + refType = 4; + sourceTree = ""; + }; + 1865FFE206253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = "text-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFE306253BB7005AB5DA = { + children = ( + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FFE406253BB7005AB5DA = { + children = ( + 1865FFE506253BB7005AB5DA, + 1865FFE606253BB7005AB5DA, + 1865FFE706253BB7005AB5DA, + 1865FFE806253BB7005AB5DA, + 1865FFE906253BB8005AB5DA, + 1865FFEA06253BB8005AB5DA, + 1865FFEB06253BB8005AB5DA, + 1865FFEC06253BB8005AB5DA, + ); + isa = PBXGroup; + path = wcprops; + refType = 4; + sourceTree = ""; + }; + 1865FFE506253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.def.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFE606253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_heretic2.vcproj.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFE706253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFE806253BB7005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFE906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFEA06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfaceflagsdialog_heretic2.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFEB06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.cpp.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFEC06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfdlg_plugin.h.svn-work"; + refType = 4; + sourceTree = ""; + }; + 1865FFED06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = surface_heretic2.def; + refType = 4; + sourceTree = ""; + }; + 1865FFEE06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = surface_heretic2.vcproj; + refType = 4; + sourceTree = ""; + }; + 1865FFEF06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfacedialog.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FFF006253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfacedialog.h; + refType = 4; + sourceTree = ""; + }; + 1865FFF106253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfaceflagsdialog_heretic2.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FFF206253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfaceflagsdialog_heretic2.h; + refType = 4; + sourceTree = ""; + }; + 1865FFF306253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = surfdlg_plugin.cpp; + refType = 4; + sourceTree = ""; + }; + 1865FFF406253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = surfdlg_plugin.h; + refType = 4; + sourceTree = ""; + }; + 1865FFF506253BB8005AB5DA = { + children = ( + 1865FFF606253BB8005AB5DA, + 1865002506253BB8005AB5DA, + 1865002606253BB8005AB5DA, + 1865002706253BB8005AB5DA, + 1865002806253BB8005AB5DA, + 1865002906253BB8005AB5DA, + 1865002A06253BB8005AB5DA, + 1865002B06253BB8005AB5DA, + 1865002C06253BB8005AB5DA, + ); + isa = PBXGroup; + path = surface_quake2; + refType = 4; + sourceTree = ""; + }; + 1865FFF606253BB8005AB5DA = { + children = ( + 1865FFF706253BB8005AB5DA, + 1865FFF806253BB8005AB5DA, + 1865FFF906253BB8005AB5DA, + 1865FFFA06253BB8005AB5DA, + 1865FFFB06253BB8005AB5DA, + 1865000406253BB8005AB5DA, + 1865000D06253BB8005AB5DA, + 1865000E06253BB8005AB5DA, + 1865001706253BB8005AB5DA, + 1865001C06253BB8005AB5DA, + ); + isa = PBXGroup; + path = .svn; + refType = 4; + sourceTree = ""; + }; + 1865FFF706253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "dir-wcprops"; + refType = 4; + sourceTree = ""; + }; + 1865FFF806253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "empty-file"; + refType = 4; + sourceTree = ""; + }; + 1865FFF906253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + path = entries; + refType = 4; + sourceTree = ""; + }; + 1865FFFA06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = format; + refType = 4; + sourceTree = ""; + }; + 1865FFFB06253BB8005AB5DA = { + children = ( + 1865FFFC06253BB8005AB5DA, + 1865FFFD06253BB8005AB5DA, + 1865FFFE06253BB8005AB5DA, + 1865FFFF06253BB8005AB5DA, + 1865000006253BB8005AB5DA, + 1865000106253BB8005AB5DA, + 1865000206253BB8005AB5DA, + 1865000306253BB8005AB5DA, + ); + isa = PBXGroup; + path = "prop-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFFC06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.def.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFFD06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surface_quake2.vcproj.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFFE06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.cpp.svn-base"; + refType = 4; + sourceTree = ""; + }; + 1865FFFF06253BB8005AB5DA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = "surfacedialog.h.svn-base"; + refType = 4; + sourceTree = ""; + }; + }; + rootObject = 1865EBCC06253B29005AB5DA; +} diff --git a/radiant/.cvsignore b/radiant/.cvsignore new file mode 100644 index 00000000..72b49b5f --- /dev/null +++ b/radiant/.cvsignore @@ -0,0 +1,16 @@ +Debug +Release +radiant +*.d +*.o +*.opt +*.ncb +*.BAK +*.00* +*.plg +radiant +q3map +unnamed.map +.snprj +tools +*.gcse diff --git a/radiant/Makefile.mac b/radiant/Makefile.mac new file mode 100644 index 00000000..27260a84 --- /dev/null +++ b/radiant/Makefile.mac @@ -0,0 +1,91 @@ +## Makefile for GtkRadiant + +ifeq ($(DEBUG),1) +DEBUG=true +else +DEBUG=false +endif + +CC=gcc +CPPFLAGS=-I../libs -I../include `gtk-config --cflags` `xml-config --cflags` -I/usr/X11R6/include -Wall -DQUAKE3 +LDFLAGS=`xml-config --libs` +DATE=`date +%m%d` +ZIP=radiant-src.$(DATE).tgz +LIBS=../libs/cmdlib.a ../libs/pak.a ../libs/jpeg6.a ../libs/l_net.a +OUTDIR=$(RADIANT_DATA) + +LDFLAGS += $(subst -rdynamic,,$(shell gtk-config --libs)) -lGL /usr/local/lib/libdl.a + +ifeq ($(DEBUG), false) +CPPFLAGS += -O3 -DNDEBUG +else +CPPFLAGS += -g -D_DEBUG +endif + +CFLAGS=$(CPPFLAGS) + +SRC= glwidget.cpp qgl.c bmp.cpp brush.cpp brush_primit.cpp brushscript.cpp camwindow.cpp \ + csg.cpp dialog.cpp dialoginfo.cpp drag.cpp eclass.cpp entity.cpp file.cpp \ + findtexturedialog.cpp glinterface.cpp glwindow.cpp groupdialog.cpp gtkdlgs.cpp \ + gtkmisc.cpp iepairs.cpp ishaders.cpp lbmlib.cpp \ + main.cpp mainframe.cpp map.cpp mathlib.cpp messaging.cpp missing.cpp parse.cpp \ + patchdialog.cpp plugin.cpp pluginentities.cpp pluginmanager.cpp pmesh.cpp \ + points.cpp preferences.cpp profile.cpp qe3.cpp select.cpp \ + selectedface.cpp shaderinfo.cpp surfacedialog.cpp surfaceplugin.cpp \ + texwindow.cpp undo.cpp vertsel.cpp watchbsp.cpp winding.cpp xywindow.cpp \ + z.cpp zwindow.cpp feedback.cpp gtkfilesel-darwin.c + +# TA_HACK +SRC += vfs.cpp + +OBJS := \ + $(patsubst %.c,%.o,$(filter %.c,$(SRC))) \ + $(patsubst %.cpp,%.o,$(filter %.cpp,$(SRC))) + +all: radiant + +help: + @echo 'Use "make DEBUG=0" or "export DEBUG=1; make" for release builds' + +radiant: $(OBJS) $(LIBS) + $(CC) -o radiant $(OBJS) $(LDFLAGS) $(LIBS) + @if [ -d $(OUTDIR) ]; then cp radiant $(OUTDIR); fi + +# Other targets +.PHONY: clean veryclean + +clean: + rm -f *.o *.d radiant core + +veryclean: clean + find libs -name \*.o | xargs rm -f + rm -f libs/*.a + +zip: veryclean + cd .. && tar -zcf $(ZIP) radiant + +## Dependencies + +-include $(OBJS:.o=.d) + +## Libraries + +../libs/cmdlib.a: + cd ../libs/cmdlib && make + +../libs/pak.a: + cd ../libs/pak && make + +../libs/jpeg6.a: + cd ../libs/jpeg6 && make + +../libs/l_net.a: + cd ../libs/l_net && make + +libs: + cd ../libs/cmdlib && $(MAKE) clean && $(MAKE) DEBUG=$(DEBUG) + cd ../libs/pak && $(MAKE) clean && $(MAKE) DEBUG=$(DEBUG) + cd ../libs/l_net && $(MAKE) clean && $(MAKE) DEBUG=$(DEBUG) + +tools: + cd ../q3tools/q3map && $(MAKE) clean && $(MAKE) DEBUG=$(DEBUG) diff --git a/radiant/bitmaps/brush_flipx.bmp b/radiant/bitmaps/brush_flipx.bmp new file mode 100644 index 0000000000000000000000000000000000000000..91f3d669dda151af543b10ab28f4e294cc86c05e GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!uh(7^B?2pbw27#eUX!6PmxC@7!^ByiEfg2Dod fhJrw7D4-}TEGQ@pQg4W$q2h3L1k3~31F{SNlY0=` literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/brush_flipy.bmp b/radiant/bitmaps/brush_flipy.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0f8e65c610f5368a73925c35fb1bd848853358d8 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!uh(7^B?2pbw27#eUX!6PmxC@7!^ByiHgKzTz! bLqTL(SXfZd&=9B(BrJ?V<1`1!9*|`KjDHZh literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/brush_flipz.bmp b/radiant/bitmaps/brush_flipz.bmp new file mode 100644 index 0000000000000000000000000000000000000000..38c20ff2519d5f02b80269ef76928be6b6d93f65 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!uh(7^B?2pbw27#eUX!6PmxC@7!^BnZ*M#>N7Q f#>R$%h9LFAfvNT1E`3B5ljQ!3*m#rg@BqM!ipeKpfZ?gAf6xq8^jHU literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/brush_rotatez.bmp b/radiant/bitmaps/brush_rotatez.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fcea0814fb8ebcd4c8faae2fc244f9f857e8be36 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!uh(7^B?2pe!o6A%|f0z!g9V4jem5`-3l@)cp? n5E`yU0Lo%u6ckiaQUtnJ5NrfkTv1REC=3z+ih|`q6bt|W69Ely literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/cap_bevel.bmp b/radiant/bitmaps/cap_bevel.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0de324422fd7dba22730213de7b6f25766141550 GIT binary patch literal 154 zcmZ?roy7nFc0fu4h$Vqo9Ecf#5Ep0wO8o!-pWz3PM#q1EV#xR(kPpKDLAU{m4*=;0 VK>PuSfr|eF75oPZ0L^TGVE}qrD%t=5 literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/cap_endcap.bmp b/radiant/bitmaps/cap_endcap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8e6c7f2a36d1b44edd04cbdcc55cbc5845ba75f6 GIT binary patch literal 154 zcmZ?roy7nFc0fu4h$Vqo9Ecf#5Ep0wO8o!-pWy%lV*{!90RwXb41Zu?Z}`E$-|&Y) SzTqE(eZ&8Q{~Lhjf-wN=L@Go8 literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/cap_ibevel.bmp b/radiant/bitmaps/cap_ibevel.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ccab98daa2eacb91123dba59b83ff5837d279634 GIT binary patch literal 154 zcmZ?roy7nFc0fu4h$Vqo9Ecf#5Ep0wO8o!-pMm}V{|0o-3=~7gj6gmJ12r@-)I+g7 Vkd_BxejsKBVn!flkOvtH2LR8SFW&$F literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/cap_iendcap.bmp b/radiant/bitmaps/cap_iendcap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9640c9ae8c97b9c5d183743b93a805bbbabc9f48 GIT binary patch literal 154 zcmZ?roy7nFc0fu4h$Vqo9Ecf#5Ep0wO8o!-pTYkBKa#Qh|33^c%>Vxf1N;9E49x!@ PFfjfJQ3M!%P$U zNR?V^^r9+|>V3ri?@?k%5JwhEi9*44#)MSiviC!AQhE0sKNck;D4f}dq&aVc^!G%@ FcYQaM77YLZ literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/dontselectcurve.bmp b/radiant/bitmaps/dontselectcurve.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a7b9795453902fefcccac030a4fea52bed91b66e GIT binary patch literal 238 zcmaitK@Na02n3hLyV4f`C*R@S?|AmbexWXHk0z49vO|F5d@$mo?97e1G6f6kcQiB( z8t(7$FV%d)SE4BbbU>JZwgcKQS3!iqw3dRYW^h&daIIcTK)Kh~vy3wdgmxax1}}ue B3CaKf literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/dontselectmodel.bmp b/radiant/bitmaps/dontselectmodel.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e81b118950ff73cb8aec9d83770c59a68ede1251 GIT binary patch literal 238 zcmaitK@Na02n3<=ZnrPkdh#9K{f=i}>=)|NdTb&IEIR}^&c{Yvl3kgVtI};zokz2# zL9=^4{-uZ~dgTalvkn9U$aWx0I%?uZ5+%uYWdI<2MfO4(wAa_8j57gT_B$Ajy{JQ3;-zp4B;SZi0+#q2Okt^9FTKQB9X{^CM!MpnV*WX!6&CX3>cf* E1G1zTbpQYW literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/file_save.bmp b/radiant/bitmaps/file_save.bmp new file mode 100644 index 0000000000000000000000000000000000000000..651afb68952db64d2954394aa6252f2fb3bccf3b GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!vMaNxiJhW|jw(9nQe5e^w87=Xw#DHsD8g3Q=y e29P)yK;#*WnG_5JfdD9umu7& z6Ol&ZV|$oSI-YIv{Tf}1r125l@&eV3!LLV-vVK@QZQm6ngjzy%;1WVnEr?uWC@G>D h*BH7MY5B&Qf1j@fo!|hW_aF6`=hU6B&7Z6mJ^@8kE3g0n literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/logo.bmp b/radiant/bitmaps/logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..759b87cbfa56446b28f29c0f86b298fd10edf435 GIT binary patch literal 47936 zcmeHw=XV=dmM4jvLm?FkC=_xP0D?#)mn=CED9YoihAb_1?Yr z{oZ}|-WTdAR+#$xp5_&XUkd)a)cUWt2W>v5e|{xr{%b$zCb|f85$Gb&MWBm77lAGU zT?D!a>=FX;(QG0-8y~DhL*=kN%474}j9F~X$Y?GVo=XhQ#s+4_{nM0VI5JX-4^$w3 zY_J@{BWxD8ou5f?xPsVZB{9h4nH{0BJdQvp5Tz1JiSS%}faXOP56wmc<#BgDY>s-d zA;LiR_OiE;qFe*{%t~r%F*UUm8?IQ5Zpfg~5V?3AipK_K$NYJl!n3Uu{AnWG*@;C) z&Z%I@YoMcX-0aRy)ncKUNq;e9jq^Cd&Vpi*G8J8Hiai?*mikOXoo|`6P$}mtO-q$z&}^#yX2M)4hWund!nh zl*(jQqLHdzNx*X*W}lfqkV!WZQ%eJVX)brOrqJxcU~+nTjjmU2C7o(`t)q{S?cobV z)3a;&JPk-XQwunvy*=CY<&^#Al0`yet+cGBrC5RZOpBQuSD5 z!EW-yE3rads_bjy;WLdG^%fIu$Bj0V(T1UBpLa5sUCCt{xpX5QU9{mYC?ya`a>dnL zW|c13ymRT*TzUm=h7?pf9$B0WmNbaIEiC03q}w?K0yLuI^9Gfjc}04MOC?$c05Te! zwd-9VfXPJP1mUonU8z)!=9OBB#~1tTldN726x8V*rSe8L)kr0l2goFcEod_`;jU7# z*~oNd8|mb-pPX#JZ72AA5nT&VAJB#5@~|h(dZe$mGw&dgOfNBDfbxy{i#%=%d#%>W z)UR2^mH0$e&PRY=FN-}9o1Mj zjBb;r0GVVxF}4^Vs-`BEnqn;GlC9SI6^X|3}&ia*`J}cYX<`=5VJg4hDS#fGwr36CBbY%~q3vWSV23;u*hsWmf z1X8KlHPZi!?t1wPK{O&Y0H4LYz~7xG%}fn9@Hl2_Kg(_ExR5YtGdh~<`vkS_VYw!2}fGk zL)repXuDZx_(6v3>U6FJ3?n&U9QLKzEZX3}Wi-10d)ns2Ya^id%^r@Twi3gd0lxX0 zOw@eT1XHT>m)83d*c{rL0g<31{w=X*Y!39qWPQ|~SIaPuI}A;cg9@c-XErpLQz|!Y za8s7v@OZA+Y#b;x63pXv7fRT1wA8N6-~(cS+Fuw#KB>^$}OD(^6{mX0Qgp z4y-{ux#Vt!CBTSs50oC-oT;%nRAz1?Ay;7K`2$QN$EOxNt`Vc#gZF#9qZ3T;f>%?K zd9$Wvrl6qSK$Zb}KsU8A;V(g(@Ok1?dO6S7&kpR<@#UcN@%BDnUduIA3@qw^^V{nE zLwipPm0U@UFJ)qNIt@r9mPf(`gRW&S+x3P7YI4q04nQT+>Bcabf#?Gsvf12B5gLs) z1)w?(y{}yau&3>PZWUTJ8LRp2TOtIN+EAXOjTji(=;)k_phH5qNWi|*vN_4f5}~Ez z9OhzidFf&uYy}XEPR?7^bodDur~vIEX!l$n3l~K^8S@-|4LDhzX<`q}GE{*W)9V?B z?#fg)k*uZD%S;-gqk!WH*cVsxIk2(Iu|(BRMOfb|&S~3wnr&0pnFxgb6QGSPM*=e; zDhl1LT?t5Vc%nQ6dYM%)-eUtrmDB(a<#M!GZbb`I6LW}I*DfLyO0(0nSpc%BL~V#n zx4Q)7K@hA^YMD47=rySY98|_3=+p;MW{91Govs7cy!o6$M^Y}wR{eOWe8MjVb2x~>g2Vv zG~;U-bsP;9L{fw!5{Xp^=5R!(t4u6OhyKB`L1peFiKy}NTvLrwjS+X6!{&`f3QQNK zt%_}|Gc)*F+EO+xYcgI7P_a(zF$_?7h<$3g4{zBV%0t_G=v{CprxwlHE!Gd(HlAOg z2Sn+5Y-Apj+ti3LS6BsA27@!~&u<&K8gPn^@0(iIj*e*4G+dU7RUqw1Bwv_br#nWn z9<)Cu#^muu&E89oUclFmg^Dl=>a6BBOmD_HQ;T6L)k#ckFf;uZD1|2xREI3?{(7)xxb70BKV- zhnXHTf^{05$hXFl$@&wDl7&Ws$>soH=u-bw$Pr`yP$(2*dSZMe zM-LC^5lthVsErSm#ln_@ba}$Fl>^neBbD<0#N;A@Zqa*?fiIL7=Qn6m)|_+z)&MHd z84s5c$(HE}$gDR)e9-dT4ECV(;4dLWfVWNTrdRU{;VtdYqo}r+JT8)wZ?4y%>dV^!O zLTd`#kOzQ|j8`O0YXjtH?8j-nhqn-8hA2ADf$j?WosKRg$E)edg>0hE06(3pP3LRy zn@cXFC+E^r3#rM4vA%p;tequNxdo=)^zbCpNJJLlj*nGS(HdC3)~oai#A|%6cpFI$ zM>t)9XlFAUG~igMAQ39I|cn@%fuvT!4LLW4`iyb?#Vnw9*;h zx9QV}&g}<}OQYVj4{esHKBXUnMrwN1TGH(*rbv(WwurU3KB z1_YHbc}ACN{({oCum||_%lRCP5bC*neJWIFOSQ8^Hor(?oPuesMjoa$vS7j?0ryHC zo+RmDV05^sMd_))N3Xu%M454uO(OB=5@{ZUnrzDn*ca$}(<4HrNtubXe5yg;nR+(A z><>gFVr6H+rp?)yn|Xe*ax4?8nYEh(rFJ$hUtFBu0|JBmbPJ>#k&#)YbThnd=Y$w@ z2IBjsLS+*5k#L^J-JDJX>?adtn77R)={P6opnWZ1KV4eSZxOr6=pj3XDYPfRKk3i4 zdF?C_EtKNf1^Uia6NR~Cv63py!ksM6OidR;$+*SQ$K!44;x?*MnI<)}+$_Ej%~S_R zvMLE3>us0;l&KNQ@Y z1?=SeJx+5t9JyR>wOY+)vsf$!L_3A$aal@TlCTVKwn+0eWCLHVQmLQ_;NMxKo8B=3 zTrL+w(UV6H?`<>?1mSSEEQIlRY`HpXGLNyhf)CgO@VRUT$Bo;XYsZ|s8Ntrr218?U zb!C1*r_=FxyiQC60-jV|G+Uyat-1|1M=F&#DX(6Sb(*QpvfcF8BGB8b)9O;m1C{9+ zwMq%yptFQnERv`zW@~cmV>*ja$k!Q06v*R)fKDRa^pg=#DOI8HYHU0%5ev5|u|zBt zAqyr;R>0fh2Y?uK2^BgfMQl$d+vVqjfT5F zQtMFSm9O0BO6&!jBd(Tj!5&6hG9=g|IWEy1Fd6OJ$f(tr z-f~KX)nPQe?N#^BogpCL^;+y%q2{d76xGPL1d`A!GSx_r_=HG(h%jw#jA97W*qfh6 zusvew_7G@ioV&S%0ybeQ@Kxswcv7R--1P~_@OZs)b)-jpQivQenLM3XL3E_n;3#og zsXr){ZdvW>%+^i+Q3NC+uGu=vRbJ2=(>i2x3m+5`^4Tg~qDOj)r#xcB`#XoP5CZ9R zHjFs0zz$30+e4r~%CP&gjetTTz%2_LhVq z1szlP98QnNHA#7IDGle5j=kZX#k=VzBLHjM95#!zJNx|Sw3b&*);(6^mcgr1AvZe? z$@N!yBquGltf*tQ2lkT;1oM6Vy9(^03iWonf+sWVzG))>dpiUIe#jRZ8og$4-n7^c zQdUd*EhJ#p0Jj|nbJQa_1xr_A(dPJ7DC7kF)1>#d1bsn`g<$rfdwmlGU}uh4EF2pi zAB)_wdhSqt&-*B9)1>$GC=_ag^|Z$HYLDc!(K0KQY;GfiQ32`BINY}-x{E6PNOy`^WVL`2?DSk1X0S<@!~}MegDw?iO7vyEFqIhp-mVv8VycRFPWUTS&H+x zwGNrvoZGbCceir1xEc`m)t|M62D5KxHza&X~gNZwl2fB8DQE zpvQ6OK6?@Zu#H$E=1-1RMkAkwMji|d-^#_a3K?vNrIi>)u115;)qj`ry)V&UwK-3~ z_O&)Csg$qLr!gB~|B^yKClYPC;dY*G;>ifWPE158j!rHIhTkWBZ#(;5jgBTH!qz?< z2pb6^OnUD+z3(av*Dd5317>U!lS=q1eI9q*mS`_4&?Sj%%j9!ATQ~6p1i&;pUklPri}o&Q#B$B1lP5e*Hpx-sO75P6OoErmRrc{ zHJLL;=WP>t+i1USa$M14n{#HkK~GrMF&g`qMXC)%z3B?t^t*{CAOP_=i_J3V)Pc}` zt>twMaUHe1;-V(xlGfs@h|jV(W(ewS6M4r(-NPN%5cQ_bu@HpCzF%*HvDIZEa!{q- z{zc~#*mfTS0xbBFm&>u53?rkb431k`^Q$`Zb<#0`JluCF5^~($hQ03tu=iHadj$1{ zMnkqoP=v{Z+YX`DTY$Ylbwq=jyQuCM0eTXX!y#?v(TNKLb%$1c({&da($y05e|+p}!fxw;j`4-vVDNK#rk$$BsF7GcwqFNax_li#T~l zZ+$~cyyo>}F->dfN+uD8!>4?MUpl<^0eiClJtHy1d3wxzh6dpPs82*aJ-uI!) z|B=Bo#vIAQX0sf25;LDft#8TDD;&j14d&}k;XeX7z|5#P%$)JzGh2~J3g0s*6k3hO zfE%-kWF&Eu^uK5Iyp1_-TWz5Ct>to!QV|}$)Ia#8+4YXibD#2mj1#fuh!-Y6Sstn% zx1Ohct?p%({EQA8+=n_+5doY&GDOGym5If7a25IU&d^2fxYjMo<)g8Uobxq&JGSn1A!rr$4in9hr?np zYE>$kSPWmR(<@t`^&B{4u-W~Dux7^Nfxm~Q*e3aAOMUNBASuWTU_*e;q+#Y!0B3GU zL`sEJkE$#dlg;jMxdVfP@rj9QHhUyrxDZWV42@jygxM%PC$U#+@d3t~hK2k9`Ud0{v6xj7% z`MDn1IoQV2D?0%@d4$Lzk!l6OmT=pGjVzJwl(#Pu2#k;vWwDw`r=<@(yu%I_55A6u z4hd!uS_4cXtv=t=b^w?`Ixd`d%;yUQLbydj0et*{_w6G0$+VzgkDk_Uy&KE3DlPa>T3p~ zXfd=ViV-DZqt4*ueHHPh-gehaePDBzxy^|-K93vnO<1Vc&D6U}!>fQjTXCK(hpi-M zd!?sY($hWS=jmH`yhm`XM|^~0z$ouvmLojUTeQ4hM&h zP9=^O%Ll9TYjd-eOd=Wz^jipAr9!05&cHOncVv!eMF-TmU{8cni4>MDTy8R!h?i#< zvW1nQ@rIdPl%rL?VgV%%kDTWr=eWu^ZW1Y}q|uA3Zn%C|C=+E`pVTCc4a^SOb5Pmk&(QYkoQ+8gXfTm*c;{eTH{d))bA zX>oafGP~vFWeNKg+ z*P1V>OqaCQ>uTavBX!pi_`v4BZ}EL(>HmZr_`*N_)nNSRW0_w~m7-%KS> z_E8pYbFCZ}Q4B;~YkgO1y^C7khN&B)iT;!plmbOH)%o@5`CnC6|7E)R`_bfIg`>X? zPX4)n>?_ycXI9?_2I>yxd`oY8Lrq*$;+JLE1)2VgM0Y}@0XMv#r(EYMR(XmBPf_P1 zOMK;mNHs6lEhw-mVwlxgDg-(28-#-@_pR+Yy4F~o7#;>Q3#TV?IP_xXvs8T`4;QM( z;>mQmvK&o9_*Qhdr%m=8YRah$d9|^uK+7`ij7(dVX_w_F%;lakk{6BCWwZA+XXsX7 z?Cs&i{b=FCOy#5e{QbF=k1F+d=IeKs*WO%Oy*{(>LVosSv3k6^d}?v!)XMtvwbf(Q z+Wx{!J((@QWC4U6P(O)~Yqr;Q*7r5$J1Wy11b)?i;Ds6%A%Vqo&MiOk(p<(*Rf zz3R&CYW-Tddb&J+uvA&e!}(LG?8M|mI2`Ktx@>ln*^F5%2EwG*>0qy)7@|>~7SW>` zy-ouQAqs^QLOnR1Lcpi(E64!zn1pQsbAABWEAiWM?5a}bfQp0OgV%=xTvTd>R;xmF zDxFq^AX2451gl^$oUqw&yWQk;n)|$DAkaS;9vF{IB+~h8VF3Q^6z_xUd9~zb>^Cmn9<@n9iBE=lNK^bc~kwN%w(*T%a_3R0{3Tz zJ+1Mm-X9$Bc*E|#F&jBbIL6G*gu^rI8#)}xUahWuSl|Eg>Y;n}jjPqhvEpnk5{m_c zK8mywgkGx!_aKwYBoKSTErZ=Qu>A>QQ7~bAfEK*A0JI0tg{$=h#yET!<bmT^!JjL{dI010LSF8UWHGQ`ll zY85mWf*G_{i^1)74h)8pa86=vW8=`}jU%_}8}F>_|7`u>kIM^pL!-w?Z`DSnty$lqpjILN-f{-Mx7Y+`C@uJ-cU!S{}x|Ivwa_xB!pp**)V zIyypZ#9#ztnhTTw5}*=r2oDSi)oO*A!1}zdNOWqs zap2^cH%?!CaPjJ|j-LFiP&q#^GVAn=nXO*E!D__K(8=1|pI!o_Ga8LfCpi^O?LTz> zt$V-x{LBAz_ufwr9zHQS6@ei-oGnD_5$F^Qt-wIQc($p;OkJ6(KP_pv7e(RS< zPTfoAmYtLjJ}h;bj0(}y{jw1>1MCG!I+vCkA3ylTZ-4uT8#nKz(n*6J6^mdPOJ5)( zNDA_T;7=FnM}dShMVw^T75Kv9d0-$vQsd`g^7GMbPwNR(2P)NSismR%Dv=7w;c*?n8Zb#L~H#>YdRo$xOHa-6?*zv^eEa`X?*bE$A9@ZzumKM14U70 z{Qa#tfqp}DIXOA`$tMr~{eS!~fB2{0|K`gtj_h3>2>1;~BP{VjOa?9Rt@(Td0yOqI z2jRMhQ=e*WA8Czycn`M=egi5`DJ!beB~qE=r_O%#;ER{9z7hxqpc_EM@s!Aee&aZv z$)s=IeDjMhfA))?{OT{h`0CEpmlw)~KDSG)(F%p4-Gm>oSE@}$=bJ|IQ=RQ&jiJH) zF3!n;?@S@+j>V@JmJgghe|7(%=lc8ml}aVV*G~y}AOpC9bHy+WXwS~fo;Z2_rOR*K zdgFt4Zrr*%u5UDx^85`BW@@rzikFG$;6USak;T78(f7RBDHxyL9&K&GXM++q1Mb844LS zD*kRAk|mL<_4Zc?_m{Z)3)EEI1?<7E!B&1a8rbIW^oQa@<8#B~mB3&WCoC{#r!}-W ztmy>psitY_%+QI|3qw8d!Qr9NRHjlWtuIs$)+%$k=p?RthQpk8ZKP5JwqaVmUzt5W z(GxSzH0FY!MX%SpTvT8Gu)9Cu?vLB3AtP>+%H@D}Tcq7h0Ap|}(9z(uI1Dq8B<1(} zG@9Kwx%gdoJ5T9qSAKEgAf&N*mlo&RtgUovqz-G%)fzSLi3It^cZA7o2B| z00i_@-@(Di@4ex#ln?)*y=Tm`OP)ahf=bf0XDt5Df#E+>Al5D{yNCc_@1z|Y|DkX26RGSeF4O&B5#4#kY3v=Pfysa84&H~w)14RW z=KR(OKtPWZDgWs29KO3E@$N0werv)1Gzg%^3GeW49sO_eg`0;){b^L~dtVFGFytTo zt)uTXF6`IoUb~8bR_70m|DD@+9kyZZD&sD*9)*eujsGSz^g8V0?833T2*AHJ6Pozz z;fdEf4<_AR5q_}Tq%uQr?AJr1SK(NZA1nypQN>|DSYP<3fza9JYUy_*#1E9MKp-ar zpSt^xb{@d~1I1#utIg+2?EUYPefyf&?rkzPmwW_uB-*dL1^3sLZ?1y2}v`+Ulk6?$t%0 zi$E8FE&^Qyx(IX;csv6C_un4>y!-UoBM|vt&z?t@!{ZV7<^O*C^X}7UkHAm<=dCx(QUsZa8OnVx(dw`FFq~qt)ZmIHTwrJ=AM#VMe-Z7j5w?pK7Igc!V2F ViIEi)faozYgwRTgsC)=d5CGF44;ugg literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/patch_insdel.bmp b/radiant/bitmaps/patch_insdel.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b60b76b033a9991dff98b807ccafbae1a25c6298 GIT binary patch literal 238 zcmaKju@QhU3=ad$qg-d1A5k>&cv($QrrTclNHIyeq1RyX$v(`Bh{sW^N*Tt rp8EIXV+WK1gXrN-Q;q^!m^$Aud(PQcWmAq;X6>6UN~F1yh_CYj3O*JL literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/patch_showboundingbox.bmp b/radiant/bitmaps/patch_showboundingbox.bmp new file mode 100644 index 0000000000000000000000000000000000000000..357cfaf16f93ebcdc1930455a13d7da75d9a7c78 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!uh(7wDicVgu=Z{6de^abVpq`M=WIN~g^<8e=1ndvl#y)7hODG!|HCRf zYvsxQclNQv4SNRVkdQ0_>Dd@aqMAb_yiyYkHqk+S$j+@|$l(oo=I9(Hf_O;8zgKVo D3GfuK literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/patch_wireframe.bmp b/radiant/bitmaps/patch_wireframe.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9804274f144f6629015ccfae9a60d24dc560d995 GIT binary patch literal 238 zcmbV@u@!(o2txzUUfAFsm2=p;ju?>JQ3=0xFRGiR-v68DE05c;O@B?!%=7nOnLTup3cI-%5w#yn$+Dwk*Kz7zs zzmTmIv%-<)tgQVXs0jPxan%HC`PB%d30UcHbVfK9fcK7t`c&^!uRCx^l!*2>)?WDr DEQ=%; literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/scalelockx.bmp b/radiant/bitmaps/scalelockx.bmp new file mode 100644 index 0000000000000000000000000000000000000000..61363da20402f127cdf8042fabb5731217064d0d GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!vM@Sgz)|AR=;eKt0VOa%qLq!5jg)|V b7_DS%tOVi%1t2t(50i({Xy!o8huH@J;eKt0VOa1(aJ_jO897F bW3ark5l|se9gt^?OvB9qF&JUy!|Ve9-)IxJ literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/scalelockz.bmp b/radiant/bitmaps/scalelockz.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5692e4a74fdf22cf5ad7bf381c97b2ea0003028d GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!vM@Sgz)|AR=;eKt0VOa%qLqz}m6U*d cWh0;rNF2yTp+OR0^-y(C^=Rfm&4<|s0M#B7h5!Hn literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/select_mouserotate.bmp b/radiant/bitmaps/select_mouserotate.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0139fd55cf70da5ae777eaed7033ec3e729f2039 GIT binary patch literal 238 zcma)!u?@p83 q1)vciTG`mx01Isb76+<#HZe936fib6aY3bBpnRYaV0ly;;ywTvWg7zk literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_csgmerge.bmp b/radiant/bitmaps/selection_csgmerge.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a77eba14167bcf7ea83abf1f868c134f1d49ac55 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!uh(7YV$Y8fGXK>=oCW1u+1Y`ARzVLB4u literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_csgsubtract.bmp b/radiant/bitmaps/selection_csgsubtract.bmp new file mode 100644 index 0000000000000000000000000000000000000000..902f32f55f7ed75ac5ed0af1a4a9b4199872292d GIT binary patch literal 238 zcmb7-!3}^Q3`N_-v-YzAoSehE>llw6&UsuxKQx5In>4Q<`rESYx5POpD>1SVm5Ev8 xB-b3YLQ5_W!`(;e&&`w{sVEYVVF*QkE2;}iMFA^W>9EVbI{fJG^WS~dt-J+04*mcD literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_makehollow.bmp b/radiant/bitmaps/selection_makehollow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1b62f2232652ce58a761c8f3d30534cdf6e23b88 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!u0Lj@2Y;e%kX0GMcCIB?(q!+#*81TYGMfdC_e YfB++qU<3;Q*)VZ(`7raK=D^$t05Jj%NB{r; literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_selectcompletetall.bmp b/radiant/bitmaps/selection_selectcompletetall.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1f911e8c728ce13cfc8c7982dad0158aa507ba55 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!ux(7c|%te=4a%r|CILZxBi#t3_ajRB;s82JDI literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_selectinside.bmp b/radiant/bitmaps/selection_selectinside.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5670d3ad700284838f890bbeefab35194c60a0ee GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!ux(7$3~io^8*`Nj+k%pkrolM;l6@uB8J?E?U;nHg;W literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_selectpartialtall.bmp b/radiant/bitmaps/selection_selectpartialtall.bmp new file mode 100644 index 0000000000000000000000000000000000000000..77b418be076d393d10307188fedfa2c2e2fbbce8 GIT binary patch literal 238 zcmb7;!3}^Q3`L9eE|CS0lgE;7;N5jRI~o(Yf_^AoP5k8dr9aTJ?H8F2V1+$A!H!1M zFP&6Mp&RF~G%FMoOBm!~Nvz^uT8_Tm6R+w>NCFrob`svBZ*yvnpL1nOGf2j)miK)R DkZKh# literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/selection_selecttouching.bmp b/radiant/bitmaps/selection_selecttouching.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9a60815d2af9dbac34401625f72d0e8de0161108 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!ux(71LU&Jx>7MDyIqb~r#GRaHc5>QDn{y6qgeB*k5lMn5K@bH@ zh=PhJK~a)n<)I)!!1U1fzVCPHbl;g>eD8hVP?S+pc< zab#pfR8#~RD=l8KSiiEx#U#Yr5)vdOCdBa|yFETJQ8MxIu_WyPJ+axM=|fzcqb#m-eDPX#KQyG&E@HmM->WoWTxuw$%NQ+R=N)t3ELpe8*Cz0V1kXjyRh7f#iY;;)Ik|l;XVc|<6 zBg3PjBBP=sBO=0-M0^WoGmkQrR-#ZJVJI(;5W*UQ^Q^fCh4R_~=?Mgv!XU-Sn6HF%Jd10P8RCUc z;1HTM9Kz%ZpOA!$WUgcRRudnUo$QG)RXkTs6SBy0)%NzeJnh@cWZfdgs8 z;Yg$rxfiw+{tR-da3B?=PJA$*7{`!JXQU5wIM^`*9~#mA>sPd|8L0-VB|5?#$xBEH z&IrgC#YGt@NDwF>DO#Z&1gRGC&@^XaO`6{m9~%=H9vu}C8y)G2i>*lU=D3~Uoo7)~ z2rDVtFr;Mc)JaV)@wq(-^ulng&{+sBl!pR_)Op#N+cs@@CX&C~QU@@(FP<$S7yL&6NM-8F`_zN%FW* z5+E3628_aZDg$A{C5ynRNlTy=qJV2yxQGIHQV19s85tW#AHowH5w^I?)4r6(2{LtQmP5H_&Jr5PoQUuak0z- zcj@$58M=X*D^E!V`(6fua4>o*ILj*Aqaz{L+Ud!ce)`k@{Kwz_`@jGD|1p1LKKk>Y z5A4}(Nku4Nb2uZD1L6M6aNzGrM?;~8!eZi}CwdL86W|N0lTZ_jd63M4(8rM1NKvJ; zmP1=Inm3GUuxvyDbl^rxLu%_C%C$ z8UUHE-&H{?D~i4j6J-sMVM}I>Mwp@SnAnK8gvfY1xI)Gm(GwLeQbHvOG6Z=d#@UWp8$GOg*;`KT$>W>EX{t(2&gFl;QmYB*Li^aTEtylH{@Iy#TXm6jIB z&(BNG%uMk3y_xxY4j#Glo-Z9bde$}9T)l1Emhy_StgOt`)D$3JR8*Loo0F51&0RV> z5QIF?(~mS>knE}q7!)IKqa&TMQ6Y%NeOWv zJ;P7|$c_{TpUKYsidzxX+Suf6u# zuYdjPd+)s$Mq&s6q{Qz5`^ogp7VWS_r#TX8(|r!38O($R&3>I+W;4g*tWEbfmKF_m zb@;s=#S2Z5sN=LJ4D@vU zg5?~E%Zz@}@DE)PJt0va78d68M|#t3PB&6spk!2}fzn*ihNkEegoR3qZY7r~43dt# z%)U_yJXDi%g5eDjM6d*0Bz1yGScNCTX7ZKcIw}PDD#6BFsJUWX{z#+lEyxSrtt5{& zj4D?%1eF8Yn(0`uf`PwzmOWm*4DB{|(JS%@1h>~)y}aSVOD?_g>T52#^wRsj{FUpj zzy84oAAI)NAOGYhKe_P23wG_=arEd>fd9bb(D+FTVfoy9VxJ=l}Dc|9t0+& zf8WzjeUDD`b#^FK#l9lO0_EvVk~_kihW3wer$yM}abJP_lDNch906AfPK`Yg&nu|+ zRfOtCrK-7#C1A*CR7?o1hB1T(g48y;8$aD^k7GE1y*$NRmf|h;xpPtRNp^%l5_W|x zhIvLu0Y;fkbGyZ3XmjM#lBnnXJN+^7L_-ABCY@wQ1+~9^ z6{-`gX?>h0H=@M@vh@D^jA-_G5@3El1Zqnfh@!V3uQfwgbXgGZiv6GjkdRAI`%A=6 zR6oh;p$Pv_vi$uZ!^{_JVlW8t4gFP0ON@&_h5CavA_j@Ulz1Ou#3dn_tbVIjf(JcFP5!o!LJ8J!rz!8&F{Qkj@}Tx?BE z_1M_hmMvQze)!>UeB&G6|Nc{4pM3JkM;>|j@ZrP2{F!H-zU!_#Z@A(5Z-4vSfB3^6 z9)JAt?|%0?Pd)Y24}*WtJoeaQgbUzXRKGJZz9B2EHa#UX$sTYdZ&TSRg?$}lT1Ng_QPNK%Iw4#v=aE60qU$Vz}N(Pq$hyo96{*P z?hbRMh9~&}eoRtwLV^%MX~2QUpburWxeN1I=Hq8(i2%!~;MTEkSf;~P)MlOlAEs1l4 zC3+(hl86B4jYeF|GmJ6&Lt4_nB z;5M&NLxr?JJ3J+*_fORR`gCMnuuH)n&L5N|+~$@ov~rLLCjejI4;iT-Jr~r^$G&k! zqN2kR+!8bKWkw~Z#X4OufMDNXhkFg;g27%US{O;$!%X+wqYcdI10{-jrh|JaQGm~9 zP6}yC*h$2Q;1noXtHh4U4Gbk1;;tLB4_UzfE zu|9^NhD1(I_J$4X;U%~?*=Zjt&hN;}T8do* zRXLfU%rtIwlYyj41RX4G3fvMBqLO^kPSN#P&f)F=W`ND^An+S>7(>KVqz79F%@-d< z4j4{@Zb+&?l0C)AVI%`y zd7?6sl$+I9o*Pu|2Ih2t66v||Oa)MieL;G#!^$vLhbgCy8Bq|?3`g&xrVc^bfX>@#sXk;^MAxa9JrMDuD1z^O?J(zr%%zjLgmr)3)<3(I> zuQ8Lv27sy-_DuyFn*>nq=|;I%27I*{sWs^-<*CW)zo$AAz4mzGcy>Bq@J`s9#N5#u zPtl3ss@|daf)O~RM5r_$bBEpESLppAkxlVHEnoA(nPh!o5sb}oLmd%V? zY^=F0n`fWK4pS7@E~pHCEwLnAz=4^80;(KuT(=-{! zZYO3A$=JSOraLrJZ5)A5W!k4QQy&QUvoeX$r>CR%d|qx>zNKTrx2D6)I~g9TL*t_b zd}Xjid%~G#p1Et+PHtytny$L)s-B)MIs;!3$)A`QA0Hn>#e*Z2b*fXgZQJ^t?|kQq zE3Qz0=cV|s>Tf%zrDju2`L?=>?X?x|L|KUzmJs-hFBTOZR^j&+dtGkOA(k*(S%`AS zfO?Q;-s0(OjEZSSu z2ox$8WoD$+)l`#~mK2o~6=*6bF3qc`&8?`*E3YXnEiGSKQd?bBS6x+GQ&m?}MV?G% zdO$E67n_tA=XWNy)Ku=@wC>^qd-l#u>=+-~G_+!-r(>k8xv#llprf^?wRu@d5#6Rf zol&qaD_dGsQC?D*UtEyKbE_*W@^Z3Z9_^tF)=CUJ6yP=3w^XWVE4C%@Eq+>(OCXSu zk;W`%XJ_W;=T=lKt*foBWpqnRC-R~X zrr;BoD@itTh%rD2AQlap0cR8Up5Z29s!7MGVT zD=#T2DlRUdJS{C%2Zc<~49pK51PB>vdJzGJi48f1YRYq2iO(+WRM#w581OQ3`h*%dfNbrb( zf&OQoeU>&wMcQJzyF1T1>!?AQh~;apzWQVH_v)*!78e&$qQGYq@4fdP;l6XuIY+P` z6IB>Uy?N!>eX}EXj&$BV(KB9AN^3w;j09sH*`gx}f-UoVeX{u{3|9bc4t6|_#GhoDkluUy?RWq9#}D3p_rv$!|IO>K zU3KwAP+O%C*EQ2q#3%?_zWvsJ@X)v4dh5MEy>sP77fO6W<%0?PsK|m`%z~m`0_JlG z4aKe*o5$gpI98(F({^}2OyMn;B~FRx|ZvobUC@^S!3 zef@IWwC3i<=H{k``sKB?)q)+wL{%jhzOApXtFEppEGkGz^$SA1?(~eb;*z4us%2GG zm8|EICoNl6QCnLhch*#sC-H4%Rb^S(Qu$a}QC40?JJhL0#@5x6_?B|2nF`Cek;F&7 zYG|mJUbQqew=|O{)i=<$8Y(QWucKED4a?~>b?WMB_?CP}M_XUtirLxe&6_uF+PGnQ zdTMZRps%mDrKJgil$Vzx7PuX@CviLFt*y;m8TE1`V|5jx1FRxB(dZzVtts@mrm?xc zqo=W>yS}Txn$$B;y<)Jcx4)umMNM~aQ+s<;QzJwxDK12k05l+3Qe4C+8ye~$XH892 zMMW8);~9XC1pQGNTs8@U)O5py`{NP8fk?KAW=OTD);xTn3x#buwfnanVFetYi%wrD)9Tgz#P1* zy()5mD4$tbU>l^_ptVF$A4(-9#fgatg++yrJn{&*h9Lpz`RAXvW5;$Je_(~AJ%0Q+ z0M|dJfW{Tbkez5hQepS*UD$>Q1h>Opkm4UGD?Pin``WSLtYnXcN-_kys?$S2-213SPM(=?c% z3AUEkT~u7y-QBfr-P+x|cS7Mkdv@>IwUcXpULH<3&R1Vw-|XxRfmT=!{+XJZ+_Y)q z)~#E%Z{N0K$Br#qAmLiB6w(OSZCGhrw~$BFiv%bvC@n2+YHl1G8(p(@_1bl7W>?LO zjgO8`jIUk0h8wBAdCO+eZ_^Zrr$O^QQId*U_0>bbQy&ef;g;3ty48ZQsW2e7kkq*6rK3(<{bE9XQ!^e!Ho^ zcQFo7SXgRm>X9Rd_wV25^?C;e`bI~GhlU2GrzTggUbTAl?3y*JcsjT5-Mbqq(ILtq z1!JtLuFS>i%FbN6w6wFcV|sde!={a!wrt+MWBb1V_8KRh^8GVz%Vy$+OTHzs>#U-9tu$z#jagDl%8}OazUc? z>(^2fNRr>VbNik>yLRl@#+55f@0~k3RY+1pUAC_H=`N)%$1@u+O)6 z1fut&qYyRXmB&UqiNAT>fE{=Sb+j#}IwN&-X(7A*Qi-Ue?xQ0UW1_tAvF(-R-}%~C z3F(6u{{G|m@t%&hxOtv3U?C8M5MV>^-~Ren>L3IzyYK==s_-`zBwRoyBoM^izUR(6 zEWna^>-h2B)|Q-PSDA6!>oZfEax(^(S6_ee1sD}I3(q%5Ca;7<=BI?0M+RU&cML>b&*)-w*ZmBA{>*fxL=h*}EPa6Rsh2 z0s9iT9m1K{O)! zzNmm{ijXNP;82f8E+{||r@(B>Dwol{$;nAD z%Z*uCSqBarpksV{%Plvzx3`n0{MfN$`}XZ!v}h3{MdMt1?KNkdaRyHZ2;har@i!Pa z<;W%o!Vucp+UOX<#N}eYnSEmAL`!Q6b_MvQ1u9?wAOsjGjs_qa9Ub-h{FSwJH{N;o zwtf5a3XA-yf!g{8#L(o*2@DNXD&h@mhx$cDMLhSi%Pu|l+;e~%y)7un2b=VH>C&Zi z*vx_qd}wG0oH9n9cpGUVQOI7%Y4{K0bcwrI(hJl;q^(OiWBr8H1lG z)8Su!`QDE{8ucE|3^k;C8eXR zVD^XK{#H{?W_7xs^|(TxJJUsEK7oity3h0Az4rkB-CMV4w?$r={*$3I=N&n$52c-d z{qvs}96M&7A{t*ZwwQx^_aKz4XMOz9M{8%M!8@i1f>#X^dPP`_^)C(M8!a!uKPlnq zyWFmdW##Cvii!#*cfo=M@C=!S3m4vc>n-2<*0<6E0X`CehYt^+GxqO=F(?5k0IH*- zgM4Xe$(?uJL59CCeBri`xNz_>Dk=&#M!fIZwX=VqALii^7>l3%>}O$Gv=1dbi`XBP zQI`Og458%59)FBF=wi5qD}{#+9ppwb;2pI`243C0dp8-v>epR&-RC~{Ir6~&w9`%_ zgRCG=hGzHg-%o~ifCCvGdh^XUX?+^GZzx)Ux$*WrlxbxJ(moB`_J4zH9bX~YTNd$O2GX5e88(c!BHI_8>3ow zcJ|G;-bx|Qf|DpgIvqT40JV#~0U#-1>=1;9-gD0v%gV|q;c+~aTkg5%9?(q*BZ8h} z1_uV{BpJqX%{AAM;qPl-`x^3r3>)D9I~gQTS63GqC_vzZ41esY)67@C@@1qnd1NWV zpA40Idwap>p05_+FO!QK?Y z*esU-L$g?876ObSrlcsoec>nH?Km4<5Rjx1m z^f{s-z=Yr!kRhY$Rp3wDASSA{p&n!@%7_VoR#Qj51+Bo)VUEMFd4M(ddv3hW!Xucy z>*gETX2Z5R@Xk^l2Z%T;r;)m$-k$g0d++d>XA(nD%bX0Y(G4Jc?9hS#3h8wA7oBT@ zAyh*waBW&%hnCkN@Hi^me#_0+B%>MY-J#~ok)`qwe`U`4=!cXrW57ogThMuw>XL$VzUBZ2&~ zWy>CZ_+h>4i(mYrg6Q_!Z>NMCf%DmCpT&*k<-*DMsOS+g&CShdWHRWZ&6_uoLD48k z9S+BH&;10T!9dUb^f{o-w-;P^0g-ny;2q1J%(`{!&N}NXGE}?v+H1*h3tPgp8g?xP z1BJ*61u50oHA)G+y7SIE$?!+d**8L)z=xh=^W1&+UC1ju1w<2Fg`iXep6o&)12!>- z$WV?YK!(4|F24-aZ`!<(k%AXWFixP4k^;rbM+)(M4xD)=8C3a!gNMk_2rFOboO28z zqm{3^>Pn;v1G)O@tC2s{K|!m~JMX;nRGQ)Dumz5<5L}mCb{QFjgA$zl4}bWKiV?&n zB&7s@ZTa%$WLB(L@r5slWaIDNd+*T<+i8l6i^$K;&N4e>u${WQyU7qSKs%F=A+P}@ z7~VJqEiFw%4wKAr8;R$uNf|C7HCIxi-|J-gDa@Q}3pWQg5hi!tb=NDeyz;AG{VF>r z3z-lezJzfx?*Jb;fPwcW@vac|3D=l~r*O1#Uo1#`-}6-Qj*h>-QRuUaSNWH=InFN=Om8JnFL-0H3nP)Llpve6OP26 zJ^N$51-Ri;SC^NX4Rx}6mZJfv_4>>}b()`LxVvw-cCPVHKDmPVLJ@~NbZ{+N+k^=G z$=)Zw`NY26yNswYuF476KX?N6k4hj^g+qF3%9G#vru7uegYSL&TiNLW?K$EL2@o5f z5FQ=9gmq^*5GNZ=p)^GCK>*|@|CY>2B}V)s8P5S_P*-s ztH3y4A=1C}r7uywe*L;JqYZf|emY-aT^~7mgbcxbm<0Z3wT}##r4S~koD6pRnFjSOiWB_%k!pyl!U{ zTU!&7*x$&SE?ORM2sz2V{h$5pXD*i$;FEZS+Wf$u+wZ*d4#ECk(6=A8wzi0|YIbpe zdb)~0KKs~NV)I8u;_nj*Fna$4?T=C}O%Hs2a_o+gu8Z61@%l4dPQ*oDcNYioEa0$~ z*V#8D`!4($F>W8r?FvuT_@-q!ILWyl>lU!~$US$pzlS|_X-@Xg#(5Is zueszRt0tkm3y+;GU^m#e+Y{I`oST)QnjP^~kekge0%L4oMd+Swi5!CBV~0+}{#i%4 zi?0Z)UUT_nmczocUU~WD<<*tYK@$=z){zwMPGw7B1jpWEY~d{4MMtoPn99MaOxAZY zh|WR^>@eBL7be(G&qxQ1FfAcpW)>L!;0He-!{7b)-%lhBoeQV&5&pUEx@)nG;Ws{l zl$T$Ad3acC0EEMLzx!P>{5|l%1DfGRVTgzbP;uCAin=bd*hmIcGaRRNNUeb%Or963ULYAW2|*xPRV zyfksjDfira4>m0x_jT7_r}j2p3G`9yV{G81Pz?&u4jCjW#G%^=iW_gb5%0jlK05A4 zKl;&+f6OlTXBGR%AH_btgIY4UOKN-Itf?gf_K~R4l~Yc6`Q=}zh=9&Ya{;x%KJ$g+ zpw+CIdiKXZCX7HK0t%CZ4D+HE9TJ0?y7I~^DBQbuFT+6#A3buor?)q=xHLYH6YcN< zb7JACK94LEW@Qllj!kq#xKbm$@@fkVdQgnP^MfCJ|L(i*CQ?BG_%fr9z|(|`nmF70 z@WWqy?z!i%Fo7W+tHK|1kuCi=1J6JIJWP&}z)m@$0U`JY_m!zA0C6MBDlQosY{|=s zH~Uw4+@%+s&#@c}p1*$m4PSPF?7-&)uAhyUY`HgE4n#Z0I1}Tt{O+2K!M9yRO(9#9nV*@rXI_GSwaj<{hSw{gfiO$qkRLch9i-t23_D$wamD3oSP~^e<>C1fbW**KSG#kkc(3Sv zwX6Rv_K8-h-k-z%)~y#^B>p=fA~Hz^?9(f)22^Q~!ui;@^#1)Jt@r)!KZRPs3z(Xk z!pQ}d*t8h@CXl#(KK9kjM(|IU*AxVh(p5AKJhV1a5U(Ng?$ZB6iX0q zFW(Y8R7(J_A4!7s0{kiGkAYwjNo3&Wo7CC4^2#d}`&c6iYDlWs$Ca?KkGG{Q{NfiD z_McYlGi7Sb4-O9E%4xN)eEG|oLCz@l5$~$^E$s6V5kzTY#jvQ$p9!W2& zOi0ZJ<}PPKMp}yS7{E{V#5i3M$>|ZCWpH{pSOtX9`{`+E7-rqw-HnY6Xq?Q<459&` zvZ$yKTb+zr`1q>ou_6uhMy?k2k)>>=qBXWE1N`|(qJk!&+IT4kN7SWF6Ko{%@Wj_2 zwXjL%nWvs&FAK-(IJXkv%dn+p_%gGLa1vv2s=4ymVM2n|jaUvt zJzeUygJQMDO{_2a+#`pqYGD7|qerM9)_8pE(KGjd^x=oACRZx(K`Vt~|4W=frGaV6 z#QKgMJVEbYaO`YXl6`u7?7ctzNu>~1&J`ZmyIXvGA_-=TwGD#v9wBJ%4usp?(9`RT z6Hkqg z2z*ocr1|?z6~t4cuXAa~HNEzB5Mp(W6JOV=2LNL=BPY>FL?D zN!)yHZ))0&W8QMqu##^Uvo>A>0n`$iPDUk-;K`naSW6BU{LT{b!&3 zu~tK%DNdOd>8U9)D_2fTPqT8@$KHnX&OeXNPzW5< z#$a^n^?-3pSyKUxdF54CUVp>&`gBG|v_!E#Gdo*XS4SO?h*3cX&qCd$%!~|zsH{j5 zvV+=uwQk+oyu3W(f%K5+poGpVNg1O$^3Bc7N_q6Ab_Qo$#TxaIBuHj5L_E|4LPQ{+ zDWO+bZe;kgguvNnpRKkE;z-$m#^R)8cVENsXkclDgXLjI zJjNt!hGEGDsu*`Nd>G-+jC6Y0m#Mm&D>naw4?c*^L$l=-f(zWSQUuGTeuowGe{!%fROE0@+5WS3;7X8Jtqrzcquv~K+S-~PI4 zNRD8jT@0r+s96~H5Jv@*ZMsoRZgk1Kxq(ob4iZ`V3Q*ap~ z?apxQ9B&rD=ad=mz~P-d94F_u68|(uvdP3*b3n2f{S07R<9nGuQAv#A-_zK2W zJAsxJdOVBgY5-H6_Q^wCGe0k&`71_4=` zq#EliIEI$$hZJh_zy0>x$;sYDix;w@2%nOSPigj|v$2{NIEgKx9>g5>QO$3>_L_xF zGB5n_>21Tkn|oW=bvKPQ)wC=vEN2&Qc9t(K-IeTz@sKSnxQ`C>ani@S5gTCLsu>^* zT1f&}2@DE~=VKqtzWno_f91X}{rKr0@EQp49=Iaqfc0(C@gV+qP{TpBMu;M5L)- zS4U8*VRUSC{f70!Bg60jD+@%VqzcD{;xiY)zpMF@kl0mChs1I{PTgZ8#L@eI7^bn!w=Bojck8gC<4E zVg}%M5Q0$7$CTxv=vIb?bZTm1r()xBvvCga(g5VqPMJs&df~n+`W5tgAQ6oG9UyHO;BUan$=K)#R8~@xq>COYv&HS z4RN46F$!7$-89ZfDTIbpyXc||H*Q=%F)>c(4<0;9KscW!guM-FD|)GqbBO zD)#T+$CaLgyPIyjk!oxq+I9Ho!1QcwNB8pf?$WZ-;==sg{2VqIgZ)I8E7F%15y%Al zQQkl#2g7AS8Ean*eoZ!8ECK`@5}AVtqJ6~m`|rQ6t9nQP7V^M2nU6pI2x=H0%e@x% zd7B5S3hc9Y1+O3FZXO|<(pkWwzA04fhw(x(w(;|pp33yp-@SeU_MiRUcRDJUF3k)S zrKc2Sr{|=n_}od@Gf_@gq{AEG@BnY1I^4hFB)va5ItrS_siw;i-`s5!G3ZYE{w~O$Vmb5?lS^Oj(AywaX2DfK6$C2k5>z3 z@lKwIq*Pvk#VPFMt2?dj-jM;bIXHFkD&_7C)7y7%|@_w;siFTz1ljPw{89bxki;NprPLTJFiJVmY( zVFwaqz`)=D?UUh_;gKQg5L^N~pb0o2k!TR9MV~R|5onAK$m3sAlbx=N zv9YnfyliPfK|cG9*$)g%;8Lt0EEXi>#!VZzB4Ho`qag7_`j2(QvJ|(|AI63IkF3C( zK#AbsO|M?N@6h4Z8@CKht?itc?OQoBzH)MAYUSk0@xK1vhK4#~zsv%bFmYGfWUCdM zpjuj*R`hm{j0~}tX64H9(a~WZ%Gjr-bVNuXwgrvzj~#%NkB^Vys?5wFM<-`zabG66 zi{TSi86F-)L{Ud5IW)ka_?EBMtXYL$!xhN@arT~hu&A_*4l}Jt3FyNuNZoatHV>{^ z+cLVcad5P{xov6LQug)~7UpB>a|i=}Gt!e5!J8}4_{nMV5>8oTl1SZr>|@yDPCowl zV+aA%Gj-6^I0C^H{m}nd+hv8w=Sx;N(@1&wQk4nszWXjz0{b*83st6lfxHEL5eSml zSb<19R;dx7allj4SzMYlAsdqH5jhFGJaX5m=d$Nb!#Sw9d5eY6{ z42wLOnVi7Jwr)f)b+j}CTYzu$zVXwI1UUQP0jnA||3&AV!xCYtFL`Qgoy0sHLi zRqS&ks2BK~40tDL5a1-6pGTi_^oZQ0Z(>P|AL!|}UNA!N;oS4ik4evt;B~>M{sbox z0NELCB6}Gb0p4&HmuQ#M#GEMPokIFrAy;ZtyaS(#?fnpz7vizmzOb+WkDIgA@J4%Q zJ6=FZX)$rv46M2U=UM!jSs85q0}*VbZ|`WM8vJ9JXEnfqk=VJ1@+vMa!giu&etsT_ zm0ULSqX*eNXt#4*j+eGc_b6v$Cts1+P+#Ievg>UoFCk6SWf9&IqsxnQMMQo+kFwayv&7G(&xA@)dRH5@W%bq~~Cnej?UzKv1%%GkBZf)YjH4 zU0Oo>M60s0GI_HcL*_gSPiI3K!i4R|NEk>|Rb7RUq-DlPZ%I&zN3&eQKr*v4k#DVS zEeM~{@li-b%y8|7jU!XDEnPk3HTAhwjTu$-S=EiXRrUF$Wkm&foWtUfgde||vjFU4 zBvdYR$PBPrmg1u`#l?l?<)vjy+3e3+eL+b{@zT-~;6S3!rKQEBrKR}gg(W3LK$3E~ zmdUqLd8t$=Dk|W9GE}1-Q;nLXRh1R&manQ@#>s-FriPBr&cUfQGn=-r+sL-zb?erw z9vdHPUD03B(UafUno(JoQCQ4zdmdC!n9orpjxZ1|j-zJ@~$2QIQtke<^jI$MS)APNcAh;=>fsPzK9lMQP7l# z2*EyW27!+~Ko?e4Ro=g9%lPKgeN9D=aK?}6s9jV zg_l|KT80?Tw$a>K^SpTOdi|AGvNO`r_28Ezs$cZD95_1rz?t*0f6kG^#xM|fV0PsM z8-v%+&ft2W-v#&~?a#NeO~^s9o|G!D-$VkqnH?AVr4}z)xOnkG2+K@i)4DxwKxfdD z4-vdRFRvWH=dsE0v}lgRa#YRbO2XSh6o4-{yrQBE7UDEbW#uy1j73#cMB_Y#Lar2Y<+vY-dr4N_%4qxahm6)q2qMwv^QNT- z&^1K>rl=6pg>V+FB_N}vx6*SPJ?A|hCLf;|&pydOdH@n3xVVKwPs^%n3d$?fa`N2i zISH9X@fn5jnT7G$MG2V&@!nJxXxa2dn3{DNs1a;X=);@AId2}F$eZpsZRd4!{*k_M z)x<7SGIUk?%z;N219VYHWpuH*%C}O;z3wFQl~kZ95&?O+`n+sv<{DsK9wD5aSyZ*W zthKwMwTq)!9H7dts!J`eaTk|6vkMcvIFd;@IV_%}K}_CC5p8!zCAuO>3C^f^J2C&r zXgM`zG`_+U_>0|+eFf*Rhw6?yZYL;534whu%Wj7!o_L%XQB@V^r0R*pB8SgEgZ=V2fC_m>vmH$AYgepyd`_U`fFk3M+c zf+uh6sVps)H&;bQ3jd)X9rhG|GG{6|Ka?yR<$!j~qYpk{-Gb=2>+`n~G&73WX#9`_ z2#;8DlHLdV0%{tz#jvvf#%r%`SUoE@8p9qqBN-Ibz@LoT{DS>?HoszDA18HW;UMmu zBZt)Sr(<;K(T5+gr)II5k9nUdCp3{?J~|nbkQl+viufe1;jsx}aSnMeAFHvkHmrRJ zsMu%IFYuR_b#VCF018efY6>OU{6m8NT%iz{a>&~ooCJ4a81RB&2HSYyCzlhrfoo}CEdW-7OZmSxSykRyJ6Ou_(j9Fh6i_z>`qk?=D+WU>f(VFrtXRFQe zTcGU?q`C9TTt(&HoC2(n#6V75YEEoQc8tr<)Uu}rHbW^y^XBBZ1b)XMGSLZBMLLqB z?JlD8LK#@bSmOqsLDf$%mMAeXJ$7rL#~Cj(f?)&jUwrXJHWsp2jEp6wMA)AN1(rxy z(#7IpvheS~{)ZoZC~^Kd>px_;`Cwz}!^qP~*+r@t|`%=eGK z{cZoYEk4v4%2X!ZnP7Lg>jnI8urFDw1cX-cP9)kDdh5_@sT-n zW4^zS&4133BW894`z*ta4GkaxfH~;S&&_5-vLzXUz!zN0g562jXP*FbMB+v&Firb* z?nEY7y?Xh@mwaiNSU&98OAGjt-A*dA+bS|K327X`o9(%>)yEbe#S6FN^2r))P zBb;=OVxr}c8q6Jh!I5Nw8>i=$K+JjlH91a06Ac)-Yi%ud!Q<^={7{0*UMLbRRx#U0xynm+;^X-l z1;!}UHoPRmIT8M>@jd(Ov+Ok@R{!d&ud*b8r+@tT@7TqJ7eHX2M2PaLtF9t|%xQhJ zyoUae6>q)u)<-51NFGrD*)i9}us4>2*!=P_Xz+`2F^O}A>*{OQRF;mEQlLa)Sz8fiInj3_t(q5etvHzOVDb9Lem2#6@dk{hPo0U2}b%&d%IKm?>@H;h32RnQO^$AH>{z!nx1UnN1 zlol;MfmaoP%F;S(!MQWLg7sS<48x!zNn%kG7BLcuLdB7&c!aRNW5;^CjxqIVjVGFP zGOqu>V4oX9s>H(noDJ}QVPBX~7z4i5Ymi~&unESAI31E?;gzAq>${aW6Jg#rf>{+^NtVQ$$c~j7E4*8H|jTH_QecL#Nx!mQl3_%uI=Qi6tNmY$8ZvZ5kmUSA%^A z$7I|-4czhWDf#u2(Ag0Bk2vCL5*-eMh9n3p6Er`43i~V^fZuoCc?Z?cO64;@e1=sL zR#*tYvZ;d@Ce}XD0N&5}#1l`v_S$Py2Kz_=;sDlKfU)^4?2F4FEN8F}|112Vo&|qO z@D32zF~t01q7Lrf_3=mY?tT9L`te6sAKo|GP(9UJH{0H@wx?}%SL+O^vw5h4ugH;(VuhZkmb&+&Cgu`AF;p$v8egrm+!MG(7mtR zdk@pbbYNnM;Dr`Z(In9(7?Z?JL^#JG5O`f3yd)T062#!iOlzi0=GW}@R|7!d37vt7 z03`SdDFYLEg_pR!lH_+Zf_6TTkpywz4domQ1wkR8qG0}YzF4rzwGf~QzXj)Xo>pa| z|4-~|o%wD8b4K6L=|Eo8z0vg;Frr#9)aA945=;;mhIgJoG1Gadq0gcxC)3Ru9hv{( zTa|tYUhZX@*lvyUg;)+xaPvlYs3eeAhe%K#H24MkNN@AX-&nU_A}Fu{o~Gd_q6Fv; zkpLk%pwfV=DK|PS8A=T{bKv(SB}Mu&WJj*k$5N1>+Xy}A zPsiW{F=p_%rNbvdUM#dvCph!bM;`^q`~hk<6>r|WnMGmTf7UhFqJUMvdJu~XhYlU$ z%)&Rm@eP2_Ei_z$ zr=R>Tu{(a&iJ+9nn@ngmHzRXtX=!h3)02;W74=OmPRhUj%a?aePw=)(4h5I_Jf%K) zQ*KeRJ1Z$M4F|yypY3&j`HtJ?WB=1^P9EowP%m3lcH^F{$U9E}* zdF_A+3m_cGFda8sb)^Muuz%j!XEEK9*p(L62}7SlS*{f1ZaYNQFCyz>T75S=@32$D3ajC=zRH26DI`z zm;sDPI%)XXk|ElxqIhmN2L2%e{@+#s;+K0-^m69G{9GW?iANZG1>qB%2*Ne|{vfaY zOwQnazjQc=cY%K}Dbn>L)1(|_jC_M@a|?4PLPMMaqi%v@7uLe%7v&^w z5`j$;pTyW9Aha@Ego-ykG#oO2S|vXp_46y3iQ_;J8vnPy{mt>?$5G{6G5*oxxbU3q z`{_@A$_XYSexM$u|L(i*0(QRQ7#A7p6XE~G%fGN}{zZ!xLaU%WKVey4%qQuj^i$ke zlL?6ebBS|M^>PWepvOA*UX`|NhFQ z#q1NXMMc|1`$$Lg zP)GCRK<||op2r41+I;VwciNWMaH>}h_7X$0MRVMbtwb!%H`Y}B{P~|*(54-Z=<>^e z*%@g?`ME1cM_zdDIX#s?9pVqyU3mpFZa8ob{sI$Kh;WnG?SgvCy0+N$-(p|Y7E`IB z-rOknl0jF3bORO%!ebtzfhdvCv}m6g#XhhKYJ5@pq9ZKXE9_yo!sT#FDa<>5ZAPZO~{`qNo>R6Q8Cl7F*VSp83(!!wiWgKKtWX5CSDk@b~zliiD`~oScH^2In z73oeB;cN81qS)AzG8U5Bmhgl5N*9mJqLT4aMIe|nBO(Nh<&V+_?}QP8*cbgGKMRWt zj8AgoXoSVa8&HdJMf+k{%JhYPN@+g8$y?a}R5`=pJOWf@sfY!Fp`oF%v9XShb^?H` zr4lhl@3W@K-jBWe_Hr7L6Op&wb{pFo@4owPLp#BmltVRsX#B_dkB~>o z2JZ*sMW85g1@(vTzqf9%H{a{xH$yXB_H>pPor&wGS3Yph-EX||E9-?k+780!=)wafp%}*%)}WslSz>=8oN=rT~U8$$&?trHHZduS|>Dd zLG0rr2Yp+qVD4Q=oA8wy$)fsCz`lgeOoZP6U#)#(@N<{W3w_gB5GI*3R6-rFx;jq| zXrGOS4YHOrazgqyz?UaVQUu{*i`6P=ekjuDefo@FKM(sz0G4|s0el8aSD_V8B-Td@ zsA=*H$IxWXNwJ7*Ww_DGpOgtsga|jayA(|TN)o*Vm^>Q!$+IL>!7rl9i@weF3~wd} zwGg}5hl*biZBVa%rI-OhwH^xZW67&iY0Ll--DEU^L?bAD2_c%JpyE&%?31xO*$);9 zLK^HqPx|)%5Br9xME{AyIO}WtVK6 znOf1-k{w84fl`E?F>=Tdlg64wL{ z_}`cf?C5NArecS(y!D&8+SjBnCrmkZwNwjRg1<_AMcxqcHs! zmXjWy1bl&EFom3PVbPEgXhvZ^o~ZQIETOkxUxy>nOW}Oc{<6?%)+-r>3O(9n<<6ui zL>}!!VT+QX%>O!&d4rl0XgWs*@}OQt1U#vWZb({UO!4d2zCkI85IxMO+ZhscxonZyvX2LFwyl!0)Tp+%N4Ib#^IXdc>`X8 ze#lRiQK74d@e>l$WR--N>O|%M~PLQa+yvB$3d+>XC zUf#)%8IY1(n3htWol%pY(^OK>wzRmbyrie1w5zPRV`))qNkKzFZgoy(aloJF^Q7@g zXM4OHC62c_X$L2cwRPfr5_?>NlWh*@2X%@i0T7jQbXL+C+sPoyAl)z_BSpv?6IUbK z94HYYGxcB`)C*W}h>hc~HbBtvhgSvuCe}v;%N(x=!XM%r><6C};*e0^{*C)@eWlnp zSe}FbNvKEqscxd@@(LyFcSV*Lx2(oKX0$W29;#-3XW~^I`l#7mu#OVfl z^RGA|aZVR2?9oa7C}(m+lHcZV$=hv>8IOnn?;skXVbCp*hY!V)S3Weqr(+mW%2DoW z_ z1eO+y2LOMtyK{6!cT0UuYkh5PMOodlvgW#~_Qu+#+NzrJ((1AjQe8z^)zac+C56kY zDrzg1)>l=uHP$uOR@PTn)Gk|EQ(n?kTiM;x*xpb_>S<~0>u6auJ~BH#JlfwweWbd1 z3kOCuKLN>w8RTsV@yTv?ZdMlYXu2xas0bt&3WgOj3PUcGv;aDBg;opCP%f1cKJv|? zg)lZ6Edsz25|m$QT!Lwvnvym=yeciTfQ@eGK|m*@UT}ufVb9CS;eFWct*u=h>~3yq zYHVn2k(XYxFO+?x73F2Q*}O@Jx4Q@AC7A3gbHGPV+0=`nO0WP~F?L;d|ko!O|1=;EZ@f<+76 zUUzO$UV2V;b6a;qeT&!SV_{pQp-^?f>8GE5s`>lesh>OjjMJeN7!fH4aDWb}y;msQj)TiUw3rmeoNxwdLWTXRPvnaYlaI`Ta&4ZUqm!#$m_ z(@;+bnXcw~xNCB_f1s<4v~s9#bVV0o?a{vO;oeS4$c**(^tU&!nVy&#?#J>Vj)0_) zWnH@i+X#|2)i39F1sD*pW|W9rR@*@egOFQXYk?lQ{hsPrQ-NN8?o@A5&{I(hFE|bxsAhy{4G4= z3|eFVsGYZn*y0^=3A~&eK`045FJZmgqm!u{D{S>?p*}G8%;8% ztBlBnR$vQ|`6&|2Tr46sH?Nxg?=jYa<~Ic!PXRRaHq*5wOb2V0&SJgPqI*dPbAzC6=e)C!*{^>L>({aE-iQOuT4d zPMW7f!on7bEQ0tj3=;32XIBnsQMJZ{i zW!2?{WhJ>qh5P~r;wyY{IMfrCJxvbM0(}nle)hAU{fs#*TKPRr~wfTe}*U zuV`tU=EV9T>ha-~1HF@jebd7O6aBqoE4rtK`Y7b9RbxYN zFZYr*Oiyf@oup)DWMK99$j%LG_if$8X%x1+#^Vm50NCJ&-Q)3c1fZ~#)Axx{OqqaP z0CG}_jfetDU`oJ66Cr#d_Tf_0HghcKMR6OI1VbV=A*ZPOMT_7x5`{RML6YIxvyERQ z=b|XyA8G6acv$JrOu+3F^F+nI-LRZuAGT5Wn|j>0xDaTx0QS*2 zB&RFBj$kD{!*Y;oxIuYxC^**qX_SRTHDDMu#Q``}4E2 zEbLqGhsR(i_){^iwBm{&1^xh;a)>O;MeG@n-%PND+S=j}yWQ^cM zEM7A^r@_tur@pSPx4RqQa|QJP$NVlt6Xl#QDJtNgOAe}^ec~v6V_=HkDXyn1F==F4 zfUl~bS2X|;K?&ju4_>ezOezW}1o$i-5>$W=`~iH<$8qXhuT#EiNo9$jf6;6!J?IeZ9Q{{rxpHHQX+|xZrfKpPiRo zR*6kh#&6yrxDZDeP!LcduUD{deZ-?zy^rGoRk<=Rnu1#1DE;|`VgoE*jGQ0ig&`}M z-*Mo-Y1K4ruxsPmEo){r%uKGuC>iVYT?WP|`8 zM|(SAMc|BX0{b9({nP|C`G{Jf9Qf;v}w>vvSMoX;8mq^~{;uw+L%tC(D)& zfj`)Hx;(7@JD0BxG_E47h+K{eV;(UWRbz?}KwYBr6;PlIFrs7=Vr(SQwy`#dfN6^C z6m%P7Udcrs7R5$|Klv(%eWMZpJ}GSRB6NO?#QLycr3tVP*%86OAEsWiU?CQHBI=$e z8okfs*t~2~TnPI%3;QCPL@tS#LRj&Wb;c%{8wS`bD z?HcRrX65?5z6g>Y-i~eb4kz|LU=kb(7<>!-H5C4V-(zPZ4iS7)-fK z^2X)G(8M+sPXPPhxKz*$d5hM^ZzYt(xgJrgggngqH&Aw{T|nyhB;)#eQ#c2b1opXC zMDZDCU|km$6ksa1G&OZ~bO3zRy(W}CKVt*-bF#9~uxMd5y%hc@DSb=z3-*o87-`@S z-a|g3$N_*)IYC6iFkl~NM}f~V6@c&YaGu*>AElqnSq#>Tu#7y^;bacjryC^T59+yU zhVIeH(&A#2esyIfBCDdT3^_oe8ZrdY0olZcUvN4GXI5VJ(#o>J;v)PF6wxAFOujHm zAKp{;<7ycIr=ET)7CZ_A;A2ZM4;peXu9-T-I5Oad(aC%%@X7FNT2muKYbHilPmBWg zZR=O>*sx~zmi1fL&aRt6+K)^Lr}d)2R}QUMzjCa%wRN(8#mfGk@fBUG$A$nta0c2S z+Tgn1h=N|AZS;Gu7^tIzC>NAFiEj}O>!-#MFMGFa0RH5S5Lion7<+kj6`K#hkOUwI z{mYpKXPnFD+VVikxzD%?ng9!qo3M{b3LM@Jui(-vcnAJyTV_yVX`*7p0fHeF_!=7# zDj3CN;4i?R!#-ho0Y03$D1r!ESkR;uJ~p!e{P|-FU~SsKv#_KMeLxgo2JrKSY5>p^ zq>$A^P>+?uPYaL~`;0}L7n9I9c!*e;=4BT)*|ClVnq0E9Z`JCt(OJC272V=e^>*}k zVa5jyc-84Z9;Bn<)w~D$Aib%k5;K4jO=|5AbhVQK`-7crvtz@2#Vb)z^z~JE3QYrD z9iW~EX__4B7wnG?P2rt(wsR8M!oH_GOa(pPKW!aiV^14ZUajDZ|$ z$+A7o;b7wE3C4h;-Vz09d3+OkOV5#GB=VGieSQEC$4B(|X{RFY&@|WzODiil8b??Z z8bZC3{@_4LEI$0~=WzVbz=Xlx4|0(aYeC@#-i>QxVPD}N8MdUcu4e7zIIzVg$If3r zJ+Wccn`fum`DL-H$~EJ|GedoA#$bj%3{L8RZW1-Q1v?*& z59;-H+M)fi6O<|IrCJ|(`VOPsR6p+Z36uh>`BFE+nf zEQk<;KZyN=FaiQ6{HfH%@4^Q_D6?x7ZK#$8S0s-JpIEW{1^#4=5h5MKA0a4Vfd6Ui zGaSrCewCXb8-jt!Tof4>mEY>#_qE1d*I;$yg#laq^wIwA!JhWscG2=67bOnHG5ASH z02DpA2Kb=fvj4e@LiH373uL&lx4EIOt+}pZX+up_PkT#$N84bR!~u{Dn0%AN0|)^; zeNc~rST#00Gdj#`lT^{q2mbs#%xv_(U|;?gE)cT--^mds7@?=;E&!^jjslOPF8lRFU9Nf@0|9%N?-A=z$Xvz(fp`>TmXUqV4sjZazNt% z03WA7uSh5QkKRXKF$A!WD8v4z9HF7SbQ%GtGfsy}U_ZC0fcOO5YRLC*E{c7HzbK#u z3-Iw(8w&hG*bl-#hYs>1DW4PWVptok_$eO9K)sv%Zr^hJ)n;@5R zP`qW;^zM!8dfM7Jyajl1)e#7w9)q8ch^;AnOXdud_yG=+!=uDAd+ z&h^agn`sL8AKkn2(5`LkXQr@|(V4_+(fRoq*<+0jHOp!OTW?Rk?W4?Vj^}N<)$K~w zVRBXYi?}e5N2SJNOSAd}o0)YnLAL~>CCCikExoUK3;UMpx3CZJjp|1dFIMbJe840q z&wOx&IZwk>JM~m?|4&~)I6_oBHoq;7B-jV|HdzQztAI|bsc$35Z&E1Mr+PnvW9Yd# z*(`X7@rG_nbSIW~d)MBccE>w|+m22T4dR-O6WkjfSU0nBL0!?_j9)-fA;4FN0#l)ul7Y^4@%phJM3Qu(&4*TW4s^E@x9Mwd<|_h;L;&E8 zl|%g#11nJa$aBm;uwRgyBS@d;SE{;E_=~tTW|jn+`9rhgUCOoqi9LxRHtSOIm3RlB zT!1g)c1ajZVCa1aN2!GS%pY2q*LmdUQ7Gg5uL zxfux{LcmLW9UkI1I;+aY_XqwGXaN2O`zGu!@ShJ5R3slQrH?fZ@PWDYCrV#6zA^g+ z{wCtb6{W9{K;TRwj{yMo`3fO`ipR*u^2bl1{|Ev0a;NzHu&EAHu@6J1W~B3jxacP% z8t3%>d=X&jAqru0wSMQY&q^cKi!L6SsHS+aV)Fz4U??ETo;c9cIXybKHUw}$ipB@~ z>!z^*#0&tZ8)jB+Tepfh!1lGPd8ZO#P&lvLcqRd z)fDBb;t>&QU|=@j2<%wDdK+=Y)zbif-`0&s_v|>bd;8Y4YakjcpvZ6j)(v$0>dCL3 zzjb`(>iyVlxxX!{oNG54Zr7a35S1O2(c)!Qeju`(|;< z$OpnxW+{;Ud-JfLX!O1T{%KZZfHpDG_|w3Pz<Gv5V99J>)<4h4kBhKem3?SZ~)zU)T6x@5GS6AH9qjfCdNP zs^393etmmm9Uj3zcN-W7#YhI~fMwD0M%{DmZf?NZ$8qcGUePi*)zjMA(=L_(iM#L` zXc^Q`jSM1EQ2pdd7yxj~@~UMq^PCh*4vWnX>=y?YlEAtcTqYrY)e_(;ve<|Pu2kVK zv<}7g#R!z=|I65Wz{z=)_x_f&O}opazMjhAwug!arv1DDI6}Q+Fas$8v8oFx3>k+KwASp8TSL@ zg!eJynSIy*8vucz39d#CAguV~u>tU6yk0Lp1;FQ5(uxD0k-Y90AFX0jz(20{DJ%i|)bM9z<{rwbiQD|dtR!!hG!m5Zm&w8SM+6`VfIq`4 zVItBJiFjku;MX0k{j~wWlxghX@M60XWICL!g3Ps6=k_mppZ}KY6R(&)`P0DrzPhry zzPY@(rgS~|Q-BWvOwbKlwSMnzY3go?lI|bv??Q=dT@TWA3P6KeONr^x!3B218ye|Y zz0yPmXP|p(Xn;rYKrJPZ7+4gN2$0m?IHHFB{P^(f=n&bpVva6Lgj|xHB&TWK(=4aV zE_hhjn-?7z7>%!mKpgwZM3c<>Aqu&r>PfJl5x<%Hxy@>|vQ1xI!nFJGz`n$e6ajfH1aJ)qcbV!o2^Yv)Nv9%VSZn@b@8XK{P_F- z@U_dkr_FEqQ{%^8ulnE{hPVGq@We0r8@iFtd$BLTCz_0)OIZ8B9I1!wL;Xl5FJT5~ z_{Xh+EbvN{PsODZ!hyVAA;4GF5jk0z2Ejh8NG?DO1F|Y2C6FgrWC&&{M9GlkYYG`! z<^E@7QEx8RzDhJm3P5@K+6+iypNJn`JrhUxi5-&IwMBf*k}{4O@j1+%p(BCkzv}q? zd)7aAqxoI`lOt&v>g5?=IK4bGfqexY8E1TRBrU)kN1Lk*KEOxs;~JpE0WyR=fN&6X zuXH+ZCx?2L$2qNb!L|N){mAloZ}((>pPo37t|bZg>nl7#+Zf0k{<-14p6c>)&2LHe zqa#0rD6>i{!(B=23;cDYRrp)1CwN}$0baUQB0#Fr06&}d6v}=qjI9O}~KaVI1B)-3@!b3lbip2P*go5?! zxdlm$ACK>W`ULP%-&z8g4E&Rlwbv3rcR)8cK!6?J9~HouAl`9fkp@W#K!|_{HbcdD zz%{h+kNTAd#TX$NLTps955$Ex<0Nn5FDxgm!4$O#s#2{%Mb7`p!82|Up{;C^63-T&hB=$v@rgxpeFvlFg6D2 zA>fP&Qha3XW~uzHsK@ zi)WDoZ@zPDX=a-21`D05$||0_a^}^a{OIK${qUnNJng;pYqcN0SM}0Qjc@w0d*#XS z)G=dyn^c}<=ZFN5!XC-PQ=|jiX#K9S&yUX}T?hZEAfEn+iyHf)#0C3Ogm(X1=zV}M z*q3l$3D`#sWu!AtQp5%)C#qG`_y>W%JVfA+{jX<}e+?s3YaCQOc!w}&89Qb6ivQ)b&aWXKS)QF17!5R_yUQ_AM63Ds>b^J+LkZccHR{o zm>=osm>BBUx}NC+^-4a-6&?5EB63D-fN6>U6IlQMkA2O1y2WThUP5$`2~a`^@L&2O z1#s|bxl!8&dfq@KdKsn68a_r9OCEFse@zC;U#kre8lSiy7qzF)otkvS57keaL1AA) z{Qza}E0>b7tepJpd==Q2q#iHO%ywb2`YRFR)A2n~_eK+BHA$9Vt9!(PhQGG+vH8*d z0FBrP@k1rk&pmPL+GE!*-@0(NAsFN*pl>nyNcDo*Yr8vG@28Hi|L+)HKVBrQ zMD-VE@fNZF7sf}(3sd2P1b{Fw2pwEHwT*Lu(7*+tb7gnuv8xxMM=oDjnw})u$3nsK zqO!MLI`#5Te)!tGpZ@jlf3oNDJ4_#X+3?KYR}NjX^&NB1oT;g6ra(+HAua5bM(`~y zg>-0!(#v9>1A5^w@%<46TH_~?t8}-xRE(;|e*88TVypbV#(rTuzt3|smzhRhbdz^kN`>Sqxac@O(pjw)DQLvJ+X?5cyVrp!_hiXH@el|Gx%q} z`O+6Z{qfeWVf(wjY5Lq7)<5{^+>p%5l_P^Kp;c{KCS2(b~;JY$|b2~_M$$icO(bEXe;>B->dos`RXOpk-$C|Bvhra z55r@kGo)ZyO8|rbhCN7!=p>2j+`w&nN%DQFz)zH`)c0T_X5}E~73F1SLHUOcRkE9C z87G*Ra^kzOvV!dh*-#y-t*S6oRT8|TW|xRx4Z%I7{WbQJ9)Z^TXn7)jN$l(2MHCU2 z8Q_C)4SZVIPi#`OvlvZcR?5z%3jT2+AXVftAbhGrtZIb!;ynp`EeB*q)YQbUYj=iL z4dY=d5hq9DJ{=Yv1|+px$58!ii>J0WF!D9_AH8w;u^U&w{?iZNeB{c-=7xGo9QgqV z=i2J(%cr*QTs(XI%t`I+gL-&UvE>9-sOFi~84`cXGM&4}0oFfEa4TEr>ZA3}*E1b}l=xvL5*h4($`p28tr z;3t(*RDM!ToOL*ll8lVBg0z(U)B{B+`-@Tz6sH_0NlhtDO)XDPtI9~P&OBIqD9d>G zkSY7HIXB0YmkZVA=G5e76J@ThSKS(z&;V%*T6^d5CG-VIQF%s0{$>;LI}tR5V%ufRu87q^8Ypbxf8LRFb1@d zpktf4hq7H(>zIoAYM%~~4q7SXlgQqwZPEDWc5hud|Jbc-&p!Uhlee$G`O({VuU#Rz zPuWR+F`2YN3NwehJ3%p4y^iCd?%_Zb6IT`{Mqwn1{ILW;y`pJYmrpVKkpS8TzzjeX zkmiH5OgOQ51S2cIq|)dP-`Je{(La3k```ZNum94sn`bUMuK$*M^I6BzlkW8=-H}$w z)u>1&meaodatIMNId}u|nm{FbU!z{Pz+Zq5gt6Sw-m2h7;HqB2Y05T0ydEZUKxT?T zM>P}{$hQy_%m*x(o1^%O7?)2K$=EB_O z(jr+@slcb6e|n4@-@@d`3K0NA!4&H+(EH@(q~-@>fH=PfEP5Q9pQL|(N6T1W7iQS{ z{M5?aT;$Qu)V%vYYCiPS=+&24z99l+Vi@-UbR!}#62QJr4InzSJ%Gli&(r$a+wfl~ zX%OX-r2Cwy!M>-};7#C{Ayg880F3B;`a(+R3dSk2#o`_*f99hMXxUjv$X#^D} zkE3I8d#djsiJQU+qd}_Q4_LT!0uR2q}=QiYk zU|(D@QU5Ym>XkJ9wFKB}0LcFG#8Ti(P*2F0HG^p>g{i4UDJi8XDdj2qt5Ocsq#Q7% zrkK;yEE#F$jC9CyFavTNKIF~M3lcp^h3$pt!7(zeXC#1@h`4e4R5Xd)nhA z-`b)B`_zqG+&yvQ;dsBDFE0PhYi-Rjf~UoZML9AvbnU zP({$u7BjZY_?Pa^j10W<>gI31^vnP2v%h+7XU92t**kyTG;lN&Y$_`(IhZcRkh}n| z$WQ&+W9_SG-2__5fM5|3QwcuAxV+4=#~fr z3W`tw&(Jv;?Q2MYMv;25%r#Y)DJk4VR3FHbnk)vYr-%Cm z`*V|AK^ma_XNkAWj8h4K1eRoLq6UC@!5CYanc#@E_P2b#_WeIGef%fZ-+8s^=7$!i zr{=~+`4-j!h!zZ{G9trKf#uJflvQuurF#|SDA_z zFG?+WzZMJnQ~J2Nm`ob`TJ_7UC5(S<#OnHB%m6eR#BN8$1hO&?mZqkZ9N1T$vac$2 zpCNUBZQ21^Q(B58J=K}51#C7V}k@F|Fubw-7A}+Lnp*xfj z>K6~k`qwh*U}_rYBH-!gv9oPXc8Sp)8eX$>t<`oPv+us>IQ72AZ(RNEH@}A7|I#1+ zZp-9q)qnrK>3_c3@%Vd)#1b%BS4ln0DikpY#cZPkBoVVjYzVW6_8%SOBE-xBSZ0N0@A;R83okCtFU?I#$q;%UfJ4BaR)+|{yM8;^ z+0ob5Hqg=0+txZ2rM0c$z8^7Ec;mx-cuNBt5-M%=iPSV5m9;7#^q<0-J(a+rbP_>^hVM-UZQ_ z>5j|{XO@uraHccsAgwp&5JZPht?4OAvLH8-l#UEZF)0$@3#CE^B>`$^#TYnX$Vj)A zmU{h-zLrsU`-H1?#2kv1n(T)Qip5rh*@$Lkl!vadws zN@`Lx(9hfn_U}{twz!w1Y=CTQt#NFyALfBEAR_z#|K!mP*703N^9uOC0-nYw6dnJ%t0;TeG@t*kY2akRzLhg~%Ai6Q}d zsqQ0QFP3H8RtML@lq}#DNeevn*Wof1%~SiL=gLYR;7_OpAftj%D)6hYtWy2xeY|%h z0MFExfY$pDVjp7_wiVN#e?mJZDf{=+lSNf*4nh4`USY6n%6|66isK(MKm8@|t>3wN zX6Jp+KmOIf{*%wW^v>|&3B&Jv&+^+p7`^c1{vf3h!U_^ z^_1T*rwCqsC-`Ne$+>VR5_n~PzT?hEosWFpu=}3!$xC?+Q?ES+hksw)swJj@m;%*=v}3_R|N)YM94cx$|)jv-Jl7JgbPDjOA_ zBrCd`iwfG7v;z?RWG8vuoVs5wDx{m!@f02)!G1i`Msrgf9mw+Iu<*6f1S+! z3d{Of@I_VmI0}o!ymB3kp)=N`7d z@a38he4}CJ*q?vuWB1;8{qMi{7gLKzJw0n>R{Stzyu37H=r$SOqXYbj6^ZSnh7{m~ zSv{b%(qSW@>}fu(wZQ;>^hg0VE5A4vMI_sH9z8BQJEta7uUH5!0L%0 zkF&-)%DLH@(W&yL(OgR%yS1|wAnLZVvU++%@^>hGf(Ez@V4pAQaG&n5L};L+tvlA- z)6#m!^Rg&CRTx+LEBc78@6Xi*?Hi1p405W9<~2@>#^`Z^7Nj4eHe67yGK ze}r-N!OWb4nRyxM#c3%OsVUX>=>Uks4hQUe378AgQ&X&|saEL=@D(LhxxhaOa{;@0 zYfd|0PKN~Y3H^S+m=5t)cT~$iiv16z3-C>u8ODRifmHg|`~sIXXb<*V>-+6Z1K!R_ zZ_li|cg{bw<{4abchA;(oAOGkGAZU!oJwUQ<_|B1Le%;mPhZ3T=diCrdEi<|45y^f z(BIY1QJ*HO7IQfiaHOvX&RLioMI*pb(Duga>8(wGkH)`o{tO+k5Ae^QIDYZe4%<2{ zOiWPU%${(dkIIys;;P!^r_3Mu*N)%#G6ytouPmU}Wg*WZtN&(kE#XN*f7;(CB*nHo z+=EGv9MHfgL#@O6$O^1h%#Zo;@vW7m#hZ^?Kly{&Pyf4j;l!su@Z!BU?)};4KGQik zXK5WPES2Ml(E>nTt5iBj0S$Rk{d=&F(uV*hOoparSsj?AmL;bAvCk6}7!!Vh zQtk)=F;Wo)sD9<+BS5%_dBDxmSMo&muhJ3*nW63n_3@WPyi|=^rzkT+!xk2Pf!u9N~Gq1FxnhE zqKmcmr*>BtXo2+UkpWim;PMmklc1m4--Fwj2#LOuaG9Oz?`Y?5##9vlPvy#L4YiAt zlS@++WsP91Y2fou;McPa2zA1}tu5WLSWhdvg0xc9(b*E~YH23TXJrqcM4TC})4!f} zFKO(@m9_dvUs2e{ZchfIL=43hnW{z68jUZCHJ2tsj^d}%vLHR3Oq^(WZCYc}qu&+! zw0W;WdFdGWNC2)w=F|tIfx5_7;)J)Z3BcB-r_^#?J+n3~l?Q6C0dt}{K}xO5TW#A* zM=5$*`n3mBjhX4DtV8yqQm@@>4YZqr{pMhIbzMtUeY+t#V2X{~J7(Q|tNx)a|G;r) z$8xo=4I2Q&tDhVn2Zll-nX=oTrbM_;oAla$M^Gp)326!KO$UH_4Sf9(%x)`O$mq`JvtlWCi^m{MYe)?tm%8i%a@z#4kedX6b@+-lXfr46RSw%71 z>7oRZ`ZSJxb~sR3Hc|RgkcZ7L@j8ut1R^H7-Yp6tkaX3h3P@pDN`Q#CC~>J(x%Nvz zF>D8kF@PDM->RD>k^q-0;M2%Iw@2wKp@A5RM<8_v%OA+o?%%)vp@$yA4B$3z`<(Gz z->&}nJ zreHFrhq{MVx?)YJ`>y8ZmikCrQxxoX#+o=<)NQko<=1Qm6Ka6#QAxr-iG6*APla8{ z1tbi6#k7f36c%i}2u;ZZrOTL4Vtx!|etKGI8juI<5@!RXkN`iS>oL61zghw)*oxUN zw<-JoeyhHyzfLQdRg{D<8r+n1(0n+H++Py%x`V(WEhz0?;)*=;fH^DET2NvwXNf_* zyRO6E)L-8*=8KIO{GDa)#&Um?A=FnL95RGQElqQ_wxjN@GtQ24){e90)}vM4uDmkJ z2V@OS9QaB!>s$uRtCy>510Ze&U>*SK1g?J``+T%_oEcklO||v`*`rT+c~dL%vx_s+ zQ=`M(?XC57ekwLO2M%=Was**;m58Axnbi$!=EfhDUsz>bdAt8Ne&YDb8?LYX^vHAX zqf+63;$^91Nuw-K)kPrmd;_0hj$fsP7gBs1QO?Lta2h+JOie6ph=D2v_`SE-q28Ocp z_ecQjRbA>MVoC`CfUg#8fqqHy0{{I7_H&A|?Z)pKKK`2d7r*xAC!TuwKmYZoul(dg zPu=uHyQ`bVoOKOHmlibk*?a zHZ#tt9HcMVS6$b?0DsEQdRkg12U*KA#63KL=QA(Z{1EVGQ-zLblr!U-!=ctFo5?i- z{Kim#O_pTkR9wY8p!bslpA-Ugv>edbhYz(=ufeXuP$B{3x>{{2R|EwptV5u_EKP!G z#xx1v(JHO2bh@(ebUnTOi3f5@d+fQCe!n~UJe1hmhd}KPDSyx@rU^O`l^8s~D zhB)$EuS(rdQm;Z$IoMB6h4fq6>VqkcvNDe|V)J(xyzSO-XSjWIeBo&C_-eJUt2Wf- zXzX*;51PV*6`sy=Ur%NIl&$@^tMk0A~?nA#Hiy~miAb)k5lbUM&dT?exnz{=!pY5 z3O#WEagj9$6f?_NJ8XYy_W4i#Quv);b^O(9jxWE__L2XAUvQ2^I%~@~{^asNH>wIJ zlw%;on4e(pj+tXhCa`oDQ-5U^hg8B=2qHceqjYqL8;&k7PHo?CeDcSp-@a$K_@Rlx zp5J=M6N4@Fxl+SLj664~@pWe}_TvV>!X|&WhANm91r4ml;Ah7i*$9U#SO`hLY9Akf za~pl2jf&Tw(jp)DqDTe>fBj@y?qQHHFCgV#DEK1;c!DbSlL(|Duuna3s@f4$s*cr? zP2kU#i|J{HEGus|y#I%$cmLCc^Vfd(oqu}ya#kfDimP7Uz50+u;i8pi%ckYc>4Ya>{P8 zP>51dTIyn%xyQ|VxsF(Kdvmm_wM7w%KBiF5Zc>rfriNy)AFQkQ`$-rj^uAzLX&G%X ziO@}w2EO7(VN{Lx|Ei5k32{rZiw|d30=>9$$Cno^A17tcW3Eepoy=OC?i=TORrUjF zTB&S}^y<|8m(jws%e~_0O%<_e@rMTgqIG=1`}-u{YQ= zX>I5&b;nBleTK#BtV z9kQ9sZkLOCWQvt6wFbXGknT%addZcm1rKu|9X7?SPI4@ z;1B!3rL6Q}I|z0ILmIFX6qzHKlaC+_18n}q$?-KR1Ww+vedI@$U%h91^bb9C4V@ty z2T0+dvYX0YYkx2HsihI)9H$UcDmaOKeh*jpB|u)oUw$FKDk0hg#fnYkI*a}=?9~(Q zO9t+QaaGVn!=F}vo$O2;`|5$PyA~rnLHi(a>|?kB|0MRs^_N#F9zaS;Wq8o^#9!3D z^E*>V&VA?WfA^Cge(&PO0$chKzHJJJPar(8_Gc*Glif8j-2pgOJu!Kf;%e-p;7;y3Fjyh;EN`DK;83JYkbX_@~N;Z zF2Uh~!&z8(C|rVXR>`kPfG!!t!)MnG_XSC;mWP^zYV zbgDB`TqOl{)m6TV3QJy|zp|1u5Uu$+D0jYVCTQ=lN9+!3af!X8*u@d#CB;>l8Rh9I zWoZXW(+20j?HC6{2O`%pxq|<^8 zP~T^a%vf5EySmT2yD$5?Za6xw*t#y;`_9|j7RyX_sRxtb9|a+@6)o`pzhGZg`y?T+ zrvu=}2V4aJyBr>SlhP1{%BN2a=ee;>j20oBN~ODd|_0_cZAk})vd6RA}t3r zel_ql_BDRv*jJ)}LD8yTV4x&`4h87(!VZ%$)z1X|m=;QEN{&W-U8_2QzpDAc4q?Yh zS*4l4KHGgjg#EPON>vgex1iK^>V2kXzt%Fl^M%j<&JX_S>np>ZVx8pVwl+ktrih@j z7>dk3L&SJuFHzHrZNI)a%h&>KZKdlhd{-<=G=Qr{@evi05vPbn@;qYQqoBr%@s==fg3+82``FDtt|E6bRXVoN<>!->w=PozDGeX;hH|E`_% zy~_P(`T)N?b-yM`c}r6dP|7PL{e8vh4;3jYPJ5^*Z69rU#{SC8^cr@{tf&aq8X;$S zsWJC()xk7l&f(Tj=*ZgU_VH7!SncI71fSPS?LL-C>Ve|a{Y9z!N~Ck3oP_|@HKleJ z#XV&%PrlV6*tfb0?Ve(XuhJJXh8n!B6lW~8j;=S4E)K6=9ND-rw0^sH>E_txQ|ejE@{`fzv|NFJk5C0a6 zd~cjNNv038AHyE+9&H7#LA{PmX%`YZAGU;DwZ^CAEw_j>CtE8}6?y|b-Tb(u z>c2nrDigcWfrl8_eN;6W+ z(97wmCFv<8Y5Pjj9s=wo>HEqK9;iH&R+E3oT2&mdnL~D~-(>U}4EEA8TXBiIy2e~o zSaC4jSy|c}i_MHruPm-@ZXDZK+gw@ZsM1AFbarwe01JZB_6Z?X2pSX?lp0O>7H5Ik zS!i)p`y$Tfj@nS8E!yH}?x^&JE8RhFYiG~o+}zr+6~bfJo<4r{sfC@#M%N#mJpQ)! zxhFh5HyTDBX`OwzWBy`&|AN8k#ZUtRg>uUAefTpA8tIH}67qE7HW*_nq$Pliw#=YP z^y_e`;xuvAhDupdSs5SvlPtdtC~ z+KQW#&jS%tD7b{8|&yupS7}z-98AUv09ekJYiDG z_;sA0F=WsXm6{kgMvNJ{VNzqnToCG-@Yti1Hw!-q<< zGKsO<(ht}(4$wkW+Mx8&^%B_Ez*pvd9QdlD9@Go)6ZSmSeWeHXK>#0(3{@UFSa~?J z>`+EcK~7CkUU}Z3;+)LV+(VT`d4|#=hoL6o^{_$l^yKvH)J$(jS5qh)4b;_pJW)2- z^m#*8bF2Me4_ghMAD*`Ni>xna)^SEt{=nWtC@Tma_*-aj_iJW2nik zHRfAvr4Dz6+h?h7G)5xMSWDy3h^Mu)%;_$7It>ATLr?G2#<8OpZf#w@JGihrw0L=8 z=gIX8FEmU%Z11@08@Lr2yHh`Pt$lvCb#S86z@N|RMdDR)3Bcehrq<||mbXg9CnG9} zi;3zf(e;Us9Xh(8TVI%U6H=gMWGTDuWNH_z>=B>s|Q`Nu~%g$Lkch@$jK8Iv=jg++O*{e74g z8$io}gLX-y3Gt!y!T!d= zEHDT1RPH55Oze5JdIAy3MFy5prA0(=Gm=3>E4!u5O?zBU@goZI{Z`{IJ#qWJk6&>| zx+`WMD?9yLma%L2aSXs-4}C9e84Q7WBF>zIe6q8L2^lKkJ<cUq)qxzHIqJzSx zEoMDz)#m zqvFuP>YPL6hYptI9cD8xhsWn@Xm;1P_@nLq#x{4PIndPB(AM45*3;fM*3mZ_iFUZd zF@HmQeREG^OHX~Yy|JOWwXxZ6vztnaO&pz&ooy*Abz7|#r>E8(wE7}eZ=J>EvDn>4 zySv8WF1A_=4AliDLxJ5=?sk>AoP{<^p4F6VF&5Y?wLyQS+g55fmAdVfL6^U+p?z#( z=IH79?ei47;RGH2mXvRW(!p1@hJ{B_{@FRosGn#x}GU2=TX-h+J|QbQ(a(xH2; zviY0UpRLD2THvgSzObWm=e60-TQy{IJ=uqGMK~zEufNXfT`9pJ9iRjYvPC3|dhz$@ z*a{fYm6AkvH_SbJ|$t4(!Hg+mQ#8EaW{&V;LkJ*L8A+}Kd_*W08C8lX<|c;52Kw0C0>^~|GA^vn ze(&4g_`+vD(KLCy`pLhldH(;@F5KZjiX_-IT9a}BzS2Af_Tw+bczYpCU-K9@C!eDk zQa?@ib<54NTfh1SCTH=XOyj{+TY8E!?EqvKb&sjPpYplAp}Zvat5Wtqpyjm}ugrUm zdR+Trf^S*rHF;T;Ia%e|nMH>)%d2aQzK|stvxM6%^_});r=zjM)!6Bcb@`e)T;XPW zUDOtcnmpkud&uBwsC6}1e9eKz_E0p|*xDXxZgB;I9JAwecuf{(xzSQ$aa6g3HNJ3_ zH&7j@D|0%l+#UlRx2N3cE-+h)tTqpI5Ix=AmY5|HGDkx8XoI(<*%7%EPp1X7Dk+)uZ{P}B7zU$TzSwENO%D{ZK{K-V(`m#xl_+qaz%l#Gajrag?&W0 z+hH#EB*ob>&fvR1C`K;@K zIW^b;xE2C*U{U%w0(1!UVV7zx2KSPmnjIUPo?W#){DJ{<)97_}aZ!{_3}XHMae<<;5S`-u!p==}QF^Y9=^A22asm6brN&xy0*d zYyb^>%}&X0(b3OLGMK)?Z9I#4C^&qGT{27=thL#vjQkWN08xGFX-VQ6@SPv1rjw!? zP+!R!J*@isivGU3$FDaRoQjWUy7*e6{XSmEC7@2b}&oi^uB-M%)dtaC@IG z)@cYt${fBDo448%u5bh@T>*nHXz&H>k$PuCW3|Uu>GGC2+?8%$mDg_w1ni9s;jYfU zS&}sCQ=3PEYb`L@$n9&c!D!hI8)DT#gMXK7p~$DEFy7aduRe;U6t4*cZQ zJb-B<}(dzcb|Xs+6%YOfBgBoAHH*{u6w$|8w=O@&up%- zS_k;A&PtRIf+w}(3EnvaLfibb5WI?ks?`&BA_u5ZnHd>foLlf*|BZs?dHHGC?3XSp z#(*|zU4xw#jej5bdo;L)Gw9|Irgm4BJE*KZtr+d7H}+4JPsI|2_TpWOLIy={NCf?; z{zZ&%F>X95Nuu!1sE8{>pF!d|`cZPHB0kkCP{4ltPgPavfE`6o%cuIKqX0b0Znv{n zp*lJeEEbUJ@_Ss1oRULX4tktQes0%TbTH_Z+-RNy?dYi=m)|#K4SRTYli3k(X#wFn+fg3?9cR*T$F&m zEEY?~`ZVN|ESLOlobeJOMTT5l07ROMamk@W22uB7r3E~|P!(I~+HmLBxLj?yOD$Yo)&SxcWdfvg*oP(*9Z*yk3!Rs@4{Z%es znblS8@Hs+JTU~u^pw1c!oBaW!%TeRBl~|00rrLtq8qU-#G203a=De!fVzV{Bx`xvA zDy!Y-_SJgoEP;BK;S`u0g=SZY)mQEam01F{u876o7;5XT@9gn3HkoQRDMm-(Cp4s)T?T;w#Bd95`;x3{BxWaY^Ar8~RV zpEz~(@uO#N&mO%tv~sOy={9k{-qojj#!vN(Y>ywgyME?zZ>R-iQ2V45J(*K6020`b zvubkI#1cpdhj>TiM%+Bm^OeNDu=Rs4<}23T?caQp_xN+3lkf4~{rn?$pZME9{mhU5 z^Lu~r-nYBFp~BLNfX_>WpZxyj!VH!C8vC#!EQ*$g+N1Rt|JeL^0km+hR#@Bv>q2v* z!!sis|2OO1cp{SmC)v%Cvl=bIfS>iE_mk$>(K?ByY-##h?P6?eID;B6i_(|vTiDDS z9g~+sf{J5usA>V)hzM=%@5R103E)e)s4@cREmm2g_j#=FtICVW$g-u63|5vvUwB$R z)nBKt{|x>K^gK4d_$gX&q4p*8Cv`p$@qH;*Q0YG{4Je!BNFsG+m(+41Rh(8cyKF)1 zfW+n-dW{}t5@W^i(gJo2d%(^}@)iM0%Ughd>Ga97J6q`erMZRR?N7KbeKIg|{3DN^ z`^ope^YY6-e(Arx;C}W`3@^P=^V~n%r*3h4x}I<(qQFzxkeVxKHJ=EU)eGQj?5o(3 zvNPjj#&_d%pYa~RKI4?l1XShbI&-rfET~V@F+En(DAZG{b07FpA)j>Z$95FRij!tKDvMFk}x!EWWxbo1@rh zHVBISWh5xQ#N6zqHcPSDSVSJVs-~d2ro?D2G1*GZj{ItKmEBuu^OP9v1vMrFLaD`3 z>GYPEokg{de50e->ML^uD{P^1OR&lwW+xV3w7scku%V+j6zgj09vq%tT-w-L+d8qf zwX?Fdy?Es4%-Tkzv(xAg^v%wOdb;v0rXq*6&~D7P)fBmED+5kPbF_PA{>Ztj>!&Zz zA3HO?vfDGYJ-hYD^69rtY`vv>_Ig9l$>6}1*2SksHXpZp8}VXAOC4gDnQYdmXk5$O zF;kkvFo>^22N_X+H9QgMI}Egb_wyJk6=q$xUsD>kihb6e7;4jAry6x6cb-I>DI->;e=>vHr zDkG^o+6DmT82kXA4m+{1Is*x?MJ3hRO5-#C-Tv7BY@9#$_A^WGf7{*9|N2X}9(jxP zJ^!cX1Fu)U^;_QMhdE;^F6`ypM#V*9zi7c0FVW$x5~53aoyynCW~WdNT9y`<)abU+W_ z=V?lLC=W_|C^vmS>OMO=v)ou?_WJ@&vAX6KUt@D)M~}ZTX7U6|&9+Lrr^?|iFS|me zV_j2?zp>I2sj%Z3ge&dg3ah``5pdO04cXr}Hap0b>rn`}+t&Y6k+#f60vC+D_K^v|z!&a86qeRO1FX6N?! zk%wEyt~8BYY#6;38hyBB>G|P}r!4L!rl5dT0EeXLJTY-HYmip=AU%FvO{=yIBdUzkTORfByPwKmE*m-)^p{r09+c zF&5?kd)G0cu^2eafX-6ZXWn}87*a@d%ne2zw7oA&Y&@**1h=zSKQgME;wepMX2 zN$l&wKl1y03ef@k=wF@;mXk17Odn6Na8X~^e+jo~O8$i!`*A}>^u8|iO{jhe2oS^+ z7Xb8e=!EQrD93f8_XYbSJ+gZq7$;N$>Jg_%0Nx@$88JP8xeD=zTu?ugidj9XLp8A{W+kaHIaD(lo1boxrokQQntil*8T(nk@1P;28+vfFwL6A8u`Q`Syh^gmQVWl zD0&^kmjFI^*Q8?j#i;xJqUdu|9?DNYP>_+5pSCam;Qo@r?DDFzTASJ5*br%D8B$+! zS6@S0XRK$SuBnwMe?g78)Z{EPyGv_bCAF?{tG^UIZm{N6u~l+yp}|&MYcDZ64bD)N zHCSTw7S_5k?2UC%()5KEcd^-3X7N=!!=_-fy|Kd*X|3_p^R~)?1gJB5!tREa=AJ=- zKe@Ou$4PV>TdPNRfWOB6=FaZs&Y9J%lcV!1fmoY07_mhfd#C1_`Uh(LeotGhWqh=2 zW_omWp>KAod2qnn(d}&Qb+?a(Iaq1)#_;N`mdW$6iObF7H)6AQM^3(TVEyqLXOrkU zNz)6)Wjd75R)a5Zlhsoi_3>6=pD!lo>*rCQyuxE`bjNx42Ls13|x^RenekKAIh8`}sC@KLur?;u9#-9oUp#0${Q5fiUX6 zw5p=Crn0QET(92&_z?a+_n^rnPMUzNR@~@)c6>vh@u`jy?8QF+sK&Tf`nt~->F9qt zjuQzD^5>!S#R1{()Jp}EhRXePKc8?i2upogO{|Q6>?=y_*uNd~g2}-Mvsujy7jhEe zNrxfQieAH?w+tYCI*^X?q4b#rqI{dIr(RxQN#^RsN3Fm8pOwG3h0&V8zL-%W@MU96WicjfetxLNyR=dzA}p7y#HR$D z_t^GYU&O0-U_Truww}w)3q?DZwl21WV*npdA0M9-9xG>w=cDM!+JkrCFLXb1Cq};5 z`4r<}=O1{eFl8U=KIgzgMVV=pg*nwFd4_`AvaExZg}H9l(lkdqdwctahkJ)dyN5hsq+H!29-x&6p!Vy!X(HZLubWKJ2m;0A4Om5$99^Y-5xY|B*ZDj5G?D=oIRM2|ev+GzL?GCg+P=(8vZ!p8AMko)XEl&_ z_>kRh)u?AM88<|z9y%nU*7X2i%TKUR9}7zBeTpOr@ey^|n46y1x@`ZA|ET%!ciR_F zfAb4}_3CS{{N{_l7#Kfgo4skBx@MfZ>=-#xX0*kpIuYU579%oW4Q+hP)PM=(<+?8S zg}dOfxDg~{ph=B!TjZR=%kOe@8@EXN~@m#!@QMBzQy*E{GE$(OJm z*1k^Of%KGph3uzIZC+MpS+*1cRpw?_FXa!17QE#z)4w z21nZa2Aev%ef3QShcCavlwD$Aue5>+dvUd=!W=NVi38NvI0B_cSFyoaZ1j}bf|ZU) zl_O#cw%Nno=0KZ0(&3DDLzYOJDcEKScaSA?Mti(1gF>+ZPpqGgtEtx&?eRo=e9Z%% zXumJoA8s9PADEt8+Q81&+J9~9iPP4>8CYV;^T^szgl=^T*f2x^Q zV;}fW4-K?8H)FpLSMs`C{hjh%AkWiikrkkzr@e(^7m;*;OGBPt7}v{qp#<}(KITj$ zY<@WyuLOgiKE!pc&;|H=Nbf!a_8}Q8RmexHz$-Pp`dV_(p} zM>=Wj1AmbK%KgU+;L%tKz@L}RY#QonpBn7v=X2Vi$lW}ae{~IXiKCjHM~7k2qJXz5r_Tx99M&VpBpqFxAHMQ7^RNB5_N5=R&+UBki+}y2|MIp03y_#sNrM9xO9^OKLq5wR1Ka{jKJ@c2@)GyrDqLkT2HnY3}#L z23$>j&c;4>(}2Cc$J0FIZ5j5pj`-R}>N+RFJ=5XN$xz2cq-Q4BGhNp;8S0v>?-=hy zWwBEQhf*FnzOuQ!yt%V{>=d-Hfg^Bg`}C!g=dK<G>l&%bTaRPG8wRdv$nj z%^GQ>E~wn+sjBlE!a;Lmtgd^sXLdW-x9RIW5*pi%j_kAz?ZkpDoXt3Q^2yl~ccX2? za%7GuwEG9v#I^s=V_#I+eeBa$(;AoCacLl$Eb+=b#KDw~V7uqWZ&}{`@0RDjZs^`{ zTAVf2%t;wJX%t~YxNc{4nKINVwP_5jh;j$Ba3%^16oYyo4-e!1YwW|!u&zco9E;xf zIh~lxl%YiHBLix=u{IC*y2k!MM{7qc8t}QUrG@KV}ukAQMn)Vdnv!cyMcy#x>+X40>OM&cf;(t!EULDVDuO$#tk!ozSi}K zK|~^?B_}N+7t3G#BPDy$`?&l)PkprdSMOE7_xsWDV_*F9KlVS5=p76anUzX6ae4a)3EWKwHOjc%1MmmdO%hDv8hoUbcmv`Wyl9U6~ z)z{grA*a)AG};Y@XhVHZUvF1;cNhQb?(PNb?H#esuGX&ZhFF^?7=gT@24^5l>x(qj zSe=EH#*%7ViNR5c!)^^$+ao4V)aYrfan~DtO$JZ2+FoDlYBKv;tt_^UbUPb*ea(Yl z-`_ImYaR5rf%Kt3>qw|$%-=E`>=+AnjtAODgB{~^BE8e~y))tNsc`R1q<=QjKhroc z6C0fC8DANgS{%G`kpZ?LAWz9tl@4YMMk!`?b!VGHYlWA!6jT_f9_BfD+U-kI6$*_}5p zpM5sgG0r~a7-3Q@tp&2~3-(2lW9^HxrV4wKCY%n%X!vUhkmLl+S5>oyni6)-&nt?I zZQGvxTGgdbUe;3N7qELK;1ru2 zT#Go9b@~hgOVo=wfSolg>@vu%1BeB9kygM?9~9H5q(3o0o&8Tp0E9>mh~O5R*#he$ zNwkOn`?^R#58__dXMm6Zdu#w1GA$E8eL^_M#kfg8dL}P7S|6HD?5T_B<5bQ1fG?}4 zv})?6Z}pL(p5F0(N#5yE;^%{LMp6$fEd!f$0T8zOEgf#d1|Y@X_oh$P{MsAl_k2Gv zvhm_`cVD=5InXlbjE&?~J2|PwYPFJIh)=irkHj{4C9HQX0W@#K8AiF23}iwO3h?*d z5LY)$MQ)zAp>yl{FO80F*|Kx2sj_9R^%`qcP<5_V)Dj^!0c3^!5!7HO5+kk^1_k zSTNe`stZ~@KAWe`=?}Z>*gU7+6KvpZt=(;P*O{HcYOBxS2-P|w21mWg9d*>TS?XFW zb*=VbrvnOgIzwHa#$I1jpFcLhDAlzL24aJORtO<55NsQ+?;4MEj)ptNB6PaO>pREU zqa)lk-q1JQ*gsQGJ2)GK`e)il7TSj9I>(l}#})@Bmq%w;r(_Bb7%GV>7%DEY@NQezI|rn#JQupm*YZA(M%pWhCHfkSp{TE;*WT1_s_(W$ zN3G4Xq2aCA*zunT|=_K|+;|~|P#ThxOy$@=2k`meb zs`3ht-HALA%YpsA5D6+9nAHCIN_-p>VF$)h1f?P%uTj4j`}!jeY7Y86L)~qhn4@7k zG0-=h!C54G?HTi#`!Lztp{9de53(EKdvv%&DOu^ zvxbkqZvJoIaZFxq_Bg#xOOer*nO{O`n1~4bA8Nxc34aZJjeU6I|BZdkKk$a;F3noP zS7@HR98aWkjCCqQa=xH_+8HHZnRqG%_(hIX=qyA%i{L81*a-9q#DrZtv_0*EiId%|^G|;t$l= zU9}F6JJb+tYzfpi1AK=sgb;8AFazqH{zx_9eS@>g>bH2J_CTw}+f3E2J=kmwG}{6# zIQY&;r@Ow()6nT{>%zu}NRgQg{gMf39KTR@=;l-i7mht9OUD-ZD6Q!AwB{8CaA%v!GuR){29j&R$Al zUq^MA>-!-=Nvb6Yx3bKCd1=Y> z)-P7S^LzHU{H^)e+l#GUbTR0rDv49(ISg8?eZViV2kD5luU^PK#TfUozn5n~cT(xA zAE$$?;!a^zQfhZ*y4k3#|G1wvu888^L4$=jC;Gbh2D-YIb3epndPa;K)S^FegwUb9OxR0_KZin$C~>mV}oE{;2#^BZ5^F!9YOog4^GZcFD$Qa z9^Kg5Sv_`Qa(QcVX=`NeNXO7z_vqrx>JDE2ky96roxZen=E~a6`PH3^8z-+!ubmp4 z+3Xx!K@Q9vJs0jC_q7a9Zk%r#S`PNE)^#6?4DCjzu6Hg!+_m!X(Dq}?=ifdswrQ-W z79q@@Kl-IqJk$3x6RO{;mWb~E<&~8G+`|p5VI!?mQBu;<++0@9`CP>;3(b?=vgL4d_UhV9LS z1*G&Bp66yH0QYknkk>c!MF@G)(h!aY>xh+sV$4vKdkMkEsw&{ms#|i88vEq$*kc&I z4|0LL09GaSic4_~2v^9bY-B}MftHy3Tn=}3TJ0{Y9h)DKf_%`DL3hygNz^BWfJQoP z(h{JYn3yrh0Z>;je)UI8BwE zSQu(lwl?i(>B|)VT;xZad|cQ3LwjGpD~{q@`ip{n*<3ECxXjQ!b82AnjI*TLk}7-a z`AUkqJig_@p^>(>nA2g(&GFY%_s3#G9bJgqKZ}HT#Bf8lWg)H7Cn?L3bx7zEPY=K5kq{S0y1@Z_1N0?5luc6%^1@&G2 z#tu6EXs3_2vF=bypFi5AsK;I3>22utM0?%QUT<@M2szL_4mEU*M0-b@`o^02#-sh? zEyGi7W3z1|GvQbVYl4QS=jPYg&-%pD(UX%)M~Mb>j?9m8I_1Xh`u5q)6Bmx1x^(2^ zh4q~ao2ResT)4Hib9sE}M6_?t8yjpHSr}P4HNAQ6%&n(4FFah=HS1|#2=*Oo96cSI zzT7&0y>;R8{F%3IUV2Ag`(RlylK@w0zxI9^kDjUIEbFX(DP}=*QzXo`Jp2&-(~|HU8b||t+@S1jni9<1Ek%2Z7(qn`hKnS zk%|lvSG1f&*dlT%vEa0n(WyoI$#>_4M-Sx|<9monmy?4dWU*MVg+$9Iy}5XJ|G&h( zW*aR5H2jmQM6(cYaW#qTV+}TSkN1vl*b1ts-eIR5M^1K&!`9*T1Z%3D#YJ@$6=Ab! zq^qO1si~#DVR3$Ob%h0slPwL=SUA$?^*O7mgAR9JS9en|Xs@jFS}Xyl(?`m)#$YxW zydF;|9Co_hl+jB?6-#@Z_c4O!K+VOL%TW3-F^P6X8HcqeYTv<4Fad`1$)8LZ9 z-(FkSR@X5xFt>I3=2H*9<()G}&xd-Z{atg7BS%}NPBl&JwoY9b+kABH%-c54KG_v* zDG~i9*w@pfr!NWNBZ z0$akd@F9u`MNc2p!@w}ACKyovk zhuI2Glg1XiXHV%q7-v{DCHp)d!mc1VpoxErPqpgjBV%n15z*-X$J=`bN0zSleUo-4 zU~)o60}V7nqtQ9%oV(EhjT{F#4=}(CCeQ4oot@pCjh8p@l9!n>$)ae=G$oRyqNFNX zl0_?&Y11l8bkP;_hBiDvIT)r%t_n`ZT8docI6aV7K{QPM-q* zpvw_-q504X+lOy69SUY5bUO(e$~(<>e%Do)WiE!4?^5V)je~t zqc9DG8(9hJiTrZ(rXHg!ogLEGHFVKhlPMLaPgzwczP3$if2}%qTHoBDYpBzl zKj$+VXXh3cmR2XHXGg{+^4Tm=PHUguVKA9{dkNxSKYhBruC809(lj;F#IU`k#cVWM zthQb%>J)pz>SUZrJb?Go$T;JVqh*kypo&PN(`-;!h;$|s@Iz%nlQ1pcmEZ& zexK$immH}fXLiEXf5Tl^h>z?}ZGKQ%cv#+kyM61qr%#8-0-S;&A5zc6v&KIoJpcP< z9nVxeWyR>LK6e(Jl-omMU%0On-&O6^tEFr<67XX#v$d{;Z>XOBBi)C8$lOSVag&LP z#AhE016G;g$Qq<0nB+!<6|i6%qr(GXuMId`-BvTzE1I@8zuPILyp)OZBdozbf}V?= zCWGD3hdw%Fs8-=AgZ^N@ zw!W5Ze>esUYKHm8r@J*>y`4SUj_#h0E`*tq<2 z@&_(xYf~v5FO6_2m(>Ex@>4KOW7CV}x7?d=oG!@#Vx!oaQ=LAduJ?B($_Vk>eF45DR|m*HNNgnhq_gJ?A?^=dah+?q2NsMDeGKDzzY ztLIKqop(~*($c5Z>J7$Ti=)Hf&^m%fPYg16q9$*|=8M=o5t?rR^KJoiU#CGR_B|GF zug%wo2_TMMz1?SY`OR(!mswQCtq375-SXa3xmPJV7xq%8=mSP zo#`LFQ5c`ijo&CvFJ#AWq-p3qG#9JP7ADuG*6t0@ZKsBoe7WiP&{}SMJ3YSTFU;E# z z3y3?(Edu!RCUdWN$&CX3Tn43szCtn<@q2Kbf_)Sn5#+eUfCaczh@b^w4H%#;JGPPoFe4)CKiAV`H86+Le~mCuyif&ffJC#|>@j za(`iXaHNngI?Yy1V6zbhK-G`_vj;pVimrA{8eHHmyF9%tMIZ>cMRH_FBC(;pw${bapotJtP+5|F4q8 zEy99Uj~`-fb_Go?0d}G7djfWUP`C{}FoCeu8==XM*%P+-VKNbmKW+~uEWVftp5vu% zH`-$jllMZfpuNx2=Zu?)1_n~DSl*W`gtDb*|3IodoE;oXmWRXrl@Rc+jO9nCi{m%? z$8Ui8%=k=xYCbVME#aRVUmjn+GqZMoU}h^hxEL)jq(;{Ir*CDZwiCk}g_)iF#CmCZ zeP!?Yz4yPo`S`_)Rh_cR~929tGU_R{Yy`V_TKKj{W;==Jt|dI^XFO1r~DQ6 zmC&93W0^o7WzGF>;`w0!%Ab>I2(uE)QdPBF&42=GC= zRQTmqtQxjJn724`1}uAR=CIoZoS}frW$x4A<%{_C-FjRGqhMFF)!_qNjL?Tm02!xA zw221q5TB9@V8ueOB|=DXVM`VMU?22JF%3LfgMEDdsQQR|un!&pEOH-rA1ZNIy9VIn z;YaRwtGj>>l9P|izd-y7eOcsBC~7}{@N4jwe;?rU_X*??VSpEzVNgbc%^+A7-xIRK z1nAplGD-ORY&Niu=w}92A`nQ0f}U`;H!~X+oY0e20wvruzz*brKm3ygngDBVDZuAm zakr8C5$YusxsUr4pA6p>>ixH63=X zw!5)Gb>ZB#6DO_!dFpUa9KCqr==tMEKt0%3=*YQaN6rEK6M|~qIeNb4WMkbmGRf7g z?Y&039;MwIv=c1w1)cbfe14n9XL5S*_8Y;w%WHOf%^ntRi_-&{9d5IowcF})+uUBr z>JmJ`==7Of0i#=BAGvSyhfn}4zMwr2L;p8Afq#^u7J>ah!sbs{{RxX71t8w%jOlD) zy(6r(1aJVFeIgp@j^_Ny{$QpU$(2&2O0F^jrOTtS(r~yq6dxGrADbSWStw7==SQY1 zGfVxGbJ2mZ`0yOq?;l&9SiU{G@nB?rH#NB6&rc;sSJRU>lcSrZ*}d}Y?d<5v^u~kL zz32B|f4TMaqq&{;@{=2$(zJVEHax!3KYuqpdw=rLx1YTI{>s=?7wxr0**R(02Xm3c zFb`Z^G_B(7s=-X@{nu!lVk1OC3-aOuw1nPrMyVq() zLxA8C68l2cHyYpord}qV>KHf$>AJf*F{)Ka{RXh#ObfiG2C47^Rn&gr;*<8c#J(c; zLA^pSfx0%8TGQ5ns*ld!)85tDO22k^r_dQ70TomqG$r9L7u-Nn)tZ10RM`vs1isSU z(QedH`5vd`n`a%H>@N7U;{2He~S*dR9+;m%P) zo<;QxH<^=g0B$cAqf*Wy)C2rOB)Nfj%jq&YaRPYsB+z;Sl>Zn# zL4zBI031L#{fw@t!O1a##JBq6R$m5!*#?pi1(c*A&V3cJ3!q_az|G?DZ=)!7Y;znd}COte~oLU>0 z-k4k8Ti$*=zOu=BBqYQ(LL=t>oBNxV$jFc7I{};qB+2?7jcx!;iiL2S`sW z+cKlh(o}eIH8OKEJ^yg_-j`2be7Q0?(^lVd?#z#1Up~kEM=sg>*Ps8vYk_^SRX|Z8 znVcP?LTQxa)X>lr&4>m@3`<|s@BL2a%1@=znPkMDi3z03Eeh}vPi#vGf3_vKW)Dk+ zU)iO!LlVGe=Z8JCMsx%ePd>nx>H$}}LA|0Ia~T+6jl^`AgyAd&C}`66YCGCmRkXXr z1=-wK#XdqG0~|a8Pb9Lm#F5CzWt4nj?}JZ_0@ihPBrSBbX*6spbyrWj5c(4PKwj$n zN;q6#UpPn<*(sHOI6xKt{9nSRxON4eqoM7ywg--6=+#OUg|7;s{JU*dG=G78i+Nx3 zQPh5(;xGS)KNdZ3CZ@6^HYBct= zwOu`R^6IH~FTZ<20{<}fPaQu}^X~D>=g!n#z0}^N?Q?h?{s6#t`vVTI58zAeTO4i+ z@|~lU^$xem?)oOd3Y3#hu&=YZv^E#T{#H*=?+Ri{^tpmW`ugmlK1H$<3go4LzfXaG zFlh@UO%(E2IginiFu9_r2ej{Sg_8bwE|}~OrAy)50PxS0hSH^xL}4gh8A~DJOTd4O z?EU=6OksS!GDC=etuVEa8(%0*uMW;_Os#HDt?iDl-X2=oDbL?3%-t%^-6_oOB}Q&0 zMm8(+dvjY)x1M}_^U24Xk3PEp`djq-_4H4MMi;yzbHT~A!02Xt;_m$2Pai#bJCH7l zUeX8dor8z?ji-J%hhItg;tG-dK^f-x^G>scfxMH0bmkctE-*%u){zAUxu(ifJ%fAN z@h8OXiAPIColVI0W0$f;r5lQu5E38louk`g6drqv8GE12@3PqfUN55_CF;474UApD zWr%wz8NoilSFkTE{e8LLN2R-_wY3GmenUf@AQp}Fk^=xhATQN&q3SD@J|JCUU#R^O z{`dwP8q}?Aoo$+~woVA(a|HXyd=MhsA_~|A9}xdUy7OTt0N9uC2m2@(9m?nq)qOR>&m9Fut)%tEd86CKx%;CU3hnC zg{X8xtnL}Hi?|!wJ~qCtQ{(rz>u^cFL&LpyIV0u%S@6Cu_m6^lCNuVQcC@#t z+Pk%VHkX6Rz({<6@AlYSLYcRs(t~=N(_(j_;hStO$Y65{BFXmZy*6d>GZqY5~n9B~qcY*o1*P_XZg=?VW?{TxvS?Ebhjl=Q_i0AEn5 z5KNWAnNln_KwFO_62CN(txSOZ7=FK@DN_5&lS`$^C9q$aSu9O04bN|kEZ!Vl+#FrH zS)N@RUD=tu`JjJxD|ch3y!aqHbtgHon;O40w0M8<&g=CDAC0ZtTiSho`^D#jOSi)# z%bv=jcX-u3y6meg_uqK1@%YOJPhNMoYov$gFc1Icb5}O@{z2;hyg<&8Ygb662eR3r z{(c}oTr5`djBd;i_UFsFep|fMQ(Q*bM@SK?ViSUWHY6lPmE4?cTHuUtpPlS9>A`h? z=)A!IoJrC2cs)YyV+A;@T*e;eDE7QfsKi_YG?4gqgD{rC4md)cW*3NPo`QFzJOuEO z`zZV@P`p7R*ykv+_!vi{nE530?2CIv`qO`aQNx-xbyr&l@CWi$!uhXg`HCPs$kdgn zm)roMFI9a|5AhO4L0&LZtEkL{db>K|0Kgxs1mH6U5d!`w0B|rk07uA)GN53elX3WL{xeR(Z}@N z-IoP~_Z__Zcvm!m>RQ-0qG7u-vgg1jEU_F%|DfZRD8TPHe>P^f z#XTNFb0dSRAO=@aq$BEdjvu`yBtGK)7zFSYw;so1t+iLXR81F73UMz@evShE?;N{y z=H$gQC!1=o>9pNO1A3mGer|1=4x`QCaC;qydjms>(P@{zWd=4>)S_^zCxnMMxjKU69X77LXEgW-UGA)3zF zEA#0%RaI!7B8!jRD8&#*ND6&+uaxF20JY0(z;#dYwUgjHroYqSvyrPK{Qqoqx!bu+ z82jk?MiCK^vL4_7pKeV@a}$`a1L=~a#FxNF?#n)1;1O&h{lPwJ0K|D*e026W(DrNb z40g1tHT%>K@HMIqN$?d#^ebkMf_>yWsFxU*;$BL8ℑrExG12tvjfEti{pS)=J(H znm@poLZ5HWT4Epg^NRpJZ^6*`naKUBl4Ca-i4Jgq%VgwkaO;$iC_Yc2I7wCj%we0{imcKK8lhz)M_B_ob&% z&Dn<9E4H3?g81~Q|f>x(CjfqDV_qesr4I9_+*f~Hl4S!cId@#u84sY&oN_VxAj^_d(l8&cls zf&jkWV%3{1daDiKLk6oIyep8m^_p#3lU0z>29fZu(OcDeYa7$Dj5bR8^8+8?x=-DAn6DtJkhi- zmW6_eJn%>EhrXh6I5Uta4rc~Ob3^0#;i>%a3|YRV@%h1-)zZ{TvND|-oXL$X3@_ds zNAus<9bMZgEpBCQtVJeP0d;I@ODfHR2>`aMn+aiFEdVs{Ik_)_GK7%Qdxr3#yU>~GQB_H6kXi?mKQsI~4 zSjv6W0O8W-Q|JaQO?8d+P(xEA1J=NPhpG+IsD1?d#0)?X_WjqCd@15Vy<`Fs^;GC9 zin6HAKaZ(YbDGS)mgYu8KaiJdKMP6x5D3&G`i1m2;}YNCIf<^4DyfA2<5ALwSd&4-xX-4# zI$`+p&=tK#O8l=j1q_d3L{X2pzhNYQ5YZwWeHSk3y49VR&!XhZemgBEjx`@Y)_CG* zBN6=LM;T??boyNd_@bFMz(?FG-8GM02K8T&aPLd!9w)D!dPi9LM+NYOlmFN;#&vbJ zwK?qeUR^JlpN-eA>$J1YC zMB;;blQU#;1T9XQ_Q!xcV7C(JcLwdgs5_WM;U@}U55yh8xHFh=hg1GoR!}@2NEQO< z|LGzW$qvT)2U7#X>B>krE6xPdrAU4#QJRRCC&PuY{Mcf4e4#M2T$ov!T)#E8zB90V zb7l)6{vdHjk$6H$Tm2djS zZu=%SODj)GOD|?OpKNXIFoRclaQm)Wp7l5Xags+YOoN)U3~a&@r;SEFnJA=E`FI@o zvw#njvYCPYT#@dPiC8WXk9gg2zo^Mg28AygJ^=Q?JDU?}#a5KkN{S@8V_AntZgJV% zZeM4hh>=T_-%GnSMaIc(%xCfSk+hFY#J>j?@SLlV_e$U%!QH5!9u2>Wed*puxC3)+ zd{D0hw?!@=qF=xt(GTRoJ_Yx{juv%C3&(cOG}kvG2Jx8@ z-2>^6bRbkwkD!;32m5l(5n^uG*_xB*&z-KjdYQs}P>jTfKU@veP7o!09oDMvMqy;jy2aHR#pPR{j=4I7M!b{)}!M6!7`bi%4dEI>FVuk@9t%KPLJNC z)mxyRK2x{e$V;eOXX@%TcJ>-uwe;UJwa|@UZ&T@M;BW6VIeMrAq5{b2F_8n{4Je_* zkjo#kkl<$zzyXXlzuw|CkOpjWV+B~;5eq!Q9&q^+PJoZSA52K>vv38Iu3*X=$$BDL zcO>gW4ak=80QeF)t3N_yK}(q-ZM`iHZ?X_Cjbr#H2PodTF|m4UaAAFfJpZk`Q=4~& z*0u+ix5jSn6_&Ru>-UD%ALVCn53fF&-~C`_vuogc=(yOu;?#s zxhs3V$-VgW?SbXjr5pEm@4w9E`bCXi2lAnm!$i zW@54aM52^V<|iBgyi3S)WHYlH*`HD>0c!Em zhXc^<4W`ATLo5%q8ugX@LoJUxu!od_?Dc-$Zz z)B}HxWD?4RB20{4jfO59(u4Um==1Wc{cvcF_#kp(;O?9|)hycS3mYHQ3*aB$ABrd7 zFIwyh;P0FH!mEFv>K|ag3Vexu;4ig(0e=PfU>{%K*%QZVPMkPLtLEd!1pLpQZE93? z;XO53^%fgPtsa4H>NS{kMypl`cLDP%(ltGL7==PQ)?mL&XCgnKrCYSvZ8KOjCR>-u z4iYH@*5mvqIso=Pemga1B6A>QA@j!`&;xv|ew!cc_ZXa=eRh-qu+K}B0f!$yK-3Ws z@W<6Jm_PuAAmHx|q`$?+M_l8#Q+}L?Oy7s6v#}vQEgR}SYBb&1~AKiZT z$=crg4?p;+k(K9x(x$t->mPmS8``cczZ_nDGkx>roqNxK2zIHA(Nv$TRPTkXKX}A2 z2aT%DW48y~E>dn{!2r^~Kbb71Qj)UKC_*Ic^#(j{9Bw$P*;EJ@QqU3l03W%}CIsV% zBnT8sfevSYcnfG#$Le=DdZNP}#hri`CqIqOg@<46UOvUgN!%qd24_Agy67z;6HjsD z?}J@UquI8$_O|v8b(_Kgq{1(;kK7jxIuziO&jb8X6|nT-7)?a~n;XSP73?1v`$F^I zKcguBovrP>1&<+}NA~0g@-nnn#XhP9YbhWl_6Y>g>WqOx4CR9uDF880h{C6~<|g1Q zML#-#NpS!IZ88@26@GmFR>3Nf`|t|v1y~;t<{Fd)un%#DOsAlz1`>76+%B?!z`oS4 zxM^~M`2e~J6M%hWJ&8jo005szBIn(BP)VyWnY%S4*Yog240E3jxWN8?P+Ir%3%N}A z`k1QISl3f`rA;*1dx!QrOw4H{NT*E9kqJCtUxf07#6Lot%>%DK2EG*fLeCef{(;aJ zDLsdPFR?G>zVP!OJ9_2JnN~`?X>&^NzDt+d)S51>5y%VF_nA7i26d-SrO~!^={o4? zr89Qxj2f+gJXKk39gt3?);70xwWzz>G`*bHXpJ4cW_7Q*!(ax9z4ZLC+57DH{9R_J z*Fvz5s1)1N8+3RD_7VDeJJ|Ok<&E}0ugR_HrA2_J&*Ft4^jQcFl2*i zn;qX7oZ1N&7F~s#p3*(vz}@uZ%O`l-S3`$$K}&re(rhZ5L_1F$nW zO6?R-%a^nbJq*RKkf zKHzO>0{a5;ogHdTds~OPgQFV8MwDKp^hoSWRLVYn68i{!SO*uVnA_5-qU8wCR^+}~ z!n{Kz;LjRcmMFibwWG7OL(|euRWLV)n5VpP9MJ(d0(QBO(w`%3I7K%;nsH+OD>H@Y z(|@k!)VZ^Q1Mmrohj3J4zW{vmLF`X>`!V^IBdR#$v052+PuhYT{Gy-RtW^a7CIBmd zA$W)a*zMdmvI4lhuv3Sz5A3smfgrYg4rhQ1+#)py6^lelt_S#}RiHe`5(AzfiV|N; z{6JaG|4r=kyTwnZ?=H;}&T7>y)aGF3HwoZlHH|IAbF><2|1k#)mTr@^8~wp<*E?K#yT?Sa zj}!8n1QYO^oq;~9*Wd{BT0Fh@W}E>Ge-wVL!P%v=QNDyefC<0|Kd^82$AG^(m~i@I z?r_o@OL=G*9!t4G35pHvA|WvD3a5IAFPQAjn!X0LR;4vq0#v(=qV~s%6Pdx;f$5du z`OTrZ^~u$p8*94)`%}x6#qF7mdu#Vz&Is(kSh@Rp?fysew_cIPKePG#T6Fe2g0bn8{E)`K)?j*TxJ z``Gv_l=L2v;ZqIvaT(u2+V~RqGIKymf6lOg01w#5&kyz`3HYBm3GfB>@c^7TjohTB zuDPk9ucuq07$8GH8>gR3N%I4q5ZG_1uOl4KQ$PXZU3sNEN)I6}0)PynCC}t2^(7Q7 zV`khL$_DHrf0FZ%;I6c}QvM4*4(eqM6eAZ=i`W2v1@@)i56z&tsaD%mD;sNzwz|iT z2-Gt>Lp0ZwQ*o6+*a&^$-}^DDz9RJhD&SY;{yz4P9;w0g_pUJZFW1yurAxq-D@{!; zZJM4=Vm@R9^%;dGuQhPg^cW=efxldEtTF)@0!#oMK-JcxYS*ed``UZx=VPHTP-{Wq z7sLt&Hmdu~CSNp|t;C9B;rwW< zFp2aZncuA7`JY_MO)U1$uB9fIhL(5cZa&z&_j3L2tNHEsrZyfe?!MZ7{Kf3{`?H&` zo__d~AAIpMw;q2Hs@&3rru@Yj(`6(M!qaal2^8<#X9696&Kg(2H0+nRrU~46w`^XoG!3yc&TI z?ltX)6@K2r-pBvHkA0GD0PTUoFXcWy0kGexZtp^0ID~zP^lEw!wLCK3*Qp}z-_h2h zf&-D@4+oHjKMMhNg@8XdRG9e(a{nv%pE(KYMR##D|FdLPBUXh`K!FX7M*y-2bdtS* zrH?D`pst7PKGXxo6}W-6%L(yB5Z0suawVS6Dx*M2z*VAX{vz#18vbFo!yWDKOiuee z#J?4@OPCU70;wGN2v!EzCya>c(WmVp3lT56+y+wf=eLP89!dK?e>%aR(`q|37i$pu zhbMoYs+S+!lwioOh44C=7=m5PYYyrS73HVE@>HsXHN}%q517Iff zwRY-Nbo1*rb@h?wL;gR&_dEP}?*n#H`n_SZGia~{^wxlm+$$HZ{y?|EX>j<#yVV`E zxr0t`m@(NFr=MATHU{{j0C?!v5%Y$VG!^kD(w=C-pU8Q_8Fz@DKPjU8;Y`6F&xX@w z3J-hHGz9hsk^>Wo(qytc9WPCkrGt{78S+Rl}bRDK&qvFXPd?CDH&w{+@xI%ZatN&c3JzXOuhS$J1}= z)U-8<=HIoKsX?JGMs(c~EqCAmU|#|sDG%y_KMNE9;E&LUAqWQ`uDpgiE=CXoQsLo; z6DaAsDEwFr%`MIFD}WE8yVM$vQrydoKAFvn(EkeitxCS1y0h_m9iA>Q4i~EG{Ja!w zRPpldyZZO-eIfdV4xso0x!)|59!Y{lNJ59^%Yr^YjR8)i11S#!cM`%MG*vBO~`Jv0^uJpilj&6zLE(nL_fesp@Ow?pTp^a_K6pc{B+Rk4pKnj5-~yP zej%Cw&jI@a{z|?CN(jM-%Ty{U`vLf)#NZbas=gBAlRuI1H@fcj)>9|&?}7c6Q|~qs z;}czWPe|+&&Qrv_NZun~S4rSGjQxF8zpC(m6Z-=4RZ?_*UZVCxrw`Fd-l{ppbMGVm zV=`(D2Bbg6eygSr>s}CgewU%6#|Xg+Kt04la)as_(JC}w_uW;^)# zZGKYviR{w^*bj4n@a^}SJ*fIDZ~*q2Tw0n18SLGCHmra?Y&C-Zo~RQz$1>h4wOX89@s_7T zgL5SKjj!FVEN-sedHUY#Z{2+G!Tk1f9Q#`jKiPfq#oC=WE4!~(cVF*5`Brx1rZqC{ z%dW)Ao4Jv#Sa~Hjyq%kSoSA#Cvh-x?#`;jHa^<2Jye>Gra+G|4+I*Ng?tP<9XTkF< z#SmWN1LYs9pLieczEm{U(#T}ROJsS3JZ^gRP-TX!my#V^gKoHi)chqAK=exv09%l1 ze;}Gv_ivwV>FQ`}i+bqX-oDt1IMXEe?@Z#dDC!|kMuerHh3F@KnW6MkR9?6bT&$0U;p|^^C z<$`WrvS@1({m>-#r9lCr1*i|OFXaA#CO~{2;6rj+l8g)@N4aKyWDgfBF@kHCFHwbr z^atbkPKEL#SgzmHr$_7(jNm*b82mx8?p?T5fjl`668re@g$M5-6B79I6f#JXY`$yl z=QOu|!&_XA`UBkFs8^Iw0e{i_)+n5)$bB4-xF2yUVqpSVRCVT*=F)`*=H)3~eSv*3GEWrg{EevkQsF;*JaY*9r;Z&t#R$&Y zYdu=69{3w^{h2V~RT|;e6V%?@+S%9ErB`?9CGZbppEZU6EP`vmez)EZ@GZd5O=*B| z@4EwG2=R@bZnTFWM1L2PHx-9JPJX06)ZSx~|4XON+G})yeUmdHa{FB&UnK3PoF!cd zCbRxz9#_B3kHepYpHikY63vu7(Yz~?WlD%GkO<&JuZ$v-RMUg{>DGdmk?Cd@wMx=Sk0p zi|g6Zolt4fo*WD2XZpw2$JU=^W*&|%+#4U6YHx1AQ6-@d`lShgl%dZBHImxSPMYB$ z_i2iS#6b*!dLn(~^N`g;h@WjqF9-sLw7WqQAj)4wG#E$Q2k)}x6g2>(ONq|{dBj`t zXibzZby!J*p~}oIb164dDST?ZuAZNkw9*qM|lnSgw$X>F&b z31tVN599%|1b$VHA70?`6WB+|SNMbch*S?G_E~e^MK3&>T3?_uaJ^Bl^P%1=*bn)jeLx0sSG&6I+Eq4#z&_phMGt2sA}oIES&|{_ zb}OB*ob?PjA zv{Z2iu=J7m68K)SAxPBm$4w42e|m$&@%H2B1OA}CLuXU>n0t&g1Gj2=`LAsTt6xL` zoV5CkQu{;3FByQLWPc=62xW?7_&9^8{rOO$l*m=$`N2@S9L*2ggDFx6$r7Z;7oB^v zgVV){rT(#n><~`BrP%OvW@0fvy*#|Ixq0X5gBNd~y!w3O?n~16@4fui&4(Y}eDE>Y zhn~Fo>Fq~fEZ+JcJ$frz-WZyH5Fc4H$A-M|N;X?64^9C8iS<{N$|QbZMo9zz!*U<- zB^5lRTSM)2HUoAgLMKi;sdxu1tdd(*7mM5$d+>#=pIQK&b~ulcGJCb3Cxmx*Tl%brbeZm=Kd&c zL_fk^YWN&60U(vCv8joY9FesP@DZ}KE5gMmflnVlknbNDu!3_BE9BqWsI3U2PiF3;q)+?gbtci7!=sj@89s1wgV03=l5n0)YS3y9)M^ z{<6Ued=CalUoZSBF~1+|6F$U3=+S7r4jUoS1DK1VCnR{-Eku0WFPa`m7Yaurdhi6I zFok%`zWTQ1J3nmy>Awsvf6|{#C&PZphY8BSE(j%9mGUCW4G{f2?hYCsDNa8a8zk7$ zz5;+TaGuPW-qsFOePE7TPkp`yRbPSpfmiN8i@X7>>RMT>7nDwapzIn+WZ7^|truG}!xEI`*3h@U{1v z+u#PhW`K{LUO@5Kj9-DUr47A(Nj3{y2zMC~kH|sP1cUe6YOp^!eNG zKY8<=z2{$SKl*g<*|#5l@PjR|zx94;`fjYaHaxw(_26ZBaxDz23B}?L+xX1V^20C7 zV=L)!_}WEUp@>3GNbX`@vKeLcU)1=YJBR;A-Q0w2NE#1m{38S9L?q1MT{$qC{n6Ia zTFT{eF_Fp(uJQ1r`Af+zr9Ur$Kb%1-24YQGX&9HDQ^-z{9ZIYGeV@E6v&A)sgAOB| zKzysZ4WuLM5$NDrrsd=9=OmEl0{8>zJ1oLj~1OY?E&)OUGRr?%|0Jcs(Miv)U+sPexGv7 zfOC}tNTDyJxxx^n^3NJZRJ}|}d|pbD3<~`K?DKczM{shGw;c3(99E0K{^^?5#wM55 zOwKdfKK6bLZ-CMU0SS(E56k5xtUw5KiYD+1S~Yw7Uliz_IGngkDF1IB`_lGD^q-`$H{hE1(-F+&pQPrhyQ1@JK?zmj1 zI(MbvdQ*F2TerHWudC14-DmA4g->szov)5YzGj!s>_Xz>t|w`S{5`PG5Kk}u`B2;! zN(Lht{3Z@!b0Ud1PBOo6*M~EKSie7-3sANb%LJlXe}wUW8GtWq`5i%;c%)2TTK&iH z=GpvFPbB4wX1$Rd?mnkK=?bNV(9aDf3Ztp=1gKAxM!3x8HvJ>eJcvdw1UZ~B5%?AD{t z$L8*qCwJ0=YvsY&+dFq2K6pA-s>I0da8O<4SlM|nv+*<*2%`G(SmpEOK_5^x^G9rI zh`F$od^XqBTMWinFoaL-lA@QR?=$z>Xfl;^$#PCKlSj~ldWa2%JOb>})el49BrjQT zr1yT*?-FQ}XeM=7V&JeQ+&xevYg$-T^*_JV%I6 z!7ez@9|8FA71n$ZhQQx!YH6kn1pgjbM%9;!Jx72qkHB9s?K>6hBkP5)PsIA$@Ci`W zD++tXm96c#3(!)ew$D9cA^*E7q9ueS6X0Ebmt1p{Lce+?*oV=HZomqEfO|;I0XCp+ zX(sfB&X3%OojJ^u@K^yXN`8_UD>}eIYa_5MUvkEWH&5vTgcG2UPUlAEx?lXm_Pc-Q zk|~Qtl#WKECI;t^)AriswDk2+DN}ppGTT5Xfxe&BUXz#G4FV|Am3rqjN@E6z@ zboAV*lPIf=s&;_i($&|j(J_hd!u2MAkKAu=*LF}FA!>OXU0~nn0QI7MpUrEqdkNJU z?LLG)9sh(7_eVu|E*STPQ^80&6wLx#7aV{@ouCNSk*ybs=Oc-HJX45Krk5xNV|jn9 z-y7@4ga`OE^S3GR_r?o8^7#|_Ks@h{ax6r%1ECZOKpH21qF;3Kq?||e@ff=iE)J&$ zCrc9x(ekvvf83KB9h%!r57W?ZcH!pU?xRg~&qzV+UlFW2{8%xyjd{u}o{ z*narQ&g0MLHlMBE`CxhL`NaI~^3+DTI5L{dEDTR!O~@a_ zic}!N_7ohT8qiUkJnYK-^B8@SE}y^H+|WeOjG=$x98UKj>BkF0w1zJB)0Q8ZE+sxk zP|t=$B(WjcoKn?O@_DXaxx$_T``Gr(;R3K=1i3HM@IW!}m+j!;G!Pd^{=j9@ zZzgdqvwUS;p2R+XMCkk%&eObtYhWGd3~g<#ojCSeg{oim>VxGf$*?|xl(em7ZUY9a!}1@`j+)XgeVhWRFZG5#+W;$|s=8(agPDsfVt=ZwU)JR{i!N)M9` z=p4e_arr^P7L6|rEDi;_eY4zc|viwKjQL*y(G3E#AuC{=nuqm4kb<37e#ibsnCg}i*ai6sl-W@ zLh%CF_X(sIeX)W+T0q1*;SwR-`zcpA6G|3?iGn*!R)3NBel$}`)5tedW@dM3e6~1t zV{m#gJvc!h@9fx2bYRk)9yT)CuQ*YhST0X5-@Nzq;foI+zxw#u2cJFr@LPADe0cZ0 zw=1`vJbLxz;;rXPJFj*geY&*$a$)nu^wPbR^}Wg2af z$lNo%vKvhgSbI7VwjxvOp#PGxPxlQyurJ{+7GenFdF)&Yfti6P>RPVU*9PY-PkwW7 zaCE#>sN~W#h-MSAA*Id__GM^~BPU@C5ZH&v3GCDLveD#>7w}1A8Ql1n8I;Xn0XTpX zjz?Z&u%mYZE|4N+Jsd!=0)}xi3F3iuWxW*l9Hp7Bz+4D-#C?_IyU2P_5BB$y0f;Izx8h(BC9;ZrA%V{k@JML0kU|{D zvzDxYGm>lZbNCf}7QKgWNK7#0k$ebhh_zkUWW24@c!bOCHNj zX3ZUDgc)u9m{b_>aE%D(A=!z;!jQXT!)LG7;!Nb`;+(OXOvG>-u3aaQ19e2YcO>(# zGJ)!%dY*eo)`zyff%2S|np2eIi_ASGh<~8!EA2Q=9Hs5vB|((v{>QN|MgM;m_K%2& zKXmE{%D~Z+$Bz;Br-dMQQ;cS6YPwS2bfux?T2pInb6Zn;7ixcx(TrbD&`sC>cUjY1j&px5A*WS~Q*Z1C^ zSiHNu^=$Rl%h{DDBhxphCue5IM@Q1}a=@Q;SQB1%d1N|XSxn|e?YeGKa|gy|G`PpE zU4zwMtPvhvNLc!chlg#b>_h>1xkk*9{f=%b9Mkpfjs163kN-(<_q)Tz+(@4C-W2-0 zB)ohGcd;Rroyifr1AKS_7bxa{zoDTXwL*C9uUxs%)Lq+Yxx%cEt3(ZeI&X-C99)0= z-|zvh0vCXVg@S!yBZ$fxMDFE_U?0d!yFf^Mz^KqA(V|jdzp=3q>qbQJl!QI0x^q?}ab6_;waO$wQQ0R9ftI$878L^puzMu%!Kqw;Yu1OcFJE$mB=)(I zg}^>-?XQx%Kto-TiU47!@GjVwi~9<4ccOu%2N z0mpCxyvw9x_Q$2hrt2-OwJORE+i4`;Ox|ygi3vXF{K$R$_H^Sk*o6WB{OvgU!ih*C z6OL!XiBvR|i_(ZAnhhcPMH{aEa3&wk(v+hZryEbM5=oc*z&}~^MGLNAzr~$0I}>I{ z!sbaj0%=z`hu_bJ1JD;o6Y$0IXaYK`ud!WQ*V@^xx7j0^^zdY1Vm3KA5vfds2PZv+ z;ZSMZlo~c>hRpeq*zjz0czX5rLxlc&AAI)mqc872`{==o&+a_=Xl?hsksCK}J^XNd zZg+5UV`k~@>eh>i*)2w5P8M>L`CKUwEO;HLc|+41k;-apaMk6FxVqXagC(7+rHM2( zo~_ciS-SYDU_T6hq%1`CP#3M&tW4$4l&*+aN~j zpzTY?zD(e$9HzRc3&K8sTV!BYu6w2xTax{&{zJ&H3Vjf?t=m_S`p0vf2)>*02 z#qFQ5c++N2Qg06%9R&SJ_f0!O876@e)+e;*MJh7Ha+3BP3(3J5B6^R&-zj^o7(&p3YrMsh3 zo68&T%`Wdw&_*+vs4%EK;x9#`mC;#x`R1m!lM~y?!3ATdCXRPg+unHL+!dI=h%@i= ze+hZTq!ywdyP337L@RzceDd{7M(*g=Z2hw8m;PVd$A5pMQbF#Qb7@+1;zW|b2jfme|aSFkZ;HrL$T*q$m8KNZ~zE>KsZN*BSQEFAr^AY zXT@((zBW%nnhBi54N4D!n)8<$qVtV+e!cF_Z#qM{M8HEI9-z%Fg|BkAS)gcf&w;;G z1Kdk^4ff}HIyIQ}I9712U?(*;G*PHUWaSDb#ete9^_MFAg_)vYp98s&>e||_ z>(?~bE-TqP(yK3Xcocj81ae<=;QZ@h|8R(3>i^&L^6mTj6j?7Mel^B-fPI1YLj)h- z<-5m@o;Y!g6sz+nia1rUtr{AyHmR;Owq9#dH>z;}TD2A*-S!mC9HAd29!Dl#IGK&4 zav|ZP%VF0`;EPUNsX{DQOfed`Sjv?Ka;3pE(>Jno!zxV!UKec)9{ng!PvnvmmZa$ry-=$b@ zb>q%7O*J#Au~cd}m6;fuDU2>=hF6L+JC)@}gG=`VftazQ*{W@8Ja?vnw336SOj76r z{3`a@q}ORSUt5dxMcnPIObuq!tuKFH{kQ&~+^vtt21*Qo1M+M$HX9;_ttejtdCtg9 zD0S3)B0>{y^41VRE%mkE|LFDa{L0VjWiyH7}eiV0ho9E-jp685TJRep26GpNV6&%3ZJA$zaT(;5^C zW1p`LD?rI-jkxDK3%+;YAK0&$6{7iEi^kA4_M-mfKhsS-iv@h#!iIn??u@CU8*vH#QkhhWk+vm^L zo)Xb~%>09ho>28c{nZns?jOSbL1`X>zAE(p3Z4J2hkdGh$nxEf@=IBN2>Yj$HTwU_ z6UPw*2f%N*Qr~c`u^HR{YExT%Yd1HxU1w(|FW5JUK|GlJ$bC>x2tG$zj%d3_vz-i* zU65$JnJ=Xa9{!Q(NNLoO8E|9=L#46w$TTB+LIdN$p~=C;wXFwFw;w&*y8oP{zWdKV ze)JM;|KkTQzxC?VpZw%Izp#4yIoRL4{d#8k-saBZt=*mV#ksk1VZ1-LIJ+=Cw>GtK zD?hSQn7CP)y*;({a&+U_z~s82v$I!qwe>=c3hbXdTipQ2dVzgqlqY2?#P{p3T|Y}E zohh(9xA-T2^xw`dZMXj5Py4?A$0Jj-0AGmmB(1u{JZQQ1cnR^6O^7gpWaddeDdxAj!>Vk5HoWrRt>M=%7%S9Ta#>{;*vfql6E zN5Y)NIdJWYv>KSmg<~H%E|Dvxb``?Nblmu2_>Kbh>Seu}eLufY2{b)?mJdQzwO^i* zrM|)mfKs9EY-wm#8sGj%U5^ys@@va42}?z|~j(rC7?9)NQzs&QOOhDrO@KM43QEu<$rsj)HjprNduhchQ zZ2UfTD$t%sl%m2m)X1CSf4Y@kS}LA{V_9ex@s?}DablkbA_Bz#bw2@iv25?_7~0(&A-;H zX|d3Jl+OrR(Bm(jh{!;oQ zetb?B(|esp!$1A~zxQwd$A6yQc+>Fg51TiBp;>E`=-?<&piq??@a2S9RPi4BaiG%`J?zC z#4nYuPG(wzeLSA^oyNOs3xDSqf6#m5gQidZSL?#t{v?f4d{Wj+DKGCi_n((M2nl}{ zoTtlLQoSET6tcu$)yo)aay z@9Y=pDCzoNsroqg05yH~S}tF#r8x1_$(~k~y7rpVg70rw?*E5u0nS$y0IBUu4j|UN zb?Ti<*RR#Lw_k7XsBQ0rE;YAas%K+&bWp-$@%GV|gMuAp(w5mzzfFLjbB41D6UZqs zdK3WBZj1JM@&18yX&@_rKU^9ZDJs}6Rz|a==;sDwxshOUFqj$&rH37%f;CXE1&h{T z!4$~qeMw^=Z4PBUWV{Yeqz6V*rNQFx=)lBGacVJ88g~>%J*6@Kz*uy2rn10nzMBJc zDJ8_DuqYGAH3wH2={je`B%S2MR?R+b+YhZY#7tG-avcHunUYH8;0 z17EzvyuYMwYSG$5&5_aG{MyYs_x_I`{`v3y#;l5yArnJ48yh{iF!^-l|bkK znEc8ZJ_Y-_zAoB-i!;*Rmq)NKuSeF?){h(^LF!IEuA}o(M?2qK{)Fle;fw^n@K4e} z4B#v5RRHY3sF4e<R&A2PUp^CYihpU-d(RXH0X?%+q*9|w4bkStylN9X)PL~ zvztksOx_8ktfb{IQ#+J*hVw2lS-YR3Csu$1_>-jo3P67a%x01J10$u%Xt^?08WfZ& z3oWiOOJZjG;U; zk@9$acq%!5BQ`pdo1B~9zO%abXkvM5b?4E>ou^M;fBy7?&)@&#+wXt+-4~yH_rc3g zmv){^uiv||a%Xe*(Vd-JYtyv%tt^cUu1t?Du5b5`uFNdoFHLM#rgsPD_QqBptvr0Y zaQB1a!u`tJ9jDFNdGVb3{5iTIp@&0^+7vsE8E%ZBzgnwtr@G7AoyGg6@~!WE`0{`F zXMgbC{k_gR|AqPC-yW+Bja5*6l5&G_gxGi-K{{KJ4arN0y~no9#KP8Cr7b?0j>W$F zeD^yaJxk9&ZW#OIT4=I0P`+H>%(jz|0RoW30>D8}MoAV)J4&K{73N%nB<08%`4RCc zkahMffx~V*b&A<85UpTeNAuQht;9Y62e4H=AL);XN6<5LTc-5z5wZAD>{r!(7E%X5 z0iXm}`H#A_on5VTGr*IlIO^rk0oQyYB9zmL9an;|;OZjuCK)iDG zQhjqm;Xp7IPf%&tdi`n-qs9#e6gunm{rLJsl8@5D>#vaV-+b#UbKsC&ux}C2^AIdURt1=4S z%bxp&IW~4)-@9HshYxUif z7IgNh)ef62TqxzIW-H|Gj?G3ZlZmmp;><$n#=_Xj#`5mNxm)+{z4zw+dmp~{`mz;^7r z0u;?3Z=Oiml~zDi6Od;R_kdkO{s8s+K7TZSIEEl9{yI8wiAxCz>Lu{y*XCF7(>Q|( zApC(O@GD6Or~&+5NOAxPKYqKSB=F-eskAQF+_wZ_&&B=c|n#XtUcfAT*KKK`ZVFaDzS z=^yBFGgoRG;7VV^K5`##KqJ{lCytAn+$#1-;K8NOFr8yZYMHs&-JQu~A(zeGbm?LT z{fN4|ub(^1V4bhU`>OW-c^dB@RqFVviyy7&6CL}%QN;I6y#FVjk!<12J0~y}&tGXi zU#Gd;X1LU%J73#*wNcyN>tc+iJ(%+*3jS=_M^roul|8AFBVM+I`fZ_pK&bv89Ib6lrVQ7j)!=gKn+!_&*zk=f|rjK4gY9-l4Gtqv}3GNWf=b!U0| z!M*oBeDM6^S8u=b-bdeF+IhTk`{}~=ld;vk<*mne?mphxT3(wUUY#D?T3)-+!Uw}0oq{=a_sXK(KBwD&r6Cf5Knx%zXZbOOjrm0n^W zaf8AyqYuh^y{{5f*$*=t4&zcfbO~Db3JAJ*SljxHO zH7O>r#6FN`{{wSKVn>AU4_fb{{7c|h9sAOI2EM>PzIR2q?}Ht@E07l)KrY||QlA%s zUMbN9@1R>ko1?@#1_CO*L^?;g;4Q9HbcTJW0eFXvaB+`X{I$+@4d0pH0>Jq#m?sE1_{k`S3l(zH1^O2vkc2%YERg=V9tEw`c$&zK7<-}&sLU;F;I1}Y<+ z3tw91UZ+!ud^Ez)bC3@9fjs3r@Bt*gd@ei%o&{7+CkXTpmy6oiu&sFWC*ObYcYpO~ zZtmRexc^(Vl@Gd-^Bs;PcHY;pj|RnDpZc0J*A?LZSnM~Rt+8meiDZ(&EH1m9P@uY@ zj+P^A?CWP3srln|eu;fy6aab21b!6zQVsa3gU5kq@5i4}xWw1wzF-RnpF;ZclH)nD z4bReKm<;N+3w6DxuXUZe+I6wPsOqL;R0iwb5zTlq{n0`>QmT0JC0lC15YFoZSxY4E zOcwp3i~d-qJeIGFRYs?V#-@kIXQ1NHWSoSY{D?1AW@wkzY}23*wzSb0hIyggbmJr` zw56q^wyvwLuCuPbtD&L0xtST+eXVUwyz*u9aTv(dVtQ!Smml+&rUL_0(UIBs*g|S- zVSe-e(Cp^o)}z}`K79QC7n}E9jV)H6~-sat>Po6y3S({#;9bI3Ty?yt| z+{XR!`R&1}_59#MZg^#U<>Ac6v+<=TBa075Y3sfB{+;Jv%xpdxT)OLY1XSnF^)@$= zrXqnaj~Ir%>DjjD|6S9kf4=zo2S5DtKmDy=`$Z;T)i)P|J?Yk|PYtOrPd!c;ie_TG7tNgt0iw2t`X>ZRiH{bgB;lqay7~p$;zvq{STE-s6 zM%VA3S$ukJFVHLcxA*O$*GH0x~#{En@6bGoR^w zPDObupN}5P9=F?$0U2@#K(X0i)XC+wMFqbT`!uV+svtXm=Qo)@!#?BxfA^LE{0RFj z(+^w7fh_iOGd?iDmn_Jl6O{!8)uk0R&5A0arJSRy5?Sh%UQ0)pC)Q;TCEEN^wJ&Cf zq#TK~HP&kgc58eItuLYXC#{jbKpOS+{)_oR0gS( zYEE4(x2l3yS-}NutE~~$)rv7BrJ+vRP%mq20Mo|sak$!A`CN@iKsqud(#~|BuY1s& z9<@aKv0Uj9PkJ;oFdfWHOswwrPOp*yoh$oW2e;9%3vys?^TPPb`H7V?`xmaCIla5P zJhi?sv$c1AdFSH5Pj?#%p{`S zky^ekK8M2SNfcy&oaNxxBqej31no-urXGg`Z!&b@yNV`Jc|uEpgP= z8moTfWMNdY#Iolkv@qW#(S>3S3|@IogFL|n8H@e(W)(c#O%u{yql z7aXl$|3Y^5%Lnf~`%nMwUp;?xSFUrQ7%@qkqvFfQHxFG8qyzg*>0=)r06b*20DcrW z{6~j}tarYWzV;^%-gx>S|Kq>?_WSSa`c}o^d8Iul77HPAvWsPRS5%-?Xg$Va=D$({ zyi>@NXg&+&Q_kO1S}drm)ym~s%o|mp^R*PqtkDX8m!F?H0dm$o+X433VtjyXe;W<> ztp~rx{!w2qX5%yLlc`?pQUE?g4O)WJ(VrOqhb-y_p}tb$s+4*fl$|PP+!F70MAD{? zgxntFTLNNBKxPT({7Fl=*Bt8C`FpS&i9uJgKad`Z_M+})INUde2p#fsJjr2$KPf^p zklF@VNl2PRBTMvn;#XG+YpccewNlJwZmgFzHOQJ96`bZ)9!D+U0sH1QwI>{Pbfw(s z9!EOk?H%gq8xHl4hB71R@tNf4RPW5f)Ye|t*i2?_Wp4Mv+W8xq>Ght;)sdzBtqXT{ z4{mMlp55En*x5ny&-t;1z4XXZq?5+@J-OFAdv<*D%E;>B#`!xJ zZoN6UbS~OGE^9%+qtc*K)gbGuvbq+by~;|CR4bi(+I;3`)`8{cw=VX_!zcqm#SOam zAg%`$!xq>k?lfj#Vjn^P%a6`h%?@1!(aX2+p|+s9I@h5O#@Ur z>Gek{c!{aY?tHez{m+2^66$lnM^$gGZWpDy4E{*k7xG0)xZGtb;2o$3_6=%1Q~iwX ze~o=PAqK!HgMZcmNTmU?d|5P~sd!)?i-q`eTSgVY7Vs3y4q{hezC;)ltuh4$`_j$` zBpeCIW8t3zX2Q^&13vrbQ|U+SZ9K$2!#=9{C>=stV?}*4U(~hBJNHMnv)}o}&wuu> z{_-#SyQ0VwGHEqQS}1{^17A4UKE8bX5NsbN0O{{RnE;N!KQq#sOfH?5fBaY0!|(p# zFMs(j{>OjbH99Z0Bpdk(2vPb|R1kkJG7wP#P+7@CB{fE2(ky-E-y@EFmb6c?UxV0R zc}dgBQfN9Ew;3$}xHVM>_Ei^>DY_WA^RlmxVjp|}D~Dyq{2BR&A&@;zT>-gse%DTp z*kdQh5V8V+xebART$3pMEcV&_ud1SgmS#bN)LG5Z)zqTvD<&V96>?>JyV2?Mx4Ak* z?fzzkm8*6rtszsm-y9t@hBBV?usb#Ahz+`81EyfQy`u}h{f_jAJvnHMWc0R9L1QyQ zqB-CTYO2uRnJ9e*{H6wZOOp~~+K#Yql*`cU+8=>`wkyz`P7e-d2H*_K^kp)sRH|=i zXn1mRd2@4eWi>H6(YLtPzqI4;9ryQ*_e?F%?;I}fUmKj=ym0Z>^zwe!$Vzf}35I+} zYEtKlb&V{KES?{jJJUTu=Juj{|M2SJ(8|U6-RqZbKVI0s)-}4)rqFRK${@5!FYJnH zqD&hpj1baV?pML&N|H(i6!6#2eO-*o$U|M228cueSh6%X^q(kYW=#S}r z{8-EhkO&7xd;49NzaxD2Uw5B>`lrAC!^>y)_-)pc)fh;M>TD7xfdrtLU6tsA&8w|p zX}USbKHJIW?&h-hAq}VyfQ?T|cNxIZd;go*|Lt-hr}QCA@=w$h6<|w{{`bQ^&dfnR zCm+ZW`1T3vY4d-~{9@S8dzBm~ThIVZ`9!C5d2?;!DOdp|#hmJ@=87^&b3OVanJpHP zNX`?qawY983YXX%R0dM&&R%1<&l>4926{B!w9FoEb%qs|4!tj7jrHrpeMWyugp{Gm zau9xg)hR)BCBr_``%wDwoYLoW+k||bSZI_1*u3maw;ma!9=k@fYe=@o|g?%=Hy#W(KFNo z=DC#(1klW093*GL_QwJxsI6(TCz}_ZB{%Q<;wRr5iTk0OB_a_SnZ&B4!kzdPm;_+_ zAK1q)g(KKv;inl$B-2CFn#ccK@Y-LbX10gpAqW+aeLe?Dz7D`A*r!R|q*F2q4Jg2W zJNA!38+x2V8>E`R?KsT;KKqOYARDl;ycFBxOdw|wytD&`z`TXuIL^R+e47xE0B+&PxpE6fX4ZuQb$tejH$heHdjRBj<$EE4V~R>CZ7P~BTkj`F@&9BpAr6?-dD6VwNj|V|+pB-4(&&=+OuUzOtD1UnQ@bz_7v&Yf)FAz=XDF>>{bP})XI zS)t;A1;89|X3CwR9!vm>5q^jTA{l6|KBzuVz$4fP-VsZq?RvlmFe3m^CEj}sVWLW( zaeJViVV?n$Av7E5qxL?uJn&9Lfn1H_Y=^l5@DzC#0H;Yo4ExyPA%lO;#fQ9K_P&f- zkdGmw=|eCmWO5#tkAEa;=Yd=jj5x~PfyO6rrVF~B0UxMmz$ZaKx{oc+LBlNc^e31^ z{tcr4a+7HAa-eUazr)F?Z$N#HNw34NfL{kjeU6pk=g4*R!Vi=c)E)k0XD6(-;M!f` zhyPJ_;b#JC6h%a+=iuO*t*>XENCtm2Y^*IQf=>^69E$#>^;_b1#}N1T!Ta%ZfPL8J zn7~Ui1K}h*()-`Q^$|m02gwJ(J03rH>;o_nM79k3bhI~P`$TA*c(tyukk^C`{oZE2 zp}LA&RaV_tQOm1oY$&giG&ZAEf?g(TE-P)WIN5OWBt!&HV&F?n0tuF$r?BzbJR+?} zs`Dt@y>0eRjXSJ!MMZo$AC~?R_JuW7FB$s``)VkCihaFA)Gn8rm2#W9)v0ZB>$P5^ zK45MSIczbgey=+f@b!i|`=gQJL~=5np6~6R>+hQ!7#N?MOD`;@7dL_Z^z3f;%Im-0^>RCWB>SKdY|xoPBY+7I&{(g zUD&}9ve2@R(}HnwBncmbSE*(P+s9(spRs*B#UKwM!1f7ar#?F5} z%miTAXTU%1;im$D#RrKrz+zXx#jy`*z=#B_{#LmX{S1*z3%@4(8~FD!)C2E1>=SfT z_~(GnN&pD_!3PjCz#>LCcoS)skFHu3TzS1EftU-*tZ>=7+FFOzk_ZJ7oxT*Ehy^Gi7iyrw!pK15Q#`AgsX?X6;b`o@Jiw_b_Ww%n1I5+(`L#uGEt1$Dx!Q4Dvwenlit#M=kDvC<_hqQ3Tfz{q zkb>AyezLy2s<9kV>?X0&#xuluwv52qEohI5O=zrH9q09sd4EXgD4l z>*|{7PA~LzuMK84Mu&D6X4keirna|-HqNEy_XZZu4lZ5D%%7cDyS#et!Gq_Y-F^DW z?B2D^+-cx_`P}{Gv-if<5Z609vVL)V=gR2%g_YA+7xpf9O)Mdp)l^<4<#6%S<37dw zR*bwu#n~w&m((?(`&k6lpb;{I8w)x#q&}q(Y!)}M2n>PlCeKK5 ztq3eutUQ@Xqu;+VP-QFlOrz z9W7M=_y8{;&#=#Eza9a;BWU9Y>~R2-=I@c%9H0%5;w9{b*k+d!mjV+YseL)%1N&Gx z&JT<;p8z8RN2n*` z&;8_-K8lWDWwgMM&*vjE3bq;J{0;Cu9?i=;uA~2d*(b0i@Fc+hCWP^Jv>C{WtSF$s z|IKrL$EPAxpDc>~hVn8#U)e0s)-}oMIV!%|+t?Zq+Ph`JQ9)=_5gm1QPokQ}))5QE zy1Ki%f=)Y3bwoPq3iE4Gse}&Xh57YGg|JHMOF;=vwVbMKM3?D?W+m=Hp_E%w+fq@+ zKUI#93B`UTuup(b9eu}@K7bFUPmO(RM_wK4oe(6zfh$h|)*K*%i+J>RMJHHn$+*~d%!D<-u7rx|aNGT8 zE^jh7E82@I5xd85=kg*5wYa=dv*a~8fYQ_k8V8ZVS=h9Y7A6hyccGrVNxoLdSIU!Vhs4O1(0ijeexU83XAS|w6{0q zoH$plw7~p;KM@U&xLj@{%6w@80)c;7Nlumj4rKjT+x36@o8lV#kB zau(f#hhN&%0LW*(eAL*_DSd{0vqEN5DP0=1N3Zn&`xaBkZjE_dNw2#*;Oh%^48-zQw(sneE8r8m2J=`$~ZTGk1`U z({8p^=>kptS6a{hespv-6$uBuPQMEyo-Jqu$3{Y6pqp8%u^F^hy#}^F3<2C!Say?< z!-4PcR7+ibt3raVDMiJ_xTSHQv*O%beJ<{KX4-@ElaT#U+Fp+K=VSt&%Gw2R_tB2r zu=mlIUyFwwz)%plCPJRlF? zGtLjrKo@oLlPUld2v7r`l7u6-ArS=>{v@UV@}QI|Fen%n3z!Nzi^Aa#p$7@Tz80qO z$@g zUqGICUn9YsD*$>Qp@G39S}Vt-QYA<}ysk(yMDPTu_(JqeMT#`i4bX2Sr(}V+qy2B_ zTzdR#y8u?eOGlWapaA+eD=2c;gj=5Nzw}h@3e3Y$35Nqh0K`ZqTLcskSR}>5l#}3O zq#t1AE`oj9Gmvc2IFu^ug2tjkWG2^_o|K4nYDY|A4hq{`%_4m>udTX8S>B|o5?X6y z{yJ4y=^1sU=AwO*eVKlYkmz(_cDd7{R)YXEmK2e)rlP`zqJqZaqQ>IlhN9x8lA@Nf zBIG%6%1ihsOZWgjocy&_V(5BKvy{t~bGg#S21RpYE2pK6$I}RSS|MLA7J~3oV_#-h z$z58FSFiQ88-wVs>2@X2-!kAycla{l&f$1uB9)x$>t5*ZTNxhQ92?o4nmj!}dv0;z z;_Bk$+(V6Y|)K+MG4TFc8D=Jic0gU>tXjD6KL3Hnb5Ip#o-qm|OiFk+C z;k2UrtC0+Svs$70t$M9Rr@>4&EHsYBaX+TTS_9IA8~ z>M3RkSI2R(NF*-niYM5orFl^OSlPrLTm-L0xSxjSh^8iqzNDBJ$D#B=?16eQSA;Fn zewYssTWEPm1{M@xT%rvYgp4d|ED$=8;}S%kC{&0-HURtZsL>$;i~umDpHuhLG9q#k zqzGRQ+=GPkA2|m|bq@-HP_jf92ml%QS6+&*6cxl!-$(^A8QXzzU>}KmOwlt(A9MA? z4*)p;TL7Yftyo6@KNec}qQ@Dhr3FLPgB~viEViI48vN}?cxRmX>xVh4QD`Fykd69L z>|_6UTmVTybtMH*#5s7f9ftjv4iYRMy__W!k&D9>K)3Zppxgzd`9B;H^fS=BBRUR% z*b7t+&@)-uA(Vb&X)#HwtFPytI?1VnyI9?%un1Icr8(Sc>=4Mzb(~g?)GRlKCGAOx zdqCvq7aF4)TR0p`0}fDp{ps#xI2^E9;Jd3U%p*!4@d(Twr3o)sEuXIy@b$3tsh7{BkipUC0ProC>uJF1w3&&A z-|GbSyMz9LNN^+(ok%B9mb)~VSsNYNo*3PqnLNKZcet{6d3||sV#+tN(1nIwYlz(+ zjIAGTU3~4~v(N6n{prEo=MSHM|K=MX-+uD#E3bX9dibz+<1hx`FYWs$*Md`Pp_xtp z*qSYvY&un?;Iu>ozF1ek`tZx9$A4>BdzOetJ2A(NW{P4kgvVkA_8l1ePIQT9#c8!-YA1$y!MBaBHCRQ(g-il4Wry1vJ5YI0{W*Zs9nw}8 z)-nEo4(LZF0U#VOVUvsL8gvj3nsQKg905M?4kSVaXH_<>(q#ZAASE?Bl#L^ncNBeN z$5|0Bga97mYHZ8I0uG`Sh!K9$q3cNR6Q?3e;mf)BXp#V4u0fF?!h%$2;FCb_=R6NE zK!|{nD=-m^1S{dOq@fM`+gZdP-vho7_MNcr2YMfzpTzY@#&b3zKwSN_0tj1Ze=sOw z`$L?Tmnmf^C6?j&7KO=;x=BP^FfH9jsx27mvBf^b0)USsKo$`o`;id(b)&8yq67XF ztI-(op$yY&H|VN?eI(n{_5TI?fbB~FuP!`MTbvJR@RHuo!ubgMS^OS7#B~5PK#zqU za55wI5Cvq>4nox^FDlA!C@ug+k;H>TBP+`_^Z#J^SL(v(GQyd%kh`QD*y6WbJHV zawRx0k(ihb&aC@JR-NGohm=d0cd!LBT9QN|k=LOpnlSlBl0`(c@W$WfH_Egq(!%j;HkC zSpb~DANvgQIpCAN9H`Hw?Ruc}fqm>l(St=0!a$?{R1RdrdDQ2iQX}4%P4yv;M_?bS zAO1!|t4<4Ep-?F){7G5@CJo_VO^cEk{8{Lq@qZ>28TPZrKJl3n+E3&F>K)Ly7)?%4 zF+^hlWKOr)glR`Qm8we6rbsNh(aF!{j3Bf}@-Fv7|$2-AQs?un+%A!<*atXh66t4gVtid8MmqUuUsO}$8JZ)i^G;owAopGqQdtzvK2%YHrdY~DdIt~2x1o9<>?KfjG(WwfQZof4?3*d z>^_STh0t-2E$Mf6clt7s&Y@&%G!>uhO)U)et&9w9Pmb-)PMxJn|LWSxjm`DRsX0r0 zMD6eC7+M)vxj4Cf^YpFf_nv-!`^l&GpMLN0yTA9wi|>O2Y+rqC?!w*V=7r$=R%d1+ zn&?iZ($Se^@6d`THo&W^N6`T?nyit2O=jPZ(E~0L$9Gu?>fy=9{64@Oz$eq&jRu=h z?=Tt7I@tRNqif-4!VE`Un;Ns8z0~LLb68zAi&QKqp?V(@fOW28q5%7h--7hAd>&G$ z3)eKK#;R9J34~v^}1DuHy z$Uz0Nc?o8*sD3AUpY2d-fZ|+q=)xEdQnH7|I6uKYN#r9{dpQ62VwYkc1|o2RP9qQ@_w(X-*p|@%(0%})Ev-t4@&T|a zzk_sJvg`FTx6g>bU*F#5B&fE}zp@hVofVIT#5Q*nW)wo=J$wrJJpYh;v&G{BlvjHPUD z5LTXSE-B_Ui5hw87Eyb%P+!m2@RU}e(yr8b{NcVt@3=3V(U>|_=AfX}+Q@BHD|MOf z^k{$oU~li}z(6LQN{54Pqh5_UQ01j96#Hmo*?6i33EaTGpaQ_J5S==SPUZloj6C2%m2h3d|C*MJlt%mBebc1)ZKQw>J@R`|x{(UACmxp2j%KPymVa zLut};X{m z4WimAm)&7P$DvRPQ(O_M1L{Hev4xfg_M!B%df#ZU8VzQ>4qJ?O!6Zi^p9huUFk!rV zJI==fE3mcer6OJ#9XZXg&uD*+{6oQEF^4}2T44wS5yuzkF?q;>eGT=PgGp60Nvs8v z2bvhWCXAZK?5LTa6$tEE21dpTa0Gb7mY$YX*?1uq6g@Zq-G{wT+V$iT`IxT{TVmr= z?6a2u{y;tUsT?4Z2Uo^9?1M4vZVFm zJ61q09ml?+u3BDKC2Odaw{Y|-gWDZ3BhQ@AZx;!HeVa^bQ>p+Lt0U(2b=h1PXc;Hg zmdlp%I(j<1J(#SKjz{B>a5CkIriVtSSEffdXD4?S=gzOMT-n~Zv9%8DZ*A^R9z2-6 z{QBhidlS32=1$)`d*}JJ#~uoZ33LGHhlG1`&38Fx&wZVWbKS8XpXw`SUG0E%ZL@dY~T5V$cKo zhBmcSC@{k34?h4VM4N~=01Gd%7-0d(F}@uto+_s8oVM=yYu>N!@2pF)#vgSU3VaLJMO{Re#p!&)^K; zvmKP>LeVoDA9#nlXU0Bu$eS`_|5&7erU@a+z!HOrhyS>o0qWZ|##~;pibw`h1%ND? z77nr#so#$>f6yKX0cQI!X~2j*NIuj4MDL?42w6gy-$$JQ)IcD;b>Keq*sO5HbT~+i zwZrT7`J<}t6;*iDW^!N}f*(14c5A>zep5gmMjS)|lLL4N@=uoE>vub)@INED6jivb z@`}7{jV*D?9j%wp%^qTlI$x}po@Gj(F?NQ1SjzCylhXisx^SE=YOs^8zqxjxfH|85 z0Dw2awT{?2nf><)?Gt{YA@4+E-ihXd{Fb78j06StaWd~@sZ}X6$s~Lry&#W&vdknA znHAD@sYp;!j=AB8!Esu|wT&{405^h5V-Bf}L5bSU6}218oq+%FOF0WqM-MqO2_-`z4>?~hu~=jTtN_5LdcPdOeN63im@ui+2v9>@dmZ+$)8+B_ zbiv*>Z_;J8!+VdEZ1mK!x9f2l)H=+6z#n=a5&(K1J080kGku(vc9T}^G8qkW88mXP zI_5a`k7#_>_s;MRoeoPJ76G1Rb-o0}Oh?nwKjO4MI#Pqv$eEN3NMBT;gl4%iv@12 zx?LjVz%8GDqPe_+&ueXHQIu8kY8%9@DvaI^sLc_H(j}JK9loB?@r9+8^`+H~`Nh?V ziTVDaQ8b~Cdp(H4t6Q3UCeui7@6zlH*3|Hj$7qx_H%potTU(kW)s<*}Cq7jntvV&E zsZ=!7wM%6ty<1~W>m7Z-kXb5gmq>`xS4f;DyUm`kx>D_ql*88-4@SZk6UOIZc3#r& z>hB81Q!$<2BeB}m-Y}{N9f=WlC=u!%_x8;9PHrEbK67ht^V-h#(8}h_;X`15;rg4i z2d}SRdF%S)Pwqec{Jqb=dj8!nH?BOG*t^+-&RuKghG$mhGyVP1aHhMr)8lvRbS}5c ztkof^%c-go)YhSd0rwA!)ME>!fcu0w`f$%6lyBCm5#2NE3H-5is#d@s1b{IC>|^0L z#yUed;8~ahNa%&R3ckuXD&zUsGOLzJ06fKV`Rg9*IE#fNin z0y`Pl&%r;tpRMF2fd(u{8+LK*KpFt@OzCH_Ps9}Yw4fOXRUoEDauX@HA-RjJc!5d) z`VY@e8-yr;NF?z-S_J?TiA4tS1tL`vLpP)%q1~v5d+S*8ox4rYaI96&2F1hr&NRU|NXIFR{-yNA>;tTem+5c zZZ#AlBQ9J15BM|5kOe-F3md$=j9XgLP(axGOY0@k_e%Nxn;$eEh24hQMFk$ra+^>P*KaTZRAK>Eo6>{(I=J~%#O(T z#NztK*80Zg+WPw1`o_}Q+QjHsDiDD8Kvq|4RwxFN$uYS8y1VDc#~}wiX0t&iMOK~_ zuAHh$EESipQEK&VX0+ln*wPlypw~a(cSh|18hnp3iO+2J_|i5{x7C>ngob?nu87?c zG8?0IbHZ!yiTHYY!r|_iKHyb(J=R2zJvnTO45~a`rr20$a&P{^>o@K{zIuLte}AuU z<;=ymK0E#T`+E=GTfF#q_0r?hH{N;t{tsSz_lxE8_d18x+{0U@uIb?9I!66wVllMP z3-^q5B!*z*!DWY-qa4-m6&1poT8wf7{ev#ZF++A^;FbXPvt-^#*gi0R9PbS5;Qv^F zJQnx>7O)TH1?;m})p7V^pFPAqj2-AQX7J_|A9f%R(1wePrW||`o2W(gZx(<#BoaIx zrPa~uJR%T|LmT_-1O`mDWxzi|H#B~B#xAhW_R)SH=YVWvS2nSSkapw%U<--CW^+^F zKvD&W=YfX)84bWT=j(&y!Lx*%5SvATID$kV0{ls$GFeC1rxE~!C--eI)erb1)d#?5 zN}mFscuT6Pt5kBCy*(FrHF#_$uhR-Ye*k*S<#0LCQ^x~`fD7|^v(Xs@XbcSO_a)3AFSi$0_ic(r0lu2!ZVRMDL%# znYoAc1$nUI1t-g;wKc#dxILrpP|(L$P9Wf5OK|~a0pqkLR1LH9^IpYda2~R2it_p8 zB_@%e4W%AM1x@*{@Jox-P4$Y}YGqxGNh(UBlCd)wiuH6x`xF{`9amn*lZw6x%E7Ik_$Y?hGIl=Rz&y2Hu72)eCVqG4B0Dn2z6omlkrO_`G8cC^|)edp1q zKYIPc@6K$jkFTxvE}gyq!4IGQ;AiiA?(ZX!VB@% zBAy88zQoIMME;5MpLQX`_mC5V4F1?cAmCfVf)HTeA*=wsMh$C=;bpJfiv) zXlqkfjrcgx>BM;d2KE`oi8n9rReotPucU}ml$8MNOm0b`1buQa9K58^z-!UAG>PDc z&p#nPRp!%aq7KJUJeI*k@^El+XmDg=x-;GcnM7i^x7V%LOY3S>O%3ig^n8yXZA+VJvj5`2a~6-2L`7D zL&M$6XJ#)w-g)re-4B0n{@~&G&h_(mpI?9c;rQ0&(AZvT`C4H9pmS=cXXVg4y6x&+ z=*TQ4M%SW4%fa4pi^*!#Y4|AP#8+BZ4erO%KbY!gw*;5~xshCUzun?=SS${&%kCuD zZ`U&dz;r#dJR|w|2Cxs{v&H9fPEvax+8<77rkIkklw7%Qjx;md+{gFCCb4ixt! z>eNI$6h{dt9!UqS9M%ZpXeVBv2?wzS<)+w2Mjy5PDYs`Y!L#fHhSMDC*$z2}a()JU z^iyT;h%H`)m%to=G$0+la)$qr6~L}cP9s5o*8iUb8n77N0e||zNVX3SGWo-!2ChNi0}eX| z@?s&^0ug*T@bN4pIi3RQv7qspkjL-Ky#0Vb7JhLVpIe@f$+oZ5m6dYQwXgaV2i2Fv zT~Am&G(MPoJ^Xvv$2s&NBl$U*0Ox#tegVqEjS2-R{xX{*eqX$!1D$H%xC828vvZ0I zImJat2y1O_)Cjm50Y`*6Ab5%r_}|^i8_IbsH{Nh6Je6pbT^H1=K3b=*&oPs=6 zeT|;mtU{-(@=`sQGttwtwy?0hy1G0yory#M|9B{3ad*fy7U(^j%iA|JFf}u^w79Ue zFgrCefL!`iXJBh(`2hI8K-TGVXU^=O-rLz-U0I!+oweF+sLcko@aeQ;y*+bNQw!sh znRr(y7!D`9BE1>4)uFQlG;))&v7xoTTHREqX=yNUn+f*CVvD9-rSA~6I`!s=-jXyq z`eNyYU~C8lvSEzM3;1n8zbot?n;V{88t$F!>zW$vTiuvFyghgM;quKVlNatSUVE#1 z?V>X?XYUh%hfc%Hp#};8<+yl@8EENRvojcqf zi!a*l>F_ulE~^DJ0KR=Ne}?^>fzPx*13vV=L@0o}kEEW`fHmMx5>()|K1ya|z{e42 zc~U}#rgpT{9n)ilTprjygCre=L)0`;vPXV?zzX{e`#4T4ZmRbg=f@F-eQdFxTLg5p zCnvVpC-{{TfFH*`lK>#+IkA8_TnGWMm#|B*_hlaj*vFe9fcMCLGXwyCvgn|n#>RTBs`5I|uw9qJW}a zSW?6*%;)Bx;1=YG%8IqkjqQ9cR+rnoHaoYowS9VT@9fU*%GC5wGM;q%0yeisBsFk2 zQICCjaba(3b8T?}!Mm8#F0ZN-ovP>#ht8irI0N_}9-O~?cyM?K1~9R(&^IyZ3Wr2u zA=33dTFt`P=+64ux$WKkt^L)Ft@*X}zVSJY-KS|YDH@s-b*EbEYBbIDdTygZz_TdZ zOlm``)+5t-L~@<9&91S8ZN5H#bj;c@VDcvIfvCyX+2-@BoUTY;YGz?{a&fe8Zgl40 z?7@@g>$l$6y7zSQ@b2*GdjtD-ePbK$;rZ11#gTKb&0KkF_tCeOuf4r|`SIH2Hx|!7 zn%KYBzk55ncp)}>K00}>b9g5@x;3|TdHdkbEK2!i_Z;y-x!Et&JKzgxEGy;IR(HCc z=%o*^W9k!b4CHP+st2(M8f%kjD;UTT{bt;Xw1kiu_8draq5#)nD8?2Ck8^%V0LJ;T1E(Bh0y75) z8Q=<8$d7%7++~?{Pb3d`J~9cZ{Gs6n!T|t$mgC2;&ptDgKe?>{ZF5kShf?2$dP;i; z`C9U=oCo&t6i|;dAq1GH$N3fLxmTEv8NN=Z({8oOI4wxLfm$b89%Fh4 zX=igeF`DyeWhZqKZ#+zI$OpveQRJc#i%|s@??fI^2<@HyX0ur-^O}tvE~gLSW{51c z(%Py(LOa^mAXxUB*yq5R5B-j-734v`1M-B@mzBs)om5nvf|e)n2Ood~A^!vpT0{bG zn`$5$S)Q8OT3$K5xplCA`t0uR?)uu=?CiqmsIyfrtthuhMKdGAd+Tc})6<<+i>$Vq zTLkiu?=~8@clTDewkGFiH_q&A?C&hCuLXNj!JZy(JSI2kMXd^*Trt+ueXzfO?c(K& zm#>_;aIk&$T;J%t&ghi2aNz2f*PT)}H|gYBt=g*5`E-`J)*2RQEkdn9rnAUYR+qmw z5FK@N_L_WYy*t%v>1@SJz(B}=23h^cy6s!pnwnT28CaW~I)8fk`t7Bwk4DelnY;Gp z%;h&GFFj0cTpHNDGjZ_d(7_wiSKnT_^>qKQC;=z8Mi1MOET)aZUFlfu={s6O-RLkQ#+ z0XxlFXIU#JX}LOT(xD0gJ)(%YfPc1EHbX1J9k$;9K26I9>a&Zu0=_oPnXJH;VIQx} z2?3ywENbrq<5&#rjP?_mgMpjW6#x+=;t=fPe1>}V8Gv_ynxPv)fVKX>$H2$KB1fnR zfE^|xuw|cweGGOrg#=Y!&Bw9NR6n!*3F@i#&uV-calV}2ey`SON(WW?!3Ld4+I+!l|?fNc3p zS2E)Db|62&Xh5@?PODjoq*>Ve$MilR51kHBV+T}Uj*eI*MUVi1d^@+r$Z6I#){DwY zgvEsf{`n__g$3%m8mCMWF&T#{l>|+O%S!xu z?PO1Sv^y2G+0>ZbTtLW!MkE><9h+QS^v1&BzEo_mcV=xdl0hTiPJ_eNs?&+p8kN>C z(m!b}*))@og*m$gKCX^U5x`KLVP^fb#oql5^79Z+cnC)MkPj0RcY;Fz=&Ubf?b;swY zC(m7+y?A%w%ERUBZ>-#Uvh(nRk^Q@w?YrZb-=4Vq=IY(&2XB77|KPptyHDpYJjkqG z>R-CNaqz~ChwtCK|MdRj_pjW0zIkw`cVZ*bKW7Q0Oo14NkqPAL#>z^BiMykb{&ai* zqs8N4+!g4w54|7kh_}r>Y}@=G(ly)_@+CStSk@m@1FCzF%#UP0Xn)*$(EiND2f`2M zGn#Fu%n=v68jkBmuhpq?S3BW1y zC-A3TzH@}1nFDgM2$B|UmW^#{=zWr51&3gI3>H+HCg?)CMQ1>GU zHxPzE#0Bzpnh=zSf3K)OURUEY=m%0=gPFd*WHRWmql69Swp}6P!b{JvPeXXkCtl$| zbtrp~mc-SzbT9a{b!P+c$3BzIx@x^6b2Z*P>~u)iu{C z(V0`NDDlMK?m(P)i z4-cfL(~+5h`0{w_^zy*g_C$O-b?@D!EARBI-k7@f zbm7j6wFfVD9==$={r2ctX#CTuxiiD-*D_0&)AN@G)^3h&-Rzk^mzdb>=$&Z~bg3Oa zmDMe1HE^Y^Esc$Gu^47frYnZkn~bJnA+&Yv=!|N|4+XQ2eLa(1u}C`D847qp=q5^; zq>Fg`koafN1NF$O6$zk*xJ`{5xUG6-_XvB zX0Adep#B%}Z2+IDT7pC}S)^Z;)HHOpU zS7S$r78aAN9xSMP#`AM}A2fiy5xW}O$Ch0OSHM1=B85fS{+}em$V?CF0l@LB#;4gw za-ml0f*IGTUtaDa>xkIzeDK*_{<@n-BJkWq{MMD50{;wywqdRO^uJjV>Xyd zCQ!T<3kPi`5O~0xk$gh$De!@PZr%xk>wy~*%IwI}WVk=kH{6d(7`wx((wq86CN5mQe(Uao zyANKwedpo&(wbANLHR9GXgb_}M<}j!cS50Ks;?v1W%S0-{NEgj2D&nV@Tfa9Z1SY+ zojuM_UobW4i}hRlF;gfRh(?B@on!IfbUMC}NpDQ`Upzg#zBi3leUtkeZ+-UZ=8Ze) z^^Lxr{l1-R6XzZeZ$F&4{Pyzw_ZDxxy?o=1=?f3~w=Sob&PM0X51xLIT)pleJL?_T zbEH=+i79XItS2?D^G2oZ4rRN8uQYIFn#LABZe8RpV6YA}KGZ=X)X@>`R))sv4PmR( z*PRGMDd5Jy{R1n&Wi`RM1Xj<$PFl&8m*wT><>j5oFUUjoK41>8Ly0rDUKaH1Kp-Blql|h65NvZt*t0+!10BOJlqnP|gD19ZhiO>q z#3R(5Q~*)wfi1gi?jr064q}!cWB5W24-2n?y2lIIyI{*c2F}b~0SEDRkTy{FIb)w; zpK5W8cbrH66{rKdcC#(##aFoVUs6^gE-7lO zsWLV-m^jU5Zi}I@USC(+T5(c&vRqVH06{@zMIOWj&If1ktCW5<6kdx>BI?j-P&ktb z1#C(gu_ItI6y{4#mPgvM6!RfQtuif4`eXw!n!raF8`SeV^z1K=TsyaV zaCP_a{^j?+|Lq_C(XZ~l`)u*z#mp9(@Lca+x!%2fFSU7l=Xr^H~F8*BnqJEELTT&cO;)R&Co9-udX z-{W#}rP|6`9@HQhUW0NIQlnFhw!1~eMTG!+VNt<}yjOFppfDc? z!SG3N|0tl(I6uKU#eQL7A(H@*0)<7zs3JwWOAb>EUu?^i<4d^1Qw)sQ$>E(Lkv*gm zKn`tAT?a_iA$B@DnV}wATr&qi@-6}r<;Q~FKMMANdt__+aB;jG!iT*zw(Kc_WtwV8 zy?l^71mG-<2QmRx0GK}n5y=67D-xr?8S^JWgsc>j6M934heRkwhacdabmAbjx|kq` z>V8lr@-?z=5`vU1JVfihQ^=B{dD9gnZ=wVRK&TN!6_i>bHMAk|vJIUU!0^!lK2E&2 z!Jc?DlZ>KAlaMb!n_r_|lOobS-V=}YLcB*qkpGYp-1?d_xa^vnVC=)CP*p_Z`y_3T zVE-F<2d;CAA^m7ekWR~OzUBjz31rQADEAYuNGi(H;m*~?xy6~O@u7jS!M>=&DlIJ` z7-uU#53m)N7E9sWLoQH$o~Wn*kSFv${{(qhSbzmw6A94L)K*ogsjg~otk>04$%>1F zczHoSPQw;9zFQ`7%cY;%#&M>G}co=u^D{`~UH_U^{+)!wo7K=){S zN7@`8N9E91q+>b}Ug%CNXHx6Ky*pFG2kWypF6}o4Zc-tAjE?Ag8+Svu(1x;lM$fBNA5@W$o2GdDMGzLQzMomsmbnmO=~?|KGS+GCR% ze?NL@s-3}Bt4D6Mi`p!Fg_$GNSj<*Pe!v`)o?tn`yM$IwNH$kN#qqep79MnXNihHo zm=^)I1qB6wJ&JVDmjlgtu+7iUJCSz+3)-Kpg2DnIok1S2#L2i_OX(kUJ}yGQPyULb z>cm;qOjIge#1+p#N>F(;2^afV40kxl9Pi|y5T$ls2mMhnOZC1SKxQb0ZpGD@wq+NA zK_NxCF1H1zAtq`HD$FS;dwJQ$4Tu0%W; zjie*7OcF+49JfK6R7~Rg<)s=__%zg`!8JoECF)6XXMyzP{EW;Fy}~l_yJ?6~N%HI9aARS&kE=CB?7{ zAX1oBrGlW8Nm!r+^6I)GcKYVePRy$_)h6C}C$LH!w zL}Sr#XGh1}%D0jYQwq2O<@lqhCF-6bn%$o`cmmKT z!2iY{qy)KhkD7K8x_j-z)rP1{E7tiSU4FAJ2);ugptM;*_$$W zG8uw>CXuj1JAE-epUpP_$BXb0QrFWXM%lf*(WF07s}xG1IH(L zKl;Nrmiq#8z{d`gyh0D03VhY7LH@#8^-^OAgc=sAiB{x8J!R`N~I2;ODsdz zj?#LrF1-@ZOb?~wQ2LnMhpkbi1oq3}qeHP(aS_S!%ckr9o!I{-0bt}mtL16N4%-Lt zS)2~Uo@C~f7TXl^$==?z`Puog@r8-;q}wSjDQ5aQi`nurGpE@O=lRKUF*JB#L2G%L zgU5A?MGgVqDd78MQY<%$WSg7X8yjrg7MF)?dRJc#HIvXn4dxwmXu+(7_+e~toRpGYDT{c~ZPwB9F)T*`1tba)0bbn_UOayOOF@#Kmg`2k!v#CIU5fzr4#F!?w#TOGZP~R(_;s- z+Lvo4@|+zx{WA^U)8#HFxF0*o8YA_ugB+@nq@R8@HZ) z`smrmZ@&NiJeznm=cbmVMR2{kj@v{G-Uc|EF)p{R0jcDrROvJ9<5nbhC51E5K4nCkLjnNi&_21p>+z3FZz0V#3``H`-0G0*> zah%Bz24QTW#2NPSLiTc8lf4Q6$G?R`BepmzwGzg;7EGrhsH6<|o1w1~CAdo6zRM9_R zA73@2{Y0VD#t4N)_zv>{_G8la1j9Z9KDPM7uY#Wj-#F|u{B%gEz;raMCbF$Vc14vY zAm93KY~|AE;P6noYpAEoqHP2A8T?s2?{U4KrTxsaN4CeaaH+cw2dS5yfgM{^)*vI7 zIq(Vg=>qVvL(TboheAF(JUBBnv^+DjI6h{VN}%qck4Wf|2!MUJSYSu`P*tU(yi5jNUsNb6DwMz_ z2&G?KBq%K47v`%Q>Wqj}wOeHE7L~Tio&XuDAv_oZS;T zUs7fF^V^JalS|g_6X|?Xy~kj(@;S{yBv$c6by6L_)qv(Q&GmHvKBh@yC>(AY(s+;F zhXnV~Ik}o#fFHH^Wo6`61oh9$%fX*LBzGoNM&yR1@`2onU=bxHXw@l!m7Q&XpT$0) zceG##Q$Tfpp2B$G3(qKK%N~~!d1X{7!Mer(|&oG_? zJ_GylZB_!{%HRViDH4dmCGhS!L4*&$Bml0Aj|4a~M<25LfPJWbIQnR0KO5b{3v*6C z#{BW|h>wv<04RMFFGwig5OMf5r!X`UzL2je7SZ(}PE>v#`)-dxKmSPG7ZG6#`C3?z zk6#7apV2muHH=KCuOYu|Lv<}iuwWcRB|0BZz25rf{~WmRt^VQB!QNEF>#i&+An<>c zbjBl{wT^LqhJ9=qhtC3>NdVCMBcq-XemslQkc1C^8q@d)t|4B}J3%6MWQVx&UPa5` z!B}{zzi)kZdV6_sFcwu;S4#@>Mab5JQ4iOBLB71WNKsNO19;(wEHANhn#0Je5BNqg z0^Vtf>D#bEZK{A==9h@QQX!U4CU&Dg9-8HrmT0OfVGHOR>*4J;^SLHu8o(z|UZxfD zjAo0*f+QS+!DuxGx((qjh1abLc(g$u&uqlLCfH$$hgv-@ExIIhMGc*uwqPvWJJ>xj zHZ(UgHaEApwz{>qd+zY!l^eIO-nn-V1mOMmzx~wMwipcEnt7J@671n z+414?6C>xR#xBl`U!0k^y}A0+FTVRve)Wrg^sBG__HX~@|M<`U=l}8_{=;*O(ncA$(g0b-A5^KFR#AB*6c0-xzn24|ecG(IlEc36Tvp%7Vp zP0Rs?dYpqryYCWikM$Dv8QyUmJGqq;2!JX+0J|D4$gYWp>{GEo9uz$wPa^&l_>BDH z1LHIzALw8p>H(njyd-ysNI&|)Br;O8NEW^XME$_3V7ar!ga8aCNKSl@)WV|QEBlJ^ z<>J5mJe-U(*&_R3T$Jz=>=zb7fR`1Q)K=9HsSed&*MK&tb#*OGf>v$ccI&-g>)!YW znYr~$GExn8@#-t(uacH}=(G0{_6hK*a?fdY#_*AH518ZNal(&>u3$Lnl2?buc)UT9x zsFWS8N~Z)S1JA9Ld$p=|sX$d*NfL~0uJ+ED*5}s*yoP9}+~;gYdzz5nlnS~tT|85p z#Ac8?Yzl{4?+9*zW3tU{deE{&X0fkd%ySxpZw^nfBa{E@khV@(-$v3 zI5RV~9FMJZB{zFhTf>7Zv$L4Tae8#{{P^(U)Y#$7#FN8wfAaI6e);*QKl$;L?J|6l+8|N2)Oj~?Cp@VjRozPEbq*~t3+$;`+^C^*>Z>-YLm5^M_exqD~a-J`~i zL@P4+?HxLQOl}LQEFqP(^X>LPgL6Nf(* z5_^ckrPenCHG@3c0&Z*pH8>f_!eY>7dLQ`0advU`6ms)`dU9o03WO?ry@#4?u#fj;?|6I%`*2XOx6bK(27GK==}T}9I6ux|r)6c`k=`f11p<7roJa!^ zsq<}afoLUo2W6t`xcp?_DrHgx^;pcdBEY9kS@Mu!pX?Cq6ZjVvA&`*6J~D|>^4`+W zgtonJK7FtI&7Wys{8R77)oP?(5R?C?k^Yh1hgTm3cY>3pvg%6Y!+^}^;Ex?(UtV2_ zgP`|pv1eJl9$H?A!ZDQIkWk$T@NId|>olJ9YU`+2FAyB1CLWLr_00E*)fDoeh-n;3&8ZZVMcN_O^k3GF4Gs(;( znaNHz*(AHkZnD{Iwmjco-+S%>Ws>DN&*AE--FtN2UoRnW;km+$zkeTO0Jk^a0N?jV zDDQ!{e2*OTKYkQ&j`a00B&#ZOvnzA5^ht?X5sFk%NVGp&;pIlK@8u@~mKLxLLIyysq6jY!xu<(1+ehT#5`ZuOdj~(HMYGw$fB=px%wMVSj}CVX z;R_O!e$nzceLhPrap19?5ZN0H3xF~*Ej^>CI8|R9otYJ$qK;IjCS>JkE3321%f<0= z0SZNWeqr0d>6x{)TaO+*d->wwi|1!AUm97No!nTP+B|pt$&+_}_@h@JfByLw-+cbX zFQ2`9Z)0k_PLo=m7+;o}q}6Ft^u;B4*--r3vNPIpGuw1I1C?cuZr`|m9?y!YPE zKL5jC{{7YmFVou^8mAUYyQfQf&*YYm6{wQ(BIFuHSW1{w9-a^osSzjUi4)WL5wU(E zB_}L~7o}oJA^%4!le5p>ekNc4vG3@oP64rqD@WxFTSSzTIy$EicuNe;RL9@HAIzO_ zdgc!YN06So=f^*CG!I?j+_enJO!J@^1SFi3T3sOP(c1)t{V>TE}H1n_kf`#`se zq0<9=7w}GKg5xe(KudapbPTzFySFM_5Ij*n*6VEU+z zi(DSW^P?UPfbVwVC~9Kxo$R>|wlo1}SN?zFHBa;7C|w0zo*MHpgWV%M&;GUV!_V$x zegXpyJE-2y``+?Db&`#;maxUa4fpzMKF5z{DI=@(1=R+9V_8XYs#@&o!ajb?@7PiA z1N%JQe9h;;TS5yn_R&L-`B{e#^32VE>zr_Ti6*sDms_5x(W?^hFcIbMyUbMnd$UWiV;=t!hlhsA2n%C3W(AQJl*=}sC&nPZd zq@-pTj5+1ynlfWlYI>j|CMq*Oqr7rvb>;S>2M?Y-fB5|6?dQ){u3lNVa{0#7XCHt0 zlOKNh(;t2H^^bq@kDq-0&7)hl1}aL7$*O!!W^7K8Jg+1xC$B0qy)G-GF)z0Hdf3~b=+u7G8d3?0z@NeXF7SzM{|#V%Pe!A*87K@yWgz+jEPZ=o zKYmaoOj{yNkolpJD~u8XHZCl7jIOkE>eEj?+PQfrBslok>#xJqPq9xEcoEX?aA?2F zvBMZh*g?_?u7YlNo<2CyGwW63*t-0#?7?}Ph*eau|5 z6C$_O=`uCtIhj?(<*iKv#ih;RngV{JTA)$O^!ZVx<=~b@l4{?&hh@ z`mWKY;v!w7G*c$iNW+v#8H&7mS*npOjr9l;dj?Bc5{0Ko#1Btkiy{9)M2O%Gf{y6^7JdSB4LxWD?c-mz&jMj;b zM+Qtz%pY6^&J4HxF7PStu-oZ|_hQWZCg7VGH^Dxs#l44mnlZR|DOQ5K%vKQF1+u$4e zK2`aFcYxV*Dgw9{5|cn;l3@uX$wy=`!G~_h8Dt!n9*FtD8D|eWYkRCeg+D<( zV=QH`Pk1^d0yrS9K<1B;)F1@xD*hDv5c`SbkKb|segy533SkVLw>oKMd&Dk7FKL$E7ZuKrjSh}a4v3AGr>bD> z7bhpl)M)~xGE5blqSF;r)%1*wG<0{i^z`%$kG7ADmA1B)wl=35OB3_;B@K<$ue1*T|&Q}bl{qTuX2QD%``U$5;RFCShs_RLkb zj?=5eRBW8I<;3qLBOu!x@_3=lbj{r2Lo(xC@1O+@K`sSW>nqnXO z7H^0Dkg$8=G>3_Aw^R;6(_any#KI2)9hL9_WD0!7G)E16jCYJ-{V=LCSR?8))NoJ? z@clhV5@7xv_9aHV&t&=`sQS;m8owmb3m~%r_=uyXGbxd7Y3Ypc z<0!3rW*=wj$2p7l(B~Z3Km6MF;NM5(E)v@Vqx~D-cRq0xRj}O6kGr7qEtGe-%#I%s z`}!a-p6~2HXo97M5A0@^=3HAVp_3io-kOgCB-gOKlEOrp$_NFA9e}KM2K%4@z&`uf zQNZ8-_%XpLi_FMy@cjyHUON)x%Z)}&idqyD>(7evaSz02o;VU}XASJfvRRp7lHwHf zr%ox;q&4dEQNMbiu?}FuRJ_^!Kaw2xPWhij0P1^387uYIq30Q(2t z#O!xyf2gBfj9ikIou01E)s|JHX!T*S$#$;xwv}o6x zC`pcs)TE0NRQ__YA~{2?*VpxSSGKq4DoW})J4O~4YrFb#E33mb8L1_e#^%=i%G!#K z{=T`{sk0kntE(f+%M&Z>XD{6Z{6GHe$6x;R>#x54_Gka_t1o``i>$shZW1pn;H3vXf5 z!g}CA%=kns#{e)*JQ}+l&V6F%XOv=-I*f-D!t^aT#+hCINYeL+!3_gvn3s{Lc#1?i zo0vW&FPKfw0$JaMyrYdB;E$pKr(oFJw~vhd`|$$6A8+~Y8^8My=XZ(2p3M+vK!q4W zv@6@g=m!l2=q5q?jIwV^>Y>UDeHJeuM1#}-BvuP71^psI37Osjq^*F5j~!~!5i$z& z5>bj$R1j4>#7X2(U@&&q-56l}3K+YuXG{SE`3&~)F4O~{d>;ZH?S*1zX=w)&EIZI8 zt=Xmh<|$v%k-x(}%=?IaJ#vs`eG1j{V8=tW9%fQ6%gH{J`1%G#HvYs(S}2y1V-q=H|C9 zY~HwY?cuW*AAIuTpMLZ8FMjolU;pz@zy0OKyDwI^?~l%0$T7CY=(-cq3k#D~6*(E1 zhPt4%CcdgJL{lcsFOIFO)-?7O^(|#Ij_Fzksw&FM)XBv$(FKv=x(G#KVnSw7RZK~H zUft<%O}Q{KlOs=I%i`HmrFW>@U###ENIm>TsD900-`*$0f|ug z)?18ze+Y@UNVg{ib`TGWX3b{1)uh4kX;WRa&V(4Sx9fJ*PXM3rFE;5AhVG02B*2X?hEeF-+$vL7*pr6gntc0Ze*;nI4$14^RW_bO7VPJ{AE@Y3cpq zmMQk}33v;gP4A_jMgYE-`Acz1zk*)Co+J;|o}~Bz;4nYZO9l36w2uk<^nmy!8EFAG zjsa;OA4nq#Kp6;I1`?Z>tz1$BLVWH3JOyb2^4@~{kt(3rr!du$L|O- zPVoQMTPTSL>@$2HOy3FvQQWZipqPV`r45Pnuy#50#_QnwsN0DaT@2s<9^Cgx#YJI! zlOG@0CuV%8^Jd2cP7W%0Sgu-?r%q0fjm}afAY!LHU#m?{g61yva04@iPb~socyCX! zn@gCddyu1p(8?01=fd`GaguLt#ye>)adQUDlY;}wGBu|=+UCYa`kNY>4G37t$&FA% zd3!{9!ieXdA{3+u_-R3bMR73|X=-C?a${kBcUegZvho$OIJR#B+c%ldN%Z#x_G8&T zk$k@pMTl4-P7DoA3=C8U3Nu8ZxrqsR27OAQE+I1`AtyUomoH67M%rDtR2uALD{{4u zi;qai%StcF&oXM&1v!yfDKWr(TVq*AN1Cxvo~((Nu;iem)0Jb(IV1T$PL9Y<(2B%o{Xl^ zoVt;w#;(c?byUk0mm{At+YsuSoWn$NEX5IO1@> z0J%Fm(9Yh8;vKVtwJjiEA_eA0j~@hfu}j`~18jm=_E2maX}M;{Q8)s&ddTol5CC~n zW!mZ#>drbk+QT$vV{1jCPzci@%BPu`IqcP7YRFWDGz**p1r!K?unFckW5P8|VHgzt zI7z7l#k=Wc^m8apz*Bfgz(Q(k@1hcz1wwI#;+M+sren(M3HhIH z#J)!i{?3?T>W9_c1pn`X9p8e1Zz0%s*tG=GOT}f=8=?0??+&Vp$z(xM56y)H{Fnj& zm>mDVyE{S_7^30r?g<`Ecs=+zlO=(5#%fcGtI6(afBRmRAD4g6oG7hwt@rSNM9#q=AvC@i~T)LPL3e zx>~D{6s08P73kDO`5DCp$%dkog5tz1Z6s=qh0Egw{5Y<^R-LFd7G+nI6;_v|>GP5b zb7J!|a%-vzYZ}svN^>h3^6R^Et6JMnk1d_sTG~24eP*k7Vy$=f%)+^gQ)_3njWxxc zE&0t2#hvX5hN3uwA-|)wVQg%8_3ZrirPkruGgoeY`SWl8<=_78U;p^WPd@)*bYZ2g ze^^)9sjVK>7+W+&?PBnrLUxSPS-VKsOqfA&MQfbD~^pU zijUQ$s56UdOG>Nj(66WNbXrMgWL}*-yEZ(lDnOaxFINd8Re~_3uTbLd?Ta7tQdVR*oa|xFPI6Zlj9?pU81nFaRS_*aPA%SrmR$8DSM<&h?2d4)K^CRW?%7_MCZhvhRqT*8o z+<0GaU_a51mBe8u__1PGUNR^9Xr6C^DqLUFWM~@F8Vu<&QE_rYewI2jKQl?66PKSG znU$|8s?1MK%~VLUk>ndJ)F@cXS6Y!{Ebknf>6u!r z?&u$1TwdSaUcY!{W$Wsh?VaU|*Ox9_oY`1!n;5Ph>MiT*Y@Hr!ot~;39I6=Vs~H|@ z92*~BKi51oSKT|jcJ0O&|M2a<{NWG(^t*rFdHSTJtyNQ8ouY58>7QvIzmRPh3`;Ew zN~x6V>XfB5Y0aH&^IMHm=LSM@EH^(<;iI@3x! z6N+1-@|&Y|4Phw-Y(5xkJKs_>MT-{Kk$KJ)s&ehr8%^i%^1xX^jmGv_h1HVoQYB z-Bi2X7&+{7if%xF@=6>~6p(j)Cv=vg12ce6?EsVl&`;Q%87_=30tEm(abI)*wzxGq zK;Ll7&}*n=k6@p%XM&~DzrzO(!4yW}55AB0;-jb(K|cWxF(^GDSwD;m;QwAKy)Wio zsE|V<`2l<^0u}x#_8EW^n3GpB)POmID4<;miPz(Hh^Y_~5vjO>8pv?C61NNNtHesn z)bt~jKP=4g17QXcprqjFF=7Y6k4PjNVjCoX(EAas?O37POyv5FE~f?-Ls%(^WJSw~UsS*JaD4+9-KONMODyQKK(XX6A>f z^D;8?vfv*N3(1y-rUvk$z1@?8g41LXIqBJHxw*2GC{zMc7sDP=UR+hzJ~%e9u)KJ7 z{ruG{7%LkWmd{;;FYoN-Yx7&@=C{sHtt~Z;57dnh^e)W|pIvR4oB$DMoE|S3=&v20 zsvTL(Y3|CdYdnAZ-WOm0{FlG|m!}_m+&jCVtLhLZ7@CKd&s}@bGrnEkKB>s44%d~a zDr<}b6Rk6whQ8&zhLQ5j9AkWBWsat(szp^hlGQm^+Iv>tx?t>>Pd9d`^v!8iy$QxH zU|*hI?2i%w>O6@&j>QddLc%yP?(On@Y-4O-IuPuA2xwq{Po#ZDog{nA+R_mnTfyiZ zpeKVbA^_bLj2_)4++7{rTwut93Csy+&`!(U&5Z?@9C2n5AOi)av=>OQI7tVdqC1}f z2(ggU1Dqsp*~31?H9Z5=(;z*@Y{(?}GR8E>6*vR`I6)#44-9w$s(%N6BFWo1SR6My zj6g*O^_1@e7<+&Fp#lI}aCrd!B)kVOXM%jl{V_CzQUeD2E=(m)5;bJHNP6*@>D@t{ zCyX9)J82n4y#F|0s(4`$h^vCcBkh&-AP0NKe}+yHT0sY_2PW5{y{#RzFqA~Iv9Uyh zUt7}P_oS`WNwoTeu!2U$qym^ZyfDX4TELh=#D2h^F%%$15b;-UK{PYbe83;5$7Wy# zG4_Hmnt{H&@fyKCJbioNJ$t2lP_&a|@lc<>2drn-mSHT9_|V`Kg`y}^gAkpD(&G9u zV@Y;qR#aqaxLlu_QmxCY%*#@Tp&bq@RU&RG(s$KXw^fuk7U^?ja+v1g{e4wD|9G}f z6hiUsZRAc4acovmV*Ge}%f|f7`pop==*ZI8NMBWD5en}I2#v8Z&G~tTgqTc8NO6p^ zJUO|yqO7N)tX7knD&(ece3N->z(1Mir{Z$re7s}0eu;_bR$(k|9xbnGG{nc|A@(&W zFfTEwu(T?xtUg6so}G{o@9zUqAr6iSo*(p!FgvRdOAA#1Ulpkcj8PS{p|Xs8&hkWBMUI;FE^d;>tC7eU!ET#bYQ4q zWU#m!@j0z|Ej`A8DMRmIdS%_@#`e2E{OXf0fByLWA1q$nsp=k2)}!Or)(4;d^!-o2 z-n{i(Rotj5u1G4cE;~I_Hhea@VKSw(tvDmSC`M7C&8+GeEF0OZIK9;{vfVauv2Ef) zvY|y)T%Xf0q^TN=%B>Qm8A6kE38}geQG}N_$I;%|2{s+ZZ4Hb-LMEFKwdtJPz!4ai z(3?cghZuSM@X3?MQBTg+<`g=fIXc)fac_#0SXK4om}=hXGJCa3%@1Gzk|kpk+63o_Y3f z6mtffyHYwO0`S@+frVBi01`~1{vPV_p9I1%OcE5}05V^Q;*ZGxJqmy?q940^U{6AY z=`h(J=uLrA0sEk4l-Dzip5*mVjfUz12vcN`POFVE(hgH|7%!&h>59=~82o9>08<_i zWiQbU(#+Ap#>vqZv!jERlcO~%tT?)$*|*IpSn#ba5U*utZw-MBG5~%}D*Qw7hvpBf z0it=aEc8Y|4?zl`>{AK=`fr9B>u>o{d9;sbjE^U97w+mLgGt}bDbCLav2Cj}ljqk~*XL)qmKN5hCc4YZV5!q7sxmWh&hzDZm<*eVDBeyjv8TP+o7z$ok6s+yXOS?L9F zvDvZl>Dk$an!1weMs0FRhD4MqV2+t~QVwVj&}U#wr*ncuiDclO-y(o)~T{OJ0* ziH(b=mp2C&S1bF53tD@#>N{2CO{rD28P#>un-|~x{Hu3=@RP^yeKvY#JH=3$R9v=j z;o^_K`N!Y>>z_aS=GRRl3t5#7G5QMaz*Ji6Y;@`A7=1gshw39`=pHmSzcjgZzj^9v z>*Uq(vk&Tr*5mY*nf1-urjg8=(~>lOs9G19rdOrr@&iQf9xN#901IFUZbI?MuoV_I z@S*(&p&3F@gxrXjetW2e))p`T0sGiv&gi7z?hK>>nI4|5-aa1w9A7TaPlPgX0sKIr zz@LSvHa3UpNx|?qCWoB~z@uM;FWuePOhhh43SeRq1{mR)Ae|1%#OX0`N4Kl#S!`XL zp@VK?9AhWbSK@#^!~q5*d88l^g#YcI3H!Kl98>Hc01?=C0I`S;hyg%=ALH}~^&p>2 zXIM9F5qVE$TE`n#j@zN^o?;(2MFSCW*Ob=bSvnXN|5xl&vf#_~7}~W4Frq$%KYkrj z8<4aBAnAb|Z-3MTL$x0#M?2K}gXl#Xjd;Pn=|uDsP;kcZfyHuw|I!{dSx7PFlmeh? zBDu>q_rah?X+C}q98gM&RRRS#1+oHd0R@_1>Sy>qO#Oew{u_UTebmnNI&l>GeoUZH z9j?%4q*oy(KPL-JzqY8bszBFZ)HjtD*XZ->^@XivC9UP9oi$bMI(+u<}yk%SsCBD@qOM ze3h1-r!Q9J=j-ZfYwN0W<)JA&c4kOm0^3L7;wW=*5Ia~4%#OzRxFrbuRWj1=C^kGi zJvKHiJR(CT9jL26e`aN4Zf)SKuuM91(8$0^-?fvMEt*&lMuc^yxLQvlMcR&B~LxlCd`#J3V%DjSDec|w# zrB8nLlRy6FUw-q4Kb^gHU*FIfQ&^{}IUQR$E6nK^>rZPmg*g#n`AO09(<@6CpLZ_Y z>73sgTHeWT?2pnK;|l6BD~45uPEo2>4zp{PJ~2hZ4G3~@bV2_&R|iM@=-68L(HV7; zD53UNB#0CSFjU$Ezi@E0LsmH;kKN_v3EAD1!|~+@@B~48u?%HDf<@9$X?R$eJWL`B z3kXK7XfB84=kK-KjE3+yCi0f@da|Xz>*r!j+InZ(5Rzsq+2 zFW8~WoA6F;n0Sbj*w1iYfUJ=cfqT$5K^_M{Jro?0mxK~Sh-G5*W3m+c_d`yAox{n& zfpC8s@5hi7hN?Is<#soZn6U{^?BhnLEdmc2_!Eu~u;U@48lYSWaY=l~@(+g~l7D@9 zz8tPEhjMm?Tu^xl{k}=%Pd_GF7zh5S|4&)~uvsXI?&m8AL=7IUKcCI!ut+yVbSdVr z&>|6)1Q8wt%4q9oV`FcPwny;PfTiO$al=Os9s)VShv4f#b4YPfs3tD%NFzeT7O@u| z+=n(ji0p;fPeS@>m40IJ`z!WIHZG~7OG;;lvAmPQ#D(dpRYe8*G<9xlOlgLuC{+!1 zU#r)3)Kv5})(^F{O!Rh-cXvVNFNlsx7mM_<(J6uaNDt=-SH~!K=U6ZIXb)F~lbzhj z4)V6x=2WDcQ=VM1I5===WBu~E^-Jg0FRZOhv^M2O$PMu^T?TzI%8>;K^bvBMT#~|J z=S#&UQRsWYNru?(&q~7Z^GWpeigI&Ox;tlzgYu*0#fdTcn23y&WVOCPRhXAkqOUI0 zLRyGpdujp&YB&e|d?H-!gHN51*jPeqC_}P9dPa&mBS9IH5}%e9l@RO4HpImZHq;Ha zG@Wi}YOk!G92>uR_4>8#t7}`=ws#&~y7Tzz{inn8YxRS3jiU=gt84R@E{?38?V4V! z8W}6>=*w;HOs%d>udJyX8ovALy-$Ap^OqlgF}Zm;3Dm5yX8FqYSKt2PPyhYDzx($; zU%LN1uclj(Q!mwZM^w!DX@>lDBPscH8f8>=T-3nWneO@9Et6L}=5O{)oGq$qj@MO2 zXlk;`hN5$8qVr3XnFSdr9+;dW5=#^k5h}S!P_B#1^>RVl2oz*U(T+B!&>qGdj$-)m zZLCkZdm!4(orB(@0lZLAP?%hdX6^C_Sy;F%JT^+MjF2dRe2G{VCRWJMu#4}{0r0`` zu`PjmY*dCxkz$o(YcYd4-iyv<$O5(>lmbA5Vjt|10tDD$;6sYpV!(_KYCwTcI4{HN zabV*6rjzukT`QKYodb#6IeD04pq!Cn-!y|*AZQMu z?`R(Y?oVcho|xzi{YHl0LRKLW{(BfF_X0Wq_)`+MduvXl9RLU~!Pd#v4k2FF78Y(!j_%Hm?vC~+ zVN^i34rKH&=014(7$4sr_L=(mw4x@G@=!BBipSBXB-a@9mD*gG@yjwZ@UR%U`P!WJ zsxqK{dZ2Hz4>fE0nu-bw;-dBOu_cKKDFIvnUutiS5$Wm}=j{%h${cLMo$V#ImU2g% zB#v))S?Tur>XogH>)Tt`FKnKhnQF+*GA71VrK%gVG7BTa^A%F$yyuF7(*>NIkN}O4 ztA?`A0AI!S2KMpc!4@YXTpVBr$QB0~;-m6%vQ-5zI2udy(#ld)8KR&Fcc)YVCnHFh zD&Q(TT_QbQ3Y8JLGO-~uO{3Em>a-a#(T0qIELC=DLT+BFHbW}uEXp6KD$SIN8+Car zr%$hpk9YSD_0O-)Z(Y9o{ME|#mAZkcqLzMrOIz>a%It+J(_2^D7gx&qMv6N7vKyM! z6_tke_A}S7z4O^;pMLe#jTg@gn_I@uo_p}_2fzI1-~H$R{=eV<`+wef^~1dS5k+nX zH>uVsy22^C)<3sD!Pu@&&(6rmuOD8onY`RMbFF!FMPH;(%hDwkw&c`|Yiq}%bIN0K z3S-l?8M%dVNl9{qqQ72`qll*O4cJM9a^6y6Ye3$Q=O6j8h z)thgiGB)aFr-e!CiVE8*%j*jBn~jFr0$p8!uE|)`-&8+8JOu26^-p$n_SRH2=yk1y z`Ne466)aTq{S#Q8(H<^f&G9}S;M5=j7!Uwt_Es^TuFVDc7uQy=UDyQnZ)~5xwzWCe z-`iP`4~t(vHYD z>5S^C>fzCj$%XEjwYrJfmWidV`L){NiIV>Q`tgyTh1vV>zWU;uZ=QYh;qc1Z?U(P} zeg4ijzx?%||L6bx>wo;^#V233jIPJ#cd=v2oTH4+$`WB_eQaq%I+}%d4)m>EZJN7W zKXxHAyC5noR9oDTS2vT}IG0&D6qQ*li9?Iu^t24EGB#EwA&uD3t|dYost5@Q3l2hq zT>u{~HeBpcrPUlRB5Ny46x`NY)*=OUm%^4g{0MY#YVlwFz* z0DlaEtUUuh<@l5cQ20~Xp4zU#$Y8jJG5-jHUy$R%U>UeKB^Dtj4&h1gW?S0Y9zS`K zvzvf8QO>?BJvXR7GfS`B&gk5K!lJod>>?%&*ov}xoi$d zFBc7?g9I#|9~z|#CBbaIzrTRPM)wYX9}h2F8Yx@ghUjWEQ~-@+qI!Hiy@Cbkuq;HY z?g+6cRv}M{QKD=wMtWkLN*O625Qy|0tD+Kjo6G4jLK2fmM598B#y6wpSk zEkCp4VmBvka(rh^Wlw!AEcs1kCB1bu0RCuK`_kmt!r1V5PuEm$&*|pI?&`A2w3IAK zs3s&JBP2jA@K5yf22R1O!L=cEL)urmIfXmff?1cS5-zVU-?@4T*uQ#y6Y#%yW_hBm zrA3$5T~tu7QA63UN{-J67GwnpfO>omJ|sUZG*1)+0RYqh9~)+6;kW+{{;`8eT%Xbu zRi2?JFko!c>Fl9i( zKTafk;te+^A#B7IjsfhWKOh`upb6#{7LW?y2uCCwiH2e50Hq<20pJRO*$@=KWKzI2 zKp4PGWqzRE#QNz0NP)@Vk9)_!jS!W8&xHrS2bwgjF?l_rpV=9)rh% zpv49JG5lF5cH_?t6mkOiypRBKl!6x=;3wd4P<)xocK2{WezLc(w~w#4r-!S(HT?L* zmj?;o-O-5_@(l|NME72$Gz_i!P^&)??ct;nQD}%AB0kVH=-A<7Z@h;7+OYW1@E*kW zn9A-UOVhE2e8ef~6ULGG^92uTy zZ>`VG(u4%61zZH`0Q;#z4uo?k>}h;Xx`3+*B%HcZzhjPZjd#db=N7y8`%M zy|8)f(uJEBHqRqGzPl5meqneRP@f|XN(*249!$mdxl6_Ufn)4xB29~AAIzqpFaQK zhY#NWVDZwmfyL$C`KkHs^P?MUU5j%g8>`dXTR5J*aK3+ev3_J|hwp#! z&DWp*?CW=b_@iI`_IH2y^M66+|Itssy>|blx}=w#RK-rJV5xE=4TU)^Wi_We7A{^u z*Pf=SjiRdda7APigqWW7g0_X+n!%*P8vn4UAgNNN&Phy84U$K3V=_1~xxr$&Bsfrt zc8da@yR(y%4HM$N7YRe5geV@ggz@(AlAu*^gj}kS!JtP*xLl!BN)!sdfEbv-?y&=b zdcYqu_92Q^VPLOPAs^tSK&G-Qqw?gp7kA)c=FF&lOFWXNL6evWq^e_o0 zKtQk`$b}gY9vN3RXP5@u+}%(q5riEA5+Pg|)^<<>SZ?k?98QE-4D3TJL_0reNMMMN zCljORjIV{o2^%yEJ$&FKynD3W1|s>H0=&rCM=vdy`dtp}^F+n$6DQ&V0?V}dEfv-M z%}r47N083m+C0(IwLCGlzA(E!KeIA1Haj@bX)M;tr6lyu-&f7^PhlkUL`eH=Z(v^| z_L%fdi(9C=kMJ7@i$+8{KXehV9NK6HL}j{U57`JJ9U-8)yW7~!$+Z& zGuR|>Mcoi!ACf+90aeA|;D+-8yq-qEnTP;T4>_L>+6^2b?HG2bnd{+mX^GsM1gYn2ZBbSri!uq?-T)0E+QFA%9m4 z_*?kzdGo#4SVi8@P+A*>kE@2 zXe++b)!CU5?W`R^>K*Le935Qk9S|smU?4;Uqg0o`mj!C!hgt#-wvM*8LOv&4O8hy9 z*@oNC1~DEdj@TYKXn*(sdT+tG4;R1vfj8|B?L*GK6Uu5GIVAP+&}%X)N@`nc+lD*Z zse(V*-!n7NhvT)`=`+(43&TSLbu|T15o!SkYX08vOBMKQz_lU&2MIER1=*rNJQeTl zp5W~s@9Bn79IHG(H~Z}Ntvi=4KE8G1?FV-sUB5ch(N+Li-NOZ7Z^}$7ijo&c%8R2T z$`ayAVxk}kr1JeB@B{k=GBG~0G%l(nHc~4U<%ohn4YK4?1RJ16Zi7bMkdC~V*!&1- zg0ELaa^gg5b7M_=MQvYYRozH?>y_1&E1Mh3lT(+@UwQWG{bz5#H#|9~GnA!B!=s_> z2l7xJx2aH@qg3UU_trNLZ*N^Wf9=89s}HU}ef99&5AQsEzIO4#{P~U3XBInVC+a6) z>uYPC8lT+U7+hX#pPHCFx4wD%=7sxrKK}BHOLy-rZeRM@FMj#w|N7tG{ozkv|LQlN z{^Z-C#JTgWlMD633k8kC=@os3u0>tbSZZl&N@10{ zpn@fkhA83{Dz#J*E)NM&O2omksFU^%Nb^84o|B`CPl(bYG~LoK+z|owh?qtBdWHhP znhm~YcI+57{7DN7QCO%%CJqq?2f~rh<#GHte4^m8Sys8o@SjZ6nqW z^|hR#d0Sf}&4|RUQbnCHj~z8LJC2fsl+i=M2N3{S z0QPYPl);iDv?Ddq(llrov$YMf6wN>ZpgW+F1``>(TMq{mz|#CAH8WDWL}!QrgorW4 zh#=lj^&htnzb8;nX&vSM^q~p+I0-i$){_pbq-jZU3|PuCn#@LYH2)7v}uu3dR@`{t`h_n+O_K`dW!gaUfH zPAYE5NCoN0mx>Cb6b)G!6^Zd#p@At}Ul{rTf1J-_zM?cH5+=cXnFJr05ddQ#CnHc$ z935VyRAA`f>GSbGg1~4;kG7~GQCrr2`tx-8zoZY$p^rMf~uHP6wv-ZueVC(zefBn;c z{OWgq_{q1wnLB?^*ED>3{c`ifc<1~?-FScX$Z+4%T2=p8$IRK%?zyVLwYt$weal!* zWqWRUb3#_J2S*~1M9bomM4_Uvpy06JV7Wvr2~ z?t@-D;CKXC$kjo(C=y-{9YSqbUxKUp7?#;9q{YAdCD~Q(WQRMtiIlkI~NwB3+f!JF0sm&;}X-=(MqLE5-AA{ zmxP7}@?9Kltt`#q3q?BX2c{MFg1_1S48+7x8=H?+2Csdd%4g_lk(lKzLm4*WN`EoH1 zz@2dtW;(S$OU3d8{IddhLsexDZd^f=niu!)0Q+y>zcbn1+LND`CkZKuk2c0eWeRyk z;nIqv_*QMMF*aHgBv9?y4`By@Qh?7dKn9;O+!(7g#zYm!Bt*Xm66S~kvO5cK72@F% z;p&8B;SzOHVM1I>zJ77_!s6!5TTkD4{?UgB^4Y$7@9fTv?fW}(+Z#O#lP!}YrQL1i zy&cs9z515MhLNGutIK^0vy%S4+^ZP&i_s_ol?YW(2 zeG6Nc9=*Kw_}R6`kLE6Jcg(FcPb@SH&-O1}>X_MXpWbes*sAQFsqP#%)^tq0pvl-Fevuvi!lTKID_aHq$;C~fd!oUBxBJA!LcZ5gxF>bGk6V&Z4gN^uqN&! z<#bRg6H&5n?mPI_{$q!Zpkx8G0LUctE?~f9;uBDRXV>e;(1G1Bepo*kDTu^8K*#s< zCcV7rF%}IJ5;Im6%ZSCqz=DI!;v}UB06Se|`di>-WDruo@niXUdwN2B!NroiEh}s4 zlE9KW*xR|<*xA`)vsSW;W>>CW{pqIoG*z})~L~^R-6vI zAChr=y%N3M(|LZKg?Ts6pL^%o69E7D-P_M@-I(p^m}sgUsjX};$jcK4=Y|MN<+2#FBLz1`v8PZRiqr$e;R%0!i_c#N79l`%3LfqaM^$`u8r5$(V)mFuSs z59_V2o|;?BGS*3w;`18IEgg`J=otoIo2`;li%XvrR}P|;r6NdZ-4XKKmFw||NduS|G$3n?QieB`oZMJ z&i1_*Z-4UnllMNp_T=p|*B+c++&sO!HN1MYclm0^^mhI5TEp;4+t6G|b!U(y&L=2B z5~B`+<%Yuv;_*TQgwl}Uu#jL;pnx43>7eOo9A4O%9|{Z-n4LTY%z%@ki8j<&$g!kg zFH@`=y!ACSef!?`5EH`oga%4bZ`yc3H{Fmpz}^G)gLr}1lMEXote;8+06s-J#0Eca zz@OOqm@~wg#aQ!5gdy~L6ZVO;PsM&xwcZ&yE9S?{P#$3aZY@BL4dLLQ_4W(f2&g{NP?mS z*63IOTQ~9=ERf|w-UYe=9RaVzOtcNS1DKLpD60c<1W5@s@Zki6_Jr(4dPgJ8iwxjXnt+q^JeD0#(U~6b*gS6!Zvfu{oj8~- zOQb0edUL?Hfo8uX-`B#?H^4&>R%^^QYSYn>jw6namPf(PkMIu!fncDGFPiy=1q(xi zg%HK8>`q!cnAT+?xeku(V@J>yGg%beURmB#Thm%vd~SYb zd;JWId&t27(+Bn^JKE}VGHWzxdS$py8mg6sKnKqY3(>B3-c?i#IKz-VbG=%GD z1iUol;(_mbxuy7dx8-Ht+S+*k?dLBa-G6lR+TDv6rn)=MPL5qYvp7^$o+0EFDkRmZ zs==!AiRQ-2q(ovZ^mK*HkN_(pB>w;|qzmx<^7xqA)a1^Byo&f3eYmVFA*LM7b|AE~ zJdM#2&DyNfE$yc#S5oqfG3b#oH+b#U)5jmb*EuzkNvd$yH200nuAe`1{(4*gd~H={ zQ9@!`umE)f)G#N?!m9O^`kMag-kH9!h5o_e@s)+1`T3;_=P&Kt+PZn0B>P;ux_;y8 z%(=4|b6cCU+vnS-Cwk^)`)6lb#z%W*=Ziag+NY+!{mrlc?N5LH=imSPKmO*AAAk9a zn@>M#89O_?a{j@~_n*A?>4SGaz4hXw&6^LWHZG5zz0$Y1)jp17frZL}rMA=ag{6)B z(C7d~VyG+%QJ?5DAmnm_h4AMJf(87b06}O#kY`$rYr(u@K+FlWem`MG@;so-zVQYu zX23htWbjW~6^4QS_weUv<3KqPb{%E$bVFh{Vwd76x*_SF#8Vh__kxRIt0RjIe2wgL z#=!>&V1O0UC_ZY?+mrK&-OLrSw6+dF9%1w-Hfb{8L*{j1q#4WtI7TWQq5dR=7fLJ=LA>fY~!b1lSBTXK4P;on;X5jn4K5moB|5Swm z^#e(ykk_6PI15elhNCWfdF$Yaoh2$=mbB%uKUj-88*mE%bp zCkrP}8+VR_v$qohnw`DuoP0gmEMLBzv(VNyKOqLL{Jw^|=Ay#6)5DjyF0M^YE({GU z4iBx2k1d}b1V}se1;#j~o|xrD03)!kl>{RW2LobxMN%A`YrQ3gx^#7RXb@z603Q%e z^mcR@qF0w_JJ=5MYQeRi0N`T7% zd>_I5a328sDSSUD6eTec#;EWvy>6OXr7A&s63bbP*95qTqsr_`g5M_5y88D^~%h~+4h;Kx{+aBYyIe%Gtl>c{rf-s!>|73N8kMR>cjU(&s;UMj1MlJ zyZ_?7N3TA8@Xn_XKKQ|nr?2KNTpL)~>X|!J+dq@lG@aMERM|D5(Hesl$)c!av>Ook z`*GQ@`@;O=i{k(;N67IH=5d5UA-0PA!`4m^Wj)>9y*)f2+aiA-YV7OZ|Na}Vy@mtO z0Wemm`~>;m`=0qxGhi8eESMh@A_xZjclR43`D1fpPh!RZhoS=;l`8mjpF_L{_F?d+ z>uGiyECWD2MKlrbEl_%d=mnqv2y;GRM)Da!K=5h6 z{>hVg3fMnt4o8S3M1kW7l_$Nk%}?MO;8uWjlvXK5M!?|%2N4_><^G*})IBo7Hz zgoZ?hi3#>4p%DI+a)~z^d7Jh&_GS(aW*%Nv+z=mjfR7u?$=TnPY z{p{Ax-AfnG4E9$gB{pWIcb6DeM~7y*I(m!-eS|ET?WOYdA|XQ@mKxZXir@%n)TE8o z*T8bvS6qbnz03fwG8%8)#T=ts1o&25jipO`jWa-Lv4nxrYJ*SnVMRksczThjCA#GUEX=} z?guYE`t-)bXVYsNOBc4UJbbY8;`zfDudd&Hc=_J#doQ2gdir?h$>Xh^o4pIO<^8RN z?R87r7r*-Xx8MBoH(!49PcJ|D+0uo(Ref{7{@l4sk6(Rs_t_^mpMP}sy^psaJ{exy z>YHC}8=uQ*8;h!%&T5`DwDf1{N@NMSK@wC^^+U850=@lN&?sU0_3-oYW=H`bj9PG> z;F~A_A>eQWc?i_;M+`XBRY?0Mjvj?h3oZuD8cddAAMq~U?q1k$qJU6fAL9LYSv)o# z<^Gtl1F3Wh;8UiL%}mVuOvXB?O@XSL%syv!I{`il06-^^ol{`d;(!$A2I-tehhpWjfLQwL$?v81Qmz?fPV;L02z$YkI(@yddB#V z8U;`a%+a*w1cZ48=_iQpPf5Y?6Yu~Y!oY_B{$Tx}1{jbBkm+s#g&L(UPC~Fa%1B5@ zDLKOBVciJXWa5EA5g@mmGPgwN5wdHT;zfx4BgPFddQd`ofVd_q2m$zXfLdZ;B`Fo9 zoEScSA(_I*$zR@j$W>AzFuC~0}%f}`2+cUA(!tFmh7O^ z35Al--~dE;!WJYA4weK2g!1_!fj|}Vj2M7iO|GjCk^@oQ>$sDE32lovbMIqrn+isa_-vY>syOUoAa|U^eqnd&vmv9 zSC>^JCzQrT7e^{!a@R*HjB!yYqGgBY>Z4DtKX|sVc^NhRHm+W~`Q*{v$7s@dfA!Mk&70Sr zfAqoA_ujq#^2MbGcZXIM3RdL3jo&D&u&p-M6%lAJ0^5Hw5Ub*w4cXp$7baC_g z&h4k~UAX=3*}JbcA3UEvf2C(`scU*(-!T?!=nK(yq*rv7G<0U`%EDqbLIme=u~%UE z^#$a8y*zz9+`Zl1yxd$_o*v|(rw9C6b~ZM?KHhi%PU2a_c)OzxhXYbq?C~t5V9*D^ zACf<2$g$XLK>gow9Lnpl{pbz^@Ua8G%k=3^hM&DEumK+#+|`67(LbHK>=`l>^Pi&hz2~o3;&a-WP;Mf=v-)H zWovD23H{j|K|xTEU`Mb;`9f=J5GyJ&(Yt^Gh3H~9B2g6tLO6&U7S`R_g<3c%{25h< z7(lQ%gh(KF+9A6x~>7pc{)!u}^^yB0%{*eF~0yvm?hXj-P;k0&v9->h121 zlnwmEgbVnv{Cs?USUg{Ee3sBVIK)rH_Y7uxDnx-AwJIw!Jxi;}&}H`b58t@9 zb7kY)=HlGB*_pMmk>$RwUZWn^uSkq5QAQMo%Sz&++w=1(Qs`|JA)aH_mN9@t8I;l|y2FJ3%;_tm49 zFK+Ja?A*JzdimnYr3)`V{rJ_#AK!ZR1fBK<7Uxt(ojf&eokCxa`uPH)~F+PvPoynz%UZTm=IZo5xI zLI6CGW=U}Do8XPuX4rTpgC5;=n8BVfV_>gR?3<*0Y-1__V8-@_@PO!YWX3_TH-jRM z*!#Vjncu}bAWsLNL_~eY;{ag<*8>?Ftd>C>Vbes^-@`tf@=nf<#5Io+77Y9$t^@u6 zFR=f2!v9J0;}8#keM?5Kha(T%AG7&M==BJELN)T;nZO^C|EUwGaEIt8XE$dX5(;f@ z2BqH|xjsh_IAmjs!nZhOhLs}RpCMwD`-1{N0DvWs&M-;9nrd%j>*nMP5r~n9i0K0Z zen32=$&Xk!3VaG`tm=1x4+@Nd9|AuIv+`UX8-Z2+2zCN7gF^(#_?E{{Se-nHPU~zR z9}spp_ug9r#PLV|D?&;v}Vduy96o}Y9{w{88#~?8~H9aCSIyf{uG$Kivl9ilWoUJP@sHv&j zT3x@sxwW-0i{!hr6JyH*z3utA6{@(Z#JIAUNU&PS>SJ{^-6h36CB=x(uSrW8s3^a( zx_b92u(3GSPy<_BQG~oMMK#^raCv3v?S~IOdi6H6eu(`~Z{2u)XXp9tog3%RZ7s}9 zG}c{STe)}X!hA>j|EKFc*s8kL_3vx%Bzvc6>;)0&y;r3w2vVgeRf4Kst_TFpM7*kAQO|sAbYrMZPhjKjUT<_Xr&rFsJ)|zvT`+4rCljL8YoRG8Ae}}12 zkf~whM(aJ!_N4p)f6mDWD&7@#h??T!{F;=+ypW*8t%Uzv@^%I#ZrhUT<53tMN{LWq zdS>yys)oky-jSK6{{D`!f&8jcdf=z#HP%)&)#qo`<)-ZojgCvMij2>VOWsTKfU@G^ z>T0_6^voVVdw%}f*{SKNq2ZIK=I=g!^8DqmPk;XD+P%9Y)5nI69h*FLa(r&~=J$_p zJbE~L>HNgG`Ks=Y(ClRQnDBy@rm<5eCr{4xj7?m!S1Dqe^0e>8B z6!?vQ(3!)fHs{2AuIrK9fhmQ@YD(OA8s%0 zebl`W8;g+!i&n2%&ZLT!E0@u?S}AK-iHi@a4+p@-htLp~K2|@R0U@wr$!e8V>(tQr zt8w8`LV(bK{|ggf)iRN6L>in5e{O|jN__H9nZHCm@Ry4pS(pQ~*HU3R)_M&Q3KZFZ zA9@^dyAYKU?@|KD`^=q}>RuiJzT^PbW|mf_=7b3lKwLku8w`@Kh+v2Zm!b0Q3X!gf zU{}ib=&7iMM!*bYnHd@&0a*Bj*fxZOgcabhiF!>#?}&A~+x3I8_hqDS^KsMAqdlXl zj?Ow$D{T`q4Ly_fn;eZ@oJ|9~tX$l!w(fMJKNl}8t1YW;tUWS3baMLmR8RLx^^T$f*4TiRAzxxXeUzbK`!wYajoJSB%{LVi+i zUg@FC!s@(z#SOJp&9!y=oA*zTO`JS^@#4jsu=_I?&R@EDxWZn$I{wo^Sh=h`X*y5+uh?Ux5U+3?kaQLQ;<4K zsAuLt@&&pbMK5%{Xu3l-tWfJLPBhi%;iImmZMw$JZ?%z)j+Pd$hK@o?i3_7R7~G7a z2m26yfKMcy2Ue}6iQt@U#Rb%J!v18hO6L`3tY}h4QwUL!YM_S?Z=EWRb4V}krG*Kv z)W@M2`LjF#w}Nl13gOBVieCAdbFq{O)I#`t`K55ZVcIM1HMF?G%tgFj`rc8#_~^t; zL7G@DUq-5qumaG;NCt9yK9uPT8((sGNR8-hvl1OCECr6rm?7+a0eOjiK^PR^gK_8q zl!yk!bh?z~LoyH`>SYXp6c+Y6<`=+BxKUh!#QuWeFYzvqk_q71kVe6xufJWs_&Z#4 zWCs!QP;3Em{6v&rk*I?CBVf_*Kpuk&2_Wx3M?nTm@YqmgVTI>JP@WB%tIXV1n7O-p zd9_q#`vwH9^h{UvNH(*ywZgKglE@Oql}wiM5;Dc&A=!9nG_W12G4`y1=WJ36{5_6;{x z9X;H2dUE{C(aE`qF-|TXpE)+rH`&v5a`ec}^Jf*{Uwd-z&f_~bAKbcr=gP%%Gn1!| z3?3isyLoQ@7PG34ADtWOp6F;EXsjfMpGw|cHkRmp7P!X2xYyG?H)Kb9Y4Oqio{65$ z-s;Ml#DvzItn}^P?kUe_di>QBLW>jD7vZ znYEQEX{}|I2M-Q)9v(eBIMi|AKzn1;X#eop(`U|Jym9{O?dx~$-2ML1vnNk~`swFi ze|z=p#V?m{-7Mp4o)j0hhS4Epc`B5tWX+DDz+3?byn^P*&1!e1UW$nw%qr|ITW4a=_<}w`VpbxSwkgp`tkeACQl)#r8k|UcFj*9OZ)q??xEsy(7buD@E7!Pal#fh<3 z!fOwA5G8U8g>w9H`2hH6_J1mC;pCq}--`#L=c{jso_$N$io84EkA)AmC31m3+#B#p zAwYC~mC)e=^$X^}f)G&j{?`}+j35=7T7f*j!pRyzb`T~X;lKPloCYNJ;1Hm7A^IJj zz*12IVWOKE2>>j8105qADEi!2HHA5dd;_EwqK&&I$v+ZLcr%nGq`|_%A%I07*Oy<> zJRCOz!8j5Hv5yd^0{$N(``mM+F7W3lzXJZ1Cj|{Nw}$g$N32F@uh&)C9J6&#_WbPO zBZq1?g(YeErWiSFvoFC93#^BS;T-jE;$(zLCD3xsf5y8|v%f z8+6%dx5?6yJI zcCh|%d*?Bd+xrK`4s`(DqrF{i`8hd3+f%l=CAd0cdZ%yqDT|71&dL~UX&UY5IMUMa z;2cbT_RRG7#S_QL;kkX`+`WqzE}xj4KRR{m{JBRrZalej=fTaJPwwA)eDBV~JGXHC zothXO={Ugg-j&NYuU$SrfAY++kst4!{ps%9Oh-*-kYB9hMyh)NHHrO58|)4~#z0g3 zWY3|oLk9<&8d@?kT61%V3wo;`W;{K*eL z{`AWaFMfIa!;e>P-Mw(**70-aPG7lv@%GKx3uospUAS=j*1c!X&Rn_NGd0#aIMh2n zF?M|N(8N&7K+n|qbN$oDYP$yM#TQpLx-+jorG6}_>8MjulW$hb*0`EYVMWo!?aBM< z!8HV5%RkD)O2w6BJFub8@7*`FB-aleZF)ZV!kB7v%SIW zN`1S<8%*(HFX(-YeYP*@tbmujOW2KOy*6U|;bIcnpM5CO$@H=1b;up8+^0moA0PfraW0k6g>$ifQ2z-l0wT%k;|QD z0etCt#gRhL=Hxz#?QaU1QNapaolQ-G_lqCzR|5)(rMLjzP2 zUVS}MJxR^g*uX3u+VNA#YFAjYgE%LteW_=}BB zMjU=UWvHA|aH}96q$>}8fC&H@`K)}BX9%0|7gnNn2@I?yy#C#CDoklXC`19Cdco;A z;;RsPUwH;Hu#7Z3h3%6EgquMS130|0WYP{tY#Y1?{4TGTe}`A1{ZaJ7|G$ijTFRn@ zDQcY&rp)Y7Q5CUJ6-DVw?38gIJpcIh@MlOq^MA3=#mj{dz%GyrG9Z_r0ip;0 zSK?1FW|RMYgQIc@3Z2NE@|Ec?5CBlmf&(B8wA8hTZZb-N$_G4{-z*kFjXGy~F#i$!Du59sZ0>48)Uqrj{EV15_M$nBcP&4ZsXZ3qb-n*w{iC5U$)# zCNh~A=^HT&X~POlLlq|vo4AC~)TCX0TdiZ_17j0|;u3eJX6&u1svhncI5~al#)V6B zlanKdI*#^qjUH$%Vq}l!R>jRo;-MP zOGNa5|NU!Mq5Ai)Uw?4@I@o{m;Qq76k2pSk_~7Zo`;TtlxCK2xkzPD^YJ9Y-v3{Vl zb82Lyt)il>qBt)yG{(^mG7tQDyEI?V{IHO={Cu(qhMO7&o5dPvZs@J9ASjO?0IE+2 zQWW<^gyiiC+n1D8T-w%n@L+LELsDUWX)QH0<5Sb8PaL109UDJB)IZ+WN1y&feWM+{ z1ARkdCr+Qga^v>H$KOAC`1t0{J6CVryLjW?jeAe-J$lBv`|!!br$3y#ac$t}#Q2G0 zr!Jkp@$mlb$B*W(UMADmU`twQ-rkZz@2IHAEKX`t%bQb5x?&3Ycjb=wWb|3Z z?B5vQ?vvAPA6*ew%oL9y29EedXFIw3n~KIbdZxf#lv&`kTBmJlZ)}XWUl`rE^Z`CO zT@w3R>SUf{?rCG`FV!~l3<|k2c_1Vtc*#1Q<;&MBSB!mR0*YRuUM9nEPCQ*xcn`Gb z?kF7Mq|h!VDGrmFzSXqeFoYDCn46GTK>fJj$@KdrId;uT5m#d={%*zQ|DU;f3idxp z0YzPc9SMAnhyyqSDpl0lP*tkB1_vD#2rv|mD0&z>u*C`x#=er5D}Th~m!UnfZ$LEi z0b5=u@nwtA=J0kvP4^D4FUbSPk0&DNPj1|@W#siOK@^hw!@CICLZRb2-ew7wzNnp1 zls-pOF4;hrf*>vv;DUM~vXnX_G42G$uh;+*`TPixVJUoy%tggIps6TAKmeaVARdYU z5cx}pfW>4pe!EDd46RsAX|SQLfwifnodw9W#@C0PrH|q^)YCUGP%+uO#>_+45ceNF zIpOK#;PcT$GzY>D%vq3sQv(cq3^r36{0dq+%T}m-y^>)|nzr-Lt_(yva{nWN~#CD298b6 z-ne+>`i0B0qhsTp?c*H>N@8}UdAY;GiFr?^Hs=ECLccOE`|_~8EO>7!%)1Lx-H-Sz11{b$#%-93BZ`uWSZ z&Rn@RFgXeE=dN5FKRJ8$##L08|ha{v#q-E_)%Gi@v7F$>vS6CTe z&_WkJw}@sv-wLxG`*xKKcqBE2X16wXk5{%G-X53l;u}U{w#bgdRj;Z_WM}EJm8S1%*nwstM3S%%t>*yk^x zi0TLOlHr4KN%*DGl+R=JOYEakMbo)e035!}U^!~;h_^pA|<9&rhLek1^x2gQJ0vK_9Mh4h2}$R%&GI3fy^ zhl2b6-vi=PDNkO6XM&&}795IOwBXayW&>!^ozK8}oq?6Ej)tBNE?g1hT`=$^)raRp z5iMx4YGPzT*~|M&0Ty!!p+Pd_|=eE;sX zOE)f_yLbJ{!&^6=-n;k1g9of1A3b{U`0?|H4>^B!|Ni}J*XZdne(2zVylisz=;B4? zKF&SXE^>yI+@6H3o74Tbm&8Q3=4R8Ct1%;eq^)JLyK}s|1ABxhWcJRWtUy0_NJ&&g z$?nL?#5i1$DKQz1?Zc-LEtk&E%+F7rAZ_9N>9benPM)2aJ~29Vd~p2ep~FL6eZ!|t zpSyDT>cdBmF+h6jD#m+zuAIAg=jPozx9(lOaP8#Wh0)2A`wtIw9~qfGb@IsMcw^^5 zT>7m8eW@h{eo-OLz8)_A+x>ROhbCl3rRT-u=IzSPOem~K$Zc>7$=7jA)pt!yDn5`` z+rKBjwYhhyy>EO^PL)eQEYACNt4L-8)Eidfu2$WUmzhvr+qfY(Pup@67C%F@(EC7M z^lw>9V=k2s5@7v$rtGNNZeL>Q`|Z*d?5Gdq6V)TOtKj)Sp8OfGz>&o>>|uVykVmt_ z7ikbJHisoKU(q7c6t9z&$p(#eD$My_L-c&<+O?DpFI%&E6*5Ig4Jh%VZ_wj%eerMM z`oqj$SOPH0L#X~QzW4{&Ct2>>uQA;fy)QiYXklqhfJ7xIFEl>SkdUJ+LGPvIE+Nma zAP_iydh$_XtOD0O&+8@RxU@vU%7Aupx>fMPp)Z)eUPG>shV0 zbuvy!jLOVNNJ-lho3JY_Go_@os;=hXfw}`zw4j`sJv)2i)a2yM;NVDmTX$tyTR~Q; zpJ$Sr3#vcC#Uawxa<`M+p@QURH_yI(`x@;3_19m2{>6Xay?gz~Pfx$UedQtx>_54C z7x)8q7AMdEp5b`s%9RVpX4(q#YmyW9=Vhk{_=v)Mr7oB{UnBr&!@MI(zd9)q?4$SF z@^dlvC%ZZ(x;syd4uSp59f9e7UU(o2!h+!^m5K4iQDJEj(QVB=XD(d2@%Zk=yEn&= z9~+sRnE>@;(;Ynn`wugHySJvft^H8%?6KKfSFb&~ckgI-S9@_@cSGH=k&(-1&fmRt z|Hid@u!W(q<0I3vBgc>Rj18Aom&awL#ujAlNQ!q1^0xAJatQF;77^yXYj+6g0>wpv ziBaL{Npbn5K9M5^`ezOunK{ruk-o1nFgjgd-)aqp@7lHM>cndd z$kSG}^DC<dSI?5W(gLP5cP<*{Fa*-#`~57jADxsQ{$Y&XNCJNYfj>hbLH)>6fTL4c1(PGS@M z@{Gj3#5>?cSaAfl{41bfae|cKDB;YJzs8Y2%PZyL*M*26j-dRLILEIDHz1TC+ydY6 zzQpy+E$Em*+B8iwO)M--tr=lpXQQpBgNp$Ga~<+hq^}R`OTGUo@IQq=|0*mjfqi9( zbY+2US)wS625uGINVp~v6qoWbQ2UEq-#rdiF4j!wmy;Te>p*d?HYp@~QKDZ8- zEalEBQ5#iEC~`AI1oPXk$l}scU8bwI!rH|+Dk?ZPDYh^pF)=Q7Z%RgS2_35sb+q<$ zH?&L-ja)l>{??^S=VoV*4G+x>^iB63YR=9mAeYa>O~OCM&axyTbmBn$^M`l-`s?l6 z_wU}kd-qD1rfSG~A#k+Pj zWTx*g$R$0mAbckcxBxQ2!~}PjBu`hcpA{5P5)&nydztCP_4XI#W9*N09X!tLkB;{I z@DN^%T|m6AC@KsmWNvh5Wp-wN=iu4%m##m!dGYS`Bhyp;!z10jgDnRR71uQs);CnO zv{%%%bar-6kB!~BeC6ToJA2KLA{c;fFzrcLAOdl*>_7tS)Hh?gM=eY7JrL< z3-&>`)czb<68^Zzu?67#yoP{2*vG&JeL$5$dr*%zUT9$yx>%r9l-qo_R8SN?Gk^ur zq9@PV)hft4DsypCtY_jb?YZC$0`dp}K+OX0QesFsfY}bs5EJf{%03}6l%5{o8ZeOE zN1JTq9;jCYAn>Pksilpb4TcZDOPCMl0`?*Nz*!(yMEEfNg_Bc49>Om*zC14Qe{Qn0 zu;ktT)Y|&^Aw|{!5el^bx>YMe1AGme4 z9!bho(^gl5_LIy>gO(-Bk;`f;SFIH{0*~y6j;%B>5*8H;p9)@F;i#nsf}SXgXkzx& zKk4c4**{3NT(x$knI$PnD>k{9CZJr#q1aQNq77fbt)D>>n&C80~C7+Sg00ft*8XilgZ8 zX={-l=v$K#Uz?oRT2wr6sCRM--`xE9>zBu-CVLMLHZh8~et&6AeQ8bIzViCw!pfGq z#zP0%ub#hf@7lGwv5}6llA67-UF8K$#bq_6b(z^!safUuW%b#mg&Czesm1wWsY!uR zq23WYoP&2b?+kMA_cw9#*h@p;lXJ(;oul$Mr?SE|IMB|=&%({$#x*#zsJ^tJtF*Bv zzj0`1YQ1k*nu( zL(pd=0Ol!CIkwSvD)2?267gpXMF(Yu39$VD5eSlmpS>q{CO&+p&5jJ{v3J_Y2oFcc zjdb;=%bSIj*%~ELR=}Si__|eM$m>c%ek;g$MUk*$YQYzxmQ`;GRtmX;R6yNdwUl}TJeU+%V=8g@;g2I5-zA7G?hEdc3E&QYc(d;4iU{mk;LzUj>O?VE;1`F}@(_;)_)( zE6mKa%`DWDQX*O!YCD>n(!)ddhJ+VqH4x(ys`J940{zqUHo#c{j74u!*1{qNr5R1zE2QCdh0qPwc{NcZrO zvFVxP$H#|8TN~S|Yg+0mYidd=tIHcRQ}R;wB*le*bwQR&ngy`Kx#D zoV|XneP|H=?-bwSB(bQp{rsAv;(3VR|0FEMe7p#lt{~P#9uABfrdy=gP zF62Ix+mfvd_G#q@_MI8i;pXhL*}=_g>n7(-B)mZrNem(cj~9*~SK)bF#UO7{TZd~M zC)>idm%E*)A9!a;`2Sz*gCOWHDp=wX0w4^3A*Vn)IZ48^2U?;=_NIoMe zglF>u@TCv{{yal;0H?iJ>lw45CNEIZ8}0{x5DNv4@!>Bc4S5T6;PRzRy1`LSkt9`8 zCYbqzJS`#rX2S5dvM{%@K%TA`*!B4NCDJ9j<-O&`%7tZ5b+XcA zfT#ps3&FUQqmaOyE8YgOj*)CjRoAUD#?44L-qPCMicbBOR*Ih$KOR0hs&|RtBLqZ_ z2iZILe6)1d;|A0=)X)_9+d7&WIREhk;`kNPb;%OKm?D0nERuQH8?ffkQo1j1Y-spUeIrdR68(MhVs^C_mvl9@w>KQ@s6SAj zUs98keWbmWyq%lp&XRk7tiR_-b0e|!lIV!6?R1g02{t#1-QoftI5pb;+s{8h`QJnS z-@bW^5%B)K0)Jr!AP7GG@c!-VKmL68_HRssx3Ay)_Wb+X7cU;09B*&!Z))h^1BHj> z1@A2067(=WXRn^Wc;)nk3n$K8=pUbG?(8UR ztjn*dD{E>UJUVmfCTYI+uim~jJTsk9UbeTaq@c0ZJ1WA~+s`#5);l_X((f4?A=}09^^t$6w6#=M)1cKF9h}H*7mjLKo};kW4=VnH1W;MO ze7z>j7_uiM0~(YxaMAn@$DD}q$z943v;tL*RyLNK-JD%Lwrp`1o%}a@xO#5)CaZ5H z(fm~e!Aa?3;w!;-G2@vh6?eKYmx-6L+Z81*0{sdKgo9hcUmS&D3@sK9I5RtqBNQ53 z18U3!0@q8F+IbRemWi41i`lP2BZF2Ym4_4J`d}8K&SwDoKwILSa|wU2PlH0ymsGI` zxI>Cc71o5{zoZQ-`9gvKDJjIfFCUwQoWY_uFg7$M2xer!qLHDQF#HAfX_;qfV})wv zx4<$O`TTR?IpHA*0JK@S=oD6uwBZj*oz4mGNCh)l#N-?jgHR|9QA^=oU~wXSn>>&E zR7Hhvc{$T~t*F*ynVFdzF_({t95n5sWSe-s$l)QHZ*FR8VP;Cao`Ov^ZNn8hHY?Rd z>K9Hway;M$gnG&H;`;bdTsHZfXcPP>_)u4{3%>al3HHwqxX1kB>ky7g1^z;;VX&;< zu-3uRI5=e6p@aJ;hmW*WRPPP)PxklD2n(&wEo`o6YOdN}Th>&OQ&5&1Px<`(#Ms5z z>64>F6NlOl*H*RVW|zlArh2&tTNs6!n{v`uQ+V_A_>%`WVfw&dJ|z41J4d?M7sW&jHdgo6RStD@&XC+V zF*kGU?78#TZr!?f<@%iyXD-g1JUw%2e(d<{)QP#%7l{Mhyml_$w;hACLp0?3Daf^2ZO6ZG!{u4($2xX%qtHC~VW7+0#c+7Tm z8cU68yyYu#+Th=p#=a!^yhhRh=rM?!Zd8`|=^-5B7Qd_4l8D|3^pw9&g{gdj0an0*%@^iY4w@uwVBzO5s~qpTlado;T#CJHH~tx3g2iIWM=GVpciOnR1^_B zTwB3K9UmE+nL05!d3ti{)cK1yZr;2#J)!I@%8R^^J{B&d&9Yji(h?`$y;7dBr<hphNe0Nu=vgZI80g>A%MY5Y6A%tbg(irCa;MXU_S8&6=M9kz=&Al!DVux@=o$z zoP5B(!t-&4kS>T5OiLkxlPP7nY%obV13>w9e!Wh+!_Li=04o=RtsCdEc zwITM}1mj5NF*X4HqGgAjt+kPRnDLgtoV55u2ODg+?^1qGys?b?@?UtLgMo>x(jus7Dnt06b*_;CL$)%P78lYPA>MxYB##o?h5 zw&pAb=k0N{%?sPn*Vgpp0m*)EAo)tv556y0Kj+f^m)QU7KUe{Oz9k~~+s{g#|MlDF zj*skbs!mQUj*1X5yXakH@)t&gk)==9zU-httbmrR%%-f2f#&+sm`ECTr1)+lF`zIa zv}8|AV^#(c!=kXz{W)1Q6Bs*q;9%)KYK?QlLec{LnFSndV;*d65=e^xQzQES>~gT# zVQWT@pde!depuTn=zT&k(o3^qm2^#s+&9H_D?EPMR+{=|^oo%&KB@5q|3^x!U8Am~`jD9CXl`g@ zXSYn-_Fvzvf@s6Gk?wrUe7{mFu~C)p8gcNAhPEcw{pM|39b8=;U0p0~tyI{L8fw4+ zTSAa+viU(D4Qo*Pq6CJjnboSuBaw)QOCDg+MH`**A-P53LOBv%0Q>(U=&z`LK7tN!#yavTdz*(f~FeYE(Q4LdcZC@ z0PU(JAK-`_0N{ik04yI)TGpJ46PDue2mVME2tSw4U*KZ3bVOPtON)Yd1Iljck8MbT zAN7!6pTD!<(&rN7#X@(a3q?p#MVu;fK(q!DHG@kQ;c4Y}$zA~Ug5cp=wQ5yI6g-r_D1zt)nMB0E-WXU5p3Tp*- zA@v5y>Ct(G$@%#y8Sznj1N?x0s{i(QPfsSpWky65XYMP{ugHpsOy2I-R#r6LclgXS zX+QnPh6hfKjSM$86hs8aZgzlvhng8j*;&!Sqp!Y#ejTsL`T6_3L^_I|6Bg=To=DaI z=I!g3FModi?BUZpSIKbns*ScIBEI*sfwHwiK~VJTSE-2JnTIqQj4oA+740#)~wdVyk0sqhVuZ=IZ7ZwL2s^!#y z!e#QCf_)rG6#n2J!{Go7S1tkdOIIx6Y6Sy_m9AVuPdZUmr^pltKhI+tsFHPxCvU?B z2J8al1zu99$XFl5iae2E$*bm3pZ2VPa$1J_b|~}6sj*8juB*2 zu#ecJ4F~dyHU)B#gxHxX!y2aJQjSvIO4wpWGJU$oj7wP)OW~P=7nr05m zHt0dTw6rvru2A`I>FO`PS;YN?QlZFs2#x;PXYehB^(+#^OL-Q^^Dl}D5M)r&75TBH zB9PaDi2Ja(XG<1uvNqoCzd0bxEjB(RDLORX+dJ9UH!Z+F+0S>6hg)`JRCPf`QG5~t zAvY@Ya9zdGfu8vpQeH+Vz`u5C_V{2=UtL9IY&2Q8Ar>Y?+{&UthU&{6T%P~)?H~UO z`x5x_C}{tmWCgr_{pRJ*Pww42fBNd&?C62!#7A9*S&ab1Rj;JxE{)K12zF_?*m<84U zNw6FJBKD@TKKs|_U|*ne^)iqyY@T4)0NaoLIm!|CE^w_*b_;;iQqw{a zGIxlkBRU@;57>neK<^9TzydHD8+Z%;h(!HI)xVf(K@18Q1r7S>2p}y8`Ff#(l{{%~ zE!c+-zy!p^Tf*nsjJ#RH<#W@3Hb*W~3IX{eN4XSN=LhVINa)&CIBb+!BsiSlON#1W zr7#)1rfW2{H8pjxr?A;pky_xi#bt}fR+p`=oNVCZi0gpksMD)QpVl1udLnh-#Kg$J z5LQp{Zv8rSZ9S9a>(+nu&0Ly5$T-+{dCb8*g{6aY)#YHYork-9_d*TCPg8d>~H^+In1OJqOK=N%$;^T|sczSejcAyu=UXvV8N1Y@Ohu*?H=ZBl_T|M;% zuRd&FD1C+Ue>fM<0Q`6F2?xA;`}W-*uU`G~^4BNde}DVx`J!+o6XDK3TvWbfRL)lUl`2KG_NkJEts-c%oN zVg!gI+J-YQ$XiFlOIzJXPm38M^aWKWiW(<*xYCO_-oq_KnE!@5EsUa^>|=a`BZAW% zoWhM6G-~dlsqd^|v{~1Tk=Wb4f?`|(BdoW3n|W>3b=;`2$zH|WX1(P`Ogke}jkH!pqzsddGP$PDgn z0RisbUbwp%{X*~#D;2Lh-ERPbf_;$$iyRP|YsC_gA|_}*;$|g607HP{IQmC_AQDIb zncq3BVt}L+6n+ge_tBnvqERaOR<)a@#JusIdP9ptN;LB$Sr(grYF9@_CAyMm~ z9t&m-wm(rE#R?GdN|n`A55b)fp}dA*K0^}SJhyG}^mK6DLi!dLgfvoUh=wkWm~@EW zk&v%T5g&c|Ea~pAr=1cV*4%N>F)(t4&c^SStr9Uvyede1%=wS&Bjpo$2oOJ%KIIT# zpPPe7S2}_TQ;vK>Xdcht$YJOYrjC))fD}(7{o*#+7;F!)O-$Sw;qMV(V;<$`kVMv; zpI4%nd!m;|tjE?QKcCFt9rfw4hpNij>KX?+yG~9`J$ZQh!Ig6-2K%P_d+`TSXS}H6Wo+SMVCi7A(aqR(o1T-ShMk?d?Z$QHwg6wxezWaX zfFJK05Nc&=W29%SwvJ(F|E>3>5a4@3?-Q57$?geXpk5xa_bEriX8u|fudhHaVc-e8|DT8CegKrOS_{3Qsq5hCx@||Gm94d4_#c(~ z%9Tsd=@Q^<611LzeNkQ~cL+an!jXUCNi>L5ivsx62(Zn*ChJ9ze9`mb1Mw80WWXYP z2vqT`T_s!_YgYjI#iErK9eIR<4&VcS;&j5+WwsPbzx~ZGtxffhYQ}(u19G zW4g2&pqiQLLF27%cCovCv$OZ?3UK!|GuUZsxo7LkZ!0WfKU;p;}=R0%L?fdrUXOOu^v0hbtY-?V2Uu{iKO-13Zkm^J+GJx?w z(F_B%v!V)s%w9T(=7a`Q%17=W1HTeQ0iZ|x)-8LG4~`ol`Skup%QN(cEFj>&O;e4D zz*G$+d$jkn@t+l8+GlSEZw)+dv5m%+~w&NM9H-=jvGBAZZFUQpAz-|jeQ(7?823+ zrGEz0AemJ+Xe>3@v_{7gMSzbD$n(3Ht*}~-oFf7FCdn2@9!SXmKSkj40PLSW5C-fE zFsH*rYz+oH>Th&*vbNtSyapJi_}TEhVXIQ`t|Zw4f6>HJNyQ=5CDkZM2lf04J4XVa zXXMrr)qIE^1^x@z7a@Lpj?mFBXwxTp^HP9B3i48sA|PUXBFu;HT}i|R`ydzS=@}U? z0u*-y*k>u&$KIz4o}q@WE*eo=M{s6dDHyv{kjMuG`+Q*f?JMm!rFIjIdWcGj)aUg~ zrV(R0$$P_}AmS)wOel%L027ujf~!irfWHa$`4JFubGSyZFX8`xQ4g%7^i%BpMZ7;> zj|}SZ)(8QP`1aSW7u^$4`cML?_qoHAP=S5N&CZTnT-<$q-MqbM)xcPFShphE)Uo}6 zzZT~I22rgE{87iIriRuQ76vZf&Ix7P!y{1M!g-Ij5NaRdFCLt5=Lz2N;aS{aqA;S+ z;2VmdMW!@gC=X(`7#WNoqRqG{9~NDg88-~}$*AK(=}_Se@$9ie_Q9#@uL?`&t03RQf_i?Y?yMJ z;e-1J+nPH{iaSekkN33Pzk2S?>)-zR>)odkK+1tn;r|Bf|JBcLo?X6syrsJ&qbWa| zl$-wQ%C3s?zJ~h4_0{{L!mASFs34AJIH0}FZfAR1cb3J)mM0`sBqo-{?#>AgWOyG{ z#tClD|fWVL&X zbCUn|q=2AEpCI?mJGR*Sdf0h7+j-j9`&c?|v)tlg?n;*}XCQCn=xVlktL-)~7oQz2 z+x#~=ZZS19r^O{5@W4Kn6dD|(_8-F57yoBri{XSOz(+bP_8TsA;?;PCRo7`O*EC#7 zV_914kyxj={RQ?#u8Ok9IV0D7#R@?YgfA%JD`NX*Kug&qX> zED3x;0H`id(t5>?{Ngiy1=$7$apq%mW8f<`z7mU4_9vGF6&Kz%dQCCr3#HFsVI3_N z^=vGBeHi|j!Pw(;*@d4Y0l+Ej9gq?W!1iB3zOiV|Ba&)lJY9y@0iZCt30SNV-iD>5 zP~(VGyo+2807v=Zghv|i88{)YNhA|0RRh=&qTMhq3&qd>e>J}3|Hwdc`Q%;VZz3M) zK1!)9H(5COHSkU_7*tg{OaMNd-`d8)$=Si#bu%s(J4c62&Q1mf2B>=$*q88^CrAL| z_@ws}0hC#M#tZ?l+PuufdC}L4rG)(edjT>7CWpeQj+c{R0c=||P9N?$ zIXo~wG4k~8wRdlRf2S~f$@V!)=Km@DG5z1X{`rrmXYb9m_0?qVFU+BD% z-)4J1+f81ZTznk80_}YR?L2*LJ-r;Z``P>Z*?M|!@ekhWy~EbdS%_1Hw|?y0F4{O# zj;X3a*c;S?Oz??Nme7WsL8e8YTJrXVG8USODjKklmX}KaoCoc!R;*eo`dEv6TQo5) zX^|p_MW+n9!ruer5icBZN}=0vh%-z|bl3)3+Bzhch@?Ly*BAVYErJq-5wQR;g3 zFv5YOe1;RTtCfTnUMZK*eIL^W7YKkjQ631Q57-wvmo`114_iVs=NC|<{50eDB2pgn6=LHory_Bdi!;paRl&XrU{dXIvARKL{wz@NocFUSGTxfSxr zjpB|WB*h(Dyoi9Q7)?e;2K99SU)lmPy64D<9S1vGdm44y(0#+q%F@W#_*3jl;M0|n zX$vy3Uuu6*$WJMsmeyJ|HSQnW4bHWIeR0E;2iX@mYSERoIOIi!RHW^#Wzt7(dP`<(#qQ8#udO8fFf9~~5By>EIP(eQLHK@yR@5YFP9)VR2?-pP!dRj4q5atY94T89 zKp@RurVuDJ2Ar~lY{euO1#pb-6y-mhgMEY*QId~(U*tlwJ|+JP_e7q^`zfgr#Z-tj zu1<{5BM8Y+aqshyh$Eo)t)TC;)3vrVG&3=R%^MmSiuR1U)Nyb@@+eMN3j7uFFZy$G zCx}d{Y4CAZ;-5hH@x=>AAD>ita6&gBaYKjztFDosN1-As@o#Ej`iaS6Ld(k|^F$=} z*_;M!+K*F*AOMsY*jX?+6!<$OB!wpDM&}gm&d%DEmK>Iu5|y8^r#vUAHb1>}UqNee zA@x4(`-*z%YKA*Ij*T9qw#y7S$;cJaq2_usvH zLw3Ia{$Ik|FW28h0mL~`KPmzKc>VVGx4*ym{mI<*vAi=K@nenoBL|v~?5CG+9XULy z{ywp8PU!u;-tOtaf%&03i^6y2glwnmmzm&92WHMMmOh-H!~+R`Vegw7pzhOrHa8@P z?$3xWkJ&-xZ<3b>ZcP4QZd7zxdRAFhUQt?JK}un4RN6N8&`tK+o!!DB_Te>j=A;zv3y)9r3*PPN6}ZWAqlK|4mXxNLNiFWP6tlExQdpKQfilU+as7cm zx;YV=VOt6At-4{EuC0om1$7%>Ur7lO?tKvwUy{v(>s;jQqjE$}Ej~lO zb|LabWanQziG6??1N%y)fEMi{`HE@0FQ#hJl9x7p8X7o!;QV-jz%sj9qL?FlSZ-#H zEGYy)w^VlWpQHqk&q(ZJV^XUtvCrob@K?%S*n1*spcK|&+RIoT0EF2vSV*|v72mrs z;o_$(Z8VkUtW`Rign0od2z83p^`0h>okNd>%0aspyfR0<2~f+&zW zoezV9kt0va55@~vlK%sC>>WfCRWSqykqKDJ+)plttCJEB?6Veb*QfVH3P$b^H&Fh4 zPPoIoHJ=UUPa+dlgv>Rhai`j*qcby9pMpIg&nyN? z_~iooRP^&C|3qdNcSU$WHPzvV-1{$OlYxJIfdiI1EKM82jrfT-sH(9K*@0M7oB(sF zm6Tl}hN?@&B#+E!pxHQeT+Cf!Y6BCTX)8*tXGo}jVrpo5URZWvbauh++@gfCs_e#= zimr~9vHtFfzTUC!?unk>nc?B%IL|9pq%e_@f~`=7u6;zvpT-@SkH?(J{yetGor!OU;hdmo=}xH?fk-P6|J zSi_jG^0=72KJH0gTaw&enEXX?Um6*|+dWhKwy~0ZJQB8TC0*GD8j>FsnHL$A6BV5ozc)Q0D<+cZpz+(bMFoeZ z<`gixV1Hgobzx0iMRV)Ex`yYza6`r95C?BG}ddZqBxBPDNC0j>}l7`P+Bs{ z#G)I6h8AjSop(^OIwJqW02mk*=?@0Z5X`cGyrvv(uc7taXr%71g_cH=z6K{jCoC{1(an)_K8$2CoXdp-0G|9SLPHe&$r1p53$;pv;zi%$CkOlZ%A|x`u>H9w zQV2*fC?&(f9h2|Ek$2=RuqyGlt=f<4j47@~rm#fJg=*fOMOux~__D9#ennHAtm zbq~xrK>|p?AXGr>9OIJ34=S`rNUpbCXAo4Rjwp+?*IM${=fbb>+iqbAr}68_xk;-XRjX4 zJw4HIXSC|pOxN6K-_b+ueYItWO7lu%BXUCg^27YH0=A|4xo7S0%?|RYA~Sh!cui77 zMObm3f!UEU#VNUYDTR9?QzOFnW@c41G&t*0h8W7C+Bfc(^WO&jM$Dmse)7IpL$cqc=Ecfp~|lECN4 zxu%)`K9HA<_oW+0_#QtloDzo2l+@8fBJrstofp-=3KL)_OVk7ZPtWC#a-XyRB^>xD zAAqm4@=$VmMP3}Vf&DKbPb`nlKMQQ1&545@;1g9B!8Ih2GKNHKXa(a^^>YsPMO+Ud zfQ?Vqj}i*xM3@OmXddK(bYvw9;0x?4N}qS6rTo=m(L>vIAMK?eK8$m z<#Gh9aFUZ1$Nv4TLKqS6<5n!(4NiE5+ro(y1)MCvpSpVN4*0(wU6UaphGRHO(b$-7N!0dZ(tDQ!#yVdg8?7=!vOuuz!AT?(+Qn zrMX%BekaF|oSGcFICuQc<@1kkU-{|D-QRwE^!v}x{`lp`SHFH-FJHX*`{ofuFQ;hhz@EzQ@9aXi^O0vYN@7odV&fpsan%l1ST zM1>W{MpvgMGheJ|cT_=iWN}hjRY6rnNkdUVb$)JnZB6r`9!74Abq|ho4-Fse?W=8R z&nzg7iBEQNa8_NdvK$909htuU7R7?UPD@A3OE5GxAPpWK4qpa|NC3VjBmf#&Xli0H zUw!r6%5}@vZNSGzRwoFc11I@&;2puM1fz&h(U((ywUzrO_wCzUooLbhHI8h-#FsK; z0)IDO8DB0og~obyS^<1e`m0rVBSz&iI1=ES8qoclKEVIek&E^R`(g-}m>~rvVB$P+ zX~4?Xm3vzPTyAf9WHWOj&)Mp7xAS6Q?<+U~DxAoCex4_zUSc2MFJK?_iW$RxmD-#{ zb}iCb6h9sXEx=jP?84oL>gQZo1Q=1=AH^TIAQRC0k`lmdWfcJINR&D#?mO58?!*P8 zOR$4|v3MT5D}+S03gLz>aDL&0RO|vSA1H|o8Ks;D0>DFI0v{|Id4D)cuyewlk$sKC zZs3x!pOhiOL`V=wWGzAOY1Dw(#lrp)v(G+(zlEV0OYncEeyI289slFA~PQ;a^L!3x$PmL_|QYNL(T)_jPV>eHX zT$t*+K0El}%#rIy4?LJZ`1IEB^E=}|+&J>+eD}lC?GNWW?w#&h{Klj)Mme4-AbCk5Ba-8SCgDYU${%tZ&LLEZwm)42~pprI^$P zXZ{+G3ZTXLj4snP&@(e*PJ#g{6vsYy6)!n8=RgwqDFnr$MIv^uWxPtqbgl4NlejBF z`7AaG$8~F%`M7q)nsrN6G{0S~K@QxKMc)#OBj+BNvvcV4V_|GzLbpv~vjQ+o(@_&6 zr`D?RE%T*Iv4F9^pz-C2qydr=u>ByM9K}A=GlBuqEtZN=9K^KK5tZzs!zTnlw4qz5 zVq=Gc`h}w+C{TpT0vphN<$-Su>`T;hMEj%nF{lAPw@B!ELU?RGW!#|RzGJE=z3PP> zt7l@UXG~;YoBW*hG%Uoytw(mBsKgNjKymSLT(<#Vn5M95Md`6vvH(ypUJMO|bxZhv zAo)shAD={05rlwb0=x!AFZ~ko^}wHBhq^$dv0%7(fG^w_3jDbhAe{@B@aL5*DFnpx z2mzv~qSF~c&F=*2)it>J^xWodE2h1Sq>GWq@)=GL0(9?ZaUv~oT@AFq(D?c~T6h8t zFc+BHVQ!+SvEIx;lLY90eMPr4(Ku9Tmi9Sc3#^AqMZS9W07q23u=EA$h3iQy(Fss2 zkr26l1NVy!jOY2EN;)VJB1}=D62M^ayv+|zM%r2oY9`26h5xf91P&dpvvee&9w)3-04XB_9VhxdMX^x)SY zfBfUumoI<$`RC_Pe|q}h#lsuV?p}O+?eyLAGq+Ap+&y#j{`tv==g04#9lk$5aQj5} z?UOwZE{wdmJNxQ~^S^yR_xt17SI;l~@#D2OKVSdz<@G;bTzL2V+`AW-{(O1s{jWEE zdU*2wrQx#^t;Y{nPwp>1Qk&abn%-HscYn^FhP0^Kz0nmSLJ?b+y0<1diNvH@ssotZ zm7U*MRN7MA)Yj0++>hQ~suQQi#%GR(l`@85jqxo6{(BBAzOg0A{MYEAqHNr=m<3&`|H+&dQ|xWuj9l>_XGSFv_B`( z4}kZNzaz2FQ5hu7JXt*m1O8-42blzH1|izS=4b1F2zbdoFC~E3?U)}__469VK$b9J zD+&ZDMRrmGfH(*Zp?QE0)d%KcS^xx>rqZO-DYKEk%t=oskY!~^C`IsETAef-D`=jMZb zx#V}sYxoxMzag}FhLjs_4@A-scMX&MoP3-D!;ACMdOG%-`Xzt0V%3#3giXw@jk&NSZE6DdM=%$GB&4t5Eq7y5=e#!5St(w2^$ro0!s=G zfGF6YK}Dj{E=lMuQEbi^xYf-mJtMBXx}dtTw63Xqe@kU&Yfb;b=Fy(c+0o$(Cy!s5 zpSyN;{`!UU_ikK&_UPfupI*HF?e{-k{{HjxAL-%w==QY-*DpN2dEv(gSDxQL|LF3u zTPKDtAML$5-FsuE`_}ZqTgN*eT^M?CXZDXDuDt)_(cf>MzWwFKn_us||NY^gzd!i< z57zy^Up@N!^^^C%Kl=6Qh39vVKDab^<#^}W(U!Ts+L_LhvBu29Wl4vM5<2qY59G!- zWyOR2lDIvk331iwX-!4No%OA~?Y#rNM@DGNH9S2zF*|kaykKR z2*Fd7zA6R3>>LHc2J)+C8vx`FT3%21`cObf1D+wEBPMSO!Y}o{*qrir2?{_h*l!?` z?;B4U@CVik2bS;`WI)mQg89Swsc)CqU(ox20IWeC(Dk4UL;x;;54wRlN1^@o$StF3 zg)sT$GthgeK6*}*iQl}8LK{7fx>^SMup60!w;%x&4}hkK$|*b_#m#MnHt|NhBUBtE zF7!AJ14&a<3=nw~09R^=NO)sW#ENSMsv!9Z@=E;c65&1Ll9lOWq$^_0aFq(-;nI~2 zAU45AamRnTOBl#xO{uD`CmL@cZ=*I|R)yPt1iK<{MFOpv!UUvDkl5#y#M)SVN5}`B zq?aS+j;e;%8Uq^@Ge@T_ZeH8mwT;Y|su_K?Xqi&JBa-_F?_A?Xg zTx8Ecm{2;3b3hao5M#pQ^bz#pzx)Wv!R1SV6hj$tB;r&+OsHwDU(epci>;%M4T-gY z-;yu`f0QJsZ?NRPTZ|WW%Vy`ajJ>su<&7esFpA;l=5jb0g;`4$Tkm zzkIao!TIr@?w$VqhwJZudjP=ye)Ig#S5N+W_4L2qy!g-S7k|Hg&NKgc^X%_8kKeq! z{l|;TuYNrL>W6bb-JOLqT$(&^;&9Ex{=&h!jK1o$p7Qk0eQC`(d#h5DYUuY{ys!KJ ztL{DEw5qQ4{|gMgNN0Ly3cb!S^xliT*C;3f6f4+`Es71rioGK$YE0B<)L4@kdqWhZ zCb_xyCb#$U`+uLc-uKMw3^Q}~0nO)s+#b%H_mqA1Ue9WK?X}lj`@s5pHaz&)Ll11c z>+VNxyy?!h>+ZPq&UZ;j{)`(R$v+l>zx z8q!z*DNGrTpyc*-TqU z(2C^!kYJLF1k}SZG2}t6EN=6*N!(lNPS^1Dr{)u-OKMR7{9{@s7>?m}c9j6&GsN$6 z;!NS!$GV>5UmF1*wn$qbNeK+Zj;=;b<7P4K-8&`H?KyCO!-P@5hz1eB&FXiry8&NI zqdNAv9_f#Tj(W&=4s#?mQ(*Vn?#8Qbzv-I$Z@cN?J8ymT?mHg6dp$G#AHVnRC+@$0(?btFO*)K6 zAA0h^dmp~-ru%QW`u^*#yzkn}o_+XE;Q!W(o8EqL)9XLm@W#&``OPn$`snSSZ~f%$ zU0Xl+{WdTT(m$d6Zri6S-?0DeciTSM_4WI^zkUZbVCR;%cYg5(iovJ9`RUuwJ@E45 zw>m?p?F$t{<|G`HedhDJ%A6Rqs zy4B}iw)*_bFS-2cHP_#`_U2ozy7sywjyaZiXZ-5s(4v1Kc5UdvG$Zl_S%U$KID>#O z^M{NWHoC61rml9>m{Cjy$5X<@E+R}?G0V<2G%K9yFkzg2#PiT!Dl%5htST&HJ{vQ1 zQ3hcph$(l#@GC?LZp0zTnI_9wQ*bczuW$XefgK1!2CRy`5C8A z7d;Mtr`zZuTn`6ew2CiAphEd_dudfF`SYdonakhYs-d8emWUr}RbfqiX)dOe-iUfbwZ2r~vjumv?U8v2(i)OweR0;Ny-vX6+4Y z?pc5Hee2gfboZ?rAH3^{2k+i^?;Vfaelt&jqKNwX!ns@);@as+9&T`_uM1v z-~8D|+*w!p`|6XO+dlu@_RoR&?rop#+Wz_O9h-l*W3!3- zkAAo9qupPBxa;e8cWwRkjxXQ(X7ew<{`94wV_dT-qhC430Xw8Keuesu?wQH_l zx9Z#r=Fgwszr37|rDec-C&j60mNdjoT5QtFv1AlB9pVORgkk|cNuEi8RXbs9?f9{^ z<7&$*N|?`OQ@MN7L{WpcY260hp6+1bNg$6ipWGNs040NM53PX5XdSLTR;x1XW29nz zqB}F!){-$21V|w~j{+;;Ik0yS9U<4jix1!N?)dd%E`t?NpfQde`&=It9^%x9IpAEv zu9VMR1|!C!dE7u78YZzxQh04hU;c2^fwbJ$F@6v;ei8Z+hoqrgvb&OR9zV%_n5Q!Y z4$$pU_{*_cP(5*u78e8j+#+T6^QZui2GsR7(ueA03{(L*4&fB8nPP`Zih>K|3EHt? zeF=RNaO@RbY?E9(p4rdHOfVlHCPPZ@gD`XP8H+QWPm}v#1Y}$3#2_NG_xON_&7y$O z_-;={?MVxB3^%ZYK>$1*L?_kDf1<&;z=r@Vu4cF|);WS{7z4=QRKd6bBS$Jy^3zMA zOY(!hj-|wJqY6q}7v$M<28Ep=0eZ=Uy(1#@1Awo4J9i}d5gQ)(6ZtWO^*l!m9Zc|H z%}DZ^4klYDOE^)>VFTa^F8Z+_P_gJ=+5tZh5AkW-`~e?;agv4L2;%%Nz2x4z*FSjA z`p55Izv=!vpS)-NW9x6*aNErrZe8~%<(73DZ@=xC2kv_LsfT|3izhyO>-o(ey!rL! z4|aV0#jb5zc5nM~*LKGHw(Qu>pP%pg<})ulw{6~qlK7KhuJ$T=`b$4IAX6+@HTsn8oJS<2X(M?HtdAa1{ZBJio zMA)=S_Iy6F40=W>s~T86bmZ`nb+ycutD7{TW^B!XK~+T0fqlS?=I&!COy{96t6s96 zBsJyLBWr4pI%whSxeJS`N0WOMmI}m*^H2=53I!1=c>QobY3PZBH@p+Swy_@1eT9pU zd03h^WI`NqLl#>07M{&$zJmGyJ9~PMYlLXCDE&$<*33=Q@J&u}JJhH#!2#xdW6z^l zz7@683tnP~syM%Z>8en^LVm>p)IR(hsloCGBKNy>p_RZaP<3jLP$$rR7h@5rUd%3WIRo`&{T!_C>4l)93{LIO~VU~ z}pGd^sGhA)nv#=Zvo>G_BT{290d8bCe`d}e#eiNVJ*4}u6lCN>iJJrLZF9W#2u*fEpFqr?uuYdr+iqk2?9 zXDIxHR-$pD^wQ3Z0PzHB1^y9{l9I6fRB2C|w^=i0tR_?LZR;Ms|DLBdJp9Zf4?pwJ zgHPRm@1}e2+H~)F%2W5<_1uR0-+u8a#`V7b{I@%{ezNnMExWdTxqJIpySH!qJ;6Ua zw(Z^_KCo*WOkgu=z|Jq<-u=ZZyEnf~*}3@_l-*li{{5Dhc7OKlu1}u)-6v1}{?niC z;`|qH@7nU4?Vr8%)w?fz{Q8r>e&ONQescfIn;v{&(_=3@{nYbM1Adm{c;tc$E}B1o zLI3{!31jHeu@fAh`tu?5yl-%Rw;!PmJ{ie^CW+XF0&(tn=I0SLqsC2{GFQu# zxu_VcCUYeejE33`m!WdKqX2l$6^IyV24{d-o5QTi2@jm69eO&zR>R&$B)LqHSONZ) zsKJ#u_7q$JTtG1|pKkPPa5DQtIAFn0=v>1?$dm#?&9%qz!Ev=uNB z_8I!@u^(o>q&b6k3eDAEy~1*E=v7rReuqMVMb8DPV#&BLQo%lv5^1GX8M@#AT#pWb zst?|IPNW9#3LLGxOM1Qq5h0RjD)b|`W@imfYnT*91f54nrz>g1Ow>E%)x|u=hBBq| z8}{{4#@x7uNsxRv6LT3Hr$J~OwU3!sv@p#`Ul=2ml=lOgox-t0TMV{pfZGL}@yo3J zonuJ*Le?YwIq(bELp)ej5F}tnl(0nyC^eA}-v{rAH6U-F%^9tSK8%9fQCY~ySdd#t zVia6|h%=N(NR%XIIH?8=6ZR+0oHk*`)Y0SXSk@czMh;L|4;Y66@XsyKlm`?fi-3{~ z2>%1{2QSV63_I;RVGg$Mh>=)WR5Z4(?#ROryYkXY@45XphW=lEdeiIAKlS#@Prv*6 za~j`&>%~vreQoRJ_ji7SO25_1?j2hxyLN2dx&12wes+BG<<4)u*#6Z=yEec2`!6W3 z{eH{qyT5#M*OzbZ{_5@BTVM!p?B4w9?#-|4`r@_ipZ#*{d(UltAr(^jlJ_<#fPZQuct>)xiIs`B;;e28Non$|d%sRGb5 zgoMy{;L{+e`bwleob~KRG9`1uw5c`Y$ANu9Hp%8>vr2n2feu^DyPkk9-Uzke-39~% z@8ct6oDSWA_(?1^#^}-f0Y19DOp7%3C7rsG^p2b`%=_ynlNV7)a^0drBzsEYloJrn z$_^T*qhMDuTT^bnu?LbNssavf+ih0A>!2i3?FFf}!e?5%Bh2l5(N0qMwnhq>Tf zB{d9Y%WBIEtYz$V9nWT}Ck#sjrNwdni%=402g6b_|2 z&^HA@2|A!?FNl6*x*XD)lgoi-<&%<&B3^-;!LVPz6VMP!ONe*O$!9@gCfjNy5h?tP z>Gx&@atuw}`vSGYoIO|u;K+9ewd0y&ibI}X{eX+b*lmD7$EM9fv}pP$2e>M6t)S|_ z==e;@eFj_#;MCu08DbQ?ox!y$0NCj?qqj2y{Q%h@FCDc5AX|0LuE?xC1ELnWjrI*}#z4_V4?{D4m z**9N(y8UaSd_Uj5^`o8Ne7t-6XN>OcM8tpf8*}mD<@<1_hWS3;_0@;lzj$Zsr*D1! z-Y?#IY2!~f-0{$@Yc5}P>Uk@d9J`<`;!vxNdxse0;T`Q`Yc*T59yr86mLS{fZaA%SOXs(F-dd2b&VX`75 zdi20}ud0NW5LRk4M@ks(Nym_otqNzqhVN}&TZ_y5jCw7x3z7@)tZUc zqo>w{A2f)mPKO+H;K~)t&R)6vrt8-{`_$tvz3|M-FFpJEFMs~Vt1rFw@=soU;prED z_S8?Ger(gmhc-TR?*r>^x&8VzH?O(u%8OPnIsTZ#4_ri+GbV<1*PuKz6qKNxMUl1S z6Gk{|paU3+Ho$HFSZ6y2V4s3N8~{$mpTw~uDJ<|CDdY5s0qc=GgNF_sJdDX%!@>Tr zk=nxn&<8Z4ou99c>JPV1W1p2bnYk^kFNJ+Xg9c@Y#Wg`pkE7DzIK|PQPnz7~Jk)fQ zUj+mZ3|N#WQbYT~I4H0%M)sXSDz(FoKZWF z9p(T$0={7!mX1jR4G89RX^dOs7);A9rv!0?tE55K=^F z5l4iG53C+oRn0^cSOy_S0)9Ro6@ZU-g*n5-RzQKpxU861PB;odD6G*4oe~t>*@eDq z_#A7a5_0@n0Zf_)%}O%3Tyb>aEms6J-Yhma6-Y$nO4H6l>z2yx>H%Yz7;wt_LY4(m zuMxRPlrfA4-x&jv z$6M=#@fxb?g$kS3+DsU}2M-2y@7xL6Kq&AsluQp(A@MQ`y9^pKh%#`<;K9R&vc%d@ z;6HjKMiWU7Nxlg1HG@N%UN!xQWM_Dn#y3xn=5Es|bg@Qfm}F5@ii%!QT87t|8sX3< zyCb>wDD*OXfPw$~{Oo*E&*o<{$seTxZI*9g1QM2SnO@|5k|Z+hLtXScR0m}`Jnu=g^PTbgQgD%Ab=CG zOu-MpngZCNM7v>BQb4pMI{{&(q_5|gI3L`AJda~@2BuwqTqgLNv0zzxG~@@1$Yb6b zywKL>!0F0(qQ?^SAPlM((-68T@J`8UQYHW$=c=j8eM~+5YAK9>zZDz>81yW((H%Dn zgDmhBN4oF%A}=oMsf6UMF3a^uV9n)1`&)NtM8-wGq0+|%#9+B4 ztscnP!ZofNFs^DzKl{0h1EYx-o5WX3PzcaROG6wWk;!0&0S--I!8!2#EzA!B_z<20 zAMEp|TOX*PP~-5yWCb47AAQVbQGxng8&!eSk@fT_g_shw3k6hweDX%J9Fa}*b0yi4 zBH#=93i{3Z|^9}p|p)8>kX?_n9> zojttWUAWHDIR^5)3mJi@2yqFwr{`f5+S`DyYkf`|j(zIDt5ev=Ofbt4Jx8O-7Da|{ znPCysEes{uN`nUuuNmc55(6dG0|yKu^ncJWd2-Cq^WIeGgnM!Ew-DvUBpRZqOu;sU zGK;lH&DNl?u9C&MjA=Lr zu0Z56vx8s~AVUHBuzd)F0#zUj;7Y~t&WaL@aWWKP)9%LzJJy{1x@ep7JfQqL)j9kD zJA_wl=kYr7(+JiChFS*<1oeGDC@o)BOrBLx%qwUqji9&%yyHJpc6tGWU ztGi9+GKnA6gRm3`5gQ*4Pv{=K%zz)ssc`+1`I7NJLi(sPwW7lEw07vgM<9bJ&?jMd zZbz_pCIAI;jI#{wS+YLEcgH*#&G@k5cloiyKYbU2bHX0Q4*)n=a3!C;1Dw4MY)+lP z?x@$IzAEAXmRa-B@6+Q zp~opsa)@|QorQCVCetoQ7yXc^Y<~!~azH_0AxuzNV2C~=)i}UpfI5fu6J0>lTBKrw z)@*ivXQJMKo`rDJ@?Bx3N?ne|MV$c)<3AW^^dN<<^qzGl<~^QPB=|~(WJzZV`cdtb zztZ%3!Zz>^XndAF1&J<>CEr0R%p27X+Z`ZV1Pnl?^TuRiW3!}M!(t$Lm-q%Y32}H@ zT~5Xc1_=h5lCVkrleOihAHHvXcVg`)l7 zi#@Tih)a+@!3{eQ4LS+Hs6P=vm1jZnG3Gz1Wp>h`C!kTOJQ=S~x zTE zM^J+t_}RD#(GM)K5735A4EX#+u(OIy(ziVvFee*TEfVfXa22>WGmISUwx@Aq08%uL z!{pcY4A{c_>2LH+!lm$Ck>=A&4jN(~h()X*^$Fq$eVupFJIcU^QA0~ApB{}P&!=la z)@ZhlU>;6c<=dplIgl=N4ZPfpCTUIl$-QzK*cggm&jo}|scV=Q%7i<_0ECTg+pmwX zU&4>zgT)7!w9NtPtKJ6~eWPN)~cMGcmScXK?UFzv_TR zibz9&Z40SUm{KD0W{;zs1JI)BCGxBym(|F&gaH^t??RJi(BEV(3lLK=WoU8kjjZRG zhEqSn)vY&Cp}CA_0wP9f4f~ob?6RBp!iD&13Rhyb^HLMcl8oE}7eaWuw=&C`_8g$FXO1~ZZSK+Zx* z5Ila$mM2ezBKhHI%=A?5Y{ubaW-4lw(RchrWK&=wyfkW+6z7*JF0L;Ak0hmEkP9|g zXA^T$-K0PfY6{I;sV=xbSs}%&`qg z<0F)-ijz7p>s6Y0dUPI2)AcY7Q0USevV=G}pNn=W)HAe$y@$vKcqsE=pN9+YfSS$` zWYT+qg<1nB6_cl_IApp|MOn4%!2V1reB$=@Y!0HSc?bd15>U4^r_p^q<|%^5!aVqP zx70W=?28l9Uj$}JN`Q8TmzCSB4H0gH!E+kkK=Y}SHCtEl(kT46uDsCxUTAv?41wS! zXA8M~eU%|irl8P10Gt-HrH4q#se%wr`#R8nZ0h(h5<&iDtJo- z4dB3)TnMKEvW!2Wuhj={Kv`%i2zV7mt>XHFi_jA$xIrwefNwK~pf?)I^j_+~D=Z^A zQd<+X|hzdM@a60CH@KP1DMO+;Oif}c4Kq)*F?q|pajGLLRriM)y z!Nw`DK(#!Qf=)rs8PII7tVmj05e6F~fCw4TOaf1uU;Cb{^T=X(vPFB)N@Ue@-HPUy zip2Kn$))f73rMZBu-J&|5isq-o+p!jQyo3FV+- zQJ@f~6YlYX0J8I%PrjgNmIAK!P+o zg%N9;>Zd)KN`A(Rv*SHj{1SmTpY05D$Qgr+2D;7hH6D2A;`@ysm#6KD8IYKHMf zPI5*!O8w9=?UTC88cilB|3TXVmlBOqXiAUoL}J=#ssv>!fh$4{X~pV1ojS{Yadm*6 zHC~M}UELv125u<5WAWQuqa&0QXb*e$5OJn3}yD z-t;<&V@x(5sWAafJ&}M8Tc%_Z0t@g}(Be@~s5LpV+2irWbbw$m21!Oi=}4eHcjNqF z?LtH<-b?WotD88CE0D5lL^o)dsxBKfp&ir|wnrO*mWVe2-BOHGDlDx{%SXK+)l3d0 zm?DXhQd+T2()b10iWxH_l;v`SeSoiCmOqvE8NX87tMaC9$(S`UhcwgZ2v)xvu;ip> z)g7(2A<${n8VbioSI}olB0Hf9-HVl7jAPO~#JvKl|$ik}ir$ns?+n9ie-)LTXpC&BxE7ypp`vwzEFI zn05E={`ugYf|RF#dJlTVJRDs!`n>bb+wkb4Z@u-_yYIgH>Z`Bbx&F=*jz0mt&{|H^ z?My&!14Z&$Q6H0=MdaouVG&w4SyL){(OlAYtblq{0&fSZtq<3?cN5Wx?!;SsualN6 zgbUOrR`daOi&#+l0^MSN@^(46h$U90AjK(}h_sayXdcNyR8f1V#VRO1#W$=X(0s<<3Ff)({IZH~U6(z^#8YF*Q_4^J0$LEB)>AWt1Q<2JVf_1b2ELC8^c zLqRq01AuCT$krI%QYr9elnq3rCLGiNMWviQ_fPd)nRqeqMw&i#C^ zI+RbxX(Q*GRJ(}7!zuKWH4DG_#nh7uAPO~pN4Nlout8>I?nk@9G&Bd(Am5(qjUGMf z*kg}bv10l0#~)W$S4*AsH2W5wN5$kZa&2GI!ki2?ZWxU_Pyt7r#EGF0Y6triu#7FL zaRo$_;f|)JBcxndaK4QyL%S(W4LjatJ6wWCLH(E^W_Iuu`W&weDLkf4n|jhoC$3nr z;^?D~8Z~Mp&2BU=dzOGIdW2eW2VbwEVM*8q2P$cza@LrVYbjhqAx4Mki@8fhei3f8 zdpY3ADS8&6@*EYN(es5GS=%<%l`avJR$e14^lDcTq)@Lh8Ap959v*V3gQ2 z0j6(=vKUR7H`lf~zMnI9&YXF3=5liW+<7C04F{e82PTOs6$y8>o1xX~jDa$E;GnuO zW2R1-GHd2c?zJ+HC(NIhDw8KoPPI&@&f~|8n?G-U{jYQ9MYqhEJ$n}0>{-;qpE6{~ zV98kn8vDAsG4t6L@PK*THfPRk%3Lm;>YdwyNGU?GK*3+L;=%c6ygC_Gij5-I>8l+|AKnZ;+#oH26-2Xp3FOU+ZIsl$A$ zhK}dW8!~i==_>TGoCfk9C=L)PLJR85>C>k@{q)oS@-P3A*+u{NfB(06^X8>XmqIl3 zrT9zRw!CmQZ83Wm|Fh?%`iG4jC;3Z-s?3=_V+I}R@CW-Y=%Ex)4_Hwu&p-dX9Xobp zzLDeK{qA>b)~qQhEzzif0Ug(n9!51uAuyFr{`;#ZfMIn_$7+_sF01Qr@CQq99*kh0V z(?9)FX0>UkufF6pLe1O;xnA)}fcbB|Y^MIZcke#__~ZFllt#*b{^x%-|E|nmk3Q-s zWSK-5c5U~b#~yu5=C3UtFFx@k6a$1Q3>Jj|7eZ&_SLFM>Jr15@k3ANNuzmY>y7Hg@`JeyeKmOyt|NFn2>NQurOg_kmzhv>^zyJHc&wO3; z#~*+EaZynbGzR=%eDTF*F23dFn=$h6AtAjepdQVNI>SG&yY|`!@~fHW@DmD&WSSW# zm?6zyocZewH(by6I@e${{P(~Aede!C9V6FZq%;n1eDu*ro4Ra|=keabW!!(#x=rh* zdZF>X*Is)KEF29E?7P_xUk8=d)m5K-@=4?C8=T=qFTeaUZ461%`wf0=>Q4wp?L#&p z*c|f1>;m>E`El9`o^#bzS8*FJ4Z{9WM;-|QyLrXIQAZxtR1Nod{=^^r04zXAuqp6> zETQrxCB^T(_ud|_Z*UTO7Vir4w)p%8KQ;9y*cW)2vw#ZLu@m-SQ&;Zs{EX={ASa%{ z{@QD=-QzWTJPGy@T!?sDNj9Ra5&@s?8a8y;uYdjP_yorDVbtEw7^W9oZ~@)7$CoyB zl6SrG$}5mJ%=2&l=5Lz1jPp0IyO~y^W6+T(^b~*6-H&Z}EU3af3hXlhPeQGA>mcl3 zfBp3^4CyHC+Kw18q8W*h`616g|Gcppc|k(4kLwPTjTW}b24Mf1Yt{fdL_b6g_RVVT zh}Qkv-~KkUZp|FisyE+!b13$u#aTeFIHX)a?aInZw{G3q%!@LA@|SW~5cZEa;s|VB zL>NLFF?!??M`S*;#bX>$FlVGNbcnG76!1E}{`%`N>59wlzyE$3DhT`7$p~%_guyS- zVkI*#m_B_vH0aXg+H0=K{HgilH(q}OmJHZwB`*&Av2|nr@P|J%e{bVoVI$b=RO8eY zD}wqfdK8Ki{u6At=9?Pq(^gd2n3dTk9Xeii>19nR_R;ejAH4tm`}CA=LD;|Tw%foU zKxTj7fd@8U;pn}WUw*kPLc8mcM;?jJ$2owW=^Y$S=tWdG<{No37Bun~LFVvB+ozY# zJnPK(Pv9X~E91tE3zGZN0I4ekL6Hln?L!Ye6z5B$Yk1x2)vJSO>F~o2qm_`|&;|!b z9DaE8v^WRHA9p-*1TorKo)8#qhm%iU5=2+%#xrKj2*N(i0}O@z_8s8xaq1aeGi};5 z@mQ&YS=WSMABF}?2D9e!(YOtm!r%MlmtRH?kAJ|UsKeyRlcAINcQv>Yt@yzQA8c^4 z!Jq5a-Hh9d!6-Q;sCCDVBZiL%QuU(;CdU5lcib+HA$_6sg%@5JJ+S$MMT-_C#y<26 zS%Q7~3x*RPxnSQs&l-Dzm;pXi7GM5GU-Z+T{xrTW_oqMoons%WRB785Gd~E${$5n# z_+QE`haW2Jn`0d8cRBp9Fzg?9>~UtGv`6NfwbHQ}H+9r94GvIW8~6hoT#)%EA1Lgb z&5iU`U+wEHd`-^seMjnAdvA&Gx`+RKpE`|p<_UX&eMCMW z>d3s_=56iFZ)|W(Lfz`+eyi56zVd4P+B)`u zKifwieH7^b)vPUwbo|@nd|Kmc4EtK1 zRwXNokelE9<~NNm+vjHvJM=I_7_H=9piu1N+;$Bd+QNVJ!yo?eyKbm7_Cda5zk5)d zOf&4mViRE>TLXCy@@1_bddQ(cug<)fFfs-@GtYcS$0qk>s!&jt;8*c=(FRpAU!UR) z6UcqC?*V)$B&I66Y15|20_GqA_W543%Q~SP#-~YCLCA`c5U~v{Xx{em#~*Ld4*UF1 zuuro}?KkW*6cXPA-kZt@`}l&0J&^}E*xm>GFlP}Kl-0idJ@?$RH-kWQ{J`9z1mDJD5s;sPx&#d<5ylEB@Lh>zXwIetvv?q6&F{;=G-g5)(yjt+iEc!kgpV7+u34 zEZE1)3B^8Re8_tF`9#s}iSYks+c(i;n?Jy7O~eQT8MoYeOOT5o1N%58+u#9i{zVOb z{q)mMk390ov(7#%C`5#Z9D3-Xv=1E86{KM7A9G9^`-B{K`{Ii)8dR*QKY{Qqx7#wEgPXrT^H(&JlTSX`ZD*TDLPkg-5#=-p`wUk(_Ak5a zvdrfT6Hay|A*IsMt z>l&XoonHa2HlEq~po0%;d`(klU^2wS%9GNn)kPOw6#q+k;J2~gks-gP-m=H@#~yPG zVg-qha>m-t@qJ$ybly-%U}VZ3AHK(vDeT*Xi9~W=zCNfo3HEI+tp4%~|9IF) zUnq|#Iz!ubd;GLLo}@SLz4u{OQ3h%4yJ%`X|Fao!e5RuZTwM9oiXe~%u)#V4*P9_ zb$-LXiGE=}$Qes?3Oq++A~rhN)YmmWPnbQ~0X441)~Yq}JdLku=8VaGHJ5l!yLP9X zd~!1vH~4ASu3gL=G{c$6P?{mdv?e$JtnZhv2E_Bb+^4$;MQ-qlJ^sn{VBg-0)-Jc| zhDXEV`I(cab{6&((;tHUYiKF%L+<0hBCqHkYq-agqeqWU^-`-=j1KJanmwMZ$3CCk zrVVog_juVJPvS8qw%v)Nyu3Wf)^P08!q&*`G5`1Yil$D2eYuik0kng^ z(g;D09mhUttswHIJ~Q(?^Sq!7!@e|)5+gsIL#>2nacj_5%B`fwman%~v(^SAzDbt-DqT zq0IcL`C|+sS_x()J0&ZNBq4F;cSO(3#6C|rbwz+oLHB0#hk$K>?^A*H2KysNj*O#` z!r3NHoCqaDmbjo{H5`P?{ce)`vKM4w#mBze`v`rhvci68)RHY8kjIUla_paQ!U-*2 zA6+2qBL-#fi@ifC(N8TN5FRGj!*JTPCOb#WAyj{CB=^HN~a!?0gb zQK5D+Mt4w%1F8Y`NtY2-CeA?$`_{k4%JU%Oel*g)&TpfR;`MDYVlz6=bHflQ-CdRhVq>F$?32mUNm6zMJb&>iQJd35A18qx&yP)0^~lrw@BK+AM<0q!jarJ zFH|z@>$Q|H>>qL{#B7SFjH6KOYkc43etQN)dPj}l;sO0Dw`NurH9p{g16sU3x**c| z4TJ5-1QY!f=ODs995&S6Z-9M#?{VJf*Pv{xoo(s_)9B*g$Y==i9^fOtC~%Ko{pwfo zZ@(#}^TV)YrvzdD^Upu$E&zzoC&`0P{D&1FPlK>ecnp62m|B)1h}>JA)z-1k>k?oe z=;ETJ&1t$oxz8A%`9?c-EDe$Svb#-{1%ss4iQh+H-;ir^KP&5k*i#;OMM~}?_H7Hr zKCPrYUZ&-Q>iojK*+)1=g6w_6eoDzX;J{$)o6}6wVG?0qOoygQCiiJB%dD3bihWos z#7r`XAnY^Q5MABUdI|fqbI|yau&;$Ttwuuob8u>ah1 z&&7emU3cB(UTdTR&BYX?y~4h9{!r|vC-Srp)A>m-l*WFWQ0z->hi`}~lgNGUGLp^; z#Xd}q=B2>o6JQ^za;IpJy)W!rjoBr~emk(ANawd!jwy+pVx{vNh!nqQ(*VPdeoY$taA+RWcJ-&s^zx><7wyun(NcY7(c~ zOP4N{>MQ%T4R)x9nkSI^PSx!93i}~CKV#exeiLF}kVt}ktU@;K4adGshnHgn?1#mu zM{+;Z-e=rO-)W345%yDdcOvYkO;^$`|!^F4fIsx{@?0`d7F!lwb#Mn=#!bpgH?0v{O(AQU0 zRi!pElb`6m_*lT+H@jN{<&Z}L?CZ70bb_((V|-vgncPQ)V()k9N@n2r-wXB~y!O4p z*f+UvaRtUVl3-uyu35uDiH>piA&BYiQ0(Knk2Ca)Z2QzaS-#l9u` zvIr2ENFtqI!`AH;+Y>(mv%0!Ejs4cazCP|u+w7r!{=LP1N7wli`1&li#~O-^J@JE} zYRA;NdxB36_4P&A$IX}k`|>a*!+zRuPJ;bq%jH+;DD1Q9LJ0P+-fQfeyFj`MI)9*_ z-{yLNeS8$CD=7bl{a|~aP_8(i{N|f);@O85aX*o600@(n5oIX>_L2K0k;1T#``7&Z zKwsELl*bQ}Cl0?=I>A9w>79GR^qaHxo`RgvuTpp`<4zW9Q&UGAM;Nt zK{4q`VFLV#HXJJVQ9t5*GJ_iE+8Wp+S#G)zmLHm@7dr(dR@ldM2$B0>A8P|=CgUk6 zTCC_5(@nwGop|Dj7O5(d{)=EAiy_$FH=SSHHi@rKa-TM4W9WIymbgRSr=Nbh+_?(r zZMFaY`^O;+zeYNL3WJIL{E4vt+Upoq5E6z)Lb=}#x!1VJ^xK7NL9>}OG7 z^HGG!eH-IT`6xU!aT@z!IzM@t;?$XuI6~RMKDi*24%OD12Kb5OepeujKnlhFRX@JU zvCn(q0Pv9bSvoUQl;8)8PtqFSXG@I_CYSqYv%%O`8amhc6Z!h&nNg@KTYPaqe7j(8 zTR8TWct_r#gkyY${nmjoy-3@E_?4vC*SBBiZY;3e0HMwN3HG4}J{jQ4McFzG`>8QL ziwR69_tV%nlfOIIr}2ZZA5#%UX_SY*b0=Ug?89jAEVAZwdvbS#&EvyK2yJM?MhnT; zN9Z+lCG7K`nfybC3_&4jrh_tnBEbUdF+tVA*!S2Tsr||2K6DbZslCo5oddUcZ#0}K zdp~r1{}_}}3k?wVD=I3ObDG&2%^cIDMA*_$q1Xon^eol>zOj$)jWmJH?G5(3FfS&+ z-oN^)t5UY0=t7gk!sWjF{K7$2RuZ|d02^D4$V5NBKAsbV{bpz&^QUXCyB4Q0etoTn zrG=`=8p5c8T#KRe_r;*nst(d2zC1eZ)YHJeI~k(1KSB8=(ELkFOA}#VLZALkpz}*E zm`)go{X-1T2(zULWarFDK`AM!|wedg}6tWRnY2T1h0 zz&^{wpz!141M}tNZ;U7gLHo8^054-EsLoY>06|S=mKG1Ic{48r3#5| z2m97sdxd>s5%Ka_Q64;+Zl7bH5Sqb*2Q#z=-qH5uSTyXr2OtUdv63wB?T{fu;#1>+ z2OJ0xKs}#~&Jn?X^r+DY^!U$-pTvfqs>i-!nUlzUx>y7qjQs{We^~Ag76g~_jTVd^ zYz1yhfKw3sgBmK0{gnI-#{QJ4iLsAnh4Sod4nB|!`$$g)$|G#HcmVd@E3$Xkr(2Tf z{Cq63&vgFoO5M}78!Y#`z&`nBmcj|?pSxGVoj#7 z-(JaFiOeK*VVp3|2JO(|pK0vxh1?faXbaQ%HJ2w-?kB`PL484M2<{W?+b}^A?1OX^ zVCWx~@anW@9T<$Z=57h*iqvVqvmpP$Y376%~yJ*dqQ0&7)+)2Vdeg;dDq7>xi zcV-enXJOx$TIN9TH@_cl1QJ&4*s&ufGii~S{eq0~ed-%7_dV^05p^Q$D)|_3Z=fTXWG%)IZ3)(imR~`{wIo31aMMv5f5(3NzY=EG#*78i|N$8OE={y>W#{DCl0i>&#(+^glX_$gn z>pp#Y!+7HdMYq^cX}K>g0}g<7*y1gj7cjDr82gdj=hYks>ijDd+tV438F78ztIkhV z&GFR^@(9H~Uy8^>@X6Tk(v27}GotrB_V?d^5x_$319sqVV|*Is6XwFP&p_LpIdgEB z#}_>)^JDAkz`o}zAnrO7`!f7-Mwon*S1T*4xTyHnTW%g z?t^_W1n`}wg|0J&+>fvi)9y&#FBU;cCAUbyA2o(4oaEvE;~)RH_c}lt`%*VxF~QiM zGKD76*1Glgs`H!NCrf8H!9Rds?Gw3gIzI%P1pC;(s&*H-`hlSl{yxS&RKbinNDz1l z`$Y7iXyfD8?19e6lu(^N6oXV?<71DZL; zkg~Ee<{-qJp4?Qez`j6a8wcMX_76UUZ>h(Apw55vF-I%zghwDD80d#JQaW~^d0>vF zhA=!OH#J*PQ4vE_d#M8$_S-}T>|X-=@@>%jVRC<&YEq)i$xPN4HU_5nWhPuKFGeU5!rC{qm$`#AS-@k!!$(?mXI@}LiV zcXA(zzir#L3FF7pJ~H+#A-MyeK@A-Kj(YTg#=uX@v{n!{e1QD?FTC(Vf`I@6HsBm$0`_Tqr zPjVRv{^;2fxf)wjCb@R|7W>G0rjn8ToFxO0*GK_+6NLurLR^js#AH@O?da6GysW%2 z1vYgC-smPkZEY=7+SFx@&!c#x=-IFz9MhZ1^(Ao@=Icw@`*f+M#)SI$4f{4;o|Q!~ zM&s{l>P${fjyDw1T=7@&<7w^`HGZR(+AlOmcfGGK5%$fokp%mequW)=pu9c8J~6$m zTQdcobs?5ckSB6Eh)Dse*W(f z`!F0dLs}^r_8B39qUA#l(fKux&jb_5<-Jj{ny50WPkM_^x_)9(npkZW!+uzg)G8_HhC6aa5CGVl7&R!fzAlcq!kvZ?PW{6$$_Ws7n?vrfXN z#$x1X;Lp;KJiYKLD3i{Dt_c8$-qPa1C!c&G@Tz}hEB__1uYL_3lMcw>tCL+yRb(~BaDAsOW7_xbz0 z)Wx@3XTBGx%?E{AoC$L&&R!%%Z7RBjrBV4%ouBu1Vp^?4F&eQVxcL5kZtv5%@4x>( zl3u=IrtyNJZe39Rsr`3~eJ3i^0Ah!TBc_FEI$q3(p7fmd9ZEvh;$*rpMCFCFR1w9t zctEr^^ys|Zupb=TBMh--1fo3mb(JLu3u4r#HfnHMT+B_W4lBxFp!0N)uT_1!Dj8RL(A_-vJP2?`tlP0>wkIkJ1iiMV3CV+_21elZp*I zaS$OrI`3M#@BK0;nQAA)KF=Yl2ks+xZn(~mc+I4lJsuM#SKhyz=L_=q_W2}R7)#i1 zoAn*Z{ir6?aP19i`8I$+OfT@KB@O!_YjSnzYU;Oq+$6Gy9^T@?8*jXkviHr8l)%>~ zdKUCU?frvAT4u(ACfxolRyFeiurDpgxLqjry|z?1$jR{0M_PQ4dy`>*O1-@w?B{o7 z0|X?%zUJ_1a;So22$0Kc!{(2{K3@tQf(8gO1!qEF4Eqtr`4hlM%EJ&$Z1IyH+fNF( zq}oAwdeb_;o{0oD?91i}wfAx7#(_WU!SQ5SC%j5}40~xBocyk_PZ!|xudb>B2;#Ax z&Z1rWqQav1Ls7mSA1H=6k3a7C=DRiXR}wM^`)XSGkVCQWaDd??!#-32Nz!UFIjKmNdPATCN2H#f_hay^(V$b`wlc$0=eJObbcw{_T{GYhxz*G zvfaCPH$x2m69IBigx(_a#zF~zqD&01|456s@BIarTzoM!<(j{~w_W>!{DSzCOi}7& zwTEN>>8GBq$A0+uzTr>OmxCZb|G@_zYz)U`*h`DMP6 z8=>R`*q=Uqy0=wg?3>U}FvhnWS^|l<`-qK?*-BgngA(>rITba`W<{YUz`0RDV5Uy` z1<_@^9TX+PKI$*;Mxh$&B*zWW9nWmNZiF*99en;YCk9_0%tZ z@e3GE9DO6I7z-W3;P^^!G^&u@FFXDiv|%6QOQI1G5IwfV17^I|V?W&2m&QK-Cc(b- zs`_55UIhITCUqyglp zO)`&_HOP5`~Y(+$peDTE>F+Z8ue%09m|A_X9c^8-6fB${DPui7Cq)0#TD89Q zmRsY$m!xgk5%!V06tvKHGq>Nq`)=csaltufpW|Rs zwcE5=bxy##JlOk2lg>Kev?})Lt%Jt+o_+RN;$2(Jcu9oMA%{o{O~c=~n9$HB0rnLX zVG$%KPA#$>?+z^10RskzVVb{zJ))ceh?t#~otVP#*FT3nA+SNF=zLtEU zG2h5#AAkHYT_Tch)f$~85%%@HG~q0Kknd^2XX`&ab$(S7zm{NWE{ z-o<5W*RItI1%AOl6#GXXb+l21=wki)_3__Jw1#7!mx>%)w+@s0KU_xt(#VK@H2?VT zO<~^%60!^$apo=L?6Rgx*@Netb58tMgMIEb)*;40{Zr6y6NY`(;)E;-rEBrkNI-y( zg2A4b`JUzuwf8-DhbXgE>zOlV#>76=n?7y2^c5i6}) z-EhMVG4JBC6)RToxxAOc!OE2@=PB>vt(g9Zi7By#Knd?T%3>}!k(=a-{pJEXSKY{ z*(BJ9>$do6CTWruFU4dG_2RQ_T0au#=Oyc=65`M4pecwNB*tVNOO`Bg z(!!S&-|@x6Yev`9W4~?NBMv{J#fFM5z>-Rd(Z6bS!U-qDtg7GcetzdUkXES9f6OtO z$0vej95yQp*GkN{pLNz*f2BDpf7PQ$kN6<;KxSAxKvvQwD}2Wm*SmXnY;xo@NnBYha5>liYa0`RCKr_%>~bU&DMctIfTv zI|h6vO`1gR!T4`vGD~4Wp$lL14cWH}ABPfFLtR}RPW~VT3BbZKfdAen zYP;v2d*XL4*r$2v8gsO_4aGj6xzDiQb+51wmnMT&iyw}q3?cE!@OB$l5PXwip9jb@ z6M}uE4Xnq$vex7C4^oy|{J;hm;3C620rsVAXgsC;&>=(PBcj36g8p>uyI4u!>yzA1 zaab_`o`8=zr~*M3fAGNvN*k5h=+!o%*bjPLbTNH#)KNzPBDTH9e*9Gnset17(@tPC zo#LXRs8(?fAZF^kZ{&Vg=BlKuo&<8AYQ!<_pdYBnXz4G2eT$|rxo@#j;1Os91=_{w zl+0_+Is0s0k+L!f!D`n&HzzlKoJ{7ULXXpOUn(VhGF0cs-goue{4?URSWKaHh=2X1 zmtM;2s3;aj`}SExv0yU9zdiAlVBgnS`~MyGFTC)=eT98i$20Q|NgAf}6Out4*vM;Aopz@B5&YOxzB_$s=ZI-K6$gT4B@x*b^OKF zY4e94e%PCiMO#|z0@&=L{TBgv6aC5$mH_+a>q}$5b%4F!0Q<@jEN_2XhT&SQdFTav zDN}vnE#_X(qzU4_U;>Hlu;ky!4rkPuK;2pQ$ z-nUQhoPK=@^0G?`^NNe|@^Z8Da&wxwtMO0CDu%5gN1uF?e+ix6M3|&lR#s3Z89tw3 zk$sDOpkUa4wQ<`vb%y*5?k2@axNFz0rY?)luU#vXpUtHS2ch7TB*O_82V5h$s541_$rG_Z~UHP%RMmnv>-#03!O^wVyp}cKkU+4IUf+ z&j#2Jox`g&x!R$7w_`qusr+GMdVWYG66TC`~2V&CO{kiC!G$58+X z@z`_RV*LrF<1OeHQn=;$4$j@7@qLX03-}-_evhBK`doOMW1n;-WG#r`-=|L>CMLvx zRP&!nZeG^-OTSAJpNSq6q(5o^6$ol!e;599T-nXPH}lsB`_kmH+J>&hNgl&Ky?d4v z7gSc14IEHWRZ&(}QiM1zD=B{A`RDglL;dMbe>Z#9%)Whk0sOM!!tzo|QE6#WZf-fGqQd&d6lx8Du{gL-Xk+K^(d#R_L$z=#IA%0AKg zd-duGTQ{FHI{&MgZ)yG*ybFnfVjBj*o4=S}5qa4;{SYFWoruKk&^~ls9*^tO=wR#C z#l^+(>5vdC_zeSm5g6eBCe5Vo5Jf|rQv9bi^`%TPm@;_^ObroFkf+|2S^+_c&}n1p zFnsuM*0X5p360N_A&`;2q%pmkJaPD;VQX)*fZ$tRx(VnmI;ts5V$___`InsY(sE?<=(6aEA^VWjVkAO3^)-><2u z5%4XFz?h6)L{b+LJCMR1Zh+{A)y$taFD9W9Brs>r96CA)_AOkTHy(ai81_$IvN$)p zZ*^sPZO!n}qlS&C88K?akRgMrQ3Hw#3kve{F2DS;y#WhZdS=a<*{^T!!u&kMeRXBY z&>@w>hExw5GO)6LSwVj8(4j+`CxZsRV$cC4LJL}?KyHL_5%Uirxyp@R#KAl7ykju> zEKa0K^mf*H^t;$!am5wU`4$g|2!f1FUzX|-G!TQv!YtJExSYlG2FCOAMn-@T_eej0 zPmX?4grJ89$$i)tz~?Rs>*~fC<;Ub_S}1Gr@wx=qM^|tg4T!~wCH7u`MNFJH5m^k^ zLH-JlU3?{OY9i&I#{x+<0(j8>gW^MYI71khU3wYHgH-*rneV9AIv}Z~K$IUC#e>%3 zMYCqk+_h_0GrWtRn9h?5?MsAxng~sUHy(c2;Vn{Q<^`vmyaaKK6dqeQdi=PW$rHy; znK-s~^oYTOs;Vl=u?2E-`^}m)fu!ZG3m21G5!0qmM_872=hH9o%PNknl)|Ne;MRGI~s#a$7~ zZi(~V?)VofQDVlA8+Y@%buja0B0PCJbV7LllEq8#?1`3qK9?Ez0N)|sgQY)N0nnBJ zV>L2|znE;hc6qtEtY(GmXh5p~iiJ2=EMI|>P+f~lB@y=hd+8az-PRyDo}@#{uy32M zN5I|}Ct#2F_@on0q>o0899~qAH?X>*78p*bn>=akoLSQ-wWEd&A3A72bwzo3aY+e^ zdEty1({H==RvL;H&g`blV;YKYB^IScz!p!?ptrY zwQ#{gW}nehG>*7*dcarx&fTrU=I~-jf<91B?;}|^zJZRWy-c?zzqAWkem5kEglnI%e28}C~c2VfXyP54GW%L2|YZe zid*eczBpF^L>eN6b}SlPSy6$?4SPTT{PVA5yW$FR>@$A>bAuo~R4<+>LbBmJge=hJ zfz}55u~18@q_Iyk^XY;=EKFLD-ohM#*|TS#dFGi{Tzq^ujcf3Jr^CvT(ry!mH@Ai!Qtf zZZ~A`V8k1ja6Juz6tG0K=)CUs=>X5CO@ie9veX>jl$Ezf+H2}0l+3(NhEoZW3DPrh zZUA2TmoN1?hvw~pX#n}2J@@O?t2>1Q6aAfouz%;B>me8v24fwaK{}7>-KQr=ra}05p8Ijovqv{xq<0AeTAm}+*Vj}_Hh&&99)f|-)6vL!1HRx-T6OU}%zyDG zTPp|^z)S%1ee!W$KzKd9>DbQmKv$|$Zaudqx^@%fP0(||!hez6*CK!pf1C@lvCx&^ zo%JN`MDBZ?r*j>!f$Q<%=jS0(a>&E1$RY;l{ArSm?%k5WQarg(56ZZNLZ|fXv0rxI z-je%Os+fYQWB8|7XvRjbX;YIbiyiQH{*Z27>poh$Lu%mF z2VdxPp2GvV5w-xP!mz(=8SvwE=#4xl$miBP#WwXTN)(eip$a~bE(ZS8ITZVJIzqp9 z?;Z@YWM}uu?$;Z@qKb!NpSDJn_v{Jk_aii`U%%c3`8ha*3ku-#eX_HAbI`YM4}V49 zK0UMh^+Bw#0K=?YJ?c@dFGUR6TfL6?y_@0v^K3{-q2Hx?~?% z-M_N3bl{-M;ll?H9MFG2RoUPH{c-7y7&dV9$RWc9R}ULp#an7d4L$hag=e01>KUi6 zSb6HQQ9Q!_StdZP1?zp2V%gKkZbrx$G>?4ybUSe&kX z`t%CMKK{}U9ncbccJJD!SNEcVoPq+Fd~QWWNqIT;U|w!sU$}jKK~7O|K762WpB}k6 z=mFhX02_`0$i4^cV@)$gMsq;`N~bLB7C6iIvueY5eUOu+>7r=3Ze0GL4(n2%m2hl40Mgt~qB;Ri<^aX4e{)fHtUhYmvS&z=F~ zC(fHaZT|&x-~fx}&z?4A{ItpAXV08EWBMey0Y?o(6F`&?A2MLrU`n-f16S!sjT%ZB zGiD^h9mq3cIBFPWV9m%O2>l@gD~1fJoHcFA=_{A5I`7O?=d3*Yj1{LXKjp*|jw{H^ zv&OgnqRYI{ai~w;fYu}Q8U;jatLG9rPV)o~{3q`+>`-m#ho}o+3#bGMun%)Kx{@u) zl5L^ZXb?|8=r1=-gO^I@l=3Ojzk1c`_|IWnk6U1?y?b@<)4NAbb{{wZ;+O_{?X_RV ze-1i7)XD0aJ-c`7+q-*VK~7;II$qzx!tAoL!ioxX!JOifg37A$l9B>KwexcOat-PM zuS2(l^dEa{L;TkzyAop`AfWq!CYKtSz<11Q-^~{07DX6gn1B|j?Yyh&De_AZp}eFj z4*YIu;7iI&?wcVc?Bn*(-WY;0hyBPrkjVj@dt^Qw#^PcQx}twWu}?4$H-de>m#;n| z(9geg=_#o3h;l^w#BntU`gyaa&Yd;&z(sQpIdB1cxWW86)925bF?GuL$rI|Z)A0w6 z9Wx3hkSZgGj;4$lQagIsxN)N=O&U98^0+CJ#!ebPX55&O<7!9L!VTaF!v_r=RLLur zFF$4V>N796;Oz6xJ#*FBr=4}iilrwnhI-T{2KJ~I=qWqn{8KEKCdEBMpE=X^W~52$ zHwIX(=tkY1>SAt5-G*{u*hlRTlKUiY6!wj-crQxSV~@qnag>0VNf*$&S1%X(vTm$k z7zPa!fPJ3Ot0%zk2@;XT6u^jr8>;hj3krPip8Mry_bDvMcI*TH($a#WBKSbR;^O>@ z%Cge3A`U3IIfT*m;MHgyaN+M7`v`p^`lRriv7g4ijk}qoh8VoK$j0jdAyMkj*JD=3 zdvw0xK^prGeC?(A8|1-$3jX2=rUvYXLQ63Pz!-?pq^yQC&q2pPO98pUe%rP|a^JC! zDocS01ds8Za&k#g!Qg?FXyf2|`sDHRW=%VA;hX~&&N<|ug$EzFU=HU0^hvX4PC@QZ zo-l?2w5LuU$H9cU(G$mxW4c-tJ%81?=be4-s?)*#1s9yNdi5F0mr;izN2_;@@4bC!H*3I1l~R|9Wk-xc0C$WF z>|Rn`X8r3w^Lz|Iv@b+C?9$@=%F43-{Y%P9@d)ATMaSsDt9x`uPy5bw{;gkqg*P7Fn8Lp4{7wUz6crsu z(9<;r=Xxwlbw|p0NsWzg8TaZgll~m1uQ$A>A&-@lKCjUaFJb~_BS@+6&2Sj!vIBVu)7=@!7>~kaV$BjQ_VjY)pFs^PCw{S3K^e}XOuz&QC2cNg< zjPuVw`@#!X0r_*!J@cZARs;W2Pdf$dyK&@=oNB9Y^J+ioR+S%nJL7BJPx^pLbYs*< zoKgQ;J9E<5EQG8H7rSCiONkJ@BDF40C)sXYyP}@qN@WfApa7xhY0VrU!pPSFW)ayA zd^cxMS0HTCLoxQm#+YOC8&@24)02C@Q+pr0?7wJ{v&v5GHLL@g zu-w(}jm5Ni<|C5e019zJLVFi@4YT!t%^*U*E4p5Hr2$?Kc{2o3f7-869XMb#RGV=F zo|Yy^Tf=NGu#YZFM~7mc*dAnoVtdAnnlP?r>cp|={FFrtW*>a;q5}_{5BBl?&73-6 z#+30hrc40NV0`w>$#dsUNBTP{%t*@Q@wI~ggfS@gZ~zJiumw;*a@fEH^JkuS z-dUg?>{C{)I{ln;Rp!4IBWn3oBR~^N^kJ|iO&7QWl9Q)mk1Na5rs{SZH z_9p=Rh|SVgCmeq~BX^XhK;%E@nq|v|4;zl3R_+?SH{H6KXGTMBjB#R{H-qJ%p8) zfk|-mg!;0BggQq3F+Syb=j6t)H3`a&YPC0^%xzim-4xiK+ z8{x%Eh^x@C59{D3ItzxtDv&{K-ps`tH*W0Nv!{S>enpV$E^GNTG*qrlLl{1;;eG(~ z1X3R?J~#shUeIkM0Xuie$?lCkj%Oa}&)_>08EWsZz2OGQ{eHdk^7I@=b8zn$7w49i zEYB7K>W8av3 zL`%@aw`e9U`ndoi;irgf?6P|7N9X+@qNoN3ji2w&w9CxziN|qW7zgDXLpmAeIowVfm)#smc$>o<` zaOou%Tyo(VXPvh4^rfetb?TYttUTk)70Z|5Z!C`5GqcNRRnC9wjB`%coqV6RryBHB zbgw_zA0oML78dXqf;!lkpaxk4ob;b5-5X&GU3|qwsQNjTRiy(4R+N@7`-6eMyz0SK z#DZGjM_&|v`i~ah=YCNXr0v_clabpwuscS)#pq)99Yqw?7@JNTPFhYj9Q#3IF5%~+ zTcXEC2hokuLBvn|6%hgZ!~HV74|IkDCpF3yToEcO2bN>V8&zU=GTwU$>x*FnhfH{sk3IGS`>`?~z)A;~r z7$4k!;hehK5m@?%9d^JOXPtV^>NC!}VD-5doqz6y=bdrZ%F|XZJ?)HTE6-d3_LrU_ zKYwO}&@B8JwQY2ulN2+X(tZ=U{`_9QCA!fMqGpeuGkAI10(Y`iJWh&zubY1pcwEnF27B;YZqj1YQB(3$OMqtsSK*BW`9N z;t}S?*_=mFPn1$zbMA^SDlW*$?bp+0^9A|&Sx$vU0s8BVIS{Bi7~?St9*^JdPRI(f>(aR7hrq6Oo})lI0Y1?CjsPXYBV`oTNJ%>nir z=9@BZ#*9e}7MywJinB27SFb#K)k>uQ`4^pk_Ubbo`-uLt&OU9$vZc%!tapj*$-5FY y@*c78_tKseZ}#XQYJ5jf{ht;vARs$f6ip<`0ppUkX}ysPxJ8$#s4KaK{r?A(!TjF< literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/textures_popup.bmp b/radiant/bitmaps/textures_popup.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5333382f9af910c054a511f319fe6e18159bdc3e GIT binary patch literal 238 zcmZ`yF%H5o40Nk9gXKOTau&uEmj{H*3{deE<~%Jg>KDSL-H>|L`E+N?emqy&@r7K$ z3wQ=Q8qkkXN}-C%Ia95b(2ke?Cc42H#P{0Nrl5|zjcmQ@6l1iYI*;%OxOoKg(0tGZ hUZ5!obIU)>EJ5$dI%dq57lNQZomg<)zn$Fh><4tzA4mWI literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/view_cameratoggle.bmp b/radiant/bitmaps/view_cameratoggle.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4ec79ed636b497243c378119e7dea6e25581f807 GIT binary patch literal 238 zcmaitF%H5o3`K)fX4qIOvoKbXxBxQp#8TwmfLwsIUURgZh%1Eec1HZ@|8GB8%I)z9 zn-RJYX)F2yEyypy literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/view_cameraupdate.bmp b/radiant/bitmaps/view_cameraupdate.bmp new file mode 100644 index 0000000000000000000000000000000000000000..dbb11956b0ea7953699d52f0438b8c64efe6bd9b GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!vMaNxiJhW|j=(9pop095w>|9=nx6d??hKtRC= zOu=Yn17l;508lp*SOO%k8U$9S%pMx7qyS{Hr-g##R9sxsg28lo7)U_HrMw(Oo4A*k XmjY>bAngL8OUlbZwul!42_OIf#dIZp literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/view_change.bmp b/radiant/bitmaps/view_change.bmp new file mode 100644 index 0000000000000000000000000000000000000000..31b609e5c32416e7540f43e2eb7c96462dac7b4e GIT binary patch literal 126 zcmZ?rtzv)xJ0PV2!~#If55$Z>2m&@he1s2z!2&?yKM*#+I6#{H00RRPkOu4M0P;@& bIUEcOf+7qITuKZKEFcUN;sRnpAcg?|fI$eZ literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/view_clipper.bmp b/radiant/bitmaps/view_clipper.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4ef205669234b733b1b14bcf4ea91de3398a2d2d GIT binary patch literal 238 zcmaiu!3}^g3+oh`Rwx(qLaKz7*r}aJ-H+Q|oXAEm^h_t4;4!*& vyNLQY{&&5tT5?}X49P9a;6;h>q+a|9=nx6d??h-~ggl zNkI?<1e73LMkPjr(ojP|Ak9#g8VI6YT*6WfL9}~mY9N>{F9p)fF6HIrK$@kbyu8Gb M0ji$~Zaf+T0P!LqW&i*H literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/view_entity.bmp b/radiant/bitmaps/view_entity.bmp new file mode 100644 index 0000000000000000000000000000000000000000..851ec2c3dbdeb7b938433d4bf21e5f671f257d61 GIT binary patch literal 238 zcmZ?rea8R+Wk5;;hy{R{ABY(lSb!vM@Sov7LqkIY!~g&PaVx?hBPgT<0*ZoQ3P>v( f1A!3|&0xU5fXrtGnuN>;at-kDq2@u%7lZ)-DDfB( literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/window1.bmp b/radiant/bitmaps/window1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f308f6efd5ca8e6ed3c92c1f80678852355a0f70 GIT binary patch literal 614 zcmb`DK?=km3`Nu81%&JeN*A*%^aK&NbB#H|ta~(X=KMq}RVd72Qq;cu1~)Fj+`zrp@CdGZbNmTV0jD!%CMhrf1ED-$@5Si&Am0(! z8Ygqs`hHr?3Nh!rZ#k$~9)_%9j^zUd6hWAknleXWjmC~frb(Z9_K*8L0!FvLvh-xj zd61Z;^8@TI(wTTAjG?HU8mAwV?pOU}Sy|Ro;?x-b1Avlsj_UbI3|&7!X1T+y>vv{Y aBAX=yy`8AI^B>ReQ+!+Y+e{~Z;^4nqP)U*i literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/window3.bmp b/radiant/bitmaps/window3.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2ea6feb8a653fb04b77b0d405237959a670881f5 GIT binary patch literal 614 zcma)2K@P(p3}Y1^sKkBJPCHiW3qV}=jXhy!e$H%%iI%n6QW49IV-nKiIXT4(`HpjK z=iddT1+JFnF zR{{RQOeD;YMt5HwK#C`B} dZhLn>mJjCl>~8k~p;y39;nsaD10DFfyaA`?Y<2(u literal 0 HcmV?d00001 diff --git a/radiant/bitmaps/window4.bmp b/radiant/bitmaps/window4.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5b9df3369b48fce9fdcfebb1c08708b3c806e4be GIT binary patch literal 614 zcmbV{K?=hl5JjiK3kdE@ii<7-If2D(uF)fOouhfP^#4&?6#}InRGxpnGd{NGB&rwo zJJz+Vix|B>-*!nU$&P~KIL^y{a7^qZBTu(Z>iZh;@eg*<2WuVQ&^$OQH5_t>k6#MN zi24|FLG91?cvD%^cyr|03jc#VguvX+?=XnV|8eLSuzbiIP|F+SO|bpEusnT={m9I> atWbUCi@N!WugBNtyp3e-wG24$y1W4-FJ@f; literal 0 HcmV?d00001 diff --git a/radiant/bp_dlg.cpp b/radiant/bp_dlg.cpp new file mode 100644 index 00000000..beb2f050 --- /dev/null +++ b/radiant/bp_dlg.cpp @@ -0,0 +1,155 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION +// +// custom Gtk dialog for brush primitives load/save + +#include "stdafx.h" + +void BP_dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint BP_dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +// ret: 0 = abort, 1 = load and convert, 2 = changed project settings, load and don't convert +// the user might decide to switch the BP mode in project settings +// status: 0 = loading regular, got conflict 1 = loading BP, got conflict +// int WINAPI gtk_MessageBox (GtkWidget *parent, const char* lpText, const char* lpCaption, guint32 uType) +int BP_MessageBox (int status) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkAccelGroup *accel; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (BP_dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Current map format is incompatible"); + + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + accel = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (window), accel); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + if (status == 0) + { + w = gtk_label_new ("This map was saved using brush primitives format\n" + "and your project settings use the standard format.\n" + "Do you want to convert the map, change default format or abort?\n" + "NOTE: due to limitations of the standard format, " + "some texture alignments may be lost after conversion."); + } + else + { + w = gtk_label_new ("This map was saved using standard format\n" + "and your project settings use the new \"brush primitives\" format.\n" + "Do you want to convert the map, change default format or abort?\n" + "NOTE: Next versions of Radiant will allow mixing the two formats" + "in the same maps for a smooth transition."); + } + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + w = gtk_button_new_with_label ("Convert"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (1)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Change default"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (2)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Abort load"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (0)); + gtk_widget_show (w); + ret = 0; // abort + + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + if (ret == 2) + { + // change project settings + if (status == 0) + g_qeglobals.m_bBrushPrimitMode = TRUE; + else + g_qeglobals.m_bBrushPrimitMode = FALSE; + SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", (g_qeglobals.m_bBrushPrimitMode ? "1" : "0" )); + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} diff --git a/radiant/brush.cpp b/radiant/brush.cpp new file mode 100644 index 00000000..a57913ee --- /dev/null +++ b/radiant/brush.cpp @@ -0,0 +1,3644 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +#include +#include "winding.h" +#include +#include "filters.h" + +extern MainFrame* g_pParentWnd; +extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); + +// globals + +int g_nBrushId = 0; + +#ifdef ENABLE_GROUPS +const char* Brush_Name(brush_t *b) +{ + static char cBuff[1024]; + b->numberId = g_nBrushId++; + if (g_qeglobals.m_bBrushPrimitMode) + { + sprintf(cBuff, "Brush %i", b->numberId); + Brush_SetEpair(b, "Name", cBuff); + } + return cBuff; +} +#endif + +brush_t *Brush_Alloc() +{ + brush_t *b = (brush_t*)qmalloc(sizeof(brush_t)); + return b; +} +/* +void Brush_Free(brush_t *b) +{ + free(b); +} +*/ +void PrintWinding (winding_t *w) +{ + int i; + + Sys_Printf ("-------------\n"); + for (i=0 ; inumpoints ; i++) + Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] + , w->points[i][1], w->points[i][2]); +} + +void PrintPlane (plane_t *p) +{ + Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], + p->normal[2], p->dist); +} + +void PrintVector (vec3_t v) +{ + Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); +} + + +/* +============================================================================= + + TEXTURE COORDINATES + +============================================================================= +*/ + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + float dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + + +float lightaxis[3] = {0.6f, 0.8f, 1.0f}; +/* +================ +SetShadeForPlane + +Light different planes differently to +improve recognition +================ +*/ +extern float ShadeForNormal(vec3_t normal); + +float SetShadeForPlane (plane_t *p) +{ + //return ShadeForNormal(p->normal); + + + int i; + float f; + + // axial plane + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) > 0.9) + { + f = lightaxis[i]; + return f; + } + + // between two axial planes + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) < 0.1) + { + f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; + return f; + } + + // other + f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; + return f; + +} + +vec3_t vecs[2]; +float shift[2]; + +/* +================ +Face_Alloc +================ +*/ +face_t *Face_Alloc( void ) +{ + face_t *f = (face_t*)qmalloc( sizeof( *f ) ); + return f; +} + +/* +================ +Face_Free +================ +*/ +void Face_Free( face_t *f ) +{ + assert( f != 0 ); + + if ( f->face_winding ) + { + free( f->face_winding ); + f->face_winding = 0; + } + f->texdef.~texdef_t();; + + free( f ); +} + +/* +================ +Face_Clone +================ +*/ +face_t *Face_Clone (face_t *f) +{ + face_t *n; + + n = Face_Alloc(); + n->texdef = f->texdef; + n->brushprimit_texdef = f->brushprimit_texdef; + + memcpy (n->planepts, f->planepts, sizeof(n->planepts)); + + // all other fields are derived, and will be set by Brush_Build + // FIXME: maybe not, for example n->pData! + return n; +} + +/* +================ +Face_FullClone + +makes an exact copy of the face +================ +*/ +face_t *Face_FullClone (face_t *f) +{ + face_t *n; + + n = Face_Alloc(); + n->texdef = f->texdef; + n->brushprimit_texdef = f->brushprimit_texdef; + memcpy(n->planepts, f->planepts, sizeof(n->planepts)); + memcpy(&n->plane, &f->plane, sizeof(plane_t)); + if (f->face_winding) + n->face_winding = Winding_Clone(f->face_winding); + else + n->face_winding = NULL; + n->pShader = f->pShader; + n->pShader->IncRef(); + n->d_texture = n->pShader->getTexture(); + return n; +} + +void Face_SetShader(face_t *face, const char *name) +{ + if(face->pShader != NULL) + face->pShader->DecRef(); + face->texdef.SetName(name); + face->pShader = QERApp_Shader_ForName(name); + face->pShader->IncRef(); + face->d_texture = face->pShader->getTexture(); + face->texdef.flags = face->pShader->getFlags(); +} + +void Face_SetShader(face_t *face, IShader *shader) +{ + if(face->pShader != NULL) + face->pShader->DecRef(); + face->texdef.SetName(shader->getName()); + face->d_texture = shader->getTexture(); + face->texdef.flags = shader->getFlags(); + face->pShader = shader; + face->pShader->IncRef(); +} + +/* +================ +Clamp +================ +*/ +void Clamp(float& f, int nClamp) +{ + float fFrac = f - static_cast(f); + f = static_cast(f) % nClamp; + f += fFrac; +} + +/* +================ +Face_MoveTexture +================ +*/ +void Face_MoveTexture(face_t *f, vec3_t delta) +{ + vec3_t vX, vY; + + if (g_qeglobals.m_bBrushPrimitMode) + ShiftTextureGeometric_BrushPrimit( f, delta ); + else + { + TextureAxisFromPlane(&f->plane, vX, vY); + + vec3_t vDP, vShift; + vDP[0] = DotProduct(delta, vX); + vDP[1] = DotProduct(delta, vY); + + double fAngle = f->texdef.rotate / 180 * Q_PI; + double c = cos(fAngle); + double s = sin(fAngle); + + vShift[0] = vDP[0] * c - vDP[1] * s; + vShift[1] = vDP[0] * s + vDP[1] * c; + + if (!f->texdef.scale[0]) + f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale; + if (!f->texdef.scale[1]) + f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale; + + f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0]; + f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1]; + + // clamp the shifts + Clamp(f->texdef.shift[0], f->d_texture->width); + Clamp(f->texdef.shift[1], f->d_texture->height); + } +} + +/* +================ +Face_SetColor +================ +*/ +/*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/ +void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) +{ + // set shading for face + f->d_shade = SetShadeForPlane (&f->plane); + f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade; + f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade; + f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade; +} + +/* +================ +Face_TextureVectors +================ +*/ +void Face_TextureVectors (face_t *f, float STfromXYZ[2][4]) +{ + vec3_t pvecs[2]; + int sv, tv; + float ang, sinv, cosv; + float ns, nt; + int i,j; + qtexture_t *q; + texdef_t *td; + +#ifdef _DEBUG + // this code is not supposed to be used while in BP mode, warning here can help spot the problem + if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) + Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n"); +#endif + + td = &f->texdef; + q = f->d_texture; + + memset (STfromXYZ, 0, 8*sizeof(float)); + + if (!td->scale[0]) + td->scale[0] = g_pGameDescription->mTextureDefaultScale; + if (!td->scale[1]) + td->scale[1] = g_pGameDescription->mTextureDefaultScale; + + // get natural texture axis + TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); + + // rotate axis + if (td->rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (td->rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (td->rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (td->rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = td->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (pvecs[0][0]) + sv = 0; + else if (pvecs[0][1]) + sv = 1; + else + sv = 2; + + if (pvecs[1][0]) + tv = 0; + else if (pvecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) { + ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; + nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; + STfromXYZ[i][sv] = ns; + STfromXYZ[i][tv] = nt; + } + + // scale + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i]; + + // shift + STfromXYZ[0][3] = td->shift[0]; + STfromXYZ[1][3] = td->shift[1]; + + for (j=0 ; j<4 ; j++) { + STfromXYZ[0][j] /= q->width; + STfromXYZ[1][j] /= q->height; + } +} + +/* +================ +Face_MakePlane +================ +*/ +void Face_MakePlane (face_t *f) +{ + int j; + vec3_t t1, t2, t3; + + // convert to a vector / dist plane + for (j=0 ; j<3 ; j++) + { + t1[j] = f->planepts[0][j] - f->planepts[1][j]; + t2[j] = f->planepts[2][j] - f->planepts[1][j]; + t3[j] = f->planepts[1][j]; + } + + CrossProduct(t1,t2, f->plane.normal); + if (VectorCompare (f->plane.normal, vec3_origin)) + Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n"); + VectorNormalize (f->plane.normal, f->plane.normal); + f->plane.dist = DotProduct (t3, f->plane.normal); +} + +/* +================ +EmitTextureCoordinates +================ +*/ +void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) +{ + float STfromXYZ[2][4]; + + Face_TextureVectors (f, STfromXYZ); + xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3]; + xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3]; +} + +//========================================================================== + +/* +================ +Brush_MakeFacePlanes +================ +*/ +void Brush_MakeFacePlanes (brush_t *b) +{ + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + { + Face_MakePlane (f); + } +} + +/* +================ +DrawBrushEntityName +================ +*/ +void DrawBrushEntityName (brush_t *b) +{ + const char *name; + float a, s, c; + vec3_t mid; + int i; + + if (!b->owner) + return; // during contruction + + if (b->owner == world_entity) + return; + + if (b != b->owner->brushes.onext) + return; // not key brush + + // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views + // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job? + // Brush_DrawFacingAngle() works when called, but is not being called. + if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) + { + // draw the angle pointer + a = FloatForKey (b->owner, "angle"); + s = sin (a/180*Q_PI); + c = cos (a/180*Q_PI); + for (i=0 ; i<3 ; i++) + mid[i] = (b->mins[i] + b->maxs[i])*0.5; + + qglBegin (GL_LINE_STRIP); + qglVertex3fv (mid); + mid[0] += c*8; + mid[1] += s*8; + mid[2] += s*8; + qglVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[2] -= s*4; + mid[0] -= s*4; + mid[1] += c*4; + mid[2] += c*4; + qglVertex3fv (mid); + mid[0] += c*4; + mid[1] += s*4; + mid[2] += s*4; + mid[0] += s*4; + mid[1] -= c*4; + mid[2] -= c*4; + qglVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[2] -= s*4; + mid[0] += s*4; + mid[1] -= c*4; + mid[2] -= c*4; + qglVertex3fv (mid); + qglEnd (); + } + + if (g_qeglobals.d_savedinfo.show_names) + { + name = ValueForKey (b->owner, "classname"); + qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4); + gtk_glwidget_print_string(name); + } +} + +/* +================= +Brush_MakeFaceWinding + +returns the visible polygon on a face +================= +*/ +winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face) +{ + winding_t *w; + face_t *clip; + plane_t plane; + qboolean past; + + // get a poly that covers an effectively infinite area + w = Winding_BaseForPlane (&face->plane); + + // chop the poly by all of the other faces + past = false; + for (clip = b->brush_faces ; clip && w ; clip=clip->next) + { + if (clip == face) + { + past = true; + continue; + } + if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 + && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) + { // identical plane, use the later one + if (past) + { + free (w); + return NULL; + } + continue; + } + + // flip the plane, because we want to keep the back side + VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); + plane.dist = -clip->plane.dist; + + w = Winding_Clip (w, &plane, false); + if (!w) + return w; + } + + if (w->numpoints < 3) + { + free(w); + w = NULL; + } + + if (!w) + Sys_FPrintf (SYS_WRN, "unused plane\n"); + + return w; +} + +/* +================= +Brush_SnapPlanepts +================= +*/ +void Brush_SnapPlanepts (brush_t *b) +{ + int i, j; + face_t *f; + + if (g_PrefsDlg.m_bNoClamp) + return; + + if (g_qeglobals.d_bSmallGrid) + { + for (f=b->brush_faces ; f; f=f->next) + for (i=0 ; i<3 ; i++) + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize; + } + else + { + for (f=b->brush_faces ; f; f=f->next) + for (i=0 ; i<3 ; i++) + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); + } +} + +/* +** Brush_Build +** +** Builds a brush rendering data and also sets the min/max bounds +*/ +// TTimo +// added a bConvert flag to convert between old and new brush texture formats +// TTimo +// brush grouping: update the group treeview if necessary +void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest) +{ + bool bLocalConvert; + + +#ifdef _DEBUG + if (!g_qeglobals.m_bBrushPrimitMode && bConvert) + Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n"); +#endif + + // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only + if (bConvert && !g_qeglobals.bNeedConvert) + { +#ifdef _DEBUG + //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes + // back and forth in one format or the other .. more when mixing BP / noBP in the same maps. +#endif + bLocalConvert = true; + g_qeglobals.bNeedConvert = true; + } + else + bLocalConvert = false; + + /* + ** build the windings and generate the bounding box + */ + Brush_BuildWindings(b, bSnap); + + if(b->owner->model.pRender) + { + const aabb_t *aabb = b->owner->model.pRender->GetAABB(); + VectorAdd(aabb->origin, aabb->extents, b->maxs); + VectorSubtract(aabb->origin, aabb->extents, b->mins); + } + + //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH ! + + /* + ** move the points and edges if in select mode + */ + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + SetupVertexSelection (); + + if (b->itemOwner == 0) //NULL) + Group_AddToProperGroup(b); + + if (bMarkMap) + { + Sys_MarkMapModified(); + } + + if (bLocalConvert) + g_qeglobals.bNeedConvert = false; + + // spog - applying filters to brush during brush_build instead of during redraw + if (bFilterTest) + b->bFiltered = FilterBrush( b ); +} + +/* +============== +Brush_SplitBrushByFace + +The incoming brush is NOT freed. +The incoming face is NOT left referenced. +============== +*/ +void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk) +{ + brush_t *b; + face_t *nf; + vec3_t temp; + + b = Brush_Clone (in); + nf = Face_Clone (f); + + nf->texdef = b->brush_faces->texdef; + if (bCaulk) + { + nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); + } + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *back = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *back = b; + } + + b = Brush_Clone (in); + nf = Face_Clone (f); + // swap the plane winding + VectorCopy (nf->planepts[0], temp); + VectorCopy (nf->planepts[1], nf->planepts[0]); + VectorCopy (temp, nf->planepts[1]); + + nf->texdef = b->brush_faces->texdef; + if (bCaulk) + { + nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); + } + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *front = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *front = b; + } +} + +/* +================= +Brush_BestSplitFace + +returns the best face to split the brush with. +return NULL if the brush is convex +================= +*/ +face_t *Brush_BestSplitFace(brush_t *b) +{ + face_t *face, *f, *bestface; + winding_t *front, *back; + int splits, tinywindings, value, bestvalue; + + bestvalue = 999999; + bestface = NULL; + for (face = b->brush_faces; face; face = face->next) + { + splits = 0; + tinywindings = 0; + for (f = b->brush_faces; f; f = f->next) + { + if (f == face) continue; + // + Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back); + + if (!front) + { + Winding_Free(back); + } + else if (!back) + { + Winding_Free(front); + } + else + { + splits++; + if (Winding_IsTiny(front)) tinywindings++; + if (Winding_IsTiny(back)) tinywindings++; + } + } + if (splits) + { + value = splits + 50 * tinywindings; + if (value < bestvalue) + { + bestvalue = value; + bestface = face; + } + } + } + return bestface; +} + +/* +================= +Brush_MakeConvexBrushes + +MrE FIXME: this doesn't work because the old + Brush_SplitBrushByFace is used +Turns the brush into a minimal number of convex brushes. +If the input brush is convex then it will be returned. +Otherwise the input brush will be freed. +NOTE: the input brush should have windings for the faces. +================= +*/ +brush_t *Brush_MakeConvexBrushes(brush_t *b) +{ + brush_t *front, *back, *end; + face_t *face; + + b->next = NULL; + face = Brush_BestSplitFace(b); + if (!face) return b; + Brush_SplitBrushByFace(b, face, &front, &back); + //this should never happen + if (!front && !back) return b; + Brush_Free(b); + if (!front) + return Brush_MakeConvexBrushes(back); + b = Brush_MakeConvexBrushes(front); + if (back) + { + for (end = b; end->next; end = end->next); + end->next = Brush_MakeConvexBrushes(back); + } + return b; +} + +/* +================= +Brush_Convex +================= +*/ +int Brush_Convex(brush_t *b) +{ + face_t *face1, *face2; + + for (face1 = b->brush_faces; face1; face1 = face1->next) + { + if (!face1->face_winding) continue; + for (face2 = b->brush_faces; face2; face2 = face2->next) + { + if (face1 == face2) continue; + if (!face2->face_winding) continue; + if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, + face1->plane.normal, face2->plane.normal, + face1->plane.dist, face2->plane.dist)) + { + return false; + } + } + } + return true; +} + +/* +================= +Brush_MoveVertexes + +- The input brush must be convex +- The input brush must have face windings. +- The output brush will be convex. +- Returns true if the WHOLE vertex movement is performed. +================= +*/ + +// define this to debug the vertex editing mode +#ifdef _DEBUG +//#define DBG_VERT +#endif + +#define MAX_MOVE_FACES 64 + +int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) +{ + face_t *f, *face, *newface, *lastface, *nextface; + face_t *movefaces[MAX_MOVE_FACES]; + int movefacepoints[MAX_MOVE_FACES]; + winding_t *w, tmpw; + vec3_t start, mid; + plane_t plane; + int i, j, k, nummovefaces, result, done; + float dot, front, back, frac, smallestfrac; + +#ifdef DBG_VERT + Sys_Printf("Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" ); +#endif + + result = true; + // + tmpw.numpoints = 3; + tmpw.maxpoints = 3; + VectorCopy(vertex, start); + VectorAdd(vertex, delta, end); + //snap or not? + if (bSnap) + for (i = 0; i < 3; i++) + end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize; + // + VectorCopy(end, mid); + //if the start and end are the same + if (Point_Equal(start, end, 0.3f)) return false; + //the end point may not be the same as another vertex + for (face = b->brush_faces; face; face = face->next) + { + w = face->face_winding; + if (!w) continue; + for (i = 0; i < w->numpoints; i++) + { + if (Point_Equal(w->points[i], end, 0.3f)) + { + VectorCopy(vertex, end); + return false; + } + } + } + // + done = false; + while(!done) + { + //chop off triangles from all brush faces that use the to be moved vertex + //store pointers to these chopped off triangles in movefaces[] + nummovefaces = 0; + for (face = b->brush_faces; face; face = face->next) + { + w = face->face_winding; + if (!w) continue; + for (i = 0; i < w->numpoints; i++) + { + if (Point_Equal(w->points[i], start, 0.2f)) + { + if (face->face_winding->numpoints <= 3) + { + movefacepoints[nummovefaces] = i; + movefaces[nummovefaces++] = face; + break; + } + dot = DotProduct(end, face->plane.normal) - face->plane.dist; + //if the end point is in front of the face plane + if (dot > 0.1) + { + //fanout triangle subdivision + for (k = i; k < i + w->numpoints-3; k++) + { + VectorCopy(w->points[i], tmpw.points[0]); + VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); + VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); + // + newface = Face_Clone(face); + //get the original + for (f = face; f->original; f = f->original) ; + newface->original = f; + //store the new winding + if (newface->face_winding) Winding_Free(newface->face_winding); + newface->face_winding = Winding_Clone(&tmpw); + //get the texture information + newface->pShader = face->pShader; + newface->d_texture = face->d_texture; + + //add the face to the brush + newface->next = b->brush_faces; + b->brush_faces = newface; + //add this new triangle to the move faces + movefacepoints[nummovefaces] = 0; + movefaces[nummovefaces++] = newface; + } + //give the original face a new winding + VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); + VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); + VectorCopy(w->points[i], tmpw.points[2]); + Winding_Free(face->face_winding); + face->face_winding = Winding_Clone(&tmpw); + //add the original face to the move faces + movefacepoints[nummovefaces] = 2; + movefaces[nummovefaces++] = face; + } + else + { + //chop a triangle off the face + VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); + VectorCopy(w->points[i], tmpw.points[1]); + VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); + //remove the point from the face winding + Winding_RemovePoint(w, i); + //get texture crap right + Face_SetColor(b, face, 1.0); + for (j = 0; j < w->numpoints; j++) + EmitTextureCoordinates(w->points[j], face->d_texture, face); + //make a triangle face + newface = Face_Clone(face); + //get the original + for (f = face; f->original; f = f->original) ; + newface->original = f; + //store the new winding + if (newface->face_winding) Winding_Free(newface->face_winding); + newface->face_winding = Winding_Clone(&tmpw); + //get the texture + newface->pShader = face->pShader; + newface->d_texture = newface->pShader->getTexture(); +// newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name ); + //add the face to the brush + newface->next = b->brush_faces; + b->brush_faces = newface; + // + movefacepoints[nummovefaces] = 1; + movefaces[nummovefaces++] = newface; + } + break; + } + } + } + //now movefaces contains pointers to triangle faces that + //contain the to be moved vertex + // + done = true; + VectorCopy(end, mid); + smallestfrac = 1; + for (face = b->brush_faces; face; face = face->next) + { + //check if there is a move face that has this face as the original + for (i = 0; i < nummovefaces; i++) + { + if (movefaces[i]->original == face) break; + } + if (i >= nummovefaces) continue; + //check if the original is not a move face itself + for (j = 0; j < nummovefaces; j++) + { + if (face == movefaces[j]) break; + } + //if the original is not a move face itself + if (j >= nummovefaces) + { + memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t)); + } + else + { + k = movefacepoints[j]; + w = movefaces[j]->face_winding; + VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]); + VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]); + // + k = movefacepoints[i]; + w = movefaces[i]->face_winding; + VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]); + if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) + { + VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]); + if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) + //this should never happen otherwise the face merge did a crappy job a previous pass + continue; + } + } + //now we've got the plane to check agains + front = DotProduct(start, plane.normal) - plane.dist; + back = DotProduct(end, plane.normal) - plane.dist; + //if the whole move is at one side of the plane + if (front < 0.01 && back < 0.01) continue; + if (front > -0.01 && back > -0.01) continue; + //if there's no movement orthogonal to this plane at all + if (fabs(front-back) < 0.001) continue; + //ok first only move till the plane is hit + frac = front/(front-back); + if (frac < smallestfrac) + { + mid[0] = start[0] + (end[0] - start[0]) * frac; + mid[1] = start[1] + (end[1] - start[1]) * frac; + mid[2] = start[2] + (end[2] - start[2]) * frac; + smallestfrac = frac; + } + // + done = false; + } + + //move the vertex + for (i = 0; i < nummovefaces; i++) + { + //move vertex to end position + VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]); + //create new face plane + for (j = 0; j < 3; j++) + { + VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); + } + Face_MakePlane(movefaces[i]); + if (VectorLength(movefaces[i]->plane.normal) < 0.1) + result = false; + } + //if the brush is no longer convex + if (!result || !Brush_Convex(b)) + { + for (i = 0; i < nummovefaces; i++) + { + //move the vertex back to the initial position + VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]); + //create new face plane + for (j = 0; j < 3; j++) + { + VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); + } + Face_MakePlane(movefaces[i]); + } + result = false; + VectorCopy(start, end); + done = true; + } + else + { + VectorCopy(mid, start); + } + //get texture crap right + for (i = 0; i < nummovefaces; i++) + { + Face_SetColor(b, movefaces[i], 1.0); + for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) + EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); + } + + //now try to merge faces with their original faces + lastface = NULL; + for (face = b->brush_faces; face; face = nextface) + { + nextface = face->next; + if (!face->original) + { + lastface = face; + continue; + } + if (!Plane_Equal(&face->plane, &face->original->plane, false)) + { + lastface = face; + continue; + } + w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); + if (!w) + { + lastface = face; + continue; + } + Winding_Free(face->original->face_winding); + face->original->face_winding = w; + //get texture crap right + Face_SetColor(b, face->original, 1.0); + for (j = 0; j < face->original->face_winding->numpoints; j++) + EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); + //remove the face that was merged with the original + if (lastface) lastface->next = face->next; + else b->brush_faces = face->next; + Face_Free(face); + } + } + return result; +} + +/* +================= +Brush_InsertVertexBetween +================= +*/ +int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2) +{ + face_t *face; + winding_t *w, *neww; + vec3_t point; + int i, insert; + + if (Point_Equal(p1, p2, 0.4f)) + return false; + VectorAdd(p1, p2, point); + VectorScale(point, 0.5f, point); + insert = false; + //the end point may not be the same as another vertex + for (face = b->brush_faces; face; face = face->next) + { + w = face->face_winding; + if (!w) continue; + neww = NULL; + for (i = 0; i < w->numpoints; i++) + { + if (!Point_Equal(w->points[i], p1, 0.1f)) + continue; + if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f)) + { + neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints); + break; + } + else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f)) + { + neww = Winding_InsertPoint(w, point, i); + break; + } + } + if (neww) + { + Winding_Free(face->face_winding); + face->face_winding = neww; + insert = true; + } + } + return insert; +} + + +/* +================= +Brush_ResetFaceOriginals +================= +*/ +void Brush_ResetFaceOriginals(brush_t *b) +{ + face_t *face; + + for (face = b->brush_faces; face; face = face->next) + { + face->original = NULL; + } +} + +#ifdef ENABLE_GROUPS +/* +============== +Brush_SetEpair +sets an epair for the given brush +============== +*/ +void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + if (b->patchBrush) + { + Patch_SetEpair(b->pPatch, pKey, pValue); + } + else + { + SetKeyValue(b->epairs, pKey, pValue); + } + } + else + { + Sys_Printf("Can only set key/values in Brush primitive mode\n"); + } +} + +/* +================= +Brush_GetKeyValue +================= +*/ +const char* Brush_GetKeyValue(brush_t *b, const char *pKey) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + if (b->patchBrush) + { + return Patch_GetKeyValue(b->pPatch, pKey); + } + else + { + return ValueForKey(b->epairs, pKey); + } + } + else + { + Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n"); + } + return ""; +} +#endif +/* +================= +CheckName +temporary stuff, detect potential problems when saving the texture name +================= +*/ +void CheckName( face_t *fa, char *pname ) +{ + if (!strlen(fa->texdef.GetName())) + { +#ifdef _DEBUG + Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n"); +#endif + fa->texdef.SetName(SHADER_NOT_FOUND); + strcpy(pname, SHADER_NOT_FOUND); + return; + } + + // some people manage to get long filename textures (with spaces) in their maps + if (strchr( fa->texdef.GetName(), ' ' )) + { + char Msg1[1024]; + + sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() ); + + Sys_Printf("%s\n", Msg1 ); + gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); + strcpy( pname, SHADER_NOT_FOUND ); + return; + } + + //++timo FIXME: bug #103494 detection attempt + // TODO: clean this detection part when bug will have disappeared + if (fa->texdef.GetName()[0] == '(') + { + char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected."; + Sys_Printf("%s\n", text); + gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK ); + // need to cleanup this dead face name or we may loop endlessly + fa->texdef.SetName(SHADER_NOT_FOUND); + strcpy( pname, SHADER_NOT_FOUND ); + return; + } + strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/" +} + +/* +============= +Brush_Create + +Create non-textured blocks for entities +The brush is NOT linked to any list +============= +*/ +brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) +{ + int i, j; + vec3_t pts[4][2]; + face_t *f; + brush_t *b; + +#if DBG_BP + // brush primitive mode : convert texdef to brushprimit_texdef ? + // most of the time texdef is empty + if (g_qeglobals.m_bBrushPrimitMode) + { + // check texdef is empty .. if there are cases it's not we need to write some conversion code + if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0) + Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n"); + } +#endif + + for (i=0 ; i<3 ; i++) + { + if (maxs[i] < mins[i]) + Error ("Brush_InitSolid: backwards"); + } + + b = Brush_Alloc(); + + pts[0][0][0] = mins[0]; + pts[0][0][1] = mins[1]; + + pts[1][0][0] = mins[0]; + pts[1][0][1] = maxs[1]; + + pts[2][0][0] = maxs[0]; + pts[2][0][1] = maxs[1]; + + pts[3][0][0] = maxs[0]; + pts[3][0][1] = mins[1]; + + for (i=0 ; i<4 ; i++) + { + pts[i][0][2] = mins[2]; + pts[i][1][0] = pts[i][0][0]; + pts[i][1][1] = pts[i][0][1]; + pts[i][1][2] = maxs[2]; + } + + for (i=0 ; i<4 ; i++) + { + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + j = (i+1)%4; + + VectorCopy (pts[j][1], f->planepts[0]); + VectorCopy (pts[i][1], f->planepts[1]); + VectorCopy (pts[i][0], f->planepts[2]); + } + + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[0][1], f->planepts[0]); + VectorCopy (pts[1][1], f->planepts[1]); + VectorCopy (pts[2][1], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[2][0], f->planepts[0]); + VectorCopy (pts[1][0], f->planepts[1]); + VectorCopy (pts[0][0], f->planepts[2]); + + return b; +} + +/* +============= +Brush_CreatePyramid + +Create non-textured pyramid for light entities +The brush is NOT linked to any list +============= +*/ +brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef) +{ + int i; + + //++timo handle new brush primitive ? return here ?? + return Brush_Create(mins, maxs, texdef); + + for (i=0 ; i<3 ; i++) + if (maxs[i] < mins[i]) + Error ("Brush_InitSolid: backwards"); + + brush_t* b = Brush_Alloc(); + + vec3_t corners[4]; + + float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2))); + + corners[0][0] = mins[0]; + corners[0][1] = mins[1]; + corners[0][2] = fMid; + + corners[1][0] = mins[0]; + corners[1][1] = maxs[1]; + corners[1][2] = fMid; + + corners[2][0] = maxs[0]; + corners[2][1] = maxs[1]; + corners[2][2] = fMid; + + corners[3][0] = maxs[0]; + corners[3][1] = mins[1]; + corners[3][2] = fMid; + + vec3_t top, bottom; + + top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2)); + top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2)); + top[2] = Rad_rint(maxs[2]); + + VectorCopy(top, bottom); + bottom[2] = mins[2]; + + // sides + for (i = 0; i < 4; i++) + { + face_t* f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + int j = (i+1)%4; + + VectorCopy (top, f->planepts[0]); + VectorCopy (corners[i], f->planepts[1]); + VectorCopy(corners[j], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (bottom, f->planepts[2]); + VectorCopy (corners[i], f->planepts[1]); + VectorCopy(corners[j], f->planepts[0]); + } + + return b; +} + + + + +/* +============= +Brush_MakeSided + +Makes the current brush have the given number of 2d sides +============= +*/ +void Brush_MakeSided (int sides) +{ + int i, axis; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float sv, cv; + + if (sides < 3) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (sides >= MAX_POINTS_ON_WINDING-4) + { + Sys_Printf("too many sides.\n"); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + if (g_pParentWnd->ActiveXY()) + { + switch(g_pParentWnd->ActiveXY()->GetViewType()) + { + case XY: axis = 2; break; + case XZ: axis = 1; break; + case YZ: axis = 0; break; + } + } + else + { + axis = 2; + } + + // find center of brush + width = 8; + for (i = 0; i < 3; i++) + { + mid[i] = (maxs[i] + mins[i]) * 0.5; + if (i == axis) continue; + if ((maxs[i] - mins[i]) * 0.5 > width) + width = (maxs[i] - mins[i]) * 0.5; + } + + b = Brush_Alloc(); + + // create top face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis]; + f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis]; + f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis]; + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis]; + f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis]; + f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis]; + + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + sv = sin (i*3.14159265*2/sides); + cv = cos (i*3.14159265*2/sides); + + f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5); + f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5); + f->planepts[0][axis] = mins[axis]; + + f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3]; + f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3]; + f->planepts[1][axis] = maxs[axis]; + + f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5); + f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5); + f->planepts[2][axis] = maxs[axis]; + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + + + +/* +============= +Brush_Free + +Frees the brush with all of its faces and display list. +Unlinks the brush from whichever chain it is in. +Decrements the owner entity's brushcount. +Removes owner entity if this was the last brush +unless owner is the world. +Removes from groups +============= +*/ +void Brush_Free (brush_t *b, bool bRemoveNode) +{ + face_t *f, *next; + epair_t *ep, *enext; + + // remove from group + if (bRemoveNode) + Group_RemoveBrush(b); + + // free the patch if it's there + if (b->patchBrush) + { + Patch_Delete(b->pPatch); + } + + // free faces + for (f=b->brush_faces ; f ; f=next) + { + next = f->next; + Face_Free( f ); + } + + // TTimo : free brush epairs + for (ep = b->epairs ; ep ; ep=enext ) + { + enext = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + + // unlink from active/selected list + if (b->next) + Brush_RemoveFromList (b); + + // unlink from entity list + if (b->onext) + Entity_UnlinkBrush (b); + + free (b); +} + +/* +============= +Face_MemorySize +============= +*/ +int Face_MemorySize(face_t *f ) +{ + int size = 0; + + if (f->face_winding) + { +// size += _msize(f->face_winding); + size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int); + } +// size += _msize(f); + size += sizeof(face_t); + return size; +} + +/* +============= +Brush_MemorySize +============= +*/ +int Brush_MemorySize(brush_t *b) +{ + face_t *f; + epair_t *ep; + int size = 0; + + // + if (b->patchBrush) + { + size += Patch_MemorySize(b->pPatch); + } + // + for (f = b->brush_faces; f; f = f->next) + { + size += Face_MemorySize(f); + } + // + for (ep = b->epairs; ep; ep = ep->next ) + { +// size += _msize(ep->key); + size += strlen(ep->key); +// size += _msize(ep->value); + size += strlen(ep->value); +// size += _msize(ep); + size += sizeof(epair_t); + } +// size += _msize(b); + size += sizeof(brush_t); + return size; +} + + +/* +============ +Brush_Clone + +Does NOT add the new brush to any lists +============ +*/ +brush_t *Brush_Clone (brush_t *b) +{ + brush_t *n = NULL; + face_t *f, *nf; + + if (b->patchBrush) + { + patchMesh_t *p = Patch_Duplicate(b->pPatch); + Brush_RemoveFromList(p->pSymbiot); + Entity_UnlinkBrush(p->pSymbiot); + n = p->pSymbiot; + } + else + { + n = Brush_Alloc(); + n->numberId = g_nBrushId++; + n->owner = b->owner; + for (f=b->brush_faces ; f ; f=f->next) + { + nf = Face_Clone( f ); + nf->next = n->brush_faces; + n->brush_faces = nf; + } + } + + return n; +} + +/* +============ +Brush_Clone + +Does NOT add the new brush to any lists +============ +*/ +brush_t *Brush_FullClone(brush_t *b) +{ + brush_t *n = NULL; + face_t *f, *nf, *f2, *nf2; + int j; + + if (b->patchBrush) + { + patchMesh_t *p = Patch_Duplicate(b->pPatch); + Brush_RemoveFromList(p->pSymbiot); + Entity_UnlinkBrush(p->pSymbiot); + n = p->pSymbiot; + n->owner = b->owner; + Brush_Build(n); + } + else + { + n = Brush_Alloc(); + n->numberId = g_nBrushId++; + n->owner = b->owner; + VectorCopy(b->mins, n->mins); + VectorCopy(b->maxs, n->maxs); + // + for (f = b->brush_faces; f; f = f->next) + { + if (f->original) continue; + nf = Face_FullClone(f); + nf->next = n->brush_faces; + n->brush_faces = nf; + //copy all faces that have the original set to this face + for (f2 = b->brush_faces; f2; f2 = f2->next) + { + if (f2->original == f) + { + nf2 = Face_FullClone(f2); + nf2->next = n->brush_faces; + n->brush_faces = nf2; + //set original + nf2->original = nf; + } + } + } + for (nf = n->brush_faces; nf; nf = nf->next) + { + Face_SetColor(n, nf, 1.0); + if (nf->face_winding) + { + if (g_qeglobals.m_bBrushPrimitMode) + EmitBrushPrimitTextureCoordinates(nf,nf->face_winding); + else + { + for (j = 0; j < nf->face_winding->numpoints; j++) + EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf); + } + } + } + } + return n; +} + + // FIXME - spog - finish this later.. + /* +bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3) +{ + int i; + vec3_t v1, v2, normal[3]; + float d; + + //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]); + //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]); + //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]); + //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]); + + // test ray against triangle + // get triangle plane normal + //VectorSubtract(p1, p2, v1); + //VectorSubtract(p1, p3, v2); + //CrossProduct(v1, v2, v1); + // check normal against direction + //if (DotProduct(dir, v1) >= 0) + //{ + // generate cone normals + VectorSubtract(origin, p1, v1); + VectorSubtract(origin, p2, v2); + CrossProduct(v1, v2, normal[0]); + VectorSubtract(origin, p2, v1); + VectorSubtract(origin, p3, v2); + CrossProduct(v1, v2, normal[1]); + VectorSubtract(origin, p3, v1); + VectorSubtract(origin, p1, v2); + CrossProduct(v1, v2, normal[2]); + //} + //else + //{ + // flip normals if triangle faces away + // Sys_Printf("flipped\n"); + // VectorSubtract(origin, p1, v1); + // VectorSubtract(origin, p3, v2); + // CrossProduct(v1, v2, normal[0]); + // VectorSubtract(origin, p3, v1); + // VectorSubtract(origin, p2, v2); + // CrossProduct(v1, v2, normal[1]); + // VectorSubtract(origin, p2, v1); + // VectorSubtract(origin, p1, v2); + // CrossProduct(v1, v2, normal[2]); + //} + + for (i=0; i<3; i++) + { + VectorNormalize(normal[i]); + //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]); + //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]); + d = DotProduct(dir, normal[i]); + //Sys_Printf("dotproduct: %f\n",d); + if (d < 0) + return false; + } + return true; +} +*/ + +/* +extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, + float vert0[3], float vert1[3], float vert2[3], + double *t, double *u, double *v); + +bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v) +{ + bool bIntersect = false; + float tBest = FLT_MAX; + int i, j; + vec3_t xyz[3]; + vec3_t vRay[2]; + + float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set + + VectorSubtract (origin, b->owner->origin, vRay[0]); + VectorCopy (dir, vRay[1]); + + if (angle > 0) + { + int i; + float s, c; + float x, y; + + s = sin (-angle/180*Q_PI); + c = cos (-angle/180*Q_PI); + + for (i=0; i<2; i++) + { + x = vRay[i][0]; + y = vRay[i][1]; + vRay[i][0] = (x * c) - (y * s); + vRay[i][1] = (x * s) + (y * c); + } + } + + entitymodel *model = b->owner->md3Class->model; + + while (model != NULL) + { + for (i = 0; i < model->nTriCount; i++) + { + for (j = 0; j < 3; j++) + VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]); + + if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v)) + { + bIntersect = true; + if (*t < tBest) + tBest = *t; + } + } + model = model->pNext; + } + if (bIntersect) + { + *t = tBest; + return true; + } + else + { + *t = 0; + return false; + } +} +*/ + +/* +============== +Brush_Ray + +Itersects a ray with a brush +Returns the face hit and the distance along the ray the intersection occured at +Returns NULL and 0 if not hit at all + +http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 +============== +*/ +extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v); +face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags) +{ + face_t *f, *firstface = NULL; + vec3_t p1, p2; + float frac, d1, d2; + int i; + + if (b->owner->eclass->fixedsize + && b->owner->model.pSelect + && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)) + && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) + { + ray_t ray_local; + vec_t dist_local = FLT_MAX; + ray_construct_for_vec3(&ray_local, origin, dir); + if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local)) + { + *dist = dist_local; + return b->brush_faces; + } + else + { + *dist = 0.0f; + return NULL; + } + } + + VectorCopy (origin, p1); + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord; + + for (f=b->brush_faces ; f ; f=f->next) + { + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + if (d1 >= 0 && d2 >= 0) + { + *dist = 0; + return NULL; // ray is on front side of face + } + if (d1 <=0 && d2 <= 0) + continue; + // clip the ray to the plane + frac = d1 / (d1 - d2); + if (d1 > 0) + { + firstface = f; + for (i=0 ; i<3 ; i++) + p1[i] = p1[i] + frac *(p2[i] - p1[i]); + } + else + { + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + frac *(p2[i] - p1[i]); + } + } + + // find distance p1 is along dir + VectorSubtract (p1, origin, p1); + d1 = DotProduct (p1, dir); + + *dist = d1; + + // new test stuff for patches + if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush) + { + double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are + if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v)) + { + *dist = 0; + return NULL; + } + else + { + *dist = (float)t; + //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v); + } + } + + // IMPORTANT NOTE: + // modifications to the discarding code here should be matched in the selection code + // see Brush_Draw + + // do some last minute filtering + if (firstface && nFlags & SF_CAMERA) + { + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) + { + if (strstr(firstface->texdef.GetName(), "caulk")) + { + *dist = 0; + return NULL; + } + } + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) + { + if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster")) + { + *dist = 0; + return NULL; + } + } + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) + { + if (strstr(firstface->texdef.GetName(), "clip")) + { + *dist = 0; + return NULL; + } + } + } + + return firstface; +} + +//PGM +face_t *Brush_Point (vec3_t origin, brush_t *b) +{ + face_t *f; + float d1; + + for (f=b->brush_faces ; f ; f=f->next) + { + d1 = DotProduct (origin, f->plane.normal) - f->plane.dist; + if (d1 > 0) + { + return NULL; // point is on front side of face + } + } + + return b->brush_faces; +} +//PGM + + +void Brush_AddToList (brush_t *b, brush_t *blist) +{ + if (b->next || b->prev) + Error ("Brush_AddToList: already linked"); + + if (blist == &selected_brushes || blist == &active_brushes) + { + if (b->patchBrush && blist == &selected_brushes) + { + Patch_Select(b->pPatch); + } + } + b->next = blist->next; + blist->next->prev = b; + blist->next = b; + b->prev = blist; + + // TTimo messaging + DispatchRadiantMsg( RADIANT_SELECTION ); +} + +void Brush_RemoveFromList (brush_t *b) +{ + if (!b->next || !b->prev) + Error ("Brush_RemoveFromList: not linked"); + + if (b->patchBrush) + { + Patch_Deselect(b->pPatch); + } + b->next->prev = b->prev; + b->prev->next = b->next; + b->next = b->prev = NULL; +} + +/* +=============== +SetFaceTexdef + +Doesn't set the curve flags + +NOTE : ( TTimo ) + never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture + use Texture_ForName() to find the right shader + FIXME : send the right shader ( qtexture_t * ) in the parameters ? + +TTimo: surface plugin, added an IPluginTexdef* parameter + if not NULL, get ->Copy() of it into the face ( and remember to hook ) + if NULL, ask for a default + + TTimo - shader code cleanup + added IShader* parameter + =============== +*/ +void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { + int oldFlags; + int oldContents; + face_t *tf; + + oldFlags = f->texdef.flags; + oldContents = f->texdef.contents; + if (g_qeglobals.m_bBrushPrimitMode) + { + f->texdef = *texdef; + ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); + } + else + if (bFitScale) + { + f->texdef = *texdef; + // fit the scaling of the texture on the actual plane + vec3_t p1,p2,p3; // absolute coordinates + // compute absolute coordinates + ComputeAbsolute(f,p1,p2,p3); + // compute the scale + vec3_t vx,vy; + VectorSubtract(p2,p1,vx); + VectorNormalize(vx, vx); + VectorSubtract(p3,p1,vy); + VectorNormalize(vy, vy); + // assign scale + VectorScale(vx,texdef->scale[0],vx); + VectorScale(vy,texdef->scale[1],vy); + VectorAdd(p1,vx,p2); + VectorAdd(p1,vy,p3); + // compute back shift scale rot + AbsoluteToLocal(f->plane,f,p1,p2,p3); + } + else + f->texdef = *texdef; + f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); + f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); + + // if this is a curve face, set all other curve faces to the same texdef + if (f->texdef.flags & SURF_CURVE) + { + for (tf = b->brush_faces ; tf ; tf = tf->next) + { + if (tf->texdef.flags & SURF_CURVE) + tf->texdef = f->texdef; + } + } +} + +/* +=============== +SetFaceTexdef + +Doesn't set the curve flags + +NOTE : ( TTimo ) + never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture + use Texture_ForName() to find the right shader + FIXME : send the right shader ( qtexture_t * ) in the parameters ? + + TTimo: surface plugin, added an IPluginTexdef* parameter + if not NULL, get ->Copy() of it into the face ( and remember to hook ) + if NULL, ask for a default +=============== +*/ +void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { + int oldFlags; + int oldContents; + + oldFlags = f->texdef.flags; + oldContents = f->texdef.contents; + + if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build + Face_SetShader(f, texdef->GetName()); + + if (g_qeglobals.m_bBrushPrimitMode) + { + f->texdef = *texdef; + ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); + } + else + { + if (bFitScale) + { + f->texdef = *texdef; + // fit the scaling of the texture on the actual plane + vec3_t p1,p2,p3; // absolute coordinates + // compute absolute coordinates + ComputeAbsolute(f,p1,p2,p3); + // compute the scale + vec3_t vx,vy; + VectorSubtract(p2,p1,vx); + VectorNormalize(vx, vx); + VectorSubtract(p3,p1,vy); + VectorNormalize(vy, vy); + // assign scale + VectorScale(vx,texdef->scale[0],vx); + VectorScale(vy,texdef->scale[1],vy); + VectorAdd(p1,vx,p2); + VectorAdd(p1,vy,p3); + // compute back shift scale rot + AbsoluteToLocal(f->plane,f,p1,p2,p3); + } + else + { + f->texdef = *texdef; + } + } + f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); + f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); +} + +#ifdef _DEBUG +void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) +{ + for (face_t* f = b->brush_faces ; f ; f = f->next) + SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef); + Brush_Build( b ); + if (b->patchBrush) + { + Patch_SetTexture(b->pPatch, texdef, pTexdef ); + b->bFiltered = FilterBrush( b ); + } +} +#endif + +void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) +{ + for (face_t* f = b->brush_faces ; f ; f = f->next) + SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef); + Brush_Build( b ); + if (b->patchBrush) + { + Patch_SetTexture(b->pPatch, texdef, pTexdef ); + b->bFiltered = FilterBrush( b ); + } +} + + +qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) +{ + float d1, d2, fr; + int i; + float *v; + + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + + if (d1 >= 0 && d2 >= 0) + return false; // totally outside + if (d1 <= 0 && d2 <= 0) + return true; // totally inside + + fr = d1 / (d1 - d2); + + if (d1 > 0) + v = p1; + else + v = p2; + + for (i=0 ; i<3 ; i++) + v[i] = p1[i] + fr*(p2[i] - p1[i]); + + return true; +} + + +int AddPlanept (float *f) +{ + int i; + + for (i=0 ; iowner->eclass->fixedsize) + return; + + c = 0; + for (i=0 ; i<3 ; i++) + c += AddPlanept (f->planepts[i]); + if (c == 0) + return; // already completely added + + // select all points on this plane in all brushes the selection + for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) + { + if (b2 == b) + continue; + for (f2=b2->brush_faces ; f2 ; f2=f2->next) + { + for (i=0 ; i<3 ; i++) + if (fabs(DotProduct(f2->planepts[i], f->plane.normal) + -f->plane.dist) > ON_EPSILON) + break; + if (i==3) + { // move this face as well + Brush_SelectFaceForDragging (b2, f2, shear); + break; + } + } + } + + + // if shearing, take all the planes adjacent to + // selected faces and rotate their points so the + // edge clipped by a selcted face has two of the points + if (!shear) + return; + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + w = Brush_MakeFaceWinding (b, f2); + if (!w) + continue; + + // any points on f will become new control points + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->points[i], f->plane.normal) + - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + break; + } + + // + // if none of the points were on the plane, + // leave it alone + // + if (i != w->numpoints) + { + if (i == 0) + { // see if the first clockwise point was the + // last point on the winding + d = DotProduct (w->points[w->numpoints-1] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + i = w->numpoints - 1; + } + + AddPlanept (f2->planepts[0]); + + VectorCopy (w->points[i], f2->planepts[0]); + if (++i == w->numpoints) + i = 0; + + // see if the next point is also on the plane + d = DotProduct (w->points[i] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + AddPlanept (f2->planepts[1]); + + VectorCopy (w->points[i], f2->planepts[1]); + if (++i == w->numpoints) + i = 0; + + // the third point is never on the plane + + VectorCopy (w->points[i], f2->planepts[2]); + } + + free(w); + } +} + +/* +============== +Brush_SideSelect + +The mouse click did not hit the brush, so grab one or more side +planes for dragging +============== +*/ +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir + , qboolean shear) +{ + face_t *f, *f2; + vec3_t p1, p2; + + for (f=b->brush_faces ; f ; f=f->next) + { + VectorCopy (origin, p1); + VectorMA (origin, 2*g_MaxWorldCoord, dir, p2); + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + ClipLineToFace (p1, p2, f2); + } + + if (f2) + continue; + + if (VectorCompare (p1, origin)) + continue; + if (ClipLineToFace (p1, p2, f)) + continue; + + Brush_SelectFaceForDragging (b, f, shear); + } +} + +bool g_bBuildWindingsNoTexBuild = false; + +void Brush_SetBuildWindingsNoTexBuild(bool bBuild) +{ + g_bBuildWindingsNoTexBuild = bBuild; +} + +// TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary +// saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases +// ie when we want to update a shader +// default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild +void Brush_BuildWindings( brush_t *b, bool bSnap ) +{ + winding_t *w; + face_t *face; + vec_t v; + + if (bSnap) + Brush_SnapPlanepts( b ); + + // clear the mins/maxs bounds + b->mins[0] = b->mins[1] = b->mins[2] = 99999; + b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; + + Brush_MakeFacePlanes (b); + + face = b->brush_faces; + + float fCurveColor = 1.0; + + for ( ; face ; face=face->next) + { + int i, j; + free(face->face_winding); + w = face->face_winding = Brush_MakeFaceWinding (b, face); + + if (!g_bBuildWindingsNoTexBuild || !face->d_texture) + { +#ifdef _DEBUG + // if there's no d_texture, then we expect pShader to be empty + if (!face->d_texture && face->pShader) + Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n"); +#endif + if ((!face->d_texture && !face->pShader) || !face->pShader) + { + // NOTE TTimo + // patch 84 for bug 253 doesn't dec ref the potential face->pShader + // add a debug check to make sure this is actually not necessary +#ifdef _DEBUG + if (face->pShader) + { + Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n"); + } +#endif + face->pShader = QERApp_Shader_ForName( face->texdef.GetName() ); + face->pShader->IncRef(); + face->d_texture = face->pShader->getTexture(); + } + } + + if (!w) + continue; + + for (i=0 ; inumpoints ; i++) + { + // add to bounding box + for (j=0 ; j<3 ; j++) + { + v = w->points[i][j]; + if (v > b->maxs[j]) + b->maxs[j] = v; + if (v < b->mins[j]) + b->mins[j] = v; + } + } + Face_SetColor (b, face, fCurveColor); + + fCurveColor -= .10f; + if (fCurveColor <= 0) + fCurveColor = 1.0f; + + // computing ST coordinates for the windings + if (g_qeglobals.m_bBrushPrimitMode) + { + if (g_qeglobals.bNeedConvert) + { + // we have parsed old brushes format and need conversion + // convert old brush texture representation to new format + FaceToBrushPrimitFace(face); +#ifdef _DEBUG + // use old texture coordinates code to check against + for (i=0 ; inumpoints ; i++) + EmitTextureCoordinates( w->points[i], face->d_texture, face); +#endif + } + // use new texture representation to compute texture coordinates + // in debug mode we will check against old code and warn if there are differences + EmitBrushPrimitTextureCoordinates(face,w); + } + else + { + if (g_qeglobals.bNeedConvert) + { + BrushPrimitFaceToFace(face); +/* + // we have parsed brush primitives and need conversion back to standard format + // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it + // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling + // I tried various tweaks, no luck .. seems shifting is lost + brushprimit_texdef_t aux; + ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); + TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); + face->texdef.scale[0]/=2.0; + face->texdef.scale[1]/=2.0; +*/ + } + for (i=0 ; inumpoints ; i++) + EmitTextureCoordinates( w->points[i], face->d_texture, face); + } + } +} + +/* +================== +Brush_RemoveEmptyFaces + +Frees any overconstraining faces +================== +*/ +void Brush_RemoveEmptyFaces ( brush_t *b ) +{ + face_t *f, *next; + + f = b->brush_faces; + b->brush_faces = NULL; + + for ( ; f ; f=next) + { + next = f->next; + if (!f->face_winding) + Face_Free (f); + else + { + f->next = b->brush_faces; + b->brush_faces = f; + } + + } +} + +void Brush_SnapToGrid(brush_t *pb) +{ + face_t *f; + vec3_t temp; + vec3_t diff[2]; + int mult[3]; + int i, j, n; + // TTimo: some brushes are "special" and should not be snapped + // specially fixed-size entity ones + if (pb->owner->eclass->fixedsize) + { + // save current origin + VectorCopy (pb->owner->origin, temp); + // snap the origin + VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize); + // return if amount is zero + if (VectorCompare (pb->owner->origin, temp)) + return; + // transform brush faces same amount + VectorSubtract (pb->owner->origin, temp, temp); + for (f = pb->brush_faces; f; f = f->next) + { + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], temp, f->planepts[i]); + } + } + else + { + for (f = pb->brush_faces ; f; f = f->next) + { + for (j=0; j<2; j++) + { + // spog - move planepts apart just far enough to avoid snapping two together + VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]); + for (i=0; i<3; i++) + { + if (diff[j][i] == 0.0f) + mult[i] = 2; // next value up from 1 + else // multiplier = gridsize / component difference, rounded up + mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i])); + } + + if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1 + { + n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2; + for (i=0; i<3; i++) + diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component + } + VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]); + } + + for (i=0; i<3; i++) + VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize); + + } + } + Brush_Build(pb,true,true,false,false); // don't filter +} + +void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild) +{ + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + for (int i=0 ; i<3 ; i++) + { + VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]); + } + } + if (bBuild) + { + Brush_Build(b,false,false,false,false); // don't filter + } +} + +void Brush_Center(brush_t *b, vec3_t vNewCenter) +{ + vec3_t vMid; + // get center of the brush + for (int j = 0; j < 3; j++) + { + vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5); + } + // calc distance between centers + VectorSubtract(vNewCenter, vMid, vMid); + Brush_Move(b, vMid, true); + +} + +void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax) +{ + face_t *f; + texdef_t texdef; + int i; + short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } }; + + for (i=0 ; i<3 ; i++) + if (vMax[i] < vMin[i]) + Error ("Brush_Resize: invalid input"); + + if(b->brush_faces != NULL) + texdef = b->brush_faces->texdef; + else + texdef = g_qeglobals.d_texturewin.texdef; + + while (b->brush_faces != NULL) + { + f = b->brush_faces->next; + Face_Free(b->brush_faces); + b->brush_faces = f; + } + + for(i=0; i<3; i++) + { + f = b->brush_faces; + b->brush_faces = Face_Alloc(); + b->brush_faces->next = f; + f = b->brush_faces; + f->texdef = texdef; + VectorCopy(vMax, f->planepts[0]); + VectorCopy(vMax, f->planepts[1]); + VectorCopy(vMax, f->planepts[2]); + f->planepts[2][box[i][0]] = vMin[box[i][0]]; + f->planepts[1][box[i][1]] = vMin[box[i][1]]; + } + for(i=0; i<3; i++) + { + f = b->brush_faces; + b->brush_faces = Face_Alloc(); + b->brush_faces->next = f; + f = b->brush_faces; + f->texdef = texdef; + VectorCopy(vMin, f->planepts[0]); + VectorCopy(vMin, f->planepts[1]); + VectorCopy(vMin, f->planepts[2]); + f->planepts[1][box[i][0]] = vMax[box[i][0]]; + f->planepts[2][box[i][1]] = vMax[box[i][1]]; + } +} + +void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up) +{ + int angleVal; + vec3_t angles; + + angleVal = IntForKey(e, "angle"); + if (angleVal == -1) // up + { + VectorSet(angles, 270, 0, 0); + } + else if(angleVal == -2) // down + { + VectorSet(angles, 90, 0, 0); + } + else + { + VectorSet(angles, 0, angleVal, 0); + } + + AngleVectors(angles, forward, right, up); +} + +void Brush_DrawFacingAngle (brush_t *b, entity_t *e) +{ + vec3_t forward, right, up; + vec3_t endpoint, tip1, tip2; + vec3_t start; + float dist; + + VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start); + VectorScale(start, 0.5, start); + dist = (b->maxs[0] - start[0]) * 2.5; + + FacingVectors (e, forward, right, up); + VectorMA (start, dist, forward, endpoint); + + dist = (b->maxs[0] - start[0]) * 0.5; + VectorMA (endpoint, -dist, forward, tip1); + VectorMA (tip1, -dist, up, tip1); + VectorMA (tip1, 2*dist, up, tip2); + + qglColor4f (1, 1, 1, 1); + qglLineWidth (4); + qglBegin (GL_LINES); + qglVertex3fv (start); + qglVertex3fv (endpoint); + qglVertex3fv (endpoint); + qglVertex3fv (tip1); + qglVertex3fv (endpoint); + qglVertex3fv (tip2); + qglEnd (); + qglLineWidth (1); +} + +void Brush_FaceDraw(face_t *face, int nGLState) +{ + const winding_t *w = face->face_winding; + if (w == NULL) return; + if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting) + qglNormal3fv(face->plane.normal); + /* + if (mode & DRAW_GL_TEXTURE_2D) + qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]); + qglVertexPointer(3, GL_FLOAT, 5, w->points); + + if (mode & DRAW_GL_FILL) + qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints); + else + qglDrawArrays(GL_POLYGON, 0, w->numpoints); + */ + + if (nGLState & DRAW_GL_FILL) + qglBegin(GL_TRIANGLE_FAN); + else + qglBegin(GL_POLYGON); + + for (int i=0 ; inumpoints ; i++) + { + if (nGLState & DRAW_GL_TEXTURE_2D) + qglTexCoord2fv( &w->points[i][3] ); + qglVertex3fv(w->points[i]); + } + qglEnd(); +} + +void Brush_Draw(brush_t *b) +{ + face_t *face; + int order; + qtexture_t *prev = 0; + winding_t *w; + + int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode; + int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate; + + GLfloat material[4], identity[4]; + VectorSet(identity, 0.8f, 0.8f, 0.8f); + IShader *pShader; + qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + qglDisableClientState(GL_NORMAL_ARRAY); + + // guarantee the texture will be set first + bool bTrans; + prev = NULL; + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + w = face->face_winding; + if (!w) + { + continue; // freed face + } + + bTrans = (face->pShader->getFlags() & QER_TRANS); + + if (bTrans && !(nGLState & DRAW_GL_BLEND)) + continue; + if (!bTrans && nGLState & DRAW_GL_BLEND) + continue; + + // IMPORTANT NOTE: + // modifications to the discarding code here should be matched in the selection code + // see Brush_Ray + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) + { + if (strstr(face->texdef.GetName(), "caulk")) + continue; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) + { + if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster")) + continue; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) + { + if (strstr(face->texdef.GetName(), "clip")) + continue; + } + + if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(') + { + prev = NULL; + qglDisable(GL_TEXTURE_2D); + } + else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev) + { + // set the texture for this face + prev = face->d_texture; + qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); + } + + if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting) + { + if (!b->owner->eclass->fixedsize) + material[3] = face->pShader->getTrans(); + else + material[3] = 1; + VectorCopy(face->d_color, material); + + if (nGLState & DRAW_GL_TEXTURE_2D) + qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]); + else + qglColor4fv(material); + } + else if (!b->owner->eclass->fixedsize) + { + pShader = face->pShader; + VectorCopy(pShader->getTexture()->color, material); + material[3] = identity[3] = pShader->getTrans(); + + if (nGLState & DRAW_GL_TEXTURE_2D) + qglColor4fv(identity); + else + qglColor4fv(material); + } + + // draw the polygon + + Brush_FaceDraw(face, nGLState); + } + qglPopClientAttrib(); +} + +void Face_Draw( face_t *f ) +{ + int i; + + if ( f->face_winding == 0 ) + return; + qglBegin(GL_POLYGON); + for ( i = 0 ; i < f->face_winding->numpoints; i++) + qglVertex3fv( f->face_winding->points[i] ); + qglEnd(); +} + +entity_t *FindEntity(const char *pszKey, const char *pszValue) +{ + entity_t *pe; + + pe = entities.next; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + if (!strcmp(ValueForKey(pe, pszKey), pszValue)) + return pe; + } + + return NULL; +} + +void Brush_DrawXY(brush_t *b, int nViewType) +{ + face_t *face; + int order; + winding_t *w; + int i; + + if (b->patchBrush) + { + Patch_DrawXY(b->pPatch); + if (!g_bPatchShowBounds) + return; + } + + if (b->owner->eclass->fixedsize) + { + if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT)) + { +#if 1 // requires vertex arrays enabled + DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType); +#else + vec3_t vCorners[4]; + float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2; + + vCorners[0][0] = b->mins[0]; + vCorners[0][1] = b->mins[1]; + vCorners[0][2] = fMid; + + vCorners[1][0] = b->mins[0]; + vCorners[1][1] = b->maxs[1]; + vCorners[1][2] = fMid; + + vCorners[2][0] = b->maxs[0]; + vCorners[2][1] = b->maxs[1]; + vCorners[2][2] = fMid; + + vCorners[3][0] = b->maxs[0]; + vCorners[3][1] = b->mins[1]; + vCorners[3][2] = fMid; + + vec3_t vTop, vBottom; + + vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2); + vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2); + vTop[2] = b->maxs[2]; + + VectorCopy(vTop, vBottom); + vBottom[2] = b->mins[2]; + + qglBegin(GL_LINES); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[0]); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[1]); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[2]); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[3]); + qglEnd(); + + qglBegin(GL_LINES); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[0]); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[1]); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[2]); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[3]); + qglEnd(); + + qglBegin(GL_LINE_LOOP); + qglVertex3fv(vCorners[0]); + qglVertex3fv(vCorners[1]); + qglVertex3fv(vCorners[2]); + qglVertex3fv(vCorners[3]); + qglEnd(); +#endif + DrawBrushEntityName (b); + return; + } + else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))) + { + qglPushAttrib(GL_CURRENT_BIT); // save brush colour + qglColor3fv(b->owner->eclass->color); + if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX ) + b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY); + aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + qglPopAttrib(); + return; + } + //} + } + + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + // moved so check occurs earlier + w = face->face_winding; + if (!w) + continue; + // only draw polygons facing in a direction we care about + if (nViewType == XY) + { + if (face->plane.normal[2] <= 0) + continue; + } + else + { + if (nViewType == XZ) + { + if (face->plane.normal[1] >= 0) // stop axes being mirrored + continue; + } + else + { + if (face->plane.normal[0] <= 0) + continue; + } + } + + // draw the polygon + qglBegin(GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + qglVertex3fv(w->points[i]); + qglEnd(); + } + + DrawBrushEntityName (b); + +} + +/* +============ +Brush_Move +============ +*/ +void Brush_Move (brush_t *b, const vec3_t move, bool bSnap) +{ + int i; + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], move, f->planepts[i]); + + if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize) + { + for (f=b->brush_faces ; f ; f=f->next) + { + vec3_t vTemp; + VectorCopy(move, vTemp); + Face_MoveTexture(f, vTemp); + } + } + + Brush_Build( b, bSnap,true,false,false); // don't filter + + + if (b->patchBrush) + { + //Patch_Move(b->nPatchID, move); + Patch_Move(b->pPatch, move); + } + + + // PGM - keep the origin vector up to date on fixed size entities. + if(b->owner->eclass->fixedsize) + { + char text[64]; + VectorAdd(b->owner->origin, move, b->owner->origin); + sprintf (text, "%i %i %i", + (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); + SetKeyValue(b->owner, "origin", text); + //VectorAdd(b->maxs, b->mins, b->owner->origin); + //VectorScale(b->owner->origin, 0.5, b->owner->origin); + } +} + + + +void Brush_Print(brush_t* b) +{ + int nFace = 0; + for (face_t* f = b->brush_faces ; f ; f=f->next) + { + Sys_Printf("Face %i\n", nFace++); + Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]); + Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]); + Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]); + } + } + + + +/* +============= +Brush_MakeSided + +Makes the current brushhave the given number of 2d sides and turns it into a cone +============= +*/ +void Brush_MakeSidedCone(int sides) +{ + int i; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float sv, cv; + + if (sides < 3 || sides > 32) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + // find center of brush + width = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > width) + width = maxs[i] - mins[i]; + } + width /= 2; + + b = Brush_Alloc(); + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; + f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; + f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; + + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + sv = sin (i*3.14159265*2/sides); + cv = cos (i*3.14159265*2/sides); + + + f->planepts[0][0] = floor(mid[0]+width*cv+0.5); + f->planepts[0][1] = floor(mid[1]+width*sv+0.5); + f->planepts[0][2] = mins[2]; + + f->planepts[1][0] = mid[0]; + f->planepts[1][1] = mid[1]; + f->planepts[1][2] = maxs[2]; + + f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5); + f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5); + f->planepts[2][2] = maxs[2]; + + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Brush_MakeSided + +Makes the current brushhave the given number of 2d sides and turns it into a sphere +============= + +*/ +void Brush_MakeSidedSphere(int sides) +{ + int i,j; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + + if (sides < 4 || sides > 32) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + // find center of brush + float radius = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > radius) + radius = maxs[i] - mins[i]; + } + radius /= 2; + + b = Brush_Alloc(); + + float dt = float(2 * Q_PI / sides); + float dp = float(Q_PI / sides); + float t,p; + for(i=0; i <= sides-1; i++) + { + for(j=0;j <= sides-2; j++) + { + t = i * dt; + p = float(j * dp - Q_PI / 2); + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorPolar(f->planepts[0], radius, t, p); + VectorPolar(f->planepts[1], radius, t, p + dp); + VectorPolar(f->planepts[2], radius, t + dt, p + dp); + + for (int k = 0; k < 3; k++) + VectorAdd(f->planepts[k], mid, f->planepts[k]); + } + } + + p = float((sides - 1) * dp - Q_PI / 2); + for(i = 0; i <= sides-1; i++) + { + t = i * dt; + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorPolar(f->planepts[0], radius, t, p); + VectorPolar(f->planepts[1], radius, t + dt, p + dp); + VectorPolar(f->planepts[2], radius, t + dt, p); + + for (int k = 0; k < 3; k++) + VectorAdd(f->planepts[k], mid, f->planepts[k]); + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + +void Face_FitTexture( face_t * face, int nHeight, int nWidth ) +{ + winding_t *w; + vec3_t mins,maxs; + int i; + float width, height, temp; + float rot_width, rot_height; + float cosv,sinv,ang; + float min_t, min_s, max_t, max_s; + float s,t; + vec3_t vecs[2]; + vec3_t coords[4]; + texdef_t *td; + + if (nHeight < 1) + nHeight = 1; + if (nWidth < 1) + nWidth = 1; + + ClearBounds (mins, maxs); + + w = face->face_winding; + if (!w) + { + return; + } + for (i=0 ; inumpoints ; i++) + { + AddPointToBounds( w->points[i], mins, maxs ); + } + + if (g_qeglobals.m_bBrushPrimitMode) + Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth ); + else + { + + td = &face->texdef; + // + // get the current angle + // + ang = td->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + + // get natural texture axis + TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); + + min_s = DotProduct( mins, vecs[0] ); + min_t = DotProduct( mins, vecs[1] ); + max_s = DotProduct( maxs, vecs[0] ); + max_t = DotProduct( maxs, vecs[1] ); + width = max_s - min_s; + height = max_t - min_t; + coords[0][0] = min_s; + coords[0][1] = min_t; + coords[1][0] = max_s; + coords[1][1] = min_t; + coords[2][0] = min_s; + coords[2][1] = max_t; + coords[3][0] = max_s; + coords[3][1] = max_t; + min_s = min_t = 99999; + max_s = max_t = -99999; + for (i=0; i<4; i++) + { + s = cosv * coords[i][0] - sinv * coords[i][1]; + t = sinv * coords[i][0] + cosv * coords[i][1]; + if (i&1) + { + if (s > max_s) + { + max_s = s; + } + } + else + { + if (s < min_s) + { + min_s = s; + } + if (i<2) + { + if (t < min_t) + { + min_t = t; + } + } + else + { + if (t > max_t) + { + max_t = t; + } + } + } + } + rot_width = (max_s - min_s); + rot_height = (max_t - min_t); + td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth))); + td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight))); + + td->shift[0] = min_s/td->scale[0]; + temp = (int)(td->shift[0] / (face->d_texture->width*nWidth)); + temp = (temp+1)*face->d_texture->width*nWidth; + td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth); + + td->shift[1] = min_t/td->scale[1]; + temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); + temp = (temp+1)*(face->d_texture->height*nHeight); + td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); + + td->shift[1] = min_t/td->scale[1]; + temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); + temp = (temp+1)*(face->d_texture->height*nHeight); + td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); + + } +} + +void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ) +{ + face_t *face; + + for (face = b->brush_faces ; face ; face=face->next) + { + Face_FitTexture( face, nHeight, nWidth ); + } +} + +void aabb_draw(const aabb_t *aabb, int mode) +{ + vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } }; + vec3_t points[8]; + vec3_t vMin, vMax; + VectorSubtract(aabb->origin, aabb->extents, vMin); + VectorAdd(aabb->origin, aabb->extents, vMax); + VectorSet(points[0], vMin[0], vMax[1], vMax[2]); + VectorSet(points[1], vMax[0], vMax[1], vMax[2]); + VectorSet(points[2], vMax[0], vMin[1], vMax[2]); + VectorSet(points[3], vMin[0], vMin[1], vMax[2]); + VectorSet(points[4], vMin[0], vMax[1], vMin[2]); + VectorSet(points[5], vMax[0], vMax[1], vMin[2]); + VectorSet(points[6], vMax[0], vMin[1], vMin[2]); + VectorSet(points[7], vMin[0], vMin[1], vMin[2]); + + qglBegin(GL_QUADS); + + qglNormal3fv(normals[0]); + qglVertex3fv(points[2]); + qglVertex3fv(points[1]); + qglVertex3fv(points[5]); + qglVertex3fv(points[6]); + + qglNormal3fv(normals[1]); + qglVertex3fv(points[1]); + qglVertex3fv(points[0]); + qglVertex3fv(points[4]); + qglVertex3fv(points[5]); + + qglNormal3fv(normals[2]); + qglVertex3fv(points[0]); + qglVertex3fv(points[1]); + qglVertex3fv(points[2]); + qglVertex3fv(points[3]); + + qglNormal3fv(normals[3]); + qglVertex3fv(points[3]); + qglVertex3fv(points[7]); + qglVertex3fv(points[4]); + qglVertex3fv(points[0]); + + qglNormal3fv(normals[4]); + qglVertex3fv(points[3]); + qglVertex3fv(points[2]); + qglVertex3fv(points[6]); + qglVertex3fv(points[7]); + + qglNormal3fv(normals[5]); + qglVertex3fv(points[7]); + qglVertex3fv(points[6]); + qglVertex3fv(points[5]); + qglVertex3fv(points[4]); + + qglEnd(); + +/* + + + vec3_t Coords[8]; + + vec3_t vMin, vMax; + VectorSubtract(aabb->origin, aabb->extents, vMin); + VectorAdd(aabb->origin, aabb->extents, vMax); + VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]); + VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]); + VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]); + VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]); + VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]); + VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]); + VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]); + VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]); + + vec3_t Normals[8] = { {-1, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 1 }, + { 0, 0,-1 }, + { 0, 1, 0 }, + { 1, 0, 0 }, + { 0,-1, 0 } }; + + unsigned short Indices[24] = { 2, 1, 5, 6, + 1, 0, 4, 5, + 0, 1, 2, 3, + 3, 7, 4, 0, + 3, 2, 6, 7, + 7, 6, 5, 4 }; + + qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays + qglNormalPointer(GL_FLOAT, 0, Normals); + + //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array + + qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices); + + //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array +*/ +} + +qboolean IsBrushSelected(brush_t* bSel) +{ + for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next) + { + if (b == bSel) + return true; + } + return false; +} + + diff --git a/radiant/brush.h b/radiant/brush.h new file mode 100644 index 00000000..dc0a6641 --- /dev/null +++ b/radiant/brush.h @@ -0,0 +1,89 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +// brush.h + +// some usefull flags to control the behaviour of Brush_Build +extern bool g_bBuildWindingsNoTexBuild; + +void Brush_AddToList (brush_t *b, brush_t *lst); +void Brush_Build(brush_t *b, bool bSnap = true, bool bMarkMap = true, bool bConvert = false, bool bFilterTest = true); +void Brush_SetBuildWindingsNoTexBuild(bool bBuild); +void Brush_BuildWindings( brush_t *b, bool bSnap = true ); +brush_t* Brush_Clone (brush_t *b); +brush_t* Brush_FullClone(brush_t *b); +brush_t* Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef); +void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax); +void Brush_FaceDraw(face_t *face, int nGLState); +void Brush_Draw( brush_t *b ); +void Brush_DrawXY(brush_t *b, int nViewType); +// set bRemoveNode to false to avoid trying to delete the item in group view tree control +void Brush_Free (brush_t *b, bool bRemoveNode = true); +int Brush_MemorySize(brush_t *b); +void Brush_MakeSided (int sides); +void Brush_MakeSidedCone (int sides); +void Brush_Move (brush_t *b, const vec3_t move, bool bSnap = true); +int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap = true); +void Brush_ResetFaceOriginals(brush_t *b); +face_t* Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags = 0); +void Brush_RemoveFromList (brush_t *b); +// bCaulk means the faces created during the operation will be caulked, this is used in conjunction with g_PrefsDlg.m_bClipCaulk +void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk = false); +void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear); +void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, IPluginTexdef* pPlugTexdef= (IPluginTexdef*)NULL); +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir, qboolean shear); +void Brush_SnapToGrid(brush_t *pb); +void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild = true); +void Brush_MakeSidedSphere(int sides); +//void Brush_Write (brush_t *b, FILE *f); +//void Brush_Write (brush_t *b, MemStream* pMemFile); +void Brush_RemoveEmptyFaces ( brush_t *b ); +winding_t* Brush_MakeFaceWinding (brush_t *b, face_t *face); + +void Brush_RefreshShader(brush_t *b); + +int AddPlanept (float *f); +float SetShadeForPlane (plane_t *p); + +face_t* Face_Alloc( void ); +void Face_Free( face_t *f ); +face_t* Face_Clone (face_t *f); +void Face_SetShader(face_t *face, const char *name); +/*! +faster version if you know the IShader already +(instead of hash table lookup by name) +*/ +void Face_SetShader(face_t *face, IShader *shader); +void Face_MakePlane (face_t *f); +void Face_Draw( face_t *face ); +void Face_TextureVectors (face_t *f, float STfromXYZ[2][4]); +void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, IPluginTexdef* pPlugTexdef = NULL ); + +void Face_FitTexture( face_t * face, int nHeight, int nWidth ); +void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ); +//void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue); +//const char* Brush_GetKeyValue(brush_t *b, const char *pKey); +brush_t *Brush_Alloc(); +const char* Brush_Name(brush_t *b); + +//eclass_t* HasModel(brush_t *b); +void aabb_draw(const aabb_t *aabb, int mode); diff --git a/radiant/brush_primit.cpp b/radiant/brush_primit.cpp new file mode 100644 index 00000000..22fca0ad --- /dev/null +++ b/radiant/brush_primit.cpp @@ -0,0 +1,600 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" + +// compute a determinant using Sarrus rule +//++timo "inline" this with a macro +// NOTE : the three vec3_t are understood as columns of the matrix +vec_t SarrusDet(vec3_t a, vec3_t b, vec3_t c) +{ + return a[0]*b[1]*c[2]+b[0]*c[1]*a[2]+c[0]*a[1]*b[2] + -c[0]*b[1]*a[2]-a[1]*b[0]*c[2]-a[0]*b[2]*c[1]; +} + +// in many case we know three points A,B,C in two axis base B1 and B2 +// and we want the matrix M so that A(B1) = T * A(B2) +// NOTE: 2D homogeneous space stuff +// NOTE: we don't do any check to see if there's a solution or we have a particular case .. need to make sure before calling +// NOTE: the third coord of the A,B,C point is ignored +// NOTE: see the commented out section to fill M and D +//++timo TODO: update the other members to use this when possible +void MatrixForPoints( vec3_t M[3], vec3_t D[2], brushprimit_texdef_t *T ) +{ +// vec3_t M[3]; // columns of the matrix .. easier that way (the indexing is not standard! it's column-line .. later computations are easier that way) + vec_t det; +// vec3_t D[2]; + M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; +#if 0 + // fill the data vectors + M[0][0]=A2[0]; M[0][1]=B2[0]; M[0][2]=C2[0]; + M[1][0]=A2[1]; M[1][1]=B2[1]; M[1][2]=C2[1]; + M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; + D[0][0]=A1[0]; + D[0][1]=B1[0]; + D[0][2]=C1[0]; + D[1][0]=A1[1]; + D[1][1]=B1[1]; + D[1][2]=C1[1]; +#endif + // solve + det = SarrusDet( M[0], M[1], M[2] ); + T->coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; + T->coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; + T->coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; + T->coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; + T->coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; + T->coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; +} + +//++timo replace everywhere texX by texS etc. ( ----> and in q3map !) +// NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME ! +// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0 +// rotation by (0,RotY,RotZ) assigns X to normal +void ComputeAxisBase(vec3_t normal,vec3_t texS,vec3_t texT ) +{ + vec_t RotY,RotZ; + // do some cleaning + if (fabs(normal[0])<1e-6) + normal[0]=0.0f; + if (fabs(normal[1])<1e-6) + normal[1]=0.0f; + if (fabs(normal[2])<1e-6) + normal[2]=0.0f; + RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0])); + RotZ=atan2(normal[1],normal[0]); + // rotate (0,1,0) and (0,0,1) to compute texS and texT + texS[0]=-sin(RotZ); + texS[1]=cos(RotZ); + texS[2]=0; + // the texT vector is along -Z ( T texture coorinates axis ) + texT[0]=-sin(RotY)*cos(RotZ); + texT[1]=-sin(RotY)*sin(RotZ); + texT[2]=-cos(RotY); +} + +void FaceToBrushPrimitFace(face_t *f) +{ + vec3_t texX,texY; + vec3_t proj; + // ST of (0,0) (1,0) (0,1) + vec_t ST[3][5]; // [ point index ] [ xyz ST ] + //++timo not used as long as brushprimit_texdef and texdef are static +/* f->brushprimit_texdef.contents=f->texdef.contents; + f->brushprimit_texdef.flags=f->texdef.flags; + f->brushprimit_texdef.value=f->texdef.value; + strcpy(f->brushprimit_texdef.name,f->texdef.name); */ +#ifdef DBG_BP + if ( f->plane.normal[0]==0.0f && f->plane.normal[1]==0.0f && f->plane.normal[2]==0.0f ) + { + Sys_Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n"); + } + // check d_texture + if (!f->d_texture) + { + Sys_Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n"); + return; + } +#endif + // compute axis base + ComputeAxisBase(f->plane.normal,texX,texY); + // compute projection vector + VectorCopy(f->plane.normal,proj); + VectorScale(proj,f->plane.dist,proj); + // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane + // (1,0) in plane axis base is texX in world coordinates + projection on the affine plane + // (0,1) in plane axis base is texY in world coordinates + projection on the affine plane + // use old texture code to compute the ST coords of these points + VectorCopy(proj,ST[0]); + EmitTextureCoordinates(ST[0], f->d_texture, f); + VectorCopy(texX,ST[1]); + VectorAdd(ST[1],proj,ST[1]); + EmitTextureCoordinates(ST[1], f->d_texture, f); + VectorCopy(texY,ST[2]); + VectorAdd(ST[2],proj,ST[2]); + EmitTextureCoordinates(ST[2], f->d_texture, f); + // compute texture matrix + f->brushprimit_texdef.coords[0][2]=ST[0][3]; + f->brushprimit_texdef.coords[1][2]=ST[0][4]; + f->brushprimit_texdef.coords[0][0]=ST[1][3]-f->brushprimit_texdef.coords[0][2]; + f->brushprimit_texdef.coords[1][0]=ST[1][4]-f->brushprimit_texdef.coords[1][2]; + f->brushprimit_texdef.coords[0][1]=ST[2][3]-f->brushprimit_texdef.coords[0][2]; + f->brushprimit_texdef.coords[1][1]=ST[2][4]-f->brushprimit_texdef.coords[1][2]; +} + +// compute texture coordinates for the winding points +void EmitBrushPrimitTextureCoordinates(face_t * f, winding_t * w) +{ + vec3_t texX,texY; + vec_t x,y; + // compute axis base + ComputeAxisBase(f->plane.normal,texX,texY); + // in case the texcoords matrix is empty, build a default one + // same behaviour as if scale[0]==0 && scale[1]==0 in old code + if (f->brushprimit_texdef.coords[0][0]==0 && f->brushprimit_texdef.coords[1][0]==0 && f->brushprimit_texdef.coords[0][1]==0 && f->brushprimit_texdef.coords[1][1]==0) + { + f->brushprimit_texdef.coords[0][0] = 1.0f; + f->brushprimit_texdef.coords[1][1] = 1.0f; + ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); + } + int i; + for (i=0 ; inumpoints ; i++) + { + x=DotProduct(w->points[i],texX); + y=DotProduct(w->points[i],texY); +#ifdef DBG_BP + if (g_qeglobals.bNeedConvert) + { + // check we compute the same ST as the traditional texture computation used before + vec_t S=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; + vec_t T=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; + if ( fabs(S-w->points[i][3])>1e-2 || fabs(T-w->points[i][4])>1e-2 ) + { + if ( fabs(S-w->points[i][3])>1e-4 || fabs(T-w->points[i][4])>1e-4 ) + Sys_Printf("Warning : precision loss in brush -> brush primitive texture computation\n"); + else + Sys_Printf("Warning : brush -> brush primitive texture computation bug detected\n"); + } + } +#endif + w->points[i][3]=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; + w->points[i][4]=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; + } +} + +// compute a fake shift scale rot representation from the texture matrix +// these shift scale rot values are to be understood in the local axis base +void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] ) +{ +#ifdef DBG_BP + // check this matrix is orthogonal + if (fabs(texMat[0][0]*texMat[0][1]+texMat[1][0]*texMat[1][1])>ZERO_EPSILON) + Sys_Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n"); +#endif + scale[0]=sqrt(texMat[0][0]*texMat[0][0]+texMat[1][0]*texMat[1][0]); + scale[1]=sqrt(texMat[0][1]*texMat[0][1]+texMat[1][1]*texMat[1][1]); +#ifdef DBG_BP + if (scale[0]0) + *rot=90.0f; + else + *rot=-90.0f; + } + else + *rot = RAD2DEG( atan2( texMat[1][0], texMat[0][0] ) ); + shift[0] = -texMat[0][2]; + shift[1] = texMat[1][2]; +} + +// compute back the texture matrix from fake shift scale rot +// the matrix returned must be understood as a qtexture_t with width=2 height=2 ( the default one ) +void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] ) +{ + texMat[0][0] = scale[0] * cos( DEG2RAD( rot ) ); + texMat[1][0] = scale[0] * sin( DEG2RAD( rot ) ); + texMat[0][1] = -1.0f * scale[1] * sin( DEG2RAD( rot ) ); + texMat[1][1] = scale[1] * cos( DEG2RAD( rot ) ); + texMat[0][2] = -shift[0]; + texMat[1][2] = shift[1]; +} + +// convert a texture matrix between two qtexture_t +// if NULL for qtexture_t, basic 2x2 texture is assumed ( straight mapping between s/t coordinates and geometric coordinates ) +void ConvertTexMatWithQTexture( vec_t texMat1[2][3], qtexture_t *qtex1, vec_t texMat2[2][3], qtexture_t *qtex2 ) +{ + float s1,s2; + s1 = ( qtex1 ? static_cast( qtex1->width ) : 2.0f ) / ( qtex2 ? static_cast( qtex2->width ) : 2.0f ); + s2 = ( qtex1 ? static_cast( qtex1->height ) : 2.0f ) / ( qtex2 ? static_cast( qtex2->height ) : 2.0f ); + texMat2[0][0]=s1*texMat1[0][0]; + texMat2[0][1]=s1*texMat1[0][1]; + texMat2[0][2]=s1*texMat1[0][2]; + texMat2[1][0]=s2*texMat1[1][0]; + texMat2[1][1]=s2*texMat1[1][1]; + texMat2[1][2]=s2*texMat1[1][2]; +} + +void ConvertTexMatWithQTexture( brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2 ) +{ + ConvertTexMatWithQTexture(texMat1->coords, qtex1, texMat2->coords, qtex2); +} + +// used for texture locking +// will move the texture according to a geometric vector +void ShiftTextureGeometric_BrushPrimit(face_t *f, vec3_t delta) +{ + vec3_t texS,texT; + vec_t tx,ty; + vec3_t M[3]; // columns of the matrix .. easier that way + vec_t det; + vec3_t D[2]; + // compute plane axis base ( doesn't change with translation ) + ComputeAxisBase( f->plane.normal, texS, texT ); + // compute translation vector in plane axis base + tx = DotProduct( delta, texS ); + ty = DotProduct( delta, texT ); + // fill the data vectors + M[0][0]=tx; M[0][1]=1.0f+tx; M[0][2]=tx; + M[1][0]=ty; M[1][1]=ty; M[1][2]=1.0f+ty; + M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; + D[0][0]=f->brushprimit_texdef.coords[0][2]; + D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; + D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; + D[1][0]=f->brushprimit_texdef.coords[1][2]; + D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; + D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; + // solve + det = SarrusDet( M[0], M[1], M[2] ); + f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; + f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; + f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; +} + +// shift a texture (texture adjustments) along it's current texture axes +// x and y are geometric values, which we must compute as ST increments +// this depends on the texture size and the pixel/texel ratio +void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y) +{ + float s,t; + // as a ratio against texture size + // the scale of the texture is not relevant here (we work directly on a transformation from the base vectors) + s = (x * 2.0) / (float)f->d_texture->width; + t = (y * 2.0) / (float)f->d_texture->height; + f->brushprimit_texdef.coords[0][2] -= s; + f->brushprimit_texdef.coords[1][2] -= t; +} + +// TTimo: FIXME: I don't like that, it feels broken +// (and it's likely that it's not used anymore) +// best fitted 2D vector is x.X+y.Y +void ComputeBest2DVector( vec3_t v, vec3_t X, vec3_t Y, int &x, int &y ) +{ + double sx,sy; + sx = DotProduct( v, X ); + sy = DotProduct( v, Y ); + if ( fabs(sy) > fabs(sx) ) + { + x = 0; + if ( sy > 0.0 ) + y = 1; + else + y = -1; + } + else + { + y = 0; + if ( sx > 0.0 ) + x = 1; + else + x = -1; + } +} + +//++timo FIXME quick'n dirty hack, doesn't care about current texture settings (angle) +// can be improved .. bug #107311 +// mins and maxs are the face bounding box +//++timo fixme: we use the face info, mins and maxs are irrelevant +void Face_FitTexture_BrushPrimit( face_t *f, vec3_t mins, vec3_t maxs, int nHeight, int nWidth ) +{ + vec3_t BBoxSTMin, BBoxSTMax; + winding_t *w; + int i,j; + vec_t val; + vec3_t M[3],D[2]; +// vec3_t N[2],Mf[2]; + brushprimit_texdef_t N; + vec3_t Mf[2]; + + + // we'll be working on a standardized texture size +// ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &f->brushprimit_texdef, NULL ); + // compute the BBox in ST coords + EmitBrushPrimitTextureCoordinates( f, f->face_winding ); + ClearBounds( BBoxSTMin, BBoxSTMax ); + w = f->face_winding; + for (i=0 ; inumpoints ; i++) + { + // AddPointToBounds in 2D on (S,T) coordinates + for (j=0 ; j<2 ; j++) + { + val = w->points[i][j+3]; + if (val < BBoxSTMin[j]) + BBoxSTMin[j] = val; + if (val > BBoxSTMax[j]) + BBoxSTMax[j] = val; + } + } + // we have the three points of the BBox (BBoxSTMin[0].BBoxSTMin[1]) (BBoxSTMax[0],BBoxSTMin[1]) (BBoxSTMin[0],BBoxSTMax[1]) in ST space + // the BP matrix we are looking for gives (0,0) (nwidth,0) (0,nHeight) coordinates in (Sfit,Tfit) space to these three points + // we have A(Sfit,Tfit) = (0,0) = Mf * A(TexS,TexT) = N * M * A(TexS,TexT) = N * A(S,T) + // so we solve the system for N and then Mf = N * M + M[0][0] = BBoxSTMin[0]; M[0][1] = BBoxSTMax[0]; M[0][2] = BBoxSTMin[0]; + M[1][0] = BBoxSTMin[1]; M[1][1] = BBoxSTMin[1]; M[1][2] = BBoxSTMax[1]; + D[0][0] = 0.0f; D[0][1] = nWidth; D[0][2] = 0.0f; + D[1][0] = 0.0f; D[1][1] = 0.0f; D[1][2] = nHeight; + MatrixForPoints( M, D, &N ); + +#if 0 + // FIT operation gives coordinates of three points of the bounding box in (S',T'), our target axis base + // A(S',T')=(0,0) B(S',T')=(nWidth,0) C(S',T')=(0,nHeight) + // and we have them in (S,T) axis base: A(S,T)=(BBoxSTMin[0],BBoxSTMin[1]) B(S,T)=(BBoxSTMax[0],BBoxSTMin[1]) C(S,T)=(BBoxSTMin[0],BBoxSTMax[1]) + // we compute the N transformation so that: A(S',T') = N * A(S,T) + VectorSet( N[0], (BBoxSTMax[0]-BBoxSTMin[0])/(float)nWidth, 0.0f, BBoxSTMin[0] ); + VectorSet( N[1], 0.0f, (BBoxSTMax[1]-BBoxSTMin[1])/(float)nHeight, BBoxSTMin[1] ); +#endif + + // the final matrix is the product (Mf stands for Mfit) + Mf[0][0] = N.coords[0][0] * f->brushprimit_texdef.coords[0][0] + N.coords[0][1] * f->brushprimit_texdef.coords[1][0]; + Mf[0][1] = N.coords[0][0] * f->brushprimit_texdef.coords[0][1] + N.coords[0][1] * f->brushprimit_texdef.coords[1][1]; + Mf[0][2] = N.coords[0][0] * f->brushprimit_texdef.coords[0][2] + N.coords[0][1] * f->brushprimit_texdef.coords[1][2] + N.coords[0][2]; + Mf[1][0] = N.coords[1][0] * f->brushprimit_texdef.coords[0][0] + N.coords[1][1] * f->brushprimit_texdef.coords[1][0]; + Mf[1][1] = N.coords[1][0] * f->brushprimit_texdef.coords[0][1] + N.coords[1][1] * f->brushprimit_texdef.coords[1][1]; + Mf[1][2] = N.coords[1][0] * f->brushprimit_texdef.coords[0][2] + N.coords[1][1] * f->brushprimit_texdef.coords[1][2] + N.coords[1][2]; + // copy back + VectorCopy( Mf[0], f->brushprimit_texdef.coords[0] ); + VectorCopy( Mf[1], f->brushprimit_texdef.coords[1] ); + // handle the texture size +// ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); +} + +void BrushPrimitFaceToFace(face_t *face) +{ + // we have parsed brush primitives and need conversion back to standard format + // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it + // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling + // I tried various tweaks, no luck .. seems shifting is lost + brushprimit_texdef_t aux; + ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); + TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); + face->texdef.scale[0]/=2.0; + face->texdef.scale[1]/=2.0; +} + +// TEXTURE LOCKING ----------------------------------------------------------------------------------------------------- +// (Relevant to the editor only?) + +// internally used for texture locking on rotation and flipping +// the general algorithm is the same for both lockings, it's only the geometric transformation part that changes +// so I wanted to keep it in a single function +// if there are more linear transformations that need the locking, going to a C++ or code pointer solution would be best +// (but right now I want to keep brush_primit.cpp striclty C) + +qboolean txlock_bRotation; + +// rotation locking params +int txl_nAxis; +float txl_fDeg; +vec3_t txl_vOrigin; + +// flip locking params +vec3_t txl_matrix[3]; +vec3_t txl_origin; + +void TextureLockTransformation_BrushPrimit(face_t *f) +{ + vec3_t Orig,texS,texT; // axis base of initial plane + // used by transformation algo + vec3_t temp; int j; + vec3_t vRotate; // rotation vector + + vec3_t rOrig,rvecS,rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base } + vec3_t rNormal,rtexS,rtexT; // axis base for the transformed plane + vec3_t lOrig,lvecS,lvecT; // [2] are not used ( but usefull for debugging ) + vec3_t M[3]; + vec_t det; + vec3_t D[2]; + + // compute plane axis base + ComputeAxisBase( f->plane.normal, texS, texT ); + VectorSet(Orig, 0.0f, 0.0f, 0.0f); + + // compute coordinates of (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) after transformation + // (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) <-> (0,0,0) texS texT ( expressed world axis base ) + // input: Orig, texS, texT (and the global locking params) + // ouput: rOrig, rvecS, rvecT, rNormal + if (txlock_bRotation) { + // rotation vector + VectorSet( vRotate, 0.0f, 0.0f, 0.0f ); + vRotate[txl_nAxis]=txl_fDeg; + VectorRotateOrigin ( Orig, vRotate, txl_vOrigin, rOrig ); + VectorRotateOrigin ( texS, vRotate, txl_vOrigin, rvecS ); + VectorRotateOrigin ( texT, vRotate, txl_vOrigin, rvecT ); + // compute normal of plane after rotation + VectorRotate ( f->plane.normal, vRotate, rNormal ); + } + else + { + VectorSubtract (Orig, txl_origin, temp); + for (j=0 ; j<3 ; j++) + rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; + VectorSubtract (texS, txl_origin, temp); + for (j=0 ; j<3 ; j++) + rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; + VectorSubtract (texT, txl_origin, temp); + for (j=0 ; j<3 ; j++) + rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; + // we also need the axis base of the target plane, apply the transformation matrix to the normal too.. + for (j=0 ; j<3 ; j++) + rNormal[j] = DotProduct(f->plane.normal, txl_matrix[j]); + } + + // compute rotated plane axis base + ComputeAxisBase( rNormal, rtexS, rtexT ); + // compute S/T coordinates of the three points in rotated axis base ( in M matrix ) + lOrig[0] = DotProduct( rOrig, rtexS ); + lOrig[1] = DotProduct( rOrig, rtexT ); + lvecS[0] = DotProduct( rvecS, rtexS ); + lvecS[1] = DotProduct( rvecS, rtexT ); + lvecT[0] = DotProduct( rvecT, rtexS ); + lvecT[1] = DotProduct( rvecT, rtexT ); + M[0][0] = lOrig[0]; M[1][0] = lOrig[1]; M[2][0] = 1.0f; + M[0][1] = lvecS[0]; M[1][1] = lvecS[1]; M[2][1] = 1.0f; + M[0][2] = lvecT[0]; M[1][2] = lvecT[1]; M[2][2] = 1.0f; + // fill data vector + D[0][0]=f->brushprimit_texdef.coords[0][2]; + D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; + D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; + D[1][0]=f->brushprimit_texdef.coords[1][2]; + D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; + D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; + // solve + det = SarrusDet( M[0], M[1], M[2] ); + f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; + f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; + f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; +} + +// texture locking +// called before the points on the face are actually rotated +void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin ) +{ + // this is a placeholder to call the general texture locking algorithm + txlock_bRotation = true; + txl_nAxis = nAxis; + txl_fDeg = fDeg; + VectorCopy(vOrigin, txl_vOrigin); + TextureLockTransformation_BrushPrimit(f); +} + +// compute the new brush primit texture matrix for a transformation matrix and a flip order flag (change plane orientation) +// this matches the select_matrix algo used in select.cpp +// this needs to be called on the face BEFORE any geometric transformation +// it will compute the texture matrix that will represent the same texture on the face after the geometric transformation is done +void ApplyMatrix_BrushPrimit(face_t *f, vec3_t matrix[3], vec3_t origin) +{ + // this is a placeholder to call the general texture locking algorithm + txlock_bRotation = false; + VectorCopy(matrix[0], txl_matrix[0]); + VectorCopy(matrix[1], txl_matrix[1]); + VectorCopy(matrix[2], txl_matrix[2]); + VectorCopy(origin, txl_origin); + TextureLockTransformation_BrushPrimit(f); +} + +// don't do C==A! +void BPMatMul(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]) +{ + C[0][0] = A[0][0]*B[0][0]+A[0][1]*B[1][0]; + C[1][0] = A[1][0]*B[0][0]+A[1][1]*B[1][0]; + C[0][1] = A[0][0]*B[0][1]+A[0][1]*B[1][1]; + C[1][1] = A[1][0]*B[0][1]+A[1][1]*B[1][1]; + C[0][2] = A[0][0]*B[0][2]+A[0][1]*B[1][2]+A[0][2]; + C[1][2] = A[1][0]*B[0][2]+A[1][1]*B[1][2]+A[1][2]; +} + +void BPMatDump(vec_t A[2][3]) +{ + Sys_Printf("%g %g %g\n%g %g %g\n0 0 1\n", A[0][0], A[0][1], A[0][2], A[1][0], A[1][1], A[1][2]); +} + +void BPMatRotate(vec_t A[2][3], float theta) +{ + vec_t m[2][3]; + vec_t aux[2][3]; + memset(&m, 0, sizeof(vec_t)*6); + m[0][0] = cos(theta*Q_PI/180.0); + m[0][1] = -sin(theta*Q_PI/180.0); + m[1][0] = -m[0][1]; + m[1][1] = m[0][0]; + BPMatMul(A, m, aux); + BPMatCopy(aux,A); +} + +// get the relative axes of the current texturing +void BrushPrimit_GetRelativeAxes(face_t *f, vec3_t vecS, vec3_t vecT) +{ + vec_t vS[2],vT[2]; + // first we compute them as expressed in plane axis base + // BP matrix has coordinates of plane axis base expressed in geometric axis base + // so we use the line vectors + vS[0] = f->brushprimit_texdef.coords[0][0]; + vS[1] = f->brushprimit_texdef.coords[0][1]; + vT[0] = f->brushprimit_texdef.coords[1][0]; + vT[1] = f->brushprimit_texdef.coords[1][1]; + // now compute those vectors in geometric space + vec3_t texS, texT; // axis base of the plane (geometric) + ComputeAxisBase(f->plane.normal, texS, texT); + // vecS[] = vS[0].texS[] + vS[1].texT[] + // vecT[] = vT[0].texS[] + vT[1].texT[] + vecS[0] = vS[0]*texS[0] + vS[1]*texT[0]; + vecS[1] = vS[0]*texS[1] + vS[1]*texT[1]; + vecS[2] = vS[0]*texS[2] + vS[1]*texT[2]; + vecT[0] = vT[0]*texS[0] + vT[1]*texT[0]; + vecT[1] = vT[0]*texS[1] + vT[1]*texT[1]; + vecT[2] = vT[0]*texS[2] + vT[1]*texT[2]; +} + +// GL matrix 4x4 product (3D homogeneous matrix) +// NOTE: the crappy thing is that GL doesn't follow the standard convention [line][column] +// otherwise it's all good +void GLMatMul(vec_t M[4][4], vec_t A[4], vec_t B[4]) +{ + unsigned short i,j; + for (i=0;i<4;i++) + { + B[i] = 0.0; + for (j=0;j<4;j++) + { + B[i] += M[j][i]*A[j]; + } + } +} + +qboolean IsBrushPrimitMode() +{ + return(g_qeglobals.m_bBrushPrimitMode); +} diff --git a/radiant/brushscript.cpp b/radiant/brushscript.cpp new file mode 100644 index 00000000..3fa141d3 --- /dev/null +++ b/radiant/brushscript.cpp @@ -0,0 +1,698 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// BrushScript stuff +// + +/*! +\todo is this still used / in working state? +should we cleanup and remove it for good +*/ + +#include "stdafx.h" +#include "gtkmisc.h" + +// +struct SVariableDef +{ + CString m_strName; + CString m_strInput; + float m_fValue; +}; + +struct SVecVariableDef +{ + CString m_strName; + CString m_strInput; + vec3_t m_vValue; +}; + + + +const int MAX_VARIABLES = 64; + +brush_t* g_pHold1 = NULL; +brush_t* g_pHold2 = NULL; +brush_t* g_pHold3 = NULL; +bool g_bRotateAroundSelection; +int g_nVariableCount; +int g_nVecVariableCount; +int g_nLoopCounter; +float g_fDefault = 9999.9f; +vec3_t g_vDefault; +bool g_bStartLoop; +char* g_pLooper; +bool g_bKeepGoing; + +SVariableDef g_Variables[MAX_VARIABLES]; +SVecVariableDef g_VecVariables[MAX_VARIABLES]; + +void InitForScriptRun() +{ + g_pHold1 = NULL; + g_pHold2 = NULL; + g_pHold3 = NULL; + g_bRotateAroundSelection = true; + g_nVariableCount = 0; + g_nVecVariableCount = 0; + g_nLoopCounter = 0; + g_bStartLoop = false; + g_pLooper = NULL; + g_bKeepGoing = true; +} + +void AddVariable(const char* pName, float fValue, const char* pInput = NULL) +{ + if (g_nVariableCount < MAX_VARIABLES) + { + g_Variables[g_nVariableCount].m_strName = pName; + g_Variables[g_nVariableCount].m_strName.MakeLower(); + g_Variables[g_nVariableCount].m_fValue = fValue; + if (pInput) + g_Variables[g_nVariableCount].m_strInput = pInput; + g_nVariableCount++; + } + else + gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!"); +} + +float VariableValue(const char* pName) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVariableCount; n++) + { + if (strName == g_Variables[n].m_strName) + return g_Variables[n].m_fValue; + } + //strName.Format("Reference to non-existant varirable %s", pName); + //g_pParentWnd->MessageBox(strName); + return g_fDefault; +} + +void SetVariableValue(const char* pName, float fValue) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVariableCount; n++) + { + if (strName == g_Variables[n].m_strName) + g_Variables[n].m_fValue = fValue; + } +} + + + +void AddVectorVariable(const char* pName, const char* pInput = NULL) +{ + if (g_nVecVariableCount < MAX_VARIABLES) + { + g_VecVariables[g_nVecVariableCount].m_strName = pName; + g_VecVariables[g_nVecVariableCount].m_strName.MakeLower(); + if (pInput) + g_VecVariables[g_nVariableCount].m_strInput = pInput; + g_nVecVariableCount++; + } + else + gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!"); +} + +void VectorVariableValue(const char* pName, vec3_t& v) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVecVariableCount; n++) + { + if (strName == g_VecVariables[n].m_strName) + { + VectorCopy(g_VecVariables[n].m_vValue, v); + return; + } + } + strName.Format("Reference to non-existant variable %s", pName); + gtk_MessageBox(g_pParentWnd->m_pWidget, strName); +} + +void SetVectorVariableValue(const char* pName, vec3_t v) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVecVariableCount; n++) + { + if (strName == g_VecVariables[n].m_strName) + VectorCopy(v, g_VecVariables[n].m_vValue); + } +} + + + + + +// commands +// +// _CopySelected(nHoldPos) +// copies selected brush to hold spot 1, 2 or 3 +// +// _MoveSelected(x, y, z) +// moves selected brush by coords provided +// +// _RotateSelected(x, y, z) +// rotates selected brush by coords provided +// +// _MoveHold(nHoldPos, x, y, z) +// moves brush in hold pos by coords provided +// +// _RotateHold(nHoldPos, x, y, z) +// rotates brush in hold pos by coords provided +// +// _CopyToMap(nHoldPos) +// copies hold brush to map +// +// _CopyAndSelect(nHoldPos) +// copies hold brush to map and selects it +// +// _Input(VarName1, ... VarNamennn) +// inputs a list of values from the user +// + +typedef void (PFNScript)(char*&); + + +struct SBrushScript +{ + const char* m_pName; + PFNScript* m_pProc; +}; + + +const char* GetParam(char*& pBuffer) +{ + static CString strParam; + bool bStringMode = false; + + while (*pBuffer != (char)NULL && isspace(*pBuffer)) // skip and whitespace + pBuffer++; + + if (*pBuffer == '(') // if it's an opening paren, skip it + pBuffer++; + + if (*pBuffer == '\"') // string ? + { + pBuffer++; + bStringMode = true; + } + + strParam = ""; + + if (bStringMode) + { + while (*pBuffer != (char)NULL && *pBuffer != '\"') + strParam += *pBuffer++; + } + else + { + while (*pBuffer != (char)NULL && *pBuffer != ' ' && *pBuffer != ')' && *pBuffer != ',') + strParam += *pBuffer++; + } + + if (*pBuffer != (char)NULL) // skip last char + pBuffer++; + + if (strParam.GetLength() > 0) + { + if (strParam.GetAt(0) == '$') // ? variable name + { + float f = VariableValue(strParam); + if (f != g_fDefault) + strParam.Format("%f", f); + } + } + + return strParam; +} + +brush_t* CopyBrush(brush_t* p) +{ + brush_t* pCopy = Brush_Clone(p); + //Brush_AddToList (pCopy, &active_brushes); + //Entity_LinkBrush (world_entity, pCopy); + Brush_Build(pCopy, false); + + return pCopy; +} + + +void CopySelected(char*& pBuffer) +{ + // expects one param + CString strParam = GetParam(pBuffer); + int n = atoi(strParam); + + brush_t* pCopy = NULL; + if (selected_brushes.next != &selected_brushes && + selected_brushes.next->next == &selected_brushes) + pCopy = selected_brushes.next; + + if (pCopy) + { + if (n == 1) + { + //if (g_pHold1) + //Brush_Free(g_pHold1); + g_pHold1 = CopyBrush(pCopy); + } + else if (n == 2) + { + //if (g_pHold2) + //Brush_Free(g_pHold2); + g_pHold2 = CopyBrush(pCopy); + } + else + { + //if (g_pHold3) + //Brush_Free(g_pHold3); + g_pHold3 = CopyBrush(pCopy); + } + } +} + +void MoveSelected(char*& pBuffer) +{ + vec3_t v; + CString strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + Select_Move(v, false); + Sys_UpdateWindows(W_ALL); +} + +void RotateSelected(char*& pBuffer) +{ + vec3_t v; + + if (g_bRotateAroundSelection) + { + Select_GetTrueMid(v); + VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin()); + } + + CString strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + for (int i = 0; i < 3; i++) + if (v[i] != 0.0) + Select_RotateAxis(i, v[i], false , true); + Sys_UpdateWindows(W_ALL); +} + +void MoveHold(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + vec3_t v; + strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + Brush_Move (pBrush, v, false); + } +} + +void RotateHold(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + vec3_t v; + strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + for (int i = 0; i < 3; i++) + if (v[i] != 0.0) + Select_RotateAxis(i, v[i]); + } +} + +void CopyToMap(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + Brush_AddToList(pBrush, &active_brushes); + Entity_LinkBrush (world_entity, pBrush); + Brush_Build(pBrush, false); + + Sys_UpdateWindows(W_ALL); + } +} + +void CopyAndSelect(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + Select_Deselect(); + Brush_AddToList(pBrush, &active_brushes); + Entity_LinkBrush (world_entity, pBrush); + Brush_Build(pBrush, false); + + Select_Brush(pBrush); + Sys_UpdateWindows(W_ALL); + } +} + +void Input(char*& pBuffer) +{ + bool bGo = false; + const char *fields[5] = { "", "", "", "", "" }; + float values[5]; + + for (int n = 0; n < g_nVariableCount; n++) + { + if (g_Variables[n].m_strInput.GetLength() > 0) + { + bGo = true; + if (n < 5) + { + switch (n) + { + case 0 : fields[1] = g_Variables[n].m_strInput.GetBuffer (); break; + case 1 : fields[2] = g_Variables[n].m_strInput.GetBuffer (); break; + case 2 : fields[3] = g_Variables[n].m_strInput.GetBuffer (); break; + case 3 : fields[4] = g_Variables[n].m_strInput.GetBuffer (); break; + case 4 : fields[5] = g_Variables[n].m_strInput.GetBuffer (); break; + } + } + } + } + + if (bGo) + { + if (DoBSInputDlg (fields, values) == IDOK) + { + for (int n = 0; n < g_nVariableCount; n++) + { + if (g_Variables[n].m_strInput.GetLength() > 0) + { + if (n < 5) + { + switch (n) + { + case 0 : g_Variables[n].m_fValue = values[1]; break; + case 1 : g_Variables[n].m_fValue = values[2]; break; + case 2 : g_Variables[n].m_fValue = values[3]; break; + case 3 : g_Variables[n].m_fValue = values[4]; break; + case 4 : g_Variables[n].m_fValue = values[5]; break; + } + } + } + } + } + else g_bKeepGoing = false; + } +} + +bool g_bWaiting; +void _3DPointDone(bool b, int n) +{ + g_bWaiting = false; +} + +void _3DPointInput(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + CString strParam2 = GetParam(pBuffer); + ShowInfoDialog(strParam2); + AddVectorVariable(strParam, strParam2); + g_bWaiting = true; + AcquirePath(2, &_3DPointDone); + while (g_bWaiting) + gtk_main_iteration (); + HideInfoDialog(); + SetVectorVariableValue(strParam, g_PathPoints[0]); +} + +void SetRotateOrigin(char*& pBuffer) +{ + vec3_t v; + CString strParam = GetParam(pBuffer); + VectorVariableValue(strParam, v); + VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin()); + g_bRotateAroundSelection = false; +} + +void InputVar(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + CString strParam2 = GetParam(pBuffer); + AddVariable(strParam, 0.0, strParam2); +} + +void LoopCount(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + g_nLoopCounter = atoi(strParam); + if (g_nLoopCounter == 0) + g_nLoopCounter = (int)VariableValue(strParam); + if (g_nLoopCounter > 0) + g_pLooper = pBuffer; +} + +void LoopRun(char*& pBuffer) +{ + if (g_bStartLoop == true) + { + g_nLoopCounter--; + if (g_nLoopCounter == 0) + { + g_bStartLoop = false; + GetParam(pBuffer); + } + else + pBuffer = g_pLooper; + } + else + { + if (g_pLooper && g_nLoopCounter > 0) + { + g_bStartLoop = true; + pBuffer = g_pLooper; + } + else + { + GetParam(pBuffer); + } + } +} + + +void ConfirmMessage(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + if (gtk_MessageBox(g_pParentWnd->m_pWidget, strParam, "Script Info", MB_OKCANCEL) == IDCANCEL) + g_bKeepGoing = false; +} + +void Spherize(char*& pBuffer) +{ + g_bScreenUpdates = false; + for (int n = 0; n < 120; n += 36) + { + for (int i = 0; i < 360; i += 36) + { + Select_RotateAxis(0, i, false , true); + CSG_Subtract(); + } + Select_RotateAxis(2, n, false , true); + } + g_bScreenUpdates = true; +} + +void RunIt(char*& pBuffer); +SBrushScript g_ScriptCmds[] = +{ + {"_CopySelected", &CopySelected}, + {"_MoveSelected", &MoveSelected}, + {"_RotateSelected", &RotateSelected}, + {"_MoveHold", &MoveHold}, + {"_RotateHold", &RotateHold}, + {"_CopyToMap", &CopyToMap}, + {"_CopyAndSelect", &CopyAndSelect}, + {"_Input", &Input}, + {"_3DPointInput", &_3DPointInput}, + {"_SetRotateOrigin", &SetRotateOrigin}, + {"_InputVar", &InputVar}, + {"_LoopCount", &LoopCount}, + {"_LoopRun", &LoopRun}, + {"_ConfirmMessage", &ConfirmMessage}, + {"_Spherize", &Spherize}, + {"_RunScript", RunIt} +}; + +const int g_nScriptCmdCount = sizeof(g_ScriptCmds) / sizeof(SBrushScript); + +void RunScript(char* pBuffer) +{ + g_pHold1 = NULL; + g_pHold2 = NULL; + g_pHold3 = NULL; + + while (g_bKeepGoing && pBuffer && *pBuffer) + { + while (*pBuffer != (char)NULL && *pBuffer != '_') + pBuffer++; + + char* pTemp = pBuffer; + int nLen = 0; + while (*pTemp != (char)NULL && *pTemp != '(') + { + pTemp++; + nLen++; + } + if (*pBuffer != (char)NULL) + { + bool bFound = false; + for (int i = 0; i < g_nScriptCmdCount; i++) + { + //if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, strlen(g_ScriptCmds[i].m_pName)) == 0) + if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, nLen) == 0) + { + pBuffer += strlen(g_ScriptCmds[i].m_pName); + g_ScriptCmds[i].m_pProc(pBuffer); + if (g_bStartLoop) + { + } + bFound = true; + break; + } + } + if (!bFound) + pBuffer++; + } + } +} + + +void RunScriptByName(char* pBuffer, bool bInit) +{ + if (bInit) + InitForScriptRun(); + char* pScript = new char[4096]; + CString strINI; + strINI = g_strGameToolsPath; + strINI += "/scripts.ini"; + CString strScript; + FILE *f; + + f = fopen (strINI.GetBuffer(), "rt"); + if (f != NULL) + { + char line[1024], *ptr; + + // read section names + while (fgets (line, 1024, f) != 0) + { + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (line, pScript) == 0) + { + while (fgets (line, 1024, f) != 0) + { + if ((strchr (line, '=') == NULL) || + strlen (line) == 0) + break; + strScript += line; + } + break; + } + } + fclose (f); + } + RunScript((char*)strScript.GetBuffer()); +} + + +void RunIt(char*& pBuffer) +{ + brush_t* p1 = g_pHold1; + brush_t* p2 = g_pHold2; + brush_t* p3 = g_pHold3; + + CString strParam = GetParam(pBuffer); + RunScriptByName((char*)strParam.GetBuffer(), false); + + g_pHold3 = p3; + g_pHold2 = p2; + g_pHold1 = p1; +} + diff --git a/radiant/camera.h b/radiant/camera.h new file mode 100644 index 00000000..f7c90dd0 --- /dev/null +++ b/radiant/camera.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// window system independent camera view code + +typedef enum +{ + cd_wire, + cd_solid, + cd_texture, + cd_light, +// cd_blend +} camera_draw_mode; + +#define DRAW_GL_FILL 0x0001 +#define DRAW_GL_LIGHTING 0x0010 +#define DRAW_GL_TEXTURE_2D 0x0100 +#define DRAW_GL_BLEND 0x1000 + +#define DRAW_GL_WIRE 0x0000 +#define DRAW_GL_FLAT 0x0001 +#define DRAW_GL_SOLID 0x0011 +#define DRAW_GL_TEXTURED 0x0111 + +#define DRAW_WIRE 0 +#define DRAW_SOLID 1 +#define DRAW_TEXTURED 2 + +// TTimo: camera code is a huge mess +// someone courageous should clean it up +// this will probably happen when we have new rendering code + +#define MOVE_FORWARD 0x001 +#define MOVE_BACK 0x002 +#define MOVE_ROTRIGHT 0x004 +#define MOVE_ROTLEFT 0x008 +#define MOVE_STRAFERIGHT 0x010 +#define MOVE_STRAFELEFT 0x020 + +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; + // TTimo + // indexes: PITCH = 0 YAW = 1 ROLL = 3 + // AFAIK in Radiant we always have ROLL=0 + vec3_t angles; + + camera_draw_mode draw_mode; + int draw_glstate; + + vec3_t color; // background + + vec3_t forward, right; // move matrix (TTimo: used to have up but it was not updated) + vec3_t vup, vpn, vright; // view matrix (taken from the GL_PROJECTION matrix) + + float projection[4][4]; + float modelview[4][4]; + + unsigned int movementflags; // movement flags + +} camera_t; diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp new file mode 100644 index 00000000..09edb418 --- /dev/null +++ b/radiant/camwindow.cpp @@ -0,0 +1,1700 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Camera Window +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include + +extern void DrawPathLines(); +extern void Select_ShiftTexture(int x, int y); +extern void Select_RotateTexture(int amt); +extern void DrawAlternatePoint(vec3_t v, float scale); +//extern void Select_ScaleTexture(int x, int y); + +extern int g_nPatchClickedView; + +brush_t* g_pSplitList = NULL; + +// ============================================================================= +// CamWnd class + +CamWnd::CamWnd () + : GLWindow (TRUE), m_XORRectangle(m_pWidget) +{ + m_nNumTransBrushes = 0; + memset(&m_Camera, 0, sizeof(camera_t)); + m_pSide_select = NULL; + m_bClipMode = false; + m_bFreeMove = false; + Cam_Init(); +} + +CamWnd::~CamWnd () +{ +} + +void CamWnd::OnCreate () +{ + if (!MakeCurrent ()) + Error ("glMakeCurrent failed"); + + gtk_glwidget_create_font (m_pWidget); + + // report OpenGL information + Sys_Printf ("GL_VENDOR: %s\n", qglGetString (GL_VENDOR)); + Sys_Printf ("GL_RENDERER: %s\n", qglGetString (GL_RENDERER)); + Sys_Printf ("GL_VERSION: %s\n", qglGetString (GL_VERSION)); + Sys_Printf ("GL_EXTENSIONS: %s\n", qglGetString (GL_EXTENSIONS)); + + // Set off texture compression supported + g_qeglobals.bTextureCompressionSupported = 0; + + // finalize OpenGL init + // NOTE + // why is this here? well .. the Gtk objects get constructed when you enter gtk_main + // and I wanted to have the extensions information in the editor startup console (avoid looking that up in the early console) + // RIANT + // I Split this up so as to add support for extension and user-friendly + // compression format selection. + // ADD new globals for your new format so as to minimise + // calls to Sys_QGL_ExtensionSupported + // NOTE TTimo: I don't really like this approach with globals. Frequent calls to Sys_QGL_ExtensionSupported don't sound like + // a problem to me. If there is some caching to be done, then I think it should be inside Sys_QGL_ExtensionSupported + /////////////////////////////////////////// + // Check for default OpenGL + if (Sys_QGL_ExtensionSupported ("GL_ARB_texture_compression")) + { + g_qeglobals.bTextureCompressionSupported = 1; + g_qeglobals.m_bOpenGLCompressionSupported = 1; + } + + // INSERT PROPRIETARY EXTENSIONS HERE + // Check for S3 extensions + // create a bool global for extension supported + if (Sys_QGL_ExtensionSupported ("GL_EXT_texture_compression_s3tc")) + { + g_qeglobals.bTextureCompressionSupported = 1; + g_qeglobals.m_bS3CompressionSupported = 1; + } + + g_qeglobals.m_bOpenGLReady = true; + + g_PrefsDlg.UpdateTextureCompression(); + +#ifdef ATIHACK_812 + g_PrefsDlg.UpdateATIHack(); +#endif + + g_qeglobals_gui.d_camera = m_pWidget; +} + +void CamWnd::Cam_Init () +{ + m_Camera.timing = false; + m_Camera.origin[0] = 0.f; + m_Camera.origin[1] = 20.f; + m_Camera.origin[2] = 46.f; + m_Camera.color[0] = 0.3f; + m_Camera.color[1] = 0.3f; + m_Camera.color[2] = 0.3f; + m_nCambuttonstate = 0; +} + +void CamWnd::OnSize(int cx, int cy) +{ + m_Camera.width = cx; + m_Camera.height = cy; + gtk_widget_queue_draw(m_pWidget); +} + +rectangle_t rectangle_from_area_cam() +{ + const float left = MIN(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); + const float top = MAX(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); + const float right = MAX(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); + const float bottom = MIN(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); + return rectangle_t(left, bottom, right - left, top - bottom); +} + +void update_xor_rectangle(XORRectangle& xor_rectangle) +{ + rectangle_t rectangle; + if ((g_qeglobals.d_select_mode == sel_area)) + rectangle = rectangle_from_area_cam(); + xor_rectangle.set(rectangle); +} + +void CamWnd::OnMouseMove(guint32 flags, int pointx, int pointy) +{ + int height = m_pWidget->allocation.height; + // NOTE RR2DO2 this hasn't got any use anymore really. It is an old qeradiant feature + // that can be re-enabled by removing the checks for HasCapture and not shift/ctrl down + // but the scaling/rotating (unless done with the steps set in the surface inspector + // dialog) is way too sensitive to be of any use + if (HasCapture () && Sys_AltDown () && + !((flags & MK_SHIFT) || (flags & MK_CONTROL))) + { + if (flags & MK_CONTROL) + Select_RotateTexture(pointy - m_ptLastCursorY); + else + if (flags & MK_SHIFT) + Select_ScaleTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); + else + Select_ShiftTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); + } + else + { + Cam_MouseMoved(pointx, height - 1 - pointy, flags); + } + m_ptLastCursorX = pointx; + m_ptLastCursorY = pointy; + + update_xor_rectangle(m_XORRectangle); +} + +void CamWnd::OnMouseWheel(bool bUp) +{ + if (bUp) + VectorMA (m_Camera.origin, g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + else + VectorMA (m_Camera.origin, -g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); +} + +void CamWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) +{ + m_ptLastCursorX = pointx; + m_ptLastCursorY = pointy; + OriginalMouseDown(nFlags, pointx, pointy); +} + +void CamWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseUp(nFlags, pointx, pointy); +} + +void CamWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseDown(nFlags, pointx, pointy); +} + +void CamWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseUp(nFlags, pointx, pointy); +} + +void CamWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseDown(nFlags, pointx, pointy); +} + +void CamWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseUp(nFlags, pointx, pointy); +} + +void CamWnd::OriginalMouseUp(guint32 nFlags, int pointx, int pointy) +{ + int height = m_pWidget->allocation.height; + + if(g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) + { + g_qeglobals.d_select_mode = sel_brush; + } + + Cam_MouseUp(pointx, height - 1 - pointy, nFlags); + ReleaseCapture (); + + update_xor_rectangle(m_XORRectangle); +} + +void CamWnd::OriginalMouseDown(guint32 nFlags, int pointx, int pointy) +{ + int height = m_pWidget->allocation.height; + + SetFocus(); + SetCapture(); + Cam_MouseDown (pointx, height - 1 - pointy, nFlags); + + update_xor_rectangle(m_XORRectangle); +} + +void CamWnd::Cam_BuildMatrix() +{ + float ya; + float matrix[4][4]; + int i; + + if (!m_bFreeMove) + { + ya = m_Camera.angles[1]/180*Q_PI; + + // the movement matrix is kept 2d + m_Camera.forward[0] = cos(ya); + m_Camera.forward[1] = sin(ya); + m_Camera.forward[2] = 0; + m_Camera.right[0] = m_Camera.forward[1]; + m_Camera.right[1] = -m_Camera.forward[0]; + } + else + { + AngleVectors( m_Camera.angles, m_Camera.forward, m_Camera.right, NULL ); + m_Camera.forward[2] = -m_Camera.forward[2]; + } + + memcpy(matrix, m_Camera.projection, sizeof(m4x4_t)); + m4x4_multiply_by_m4x4(&matrix[0][0], &m_Camera.modelview[0][0]); + + //qglGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]); + + for (i=0 ; i<3 ; i++) + { + m_Camera.vright[i] = matrix[i][0]; + m_Camera.vup[i] = matrix[i][1]; + m_Camera.vpn[i] = matrix[i][2]; + } + + VectorNormalize (m_Camera.vright, m_Camera.vright); + VectorNormalize (m_Camera.vup, m_Camera.vup); + VectorNormalize (m_Camera.vpn, m_Camera.vpn); +} + +void CamWnd::Cam_ChangeFloor (qboolean up) +{ + brush_t *b; + float d, bestd, current; + vec3_t start, dir; + + start[0] = m_Camera.origin[0]; + start[1] = m_Camera.origin[1]; + start[2] = g_MaxWorldCoord; + dir[0] = dir[1] = 0; + dir[2] = -1; + + current = g_MaxWorldCoord - (m_Camera.origin[2] - 48); + if (up) + bestd = 0; + else + bestd = 2*g_MaxWorldCoord; + + for (b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (!Brush_Ray (start, dir, b, &d)) + continue; + if (up && d < current && d > bestd) + bestd = d; + if (!up && d > current && d < bestd) + bestd = d; + } + + if (bestd == 0 || bestd == 2*g_MaxWorldCoord) + return; + + m_Camera.origin[2] += current - bestd; + Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY); +} + +void CamWnd::Cam_PositionDrag() +{ + int x, y; + + Sys_GetCursorPos (&x, &y); + if (x != m_ptCursorX || y != m_ptCursorY) + { + x -= m_ptCursorX; + VectorMA (m_Camera.origin, x, m_Camera.vright, m_Camera.origin); + y -= m_ptCursorY; + m_Camera.origin[2] -= y; + Sys_SetCursorPos(m_ptCursorX, m_ptCursorY); + Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); + } +} + +void CamWnd::Cam_MouseControl (float dtime) +{ + Cam_KeyControl (dtime); + + if( g_PrefsDlg.m_bCamFreeLook ) + { + int dx, dy; + gint x, y; + + if( !m_bFreeMove || m_nCambuttonstate == MK_CONTROL ) + return; + + // Update angles + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + dx = m_ptLastCamCursorX - m_ptCursorX; + dy = m_ptLastCamCursorY - m_ptCursorY; + + gdk_window_get_origin( m_pWidget->window, &x, &y); + + m_ptLastCamCursorX = x + (m_Camera.width / 2); + m_ptLastCamCursorY = y + (m_Camera.height / 2); + + Sys_SetCursorPos(m_ptLastCamCursorX, m_ptLastCamCursorY); + + // Don't use pitch + if(!g_PrefsDlg.m_bCamFreeLookStrafe) { + if (g_PrefsDlg.m_bCamInverseMouse) + m_Camera.angles[PITCH] -= dy * dtime * g_PrefsDlg.m_nAngleSpeed; + else + m_Camera.angles[PITCH] += dy * dtime * g_PrefsDlg.m_nAngleSpeed; + } else { + VectorMA (m_Camera.origin, dy * (float) (g_PrefsDlg.m_nMoveSpeed / 6.0f), m_Camera.forward, m_Camera.origin); + } + + m_Camera.angles[YAW] += dx * dtime * g_PrefsDlg.m_nAngleSpeed; + + if (m_Camera.angles[PITCH] > 90) + m_Camera.angles[PITCH] = 90; + else if (m_Camera.angles[PITCH] < -90) + m_Camera.angles[PITCH] = -90; + + if (m_Camera.angles[YAW] >= 360) + m_Camera.angles[YAW] = 0; + else if (m_Camera.angles[YAW] <= -360) + m_Camera.angles[YAW] = 0; + + if( dx || dy || m_Camera.movementflags ) + { + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); + } + } + else + { + int xl, xh; + int yl, yh; + float xf, yf; + + if (g_PrefsDlg.m_nMouseButtons == 2) + { + if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT)) + return; + } + else + { + if (m_nCambuttonstate != MK_RBUTTON) + return; + } + + xf = (float)(m_ptButtonX - m_Camera.width/2) / (m_Camera.width/2); + yf = (float)(m_ptButtonY - m_Camera.height/2) / (m_Camera.height/2); + + xl = m_Camera.width/3; + xh = xl*2; + yl = m_Camera.height/3; + yh = yl*2; + + xf *= 1.0 - fabs(yf); + if (xf < 0) + { + xf += 0.1f; + if (xf > 0) + xf = 0; + } + else + { + xf -= 0.1f; + if (xf < 0) + xf = 0; + } + + VectorMA (m_Camera.origin, yf*dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + m_Camera.angles[YAW] += xf*-dtime*g_PrefsDlg.m_nAngleSpeed; + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); + } +} + +void CamWnd::Cam_KeyControl (float dtime) { + + // Update angles + if (m_Camera.movementflags & MOVE_ROTLEFT) + m_Camera.angles[YAW] += 15*dtime*g_PrefsDlg.m_nAngleSpeed; + if (m_Camera.movementflags & MOVE_ROTRIGHT) + m_Camera.angles[YAW] -= 15*dtime*g_PrefsDlg.m_nAngleSpeed; + + // Update position + if (m_Camera.movementflags & MOVE_FORWARD) + VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + if (m_Camera.movementflags & MOVE_BACK) + VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + if (m_Camera.movementflags & MOVE_STRAFELEFT) + VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); + if (m_Camera.movementflags & MOVE_STRAFERIGHT) + VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); + + // Save a screen update (when m_bFreeMove is enabled, mousecontrol does the update) + if( !m_bFreeMove && m_Camera.movementflags ) + { + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); + } +} + +// NOTE TTimo if there's an OS-level focus out of the application +// then we can release the camera cursor grab +static gint camwindow_focusout(GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + g_pParentWnd->GetCamWnd ()->ToggleFreeMove(); + return FALSE; +} + +void CamWnd::ToggleFreeMove() +{ + GdkWindow *window; + GtkWidget *widget; + + m_bFreeMove = !m_bFreeMove; + Camera()->movementflags = 0; + m_ptLastCamCursorX = m_ptCursorX; + m_ptLastCamCursorY = m_ptCursorY; + + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + { + widget = g_pParentWnd->GetCamWnd ()->m_pParent; + window = widget->window; + } + else + { + widget = g_pParentWnd->m_pWidget; + window = widget->window; + } + + if (m_bFreeMove) + { + + SetFocus(); + SetCapture(); + + { + GdkPixmap *pixmap; + GdkBitmap *mask; + char buffer [(32 * 32)/8]; + memset (buffer, 0, (32 * 32)/8); + GdkColor white = {0, 0xffff, 0xffff, 0xffff}; + GdkColor black = {0, 0x0000, 0x0000, 0x0000}; + pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); + + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + gdk_drawable_unref (pixmap); + gdk_drawable_unref (mask); + } + + // RR2DO2: FIXME why does this only work the 2nd and + // further times the event is called? (floating windows + // mode seems to work fine though...) + m_FocusOutHandler_id = gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event", + GTK_SIGNAL_FUNC (camwindow_focusout), g_pParentWnd); + + { + GdkEventMask mask = (GdkEventMask)(GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_BUTTON2_MOTION_MASK + | GDK_BUTTON3_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK); + + gdk_pointer_grab(widget->window, TRUE, mask, widget->window, NULL, GDK_CURRENT_TIME); + } + } + else + { + gdk_pointer_ungrab(GDK_CURRENT_TIME); + + gtk_signal_disconnect (GTK_OBJECT (widget), m_FocusOutHandler_id); + + GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + + ReleaseCapture(); + } + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); +} + +void CamWnd::Cam_MouseDown(int x, int y, int buttons) +{ + vec3_t dir; + float f, r, u; + int i; + + + // + // calc ray direction + // + u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); + r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; + VectorNormalize (dir, dir); + + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + m_nCambuttonstate = buttons; + m_ptButtonX = x; + m_ptButtonY = y; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + if ((buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + || (buttons == nMouseButton) + || (buttons == (nMouseButton|MK_SHIFT)) + || (buttons == (nMouseButton|MK_CONTROL)) + || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL))) + { + if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT))) + { + if (g_PrefsDlg.m_bCamFreeLook) + ToggleFreeMove(); + else + Cam_MouseControl (0.1f); + } + else + { + // something global needs to track which window is responsible for stuff + Patch_SetView(W_CAMERA); + Drag_Begin (x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir, true); + } + return; + } + + if (buttons == MK_RBUTTON) + { + if (g_PrefsDlg.m_bCamFreeLook) + ToggleFreeMove(); + else + Cam_MouseControl (0.1f); + return; + } +} + +void CamWnd::Cam_MouseUp (int x, int y, int buttons) +{ + m_nCambuttonstate = 0; + Drag_MouseUp (buttons); +} + +void CamWnd::Cam_MouseMoved (int x, int y, int buttons) +{ + m_nCambuttonstate = buttons; + if (!buttons) + return; + + if( g_PrefsDlg.m_nCamDragMultiSelect ) + { + if (g_qeglobals.d_select_mode == sel_brush_on || g_qeglobals.d_select_mode == sel_brush_off) + { + bool bDoDragMultiSelect = FALSE; + + if( g_PrefsDlg.m_nCamDragMultiSelect == 1 && buttons == (MK_LBUTTON|MK_SHIFT) ) + bDoDragMultiSelect = TRUE; + else if( g_PrefsDlg.m_nCamDragMultiSelect == 2 && buttons == (MK_LBUTTON|MK_CONTROL) && Sys_AltDown() ) + bDoDragMultiSelect = TRUE; + + if( bDoDragMultiSelect ) + { + vec3_t dir; + float f, r, u; + int i; + + // + // calc ray direction + // + u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); + r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; + VectorNormalize (dir,dir); + + switch( g_qeglobals.d_select_mode ) + { + case sel_brush_on: + Select_Ray( m_Camera.origin, dir, (SF_DRAG_ON|SF_CAMERA) ); + break; + + case sel_brush_off: + Select_Ray( m_Camera.origin, dir, (SF_DRAG_OFF|SF_CAMERA) ); + break; + + default: + break; + } + return; + } + } + else if (g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) + { + if( buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) + { + vec3_t dir; + float f, r, u; + int i; + + // + // calc ray direction + // + u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); + r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; + VectorNormalize (dir,dir); + + switch( g_qeglobals.d_select_mode ) + { + case sel_facets_on: + Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_ON|SF_CAMERA) ); + break; + + case sel_facets_off: + Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_OFF|SF_CAMERA) ); + break; + + default: + break; + } + return; + } + } + } + + m_ptButtonX = x; + m_ptButtonY = y; + + if ( (m_bFreeMove && (buttons & MK_CONTROL) && !(buttons & MK_SHIFT)) || (!m_bFreeMove && (buttons == (MK_RBUTTON|MK_CONTROL))) ) + { + Cam_PositionDrag (); + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + return; + } + + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + if (buttons & (MK_LBUTTON | MK_MBUTTON) ) + { + Drag_MouseMoved (x, y, buttons); + if(g_qeglobals.d_select_mode != sel_area) + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + } +} + +void CamWnd::InitCull() +{ + int i; + + VectorSubtract (m_Camera.vpn, m_Camera.vright, m_vCull1); + VectorAdd (m_Camera.vpn, m_Camera.vright, m_vCull2); + + for (i=0 ; i<3 ; i++) + { + if (m_vCull1[i] > 0) + m_nCullv1[i] = 3+i; + else + m_nCullv1[i] = i; + if (m_vCull2[i] > 0) + m_nCullv2[i] = 3+i; + else + m_nCullv2[i] = i; + } +} + +qboolean CamWnd::CullBrush (brush_t *b) +{ + int i; + vec3_t point; + float d; + + if (g_PrefsDlg.m_bCubicClipping) + { + float fLevel = g_PrefsDlg.m_nCubicScale * 64; + + point[0] = m_Camera.origin[0] - fLevel; + point[1] = m_Camera.origin[1] - fLevel; + point[2] = m_Camera.origin[2] - fLevel; + + for (i=0; i<3; i++) + if (b->mins[i] < point[i] && b->maxs[i] < point[i]) + return true; + + point[0] = m_Camera.origin[0] + fLevel; + point[1] = m_Camera.origin[1] + fLevel; + point[2] = m_Camera.origin[2] + fLevel; + + for (i=0; i<3; i++) + if (b->mins[i] > point[i] && b->maxs[i] > point[i]) + return true; + } + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i]; + + d = DotProduct (point, m_vCull1); + if (d < -1) + return true; + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i]; + + d = DotProduct (point, m_vCull2); + if (d < -1) + return true; + + return false; +} + +// project a 3D point onto the camera space +// we use the GL viewing matrixes +// this is the implementation of a glu function (I realized that afterwards): gluProject +void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2]) +{ + + vec_t P1[4],P2[4],P3[4]; + VectorCopy(A,P1); P1[3] = 1; + + GLMatMul(m_Camera.modelview , P1, P2); + GLMatMul(m_Camera.projection, P2, P3); + + // we ASSUME that the view port is 0 0 m_Camera.width m_Camera.height (you can check in Cam_Draw) + B[0] = (float)m_Camera.width * ( P3[0] + 1.0 ) / 2.0; + B[1] = (float)m_Camera.height * ( P3[1] + 1.0 ) / 2.0; + +} + +// vec defines a direction in geometric space and P an origin point +// the user is interacting from the camera view +// (for example with texture adjustment shortcuts) +// and intuitively if he hits left / right / up / down +// what happens in geometric space should match the left/right/up/down move in camera space +// axis = 0: vec is along left/right +// axis = 1: vec is along up/down +// sgn = +1: same directions +// sgn = -1: opposite directions +// Implementation: +// typical use case is giving a face center and a normalized vector +// 1) compute start and endpoint, project them in camera view, get the direction +// depending on the situation, we might bump into precision issues with that +// 2) possible to compute the projected direction independently? +// this solution would be better but right now I don't see how to do it.. +void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn) +{ + + vec_t A[2],B[2],V[2]; + ProjectCamera(P,A); + vec3_t Q; + VectorAdd(P,vec,Q); + ProjectCamera(Q,B); + // V is the vector projected in camera space + V[0] = B[0] - A[0]; + V[1] = B[1] - A[1]; + if (fabs(V[0])>fabs(V[1])) + { + // best match is against right + axis = 0; + if (V[0]>0) + sgn = +1; + else + sgn = -1; + } + else + { + // best match is against up + axis = 1; + if (V[1]>0) + sgn = +1; + else + sgn = -1; + } +} + +#if 0 +void CamWnd::DrawLightRadius(brush_t* pBrush) +{ + // if lighting + int nRadius = Brush_LightRadius(pBrush); + if (nRadius > 0) + { + Brush_SetLightColor(pBrush); + qglEnable (GL_BLEND); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDisable (GL_TEXTURE_2D); + + qglEnable(GL_TEXTURE_2D); + qglDisable(GL_BLEND); + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + } +} +#endif + +extern void DrawPatchMesh(patchMesh_t *pm); +extern void DrawPatchControls(patchMesh_t *pm); +extern void Brush_DrawFacingAngle (brush_t *b, entity_t *e); +extern void Brush_DrawModel(brush_t *b, bool bTextured = false); +extern void DrawModelOrigin(brush_t *b); +extern void DrawModelBBox(brush_t *b); + +void CamWnd::Cam_DrawBrush(brush_t *b, int mode) +{ + int nGLState = m_Camera.draw_glstate; + int nDrawMode = m_Camera.draw_mode; + int nModelMode = g_PrefsDlg.m_nEntityShowState; + + GLfloat material[4], identity[4]; + VectorSet(identity, 0.8f, 0.8f, 0.8f); + IShader *pShader; + + // lights + if (b->owner->eclass->fixedsize && b->owner->eclass->nShowFlags & ECLASS_LIGHT && g_PrefsDlg.m_bNewLightDraw) + { + switch (mode) + { + case DRAW_SOLID: + VectorCopy(b->owner->color, material); + VectorScale(material, 0.8f, material); + material[3] = 1.0f; + + qglColor4fv(material); + + if (g_PrefsDlg.m_bNewLightDraw) + DrawLight(b->owner, nGLState, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, 0); + + break; + } + } + + // models + else if(b->owner->eclass->fixedsize && b->owner->model.pRender + && !(!IsBrushSelected(b) && (nModelMode & ENTITY_SELECTED_ONLY))) + { + switch (mode) + { + case DRAW_TEXTURED: + if (!(nModelMode & ENTITY_WIREFRAME) && nModelMode != ENTITY_BOX) + { + VectorCopy(b->owner->eclass->color, material); + material[3] = identity[3] = 1.0f; + + qglEnable(GL_CULL_FACE); + + if(!(nGLState & DRAW_GL_TEXTURE_2D)) qglColor4fv(material); + else qglColor4fv(identity); + if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); + + b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); + } + break; + case DRAW_WIRE: + VectorCopy(b->owner->eclass->color, material); + material[3] = 1.0f; + qglColor4fv(material); + + // model view mode "wireframe" or "selected wire" + if(nModelMode & ENTITY_WIREFRAME) + b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); + + // model view mode "skinned and boxed" + if(!(b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) ) + { + qglColor4fv(material); + aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + } + else if(nModelMode & ENTITY_BOXED) + { + aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + } +/* + if(!(nModelMode & ENTITY_BOXED) && b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) + DrawModelOrigin(b); +*/ + } + } + + // patches + else if (b->patchBrush) + { + bool bTrans = (b->pPatch->pShader->getTrans() < 1.0f); + switch(mode) + { + case DRAW_TEXTURED: + if (!g_bPatchWireFrame && ((nGLState & DRAW_GL_BLEND && bTrans) || (!(nGLState & DRAW_GL_BLEND) && !bTrans))) + { + qglDisable(GL_CULL_FACE); + + pShader = b->pPatch->pShader; + VectorCopy(pShader->getTexture()->color, material); + material[3] = identity[3] = pShader->getTrans(); + + if(nGLState & DRAW_GL_TEXTURE_2D) { + qglColor4fv(identity); + qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); + } + else + qglColor4fv(material); + if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); + + DrawPatchMesh(b->pPatch); + } + break; + case DRAW_WIRE: + if (g_bPatchWireFrame) + { + VectorCopy(b->pPatch->pShader->getTexture()->color, material); + material[3] = 1.0; + qglColor4fv(material); + DrawPatchMesh(b->pPatch); + } + if ( b->pPatch->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint + || g_qeglobals.d_select_mode == sel_area + || g_bPatchBendMode)) + DrawPatchControls(b->pPatch); + } + } + + // brushes + else if(b->owner->eclass->fixedsize) + { + switch(mode) + { + case DRAW_SOLID: + VectorCopy(b->owner->eclass->color, material); + VectorScale(material, 0.8f, material); + material[3] = 1.0f; + qglColor4fv(material); + + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + Brush_Draw(b); + break; + case DRAW_WIRE: + if((g_qeglobals.d_savedinfo.include & INCLUDE_ANGLES) + && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) + Brush_DrawFacingAngle(b, b->owner); + } + } + + // brushes + else + { + switch(mode) + { + case DRAW_TEXTURED: + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + Brush_Draw(b); + } + } +} + +void CamWnd::Cam_DrawBrushes(int mode) +{ + brush_t *b; + brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; + + for(b = active_brushes.next; b != &active_brushes; b=b->next) + if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); + for(b = pList->next; b != pList; b=b->next) + if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); +} + +void CamWnd::Cam_DrawStuff() +{ + GLfloat identity[4]; + VectorSet(identity, 0.8f, 0.8f, 0.8f); + brush_t *b; + + for(b = active_brushes.next; b != &active_brushes; b=b->next) + b->bCamCulled = CullBrush(b); + + for(b = selected_brushes.next; b != &selected_brushes; b=b->next) + b->bCamCulled = CullBrush(b); + + switch (m_Camera.draw_mode) + { + case cd_wire: + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_BLEND); + qglEnable(GL_DEPTH_TEST); + qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + qglShadeModel(GL_FLAT); + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_NORMAL_ARRAY); + } + m_Camera.draw_glstate = DRAW_GL_WIRE; + break; + + case cd_solid: + qglCullFace(GL_FRONT); + qglEnable(GL_CULL_FACE); + qglShadeModel (GL_FLAT); + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_BLEND); + qglEnable(GL_DEPTH_TEST); + qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + qglPolygonOffset(-1.0, 2); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_LIGHTING); + qglEnable(GL_COLOR_MATERIAL); +// qglEnable(GL_RESCALE_NORMAL); + qglEnableClientState(GL_NORMAL_ARRAY); + } + m_Camera.draw_glstate = DRAW_GL_SOLID; + break; + + case cd_texture: + qglCullFace(GL_FRONT); + qglEnable(GL_CULL_FACE); + qglShadeModel (GL_FLAT); + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + qglEnable(GL_TEXTURE_2D); + qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + qglDisable(GL_BLEND); + qglEnable(GL_DEPTH_TEST); + qglEnableClientState(GL_VERTEX_ARRAY); + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); + qglEnableClientState(GL_NORMAL_ARRAY); +// qglEnable(GL_RESCALE_NORMAL); + } + qglPolygonOffset(-1.0, 2); + m_Camera.draw_glstate = DRAW_GL_TEXTURED; + break; + + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + Cam_DrawBrushes(DRAW_TEXTURED); + + // setup for solid stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + qglDisable(GL_TEXTURE_2D); + m_Camera.draw_glstate &= ~DRAW_GL_TEXTURE_2D; + if(g_PrefsDlg.m_bGLLighting) + qglEnable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + break; + case cd_solid: + break; + case cd_wire: + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + Cam_DrawBrushes(DRAW_SOLID); + + // setup for wireframe stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_NORMAL_ARRAY); +// qglDisable(GL_RESCALE_NORMAL); + } + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + case cd_solid: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_NORMAL_ARRAY); +// qglDisable(GL_RESCALE_NORMAL); + } + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + case cd_wire: + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + qglDisable(GL_CULL_FACE); + Cam_DrawBrushes(DRAW_WIRE); + + // setup for transparent texture stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_COLOR_MATERIAL); + qglEnableClientState(GL_NORMAL_ARRAY); + qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); + } + qglEnable(GL_TEXTURE_2D); + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + m_Camera.draw_glstate = DRAW_GL_TEXTURED; + break; + case cd_solid: + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_LIGHTING); + qglEnable(GL_COLOR_MATERIAL); + qglEnableClientState(GL_NORMAL_ARRAY); +// qglEnable(GL_RESCALE_NORMAL); + } + m_Camera.draw_glstate = DRAW_GL_SOLID; + break; + case cd_wire: + m_Camera.draw_glstate = DRAW_GL_WIRE; + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + + qglEnable(GL_BLEND); + m_Camera.draw_glstate |= DRAW_GL_BLEND; + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // FIXME: some .TGA are buggy, have a completely empty alpha channel + // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE + // so I decided using GL_DECAL instead + // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent. + // this could get better if you can get qglTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome + // Arnout: empty alpha channels are now always filled with data. Don't set this anymore (would cause problems with qer_alphafunc too) +// qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + + Cam_DrawBrushes(DRAW_TEXTURED); + +// qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + qglDisable(GL_BLEND); + + // setup for wireframe stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_COLOR_MATERIAL); + qglDisable(GL_LIGHTING); +// qglDisable(GL_RESCALE_NORMAL); + } + break; + case cd_solid: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_COLOR_MATERIAL); + qglDisable(GL_LIGHTING); +// qglDisable(GL_RESCALE_NORMAL); + } + break; + case cd_wire: + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + +} + +/* +============== +Cam_Draw +============== +*/ + +void QueueClear (); +void QueueDraw (); + +void CamWnd::Cam_Draw() +{ + brush_t *brush; + face_t *face; + float screenaspect; + float yfov; + double start, end; + int i; + + if (!active_brushes.next) + return; // not valid yet + + if (m_Camera.timing) + start = Sys_DoubleTime (); + + // + // clear + // + QE_CheckOpenGLForErrors(); + + qglViewport(0, 0, m_Camera.width, m_Camera.height); + qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0); + qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // + // set up viewpoint + // + + + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + screenaspect = (float)m_Camera.width / m_Camera.height; + yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI; + qgluPerspective (yfov, screenaspect, 8, 32768); + + // we're too lazy to calc projection matrix ourselves!!! + qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); + + vec3_t vec; + + m4x4_identity(&m_Camera.modelview[0][0]); + VectorSet(vec, -90, 0, 0); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, 0, 0, 90); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, 0, m_Camera.angles[0], 0); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, 0, 0, -m_Camera.angles[1]); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, -m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]); + m4x4_translate_by_vec3(&m_Camera.modelview[0][0], vec); + + Cam_BuildMatrix (); + + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity(); + + qglMultMatrixf(&m_Camera.modelview[0][0]); + + // grab the GL_PROJECTION and GL_MODELVIEW matrixes + // used in GetRelativeAxes + //qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); + //qglGetFloatv (GL_MODELVIEW_MATRIX, &m_Camera.modelview[0][0]); + +#if 0 + // TTimo: this is not used, just for verification (0, 0, m_Camera.width, m_Camera.height) + GLint viewprt[4]; + qglGetIntegerv (GL_VIEWPORT, viewprt); +#endif + + if (g_PrefsDlg.m_bGLLighting) + { + GLfloat inverse_cam_dir[4], ambient[4], diffuse[4];//, material[4]; + + ambient[0] = ambient[1] = ambient[2] = 0.6f; + ambient[3] = 1.0f; + diffuse[0] = diffuse[1] = diffuse[2] = 0.4f; + diffuse[3] = 1.0f; + //material[0] = material[1] = material[2] = 0.8f; + //material[3] = 1.0f; + + vec3_t vCam, vRotate; + VectorSet(vCam, -1, 0, 0); //default cam pos + VectorSet(vRotate, 0, -m_Camera.angles[0], 0); + VectorRotate(vCam, vRotate, vCam); + VectorSet(vRotate, 0, 0, m_Camera.angles[1]); + VectorRotate(vCam, vRotate, vCam); + + inverse_cam_dir[0] = vCam[0]; + inverse_cam_dir[1] = vCam[1]; + inverse_cam_dir[2] = vCam[2]; + inverse_cam_dir[3] = 0; + + qglColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + + qglLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir); + + qglLightfv(GL_LIGHT0, GL_AMBIENT, ambient); + qglLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); + + qglEnable(GL_LIGHT0); + } + + InitCull (); + + // + // draw stuff + // + + Cam_DrawStuff(); + + qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_NORMAL_ARRAY); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + qglDisable (GL_TEXTURE_2D); + qglDisable (GL_LIGHTING); + qglDisable (GL_COLOR_MATERIAL); + + qglEnable (GL_CULL_FACE); + + brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; + + if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) + { + qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2], 0.3f); + qglEnable (GL_BLEND); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDepthFunc (GL_LEQUAL); + for (brush = pList->next ; brush != pList ; brush=brush->next) + { + if (brush->bCamCulled) // draw selected faces of filtered brushes to remind that there is a selection + continue; + + if (brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area)) + continue; + + if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) + { + DrawPatchMesh(brush->pPatch); + } + else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) + { + brush->owner->model.pRender->Draw(DRAW_GL_FLAT, (DRAW_RF_SEL_OUTLINE|DRAW_RF_CAM)); + } + else + { + for (face=brush->brush_faces ; face ; face=face->next) + Brush_FaceDraw(face, DRAW_GL_FLAT); + } + } + + + int nCount = g_ptrSelectedFaces.GetSize(); + if (nCount > 0) + { + for (int i = 0; i < nCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + Brush_FaceDraw(selFace, DRAW_GL_FLAT); + } + } + + qglDisableClientState(GL_NORMAL_ARRAY); + qglDepthFunc (GL_LESS); + } + + if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) + { + // non-zbuffered outline + qglDisable (GL_BLEND); + qglDisable (GL_DEPTH_TEST); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglColor3f (1, 1, 1); + for (brush = pList->next ; brush != pList ; brush=brush->next) + { + if ((brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area))) + continue; + + if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) + { + DrawPatchMesh(brush->pPatch); + } + else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) + { + brush->owner->model.pRender->Draw(DRAW_GL_WIRE, (DRAW_RF_SEL_FILL|DRAW_RF_CAM)); + + // Hydra : always draw bbox outline! + aabb_draw(brush->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + } + else + { + for (face=brush->brush_faces ; face ; face=face->next) + Brush_FaceDraw(face, DRAW_GL_WIRE); + } + } + } + + // edge / vertex flags + if (g_qeglobals.d_select_mode == sel_vertex) + { + // GL_POINTS on Kyro Workaround + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + // brush verts + qglPointSize (4); + qglColor3f (0,1,0); + qglBegin (GL_POINTS); + for (i=0 ; inext) + brush->bCamCulled = false; + + for (brush = pList->next ; brush != pList ; brush=brush->next) + brush->bCamCulled = false; +} + +void CamWnd::OnExpose () +{ + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: glXMakeCurrent failed..\n "); + Sys_Printf("Please restart Radiant if the camera view is not working\n"); + } + else + { + QE_CheckOpenGLForErrors(); + g_pSplitList = NULL; + if (g_bClipMode) + { + if (g_Clip1.Set() && g_Clip2.Set()) + { + g_pSplitList = (g_bSwitch) ? + &g_brBackSplits : &g_brFrontSplits; + } + } + + Patch_LODMatchAll(); // spog + + Cam_Draw (); + QE_CheckOpenGLForErrors (); + + m_XORRectangle.set(rectangle_t()); + SwapBuffers (); + } +} + +void CamWnd::BenchMark() +{ + if (!MakeCurrent ()) + Error ("glXMakeCurrent failed in Benchmark"); + + qglDrawBuffer (GL_FRONT); + double dStart = Sys_DoubleTime (); + for (int i=0 ; i < 100 ; i++) + { + m_Camera.angles[YAW] = i*4; + Cam_Draw(); + } + SwapBuffers (); + qglDrawBuffer (GL_BACK); + double dEnd = Sys_DoubleTime (); + Sys_Printf ("%5.2f seconds\n", dEnd - dStart); +} diff --git a/radiant/camwindow.h b/radiant/camwindow.h new file mode 100644 index 00000000..98556b00 --- /dev/null +++ b/radiant/camwindow.h @@ -0,0 +1,171 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CAMWINDOW_H_ +#define _CAMWINDOW_H_ + +class XYWnd; + +#include "glwindow.h" + +class rectangle_t +{ +public: + rectangle_t() + : x(0), y(0), w(0), h(0) + {} + rectangle_t(float _x, float _y, float _w, float _h) + : x(_x), y(_y), w(_w), h(_h) + {} + float x; + float y; + float w; + float h; +}; + +class XORRectangle +{ +public: + XORRectangle(GtkWidget* widget) + : m_widget(widget), m_gc(NULL) + {} + ~XORRectangle() + { + if(initialised()) + gdk_gc_unref(m_gc); + } + void set(rectangle_t rectangle) + { + lazy_init(); + draw(); + m_rectangle = rectangle; + draw(); + } +private: + bool initialised() const + { + return m_gc != NULL; + } + void lazy_init() + { + if(!initialised()) + { + m_gc = gdk_gc_new(m_widget->window); + + GdkColor color = { 0, 0xffff, 0xffff, 0xffff, }; + GdkColormap* colormap = gdk_window_get_colormap(m_widget->window); + gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE); + gdk_gc_copy(m_gc, m_widget->style->white_gc); + gdk_gc_set_foreground(m_gc, &color); + gdk_gc_set_background(m_gc, &color); + + gdk_gc_set_function(m_gc, GDK_XOR); + } + } + void draw() const + { + const int x = (int)m_rectangle.x; + const int y = (int)m_rectangle.y; + const int w = (int)m_rectangle.w; + const int h = (int)m_rectangle.h; + gdk_draw_rectangle(m_widget->window, m_gc, TRUE, x, -(h) - (y - m_widget->allocation.height), w, h); + } + + rectangle_t m_rectangle; + + GdkGC* m_gc; + GtkWidget* m_widget; +}; + +class CamWnd : public GLWindow +{ +public: + void MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn); + void ReInitGL(); + void BenchMark(); + CamWnd(); + virtual ~CamWnd(); + camera_t *Camera(){return &m_Camera;}; + void Cam_MouseControl(float dtime); + void Cam_ChangeFloor(qboolean up); + void ToggleFreeMove(); + bool m_bFreeMove; + +protected: + void Cam_Init(); + void Cam_BuildMatrix(); + void Cam_PositionDrag(); + void Cam_KeyControl(float dtime); + void Cam_MouseDown(int x, int y, int buttons); + void Cam_MouseUp (int x, int y, int buttons); + void Cam_MouseMoved (int x, int y, int buttons); + void InitCull(); + qboolean CullBrush (brush_t *b); + void Cam_Draw(); + void Cam_DrawStuff(); + void Cam_DrawBrushes(int mode); + void Cam_DrawBrush(brush_t *b, int mode); + + brush_t* m_TransBrushes[MAX_MAP_BRUSHES]; + int m_nNumTransBrushes; + camera_t m_Camera; + int m_nCambuttonstate; + int m_ptButtonX; + int m_ptCursorX; + int m_ptLastCursorX; + int m_ptLastCamCursorX; + int m_ptButtonY; + int m_ptCursorY; + int m_ptLastCursorY; + int m_ptLastCamCursorY; + face_t* m_pSide_select; + vec3_t m_vCull1; + vec3_t m_vCull2; + int m_nCullv1[3]; + int m_nCullv2[3]; + bool m_bClipMode; + guint m_FocusOutHandler_id; + + void OnCreate (); + void OnExpose (); + void OnLButtonDown (guint32 flags, int x, int y); + void OnRButtonDown (guint32 flags, int x, int y); + void OnMButtonDown (guint32 flags, int x, int y); + void OnLButtonUp (guint32 flags, int pointx, int pointy); + void OnRButtonUp (guint32 flags, int pointx, int pointy); + void OnMButtonUp (guint32 flags, int pointx, int pointy); + void OnMouseMove (guint32 flags, int pointx, int pointy); + void OnMouseWheel(bool bUp); + void OnSize(int cx, int cy); + +protected: + void OriginalMouseDown (guint32 nFlags, int pointX, int pointY); + void OriginalMouseUp (guint32 nFlags, int pointX, int pointY); + +private: + XORRectangle m_XORRectangle; + + // project a point in geometric space into camera space + void ProjectCamera(const vec3_t A, vec_t B[2]); +}; + + +#endif // _CAMWINDOW_H_ diff --git a/radiant/csg.cpp b/radiant/csg.cpp new file mode 100644 index 00000000..4e41a611 --- /dev/null +++ b/radiant/csg.cpp @@ -0,0 +1,687 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +#include "winding.h" +#include "filters.h" + +/* +============= +CSG_MakeHollow +============= +*/ + +void Brush_Scale(brush_t* b) +{ + for (face_t* f = b->brush_faces ; f ; f=f->next) + { + for (int i=0 ; i<3 ; i++) + { + VectorScale (f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i]); + } + } +} + +void CSG_MakeHollow (void) +{ + brush_t *b, *front, *back, *next; + face_t *f; + face_t split; + vec3_t move; + int i; + + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + + if (b->owner->eclass->fixedsize || b->patchBrush || b->bFiltered) + continue; + + for (f = b->brush_faces ; f ; f=f->next) + { + split = *f; + VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move); + for (i=0 ; i<3 ; i++) + VectorSubtract (split.planepts[i], move, split.planepts[i]); + + Brush_SplitBrushByFace (b, &split, &front, &back); + if (back) + Brush_Free (back); + if (front) + Brush_AddToList (front, &selected_brushes); + } + Brush_Free (b); + } + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Brush_Merge + + Returns a new brush that is created by merging brush1 and brush2. + May return NULL if brush1 and brush2 do not create a convex brush when merged. + The input brushes brush1 and brush2 stay intact. + + if onlyshape is true then the merge is allowed based on the shape only + otherwise the texture/shader references of faces in the same plane have to + be the same as well. +============= +*/ +brush_t *Brush_Merge(brush_t *brush1, brush_t *brush2, int onlyshape) +{ + int i, shared; + brush_t *newbrush; + face_t *face1, *face2, *newface, *f; + + // check for bounding box overlapp + for (i = 0; i < 3; i++) + { + if (brush1->mins[i] > brush2->maxs[i] + ON_EPSILON + || brush1->maxs[i] < brush2->mins[i] - ON_EPSILON) + { + // never merge if the brushes overlap + return NULL; + } + } + // + shared = 0; + // check if the new brush would be convex... flipped planes make a brush non-convex + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't check the faces of brush 1 and 2 touching each other + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + { + shared++; + // there may only be ONE shared side + if (shared > 1) + return NULL; + break; + } + } + // if this face plane is shared + if (face2) continue; + // + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + // don't check the faces of brush 1 and 2 touching each other + for (f = brush1->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face2->plane, &f->plane, true)) break; + } + if (f) + continue; + // + if (Plane_Equal(&face1->plane, &face2->plane, false)) + { + //if the texture/shader references should be the same but are not + if (!onlyshape && stricmp(face1->texdef.GetName(), face2->texdef.GetName()) != 0) return NULL; + continue; + } + // + if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, + face1->plane.normal, face2->plane.normal, + face1->plane.dist, face2->plane.dist)) + { + return NULL; + } //end if + } //end for + } //end for + // + newbrush = Brush_Alloc(); + // + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't add the faces of brush 1 and 2 touching each other + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + break; + } + if (face2) + continue; + // don't add faces with the same plane twice + for (f = newbrush->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face1->plane, &f->plane, false)) + break; + if (Plane_Equal(&face1->plane, &f->plane, true)) + break; + } + if (f) + continue; + // + newface = Face_Alloc(); + newface->texdef = face1->texdef; + VectorCopy(face1->planepts[0], newface->planepts[0]); + VectorCopy(face1->planepts[1], newface->planepts[1]); + VectorCopy(face1->planepts[2], newface->planepts[2]); + newface->plane = face1->plane; + newface->next = newbrush->brush_faces; + newbrush->brush_faces = newface; + } + // + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + // don't add the faces of brush 1 and 2 touching each other + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + if (Plane_Equal(&face2->plane, &face1->plane, true)) + break; + } + if (face1) + continue; + // don't add faces with the same plane twice + for (f = newbrush->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face2->plane, &f->plane, false)) + break; + if (Plane_Equal(&face2->plane, &f->plane, true)) + break; + } + if (f) + continue; + // + newface = Face_Alloc(); + newface->texdef = face2->texdef; + VectorCopy(face2->planepts[0], newface->planepts[0]); + VectorCopy(face2->planepts[1], newface->planepts[1]); + VectorCopy(face2->planepts[2], newface->planepts[2]); + newface->plane = face2->plane; + newface->next = newbrush->brush_faces; + newbrush->brush_faces = newface; + } + // link the new brush to an entity + Entity_LinkBrush (brush1->owner, newbrush); + // build windings for the faces + Brush_BuildWindings( newbrush, false); + + return newbrush; +} + +/* +============= +Brush_MergeListPairs + + Returns a list with merged brushes. + Tries to merge brushes pair wise. + The input list is destroyed. + Input and output should be a single linked list using .next +============= +*/ +brush_t *Brush_MergeListPairs(brush_t *brushlist, int onlyshape) +{ + int nummerges, merged; + brush_t *b1, *b2, *tail, *newbrush, *newbrushlist; + brush_t *lastb2; + + if (!brushlist) return NULL; + + nummerges = 0; + do + { + for (tail = brushlist; tail; tail = tail->next) + { + if (!tail->next) break; + } + merged = 0; + newbrushlist = NULL; + for (b1 = brushlist; b1; b1 = brushlist) + { + lastb2 = b1; + for (b2 = b1->next; b2; b2 = b2->next) + { + newbrush = Brush_Merge(b1, b2, onlyshape); + if (newbrush) + { + tail->next = newbrush; + lastb2->next = b2->next; + brushlist = brushlist->next; + b1->next = b1->prev = NULL; + b2->next = b2->prev = NULL; + Brush_Free(b1); + Brush_Free(b2); + for (tail = brushlist; tail; tail = tail->next) + { + if (!tail->next) break; + } //end for + merged++; + nummerges++; + break; + } + lastb2 = b2; + } + //if b1 can't be merged with any of the other brushes + if (!b2) + { + brushlist = brushlist->next; + //keep b1 + b1->next = newbrushlist; + newbrushlist = b1; + } + } + brushlist = newbrushlist; + } while(merged); + return newbrushlist; +} + +/* +============= +Brush_MergeList + + Tries to merge all brushes in the list into one new brush. + The input brush list stays intact. + Returns NULL if no merged brush can be created. + To create a new brush the brushes in the list may not overlap and + the outer faces of the brushes together should make a new convex brush. + + if onlyshape is true then the merge is allowed based on the shape only + otherwise the texture/shader references of faces in the same plane have to + be the same as well. +============= +*/ +brush_t *Brush_MergeList(brush_t *brushlist, int onlyshape) +{ + brush_t *brush1, *brush2, *brush3, *newbrush; + face_t *face1, *face2, *face3, *newface, *f; + + if (!brushlist) return NULL; + for (brush1 = brushlist; brush1; brush1 = brush1->next) + { + // check if the new brush would be convex... flipped planes make a brush concave + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't check face1 if it touches another brush + for (brush2 = brushlist; brush2; brush2 = brush2->next) + { + if (brush2 == brush1) continue; + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + { + break; + } + } + if (face2) break; + } + // if face1 touches another brush + if (brush2) continue; + // + for (brush2 = brush1->next; brush2; brush2 = brush2->next) + { + // don't check the faces of brush 2 touching another brush + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + for (brush3 = brushlist; brush3; brush3 = brush3->next) + { + if (brush3 == brush2) continue; + for (face3 = brush3->brush_faces; face3; face3 = face3->next) + { + if (Plane_Equal(&face2->plane, &face3->plane, true)) break; + } + if (face3) break; + } + // if face2 touches another brush + if (brush3) continue; + // + if (Plane_Equal(&face1->plane, &face2->plane, false)) + { + //if the texture/shader references should be the same but are not + if (!onlyshape && stricmp(face1->texdef.GetName(), face2->texdef.GetName()) != 0) return NULL; + continue; + } + // + if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, + face1->plane.normal, face2->plane.normal, + face1->plane.dist, face2->plane.dist)) + { + return NULL; + } + } + } + } + } + // + newbrush = Brush_Alloc(); + // + for (brush1 = brushlist; brush1; brush1 = brush1->next) + { + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't add face1 to the new brush if it touches another brush + for (brush2 = brushlist; brush2; brush2 = brush2->next) + { + if (brush2 == brush1) continue; + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + { + break; + } + } + if (face2) break; + } + if (brush2) continue; + // don't add faces with the same plane twice + for (f = newbrush->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face1->plane, &f->plane, false)) + break; + if (Plane_Equal(&face1->plane, &f->plane, true)) + break; + } + if (f) + continue; + // + newface = Face_Alloc(); + newface->texdef = face1->texdef; + VectorCopy(face1->planepts[0], newface->planepts[0]); + VectorCopy(face1->planepts[1], newface->planepts[1]); + VectorCopy(face1->planepts[2], newface->planepts[2]); + newface->plane = face1->plane; + newface->next = newbrush->brush_faces; + newbrush->brush_faces = newface; + } + } + // link the new brush to an entity + Entity_LinkBrush (brushlist->owner, newbrush); + // build windings for the faces + Brush_BuildWindings( newbrush, false); + + return newbrush; +} + +/* +============= +Brush_Subtract + + Returns a list of brushes that remain after B is subtracted from A. + May by empty if A is contained inside B. + The originals are undisturbed. +============= +*/ +brush_t *Brush_Subtract(brush_t *a, brush_t *b) +{ + // a - b = out (list) + brush_t *front, *back; + brush_t *in, *out, *next; + face_t *f; + + in = a; + out = NULL; + for (f = b->brush_faces; f && in; f = f->next) + { + Brush_SplitBrushByFace(in, f, &front, &back); + if (in != a) Brush_Free(in); + if (front) + { // add to list + front->next = out; + out = front; + } + in = back; + } + //NOTE: in != a just in case brush b has no faces + if (in && in != a) + { + Brush_Free(in); + } + else + { //didn't really intersect + for (b = out; b; b = next) + { + next = b->next; + b->next = b->prev = NULL; + Brush_Free(b); + } + return a; + } + return out; +} + +/* +============= +CSG_Subtract +============= +*/ +void CSG_Subtract (void) +{ + brush_t *b, *s, *fragments, *nextfragment, *frag, *next, *snext; + brush_t fragmentlist; + int i, numfragments, numbrushes; + + Sys_Printf ("Subtracting...\n"); + + if (selected_brushes.next == &selected_brushes) + { + Sys_Printf("No brushes selected.\n"); + return; + } + + fragmentlist.next = &fragmentlist; + fragmentlist.prev = &fragmentlist; + + numfragments = 0; + numbrushes = 0; + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + + if (b->owner->eclass->fixedsize) + continue; // can't use texture from a fixed entity, so don't subtract + + // chop all fragments further up + for (s = fragmentlist.next; s != &fragmentlist; s = snext) + { + snext = s->next; + + for (i=0 ; i<3 ; i++) + if (b->mins[i] >= s->maxs[i] - ON_EPSILON + || b->maxs[i] <= s->mins[i] + ON_EPSILON) + break; + if (i != 3) + continue; // definately don't touch + fragments = Brush_Subtract(s, b); + // if the brushes did not really intersect + if (fragments == s) + continue; + // try to merge fragments + fragments = Brush_MergeListPairs(fragments, true); + // add the fragments to the list + for (frag = fragments; frag; frag = nextfragment) + { + nextfragment = frag->next; + frag->next = NULL; + frag->owner = s->owner; + Brush_AddToList(frag, &fragmentlist); + } + // free the original brush + Brush_Free(s); + } + + // chop any active brushes up + for (s = active_brushes.next; s != &active_brushes; s = snext) + { + snext = s->next; + + if (s->owner->eclass->fixedsize || s->patchBrush || s->bFiltered) + continue; + + if (s->brush_faces->pShader->getFlags() & QER_NOCARVE) + { + continue; + } + + for (i=0 ; i<3 ; i++) + if (b->mins[i] >= s->maxs[i] - ON_EPSILON + || b->maxs[i] <= s->mins[i] + ON_EPSILON) + break; + if (i != 3) + continue; // definately don't touch + + fragments = Brush_Subtract(s, b); + // if the brushes did not really intersect + if (fragments == s) + continue; + // + Undo_AddBrush(s); + // one extra brush chopped up + numbrushes++; + // try to merge fragments + fragments = Brush_MergeListPairs(fragments, true); + // add the fragments to the list + for (frag = fragments; frag; frag = nextfragment) + { + nextfragment = frag->next; + frag->next = NULL; + frag->owner = s->owner; + Brush_AddToList(frag, &fragmentlist); + } + // free the original brush + Brush_Free(s); + } + } + + // move all fragments to the active brush list + for (frag = fragmentlist.next; frag != &fragmentlist; frag = nextfragment) + { + nextfragment = frag->next; + numfragments++; + Brush_RemoveFromList(frag); + Brush_AddToList(frag, &active_brushes); + Undo_EndBrush(frag); + } + + /*if (numfragments == 0) + { + Sys_Printf("Selected brush%s did not intersect with any other brushes.\n", + (selected_brushes.next->next == &selected_brushes) ? "":"es"); + return; + }*/ + Sys_Printf("done. (created %d fragment%s out of %d brush%s)\n", numfragments, (numfragments == 1)?"":"s", + numbrushes, (numbrushes == 1)?"":"es"); + Sys_UpdateWindows(W_ALL); +} + +/* +============= +CSG_Merge +============= +*/ +void CSG_Merge(void) +{ + brush_t *b, *next, *newlist, *newbrush; + struct entity_s *owner; + + Sys_Printf ("Merging...\n"); + + if (selected_brushes.next == &selected_brushes) + { + Sys_Printf("No brushes selected.\n"); + return; + } + + if (selected_brushes.next->next == &selected_brushes) + { + Sys_Printf("At least two brushes have to be selected.\n"); + return; + } + + owner = selected_brushes.next->owner; + + for (b = selected_brushes.next; b != &selected_brushes; b = next) + { + next = b->next; + + if (b->owner->eclass->fixedsize) + { + // can't use texture from a fixed entity, so don't subtract + Sys_Printf("Cannot add fixed size entities.\n"); + return; + } + + if (b->patchBrush) + { + Sys_Printf("Cannot add patches.\n"); + return; + } + + // TTimo: cleanup + // disable the qer_nocarve for CSG-MERGE operations +#if 0 + if (b->brush_faces->d_texture->bFromShader && (b->brush_faces->d_texture->nShaderFlags & QER_NOCARVE)) + { + Sys_Printf("Cannot add brushes using shaders that don't allows CSG operations.\n"); + return; + } +#endif + + if (b->owner != owner) + { + Sys_Printf("Cannot add brushes from different entities.\n"); + return; + } + + } + + newlist = NULL; + for (b = selected_brushes.next; b != &selected_brushes; b = next) + { + next = b->next; + + Brush_RemoveFromList(b); + b->next = newlist; + b->prev = NULL; + newlist = b; + } + + newbrush = Brush_MergeList(newlist, true); + // if the new brush would not be convex + if (!newbrush) + { + // add the brushes back into the selection + for (b = newlist; b; b = next) + { + next = b->next; + b->next = NULL; + b->prev = NULL; + Brush_AddToList(b, &selected_brushes); + } + Sys_Printf("Cannot add a set of brushes with a concave hull.\n"); + return; + } + // free the original brushes + for (b = newlist; b; b = next) + { + next = b->next; + b->next = NULL; + b->prev = NULL; + Brush_Free(b); + } + + newbrush->bFiltered = FilterBrush(newbrush); // spog - set filters for the new brush + + Brush_AddToList(newbrush, &selected_brushes); + + Sys_Printf ("done.\n"); + Sys_UpdateWindows (W_ALL); +} diff --git a/radiant/dialog.cpp b/radiant/dialog.cpp new file mode 100644 index 00000000..bbaa84d2 --- /dev/null +++ b/radiant/dialog.cpp @@ -0,0 +1,295 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Base dialog class, provides a way to run modal dialogs and +// set/get the widget values in member variables. +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include + +typedef struct +{ + GtkObject *object; + void *buffer; + DLG_DATA_TYPE type; +} DLG_DATA; + +// ============================================================================= +// Dialog class + +Dialog::Dialog () +{ + m_pDataList = (GSList*)NULL; + m_nReturn = IDCANCEL; + m_bNeedBuild = true; + m_nLoop = 0; +} + +Dialog::~Dialog () +{ + while (m_pDataList) + { + free (m_pDataList->data); + m_pDataList = g_slist_remove (m_pDataList, m_pDataList->data); + } + + if (m_pWidget != NULL) + gtk_widget_destroy (m_pWidget); +} + +// i suspect that this is redundant - gtk manages to remember the data stored in its widgets across a hide/show +void Dialog::ShowDlg () +{ + Create (); + UpdateData (FALSE); + gtk_widget_show (m_pWidget); +} + +void Dialog::HideDlg () +{ + UpdateData (TRUE); + gtk_widget_hide (m_pWidget); +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + reinterpret_cast(data)->HideDlg(); + reinterpret_cast(data)->EndModal(IDCANCEL); + return TRUE; +} + +void Dialog::Create () +{ + if (m_bNeedBuild) + { + m_pWidget = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "delete_event", + GTK_SIGNAL_FUNC (delete_event_callback), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (m_pWidget), "loop", &m_nLoop); + g_object_set_data (G_OBJECT (m_pWidget), "ret", &m_nReturn); + + BuildDialog (); + m_bNeedBuild = false; + } +} + +void Dialog::Destroy () +{ + if (m_pWidget != NULL) + { + gtk_widget_destroy (m_pWidget); + m_pWidget = NULL; + } +} + +void Dialog::AddDialogData (GtkObject *object, void *buf, DLG_DATA_TYPE type) +{ + DLG_DATA *data; + + data = (DLG_DATA*)qmalloc (sizeof(DLG_DATA)); + data->object = object; + data->buffer = buf; + data->type = type; + + m_pDataList = g_slist_append (m_pDataList, data); +} + +void Dialog::AddModalButton (GtkWidget *widget, int ret) +{ + gtk_signal_connect (GTK_OBJECT (widget), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (ret)); +} + +void Dialog::UpdateData (bool retrieve) + { + DLG_DATA *data; + GSList *lst; + char buf[32]; + + if (retrieve) + { + for (lst = m_pDataList; lst != NULL; lst = g_slist_next (lst)) + { + data = (DLG_DATA*)lst->data; + + switch (data->type) + { + case DLG_CHECK_BOOL: + *(bool*)data->buffer = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->object)); + break; + case DLG_RADIO_INT: + { + GSList *radio = gtk_radio_button_group (GTK_RADIO_BUTTON (data->object)); + *(int*)data->buffer = g_slist_length (radio) - 1; + for (; radio; radio = g_slist_next (radio)) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio->data))) + break; + else + (*(int*)data->buffer)--; + } break; + case DLG_ENTRY_TEXT: + { + const char *txt; + Str* str; + str = (Str*)data->buffer; + txt = gtk_entry_get_text (GTK_ENTRY (data->object)); + *str = txt; + } break; + case DLG_ENTRY_FLOAT: + *(float*)data->buffer = atof (gtk_entry_get_text (GTK_ENTRY (data->object))); + break; + case DLG_ENTRY_INT: + *(int*)data->buffer = atoi (gtk_entry_get_text (GTK_ENTRY (data->object))); + break; + case DLG_SPIN_FLOAT: + *(float*)data->buffer = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (data->object)); + break; + case DLG_SPIN_INT: + *(int*)data->buffer = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (data->object)); + break; + case DLG_ADJ_INT: + *(int*)data->buffer = (int) GTK_ADJUSTMENT (data->object)->value; + break; + case DLG_COMBO_INT: + { + GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children; + char *label; + const char *entry; + int i; + + *(int*)data->buffer = -1; + entry = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (data->object)->entry)); + + for (i = 0; lst != NULL; lst = g_list_next (lst)) + { + gtk_label_get (GTK_LABEL (GTK_BIN (lst->data)->child), &label); + + if (strcmp (label, entry) == 0) + { + *(int*)data->buffer = i; + break; + } + i++; + } + } break; + } + } + } + else + { + for (lst = m_pDataList; lst != NULL; lst = g_slist_next (lst)) + { + data = (DLG_DATA*)lst->data; + + switch (data->type) + { + case DLG_CHECK_BOOL: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->object), *(bool*)data->buffer); + break; + case DLG_RADIO_INT: + { + GSList *radio = gtk_radio_button_group (GTK_RADIO_BUTTON (data->object)); + gpointer btn = g_slist_nth_data (radio, g_slist_length (radio) - (*(int*)data->buffer) - 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), TRUE); + } break; + case DLG_ENTRY_TEXT: + { + Str* str; + str = (Str*)data->buffer; + const char *txt = str->GetBuffer (); + gtk_entry_set_text (GTK_ENTRY (data->object), txt); + } break; + case DLG_ENTRY_FLOAT: + sprintf (buf, "%g", (*(float*)data->buffer)); + gtk_entry_set_text (GTK_ENTRY (data->object), buf); + break; + case DLG_ENTRY_INT: + sprintf (buf, "%d", (*(int*)data->buffer)); + gtk_entry_set_text (GTK_ENTRY (data->object), buf); + break; + case DLG_SPIN_FLOAT: + gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->object), (*(float*)data->buffer)); + break; + case DLG_SPIN_INT: + gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->object), (*(int*)data->buffer)); + break; + case DLG_ADJ_INT: + gtk_adjustment_set_value (GTK_ADJUSTMENT (data->object), (*(int*)data->buffer)); + break; + case DLG_COMBO_INT: + { + GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children; + char *entry = ""; + + if (*(int*)data->buffer != -1) + { + lst = g_list_nth (lst, *(int*)data->buffer); + if (lst != NULL) + gtk_label_get (GTK_LABEL (GTK_BIN (lst->data)->child), &entry); + } + + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (data->object)->entry), entry); + } break; + } + } + } +} + +void Dialog::EndModal (int code) +{ + m_nLoop = 0; + m_nReturn = code; +} + +int Dialog::DoModal () +{ + Create (); + UpdateData (FALSE); + + PreModal(); + + gtk_grab_add (m_pWidget); + gtk_widget_show (m_pWidget); + + m_nLoop = 1; + while (m_nLoop) + gtk_main_iteration (); + + if (m_pWidget != NULL) + { + UpdateData (TRUE); + + gtk_grab_remove (m_pWidget); + gtk_widget_hide (m_pWidget); + } + PostModal (m_nReturn); + + return m_nReturn; +} + diff --git a/radiant/dialog.h b/radiant/dialog.h new file mode 100644 index 00000000..f9450efe --- /dev/null +++ b/radiant/dialog.h @@ -0,0 +1,85 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _DIALOG_H_ +#define _DIALOG_H_ + +#include +#include "str.h" +#include "gtkmisc.h" + +typedef enum +{ + DLG_CHECK_BOOL, + DLG_RADIO_INT, + DLG_ENTRY_TEXT, + DLG_ENTRY_FLOAT, + DLG_ENTRY_INT, + DLG_SPIN_FLOAT, + DLG_SPIN_INT, + DLG_ADJ_INT, + DLG_COMBO_INT +} DLG_DATA_TYPE; + +class Dialog +{ + public: + Dialog (); + virtual ~Dialog (); + + /*! + start modal dialog box + you need to use AddModalButton to select IDOK IDCANCEL buttons + */ + int DoModal (); + void EndModal (int code); + virtual void BuildDialog () = 0; + virtual void UpdateData (bool retrieve); + virtual void PreModal () { }; + virtual void PostModal (int code) { }; + virtual void ShowDlg (); + virtual void HideDlg (); + void Create (); + void Destroy (); + GtkWidget* GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), name)); } + GtkWidget* GetWidget () + { return m_pWidget; } + + protected: + GtkWidget *m_pWidget; + int m_nLoop; + int m_nReturn; + + void AddDialogData (GtkWidget *widget, void *buf, DLG_DATA_TYPE type) + { AddDialogData (GTK_OBJECT (widget), buf, type); }; + void AddDialogData (GtkObject *object, void *buf, DLG_DATA_TYPE type); + /*! + used in overloaded BuildDialog implementations to configure modal behaviour easily + */ + void AddModalButton (GtkWidget *widget, int ret); + + private: + GSList* m_pDataList; + bool m_bNeedBuild; +}; + +#endif // _DIALOG_H_ diff --git a/radiant/dialoginfo.cpp b/radiant/dialoginfo.cpp new file mode 100644 index 00000000..cdba7f24 --- /dev/null +++ b/radiant/dialoginfo.cpp @@ -0,0 +1,75 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// InfoDialog - non-modal, not derived from Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +//#include "qe3.h" + +GtkWidget *g_dlgInfo; +GtkWidget *s_pEdit; + +// ============================================================================= +// Global functions + +void ShowInfoDialog(const char* pText) +{ + if (g_dlgInfo == NULL) + { + GtkWidget *dlg, *scr, *text; + + g_dlgInfo = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Information"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (gtk_widget_hide), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 150); + + scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_container_add (GTK_CONTAINER (dlg), scr); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_set_border_width (GTK_CONTAINER (scr), 5); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + s_pEdit = text = gtk_text_view_new(); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + } + + GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(s_pEdit)); + gtk_text_buffer_set_text (buffer, pText, -1); + gtk_widget_show (g_dlgInfo); +} + +void HideInfoDialog() +{ + if (g_dlgInfo) + gtk_widget_hide (g_dlgInfo); +} + diff --git a/radiant/drag.cpp b/radiant/drag.cpp new file mode 100644 index 00000000..f9e67aef --- /dev/null +++ b/radiant/drag.cpp @@ -0,0 +1,845 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +//#include "qe3.h" + +/* + + drag either multiple brushes, or select plane points from + a single brush. + +*/ + +extern int g_nPatchClickedView; + +qboolean drag_ok; +vec3_t drag_xvec; +vec3_t drag_yvec; + +//static int buttonstate; +int pressx, pressy; +static vec3_t pressdelta; +static vec3_t vPressStart; +//static int buttonx, buttony; + + +//int num_move_points; +//float *move_points[1024]; + +int lastx, lasty; + +qboolean drag_first; + + +void AxializeVector (vec3_t v) +{ + vec3_t a; + float o; + int i; + + if (!v[0] && !v[1]) + return; + if (!v[1] && !v[2]) + return; + if (!v[0] && !v[2]) + return; + + for (i=0 ; i<3 ; i++) + a[i] = fabs(v[i]); + if (a[0] > a[1] && a[0] > a[2]) + i = 0; + else if (a[1] > a[0] && a[1] > a[2]) + i = 1; + else + i = 2; + + o = v[i]; + VectorCopy (vec3_origin, v); + if (o<0) + v[i] = -1; + else + v[i] = 1; + +} + +/* +=========== +Drag_Setup +=========== +*/ +extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons); + +void Drag_Setup (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir) +{ + trace_t t; + face_t *f; + + drag_first = true; + + VectorCopy (vec3_origin, pressdelta); + pressx = x; + pressy = y; + + // snap to nearest axis for camwindow drags + VectorCopy (xaxis, drag_xvec); + AxializeVector (drag_xvec); + VectorCopy (yaxis, drag_yvec); + AxializeVector (drag_yvec); + + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + SelectCurvePointByRay (origin, dir, buttons); + + if(g_qeglobals.d_select_mode == sel_area) + { + drag_ok = true; + + if(g_nPatchClickedView == W_CAMERA ) { + VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 ); + VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 ); + } + } + else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected + { + drag_ok = true; + Sys_UpdateWindows(W_ALL); + Undo_Start("drag curve point"); + Undo_AddBrushList(&selected_brushes); + } + return; + } + else + { + g_qeglobals.d_num_move_points = 0; + } + + if (g_qeglobals.d_select_mode == sel_areatall) + { + VectorCopy(origin, g_qeglobals.d_vAreaTL); + VectorCopy(origin, g_qeglobals.d_vAreaBR); + + Sys_UpdateWindows(W_ALL); + + drag_ok = true; + return; + } + + if (selected_brushes.next == &selected_brushes) + { + //in this case a new brush is created when the dragging + //takes place in the XYWnd, An useless undo is created + //when the dragging takes place in the CamWnd + Undo_Start("create brush"); + + Sys_Status("No selection to drag", 0); + return; + } + + if (g_qeglobals.d_select_mode == sel_vertex) + { + SelectVertexByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + Undo_Start("drag vertex"); + Undo_AddBrushList(&selected_brushes); + // Need an update here for highlighting selected vertices + Sys_UpdateWindows(W_XY | W_CAMERA); + return; + } + } + + if (g_qeglobals.d_select_mode == sel_edge) + { + SelectEdgeByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + Undo_Start("drag edge"); + Undo_AddBrushList(&selected_brushes); + return; + } + } + + // + // check for direct hit first + // + t = Test_Ray (origin, dir, true); + if (t.selected) + { + drag_ok = true; + + Undo_Start("drag selection"); + Undo_AddBrushList(&selected_brushes); + + if (buttons == (MK_LBUTTON|MK_CONTROL) ) + { + Sys_Printf ("Shear dragging face\n"); + Brush_SelectFaceForDragging (t.brush, t.face, true); + } + else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) + { + Sys_Printf ("Sticky dragging brush\n"); + for (f=t.brush->brush_faces ; f ; f=f->next) + Brush_SelectFaceForDragging (t.brush, f, false); + } + else + Sys_Printf ("Dragging entire selection\n"); + + return; + } + + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + return; + + // + // check for side hit + // + // multiple brushes selected? + if (selected_brushes.next->next != &selected_brushes) + { + // yes, special handling + bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true; + if (bOK) + { + for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next) + { + if (buttons & MK_CONTROL) + Brush_SideSelect (pBrush, origin, dir, true); + else + Brush_SideSelect (pBrush, origin, dir, false); + } + } + else + { + Sys_Printf ("press ALT to drag multiple edges\n"); + return; + } + } + else + { + // single select.. trying to drag fixed entities handle themselves and just move + if (buttons & MK_CONTROL) + Brush_SideSelect (selected_brushes.next, origin, dir, true); + else + Brush_SideSelect (selected_brushes.next, origin, dir, false); + } + + Sys_Printf ("Side stretch\n"); + drag_ok = true; + + Undo_Start("side stretch"); + Undo_AddBrushList(&selected_brushes); +} + +entity_t *peLink; + +void UpdateTarget(vec3_t origin, vec3_t dir) +{ + trace_t t; + entity_t *pe; + int i; + char sz[128]; + + t = Test_Ray (origin, dir, 0); + + if (!t.brush) + return; + + pe = t.brush->owner; + + if (pe == NULL) + return; + + // is this the first? + if (peLink != NULL) + { + + // Get the target id from out current target + // if there is no id, make one + + i = IntForKey(pe, "target"); + if (i <= 0) + { + i = GetUniqueTargetId(1); + sprintf(sz, "%d", i); + + SetKeyValue(pe, "target", sz); + } + + // set the target # into our src + + sprintf(sz, "%d", i); + SetKeyValue(peLink, "targetname", sz); + + Sys_UpdateWindows(W_ENTITY); + + } + + // promote the target to the src + + peLink = pe; + +} + +/* +=========== +Drag_Begin +//++timo test three button mouse and three button emulation here ? +=========== +*/ +void Drag_Begin (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir, bool sf_camera) +{ + trace_t t; + bool altdown; + int nFlag; + + drag_ok = false; + VectorCopy (vec3_origin, pressdelta); + VectorCopy (vec3_origin, vPressStart); + + drag_first = true; + peLink = NULL; + + altdown = Sys_AltDown(); + + // shift-LBUTTON = select entire brush + // shift-alt-LBUTTON = drill select + if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) + { + nFlag = altdown ? SF_CYCLE : 0; + if (sf_camera) + nFlag |= SF_CAMERA; + else + nFlag |= SF_ENTITIES_FIRST; + Select_Ray(origin, dir, nFlag); + return; + } + + // (shift-)alt-LBUTTON = area select completely tall + if ( !sf_camera && + ( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) && + altdown && g_qeglobals.d_select_mode != sel_curvepoint) + { + if (g_pParentWnd->ActiveXY()->AreaSelectOK()) + { + g_qeglobals.d_select_mode = sel_areatall; + + Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); + return; + } + } + + // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities + if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint) + { + nFlag = 0; + if (sf_camera) + nFlag |= SF_CAMERA; + else + nFlag |= SF_ENTITIES_FIRST; + Select_Ray (origin, dir, nFlag); + UpdateSurfaceDialog(); + + return; + } + + // ctrl-shift LBUTTON = select single face + if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) + { + if(Sys_AltDown()) + { + brush_t *b; + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->pPatch) + continue; + + for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) + { + g_ptrSelectedFaces.Add(pFace); + g_ptrSelectedFaceBrushes.Add(b); + } + } + + for (b = selected_brushes.next; b != &selected_brushes; ) + { + brush_t *pb = b; + b = b->next; + Brush_RemoveFromList (pb); + Brush_AddToList (pb, &active_brushes); + } + } + else + Select_Deselect (true); + + Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA)); + return; + } + + + // LBUTTON + all other modifiers = manipulate selection + if (buttons & MK_LBUTTON) + { + Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); + return; + } + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + // middle button = grab texture + if (buttons == nMouseButton) + { + t = Test_Ray (origin, dir, false); + if (t.face) + { + UpdateWorkzone_ForBrush( t.brush ); + // use a local brushprimit_texdef fitted to a default 2x2 texture + brushprimit_texdef_t bp_local; + ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL ); + Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL); + UpdateSurfaceDialog(); + UpdatePatchInspector(); + } + else + Sys_Printf ("Did not select a texture\n"); + return; + } + + // ctrl-middle button = set entire brush to texture + if (buttons == (nMouseButton|MK_CONTROL) ) + { + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.GetName()[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast( g_qeglobals.d_texturewin.pTexdef ) ); + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a btrush\n"); + return; + } + + // ctrl-shift-middle button = set single face to texture + if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) ) + { + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.GetName()[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef); + Brush_Build( t.brush ); + + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a btrush\n"); + return; + } + + if (buttons == (nMouseButton | MK_SHIFT)) + { + Sys_Printf("Set brush face texture info\n"); + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.GetName()[0] == '(') + { + if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT) + { + CString strBuff; + qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture(); + if (pTex) + { + vec3_t vColor; + VectorCopy(pTex->color, vColor); + + float fLargest = 0.0f; + for (int i = 0; i < 3; i++) + { + if (vColor[i] > fLargest) + fLargest = vColor[i]; + } + + if (fLargest == 0.0f) + { + vColor[0] = vColor[1] = vColor[2] = 1.0f; + } + else + { + float fScale = 1.0f / fLargest; + for (int i = 0; i < 3; i++) + { + vColor[i] *= fScale; + } + } + strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]); + SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer()); + Sys_UpdateWindows (W_ALL); + } + } + else + { + Sys_Printf ("Can't select an entity brush face\n"); + } + } + else + { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=425 + Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName()); + Brush_Build(t.brush); + + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a brush\n"); + return; + } + +} + + +// +//=========== +//MoveSelection +//=========== +// +void MoveSelection (vec3_t move) +{ + int i, success; + brush_t *b; + CString strStatus; + vec3_t vTemp, vTemp2, end; + + if (!move[0] && !move[1] && !move[2]) + { + return; + } + + if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)) + { + move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0]; + move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1]; + move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2]; + } + + if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode) + { + float fDeg = -move[2]; + float fAdj = move[2]; + int nAxis = 0; + if (g_pParentWnd->ActiveXY()->GetViewType() == XY) + { + fDeg = -move[1]; + fAdj = move[1]; + nAxis = 2; + } + else + if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) + { + fDeg = move[2]; + fAdj = move[2]; + nAxis = 1; + } + else + nAxis = 0; + + g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; + strStatus.Format("%s x:: %.1f y:: %.1f z:: %.1f", (g_bPatchBendMode) ? "Bend angle" : "Rotation", g_pParentWnd->ActiveXY()->Rotation()[0], g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); + g_pParentWnd->SetStatusText(2, strStatus); + + if (g_bPatchBendMode) + { + Patch_SelectBendNormal(); + Select_RotateAxis(nAxis, fDeg*2, false, true); + Patch_SelectBendAxis(); + Select_RotateAxis(nAxis, fDeg, false, true); + } + else + { + Select_RotateAxis(nAxis, fDeg, false, true); + } + return; + } + + if (g_pParentWnd->ActiveXY()->ScaleMode()) + { + vec3_t v; + v[0] = v[1] = v[2] = 1.0f; + if (move[1] > 0) + { + v[0] = 1.1f; + v[1] = 1.1f; + v[2] = 1.1f; + } + else + if (move[1] < 0) + { + v[0] = 0.9f; + v[1] = 0.9f; + v[2] = 0.9f; + } + + Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0], + (g_nScaleHow & SCALE_Y) ? 1.0f : v[1], + (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]); + // is that really necessary??? + Sys_UpdateWindows (W_ALL); + return; + } + + + vec3_t vDistance; + VectorSubtract(pressdelta, vPressStart, vDistance); + strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]); + g_pParentWnd->SetStatusText(3, strStatus); + + // + // dragging only a part of the selection + // + + // this is fairly crappy way to deal with curvepoint and area selection + // but it touches the smallest amount of code this way + // + if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) + { + //area selection + if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) + { + VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR); + return; + } + //curve point selection + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + Patch_UpdateSelected(move); + return; + } + //vertex selection + if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit) + { + if(g_qeglobals.d_num_move_points) { + success = true; + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true); + } + if (success) + VectorCopy(end, g_qeglobals.d_move_points[0]); + } + return; + } + //all other selection types + for (i=0 ; inext) + { + bool bMoved = false; + for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next) + for(int p=0; !bMoved && p<3; p++) + for (i=0 ; !bMoved && iplanepts[p] == g_qeglobals.d_move_points[i]) + bMoved = true; + if(!bMoved) continue; + + VectorCopy(b->maxs, vTemp); + VectorSubtract(vTemp, b->mins, vTemp); + Brush_Build(b,true,true,false,false); // don't filter + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] > b->maxs[i] + || b->maxs[i] - b->mins[i] > g_MaxBrushSize) + break; // dragged backwards or fucked up + } + if (i != 3) + break; + if (b->patchBrush) + { + VectorCopy(b->maxs, vTemp2); + VectorSubtract(vTemp2, b->mins, vTemp2); + VectorSubtract(vTemp2, vTemp, vTemp2); + //if (!Patch_DragScale(b->nPatchID, vTemp2, move)) + if (!Patch_DragScale(b->pPatch, vTemp2, move)) + { + b = NULL; + break; + } + } + } + // if any of the brushes were crushed out of existance + // calcel the entire move + if (b != &selected_brushes) + { + Sys_Printf ("Brush dragged backwards, move canceled\n"); + for (i=0 ; inext) + Brush_Build(b,true,true,false,false); // don't filter + } + + } + else + { + // reset face originals from vertex edit mode + // this is dirty, but unfortunately necessary because Brush_Build + // can remove windings + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + Brush_ResetFaceOriginals(b); + } + // + // if there are lots of brushes selected, just translate instead + // of rebuilding the brushes + // NOTE: this is not actually done, but would be a good idea + // + Select_Move (move); + } +} + +/* +=========== +Drag_MouseMoved +=========== +*/ +void Drag_MouseMoved (int x, int y, int buttons) +{ + vec3_t move, delta; + int i; + + if (!buttons) + { + drag_ok = false; + return; + } + if (!drag_ok) + return; + + // clear along one axis + if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall)) + { + drag_first = false; + if (abs(x-pressx) > abs(y-pressy)) + y = pressy; + else + x = pressx; + } + + if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA) + { + camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera(); + + // snap to window + if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0; + if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0; + + VectorSet (move, x - pressx, y - pressy, 0); + } else + { + for (i=0 ; i<3 ; i++) + { + move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy); + if (!g_PrefsDlg.m_bNoClamp) + { + move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + } + + VectorSubtract (move, pressdelta, delta); + VectorCopy (move, pressdelta); + + MoveSelection (delta); +} + +/* +=========== +Drag_MouseUp +=========== +*/ +void Drag_MouseUp (int nButtons) +{ + Sys_Status ("Drag completed.", 0); + + if (g_qeglobals.d_select_mode == sel_area) + { + Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held + g_qeglobals.d_select_mode = sel_curvepoint; + Sys_UpdateWindows (W_ALL); + } + + if (g_qeglobals.d_select_mode == sel_areatall) + { + vec3_t mins, maxs; + + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + // get our rectangle + mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] ); + mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] ); + maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] ); + maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] ); + + // deselect current selection + if( !(nButtons & (MK_CONTROL|MK_SHIFT)) ) + Select_Deselect(); + + // select new selection + Select_RealCompleteTall( mins, maxs ); + + Sys_UpdateWindows (W_ALL); + } + + if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) + { + Select_Move (g_qeglobals.d_select_translate); + VectorCopy (vec3_origin, g_qeglobals.d_select_translate); + Sys_UpdateWindows (W_CAMERA); + } + + /* note: added cleanup here, since an edge drag will leave selected vertices + in g_qeglobals.d_num_move_points + */ + if ( g_qeglobals.d_select_mode != sel_vertex && + g_qeglobals.d_select_mode != sel_curvepoint && + g_qeglobals.d_select_mode != sel_edge) + g_qeglobals.d_num_move_points = 0; + + g_pParentWnd->SetStatusText(3, ""); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + UpdateSurfaceDialog(); +} diff --git a/radiant/eclass.cpp b/radiant/eclass.cpp new file mode 100644 index 00000000..991e9b87 --- /dev/null +++ b/radiant/eclass.cpp @@ -0,0 +1,497 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#include "assert.h" + +eclass_t *eclass = NULL; +eclass_t *eclass_bad = NULL; +const vec3_t smallbox[2] = {{-8,-8,-8},{8,8,8}}; +char eclass_directory[1024]; + +qboolean parsing_single = false; +eclass_t *eclass_e; + +/*! +implementation of the EClass manager API +*/ +eclass_t** Get_EClass_E() +{ + return &eclass_e; +} + +void Set_Eclass_Found(qboolean b) +{ + eclass_found = b; +} + +qboolean Get_Parsing_Single() +{ + return parsing_single; +} + + +// md3 cache for misc_models +//eclass_t *g_md3Cache = NULL; + +/* + +the classname, color triple, and bounding box are parsed out of comments +A ? size means take the exact brush size. + +/ *QUAKED (0 0 0) ? +/ *QUAKED (0 0 0) (-8 -8 -8) (8 8 8) + +Flag names can follow the size description: + +/ *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY + +*/ + +void CleanEntityList(eclass_t *&pList) +{ + while (pList) + { + eclass_t* pTemp = pList->next; + + entitymodel *model = pList->model; + while (model != NULL) + { + delete []model->pTriList; + if (model->strSkin) + g_string_free( (GString *)model->strSkin, TRUE ); + model->strSkin = NULL; + model = model->pNext; + } + + if (pList->modelpath) { + free(pList->modelpath); + pList->modelpath = NULL; + } + if (pList->skinpath) { + free(pList->skinpath); + pList->skinpath = NULL; + } + + free(pList->name); + free(pList->comments); + free(pList); + pList = pTemp; + } + + pList = NULL; + +} + + +void CleanUpEntities() +{ + // NOTE: maybe some leak checks needed .. older versions of Radiant looked like they were freezing more stuff + CleanEntityList(eclass); + //CleanEntityList(g_md3Cache); + if (eclass_bad) + { + free(eclass_bad->name); + free(eclass_bad->comments); + free(eclass_bad); + eclass_bad = NULL; + } +} + +void EClass_InsertSortedList(eclass_t *&pList, eclass_t *e) +{ + eclass_t *s; + + if (!pList) + { + pList = e; + return; + } + + + s = pList; + if (stricmp (e->name, s->name) < 0) + { + e->next = s; + pList = e; + return; + } + + do + { + if (!s->next || stricmp (e->name, s->next->name) < 0) + { + e->next = s->next; + s->next = e; + return; + } + s=s->next; + } while (1); +} + +/* +================= +Eclass_InsertAlphabetized +================= +*/ +void Eclass_InsertAlphabetized (eclass_t *e) +{ +#if 1 + EClass_InsertSortedList(eclass, e); +#else + eclass_t *s; + + if (!eclass) + { + eclass = e; + return; + } + + + s = eclass; + if (stricmp (e->name, s->name) < 0) + { + e->next = s; + eclass = e; + return; + } + + do + { + if (!s->next || stricmp (e->name, s->next->name) < 0) + { + e->next = s->next; + s->next = e; + return; + } + s=s->next; + } while (1); +#endif +} + +/*! +This looks at each eclass_t, if it has a "modelpath" set then it leaves it alone +if it's not set it checks to see if a file called "sprites/.*" exists, and +if it does exist then it sets the "modelpath" to "sprites/.spr" +*/ +void Eclass_CreateSpriteModelPaths() +{ + int Counts[4] = { 0, 0, 0, 0 }; + char filename[512]; // should be big enough, ExtractFileBase doesn't take a buffer size... + eclass_t *e; + + // get a list of all sprite/*>* files in all sprite/ directories + Sys_Printf("Searching VFS for files in sprites/*.* that match entity names...\n"); + GSList *pFiles = vfsGetFileList("sprites", NULL); + GSList *pFile; + + if (pFiles) + { + + // find an eclass without a modelpath. + for (e=eclass ; e ; e=e->next) + { + Counts[0]++; + if (e->modelpath) + { +#ifdef _DEBUG + Sys_Printf("Ignoring sprite for entity %s (modelpath: \"%s\")\n",e->name,e->modelpath); +#endif + Counts[1]++; + continue; // ignore this eclass, it's already got a model + } + + // TODO: remove this check when we can have sprites for non-fixed size entities. + if (!e->fixedsize) + { +#ifdef _DEBUG + Sys_Printf("Ignoring sprite for non-fixed-size entity %s\n",e->name); +#endif + Counts[2]++; + continue; // can't have sprites for non-fixed size entities (yet!) + } + + + Sys_Printf("Searching for sprite for fixed-size entity %s...",e->name); + + pFile = pFiles; // point to start of list + + // look for a file that has the same name, with any extension. + bool Found = FALSE; + while (pFile) + { + + // strip the path/ and the .extension. + ExtractFileBase((char *)pFile->data,filename); + + // does the eclass name match the filename? + if (stricmp(e->name,filename) == 0) + { + // yes, so generate a sprite filename using the all-encompasing .spr extension + // so that the model wrapper knows the sprite model plugin will be the model + // plugin used to render it. + CString strSpriteName; + strSpriteName.Format("sprites/%s.spr",e->name); + e->modelpath = strdup(strSpriteName.GetBuffer()); + Sys_Printf("Found! (\"%s\")\n",(char *)pFile->data); + Counts[3]++; + Found = TRUE; + } + pFile = pFile->next; + } + + if (!Found) + Sys_Printf("not found\n"); + + } + + vfsClearFileDirList(&pFiles); + } + Sys_Printf("%d entities were scanned\n" + "%d entities that already had models/sprites were ignored\n" + "%d non-fixed-size entities were ignored\n" + "%d entities did not have matching sprite files\n" + "%d entities had sprite files and have been attached\n", + Counts[0],Counts[1],Counts[2],Counts[0]-Counts[3],Counts[3]); + +} + +void EClass_InitForFileList(GSList *pFiles, _EClassTable *pTable) +{ + GSList *pFile = pFiles; + while (pFile) + { + // for a given name, we grab the first .def in the vfs + // this allows to override baseq3/scripts/entities.def for instance + char relPath[PATH_MAX]; + strcpy(relPath, "scripts/"); + strcat(relPath, (char*)pFile->data); + // FIXME TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 + if (!vfsGetFullPath(relPath, 0, 0)) + { + Sys_FPrintf(SYS_ERR, "Failed to find the full path for '%s' in the VFS\n", relPath); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + } + else + pTable->m_pfnScanFile(vfsGetFullPath(relPath, 0, 0)); + pFile = pFile->next; + } +} + +/*! +Manually create an eclass_t, for when no modules exist. +this replaces and centralizes the eclass_t allocation +*/ +eclass_t * EClass_Create( const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments ) +{ + eclass_t *e; + char color[128]; + + e = (eclass_t*)malloc(sizeof(*e)); + memset (e, 0, sizeof(*e)); + + e->name = strdup(name); + + // grab the color, reformat as texture name + e->color[0] = col1; + e->color[1] = col2; + e->color[2] = col3; + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + e->texdef.SetName(color); + + // supplied size ? + if (mins && maxs) + { + // Hydra: + // If we set worldspawn to be a fixed-size all the textures are + // displayed as flat-shaded. This is a KLUDGE now that we have + // multiple game support as the worldspawn entity is game specific. + // Note that this is only ever fixed for the user if a definition + // for the worldspawn entity was not loaded, this can happen for + // several reasons: + // a) no entity definition plugin exists + // b) no entity definition files were found + // c) no entity definition file contained an entry for worldspawn. + + if (stricmp(name,"worldspawn") != 0) e->fixedsize = true; + + // copy the sizes.. + memcpy(e->mins,mins,sizeof(vec3_t)); + memcpy(e->maxs,maxs,sizeof(vec3_t)); + } + + if (comments) + e->comments = strdup(comments); + else + { + e->comments = (char*)malloc(1); + e->comments[0] = '\0'; + } + + return e; +} + +void Eclass_Init () +{ + GSList *pFiles; + + // start by creating the default unknown eclass + eclass_bad = EClass_Create("UNKNOWN_CLASS" , 0, 0.5, 0,NULL,NULL,NULL); + + // now scan the definitions + _EClassTable *pTable = &g_EClassDefTable; + while (pTable) + { + // read in all scripts/*. + pFiles = vfsGetFileList("scripts", pTable->m_pfnGetExtension()); + if (pFiles) + { + GSList *pFile = pFiles; + while (pFile) + { + /*! + \todo the MP/SP filtering rules need to be CLEANED UP and SANITIZED + */ + // HACK + // JKII SP/MP mapping mode + if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp")) + { + // SP mapping, ignore mp_*.def + char *name = (char *)pFile->data; + if (name[0]=='m' && name[1]=='p' && name[2]=='_') + { + Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + else + { + // MP mapping, ignore sp_*.def + char *name = (char *)pFile->data; + if (name[0]=='s' && name[1]=='p' && name[2]=='_') + { + Sys_Printf("Multiplayer mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + } + // RIANT + // STVEF SP/MP mapping mode + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp")) + { + // SP mapping, ignore mp_*.def + char *name = (char *)pFile->data; + if (name[0]=='m' && name[1]=='p' && name[2]=='_') + { + Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + else + { + // HM mapping, ignore sp_*.def + char *name = (char *)pFile->data; + if (name[0]=='h' && name[1]=='m' && name[2]=='_') + { + Sys_Printf("HoloMatch mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + } + // for a given name, we grab the first .def in the vfs + // this allows to override baseq3/scripts/entities.def for instance + char relPath[PATH_MAX]; + strcpy(relPath, "scripts/"); + strcat(relPath, (char*)pFile->data); + // FIXME TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 + char *fullpath = vfsGetFullPath(relPath, 0, 0); + if (!fullpath) + { + Sys_FPrintf(SYS_ERR, "Failed to find the full path for \"%s\" in the VFS\n", relPath); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + } + else + pTable->m_pfnScanFile(fullpath); + if (g_pGameDescription->mEClassSingleLoad) + break; + pFile = pFile->next; + } + vfsClearFileDirList(&pFiles); + pFiles = NULL; + } + else + Sys_FPrintf(SYS_ERR, "Didn't find any scripts/*.%s files to load EClass information\n", pTable->m_pfnGetExtension()); + + // we deal with two formats max, if the other table exists, loop again + if (g_bHaveEClassExt && pTable == &g_EClassDefTable) + pTable = &g_EClassExtTable; + else + pTable = NULL; // done, exit + } + Eclass_CreateSpriteModelPaths(); +} + +eclass_t *Eclass_ForName (const char *name, qboolean has_brushes) +{ + eclass_t *e; + + if (!name || *name == '\0') + return eclass_bad; + +#ifdef _DEBUG + // grouping stuff, not an eclass + if (strcmp(name, "group_info")==0) + Sys_Printf("WARNING: unexpected group_info entity in Eclass_ForName\n"); +#endif + + if (!name) + return eclass_bad; + + for (e=eclass ; e ; e=e->next) + if (!strcmp (name, e->name)) + return e; + + // create a new class for it + if (has_brushes) + { + e = EClass_Create(name , 0, 0.5, 0,NULL,NULL,"Not found in source."); + } + else + { + e = EClass_Create(name , 0, 0.5, 0,&smallbox[0],&smallbox[1],"Not found in source."); + } + + Eclass_InsertAlphabetized (e); + + return e; +} diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp new file mode 100644 index 00000000..6c22dbf4 --- /dev/null +++ b/radiant/eclass_def.cpp @@ -0,0 +1,306 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "cmdlib.h" + +#include "synapse.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#define USE_ECLASSMANAGER_DEFINE +#include "ieclass.h" +#define USE_SCRIPLIBTABLE_DEFINE +#include "iscriplib.h" + +#define __VFSTABLENAME g_FileSystemTable_def +#define USE_VFSTABLE_DEFINE +#include "ifilesystem.h" + + +#include "eclass_def.h" + +/*! \file eclass_def.cpp + \brief .def entity description format + implements parsing for .def entity format + this is statically linked into the radiant core as we always need it, but really considered + as an idependant module by the rest of the core. "ECLASS_MAJOR" "def" +*/ + +_QERScripLibTable g_ScripLibTable; +_EClassManagerTable g_EClassManagerTable; +_QERFuncTable_1 g_FuncTable; +_QERFileSystemTable g_FileSystemTable_def; + +CSynapseBuiltinClientDef eclass_def; + +// forward declare, I'm cheap +void Eclass_ScanFile (char *filename); + +const char* EClass_GetExtension() +{ + return "def"; +} + +void CSynapseBuiltinClientDef::EnumerateInterfaces(CSynapseServer *server) +{ + AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable); + AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(g_EClassManagerTable), SYN_REQUIRE, &g_EClassManagerTable); + // hardcode the minor for now, we can still add it to the synapse.config at some point + AddAPI(VFS_MAJOR, "pk3", sizeof(g_FileSystemTable_def), SYN_REQUIRE, &g_FileSystemTable_def); + + AddAPI(ECLASS_MAJOR, "def", sizeof(_EClassTable)); +} + +bool CSynapseBuiltinClientDef::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, ECLASS_MAJOR)) + { + _EClassTable* pTable= static_cast<_EClassTable*>(pAPI->mpTable); + pTable->m_pfnScanFile = &Eclass_ScanFile; + pTable->m_pfnGetExtension = &EClass_GetExtension; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseBuiltinClientDef::GetInfo() +{ + return "Builtin .def module built " __DATE__ " " RADIANT_VERSION; +} + +// ------------------------------------------------------------------------------------------------ + +qboolean eclass_found; +char *debugname; + +void setSpecialLoad(eclass_t *e, const char* pWhat, char*& p) +{ + // Hydra: removed some amazingly bad cstring usage, whoever wrote that + // needs to be taken out and shot. + + char *pText = NULL; + char *where = NULL; + + p = NULL; // incase we don't find what we're looking for. + where = strstr(e->comments,pWhat); + if (!where) + return; + + pText = where + strlen(pWhat); + if (*pText == '\"') + pText++; + + where = strchr(pText,'\"'); + if (where) + { + int len = (where-pText); + p = new char[len + 1]; + strncpy(p,pText,len); + p[len]=0; // just to make sure, as most implementations of strncpy don't null terminate + } + else + p = strdup(pText); +} + +eclass_t *Eclass_InitFromText (char *text) +{ + char *t; + int len; + int r, i; + char parms[256], *p; + eclass_t *e; + char color[128]; + + e = (eclass_t*)malloc(sizeof(*e)); + memset (e, 0, sizeof(*e)); + + text += strlen("/*QUAKED "); + + // grab the name + text = COM_Parse (text); + e->name = (char*)malloc (strlen(Get_COM_Token())+1); + strcpy (e->name, Get_COM_Token()); + debugname = e->name; + + // grab the color, reformat as texture name + r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); + if (r != 3) { + return e; + } + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + //strcpy (e->texdef.name, color); + e->texdef.SetName(color); + + while (*text != ')') + { + if (!*text) { + return e; + } + text++; + } + text++; + + // get the size + text = COM_Parse (text); + if (Get_COM_Token()[0] == '(') + { // parse the size as two vectors + e->fixedsize = true; + r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], + &e->maxs[0], &e->maxs[1], &e->maxs[2]); + if (r != 6) { + return e; + } + + for (i=0 ; i<2 ; i++) + { + while (*text != ')') + { + if (!*text) { + return e; + } + text++; + } + text++; + } + } + + // get the flags + + // copy to the first /n + p = parms; + while (*text && *text != '\n') + *p++ = *text++; + *p = 0; + text++; + + // any remaining words are parm flags + p = parms; + for (i=0 ; iflagnames[i], Get_COM_Token()); + } + + // find the length until close comment + for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) + ; + + // copy the comment block out + len = t-text; + e->comments = (char*)malloc (len+1); + memcpy (e->comments, text, len); +#ifdef _WIN32 + // the win32 Gtk widgets are expecting text stuff to be in unix format (that is CR only instead of DOS's CR/LF) + // we convert on the fly by replacing the LF with a ' ' (yeah I'm cheap) + for (i=0 ; icomments[i] = ' '; + else + e->comments[i] = text[i]; +#endif + e->comments[len] = 0; + + setSpecialLoad(e, "model=", e->modelpath); + setSpecialLoad(e, "skin=", e->skinpath); + char *pFrame = NULL; + setSpecialLoad(e, "frame=", pFrame); + if (pFrame != NULL) + { + e->nFrame = atoi(pFrame); + delete pFrame; //Hydra - Fixed memory leak! + } + + if(!e->skinpath) + setSpecialLoad(e, "texture=", e->skinpath); + + // setup show flags + e->nShowFlags = 0; + if (strcmpi(e->name, "light") == 0 || strcmpi(e->name, "dlight") == 0 || strcmpi(e->name, "lightjunior") == 0) + { + e->nShowFlags |= ECLASS_LIGHT; + } + + if ( (strnicmp(e->name, "info_player", strlen("info_player")) == 0) + ||(strnicmp(e->name, "path_corner", strlen("path_corner")) == 0) + ||(strnicmp(e->name, "team_ctf", strlen("team_ctf")) == 0) + ||(strnicmp(e->name, "misc_teleporter_dest", strlen("misc_teleporter_dest")) == 0) + ) + { + e->nShowFlags |= ECLASS_ANGLE; + } + if (strcmpi(e->name, "path") == 0) + { + e->nShowFlags |= ECLASS_PATH; + } + if (strcmpi(e->name, "misc_model") == 0) + { + e->nShowFlags |= ECLASS_MISCMODEL; + } + + + return e; +} + +void Eclass_ScanFile (char *filename) +{ + int size; + char *data; + eclass_t *e; + int i; + char temp[1024]; + + QE_ConvertDOSToUnixName( temp, filename ); + + size = vfsLoadFullPathFile(filename, (void**)&data); + if (size <= 0) + { + Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename); + return; + } + Sys_Printf ("ScanFile: %s\n", temp); + eclass_found = false; + for (i=0 ; i +#endif + +/* +================= +Error + +For abnormal program terminations +================= +*/ + +/*! +\todo +FIXME the prompt wether to do prefs dialog, may not even be possible +if the crash happens before the game is loaded +*/ + +void Error (const char *error, ...) +{ + va_list argptr; + char text[4096]; + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + strcat( text, "\n" ); + +#if defined (__linux__) || defined (__APPLE__) + if (errno != 0) + { + strcat( text, "errno: " ); + strcat( text, strerror (errno)); + strcat( text, "\n"); + } +#endif + +#ifdef _WIN32 + if (GetLastError() != 0) + { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + strcat( text, "GetLastError: " ); + /* + Gtk will only crunch 0<=char<=127 + this is a bit hackish, but I didn't find useful functions in win32 API for this + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 + */ + TCHAR *scan, *next = (TCHAR*)lpMsgBuf; + do + { + scan = next; + text[strlen(text)+1] = '\0'; + if ((scan[0] >= 0) && (scan[0] <= 127)) + text[strlen(text)] = scan[0]; + else + text[strlen(text)] = '?'; + next = CharNext(scan); + } while (next != scan); + strcat( text, "\n"); + LocalFree( lpMsgBuf ); + } +#endif + + // we need to have a current context to call glError() + if (g_qeglobals_gui.d_glBase != NULL) + { + // qglGetError .. can record several errors, clears after calling + //++timo TODO: be able to deal with several errors if necessary, for now I'm just warning about pending error messages + // NOTE: forget that, most boards don't seem to follow the OpenGL standard + GLenum iGLError = qglGetError(); + if (iGLError != GL_NO_ERROR) + { + // use our own gluErrorString + strcat( text, "qgluErrorString: " ); + strcat( text, (char*)qgluErrorString( iGLError ) ); + strcat( text, "\n" ); + } + } + + strcat (text, "An unrecoverable error has occured.\n" + "Would you like to edit Preferences before exiting Radiant?"); + + Sys_Printf(text); + + if (gtk_MessageBox(NULL, text, "Error", MB_YESNO) == IDYES) + { + Sys_Printf("Doing prefs..\n"); + g_PrefsDlg.LoadPrefs (); + g_PrefsDlg.DoModal(); + } + + QGL_Shutdown(); + + g_PrefsDlg.Destroy (); + g_dlgSurface.Destroy (); + g_dlgFind.Destroy (); + + // force close logging if necessary + g_PrefsDlg.mGamesDialog.m_bLogConsole = false; + Sys_LogFile(); + + _exit (1); +} + +void WINAPI Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + Error((const char *)text); +} diff --git a/radiant/feedback.cpp b/radiant/feedback.cpp new file mode 100644 index 00000000..26e283da --- /dev/null +++ b/radiant/feedback.cpp @@ -0,0 +1,368 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// classes used for describing geometry information from q3map feedback +// + +#include "stdafx.h" + +#include "feedback.h" +#include "glib.h" +#include + +CDbgDlg g_DbgDlg; + +void CSelectMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "select")==0) + { + // read the message + ESelectState = SELECT_MESSAGE; + } + else + { + // read the brush + assert (strcmp ((char *)name, "brush")==0); + assert (ESelectState == SELECT_MESSAGE); + ESelectState = SELECT_BRUSH; + } +} + +void CSelectMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "select")==0) + { + ctx->bGeometry = false; + } +} + +void CSelectMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + if (ESelectState == SELECT_MESSAGE) + { + message = g_string_sized_new (len+1); + memcpy (message->str, ch, len); + message->str[len]='\0'; + Sys_Printf ("%s\n", message->str); + } + else + { + assert (ESelectState == SELECT_BRUSH); + sscanf ((char *)ch, "%i %i", &entitynum, &brushnum); + } +} + +void CSelectMsg::Highlight () +{ + Select_Deselect (); + SelectBrush (entitynum, brushnum); +} + +void CPointMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "pointmsg")==0) + { + // read the message + EPointState = POINT_MESSAGE; + } + else + { + // read the brush + assert (strcmp ((char *)name, "point")==0); + assert (EPointState == POINT_MESSAGE); + EPointState = POINT_POINT; + } +} + +void CPointMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "pointmsg")==0) + { + ctx->bGeometry = false; + } +} + +void CPointMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + if (EPointState == POINT_MESSAGE) + { + message = g_string_sized_new (len+1); + memcpy (message->str, ch, len); + message->str[len]='\0'; + Sys_Printf ("%s\n", message->str); + } + else + { + assert (EPointState == POINT_POINT); + sscanf ((char *)ch, "%g %g %g", &(pt[0]), &(pt[1]), &(pt[2])); + } +} + +void CPointMsg::Highlight () +{ + // use the entity API to push a point + // the API requires a ref count, we do it manually for the current instance + if (refCount == 0) + { + refCount++; + QERApp_HookGL2DWindow (this); + } +} + +void CPointMsg::DropHighlight () +{ + assert (refCount > 0); + QERApp_UnHookGL2DWindow (this); + // do a refCount-- locally (see Highlight) + refCount--; +} + +void CPointMsg::Draw2D( VIEWTYPE vt ) +{ + int nDim1 = (vt == YZ) ? 1 : 0; + int nDim2 = (vt == XY) ? 1 : 2; + qglPointSize(4); + qglColor3f(1.0f,0.0f,0.0f); + qglBegin (GL_POINTS); + qglVertex2f (pt[nDim1], pt[nDim2]); + qglEnd(); + qglBegin (GL_LINE_LOOP); + qglVertex2f (pt[nDim1]-8, pt[nDim2]-8); + qglVertex2f (pt[nDim1]+8, pt[nDim2]-8); + qglVertex2f (pt[nDim1]+8, pt[nDim2]+8); + qglVertex2f (pt[nDim1]-8, pt[nDim2]+8); + qglEnd(); +} + +void CWindingMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "windingmsg")==0) + { + // read the message + EPointState = WINDING_MESSAGE; + } + else + { + // read the brush + assert (strcmp ((char *)name, "winding")==0); + assert (EPointState == WINDING_MESSAGE); + EPointState = WINDING_WINDING; + } +} + +void CWindingMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "windingmsg")==0) + { + ctx->bGeometry = false; + } +} + +void CWindingMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + if (EPointState == WINDING_MESSAGE) + { + message = g_string_sized_new (len+1); + memcpy (message->str, ch, len); + message->str[len]='\0'; + Sys_Printf ("%s\n", message->str); + } + else + { + char* c; + int i; + + assert (EPointState == WINDING_WINDING); + + + c = (char*)ch; + sscanf (c, "%i ", &numpoints); + + for(i = 0; i < numpoints; i++) + { + c = strchr(++c, '('); + if (c) // even if we are given the number of points when the cycle begins .. don't trust it too much + sscanf(c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2]); + else + break; + } + numpoints = i; + } +} + +void CWindingMsg::Highlight () +{ + // use the entity API to push a point + // the API requires a ref count, we do it manually for the current instance + if (refCount == 0) + { + refCount++; + QERApp_HookGL2DWindow (this); + } +} + +void CWindingMsg::DropHighlight () +{ + assert (refCount > 0); + QERApp_UnHookGL2DWindow (this); + // do a refCount-- locally (see Highlight) + refCount--; +} + +void CWindingMsg::Draw2D( VIEWTYPE vt ) +{ + int i; + + int nDim1 = (vt == YZ) ? 1 : 0; + int nDim2 = (vt == XY) ? 1 : 2; + qglColor3f(1.0f,0.f,0.0f); + + qglPointSize(4); + qglBegin (GL_POINTS); + for(i = 0; i < numpoints; i++) + qglVertex2f (wt[i][nDim1], wt[i][nDim2]); + qglEnd(); + qglPointSize(1); + + qglEnable (GL_BLEND); + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglColor4f(0.133f,0.4f,1.0f,0.5f); + qglBegin (GL_POLYGON); + for(i = 0; i < numpoints; i++) + qglVertex2f (wt[i][nDim1], wt[i][nDim2]); + qglEnd(); + qglDisable (GL_BLEND); +} + +// triggered when the user selects an entry in the feedback box +static void feedback_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + g_DbgDlg.DropHighlight(); + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &selected); + g_DbgDlg.SetHighlight(gtk_tree_path_get_indices(path)[0]); + gtk_tree_path_free(path); + } +} + +void CDbgDlg::DropHighlight() +{ + if (m_pHighlight) + { + m_pHighlight->DropHighlight(); + m_pHighlight = NULL; + } +} + +void CDbgDlg::SetHighlight(gint row) +{ + ISAXHandler *h = GetElement(row); + if (h != NULL) + { + h->Highlight(); + m_pHighlight = h; + } +} + +ISAXHandler *CDbgDlg::GetElement (gint row) +{ + return static_cast(g_ptr_array_index(m_pFeedbackElements, row)); +} + +void CDbgDlg::Init () +{ + DropHighlight(); + + // free all the ISAXHandler*, clean it + while (m_pFeedbackElements->len) + { + delete static_cast(g_ptr_array_index (m_pFeedbackElements, 0)); + g_ptr_array_remove_index (m_pFeedbackElements, 0); + } + + if (m_clist != NULL) + gtk_list_store_clear (m_clist); +} + +void CDbgDlg::Push (ISAXHandler *pHandler) +{ + // push in the list + g_ptr_array_add (m_pFeedbackElements, (void *)pHandler); + + if (m_pWidget == NULL) + Create(); + // put stuff in the list + gtk_list_store_clear (m_clist); + for(unsigned int i = 0; i < m_pFeedbackElements->len; ++i) + { + GtkTreeIter iter; + gtk_list_store_append(m_clist, &iter); + gtk_list_store_set(m_clist, &iter, 0, GetElement(i)->getName(), -1); + } + + ShowDlg(); +} + +void CDbgDlg::BuildDialog () +{ + gtk_window_set_title (GTK_WINDOW (m_pWidget), "Q3Map debug window"); + + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_container_add (GTK_CONTAINER (m_pWidget), GTK_WIDGET (scr)); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(feedback_selection_changed), NULL); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + + m_clist = store; + } +} diff --git a/radiant/feedback.h b/radiant/feedback.h new file mode 100644 index 00000000..687fe94b --- /dev/null +++ b/radiant/feedback.h @@ -0,0 +1,125 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// classes used for describing geometry information from q3map feedback +// + +#ifndef __Q3MAP_FEEDBACK__ +#define __Q3MAP_FEEDBACK__ + +#include "libxml/parser.h" + +// a select message with a brush/entity select information +class CSelectMsg : public ISAXHandler +{ + enum { SELECT_MESSAGE, SELECT_BRUSH } ESelectState; + GString *message; + int entitynum, brushnum; +public: + CSelectMsg() { ESelectState = SELECT_MESSAGE; } + // SAX interface + void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs); + void saxEndElement (message_info_t *ctx, const xmlChar *name); + void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len); + // for use in the dialog window + char *getName() { return message->str; } + void Highlight(); + void DropHighlight() { } +}; + +class CPointMsg : public ISAXHandler, public IGL2DWindow +{ + enum { POINT_MESSAGE, POINT_POINT } EPointState; + GString *message; + vec3_t pt; + int refCount; +public: + CPointMsg() { EPointState = POINT_MESSAGE; refCount = 0; } + // SAX interface + void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs); + void saxEndElement (message_info_t *ctx, const xmlChar *name); + void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len); + // for use in the dialog window + char *getName() { return message->str; } + void Highlight(); + void DropHighlight(); + + // IGL2DWindow interface -------------------------------- + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); +}; + +class CWindingMsg : public ISAXHandler, public IGL2DWindow +{ + enum { WINDING_MESSAGE, WINDING_WINDING } EPointState; + GString *message; + vec3_t wt[256]; + int numpoints; + int refCount; +public: + CWindingMsg() { EPointState = WINDING_MESSAGE; refCount = 0; numpoints = 0; } + // SAX interface + void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs); + void saxEndElement (message_info_t *ctx, const xmlChar *name); + void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len); + // for use in the dialog window + char *getName() { return message->str; } + void Highlight(); + void DropHighlight(); + + // IGL2DWindow interface -------------------------------- + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); +}; + +class CDbgDlg : public Dialog +{ + GPtrArray *m_pFeedbackElements; + // the list widget we use in the dialog + GtkListStore* m_clist; + ISAXHandler *m_pHighlight; +public: + CDbgDlg() { m_pFeedbackElements = g_ptr_array_new (); m_pHighlight = NULL; } + virtual ~CDbgDlg() { } + // refresh items + void Push (ISAXHandler *); + // clean the debug window, release all ISAXHanlders we have + void Init(); + ISAXHandler *GetElement(gint row); + void SetHighlight(gint row); + void DropHighlight(); +// void HideDlg(); +protected: + void BuildDialog (); +}; + +extern CDbgDlg g_DbgDlg; + +#endif diff --git a/radiant/file.cpp b/radiant/file.cpp new file mode 100644 index 00000000..0f3c8555 --- /dev/null +++ b/radiant/file.cpp @@ -0,0 +1,390 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// File class, can be a memory file or a regular disk file. +// Originally from LeoCAD, used with permission from the author. :) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" + +#include +#include +#include +#include + + +IDataStream::IDataStream() +{ } + +IDataStream::~IDataStream() +{ } + +///////////////////////////////////////////////////////////////////////////// +// File construction/destruction + +MemStream::MemStream() +{ + m_nGrowBytes = 1024; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; + m_pBuffer = NULL; + m_bAutoDelete = true; +} + +MemStream::MemStream(unsigned long nLen) +{ + m_nGrowBytes = 1024; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; + m_pBuffer = NULL; + m_bAutoDelete = true; + + GrowFile (nLen); +} + +FileStream::FileStream() +{ + m_hFile = NULL; + m_bCloseOnDelete = false; +} + +MemStream::~MemStream() +{ + if (m_pBuffer) + Close(); + + m_nGrowBytes = 0; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; +} + +FileStream::~FileStream() +{ + if (m_hFile != NULL && m_bCloseOnDelete) + Close(); +} + +///////////////////////////////////////////////////////////////////////////// +// File operations + +char* MemStream::ReadString(char* pBuf, unsigned long nMax) +{ + int nRead = 0; + unsigned char ch; + + if (nMax <= 0) + return NULL; + if (m_nPosition >= m_nFileSize) + return NULL; + + while ((--nMax)) + { + if (m_nPosition == m_nFileSize) + break; + + ch = m_pBuffer[m_nPosition]; + m_nPosition++; + pBuf[nRead++] = ch; + + if (ch == '\n') + break; + } + + pBuf[nRead] = '\0'; + return pBuf; +} + +char* FileStream::ReadString(char* pBuf, unsigned long nMax) +{ + return fgets(pBuf, nMax, m_hFile); +} + +unsigned long MemStream::Read(void* pBuf, unsigned long nCount) +{ + if (nCount == 0) + return 0; + + if (m_nPosition > m_nFileSize) + return 0; + + unsigned long nRead; + if (m_nPosition + nCount > m_nFileSize) + nRead = (unsigned long)(m_nFileSize - m_nPosition); + else + nRead = nCount; + + memcpy((unsigned char*)pBuf, (unsigned char*)m_pBuffer + m_nPosition, nRead); + m_nPosition += nRead; + + return nRead; +} + +unsigned long FileStream::Read(void* pBuf, unsigned long nCount) +{ + return fread(pBuf, 1, nCount, m_hFile); +} + +int MemStream::GetChar() +{ + if (m_nPosition > m_nFileSize) + return 0; + + unsigned char* ret = (unsigned char*)m_pBuffer + m_nPosition; + m_nPosition++; + + return *ret; +} + +int FileStream::GetChar() +{ + return fgetc(m_hFile); +} + +unsigned long MemStream::Write(const void* pBuf, unsigned long nCount) +{ + if (nCount == 0) + return 0; + + if (m_nPosition + nCount > m_nBufferSize) + GrowFile(m_nPosition + nCount); + + memcpy((unsigned char*)m_pBuffer + m_nPosition, (unsigned char*)pBuf, nCount); + + m_nPosition += nCount; + + if (m_nPosition > m_nFileSize) + m_nFileSize = m_nPosition; + + return nCount; +} + +unsigned long FileStream::Write(const void* pBuf, unsigned long nCount) +{ + return fwrite(pBuf, 1, nCount, m_hFile); +} + +int MemStream::PutChar(int c) +{ + if (m_nPosition + 1 > m_nBufferSize) + GrowFile(m_nPosition + 1); + + unsigned char* bt = (unsigned char*)m_pBuffer + m_nPosition; + *bt = c; + + m_nPosition++; + + if (m_nPosition > m_nFileSize) + m_nFileSize = m_nPosition; + + return 1; +} + +/*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */ +void FileStream::printf(const char* s, ...) +{ + va_list args; + + va_start (args, s); + vfprintf(m_hFile, s, args); + va_end (args); +} + +/*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */ +void MemStream::printf(const char* s, ...) +{ + va_list args; + + char buffer[4096]; + va_start (args, s); + vsprintf(buffer, s, args); + va_end (args); + Write(buffer, strlen(buffer)); +} + +int FileStream::PutChar(int c) +{ + return fputc(c, m_hFile); +} + +bool FileStream::Open(const char *filename, const char *mode) +{ + m_hFile = fopen(filename, mode); + m_bCloseOnDelete = true; + + return (m_hFile != NULL); +} + +void MemStream::Close() +{ + m_nGrowBytes = 0; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; + if (m_pBuffer && m_bAutoDelete) + free(m_pBuffer); + m_pBuffer = NULL; +} + +void FileStream::Close() +{ + if (m_hFile != NULL) + fclose(m_hFile); + + m_hFile = NULL; + m_bCloseOnDelete = false; +} + +unsigned long MemStream::Seek(long lOff, int nFrom) +{ + unsigned long lNewPos = m_nPosition; + + if (nFrom == SEEK_SET) + lNewPos = lOff; + else if (nFrom == SEEK_CUR) + lNewPos += lOff; + else if (nFrom == SEEK_END) + lNewPos = m_nFileSize + lOff; + else + return (unsigned long)-1; + + m_nPosition = lNewPos; + + return m_nPosition; +} + +unsigned long FileStream::Seek(long lOff, int nFrom) +{ + fseek (m_hFile, lOff, nFrom); + + return ftell(m_hFile); +} + +unsigned long MemStream::GetPosition() const +{ + return m_nPosition; +} + +unsigned long FileStream::GetPosition() const +{ + return ftell(m_hFile); +} + +void MemStream::GrowFile(unsigned long nNewLen) +{ + if (nNewLen > m_nBufferSize) + { + // grow the buffer + unsigned long nNewBufferSize = m_nBufferSize; + + // determine new buffer size + while (nNewBufferSize < nNewLen) + nNewBufferSize += m_nGrowBytes; + + // allocate new buffer + unsigned char* lpNew; + if (m_pBuffer == NULL) + lpNew = static_cast(malloc(nNewBufferSize)); + else + lpNew = static_cast(realloc(m_pBuffer, nNewBufferSize)); + + m_pBuffer = lpNew; + m_nBufferSize = nNewBufferSize; + } +} + +void MemStream::Flush() +{ + // Nothing to be done +} + +void FileStream::Flush() +{ + if (m_hFile == NULL) + return; + + fflush(m_hFile); +} + +void MemStream::Abort() +{ + Close(); +} + +void FileStream::Abort() +{ + if (m_hFile != NULL) + { + // close but ignore errors + if (m_bCloseOnDelete) + fclose(m_hFile); + m_hFile = NULL; + m_bCloseOnDelete = false; + } +} + +void MemStream::SetLength(unsigned long nNewLen) +{ + if (nNewLen > m_nBufferSize) + GrowFile(nNewLen); + + if (nNewLen < m_nPosition) + m_nPosition = nNewLen; + + m_nFileSize = nNewLen; +} + +void FileStream::SetLength(unsigned long nNewLen) +{ + fseek(m_hFile, nNewLen, SEEK_SET); +} + +unsigned long MemStream::GetLength() const +{ + return m_nFileSize; +} + +unsigned long FileStream::GetLength() const +{ + unsigned long nLen, nCur; + + // Seek is a non const operation + nCur = ftell(m_hFile); + fseek(m_hFile, 0, SEEK_END); + nLen = ftell(m_hFile); + fseek(m_hFile, nCur, SEEK_SET); + + return nLen; +} diff --git a/radiant/file.h b/radiant/file.h new file mode 100644 index 00000000..d9f1bd7e --- /dev/null +++ b/radiant/file.h @@ -0,0 +1,119 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// file.h +//////////////////////////////////////////////////// + +#ifndef _FILE_H_ +#define _FILE_H_ + +//#include + +class MemStream : public IDataStream +{ +public: + MemStream(); + MemStream(unsigned long nLen); + virtual ~MemStream(); + + int refCount; + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + +protected: + // MemFile specific: + unsigned long m_nGrowBytes; + unsigned long m_nPosition; + unsigned long m_nBufferSize; + unsigned long m_nFileSize; + unsigned char* m_pBuffer; + bool m_bAutoDelete; + void GrowFile(unsigned long nNewLen); + +public: + unsigned long GetPosition() const; + unsigned long Seek(long lOff, int nFrom); + void SetLength(unsigned long nNewLen); + unsigned long GetLength() const; + + unsigned char* GetBuffer () const + { return m_pBuffer; } + + char* ReadString(char* pBuf, unsigned long nMax); + unsigned long Read(void* pBuf, unsigned long nCount); + unsigned long Write(const void* pBuf, unsigned long nCount); + int GetChar(); + int PutChar(int c); + + void printf(const char*, ...); ///< \todo implement on MemStream + + void Abort(); + void Flush(); + void Close(); + bool Open(const char *filename, const char *mode); +}; + +class FileStream : public IDataStream +{ +public: + FileStream(); + virtual ~FileStream(); + + int refCount; + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + +protected: + // DiscFile specific: + FILE* m_hFile; + bool m_bCloseOnDelete; + +public: + unsigned long GetPosition() const; + unsigned long Seek(long lOff, int nFrom); + void SetLength(unsigned long nNewLen); + unsigned long GetLength() const; + + char* ReadString(char* pBuf, unsigned long nMax); + unsigned long Read(void* pBuf, unsigned long nCount); + unsigned long Write(const void* pBuf, unsigned long nCount); + int GetChar(); + int PutChar(int c); + + void printf(const char*, ...); ///< completely matches the usual printf behaviour + + void Abort(); + void Flush(); + void Close(); + bool Open(const char *filename, const char *mode); +}; + +#endif // _FILE_H_ diff --git a/radiant/filters.cpp b/radiant/filters.cpp new file mode 100644 index 00000000..6d6c9129 --- /dev/null +++ b/radiant/filters.cpp @@ -0,0 +1,242 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "stdafx.h" + +bfilter_t *FilterAdd(bfilter_t *pFilter, int type, int bmask, char *str, int exclude) +{ + bfilter_t *pNew = new bfilter_t; + pNew->next = pFilter; + pNew->attribute = type; + if (type == 1 || type == 3) pNew->string = str; + if (type == 2 || type == 4) pNew->mask = bmask; + if (g_qeglobals.d_savedinfo.exclude & exclude) + pNew->active = true; + else + pNew->active = false; + return pNew; +} + + // removes the filter list at *pFilter, returns NULL pointer +bfilter_t *FilterListDelete(bfilter_t *pFilter) +{ + if (pFilter != NULL) + { + FilterListDelete(pFilter->next); + delete pFilter; + } + return NULL; +} + + + //spog - FilterUpdate is called each time the filters are changed by menu or shortcuts +bfilter_t *FilterUpdate(bfilter_t *pFilter) +{ + pFilter = FilterAdd(pFilter,1,0,"clip",EXCLUDE_CLIP); + pFilter = FilterAdd(pFilter,1,0,"caulk",EXCLUDE_CAULK); + pFilter = FilterAdd(pFilter,1,0,"liquids",EXCLUDE_LIQUIDS); + pFilter = FilterAdd(pFilter,1,0,"hint",EXCLUDE_HINTSSKIPS); + pFilter = FilterAdd(pFilter,1,0,"clusterportal",EXCLUDE_CLUSTERPORTALS); + pFilter = FilterAdd(pFilter,1,0,"areaportal",EXCLUDE_AREAPORTALS); + pFilter = FilterAdd(pFilter,2,QER_TRANS,NULL,EXCLUDE_TRANSLUCENT); + pFilter = FilterAdd(pFilter,3,0,"trigger",EXCLUDE_TRIGGERS); + pFilter = FilterAdd(pFilter,3,0,"misc_model",EXCLUDE_MODELS); + pFilter = FilterAdd(pFilter,3,0,"misc_gamemodel",EXCLUDE_MODELS); + pFilter = FilterAdd(pFilter,4,ECLASS_LIGHT,NULL,EXCLUDE_LIGHTS); + pFilter = FilterAdd(pFilter,4,ECLASS_PATH,NULL,EXCLUDE_PATHS); + pFilter = FilterAdd(pFilter,1,0,"lightgrid",EXCLUDE_LIGHTGRID); + pFilter = FilterAdd(pFilter,1,0,"botclip",EXCLUDE_BOTCLIP); + pFilter = FilterAdd(pFilter,1,0,"clipmonster",EXCLUDE_BOTCLIP); + return pFilter; +} + +/* +================== +FilterBrush +================== +*/ + +bool FilterBrush(brush_t *pb) +{ + + if (!pb->owner) + return FALSE; // during construction + + if (pb->hiddenBrush) + return TRUE; + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) + { + if (strcmp(pb->owner->eclass->name, "worldspawn") == 0 || !strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world + { + return TRUE; + } + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) + { + if (strcmp(pb->owner->eclass->name, "worldspawn") != 0 && strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world + { + return TRUE; + } + } + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES ) + { + if (pb->patchBrush) + { + return TRUE; + } + } + + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS ) + { + if (!pb->patchBrush && pb->brush_faces->texdef.contents & CONTENTS_DETAIL ) + { + return TRUE; + } + } + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL ) + { + if (!pb->patchBrush && !( pb->brush_faces->texdef.contents & CONTENTS_DETAIL )) + { + return TRUE; + } + } + + // if brush belongs to world entity or a brushmodel entity and is not a patch + if ( ( strcmp(pb->owner->eclass->name, "worldspawn") == 0 + || !strncmp( pb->owner->eclass->name, "func", 4) + || !strncmp( pb->owner->eclass->name, "trigger", 7) ) && !pb->patchBrush ) + { + bool filterbrush; + for (face_t *f=pb->brush_faces;f!=NULL;f = f->next) + { + filterbrush=false; + for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; + filters != NULL; + filters = filters->next) + { + // exclude by attribute 1 brush->face->pShader->getName() + if (filters->active && filters->attribute == 1) + { + if (strstr(f->pShader->getName(),filters->string)) + { + filterbrush=true; + break; + } + } + // exclude by attribute 2 brush->face->pShader->getFlags() + else if (filters->active + && filters->attribute == 2) + { + if (f->pShader->getFlags() & filters->mask) + { + filterbrush=true; + break; + } + } + } + if (!filterbrush) + break; + } + if (filterbrush)// if no face is found that should not be excluded + return true; // exclude this brush + } + + // if brush is a patch + if ( pb->patchBrush ) + { + bool drawpatch=true; + for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; + filters != NULL; + filters = filters->next) + { + // exclude by attribute 1 (for patch) brush->pPatch->pShader->getName() + if (filters->active + && filters->attribute == 1) + { + if (strstr(pb->pPatch->pShader->getName(),filters->string)) + { + drawpatch=false; + break; + } + } + + // exclude by attribute 2 (for patch) brush->pPatch->pShader->getFlags() + if (filters->active + && filters->attribute == 2) + { + if (pb->pPatch->pShader->getFlags() & filters->mask) + { + drawpatch=false; + break; + } + } + } + if (!drawpatch) // if a shader is found that should be excluded + return TRUE; // exclude this patch + } + + if (strcmp(pb->owner->eclass->name, "worldspawn") != 0) // if brush does not belong to world entity + { + bool drawentity=true; + for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; + filters != NULL; + filters = filters->next) + { + // exclude by attribute 3 brush->owner->eclass->name + if (filters->active + && filters->attribute == 3) + { + if (strstr(pb->owner->eclass->name,filters->string)) + { + drawentity=false; + break; + } + } + + // exclude by attribute 4 brush->owner->eclass->nShowFlags + else if (filters->active + && filters->attribute == 4) + { + if ( pb->owner->eclass->nShowFlags & filters->mask ) + { + drawentity=false; + break; + } + } + } + if (!drawentity) // if an eclass property is found that should be excluded + return TRUE; // exclude this brush + } + return FALSE; +} diff --git a/radiant/filters.h b/radiant/filters.h new file mode 100644 index 00000000..5f467f1d --- /dev/null +++ b/radiant/filters.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _FILTERS_H_ +#define _FILTERS_H_ + +bfilter_t *FilterAdd(bfilter_t *pFilter, int type, int bmask, char *str, int exclude); +bfilter_t *FilterListDelete(bfilter_t *pFilter); +bfilter_t *FilterUpdate(bfilter_t *pFilter); +bool FilterBrush(brush_t *pb); + +#endif // _FILTERS_H_ diff --git a/radiant/findtexturedialog.cpp b/radiant/findtexturedialog.cpp new file mode 100644 index 00000000..9cbe68d8 --- /dev/null +++ b/radiant/findtexturedialog.cpp @@ -0,0 +1,289 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Find/Replace textures dialogs +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include "findtexturedialog.h" + +FindTextureDialog g_TexFindDlg; +FindTextureDialog& g_dlgFind = g_TexFindDlg; +static bool g_bFindActive = true; + +static void OnApply(GtkWidget *widget, gpointer data) +{ + g_dlgFind.UpdateData(TRUE); + FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, + g_dlgFind.m_bSelectedOnly, g_dlgFind.m_bForce, FALSE); +} + +static void OnFind(GtkWidget *widget, gpointer data) +{ + g_dlgFind.UpdateData(TRUE); + FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, + g_dlgFind.m_bSelectedOnly, FALSE, TRUE); +} + +static void OnOK(GtkWidget *widget, gpointer data) +{ + g_dlgFind.UpdateData(TRUE); + FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, + g_dlgFind.m_bSelectedOnly, g_dlgFind.m_bForce, FALSE); + g_dlgFind.HideDlg (); +} + +static void OnClose(GtkWidget *widget, gpointer data) +{ + g_dlgFind.HideDlg (); +} + +static void popup_selected (GtkWidget *widget, gpointer data) +{ + gchar *str; + + gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); + gtk_entry_set_text (GTK_ENTRY (data), str); +} + +static void find_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget *menu, *item; + menu = gtk_menu_new (); + + for (int i = 0; i < QERApp_GetActiveShaderCount (); i++) + { + IShader *pShader = QERApp_ActiveShader_ForIndex (i); + + item = gtk_menu_item_new_with_label (pShader->getName ()); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (popup_selected), data); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +static gint find_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer data) +{ + g_bFindActive = true; + return FALSE; +} + +static gint replace_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer data) +{ + g_bFindActive = false; + return FALSE; +} + +// ============================================================================= +// FindTextureDialog class + +FindTextureDialog::FindTextureDialog () +{ + m_bSelectedOnly = FALSE; + m_strFind = ""; + m_strReplace = ""; + m_bForce = FALSE; + m_bLive = TRUE; +} + +FindTextureDialog::~FindTextureDialog () +{ +} + +void FindTextureDialog::BuildDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *table, *label; + GtkWidget *button, *check, *entry, *arrow; + + dlg = m_pWidget; + gtk_window_set_title (GTK_WINDOW (dlg), "Find / Replace Texture(s)"); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + table = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Find:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Replace:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (entry), "focus_in_event", + GTK_SIGNAL_FUNC (find_focus_in), NULL); + AddDialogData (entry, &m_strFind, DLG_ENTRY_TEXT); + + button = gtk_button_new (); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (find_clicked), entry); + + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (button), arrow); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (entry), "focus_in_event", + GTK_SIGNAL_FUNC (replace_focus_in), NULL); + AddDialogData (entry, &m_strReplace, DLG_ENTRY_TEXT); + + button = gtk_button_new (); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (find_clicked), entry); + + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (button), arrow); + + check = gtk_check_button_new_with_label ("Use selected brushes only"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + AddDialogData (check, &m_bSelectedOnly, DLG_CHECK_BOOL); + + check = gtk_check_button_new_with_label ("Replace everywhere (selected/active), don't test against Find"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + AddDialogData (check, &m_bForce, DLG_CHECK_BOOL); + + check = gtk_check_button_new_with_label ("Live updates from Texture/Camera windows"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + AddDialogData (check, &m_bLive, DLG_CHECK_BOOL); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label( "Find" ); + gtk_widget_show( button ); + gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 ); + gtk_signal_connect( GTK_OBJECT( button ), "clicked", + GTK_SIGNAL_FUNC( OnFind ), NULL ); + gtk_widget_set_usize( button, 60, -2 ); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnOK), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnApply), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnClose), NULL); + gtk_widget_set_usize (button, 60, -2); + + gtk_widget_show (dlg); +} + +void FindTextureDialog::updateTextures(const char *p) +{ + if (isOpen()) + { + if (g_bFindActive) + { + setFindStr(p); + } + else + { + setReplaceStr(p); + } + } +} + +bool FindTextureDialog::isOpen() +{ + return (g_dlgFind.m_pWidget == NULL || GTK_WIDGET_VISIBLE (g_dlgFind.m_pWidget) == FALSE) ? false : true; +} + +void FindTextureDialog::setFindStr(const char * p) +{ + g_dlgFind.UpdateData(TRUE); + if (g_dlgFind.m_bLive) + { + g_dlgFind.m_strFind = p; + g_dlgFind.UpdateData(FALSE); + } +} + +void FindTextureDialog::setReplaceStr(const char * p) +{ + g_dlgFind.UpdateData(TRUE); + if (g_dlgFind.m_bLive) + { + g_dlgFind.m_strReplace = p; + g_dlgFind.UpdateData(FALSE); + } +} + +void FindTextureDialog::show() +{ + g_dlgFind.ShowDlg (); +} diff --git a/radiant/findtexturedialog.h b/radiant/findtexturedialog.h new file mode 100644 index 00000000..96060ea2 --- /dev/null +++ b/radiant/findtexturedialog.h @@ -0,0 +1,49 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _FINDTEXTUREDIALOG_H_ +#define _FINDTEXTUREDIALOG_H_ + +#include "dialog.h" + +class FindTextureDialog : public Dialog +{ + public: + static void setReplaceStr(const char* p); + static void setFindStr(const char* p); + static bool isOpen(); + static void show(); + static void updateTextures(const char* p); + + FindTextureDialog (); + virtual ~FindTextureDialog (); + void BuildDialog (); + + bool m_bSelectedOnly; + Str m_strFind; + Str m_strReplace; + bool m_bForce; + bool m_bLive; + +}; + + +#endif //_FINDTEXTUREDIALOG_H_ diff --git a/radiant/glinterface.cpp b/radiant/glinterface.cpp new file mode 100644 index 00000000..254c368e --- /dev/null +++ b/radiant/glinterface.cpp @@ -0,0 +1,91 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// Quick interface hack for selected face interface +// this one really needs more work, but I'm in a hurry with TexTool + +#include "stdafx.h" +//#include "qe3.h" + +// stores objects that want to be hooked into drawing in the XY window or Camera view +//++timo TODO: add support for Z view ... (texture view?) +CPtrArray l_GL2DWindows; +CPtrArray l_GL3DWindows; + +void WINAPI QERApp_HookGL2DWindow(IGL2DWindow* pGLW) +{ + l_GL2DWindows.Add( pGLW ); + pGLW->IncRef(); +} + +void WINAPI QERApp_UnHookGL2DWindow(IGL2DWindow* pGLW) +{ + for( int i = 0; i < l_GL2DWindows.GetSize(); i++ ) + { + if (l_GL2DWindows.GetAt(i) == pGLW) + { + l_GL2DWindows.RemoveAt(i); + pGLW->DecRef(); + return; + } + } +#ifdef _DEBUG + Sys_Printf("ERROR: IGL2DWindow* not found in QERApp_UnHookGL2DWindow\n"); +#endif +} + +void Draw2DPluginEntities( VIEWTYPE vt ) +{ + for(int i = 0; i(l_GL2DWindows.GetAt(i))->Draw2D( vt ); +} + +void WINAPI QERApp_HookGL3DWindow(IGL3DWindow* pGLW) +{ + l_GL3DWindows.Add( pGLW ); + pGLW->IncRef(); +} + +void WINAPI QERApp_UnHookGL3DWindow(IGL3DWindow* pGLW) +{ + for( int i = 0; i < l_GL3DWindows.GetSize(); i++ ) + { + if (l_GL3DWindows.GetAt(i) == pGLW) + { + l_GL3DWindows.RemoveAt(i); + pGLW->DecRef(); + return; + } + } +#ifdef _DEBUG + Sys_Printf("ERROR: IGL3DWindow* not found in QERApp_UnHookGL3DWindow\n"); +#endif +} + +void Draw3DPluginEntities() +{ + for(int i = 0; i(l_GL3DWindows.GetAt(i))->Draw3D(); +} diff --git a/radiant/glwidget.cpp b/radiant/glwidget.cpp new file mode 100644 index 00000000..ca8a11b0 --- /dev/null +++ b/radiant/glwidget.cpp @@ -0,0 +1,254 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// OpenGL widget based on GtkGLExt + +#include "stdafx.h" + +#include +#include "glwidget.h" +#include "qgl.h" + +typedef int* attribs_t; +typedef const attribs_t* configs_iterator; + +int config_rgba32[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 1, + GDK_GL_BLUE_SIZE, 1, + GDK_GL_GREEN_SIZE, 1, + GDK_GL_ALPHA_SIZE, 1, + GDK_GL_ATTRIB_LIST_NONE, +}; + +const attribs_t configs[] = { + config_rgba32, + config_rgba, +}; + +GdkGLConfig* glconfig_new() +{ + GdkGLConfig* glconfig = NULL; + + for(configs_iterator i = configs, end = configs + 2; i != end && glconfig == NULL; ++i) + { + glconfig = gdk_gl_config_new(*i); + } + + if(glconfig == NULL) + { + return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE)); + } + + return glconfig; +} + +int config_rgba32_depth32[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 32, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba32_depth24[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 24, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba32_depth16[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 16, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba32_depth[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 1, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba_depth16[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 1, + GDK_GL_BLUE_SIZE, 1, + GDK_GL_GREEN_SIZE, 1, + GDK_GL_ALPHA_SIZE, 1, + GDK_GL_DEPTH_SIZE, 16, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba_depth[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 1, + GDK_GL_BLUE_SIZE, 1, + GDK_GL_GREEN_SIZE, 1, + GDK_GL_ALPHA_SIZE, 1, + GDK_GL_DEPTH_SIZE, 1, + GDK_GL_ATTRIB_LIST_NONE, +}; + +const attribs_t configs_with_depth[] = +{ + config_rgba32_depth32, + config_rgba32_depth24, + config_rgba32_depth16, + config_rgba32_depth, + config_rgba_depth16, + config_rgba_depth, +}; + +GdkGLConfig* glconfig_new_with_depth() +{ + GdkGLConfig* glconfig = NULL; + + for(configs_iterator i = configs_with_depth, end = configs_with_depth + 6; i != end && glconfig == NULL; ++i) + { + glconfig = gdk_gl_config_new(*i); + } + + if(glconfig == NULL) + { + return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE | GDK_GL_MODE_DEPTH)); + } + + return glconfig; +} + +GtkWidget* WINAPI gtk_glwidget_new (gboolean zbuffer, GtkWidget* share) +{ + GtkWidget* drawing_area = gtk_drawing_area_new(); + GdkGLConfig* glconfig = (zbuffer) ? glconfig_new_with_depth() : glconfig_new(); + GdkGLContext* shared_context = (share) ? gtk_widget_get_gl_context(share) : NULL; + + gtk_widget_set_gl_capability (drawing_area, glconfig, shared_context, TRUE, GDK_GL_RGBA_TYPE); + + return drawing_area; +} + +void WINAPI gtk_glwidget_destroy_context (GtkWidget *widget) +{ +} + +void WINAPI gtk_glwidget_create_context (GtkWidget *widget) +{ +} + +void WINAPI gtk_glwidget_swap_buffers (GtkWidget *widget) +{ + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); + gdk_gl_drawable_swap_buffers (gldrawable); +} + +gboolean WINAPI gtk_glwidget_make_current (GtkWidget *widget) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); + return gdk_gl_drawable_gl_begin (gldrawable, glcontext); +} + +GLuint font_list_base; +static gchar font_string[] = "courier 8"; +static gint font_height; + +void gtk_glwidget_create_font (GtkWidget *widget) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); + + PangoFontDescription *font_desc; + PangoFont *font; + PangoFontMetrics *font_metrics; + + font_list_base = qglGenLists (256); + + font_desc = pango_font_description_from_string (font_string); + + font = gdk_gl_font_use_pango_font (font_desc, 0, 256, font_list_base); + + if(font != NULL) + { + font_metrics = pango_font_get_metrics (font, NULL); + + font_height = pango_font_metrics_get_ascent (font_metrics) + + pango_font_metrics_get_descent (font_metrics); + font_height = PANGO_PIXELS (font_height); + + pango_font_metrics_unref (font_metrics); + } + + pango_font_description_free (font_desc); +} + + +void gtk_glwidget_print_string(const char *s) +{ + qglListBase(font_list_base); + qglCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned char *)s); +} + +void gtk_glwidget_print_char(char s) +{ + qglListBase(font_list_base); + qglCallLists(1, GL_UNSIGNED_BYTE, (unsigned char *) &s); +} + diff --git a/radiant/glwidget.h b/radiant/glwidget.h new file mode 100644 index 00000000..1ce7f140 --- /dev/null +++ b/radiant/glwidget.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _GLWIDGET_H_ +#define _GLWIDGET_H_ + +GtkWidget* WINAPI gtk_glwidget_new (gboolean zbufffer, GtkWidget* share); +void WINAPI gtk_glwidget_swap_buffers (GtkWidget *widget); +gboolean WINAPI gtk_glwidget_make_current (GtkWidget *widget); +void WINAPI gtk_glwidget_destroy_context (GtkWidget *widget); +void WINAPI gtk_glwidget_create_context (GtkWidget *widget); +void gtk_glwidget_create_font (GtkWidget *widget); + +void gtk_glwidget_print_string(const char *s); +void gtk_glwidget_print_char(char s); + + +#endif /* _GLWIDGET_H_ */ diff --git a/radiant/glwindow.cpp b/radiant/glwindow.cpp new file mode 100644 index 00000000..72dbd621 --- /dev/null +++ b/radiant/glwindow.cpp @@ -0,0 +1,287 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// GLWindow - Base class for the small views used by Radiant +// +// Leonardo Zide (leo@lokigames.com +// + +#include "stdafx.h" +#include "glwidget.h" +#include "glwindow.h" + +// ============================================================================= +// static functions + +static void realize (GtkWidget *widget, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + + wnd->OnCreate (); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + +#ifndef _WIN32 + if (event->count > 0) + return TRUE; +#endif + + if (!g_pParentWnd->IsSleeping ()) + wnd->OnExpose (); + + return TRUE; +} + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + guint32 flags = 0; + + gdk_pointer_grab (widget->window, FALSE, + (GdkEventMask)(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK), + NULL, NULL, GDK_CURRENT_TIME); + + gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), widget); + + switch (event->button) + { + case 1: flags |= MK_LBUTTON; break; + case 2: flags |= MK_MBUTTON; break; + case 3: flags |= MK_RBUTTON; break; +#if !GTK_CHECK_VERSION (1,3,0) + case 4: wnd->OnMouseWheel(true); break; + case 5: wnd->OnMouseWheel(false); break; +#endif + } + + if ((event->state & GDK_CONTROL_MASK) != 0) + flags |= MK_CONTROL; + + if ((event->state & GDK_SHIFT_MASK) != 0) + flags |= MK_SHIFT; + + if (event->type == GDK_BUTTON_PRESS) + { + switch (event->button) + { + case 1: + wnd->OnLButtonDown (flags, (int)event->x, (int)event->y); break; + case 2: + wnd->OnMButtonDown (flags, (int)event->x, (int)event->y); break; + case 3: + wnd->OnRButtonDown (flags, (int)event->x, (int)event->y); break; + } + } + else if (event->type == GDK_2BUTTON_PRESS) + { + // do nothing + } +} + +static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + guint32 flags = 0; + + gdk_pointer_ungrab (GDK_CURRENT_TIME); + + if ((event->state & GDK_CONTROL_MASK) != 0) + flags |= MK_CONTROL; + + if ((event->state & GDK_SHIFT_MASK) != 0) + flags |= MK_SHIFT; + + switch (event->button) + { + case 1: + wnd->OnLButtonUp (flags, (int)event->x, (int)event->y); break; + case 2: + wnd->OnMButtonUp (flags, (int)event->x, (int)event->y); break; + case 3: + wnd->OnRButtonUp (flags, (int)event->x, (int)event->y); break; + } +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + guint32 flags = 0; + + if ((event->state & GDK_BUTTON1_MASK) != 0) + flags |= MK_LBUTTON; + + if ((event->state & GDK_BUTTON2_MASK) != 0) + flags |= MK_MBUTTON; + + if ((event->state & GDK_BUTTON3_MASK) != 0) + flags |= MK_RBUTTON; + + if ((event->state & GDK_CONTROL_MASK) != 0) + flags |= MK_CONTROL; + + if ((event->state & GDK_SHIFT_MASK) != 0) + flags |= MK_SHIFT; + + wnd->OnMouseMove (flags, (int)event->x, (int)event->y); +} + +static void resize (GtkWidget *widget, GtkAllocation *allocation, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + wnd->OnSize (allocation->width, allocation->height); +} + +static gint timer (gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + wnd->OnTimer (); + + return TRUE; +} + +//! GtkGLExt port. +/* +static void create_context (GtkWidget *widget, gpointer data) +{ + if (g_qeglobals_gui.d_glBase == NULL) + g_qeglobals_gui.d_glBase = widget; +} + +static void destroy_context (GtkWidget *widget, gpointer data) +{ + if (g_qeglobals_gui.d_glBase == widget) + g_qeglobals_gui.d_glBase = NULL; +} +*/ + +#if GTK_CHECK_VERSION (1,3,0) +static gint scroll_event( GtkWidget *widget, + GdkEventScroll *event, + gpointer data ) +{ + GLWindow *wnd = (GLWindow*)data; + wnd->OnMouseWheel((event->direction == GDK_SCROLL_UP) ? true : false); + return TRUE; +} +#endif + +// ============================================================================= +// GLWindow class + +#ifdef _DEBUG +//#define DBG_GLWINDOW +#endif + +GLWindow::GLWindow (bool zbuffer) +{ + m_nTimer = 0; + m_bMouseCapture = FALSE; + m_pParent = NULL; + + m_pWidget = gtk_glwidget_new (zbuffer, g_qeglobals_gui.d_glBase); + GTK_WIDGET_SET_FLAGS (m_pWidget, GTK_CAN_FOCUS); + +#ifdef DBG_GLWINDOW + Sys_Printf("GLWindow::GLWindow m_pWidget = %p\n", m_pWidget); +#endif + +//! GtkGLExt port. +//#if defined (__linux__) || defined (__APPLE__) + if (g_qeglobals_gui.d_glBase == NULL) + g_qeglobals_gui.d_glBase = m_pWidget; +//#endif + +#if GTK_CHECK_VERSION (1,3,0) + gtk_widget_set_events (m_pWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); +#else + gtk_widget_set_events (m_pWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); +#endif + + // Connect signal handlers + gtk_signal_connect (GTK_OBJECT (m_pWidget), "realize", GTK_SIGNAL_FUNC (realize), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "expose_event", GTK_SIGNAL_FUNC (expose), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "button_press_event", GTK_SIGNAL_FUNC (button_press), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "button_release_event",GTK_SIGNAL_FUNC (button_release), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "size_allocate", GTK_SIGNAL_FUNC (resize), this); +//! GtkGLExt port. +// gtk_signal_connect (GTK_OBJECT (m_pWidget), "create_context", GTK_SIGNAL_FUNC (create_context), this); +// gtk_signal_connect (GTK_OBJECT (m_pWidget), "destroy_context", GTK_SIGNAL_FUNC (destroy_context), this); +#if GTK_CHECK_VERSION (1,3,0) + gtk_signal_connect (GTK_OBJECT (m_pWidget), "scroll_event", GTK_SIGNAL_FUNC (scroll_event), this); +#endif +} + +GLWindow::~GLWindow () +{ +#ifdef DBG_GLWINDOW + Sys_Printf("GLWindow::~GLWindow m_pWidget = %p\n", m_pWidget); +#endif + + if (m_pWidget && GTK_IS_WIDGET (m_pWidget)) + gtk_widget_destroy (m_pWidget); +} + +void GLWindow::DestroyContext () +{ + gtk_glwidget_destroy_context (m_pWidget); +} + +void GLWindow::CreateContext () +{ + gtk_glwidget_create_context (m_pWidget); +} + +void GLWindow::SetTimer (guint millisec) +{ + m_nTimer = gtk_timeout_add (millisec, timer, this); +} + +void GLWindow::KillTimer () +{ + gtk_timeout_remove (m_nTimer); + m_nTimer = 0; +} + +bool GLWindow::MakeCurrent () +{ + return gtk_glwidget_make_current (m_pWidget); +} + +void GLWindow::SwapBuffers () +{ + gtk_glwidget_swap_buffers (m_pWidget); +} diff --git a/radiant/glwindow.h b/radiant/glwindow.h new file mode 100644 index 00000000..209b94d3 --- /dev/null +++ b/radiant/glwindow.h @@ -0,0 +1,108 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _GLWINDOW_H_ +#define _GLWINDOW_H_ + +class GLWindow +{ + public: + GLWindow (bool zbuffer); + virtual ~GLWindow (); + + bool MakeCurrent (); + void SwapBuffers (); + void SetTimer (guint millisec); + void KillTimer (); + bool HasTimer () + { return m_nTimer != 0; } + void DestroyContext (); + void CreateContext (); + + virtual void OnCreate () { } + virtual void OnExpose () { } + + virtual void OnLButtonDown (guint32 flags, int x, int y) { } + virtual void OnRButtonDown (guint32 flags, int x, int y) { } + virtual void OnMButtonDown (guint32 flags, int x, int y) { } + virtual void OnLButtonUp (guint32 flags, int pointx, int pointy) { } + virtual void OnRButtonUp (guint32 flags, int pointx, int pointy) { } + virtual void OnMButtonUp (guint32 flags, int pointx, int pointy) { } + virtual void OnMouseMove (guint32 flags, int pointx, int pointy) { } + + + virtual void OnSize (int cx, int cy) { } + virtual void OnTimer () { } + + virtual void OnMouseWheel (bool bUp) { } + + void RedrawWindow () + { + gtk_widget_queue_draw(m_pWidget); + } + + void SetFocus () + { + /* gdk_window_raise (m_pWidget->window); */ + } + + void SetCapture () + { + m_bMouseCapture = TRUE; + } + + void ReleaseCapture () + { + m_bMouseCapture = FALSE; + } + + bool HasCapture () + { + return m_bMouseCapture; + } + + GtkWidget* GetWidget () + { + return m_pWidget; + } + + // member variables + public: + GtkWidget* m_pParent; // for floating windows only + + protected: + bool m_bMouseCapture; + GtkWidget* m_pWidget; + + private: + guint m_nTimer; // only one timer supported +}; + +#endif //_GLWINDOW_H_ diff --git a/radiant/groupdialog.cpp b/radiant/groupdialog.cpp new file mode 100644 index 00000000..7fac4b89 --- /dev/null +++ b/radiant/groupdialog.cpp @@ -0,0 +1,1713 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Floating dialog that contains a notebook with at least Entities and Group tabs +// I merged the 2 MS Windows dialogs in a single class +// +// Leonardo Zide (leo@lokigames.com) +// + +#ifndef _WIN32 + #include +#endif +#include +#include "stdafx.h" +#include "groupdialog.h" + +GtkWidget* EntWidgets[EntLast]; +GtkListStore* g_entlist_store; +GtkListStore* g_entprops_store; +int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE +qboolean multiple_entities; +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=17 +qboolean disable_spawn_get = false; +entity_t *edit_entity; +/* +static GdkPixmap *tree_pixmaps[7]; +static GdkBitmap *tree_masks[7]; +*/ +#define IMG_PATCH 0 +#define IMG_BRUSH 1 +#define IMG_GROUP 2 +#define IMG_ENTITY 3 +#define IMG_ENTITYGROUP 4 +#define IMG_MODEL 5 +#define IMG_SCRIPT 6 + +// misc group support +#define MAX_GROUPS 4096 +#define GROUP_DELIMETER '@' +#define GROUPNAME "QER_Group_%i" + +GroupDlg g_wndGroup; +GroupDlg *g_pGroupDlg = &g_wndGroup; + +// group_t are loaded / saved through "group_info" entities +// they hold epairs for group settings and additionnal access info (tree nodes) +group_t *g_pGroups = NULL; + +// the number of active spawnflags +static int spawnflag_count; +// table: index, match spawnflag item to the spawnflag index (i.e. which bit) +static int spawn_table[MAX_FLAGS]; +// we change the layout depending on how many spawn flags we need to display +// the table is a 4x4 in which we need to put the comment box EntWidgets[EntComment] and the spawn flags.. +static GtkWidget *LayoutTable; +// 0: none of them are hooked +// 1: only the text, 2: text and four checks, 3: text and 8 checks +static int widget_state = 0; + +static void entity_check (GtkWidget *widget, gpointer data); + +// ============================================================================= +// Global functions + +/* +=============================================================== + +ENTITY WINDOW + +=============================================================== +*/ + +void FillClassList () +{ + GtkListStore* store = g_entlist_store; + + gtk_list_store_clear(store); + + for (eclass_t* e = eclass ; e ; e = e->next) + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, e->name, 1, e, -1); + } +} + +// SetKeyValuePairs +// +// Reset the key/value (aka property) listbox and fill it with the +// k/v pairs from the entity being edited. +// + +void SetKeyValuePairs (bool bClearMD3) +{ + GtkListStore* store = g_entprops_store; + + gtk_list_store_clear(store); + + if (edit_entity == NULL) + { + // if there's no entity, then display no key/values + return; + } + + // save current key/val pair around filling epair box + // row_select wipes it and sets to first in list + Str strKey = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + Str strVal = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); + + + // Walk through list and add pairs + for(epair_t* epair = edit_entity->epairs ; epair ; epair = epair->next) + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, epair->key, 1, epair->value, -1); + } + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), strKey.GetBuffer()); + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), strVal.GetBuffer()); + + Sys_UpdateWindows(W_CAMERA | W_XY); +} + +// SetSpawnFlags +// +// Update the checkboxes to reflect the flag state of the entity +// +void SetSpawnFlags(void) +{ + int f, i, v; + + disable_spawn_get = true; + + f = atoi(ValueForKey (edit_entity, "spawnflags")); + for (i=0 ; inext) + DeleteKey (b->owner, "spawnflags"); + } + else + DeleteKey (edit_entity, "spawnflags"); + } + else + { + sprintf (sz, "%i", f); + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + SetKeyValue(b->owner, "spawnflags", sz); + } + else + SetKeyValue (edit_entity, "spawnflags", sz); + } + SetKeyValuePairs (); +} + +//#define DBG_UPDATESEL + +// UpdateSel +// +// Update the listbox, checkboxes and k/v pairs to reflect the new selection +// iIndex is the index in the list box with the class name, -1 if not found +bool UpdateSel(int iIndex, eclass_t *pec) +{ + int i, next_state; + brush_t *b; + + // syndrom of crappy code, we may get into stack overflowing crap with this function and Gtk + // if we play with the list of entity classes + // using a static flag to prevent recursion + static bool bBlockUpdate = false; + + if (bBlockUpdate) + return FALSE; // NOTE TTimo wtf is the return value for anyway? + +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN, "UpdateSel\n"); +#endif + + if (selected_brushes.next == &selected_brushes) + { + edit_entity = world_entity; + multiple_entities = false; + } + else + { + edit_entity = selected_brushes.next->owner; + for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next) + { + if (b->owner != edit_entity) + { + multiple_entities = true; + break; + } + } + } + + if (iIndex != -1) + { +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN,"Setting focus_row to %d\n", iIndex); +#endif + bBlockUpdate = true; + + GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); + GtkTreePath* path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, iIndex); + gtk_tree_selection_select_path(gtk_tree_view_get_selection(view), path); + gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); + gtk_tree_path_free(path); + + bBlockUpdate = false; + } + + if (pec == NULL) + return TRUE; + + // Set up the description + { + GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(EntWidgets[EntComment])); + gtk_text_buffer_set_text (buffer, pec->comments, -1); + } + + spawnflag_count = 0; + + // do a first pass to count the spawn flags, don't touch the widgets, we don't know in what state they are + for (i=0 ; iflagnames[i] && pec->flagnames[i][0] != 0 && strcmp(pec->flagnames[i],"-")) + { + spawn_table[spawnflag_count] = i; + spawnflag_count++; + } + } + + // what's new widget state + if (spawnflag_count==0) + next_state = 1; + else if (spawnflag_count<=4) + next_state = 2; + else if (spawnflag_count<=8) + next_state = 3; + else if (spawnflag_count<=12) + next_state = 4; + else + next_state = 5; + widget_state = next_state; + static int last_count = 0; + + // disable all remaining boxes + // NOTE: these boxes might not even be on display + for (i = 0; i < last_count; i++) + { + GtkWidget* widget = EntWidgets[EntCheck1+i]; + gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child), " "); + gtk_widget_hide (widget); + gtk_widget_ref (widget); + gtk_container_remove (GTK_CONTAINER (LayoutTable), widget); + } + last_count = spawnflag_count; + + for (i=0 ; iflagnames[spawn_table[i]]; + str.MakeLower (); + +// gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, + gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_unref (widget); + + gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child), str.GetBuffer ()); + } + + SetSpawnFlags(); + + SetKeyValuePairs(); + + return TRUE; +} + +bool UpdateEntitySel(eclass_t *pec) +{ +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN, "UpdateEntitySel\n"); +#endif + + GtkTreeModel* model = GTK_TREE_MODEL(g_entlist_store); + GtkTreeIter iter; + unsigned int i = 0; + for(gboolean good = gtk_tree_model_get_iter_first(model, &iter); good != FALSE; good = gtk_tree_model_iter_next(model, &iter)) + { + char* text; + gtk_tree_model_get(model, &iter, 0, &text, -1); + if (strcmp (text, pec->name) == 0) + { +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN, "found a match: %d %s\n", i, pec->name); +#endif + return UpdateSel (i, pec); + } + g_free(text); + ++i; + } + return UpdateSel (-1, pec); +} + +// CreateEntity +// +// Creates a new entity based on the currently selected brush and entity type. +// + +void CreateEntity(void) +{ + GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); + + // check to make sure we have a brush + if (selected_brushes.next == &selected_brushes) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "You must have a selected brush to create an entity", "info"); + return; + } + + // find out what type of entity we are trying to create + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(view), &model, &iter) == FALSE) + { + gtk_MessageBox (g_pParentWnd->m_pWidget, "You must have a selected class to create an entity", "info"); + return; + } + + char* text; + gtk_tree_model_get(model, &iter, 0, &text, -1); + CreateEntityFromName(text, vec3_origin); + g_free(text); + + if (selected_brushes.next == &selected_brushes) + edit_entity = world_entity; + else + edit_entity = selected_brushes.next->owner; + + SetKeyValuePairs(); + Select_Deselect (); + Select_Brush (edit_entity->brushes.onext); + Sys_UpdateWindows(W_ALL); +} + +/* +=============== +AddProp + +=============== +*/ +void AddProp() +{ + if (edit_entity == NULL) + return; + + // Get current selection text + const char* key = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + const char* value = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); + + + // TTimo: if you change the classname to worldspawn you won't merge back in the structural brushes but create a parasite entity + if (!strcmp(key, "classname") && !strcmp(value, "worldspawn")) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "Cannot change \"classname\" key back to worldspawn.", NULL, MB_OK ); + return; + } + + + // RR2DO2: we don't want spaces in entity keys + if (strstr( key, " " )) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "No spaces are allowed in entity keys.", NULL, MB_OK ); + return; + } + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + SetKeyValue(b->owner, key, value); + } + else + SetKeyValue(edit_entity, key, value); + + // refresh the prop listbox + SetKeyValuePairs(); + + +#ifdef USEPLUGINENTITIES + // if it's a plugin entity, perhaps we need to update some drawing parameters + // NOTE: perhaps moving this code to a seperate func would help if we need it in other places + // TODO: we need to call some update func in the IPluginEntity in case model name changes etc. + // ( for the moment only bounding brush is updated ), see UpdateModelBrush in Ritual's Q3Radiant + if (edit_entity->eclass->nShowFlags & ECLASS_PLUGINENTITY) + { + vec3_t mins, maxs; + edit_entity->pPlugEnt->GetBounds( mins, maxs ); + // replace old bounding brush by newly computed one + // NOTE: this part is similar to Entity_BuildModelBrush in Ritual's Q3Radiant, it can be + // usefull moved into a seperate func + brush_t *b,*oldbrush; + if (edit_entity->brushes.onext != &edit_entity->brushes) + oldbrush = edit_entity->brushes.onext; + b = Brush_Create (mins, maxs, &edit_entity->eclass->texdef); + Entity_LinkBrush (edit_entity, b); + Brush_Build( b, true ); + Select_Deselect(); + Brush_AddToList (edit_entity->brushes.onext, &selected_brushes); + if (oldbrush) + Brush_Free( oldbrush ); + } +#endif // USEPLUGINENTITIES +} + +/* +=============== +DelProp + +=============== +*/ +void DelProp(void) +{ + if (edit_entity == NULL) + return; + + // Get current selection text + const char* key = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + DeleteKey(b->owner, key); + } + else + DeleteKey(edit_entity, key); + + // refresh the prop listbox + SetKeyValuePairs(); +} + +void ResetEntity () +{ + epair_t *pep; + int i; + + if (edit_entity == NULL) + return; + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next; b != &selected_brushes; b=b->next) + for (pep = b->owner->epairs; pep; ) + { + if (strcmp (pep->key, "classname") != 0) + { + DeleteKey (b->owner, pep->key); + pep = b->owner->epairs; + } + else + pep = pep->next; + } + } + else + for (pep = edit_entity->epairs; pep; ) + { + if (strcmp (pep->key, "classname") != 0) + { + DeleteKey (edit_entity, pep->key); + pep = edit_entity->epairs; + } + else + pep = pep->next; + } + + // refresh the dialog + SetKeyValuePairs (); + for (i = EntCheck1; i <= EntCheck16; i++) + gtk_signal_handler_block_by_func (GTK_OBJECT (EntWidgets[i]), GTK_SIGNAL_FUNC (entity_check), NULL); + SetSpawnFlags (); + for (i = EntCheck1; i <= EntCheck16; i++) + gtk_signal_handler_unblock_by_func (GTK_OBJECT (EntWidgets[i]), GTK_SIGNAL_FUNC (entity_check), NULL); +} + +bool GetSelectAllCriteria(CString &strKey, CString &strVal) +{ + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(EntWidgets[EntProps])), &model, &iter) + && (inspector_mode == W_ENTITY) + && GTK_WIDGET_VISIBLE (g_pGroupDlg->m_pWidget)) + { + strKey = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + strVal = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); + return TRUE; + } + return FALSE; +} + + +void AssignSound() +{ + char buffer[NAME_MAX]; + + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "sound/"); + + if( access(buffer, R_OK) != 0 ) + { + // just go to fsmain + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "/"); + } + + const char *filename = file_dialog (g_pGroupDlg->m_pWidget, TRUE, "Open Wav File", buffer, "sound"); + if (filename != NULL) + { + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "noise"); + char *aux = vfsExtractRelativePath (filename); + CString str; + if (aux) + str = aux; + else + { + Sys_FPrintf (SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n"); + str = filename; + } + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), str.GetBuffer()); + AddProp(); + } +} + +void AssignModel() +{ + char buffer[NAME_MAX]; + + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "models/"); + + if( access(buffer, R_OK) != 0 ) + { + // just go to fsmain + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "/"); + } + + const char *filename = file_dialog (g_pGroupDlg->m_pWidget, TRUE, "Open Model", buffer, MODEL_MAJOR); + if (filename != NULL) + { + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "model"); + // use VFS to get the correct relative path + char *aux = vfsExtractRelativePath (filename); + CString str; + if (aux) + str = aux; + else + { + Sys_FPrintf (SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n"); + str = filename; + } + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), str.GetBuffer()); + AddProp(); + edit_entity->brushes.onext->bModelFailed = false; + } +} + +/* +============== +SetInspectorMode +============== +*/ +void SetInspectorMode(int iType) +{ + if (iType == W_GROUP) + gtk_MessageBox(g_pParentWnd->m_pWidget, "Brush grouping is not functional yet", NULL, MB_OK | MB_ICONWARNING ); + + if (!g_pParentWnd->FloatingGroupDialog() && + (iType == W_TEXTURE || iType == W_CONSOLE)) + return; + + // Is the caller asking us to cycle to the next window? + if (iType == -1) + { + if (inspector_mode == W_ENTITY) + iType = W_TEXTURE; + else if (inspector_mode == W_TEXTURE) + iType = W_CONSOLE; + else if (inspector_mode == W_CONSOLE) + iType = W_GROUP; + else + iType = W_ENTITY; + } + + switch(iType) + { + case W_ENTITY: + // entity is always first in the inspector + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Entities"); + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 0); + break; + + case W_TEXTURE: + g_pParentWnd->GetTexWnd()->FocusEdit(); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Textures"); + if (g_pParentWnd->FloatingGroupDialog()) + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 1); + break; + + case W_CONSOLE: + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Console"); + if (g_pParentWnd->FloatingGroupDialog()) + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 2); + break; + + case W_GROUP: + if (g_pParentWnd->FloatingGroupDialog()) + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 3); + else + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 1); + break; + + default: + break; + } +} + +void Group_Add(entity_t *e) +{ + /* + group_t *g = (group_t*)qmalloc(sizeof(group_t)); + g->epairs = e->epairs; + g->next = NULL; + e->epairs = NULL; + + // create a new group node + char *text = ValueForKey(g->epairs, "group"); + g->itemOwner = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_wndGroup.m_hWorld, NULL, &text, 0, + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], TRUE, TRUE); + g->next = g_pGroups; + g_pGroups = g; + */ +} +/* +group_t* Group_Alloc(char *name) +{ + group_t *g = (group_t*)qmalloc(sizeof(group_t)); + SetKeyValue( g->epairs, "group", name ); + return g; +} + +group_t* Group_ForName(const char * name) +{ + group_t *g = g_pGroups; + while (g != NULL) + { + if (strcmp( ValueForKey(g->epairs,"group"), name ) == 0) + break; + g = g->next; + } + return g; +} + +void Group_AddToItem(brush_t *b, GtkCTreeNode* item) +{ + int nImage = IMG_BRUSH; + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + const char *pName = NULL; + // const char *pNamed = Brush_GetKeyValue(b, "name"); + + if (!b->owner || (b->owner == world_entity)) + { + if (b->patchBrush) + { + pName = "Generic Patch"; + nImage = IMG_PATCH; + } + else + { + pName = "Generic Brush"; + nImage = IMG_BRUSH; + } + } + else + { + pName = b->owner->eclass->name; + if (b->owner->eclass->fixedsize) + { + nImage = IMG_ENTITY; + } + else + { + nImage = IMG_ENTITYGROUP; + } + } + + GtkCTreeNode *newItem; + int i = (b->patchBrush) ? IMG_PATCH : IMG_BRUSH; + newItem = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), item, NULL, (gchar**)&pName, 0, + tree_pixmaps[i], tree_masks[i], tree_pixmaps[i], + tree_masks[i], TRUE, TRUE); + gtk_ctree_node_set_row_data (GTK_CTREE (g_wndGroup.m_pTree), newItem, b); + b->itemOwner = newItem; +} +*/ +void Group_RemoveBrush(brush_t *b) +{ + /* + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + if (b->itemOwner) + { + gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); + b->itemOwner = NULL; + } + DeleteKey(b->epairs, "group"); + */ +} +/* +void Group_AddToWorld(brush_t *b) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + GtkCTreeNode *parent = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); + Group_AddToItem(b, parent); +} +*/ +void Group_AddToProperGroup(brush_t *b) +{ + /* + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + + // NOTE: we do a local copy of the "group" key because it gets erased by Group_RemoveBrush + const char *pGroup = Brush_GetKeyValue(b, "group"); + // remove the entry in the tree if there's one + if (b->itemOwner) + { + gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); + b->itemOwner = NULL; + } + + if (*pGroup != 0) + { + // find the item + group_t *g = Group_ForName(pGroup); + if (g) + Group_AddToItem(b, g->itemOwner); +#ifdef _DEBUG + else + Sys_Printf("WARNING: unexpected Group_ForName not found in Group_AddToProperGroup\n"); +#endif + } + else + { + Group_AddToWorld(b); + } + */ +} +/* +void Group_AddToSelected(brush_t *b) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + GtkCTreeNode *item; + item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), GTK_CLIST (g_pGroupDlg->m_pTree)->focus_row); + if (item == NULL) + { + item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); + } + Group_AddToItem(b, item); +} +*/ +/* +void Group_Save(FILE *f) +{ + group_t *g = g_pGroups; + while (g) + { + fprintf(f,"{\n\"classname\" \"group_info\"\n\"group\" \"%s\"\n}\n", ValueForKey( g->epairs, "group" )); + g = g->next; + } +} +*/ + +void Group_Init() +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + // start by cleaning everything + // clean the groups + //++timo FIXME: we leak, delete the groups on the way (I don't have time to do it now) +#ifdef _DEBUG + Sys_Printf("TODO: fix leak in Group_Init\n"); +#endif + group_t *g = g_pGroups; + while (g) + { + epair_t *ep,*enext; + for (ep = g->epairs ; ep ; ep=enext ) + { + enext = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + g = g->next; + } + /* + GtkCTreeNode *world; + char *text = "World"; + g_pGroups = NULL; + gtk_clist_clear (GTK_CLIST (g_wndGroup.m_pTree)); + world = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), NULL, NULL, &text, 0, + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], tree_pixmaps[IMG_GROUP], + tree_masks[IMG_GROUP], FALSE, TRUE); + */ + // walk through all the brushes, remove the itemOwner key and add them back where they belong + brush_t *b; + for (b = active_brushes.next; b != &active_brushes; b = b->next) + { + b->itemOwner = NULL; + Group_AddToProperGroup(b); + } + for (b = selected_brushes.next ; b != &selected_brushes ; b = b->next) + { + b->itemOwner = NULL; + Group_AddToProperGroup(b); + } +} +/* +// scan through world_entity for groups in this map? +// we use GROUPNAME "QER_group_%i" to look for existing groups and their naming +//++timo FIXME: is this actually needed for anything? +void Group_GetListFromWorld(GSList **pArray) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + + if (world_entity == NULL) + { + return; + } + + char cBuff[1024]; + for (int i =0; i < MAX_GROUPS; i++) + { + sprintf(cBuff, GROUPNAME, i); + char *pGroup = ValueForKey(world_entity, cBuff); + if (pGroup && strlen(pGroup) > 0) + { + *pArray = g_slist_append (*pArray, g_strdup (pGroup)); + } + else + { + break; + } + } +} + +void Group_RemoveListFromWorld() +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + GSList* array = NULL; + Group_GetListFromWorld(&array); + + while (array) + { + DeleteKey(world_entity, (char*)array->data); + g_free (array->data); + array = g_slist_remove (array, array->data); + } +} + +int CountChar(const char *p, char c) +{ + int nCount = 0; + int nLen = strlen(p)-1; + while (nLen-- >= 0) + { + if (p[nLen] == c) + { + nCount++; + } + } + return nCount; +} +*/ +// ============================================================================= +// callbacks + +static void eclasslist_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + GtkTreeModel* model; + GtkTreeIter selected; + // no world entity, we are not ready yet + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=917 + if( !world_entity ) { + return; + } + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + eclass_t* eclass; + gtk_tree_model_get(model, &selected, 1, &eclass, -1); + if(eclass != NULL) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &selected); + UpdateSel(gtk_tree_path_get_indices(path)[0], eclass); + gtk_tree_path_free(path); + } + } +} + +static gint eclasslist_button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + CreateEntity (); + return TRUE; + } + return FALSE; +} + +static gint eclasslist_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper (event->keyval); + + if (event->keyval == GDK_Return) + { + CreateEntity (); + return TRUE; + } + + // select the entity that starts with the key pressed + if (code <= 'Z' && code >= 'A') + { + GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(view), &model, &iter) == FALSE + || gtk_tree_model_iter_next(model, &iter) == FALSE) + { + gtk_tree_model_get_iter_first(model, &iter); + } + + for(unsigned int count = gtk_tree_model_iter_n_children(model, NULL); count > 0; --count) + { + char* text; + gtk_tree_model_get(model, &iter, 0, &text, -1); + + if (toupper (text[0]) == (int)code) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iter); + gtk_tree_selection_select_path(gtk_tree_view_get_selection(view), path); + gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); + gtk_tree_path_free(path); + count = 1; + } + + g_free(text); + + if(gtk_tree_model_iter_next(model, &iter) == FALSE) + gtk_tree_model_get_iter_first(model, &iter); + } + + return TRUE; + } + return FALSE; +} + + +static void proplist_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + // find out what type of entity we are trying to create + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE) + { + return; + } + + char* key; + char* val; + gtk_tree_model_get(model, &iter, 0, &key, 1, &val, -1); + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), key); + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), val); + + g_free(key); + g_free(val); +} + +static void entity_check (GtkWidget *widget, gpointer data) +{ + if( !disable_spawn_get ) + GetSpawnFlags(); +} + +static void entitylist_angle (GtkWidget *widget, gpointer data) +{ + SetKeyValue (edit_entity, "angle", (char*)data); + SetKeyValuePairs (); +} + +static gint entityentry_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + if (event->keyval == GDK_Tab) + { + if (widget == EntWidgets[EntKeyField]) + { + //gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); + gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntValueField]); + } + else + gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntKeyField]); + + return TRUE; + } + else if (event->keyval == GDK_Return) + { + if (widget == EntWidgets[EntKeyField]) + { + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); + gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntValueField]); + } + else + { + AddProp (); + } + return TRUE; + } + + return FALSE; +} +/* +// add a new group, put all selected brushes into the group +static void groupdlg_add (GtkWidget *widget, gpointer data) +{ + char* name = DoNameDlg ("New Group"); + + if (name != NULL) + { + // create a new group node + GtkCTreeNode *item; + item = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_pGroupDlg->m_hWorld, NULL, &name, 0, + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], FALSE, TRUE); + + // create a new group + group_t *g = Group_Alloc (name); + g->itemOwner = item; + g->next = g_pGroups; + g_pGroups = g; + + // now add the selected brushes + // NOTE: it would be much faster to give the group_t for adding + // but Select_AddToGroup is the standard way for all other cases + Select_AddToGroup (name); + g_free (name); + } +} +*/ +static void switch_page (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data) +{ + char *text; + gtk_label_get(GTK_LABEL(gtk_notebook_get_tab_label(notebook, gtk_notebook_get_nth_page(notebook, page_num))), &text); + gtk_window_set_title (GTK_WINDOW (data), text); + + gpointer item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_misc_selectentitycolor"); + + if (g_pParentWnd->FloatingGroupDialog()) + { + switch (page_num) + { + case 0: inspector_mode = W_ENTITY; break; + case 1: inspector_mode = W_TEXTURE; break; + case 2: inspector_mode = W_CONSOLE; break; + default: inspector_mode = W_GROUP; break; + } + } + else + { + if (page_num == 0) + inspector_mode = W_ENTITY; + else + inspector_mode = W_GROUP; + } + + if (inspector_mode == W_ENTITY) + gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE); + else + gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); +} + +// ============================================================================= +// GroupDlg class + +// NOTE: when a key is hit with group window focused, we catch in this handler but it gets propagated to mainframe too +// therefore the message will be intercepted and used as a ID_SELECTION_DESELECT +static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ +#ifdef DBG_PI + Sys_Printf("OnDialogKey\n"); +#endif + if ((event->keyval == GDK_Escape) && (g_pParentWnd->CurrentStyle() != MainFrame::eFloating)) + { + // toggle off the group view (whatever part of it is currently displayed) + // this used to be done with a g_pParentWnd->OnViewEntity(); but it had bad consequences + // http://fenris.lokigames.com/show_bug.cgi?id=2773 + widget_delete_hide (g_qeglobals_gui.d_entity); + return TRUE; + } + return FALSE; +} + +GroupDlg::GroupDlg () +{ + m_pWidget = NULL; + m_hWorld = NULL; +} + +#ifdef _WIN32 +extern void PositionWindowOnPrimaryScreen(window_position_t& position); +#endif + +void GroupDlg::Create () +{ + if (m_pWidget != NULL) + return; + + GtkWidget* dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posEntityWnd ); + } +#endif + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posEntityWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (widget_delete_hide), NULL); + // catch 'Esc' + gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + g_qeglobals_gui.d_entity = dlg; + + { + GtkWidget* notebook = gtk_notebook_new (); + gtk_widget_show (notebook); + gtk_container_add (GTK_CONTAINER (dlg), notebook); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM); + m_pNotebook = notebook; + + { + GtkWidget* vbox = gtk_vbox_new (FALSE, 2); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); + + { + GtkWidget* label = gtk_label_new ("Entities"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + } + + { + GtkWidget* split1 = gtk_vpaned_new (); + gtk_box_pack_start (GTK_BOX (vbox), split1, TRUE, TRUE, 0); + gtk_widget_show (split1); + + { + GtkWidget* split2 = gtk_vpaned_new (); + gtk_paned_add1 (GTK_PANED (split1), split2); + gtk_widget_show (split2); + + g_object_set_data (G_OBJECT (dlg), "split1", split1); + g_object_set_data (G_OBJECT (dlg), "split2", split2); + + { + GtkWidget* vbox2 = gtk_vbox_new (FALSE, 2); + gtk_widget_show (vbox2); + gtk_paned_pack2 (GTK_PANED (split1), vbox2, FALSE, FALSE); + + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_paned_add1 (GTK_PANED (split2), scr); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + g_signal_connect(G_OBJECT(view), "button_press_event", G_CALLBACK(eclasslist_button_press), NULL); + g_signal_connect(G_OBJECT(view), "key_press_event", G_CALLBACK(eclasslist_keypress), this); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(eclasslist_selection_changed), dlg); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + EntWidgets[EntList] = view; + g_entlist_store = store; + } + } + + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_paned_add2 (GTK_PANED (split2), scr); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkWidget* text = gtk_text_view_new(); + gtk_widget_set_size_request(text, 0, -1); // allow shrinking + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); + gtk_widget_show (text); + gtk_container_add (GTK_CONTAINER (scr), text); + EntWidgets[EntComment] = text; + } + } + + { + // Spawnflags (4 colums wide max, or window gets too wide.) + GtkWidget* table = LayoutTable = gtk_table_new (4, 4, FALSE); + gtk_box_pack_start (GTK_BOX (vbox2), LayoutTable, FALSE, TRUE, 0); + gtk_widget_show(LayoutTable); + + for (int i = 0; i < MAX_FLAGS; i++) + { + GtkWidget* check = gtk_check_button_new_with_label (""); + gtk_widget_ref (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + EntWidgets[EntCheck1+i] = check; + } + + //++timo cleanme: these flags where Q2 stuff + /* + check = gtk_check_button_new_with_label ("!Easy"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck17] = check; + + check = gtk_check_button_new_with_label ("!Medium"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck18] = check; + + check = gtk_check_button_new_with_label ("!Hard"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck19] = check; + + check = gtk_check_button_new_with_label ("!DeathMatch"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck20] = check; + */ + } + + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox2), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(proplist_selection_changed), dlg); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + + EntWidgets[EntProps] = view; + g_entprops_store = store; + } + } + } + + int x = g_PrefsDlg.mWindowInfo.nEntitySplit1; + if (x != -1) + { + gtk_paned_set_position (GTK_PANED (split1), x); + + while (gtk_events_pending ()) gtk_main_iteration (); + x = g_PrefsDlg.mWindowInfo.nEntitySplit2; + + if (x != -1) + gtk_paned_set_position (GTK_PANED (split2), x); + } + } + } + + { + GtkWidget* table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 3); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + { + GtkWidget* entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK); + gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", + GTK_SIGNAL_FUNC (entityentry_keypress), this); + EntWidgets[EntKeyField] = entry; + } + + { + GtkWidget* entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK); + gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", + GTK_SIGNAL_FUNC (entityentry_keypress), this); + EntWidgets[EntValueField] = entry; + } + + { + GtkWidget* label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + } + + { + GtkWidget* label = gtk_label_new ("Key"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + } + } + + { + GtkWidget* hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + { + GtkWidget* table = gtk_table_new (3, 3, TRUE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0); + + { + GtkWidget* button = gtk_button_new_with_label ("360"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"360"); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("45"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"45"); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("90"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"90"); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + + { + GtkWidget* button = gtk_button_new_with_label ("135"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"135"); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("180"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"180"); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("225"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"225"); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("270"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"270"); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("315"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"315"); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + } + + { + GtkWidget* vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0); + + { + GtkWidget* button = gtk_button_new_with_label ("Reset"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (ResetEntity), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Up"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"-1"); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Dn"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"-2"); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + } + + { + GtkWidget* vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0); + + { + GtkWidget* button = gtk_button_new_with_label ("Del Key/Pair"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (DelProp), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Sound..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (AssignSound), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Model..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (AssignModel), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + } + } + } + + if (g_pParentWnd->FloatingGroupDialog()) + { + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + gtk_widget_show (scr); + gtk_container_set_border_width (GTK_CONTAINER (scr), 3); + + { + GtkWidget* text = gtk_text_view_new (); + gtk_widget_set_size_request(text, 0, -1); // allow shrinking + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable (GTK_TEXT_VIEW(text), FALSE); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + g_qeglobals_gui.d_edit = text; + } + + { + GtkWidget* label = gtk_label_new ("Console"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scr, label); + } + } + } + + + //++timo NOTE: this part for grouping code, don't remove! (we'll put it back in sometime soon) + + /* + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); + + scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + ctree = gtk_ctree_new (1, 0); + gtk_widget_show (ctree); + gtk_container_add (GTK_CONTAINER (scr), ctree); + gtk_clist_column_titles_hide (GTK_CLIST (ctree)); + m_pTree = ctree; + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Add..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (groupdlg_add), NULL); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Edit..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Delete"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + label = gtk_label_new ("Groups"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + */ + inspector_mode = W_ENTITY; + // gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); + m_pWidget = dlg; + /* + load_pixmap ("grouptree1.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[0], &tree_masks[0]); + load_pixmap ("grouptree2.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[1], &tree_masks[1]); + load_pixmap ("grouptree3.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[2], &tree_masks[2]); + load_pixmap ("grouptree4.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[3], &tree_masks[3]); + load_pixmap ("grouptree5.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[4], &tree_masks[4]); + load_pixmap ("grouptree6.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[5], &tree_masks[5]); + load_pixmap ("grouptree7.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[6], &tree_masks[6]); + + Group_Init(); +*/ + g_signal_connect (G_OBJECT (notebook), "switch_page", G_CALLBACK (switch_page), dlg); + } +} + diff --git a/radiant/groupdialog.h b/radiant/groupdialog.h new file mode 100644 index 00000000..a2531071 --- /dev/null +++ b/radiant/groupdialog.h @@ -0,0 +1,108 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _GROUPDIALOG_H_ +#define _GROUPDIALOG_H_ + +#define DlgXBorder 5 +#define DlgYBorder 5 + + +enum +{ + EntList, + EntComment, +// Spawnflags + EntCheck1, + EntCheck2, + EntCheck3, + EntCheck4, + EntCheck5, + EntCheck6, + EntCheck7, + EntCheck8, +// Extra Spawnflags for Halflife Support + EntCheck9, + EntCheck10, + EntCheck11, + EntCheck12, + EntCheck13, + EntCheck14, + EntCheck15, + EntCheck16, + +/* + EntCheck17, + EntCheck18, + EntCheck19, + EntCheck20, +*/ + EntProps, + EntDir0, + EntDir45, + EntDir90, + EntDir135, + EntDir180, + EntDir225, + EntDir270, + EntDir315, + EntDirUp, + EntDirDown, + EntDelProp, + EntKeyLabel, + EntKeyField, + EntValueLabel, + EntValueField, + EntColor, + EntAssignSounds, + EntAssignModels, + EntTab, + + EntLast, +}; + +// 17..20 where used for spawnflags (!Easy !Medium !Hard etc.), empty now.. +extern GtkWidget* EntWidgets[EntLast]; + +//extern int rgIds[EntLast]; + + +class GroupDlg +{ + public: + GroupDlg (); + void Create (); + + void Show () + { gtk_widget_show (m_pWidget); }; + void Hide () + { gtk_widget_hide (m_pWidget); }; + + public: + GtkWidget* m_pNotebook; + GtkWidget* m_pWidget; + GtkWidget* m_pTree; + GtkCTreeNode* m_hWorld; //leo: not used keeping because of the win32 version +}; + +extern GroupDlg *g_pGroupDlg; + +#endif // _GROUPDIALOG_H_ diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp new file mode 100644 index 00000000..b75b02d1 --- /dev/null +++ b/radiant/gtkdlgs.cpp @@ -0,0 +1,4045 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Some small dialogs that don't need much +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 +#include +#endif + +// ============================================================================= +// Color selection dialog + +qboolean DoColor (int iIndex) +{ + static bool bColorOpen = false; + + if(bColorOpen) + { + Sys_FPrintf(SYS_WRN, "DoColor dialog is already open\n"); + return false; + } + + bColorOpen = true; + + if (color_dialog (g_pParentWnd->m_pWidget, g_qeglobals.d_savedinfo.colors[iIndex])) + { + /* + ** scale colors so that at least one component is at 1.0F + ** if this is meant to select an entity color + */ + if (iIndex == COLOR_ENTITY) + { + float largest = 0.0F; + + if ( g_qeglobals.d_savedinfo.colors[iIndex][0] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][0]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][1] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][1]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][2] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][2]; + + if ( largest == 0.0F ) + { + g_qeglobals.d_savedinfo.colors[iIndex][0] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][1] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][2] = 1.0F; + } + else + { + float scaler = 1.0F / largest; + + g_qeglobals.d_savedinfo.colors[iIndex][0] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][1] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][2] *= scaler; + } + } + + Sys_UpdateWindows (W_ALL); + bColorOpen = false; + return true; + } + else { + bColorOpen = false; + return false; + } +} + +// ============================================================================= +// Project settings dialog + +static void UpdateBSPCommandList (GtkWidget *dialog); + +static void DoProjectAddEdit (bool edit, GtkWidget *parent) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *table, *button; + GtkWidget *cmd, *text; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + if (edit) + gtk_window_set_title (GTK_WINDOW (dlg), "Edit Command"); + else + gtk_window_set_title (GTK_WINDOW (dlg), "Add Command"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Menu text"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Command"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + text = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "text", text); + gtk_widget_show (text); + gtk_table_attach (GTK_TABLE (table), text, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (text, 300, -2); + + cmd = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "cmd", cmd); + gtk_widget_show (cmd); + gtk_table_attach (GTK_TABLE (table), cmd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (cmd, 300, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + if (edit) + { + GtkTreeView* view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(parent), "view")); + GtkTreeSelection* selection = gtk_tree_view_get_selection(view); + GtkTreeIter iter; + GtkTreeModel* model; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + char* key; + gtk_tree_model_get(model, &iter, 0, &key, -1); + const char* value = ValueForKey (g_qeglobals.d_project_entity, key); + gtk_entry_set_text (GTK_ENTRY (text), key); + gtk_entry_set_text (GTK_ENTRY (cmd), value); + g_free(key); + } + } + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char* key = gtk_entry_get_text (GTK_ENTRY (text)); + const char* value = gtk_entry_get_text (GTK_ENTRY (cmd)); + + if (strlen (key) <= 0 || strlen (value) <= 0) + { + Sys_Printf ("Command not added\n"); + } + else + { + if (edit) + { + SetKeyValue (g_qeglobals.d_project_entity, key, value); + FillBSPMenu (); + } + else + { + if (key[0] == 'b' && key[1] == 's' && key[2] == 'p') + { + SetKeyValue (g_qeglobals.d_project_entity, key, value); + FillBSPMenu (); + } + else + Sys_Printf ("BSP commands must be preceded by \"bsp\""); + } + + UpdateBSPCommandList (parent); + } + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +static void UpdateBSPCommandList (GtkWidget *dialog) +{ + GtkListStore* store = GTK_LIST_STORE (g_object_get_data (G_OBJECT(dialog), "bsp_commands")); + + gtk_list_store_clear(store); + + for(epair_t* ep = g_qeglobals.d_project_entity->epairs; ep != NULL; ep = ep->next) + { + if(ep->key[0] == 'b' && ep->key[1] == 's' && ep->key[2] == 'p') + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, ep->key, -1); + } + } +} + +static void project_add (GtkWidget *widget, gpointer data) +{ + GtkWidget *dlg = GTK_WIDGET (data); + DoProjectAddEdit (false, dlg); + UpdateBSPCommandList (dlg); +} + +static void project_change (GtkWidget *widget, gpointer data) +{ + GtkWidget *dlg = GTK_WIDGET (data); + DoProjectAddEdit (true, dlg); + UpdateBSPCommandList (dlg); +} + +static void project_remove (GtkWidget *widget, gpointer data) +{ + GtkWidget* project = GTK_WIDGET(data); + + GtkTreeView* view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(project), "view")); + GtkTreeSelection* selection = gtk_tree_view_get_selection(view); + GtkTreeIter iter; + GtkTreeModel* model; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + char* key; + gtk_tree_model_get(model, &iter, 0, &key, -1); + DeleteKey (g_qeglobals.d_project_entity, key); + g_free(key); + + char* index = gtk_tree_model_get_string_from_iter(model, &iter); + Sys_Printf ("Selected %s\n", index); + g_free(index); + + UpdateBSPCommandList(project); + FillBSPMenu(); + } +} + +static const char* sQ3ComboItem = "Quake III Arena"; +static const char* sTAComboItem = "Quake III: Team Arena"; +static const char* sModComboItem = "Custom Quake III modification"; +static const char* sWolfComboItem = "Return To Castle Wolfenstein"; +static const char* sWolfModComboItem = "Custom RTCW modification"; +static const char* sHLComboItem = "Half-life"; +static const char* sHLModComboItem = "Custom Half-life modification"; + +static const char* sWolfSPCombo = "Single Player mapping mode"; +static const char* sWolfMPCombo = "Multiplayer mapping mode"; + +// Arnout +// HARD-CODED ET HACK +static const char* sETComboItem = "Wolfenstein: Enemy Territory"; +static const char* sETModComboItem = "Custom ET modification"; + +// RIANT +// HARD-CODED JK2 HACK +static const char* sJK2ComboItem = "Jedi Knight II Outcast"; +static const char* sJK2ModComboItem = "Custom JK2 modification"; +static const char* sJK2SPCombo = "Single Player mapping mode"; +static const char* sJK2MPCombo = "Multiplayer mapping mode"; + +// TTimo +// HARD-CODED JA HACK +static const char* sJAComboItem = "Jedi Knight Jedi Academy"; +static const char* sJAModComboItem = "Custom JA modification"; +static const char* sJASPCombo = "Single Player mapping mode"; +static const char* sJAMPCombo = "Multiplayer mapping mode"; + +// RIANT +// HARD-CODED STVEF2 HACK +static const char* sSTVEFComboItem = "Star Trek Voyager : Elite Force"; +static const char* sSTVEFModComboItem = "Custom Elite Force modification"; +static const char* sSTVEFSPCombo = "Single Player mapping mode"; +static const char* sSTVEFMPCombo = "Holo Match mapping mode"; + +// RIANT +// HARD-CODED SOF2 HACK +static const char* sSOF2ComboItem = "Soldier of Fortune II - Double Helix"; +static const char* sSOF2ModComboItem = "Custom Sof2 modification"; +static const char* sSOF2SPCombo = "Single Player mapping mode"; +static const char* sSOF2MPCombo = "Multiplayer mapping mode"; + +static GtkWidget* game_select; // GTK_COMBO +static GtkEntry* fsgame_entry; + +gint OnSelchangeComboWhatgame (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + const char *dir = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(game_select)->entry)); + // HACK: Wolf + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strcmp(dir,sWolfComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + + } + // HACK: ET + else if (g_pGameDescription->mGameFile == "et.game") + { + if (!strcmp(dir,sETComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + + } + else if (g_pGameDescription->mGameFile == "hl.game") + { + if (!strcmp(dir,sHLComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + + } + // RIANT + // HACK: JK2 + else if (g_pGameDescription->mGameFile == "jk2.game") + { + if (!strcmp(dir,sJK2ComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // TTimo + // HACK: JA + else if (g_pGameDescription->mGameFile == "ja.game") + { + if (!strcmp(dir,sJAComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // RIANT + // HACK: STVEF + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strcmp(dir,sSTVEFComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // RIANT + // HACK: SOF2 + else if (g_pGameDescription->mGameFile == "sof2.game") + { + if (!strcmp(dir,sSOF2ComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // QUAKE 3 + else + { + if (!strcmp(dir,sQ3ComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else if (!strcmp(dir,sTAComboItem)) + { + gtk_entry_set_text (fsgame_entry, "missionpack"); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + + return TRUE; +} + +void DoProjectSettings () +{ + GtkWidget *project; + GtkWidget *frame, *label, *vbox, *table1, *table2, *button; + GtkWidget *brush; + GtkWidget *scr; + GtkWidget *base, *game; + GtkWidget *gamemode_combo; + GList *combo_list = (GList*)NULL; + + int loop = 1, ret = IDCANCEL; + + project = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (project), "Project Settings"); + gtk_signal_connect (GTK_OBJECT (project), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (project), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (project), "loop", &loop); + g_object_set_data (G_OBJECT (project), "ret", &ret); + gtk_window_set_default_size (GTK_WINDOW (project), 550, 400); + + table1 = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (project), table1); + gtk_container_set_border_width (GTK_CONTAINER (table1), 5); + gtk_table_set_row_spacings (GTK_TABLE (table1), 5); + gtk_table_set_col_spacings (GTK_TABLE (table1), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_table_attach (GTK_TABLE (table1), vbox, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_table_attach (GTK_TABLE (table1), vbox, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("Add..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (project_add), project); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Change..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (project_change), project); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Remove"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (project_remove), project); + gtk_widget_set_usize (button, 60, -2); + + frame = gtk_frame_new ("Misc settings"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + brush = gtk_check_button_new_with_label ("Use brush primitives in MAP files (NOTE: experimental feature,\n" + "required by the texture tools plugin)"); + gtk_widget_show (brush); + gtk_container_add (GTK_CONTAINER (frame), brush); + gtk_container_set_border_width (GTK_CONTAINER (brush), 5); + + frame = gtk_frame_new ("Menu commands"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_container_add (GTK_CONTAINER (frame), scr); + gtk_container_set_border_width (GTK_CONTAINER (scr), 5); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + + GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + + gtk_widget_show(view); + + g_object_set_data(G_OBJECT (project), "view", view); + g_object_set_data(G_OBJECT (project), "bsp_commands", store); + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + } + + frame = gtk_frame_new ("Project settings"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + // HACK: hardcoded game stuff + if (g_pGameDescription->mGameFile == "wolf.game" || + g_pGameDescription->mGameFile == "et.game" || + g_pGameDescription->mGameFile == "jk2.game" || + g_pGameDescription->mGameFile == "stvef.game" || + g_pGameDescription->mGameFile == "sof2.game" || + g_pGameDescription->mGameFile == "ja.game" ) + { + table2 = gtk_table_new (9, 2, FALSE); + } + else + { + table2 = gtk_table_new (8, 2, FALSE); + } + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (frame), table2); + gtk_container_set_border_width (GTK_CONTAINER (table2), 5); + gtk_table_set_row_spacings (GTK_TABLE (table2), 5); + gtk_table_set_col_spacings (GTK_TABLE (table2), 5); + + /* + fill in the game selection combo + HACK: hardcoded Q3/Wolf/HL switch + \todo that stuff would be faster to write with implementation of property bags and associated code to edit + */ + if (g_pGameDescription->mGameFile == "wolf.game") + { + combo_list = g_list_append (combo_list, (void *)sWolfComboItem); + combo_list = g_list_append (combo_list, (void *)sWolfModComboItem); + } + else if (g_pGameDescription->mGameFile == "et.game") + { + combo_list = g_list_append (combo_list, (void *)sETComboItem); + combo_list = g_list_append (combo_list, (void *)sETModComboItem); + } + else if (g_pGameDescription->mGameFile == "hl.game") + { + combo_list = g_list_append (combo_list, (void *)sHLComboItem); + combo_list = g_list_append (combo_list, (void *)sHLModComboItem); + } + // RIANT + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + combo_list = g_list_append (combo_list, (void *)sJK2ComboItem); + combo_list = g_list_append (combo_list, (void *)sJK2ModComboItem); + } + // TTimo + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + combo_list = g_list_append (combo_list, (void *)sJAComboItem); + combo_list = g_list_append (combo_list, (void *)sJAModComboItem); + } + // RIANT + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + combo_list = g_list_append (combo_list, (void *)sSTVEFComboItem); + combo_list = g_list_append (combo_list, (void *)sSTVEFModComboItem); + } + // RIANT + // SOF2 HACK A LA JK2 A LA WOLF + else if (g_pGameDescription->mGameFile == "sof2.game") + { + combo_list = g_list_append (combo_list, (void *)sSOF2ComboItem); + combo_list = g_list_append (combo_list, (void *)sSOF2ModComboItem); + } + else + { + // Q3 or default + combo_list = g_list_append (combo_list, (void *)sQ3ComboItem); + combo_list = g_list_append (combo_list, (void *)sTAComboItem); + combo_list = g_list_append (combo_list, (void *)sModComboItem); + } + + game_select = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (game_select), combo_list); + gtk_widget_show (game_select); + gtk_table_attach (GTK_TABLE (table2), game_select, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + gtk_signal_connect (GTK_OBJECT(GTK_COMBO (game_select)->entry), "changed", + GTK_SIGNAL_FUNC (OnSelchangeComboWhatgame), NULL); + + g_list_free (combo_list); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (game_select)->entry), FALSE); + + game = gtk_entry_new(); + fsgame_entry = GTK_ENTRY(game); + gtk_widget_show(game); + gtk_table_attach(GTK_TABLE(table2), game, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + /* + wolf specific: select MP or SP mode + */ + if (g_pGameDescription->mGameFile == "wolf.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sWolfSPCombo); + combo_list = g_list_append (combo_list, (void *)sWolfMPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + + // RIANT + // JK2 HACK + if (g_pGameDescription->mGameFile == "jk2.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sJK2SPCombo); + combo_list = g_list_append (combo_list, (void *)sJK2MPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + // TTimo + // JA HACK + if (g_pGameDescription->mGameFile == "ja.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sJASPCombo); + combo_list = g_list_append (combo_list, (void *)sJAMPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + // RIANT + // STVEF HACK + if (g_pGameDescription->mGameFile == "stvef.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sSTVEFSPCombo); + combo_list = g_list_append (combo_list, (void *)sSTVEFMPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + // RIANT + // SOF2 HACK + if (g_pGameDescription->mGameFile == "sof2.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sSOF2SPCombo); + combo_list = g_list_append (combo_list, (void *)sSOF2MPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + + /* + the usual stuff + */ + + base = gtk_entry_new (); + g_object_set_data (G_OBJECT (project), "base", base); + gtk_widget_show (base); + gtk_table_attach (GTK_TABLE (table2), base, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + + label = gtk_label_new ("basepath"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + + label = gtk_label_new ("Select mod"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("fs_game"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + // Initialize fields + gtk_entry_set_text (GTK_ENTRY (base), ValueForKey (g_qeglobals.d_project_entity, "basepath")); + UpdateBSPCommandList (project); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (brush), (g_qeglobals.m_bBrushPrimitMode) ? TRUE : FALSE); + + // initialise the fs_game selection from the project settings into the dialog + const char *dir = ValueForKey (g_qeglobals.d_project_entity, "gamename"); + // HACK: hardcoded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"main")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sWolfComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sWolfModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // HACK: hardcoded et stuff + if (g_pGameDescription->mGameFile == "et.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"etmain")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sETComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sETModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // HACK: hardcoded half-life stuff + else if (g_pGameDescription->mGameFile == "hl.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"valve")) + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sHLComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sHLModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // RIANT + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"base")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJK2ComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJK2ModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // TTimo + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"base")) + { + // no fs_game set, we are running stock editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJAComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJAModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // RIANT + // STVEF2 HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"baseEf")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSTVEFComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSTVEFModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // RIANT + // SOF2 HACK + else if (g_pGameDescription->mGameFile == "sof2.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"base")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSOF2ComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSOF2ModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + else + { + if ((strlen(dir) == 0) || !strcmp(dir,"baseq3")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sQ3ComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else if (!strcmp(dir,"missionpack")) + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sTAComboItem); + gtk_entry_set_text (GTK_ENTRY (game), "missionpack"); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + + // HACK: hardcoded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sWolfSPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sWolfMPCombo); + } + } + + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJK2SPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJK2MPCombo); + } + } + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJASPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJAMPCombo); + } + } + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSTVEFSPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSTVEFMPCombo); + } + } + // SOF2 HACK + else if (g_pGameDescription->mGameFile == "sof2.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSOF2SPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSOF2MPCombo); + } + } + + gtk_grab_add (project); + gtk_widget_show (project); + + g_pGameDescription->Dump(); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + char buf[1024]; + const char *r; + char *w; + + // convert path to unix format + for(r = gtk_entry_get_text (GTK_ENTRY (base)), w=buf; *r != '\0'; r++, w++) + *w = (*r == '\\') ? '/' : *r; + // add last slash + if(w != buf && *(w-1) != '/') *(w++) = '/'; + // terminate string + *w = '\0'; + SetKeyValue (g_qeglobals.d_project_entity, "basepath", buf); + + dir = gtk_entry_get_text (GTK_ENTRY (game)); + // Hack: hard coded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strlen(dir) || !stricmp(dir,"main")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + // Hack: hard coded ET stuff + else if (g_pGameDescription->mGameFile == "et.game") + { + if (!strlen(dir) || !stricmp(dir,"etmain")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + // Hack: hard coded Half-life stuff + else if (g_pGameDescription->mGameFile == "hl.game") + { + if (!strlen(dir) || !stricmp(dir,"valve")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + else if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + { + if (!strlen(dir) || !stricmp(dir,"base")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + // RIANT + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strlen(dir) || !stricmp(dir,"baseEf")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + else + { + if (!strlen(dir) || !strcmp(dir,"baseq3")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + + // HACK: hardcoded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sWolfSPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + // RIANT + // JK2 HACK + if (g_pGameDescription->mGameFile == "jk2.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sJK2SPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + // TTimo + // JA HACK + if (g_pGameDescription->mGameFile == "ja.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sJASPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + // RIANT + // STVEF HACK + if (g_pGameDescription->mGameFile == "stvef.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sSTVEFSPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; + const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); + if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); + g_qeglobals.m_strHomeMaps += str; + g_qeglobals.m_strHomeMaps += '/'; + + // RIANT + // SOF2 HACK + if (g_pGameDescription->mGameFile == "sof2.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sSOF2SPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (brush))) + g_qeglobals.m_bBrushPrimitMode = TRUE; + else + g_qeglobals.m_bBrushPrimitMode = FALSE; + + SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", (g_qeglobals.m_bBrushPrimitMode ? "1" : "0" )); + +// QE_CheckProjectEntity(); + + QE_SaveProject( g_PrefsDlg.m_strLastProject.GetBuffer() ); + } + + gtk_grab_remove (project); + gtk_widget_destroy (project); +} + +// ============================================================================= +// MapInfo dialog + +void DoMapInfo () +{ + static GtkWidget *dlg; + GtkWidget *vbox, *vbox2, *hbox, *table, *button, *label, *scr; + GtkWidget *brushes_entry, *entities_entry, *net_entry; + int loop = 1, ret = IDCANCEL; + + if (dlg != NULL) + return; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + load_window_pos(dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Map Info"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + brushes_entry = gtk_entry_new (); + gtk_widget_show (brushes_entry); + gtk_table_attach (GTK_TABLE (table), brushes_entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (brushes_entry), FALSE); + + entities_entry = gtk_entry_new (); + gtk_widget_show (entities_entry); + gtk_table_attach (GTK_TABLE (table), entities_entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (entities_entry), FALSE); + + net_entry = gtk_entry_new (); + gtk_widget_show (net_entry); + gtk_table_attach (GTK_TABLE (table), net_entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (net_entry), FALSE); + + label = gtk_label_new ("Total Brushes"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Total Entities"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Net brush count\n(non entity)"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + label = gtk_label_new ("Entity breakdown"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (scr), 5); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + { + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + gtk_tree_view_column_set_sort_column_id(column, 0); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + gtk_tree_view_column_set_sort_column_id(column, 1); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + } + + // Initialize fields + int TotalBrushes = 0, TotalEntities = 0, Net = 0; + + for (brush_t* pBrush = active_brushes.next; pBrush != &active_brushes; pBrush = pBrush->next) + { + TotalBrushes++; + if (pBrush->owner == world_entity) + Net++; + } + + typedef struct + { + const char *name; + int count; + } map_t; + + GSList *l, *entitymap = NULL; + map_t *entry; + + for (entity_t* pEntity = entities.next; pEntity != &entities; pEntity=pEntity->next) + { + TotalEntities++; + bool add = true; + + for (l = entitymap; l; l = g_slist_next (l)) + { + entry = (map_t*)l->data; + + if (strcmp (entry->name, pEntity->eclass->name) == 0) + { + entry->count++; + add = false; + break; + } + } + + if (add) + { + entry = (map_t*)qmalloc (sizeof (map_t)); + entry->name = pEntity->eclass->name; + entry->count = 1; + entitymap = g_slist_append (entitymap, entry); + } + } + + while (entitymap) + { + entry = (map_t*)entitymap->data; + char tmp[16]; + sprintf (tmp, "%d", entry->count); + GtkTreeIter iter; + gtk_list_store_append(GTK_LIST_STORE(store), &iter); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, entry->name, 1, tmp, -1); + free (entry); + entitymap = g_slist_remove (entitymap, entry); + } + + g_object_unref(G_OBJECT(store)); + + char tmp[16]; + sprintf (tmp, "%d", TotalBrushes); + gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp); + sprintf (tmp, "%d", TotalEntities); + gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp); + sprintf (tmp, "%d", Net); + gtk_entry_set_text (GTK_ENTRY (net_entry), tmp); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + // save before exit + save_window_pos(dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + dlg = NULL; +} + +// ============================================================================= +// Entity List dialog + +static void entitylist_select (GtkWidget *widget, gpointer data) +{ + GtkTreeView* view = GTK_TREE_VIEW(g_object_get_data (G_OBJECT (data), "entities")); + + GtkTreeSelection* selection = gtk_tree_view_get_selection(view); + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + entity_t* pEntity; + gtk_tree_model_get(model, &selected, 1, &pEntity, -1); + + if (pEntity) + { + for (epair_t* pEpair = pEntity->epairs; pEpair; pEpair = pEpair->next) + { + Select_Deselect (); + Select_Brush (pEntity->brushes.onext); + Sys_UpdateWindows(W_ALL); + } + } + } +} + +static gint entitylist_click (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + entitylist_select (NULL, data); + return TRUE; + } + return FALSE; +} + +static void entitylist_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + GtkListStore* store = GTK_LIST_STORE (g_object_get_data (G_OBJECT (data), "keyvalues")); + + gtk_list_store_clear(store); + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + entity_t* pEntity; + gtk_tree_model_get(model, &selected, 1, &pEntity, -1); + + if (pEntity) + { + for (epair_t* pEpair = pEntity->epairs; pEpair; pEpair = pEpair->next) + { + GtkTreeIter appended; + gtk_list_store_append(store, &appended); + gtk_list_store_set(store, &appended, 0, pEpair->key, 1, pEpair->value, -1); + } + } + } +} + +void DoEntityList () +{ + static GtkWidget *dlg; + GtkWidget *vbox, *hbox, *hbox2, *button, *scr; + int loop = 1, ret = IDCANCEL; + + if (dlg != NULL) + return; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posEntityInfoWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + g_signal_connect(G_OBJECT(view), "button_press_event", G_CALLBACK(entitylist_click), dlg); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(entitylist_selection_changed), dlg); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + g_object_set_data (G_OBJECT (dlg), "entities", view); + + { + { + GtkTreeIter child; + gtk_tree_store_append(store, &child, NULL); + gtk_tree_store_set(store, &child, 0, world_entity->eclass->name, 1, world_entity, -1); + } + + GSList *l, *entitymap = NULL; + typedef struct + { + GtkTreeIter node; + const char *name; + } map_t; + map_t *entry; + + for (entity_t* pEntity=entities.next; pEntity != &entities; pEntity=pEntity->next) + { + GtkTreeIter parent; + bool found = false; + + for (l = entitymap; l; l = g_slist_next (l)) + { + entry = (map_t*)l->data; + + if (strcmp (entry->name, pEntity->eclass->name) == 0) + { + parent = entry->node; + found = true; + break; + } + } + + if (!found) + { + gtk_tree_store_append(store, &parent, NULL); + gtk_tree_store_set(store, &parent, 0, pEntity->eclass->name, 1, NULL, -1); + + entry = (map_t*)malloc (sizeof(map_t)); + entitymap = g_slist_append (entitymap, entry); + entry->name = pEntity->eclass->name; + entry->node = parent; + } + + GtkTreeIter child; + gtk_tree_store_append(store, &child, &parent); + gtk_tree_store_set(store, &child, 0, pEntity->eclass->name, 1, pEntity, -1); + } + + while (entitymap) + { + free (entitymap->data); + entitymap = g_slist_remove (entitymap, entitymap->data); + } + } + + g_object_unref(G_OBJECT(store)); + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Value", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + + g_object_set_data(G_OBJECT(dlg), "keyvalues", store); + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + } + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("Select"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (entitylist_select), dlg); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + save_window_pos (dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + dlg = NULL; +} + +// ============================================================================= +// Rotate dialog + +static void rotatedlg_apply (GtkWidget *widget, gpointer data) +{ + GtkSpinButton *spin; + float f; + + spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "x")); + f = gtk_spin_button_get_value_as_float (spin); + if (f != 0.0) + Select_RotateAxis(0,f); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); // reset to 0 on Apply + + spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "y")); + f = gtk_spin_button_get_value_as_float (spin); + if (f != 0.0) + Select_RotateAxis(1,f); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); + + spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "z")); + f = gtk_spin_button_get_value_as_float (spin); + if (f != 0.0) + Select_RotateAxis(2,f); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); +} + +void DoRotateDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *table, *label, *button; + GtkWidget *x, *y, *z; + GtkObject *adj; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Arbitrary rotation"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new (" X "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (" Y "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (" Z "); + + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); + x = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + g_object_set_data (G_OBJECT (dlg), "x", x); + gtk_widget_show (x); + gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (x, 60, -2); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (x), TRUE); + + adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); + y = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + g_object_set_data (G_OBJECT (dlg), "y", y); + gtk_widget_show (y); + gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (y), TRUE); + + adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); + z = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + g_object_set_data (G_OBJECT (dlg), "z", z); + gtk_widget_show (z); + gtk_table_attach (GTK_TABLE (table), z, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (z), TRUE); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (rotatedlg_apply), dlg); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + rotatedlg_apply (button, dlg); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Gamma dialog + +void DoGamma () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Gamma"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + + label = gtk_label_new ("0.0 is brightest\n1.0 is darkest"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + label = gtk_label_new ("You must restart for the\nsettings to take effect"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + char buf[16]; + sprintf (buf, "%1.1f", g_qeglobals.d_savedinfo.fGamma); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + g_qeglobals.d_savedinfo.fGamma = g_strtod (gtk_entry_get_text (GTK_ENTRY (entry)), NULL); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Find Brush Dialog + +// helper function to walk through the active brushes only and drop the regioned out ones +bool WalkRegionBrush (brush_t **b, entity_t *e) +{ + brush_t *b2; + do + { + for(b2=active_brushes.next ; b2 != &active_brushes ; b2=b2->next) + { + if (b2==*b) + break; // this is an active brush + } + if (b2==&active_brushes) + { + // this is a regioned out brush + *b = (*b)->onext; + if (*b == &e->brushes) + { + Sys_Status ("No such brush", 0); + return false; + } + } + } while (b2==&active_brushes); + return true; +} + +void SelectBrush (int entitynum, int brushnum) +{ + entity_t *e; + brush_t *b; + int i; + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // making this work when regioning is on too + + if (entitynum == 0) + e = world_entity; + else + { + e = entities.next; + while (--entitynum) + { + e = e->next; + if (e == &entities) + { + Sys_Status ("No such entity", 0); + return; + } + if (region_active) + { + // we need to make sure we walk to the next 'active' entity to have a valid --entitynum + // that is, find a brush that belongs to this entity in the active brushes + do + { + for (b = active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (b->owner == e) + break; // this is an active entity + } + if (b==&active_brushes) + { + // this is a regioned out entity + e = e->next; + // don't walk past the end either + if (e == &entities) + { + Sys_Status ("No such entity", 0); + return; + } + } + } while(b==&active_brushes); + } + } + } + + b = e->brushes.onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush", 0); + return; + } + if (region_active) + { + if (!WalkRegionBrush(&b, e)) + return; + } + + while (brushnum--) + { + b = b->onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush", 0); + return; + } + if (region_active) + { + if (!WalkRegionBrush(&b, e)) + return; + } + } + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + + Sys_UpdateWindows (W_ALL); + for (i = 0; i < 3; i++) + { + if (g_pParentWnd->GetXYWnd()) + g_pParentWnd->GetXYWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; + + if (g_pParentWnd->GetXZWnd()) + g_pParentWnd->GetXZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; + + if (g_pParentWnd->GetYZWnd()) + g_pParentWnd->GetYZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; + } + + Sys_Status ("Selected", 0); +} + +static void GetSelectionIndex (int *ent, int *brush) +{ + brush_t *b, *b2; + entity_t *entity; + + *ent = *brush = 0; + + b = selected_brushes.next; + if (b == &selected_brushes) + return; + + // find entity + if (b->owner != world_entity) + { + (*ent)++; + for (entity = entities.next; entity != &entities; entity=entity->next, (*ent)++) + ; + } + + // find brush + for (b2=b->owner->brushes.onext; b2 != b && b2 != &b->owner->brushes; b2=b2->onext, (*brush)++) + ; +} + +void DoFind () +{ + GtkWidget *dlg, *vbox, *hbox, *table, *label, *button, *entity, *brush; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Find Brush"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Entity number"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Brush number"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + entity = gtk_entry_new (); + gtk_widget_show (entity); + gtk_table_attach (GTK_TABLE (table), entity, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + brush = gtk_entry_new (); + gtk_widget_show (brush); + gtk_table_attach (GTK_TABLE (table), brush, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + char buf[16]; + int ent, br; + + GetSelectionIndex (&ent, &br); + sprintf (buf, "%i", ent); + gtk_entry_set_text (GTK_ENTRY (entity), buf); + sprintf (buf, "%i", br); + gtk_entry_set_text (GTK_ENTRY (brush), buf); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char *entstr = gtk_entry_get_text (GTK_ENTRY (entity)); + const char *brushstr = gtk_entry_get_text (GTK_ENTRY (brush)); + SelectBrush (atoi(entstr), atoi(brushstr)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Arbitrary Sides dialog + +void DoSides (bool bCone, bool bSphere, bool bTorus) +{ + GtkWidget *dlg, *vbox, *hbox, *button, *label, *entry; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Arbitrary sides"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + label = gtk_label_new ("Sides:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char *str = gtk_entry_get_text (GTK_ENTRY (entry)); + + if (bCone) + Brush_MakeSidedCone(atoi(str)); + else if (bSphere) + Brush_MakeSidedSphere(atoi(str)); + else + Brush_MakeSided (atoi(str)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// New Patch dialog + +void DoNewPatchDlg () +{ + GtkWidget *dlg, *hbox, *table, *vbox, *label, *button, *combo; + GtkWidget *width, *height; + GList *combo_list = (GList*)NULL; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Patch density"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Width:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Height:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + combo_list = g_list_append (combo_list, (void *)"3"); + combo_list = g_list_append (combo_list, (void *)"5"); + combo_list = g_list_append (combo_list, (void *)"7"); + combo_list = g_list_append (combo_list, (void *)"9"); + combo_list = g_list_append (combo_list, (void *)"11"); + combo_list = g_list_append (combo_list, (void *)"13"); + combo_list = g_list_append (combo_list, (void *)"15"); + + combo = gtk_combo_new (); + width = GTK_COMBO (combo)->entry; + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + combo = gtk_combo_new (); + height = GTK_COMBO (combo)->entry; + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + g_list_free (combo_list); + gtk_entry_set_text (GTK_ENTRY (width), "3"); + gtk_entry_set_editable (GTK_ENTRY (width), FALSE); + gtk_entry_set_text (GTK_ENTRY (height), "3"); + gtk_entry_set_editable (GTK_ENTRY (height), FALSE); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char* w = gtk_entry_get_text (GTK_ENTRY (width)); + const char* h = gtk_entry_get_text (GTK_ENTRY (height)); + + Patch_GenericMesh(atoi (w), atoi (h), g_pParentWnd->ActiveXY ()->GetViewType ()); + Sys_UpdateWindows (W_ALL); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// New Patch dialog + +void DoScaleDlg () +{ + GtkWidget *dlg, *hbox, *table, *vbox, *label, *button; + GtkWidget *x, *y, *z; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Scale"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Z:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + x = gtk_entry_new (); + gtk_widget_show (x); + gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + y = gtk_entry_new (); + gtk_widget_show (y); + gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + z = gtk_entry_new (); + gtk_widget_show (z); + gtk_table_attach (GTK_TABLE (table), z, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + gtk_entry_set_text (GTK_ENTRY (x), "1.0"); + gtk_entry_set_text (GTK_ENTRY (y), "1.0"); + gtk_entry_set_text (GTK_ENTRY (z), "1.0"); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + float sx, sy, sz; + sx = atof (gtk_entry_get_text (GTK_ENTRY (x))); + sy = atof (gtk_entry_get_text (GTK_ENTRY (y))); + sz = atof (gtk_entry_get_text (GTK_ENTRY (z))); + + if (sx > 0 && sy > 0 && sz > 0) + { + Select_Scale(sx, sy, sz); + Sys_UpdateWindows (W_ALL); + } + else + Sys_Printf("Warning.. Tried to scale by a zero value."); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Thicken Patch dialog + +void DoThickenDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *vbox2, *button, *label; + GtkWidget *amount, *seams, *group; + int loop = 1, ret = IDCANCEL; + static qboolean bGroupResult = true; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Thicken Patch"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + label = gtk_label_new ("This produces a set of patches\n" + "that contains the original patch along with the\n" + "'thick' patch and an optimal set of seam patches."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + label = gtk_label_new ("Amount:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + amount = gtk_entry_new (); + gtk_widget_show (amount); + gtk_box_pack_start (GTK_BOX (hbox), amount, FALSE, FALSE, 0); + + seams = gtk_check_button_new_with_label ("Seams"); + gtk_widget_show (seams); + gtk_box_pack_start (GTK_BOX (hbox), seams, FALSE, FALSE, 0); + + // bGroupResult + group = gtk_check_button_new_with_label("Result to func_group"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(group), bGroupResult); + gtk_box_pack_start(GTK_BOX(vbox), group, FALSE, FALSE, 0); + gtk_widget_show(group); + + + // Initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seams), TRUE); + gtk_entry_set_text (GTK_ENTRY (amount), "8"); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group))) + bGroupResult = true; + else + bGroupResult = false; + Patch_Thicken (atoi (gtk_entry_get_text (GTK_ENTRY (amount))), + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (seams)), bGroupResult); + Sys_UpdateWindows (W_ALL); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// About dialog (no program is complete without one) + +void about_button_changelog (GtkWidget *widget, gpointer data) +{ + Str log; + log = g_strAppPath; + log += "changelog.txt"; + OpenURL(log.GetBuffer()); +} + +void about_button_credits (GtkWidget *widget, gpointer data) +{ + Str cred; + cred = g_strAppPath; + cred += "credits.html"; + OpenURL(cred.GetBuffer()); +} + +void DoAbout () +{ + GtkWidget *dlg, *vbox, *vbox2, *hbox, *frame, *table, *label, *pixmap, *button, *sc_extensions, *text_extensions; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About GtkRadiant"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, FALSE, 0); + + frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "logo.bmp"); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (frame), pixmap); + + label = gtk_label_new ("GtkRadiant " RADIANT_VERSION "\n" + __DATE__ "\n\n" + RADIANT_ABOUTMSG "\n\n" + "By qeradiant.com\n\n" + "This product contains software technology\n" + "from id Software, Inc. ('id Technology').\n" + "id Technology 2000 id Software,Inc.\n\n" + "GtkRadiant is unsupported, however\n" + "you may report your problems at\n" + "http://zerowing.idsoftware.com/bugzilla" + ); + + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + button = gtk_button_new_with_label ("Credits"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (about_button_credits), NULL); + + button = gtk_button_new_with_label ("Changelog"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (about_button_changelog), NULL); + + frame = gtk_frame_new ("OpenGL Properties"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + label = gtk_label_new ("Vendor:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Version:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Renderer:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ((char*)qglGetString (GL_VENDOR)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ((char*)qglGetString (GL_VERSION)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ((char*)qglGetString (GL_RENDERER)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + frame = gtk_frame_new ("OpenGL Extensions"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (frame), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + sc_extensions = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(hbox), sc_extensions, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_extensions), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_extensions), GTK_SHADOW_IN); + gtk_widget_show(sc_extensions); + + text_extensions = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text_extensions), FALSE); + gtk_container_add (GTK_CONTAINER (sc_extensions), text_extensions); + GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_extensions)); + gtk_text_buffer_set_text(buffer, (char *)qglGetString(GL_EXTENSIONS), -1); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_extensions), GTK_WRAP_WORD);; + gtk_widget_show(text_extensions); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Command List dialog + +void DoCommandListDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *scr, *button; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Mapped Commands"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 400); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Command", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + gtk_container_add(GTK_CONTAINER (scr), view); + + { + // Initialize dialog + CString path; + path = g_strTempPath; + path += "commandlist.txt"; + + GSList *cmds = NULL; + int n; + + for (n = 0; n < g_nCommandCount; n++) + cmds = g_slist_append (cmds, g_Commands[n].m_strCommand); + cmds = g_slist_sort (cmds, (gint (*)(const void *, const void *))strcmp); + + Sys_Printf("Writing the command list to %s", path.GetBuffer() ); + FILE* fileout = fopen (path.GetBuffer (), "wt"); + + while (cmds) + { + for (n = 0; n < g_nCommandCount; n++) + if (cmds->data == g_Commands[n].m_strCommand) + break; + + char c = g_Commands[n].m_nKey; + CString strLine, strMod(""), strKeys (c); + + for (int k = 0; k < g_nKeyCount; k++) + { + if (g_Keys[k].m_nVKKey == g_Commands[n].m_nKey) + { + strKeys = g_Keys[k].m_strName; + break; + } + } + + if (g_Commands[n].m_nModifiers & RAD_SHIFT) + strMod = "Shift"; + if (g_Commands[n].m_nModifiers & RAD_ALT) + strMod += (strMod.GetLength() > 0) ? " + Alt" : "Alt"; + if (g_Commands[n].m_nModifiers & RAD_CONTROL) + strMod += (strMod.GetLength() > 0) ? " + Control" : "Control"; + if (strMod.GetLength() > 0) + strMod += " + "; + strMod += strKeys; + + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, g_Commands[n].m_strCommand, 1, strMod.GetBuffer (), -1); + } + + if (fileout != NULL) + { + strLine.Format("%-25s %s\r\n", g_Commands[n].m_strCommand, strMod.GetBuffer ()); + fputs (strLine.GetBuffer (), fileout); + } + + cmds = g_slist_remove (cmds, cmds->data); + } + + if (fileout != NULL) + fclose (fileout); + } + + g_object_unref(G_OBJECT(store)); + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Texture List dialog + +void DoTextureListDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *scr, *button; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Textures"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 400); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + GtkWidget* texture_list; + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + gtk_container_add(GTK_CONTAINER (scr), view); + + { + // Initialize dialog + GSList *textures = (GSList*)NULL; + FillTextureMenu(&textures); + while (textures != NULL) + { + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, (gchar*)textures->data, -1); + } + free (textures->data); + textures = g_slist_remove (textures, textures->data); + } + } + + g_object_unref(G_OBJECT(store)); + + texture_list = view; + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Load"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(texture_list)); + + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iter); + if(gtk_tree_path_get_depth(path) == 1) + Texture_ShowDirectory(gtk_tree_path_get_indices(path)[0] + CMD_TEXTUREWAD); + gtk_tree_path_free(path); + } + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Cap dialog + +int DoCapDlg (int *type, bool *b_GroupResult) +{ + GtkWidget *dlg, *vbox, *hbox, *table, *pixmap, *button, *group_toggle, *radio_vbox; + GtkWidget *bevel, *endcap, *ibevel, *iendcap; + GSList *group = (GSList*)NULL; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Cap"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + // Gef: Added a vbox to contain the toggle buttons + radio_vbox = gtk_vbox_new(FALSE, 4); + gtk_container_add(GTK_CONTAINER(hbox), radio_vbox); + gtk_widget_show(radio_vbox); + + table = gtk_table_new (4, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (radio_vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_bevel.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_endcap.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_ibevel.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_iendcap.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + bevel = gtk_radio_button_new_with_label (group, "Bevel"); + gtk_widget_show (bevel); + gtk_table_attach (GTK_TABLE (table), bevel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (bevel)); + + endcap = gtk_radio_button_new_with_label (group, "Endcap"); + gtk_widget_show (endcap); + gtk_table_attach (GTK_TABLE (table), endcap, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (endcap)); + + ibevel = gtk_radio_button_new_with_label (group, "Inverted Bevel"); + gtk_widget_show (ibevel); + gtk_table_attach (GTK_TABLE (table), ibevel, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (ibevel)); + + iendcap = gtk_radio_button_new_with_label (group, "Inverted Endcap"); + gtk_widget_show (iendcap); + gtk_table_attach (GTK_TABLE (table), iendcap, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (iendcap)); + + // Gef: added radio toggle for func_grouping capped patches + group_toggle = gtk_check_button_new_with_label("Result to func_group"); + gtk_container_add(GTK_CONTAINER(radio_vbox), group_toggle); + gtk_widget_show(group_toggle); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + // Gef: Set the state of the func_group toggle + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (group_toggle), *b_GroupResult); + + // Initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bevel), TRUE); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bevel))) + *type = BEVEL; //*type = CapDialog::BEVEL; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (endcap))) + *type = ENDCAP; //*type = CapDialog::ENDCAP; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ibevel))) + *type = IBEVEL; // *type = CapDialog::IBEVEL; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (iendcap))) + *type = IENDCAP; // *type = CapDialog::IENDCAP; + + // Gef: Added toggle for optional cap func_grouping + *b_GroupResult = (bool *)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group_toggle)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// Scripts dialog + +void DoScriptsDlg () +{ + GtkWidget *dlg, *vbox, *vbox2, *hbox, *label, *button, *scr; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Available Scripts - Not Implemented Yet"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("WARNING: BrushScripting is in a highly experimental state and is\n" + "far from complete. If you attempt to use them it is VERY LIKELY\n" + "that Radiant will crash. Save your work before attempting to\n" + "make use of any scripting features."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + GtkWidget* scripts_list; + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + gtk_container_add(GTK_CONTAINER (scr), view); + + { + // Initialize dialog + CString strINI; + strINI = g_strGameToolsPath; + strINI += "/scripts.ini"; + FILE *f; + + f = fopen (strINI.GetBuffer(), "rt"); + if (f != NULL) + { + char line[1024], *ptr; + + // read section names + while (fgets (line, 1024, f) != 0) + { + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, line, -1); + } + } + fclose (f); + } + } + + g_object_unref(G_OBJECT(store)); + + scripts_list = view; + } + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Run"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("New..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_widget_set_sensitive (button, FALSE); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Edit..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_widget_set_sensitive (button, FALSE); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(scripts_list)); + + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + char* script; + gtk_tree_model_get(model, &iter, 0, &script, -1); + RunScriptByName(script, true); + g_free(script); + } + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// dialog + +int DoBSInputDlg (const char *fields[5], float values[5]) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button; + GtkWidget *entries[5]; + int i, loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "BrushScript Input"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + // Create entries and initialize them + for (i = 0; i < 5; i++) + { + if (strlen (fields[i]) == 0) + continue; + + label = gtk_label_new (fields[i]); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + entries[i] = gtk_entry_new (); + gtk_widget_show (entries[i]); + gtk_box_pack_start (GTK_BOX (vbox), entries[i], TRUE, TRUE, 0); + + char buf[32]; + sprintf (buf, "%f", values[i]); + gtk_entry_set_text (GTK_ENTRY (entries[i]), buf); + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + for (i = 0; i < 5; i++) + { + if (strlen (fields[i]) == 0) + continue; + + values[i] = atof (gtk_entry_get_text (GTK_ENTRY (entries[i]))); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// TextureLayout dialog + +int DoTextureLayout (float *fx, float *fy) +{ + GtkWidget *dlg, *vbox, *hbox, *table, *label, *button; + GtkWidget *x, *y; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Patch texture layout"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new ("Texture will be fit across the patch based\n" + "on the x and y values given. Values of 1x1\n" + "will \"fit\" the texture. 2x2 will repeat\n" + "it twice, etc."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Texture x:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Texture y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + x = gtk_entry_new (); + gtk_widget_show (x); + gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + y = gtk_entry_new (); + gtk_widget_show (y); + gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + // Initialize + gtk_entry_set_text (GTK_ENTRY (x), "4.0"); + gtk_entry_set_text (GTK_ENTRY (y), "4.0"); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + *fx = atof (gtk_entry_get_text (GTK_ENTRY (x))); + *fy = atof (gtk_entry_get_text (GTK_ENTRY (y))); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// Name dialog + +char* DoNameDlg (const char* title) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; + int loop = 1, ret = IDCANCEL; + char *str; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), title); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + label = gtk_label_new ("Name:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + else + str = NULL; + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return str; +} + +// ============================================================================= +// NewProject dialog + +char* DoNewProjectDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry, *check; + int loop = 1, ret = IDCANCEL; + char *str; + + // start by a warning message + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=459 + CString msg; + msg = "Are you sure you want a new project?\n"; + msg += "Please note that creating a new project is not the prefered way to setup GtkRadiant for mod editing.\n"; + msg += "Check http://www.qeradiant.com/faq/index.cgi?file=220 for more information"; + if (gtk_MessageBox(NULL, msg.GetBuffer(), "Confirm", MB_YESNO, "http://www.qeradiant.com/faq/index.cgi?file=220" ) == IDNO) + { + return NULL; + } + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "New Project"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + label = gtk_label_new ("This will create a new directory beneath your\n" + "game path based on the project name you give."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + label = gtk_label_new ("Project name:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + + check = gtk_check_button_new_with_label ("Include game dll files"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + gtk_widget_set_sensitive (check, FALSE); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + else + str = NULL; + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return str; +} + +// ============================================================================= +// Text Editor dialog + +// master window widget +static GtkWidget *text_editor = NULL; +static GtkWidget *text_widget; // slave, text widget from the gtk editor + +static gint editor_delete (GtkWidget *widget, gpointer data) +{ + if (gtk_MessageBox (widget, "Close the shader editor ?", "Radiant", MB_YESNO) == IDNO) + return TRUE; + + gtk_widget_hide (text_editor); + + return TRUE; +} + +static void editor_save (GtkWidget *widget, gpointer data) +{ + FILE *f = fopen ((char*)g_object_get_data (G_OBJECT (data), "filename"), "w"); + gpointer text = g_object_get_data (G_OBJECT (data), "text"); + + if (f == NULL) + { + gtk_MessageBox (GTK_WIDGET(data), "Error saving file !"); + return; + } + + char *str = gtk_editable_get_chars (GTK_EDITABLE (text), 0, -1); + fwrite (str, 1, strlen (str), f); + fclose (f); +} + +static void editor_close (GtkWidget *widget, gpointer data) +{ + if (gtk_MessageBox (text_editor, "Close the shader editor ?", "Radiant", MB_YESNO) == IDNO) + return; + + gtk_widget_hide (text_editor); +} + +// several attempts +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=355 +#if 0 +#ifdef _WIN32 + +HWND FindEditWindow() +{ + return FindWindow("TFormEditPadLite", NULL); +} + +HWND FindEditWindow() +{ + HWND hwnd = FindWindow("TFormEditPadLite", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TEditPadEditor", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TWinControlProxy", NULL); + return hwnd; + } + } + } + } + return NULL; +} + +HWND FindEditWindow() +{ + HWND hwnd = FindWindow("TFormEditPadLite", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TFrameSearchReplace", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TJGStringEditorControl", NULL); + return hwnd; + } + } + } + } + } + return NULL; +} + +HWND FindEditWindow() +{ + HWND hwnd = FindWindow("TEditPadForm", NULL); + HWND hwndEdit = NULL; + if (hwnd != NULL) + { + HWND hwndTab = FindWindowEx(hwnd, NULL, "TTabControl", NULL); + if (hwndTab != NULL) + { + hwndEdit = FindWindowEx(hwndTab, NULL, "TRicherEdit", NULL); + } + } + return hwndEdit; +} +#endif +#endif // #if 0 + +static void CreateGtkTextEditor () +{ + GtkWidget *dlg; + GtkWidget *vbox, *hbox, *button, *scr, *text; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (editor_delete), NULL); + gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 300); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + text = gtk_text_view_new(); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + g_object_set_data (G_OBJECT (dlg), "text", text); + gtk_text_view_set_editable (GTK_TEXT_VIEW(text), TRUE); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (editor_close), dlg); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Save"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (editor_save), dlg); + gtk_widget_set_usize (button, 60, -2); + + text_editor = dlg; + text_widget = text; +} + +static void DoGtkTextEditor (const char* filename, guint cursorpos) +{ + if (!text_editor) + CreateGtkTextEditor(); // build it the first time we need it + + // Load file + FILE *f = fopen (filename, "r"); + + if (f == NULL) + { + Sys_Printf("Unable to load file %s in shader editor.\n", filename); + gtk_widget_hide (text_editor); + } + else + { + fseek (f, 0, SEEK_END); + int len = ftell (f); + void *buf = qmalloc (len); + void *old_filename; + + rewind (f); + fread (buf, 1, len, f); + + gtk_window_set_title (GTK_WINDOW (text_editor), filename); + + GtkTextBuffer* text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_widget)); + gtk_text_buffer_set_text(text_buffer, (char*)buf, len); + + old_filename = g_object_get_data (G_OBJECT (text_editor), "filename"); + if (old_filename) + free(old_filename); + g_object_set_data (G_OBJECT (text_editor), "filename", strdup (filename)); + + // trying to show later + gtk_widget_show (text_editor); + +#ifdef _WIN32 + while (gtk_events_pending ()) + gtk_main_iteration (); +#endif + + // only move the cursor if it's not exceeding the size.. + // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters + // len is the max size in bytes, not in characters either, but the character count is below that limit.. + // thinking .. the difference between character count and byte count would be only because of CR/LF? + { + GtkTextIter text_iter; + // character offset, not byte offset + gtk_text_buffer_get_iter_at_offset(text_buffer, &text_iter, cursorpos); + gtk_text_buffer_place_cursor(text_buffer, &text_iter); + } + +#ifdef _WIN32 + gtk_widget_queue_draw(text_widget); +#endif + + free (buf); + fclose (f); + } +} + +void DoTextEditor (const char* filename, int cursorpos) +{ + CString strEditCommand; +#ifdef _WIN32 + if (g_PrefsDlg.m_bUseWin32Editor) + { + Sys_Printf("opening file '%s' (line %d info ignored)\n", filename); + ShellExecute((HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", filename, NULL, NULL, SW_SHOW ); + return; + } +#else + // check if a custom editor is set + if((g_PrefsDlg.m_bUseCustomEditor) && (g_PrefsDlg.m_strEditorCommand.GetLength() > 0)) + { + strEditCommand = g_PrefsDlg.m_strEditorCommand; + strEditCommand += " \""; + strEditCommand += filename; + strEditCommand += "\""; + + Sys_Printf("Launching: %s\n", strEditCommand.GetBuffer()); + // note: linux does not return false if the command failed so it will assume success + if (Q_Exec(NULL, (char *)strEditCommand.GetBuffer(), NULL, true) == false) + { + Sys_FPrintf(SYS_WRN, "Warning: Failed to execute %s, using default\n", strEditCommand.GetBuffer()); + } + else + { + // the command (appeared) to run successfully, no need to do anything more + return; + } + } +#endif + + DoGtkTextEditor (filename, cursorpos); + + // old win32 code with EditPad bindings, broken + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=355 +#if 0 + strEditCommand = g_strAppPath.GetBuffer(); + strEditCommand += "editpad.exe"; + strEditCommand += " \""; + strEditCommand += filename; + strEditCommand += "\""; + if (Q_Exec(NULL, (char *)strEditCommand.GetBuffer(), NULL, true) == false) + { + Sys_FPrintf(SYS_WRN, "WARNING: Gtk shader editor is not fully functional on windows in general and unstable on win98 in particular.\n"); + Sys_FPrintf(SYS_WRN, " you can use EditPad instead (install it in Radiant's directory): http://www.qeradiant.com/?data=files&files_dir=18\n"); + DoGtkTextEditor (filename, cursorpos); + } + else + { + // TTimo: we used to call Delay here, to continue processing messages. But it seems to induce a lot of instabilities. + // so now the user will simply have to wait. + Sleep( 1500 ); + + // now grab the edit window and scroll to the shader we want to edit + HWND hwndEdit = FindEditWindow(); + + if (hwndEdit != NULL) + PostMessage(hwndEdit, EM_SETSEL, cursorpos, cursorpos); + else + Sys_Printf("Unable to load shader editor.\n"); + } +#endif +} + +// ============================================================================= +// Light Intensity dialog + +int DoLightIntensityDlg (int *intensity) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Light intensity"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + GtkAccelGroup *accel_group = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (dlg), accel_group); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new ("ESC for default, ENTER to validate"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_add_accelerator (button, "clicked", accel_group, + GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_add_accelerator (button, "clicked", accel_group, + GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE); + gtk_widget_set_usize (button, 60, -2); + + char buf[16]; + sprintf (buf, "%d", *intensity); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + *intensity = atoi (gtk_entry_get_text (GTK_ENTRY (entry))); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} diff --git a/radiant/gtkfilesel-darwin.c b/radiant/gtkfilesel-darwin.c new file mode 100644 index 00000000..2076423c --- /dev/null +++ b/radiant/gtkfilesel-darwin.c @@ -0,0 +1,3360 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + + +// leo FIXME: if we keep this file then we'll need to ask permission to the author, this is LGPL +// This file is from the Advanced File Selector widget +// by Michael Torrie +// http://students.cs.byu.edu/~torriem/gtk/ + +// common files win32/linux +#include +#include +#include +#include +#include +#include + +// TTimo +// NOTE: the mkdir stuff etc. is in .. but I don't know what's the best strategy yet. +// just including here doesn't cut it + +#if defined (__linux__) || (__APPLE__) +#include +#include +#include +#include +#include "fnmatch.h" +#endif + +// leo: added "gtk/" +#include "gdk/gdkkeysyms.h" +#include "gtk/gtkbutton.h" +#include "gtk/gtkentry.h" +#include "gtkfilesel-darwin.h" +#include "gtk/gtkhbox.h" +#include "gtk/gtkhbbox.h" +#include "gtk/gtklabel.h" +#include "gtk/gtklist.h" +#include "gtk/gtklistitem.h" +#include "gtk/gtkmain.h" +#include "gtk/gtkscrolledwindow.h" +#include "gtk/gtksignal.h" +#include "gtk/gtkvbox.h" +#include "gtk/gtkmenu.h" +#include "gtk/gtkmenuitem.h" +#include "gtk/gtkoptionmenu.h" +#include "gtk/gtkclist.h" +#include "gtk/gtkdialog.h" +#include "gtk/gtkcombo.h" +#include "gtk/gtkframe.h" + +// leo: disable NLS +//#include "gtk/gtkintl.h" +#define _(String) (String) + +#define DIR_LIST_WIDTH 180 +#define DIR_LIST_HEIGHT 180 +#define FILE_LIST_WIDTH 180 +#define FILE_LIST_HEIGHT 180 + +/* I've put this here so it doesn't get confused with the + * file completion interface */ +typedef struct _HistoryCallbackArg HistoryCallbackArg; + +struct _HistoryCallbackArg +{ + gchar *directory; + GtkWidget *menu_item; +}; + + +typedef struct _CompletionState CompletionState; +typedef struct _CompletionDir CompletionDir; +typedef struct _CompletionDirSent CompletionDirSent; +typedef struct _CompletionDirEntry CompletionDirEntry; +typedef struct _CompletionUserDir CompletionUserDir; +typedef struct _PossibleCompletion PossibleCompletion; + +/* Non-external file completion decls and structures */ + +/* A contant telling PRCS how many directories to cache. Its actually + * kept in a list, so the geometry isn't important. */ +#define CMPL_DIRECTORY_CACHE_SIZE 10 + +/* A constant used to determine whether a substring was an exact + * match by first_diff_index() + */ +#define PATTERN_MATCH -1 +/* The arguments used by all fnmatch() calls below + */ +#define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD) + +#define CMPL_ERRNO_TOO_LONG ((1<<16)-1) + +/* This structure contains all the useful information about a directory + * for the purposes of filename completion. These structures are cached + * in the CompletionState struct. CompletionDir's are reference counted. + */ +struct _CompletionDirSent +{ + ino_t inode; + time_t mtime; + dev_t device; + + gint entry_count; + gchar *name_buffer; /* memory segment containing names of all entries */ + + struct _CompletionDirEntry *entries; +}; + +struct _CompletionDir +{ + CompletionDirSent *sent; + + gchar *fullname; + gint fullname_len; + + struct _CompletionDir *cmpl_parent; + gint cmpl_index; + gchar *cmpl_text; +}; + +/* This structure contains pairs of directory entry names with a flag saying + * whether or not they are a valid directory. NOTE: This information is used + * to provide the caller with information about whether to update its completions + * or try to open a file. Since directories are cached by the directory mtime, + * a symlink which points to an invalid file (which will not be a directory), + * will not be reevaluated if that file is created, unless the containing + * directory is touched. I consider this case to be worth ignoring (josh). + */ +struct _CompletionDirEntry +{ + gint is_dir; + gchar *entry_name; +}; + +struct _CompletionUserDir +{ + gchar *login; + gchar *homedir; +}; + +struct _PossibleCompletion +{ + /* accessible fields, all are accessed externally by functions + * declared above + */ + gchar *text; + gint is_a_completion; + gint is_directory; + + gint file_size; + gint file_time; + gint uid; + gint gid; + /* Private fields + */ + gint text_alloc; +}; + +struct _CompletionState +{ + gint last_valid_char; + gchar *updated_text; + gint updated_text_len; + gint updated_text_alloc; + gint re_complete; + + gchar *user_dir_name_buffer; + gint user_directories_len; + + gchar *last_completion_text; + + gint user_completion_index; /* if >= 0, currently completing ~user */ + + struct _CompletionDir *completion_dir; /* directory completing from */ + struct _CompletionDir *active_completion_dir; + + struct _PossibleCompletion the_completion; + + struct _CompletionDir *reference_dir; /* initial directory */ + + GList* directory_storage; + GList* directory_sent_storage; + + struct _CompletionUserDir *user_directories; +}; + + +/* File completion functions which would be external, were they used + * outside of this file. + */ + +static CompletionState* cmpl_init_state (void); +static void cmpl_free_state (CompletionState *cmpl_state); +static gint cmpl_state_okay (CompletionState* cmpl_state); +static gchar* cmpl_strerror (gint); + +static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, + gchar **remaining_text, + CompletionState *cmpl_state); + +/* Returns a name for consideration, possibly a completion, this name + * will be invalid after the next call to cmpl_next_completion. + */ +static char* cmpl_this_completion (PossibleCompletion*); + +/* True if this completion matches the given text. Otherwise, this + * output can be used to have a list of non-completions. + */ +static gint cmpl_is_a_completion (PossibleCompletion*); + +/* True if the completion is a directory + */ +static gint cmpl_is_directory (PossibleCompletion*); + +/* Obtains the next completion, or NULL + */ +static PossibleCompletion* cmpl_next_completion (CompletionState*); + +/* Updating completions: the return value of cmpl_updated_text() will + * be text_to_complete completed as much as possible after the most + * recent call to cmpl_completion_matches. For the present + * application, this is the suggested replacement for the user's input + * string. You must CALL THIS AFTER ALL cmpl_text_completions have + * been received. + */ +static gchar* cmpl_updated_text (CompletionState* cmpl_state); + +/* After updating, to see if the completion was a directory, call + * this. If it was, you should consider re-calling completion_matches. + */ +static gint cmpl_updated_dir (CompletionState* cmpl_state); + +/* Current location: if using file completion, return the current + * directory, from which file completion begins. More specifically, + * the cwd concatenated with all exact completions up to the last + * directory delimiter('/'). + */ +static gchar* cmpl_reference_position (CompletionState* cmpl_state); + +/* backing up: if cmpl_completion_matches returns NULL, you may query + * the index of the last completable character into cmpl_updated_text. + */ +static gint cmpl_last_valid_char (CompletionState* cmpl_state); + +/* When the user selects a non-directory, call cmpl_completion_fullname + * to get the full name of the selected file. + */ +static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state); + + +/* Directory operations. */ +static CompletionDir* open_ref_dir (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static gboolean check_dir (gchar *dir_name, + struct stat *result, + gboolean *stat_subdirs); +static CompletionDir* open_dir (gchar* dir_name, + CompletionState* cmpl_state); +static CompletionDir* open_user_dir (gchar* text_to_complete, + CompletionState *cmpl_state); +static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, + CompletionState *cmpl_state); +static CompletionDirSent* open_new_dir (gchar* dir_name, + struct stat* sbuf, + gboolean stat_subdirs); +static gint correct_dir_fullname (CompletionDir* cmpl_dir); +static gint correct_parent (CompletionDir* cmpl_dir, + struct stat *sbuf); +static gchar* find_parent_dir_fullname (gchar* dirname); +static CompletionDir* attach_dir (CompletionDirSent* sent, + gchar* dir_name, + CompletionState *cmpl_state); +static void free_dir_sent (CompletionDirSent* sent); +static void free_dir (CompletionDir *dir); +static void prune_memory_usage(CompletionState *cmpl_state); + +/* Completion operations */ +static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state); +static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state); +static CompletionDir* find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static PossibleCompletion* append_completion_text(gchar* text, + CompletionState* cmpl_state); +static gint get_pwdb(CompletionState* cmpl_state); +static gint first_diff_index(gchar* pat, gchar* text); +static gint compare_user_dir(const void* a, const void* b); +static gint compare_cmpl_dir(const void* a, const void* b); +static void update_cmpl(PossibleCompletion* poss, + CompletionState* cmpl_state); + +static void gtk_file_selection_class_init (GtkFileSelectionClass *klass); +static void gtk_file_selection_init (GtkFileSelection *filesel); +static void gtk_file_selection_destroy (GtkObject *object); +static gint gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); + +static void gtk_file_selection_file_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data); + +static void gtk_file_selection_dir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer data); + +static void gtk_file_selection_undir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer data); + +static void gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete); +static void gtk_file_selection_abort (GtkFileSelection *fs); + +static void gtk_file_selection_update_history_menu (GtkFileSelection *fs, + gchar *current_dir); + +static void gtk_file_selection_create_dir (GtkWidget *widget, gpointer data); +static void gtk_file_selection_delete_file (GtkWidget *widget, gpointer data); +static void gtk_file_selection_rename_file (GtkWidget *widget, gpointer data); + +static gboolean gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data); +static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); +static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist, + GdkEventButton *event, + gpointer user_data); +static void gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data); +static void gtk_file_selection_create_dir (GtkWidget *widget, gpointer data); +static void gtk_file_selection_delete_file (GtkWidget *widget, gpointer data); +static void gtk_file_selection_rename_file (GtkWidget *widget, gpointer data); +static void gtk_file_selection_home_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_up_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_prev_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_next_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data); + +static gint gtk_file_selection_match_char (gchar, gchar *mask); +static gint gtk_file_selection_match_mask (gchar *,gchar *); + + +static GtkWindowClass *parent_class = NULL; + +/* Saves errno when something cmpl does fails. */ +static gint cmpl_errno; + + +void gtk_file_selection_clear_masks (GtkFileSelection *filesel) +{ + GList *list; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + list = filesel->masks; + while (list) + { + g_free (list->data); + list = list->next; + } + filesel->masks = NULL; + + gtk_list_clear_items (GTK_LIST (GTK_COMBO (filesel->mask_entry)->list), 0, -1); +} + +void gtk_file_selection_set_masks (GtkFileSelection *filesel, const gchar **masks) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + while (*masks) + { + filesel->masks = g_list_append (filesel->masks, (gpointer)*masks); + masks++; + } + + if (filesel->masks) + gtk_combo_set_popdown_strings (GTK_COMBO (filesel->mask_entry), filesel->masks); +} + + +/* General notes: + * Make prev and next inactive if their respective * + * histories are empty. + * Add facilities for handling hidden files and * + * directories * + * Add an api to access the mask, and hidden files * + * check box? (prob not in 1.2.x series) * + */ + +/* Routine for applying mask to filenames * + * Need to be optimized to minimize recursion * + * help the for loop by looking for the next * + * instance of the mask character following * + * the '*'. ei *.c -- look for '.' * + * Also, swap all *? pairs (-> ?*), as that * + * will make it possible to look ahead (? * + * makes it very nondeterministic as in *?.c * + * which really is ?*.c * + * Allow multiply masks, separted by commas * + * Allow more flexible [] handling (ie [a-zA-Z] * + * * + */ +static gint gtk_file_selection_match_char (gchar text, gchar *mask){ + gchar *maskc; + gint x; + gint s; + + if (mask[0] == '[') + { + if (!strchr (mask,']')) return 0; + maskc = g_strdup(mask + 1); /* get the portion of mask inside []*/ + + (*(strchr (maskc,']'))) = 0; + s = strlen ((char *)maskc); + + for (x = 0; x < s; x++){ + if (text == maskc[x]) + { + g_free (maskc); + return s + 2; + } + } + g_free (maskc); + return 0; + } + + if (mask[0] == '?') return 1; + if (mask[0] == text) return 1; + + return 0; +} + + +static gint gtk_file_selection_match_mask (gchar *text, gchar *mask){ + + int mc; + int tc; + + tc = 0; mc = 0; + + if (mask[0] == 0 && text[0] == 0) return 1; + + if (mask[0] == '*') + { + for (tc = 0; tc <= strlen(text); tc++) + { + if (gtk_file_selection_match_mask (text + tc, mask + 1)) + return 1; + } + return 0; + } + mc = gtk_file_selection_match_char (text[0], mask); + + if(mc) + return gtk_file_selection_match_mask (text + 1, mask + mc); + else + return 0; +} + +GtkType +gtk_file_selection_get_type (void) +{ + static GtkType file_selection_type = 0; + + if (!file_selection_type) + { + static const GtkTypeInfo filesel_info = + { + "GtkFileSelection", + sizeof (GtkFileSelection), + sizeof (GtkFileSelectionClass), + (GtkClassInitFunc) gtk_file_selection_class_init, + (GtkObjectInitFunc) gtk_file_selection_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + file_selection_type = gtk_type_unique (GTK_TYPE_WINDOW, &filesel_info); + } + + return file_selection_type; +} + +static void +gtk_file_selection_class_init (GtkFileSelectionClass *klass) //tigital +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) klass; + + parent_class = gtk_type_class (GTK_TYPE_WINDOW); + + object_class->destroy = gtk_file_selection_destroy; +} + +static void +gtk_file_selection_init (GtkFileSelection *filesel) +{ + GtkWidget *entry_vbox; + GtkWidget *label; + GtkWidget *list_hbox; + GtkWidget *confirm_area; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *pulldown_hbox; + GtkWidget *scrolled_win; + GtkWidget *mask_label; + GtkWidget *bigframe; + GtkWidget *label_lookingin; + GtkWidget *up_button; + GtkWidget *home_button; + GtkWidget *prev_button; + GtkWidget *next_button; + GtkWidget *refresh_button; + + char *dir_title [2]; + char *file_title [2]; + + filesel->cmpl_state = cmpl_init_state (); + + filesel->mask=NULL; + filesel->prev_history=NULL; + filesel->next_history=NULL; + filesel->saved_entry=NULL; + + /* The dialog-sized vertical box */ + filesel->main_vbox = gtk_vbox_new (FALSE, 10); + gtk_container_set_border_width (GTK_CONTAINER (filesel), 10); + gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox); + gtk_widget_show (filesel->main_vbox); + + /* The horizontal box containing create, rename etc. buttons */ + filesel->button_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(filesel->button_area), GTK_BUTTONBOX_START); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(filesel->button_area), 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->button_area, + FALSE, FALSE, 0); + gtk_widget_show (filesel->button_area); + + gtk_file_selection_show_fileop_buttons(filesel); + + /* hbox for pulldown menu */ + pulldown_hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), pulldown_hbox, FALSE, FALSE, 0); + gtk_widget_show (pulldown_hbox); + + /* The combo box that replaces the pulldown menu */ + label_lookingin = gtk_label_new (_("Looking in:")); + gtk_widget_show (label_lookingin); + gtk_box_pack_start (GTK_BOX (pulldown_hbox), label_lookingin, FALSE, FALSE, 0); + + filesel->history_combo = gtk_combo_new(); + gtk_widget_show(filesel->history_combo); + gtk_combo_set_value_in_list(GTK_COMBO(filesel->history_combo),FALSE,FALSE); + gtk_box_pack_start (GTK_BOX(pulldown_hbox),filesel->history_combo, + TRUE,TRUE, 0); + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->entry),"key-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"button-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_list_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"key-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_list_key_handler, + (gpointer) filesel); + + /* frame to put the following hbox in */ + bigframe = gtk_frame_new (NULL); + gtk_widget_show (bigframe); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), bigframe, TRUE, TRUE, 0); + + /* The horizontal box containing the directory and file listboxes */ + list_hbox = gtk_hbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER(bigframe), list_hbox); + gtk_container_set_border_width (GTK_CONTAINER (list_hbox), 5); + gtk_widget_show (list_hbox); + + /* vbox to put the buttons and directory listing in */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (list_hbox), vbox, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + home_button = gtk_button_new_with_label (_("Home")); + gtk_widget_show (home_button); + gtk_signal_connect (GTK_OBJECT (home_button), "clicked", + (GtkSignalFunc) gtk_file_selection_home_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox), home_button, TRUE,TRUE, 0); + + prev_button = gtk_button_new_with_label (_("Prev")); + gtk_signal_connect (GTK_OBJECT (prev_button), "clicked", + (GtkSignalFunc) gtk_file_selection_prev_button, + (gpointer) filesel); + gtk_widget_show (prev_button); + gtk_box_pack_start (GTK_BOX (hbox), prev_button, TRUE,TRUE, 0); + + up_button = gtk_button_new_with_label (_("Up")); + gtk_signal_connect (GTK_OBJECT (up_button), "clicked", + (GtkSignalFunc) gtk_file_selection_up_button, + (gpointer) filesel); + gtk_widget_show (up_button); + gtk_box_pack_start (GTK_BOX (hbox), up_button, TRUE,TRUE, 0); + + next_button = gtk_button_new_with_label (_("Next")); + gtk_widget_show (next_button); + gtk_signal_connect (GTK_OBJECT (next_button), "clicked", + (GtkSignalFunc) gtk_file_selection_next_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox), next_button, TRUE,TRUE, 0); + + refresh_button = gtk_button_new_with_label (_("Refresh")); + gtk_widget_show (refresh_button); + gtk_signal_connect (GTK_OBJECT (refresh_button), "clicked", + (GtkSignalFunc) gtk_file_selection_refresh_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox), refresh_button, TRUE, TRUE, 0); + + /* The directories clist */ + dir_title[0] = _("Directories"); + dir_title[1] = NULL; + filesel->dir_list = gtk_clist_new_with_titles (1, (gchar**) dir_title); + gtk_widget_set_usize (filesel->dir_list, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "select_row", + (GtkSignalFunc) gtk_file_selection_dir_button, + (gpointer) filesel); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "unselect_row", + (GtkSignalFunc) gtk_file_selection_undir_button, + (gpointer) filesel); + gtk_clist_column_titles_passive (GTK_CLIST (filesel->dir_list)); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->dir_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE,TRUE, 5); + gtk_widget_show (filesel->dir_list); + gtk_widget_show (scrolled_win); + + /* vbox area for mask entry and files clist */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (list_hbox), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + mask_label = gtk_label_new (_("Mask:")); + gtk_widget_show (mask_label); + gtk_box_pack_start (GTK_BOX (hbox), mask_label, FALSE, FALSE, 0); + + filesel->mask_entry = gtk_entry_new (); + gtk_widget_show (filesel->mask_entry); + gtk_signal_connect(GTK_OBJECT(filesel->mask_entry),"activate", + (GtkSignalFunc) gtk_file_selection_mask_entry_callback, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox),filesel->mask_entry, TRUE, TRUE, 0); + + + /* The files clist */ + file_title[0] = _("Files"); + file_title[1] = NULL; + filesel->file_list = gtk_clist_new_with_titles (1, (gchar**) file_title); + gtk_widget_set_usize (filesel->file_list, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "select_row", + (GtkSignalFunc) gtk_file_selection_file_button, + (gpointer) filesel); + gtk_clist_column_titles_passive (GTK_CLIST (filesel->file_list)); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->file_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 5); + gtk_widget_show (filesel->file_list); + gtk_widget_show (scrolled_win); + + /* action area for packing buttons into. */ + filesel->action_area = gtk_hbox_new (TRUE, 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->action_area, + FALSE, FALSE, 0); + gtk_widget_show (filesel->action_area); + + /* The OK/Cancel button area */ + confirm_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(confirm_area), 5); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), confirm_area, FALSE, FALSE, 0); + gtk_widget_show (confirm_area); + + /* The OK button */ + filesel->ok_button = gtk_button_new_with_label (_("OK")); + GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (filesel->ok_button); + gtk_widget_show (filesel->ok_button); + + /* The Cancel button */ + filesel->cancel_button = gtk_button_new_with_label (_("Cancel")); + GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->cancel_button); + + /* The selection entry widget */ + entry_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 0); + gtk_widget_show (entry_vbox); + + filesel->selection_text = label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + filesel->selection_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event", + (GtkSignalFunc) gtk_file_selection_key_press, filesel); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event", + (GtkSignalFunc) gtk_widget_grab_default, + GTK_OBJECT (filesel->ok_button)); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate", + (GtkSignalFunc) gtk_button_clicked, + GTK_OBJECT (filesel->ok_button)); + gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_entry, TRUE, TRUE, 0); + gtk_widget_show (filesel->selection_entry); + + if (!cmpl_state_okay (filesel->cmpl_state)) + { + gchar err_buf[256]; + + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); + + gtk_label_set_text (GTK_LABEL (filesel->selection_text), err_buf); + } + else + { + gtk_file_selection_populate (filesel, "", FALSE); + } + + gtk_widget_grab_focus (filesel->selection_entry); +} + +GtkWidget* +gtk_file_selection_new (const gchar *title) +{ + GtkFileSelection *filesel; + + filesel = gtk_type_new (GTK_TYPE_FILE_SELECTION); + gtk_window_set_title (GTK_WINDOW (filesel), title); + + return GTK_WIDGET (filesel); +} + +void +gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + /* delete, create directory, and rename */ + if (!filesel->fileop_c_dir) + { + filesel->fileop_c_dir = gtk_button_new_with_label (_("Create Dir")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_c_dir), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_c_dir, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_c_dir); + } + + if (!filesel->fileop_del_file) + { + filesel->fileop_del_file = gtk_button_new_with_label (_("Delete File")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_del_file), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_del_file, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_del_file); + } + + if (!filesel->fileop_ren_file) + { + filesel->fileop_ren_file = gtk_button_new_with_label (_("Rename File")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_ren_file), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_ren_file, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_ren_file); + } + + gtk_widget_queue_resize(GTK_WIDGET(filesel)); +} + +void +gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + if (filesel->fileop_ren_file) + { + gtk_widget_destroy (filesel->fileop_ren_file); + filesel->fileop_ren_file = NULL; + } + + if (filesel->fileop_del_file) + { + gtk_widget_destroy (filesel->fileop_del_file); + filesel->fileop_del_file = NULL; + } + + if (filesel->fileop_c_dir) + { + gtk_widget_destroy (filesel->fileop_c_dir); + filesel->fileop_c_dir = NULL; + } +} + + + +void +gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename) +{ + char buf[MAXPATHLEN]; + const char *name, *last_slash; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (filename != NULL); + + last_slash = strrchr (filename, '/'); + + if (!last_slash) + { + buf[0] = 0; + name = filename; + } + else + { + gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1); + + strncpy (buf, filename, len); + buf[len] = 0; + + name = last_slash + 1; + } + + gtk_file_selection_populate (filesel, buf, FALSE); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); +} + +gchar* +gtk_file_selection_get_filename (GtkFileSelection *filesel) +{ + static char nothing[2] = ""; + char *text; + char *filename; + + g_return_val_if_fail (filesel != NULL, nothing); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); + + text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + if (text) + { + filename = cmpl_completion_fullname (text, filesel->cmpl_state); + return filename; + } + + return nothing; +} + +void +gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern) +{ + gchar *new_pattern; + gint x; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (pattern != NULL); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), pattern); + + if(strchr(pattern,'*') || strchr(pattern,'?')) + { + for(x=strlen(pattern);x>=0;x--) + { + if(pattern[x]=='/') break; + } + gtk_entry_set_text(GTK_ENTRY(filesel->mask_entry),g_strdup(pattern+x+1)); + + if(filesel->mask) g_free(filesel->mask); + + filesel->mask=g_strdup(pattern+x+1); + new_pattern=g_strdup(pattern); + new_pattern[x+1]=0; + gtk_file_selection_populate (filesel, (gchar*) new_pattern, TRUE); + g_free(new_pattern); + } + else + { + gtk_file_selection_populate (filesel, (gchar*) pattern, TRUE); + } +} + +static void +gtk_file_selection_destroy (GtkObject *object) +{ + GtkFileSelection *filesel; + GList *list; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (object)); + + filesel = GTK_FILE_SELECTION (object); + + if (filesel->fileop_dialog) + gtk_widget_destroy (filesel->fileop_dialog); + + if (filesel->next_history) + { + list = filesel->next_history; + while (list) + { + g_free (list->data); + list = list->next; + } + } + g_list_free (filesel->next_history); + filesel->next_history = NULL; + + if (filesel->prev_history) + { + list = filesel->prev_history; + while (list) + { + g_free (list->data); + list = list->next; + } + } + g_list_free (filesel->prev_history); + filesel->prev_history = NULL; + + if (filesel->mask) + { + g_free (filesel->mask); + filesel->mask = NULL; + } + + cmpl_free_state (filesel->cmpl_state); + filesel->cmpl_state = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/* Begin file operations callbacks */ + +static void +gtk_file_selection_fileop_error (GtkFileSelection *fs, gchar *error_message) +{ + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dialog; + + g_return_if_fail (error_message != NULL); + + /* main dialog */ + dialog = gtk_dialog_new (); + /* + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + */ + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, make this dialog modal too */ + /* When error dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + label = gtk_label_new(error_message); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + /* yes, we free it */ + g_free (error_message); + + /* close button */ + button = gtk_button_new_with_label (_("Close")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static void +gtk_file_selection_fileop_destroy (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + fs->fileop_dialog = NULL; +} + + +static void +gtk_file_selection_create_dir_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + gchar *dirname; + gchar *path; + gchar *full_path; + gchar *buf; + CompletionState *cmpl_state; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + dirname = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + full_path = g_strconcat (path, "/", dirname, NULL); + if ( (mkdir (full_path, 0755) < 0) ) + { + buf = g_strconcat ("Error creating directory \"", dirname, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (full_path); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_create_dir (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *button; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Create Directory")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + label = gtk_label_new(_("Directory name:")); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + /* The directory entry widget */ + fs->fileop_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, + TRUE, TRUE, 5); + GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT); + gtk_widget_show (fs->fileop_entry); + + /* buttons */ + button = gtk_button_new_with_label (_("Create")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static void +gtk_file_selection_delete_file_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + CompletionState *cmpl_state; + gchar *path; + gchar *full_path; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + full_path = g_strconcat (path, "/", fs->fileop_file, NULL); + if ( (unlink (full_path) < 0) ) + { + buf = g_strconcat ("Error deleting file \"", fs->fileop_file, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (full_path); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dialog; + gchar *filename; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + filename = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + if (strlen(filename) < 1) + return; + + fs->fileop_file = filename; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Delete File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + buf = g_strconcat ("Really delete file \"", filename, "\" ?", NULL); + label = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + g_free(buf); + + /* buttons */ + button = gtk_button_new_with_label (_("Delete")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); + +} + +static void +gtk_file_selection_rename_file_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + gchar *buf; + gchar *file; + gchar *path; + gchar *new_filename; + gchar *old_filename; + CompletionState *cmpl_state; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + new_filename = g_strconcat (path, "/", file, NULL); + old_filename = g_strconcat (path, "/", fs->fileop_file, NULL); + + if ( (rename (old_filename, new_filename)) < 0) + { + buf = g_strconcat ("Error renaming file \"", file, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (new_filename); + g_free (old_filename); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *button; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + if (strlen(fs->fileop_file) < 1) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Rename File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + buf = g_strconcat ("Rename file \"", fs->fileop_file, "\" to:", NULL); + label = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + g_free(buf); + + /* New filename entry */ + fs->fileop_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, + TRUE, TRUE, 5); + GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT); + gtk_widget_show (fs->fileop_entry); + + gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file); + gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry), + 0, strlen (fs->fileop_file)); + + /* buttons */ + button = gtk_button_new_with_label (_("Rename")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + + +static gint +gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + GtkFileSelection *fs; + char *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + + if (event->keyval == GDK_Tab) + { + text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + + text = g_strdup (text); + + gtk_file_selection_populate (fs, text, TRUE); + + g_free (text); + + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + + return TRUE; + } + if (fs->saved_entry) + { + gtk_clist_unselect_all ((GtkCList *) (fs->dir_list)); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + + + return FALSE; +} + +static void +gtk_file_selection_home_button (GtkWidget *widget, gpointer data){ + GList *list; + + GtkFileSelection *fs=data; + + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs,"~/",FALSE); +} + +static void +gtk_file_selection_up_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs, "../", FALSE); /*change directories. */ + +} + +static void +gtk_file_selection_prev_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + GList *first; + gchar *path; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->prev_history; + + if (list && g_list_length(list) > 1) + { + first = list; /* get first element */ + list = list->next; /* pop off current directory */ + + list->prev = NULL; /* make this the new head. */ + + fs->prev_history = list; /* update prev_history list */ + fs->next_history = g_list_prepend(fs->next_history,first->data); /* put it on next_history */ + + first->next = NULL; /* orphan the old first node */ + g_list_free (first); /* free the node (data is now in use by next_history) */ + + + + path = g_malloc(strlen(list->data)+4); /* plenty of space */ + strcpy(path,list->data); /* get the 2nd path in the history */ + strcat(path,"/"); /* append a '/' */ + gtk_file_selection_populate (fs, path, FALSE); /* change directories. */ + g_free (path); + } +} + +static void +gtk_file_selection_next_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + GList *first; + gchar *path; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->next_history; + + if (list && g_list_length(list) > 0) + { + first = list; /*get first element*/ + list = list->next; /*pop off current directory*/ + + if (list) + list->prev = NULL; + + fs->next_history = list; /*update prev_history list*/ + + path = g_malloc(strlen(first->data)+4); /*plenty of space*/ + strcpy(path,first->data); + strcat(path,"/"); /*append a / */ + gtk_file_selection_populate (fs, path, FALSE); /*change directories.*/ + g_free(path); + + first->next = NULL; /* orphan the old first node */ + g_list_free (first); /* free the node (data is now in use by next_history) */ + + } +} + +void static +gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_file_selection_populate (fs,"",FALSE); +} + +static void +gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + + if(fs->mask) + g_free (fs->mask); + + fs->mask = g_strdup(gtk_entry_get_text (GTK_ENTRY(fs->mask_entry))); + + if (strlen(fs->mask) == 0) + { + g_free (fs->mask); + fs->mask = NULL; + } + + gtk_file_selection_refresh_button (widget,data); +} + +static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + /* + g_print("Key pressed! \n"); + */ + + return TRUE; +} + +static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist, + GdkEventButton *event, + gpointer user_data) +{ + + GtkFileSelection *fs = user_data; + GList *list; + gchar *path; + + list = fs->next_history; + if(list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + path = g_malloc(strlen(gtk_entry_get_text(GTK_ENTRY (((GtkCombo *)fs->history_combo)->entry)))+4); + strcpy (path,gtk_entry_get_text(GTK_ENTRY( ((GtkCombo *)fs->history_combo)->entry))); + strcat (path,"/"); + + gtk_file_selection_populate (fs,path,TRUE); + + g_free (path); + + return TRUE; +} + +static gboolean +gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + GtkEntry *entry=(GtkEntry *)widget; + GtkFileSelection *fs=data; + GList *list; + gchar *path; + + g_return_val_if_fail (fs != NULL,FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs),FALSE); + + + if (event->keyval == GDK_Return) + { + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + path = g_malloc(strlen(gtk_entry_get_text(entry))+4); + strcpy (path,gtk_entry_get_text(entry)); + strcat (path,"/"); + gtk_file_selection_populate (fs,path,TRUE); + g_free (path); + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + return TRUE; + } + else + { + return FALSE; + } + +} + +static void +gtk_file_selection_update_history_menu (GtkFileSelection *fs, + gchar *current_directory) +{ + gchar *current_dir; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + g_return_if_fail (current_directory != NULL); + + current_dir = g_strdup (current_directory); + + if(fs->prev_history) + { + if (strcmp((fs->prev_history)->data,current_dir)) + { /*if this item isn't on the top of the list */ + fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir)); + } + } else { + fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir)); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (fs->history_combo),fs->prev_history); + + g_free (current_dir); +} + +static void +gtk_file_selection_file_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = user_data; + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->file_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + break; + + default: + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } +} + +static void +gtk_file_selection_dir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GList *list; + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = GTK_FILE_SELECTION (user_data); + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs, filename, FALSE); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + break; + + default: + /* here we need to add the "filename" to the beginning of what's already + in the entry. Save what's in the entry, then restore it on the double click + */ + if (fs->saved_entry) g_free (fs->saved_entry); + fs->saved_entry=g_strdup(gtk_entry_get_text(GTK_ENTRY (fs->selection_entry))); + + temp=g_strconcat(filename,fs->saved_entry,NULL); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), temp); + g_free (temp); + + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } +} + +static void +gtk_file_selection_undir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = GTK_FILE_SELECTION (user_data); + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + default: + /* here we need to add the "filename" to the beginning of what's already + in the entry. Save what's in the entry, then restore it on the double click + */ + if (fs->saved_entry) + { + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); //????? + + g_free (filename); + } +} + +static void +gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete) +{ + CompletionState *cmpl_state; + PossibleCompletion* poss; + gchar* filename; + gint row; + gchar* rem_path = rel_path; + gchar* sel_text; + gchar* text[2]; + gint did_recurse = FALSE; + gint possible_count = 0; + gint selection_index = -1; + gint file_list_width; + gint dir_list_width; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + cmpl_state = (CompletionState*) fs->cmpl_state; + poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state); + + if (!cmpl_state_okay (cmpl_state)) + { + /* Something went wrong. */ + gtk_file_selection_abort (fs); + return; + } + + g_assert (cmpl_state->reference_dir); + + gtk_clist_freeze (GTK_CLIST (fs->dir_list)); + gtk_clist_clear (GTK_CLIST (fs->dir_list)); + gtk_clist_freeze (GTK_CLIST (fs->file_list)); + gtk_clist_clear (GTK_CLIST (fs->file_list)); + + /* Set the dir_list to include ./ and ../ */ + text[1] = NULL; + text[0] = "./"; + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + + text[0] = "../"; + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + + /*reset the max widths of the lists*/ + dir_list_width = gdk_string_width(fs->dir_list->style->font,"../"); + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0,dir_list_width); + file_list_width = 1; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,file_list_width); + + while (poss) + { + if (cmpl_is_a_completion (poss)) + { + possible_count += 1; + + filename = cmpl_this_completion (poss); + + text[0] = filename; + + if (cmpl_is_directory (poss)) + { + if (strcmp (filename, "./") != 0 && + strcmp (filename, "../") != 0) + { + int width = gdk_string_width(fs->dir_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + if(width > dir_list_width) + { + dir_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0, + width); + } + } + } + else + { + if(fs->mask) + { + if (gtk_file_selection_match_mask(filename,fs->mask)) + { + int width = gdk_string_width(fs->file_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->file_list), text); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } + } + } + else + { + int width = gdk_string_width(fs->file_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->file_list), text); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } + } + } + } + + poss = cmpl_next_completion (cmpl_state); + } + + gtk_clist_thaw (GTK_CLIST (fs->dir_list)); + gtk_clist_thaw (GTK_CLIST (fs->file_list)); + + /* File lists are set. */ + + g_assert (cmpl_state->reference_dir); + + if (try_complete) + { + + /* User is trying to complete filenames, so advance the user's input + * string to the updated_text, which is the common leading substring + * of all possible completions, and if its a directory attempt + * attempt completions in it. */ + + if (cmpl_updated_text (cmpl_state)[0]) + { + + if (cmpl_updated_dir (cmpl_state)) + { + gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state)); + + did_recurse = TRUE; + + gtk_file_selection_populate (fs, dir_name, TRUE); + + g_free (dir_name); + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), + cmpl_updated_text (cmpl_state)); + } + } + else + { + selection_index = cmpl_last_valid_char (cmpl_state) - + (strlen (rel_path) - strlen (rem_path)); + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path); + } + } + else + { + if (fs->selection_entry) + /* Here we need to take the old filename and keep it!*/ + /*gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");*/ + ; + } + + if (!did_recurse) + { + if (fs->selection_entry) + gtk_entry_set_position (GTK_ENTRY (fs->selection_entry), selection_index); + + if (fs->selection_entry) + { + sel_text = g_strconcat (_("Selection: "), + cmpl_reference_position (cmpl_state), + NULL); + + gtk_label_set_text (GTK_LABEL (fs->selection_text), sel_text); + g_free (sel_text); + } + + gtk_file_selection_update_history_menu (fs, cmpl_reference_position (cmpl_state)); + + } +} + +static void +gtk_file_selection_abort (GtkFileSelection *fs) +{ + gchar err_buf[256]; + + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); + + /* BEEP gdk_beep(); */ + + if (fs->selection_entry) + gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf); +} + +/**********************************************************************/ +/* External Interface */ +/**********************************************************************/ + +/* The four completion state selectors + */ +static gchar* +cmpl_updated_text (CompletionState* cmpl_state) +{ + return cmpl_state->updated_text; +} + +static gint +cmpl_updated_dir (CompletionState* cmpl_state) +{ + return cmpl_state->re_complete; +} + +static gchar* +cmpl_reference_position (CompletionState* cmpl_state) +{ + return cmpl_state->reference_dir->fullname; +} + +static gint +cmpl_last_valid_char (CompletionState* cmpl_state) +{ + return cmpl_state->last_valid_char; +} + +static gchar* +cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) +{ + static char nothing[2] = ""; + + if (!cmpl_state_okay (cmpl_state)) + { + return nothing; + } + else if (text[0] == '/') + { + strcpy (cmpl_state->updated_text, text); + } + else if (text[0] == '~') + { + CompletionDir* dir; + char* slash; + + dir = open_user_dir (text, cmpl_state); + + if (!dir) + { + /* spencer says just return ~something, so + * for now just do it. */ + strcpy (cmpl_state->updated_text, text); + } + else + { + + strcpy (cmpl_state->updated_text, dir->fullname); + + slash = strchr (text, '/'); + + if (slash) + strcat (cmpl_state->updated_text, slash); + } + } + else + { + strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); + if (strcmp (cmpl_state->reference_dir->fullname, "/") != 0) + strcat (cmpl_state->updated_text, "/"); + strcat (cmpl_state->updated_text, text); + } + + return cmpl_state->updated_text; +} + +/* The three completion selectors + */ +static gchar* +cmpl_this_completion (PossibleCompletion* pc) +{ + return pc->text; +} + +static gint +cmpl_is_directory (PossibleCompletion* pc) +{ + return pc->is_directory; +} + +static gint +cmpl_is_a_completion (PossibleCompletion* pc) +{ + return pc->is_a_completion; +} + +/**********************************************************************/ +/* Construction, deletion */ +/**********************************************************************/ + +static CompletionState* +cmpl_init_state (void) +{ + gchar getcwd_buf[2*MAXPATHLEN]; + CompletionState *new_state; + + new_state = g_new (CompletionState, 1); + + /* We don't use getcwd() on SUNOS, because, it does a popen("pwd") + * and, if that wasn't bad enough, hangs in doing so. + */ +#if defined(sun) && !defined(__SVR4) + if (!getwd (getcwd_buf)) +#else + if (!getcwd (getcwd_buf, MAXPATHLEN)) +#endif + { + /* Oh joy, we can't get the current directory. Um..., we should have + * a root directory, right? Right? (Probably not portable to non-Unix) + */ + strcpy (getcwd_buf, "/"); + } + +tryagain: + + new_state->reference_dir = NULL; + new_state->completion_dir = NULL; + new_state->active_completion_dir = NULL; + new_state->directory_storage = NULL; + new_state->directory_sent_storage = NULL; + new_state->last_valid_char = 0; + new_state->updated_text = g_new (gchar, MAXPATHLEN); + new_state->updated_text_alloc = MAXPATHLEN; + new_state->the_completion.text = g_new (gchar, MAXPATHLEN); + new_state->the_completion.text_alloc = MAXPATHLEN; + new_state->user_dir_name_buffer = NULL; + new_state->user_directories = NULL; + + new_state->reference_dir = open_dir (getcwd_buf, new_state); + + if (!new_state->reference_dir) + { + /* Directories changing from underneath us, grumble */ + strcpy (getcwd_buf, "/"); + goto tryagain; + } + + return new_state; +} + +static void +cmpl_free_dir_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_dir_sent_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir_sent (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_state (CompletionState* cmpl_state) +{ + cmpl_free_dir_list (cmpl_state->directory_storage); + cmpl_free_dir_sent_list (cmpl_state->directory_sent_storage); + + if (cmpl_state->user_dir_name_buffer) + g_free (cmpl_state->user_dir_name_buffer); + if (cmpl_state->user_directories) + g_free (cmpl_state->user_directories); + if (cmpl_state->the_completion.text) + g_free (cmpl_state->the_completion.text); + if (cmpl_state->updated_text) + g_free (cmpl_state->updated_text); + + g_free (cmpl_state); +} + +static void +free_dir(CompletionDir* dir) +{ + g_free(dir->fullname); + g_free(dir); +} + +static void +free_dir_sent(CompletionDirSent* sent) +{ + g_free(sent->name_buffer); + g_free(sent->entries); + g_free(sent); +} + +static void +prune_memory_usage(CompletionState *cmpl_state) +{ + GList* cdsl = cmpl_state->directory_sent_storage; + GList* cdl = cmpl_state->directory_storage; + GList* cdl0 = cdl; + gint len = 0; + + for(; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1) + cdsl = cdsl->next; + + if (cdsl) { + cmpl_free_dir_sent_list(cdsl->next); + cdsl->next = NULL; + } + + cmpl_state->directory_storage = NULL; + while (cdl) { + if (cdl->data == cmpl_state->reference_dir) + cmpl_state->directory_storage = g_list_prepend(NULL, cdl->data); + else + free_dir (cdl->data); + cdl = cdl->next; + } + + g_list_free(cdl0); +} + +/**********************************************************************/ +/* The main entrances. */ +/**********************************************************************/ + +static PossibleCompletion* +cmpl_completion_matches (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + PossibleCompletion *poss; + + prune_memory_usage(cmpl_state); + + g_assert (text_to_complete != NULL); + + cmpl_state->user_completion_index = -1; + cmpl_state->last_completion_text = text_to_complete; + cmpl_state->the_completion.text[0] = 0; + cmpl_state->last_valid_char = 0; + cmpl_state->updated_text_len = -1; + cmpl_state->updated_text[0] = 0; + cmpl_state->re_complete = FALSE; + + first_slash = strchr (text_to_complete, '/'); + + if (text_to_complete[0] == '~' && !first_slash) + { + /* Text starts with ~ and there is no slash, show all the + * home directory completions. + */ + poss = attempt_homedir_completion (text_to_complete, cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; + } + + cmpl_state->reference_dir = + open_ref_dir (text_to_complete, remaining_text, cmpl_state); + + if(!cmpl_state->reference_dir) + return NULL; + + cmpl_state->completion_dir = + find_completion_dir (*remaining_text, remaining_text, cmpl_state); + + cmpl_state->last_valid_char = *remaining_text - text_to_complete; + + if(!cmpl_state->completion_dir) + return NULL; + + cmpl_state->completion_dir->cmpl_index = -1; + cmpl_state->completion_dir->cmpl_parent = NULL; + cmpl_state->completion_dir->cmpl_text = *remaining_text; + + cmpl_state->active_completion_dir = cmpl_state->completion_dir; + + cmpl_state->reference_dir = cmpl_state->completion_dir; + + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +static PossibleCompletion* +cmpl_next_completion (CompletionState* cmpl_state) +{ + PossibleCompletion* poss = NULL; + + cmpl_state->the_completion.text[0] = 0; + + if(cmpl_state->user_completion_index >= 0) + poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state); + else + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +/**********************************************************************/ +/* Directory Operations */ +/**********************************************************************/ + +/* Open the directory where completion will begin from, if possible. */ +static CompletionDir* +open_ref_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + CompletionDir *new_dir; + + first_slash = strchr(text_to_complete, '/'); + + if (text_to_complete[0] == '~') + { + new_dir = open_user_dir(text_to_complete, cmpl_state); + + if(new_dir) + { + if(first_slash) + *remaining_text = first_slash + 1; + else + *remaining_text = text_to_complete + strlen(text_to_complete); + } + else + { + return NULL; + } + } + else if (text_to_complete[0] == '/' || !cmpl_state->reference_dir) + { + gchar *tmp = g_strdup(text_to_complete); + gchar *p; + + p = tmp; + while (*p && *p != '*' && *p != '?') + p++; + + *p = '\0'; + p = strrchr(tmp, '/'); + if (p) + { + if (p == tmp) + p++; + + *p = '\0'; + + new_dir = open_dir(tmp, cmpl_state); + + if(new_dir) + *remaining_text = text_to_complete + + ((p == tmp + 1) ? (p - tmp) : (p + 1 - tmp)); + } + else + { + /* If no possible candidates, use the cwd */ + gchar *curdir = g_get_current_dir (); + + new_dir = open_dir(curdir, cmpl_state); + + if (new_dir) + *remaining_text = text_to_complete; + + g_free (curdir); + } + + g_free (tmp); + } + else + { + *remaining_text = text_to_complete; + + new_dir = open_dir(cmpl_state->reference_dir->fullname, cmpl_state); + } + + if(new_dir) + { + new_dir->cmpl_index = -1; + new_dir->cmpl_parent = NULL; + } + + return new_dir; +} + +/* open a directory by user name */ +static CompletionDir* +open_user_dir(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gchar *first_slash; + gint cmp_len; + + g_assert(text_to_complete && text_to_complete[0] == '~'); + + first_slash = strchr(text_to_complete, '/'); + + if (first_slash) + cmp_len = first_slash - text_to_complete - 1; + else + cmp_len = strlen(text_to_complete + 1); + + if(!cmp_len) + { + /* ~/ */ + gchar *homedir = g_get_home_dir (); + + if (homedir) + return open_dir(homedir, cmpl_state); + else + return NULL; + } + else + { + /* ~user/ */ + char* copy = g_new(char, cmp_len + 1); + struct passwd *pwd; + strncpy(copy, text_to_complete + 1, cmp_len); + copy[cmp_len] = 0; + pwd = getpwnam(copy); + g_free(copy); + if (!pwd) + { + cmpl_errno = errno; + return NULL; + } + + return open_dir(pwd->pw_dir, cmpl_state); + } +} + +/* open a directory relative the the current relative directory */ +static CompletionDir* +open_relative_dir(gchar* dir_name, + CompletionDir* dir, + CompletionState *cmpl_state) +{ + gchar path_buf[2*MAXPATHLEN]; + + if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir->fullname); + + if(dir->fullname_len > 1) + { + path_buf[dir->fullname_len] = '/'; + strcpy(path_buf + dir->fullname_len + 1, dir_name); + } + else + { + strcpy(path_buf + dir->fullname_len, dir_name); + } + + return open_dir(path_buf, cmpl_state); +} + +/* after the cache lookup fails, really open a new directory */ +static CompletionDirSent* +open_new_dir(gchar* dir_name, struct stat* sbuf, gboolean stat_subdirs) +{ + CompletionDirSent* sent; + DIR* directory; + gchar *buffer_ptr; + struct dirent *dirent_ptr; + gint buffer_size = 0; + gint entry_count = 0; + gint i; + struct stat ent_sbuf; + char path_buf[MAXPATHLEN*2]; + gint path_buf_len; + + sent = g_new(CompletionDirSent, 1); + sent->mtime = sbuf->st_mtime; + sent->inode = sbuf->st_ino; + sent->device = sbuf->st_dev; + + path_buf_len = strlen(dir_name); + + if (path_buf_len > MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir_name); + + directory = opendir(dir_name); + + if(!directory) + { + cmpl_errno = errno; + return NULL; + } + + while((dirent_ptr = readdir(directory)) != NULL) + { + int entry_len = strlen(dirent_ptr->d_name); + buffer_size += entry_len + 1; + entry_count += 1; + + if(path_buf_len + entry_len + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + closedir(directory); + return NULL; + } + } + + sent->name_buffer = g_new(gchar, buffer_size); + sent->entries = g_new(CompletionDirEntry, entry_count); + sent->entry_count = entry_count; + + buffer_ptr = sent->name_buffer; + + rewinddir(directory); + + for(i = 0; i < entry_count; i += 1) + { + dirent_ptr = readdir(directory); + + if(!dirent_ptr) + { + cmpl_errno = errno; + closedir(directory); + return NULL; + } + + strcpy(buffer_ptr, dirent_ptr->d_name); + sent->entries[i].entry_name = buffer_ptr; + buffer_ptr += strlen(dirent_ptr->d_name); + *buffer_ptr = 0; + buffer_ptr += 1; + + path_buf[path_buf_len] = '/'; + strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); + + if (stat_subdirs) + { + if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) + sent->entries[i].is_dir = 1; + else + /* stat may fail, and we don't mind, since it could be a + * dangling symlink. */ + sent->entries[i].is_dir = 0; + } + else + sent->entries[i].is_dir = 1; + } + + qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); + + closedir(directory); + + return sent; +} + +static gboolean +check_dir(gchar *dir_name, struct stat *result, gboolean *stat_subdirs) +{ + /* A list of directories that we know only contain other directories. + * Trying to stat every file in these directories would be very + * expensive. + */ + + static struct { + gchar *name; + gboolean present; + struct stat statbuf; + } no_stat_dirs[] = { + { "/afs", FALSE, { 0 } }, + { "/net", FALSE, { 0 } } + }; + + static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]); + static gboolean initialized = FALSE; + + gint i; + + if (!initialized) + { + initialized = TRUE; + for (i = 0; i < n_no_stat_dirs; i++) + { + if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0) + no_stat_dirs[i].present = TRUE; + } + } + + if(stat(dir_name, result) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + *stat_subdirs = TRUE; + for (i=0; ist_dev) && + (no_stat_dirs[i].statbuf.st_ino == result->st_ino)) + { + *stat_subdirs = FALSE; + break; + } + } + + return TRUE; +} + +/* open a directory by absolute pathname */ +static CompletionDir* +open_dir(gchar* dir_name, CompletionState* cmpl_state) +{ + struct stat sbuf; + gboolean stat_subdirs; + CompletionDirSent *sent; + GList* cdsl; + + if (!check_dir (dir_name, &sbuf, &stat_subdirs)) + return NULL; + + cdsl = cmpl_state->directory_sent_storage; + + while (cdsl) + { + sent = cdsl->data; + + if(sent->inode == sbuf.st_ino && + sent->mtime == sbuf.st_mtime && + sent->device == sbuf.st_dev) + return attach_dir(sent, dir_name, cmpl_state); + + cdsl = cdsl->next; + } + + sent = open_new_dir(dir_name, &sbuf, stat_subdirs); + + if (sent) { + cmpl_state->directory_sent_storage = + g_list_prepend(cmpl_state->directory_sent_storage, sent); + + return attach_dir(sent, dir_name, cmpl_state); + } + + return NULL; +} + +static CompletionDir* +attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state) +{ + CompletionDir* new_dir; + + new_dir = g_new(CompletionDir, 1); + + cmpl_state->directory_storage = + g_list_prepend(cmpl_state->directory_storage, new_dir); + + new_dir->sent = sent; + new_dir->fullname = g_strdup(dir_name); + new_dir->fullname_len = strlen(dir_name); + + return new_dir; +} + +static gint +correct_dir_fullname(CompletionDir* cmpl_dir) +{ + gint length = strlen(cmpl_dir->fullname); + struct stat sbuf; + + if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) + { + if (length == 2) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } else { + cmpl_dir->fullname[length - 2] = 0; + } + } + else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) + cmpl_dir->fullname[length - 2] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) + { + if(length == 3) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 2] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) + { + if(length == 4) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 3] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + + cmpl_dir->fullname_len = strlen(cmpl_dir->fullname); + + return TRUE; +} + +static gint +correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) +{ + struct stat parbuf; + gchar *last_slash; + gchar *new_name; + gchar c = 0; + + last_slash = strrchr(cmpl_dir->fullname, '/'); + + g_assert(last_slash); + + if(last_slash != cmpl_dir->fullname) + { /* last_slash[0] = 0; */ } + else + { + c = last_slash[1]; + last_slash[1] = 0; + } + + if (stat(cmpl_dir->fullname, &parbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) + /* it wasn't a link */ + return TRUE; + + if(c) + last_slash[1] = c; + /* else + last_slash[0] = '/'; */ + + /* it was a link, have to figure it out the hard way */ + + new_name = find_parent_dir_fullname(cmpl_dir->fullname); + + if (!new_name) + return FALSE; + + g_free(cmpl_dir->fullname); + + cmpl_dir->fullname = new_name; + + return TRUE; +} + +static gchar* +find_parent_dir_fullname(gchar* dirname) +{ + gchar buffer[MAXPATHLEN]; + gchar buffer2[MAXPATHLEN]; + +#if defined(sun) && !defined(__SVR4) + if(!getwd(buffer)) +#else + if(!getcwd(buffer, MAXPATHLEN)) +#endif + { + cmpl_errno = errno; + return NULL; + } + + if(chdir(dirname) != 0 || chdir("..") != 0) + { + cmpl_errno = errno; + return NULL; + } + +#if defined(sun) && !defined(__SVR4) + if(!getwd(buffer2)) +#else + if(!getcwd(buffer2, MAXPATHLEN)) +#endif + { + chdir(buffer); + cmpl_errno = errno; + + return NULL; + } + + if(chdir(buffer) != 0) + { + cmpl_errno = errno; + return NULL; + } + + return g_strdup(buffer2); +} + +/**********************************************************************/ +/* Completion Operations */ +/**********************************************************************/ + +static PossibleCompletion* +attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gint index, length; + + if (!cmpl_state->user_dir_name_buffer && + !get_pwdb(cmpl_state)) + return NULL; + length = strlen(text_to_complete) - 1; + + cmpl_state->user_completion_index += 1; + + while(cmpl_state->user_completion_index < cmpl_state->user_directories_len) + { + index = first_diff_index(text_to_complete + 1, + cmpl_state->user_directories + [cmpl_state->user_completion_index].login); + + switch(index) + { + case PATTERN_MATCH: + break; + default: + if(cmpl_state->last_valid_char < (index + 1)) + cmpl_state->last_valid_char = index + 1; + cmpl_state->user_completion_index += 1; + continue; + } + + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + append_completion_text("~", cmpl_state); + + append_completion_text(cmpl_state-> + user_directories[cmpl_state->user_completion_index].login, + cmpl_state); + + return append_completion_text("/", cmpl_state); + } + + if(text_to_complete[1] || + cmpl_state->user_completion_index > cmpl_state->user_directories_len) + { + cmpl_state->user_completion_index = -1; + return NULL; + } + else + { + cmpl_state->user_completion_index += 1; + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + return append_completion_text("~/", cmpl_state); + } +} + +/* returns the index (>= 0) of the first differing character, + * PATTERN_MATCH if the completion matches */ +static gint +first_diff_index(gchar* pat, gchar* text) +{ + gint diff = 0; + + while(*pat && *text && *text == *pat) + { + pat += 1; + text += 1; + diff += 1; + } + + if(*pat) + return diff; + + return PATTERN_MATCH; +} + +static PossibleCompletion* +append_completion_text(gchar* text, CompletionState* cmpl_state) +{ + gint len, i = 1; + + if(!cmpl_state->the_completion.text) + return NULL; + + len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1; + + if(cmpl_state->the_completion.text_alloc > len) + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } + + while(i < len) { i <<= 1; } + + cmpl_state->the_completion.text_alloc = i; + + cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i); + + if(!cmpl_state->the_completion.text) + return NULL; + else + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } +} + +static CompletionDir* +find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash = strchr(text_to_complete, '/'); + CompletionDir* dir = cmpl_state->reference_dir; + CompletionDir* next; + *remaining_text = text_to_complete; + + while(first_slash) + { + gint len = first_slash - *remaining_text; + gint found = 0; + gchar *found_name = NULL; /* Quiet gcc */ + gint i; + gchar* pat_buf = g_new (gchar, len + 1); + + strncpy(pat_buf, *remaining_text, len); + pat_buf[len] = 0; + + for(i = 0; i < dir->sent->entry_count; i += 1) + { + if(dir->sent->entries[i].is_dir && + fnmatch(pat_buf, dir->sent->entries[i].entry_name, + FNMATCH_FLAGS)!= FNM_NOMATCH) + { + if(found) + { + g_free (pat_buf); + return dir; + } + else + { + found = 1; + found_name = dir->sent->entries[i].entry_name; + } + } + } + + if (!found) + { + /* Perhaps we are trying to open an automount directory */ + found_name = pat_buf; + } + + next = open_relative_dir(found_name, dir, cmpl_state); + + if(!next) + { + g_free (pat_buf); + return NULL; + } + + next->cmpl_parent = dir; + + dir = next; + + if(!correct_dir_fullname(dir)) + { + g_free(pat_buf); + return NULL; + } + + *remaining_text = first_slash + 1; + first_slash = strchr(*remaining_text, '/'); + + g_free (pat_buf); + } + + return dir; +} + +static void +update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state) +{ + gint cmpl_len; + + if(!poss || !cmpl_is_a_completion(poss)) + return; + + cmpl_len = strlen(cmpl_this_completion(poss)); + + if(cmpl_state->updated_text_alloc < cmpl_len + 1) + { + cmpl_state->updated_text = + (gchar*)g_realloc(cmpl_state->updated_text, + cmpl_state->updated_text_alloc); + cmpl_state->updated_text_alloc = 2*cmpl_len; + } + + if(cmpl_state->updated_text_len < 0) + { + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + cmpl_state->updated_text_len = cmpl_len; + cmpl_state->re_complete = cmpl_is_directory(poss); + } + else if(cmpl_state->updated_text_len == 0) + { + cmpl_state->re_complete = FALSE; + } + else + { + gint first_diff = + first_diff_index(cmpl_state->updated_text, + cmpl_this_completion(poss)); + + cmpl_state->re_complete = FALSE; + + if(first_diff == PATTERN_MATCH) + return; + + if(first_diff > cmpl_state->updated_text_len) + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + + cmpl_state->updated_text_len = first_diff; + cmpl_state->updated_text[first_diff] = 0; + } +} + +static PossibleCompletion* +attempt_file_completion(CompletionState *cmpl_state) +{ + gchar *pat_buf, *first_slash; + CompletionDir *dir = cmpl_state->active_completion_dir; + + dir->cmpl_index += 1; + + if(dir->cmpl_index == dir->sent->entry_count) + { + if(dir->cmpl_parent == NULL) + { + cmpl_state->active_completion_dir = NULL; + + return NULL; + } + else + { + cmpl_state->active_completion_dir = dir->cmpl_parent; + + return attempt_file_completion(cmpl_state); + } + } + + g_assert(dir->cmpl_text); + + first_slash = strchr(dir->cmpl_text, '/'); + + if(first_slash) + { + gint len = first_slash - dir->cmpl_text; + + pat_buf = g_new (gchar, len + 1); + strncpy(pat_buf, dir->cmpl_text, len); + pat_buf[len] = 0; + } + else + { + gint len = strlen(dir->cmpl_text); + + pat_buf = g_new (gchar, len + 2); + strcpy(pat_buf, dir->cmpl_text); + strcpy(pat_buf + len, "*"); + } + + if(first_slash) + { + if(dir->sent->entries[dir->cmpl_index].is_dir) + { + if(fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH) + { + CompletionDir* new_dir; + + new_dir = open_relative_dir(dir->sent->entries[dir->cmpl_index].entry_name, + dir, cmpl_state); + + if(!new_dir) + { + g_free (pat_buf); + return NULL; + } + + new_dir->cmpl_parent = dir; + + new_dir->cmpl_index = -1; + new_dir->cmpl_text = first_slash + 1; + + cmpl_state->active_completion_dir = new_dir; + + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + if(dir->cmpl_parent != NULL) + { + append_completion_text(dir->fullname + + strlen(cmpl_state->completion_dir->fullname) + 1, + cmpl_state); + append_completion_text("/", cmpl_state); + } + + append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); + + cmpl_state->the_completion.is_a_completion = + (fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH); + + cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; + if(dir->sent->entries[dir->cmpl_index].is_dir) + append_completion_text("/", cmpl_state); + + g_free (pat_buf); + return &cmpl_state->the_completion; + } +} + + +static gint +get_pwdb(CompletionState* cmpl_state) +{ + struct passwd *pwd_ptr; + gchar* buf_ptr; + gint len = 0, i, count = 0; + + if(cmpl_state->user_dir_name_buffer) + return TRUE; + setpwent (); + + while ((pwd_ptr = getpwent()) != NULL) + { + len += strlen(pwd_ptr->pw_name); + len += strlen(pwd_ptr->pw_dir); + len += 2; + count += 1; + } + + setpwent (); + + cmpl_state->user_dir_name_buffer = g_new(gchar, len); + cmpl_state->user_directories = g_new(CompletionUserDir, count); + cmpl_state->user_directories_len = count; + + buf_ptr = cmpl_state->user_dir_name_buffer; + + for(i = 0; i < count; i += 1) + { + pwd_ptr = getpwent(); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + + strcpy(buf_ptr, pwd_ptr->pw_name); + cmpl_state->user_directories[i].login = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + strcpy(buf_ptr, pwd_ptr->pw_dir); + cmpl_state->user_directories[i].homedir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + qsort(cmpl_state->user_directories, + cmpl_state->user_directories_len, + sizeof(CompletionUserDir), + compare_user_dir); + + endpwent(); + + return TRUE; + +error: + + if(cmpl_state->user_dir_name_buffer) + g_free(cmpl_state->user_dir_name_buffer); + if(cmpl_state->user_directories) + g_free(cmpl_state->user_directories); + + cmpl_state->user_dir_name_buffer = NULL; + cmpl_state->user_directories = NULL; + + return FALSE; +} + +static gint +compare_user_dir(const void* a, const void* b) +{ + return strcmp((((CompletionUserDir*)a))->login, + (((CompletionUserDir*)b))->login); +} + +static gint +compare_cmpl_dir(const void* a, const void* b) +{ + return strcmp((((CompletionDirEntry*)a))->entry_name, + (((CompletionDirEntry*)b))->entry_name); +} + +static gint +cmpl_state_okay(CompletionState* cmpl_state) +{ + return cmpl_state && cmpl_state->reference_dir; +} + +static gchar* +cmpl_strerror(gint err) +{ + if(err == CMPL_ERRNO_TOO_LONG) + return "Name too long"; + else + return g_strerror (err); +} + + +/* Testing area */ +#ifdef TORRIE_DEBUG + +/* Get the selected filename and print it to the console */ +void file_ok_sel( GtkWidget *w, + GtkFileSelection *fs ) +{ + g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); +} + +void destroy( GtkWidget *widget, + gpointer data ) +{ + gtk_main_quit (); +} + +int main( int argc, + char *argv[] ) +{ + GtkWidget *filew; + + gtk_init (&argc, &argv); + + /* Create a new file selection widget */ + filew = gtk_file_selection_new ("Michael's Glorious File Selector"); +// gtk_file_selection_complete(GTK_FILE_SELECTION(filew),"bob"); + + + gtk_signal_connect (GTK_OBJECT (filew), "destroy", + (GtkSignalFunc) destroy, &filew); + /* Connect the ok_button to file_ok_sel function */ + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), + "clicked", (GtkSignalFunc) file_ok_sel, filew ); + + /* Connect the cancel_button to destroy the widget */ + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION + (filew)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (filew)); + + + gtk_widget_show(filew); + +/* + g_print("%d",gtk_file_selection_match_mask("mask.c","m*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.c","m???.c")); + g_print("%d",gtk_file_selection_match_mask("mask.c","m??*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c???")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c*")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","n*.c???")); + g_print("%d",gtk_file_selection_match_mask("mask.c","[mn]*")); + g_print("%d",gtk_file_selection_match_mask("COPYING","*.xpm")); +*/ + gtk_main (); + + return 0; +} + +/* example-end */ +#endif diff --git a/radiant/gtkfilesel-darwin.h b/radiant/gtkfilesel-darwin.h new file mode 100644 index 00000000..e264e1b2 --- /dev/null +++ b/radiant/gtkfilesel-darwin.h @@ -0,0 +1,129 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_FILESEL_H__ +#define __GTK_FILESEL_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TYPE_FILE_SELECTION (gtk_file_selection_get_type ()) +#define GTK_FILE_SELECTION(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_FILE_SELECTION, GtkFileSelection)) +#define GTK_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SELECTION, GtkFileSelectionClass)) +#define GTK_IS_FILE_SELECTION(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_FILE_SELECTION)) +#define GTK_IS_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SELECTION)) + + +typedef struct _GtkFileSelection GtkFileSelection; +typedef struct _GtkFileSelectionClass GtkFileSelectionClass; + +struct _GtkFileSelection +{ + GtkWindow window; + + GtkWidget *dir_list; + GtkWidget *file_list; + GtkWidget *selection_entry; + GtkWidget *selection_text; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *cancel_button; + GtkWidget *help_button; + + /* These are not used. Just fillers in the class structure */ + GtkWidget *history_pulldown; + GtkWidget *history_menu; + GList *history_list; + /* ***************** */ + + GtkWidget *fileop_dialog; + GtkWidget *fileop_entry; + gchar *fileop_file; + gpointer cmpl_state; + + GtkWidget *fileop_c_dir; + GtkWidget *fileop_del_file; + GtkWidget *fileop_ren_file; + + GtkWidget *button_area; + GtkWidget *action_area; + + GtkWidget *history_combo; + GList *prev_history; + GList *next_history; + GtkWidget *mask_entry; + gchar *mask; + gchar *saved_entry; + + GList *masks; + +}; + +struct _GtkFileSelectionClass +{ + GtkWindowClass parent_class; +}; + + +GtkType gtk_file_selection_get_type (void); +GtkWidget* gtk_file_selection_new (const gchar *title); +void gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename); +gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel); +void gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern); +void gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel); +void gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel); + +/* proposed interface */ +void gtk_file_selection_clear_masks (GtkFileSelection *filesel); +void gtk_file_selection_set_masks (GtkFileSelection *filesel, + const gchar **masks); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FILESEL_H__ */ + + + + + + + + + + diff --git a/radiant/gtkfilesel-linux.c b/radiant/gtkfilesel-linux.c new file mode 100644 index 00000000..58af1801 --- /dev/null +++ b/radiant/gtkfilesel-linux.c @@ -0,0 +1,4987 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +#define LEO + +#ifdef LEO +#define _(a) a + +static char * back_xpm[] = { +"14 14 33 1", +" c None", +". c #000000", +"+ c #C6D7C6", +"@ c #E7EBE7", +"# c #FFFFFF", +"$ c #DEEBDE", +"% c #F7F7F7", +"& c #DEE7DE", +"* c #EFF3EF", +"= c #101810", +"- c #B5C7AD", +"; c #EFEFEF", +"> c #D6E3D6", +", c #213021", +"' c #315931", +") c #52824A", +"! c #739A6B", +"~ c #84A673", +"{ c #7BA673", +"] c #84AA73", +"^ c #84AA7B", +"/ c #84AE7B", +"( c #63925A", +"_ c #526D4A", +": c #4A7D42", +"< c #739E6B", +"[ c #739A63", +"} c #4A7539", +"| c #638E52", +"1 c #427139", +"2 c #6BA663", +"3 c #5A8A52", +"4 c #315929", +" ..", +" ..+.", +" ..@#+.", +" ..$#%%+.", +" ..&#%*%%+.", +" .=&#******+.", +"..-#;>&@****+,", +"..')!~{]^/^/(.", +" .._:<^~^/^(.", +" ..':[]~/(.", +" ..}:[~|.", +" ..123.", +" ..4.", +" .."}; + +static char * up_xpm[] = { +"14 14 36 1", +" c None", +". c #000000", +"+ c #181C18", +"@ c #D6DBD6", +"# c #94AA8C", +"$ c #000400", +"% c #DEDFDE", +"& c #94AA84", +"* c #E7E3E7", +"= c #94B28C", +"- c #6B865A", +"; c #EFEBEF", +"> c #9CB694", +", c #8CA684", +"' c #EFEFEF", +") c #F7EFF7", +"! c #9CB68C", +"~ c #63865A", +"{ c #94B684", +"] c #94AE84", +"^ c #739263", +"/ c #F7F3F7", +"( c #94B284", +"_ c #849E73", +": c #8CAE7B", +"< c #8CAA84", +"[ c #7B966B", +"} c #8CA67B", +"| c #DEDBD6", +"1 c #E7E7E7", +"2 c #8CAE84", +"3 c #8CAA7B", +"4 c #738E63", +"5 c #BDBEB5", +"6 c #BDC3BD", +"7 c #637D52", +" .. ", +" .. ", +" +@#$ ", +" .%&. ", +" .**=-. ", +" .;;>,. ", +" .*')!&~. ", +" .;)){]^. ", +" .*')/(]_-. ", +" .;)//::<[. ", +" .*')//:::}-. ", +" .|1;;12]3}4. ", +".556666^^^^-7.", +".............."}; + +static char * forward_xpm[] = { +"14 14 36 1", +" c None", +". c #000000", +"+ c #E7EBDE", +"@ c #FFFFFF", +"# c #F7F7EF", +"$ c #D6E3D6", +"% c #F7F7F7", +"& c #EFF3EF", +"* c #CEDFCE", +"= c #CEDBC6", +"- c #E7EFE7", +"; c #181818", +"> c #292829", +", c #E7EBE7", +"' c #DEE7DE", +") c #B5C7AD", +"! c #9CBA94", +"~ c #8CAE84", +"{ c #84AA7B", +"] c #7BA673", +"^ c #84A67B", +"/ c #739A6B", +"( c #5A824A", +"_ c #395931", +": c #9CBA8C", +"< c #84AE7B", +"[ c #739E6B", +"} c #527D4A", +"| c #425942", +"1 c #84A673", +"2 c #4A7142", +"3 c #94B284", +"4 c #395D31", +"5 c #5A8652", +"6 c #315929", +"7 c #396531", +".. ", +".+.. ", +".@#$.. ", +".@%&#*.. ", +".@%%&&%=.. ", +".@&&&&&-#=;. ", +">@&&&&,'$'&)..", +".!~{~{{]^/(_..", +".:{<{^{[}|.. ", +".:<1{/}2.. ", +".31/}4.. ", +".{56.. ", +".7.. ", +".. "}; + +static char * refresh_xpm[] = { +"16 16 11 1", +" c None", +". c #000000", +"+ c #526942", +"@ c #4A6139", +"# c #526542", +"$ c #5A7142", +"% c #425531", +"& c #314529", +"* c #425131", +"= c #425931", +"- c #5A754A", +" . ", +" .. ", +" .+@... ", +" .#$##@%.. ", +" .+#...%%. ", +" . .. .&. ", +" . . .&. ", +" .. .. ", +" .. .. ", +" .*. . . ", +" .*. .. . ", +" .%@...#=. ", +" ..##-#@#. ", +" ...@%. ", +" .. ", +" . "}; + +#endif + +#ifndef LEO +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fnmatch.h" + +#if (defined TORRIE_DEBUG || defined LEO) +#include +#include +#include +#include "gtkfilesel-linux.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include "gdk/gdkkeysyms.h" +#include "gtkbutton.h" +#include "gtkentry.h" +#include "gtkfilesel.h" +#include "gtkhbox.h" +#include "gtkhbbox.h" +#include "gtklabel.h" +#include "gtklist.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtkscrolledwindow.h" +#include "gtksignal.h" +#include "gtkvbox.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtkoptionmenu.h" +#include "gtkclist.h" +#include "gtkdialog.h" +#include "gtkcombo.h" +#include "gtkframe.h" +#include "gtkhpaned.h" +#include "gtktable.h" +#include "gtkpixmap.h" +#include "gtknotebook.h" +#include "gtkhseparator.h" +#include "gtktogglebutton.h" +#endif + +#ifndef LEO +#include "gtkintl.h" + +#include "back.xpm" +#include "up.xpm" +#include "forward.xpm" +#include "refresh.xpm" +#endif + +#define DIR_LIST_WIDTH 180 +#define DIR_LIST_HEIGHT 180 +#define FILE_LIST_WIDTH 180 +#define FILE_LIST_HEIGHT 180 +#define BOOKMARK_FILE "/.gtkfilesel_bookmarks" +#define MASK_FILE "/.gtkfilesel_masks" +#define TIME_STRING_BUF 50 + +/* I've put this here so it doesn't get confused with the + * file completion interface */ +typedef struct _HistoryCallbackArg HistoryCallbackArg; + +struct _HistoryCallbackArg +{ + gchar *directory; + GtkWidget *menu_item; +}; + + +typedef struct _BookmarkMenuStruct BookmarkMenuStruct; +struct _BookmarkMenuStruct { + GtkWidget *menu_item; + gchar *desc; + gchar *path; +}; + +typedef struct _CompletionState CompletionState; +typedef struct _CompletionDir CompletionDir; +typedef struct _CompletionDirSent CompletionDirSent; +typedef struct _CompletionDirEntry CompletionDirEntry; +typedef struct _CompletionUserDir CompletionUserDir; +typedef struct _PossibleCompletion PossibleCompletion; + +/* Non-external file completion decls and structures */ + +/* A contant telling PRCS how many directories to cache. Its actually + * kept in a list, so the geometry isn't important. */ +#define CMPL_DIRECTORY_CACHE_SIZE 10 + +/* A constant used to determine whether a substring was an exact + * match by first_diff_index() + */ +#define PATTERN_MATCH -1 +/* The arguments used by all fnmatch() calls below + */ +#define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD) + +#define CMPL_ERRNO_TOO_LONG ((1<<16)-1) + +/* This structure contains all the useful information about a directory + * for the purposes of filename completion. These structures are cached + * in the CompletionState struct. CompletionDir's are reference counted. + */ +struct _CompletionDirSent +{ + ino_t inode; + time_t mtime; + dev_t device; + + gint entry_count; + gchar *name_buffer; /* memory segment containing names of all entries */ + + struct _CompletionDirEntry *entries; +}; + +struct _CompletionDir +{ + CompletionDirSent *sent; + + gchar *fullname; + gint fullname_len; + + struct _CompletionDir *cmpl_parent; + gint cmpl_index; + gchar *cmpl_text; +}; + +/* This structure contains pairs of directory entry names with a flag saying + * whether or not they are a valid directory. NOTE: This information is used + * to provide the caller with information about whether to update its completions + * or try to open a file. Since directories are cached by the directory mtime, + * a symlink which points to an invalid file (which will not be a directory), + * will not be reevaluated if that file is created, unless the containing + * directory is touched. I consider this case to be worth ignoring (josh). + */ +struct _CompletionDirEntry +{ + gint is_dir; + gchar *entry_name; +}; + +struct _CompletionUserDir +{ + gchar *login; + gchar *homedir; +}; + +struct _PossibleCompletion +{ + /* accessible fields, all are accessed externally by functions + * declared above + */ + gchar *text; + gint is_a_completion; + gint is_directory; + + gint file_size; + gint file_time; + gint uid; + gint gid; + /* Private fields + */ + gint text_alloc; +}; + +struct _CompletionState +{ + gint last_valid_char; + gchar *updated_text; + gint updated_text_len; + gint updated_text_alloc; + gint re_complete; + + gchar *user_dir_name_buffer; + gint user_directories_len; + + gchar *last_completion_text; + + gint user_completion_index; /* if >= 0, currently completing ~user */ + + struct _CompletionDir *completion_dir; /* directory completing from */ + struct _CompletionDir *active_completion_dir; + + struct _PossibleCompletion the_completion; + + struct _CompletionDir *reference_dir; /* initial directory */ + + GList* directory_storage; + GList* directory_sent_storage; + + struct _CompletionUserDir *user_directories; +}; + +/* Widgets from the Properties Dialog */ +typedef struct _PropertiesPrivate PropertiesPrivate; + +struct _PropertiesPrivate +{ + GtkWidget *mode_label; + GtkWidget *mode_buttons[12]; +}; + +/* pixmap creation function */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *pixmap_char); + +/* File completion functions which would be external, were they used + * outside of this file. + */ + +static CompletionState* cmpl_init_state (void); +static void cmpl_free_state (CompletionState *cmpl_state); +static gint cmpl_state_okay (CompletionState* cmpl_state); +static gchar* cmpl_strerror (gint); + +static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, + gchar **remaining_text, + CompletionState *cmpl_state); + +/* Returns a name for consideration, possibly a completion, this name + * will be invalid after the next call to cmpl_next_completion. + */ +static char* cmpl_this_completion (PossibleCompletion*); + +/* True if this completion matches the given text. Otherwise, this + * output can be used to have a list of non-completions. + */ +static gint cmpl_is_a_completion (PossibleCompletion*); + +/* True if the completion is a directory + */ +static gint cmpl_is_directory (PossibleCompletion*); + +/* Obtains the next completion, or NULL + */ +static PossibleCompletion* cmpl_next_completion (CompletionState*); + +/* Updating completions: the return value of cmpl_updated_text() will + * be text_to_complete completed as much as possible after the most + * recent call to cmpl_completion_matches. For the present + * application, this is the suggested replacement for the user's input + * string. You must CALL THIS AFTER ALL cmpl_text_completions have + * been received. + */ +static gchar* cmpl_updated_text (CompletionState* cmpl_state); + +/* After updating, to see if the completion was a directory, call + * this. If it was, you should consider re-calling completion_matches. + */ +static gint cmpl_updated_dir (CompletionState* cmpl_state); + +/* Current location: if using file completion, return the current + * directory, from which file completion begins. More specifically, + * the cwd concatenated with all exact completions up to the last + * directory delimiter('/'). + */ +static gchar* cmpl_reference_position (CompletionState* cmpl_state); + +/* backing up: if cmpl_completion_matches returns NULL, you may query + * the index of the last completable character into cmpl_updated_text. + */ +static gint cmpl_last_valid_char (CompletionState* cmpl_state); + +/* When the user selects a non-directory, call cmpl_completion_fullname + * to get the full name of the selected file. + */ +static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state); + + +/* Directory operations. */ +static CompletionDir* open_ref_dir (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static gboolean check_dir (gchar *dir_name, + struct stat *result, + gboolean *stat_subdirs); +static CompletionDir* open_dir (gchar* dir_name, + CompletionState* cmpl_state); +static CompletionDir* open_user_dir (gchar* text_to_complete, + CompletionState *cmpl_state); +static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, + CompletionState *cmpl_state); +static CompletionDirSent* open_new_dir (gchar* dir_name, + struct stat* sbuf, + gboolean stat_subdirs); +static gint correct_dir_fullname (CompletionDir* cmpl_dir); +static gint correct_parent (CompletionDir* cmpl_dir, + struct stat *sbuf); +static gchar* find_parent_dir_fullname (gchar* dirname); +static CompletionDir* attach_dir (CompletionDirSent* sent, + gchar* dir_name, + CompletionState *cmpl_state); +static void free_dir_sent (CompletionDirSent* sent); +static void free_dir (CompletionDir *dir); +static void prune_memory_usage(CompletionState *cmpl_state); + +/* Completion operations */ +static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state); +static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state); +static CompletionDir* find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static PossibleCompletion* append_completion_text(gchar* text, + CompletionState* cmpl_state); +static gint get_pwdb(CompletionState* cmpl_state); +static gint first_diff_index(gchar* pat, gchar* text); +static gint compare_user_dir(const void* a, const void* b); +static gint compare_cmpl_dir(const void* a, const void* b); +static void update_cmpl(PossibleCompletion* poss, + CompletionState* cmpl_state); + +static void gtk_file_selection_class_init (GtkFileSelectionClass *klass); +static void gtk_file_selection_init (GtkFileSelection *filesel); +static void gtk_file_selection_realize (GtkWidget *widget); +static void gtk_file_selection_destroy (GtkObject *object); +static gint gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); + +static void gtk_file_selection_file_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data); + +static void gtk_file_selection_dir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer data); + +static void gtk_file_selection_undir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer data); + +static void gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete); +static void gtk_file_selection_abort (GtkFileSelection *fs); + +static void gtk_file_selection_update_history_menu (GtkFileSelection *fs, + gchar *current_dir); + +static void gtk_file_selection_create_dir (gpointer data); +static void gtk_file_selection_delete_file (gpointer data); +static void gtk_file_selection_rename_file (gpointer data); +static void gtk_file_selection_properties (gpointer data); +static void gtk_file_selection_properties_update_mode (GtkWidget *widget, gpointer data); +static mode_t gtk_file_selection_properties_get_mode (PropertiesPrivate* private); + +static gboolean gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data); +static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); +static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist, + GdkEventButton *event, + + gpointer user_data); +static void gtk_file_selection_bookmark_callback (GtkWidget *widget, gpointer data); +static void gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data); +static gint gtk_file_selection_mask_entry_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data); +static gint gtk_file_selection_mask_entry_button_callback (GtkWidget *widget, GdkEventButton *event, gpointer data); + +//static void gtk_file_selection_home_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_bookmark_button (GtkWidget *widget, + GtkFileSelection *fs); + +static void gtk_file_selection_up_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_prev_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_next_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data); + +static gint gtk_file_selection_files_list_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data); + + +static gint gtk_file_selection_match_char (gchar, gchar *mask); +static gint gtk_file_selection_match_mask (gchar *,gchar *); + +static void gtk_file_selection_load_bookmarks(GtkFileSelection *fs); +static void gtk_file_selection_add_bookmark (GtkFileSelection *fs, gchar *desc, gchar *path); +gint gtk_file_selection_save_bookmarks (GtkFileSelection *fs); + +static void gtk_file_selection_load_masks(GtkFileSelection *fs); + +static gint gtk_file_selection_show_fileop_menu (GtkCList *clist, + GdkEvent *event, + GtkFileSelection *fs); + + +static GtkWindowClass *parent_class = NULL; + +/* Saves errno when something cmpl does fails. */ +static gint cmpl_errno; + +#ifdef G_WITH_CYGWIN +/* + * Take the path currently in the file selection + * entry field and translate as necessary from + * a WIN32 style to CYGWIN32 style path. For + * instance translate: + * x:\somepath\file.jpg + * to: + * //x/somepath/file.jpg + * + * Replace the path in the selection text field. + * Return a boolean value concerning whether a + * translation had to be made. + */ +int +translate_win32_path (GtkFileSelection *filesel) +{ + int updated = 0; + gchar *path; + + /* + * Retrieve the current path + */ + path = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + + /* + * Translate only if this looks like a DOS-ish + * path... First handle any drive letters. + */ + if (isalpha (path[0]) && (path[1] == ':')) { + /* + * This part kind of stinks... It isn't possible + * to know if there is enough space in the current + * string for the extra character required in this + * conversion. Assume that there isn't enough space + * and use the set function on the text field to + * set the newly created string. + */ + gchar *newPath = g_strdup_printf ("//%c/%s", path[0], (path + 3)); + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), newPath); + + path = newPath; + updated = 1; + } + + /* + * Now, replace backslashes with forward slashes + * if necessary. + */ + if (strchr (path, '\\')) + { + int index; + for (index = 0; path[index] != '\0'; index++) + if (path[index] == '\\') + path[index] = '/'; + + updated = 1; + } + + return updated; +} +#endif + +/* General notes: + * Make prev and next inactive if their respective * + * histories are empty. + * Add facilities for handling hidden files and * + * directories * + * Add an api to access the mask, and hidden files * + * check box? (prob not in 1.2.x series) * + */ + +/* Routine for applying mask to filenames * + * Need to be optimized to minimize recursion * + * help the for loop by looking for the next * + * instance of the mask character following * + * the '*'. ei *.c -- look for '.' * + * Also, swap all *? pairs (-> ?*), as that * + * will make it possible to look ahead (? * + * makes it very nondeterministic as in *?.c * + * which really is ?*.c * + * * + */ +static gint gtk_file_selection_match_char (gchar text, gchar *mask) +{ + gchar *maskc; + gint x; + gint s; + gchar lastc; + gchar nextc; + + if (mask[0] == '[') + { + if (!strchr (mask,']')) return 0; + lastc = 0; + + maskc = g_strdup(mask + 1); /* get the portion of mask inside []*/ + (*(strchr (maskc + 1,']'))) = 0; + s = strlen ((char *)maskc); + + for (x = 0 ; x < s ; x ++){ + if (maskc[x] == '-') + { + if (x == s) return 1; + nextc = maskc[x + 1]; + + if (nextc > lastc) + { + if ((lastc <= text) && (nextc >= text)) + { + g_free (maskc); + return s + 2; + } + } + else if ((lastc >= text) && (nextc <= text)) + { + g_free (maskc); + return s + 2; + } + } + else if (text == maskc[x]) + { + g_free (maskc); + return s + 2; + } + lastc = maskc[x]; + } + g_free (maskc); + + return 0; + } + + if (mask[0] == '?') return 1; + if (mask[0] == text) return 1; + + return 0; +} + + +static gint gtk_file_selection_match_mask1 (gchar *text, gchar *mask) +{ + + int mc; + int tc; + + tc = 0; mc = 0; + + if (mask[0] == 0 && text[0] == 0) return 1; + + if (mask[0] == '*') + { + for (tc = 0; tc <= strlen(text); tc++) + { + if (gtk_file_selection_match_mask1 (text + tc, mask + 1)) + return 1; + } + return 0; + } + mc = gtk_file_selection_match_char (text[0], mask); + + if(mc) + return gtk_file_selection_match_mask1 (text + 1, mask + mc); + else + return 0; +} + +static gint gtk_file_selection_match_mask (gchar *text, gchar *mask) +{ + gchar *masks; + gchar *bmask; + gchar *emask; + + masks=g_strdup(mask); + + emask=strchr(masks,'<'); + if(emask){ + bmask=emask+1; + emask=strchr(bmask,'>'); + if(emask){ + *emask=0; + } + }else{ + bmask=masks; + } + + do{ + if((emask=strchr(bmask,',')) || (emask=strchr(bmask,';'))){ + *emask=0; + if (gtk_file_selection_match_mask1 (text, bmask)){ + g_free(masks); + return 1; + } + + bmask=emask+1; + } + }while(emask); + + if(gtk_file_selection_match_mask1 (text, bmask)){ + g_free(masks); + return 1; + } + g_free(masks); + return 0; +} + +static void +gtk_file_selection_load_bookmarks(GtkFileSelection *fs) +{ + GList *list; + gchar *bookmark_file; + gchar *bookmark_data; + struct stat file_info; + gint file; + gint lp; + gint cp; + BookmarkMenuStruct *item; + + + if(fs->bookmark_list){ //erase + list=fs->bookmark_list; + while(list){ + item=list->data; + g_free(item->desc); + g_free(item->path); + g_free(item); + list=list->next; + } + g_list_free (fs->bookmark_list); + fs->bookmark_list = NULL; + gtk_widget_destroy (fs->bookmark_menu); + } + + fs->bookmark_menu=gtk_menu_new(); + + /* spacer */ + item=g_malloc(sizeof(item)); + item->menu_item = gtk_menu_item_new(); + gtk_widget_show(item->menu_item); + gtk_menu_append (GTK_MENU(fs->bookmark_menu), item->menu_item); + + item=g_malloc(sizeof(item)); + item->desc=g_strdup("Add bookmark"); + item->path=g_strdup("."); + item->menu_item=gtk_menu_item_new_with_label (item->desc); + gtk_widget_show(item->menu_item); + //fs->bookmark_list=g_list_append(fs->bookmark_list,item); + //set signal here!! + gtk_menu_append (GTK_MENU(fs->bookmark_menu), item->menu_item); + + item=g_malloc(sizeof(item)); + item->desc=g_strdup("Edit bookmark"); + item->path=g_strdup("."); + item->menu_item=gtk_menu_item_new_with_label (item->desc); + gtk_widget_show(item->menu_item); + //fs->bookmark_list=g_list_append(fs->bookmark_list,item); + //set signal here!! + gtk_menu_append (GTK_MENU(fs->bookmark_menu), item->menu_item); + + bookmark_file=g_strconcat(g_get_home_dir(), BOOKMARK_FILE ,NULL); + if(!stat(bookmark_file,&file_info) && (file = open(bookmark_file, O_RDONLY )) > 0) + { + if(file_info.st_size <65536 ) + { + bookmark_data=g_malloc(file_info.st_size); + + if(file && read(file, bookmark_data, file_info.st_size)) + { + cp=lp=0; + + while (cp < file_info.st_size) + { + while (cp < file_info.st_size && bookmark_data[cp] != '<' ) + cp++; + bookmark_data[cp]=0; + item=g_malloc(sizeof(BookmarkMenuStruct)); + item->desc=g_strdup(bookmark_data+lp); + lp=++cp; + + while (cp < file_info.st_size && bookmark_data[cp] != '>' ) + cp++; + + bookmark_data[cp]=0; + //create menu items + item->path=g_strdup(bookmark_data+lp); + gtk_file_selection_add_bookmark ((gpointer) fs, (gpointer) item->desc, (gpointer) item->path); + + cp++; + + while(cp < file_info.st_size && bookmark_data[cp] < 33 ) + cp++; + lp=cp; + } + } + + close(file); + } + } else { + + /* Add some default items, then save off to bookmarks file */ + + gtk_file_selection_add_bookmark ((gpointer) fs, "Home", "~/"); + gtk_file_selection_add_bookmark ((gpointer) fs, "Root", "/"); + + gtk_file_selection_save_bookmarks ((gpointer) fs); + } +} + +static void +gtk_file_selection_add_bookmark (GtkFileSelection *fs, gchar *desc, gchar *path) +{ + /* Add item to menu */ + BookmarkMenuStruct *item; + item=g_malloc(sizeof(item)); + item->desc = (gpointer) desc; + item->path = (gpointer) path; + item->menu_item=gtk_menu_item_new_with_label (item->desc); + gtk_widget_show(item->menu_item); + fs->bookmark_list=g_list_append(fs->bookmark_list,item); + gtk_signal_connect (GTK_OBJECT(item->menu_item), "activate", + (GtkSignalFunc) gtk_file_selection_bookmark_callback, + (gpointer) fs); + gtk_menu_insert (GTK_MENU(fs->bookmark_menu), item->menu_item, g_list_length(fs->bookmark_list) -1); +} + +gint +gtk_file_selection_save_bookmarks (GtkFileSelection *fs) +{ + BookmarkMenuStruct *item; + gchar *bookmark_file; + gchar *item_data; + gint file; + GList *list; + + bookmark_file=g_strconcat(g_get_home_dir(), BOOKMARK_FILE ,NULL); + + if ((file = open(bookmark_file, O_CREAT | O_WRONLY | O_TRUNC, 0600)) > 0) + { + for (list = g_list_first (fs->bookmark_list); list != NULL; list = g_list_next(list)) { + item = list->data; + item_data = g_strconcat(item->desc, " <", item->path, ">\n", NULL); + if (write (file, item_data, strlen(item_data)) != strlen(item_data)) { + return TRUE; + } + g_free(item_data); + } + + close(file); + } else { + return TRUE; + } + + return FALSE; +} + +static void +gtk_file_selection_load_masks(GtkFileSelection *fs) +{ + /* + GList *list; + gchar *masks_file; + gchar *masks_data; + struct stat file_info; + gint file; + gint lp; + gint cp; + + if(fs->masks){ + list=fs->masks; + while(list){ + g_free(list->data); + list=list->next; + } + fs->masks = NULL; + } + + masks_file=g_strconcat(g_get_home_dir(), MASK_FILE,NULL); //put in #define + if(!stat(masks_file,&file_info)) + { + if(file_info.st_size <65536 ) + { + masks_data=g_malloc(file_info.st_size); + + file = open(masks_file, O_RDONLY ); + + if(file && read(file, masks_data, file_info.st_size)) + { + cp=lp=0; + + while (cp < file_info.st_size) + { + while (cp < file_info.st_size && masks_data[cp] != '>' ) + cp++; + + masks_data[++cp]=0; + if (masks_data[lp]=='<') { //if there was no description, strip off brackets + lp++; + masks_data[cp-1]=0; + } +// g_print("%s\n",masks_data+lp); + fs->masks = g_list_append(fs->masks, g_strdup(masks_data+lp)); + + while(cp < file_info.st_size && masks_data[cp] < 33 ) + cp++; + lp=cp; + } + } + + close(file); + } + } + */ + if (!fs->masks) { + /* masks is still null, fill it with default data... */ + /* + fs->masks = g_list_append(fs->masks, "all files <*>"); + fs->masks = g_list_append(fs->masks, "mp3s/playlists <*.mp3,*.m3u>"); + fs->masks = g_list_append(fs->masks, "src/hdr <*.[CcHh],*.[Cc][Cc],*.[Hh][Hh],*.cpp>"); + fs->masks = g_list_append(fs->masks, "html docs <*.html,*.htm,*.HTM,*.php*,*.inc>"); + fs->masks = g_list_append(fs->masks, "images <*.png,*.jpg,*.jpeg,*.gif,*.xpm,*.tiff>"); + fs->masks = g_list_append(fs->masks, "package <*.rpm,*.deb>"); + fs->masks = g_list_append(fs->masks, "archive <*.tgz,*.tb2,*.tar*,*.zip,*.rar>"); + fs->masks = g_list_append(fs->masks, "compressed <*.Z,*.gz,*.bz2>"); + */ + } +} + +void gtk_file_selection_clear_masks (GtkFileSelection *filesel) +{ + GList *list; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + list = filesel->masks; + while (list) + { + g_free (list->data); + list = list->next; + } + filesel->masks = NULL; + + gtk_list_clear_items (GTK_LIST (GTK_COMBO (filesel->mask_entry)->list), 0, -1); +} + +void gtk_file_selection_set_masks (GtkFileSelection *filesel, const gchar **masks) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + while (*masks) + { + filesel->masks = g_list_append (filesel->masks, (gpointer)*masks); + masks++; + } + + if (filesel->masks) + gtk_combo_set_popdown_strings (GTK_COMBO (filesel->mask_entry), filesel->masks); +} + +GtkType +gtk_file_selection_get_type (void) +{ + static GtkType file_selection_type = 0; + + if (!file_selection_type) + { + static const GtkTypeInfo filesel_info = + { + "GtkFileSelection", + sizeof (GtkFileSelection), + sizeof (GtkFileSelectionClass), + (GtkClassInitFunc) gtk_file_selection_class_init, + (GtkObjectInitFunc) gtk_file_selection_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + file_selection_type = gtk_type_unique (GTK_TYPE_WINDOW, &filesel_info); + } + + return file_selection_type; +} + +static void +gtk_file_selection_class_init (GtkFileSelectionClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + + parent_class = gtk_type_class (GTK_TYPE_WINDOW); + + widget_class = GTK_WIDGET_CLASS (class); + + widget_class->realize = gtk_file_selection_realize; + object_class->destroy = gtk_file_selection_destroy; +} + +static void +gtk_file_selection_init (GtkFileSelection *filesel) +{ + GtkWidget *entry_vbox; + GtkWidget *label; + GtkWidget *list_vbox; + GtkWidget *confirm_area; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *hbox2; + GtkWidget *table; + GtkWidget *pulldown_hbox; + GtkWidget *scrolled_win; + GtkWidget *mask_label; + GtkWidget *bigframe; + GtkWidget *button; + GtkWidget *hpaned; + GtkWidget *menu_item; + GtkWidget *pixmap; + + char *dir_title [2]; + char *file_title [2]; + + filesel->cmpl_state = cmpl_init_state (); + + filesel->mask=NULL; + filesel->prev_history=NULL; + filesel->next_history=NULL; + filesel->saved_entry=NULL; + filesel->bookmark_list=NULL; + filesel->masks=NULL; + filesel->selection_text = NULL; + filesel->fileop_data = NULL; + + gtk_file_selection_load_masks(filesel); + gtk_file_selection_load_bookmarks(filesel); + + /* The dialog-sized vertical box */ + filesel->main_vbox = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (filesel), 0); + gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox); + gtk_widget_show (filesel->main_vbox); + + /* hbox for pulldown menu */ + pulldown_hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), pulldown_hbox, FALSE, FALSE, 0); + gtk_widget_show (pulldown_hbox); + + /* The horizontal box containing create, rename etc. buttons */ + +/* + filesel->button_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(filesel->button_area), GTK_BUTTONBOX_START); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(filesel->button_area), 0); + gtk_box_pack_start (GTK_BOX (pulldown_hbox), filesel->button_area, + FALSE, FALSE, 0); + gtk_button_box_set_child_size(GTK_BUTTON_BOX(filesel->button_area),0,0); + gtk_button_box_set_child_ipadding(GTK_BUTTON_BOX(filesel->button_area),0,0); + */ + + filesel->button_area = gtk_hbox_new (TRUE,0); + //gtk_box_pack_start (GTK_BOX (pulldown_hbox), filesel->button_area, + // FALSE, FALSE, 0); + + //gtk_widget_show (filesel->button_area); + + gtk_file_selection_show_fileop_buttons(filesel); + /* frame to put the following hbox in */ + bigframe = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), bigframe, TRUE, TRUE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (bigframe), GTK_SHADOW_OUT); + gtk_widget_show (bigframe); + + + list_vbox = gtk_vbox_new (FALSE,3); + gtk_widget_show(list_vbox); + gtk_container_add (GTK_CONTAINER(bigframe), list_vbox); + gtk_container_set_border_width (GTK_CONTAINER (list_vbox),2); + gtk_widget_show (list_vbox); + + /* The horizontal box containing the directory and file listboxes */ +// list_hbox = gtk_hbox_new (FALSE, 3); + //gtk_container_add (GTK_CONTAINER(bigframe), list_hbox); + //gtk_container_set_border_width (GTK_CONTAINER (list_hbox), 3); +// gtk_box_pack_start(GTK_BOX(list_vbox), list_hbox, FALSE,FALSE,0); +// gtk_widget_show (list_hbox); + + hpaned=gtk_hpaned_new(); + gtk_widget_show(hpaned); + gtk_container_set_border_width (GTK_CONTAINER (hpaned), 1); + gtk_paned_set_gutter_size (GTK_PANED (hpaned), 10); + gtk_box_pack_start (GTK_BOX(list_vbox), hpaned,TRUE,TRUE,0); + + /* vbox to put the buttons and directory listing in */ + vbox = gtk_vbox_new (FALSE, 3); + gtk_widget_show (vbox); + gtk_container_add(GTK_CONTAINER(hpaned),vbox); + //gtk_box_pack_start (GTK_BOX (hpaned), vbox, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 4); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + +// home_button = gtk_button_new_with_label (_("Home")); +// gtk_widget_show (home_button); +// gtk_signal_connect (GTK_OBJECT (home_button), "clicked", +// (GtkSignalFunc) gtk_file_selection_home_button, +// (gpointer) filesel); +// gtk_box_pack_start (GTK_BOX (hbox), home_button, TRUE,TRUE, 0); + + /* Here we add the bookmark menu button */ + #define If we're going to make bookmark a menu, we don't need + #define to keep it in the filesel structure + button=gtk_button_new_with_label(_("Bookmarks")); + gtk_widget_show(button); + gtk_box_pack_start (GTK_BOX(hbox), button, FALSE,FALSE,0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_bookmark_button, + (gpointer) filesel); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0); + gtk_widget_show(hbox2); + + /* Prev button */ + button = gtk_button_new (); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_prev_button, + (gpointer) filesel); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE,FALSE, 0); + pixmap = create_pixmap (filesel->main_vbox, (gpointer) back_xpm); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (button), pixmap); + + /* Up button */ + button = gtk_button_new (); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_up_button, + (gpointer) filesel); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE,FALSE, 0); + pixmap = create_pixmap (filesel->main_vbox, (gpointer) up_xpm); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (button), pixmap); + + /* next button */ + button = gtk_button_new (); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_next_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE,FALSE, 0); + pixmap = create_pixmap (filesel->main_vbox, (gpointer) forward_xpm); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (button), pixmap); + + /* refresh button */ + button = gtk_button_new (); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_refresh_button, + (gpointer) filesel); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE,FALSE, 0); + pixmap = create_pixmap (filesel->main_vbox, (gpointer) refresh_xpm); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (button), pixmap); + + /* menu for right click file operations */ + filesel->fileop_menu = gtk_menu_new(); + + menu_item = gtk_menu_item_new_with_label ("Rename..."); + gtk_widget_show(menu_item); + gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) gtk_file_selection_rename_file, + (gpointer) filesel); + gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item); + + menu_item = gtk_menu_item_new_with_label ("Delete"); + gtk_widget_show(menu_item); + gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item); + gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) gtk_file_selection_delete_file, + (gpointer) filesel); + + menu_item = gtk_menu_item_new (); + gtk_widget_show(menu_item); + gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item); + + menu_item = gtk_menu_item_new_with_label ("Create Directory..."); + gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) gtk_file_selection_create_dir, + (gpointer) filesel); + gtk_widget_show(menu_item); + gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item); + + menu_item = gtk_menu_item_new (); + gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item); + gtk_widget_show(menu_item); + + menu_item = gtk_menu_item_new_with_label ("Properties..."); + gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) gtk_file_selection_properties, + (gpointer) filesel); + gtk_menu_append (GTK_MENU (filesel->fileop_menu), menu_item); + gtk_widget_show(menu_item); + + /* The directories clist */ + dir_title[0] = _("Directories"); + dir_title[1] = NULL; + filesel->dir_list = gtk_clist_new_with_titles (1, (gchar**) dir_title); + gtk_widget_set_usize (filesel->dir_list, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "select_row", + (GtkSignalFunc) gtk_file_selection_dir_button, + (gpointer) filesel); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "unselect_row", + (GtkSignalFunc) gtk_file_selection_undir_button, + (gpointer) filesel); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "button_press_event", + GTK_SIGNAL_FUNC(gtk_file_selection_show_fileop_menu), + (gpointer) filesel); + + gtk_clist_column_titles_passive (GTK_CLIST (filesel->dir_list)); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->dir_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE,TRUE, 0); + //gtk_container_add(GTK_CONTAINER(hpaned), scrolled_win); + + gtk_widget_show (filesel->dir_list); + gtk_widget_show (scrolled_win); + + vbox = gtk_vbox_new (FALSE, 3); + gtk_widget_show (vbox); + gtk_container_add(GTK_CONTAINER(hpaned),vbox); + /* vbox area for mask entry and files clist */ + + hbox = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + mask_label = gtk_label_new (_("Mask:")); + gtk_widget_show (mask_label); + gtk_box_pack_start (GTK_BOX (hbox), mask_label, FALSE, FALSE, 2); + +/* + filesel->mask_entry = gtk_entry_new (); + gtk_widget_show (filesel->mask_entry); + gtk_signal_connect(GTK_OBJECT(filesel->mask_entry),"activate", + (GtkSignalFunc) gtk_file_4_mask_entry_callback, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox),filesel->mask_entry, TRUE, TRUE, 0); + */ + + filesel->mask_entry = gtk_combo_new (); + gtk_widget_show (filesel->mask_entry); + gtk_combo_set_value_in_list(GTK_COMBO(filesel->mask_entry),FALSE,FALSE); + gtk_signal_connect(GTK_OBJECT(GTK_COMBO(filesel->mask_entry)->entry),"activate", + (GtkSignalFunc) gtk_file_selection_mask_entry_callback, + (gpointer) filesel); + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->mask_entry)->entry),"key-press-event", + (GtkSignalFunc) gtk_file_selection_mask_entry_key_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->mask_entry)->list),"button-release-event", + (GtkSignalFunc) gtk_file_selection_mask_entry_button_callback, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox),filesel->mask_entry, TRUE, TRUE, 0); + + if (filesel->masks) + gtk_combo_set_popdown_strings (GTK_COMBO (filesel->mask_entry), filesel->masks); + + + /* The files clist */ + file_title[0] = _("Files"); + file_title[1] = NULL; + filesel->file_list = gtk_clist_new_with_titles (1, (gchar**) file_title); + gtk_widget_set_usize (filesel->file_list, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "select_row", + (GtkSignalFunc) gtk_file_selection_file_button, + (gpointer) filesel); + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "key-press-event", + (GtkSignalFunc) gtk_file_selection_files_list_key_callback, + (gpointer) filesel); + + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "button_press_event", + GTK_SIGNAL_FUNC(gtk_file_selection_show_fileop_menu), + (gpointer) filesel); + + gtk_clist_column_titles_passive (GTK_CLIST (filesel->file_list)); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->file_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0); + gtk_widget_show (filesel->file_list); + gtk_widget_show (scrolled_win); + + /* action area for packing buttons into. */ + filesel->action_area = gtk_hbox_new (TRUE, 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->action_area, + FALSE, FALSE, 2); + gtk_widget_show (filesel->action_area); + + /* + hbox=gtk_hbox_new(FALSE,0); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), hbox, FALSE,FALSE, 0); + gtk_widget_show (hbox); + */ + + /* The selection entry widget */ + + entry_vbox = gtk_vbox_new (FALSE, 0); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 0); + gtk_widget_show (entry_vbox); + + table = gtk_table_new ( 2, 2, FALSE ); + gtk_box_pack_start (GTK_BOX (entry_vbox), table, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (table), 4); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + + + label = gtk_label_new (_("Selection:")); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (label); + + + filesel->selection_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event", + (GtkSignalFunc) gtk_file_selection_key_press, filesel); + gtk_table_attach (GTK_TABLE (table), filesel->selection_entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (filesel->selection_entry); + + + label = gtk_label_new (_("Directory:")); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (label); + + + filesel->history_combo = gtk_combo_new(); + gtk_combo_set_value_in_list(GTK_COMBO(filesel->history_combo),FALSE,FALSE); + gtk_table_attach (GTK_TABLE (table), filesel->history_combo, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show(filesel->history_combo); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->entry),"key-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"button-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_list_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"key-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_list_key_handler, + (gpointer) filesel); + + filesel->selection_text = NULL; + + + /* The OK/Cancel button area */ + confirm_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(confirm_area), 5); + gtk_box_pack_end (GTK_BOX (entry_vbox), confirm_area, FALSE, FALSE, 0); + gtk_widget_show (confirm_area); + + /* The OK button */ + filesel->ok_button = gtk_button_new_with_label (_("OK")); + GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->ok_button, TRUE, TRUE, 0); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event", + (GtkSignalFunc) gtk_widget_grab_default, + GTK_OBJECT (filesel->ok_button)); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate", + (GtkSignalFunc) gtk_button_clicked, + GTK_OBJECT (filesel->ok_button)); + gtk_widget_grab_default (filesel->ok_button); + gtk_widget_show (filesel->ok_button); + + /* The Cancel button */ + filesel->cancel_button = gtk_button_new_with_label (_("Cancel")); + GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->cancel_button); + + gtk_widget_show(table); + + + /* + filesel->selection_text = label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + */ + + + if (!cmpl_state_okay (filesel->cmpl_state)) + { + gchar err_buf[256]; + + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); + + /* + gtk_label_set_text (GTK_LABEL (filesel->selection_text), err_buf); + */ + } + else + { + gtk_file_selection_populate (filesel, "", FALSE); + } + + gtk_widget_grab_focus (filesel->selection_entry); +} + +GtkWidget* +gtk_file_selection_new (const gchar *title) +{ + GtkFileSelection *filesel; + + filesel = gtk_type_new (GTK_TYPE_FILE_SELECTION); + gtk_window_set_title (GTK_WINDOW (filesel), title); + /* !!! put check here to figure out if screen > 640x480, if true + We need to make the file selection dialog bigger. much bigger.. + or maybe we should keep it at a certan percentage of the screen + size? */ + + gtk_window_set_default_size(GTK_WINDOW (filesel), 520, 420); + return GTK_WIDGET (filesel); +} + +void +gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + return; + + /* delete, create directory, and rename */ +/* + if (!filesel->fileop_c_dir) + { + filesel->fileop_c_dir = gtk_button_new_with_label (_("MkDir")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_c_dir), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_c_dir, TRUE,TRUE, 0); + gtk_widget_show (filesel->fileop_c_dir); + } + + if (!filesel->fileop_del_file) + { + filesel->fileop_del_file = gtk_button_new_with_label (_("Delete")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_del_file), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_del_file, TRUE,TRUE, 0); + gtk_widget_show (filesel->fileop_del_file); + } + + if (!filesel->fileop_ren_file) + { + filesel->fileop_ren_file = gtk_button_new_with_label (_("Rename")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_ren_file), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_ren_file, TRUE,TRUE, 0); + gtk_widget_show (filesel->fileop_ren_file); + } + + gtk_widget_queue_resize(GTK_WIDGET(filesel)); + */ +} + +void +gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + return; + /* + if (filesel->fileop_ren_file) + { + gtk_widget_destroy (filesel->fileop_ren_file); + filesel->fileop_ren_file = NULL; + } + + if (filesel->fileop_del_file) + { + gtk_widget_destroy (filesel->fileop_del_file); + filesel->fileop_del_file = NULL; + } + + if (filesel->fileop_c_dir) + { + gtk_widget_destroy (filesel->fileop_c_dir); + filesel->fileop_c_dir = NULL; + } + */ +} + + + +void +gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename) +{ + char buf[MAXPATHLEN]; + const char *name, *last_slash; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (filename != NULL); + + last_slash = strrchr (filename, '/'); + + if (!last_slash) + { + buf[0] = 0; + name = filename; + } + else + { + gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1); + + strncpy (buf, filename, len); + buf[len] = 0; + + name = last_slash + 1; + } + + gtk_file_selection_populate (filesel, buf, FALSE); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); +} + +gchar* +gtk_file_selection_get_filename (GtkFileSelection *filesel) +{ + static char nothing[2] = ""; + char *text; + char *filename; + + g_return_val_if_fail (filesel != NULL, nothing); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); + + text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + if (text) + { + filename = cmpl_completion_fullname (text, filesel->cmpl_state); + return filename; + } + + return nothing; +} + +void +gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern) +{ + gchar *new_pattern; + gint x; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (pattern != NULL); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), pattern); + + if(strchr(pattern,'*') || strchr(pattern,'?')) + { + for(x=strlen(pattern);x>=0;x--) + { + if(pattern[x]=='/') break; + } + gtk_entry_set_text(GTK_ENTRY(filesel->mask_entry),g_strdup(pattern+x+1)); + + if(filesel->mask) g_free(filesel->mask); + + filesel->mask=g_strdup(pattern+x+1); + new_pattern=g_strdup(pattern); + new_pattern[x+1]=0; + gtk_file_selection_populate (filesel, (gchar*) new_pattern, TRUE); + g_free(new_pattern); + } + else + { + gtk_file_selection_populate (filesel, (gchar*) pattern, TRUE); + } +} + +static void +gtk_file_selection_realize (GtkWidget *widget) +{ + GtkFileSelection *filesel; + const gchar *masks[] = { "All Files <*>", NULL }; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (widget)); + + filesel = GTK_FILE_SELECTION (widget); + + /* make sure that we have at least one mask */ + if (!filesel->masks) + gtk_file_selection_set_masks (filesel, masks); + + filesel->mask = g_strdup ((gchar*) filesel->masks->data); + gtk_file_selection_populate (filesel, "", FALSE); + + + if (GTK_WIDGET_CLASS (parent_class)->realize) + (* GTK_WIDGET_CLASS (parent_class)->realize) (widget); +} + +static void +gtk_file_selection_destroy (GtkObject *object) +{ + GtkFileSelection *filesel; + GList *list; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (object)); + + filesel = GTK_FILE_SELECTION (object); + + if (filesel->fileop_dialog) + gtk_widget_destroy (filesel->fileop_dialog); + + if (filesel->next_history) + { + list = filesel->next_history; + while (list) + { + g_free (list->data); + list = list->next; + } + } + g_list_free (filesel->next_history); + filesel->next_history = NULL; + + if (filesel->prev_history) + { + list = filesel->prev_history; + while (list) + { + g_free (list->data); + list = list->next; + } + } + g_list_free (filesel->prev_history); + filesel->prev_history = NULL; + + if (filesel->mask) + { + g_free (filesel->mask); + filesel->mask = NULL; + } + + cmpl_free_state (filesel->cmpl_state); + filesel->cmpl_state = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/* Begin file operations callbacks */ + +static gint +gtk_file_selection_show_fileop_menu (GtkCList *clist, GdkEvent *event, GtkFileSelection *fs) +{ + GdkEventButton *event_button; + + g_return_val_if_fail (clist != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (fs != NULL, FALSE); + g_return_val_if_fail (GTK_FILE_SELECTION (fs), FALSE); + + if (event->type == GDK_BUTTON_PRESS) + { + event_button = (GdkEventButton *) event; + if (event_button->button == 3) + { + + gtk_menu_popup (GTK_MENU (fs->fileop_menu), NULL, NULL, NULL, NULL, + event_button->button, event_button->time); + return TRUE; + } + } + + return FALSE; +} + +static void +gtk_file_selection_fileop_error (GtkFileSelection *fs, gchar *error_message) +{ + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dialog; + + g_return_if_fail (error_message != NULL); + + /* main dialog */ + dialog = gtk_dialog_new (); + /* + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + */ + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, make this dialog modal too */ + /* When error dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + label = gtk_label_new(error_message); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + /* yes, we free it */ + g_free (error_message); + + /* close button */ + button = gtk_button_new_with_label (_("Close")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static void +gtk_file_selection_fileop_destroy (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + fs->fileop_dialog = NULL; + g_free (fs->fileop_data); + fs->fileop_data = NULL; +} + + +static void +gtk_file_selection_create_dir_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + gchar *dirname; + gchar *path; + gchar *full_path; + gchar *buf; + CompletionState *cmpl_state; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + dirname = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + full_path = g_strconcat (path, "/", dirname, NULL); + if ( (mkdir (full_path, 0755) < 0) ) + { + buf = g_strconcat ("Error creating directory \"", dirname, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (full_path); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_create_dir (gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *button; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Create Directory")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + label = gtk_label_new(_("Directory name:")); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + /* The directory entry widget */ + fs->fileop_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, + TRUE, TRUE, 5); + GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT); + gtk_widget_show (fs->fileop_entry); + + /* buttons */ + button = gtk_button_new_with_label (_("Create")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static void +gtk_file_selection_delete_file_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + CompletionState *cmpl_state; + gchar *path; + gchar *full_path; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + full_path = g_strconcat (path, "/", fs->fileop_file, NULL); + if ( (unlink (full_path) < 0) ) + { + buf = g_strconcat ("Error deleting file \"", fs->fileop_file, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (full_path); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_delete_file (gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dialog; + gchar *filename; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + filename = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + if (strlen(filename) < 1) + return; + + fs->fileop_file = filename; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Delete File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + buf = g_strconcat ("Really delete file \"", filename, "\" ?", NULL); + label = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + g_free(buf); + + /* buttons */ + button = gtk_button_new_with_label (_("Delete")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); + +} + +static void +gtk_file_selection_rename_file_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + gchar *buf; + gchar *file; + gchar *path; + gchar *new_filename; + gchar *old_filename; + CompletionState *cmpl_state; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + new_filename = g_strconcat (path, "/", file, NULL); + old_filename = g_strconcat (path, "/", fs->fileop_file, NULL); + + if (strcmp (new_filename, old_filename)) + if ((rename (old_filename, new_filename)) < 0) + { + buf = g_strconcat ("Error renaming file \"", file, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (new_filename); + g_free (old_filename); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_file_mode_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + PropertiesPrivate *priv = fs->fileop_data; + CompletionState *cmpl_state; + gchar *filename, *file, *path; + mode_t mode; + + mode = gtk_file_selection_properties_get_mode (priv); + + file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + filename = g_strconcat (path, "/", file, NULL); + if (chmod (filename, mode) == -1) + { + gchar *buf = g_strconcat ("Error changing file mode of \"", filename, "\": ", + g_strerror (errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); + } + else + gtk_file_selection_rename_file_confirmed (widget, data); + + g_free (filename); +} + +static void +gtk_file_selection_rename_file (gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *button; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + if (strlen(fs->fileop_file) < 1) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Rename File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + buf = g_strconcat ("Rename file \"", fs->fileop_file, "\" to:", NULL); + label = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + g_free(buf); + + /* New filename entry */ + fs->fileop_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, + TRUE, TRUE, 5); + GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT); + gtk_widget_show (fs->fileop_entry); + + gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file); + gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry), + 0, strlen (fs->fileop_file)); + + /* buttons */ + button = gtk_button_new_with_label (_("Rename")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static mode_t +gtk_file_selection_properties_get_mode (PropertiesPrivate* priv) +{ + mode_t mode = 0; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[0]))) + mode |= S_IRUSR; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[1]))) + mode |= S_IWUSR; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[2]))) + mode |= S_IXUSR; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[3]))) + mode |= S_ISUID; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[4]))) + mode |= S_IRGRP; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[5]))) + mode |= S_IWGRP; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[6]))) + mode |= S_IXGRP; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[7]))) + mode |= S_ISGID; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[8]))) + mode |= S_IROTH; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[9]))) + mode |= S_IWOTH; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[10]))) + mode |= S_IXOTH; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->mode_buttons[11]))) + mode |= S_ISVTX; + + return mode; +} + +static void +gtk_file_selection_properties_update_mode (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + PropertiesPrivate *priv = fs->fileop_data; + gchar str[8]; + + sprintf (str, "(%.4o)", gtk_file_selection_properties_get_mode (priv)); + gtk_label_set (GTK_LABEL (priv->mode_label), str); +} + +static void +gtk_file_selection_properties (gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *button; + GtkWidget *notebook; + GtkWidget *table; + GtkWidget *hseparator; + GtkWidget *entry; + GtkWidget *togglebutton; + struct stat statbuf; + struct passwd *pw; + struct group *gp; + gchar *buf; + gchar *path; + gchar *filename; + gchar timeBuf[TIME_STRING_BUF]; + gint pagenum = 0; + PropertiesPrivate *priv; + int i; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + priv = fs->fileop_data = g_malloc (sizeof (PropertiesPrivate)); + + gtk_window_set_title (GTK_WINDOW (dialog), ("Properties")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + /* Dialog guts go here */ + notebook = gtk_notebook_new (); + gtk_widget_show (notebook); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), notebook, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (notebook), 8); + + path = cmpl_reference_position(fs->cmpl_state); + fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + filename = g_strconcat(path, "/", fs->fileop_file, NULL); + if (strlen(fs->fileop_file) > 0 && !(stat(filename, &statbuf))) + { + /* stats page */ + table = gtk_table_new (9, 2, FALSE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (notebook), table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_table_set_row_spacings (GTK_TABLE (table), 4); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + + label = gtk_label_new (_("Statistics")); + gtk_widget_show (label); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum), label); + pagenum++; + /* path and filename */ + label = gtk_label_new (_("Path:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new (_(path)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new (_("File Name:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + fs->fileop_entry = entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_text (GTK_ENTRY (entry), fs->fileop_file); + if (access (filename, W_OK)) + gtk_widget_set_sensitive( GTK_WIDGET (entry), FALSE); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table), hseparator, 0, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + /* file type and size */ + label = gtk_label_new (_("Type:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + switch (statbuf.st_mode & S_IFMT) + { + case S_IFSOCK: + buf = g_strdup ("Socket"); + break; + case S_IFLNK: + buf = g_strdup ("Symbolic link"); + break; + case S_IFREG: + buf = g_strdup ("File"); + break; + case S_IFBLK: + buf = g_strdup ("Block device"); + break; + case S_IFDIR: + buf = g_strdup ("Directory"); + break; + case S_IFCHR: + buf = g_strdup ("Character device"); + break; + case S_IFIFO: + buf = g_strdup ("First-in/first-out pipe"); + break; + default: + buf = g_strdup ("Unknown"); + } + + + label = gtk_label_new (buf); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new (_("Size:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new (_(g_strdup_printf ("%ld bytes", statbuf.st_size))); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table), hseparator, 0, 2, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + /* file dates */ + label = gtk_label_new (_("Created:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + strftime (timeBuf, TIME_STRING_BUF, "%a %b %d %X %Y", localtime(&statbuf.st_mtime)); + label = gtk_label_new (_(timeBuf)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + + + label = gtk_label_new (_("Modified:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + strftime (timeBuf, TIME_STRING_BUF, "%a %b %d %X %Y", localtime(&statbuf.st_mtime)); + label = gtk_label_new (_(timeBuf)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + + label = gtk_label_new (_("Accessed:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + strftime (timeBuf, TIME_STRING_BUF, "%a %b %d %X %Y", localtime(&statbuf.st_atime)); + label = gtk_label_new (_(timeBuf)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + /* permissions page */ + vbox = gtk_vbox_new (FALSE, 4); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (notebook), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new (_("Permissions")); + gtk_widget_show (label); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum), label); + pagenum++; + + /* owner / group */ + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 8); + + label = gtk_label_new (_("Owner:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new(); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((pw = getpwuid(statbuf.st_uid))) + gtk_entry_set_text(GTK_ENTRY (entry), pw->pw_name); + else + gtk_entry_set_text(GTK_ENTRY (entry), (gpointer) statbuf.st_uid); + if (access (filename, W_OK) || (getuid() != 0)) + gtk_widget_set_sensitive( GTK_WIDGET (entry), FALSE); + + + label = gtk_label_new (_("Group:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new(); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((gp = getgrgid(statbuf.st_gid))) + gtk_entry_set_text(GTK_ENTRY (entry), gp->gr_name); + else + gtk_entry_set_text(GTK_ENTRY (entry), (gpointer) statbuf.st_gid); + if (access (filename, W_OK) || (getuid() != 0)) + gtk_widget_set_sensitive( GTK_WIDGET (entry), FALSE); + + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_box_pack_start (GTK_BOX (vbox), hseparator, FALSE, TRUE, 0); + + /* permissions */ + table = gtk_table_new (4, 5, TRUE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + if (access (filename, W_OK) || ((getuid() != statbuf.st_uid) && getuid() != 0)) + gtk_widget_set_sensitive (GTK_WIDGET (table), FALSE); + + hbox = gtk_hbox_new (FALSE, 1); + gtk_widget_show (hbox); + gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + priv->mode_label = label = gtk_label_new ("(0000)"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + label = gtk_label_new (_("Read")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (_("Write")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (_("Exec")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (_("Special")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 4, 5, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + + label = gtk_label_new (_("User:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + priv->mode_buttons[0] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IRUSR) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[1] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IWUSR) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[2] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IXUSR) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[3] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 4, 5, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_ISUID) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + + + label = gtk_label_new (_("Group:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + priv->mode_buttons[4] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IRGRP) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[5] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IWGRP) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[6] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IXGRP) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[7] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 4, 5, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_ISGID) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + label = gtk_label_new (_("Other:")); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + priv->mode_buttons[8] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IROTH) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[9] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IWOTH) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[10] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_IXOTH) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + priv->mode_buttons[11] = togglebutton = gtk_toggle_button_new_with_label (""); + gtk_widget_show (togglebutton); + gtk_table_attach (GTK_TABLE (table), togglebutton, 4, 5, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if ((statbuf.st_mode & ~(S_IFMT)) & S_ISVTX) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), TRUE); + + for (i = 0; i < 12; i++) + gtk_signal_connect (GTK_OBJECT (priv->mode_buttons[i]), "toggled", + GTK_SIGNAL_FUNC (gtk_file_selection_properties_update_mode), fs); + gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (priv->mode_buttons[0])); + } + /* global page */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (notebook), vbox); + + label = gtk_label_new (_("Global")); + gtk_widget_show (label); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum), label); + pagenum++; + + label = gtk_label_new (_("dialog preferances will go here")); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + /* end of dialog guts */ + + /* buttons */ + button = gtk_button_new_with_label (_("OK")); + // gtk_signal_connect (GTK_OBJECT (button), "clicked", + // (GtkSignalFunc) gtk_file_selection_rename_file_confirmed, + // (gpointer) fs); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_file_mode_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + g_free (filename); + gtk_widget_show (dialog); +} + +static gint +gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + + GtkFileSelection *fs; + char *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + + if (fs->saved_entry) + { + gtk_clist_unselect_all ((GtkCList *) (fs->dir_list)); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + if (event->keyval == GDK_Tab) + { + text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + + text = g_strdup (text); + + gtk_file_selection_populate (fs, text, TRUE); + + g_free (text); + + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + + return TRUE; + } + + + return FALSE; +} + +/* +static void +gtk_file_selection_home_button (GtkWidget *widget, gpointer data){ + GList *list; + + GtkFileSelection *fs=data; + + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs,"~/",FALSE); +} +*/ +static void +gtk_file_selection_bookmark_button (GtkWidget *widget, + GtkFileSelection *fs) +{ + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_FILE_SELECTION (fs)); + + gtk_menu_popup (GTK_MENU (fs->bookmark_menu), NULL, NULL, NULL, NULL, + 0, 0); + +} + +static void +gtk_file_selection_up_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs, "../", FALSE); /*change directories. */ + +} + +static void +gtk_file_selection_prev_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + GList *first; + gchar *path; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->prev_history; + + if (list && g_list_length(list) > 1) + { + first = list; /* get first element */ + list = list->next; /* pop off current directory */ + + list->prev = NULL; /* make this the new head. */ + + fs->prev_history = list; /* update prev_history list */ + fs->next_history = g_list_prepend(fs->next_history,first->data); /* put it on next_history */ + + first->next = NULL; /* orphan the old first node */ + g_list_free (first); /* free the node (data is now in use by next_history) */ + + + + path = g_malloc(strlen(list->data)+4); /* plenty of space */ + strcpy(path,list->data); /* get the 2nd path in the history */ + strcat(path,"/"); /* append a '/' */ + gtk_file_selection_populate (fs, path, FALSE); /* change directories. */ + g_free (path); + } +} + +static void +gtk_file_selection_next_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + GList *first; + gchar *path; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->next_history; + + if (list && g_list_length(list) > 0) + { + first = list; /*get first element*/ + list = list->next; /*pop off current directory*/ + + if (list) + list->prev = NULL; + + fs->next_history = list; /*update prev_history list*/ + + path = g_malloc(strlen(first->data)+4); /*plenty of space*/ + strcpy(path,first->data); + strcat(path,"/"); /*append a / */ + gtk_file_selection_populate (fs, path, FALSE); /*change directories.*/ + g_free(path); + + first->next = NULL; /* orphan the old first node */ + g_list_free (first); /* free the node (data is now in use by next_history) */ + + } +} + +void static +gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_file_selection_populate (fs,"",FALSE); +} + +static void +gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + + if(fs->mask) + g_free (fs->mask); + + fs->mask = g_strdup(gtk_entry_get_text (GTK_ENTRY(GTK_COMBO(fs->mask_entry)->entry))); + + if (strlen(fs->mask) == 0) + { + g_free (fs->mask); + fs->mask = NULL; + } + + gtk_file_selection_refresh_button (widget,data); +} + +static gint gtk_file_selection_files_list_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data){ + GtkFileSelection *fs=data; + gchar *saved; + gchar key[2]; + +// g_print("Key event: %d\n",event->keyval); + //we need some sort of timeout. + + //if the key is a normal character then + //add to our saved_entry1 + //if it's backspace then remove one character + //otherwise let it through (and erase our buffer. + + if(event->keyval > GDK_space && event->keyval <= GDK_Korean_Won) { + key[1]=0; + key[0]=event->keyval; + saved=fs->saved_entry1; + if(fs->saved_entry1){ + fs->saved_entry1=g_strconcat(saved,key,NULL); + g_free(saved); + }else{ + fs->saved_entry1=g_strdup(key); + } + g_print("complete: %s\n",fs->saved_entry1); + /*gtk_label_set_text(GTK_LABEL(fs->completion_label), fs->saved_entry1); */ + + saved=g_strdup(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry))); + gtk_file_selection_complete(fs,fs->saved_entry1); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),saved); + g_free(saved); + }else if (event->keyval == GDK_BackSpace) { + if(strlen(fs->saved_entry1)){ + fs->saved_entry1[strlen(fs->saved_entry1)-1]=0; + g_print("complete: %s\n",fs->saved_entry1); + /*gtk_label_set_text(GTK_LABEL(fs->completion_label),fs->saved_entry1); */ + saved=g_strdup(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry))); + gtk_file_selection_complete(fs,fs->saved_entry1); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),saved); + g_free(saved); + } + }else if (event->keyval == GDK_Tab) { + saved=g_strdup(gtk_entry_get_text(GTK_ENTRY(fs->selection_entry))); + gtk_file_selection_populate(fs,fs->saved_entry1,TRUE); + g_free(fs->saved_entry1); + fs->saved_entry1=gtk_entry_get_text(GTK_ENTRY(fs->selection_entry)); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),saved); + g_free(saved); + + g_print("complete: %s\n",fs->saved_entry1); + /* gtk_label_set_text(GTK_LABEL(fs->completion_label),fs->saved_entry1);*/ + + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + }else { + if(fs->saved_entry1){ + g_free(fs->saved_entry1); + fs->saved_entry1=NULL; + } + /* gtk_label_set_text(GTK_LABEL(fs->completion_label)," "); */ + } + + return TRUE; +} + + +static gint gtk_file_selection_mask_entry_key_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + GtkEntry *entry=(GtkEntry *)widget; + GtkFileSelection *fs=data; + + g_return_val_if_fail (fs != NULL,FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs),FALSE); + + + if (event->keyval == GDK_Return || event->keyval == GDK_Tab) + { + if(fs->mask) + g_free(fs->mask); + + fs->mask=g_strdup(gtk_entry_get_text(entry)); + gtk_file_selection_refresh_button(widget,fs); + + if (event->keyval == GDK_Return) + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + return TRUE; + } + else + { + return FALSE; + } +} + +static gint gtk_file_selection_mask_entry_button_callback (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GtkFileSelection *fs = data; + + if(fs->mask) + g_free(fs->mask); + + fs->mask=g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(fs->mask_entry)->entry))); + gtk_file_selection_refresh_button(widget,fs); + + return TRUE; + +} + +static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + /* + g_print("Key pressed! \n"); + */ + + return TRUE; +} + +static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist, + GdkEventButton *event, + gpointer user_data) +{ + + GtkFileSelection *fs = user_data; + GList *list; + gchar *path; + + list = fs->next_history; + if(list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + path = g_malloc(strlen(gtk_entry_get_text(GTK_ENTRY (((GtkCombo *)fs->history_combo)->entry)))+4); + strcpy (path,gtk_entry_get_text(GTK_ENTRY( ((GtkCombo *)fs->history_combo)->entry))); + strcat (path,"/"); + + gtk_file_selection_populate (fs,path,TRUE); + + g_free (path); + + return TRUE; +} + +static gboolean +gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + GtkEntry *entry=(GtkEntry *)widget; + GtkFileSelection *fs=data; + GList *list; + gchar *path; + + g_return_val_if_fail (fs != NULL,FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs),FALSE); + + + if (event->keyval == GDK_Return) + { + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + path = g_malloc(strlen(gtk_entry_get_text(entry))+4); + strcpy (path,gtk_entry_get_text(entry)); + strcat (path,"/"); + gtk_file_selection_populate (fs,path,TRUE); + g_free (path); + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + return TRUE; + } + else + { + return FALSE; + } + +} + + +static void gtk_file_selection_bookmark_callback (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + BookmarkMenuStruct *item; + GList *list; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + +//g_print ("Callback\n"); + list = fs->bookmark_list; + while(list) { + item = list->data; + if (item->menu_item == widget) { + if(strcmp(item->path,"./")) { + gtk_file_selection_populate (fs, item->path, FALSE); + } + break; + } + list=list->next; + } +} + +static void +gtk_file_selection_update_history_menu (GtkFileSelection *fs, + gchar *current_directory) +{ + gchar *current_dir; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + g_return_if_fail (current_directory != NULL); + + current_dir = g_strdup (current_directory); + + if(fs->prev_history) + { + if (strcmp((fs->prev_history)->data,current_dir)) + { /*if this item isn't on the top of the list */ + fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir)); + } + } else { + fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir)); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (fs->history_combo),fs->prev_history); + + g_free (current_dir); +} + +static void +gtk_file_selection_file_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = user_data; + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->file_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (fs->saved_entry) + { + gtk_clist_unselect_all ((GtkCList *) (fs->dir_list)); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + if(fs->saved_entry1){ + g_free(fs->saved_entry1); + fs->saved_entry1=NULL; + } + /* gtk_label_set_text(GTK_LABEL(fs->completion_label)," "); */ + + + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + break; + + default: +/* + if (bevent->button && GDK_BUTTON2_MASK) + { + g_print("Right click! -- %d\n",bevent->button); + } + else + { + */ + + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + /*}*/ + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } +} + +static void +gtk_file_selection_dir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GList *list; + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = GTK_FILE_SELECTION (user_data); + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs, filename, FALSE); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + break; + + default: + /* here we need to add the "filename" to the beginning of what's already + in the entry. Save what's in the entry, then restore it on the double click + */ + if (fs->saved_entry) g_free (fs->saved_entry); + fs->saved_entry=g_strdup(gtk_entry_get_text(GTK_ENTRY (fs->selection_entry))); + + temp=g_strconcat(filename,fs->saved_entry,NULL); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), temp); + g_free (temp); + + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } +} + +static void +gtk_file_selection_undir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = GTK_FILE_SELECTION (user_data); + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + default: + /* here we need to add the "filename" to the beginning of what's already + in the entry. Save what's in the entry, then restore it on the double click + */ + if (fs->saved_entry) + { + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); //????? + + g_free (filename); + } +} + +static void +gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete) +{ + CompletionState *cmpl_state; + PossibleCompletion* poss; + gchar* filename; + gint row; + gchar* rem_path = rel_path; + gchar* sel_text; + gchar* text[2]; + gint did_recurse = FALSE; + gint possible_count = 0; + gint selection_index = -1; + gint file_list_width; + gint dir_list_width; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + cmpl_state = (CompletionState*) fs->cmpl_state; + poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state); + + if (!cmpl_state_okay (cmpl_state)) + { + /* Something went wrong. */ + gtk_file_selection_abort (fs); + return; + } + + g_assert (cmpl_state->reference_dir); + + gtk_clist_freeze (GTK_CLIST (fs->dir_list)); + gtk_clist_clear (GTK_CLIST (fs->dir_list)); + gtk_clist_freeze (GTK_CLIST (fs->file_list)); + gtk_clist_clear (GTK_CLIST (fs->file_list)); + + /* Set the dir_list to include ./ and ../ */ + /* Actually, no let's not. + text[1] = NULL; + text[0] = "./"; + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + */ + + text[0] = "../"; //Do we need ..? + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + + /*reset the max widths of the lists*/ + dir_list_width = gdk_string_width(fs->dir_list->style->font,"../"); + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0,dir_list_width); + file_list_width = 1; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,file_list_width); + + while (poss) + { + if (cmpl_is_a_completion (poss)) + { + possible_count += 1; + + filename = cmpl_this_completion (poss); + + text[0] = filename; + + if (cmpl_is_directory (poss)) + { + if (strcmp (filename, "./") != 0 && + strcmp (filename, "../") != 0) + { + int width = gdk_string_width(fs->dir_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + if(width > dir_list_width) + { + dir_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0, + width); + } + } + } + else + { + if(fs->mask) + { + if (gtk_file_selection_match_mask(filename,fs->mask)) + { + int width = gdk_string_width(fs->file_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->file_list), text); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } + } + } + else + { + int width = gdk_string_width(fs->file_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->file_list), text); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } + } + } + } + + poss = cmpl_next_completion (cmpl_state); + } + + gtk_clist_thaw (GTK_CLIST (fs->dir_list)); + gtk_clist_thaw (GTK_CLIST (fs->file_list)); + + /* File lists are set. */ + + g_assert (cmpl_state->reference_dir); + + if (try_complete) + { + + /* User is trying to complete filenames, so advance the user's input + * string to the updated_text, which is the common leading substring + * of all possible completions, and if its a directory attempt + * attempt completions in it. */ + + if (cmpl_updated_text (cmpl_state)[0]) + { + + if (cmpl_updated_dir (cmpl_state)) + { + gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state)); + + did_recurse = TRUE; + + gtk_file_selection_populate (fs, dir_name, TRUE); + + g_free (dir_name); + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), + cmpl_updated_text (cmpl_state)); + } + } + else + { + selection_index = cmpl_last_valid_char (cmpl_state) - + (strlen (rel_path) - strlen (rem_path)); + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path); + } + } + else + { + if (fs->selection_entry) + /* Here we need to take the old filename and keep it!*/ + /*gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");*/ + ; + } + + if (!did_recurse) + { + if (fs->selection_entry) + gtk_entry_set_position (GTK_ENTRY (fs->selection_entry), selection_index); + + if (fs->selection_entry) + { + sel_text = g_strconcat (_("Selection: "), + cmpl_reference_position (cmpl_state), + NULL); + +/* + gtk_label_set_text (GTK_LABEL (fs->selection_text), sel_text); +*/ + g_free (sel_text); + } + + gtk_file_selection_update_history_menu (fs, cmpl_reference_position (cmpl_state)); + + } +} + +static void +gtk_file_selection_abort (GtkFileSelection *fs) +{ + gchar err_buf[256]; + + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); + + /* BEEP gdk_beep(); */ + +/* + if (fs->selection_entry) + gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf); +*/ +} + +/**********************************************************************/ +/* External Interface */ +/**********************************************************************/ + +/* The four completion state selectors + */ +static gchar* +cmpl_updated_text (CompletionState* cmpl_state) +{ + return cmpl_state->updated_text; +} + +static gint +cmpl_updated_dir (CompletionState* cmpl_state) +{ + return cmpl_state->re_complete; +} + +static gchar* +cmpl_reference_position (CompletionState* cmpl_state) +{ + return cmpl_state->reference_dir->fullname; +} + +static gint +cmpl_last_valid_char (CompletionState* cmpl_state) +{ + return cmpl_state->last_valid_char; +} + +static gchar* +cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) +{ + static char nothing[2] = ""; + + if (!cmpl_state_okay (cmpl_state)) + { + return nothing; + } + else if (text[0] == '/') + { + strcpy (cmpl_state->updated_text, text); + } + else if (text[0] == '~') + { + CompletionDir* dir; + char* slash; + + dir = open_user_dir (text, cmpl_state); + + if (!dir) + { + /* spencer says just return ~something, so + * for now just do it. */ + strcpy (cmpl_state->updated_text, text); + } + else + { + + strcpy (cmpl_state->updated_text, dir->fullname); + + slash = strchr (text, '/'); + + if (slash) + strcat (cmpl_state->updated_text, slash); + } + } + else + { + strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); + if (strcmp (cmpl_state->reference_dir->fullname, "/") != 0) + strcat (cmpl_state->updated_text, "/"); + strcat (cmpl_state->updated_text, text); + } + + return cmpl_state->updated_text; +} + +/* The three completion selectors + */ +static gchar* +cmpl_this_completion (PossibleCompletion* pc) +{ + return pc->text; +} + +static gint +cmpl_is_directory (PossibleCompletion* pc) +{ + return pc->is_directory; +} + +static gint +cmpl_is_a_completion (PossibleCompletion* pc) +{ + return pc->is_a_completion; +} + +/**********************************************************************/ +/* Construction, deletion */ +/**********************************************************************/ + +static CompletionState* +cmpl_init_state (void) +{ + gchar getcwd_buf[2*MAXPATHLEN]; + CompletionState *new_state; + + new_state = g_new (CompletionState, 1); + + /* We don't use getcwd() on SUNOS, because, it does a popen("pwd") + * and, if that wasn't bad enough, hangs in doing so. + */ +#if defined(sun) && !defined(__SVR4) + if (!getwd (getcwd_buf)) +#else + if (!getcwd (getcwd_buf, MAXPATHLEN)) +#endif + { + /* Oh joy, we can't get the current directory. Um..., we should have + * a root directory, right? Right? (Probably not portable to non-Unix) + */ + strcpy (getcwd_buf, "/"); + } + +tryagain: + + new_state->reference_dir = NULL; + new_state->completion_dir = NULL; + new_state->active_completion_dir = NULL; + new_state->directory_storage = NULL; + new_state->directory_sent_storage = NULL; + new_state->last_valid_char = 0; + new_state->updated_text = g_new (gchar, MAXPATHLEN); + new_state->updated_text_alloc = MAXPATHLEN; + new_state->the_completion.text = g_new (gchar, MAXPATHLEN); + new_state->the_completion.text_alloc = MAXPATHLEN; + new_state->user_dir_name_buffer = NULL; + new_state->user_directories = NULL; + + new_state->reference_dir = open_dir (getcwd_buf, new_state); + + if (!new_state->reference_dir) + { + /* Directories changing from underneath us, grumble */ + strcpy (getcwd_buf, "/"); + goto tryagain; + } + + return new_state; +} + +static void +cmpl_free_dir_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_dir_sent_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir_sent (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_state (CompletionState* cmpl_state) +{ + cmpl_free_dir_list (cmpl_state->directory_storage); + cmpl_free_dir_sent_list (cmpl_state->directory_sent_storage); + + if (cmpl_state->user_dir_name_buffer) + g_free (cmpl_state->user_dir_name_buffer); + if (cmpl_state->user_directories) + g_free (cmpl_state->user_directories); + if (cmpl_state->the_completion.text) + g_free (cmpl_state->the_completion.text); + if (cmpl_state->updated_text) + g_free (cmpl_state->updated_text); + + g_free (cmpl_state); +} + +static void +free_dir(CompletionDir* dir) +{ + g_free(dir->fullname); + g_free(dir); +} + +static void +free_dir_sent(CompletionDirSent* sent) +{ + g_free(sent->name_buffer); + g_free(sent->entries); + g_free(sent); +} + +static void +prune_memory_usage(CompletionState *cmpl_state) +{ + GList* cdsl = cmpl_state->directory_sent_storage; + GList* cdl = cmpl_state->directory_storage; + GList* cdl0 = cdl; + gint len = 0; + + for(; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1) + cdsl = cdsl->next; + + if (cdsl) { + cmpl_free_dir_sent_list(cdsl->next); + cdsl->next = NULL; + } + + cmpl_state->directory_storage = NULL; + while (cdl) { + if (cdl->data == cmpl_state->reference_dir) + cmpl_state->directory_storage = g_list_prepend(NULL, cdl->data); + else + free_dir (cdl->data); + cdl = cdl->next; + } + + g_list_free(cdl0); +} + +/**********************************************************************/ +/* The main entrances. */ +/**********************************************************************/ + +static PossibleCompletion* +cmpl_completion_matches (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + PossibleCompletion *poss; + + prune_memory_usage(cmpl_state); + + g_assert (text_to_complete != NULL); + + cmpl_state->user_completion_index = -1; + cmpl_state->last_completion_text = text_to_complete; + cmpl_state->the_completion.text[0] = 0; + cmpl_state->last_valid_char = 0; + cmpl_state->updated_text_len = -1; + cmpl_state->updated_text[0] = 0; + cmpl_state->re_complete = FALSE; + + first_slash = strchr (text_to_complete, '/'); + + if (text_to_complete[0] == '~' && !first_slash) + { + /* Text starts with ~ and there is no slash, show all the + * home directory completions. + */ + poss = attempt_homedir_completion (text_to_complete, cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; + } + + cmpl_state->reference_dir = + open_ref_dir (text_to_complete, remaining_text, cmpl_state); + + if(!cmpl_state->reference_dir) + return NULL; + + cmpl_state->completion_dir = + find_completion_dir (*remaining_text, remaining_text, cmpl_state); + + cmpl_state->last_valid_char = *remaining_text - text_to_complete; + + if(!cmpl_state->completion_dir) + return NULL; + + cmpl_state->completion_dir->cmpl_index = -1; + cmpl_state->completion_dir->cmpl_parent = NULL; + cmpl_state->completion_dir->cmpl_text = *remaining_text; + + cmpl_state->active_completion_dir = cmpl_state->completion_dir; + + cmpl_state->reference_dir = cmpl_state->completion_dir; + + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +static PossibleCompletion* +cmpl_next_completion (CompletionState* cmpl_state) +{ + PossibleCompletion* poss = NULL; + + cmpl_state->the_completion.text[0] = 0; + + if(cmpl_state->user_completion_index >= 0) + poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state); + else + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +/**********************************************************************/ +/* Directory Operations */ +/**********************************************************************/ + +/* Open the directory where completion will begin from, if possible. */ +static CompletionDir* +open_ref_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + CompletionDir *new_dir; + + first_slash = strchr(text_to_complete, '/'); + + if (text_to_complete[0] == '~') + { + new_dir = open_user_dir(text_to_complete, cmpl_state); + + if(new_dir) + { + if(first_slash) + *remaining_text = first_slash + 1; + else + *remaining_text = text_to_complete + strlen(text_to_complete); + } + else + { + return NULL; + } + } + else if (text_to_complete[0] == '/' || !cmpl_state->reference_dir) + { + gchar *tmp = g_strdup(text_to_complete); + gchar *p; + + p = tmp; + while (*p && *p != '*' && *p != '?') + p++; + + *p = '\0'; + p = strrchr(tmp, '/'); + if (p) + { + if (p == tmp) + p++; + + *p = '\0'; + + new_dir = open_dir(tmp, cmpl_state); + + if(new_dir) + *remaining_text = text_to_complete + + ((p == tmp + 1) ? (p - tmp) : (p + 1 - tmp)); + } + else + { + /* If no possible candidates, use the cwd */ + gchar *curdir = g_get_current_dir (); + + new_dir = open_dir(curdir, cmpl_state); + + if (new_dir) + *remaining_text = text_to_complete; + + g_free (curdir); + } + + g_free (tmp); + } + else + { + *remaining_text = text_to_complete; + + new_dir = open_dir(cmpl_state->reference_dir->fullname, cmpl_state); + } + + if(new_dir) + { + new_dir->cmpl_index = -1; + new_dir->cmpl_parent = NULL; + } + + return new_dir; +} + +/* open a directory by user name */ +static CompletionDir* +open_user_dir(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gchar *first_slash; + gint cmp_len; + + g_assert(text_to_complete && text_to_complete[0] == '~'); + + first_slash = strchr(text_to_complete, '/'); + + if (first_slash) + cmp_len = first_slash - text_to_complete - 1; + else + cmp_len = strlen(text_to_complete + 1); + + if(!cmp_len) + { + /* ~/ */ + gchar *homedir = g_get_home_dir (); + + if (homedir) + return open_dir(homedir, cmpl_state); + else + return NULL; + } + else + { + /* ~user/ */ + char* copy = g_new(char, cmp_len + 1); + struct passwd *pwd; + strncpy(copy, text_to_complete + 1, cmp_len); + copy[cmp_len] = 0; + pwd = getpwnam(copy); + g_free(copy); + if (!pwd) + { + cmpl_errno = errno; + return NULL; + } + + return open_dir(pwd->pw_dir, cmpl_state); + } +} + +/* open a directory relative the the current relative directory */ +static CompletionDir* +open_relative_dir(gchar* dir_name, + CompletionDir* dir, + CompletionState *cmpl_state) +{ + gchar path_buf[2*MAXPATHLEN]; + + if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir->fullname); + + if(dir->fullname_len > 1) + { + path_buf[dir->fullname_len] = '/'; + strcpy(path_buf + dir->fullname_len + 1, dir_name); + } + else + { + strcpy(path_buf + dir->fullname_len, dir_name); + } + + return open_dir(path_buf, cmpl_state); +} + +/* after the cache lookup fails, really open a new directory */ +static CompletionDirSent* +open_new_dir(gchar* dir_name, struct stat* sbuf, gboolean stat_subdirs) +{ + CompletionDirSent* sent; + DIR* directory; + gchar *buffer_ptr; + struct dirent *dirent_ptr; + gint buffer_size = 0; + gint entry_count = 0; + gint i; + struct stat ent_sbuf; + char path_buf[MAXPATHLEN*2]; + gint path_buf_len; + + sent = g_new(CompletionDirSent, 1); + sent->mtime = sbuf->st_mtime; + sent->inode = sbuf->st_ino; + sent->device = sbuf->st_dev; + + path_buf_len = strlen(dir_name); + + if (path_buf_len > MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir_name); + + directory = opendir(dir_name); + + if(!directory) + { + cmpl_errno = errno; + return NULL; + } + + while((dirent_ptr = readdir(directory)) != NULL) + { + int entry_len = strlen(dirent_ptr->d_name); + buffer_size += entry_len + 1; + entry_count += 1; + + if(path_buf_len + entry_len + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + closedir(directory); + return NULL; + } + } + + sent->name_buffer = g_new(gchar, buffer_size); + sent->entries = g_new(CompletionDirEntry, entry_count); + sent->entry_count = entry_count; + + buffer_ptr = sent->name_buffer; + + rewinddir(directory); + + for(i = 0; i < entry_count; i += 1) + { + dirent_ptr = readdir(directory); + + if(!dirent_ptr) + { + cmpl_errno = errno; + closedir(directory); + return NULL; + } + + strcpy(buffer_ptr, dirent_ptr->d_name); + sent->entries[i].entry_name = buffer_ptr; + buffer_ptr += strlen(dirent_ptr->d_name); + *buffer_ptr = 0; + buffer_ptr += 1; + + path_buf[path_buf_len] = '/'; + strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); + + if (stat_subdirs) + { + if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) + sent->entries[i].is_dir = 1; + else + /* stat may fail, and we don't mind, since it could be a + * dangling symlink. */ + sent->entries[i].is_dir = 0; + } + else + sent->entries[i].is_dir = 1; + } + + qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); + + closedir(directory); + + return sent; +} + +static gboolean +check_dir(gchar *dir_name, struct stat *result, gboolean *stat_subdirs) +{ + /* A list of directories that we know only contain other directories. + * Trying to stat every file in these directories would be very + * expensive. + */ + + static struct { + gchar *name; + gboolean present; + struct stat statbuf; + } no_stat_dirs[] = { + { "/afs", FALSE, { 0 } }, + { "/net", FALSE, { 0 } } + }; + + static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]); + static gboolean initialized = FALSE; + + gint i; + + if (!initialized) + { + initialized = TRUE; + for (i = 0; i < n_no_stat_dirs; i++) + { + if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0) + no_stat_dirs[i].present = TRUE; + } + } + + if(stat(dir_name, result) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + *stat_subdirs = TRUE; + for (i=0; ist_dev) && + (no_stat_dirs[i].statbuf.st_ino == result->st_ino)) + { + *stat_subdirs = FALSE; + break; + } + } + + return TRUE; +} + +/* open a directory by absolute pathname */ +static CompletionDir* +open_dir(gchar* dir_name, CompletionState* cmpl_state) +{ + struct stat sbuf; + gboolean stat_subdirs; + CompletionDirSent *sent; + GList* cdsl; + + if (!check_dir (dir_name, &sbuf, &stat_subdirs)) + return NULL; + + cdsl = cmpl_state->directory_sent_storage; + + while (cdsl) + { + sent = cdsl->data; + + if(sent->inode == sbuf.st_ino && + sent->mtime == sbuf.st_mtime && + sent->device == sbuf.st_dev) + return attach_dir(sent, dir_name, cmpl_state); + + cdsl = cdsl->next; + } + + sent = open_new_dir(dir_name, &sbuf, stat_subdirs); + + if (sent) { + cmpl_state->directory_sent_storage = + g_list_prepend(cmpl_state->directory_sent_storage, sent); + + return attach_dir(sent, dir_name, cmpl_state); + } + + return NULL; +} + +static CompletionDir* +attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state) +{ + CompletionDir* new_dir; + + new_dir = g_new(CompletionDir, 1); + + cmpl_state->directory_storage = + g_list_prepend(cmpl_state->directory_storage, new_dir); + + new_dir->sent = sent; + new_dir->fullname = g_strdup(dir_name); + new_dir->fullname_len = strlen(dir_name); + + return new_dir; +} + +static gint +correct_dir_fullname(CompletionDir* cmpl_dir) +{ + gint length = strlen(cmpl_dir->fullname); + struct stat sbuf; + + if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) + { + if (length == 2) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } else { + cmpl_dir->fullname[length - 2] = 0; + } + } + else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) + cmpl_dir->fullname[length - 2] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) + { + if(length == 3) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 2] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) + { + if(length == 4) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 3] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + + cmpl_dir->fullname_len = strlen(cmpl_dir->fullname); + + return TRUE; +} + +static gint +correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) +{ + struct stat parbuf; + gchar *last_slash; + gchar *new_name; + gchar c = 0; + + last_slash = strrchr(cmpl_dir->fullname, '/'); + + g_assert(last_slash); + + if(last_slash != cmpl_dir->fullname) + { /* last_slash[0] = 0; */ } + else + { + c = last_slash[1]; + last_slash[1] = 0; + } + + if (stat(cmpl_dir->fullname, &parbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) + /* it wasn't a link */ + return TRUE; + + if(c) + last_slash[1] = c; + /* else + last_slash[0] = '/'; */ + + /* it was a link, have to figure it out the hard way */ + + new_name = find_parent_dir_fullname(cmpl_dir->fullname); + + if (!new_name) + return FALSE; + + g_free(cmpl_dir->fullname); + + cmpl_dir->fullname = new_name; + + return TRUE; +} + +static gchar* +find_parent_dir_fullname(gchar* dirname) +{ + gchar buffer[MAXPATHLEN]; + gchar buffer2[MAXPATHLEN]; + +#if defined(sun) && !defined(__SVR4) + if(!getwd(buffer)) +#else + if(!getcwd(buffer, MAXPATHLEN)) +#endif + { + cmpl_errno = errno; + return NULL; + } + + if(chdir(dirname) != 0 || chdir("..") != 0) + { + cmpl_errno = errno; + return NULL; + } + +#if defined(sun) && !defined(__SVR4) + if(!getwd(buffer2)) +#else + if(!getcwd(buffer2, MAXPATHLEN)) +#endif + { + chdir(buffer); + cmpl_errno = errno; + + return NULL; + } + + if(chdir(buffer) != 0) + { + cmpl_errno = errno; + return NULL; + } + + return g_strdup(buffer2); +} + +/**********************************************************************/ +/* Completion Operations */ +/**********************************************************************/ + +static PossibleCompletion* +attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gint index, length; + + if (!cmpl_state->user_dir_name_buffer && + !get_pwdb(cmpl_state)) + return NULL; + length = strlen(text_to_complete) - 1; + + cmpl_state->user_completion_index += 1; + + while(cmpl_state->user_completion_index < cmpl_state->user_directories_len) + { + index = first_diff_index(text_to_complete + 1, + cmpl_state->user_directories + [cmpl_state->user_completion_index].login); + + switch(index) + { + case PATTERN_MATCH: + break; + default: + if(cmpl_state->last_valid_char < (index + 1)) + cmpl_state->last_valid_char = index + 1; + cmpl_state->user_completion_index += 1; + continue; + } + + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + append_completion_text("~", cmpl_state); + + append_completion_text(cmpl_state-> + user_directories[cmpl_state->user_completion_index].login, + cmpl_state); + + return append_completion_text("/", cmpl_state); + } + + if(text_to_complete[1] || + cmpl_state->user_completion_index > cmpl_state->user_directories_len) + { + cmpl_state->user_completion_index = -1; + return NULL; + } + else + { + cmpl_state->user_completion_index += 1; + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + return append_completion_text("~/", cmpl_state); + } +} + +/* returns the index (>= 0) of the first differing character, + * PATTERN_MATCH if the completion matches */ +static gint +first_diff_index(gchar* pat, gchar* text) +{ + gint diff = 0; + + while(*pat && *text && *text == *pat) + { + pat += 1; + text += 1; + diff += 1; + } + + if(*pat) + return diff; + + return PATTERN_MATCH; +} + +static PossibleCompletion* +append_completion_text(gchar* text, CompletionState* cmpl_state) +{ + gint len, i = 1; + + if(!cmpl_state->the_completion.text) + return NULL; + + len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1; + + if(cmpl_state->the_completion.text_alloc > len) + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } + + while(i < len) { i <<= 1; } + + cmpl_state->the_completion.text_alloc = i; + + cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i); + + if(!cmpl_state->the_completion.text) + return NULL; + else + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } +} + +static CompletionDir* +find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash = strchr(text_to_complete, '/'); + CompletionDir* dir = cmpl_state->reference_dir; + CompletionDir* next; + *remaining_text = text_to_complete; + + while(first_slash) + { + gint len = first_slash - *remaining_text; + gint found = 0; + gchar *found_name = NULL; /* Quiet gcc */ + gint i; + gchar* pat_buf = g_new (gchar, len + 1); + + strncpy(pat_buf, *remaining_text, len); + pat_buf[len] = 0; + + for(i = 0; i < dir->sent->entry_count; i += 1) + { + if(dir->sent->entries[i].is_dir && + fnmatch(pat_buf, dir->sent->entries[i].entry_name, + FNMATCH_FLAGS)!= FNM_NOMATCH) + { + if(found) + { + g_free (pat_buf); + return dir; + } + else + { + found = 1; + found_name = dir->sent->entries[i].entry_name; + } + } + } + + if (!found) + { + /* Perhaps we are trying to open an automount directory */ + found_name = pat_buf; + } + + next = open_relative_dir(found_name, dir, cmpl_state); + + if(!next) + { + g_free (pat_buf); + return NULL; + } + + next->cmpl_parent = dir; + + dir = next; + + if(!correct_dir_fullname(dir)) + { + g_free(pat_buf); + return NULL; + } + + *remaining_text = first_slash + 1; + first_slash = strchr(*remaining_text, '/'); + + g_free (pat_buf); + } + + return dir; +} + +static void +update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state) +{ + gint cmpl_len; + + if(!poss || !cmpl_is_a_completion(poss)) + return; + + cmpl_len = strlen(cmpl_this_completion(poss)); + + if(cmpl_state->updated_text_alloc < cmpl_len + 1) + { + cmpl_state->updated_text = + (gchar*)g_realloc(cmpl_state->updated_text, + cmpl_state->updated_text_alloc); + cmpl_state->updated_text_alloc = 2*cmpl_len; + } + + if(cmpl_state->updated_text_len < 0) + { + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + cmpl_state->updated_text_len = cmpl_len; + cmpl_state->re_complete = cmpl_is_directory(poss); + } + else if(cmpl_state->updated_text_len == 0) + { + cmpl_state->re_complete = FALSE; + } + else + { + gint first_diff = + first_diff_index(cmpl_state->updated_text, + cmpl_this_completion(poss)); + + cmpl_state->re_complete = FALSE; + + if(first_diff == PATTERN_MATCH) + return; + + if(first_diff > cmpl_state->updated_text_len) + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + + cmpl_state->updated_text_len = first_diff; + cmpl_state->updated_text[first_diff] = 0; + } +} + +static PossibleCompletion* +attempt_file_completion(CompletionState *cmpl_state) +{ + gchar *pat_buf, *first_slash; + CompletionDir *dir = cmpl_state->active_completion_dir; + + dir->cmpl_index += 1; + + if(dir->cmpl_index == dir->sent->entry_count) + { + if(dir->cmpl_parent == NULL) + { + cmpl_state->active_completion_dir = NULL; + + return NULL; + } + else + { + cmpl_state->active_completion_dir = dir->cmpl_parent; + + return attempt_file_completion(cmpl_state); + } + } + + g_assert(dir->cmpl_text); + + first_slash = strchr(dir->cmpl_text, '/'); + + if(first_slash) + { + gint len = first_slash - dir->cmpl_text; + + pat_buf = g_new (gchar, len + 1); + strncpy(pat_buf, dir->cmpl_text, len); + pat_buf[len] = 0; + } + else + { + gint len = strlen(dir->cmpl_text); + + pat_buf = g_new (gchar, len + 2); + strcpy(pat_buf, dir->cmpl_text); + strcpy(pat_buf + len, "*"); + } + + if(first_slash) + { + if(dir->sent->entries[dir->cmpl_index].is_dir) + { + if(fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH) + { + CompletionDir* new_dir; + + new_dir = open_relative_dir(dir->sent->entries[dir->cmpl_index].entry_name, + dir, cmpl_state); + + if(!new_dir) + { + g_free (pat_buf); + return NULL; + } + + new_dir->cmpl_parent = dir; + + new_dir->cmpl_index = -1; + new_dir->cmpl_text = first_slash + 1; + + cmpl_state->active_completion_dir = new_dir; + + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + if(dir->cmpl_parent != NULL) + { + append_completion_text(dir->fullname + + strlen(cmpl_state->completion_dir->fullname) + 1, + cmpl_state); + append_completion_text("/", cmpl_state); + } + + append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); + + cmpl_state->the_completion.is_a_completion = + (fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH); + + cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; + if(dir->sent->entries[dir->cmpl_index].is_dir) + append_completion_text("/", cmpl_state); + + g_free (pat_buf); + return &cmpl_state->the_completion; + } +} + + +static gint +get_pwdb(CompletionState* cmpl_state) +{ + struct passwd *pwd_ptr; + gchar* buf_ptr; + gint len = 0, i, count = 0; + + if(cmpl_state->user_dir_name_buffer) + return TRUE; + setpwent (); + + while ((pwd_ptr = getpwent()) != NULL) + { + len += strlen(pwd_ptr->pw_name); + len += strlen(pwd_ptr->pw_dir); + len += 2; + count += 1; + } + + setpwent (); + + cmpl_state->user_dir_name_buffer = g_new(gchar, len); + cmpl_state->user_directories = g_new(CompletionUserDir, count); + cmpl_state->user_directories_len = count; + + buf_ptr = cmpl_state->user_dir_name_buffer; + + for(i = 0; i < count; i += 1) + { + pwd_ptr = getpwent(); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + + strcpy(buf_ptr, pwd_ptr->pw_name); + cmpl_state->user_directories[i].login = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + strcpy(buf_ptr, pwd_ptr->pw_dir); + cmpl_state->user_directories[i].homedir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + qsort(cmpl_state->user_directories, + cmpl_state->user_directories_len, + sizeof(CompletionUserDir), + compare_user_dir); + + endpwent(); + + return TRUE; + +error: + + if(cmpl_state->user_dir_name_buffer) + g_free(cmpl_state->user_dir_name_buffer); + if(cmpl_state->user_directories) + g_free(cmpl_state->user_directories); + + cmpl_state->user_dir_name_buffer = NULL; + cmpl_state->user_directories = NULL; + + return FALSE; +} + +static gint +compare_user_dir(const void* a, const void* b) +{ + return strcmp((((CompletionUserDir*)a))->login, + (((CompletionUserDir*)b))->login); +} + +static gint +compare_cmpl_dir(const void* a, const void* b) +{ + return strcmp((((CompletionDirEntry*)a))->entry_name, + (((CompletionDirEntry*)b))->entry_name); +} + +static gint +cmpl_state_okay(CompletionState* cmpl_state) +{ + return cmpl_state && cmpl_state->reference_dir; +} + +static gchar* +cmpl_strerror(gint err) +{ + if(err == CMPL_ERRNO_TOO_LONG) + return "Name too long"; + else + return g_strerror (err); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap(GtkWidget *widget, const gchar *pixmap_char) +{ + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GdkColormap *colormap; + + colormap = gtk_widget_get_colormap (widget); + + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (GTK_WIDGET(widget)->window, + colormap, + &mask, + NULL, + (gpointer) pixmap_char); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap: %s", pixmap_char); + return NULL; + } + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + + +/* Testing area */ +#ifdef TORRIE_DEBUG + +/* Get the selected filename and print it to the console */ +void file_ok_sel( GtkWidget *w, + GtkFileSelection *fs ) +{ + g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); +} + +void destroy( GtkWidget *widget, + gpointer data ) +{ + gtk_main_quit (); +} + +int main( int argc, + char *argv[] ) +{ + GtkWidget *filew; + const gchar *masks[] = { "mp3s/playlists <*.mp3,*.m3u>", + "src/hdr <*.[CcHh],*.[Cc][Cc],*.[Hh][Hh],*.cpp>", + NULL }; + + gtk_init (&argc, &argv); + + /* Create a new file selection widget */ + filew = gtk_file_selection_new ("Spiffy File Selector"); +// gtk_file_selection_complete(GTK_FILE_SELECTION(filew),"bob"); + + gtk_file_selection_set_masks (GTK_FILE_SELECTION (filew), masks); + + gtk_signal_connect (GTK_OBJECT (filew), "destroy", + (GtkSignalFunc) destroy, &filew); + /* Connect the ok_button to file_ok_sel function */ + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), + "clicked", (GtkSignalFunc) file_ok_sel, filew ); + + /* Connect the cancel_button to destroy the widget */ + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION + (filew)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (filew)); + + + gtk_widget_show(filew); + +/* + g_print("%d",gtk_file_selection_match_mask("mask.c","m*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.c","m???.c")); + g_print("%d",gtk_file_selection_match_mask("mask.c","m??*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c???")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c*")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","n*.c???")); + g_print("%d",gtk_file_selection_match_mask("mask.c","[mn]*")); + g_print("%d",gtk_file_selection_match_mask("COPYING","*.xpm")); +*/ + gtk_main (); + + return 0; +} +/* example-end */ +#endif diff --git a/radiant/gtkfilesel-linux.h b/radiant/gtkfilesel-linux.h new file mode 100644 index 00000000..5fb1c29e --- /dev/null +++ b/radiant/gtkfilesel-linux.h @@ -0,0 +1,143 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_FILESEL_H__ +#define __GTK_FILESEL_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TYPE_FILE_SELECTION (gtk_file_selection_get_type ()) +#define GTK_FILE_SELECTION(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_FILE_SELECTION, GtkFileSelection)) +#define GTK_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SELECTION, GtkFileSelectionClass)) +#define GTK_IS_FILE_SELECTION(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_FILE_SELECTION)) +#define GTK_IS_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SELECTION)) + + +typedef struct _GtkFileSelection GtkFileSelection; +typedef struct _GtkFileSelectionClass GtkFileSelectionClass; + +struct _GtkFileSelection +{ + GtkWindow window; + + GtkWidget *dir_list; + GtkWidget *file_list; + GtkWidget *selection_entry; + GtkWidget *selection_text; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *cancel_button; + GtkWidget *help_button; + + /* These are not used. Just fillers in the class structure */ + GtkWidget *history_pulldown; + GtkWidget *history_menu; + GList *history_list; + /* ***************** */ + + GtkWidget *fileop_dialog; + GtkWidget *fileop_entry; + gchar *fileop_file; + gpointer cmpl_state; + gpointer fileop_data; + + GtkWidget *fileop_c_dir; + GtkWidget *fileop_del_file; + GtkWidget *fileop_ren_file; + + GtkWidget *button_area; + GtkWidget *action_area; + + GtkWidget *history_combo; + GList *prev_history; + GList *next_history; + GtkWidget *mask_entry; + gchar *mask; + gchar *saved_entry; + gchar *saved_entry1; + GtkWidget *completion_label; + + GtkWidget *bookmark_menu; + GList *bookmark_list; + GList *masks; + + GtkWidget *fileop_menu; + +}; + +struct _GtkFileSelectionClass +{ + GtkWindowClass parent_class; +}; + + +GtkType gtk_file_selection_get_type (void); +GtkWidget* gtk_file_selection_new (const gchar *title); +void gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename); +gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel); +void gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern); +void gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel); +void gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel); + +/* proposed interface */ +void gtk_file_selection_clear_masks (GtkFileSelection *filesel); +void gtk_file_selection_set_masks (GtkFileSelection *filesel, + const gchar **masks); +/* + where masks is a NULL-terminated array of strings of the format: + + "DESCRIPTION " or simply "MASK" + ie: "C,C++ files <*.[Cc],*.cc,*.cpp>" or simply + "*.jpg,*.gif" etc + +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FILESEL_H__ */ + + + + + + + + + + diff --git a/radiant/gtkfilesel.c b/radiant/gtkfilesel.c new file mode 100644 index 00000000..58fde0bb --- /dev/null +++ b/radiant/gtkfilesel.c @@ -0,0 +1,3337 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + + +// leo FIXME: if we keep this file then we'll need to ask permission to the author, this is LGPL +// This file is from the Advanced File Selector widget +// by Michael Torrie +// http://students.cs.byu.edu/~torriem/gtk/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fnmatch.h" + +// leo: added "gtk/" +#include "gdk/gdkkeysyms.h" +#include "gtk/gtkbutton.h" +#include "gtk/gtkentry.h" +#include "gtkfilesel.h" +#include "gtk/gtkhbox.h" +#include "gtk/gtkhbbox.h" +#include "gtk/gtklabel.h" +#include "gtk/gtklist.h" +#include "gtk/gtklistitem.h" +#include "gtk/gtkmain.h" +#include "gtk/gtkscrolledwindow.h" +#include "gtk/gtksignal.h" +#include "gtk/gtkvbox.h" +#include "gtk/gtkmenu.h" +#include "gtk/gtkmenuitem.h" +#include "gtk/gtkoptionmenu.h" +#include "gtk/gtkclist.h" +#include "gtk/gtkdialog.h" +#include "gtk/gtkcombo.h" +#include "gtk/gtkframe.h" + +// leo: disable NLS +//#include "gtk/gtkintl.h" +#define _(String) (String) + +#define DIR_LIST_WIDTH 180 +#define DIR_LIST_HEIGHT 180 +#define FILE_LIST_WIDTH 180 +#define FILE_LIST_HEIGHT 180 + +/* I've put this here so it doesn't get confused with the + * file completion interface */ +typedef struct _HistoryCallbackArg HistoryCallbackArg; + +struct _HistoryCallbackArg +{ + gchar *directory; + GtkWidget *menu_item; +}; + + +typedef struct _CompletionState CompletionState; +typedef struct _CompletionDir CompletionDir; +typedef struct _CompletionDirSent CompletionDirSent; +typedef struct _CompletionDirEntry CompletionDirEntry; +typedef struct _CompletionUserDir CompletionUserDir; +typedef struct _PossibleCompletion PossibleCompletion; + +/* Non-external file completion decls and structures */ + +/* A contant telling PRCS how many directories to cache. Its actually + * kept in a list, so the geometry isn't important. */ +#define CMPL_DIRECTORY_CACHE_SIZE 10 + +/* A constant used to determine whether a substring was an exact + * match by first_diff_index() + */ +#define PATTERN_MATCH -1 +/* The arguments used by all fnmatch() calls below + */ +#define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD) + +#define CMPL_ERRNO_TOO_LONG ((1<<16)-1) + +/* This structure contains all the useful information about a directory + * for the purposes of filename completion. These structures are cached + * in the CompletionState struct. CompletionDir's are reference counted. + */ +struct _CompletionDirSent +{ + ino_t inode; + time_t mtime; + dev_t device; + + gint entry_count; + gchar *name_buffer; /* memory segment containing names of all entries */ + + struct _CompletionDirEntry *entries; +}; + +struct _CompletionDir +{ + CompletionDirSent *sent; + + gchar *fullname; + gint fullname_len; + + struct _CompletionDir *cmpl_parent; + gint cmpl_index; + gchar *cmpl_text; +}; + +/* This structure contains pairs of directory entry names with a flag saying + * whether or not they are a valid directory. NOTE: This information is used + * to provide the caller with information about whether to update its completions + * or try to open a file. Since directories are cached by the directory mtime, + * a symlink which points to an invalid file (which will not be a directory), + * will not be reevaluated if that file is created, unless the containing + * directory is touched. I consider this case to be worth ignoring (josh). + */ +struct _CompletionDirEntry +{ + gint is_dir; + gchar *entry_name; +}; + +struct _CompletionUserDir +{ + gchar *login; + gchar *homedir; +}; + +struct _PossibleCompletion +{ + /* accessible fields, all are accessed externally by functions + * declared above + */ + gchar *text; + gint is_a_completion; + gint is_directory; + + gint file_size; + gint file_time; + gint uid; + gint gid; + /* Private fields + */ + gint text_alloc; +}; + +struct _CompletionState +{ + gint last_valid_char; + gchar *updated_text; + gint updated_text_len; + gint updated_text_alloc; + gint re_complete; + + gchar *user_dir_name_buffer; + gint user_directories_len; + + gchar *last_completion_text; + + gint user_completion_index; /* if >= 0, currently completing ~user */ + + struct _CompletionDir *completion_dir; /* directory completing from */ + struct _CompletionDir *active_completion_dir; + + struct _PossibleCompletion the_completion; + + struct _CompletionDir *reference_dir; /* initial directory */ + + GList* directory_storage; + GList* directory_sent_storage; + + struct _CompletionUserDir *user_directories; +}; + + +/* File completion functions which would be external, were they used + * outside of this file. + */ + +static CompletionState* cmpl_init_state (void); +static void cmpl_free_state (CompletionState *cmpl_state); +static gint cmpl_state_okay (CompletionState* cmpl_state); +static gchar* cmpl_strerror (gint); + +static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, + gchar **remaining_text, + CompletionState *cmpl_state); + +/* Returns a name for consideration, possibly a completion, this name + * will be invalid after the next call to cmpl_next_completion. + */ +static char* cmpl_this_completion (PossibleCompletion*); + +/* True if this completion matches the given text. Otherwise, this + * output can be used to have a list of non-completions. + */ +static gint cmpl_is_a_completion (PossibleCompletion*); + +/* True if the completion is a directory + */ +static gint cmpl_is_directory (PossibleCompletion*); + +/* Obtains the next completion, or NULL + */ +static PossibleCompletion* cmpl_next_completion (CompletionState*); + +/* Updating completions: the return value of cmpl_updated_text() will + * be text_to_complete completed as much as possible after the most + * recent call to cmpl_completion_matches. For the present + * application, this is the suggested replacement for the user's input + * string. You must CALL THIS AFTER ALL cmpl_text_completions have + * been received. + */ +static gchar* cmpl_updated_text (CompletionState* cmpl_state); + +/* After updating, to see if the completion was a directory, call + * this. If it was, you should consider re-calling completion_matches. + */ +static gint cmpl_updated_dir (CompletionState* cmpl_state); + +/* Current location: if using file completion, return the current + * directory, from which file completion begins. More specifically, + * the cwd concatenated with all exact completions up to the last + * directory delimiter('/'). + */ +static gchar* cmpl_reference_position (CompletionState* cmpl_state); + +/* backing up: if cmpl_completion_matches returns NULL, you may query + * the index of the last completable character into cmpl_updated_text. + */ +static gint cmpl_last_valid_char (CompletionState* cmpl_state); + +/* When the user selects a non-directory, call cmpl_completion_fullname + * to get the full name of the selected file. + */ +static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state); + + +/* Directory operations. */ +static CompletionDir* open_ref_dir (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static gboolean check_dir (gchar *dir_name, + struct stat *result, + gboolean *stat_subdirs); +static CompletionDir* open_dir (gchar* dir_name, + CompletionState* cmpl_state); +static CompletionDir* open_user_dir (gchar* text_to_complete, + CompletionState *cmpl_state); +static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, + CompletionState *cmpl_state); +static CompletionDirSent* open_new_dir (gchar* dir_name, + struct stat* sbuf, + gboolean stat_subdirs); +static gint correct_dir_fullname (CompletionDir* cmpl_dir); +static gint correct_parent (CompletionDir* cmpl_dir, + struct stat *sbuf); +static gchar* find_parent_dir_fullname (gchar* dirname); +static CompletionDir* attach_dir (CompletionDirSent* sent, + gchar* dir_name, + CompletionState *cmpl_state); +static void free_dir_sent (CompletionDirSent* sent); +static void free_dir (CompletionDir *dir); +static void prune_memory_usage(CompletionState *cmpl_state); + +/* Completion operations */ +static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state); +static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state); +static CompletionDir* find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static PossibleCompletion* append_completion_text(gchar* text, + CompletionState* cmpl_state); +static gint get_pwdb(CompletionState* cmpl_state); +static gint first_diff_index(gchar* pat, gchar* text); +static gint compare_user_dir(const void* a, const void* b); +static gint compare_cmpl_dir(const void* a, const void* b); +static void update_cmpl(PossibleCompletion* poss, + CompletionState* cmpl_state); + +static void gtk_file_selection_class_init (GtkFileSelectionClass *klass); +static void gtk_file_selection_init (GtkFileSelection *filesel); +static void gtk_file_selection_destroy (GtkObject *object); +static gint gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); + +static void gtk_file_selection_file_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data); + +static void gtk_file_selection_dir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer data); + +static void gtk_file_selection_undir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer data); + +static void gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete); +static void gtk_file_selection_abort (GtkFileSelection *fs); + +static void gtk_file_selection_update_history_menu (GtkFileSelection *fs, + gchar *current_dir); + +static void gtk_file_selection_create_dir (GtkWidget *widget, gpointer data); +static void gtk_file_selection_delete_file (GtkWidget *widget, gpointer data); +static void gtk_file_selection_rename_file (GtkWidget *widget, gpointer data); + +static gboolean gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data); +static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); +static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist, + GdkEventButton *event, + gpointer user_data); +static void gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data); +static void gtk_file_selection_create_dir (GtkWidget *widget, gpointer data); +static void gtk_file_selection_delete_file (GtkWidget *widget, gpointer data); +static void gtk_file_selection_rename_file (GtkWidget *widget, gpointer data); +static void gtk_file_selection_home_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_up_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_prev_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_next_button (GtkWidget *widget, gpointer data); +static void gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data); + +static gint gtk_file_selection_match_char (gchar, gchar *mask); +static gint gtk_file_selection_match_mask (gchar *,gchar *); + + +static GtkWindowClass *parent_class = NULL; + +/* Saves errno when something cmpl does fails. */ +static gint cmpl_errno; + +/* General notes: + * Make prev and next inactive if their respective * + * histories are empty. + * Add facilities for handling hidden files and * + * directories * + * Add an api to access the mask, and hidden files * + * check box? (prob not in 1.2.x series) * + */ + +/* Routine for applying mask to filenames * + * Need to be optimized to minimize recursion * + * help the for loop by looking for the next * + * instance of the mask character following * + * the '*'. ei *.c -- look for '.' * + * Also, swap all *? pairs (-> ?*), as that * + * will make it possible to look ahead (? * + * makes it very nondeterministic as in *?.c * + * which really is ?*.c * + * Allow multiply masks, separted by commas * + * Allow more flexible [] handling (ie [a-zA-Z] * + * * + */ +static gint gtk_file_selection_match_char (gchar text, gchar *mask){ + gchar *maskc; + gint x; + gint s; + + if (mask[0] == '[') + { + if (!strchr (mask,']')) return 0; + maskc = g_strdup(mask + 1); /* get the portion of mask inside []*/ + + (*(strchr (maskc,']'))) = 0; + s = strlen ((char *)maskc); + + for (x = 0; x < s; x++){ + if (text == maskc[x]) + { + g_free (maskc); + return s + 2; + } + } + g_free (maskc); + return 0; + } + + if (mask[0] == '?') return 1; + if (mask[0] == text) return 1; + + return 0; +} + + +static gint gtk_file_selection_match_mask (gchar *text, gchar *mask){ + + int mc; + int tc; + + tc = 0; mc = 0; + + if (mask[0] == 0 && text[0] == 0) return 1; + + if (mask[0] == '*') + { + for (tc = 0; tc <= strlen(text); tc++) + { + if (gtk_file_selection_match_mask (text + tc, mask + 1)) + return 1; + } + return 0; + } + mc = gtk_file_selection_match_char (text[0], mask); + + if(mc) + return gtk_file_selection_match_mask (text + 1, mask + mc); + else + return 0; +} + +GtkType +gtk_file_selection_get_type (void) +{ + static GtkType file_selection_type = 0; + + if (!file_selection_type) + { + static const GtkTypeInfo filesel_info = + { + "GtkFileSelection", + sizeof (GtkFileSelection), + sizeof (GtkFileSelectionClass), + (GtkClassInitFunc) gtk_file_selection_class_init, + (GtkObjectInitFunc) gtk_file_selection_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + file_selection_type = gtk_type_unique (GTK_TYPE_WINDOW, &filesel_info); + } + + return file_selection_type; +} + +static void +gtk_file_selection_class_init (GtkFileSelectionClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + parent_class = gtk_type_class (GTK_TYPE_WINDOW); + + object_class->destroy = gtk_file_selection_destroy; +} + +static void +gtk_file_selection_init (GtkFileSelection *filesel) +{ + GtkWidget *entry_vbox; + GtkWidget *label; + GtkWidget *list_hbox; + GtkWidget *confirm_area; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *pulldown_hbox; + GtkWidget *scrolled_win; + GtkWidget *mask_label; + GtkWidget *bigframe; + GtkWidget *label_lookingin; + GtkWidget *up_button; + GtkWidget *home_button; + GtkWidget *prev_button; + GtkWidget *next_button; + GtkWidget *refresh_button; + + char *dir_title [2]; + char *file_title [2]; + + filesel->cmpl_state = cmpl_init_state (); + + filesel->mask=NULL; + filesel->prev_history=NULL; + filesel->next_history=NULL; + filesel->saved_entry=NULL; + + /* The dialog-sized vertical box */ + filesel->main_vbox = gtk_vbox_new (FALSE, 10); + gtk_container_set_border_width (GTK_CONTAINER (filesel), 10); + gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox); + gtk_widget_show (filesel->main_vbox); + + /* The horizontal box containing create, rename etc. buttons */ + filesel->button_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(filesel->button_area), GTK_BUTTONBOX_START); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(filesel->button_area), 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->button_area, + FALSE, FALSE, 0); + gtk_widget_show (filesel->button_area); + + gtk_file_selection_show_fileop_buttons(filesel); + + /* hbox for pulldown menu */ + pulldown_hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), pulldown_hbox, FALSE, FALSE, 0); + gtk_widget_show (pulldown_hbox); + + /* The combo box that replaces the pulldown menu */ + label_lookingin = gtk_label_new (_("Looking in:")); + gtk_widget_show (label_lookingin); + gtk_box_pack_start (GTK_BOX (pulldown_hbox), label_lookingin, FALSE, FALSE, 0); + + filesel->history_combo = gtk_combo_new(); + gtk_widget_show(filesel->history_combo); + gtk_combo_set_value_in_list(GTK_COMBO(filesel->history_combo),FALSE,FALSE); + gtk_box_pack_start (GTK_BOX(pulldown_hbox),filesel->history_combo, + TRUE,TRUE, 0); + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->entry),"key-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"button-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_list_callback, + (gpointer) filesel); + + gtk_signal_connect(GTK_OBJECT(((GtkCombo *)filesel->history_combo)->list),"key-press-event", + (GtkSignalFunc) gtk_file_selection_history_combo_list_key_handler, + (gpointer) filesel); + + /* frame to put the following hbox in */ + bigframe = gtk_frame_new (NULL); + gtk_widget_show (bigframe); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), bigframe, TRUE, TRUE, 0); + + /* The horizontal box containing the directory and file listboxes */ + list_hbox = gtk_hbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER(bigframe), list_hbox); + gtk_container_set_border_width (GTK_CONTAINER (list_hbox), 5); + gtk_widget_show (list_hbox); + + /* vbox to put the buttons and directory listing in */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (list_hbox), vbox, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + home_button = gtk_button_new_with_label (_("Home")); + gtk_widget_show (home_button); + gtk_signal_connect (GTK_OBJECT (home_button), "clicked", + (GtkSignalFunc) gtk_file_selection_home_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox), home_button, TRUE,TRUE, 0); + + prev_button = gtk_button_new_with_label (_("Prev")); + gtk_signal_connect (GTK_OBJECT (prev_button), "clicked", + (GtkSignalFunc) gtk_file_selection_prev_button, + (gpointer) filesel); + gtk_widget_show (prev_button); + gtk_box_pack_start (GTK_BOX (hbox), prev_button, TRUE,TRUE, 0); + + up_button = gtk_button_new_with_label (_("Up")); + gtk_signal_connect (GTK_OBJECT (up_button), "clicked", + (GtkSignalFunc) gtk_file_selection_up_button, + (gpointer) filesel); + gtk_widget_show (up_button); + gtk_box_pack_start (GTK_BOX (hbox), up_button, TRUE,TRUE, 0); + + next_button = gtk_button_new_with_label (_("Next")); + gtk_widget_show (next_button); + gtk_signal_connect (GTK_OBJECT (next_button), "clicked", + (GtkSignalFunc) gtk_file_selection_next_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox), next_button, TRUE,TRUE, 0); + + refresh_button = gtk_button_new_with_label (_("Refresh")); + gtk_widget_show (refresh_button); + gtk_signal_connect (GTK_OBJECT (refresh_button), "clicked", + (GtkSignalFunc) gtk_file_selection_refresh_button, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox), refresh_button, TRUE, TRUE, 0); + + /* The directories clist */ + dir_title[0] = _("Directories"); + dir_title[1] = NULL; + filesel->dir_list = gtk_clist_new_with_titles (1, (gchar**) dir_title); + gtk_widget_set_usize (filesel->dir_list, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "select_row", + (GtkSignalFunc) gtk_file_selection_dir_button, + (gpointer) filesel); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "unselect_row", + (GtkSignalFunc) gtk_file_selection_undir_button, + (gpointer) filesel); + gtk_clist_column_titles_passive (GTK_CLIST (filesel->dir_list)); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->dir_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE,TRUE, 5); + gtk_widget_show (filesel->dir_list); + gtk_widget_show (scrolled_win); + + /* vbox area for mask entry and files clist */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (list_hbox), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + mask_label = gtk_label_new (_("Mask:")); + gtk_widget_show (mask_label); + gtk_box_pack_start (GTK_BOX (hbox), mask_label, FALSE, FALSE, 0); + + filesel->mask_entry = gtk_entry_new (); + gtk_widget_show (filesel->mask_entry); + gtk_signal_connect(GTK_OBJECT(filesel->mask_entry),"activate", + (GtkSignalFunc) gtk_file_selection_mask_entry_callback, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (hbox),filesel->mask_entry, TRUE, TRUE, 0); + + + /* The files clist */ + file_title[0] = _("Files"); + file_title[1] = NULL; + filesel->file_list = gtk_clist_new_with_titles (1, (gchar**) file_title); + gtk_widget_set_usize (filesel->file_list, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "select_row", + (GtkSignalFunc) gtk_file_selection_file_button, + (gpointer) filesel); + gtk_clist_column_titles_passive (GTK_CLIST (filesel->file_list)); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->file_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 5); + gtk_widget_show (filesel->file_list); + gtk_widget_show (scrolled_win); + + /* action area for packing buttons into. */ + filesel->action_area = gtk_hbox_new (TRUE, 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->action_area, + FALSE, FALSE, 0); + gtk_widget_show (filesel->action_area); + + /* The OK/Cancel button area */ + confirm_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(confirm_area), 5); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), confirm_area, FALSE, FALSE, 0); + gtk_widget_show (confirm_area); + + /* The OK button */ + filesel->ok_button = gtk_button_new_with_label (_("OK")); + GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (filesel->ok_button); + gtk_widget_show (filesel->ok_button); + + /* The Cancel button */ + filesel->cancel_button = gtk_button_new_with_label (_("Cancel")); + GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->cancel_button); + + /* The selection entry widget */ + entry_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 0); + gtk_widget_show (entry_vbox); + + filesel->selection_text = label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + filesel->selection_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event", + (GtkSignalFunc) gtk_file_selection_key_press, filesel); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event", + (GtkSignalFunc) gtk_widget_grab_default, + GTK_OBJECT (filesel->ok_button)); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate", + (GtkSignalFunc) gtk_button_clicked, + GTK_OBJECT (filesel->ok_button)); + gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_entry, TRUE, TRUE, 0); + gtk_widget_show (filesel->selection_entry); + + if (!cmpl_state_okay (filesel->cmpl_state)) + { + gchar err_buf[256]; + + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); + + gtk_label_set_text (GTK_LABEL (filesel->selection_text), err_buf); + } + else + { + gtk_file_selection_populate (filesel, "", FALSE); + } + + gtk_widget_grab_focus (filesel->selection_entry); +} + +GtkWidget* +gtk_file_selection_new (const gchar *title) +{ + GtkFileSelection *filesel; + + filesel = gtk_type_new (GTK_TYPE_FILE_SELECTION); + gtk_window_set_title (GTK_WINDOW (filesel), title); + + return GTK_WIDGET (filesel); +} + +void +gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + /* delete, create directory, and rename */ + if (!filesel->fileop_c_dir) + { + filesel->fileop_c_dir = gtk_button_new_with_label (_("Create Dir")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_c_dir), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_c_dir, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_c_dir); + } + + if (!filesel->fileop_del_file) + { + filesel->fileop_del_file = gtk_button_new_with_label (_("Delete File")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_del_file), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_del_file, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_del_file); + } + + if (!filesel->fileop_ren_file) + { + filesel->fileop_ren_file = gtk_button_new_with_label (_("Rename File")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_ren_file), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_ren_file, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_ren_file); + } + + gtk_widget_queue_resize(GTK_WIDGET(filesel)); +} + +void +gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + if (filesel->fileop_ren_file) + { + gtk_widget_destroy (filesel->fileop_ren_file); + filesel->fileop_ren_file = NULL; + } + + if (filesel->fileop_del_file) + { + gtk_widget_destroy (filesel->fileop_del_file); + filesel->fileop_del_file = NULL; + } + + if (filesel->fileop_c_dir) + { + gtk_widget_destroy (filesel->fileop_c_dir); + filesel->fileop_c_dir = NULL; + } +} + + + +void +gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename) +{ + char buf[MAXPATHLEN]; + const char *name, *last_slash; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (filename != NULL); + + last_slash = strrchr (filename, '/'); + + if (!last_slash) + { + buf[0] = 0; + name = filename; + } + else + { + gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1); + + strncpy (buf, filename, len); + buf[len] = 0; + + name = last_slash + 1; + } + + gtk_file_selection_populate (filesel, buf, FALSE); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); +} + +gchar* +gtk_file_selection_get_filename (GtkFileSelection *filesel) +{ + static char nothing[2] = ""; + char *text; + char *filename; + + g_return_val_if_fail (filesel != NULL, nothing); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); + + text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + if (text) + { + filename = cmpl_completion_fullname (text, filesel->cmpl_state); + return filename; + } + + return nothing; +} + +void +gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern) +{ + gchar *new_pattern; + gint x; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (pattern != NULL); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), pattern); + + if(strchr(pattern,'*') || strchr(pattern,'?')) + { + for(x=strlen(pattern);x>=0;x--) + { + if(pattern[x]=='/') break; + } + gtk_entry_set_text(GTK_ENTRY(filesel->mask_entry),g_strdup(pattern+x+1)); + + if(filesel->mask) g_free(filesel->mask); + + filesel->mask=g_strdup(pattern+x+1); + new_pattern=g_strdup(pattern); + new_pattern[x+1]=0; + gtk_file_selection_populate (filesel, (gchar*) new_pattern, TRUE); + g_free(new_pattern); + } + else + { + gtk_file_selection_populate (filesel, (gchar*) pattern, TRUE); + } +} + +static void +gtk_file_selection_destroy (GtkObject *object) +{ + GtkFileSelection *filesel; + GList *list; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (object)); + + filesel = GTK_FILE_SELECTION (object); + + if (filesel->fileop_dialog) + gtk_widget_destroy (filesel->fileop_dialog); + + if (filesel->next_history) + { + list = filesel->next_history; + while (list) + { + g_free (list->data); + list = list->next; + } + } + g_list_free (filesel->next_history); + filesel->next_history = NULL; + + if (filesel->prev_history) + { + list = filesel->prev_history; + while (list) + { + g_free (list->data); + list = list->next; + } + } + g_list_free (filesel->prev_history); + filesel->prev_history = NULL; + + if (filesel->mask) + { + g_free (filesel->mask); + filesel->mask = NULL; + } + + cmpl_free_state (filesel->cmpl_state); + filesel->cmpl_state = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/* Begin file operations callbacks */ + +static void +gtk_file_selection_fileop_error (GtkFileSelection *fs, gchar *error_message) +{ + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dialog; + + g_return_if_fail (error_message != NULL); + + /* main dialog */ + dialog = gtk_dialog_new (); + /* + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + */ + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, make this dialog modal too */ + /* When error dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + label = gtk_label_new(error_message); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + /* yes, we free it */ + g_free (error_message); + + /* close button */ + button = gtk_button_new_with_label (_("Close")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static void +gtk_file_selection_fileop_destroy (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + fs->fileop_dialog = NULL; +} + + +static void +gtk_file_selection_create_dir_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + gchar *dirname; + gchar *path; + gchar *full_path; + gchar *buf; + CompletionState *cmpl_state; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + dirname = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + full_path = g_strconcat (path, "/", dirname, NULL); + if ( (mkdir (full_path, 0755) < 0) ) + { + buf = g_strconcat ("Error creating directory \"", dirname, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (full_path); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_create_dir (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *button; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Create Directory")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + label = gtk_label_new(_("Directory name:")); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + /* The directory entry widget */ + fs->fileop_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, + TRUE, TRUE, 5); + GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT); + gtk_widget_show (fs->fileop_entry); + + /* buttons */ + button = gtk_button_new_with_label (_("Create")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + +static void +gtk_file_selection_delete_file_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + CompletionState *cmpl_state; + gchar *path; + gchar *full_path; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + full_path = g_strconcat (path, "/", fs->fileop_file, NULL); + if ( (unlink (full_path) < 0) ) + { + buf = g_strconcat ("Error deleting file \"", fs->fileop_file, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (full_path); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dialog; + gchar *filename; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + filename = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + if (strlen(filename) < 1) + return; + + fs->fileop_file = filename; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Delete File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + buf = g_strconcat ("Really delete file \"", filename, "\" ?", NULL); + label = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + g_free(buf); + + /* buttons */ + button = gtk_button_new_with_label (_("Delete")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); + +} + +static void +gtk_file_selection_rename_file_confirmed (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + gchar *buf; + gchar *file; + gchar *path; + gchar *new_filename; + gchar *old_filename; + CompletionState *cmpl_state; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); + cmpl_state = (CompletionState*) fs->cmpl_state; + path = cmpl_reference_position (cmpl_state); + + new_filename = g_strconcat (path, "/", file, NULL); + old_filename = g_strconcat (path, "/", fs->fileop_file, NULL); + + if ( (rename (old_filename, new_filename)) < 0) + { + buf = g_strconcat ("Error renaming file \"", file, "\": ", + g_strerror(errno), NULL); + gtk_file_selection_fileop_error (fs, buf); + } + g_free (new_filename); + g_free (old_filename); + + gtk_widget_destroy (fs->fileop_dialog); + gtk_file_selection_populate (fs, "", FALSE); +} + +static void +gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) +{ + GtkFileSelection *fs = data; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *button; + gchar *buf; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + if (fs->fileop_dialog) + return; + + fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + if (strlen(fs->fileop_file) < 1) + return; + + /* main dialog */ + fs->fileop_dialog = dialog = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) gtk_file_selection_fileop_destroy, + (gpointer) fs); + gtk_window_set_title (GTK_WINDOW (dialog), _("Rename File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER(vbox), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, + FALSE, FALSE, 0); + gtk_widget_show(vbox); + + buf = g_strconcat ("Rename file \"", fs->fileop_file, "\" to:", NULL); + label = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + g_free(buf); + + /* New filename entry */ + fs->fileop_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, + TRUE, TRUE, 5); + GTK_WIDGET_SET_FLAGS(fs->fileop_entry, GTK_CAN_DEFAULT); + gtk_widget_show (fs->fileop_entry); + + gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file); + gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry), + 0, strlen (fs->fileop_file)); + + /* buttons */ + button = gtk_button_new_with_label (_("Rename")); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file_confirmed, + (gpointer) fs); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (_("Cancel")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + (gpointer) dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show (button); + + gtk_widget_show (dialog); +} + + +static gint +gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + GtkFileSelection *fs; + char *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + + if (event->keyval == GDK_Tab) + { + text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + + text = g_strdup (text); + + gtk_file_selection_populate (fs, text, TRUE); + + g_free (text); + + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + + return TRUE; + } + if (fs->saved_entry) + { + gtk_clist_unselect_all ((GtkCList *) (fs->dir_list)); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + + + return FALSE; +} + +static void +gtk_file_selection_home_button (GtkWidget *widget, gpointer data){ + GList *list; + + GtkFileSelection *fs=data; + + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs,"~/",FALSE); +} + +static void +gtk_file_selection_up_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs, "../", FALSE); /*change directories. */ + +} + +static void +gtk_file_selection_prev_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + GList *first; + gchar *path; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->prev_history; + + if (list && g_list_length(list) > 1) + { + first = list; /* get first element */ + list = list->next; /* pop off current directory */ + + list->prev = NULL; /* make this the new head. */ + + fs->prev_history = list; /* update prev_history list */ + fs->next_history = g_list_prepend(fs->next_history,first->data); /* put it on next_history */ + + first->next = NULL; /* orphan the old first node */ + g_list_free (first); /* free the node (data is now in use by next_history) */ + + + + path = g_malloc(strlen(list->data)+4); /* plenty of space */ + strcpy(path,list->data); /* get the 2nd path in the history */ + strcat(path,"/"); /* append a '/' */ + gtk_file_selection_populate (fs, path, FALSE); /* change directories. */ + g_free (path); + } +} + +static void +gtk_file_selection_next_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + GList *list; + GList *first; + gchar *path; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + list = fs->next_history; + + if (list && g_list_length(list) > 0) + { + first = list; /*get first element*/ + list = list->next; /*pop off current directory*/ + + if (list) + list->prev = NULL; + + fs->next_history = list; /*update prev_history list*/ + + path = g_malloc(strlen(first->data)+4); /*plenty of space*/ + strcpy(path,first->data); + strcat(path,"/"); /*append a / */ + gtk_file_selection_populate (fs, path, FALSE); /*change directories.*/ + g_free(path); + + first->next = NULL; /* orphan the old first node */ + g_list_free (first); /* free the node (data is now in use by next_history) */ + + } +} + +void static +gtk_file_selection_refresh_button (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_file_selection_populate (fs,"",FALSE); +} + +static void +gtk_file_selection_mask_entry_callback (GtkWidget *widget, gpointer data){ + GtkFileSelection *fs = data; + + if(fs->mask) + g_free (fs->mask); + + fs->mask = g_strdup(gtk_entry_get_text (GTK_ENTRY(fs->mask_entry))); + + if (strlen(fs->mask) == 0) + { + g_free (fs->mask); + fs->mask = NULL; + } + + gtk_file_selection_refresh_button (widget,data); +} + +static gboolean gtk_file_selection_history_combo_list_key_handler(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + /* + g_print("Key pressed! \n"); + */ + + return TRUE; +} + +static gboolean gtk_file_selection_history_combo_list_callback (GtkWidget *thelist, + GdkEventButton *event, + gpointer user_data) +{ + + GtkFileSelection *fs = user_data; + GList *list; + gchar *path; + + list = fs->next_history; + if(list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + path = g_malloc(strlen(gtk_entry_get_text(GTK_ENTRY (((GtkCombo *)fs->history_combo)->entry)))+4); + strcpy (path,gtk_entry_get_text(GTK_ENTRY( ((GtkCombo *)fs->history_combo)->entry))); + strcat (path,"/"); + + gtk_file_selection_populate (fs,path,TRUE); + + g_free (path); + + return TRUE; +} + +static gboolean +gtk_file_selection_history_combo_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + GtkEntry *entry=(GtkEntry *)widget; + GtkFileSelection *fs=data; + GList *list; + gchar *path; + + g_return_val_if_fail (fs != NULL,FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs),FALSE); + + + if (event->keyval == GDK_Return) + { + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + path = g_malloc(strlen(gtk_entry_get_text(entry))+4); + strcpy (path,gtk_entry_get_text(entry)); + strcat (path,"/"); + gtk_file_selection_populate (fs,path,TRUE); + g_free (path); + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + return TRUE; + } + else + { + return FALSE; + } + +} + +static void +gtk_file_selection_update_history_menu (GtkFileSelection *fs, + gchar *current_directory) +{ + gchar *current_dir; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + g_return_if_fail (current_directory != NULL); + + current_dir = g_strdup (current_directory); + + if(fs->prev_history) + { + if (strcmp((fs->prev_history)->data,current_dir)) + { /*if this item isn't on the top of the list */ + fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir)); + } + } else { + fs->prev_history = g_list_prepend(fs->prev_history,g_strdup(current_dir)); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (fs->history_combo),fs->prev_history); + + g_free (current_dir); +} + +static void +gtk_file_selection_file_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = user_data; + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->file_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + break; + + default: + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } +} + +static void +gtk_file_selection_dir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GList *list; + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = GTK_FILE_SELECTION (user_data); + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + list = fs->next_history; + if (list) + { + g_free (list->data); + list = list->next; + } + g_list_free (fs->next_history); + fs->next_history = NULL; + + gtk_file_selection_populate (fs, filename, FALSE); + gtk_entry_set_text(GTK_ENTRY(fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + break; + + default: + /* here we need to add the "filename" to the beginning of what's already + in the entry. Save what's in the entry, then restore it on the double click + */ + if (fs->saved_entry) g_free (fs->saved_entry); + fs->saved_entry=g_strdup(gtk_entry_get_text(GTK_ENTRY (fs->selection_entry))); + + temp=g_strconcat(filename,fs->saved_entry,NULL); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), temp); + g_free (temp); + + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } +} + +static void +gtk_file_selection_undir_button (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) +{ + GtkFileSelection *fs = NULL; + gchar *filename, *temp = NULL; + + g_return_if_fail (GTK_IS_CLIST (widget)); + + fs = GTK_FILE_SELECTION (user_data); + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + + if (filename) + { + if (bevent) + switch (bevent->type) + { + default: + /* here we need to add the "filename" to the beginning of what's already + in the entry. Save what's in the entry, then restore it on the double click + */ + if (fs->saved_entry) + { + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry),fs->saved_entry); + g_free (fs->saved_entry); + fs->saved_entry = NULL; + } + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); //????? + + g_free (filename); + } +} + +static void +gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete) +{ + CompletionState *cmpl_state; + PossibleCompletion* poss; + gchar* filename; + gint row; + gchar* rem_path = rel_path; + gchar* sel_text; + gchar* text[2]; + gint did_recurse = FALSE; + gint possible_count = 0; + gint selection_index = -1; + gint file_list_width; + gint dir_list_width; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + cmpl_state = (CompletionState*) fs->cmpl_state; + poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state); + + if (!cmpl_state_okay (cmpl_state)) + { + /* Something went wrong. */ + gtk_file_selection_abort (fs); + return; + } + + g_assert (cmpl_state->reference_dir); + + gtk_clist_freeze (GTK_CLIST (fs->dir_list)); + gtk_clist_clear (GTK_CLIST (fs->dir_list)); + gtk_clist_freeze (GTK_CLIST (fs->file_list)); + gtk_clist_clear (GTK_CLIST (fs->file_list)); + + /* Set the dir_list to include ./ and ../ */ + text[1] = NULL; + text[0] = "./"; + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + + text[0] = "../"; + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + + /*reset the max widths of the lists*/ + dir_list_width = gdk_string_width(fs->dir_list->style->font,"../"); + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0,dir_list_width); + file_list_width = 1; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,file_list_width); + + while (poss) + { + if (cmpl_is_a_completion (poss)) + { + possible_count += 1; + + filename = cmpl_this_completion (poss); + + text[0] = filename; + + if (cmpl_is_directory (poss)) + { + if (strcmp (filename, "./") != 0 && + strcmp (filename, "../") != 0) + { + int width = gdk_string_width(fs->dir_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); + if(width > dir_list_width) + { + dir_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0, + width); + } + } + } + else + { + if(fs->mask) + { + if (gtk_file_selection_match_mask(filename,fs->mask)) + { + int width = gdk_string_width(fs->file_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->file_list), text); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } + } + } + else + { + int width = gdk_string_width(fs->file_list->style->font, + filename); + row = gtk_clist_append (GTK_CLIST (fs->file_list), text); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } + } + } + } + + poss = cmpl_next_completion (cmpl_state); + } + + gtk_clist_thaw (GTK_CLIST (fs->dir_list)); + gtk_clist_thaw (GTK_CLIST (fs->file_list)); + + /* File lists are set. */ + + g_assert (cmpl_state->reference_dir); + + if (try_complete) + { + + /* User is trying to complete filenames, so advance the user's input + * string to the updated_text, which is the common leading substring + * of all possible completions, and if its a directory attempt + * attempt completions in it. */ + + if (cmpl_updated_text (cmpl_state)[0]) + { + + if (cmpl_updated_dir (cmpl_state)) + { + gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state)); + + did_recurse = TRUE; + + gtk_file_selection_populate (fs, dir_name, TRUE); + + g_free (dir_name); + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), + cmpl_updated_text (cmpl_state)); + } + } + else + { + selection_index = cmpl_last_valid_char (cmpl_state) - + (strlen (rel_path) - strlen (rem_path)); + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path); + } + } + else + { + if (fs->selection_entry) + /* Here we need to take the old filename and keep it!*/ + /*gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");*/ + ; + } + + if (!did_recurse) + { + if (fs->selection_entry) + gtk_entry_set_position (GTK_ENTRY (fs->selection_entry), selection_index); + + if (fs->selection_entry) + { + sel_text = g_strconcat (_("Selection: "), + cmpl_reference_position (cmpl_state), + NULL); + + gtk_label_set_text (GTK_LABEL (fs->selection_text), sel_text); + g_free (sel_text); + } + + gtk_file_selection_update_history_menu (fs, cmpl_reference_position (cmpl_state)); + + } +} + +static void +gtk_file_selection_abort (GtkFileSelection *fs) +{ + gchar err_buf[256]; + + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); + + /* BEEP gdk_beep(); */ + + if (fs->selection_entry) + gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf); +} + +/**********************************************************************/ +/* External Interface */ +/**********************************************************************/ + +/* The four completion state selectors + */ +static gchar* +cmpl_updated_text (CompletionState* cmpl_state) +{ + return cmpl_state->updated_text; +} + +static gint +cmpl_updated_dir (CompletionState* cmpl_state) +{ + return cmpl_state->re_complete; +} + +static gchar* +cmpl_reference_position (CompletionState* cmpl_state) +{ + return cmpl_state->reference_dir->fullname; +} + +static gint +cmpl_last_valid_char (CompletionState* cmpl_state) +{ + return cmpl_state->last_valid_char; +} + +static gchar* +cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) +{ + static char nothing[2] = ""; + + if (!cmpl_state_okay (cmpl_state)) + { + return nothing; + } + else if (text[0] == '/') + { + strcpy (cmpl_state->updated_text, text); + } + else if (text[0] == '~') + { + CompletionDir* dir; + char* slash; + + dir = open_user_dir (text, cmpl_state); + + if (!dir) + { + /* spencer says just return ~something, so + * for now just do it. */ + strcpy (cmpl_state->updated_text, text); + } + else + { + + strcpy (cmpl_state->updated_text, dir->fullname); + + slash = strchr (text, '/'); + + if (slash) + strcat (cmpl_state->updated_text, slash); + } + } + else + { + strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); + if (strcmp (cmpl_state->reference_dir->fullname, "/") != 0) + strcat (cmpl_state->updated_text, "/"); + strcat (cmpl_state->updated_text, text); + } + + return cmpl_state->updated_text; +} + +/* The three completion selectors + */ +static gchar* +cmpl_this_completion (PossibleCompletion* pc) +{ + return pc->text; +} + +static gint +cmpl_is_directory (PossibleCompletion* pc) +{ + return pc->is_directory; +} + +static gint +cmpl_is_a_completion (PossibleCompletion* pc) +{ + return pc->is_a_completion; +} + +/**********************************************************************/ +/* Construction, deletion */ +/**********************************************************************/ + +static CompletionState* +cmpl_init_state (void) +{ + gchar getcwd_buf[2*MAXPATHLEN]; + CompletionState *new_state; + + new_state = g_new (CompletionState, 1); + + /* We don't use getcwd() on SUNOS, because, it does a popen("pwd") + * and, if that wasn't bad enough, hangs in doing so. + */ +#if defined(sun) && !defined(__SVR4) + if (!getwd (getcwd_buf)) +#else + if (!getcwd (getcwd_buf, MAXPATHLEN)) +#endif + { + /* Oh joy, we can't get the current directory. Um..., we should have + * a root directory, right? Right? (Probably not portable to non-Unix) + */ + strcpy (getcwd_buf, "/"); + } + +tryagain: + + new_state->reference_dir = NULL; + new_state->completion_dir = NULL; + new_state->active_completion_dir = NULL; + new_state->directory_storage = NULL; + new_state->directory_sent_storage = NULL; + new_state->last_valid_char = 0; + new_state->updated_text = g_new (gchar, MAXPATHLEN); + new_state->updated_text_alloc = MAXPATHLEN; + new_state->the_completion.text = g_new (gchar, MAXPATHLEN); + new_state->the_completion.text_alloc = MAXPATHLEN; + new_state->user_dir_name_buffer = NULL; + new_state->user_directories = NULL; + + new_state->reference_dir = open_dir (getcwd_buf, new_state); + + if (!new_state->reference_dir) + { + /* Directories changing from underneath us, grumble */ + strcpy (getcwd_buf, "/"); + goto tryagain; + } + + return new_state; +} + +static void +cmpl_free_dir_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_dir_sent_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir_sent (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_state (CompletionState* cmpl_state) +{ + cmpl_free_dir_list (cmpl_state->directory_storage); + cmpl_free_dir_sent_list (cmpl_state->directory_sent_storage); + + if (cmpl_state->user_dir_name_buffer) + g_free (cmpl_state->user_dir_name_buffer); + if (cmpl_state->user_directories) + g_free (cmpl_state->user_directories); + if (cmpl_state->the_completion.text) + g_free (cmpl_state->the_completion.text); + if (cmpl_state->updated_text) + g_free (cmpl_state->updated_text); + + g_free (cmpl_state); +} + +static void +free_dir(CompletionDir* dir) +{ + g_free(dir->fullname); + g_free(dir); +} + +static void +free_dir_sent(CompletionDirSent* sent) +{ + g_free(sent->name_buffer); + g_free(sent->entries); + g_free(sent); +} + +static void +prune_memory_usage(CompletionState *cmpl_state) +{ + GList* cdsl = cmpl_state->directory_sent_storage; + GList* cdl = cmpl_state->directory_storage; + GList* cdl0 = cdl; + gint len = 0; + + for(; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1) + cdsl = cdsl->next; + + if (cdsl) { + cmpl_free_dir_sent_list(cdsl->next); + cdsl->next = NULL; + } + + cmpl_state->directory_storage = NULL; + while (cdl) { + if (cdl->data == cmpl_state->reference_dir) + cmpl_state->directory_storage = g_list_prepend(NULL, cdl->data); + else + free_dir (cdl->data); + cdl = cdl->next; + } + + g_list_free(cdl0); +} + +/**********************************************************************/ +/* The main entrances. */ +/**********************************************************************/ + +static PossibleCompletion* +cmpl_completion_matches (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + PossibleCompletion *poss; + + prune_memory_usage(cmpl_state); + + g_assert (text_to_complete != NULL); + + cmpl_state->user_completion_index = -1; + cmpl_state->last_completion_text = text_to_complete; + cmpl_state->the_completion.text[0] = 0; + cmpl_state->last_valid_char = 0; + cmpl_state->updated_text_len = -1; + cmpl_state->updated_text[0] = 0; + cmpl_state->re_complete = FALSE; + + first_slash = strchr (text_to_complete, '/'); + + if (text_to_complete[0] == '~' && !first_slash) + { + /* Text starts with ~ and there is no slash, show all the + * home directory completions. + */ + poss = attempt_homedir_completion (text_to_complete, cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; + } + + cmpl_state->reference_dir = + open_ref_dir (text_to_complete, remaining_text, cmpl_state); + + if(!cmpl_state->reference_dir) + return NULL; + + cmpl_state->completion_dir = + find_completion_dir (*remaining_text, remaining_text, cmpl_state); + + cmpl_state->last_valid_char = *remaining_text - text_to_complete; + + if(!cmpl_state->completion_dir) + return NULL; + + cmpl_state->completion_dir->cmpl_index = -1; + cmpl_state->completion_dir->cmpl_parent = NULL; + cmpl_state->completion_dir->cmpl_text = *remaining_text; + + cmpl_state->active_completion_dir = cmpl_state->completion_dir; + + cmpl_state->reference_dir = cmpl_state->completion_dir; + + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +static PossibleCompletion* +cmpl_next_completion (CompletionState* cmpl_state) +{ + PossibleCompletion* poss = NULL; + + cmpl_state->the_completion.text[0] = 0; + + if(cmpl_state->user_completion_index >= 0) + poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state); + else + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +/**********************************************************************/ +/* Directory Operations */ +/**********************************************************************/ + +/* Open the directory where completion will begin from, if possible. */ +static CompletionDir* +open_ref_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + CompletionDir *new_dir; + + first_slash = strchr(text_to_complete, '/'); + + if (text_to_complete[0] == '~') + { + new_dir = open_user_dir(text_to_complete, cmpl_state); + + if(new_dir) + { + if(first_slash) + *remaining_text = first_slash + 1; + else + *remaining_text = text_to_complete + strlen(text_to_complete); + } + else + { + return NULL; + } + } + else if (text_to_complete[0] == '/' || !cmpl_state->reference_dir) + { + gchar *tmp = g_strdup(text_to_complete); + gchar *p; + + p = tmp; + while (*p && *p != '*' && *p != '?') + p++; + + *p = '\0'; + p = strrchr(tmp, '/'); + if (p) + { + if (p == tmp) + p++; + + *p = '\0'; + + new_dir = open_dir(tmp, cmpl_state); + + if(new_dir) + *remaining_text = text_to_complete + + ((p == tmp + 1) ? (p - tmp) : (p + 1 - tmp)); + } + else + { + /* If no possible candidates, use the cwd */ + gchar *curdir = g_get_current_dir (); + + new_dir = open_dir(curdir, cmpl_state); + + if (new_dir) + *remaining_text = text_to_complete; + + g_free (curdir); + } + + g_free (tmp); + } + else + { + *remaining_text = text_to_complete; + + new_dir = open_dir(cmpl_state->reference_dir->fullname, cmpl_state); + } + + if(new_dir) + { + new_dir->cmpl_index = -1; + new_dir->cmpl_parent = NULL; + } + + return new_dir; +} + +/* open a directory by user name */ +static CompletionDir* +open_user_dir(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gchar *first_slash; + gint cmp_len; + + g_assert(text_to_complete && text_to_complete[0] == '~'); + + first_slash = strchr(text_to_complete, '/'); + + if (first_slash) + cmp_len = first_slash - text_to_complete - 1; + else + cmp_len = strlen(text_to_complete + 1); + + if(!cmp_len) + { + /* ~/ */ + gchar *homedir = g_get_home_dir (); + + if (homedir) + return open_dir(homedir, cmpl_state); + else + return NULL; + } + else + { + /* ~user/ */ + char* copy = g_new(char, cmp_len + 1); + struct passwd *pwd; + strncpy(copy, text_to_complete + 1, cmp_len); + copy[cmp_len] = 0; + pwd = getpwnam(copy); + g_free(copy); + if (!pwd) + { + cmpl_errno = errno; + return NULL; + } + + return open_dir(pwd->pw_dir, cmpl_state); + } +} + +/* open a directory relative the the current relative directory */ +static CompletionDir* +open_relative_dir(gchar* dir_name, + CompletionDir* dir, + CompletionState *cmpl_state) +{ + gchar path_buf[2*MAXPATHLEN]; + + if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir->fullname); + + if(dir->fullname_len > 1) + { + path_buf[dir->fullname_len] = '/'; + strcpy(path_buf + dir->fullname_len + 1, dir_name); + } + else + { + strcpy(path_buf + dir->fullname_len, dir_name); + } + + return open_dir(path_buf, cmpl_state); +} + +/* after the cache lookup fails, really open a new directory */ +static CompletionDirSent* +open_new_dir(gchar* dir_name, struct stat* sbuf, gboolean stat_subdirs) +{ + CompletionDirSent* sent; + DIR* directory; + gchar *buffer_ptr; + struct dirent *dirent_ptr; + gint buffer_size = 0; + gint entry_count = 0; + gint i; + struct stat ent_sbuf; + char path_buf[MAXPATHLEN*2]; + gint path_buf_len; + + sent = g_new(CompletionDirSent, 1); + sent->mtime = sbuf->st_mtime; + sent->inode = sbuf->st_ino; + sent->device = sbuf->st_dev; + + path_buf_len = strlen(dir_name); + + if (path_buf_len > MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir_name); + + directory = opendir(dir_name); + + if(!directory) + { + cmpl_errno = errno; + return NULL; + } + + while((dirent_ptr = readdir(directory)) != NULL) + { + int entry_len = strlen(dirent_ptr->d_name); + buffer_size += entry_len + 1; + entry_count += 1; + + if(path_buf_len + entry_len + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + closedir(directory); + return NULL; + } + } + + sent->name_buffer = g_new(gchar, buffer_size); + sent->entries = g_new(CompletionDirEntry, entry_count); + sent->entry_count = entry_count; + + buffer_ptr = sent->name_buffer; + + rewinddir(directory); + + for(i = 0; i < entry_count; i += 1) + { + dirent_ptr = readdir(directory); + + if(!dirent_ptr) + { + cmpl_errno = errno; + closedir(directory); + return NULL; + } + + strcpy(buffer_ptr, dirent_ptr->d_name); + sent->entries[i].entry_name = buffer_ptr; + buffer_ptr += strlen(dirent_ptr->d_name); + *buffer_ptr = 0; + buffer_ptr += 1; + + path_buf[path_buf_len] = '/'; + strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); + + if (stat_subdirs) + { + if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) + sent->entries[i].is_dir = 1; + else + /* stat may fail, and we don't mind, since it could be a + * dangling symlink. */ + sent->entries[i].is_dir = 0; + } + else + sent->entries[i].is_dir = 1; + } + + qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); + + closedir(directory); + + return sent; +} + +static gboolean +check_dir(gchar *dir_name, struct stat *result, gboolean *stat_subdirs) +{ + /* A list of directories that we know only contain other directories. + * Trying to stat every file in these directories would be very + * expensive. + */ + + static struct { + gchar *name; + gboolean present; + struct stat statbuf; + } no_stat_dirs[] = { + { "/afs", FALSE, { 0 } }, + { "/net", FALSE, { 0 } } + }; + + static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]); + static gboolean initialized = FALSE; + + gint i; + + if (!initialized) + { + initialized = TRUE; + for (i = 0; i < n_no_stat_dirs; i++) + { + if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0) + no_stat_dirs[i].present = TRUE; + } + } + + if(stat(dir_name, result) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + *stat_subdirs = TRUE; + for (i=0; ist_dev) && + (no_stat_dirs[i].statbuf.st_ino == result->st_ino)) + { + *stat_subdirs = FALSE; + break; + } + } + + return TRUE; +} + +/* open a directory by absolute pathname */ +static CompletionDir* +open_dir(gchar* dir_name, CompletionState* cmpl_state) +{ + struct stat sbuf; + gboolean stat_subdirs; + CompletionDirSent *sent; + GList* cdsl; + + if (!check_dir (dir_name, &sbuf, &stat_subdirs)) + return NULL; + + cdsl = cmpl_state->directory_sent_storage; + + while (cdsl) + { + sent = cdsl->data; + + if(sent->inode == sbuf.st_ino && + sent->mtime == sbuf.st_mtime && + sent->device == sbuf.st_dev) + return attach_dir(sent, dir_name, cmpl_state); + + cdsl = cdsl->next; + } + + sent = open_new_dir(dir_name, &sbuf, stat_subdirs); + + if (sent) { + cmpl_state->directory_sent_storage = + g_list_prepend(cmpl_state->directory_sent_storage, sent); + + return attach_dir(sent, dir_name, cmpl_state); + } + + return NULL; +} + +static CompletionDir* +attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state) +{ + CompletionDir* new_dir; + + new_dir = g_new(CompletionDir, 1); + + cmpl_state->directory_storage = + g_list_prepend(cmpl_state->directory_storage, new_dir); + + new_dir->sent = sent; + new_dir->fullname = g_strdup(dir_name); + new_dir->fullname_len = strlen(dir_name); + + return new_dir; +} + +static gint +correct_dir_fullname(CompletionDir* cmpl_dir) +{ + gint length = strlen(cmpl_dir->fullname); + struct stat sbuf; + + if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) + { + if (length == 2) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } else { + cmpl_dir->fullname[length - 2] = 0; + } + } + else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) + cmpl_dir->fullname[length - 2] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) + { + if(length == 3) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 2] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) + { + if(length == 4) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 3] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + + cmpl_dir->fullname_len = strlen(cmpl_dir->fullname); + + return TRUE; +} + +static gint +correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) +{ + struct stat parbuf; + gchar *last_slash; + gchar *new_name; + gchar c = 0; + + last_slash = strrchr(cmpl_dir->fullname, '/'); + + g_assert(last_slash); + + if(last_slash != cmpl_dir->fullname) + { /* last_slash[0] = 0; */ } + else + { + c = last_slash[1]; + last_slash[1] = 0; + } + + if (stat(cmpl_dir->fullname, &parbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) + /* it wasn't a link */ + return TRUE; + + if(c) + last_slash[1] = c; + /* else + last_slash[0] = '/'; */ + + /* it was a link, have to figure it out the hard way */ + + new_name = find_parent_dir_fullname(cmpl_dir->fullname); + + if (!new_name) + return FALSE; + + g_free(cmpl_dir->fullname); + + cmpl_dir->fullname = new_name; + + return TRUE; +} + +static gchar* +find_parent_dir_fullname(gchar* dirname) +{ + gchar buffer[MAXPATHLEN]; + gchar buffer2[MAXPATHLEN]; + +#if defined(sun) && !defined(__SVR4) + if(!getwd(buffer)) +#else + if(!getcwd(buffer, MAXPATHLEN)) +#endif + { + cmpl_errno = errno; + return NULL; + } + + if(chdir(dirname) != 0 || chdir("..") != 0) + { + cmpl_errno = errno; + return NULL; + } + +#if defined(sun) && !defined(__SVR4) + if(!getwd(buffer2)) +#else + if(!getcwd(buffer2, MAXPATHLEN)) +#endif + { + chdir(buffer); + cmpl_errno = errno; + + return NULL; + } + + if(chdir(buffer) != 0) + { + cmpl_errno = errno; + return NULL; + } + + return g_strdup(buffer2); +} + +/**********************************************************************/ +/* Completion Operations */ +/**********************************************************************/ + +static PossibleCompletion* +attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gint index, length; + + if (!cmpl_state->user_dir_name_buffer && + !get_pwdb(cmpl_state)) + return NULL; + length = strlen(text_to_complete) - 1; + + cmpl_state->user_completion_index += 1; + + while(cmpl_state->user_completion_index < cmpl_state->user_directories_len) + { + index = first_diff_index(text_to_complete + 1, + cmpl_state->user_directories + [cmpl_state->user_completion_index].login); + + switch(index) + { + case PATTERN_MATCH: + break; + default: + if(cmpl_state->last_valid_char < (index + 1)) + cmpl_state->last_valid_char = index + 1; + cmpl_state->user_completion_index += 1; + continue; + } + + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + append_completion_text("~", cmpl_state); + + append_completion_text(cmpl_state-> + user_directories[cmpl_state->user_completion_index].login, + cmpl_state); + + return append_completion_text("/", cmpl_state); + } + + if(text_to_complete[1] || + cmpl_state->user_completion_index > cmpl_state->user_directories_len) + { + cmpl_state->user_completion_index = -1; + return NULL; + } + else + { + cmpl_state->user_completion_index += 1; + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + return append_completion_text("~/", cmpl_state); + } +} + +/* returns the index (>= 0) of the first differing character, + * PATTERN_MATCH if the completion matches */ +static gint +first_diff_index(gchar* pat, gchar* text) +{ + gint diff = 0; + + while(*pat && *text && *text == *pat) + { + pat += 1; + text += 1; + diff += 1; + } + + if(*pat) + return diff; + + return PATTERN_MATCH; +} + +static PossibleCompletion* +append_completion_text(gchar* text, CompletionState* cmpl_state) +{ + gint len, i = 1; + + if(!cmpl_state->the_completion.text) + return NULL; + + len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1; + + if(cmpl_state->the_completion.text_alloc > len) + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } + + while(i < len) { i <<= 1; } + + cmpl_state->the_completion.text_alloc = i; + + cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i); + + if(!cmpl_state->the_completion.text) + return NULL; + else + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } +} + +static CompletionDir* +find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash = strchr(text_to_complete, '/'); + CompletionDir* dir = cmpl_state->reference_dir; + CompletionDir* next; + *remaining_text = text_to_complete; + + while(first_slash) + { + gint len = first_slash - *remaining_text; + gint found = 0; + gchar *found_name = NULL; /* Quiet gcc */ + gint i; + gchar* pat_buf = g_new (gchar, len + 1); + + strncpy(pat_buf, *remaining_text, len); + pat_buf[len] = 0; + + for(i = 0; i < dir->sent->entry_count; i += 1) + { + if(dir->sent->entries[i].is_dir && + fnmatch(pat_buf, dir->sent->entries[i].entry_name, + FNMATCH_FLAGS)!= FNM_NOMATCH) + { + if(found) + { + g_free (pat_buf); + return dir; + } + else + { + found = 1; + found_name = dir->sent->entries[i].entry_name; + } + } + } + + if (!found) + { + /* Perhaps we are trying to open an automount directory */ + found_name = pat_buf; + } + + next = open_relative_dir(found_name, dir, cmpl_state); + + if(!next) + { + g_free (pat_buf); + return NULL; + } + + next->cmpl_parent = dir; + + dir = next; + + if(!correct_dir_fullname(dir)) + { + g_free(pat_buf); + return NULL; + } + + *remaining_text = first_slash + 1; + first_slash = strchr(*remaining_text, '/'); + + g_free (pat_buf); + } + + return dir; +} + +static void +update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state) +{ + gint cmpl_len; + + if(!poss || !cmpl_is_a_completion(poss)) + return; + + cmpl_len = strlen(cmpl_this_completion(poss)); + + if(cmpl_state->updated_text_alloc < cmpl_len + 1) + { + cmpl_state->updated_text = + (gchar*)g_realloc(cmpl_state->updated_text, + cmpl_state->updated_text_alloc); + cmpl_state->updated_text_alloc = 2*cmpl_len; + } + + if(cmpl_state->updated_text_len < 0) + { + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + cmpl_state->updated_text_len = cmpl_len; + cmpl_state->re_complete = cmpl_is_directory(poss); + } + else if(cmpl_state->updated_text_len == 0) + { + cmpl_state->re_complete = FALSE; + } + else + { + gint first_diff = + first_diff_index(cmpl_state->updated_text, + cmpl_this_completion(poss)); + + cmpl_state->re_complete = FALSE; + + if(first_diff == PATTERN_MATCH) + return; + + if(first_diff > cmpl_state->updated_text_len) + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + + cmpl_state->updated_text_len = first_diff; + cmpl_state->updated_text[first_diff] = 0; + } +} + +static PossibleCompletion* +attempt_file_completion(CompletionState *cmpl_state) +{ + gchar *pat_buf, *first_slash; + CompletionDir *dir = cmpl_state->active_completion_dir; + + dir->cmpl_index += 1; + + if(dir->cmpl_index == dir->sent->entry_count) + { + if(dir->cmpl_parent == NULL) + { + cmpl_state->active_completion_dir = NULL; + + return NULL; + } + else + { + cmpl_state->active_completion_dir = dir->cmpl_parent; + + return attempt_file_completion(cmpl_state); + } + } + + g_assert(dir->cmpl_text); + + first_slash = strchr(dir->cmpl_text, '/'); + + if(first_slash) + { + gint len = first_slash - dir->cmpl_text; + + pat_buf = g_new (gchar, len + 1); + strncpy(pat_buf, dir->cmpl_text, len); + pat_buf[len] = 0; + } + else + { + gint len = strlen(dir->cmpl_text); + + pat_buf = g_new (gchar, len + 2); + strcpy(pat_buf, dir->cmpl_text); + strcpy(pat_buf + len, "*"); + } + + if(first_slash) + { + if(dir->sent->entries[dir->cmpl_index].is_dir) + { + if(fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH) + { + CompletionDir* new_dir; + + new_dir = open_relative_dir(dir->sent->entries[dir->cmpl_index].entry_name, + dir, cmpl_state); + + if(!new_dir) + { + g_free (pat_buf); + return NULL; + } + + new_dir->cmpl_parent = dir; + + new_dir->cmpl_index = -1; + new_dir->cmpl_text = first_slash + 1; + + cmpl_state->active_completion_dir = new_dir; + + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + if(dir->cmpl_parent != NULL) + { + append_completion_text(dir->fullname + + strlen(cmpl_state->completion_dir->fullname) + 1, + cmpl_state); + append_completion_text("/", cmpl_state); + } + + append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); + + cmpl_state->the_completion.is_a_completion = + (fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH); + + cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; + if(dir->sent->entries[dir->cmpl_index].is_dir) + append_completion_text("/", cmpl_state); + + g_free (pat_buf); + return &cmpl_state->the_completion; + } +} + + +static gint +get_pwdb(CompletionState* cmpl_state) +{ + struct passwd *pwd_ptr; + gchar* buf_ptr; + gint len = 0, i, count = 0; + + if(cmpl_state->user_dir_name_buffer) + return TRUE; + setpwent (); + + while ((pwd_ptr = getpwent()) != NULL) + { + len += strlen(pwd_ptr->pw_name); + len += strlen(pwd_ptr->pw_dir); + len += 2; + count += 1; + } + + setpwent (); + + cmpl_state->user_dir_name_buffer = g_new(gchar, len); + cmpl_state->user_directories = g_new(CompletionUserDir, count); + cmpl_state->user_directories_len = count; + + buf_ptr = cmpl_state->user_dir_name_buffer; + + for(i = 0; i < count; i += 1) + { + pwd_ptr = getpwent(); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + + strcpy(buf_ptr, pwd_ptr->pw_name); + cmpl_state->user_directories[i].login = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + strcpy(buf_ptr, pwd_ptr->pw_dir); + cmpl_state->user_directories[i].homedir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + qsort(cmpl_state->user_directories, + cmpl_state->user_directories_len, + sizeof(CompletionUserDir), + compare_user_dir); + + endpwent(); + + return TRUE; + +error: + + if(cmpl_state->user_dir_name_buffer) + g_free(cmpl_state->user_dir_name_buffer); + if(cmpl_state->user_directories) + g_free(cmpl_state->user_directories); + + cmpl_state->user_dir_name_buffer = NULL; + cmpl_state->user_directories = NULL; + + return FALSE; +} + +static gint +compare_user_dir(const void* a, const void* b) +{ + return strcmp((((CompletionUserDir*)a))->login, + (((CompletionUserDir*)b))->login); +} + +static gint +compare_cmpl_dir(const void* a, const void* b) +{ + return strcmp((((CompletionDirEntry*)a))->entry_name, + (((CompletionDirEntry*)b))->entry_name); +} + +static gint +cmpl_state_okay(CompletionState* cmpl_state) +{ + return cmpl_state && cmpl_state->reference_dir; +} + +static gchar* +cmpl_strerror(gint err) +{ + if(err == CMPL_ERRNO_TOO_LONG) + return "Name too long"; + else + return g_strerror (err); +} + + +/* Testing area */ +#ifdef TORRIE_DEBUG + +/* Get the selected filename and print it to the console */ +void file_ok_sel( GtkWidget *w, + GtkFileSelection *fs ) +{ + g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); +} + +void destroy( GtkWidget *widget, + gpointer data ) +{ + gtk_main_quit (); +} + +int main( int argc, + char *argv[] ) +{ + GtkWidget *filew; + + gtk_init (&argc, &argv); + + /* Create a new file selection widget */ + filew = gtk_file_selection_new ("Michael's Glorious File Selector"); +// gtk_file_selection_complete(GTK_FILE_SELECTION(filew),"bob"); + + + gtk_signal_connect (GTK_OBJECT (filew), "destroy", + (GtkSignalFunc) destroy, &filew); + /* Connect the ok_button to file_ok_sel function */ + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), + "clicked", (GtkSignalFunc) file_ok_sel, filew ); + + /* Connect the cancel_button to destroy the widget */ + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION + (filew)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (filew)); + + + gtk_widget_show(filew); + +/* + g_print("%d",gtk_file_selection_match_mask("mask.c","m*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.c","m???.c")); + g_print("%d",gtk_file_selection_match_mask("mask.c","m??*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c???")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","m*.c*")); + g_print("%d",gtk_file_selection_match_mask("mask.cout","n*.c???")); + g_print("%d",gtk_file_selection_match_mask("mask.c","[mn]*")); + g_print("%d",gtk_file_selection_match_mask("COPYING","*.xpm")); +*/ + gtk_main (); + + return 0; +} +/* example-end */ +#endif diff --git a/radiant/gtkfilesel.h b/radiant/gtkfilesel.h new file mode 100644 index 00000000..b5c2a697 --- /dev/null +++ b/radiant/gtkfilesel.h @@ -0,0 +1,143 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_FILESEL_H__ +#define __GTK_FILESEL_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TYPE_FILE_SELECTION (gtk_file_selection_get_type ()) +#define GTK_FILE_SELECTION(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_FILE_SELECTION, GtkFileSelection)) +#define GTK_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SELECTION, GtkFileSelectionClass)) +#define GTK_IS_FILE_SELECTION(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_FILE_SELECTION)) +#define GTK_IS_FILE_SELECTION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SELECTION)) + + +typedef struct _GtkFileSelection GtkFileSelection; +typedef struct _GtkFileSelectionClass GtkFileSelectionClass; + +struct _GtkFileSelection +{ + GtkWindow window; + + GtkWidget *dir_list; + GtkWidget *file_list; + GtkWidget *selection_entry; + GtkWidget *selection_text; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *cancel_button; + GtkWidget *help_button; + + /* These are not used. Just fillers in the class structure */ + GtkWidget *history_pulldown; + GtkWidget *history_menu; + GList *history_list; + /* ***************** */ + + GtkWidget *fileop_dialog; + GtkWidget *fileop_entry; + gchar *fileop_file; + gpointer cmpl_state; + + GtkWidget *fileop_c_dir; + GtkWidget *fileop_del_file; + GtkWidget *fileop_ren_file; + + GtkWidget *button_area; + GtkWidget *action_area; + + GtkWidget *history_combo; + GList *prev_history; + GList *next_history; + GtkWidget *mask_entry; + gchar *mask; + gchar *saved_entry; + +}; + +struct _GtkFileSelectionClass +{ + GtkWindowClass parent_class; +}; + + +GtkType gtk_file_selection_get_type (void); +GtkWidget* gtk_file_selection_new (const gchar *title); +void gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename); +gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel); +void gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern); +void gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel); +void gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FILESEL_H__ */ + + + + + + + + + + diff --git a/radiant/gtkmisc.cpp b/radiant/gtkmisc.cpp new file mode 100644 index 00000000..0ab59052 --- /dev/null +++ b/radiant/gtkmisc.cpp @@ -0,0 +1,1610 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Small functions to help with GTK +// + +#include + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#include + + +#ifdef _WIN32 +#include +#define WIN32_LEAN_AND_MEAN +#include +#endif + + + +#ifdef _WIN32 +#include +#include +#define R_OK 04 +#endif +#include "stdafx.h" + +// ============================================================================= +// Misc stuff + +// NOTE TTimo window position saving has always been tricky +// it doesn't work the same between win32 and linux .. see below that code is fairly different +// it's also very poorly done, the save calls are a bit randomly disctributed in the OnDestroy + +void save_window_pos (GtkWidget *wnd, window_position_t& pos) +{ + if ((wnd == NULL) || (wnd->window == NULL)) + return; + + get_window_pos(wnd, &pos.x, &pos.y); + + pos.w = wnd->allocation.width; + pos.h = wnd->allocation.height; + +#ifdef DBG_WINDOWPOS + //Sys_Printf("save_window_pos 'Window %s'\n",buf); +#endif +} + +#ifdef _WIN32 +void win32_get_window_pos(GtkWidget *widget, gint *x, gint *y) +{ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913 + if ( g_PrefsDlg.m_bStartOnPrimMon ) { + RECT rc; + POINT point; + HWND xwnd = (HWND)GDK_WINDOW_HWND (widget->window); + const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); + + GetClientRect(xwnd,&rc); + point.x=rc.left; + point.y=rc.top; + ClientToScreen(xwnd,&point); + + *x=point.x; + *y=point.y; + + *x=max(*x,-widget->allocation.width+10); + *x=min(*x,primaryMonitorRect.width-10); + *y=max(*y,-widget->allocation.height+10); + *y=min(*y,primaryMonitorRect.height-10); + } else { + // this is the same as the unix version of get_window_pos + gdk_window_get_root_origin (widget->window, x, y); + } +#ifdef DBG_WINDOWPOS + Sys_Printf("win32_get_window_pos %p %d,%d\n",widget,*x,*y); +#endif +} +#endif + +void load_window_pos (GtkWidget *wnd, window_position_t& pos) +{ +#ifdef _WIN32 + const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); + + if(pos.x < primaryMonitorRect.x + || pos.y < primaryMonitorRect.y + || pos.x > primaryMonitorRect.x + primaryMonitorRect.width + || pos.y > primaryMonitorRect.y + primaryMonitorRect.height) + gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT); +#else + // FIXME: not multihead safe + if(pos.x < 0 + || pos.y < 0 + || pos.x > gdk_screen_width () + || pos.y > gdk_screen_height ()) + gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT); +#endif + else + gtk_window_move(GTK_WINDOW(wnd), pos.x, pos.y); + + gtk_window_set_default_size (GTK_WINDOW (wnd), pos.w, pos.h); +#ifdef DBG_WINDOWPOS + Sys_Printf("load_window_pos %p 'Window,%s'\n",wnd,windowData); +#endif +} + +gint widget_delete_hide (GtkWidget *widget) +{ + gtk_widget_hide (widget); + + return TRUE; +} + + +// Thanks to Mercury, Fingolfin - ETG +int readLongLE(FILE *file, unsigned long *m_bytesRead, int *value) +{ + byte buf[4]; + int len = fread(buf, 4, 1, file); + *m_bytesRead += 4; + if (len != 1) + return -1; + + *value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; + return 0; +} + +short readShortLE(FILE *file, unsigned long *m_bytesRead, short unsigned *value) +{ + byte buf[2]; + int len = fread(buf, 2, 1, file); + *m_bytesRead += 2; + if (len != 1) + return -1; + + *value = buf[0] | buf[1] << 8; + return 0; +} + +unsigned char *load_bitmap_file (const char* filename, guint16 *width, guint16 *height) +{ + int bmWidth, bmHeight; + short unsigned bmPlanes, bmBitsPixel; + typedef struct { + unsigned char rgbBlue; + unsigned char rgbGreen; + unsigned char rgbRed; + unsigned char rgbReserved; + } RGBQUAD; + unsigned char m1,m2; + int sizeimage; + short unsigned res1,res2; + int filesize, pixoff; + int bmisize, compression; + int xscale, yscale; + int colors, impcol; + unsigned long m_bytesRead = 0; + unsigned char *imagebits = NULL; + FILE *fp; + + *width = *height = 0; + + fp = fopen(filename,"rb"); + if (fp == NULL) + { + return NULL; + } + + size_t rc; + rc = fread(&m1, 1, 1, fp); + m_bytesRead++; + if (rc == -1) + { + fclose(fp); + return NULL; + } + + rc = fread(&m2, 1, 1, fp); + m_bytesRead++; + if ((m1!='B') || (m2!='M')) + { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&filesize)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&res1)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&res2)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&pixoff)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&bmisize)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&bmWidth)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&bmHeight)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&bmPlanes)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&bmBitsPixel)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&compression)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&sizeimage)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&xscale)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&yscale)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&colors)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&impcol)) { + fclose(fp); + return NULL; + } + + if (colors == 0) + colors = 1 << bmBitsPixel; + + RGBQUAD *colormap = NULL; + if (bmBitsPixel != 24) + { + colormap = new RGBQUAD[colors]; + if (colormap == NULL) + { + fclose(fp); + return NULL; + } + + int i; + for (i = 0; i < colors; i++) + { + unsigned char r ,g, b, dummy; + + rc = fread(&b, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + rc = fread(&g, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + rc = fread(&r, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + rc = fread(&dummy, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + colormap[i].rgbRed=r; + colormap[i].rgbGreen=g; + colormap[i].rgbBlue=b; + } + } + + if ((long)m_bytesRead > pixoff) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + while ((long)m_bytesRead < pixoff) + { + char dummy; + fread(&dummy,1,1,fp); + m_bytesRead++; + } + + int w = bmWidth; + int h = bmHeight; + + // set the output params + imagebits = (unsigned char *)malloc(w * h * 3); + long row_size = w * 3; + + if (imagebits != NULL) + { + *width = w; + *height = h; + unsigned char *outbuf = imagebits; + long row = 0; + long rowOffset = 0; + + if (compression == 0) // BI_RGB + { + // read rows in reverse order + for (row = bmHeight - 1; row >= 0; row--) + { + // which row are we working on? + rowOffset = (long unsigned)row * row_size; + + if (bmBitsPixel == 24) + { + for (int col=0;col> bit_count) & mask; + + // lookup the color from the colormap - stuff it in our buffer + // swap red and blue + *(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue; + *(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen; + *(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed; + } + + // read DWORD padding + while ((m_bytesRead - pixoff) & 3) + { + char dummy; + if (fread(&dummy,1,1,fp)!=1) + { + free(imagebits); + if (colormap) + delete [] colormap; + fclose(fp); + return NULL; + } + m_bytesRead++; + } + } + } + } + else + { + int i, x = 0; + unsigned char c, c1 = 0, *pp; + row = 0; + pp = outbuf + (bmHeight - 1) * bmWidth * 3; + + if (bmBitsPixel == 8) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = colormap[c1].rgbRed; pp++; + *pp = colormap[c1].rgbGreen; pp++; + *pp = colormap[c1].rgbBlue; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + (bmHeight - row - 1) * bmWidth * 3; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x*3 + (bmHeight - row - 1) * bmWidth * 3; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + c1 = getc(fp); + *pp = colormap[c1].rgbRed; pp++; + *pp = colormap[c1].rgbGreen; pp++; + *pp = colormap[c1].rgbBlue; pp++; + } + + if (c & 1) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + else if (bmBitsPixel == 4) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + (bmHeight - row - 1) * bmWidth * 3; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x * 3 + (bmHeight - row - 1) * bmWidth * 3; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + if ((i&1) == 0) + c1 = getc(fp); + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++; + } + + if (((c & 3) == 1) || ((c & 3) == 2)) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + } + if (colormap) + delete [] colormap; + + fclose(fp); + } + return imagebits; +} + +void bmp_to_pixmap (const char* filename, GdkPixmap **pixmap, GdkBitmap **mask) +{ + guint16 width, height; + unsigned char *buf; + GdkWindow *window = gdk_get_default_root_window(); + GdkColormap *colormap; + GdkGC* gc = gdk_gc_new (window); + int i, j; + bool hasMask = false; + + *pixmap = *mask = NULL; + buf = load_bitmap_file (filename, &width, &height); + if (!buf) + return; + + colormap = gdk_drawable_get_colormap (window); + *pixmap = gdk_pixmap_new (window, width, height, -1); + + typedef struct + { + GdkColor c; + unsigned char *p; + } PAL; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + unsigned char *p = &buf[(i * width + j) * 3]; + PAL pe; + + pe.c.red = (gushort)(p[0] * 0xFF); + pe.c.green = (gushort)(p[1] * 0xFF); + pe.c.blue = (gushort)(p[2] * 0xFF); + gdk_colormap_alloc_color(colormap, &pe.c, FALSE, TRUE); + gdk_gc_set_foreground(gc, &pe.c); + gdk_draw_point(*pixmap, gc, j, i); + + if (p[0] == 0xFF && p[1] == 0x00 && p[2] == 0xFF) + hasMask = true; + } + } + + gdk_gc_unref (gc); + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + if (hasMask) + { + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + GdkColor mask_pattern; + + // pink is transparent + if ((buf[(i*width+j)*3] == 0xff) && + (buf[(i*width+j)*3+1] == 0x00) && + (buf[(i*width+j)*3+2] == 0xff)) + mask_pattern.pixel = 0; + else + mask_pattern.pixel = 1; + + gdk_gc_set_foreground (gc, &mask_pattern); + // possible Win32 Gtk bug here + //gdk_draw_point (*mask, gc, j, i); + gdk_draw_line (*mask, gc, j, i, j + 1, i); + } + } + } + else + { + GdkColor mask_pattern; + mask_pattern.pixel = 1; + gdk_gc_set_foreground (gc, &mask_pattern); + gdk_draw_rectangle (*mask, gc, 1, 0, 0, width, height); + } + gdk_gc_unref(gc); + free (buf); +} + +void load_pixmap (const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask) +{ + CString str; + + str = g_strBitmapsPath; + str += filename; + + bmp_to_pixmap (str.GetBuffer (), gdkpixmap, mask); + if (*gdkpixmap == NULL) + { + printf("gdkpixmap was null\n"); + char *dummy[] = { "1 1 1 1", " c None", " " }; + printf("calling gdk_pixmap_create_from_xpm_d\n"); + *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), mask, NULL, dummy); + } +} + +// this is the same as above but used by the plugins +// GdkPixmap **gdkpixmap, GdkBitmap **mask +bool WINAPI load_plugin_bitmap (const char* filename, void **gdkpixmap, void **mask) +{ + CString str; + + str = g_strGameToolsPath; + str += g_strPluginsDir; + str += "bitmaps/"; + str += filename; + bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); + + if (*gdkpixmap == NULL) + { + // look in the core plugins + str = g_strAppPath; + str += g_strPluginsDir; + str += "bitmaps/"; + str += filename; + bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); + + if (*gdkpixmap == NULL) + { + + // look in core modules + str = g_strAppPath; + str += g_strModulesDir; + str += "bitmaps/"; + str += filename; + bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); + + if (*gdkpixmap == NULL) + { + char *dummy[] = { "1 1 1 1", " c None", " " }; + *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), (GdkBitmap **)mask, NULL, dummy); + return false; + } + } + } + return true; +} + +// Load a xpm file and return a pixmap widget. +GtkWidget* new_pixmap (GtkWidget* widget, char* filename) +{ + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + load_pixmap (filename, widget, &gdkpixmap, &mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + + gdk_drawable_unref (gdkpixmap); + gdk_drawable_unref (mask); + + return pixmap; +} + +// ============================================================================= +// Menu stuff + +GtkWidget* menu_separator (GtkWidget *menu) +{ + GtkWidget *menu_item = gtk_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_widget_set_sensitive (menu_item, FALSE); + gtk_widget_show (menu_item); + return menu_item; +} + +GtkWidget* menu_tearoff (GtkWidget *menu) +{ + GtkWidget *menu_item = gtk_tearoff_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), menu_item); +// gtk_widget_set_sensitive (menu_item, FALSE); -- controls whether menu is detachable + gtk_widget_show (menu_item); + return menu_item; +} + +GtkWidget* create_sub_menu_with_mnemonic (GtkWidget *bar, gchar *mnemonic) +{ + GtkWidget *item, *sub_menu; + + item = gtk_menu_item_new_with_mnemonic (mnemonic); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (bar), item); + + sub_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), sub_menu); + + return sub_menu; +} + +extern void AddMenuItem (GtkWidget* menu, unsigned int id); + +GtkWidget* create_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_mnemonic (mnemonic); + + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); + + AddMenuItem (item, id); + return item; +} + +GtkWidget* create_check_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id, gboolean active) +{ + GtkWidget *item; + + item = gtk_check_menu_item_new_with_mnemonic(mnemonic); + + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), active); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); + + AddMenuItem (item, id); + return item; +} + +GtkWidget* create_radio_menu_item_with_mnemonic (GtkWidget *menu, GtkWidget *last, gchar *mnemonic, GtkSignalFunc func, int id, gboolean state) +{ + GtkWidget *item; + GSList *group = (GSList*)NULL; + + if (last != NULL) + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last)); + item = gtk_radio_menu_item_new_with_mnemonic (group, mnemonic); + gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (item), state); + + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); + + AddMenuItem (item, id); + return item; +} + +GtkWidget* create_menu_in_menu_with_mnemonic (GtkWidget *menu, const gchar *mnemonic) +{ + GtkWidget *item, *submenu; + + item = gtk_menu_item_new_with_mnemonic(mnemonic); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + + submenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); + + return submenu; +} + +// ============================================================================= +// Message Boxes + +void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +gint dialog_url_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + OpenURL((const char *)g_object_get_data (G_OBJECT (widget), "URL")); + + return TRUE; +} + +int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCaption, guint32 uType, const char* URL) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkAccelGroup *accel; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + gtk_window_set_policy(GTK_WINDOW (window),FALSE,FALSE,TRUE); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent)); + + accel = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (window), accel); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + if (URL) + { + w = gtk_button_new_with_label ("Go to URL"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_url_callback), NULL); + g_object_set_data (G_OBJECT (w), "URL", (void *)URL); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + } + + + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// ============================================================================= +// File dialog + +// fenris #3078 WHENHELLISFROZENOVER + +//#define FILEDLG_DBG + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + bool *success; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + success = (bool*)g_object_get_data (G_OBJECT (parent), "success"); + + if ((int)data == IDOK) + *success = true; + +#ifdef FILEDLG_DBG + else + Sys_Printf("file_sel_callback != IDOK\n"); +#endif + + *loop = 0; +} + +#ifdef _WIN32 +#include +static OPENFILENAME ofn; /* common dialog box structure */ +static char szDirName[MAX_PATH]; /* directory string */ +static char szFile[MAX_PATH]; /* filename string */ +static char szFileTitle[MAX_PATH]; /* file title string */ +static int i, cbString; /* integer count variables */ +static HANDLE hf; /* file handle */ +#else +static char szFile[QER_MAX_NAMELEN]; +#endif + +#define FILEDLG_CUSTOM_FILTER_LENGTH 64 +// to be used with the advanced file selector + +class CFileType : public IFileTypeList +{ + struct filetype_copy_t + { + void operator=(const filetype_t& other) + { + m_name = other.name; + m_pattern = other.pattern; + } + string_t m_name; + string_t m_pattern; + }; +public: + CFileType() + { + m_nTypes = 0; + m_pTypes = NULL; + m_strWin32Filters = NULL; + m_pstrGTKMasks = NULL; + } + + virtual ~CFileType() + { + delete[] m_pTypes; + DestroyWin32Filters(); + DestroyGTKMasks(); + } + + void addType(filetype_t type) + { + filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes+1]; + if(m_nTypes > 0) + { + for(int i=0; igetTypeList(pattern, &typelist); + +#ifdef FILEDLG_DBG + Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path); + if (pattern) + { + Sys_Printf("Patterns:\n"); + char** p = typelist.m_pstrGTKMasks; + while(*p!=NULL) + Sys_Printf("%s\n", *p++); + } + else + Sys_Printf("no patterns\n"); +#endif + +#ifdef _WIN32 + // win32 dialog stores the selected "save as type" extension in the second null-terminated string + char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH]; + + if (g_PrefsDlg.m_bNativeGUI) + { +#ifdef FILEDLG_DBG + Sys_Printf("Doing win32 file dialog..."); +#endif + // do that the native way + /* Place the terminating null character in the szFile. */ + szFile[0] = '\0'; + customfilter[0] = customfilter[1] = customfilter[2] = '\0'; + + /* Set the members of the OPENFILENAME structure. */ + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window); + if (pattern) + { + ofn.nFilterIndex = 0; + ofn.lpstrFilter = typelist.m_strWin32Filters; + } + else ofn.nFilterIndex = 1; + ofn.lpstrCustomFilter = customfilter; + ofn.nMaxCustFilter = sizeof(customfilter); + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFileTitle = NULL; // we don't need to get the name of the file + if(path) + { + // szDirName: Radiant uses unix convention for paths internally + // Win32 (of course) and Gtk (who would have thought) expect the '\\' convention + // copy path, replacing dir separators as appropriate + for(r=path, w=szDirName; *r!='\0'; r++) + *w++ = (*r=='/') ? '\\' : *r; + // terminate string + *w = '\0'; + ofn.lpstrInitialDir = szDirName; + } + else ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = title; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + /* Display the Open dialog box. */ + // it's open or close depending on 'open' parameter + if (open) + { + if (!GetOpenFileName(&ofn)) + return NULL; // canceled + } + else + { + if (!GetSaveFileName(&ofn)) + return NULL; // canceled + } + + if(pattern != NULL) + type = typelist.GetTypeForWin32Filter(customfilter+1); + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + } + else + { +#endif + // do that the Gtk way + if (title == NULL) + title = open ? "Open File" : "Save File"; + +#ifdef FILEDLG_DBG + Sys_Printf("Doing Gtk file dialog:\nBuilding new_path.."); +#endif + // we expect an actual path below, if the path is NULL we might crash + if (!path || path[0] == '\0') + { +#ifdef _WIN32 + path = "C:\\"; +#elif defined (__linux__) || defined (__APPLE__) + path = "/"; +#else + path = "/"; +#endif + } + + // alloc new path with extra char for dir separator + new_path = new char[strlen(path)+1+1]; + // copy path, replacing dir separators as appropriate + for(r=path, w=new_path; *r!='\0'; r++) + *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r; + // add dir separator to end of path if required + if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR; + // terminate string + *w = '\0'; + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); + Sys_Printf("Calling gtk_file_selection_new with title: %s...", title); +#endif + + file_sel = gtk_file_selection_new (title); + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); + Sys_Printf("Set the masks..."); +#endif + +#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0 + // set the masks + if (pattern) + { + gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel)); + gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast(typelist.m_pstrGTKMasks)); + } +#endif + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent)); + +#ifdef FILEDLG_DBG + Sys_Printf("set_data..."); +#endif + bool success = false; + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "success", &success); +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + + if (!open) + { +#ifdef FILEDLG_DBG + Sys_Printf("set_data \"overwrite\" ..."); +#endif + g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1)); +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + } + + if (new_path != NULL) + { +#ifdef FILEDLG_DBG + Sys_Printf("gtk_file_selection_set_filename... %p", file_sel); +#endif + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path); + delete[] new_path; +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + } + + gtk_grab_add (file_sel); +#ifdef FILEDLG_DBG + Sys_Printf("gtk_widget_show... %p", file_sel); +#endif + gtk_widget_show (file_sel); +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + +#ifdef FILEDLG_DBG + Sys_Printf("gtk_main_iteration..."); +#endif + while (loop) + gtk_main_iteration (); + if(success) + { +#if 0 //!\todo Add masks to GtkFileSelection in gtk2 + if(pattern!=NULL) + type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask); +#endif + strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel))); + } +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); +#ifdef _WIN32 + } +#endif + + // don't return an empty filename + if(szFile[0] == '\0') return NULL; + + // convert back to unix format + for(w=szFile; *w!='\0'; w++) + if(*w=='\\') + *w = '/'; + +#if defined(WIN32) + if (g_PrefsDlg.m_bNativeGUI) // filetype mask not supported in gtk dialog yet + { + // when saving, force an extension depending on filetype + /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */ + if(!open && pattern != NULL) + { + // last ext separator + w = strrchr(szFile, '.'); + // no extension + w = (w!=NULL) ? w : szFile+strlen(szFile); + strcpy(w, type.pattern+1); + } + } +#endif + + // prompt to overwrite existing files + if (!open) + if (access (szFile, R_OK) == 0) + if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO) + return NULL; + +#ifdef FILEDLG_DBG + // ... let's use a static filename + Sys_Printf("filename: %p\n", szFile); +#endif + + return szFile; +} + +char* WINAPI dir_dialog (void *parent, const char* title, const char* path) +{ + GtkWidget* file_sel; + char* filename = (char*)NULL; + int loop = 1; + bool success = false; + + file_sel = gtk_file_selection_new (title); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent)); + + gtk_widget_hide (GTK_FILE_SELECTION (file_sel)->file_list->parent); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + g_object_set_data (G_OBJECT (file_sel), "success", &success); + + if (path != NULL) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), path); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel))); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + return filename; +} + +bool WINAPI color_dialog (void *parent, float *color, const char* title) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = color[0]; + clr[1] = color[1]; + clr[2] = color[2]; + + dlg = gtk_color_selection_dialog_new (title); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parent)); + + gtk_widget_show (dlg); + gtk_grab_add (dlg); + + while (loop) + gtk_main_iteration (); + + GdkColor gdkcolor; + gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), &gdkcolor); + clr[0] = gdkcolor.red / 65535.0; + clr[1] = gdkcolor.green / 65535.0; + clr[2] = gdkcolor.blue / 65535.0; + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + color[0] = (float)clr[0]; + color[1] = (float)clr[1]; + color[2] = (float)clr[2]; + + return true; + } + + return false; +} + +void OpenURL(const char *url) +{ + // let's put a little comment + Sys_Printf("OpenURL: %s\n", url); +#ifdef __linux__ + // \todo FIXME: the way we open URLs on *nix should be improved. A script is good (see how I do on RTCW) + char command[2*PATH_MAX]; + snprintf( command, sizeof(command), "%s/openurl.sh \"%s\" &", g_strAppPath.GetBuffer(), url ); + if (system (command) != 0) + gtk_MessageBox (g_pParentWnd->m_pWidget, "Failed to launch Netscape!"); +#endif +#ifdef __APPLE__ + char command[2*PATH_MAX]; + snprintf (command, sizeof(command), + "open \"%s\" &", url, url); + if (system (command) != 0) + gtk_MessageBox (g_pParentWnd->m_pWidget, "Unable to launch browser!"); +#endif +#ifdef _WIN32 + ShellExecute( (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", url, NULL, NULL, SW_SHOW ); +#endif +} + +void CheckMenuSplitting (GtkWidget *&menu) +{ + GtkWidget *item,*menu2; + + GtkRequisition requisition; + gint screen_height; + + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + screen_height = gdk_screen_height (); + + if ((screen_height - requisition.height) < 20) + { + menu2 = gtk_menu_new (); + + // move the last 2 items to a submenu (3 because of win32) + for (int i = 0; i < 3; i++) + { + item = GTK_WIDGET (g_list_last (gtk_container_children (GTK_CONTAINER (menu)))->data); + gtk_widget_ref (item); + gtk_container_remove (GTK_CONTAINER (menu), item); + gtk_menu_append (GTK_MENU (menu2), item); + gtk_widget_unref (item); + } + + item = gtk_menu_item_new_with_label ("--------"); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu2); + menu = menu2; + } +} diff --git a/radiant/gtkmisc.h b/radiant/gtkmisc.h new file mode 100644 index 00000000..ee6bc5fd --- /dev/null +++ b/radiant/gtkmisc.h @@ -0,0 +1,100 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _GTK_MISC_H_ +#define _GTK_MISC_H_ + +#ifdef _WIN32 + +void win32_get_window_pos(GtkWidget *widget, gint *x, gint *y); + +inline void get_window_pos(GtkWidget *wnd, int* x, int* y) +{ + win32_get_window_pos(wnd, x, y); +} + +#else + +inline void get_window_pos(GtkWidget *wnd, int* x, int* y) +{ + gdk_window_get_root_origin (wnd->window, x, y); +} + +#endif + + +struct window_position_t +{ + int x, y, w, h; +}; + +void save_window_pos (GtkWidget *wnd, window_position_t& pos); +void load_window_pos (GtkWidget *wnd, window_position_t& pos); +gint widget_delete_hide (GtkWidget *widget); + +// GdkPixmap **gdkpixmap, GdkBitmap **mask +bool WINAPI load_plugin_bitmap (const char* filename, void **gdkpixmap, void **mask); +void load_pixmap (const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask); +GtkWidget* new_pixmap (GtkWidget* widget, char* filename); + +GtkWidget* menu_separator (GtkWidget *menu); +GtkWidget* menu_tearoff (GtkWidget *menu); +GtkWidget* create_sub_menu_with_mnemonic (GtkWidget *bar, char *mnemonic); +GtkWidget* create_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id); +GtkWidget* create_check_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id, gboolean active); +GtkWidget* create_radio_menu_item_with_mnemonic (GtkWidget *menu, GtkWidget *last, gchar *mnemonic, GtkSignalFunc func, int id, gboolean state); +GtkWidget* create_menu_in_menu_with_mnemonic (GtkWidget *menu, const gchar *mnemonic); + + +/*! +\fn gtk_MessageBox +do various message boxes, IDOK .. IDNO +URL adds an optional 'go to URL' button +*/ +int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCaption = "Radiant", guint32 uType = MB_OK, const char* URL = NULL); +// NOTE: the returned filename is allocated with g_malloc and MUST be freed with g_free (both for win32 and Gtk dialogs) +// GtkWidget *parent +const char* file_dialog (void *parent, gboolean open, const char* title, const char* path = (char*)NULL, const char* pattern = NULL); + +/*! +\fn dir_dialog, prompts for a directory +*/ +char* WINAPI dir_dialog (void *parent, const char* title = "Choose Directory", const char* path = (char*)NULL); +// GtkWidget *parent +bool WINAPI color_dialog (void *parent, float *color, const char* title = "Choose Color"); + +void dialog_button_callback (GtkWidget *widget, gpointer data); +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data); + +void OpenURL(const char *url); + +void CheckMenuSplitting (GtkWidget *&menu); + +#endif // _GTK_MISC_H_ diff --git a/radiant/main.cpp b/radiant/main.cpp new file mode 100644 index 00000000..a2e0e793 --- /dev/null +++ b/radiant/main.cpp @@ -0,0 +1,1246 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#if defined (__linux__) || defined (__APPLE__) + #include + #include + #include + #ifdef __linux__ + #include + #endif + #include + #include + #include + #include + #include +#endif + +#include +#include "stdafx.h" +#include +#include +#include + +#include + +#include "watchbsp.h" +#include "filters.h" + +bool g_bBuildList = false; +int g_argc; +char** g_argv; + +// ============================================================================= +// Splash screen + +// get rid of it when debugging +#if defined (_DEBUG) + #define SKIP_SPLASH +#endif + +static GtkWidget *splash_screen; + +// called based on a timer, or in particular cases when we don't want to keep it around +gint try_destroy_splash (gpointer data) +{ + if (splash_screen) + { + gtk_widget_destroy (splash_screen); + splash_screen = NULL; + } + return FALSE; +} + +static void create_splash () +{ + GtkWidget *alert_frame, *alert_frame1, *pixmap; + + splash_screen = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER); + gtk_widget_realize (splash_screen); + + alert_frame1 = gtk_frame_new (NULL); + gtk_widget_show (alert_frame1); + gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1); + gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT); + + alert_frame = gtk_frame_new (NULL); + gtk_widget_show (alert_frame); + + gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame); + gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN); + gtk_container_border_width (GTK_CONTAINER (alert_frame), 3); + + pixmap = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (alert_frame), pixmap); + + CString str; + guint16 width, height; + unsigned char *buf; + + str = g_strGameToolsPath; + str += "bitmaps/splash.bmp"; + + unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height); + buf = load_bitmap_file (str.GetBuffer (), &width, &height); + + if (!buf) + { + str = g_strBitmapsPath; + str += "splash.bmp"; + + buf = load_bitmap_file (str.GetBuffer (), &width, &height); + } + + if (buf) + { + GtkPreview *preview = GTK_PREVIEW (pixmap); + gtk_preview_size (preview, width, height); + for (int y = 0; y < height; y++) + gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width); + } + + gtk_widget_show_all (splash_screen); + + while (gtk_events_pending ()) + gtk_main_iteration (); +} + +// ============================================================================= +// Loki stuff + +#if defined (__linux__) || defined (__APPLE__) + +/* A short game name, could be used as argv[0] */ +static char game_name[100] = ""; + +/* The directory where the data files can be found (run directory) */ +static char datapath[PATH_MAX]; + +char *loki_gethomedir(void) +{ + char *home = NULL; + + home = getenv("HOME"); + if ( home == NULL ) + { + uid_t id = getuid(); + struct passwd *pwd; + + setpwent(); + while ( (pwd = getpwent()) != NULL ) + { + if ( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + } + endpwent(); + } + return home; +} + +/* Must be called BEFORE loki_initialize */ +void loki_setgamename(const char *n) +{ + strncpy(game_name, n, sizeof(game_name)); +} + + #ifdef __linux__ +/* Code to determine the mount point of a CD-ROM */ +int loki_getmountpoint(const char *device, char *mntpt, int max_size) +{ + char devpath[PATH_MAX], mntdevpath[PATH_MAX]; + FILE * mountfp; + struct mntent *mntent; + int mounted; + + /* Nothing to do with no device file */ + if ( device == NULL ) + { + *mntpt = '\0'; + return -1; + } + + /* Get the fully qualified path of the CD-ROM device */ + if ( realpath(device, devpath) == NULL ) + { + perror("realpath() on your CD-ROM failed"); + return(-1); + } + + /* Get the mount point */ + mounted = -1; + memset(mntpt, 0, max_size); + mountfp = setmntent( _PATH_MNTTAB, "r" ); + if ( mountfp != NULL ) + { + mounted = 0; + while ( (mntent = getmntent( mountfp )) != NULL ) + { + char *tmp, mntdev[1024]; + + strcpy(mntdev, mntent->mnt_fsname); + if ( strcmp(mntent->mnt_type, "supermount") == 0 ) + { + tmp = strstr(mntent->mnt_opts, "dev="); + if ( tmp ) + { + strcpy(mntdev, tmp+strlen("dev=")); + tmp = strchr(mntdev, ','); + if ( tmp ) + { + *tmp = '\0'; + } + } + } + if ( strncmp(mntdev, "/dev", 4) || + realpath(mntdev, mntdevpath) == NULL ) + { + continue; + } + if ( strcmp( mntdevpath, devpath ) == 0 ) + { + mounted = 1; + assert((int)strlen( mntent->mnt_dir ) < max_size); + strncpy( mntpt, mntent->mnt_dir, max_size-1); + mntpt[max_size-1] = '\0'; + break; + } + } + endmntent( mountfp ); + } + return(mounted); +} + #endif + +/* + This function gets the directory containing the running program. + argv0 - the 0'th argument to the program +*/ +// FIXME TTimo +// I don't understand this function. It looks like something cut from another piece of software +// we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var. +// even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell +void loki_initpaths(char *argv0) +{ + char temppath[PATH_MAX]; //, env[100]; + char *home; //, *ptr, *data_env; + + home = loki_gethomedir(); + if ( home == NULL ) + { + home = "."; + } + + if (*game_name == 0) /* Game name defaults to argv[0] */ + loki_setgamename(argv0); + + strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */ + if ( ! strrchr(temppath, '/') ) + { + char *path; + char *last; + int found; + + found = 0; + path = getenv("PATH"); + do + { + /* Initialize our filename variable */ + temppath[0] = '\0'; + + /* Get next entry from path variable */ + last = strchr(path, ':'); + if ( ! last ) + last = path+strlen(path); + + /* Perform tilde expansion */ + if ( *path == '~' ) + { + strcpy(temppath, home); + ++path; + } + + /* Fill in the rest of the filename */ + if ( last > (path+1) ) + { + strncat(temppath, path, (last-path)); + strcat(temppath, "/"); + } + strcat(temppath, "./"); + strcat(temppath, argv0); + + /* See if it exists, and update path */ + if ( access(temppath, X_OK) == 0 ) + { + ++found; + } + path = last+1; + + } while ( *last && !found ); + + } else + { + /* Increment argv0 to the basename */ + argv0 = strrchr(argv0, '/')+1; + } + + /* Now canonicalize it to a full pathname for the data path */ + if ( realpath(temppath, datapath) ) + { + /* There should always be '/' in the path */ + *(strrchr(datapath, '/')) = '\0'; + } +} + +char *loki_getdatapath(void) +{ + return(datapath); +} + +#endif + +// end of Loki stuff +// ============================================================================= + +void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) +{ + gboolean in_recursion; + gboolean is_fatal; + char buf[256]; + + in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; + is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; + log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK); + + if (!message) + message = "(NULL) message"; + + if (domain) + strcpy (buf, domain); + else + strcpy (buf, "**"); + strcat (buf, "-"); + + switch (log_level) + { + case G_LOG_LEVEL_ERROR: + if (in_recursion) + strcat (buf, "ERROR (recursed) **: "); + else + strcat (buf, "ERROR **: "); + break; + case G_LOG_LEVEL_CRITICAL: + if (in_recursion) + strcat (buf, "CRITICAL (recursed) **: "); + else + strcat (buf, "CRITICAL **: "); + break; + case G_LOG_LEVEL_WARNING: + if (in_recursion) + strcat (buf, "WARNING (recursed) **: "); + else + strcat (buf, "WARNING **: "); + break; + case G_LOG_LEVEL_MESSAGE: + if (in_recursion) + strcat (buf, "Message (recursed): "); + else + strcat (buf, "Message: "); + break; + case G_LOG_LEVEL_INFO: + if (in_recursion) + strcat (buf, "INFO (recursed): "); + else + strcat (buf, "INFO: "); + break; + case G_LOG_LEVEL_DEBUG: + if (in_recursion) + strcat (buf, "DEBUG (recursed): "); + else + strcat (buf, "DEBUG: "); + break; + default: + /* we are used for a log level that is not defined by GLib itself, + * try to make the best out of it. + */ + if (in_recursion) + strcat (buf, "LOG (recursed:"); + else + strcat (buf, "LOG ("); + if (log_level) + { + gchar string[] = "0x00): "; + gchar *p = string + 2; + guint i; + + i = g_bit_nth_msf (log_level, -1); + *p = i >> 4; + p++; + *p = '0' + (i & 0xf); + if (*p > '9') + *p += 'A' - '9' - 1; + + strcat (buf, string); + } else + strcat (buf, "): "); + } + + strcat (buf, message); + if (is_fatal) + strcat (buf, "\naborting...\n"); + else + strcat (buf, "\n"); + + printf ("%s\n", buf); + Sys_FPrintf (SYS_WRN, buf); + // TTimo NOTE: in some cases it may be handy to log only to the file +// Sys_FPrintf (SYS_NOCON, buf); +} + +int main (int argc, char* argv[]) +{ + char *libgl, *ptr; + int i, j, k; + +#ifdef _WIN32 + libgl = "opengl32.dll"; +#endif + +#if defined (__linux__) + libgl = "libGL.so.1"; +#endif + +#ifdef __APPLE__ + libgl = "/usr/X11R6/lib/libGL.1.dylib"; +#endif + +#if defined (__linux__) || defined (__APPLE__) + // Give away unnecessary root privileges. + // Important: must be done before calling gtk_init(). + char *loginname; + struct passwd *pw; + seteuid(getuid()); + if (geteuid() == 0 && (loginname = getlogin()) != NULL && + (pw = getpwnam(loginname)) != NULL) + setuid(pw->pw_uid); +#endif + + gtk_disable_setlocale(); + + gtk_init(&argc, &argv); + + if ((ptr = getenv ("Q3R_LIBGL")) != NULL) + libgl = ptr; + + for (i = 1; i < argc; i++) + { + char* param = argv[i]; + + if (param[0] == '-' && param[1] == '-') + { + param += 2; + + if ((strcmp (param, "libgl") == 0) && (i != argc)) + { + libgl = argv[i+1]; + argv[i] = argv[i+1] = NULL; + i++; + } else if (strcmp (param, "builddefs") == 0) + { + g_bBuildList = true; + argv[i] = NULL; + } + } + } + + for (i = 1; i < argc; i++) + { + for (k = i; k < argc; k++) + if (argv[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < argc; j++) + argv[j-k] = argv[j]; + argc -= k; + } + } + + g_argc = argc; + g_argv = argv; + + g_strPluginsDir = "plugins/"; + g_strModulesDir = "modules/"; + +#ifdef _WIN32 + // get path to the editor + char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1); + GetModuleFileName(NULL, pBuffer, _MAX_PATH); + pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0'; + QE_ConvertDOSToUnixName(pBuffer, pBuffer); + g_strAppPath.ReleaseBuffer(); + + g_strBitmapsPath = g_strAppPath; + g_strBitmapsPath += "bitmaps/"; + +#if 0 + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + // now check if we are running from a network installation + // use a dummy file as the flag + FILE *f_netrun; + CString strNetrun; + strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; + f_netrun = fopen(strNetrun.GetBuffer(), "r"); + if (f_netrun) + { + fclose(f_netrun); + g_PrefsDlg.m_bUseHomePath = true; + } +#endif + CGameDialog::UpdateNetrun(false); // read the netrun configuration + + if (CGameDialog::GetNetrun()) + { + // we have to find a per-user g_strTempPath + // this behaves the same as on Linux + g_strTempPath = getenv("USERPROFILE"); + if (!g_strTempPath.GetLength()) + { + CString msg; + msg = "Radiant is configured to run from a network installation.\n"; + msg += "I couldn't find the environement variable USERPROFILE\n"; + msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n"; + gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK); + g_strTempPath = "C:\\"; + } + g_strTempPath += "\\RadiantSettings\\"; + Q_mkdir(g_strTempPath.GetBuffer(), 0755); + g_strTempPath += RADIANT_VERSION; + g_strTempPath += "\\"; + Q_mkdir(g_strTempPath.GetBuffer(), 0755); + } + else + { + // use the core path as temp (to save commandlist.txt, and do the .pid files) + g_strTempPath = g_strAppPath; + } + +#endif + +#if defined (__linux__) || defined (__APPLE__) + Str home; + home = g_get_home_dir (); + AddSlash (home); + home += ".radiant/"; + Q_mkdir (home.GetBuffer (), 0775); + home += RADIANT_VERSION; + Q_mkdir (home.GetBuffer (), 0775); + g_strTempPath = home.GetBuffer (); + AddSlash (g_strTempPath); + + loki_initpaths(argv[0]); + + // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32) + // it's a general convention in Radiant to have the slash at the end of directories + char real[PATH_MAX]; + realpath (loki_getdatapath(), real); + if (real[strlen(real)-1] != '/') + strcat(real, "/"); + + g_strAppPath = real; + +#if 0 + printf("g_strAppPath: %s\n", g_strAppPath.GetBuffer()); +#endif + + // radiant is installed in the parent dir of "tools/" + // NOTE: this is not very easy for debugging + // maybe add options to lookup in several places? + // (for now I had to create symlinks) + g_strBitmapsPath = g_strAppPath; + g_strBitmapsPath += "bitmaps/"; +#if 0 + printf("g_strBitmapsPath: %s\n", g_strBitmapsPath.GetBuffer()); +#endif + + // we will set this right after the game selection is done + g_strGameToolsPath = g_strAppPath; + +#endif + + // init the DTD path + g_strDTDPath = g_strAppPath; + g_strDTDPath += "dtds/"; + + /*! + the global prefs loading / game selection dialog might fail for any reason we don't know about + we need to catch when it happens, to cleanup the stateful prefs which might be killing it + and to turn on console logging for lookup of the problem + this is the first part of the two step .pid system + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + */ + g_pidFile = g_strTempPath.GetBuffer (); + g_pidFile += "radiant.pid"; + + FILE *pid; + pid = fopen (g_pidFile.GetBuffer(), "r"); + if (pid != NULL) + { + fclose (pid); + CString msg; + + if (remove (g_pidFile.GetBuffer ()) == -1) + { + msg = "WARNING: Could not delete "; msg += g_pidFile; + gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + } + + // in debug, never prompt to clean registry, turn console logging auto after a failed start +#if !defined(_DEBUG) + msg = "Found the file "; + msg += g_pidFile; + msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n" + "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" + "WARNING: the global prefs will be lost if you choose YES."; + + if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + // remove global prefs and shutdown + g_PrefsDlg.mGamesDialog.Reset(); + // remove the prefs file (like a full reset of the registry) + //remove (g_PrefsDlg.m_inipath->str); + gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK ); + _exit(-1); + } + msg = "Logging console output to "; + msg += g_strTempPath; + msg += "radiant.log\nRefer to the log if Radiant fails to start again."; + + gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); +#endif + + // set without saving, the class is not in a coherent state yet + // just do the value change and call to start logging, CGamesDialog will pickup when relevant + g_PrefsDlg.mGamesDialog.m_bLogConsole = true; + g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true; + Sys_LogFile(); + } + + // create a primary .pid for global init run + pid = fopen (g_pidFile.GetBuffer(), "w"); + if (pid) + fclose (pid); + + // a safe check to avoid people running broken installations + // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing) + // make something idiot proof and someone will make better idiots, this may be overkill + // let's leave it disabled in debug mode in any case + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 +#ifndef _DEBUG +#define CHECK_VERSION +#endif +#ifdef CHECK_VERSION + // locate and open RADIANT_MAJOR and RADIANT_MINOR + qboolean bVerIsGood = true; + Str ver_file_name; + ver_file_name = g_strAppPath; + ver_file_name += "RADIANT_MAJOR"; + FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r"); + if (ver_file) + { + char buf[10]; + int chomp; + fread(buf, 1, 10, ver_file); + // chomp it (the hard way) + chomp = 0; + while(buf[chomp] >= '0' && buf[chomp] <= '9') + chomp++; + buf[chomp] = '\0'; + if (strcmp(buf, RADIANT_MAJOR_VERSION)) + { + Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf); + bVerIsGood = false; + } + } + else + { + Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer()); + bVerIsGood = false; + } + ver_file_name = g_strAppPath; + ver_file_name += "RADIANT_MINOR"; + ver_file = fopen (ver_file_name.GetBuffer(), "r"); + if (ver_file) + { + char buf[10]; + int chomp; + fread(buf, 1, 10, ver_file); + // chomp it (the hard way) + chomp = 0; + while(buf[chomp] >= '0' && buf[chomp] <= '9') + chomp++; + buf[chomp] = '\0'; + if (strcmp(buf, RADIANT_MINOR_VERSION)) + { + Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf); + bVerIsGood = false; + } + } + else + { + Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer()); + bVerIsGood = false; + } + if (!bVerIsGood) + { + CString msg; + msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n"; + msg += "Make sure you run the right/latest editor binary you installed\n"; + msg += g_strAppPath; msg += "\n"; + msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information"; + gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219"); + _exit(-1); + } +#endif + + g_qeglobals.disable_ini = false; + g_PrefsDlg.Init (); + + // close the primary + if (remove (g_pidFile.GetBuffer ()) == -1) + { + CString msg; + msg = "WARNING: Could not delete "; msg += g_pidGameFile; + gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + } + + /*! + now the secondary game dependant .pid file + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + */ + g_pidGameFile = g_PrefsDlg.m_rc_path->str; + g_pidGameFile += "radiant-game.pid"; + + pid = fopen (g_pidGameFile.GetBuffer(), "r"); + if (pid != NULL) + { + fclose (pid); + CString msg; + if (remove (g_pidGameFile.GetBuffer ()) == -1) + { + msg = "WARNING: Could not delete "; msg += g_pidGameFile; + gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + } + + msg = "Found the file "; + msg += g_pidGameFile; + msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n" + "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" + "WARNING: preferences will be lost if you choose YES."; + + // in debug, never prompt to clean registry, turn console logging auto after a failed start +#if !defined(_DEBUG) + //bleh + if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + // remove the game prefs files + remove (g_PrefsDlg.m_inipath->str); + char buf[PATH_MAX]; + sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str); + remove(buf); + // remove the global pref too + g_PrefsDlg.mGamesDialog.Reset(); + gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK ); + _exit(-1); + } + msg = "Logging console output to "; + msg += g_strTempPath; + msg += "radiant.log\nRefer to the log if Radiant fails to start again."; + + gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); +#endif + + // force console logging on! (will go in prefs too) + g_PrefsDlg.mGamesDialog.m_bLogConsole = true; + g_PrefsDlg.mGamesDialog.SavePrefs(); + Sys_LogFile(); + + g_PrefsDlg.LoadPrefs(); + + } else + { + // create one, will remove right after entering message loop + pid = fopen (g_pidGameFile.GetBuffer(), "w"); + if (pid) + fclose (pid); + + g_PrefsDlg.LoadPrefs(); + +#ifndef _DEBUG // I can't be arsed about that prompt in debug mode + // if console logging is on in the prefs, warn about performance hit + if (g_PrefsDlg.mGamesDialog.m_bLogConsole) + { + if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n" + "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + g_PrefsDlg.mGamesDialog.m_bLogConsole = false; + g_PrefsDlg.mGamesDialog.SavePrefs(); + } + } +#endif + // toggle console logging if necessary + Sys_LogFile(); + } + + // FIXME http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + // we should search in g_strTempPath, then move over to look at g_strAppPath? +#ifdef _WIN32 + // fine tune the look of the app using a gtk rc file + // we try to load an RC file placed in the application directory + // build the full path + Str sRCFile; + sRCFile = g_strAppPath; + sRCFile += "radiantgtkrc"; + // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\' + pBuffer = (char *)sRCFile.GetBuffer(); + for (i=0; i 0) + Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer()); + else + Map_New(); + + // load up shaders now that we have the map loaded + // eviltypeguy + Texture_ShowStartupShaders (); + +#ifndef SKIP_SPLASH + gdk_window_raise (splash_screen->window); + gtk_window_set_transient_for (GTK_WINDOW (splash_screen), GTK_WINDOW (g_pParentWnd->m_pWidget)); + gtk_timeout_add (1000, try_destroy_splash, NULL); +#endif + + g_pParentWnd->GetSynapseServer().DumpActiveClients(); + + //++timo: temporary debug + g_pParentWnd->DoWatchBSP(); + + gtk_main (); + + // close the log file if any + // NOTE: don't save prefs past this point! + g_PrefsDlg.mGamesDialog.m_bLogConsole = false; + // set the console window to NULL to avoid Sys_Printf crashing + g_qeglobals_gui.d_edit = NULL; + Sys_LogFile(); + + // NOTE TTimo not sure what this _exit(0) call is worth + // restricting it to linux build +#ifdef __linux__ + _exit (0); +#endif + return 0; +} + +// ydnar: quick and dirty fix, just make the buffer bigger +#define BIG_PATH_MAX 4096 + +// TTimo: decompose the BSP command into several steps so we can monitor them eventually +void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname) +{ + const char *in; + char *out; + char src[BIG_PATH_MAX]; + char rsh[BIG_PATH_MAX]; + char base[BIG_PATH_MAX]; + + strcpy(src, mapname); + strlwr(src); + in = strstr(src, "maps/"); + if (!in) + { + in = strstr(src, "maps/"); + } + if (in) + { + in += 5; + strcpy(base, in); + out = base; + while (*out) + { + if (*out == '\\') + { + *out = '/'; + } + out++; + } + } else + { + ExtractFileName (mapname, base); + } + + // this important step alters the map name to add fs_game + // NOTE: it used to add fs_basepath too + // the fs_basepath addition moved to being in the project file during the bug fixing rush + // but it may not have been the right thing to do + + // HACK: halflife compiler tools don't support -fs_game + // HACK: neither does JKII/SoF2/ etc.. + // do we use & have fs_game? + + if (g_pGameDescription->mGameFile != "hl.game" && + *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0') + { + // set with fs_game + sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname); + } + else + { + sprintf(src, "\"%s\"", mapname); + } + + rsh[0] = 0; + + QE_ConvertDOSToUnixName(src, src); + + // initialise the first step + out = new char[BIG_PATH_MAX]; //% PATH_MAX + g_ptr_array_add( out_array, out ); + + in = ValueForKey( g_qeglobals.d_project_entity, bspaction ); + while (*in) + { + if (in[0] == '!') + { + strcpy (out, rsh); + out += strlen(rsh); + in++; + continue; + } + if (in[0] == '#') + { + char tmp[2048]; + // we process these only if monitoring + if (g_PrefsDlg.m_bWatchBSP) + { + // -connect global option (the only global option so far anyway) + strcpy (tmp, " -connect 127.0.0.1:39000 "); + strcpy (out, tmp); + out += strlen(tmp); + } + in++; + continue; + } + if (in[0] == '$') + { + // $ expansion + strcpy (out, src); + out += strlen(src); + in++; + continue; + } + if (in[0] == '@') + { + *out++ = '"'; + in++; + continue; + } + if (in[0] == '&') + if (in[1] == '&') + { + // start a new step + *out = 0; + in = in + 2; + out = new char[BIG_PATH_MAX]; //% PATH_MAX + g_ptr_array_add( out_array, out ); + } + *out++ = *in++; + } + *out = 0; +} + +void FindReplace(CString& strContents, const char* pTag, const char* pValue) +{ + if (strcmp(pTag, pValue) == 0) + return; + for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) + { + int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; + CString strLeft = strContents.Left(nPos); + CString strRight = strContents.Right(nRightLen); + strLeft += pValue; + strLeft += strRight; + strContents = strLeft; + } +} + +// save the map, deals with regioning +void SaveWithRegion(char *name) +{ + strcpy (name, currentmap); + if (region_active) + { + // temporary cut the region to save regular map + region_active = false; + Map_SaveFile (name, false); + region_active = true; + StripExtension (name); + strcat (name, ".reg"); + } + + Map_SaveFile (name, region_active); +} + +void RunBsp (char *command) +{ + GPtrArray *sys; + char batpath[BIG_PATH_MAX]; //% PATH_MAX + char temppath[BIG_PATH_MAX]; //% PATH_MAX + char name[BIG_PATH_MAX]; //% PATH_MAX + char cWork[BIG_PATH_MAX]; //% PATH_MAX + FILE *hFile; + unsigned int i; + + SetInspectorMode(W_CONSOLE); + + strcpy (temppath, g_strTempPath.GetBuffer ()); + + SaveWithRegion(name); + + const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd"); + if (rsh == NULL) + { + CString strPath, strFile; + + ExtractPath_and_Filename(name, strPath, strFile); + AddSlash(strPath); + strncpy(cWork, strPath, 1024); + strcat(cWork, strFile); + } else + { + strcpy(cWork, name); + } + + // get the array ready + //++timo TODO: free the array, free the strings ourselves with delete[] + sys = g_ptr_array_new(); + + QE_ExpandBspString (command, sys, cWork); + + if (g_PrefsDlg.m_bWatchBSP) + { + // grab the file name for engine running + char *bspname = new char[1024]; + ExtractFileName( currentmap, bspname ); + StripExtension( bspname ); + g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname ); + } else + { + // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it + CString strSys; + for (i=0; i < sys->len; i++ ) + { + strSys += (char *)g_ptr_array_index( sys, i); +#ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window + if (i==0) + strSys += " >"; + else + strSys += " >>"; + strSys += "\""; + strSys += temppath; + strSys += "junk.txt\""; +#endif + strSys += "\n"; + }; + +#if defined (__linux__) || defined (__APPLE__) + + // write qe3bsp.sh + sprintf (batpath, "%sqe3bsp.sh", temppath); + Sys_Printf("Writing the compile script to '%s'\n", batpath); + Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, "#!/bin/sh \n\n"); + fprintf (hFile, strSys.GetBuffer()); + fclose (hFile); + chmod (batpath, 0744); +#endif + +#ifdef _WIN32 + sprintf (batpath, "%sqe3bsp.bat", temppath); + Sys_Printf("Writing the compile script to '%s'\n", batpath); + Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, strSys.GetBuffer()); + fclose (hFile); +#endif + + Pointfile_Delete (); + +#if defined (__linux__) || defined (__APPLE__) + + pid_t pid; + + pid = fork (); + switch (pid) + { + case -1: + Error ("CreateProcess failed"); + break; + case 0: + execlp (batpath, batpath, NULL); + printf ("execlp error !"); + _exit (0); + break; + default: + break; + } +#endif + +#ifdef _WIN32 + Sys_Printf ("Running bsp command...\n"); + Sys_Printf ("\n%s\n", strSys.GetBuffer()); + + WinExec( batpath, SW_SHOWNORMAL ); +#endif + } +#ifdef _DEBUG + // yeah, do it .. but not now right before 1.1-TA-beta release + Sys_Printf("TODO: erase GPtrArray\n"); +#endif +} + +#if 0 + +#ifdef _WIN32 + +int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ) +{ + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW | // support window + PFD_SUPPORT_OPENGL | // support OpenGL + PFD_DOUBLEBUFFER, // double buffered + PFD_TYPE_RGBA, // RGBA type + 24, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 32, // depth bits + 0, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; // + int pixelformat = 0; + + zbuffer = true; + if ( !zbuffer ) + pfd.cDepthBits = 0; + + if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) + { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf); + Error ("ChoosePixelFormat failed"); + } + + if (!SetPixelFormat(hDC, pixelformat, &pfd)) + Error ("SetPixelFormat failed"); + + return pixelformat; +} + +#endif + +#endif diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp new file mode 100644 index 00000000..3aedadda --- /dev/null +++ b/radiant/mainframe.cpp @@ -0,0 +1,7785 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Main Window for Q3Radiant +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#ifdef _WIN32 +extern "C" { +#include +#define COMPILE_MULTIMON_STUBS +#include +} +#endif +#include +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) + #include +#endif +#include "gtkmisc.h" +#include "groupdialog.h" +#include "patchdialog.h" +#include "filters.h" + +// use this to verbose what happens with the beyboard +#ifdef _DEBUG +// #define DBG_KBD +#endif + +// globals +CString g_strAppPath; ///< holds the full path of the executable +CString g_strDTDPath; ///< path to the DTD files +/*! +see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 for the two below +*/ +CString g_pidFile; ///< the global .pid file (only for global part of the startup) +CString g_pidGameFile; ///< the game-specific .pid file +CString g_strBitmapsPath; // directory where the bitmaps are stored + +/*! +points to the game tools directory, for instance +C:\Program Files\Quake III Arena\GtkRadiant +(or other games) +this is one of the main variables that are configured by the game selection on startup +/plugins +/modules +and also q3map, bspc +*/ +CString g_strGameToolsPath; ///< this is set by g_PrefsDlg.mGamesDialog +CGameDescription *g_pGameDescription; ///< shortcut to g_PrefsDlg.mGamesDialog.m_pCurrentDescription +CString g_strPluginsDir; ///< name of plugins directory, always sub-directory of toolspath +CString g_strModulesDir; ///< name of modules directory, always sub-directory of toolspath + +/*! +directory for temp files +NOTE: on *nix this is were we check for .pid +*/ +CString g_strTempPath; +MainFrame* g_pParentWnd = NULL; // used to precast to CMainFrame +PrefsDlg g_Preferences; // global prefs instance +PrefsDlg& g_PrefsDlg = g_Preferences; // reference used throughout +int g_nUpdateBits = 0; // window update flags +bool g_bScreenUpdates = true; // whether window painting is active, used in a few places + // to disable updates for speed reasons + // both of the above should be made members of CMainFrame +int g_bIgnoreCommands; // Used to ignore commands when checking menus/toolbars +GSList *g_BSPFrontendCommands; // List of commands in the BSP menu + +const int CMD_TEXTUREWAD_END = CMD_TEXTUREWAD + MAX_TEXTUREDIRS - 1; +const int CMD_BSPCOMMAND_END = CMD_BSPCOMMAND + 127; + +extern bool g_bCrossHairs; +extern int g_argc; +extern char** g_argv; +extern PatchDialog g_PatchDialog; + +GtkAccelGroup* global_accel; + +void Select_Ungroup (); + +// command mapping stuff +// +// m_strCommand is the command string +// m_nKey is the GDK_??? equivelant +// m_nModifiers are key states as follows +// bit +// 1 - shift +// 2 - alt +// 4 - control +// 8 - press only +// +#define SPEED_MOVE 32 +#define SPEED_TURN 22.5 + +// NOTE: the menu item field is REQUIRED, Gtk uses it to bind the keyboard shortcut +// - if you add a command here and you don't want a menu item, use the "hidden" menu +// - if you decide to add a menu item, check if it's not in the "hidden" menu already +SCommandInfo g_Commands[] = +{ + {"CycleOutlineStyle", 'J', 0x00, ID_SELECTION_OUTLINESTYLE, "menu_selection_outlinestyle"}, + {"CSGMerge", 'U', 0x04, ID_SELECTION_CSGMERGE, "menu_selection_csgmerge"}, + {"CSGSubtract", 'U', 0x01, ID_SELECTION_CSGSUBTRACT, "menu_selection_csgsubstract"}, + // {"ViewGroups", 'G', 0x00, ID_VIEW_GROUPS, "menu_view_groups"}, (temporary disabled) + {"HideSelected", 'H', 0x00, ID_VIEW_HIDESHOW_HIDESELECTED, "menu_view_hideshow_hideselected"}, + {"ShowHidden", 'H', 0x01, ID_VIEW_HIDESHOW_SHOWHIDDEN, "menu_view_hideshow_showhidden"}, + {"BendMode", 'B', 0x00, ID_PATCH_BEND, "menu_patch_bend"}, + {"FitTexture", 'B', 0x01, IDC_BTN_FACEFIT, "menu_idc_btn_facefit"}, + {"ViewTextures", 'T', 0, ID_VIEW_TEXTURE, "menu_view_texture"}, + {"ThickenPatch", 'T', 0x04, ID_CURVE_THICKEN, "menu_curve_thicken"}, + {"MakeOverlayPatch", 'Y', 0, ID_CURVE_OVERLAY_SET, "menu_curve_overlay_set"}, + {"ClearPatchOverlays", 'L', 0x04, ID_CURVE_OVERLAY_CLEAR, "menu_curve_overlay_clear"}, + {"SurfaceInspector", 'S', 0, ID_TEXTURES_INSPECTOR, "menu_textures_inspector"}, + {"PatchInspector", 'S', 0x01, ID_PATCH_INSPECTOR, "menu_patch_inspector"}, + {"RedisperseRows", 'E', 0x04, ID_CURVE_REDISPERSE_ROWS, "menu_curve_redisperse_rows"}, + {"RedisperseIntermediateCols", 'E', 0x05, ID_CURVE_REDISPERSE_INTERMEDIATE_COLS, "menu_curve_redisperse_cols"}, + {"InvertCurveTextureX", 'I', 0x05, ID_CURVE_NEGATIVETEXTUREY, "menu_curve_negativetexturey"}, + {"InvertCurveTextureY", 'I', 0x01, ID_CURVE_NEGATIVETEXTUREX, "menu_curve_negativetexturex"}, + {"InvertCurve", 'I', 0x04, ID_CURVE_NEGATIVE, "menu_curve_negative"}, + {"IncPatchColumn", GDK_KP_Add, 0x05, ID_CURVE_INSERTCOLUMN, "menu_curve_insertcolumn"}, + {"IncPatchRow", GDK_KP_Add, 0x04, ID_CURVE_INSERTROW, "menu_curve_insertrow"}, + {"DecPatchColumn", GDK_KP_Subtract, 0x05, ID_CURVE_DELETECOLUMN, "menu_curve_deletecolumn"}, + {"DecPatchRow", GDK_KP_Subtract, 0x04, ID_CURVE_DELETEROW, "menu_curve_deleterow"}, + {"Patch TAB", GDK_Tab, 0x00, ID_PATCH_TAB, "menu_patch_tab"}, + {"Patch TAB", GDK_Tab, 0x01, ID_PATCH_TAB, "menu_patch_tab"}, + {"SelectNudgeDown", GDK_Down, 0x02, ID_SELECTION_SELECT_NUDGEDOWN, "menu_selection_select_nudgedown"}, + {"EntityColor",'K', 0, ID_MISC_SELECTENTITYCOLOR, "menu_misc_select_entitycolor"}, + {"CameraForward", GDK_Up, 0, ID_CAMERA_FORWARD, "menu_camera_forward"}, + {"CameraBack", GDK_Down, 0, ID_CAMERA_BACK, "menu_camera_back"}, + {"CameraLeft", GDK_Left, 0, ID_CAMERA_LEFT, "menu_camera_left"}, + {"CameraRight", GDK_Right, 0, ID_CAMERA_RIGHT, "menu_camera_right"}, + {"CameraUp", 'D', 0, ID_CAMERA_UP, "menu_camera_up"}, + {"CameraDown", 'C', 0, ID_CAMERA_DOWN, "menu_camera_down"}, + {"CameraAngleUp", 'A', 0, ID_CAMERA_ANGLEUP, "menu_camera_angleup"}, + {"CameraAngleDown", 'Z', 0, ID_CAMERA_ANGLEDOWN, "menu_camera_angledown"}, + {"CameraStrafeRight", GDK_period, 0, ID_CAMERA_STRAFERIGHT, "menu_camera_straferight"}, + {"CameraStrafeLeft", GDK_comma, 0, ID_CAMERA_STRAFELEFT, "menu_camera_strafeleft"}, + {"ToggleGrid", '0', 0, ID_GRID_TOGGLE, "menu_grid_toggle"}, + {"SetGrid1", '1', 0, ID_GRID_1, "menu_grid_1"}, + {"SetGrid2", '2', 0, ID_GRID_2, "menu_grid_2"}, + {"SetGrid4", '3', 0, ID_GRID_4, "menu_grid_4"}, + {"SetGrid8", '4', 0, ID_GRID_8, "menu_grid_8"}, + {"SetGrid16", '5', 0, ID_GRID_16, "menu_grid_16"}, + {"SetGrid32", '6', 0, ID_GRID_32, "menu_grid_32"}, + {"SetGrid64", '7', 0, ID_GRID_64, "menu_grid_64"}, + {"SetGrid128", '8', 0, ID_GRID_128, "menu_grid_128"}, + {"SetGrid256", '9', 0, ID_GRID_256, "menu_grid_256"}, + {"DragEdges", 'E', 0, ID_SELECTION_DRAGEDGES, "menu_selection_dragedges"}, + {"DragVertices", 'V', 0, ID_SELECTION_DRAGVERTECIES, "menu_selection_dragvertecies"}, + {"ViewEntityInfo", 'N', 0, ID_VIEW_ENTITY, "menu_view_entity"}, + // {"ViewConsole", 'O', 0, ID_VIEW_CONSOLE, "menu_0,"}, + {"CloneSelection", GDK_space, 0, ID_SELECTION_CLONE, "menu_selection_clone"}, + {"DeleteSelection", GDK_BackSpace, 0, ID_SELECTION_DELETE, "menu_selection_delete"}, + {"UnSelectSelection", GDK_Escape, 0, ID_SELECTION_DESELECT, "menu_selection_deselect"}, + {"CenterView", GDK_End, 0, ID_VIEW_CENTER, "menu_view_center"}, + {"ZoomOut", GDK_Insert, 0, ID_VIEW_ZOOMOUT, "menu_view_zoomout"}, + {"ZoomIn", GDK_Delete, 0, ID_VIEW_ZOOMIN, "menu_view_zoomin"}, + {"UpFloor", GDK_Prior, 0, ID_VIEW_UPFLOOR, "menu_view_upfloor"}, + {"DownFloor", GDK_Next, 0, ID_VIEW_DOWNFLOOR, "menu_view_downfloor"}, + {"ToggleClipper", 'X', 0, ID_VIEW_CLIPPER, "menu_view_clipper"}, + {"ToggleCrosshairs", 'X', 0x01, ID_VIEW_CROSSHAIR, "menu_view_crosshair"}, + {"TogTexLock", 'T', 0x01, ID_TOGGLE_LOCK, "menu_toggle_lock"}, + {"TogTexRotLock", 'R', 0x01, ID_TOGGLE_ROTATELOCK, "menu_toggle_rotatelock"}, + {"ToggleRealtime", 'R', 0x04, ID_VIEW_CAMERAUPDATE, "menu_view_cameraupdate"}, + {"EntityList", 'L', 0, ID_EDIT_ENTITYINFO, "menu_edit_entityinfo"}, + {"Preferences", 'P', 0, ID_PREFS, "menu_prefs"}, + {"ToggleCamera", 'C', 0x05, ID_TOGGLECAMERA, "menu_togglecamera"}, + {"ToggleConsole", 'O', 0, ID_TOGGLECONSOLE, "menu_toggleconsole"}, + {"ToggleView", 'V', 0x05, ID_TOGGLEVIEW, "menu_toggleview"}, + {"ToggleZ", 'Z', 0x05, ID_TOGGLEZ, "menu_togglez"}, + {"ConnectSelection", 'K', 0x04, ID_SELECTION_CONNECT, "menu_selection_connect"}, + {"Brush3Sided", '3', 0x04, ID_BRUSH_3SIDED, "menu_brush_3sided"}, + {"Brush4Sided", '4', 0x04, ID_BRUSH_4SIDED, "menu_brush_4sided"}, + {"Brush5Sided", '5', 0x04, ID_BRUSH_5SIDED, "menu_brush_5sided"}, + {"Brush6Sided", '6', 0x04, ID_BRUSH_6SIDED, "menu_brush_6sided"}, + {"Brush7Sided", '7', 0x04, ID_BRUSH_7SIDED, "menu_brush_7sided"}, + {"Brush8Sided", '8', 0x04, ID_BRUSH_8SIDED, "menu_brush_8sided"}, + {"Brush9Sided", '9', 0x04, ID_BRUSH_9SIDED, "menu_brush_9sided"}, + {"MatrixTranspose", 'M', 0x05, ID_CURVE_MATRIX_TRANSPOSE, "menu_curve_matrix_transpose"}, + {"MakeDetail", 'M', 0x04, ID_SELECTION_MAKE_DETAIL, "menu_selection_make_detail"}, + {"MapInfo", 'M', 0, ID_EDIT_MAPINFO, "menu_edit_mapinfo"}, + {"NextLeakSpot", 'K', 0x05, ID_MISC_NEXTLEAKSPOT, "menu_misc_nextleakspot"}, + {"PrevLeakSpot", 'L', 0x05, ID_MISC_PREVIOUSLEAKSPOT, "menu_misc_previousleakspot"}, + {"FileOpen", 'O', 0x04, ID_FILE_OPEN, "menu_file_open"}, + {"FileSave", 'S', 0x04, ID_FILE_SAVE, "menu_file_save"}, + //% {"Exit", 'X', 0x04, ID_FILE_EXIT, "menu_file_exit"}, // ydnar: Ctrl+X should be cut + {"CenterXYView", GDK_Tab, 0x05, ID_VIEW_CENTERVIEW, "menu_view_centerview"}, + {"NextView", GDK_Tab, 0x04, ID_VIEW_NEXTVIEW, "menu_view_nextview"}, + {"ClipSelected", GDK_Return, 0x00, ID_CLIP_SELECTED, "menu_clip_selected"}, + {"SplitSelected", GDK_Return, 0x01, ID_SPLIT_SELECTED, "menu_split_selected"}, + {"FlipClip", GDK_Return, 0x04, ID_FLIP_CLIP, "menu_flip_clip"}, + {"MouseRotate", 'R', 0x00, ID_SELECT_MOUSEROTATE, "menu_select_mouserotate"}, + {"Copy", 'C', 0x04, ID_EDIT_COPYBRUSH, "menu_edit_copybrush"}, + {"Paste", 'V', 0x04, ID_EDIT_PASTEBRUSH, "menu_edit_pastebrush"}, + {"PasteToCamera", 'V', RAD_ALT, ID_EDIT_PASTEBRUSHTOCAMERA, "menu_edit_pastebrushtocamera"}, + {"Undo", 'Z', 0x04, ID_EDIT_UNDO, "menu_edit_undo"}, + {"Redo", 'Y', 0x04, ID_EDIT_REDO, "menu_edit_redo"}, + {"ZZoomOut", GDK_Insert, 0x04, ID_VIEW_ZZOOMOUT, "menu_view_zzoomout"}, + {"ZZoomIn", GDK_Delete, 0x04, ID_VIEW_ZZOOMIN, "menu_view_zzoomin"}, + {"TexRotateClock", GDK_Next, 0x01, ID_SELECTION_TEXTURE_ROTATECLOCK, "menu_selection_texture_rotateclock"}, + {"TexRotateCounter", GDK_Prior, 0x01, ID_SELECTION_TEXTURE_ROTATECOUNTER, "menu_selection_texture_rotatecounter"}, + {"TexScaleUp", GDK_Up, 0x04, ID_SELECTION_TEXTURE_SCALEUP, "menu_selection_texture_scaleup"}, + {"TexScaleDown", GDK_Down, 0x04, ID_SELECTION_TEXTURE_SCALEDOWN, "menu_selection_texture_scaledown"}, + {"TexShiftLeft", GDK_Left, 0x01, ID_SELECTION_TEXTURE_SHIFTLEFT, "menu_selection_texture_shiftleft"}, + {"TexShiftRight", GDK_Right, 0x01, ID_SELECTION_TEXTURE_SHIFTRIGHT, "menu_selection_texture_shiftright"}, + {"TexShiftUp", GDK_Up, 0x01, ID_SELECTION_TEXTURE_SHIFTUP, "menu_selection_texture_shiftup"}, + {"TexShiftDown", GDK_Down, 0x01, ID_SELECTION_TEXTURE_SHIFTDOWN, "menu_selection_texture_shiftdown"}, + {"GridDown", '[', 0x00, ID_GRID_PREV, "menu_grid_prev"}, + {"GridUp", ']', 0x00, ID_GRID_NEXT, "menu_grid_next"}, + {"TexScaleLeft", GDK_Left, 0x04, ID_SELECTION_TEXTURE_SCALELEFT, "menu_selection_texture_scaleleft"}, + {"TexScaleRight", GDK_Right, 0x04, ID_SELECTION_TEXTURE_SCALERIGHT, "menu_selection_texture_scaleright"}, + {"CubicClipZoomOut", ']', 0x04, ID_VIEW_CUBEOUT, "menu_view_cubeout"}, + {"CubicClipZoomIn", '[', 0x04, ID_VIEW_CUBEIN, "menu_view_cubein"}, + {"ToggleCubicClip", '\\', 0x04, ID_VIEW_CUBICCLIPPING, "menu_view_cubicclipping"}, + {"MoveSelectionDOWN", GDK_KP_Subtract, 0x00, ID_SELECTION_MOVEDOWN, "menu_selection_movedown"}, + {"MoveSelectionUP", GDK_KP_Add, 0x00, ID_SELECTION_MOVEUP, "menu_selection_moveup"}, + {"DumpSelectedBrush", 'D', 0x01, ID_SELECTION_PRINT, "menu_selection_print"}, + {"ToggleSizePaint", 'Q', 0x00, ID_SELECTION_TOGGLESIZEPAINT, "menu_selection_togglesizepaint"}, + {"SelectNudgeLeft", GDK_Left, 0x02, ID_SELECTION_SELECT_NUDGELEFT, "menu_selection_select_nudgeleft"}, + {"SelectNudgeRight", GDK_Right, 0x02, ID_SELECTION_SELECT_NUDGERIGHT, "menu_selection_select_nudgeright"}, + {"SelectNudgeUp", GDK_Up, 0x02, ID_SELECTION_SELECT_NUDGEUP, "menu_selection_select_nudgeup"}, + {"CycleCapTexturePatch", 'N', 0x05, ID_CURVE_CYCLECAP, "menu_curve_cyclecap"}, + {"NaturalizePatch", 'N', 0x04, ID_PATCH_NATURALIZE, "menu_patch_naturalize"}, + {"SnapToGrid", 'G', 0x04, ID_SELECT_SNAPTOGRID, "menu_select_snaptogrid"}, + {"ShowAllTextures", 'A', 0x04, ID_TEXTURES_SHOWALL, "menu_textures_showall"}, + {"SelectAllOfType", 'A', 0x01, ID_SELECT_ALL, "menu_select_all"}, + {"CapCurrentCurve", 'C', 0x01, ID_CURVE_CAP, "menu_curve_cap"}, + {"MakeStructural", 'S', 0x05, ID_SELECTION_MAKE_STRUCTURAL, "menu_selection_make_structural"}, + {"RegionSetSelection", 'R', 0x05, ID_REGION_SETSELECTION, "menu_region_setselection"}, + {"ShowInUse", 'U', 0, ID_TEXTURES_SHOWINUSE, "menu_textures_showinuse"}, + {"InvertSelection", 'I', 0, ID_SELECTION_INVERT, "menu_selection_invert"}, + {"Sleep", 'P', 0x05, ID_FILE_SLEEP, "menu_file_sleep"}, + {"SimplePatchMesh", 'P', 0x01, ID_CURVE_SIMPLEPATCHMESH, "menu_simplepatchmesh"}, + {"FilterWorldBrushes", '1', RAD_ALT, ID_FILTER_WORLD, "menu_filter_world"}, + {"FilterEntities", '2', RAD_ALT, ID_FILTER_ENTITIES, "menu_filter_entities"}, + {"FilterAreaportals", '3', RAD_ALT, ID_FILTER_AREAPORTALS, "menu_filter_areaportals"}, + {"FilterTranslucent", '4', RAD_ALT, ID_FILTER_TRANSLUCENT, "menu_filter_translucent"}, + {"FilterLiquids", '5', RAD_ALT, ID_FILTER_LIQUIDS, "menu_filter_liquids"}, + {"FilterCaulk", '6', RAD_ALT , ID_FILTER_CAULK, "menu_filter_caulk"}, + {"FilterClips", '7', RAD_ALT, ID_FILTER_CLIPS, "menu_filter_clips"}, + {"FilterBotClips", 'M', RAD_ALT, ID_FILTER_BOTCLIPS, "menu_filter_botclips"}, + {"FilterPaths", '8', RAD_ALT, ID_FILTER_PATHS, "menu_filter_paths"}, + {"FilterClusterportals", '9', RAD_ALT, ID_FILTER_CLUSTERPORTALS, "menu_filter_clusterportals"}, + {"FilterLights", '0', RAD_ALT, ID_FILTER_LIGHTS, "menu_filter_lights"}, + {"FilterPatches", 'P', RAD_CONTROL, ID_FILTER_PATCHES, "menu_filter_patches"}, + {"FilterDetails", 'D', RAD_CONTROL, ID_FILTER_DETAILS, "menu_filter_details"}, + {"FilterStructural", 'D', RAD_CONTROL|RAD_SHIFT, ID_FILTER_STRUCTURAL, "menu_filter_structural"}, + {"FilterHintsSkips", 'H', RAD_CONTROL, ID_FILTER_HINTSSKIPS, "menu_filter_hintsskips"}, + {"FilterModels", 'M', RAD_SHIFT, ID_FILTER_MODELS, "menu_filter_models"}, + {"FilterTriggers", 'T', RAD_CONTROL|RAD_SHIFT, ID_FILTER_TRIGGERS, "menu_filter_triggers"}, + {"LoadPointfile", 'L', RAD_SHIFT, ID_FILE_POINTFILE, "menu_load_pointfile"}, + {"TextureWindowScaledown", GDK_Insert, RAD_ALT, ID_TEXTUREWINDOW_SCALEDOWN, "menu_texturewindow_scaledown"}, + {"TextureWindowScaleup", GDK_Delete, RAD_ALT, ID_TEXTUREWINDOW_SCALEUP, "menu_texturewindow_scaleup"}, +}; + +int g_nCommandCount = sizeof(g_Commands) / sizeof(SCommandInfo); + +SKeyInfo g_Keys[] = +{ + {"Space", GDK_space}, + {"Backspace", GDK_BackSpace}, + {"Escape", GDK_Escape}, + {"End", GDK_End}, + {"Insert", GDK_Insert}, + {"Delete", GDK_Delete}, + {"PageUp", GDK_Prior}, + {"PageDown", GDK_Next}, + {"Up", GDK_Up}, + {"Down", GDK_Down}, + {"Left", GDK_Left}, + {"Right", GDK_Right}, + {"F1", GDK_F1}, + {"F2", GDK_F2}, + {"F3", GDK_F3}, + {"F4", GDK_F4}, + {"F5", GDK_F5}, + {"F6", GDK_F6}, + {"F7", GDK_F7}, + {"F8", GDK_F8}, + {"F9", GDK_F9}, + {"F10", GDK_F10}, + {"F11", GDK_F11}, + {"F12", GDK_F12}, + {"Tab", GDK_Tab}, + {"Return", GDK_Return}, + {"Comma", GDK_comma}, + {"Period", GDK_period}, + {"Plus", GDK_KP_Add}, + {"Multiply", GDK_multiply}, + {"Subtract", GDK_KP_Subtract}, + {"NumPad0", GDK_KP_0}, + {"NumPad1", GDK_KP_1}, + {"NumPad2", GDK_KP_2}, + {"NumPad3", GDK_KP_3}, + {"NumPad4", GDK_KP_4}, + {"NumPad5", GDK_KP_5}, + {"NumPad6", GDK_KP_6}, + {"NumPad7", GDK_KP_7}, + {"NumPad8", GDK_KP_8}, + {"NumPad9", GDK_KP_9}, + {"[", 219}, + {"]", 221}, + {"\\", 220}, + {"Home", GDK_Home} +}; + +int g_nKeyCount = sizeof(g_Keys) / sizeof(SKeyInfo); + +// ============================================================================= +// global functions + +void WINAPI Sys_UpdateWindows (int nBits) +{ + g_nUpdateBits |= nBits; +} + +// ============================================================================= +// Static functions + +// Gef: Separate handling for keyup events +void HandleKeyUp (GtkWidget *widget, gpointer data) +{ + int id = GPOINTER_TO_INT (data); +#ifdef DBG_KBD + Sys_Printf("HandleKeyUp: %d\n", id); +#endif + + if(g_bIgnoreCommands) + return; + + switch (id) + { + case ID_CAMERA_FORWARD: g_pParentWnd->OnCameraForward (FALSE); break; + case ID_CAMERA_BACK: g_pParentWnd->OnCameraBack (FALSE); break; + case ID_CAMERA_LEFT: g_pParentWnd->OnCameraLeft (FALSE); break; + case ID_CAMERA_RIGHT: g_pParentWnd->OnCameraRight (FALSE); break; + case ID_CAMERA_STRAFELEFT: g_pParentWnd->OnCameraStrafeleft (FALSE); break; + case ID_CAMERA_STRAFERIGHT: g_pParentWnd->OnCameraStraferight (FALSE); break; + } +} + +gint HandleCommand (GtkWidget *widget, gpointer data) +{ + int id = GPOINTER_TO_INT (data); +#ifdef DBG_KBD + Sys_Printf("HandleCommand %d\n", id); +#endif + + if ( g_bIgnoreCommands ) { +#ifdef DBG_KBD + Sys_Printf( "g_bIgnoreCommands %d, returning FALSE\n", g_bIgnoreCommands ); +#endif + return FALSE; + } + + if (id >= CMD_TEXTUREWAD && id <= CMD_TEXTUREWAD_END) g_pParentWnd->OnTextureWad (id); + else if (id >= CMD_BSPCOMMAND && id <= CMD_BSPCOMMAND_END) g_pParentWnd->OnBspCommand (id); + else if (id >= ID_FILE_RECENT1 && id <= ID_FILE_RECENT4) g_pParentWnd->OnMru (id); + else if (id >= ID_VIEW_NEAREST && id <= ID_TEXTURES_FLATSHADE) + { + if (GTK_CHECK_MENU_ITEM (widget)->active) + g_pParentWnd->OnViewNearest (id); + } else if (id >= ID_GRID_025 && id <= ID_GRID_256) g_pParentWnd->OnGrid (id); + else if (id >= ID_PLUGIN_START && id <= ID_PLUGIN_END) + { + char *str; + gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); + g_pParentWnd->OnPlugIn (id, str); + } else if (id >= ID_ENTITY_START && id <= ID_ENTITY_END) + { + char *str; + gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); + g_pParentWnd->ActiveXY()->OnEntityCreate (str); + } + else switch (id) + { + case ID_FILE_NEW: g_pParentWnd->OnFileNew (); break; + case ID_FILE_SLEEP: g_pParentWnd->OnSleep(); break; + case ID_FILE_OPEN: g_pParentWnd->OnFileOpen (); break; + case ID_FILE_SAVE: g_pParentWnd->OnFileSave (); break; + case ID_FILE_SAVEAS: g_pParentWnd->OnFileSaveas (); break; + case ID_FILE_EXPORTMAP: g_pParentWnd->OnFileExportmap (); break; + case ID_FILE_SAVEREGION: g_pParentWnd->OnFileSaveregion (); break; + case ID_FILE_NEWPROJECT: g_pParentWnd->OnFileNewproject (); break; + case ID_FILE_LOADPROJECT: g_pParentWnd->OnFileLoadproject (); break; + case ID_FILE_PROJECTSETTINGS: g_pParentWnd->OnFileProjectsettings (); break; + case ID_FILE_POINTFILE: g_pParentWnd->OnFilePointfile (); break; + case ID_FILE_CHECKUPDATE: g_pParentWnd->OnFileCheckUpdate (); break; + case ID_FILE_EXIT: g_pParentWnd->OnFileExit (); break; + case ID_FILE_IMPORTMAP: g_pParentWnd->OnFileImportmap (); break; + case ID_EDIT_UNDO: g_pParentWnd->OnEditUndo (); break; + case ID_EDIT_REDO: g_pParentWnd->OnEditRedo (); break; + case ID_EDIT_COPYBRUSH: g_pParentWnd->OnEditCopybrush (); break; + case ID_EDIT_PASTEBRUSH: g_pParentWnd->OnEditPastebrush (); break; + case ID_EDIT_PASTEBRUSHTOCAMERA: g_pParentWnd->OnEditPastebrushToCamera (); break; + case ID_SELECTION_DELETE: g_pParentWnd->OnSelectionDelete (); break; + case ID_EDIT_MAPINFO: g_pParentWnd->OnEditMapinfo (); break; + case ID_EDIT_ENTITYINFO: g_pParentWnd->OnEditEntityinfo (); break; + case ID_BRUSH_SCRIPTS: g_pParentWnd->OnBrushScripts (); break; + case ID_EDIT_LOADPREFAB: g_pParentWnd->OnEditLoadprefab (); break; + case ID_EDIT_SAVEPREFAB: g_pParentWnd->OnEditSaveprefab (); break; + case ID_PREFS: g_pParentWnd->OnPrefs (); break; + case ID_TOGGLECAMERA: g_pParentWnd->OnTogglecamera (); break; + case ID_TOGGLECONSOLE: g_pParentWnd->OnToggleconsole (); break; + case ID_VIEW_ENTITY: g_pParentWnd->OnViewEntity (); break; + case ID_VIEW_GROUPS: g_pParentWnd->OnViewGroups (); break; + case ID_TOGGLEVIEW: g_pParentWnd->OnToggleview (); break; + case ID_TOGGLEVIEW_YZ: g_pParentWnd->OnToggleviewYz (); break; + case ID_TOGGLEVIEW_XZ: g_pParentWnd->OnToggleviewXz (); break; + case ID_TOGGLEZ: g_pParentWnd->OnTogglez (); break; + case ID_VIEW_CENTER: g_pParentWnd->OnViewCenter (); break; + case ID_VIEW_UPFLOOR: g_pParentWnd->OnViewUpfloor (); break; + case ID_VIEW_DOWNFLOOR: g_pParentWnd->OnViewDownfloor (); break; + case ID_VIEW_CENTERVIEW: g_pParentWnd->OnViewCenterview (); break; + case ID_VIEW_NEXTVIEW: g_pParentWnd->OnViewNextview (); break; + case ID_VIEW_XY: g_pParentWnd->OnViewXy (); break; + case ID_VIEW_SIDE: g_pParentWnd->OnViewSide (); break; + case ID_VIEW_FRONT: g_pParentWnd->OnViewFront (); break; + case ID_VIEW_100: g_pParentWnd->OnView100 (); break; + case ID_VIEW_ZOOMIN: g_pParentWnd->OnViewZoomin (); break; + case ID_VIEW_ZOOMOUT: g_pParentWnd->OnViewZoomout (); break; + case ID_VIEW_Z100: g_pParentWnd->OnViewZ100 (); break; + case ID_VIEW_ZZOOMIN: g_pParentWnd->OnViewZzoomin (); break; + case ID_VIEW_ZZOOMOUT: g_pParentWnd->OnViewZzoomout (); break; + case ID_VIEW_CUBEIN: g_pParentWnd->OnViewCubein (); break; + case ID_VIEW_CUBEOUT: g_pParentWnd->OnViewCubeout (); break; + case ID_VIEW_SHOWNAMES: g_pParentWnd->OnViewShownames (); break; + case ID_VIEW_SHOWBLOCKS: g_pParentWnd->OnViewShowblocks (); break; + case ID_VIEW_SHOWCOORDINATES: g_pParentWnd->OnViewShowcoordinates (); break; + case ID_VIEW_SHOWOUTLINE: g_pParentWnd->OnViewShowOutline (); break; + case ID_VIEW_SHOWAXES: g_pParentWnd->OnViewShowAxes (); break; + case ID_VIEW_SHOWWORKZONE: g_pParentWnd->OnViewShowWorkzone (); break; + case ID_VIEW_SHOWANGLES: g_pParentWnd->OnViewShowAngles (); break; + case ID_VIEW_HIDESHOW_HIDESELECTED: g_pParentWnd->OnViewHideshowHideselected (); break; + case ID_VIEW_HIDESHOW_SHOWHIDDEN: g_pParentWnd->OnViewHideshowShowhidden (); break; + case ID_VIEW_ENTITIESAS_BOUNDINGBOX: + case ID_VIEW_ENTITIESAS_WIREFRAME: + case ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME: + case ID_VIEW_ENTITIESAS_SELECTEDSKINNED: + case ID_VIEW_ENTITIESAS_SKINNED: + case ID_VIEW_ENTITIESAS_SKINNEDANDBOXED: + g_pParentWnd->OnEntitiesSetViewAs(id); + break; + case ID_VIEW_CUBICCLIPPING: g_pParentWnd->OnViewCubicclipping (); break; + case ID_VIEW_OPENGLLIGHTING: g_pParentWnd->OnViewOpengllighting (); break; + case ID_SELECTION_DRAGEDGES: g_pParentWnd->OnSelectionDragedges (); break; + case ID_SELECTION_DRAGVERTECIES: g_pParentWnd->OnSelectionDragvertecies (); break; + case ID_SELECTION_CLONE: g_pParentWnd->OnSelectionClone (); break; + case ID_SELECTION_DESELECT: g_pParentWnd->OnSelectionDeselect (); break; + case ID_BRUSH_FLIPX: g_pParentWnd->OnBrushFlipx (); break; + case ID_BRUSH_FLIPY: g_pParentWnd->OnBrushFlipy (); break; + case ID_BRUSH_FLIPZ: g_pParentWnd->OnBrushFlipz (); break; + case ID_BRUSH_ROTATEX: g_pParentWnd->OnBrushRotatex (); break; + case ID_BRUSH_ROTATEY: g_pParentWnd->OnBrushRotatey (); break; + case ID_BRUSH_ROTATEZ: g_pParentWnd->OnBrushRotatez (); break; + case ID_SELECTION_ARBITRARYROTATION: g_pParentWnd->OnSelectionArbitraryrotation (); break; + case ID_SELECT_SCALE: g_pParentWnd->OnSelectScale (); break; + case ID_SELECTION_MAKEHOLLOW: g_pParentWnd->OnSelectionMakehollow (); break; + case ID_SELECTION_CSGSUBTRACT: g_pParentWnd->OnSelectionCsgsubtract (); break; + case ID_SELECTION_CSGMERGE: g_pParentWnd->OnSelectionCsgmerge (); break; + case ID_SELECTION_NOOUTLINE: g_pParentWnd->OnSelectionNoOutline (); break; + case ID_SELECTION_OUTLINESTYLE: g_pParentWnd->OnSelectionOutlineStyle (); break; + case ID_SELECTION_SELECTCOMPLETETALL: g_pParentWnd->OnSelectionSelectcompletetall (); break; + case ID_SELECTION_SELECTTOUCHING: g_pParentWnd->OnSelectionSelecttouching (); break; + case ID_SELECTION_SELECTPARTIALTALL: g_pParentWnd->OnSelectionSelectpartialtall (); break; + case ID_SELECTION_SELECTINSIDE: g_pParentWnd->OnSelectionSelectinside (); break; + case ID_SELECTION_SELECT_NUDGELEFT: g_pParentWnd->OnSelectionSelectNudgeleft (); break; + case ID_SELECTION_SELECT_NUDGERIGHT: g_pParentWnd->OnSelectionSelectNudgeright (); break; + case ID_SELECTION_SELECT_NUDGEUP: g_pParentWnd->OnSelectionSelectNudgeup (); break; + case ID_SELECTION_SELECT_NUDGEDOWN: g_pParentWnd->OnSelectionSelectNudgedown (); break; + case ID_VIEW_CLIPPER: g_pParentWnd->OnViewClipper (); break; + case ID_CLIP_SELECTED: g_pParentWnd->OnClipSelected (); break; + case ID_SPLIT_SELECTED: g_pParentWnd->OnSplitSelected (); break; + case ID_FLIP_CLIP: g_pParentWnd->OnFlipClip (); break; + case ID_SELECTION_CONNECT: g_pParentWnd->OnSelectionConnect (); break; + case ID_SELECTION_UNGROUPENTITY: g_pParentWnd->OnSelectionUngroupentity (); break; + case ID_SELECTION_MERGE: Select_MergeEntity(); break; + case ID_SELECTION_SEPERATE: Select_Seperate(); break; + case ID_SELECTION_MAKE_DETAIL: g_pParentWnd->OnSelectionMakeDetail (); break; + case ID_SELECTION_MAKE_STRUCTURAL: g_pParentWnd->OnSelectionMakeStructural (); break; + case ID_SNAPTOGRID: g_pParentWnd->OnSnaptogrid (); break; + case ID_TEXTURES_SHOWINUSE: g_pParentWnd->OnTexturesShowinuse (); break; + case ID_TEXTURES_SHOWALL: g_pParentWnd->OnTexturesShowall (); break; + case ID_TEXTURES_INSPECTOR: g_pParentWnd->OnTexturesInspector (); break; + case ID_TEXTURE_REPLACEALL: g_pParentWnd->OnTextureReplaceall (); break; + case ID_TOGGLE_LOCK: g_pParentWnd->OnToggleLock (); break; + case ID_TOGGLE_ROTATELOCK: g_pParentWnd->OnToggleRotatelock (); break; + case ID_TEXTURES_LOAD: g_pParentWnd->OnTexturesLoad (); break; + case ID_TEXTURES_RELOADSHADERS: g_pParentWnd->OnTexturesReloadshaders (); break; + case ID_TEXTURES_SHADERS_SHOW: g_pParentWnd->OnTexturesShadersShow (); break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_200: + case ID_TEXTURES_TEXTUREWINDOWSCALE_100: + case ID_TEXTURES_TEXTUREWINDOWSCALE_50: + case ID_TEXTURES_TEXTUREWINDOWSCALE_25: + case ID_TEXTURES_TEXTUREWINDOWSCALE_10: + g_pParentWnd->SetTextureScale (id); + break; + case ID_TEXTURES_LOADLIST: g_pParentWnd->OnTexturesLoadlist (); break; + case ID_TEXTURES_SHADERLISTONLY: g_pParentWnd->OnTexturesShaderlistonly (); break; + case ID_TEXTUREWINDOW_SCALEUP: g_pParentWnd->OnTexturewindowScaleup (); break; + case ID_TEXTUREWINDOW_SCALEDOWN: g_pParentWnd->OnTexturewindowScaledown (); break; + case ID_MISC_BENCHMARK: g_pParentWnd->OnMiscBenchmark (); break; + case ID_COLOR_SETORIGINAL: g_pParentWnd->OnColorSetoriginal (); break; + case ID_COLOR_SETQER: g_pParentWnd->OnColorSetqer (); break; + case ID_COLOR_SETBLACK: g_pParentWnd->OnColorSetblack (); break; + case ID_COLOR_SETYDNAR: g_pParentWnd->OnColorSetydnar (); break; /* ydnar */ + case ID_TEXTUREBK: g_pParentWnd->OnTexturebk (); break; + case ID_COLORS_XYBK: g_pParentWnd->OnColorsXybk (); break; + case ID_COLORS_MAJOR: g_pParentWnd->OnColorsMajor (); break; + case ID_COLORS_MINOR: g_pParentWnd->OnColorsMinor (); break; + case ID_COLORS_GRIDTEXT: g_pParentWnd->OnColorsGridtext (); break; + case ID_COLORS_GRIDBLOCK: g_pParentWnd->OnColorsGridblock (); break; + case ID_COLORS_CAMERABACK: g_pParentWnd->OnColorsCameraBack (); break; + case ID_COLORS_BRUSH: g_pParentWnd->OnColorsBrush (); break; + case ID_COLORS_SELECTEDBRUSH: g_pParentWnd->OnColorsSelectedbrush (); break; + case ID_COLORS_SELECTEDBRUSH3D: g_pParentWnd->OnColorsSelectedbrush3D (); break; + case ID_COLORS_CLIPPER: g_pParentWnd->OnColorsClipper (); break; + case ID_COLORS_VIEWNAME: g_pParentWnd->OnColorsViewname (); break; + case ID_MISC_GAMMA: g_pParentWnd->OnMiscGamma (); break; + case ID_MISC_FINDBRUSH: g_pParentWnd->OnMiscFindbrush (); break; + case ID_MISC_NEXTLEAKSPOT: g_pParentWnd->OnMiscNextleakspot (); break; + case ID_MISC_PREVIOUSLEAKSPOT: g_pParentWnd->OnMiscPreviousleakspot (); break; + case ID_MISC_PRINTXY: g_pParentWnd->OnMiscPrintxy (); break; + case ID_MISC_SELECTENTITYCOLOR: g_pParentWnd->OnMiscSelectentitycolor (); break; + case ID_CONVERTCURVES: g_pParentWnd->OnConvertcurves (); break; + case ID_REGION_OFF: g_pParentWnd->OnRegionOff (); break; + case ID_REGION_SETXY: g_pParentWnd->OnRegionSetxy (); break; + case ID_REGION_SETTALLBRUSH: g_pParentWnd->OnRegionSettallbrush (); break; + case ID_REGION_SETBRUSH: g_pParentWnd->OnRegionSetbrush (); break; + case ID_REGION_SETSELECTION: g_pParentWnd->OnRegionSetselection (); break; + case ID_BRUSH_3SIDED: g_pParentWnd->OnBrush3sided (); break; + case ID_BRUSH_4SIDED: g_pParentWnd->OnBrush4sided (); break; + case ID_BRUSH_5SIDED: g_pParentWnd->OnBrush5sided (); break; + case ID_BRUSH_6SIDED: g_pParentWnd->OnBrush6sided (); break; + case ID_BRUSH_7SIDED: g_pParentWnd->OnBrush7sided (); break; + case ID_BRUSH_8SIDED: g_pParentWnd->OnBrush8sided (); break; + case ID_BRUSH_9SIDED: g_pParentWnd->OnBrush9sided (); break; + case ID_BRUSH_ARBITRARYSIDED: g_pParentWnd->OnBrushArbitrarysided (); break; + case ID_BRUSH_MAKECONE: g_pParentWnd->OnBrushMakecone (); break; + case ID_BRUSH_PRIMITIVES_SPHERE: g_pParentWnd->OnBrushPrimitivesSphere (); break; + case ID_CURVE_PATCHTUBE: g_pParentWnd->OnCurvePatchtube (); break; + case ID_CURVE_PATCHDENSETUBE: g_pParentWnd->OnCurvePatchdensetube (); break; + case ID_CURVE_PATCHVERYDENSETUBE: g_pParentWnd->OnCurvePatchverydensetube (); break; + case ID_CURVE_PATCHSQUARE: g_pParentWnd->OnCurvePatchsquare (); break; + case ID_CURVE_PATCHENDCAP: g_pParentWnd->OnCurvePatchendcap (); break; + case ID_CURVE_PATCHBEVEL: g_pParentWnd->OnCurvePatchbevel (); break; + case ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL: g_pParentWnd->OnCurveMoreendcapsbevelsSquarebevel (); break; + case ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP: g_pParentWnd->OnCurveMoreendcapsbevelsSquareendcap();break; + case ID_CURVE_PATCHCONE: g_pParentWnd->OnCurvePatchcone (); break; + case ID_CURVE_SIMPLEPATCHMESH: g_pParentWnd->OnCurveSimplepatchmesh (); break; + case ID_CURVE_INSERT_INSERTCOLUMN: g_pParentWnd->OnCurveInsertInsertcolumn (); break; + case ID_CURVE_INSERT_ADDCOLUMN: g_pParentWnd->OnCurveInsertAddcolumn (); break; + case ID_CURVE_INSERT_INSERTROW: g_pParentWnd->OnCurveInsertInsertrow (); break; + case ID_CURVE_INSERT_ADDROW: g_pParentWnd->OnCurveInsertAddrow (); break; + case ID_CURVE_DELETE_FIRSTCOLUMN: g_pParentWnd->OnCurveDeleteFirstcolumn (); break; + case ID_CURVE_DELETE_LASTCOLUMN: g_pParentWnd->OnCurveDeleteLastcolumn (); break; + case ID_CURVE_DELETE_FIRSTROW: g_pParentWnd->OnCurveDeleteFirstrow (); break; + case ID_CURVE_DELETE_LASTROW: g_pParentWnd->OnCurveDeleteLastrow (); break; + case ID_CURVE_NEGATIVE: g_pParentWnd->OnCurveNegative (); break; + case ID_CURVE_REDISPERSE_ROWS: g_pParentWnd->OnCurveRedisperseRows (); break; + case ID_CURVE_REDISPERSE_INTERMEDIATE_COLS: g_pParentWnd->OnCurveRedisperseIntermediateCols (); break; + case ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS: g_pParentWnd->OnCurveRedisperseIntermediateRows (); break; + case ID_CURVE_MATRIX_TRANSPOSE: g_pParentWnd->OnCurveMatrixTranspose (); break; + case ID_CURVE_CAP: g_pParentWnd->OnCurveCap (); break; + case ID_CURVE_CYCLECAP: g_pParentWnd->OnCurveCyclecap (); break; + case ID_CURVE_OVERLAY_SET: g_pParentWnd->OnCurveOverlaySet (); break; + case ID_CURVE_OVERLAY_CLEAR: g_pParentWnd->OnCurveOverlayClear (); break; + case ID_CURVE_THICKEN: g_pParentWnd->OnCurveThicken (); break; + case ID_PLUGINS_REFRESH: g_pParentWnd->OnPluginsRefresh (); break; + case ID_HELP: g_pParentWnd->OnHelp (); break; + case ID_HELP_LINKS: g_pParentWnd->OnHelpLinks(); break; + case ID_HELP_BUGREPORT: g_pParentWnd->OnHelpBugreport(); break; + case ID_HELP_COMMANDLIST: g_pParentWnd->OnHelpCommandlist (); break; + case ID_HELP_ABOUT: g_pParentWnd->OnHelpAbout (); break; + case ID_DONTSELECTMODEL: g_pParentWnd->OnDontselectmodel (); break; + case ID_FILTER_AREAPORTALS: g_pParentWnd->OnFilterAreaportals (); break; + case ID_FILTER_CAULK: g_pParentWnd->OnFilterCaulk (); break; + case ID_FILTER_STRUCTURAL: g_pParentWnd->OnFilterStructural (); break; + case ID_FILTER_CLIPS: g_pParentWnd->OnFilterClips (); break; + case ID_FILTER_BOTCLIPS: g_pParentWnd->OnFilterBotClips (); break; + case ID_FILTER_DETAILS: g_pParentWnd->OnFilterDetails (); break; + case ID_FILTER_ENTITIES: g_pParentWnd->OnFilterEntities (); break; + case ID_FILTER_HINTSSKIPS: g_pParentWnd->OnFilterHintsskips (); break; + case ID_FILTER_LIGHTS: g_pParentWnd->OnFilterLights (); break; + case ID_FILTER_LIQUIDS: g_pParentWnd->OnFilterLiquids (); break; + case ID_FILTER_MODELS: g_pParentWnd->OnFilterModels (); break; + case ID_FILTER_PATCHES: g_pParentWnd->OnFilterPatches (); break; + case ID_FILTER_TRANSLUCENT: g_pParentWnd->OnFilterTranslucent (); break; + case ID_FILTER_TRIGGERS: g_pParentWnd->OnFilterTriggers (); break; + case ID_FILTER_WORLD: g_pParentWnd->OnFilterWorld (); break; + case ID_FILTER_PATHS: g_pParentWnd->OnFilterPaths (); break; + case ID_FILTER_CLUSTERPORTALS: g_pParentWnd->OnFilterClusterportals (); break; + case ID_FILTER_LIGHTGRID: g_pParentWnd->OnFilterLightgrid (); break; + + case ID_POPUP_SELECTION: g_pParentWnd->OnPopupSelection (); break; + case ID_VIEW_CHANGE: g_pParentWnd->OnViewChange (); break; + case ID_TEXTURES_POPUP: g_pParentWnd->OnTexturesPopup (); break; + case ID_VIEW_CAMERATOGGLE: g_pParentWnd->ToggleCamera (); break; + case ID_VIEW_CAMERAUPDATE: g_pParentWnd->OnViewCameraupdate (); break; + case ID_SELECT_MOUSEROTATE: g_pParentWnd->OnSelectMouserotate (); break; + case ID_SELECT_MOUSESCALE: g_pParentWnd->OnSelectMousescale (); break; + case ID_SCALELOCKX: g_pParentWnd->OnScalelockx (); break; + case ID_SCALELOCKY: g_pParentWnd->OnScalelocky (); break; + case ID_SCALELOCKZ: g_pParentWnd->OnScalelockz (); break; + case ID_DONTSELECTCURVE: g_pParentWnd->OnDontselectcurve (); break; + case ID_PATCH_SHOWBOUNDINGBOX: g_pParentWnd->OnPatchToggleBox (); break; + case ID_PATCH_WIREFRAME: g_pParentWnd->OnPatchWireframe (); break; + case ID_PATCH_BEND: g_pParentWnd->OnPatchBend (); break; + case ID_PATCH_WELD: g_pParentWnd->OnPatchWeld (); break; + case ID_PATCH_DRILLDOWN: g_pParentWnd->OnPatchDrilldown (); break; + case ID_DROP_GROUP_NAME: g_pParentWnd->OnDropGroupName (); break; + case ID_DROP_GROUP_NEWGROUP: g_pParentWnd->OnDropGroupNewgroup (); break; + case ID_DROP_GROUP_REMOVE: g_pParentWnd->OnDropGroupRemove (); break; + case ID_SHOW_ENTITIES: g_pParentWnd->OnShowEntities (); break; + + case IDC_BTN_FACEFIT: g_pParentWnd->OnFaceFit (); break; + case ID_VIEW_TEXTURE: g_pParentWnd->OnViewTexture (); break; + case ID_PATCH_INSPECTOR: g_pParentWnd->OnPatchInspector (); break; + case ID_CURVE_NEGATIVETEXTUREX: g_pParentWnd->OnCurveNegativeTextureX (); break; + case ID_CURVE_NEGATIVETEXTUREY: g_pParentWnd->OnCurveNegativeTextureY (); break; + case ID_CURVE_INSERTCOLUMN: g_pParentWnd->OnCurveInsertcolumn (); break; + case ID_CURVE_INSERTROW: g_pParentWnd->OnCurveInsertrow (); break; + case ID_CURVE_DELETECOLUMN: g_pParentWnd->OnCurveDeletecolumn (); break; + case ID_CURVE_DELETEROW: g_pParentWnd->OnCurveDeleterow (); break; + case ID_PATCH_TAB: g_pParentWnd->OnPatchTab (); break; + case ID_CAMERA_FORWARD: g_pParentWnd->OnCameraForward (TRUE); break; + case ID_CAMERA_BACK: g_pParentWnd->OnCameraBack (TRUE); break; + case ID_CAMERA_LEFT: g_pParentWnd->OnCameraLeft (TRUE); break; + case ID_CAMERA_RIGHT: g_pParentWnd->OnCameraRight (TRUE); break; + case ID_CAMERA_UP: g_pParentWnd->OnCameraUp (); break; + case ID_CAMERA_DOWN: g_pParentWnd->OnCameraDown (); break; + case ID_CAMERA_ANGLEUP: g_pParentWnd->OnCameraAngleup (); break; + case ID_CAMERA_ANGLEDOWN: g_pParentWnd->OnCameraAngledown (); break; + case ID_CAMERA_STRAFELEFT: g_pParentWnd->OnCameraStrafeleft (TRUE); break; + case ID_CAMERA_STRAFERIGHT: g_pParentWnd->OnCameraStraferight (TRUE); break; + case ID_GRID_TOGGLE: g_pParentWnd->OnGridToggle (); break; + case ID_VIEW_CONSOLE: g_pParentWnd->OnViewConsole (); break; + case ID_VIEW_CROSSHAIR: g_pParentWnd->OnViewCrosshair (); break; + case ID_SELECTION_TEXTURE_FIT: g_pParentWnd->OnSelectionTextureFit (); break; + case ID_SELECTION_TEXTURE_ROTATECLOCK: g_pParentWnd->OnSelectionTextureRotateclock (); break; + case ID_SELECTION_TEXTURE_ROTATECOUNTER: g_pParentWnd->OnSelectionTextureRotatecounter (); break; + case ID_SELECTION_TEXTURE_SCALEUP: g_pParentWnd->OnSelectionTextureScaleup (); break; + case ID_SELECTION_TEXTURE_SCALEDOWN: g_pParentWnd->OnSelectionTextureScaledown (); break; + case ID_SELECTION_TEXTURE_SHIFTLEFT: g_pParentWnd->OnSelectionTextureShiftleft (); break; + case ID_SELECTION_TEXTURE_SHIFTRIGHT: g_pParentWnd->OnSelectionTextureShiftright (); break; + case ID_SELECTION_TEXTURE_SHIFTUP: g_pParentWnd->OnSelectionTextureShiftup (); break; + case ID_SELECTION_TEXTURE_SHIFTDOWN: g_pParentWnd->OnSelectionTextureShiftdown (); break; + case ID_GRID_PREV: g_pParentWnd->OnGridPrev (); break; + case ID_GRID_NEXT: g_pParentWnd->OnGridNext (); break; + case ID_SELECTION_TEXTURE_SCALELEFT: g_pParentWnd->OnSelectionTextureScaleLeft (); break; + case ID_SELECTION_TEXTURE_SCALERIGHT: g_pParentWnd->OnSelectionTextureScaleRight (); break; + case ID_SELECTION_MOVEDOWN: g_pParentWnd->OnSelectionMovedown (); break; + case ID_SELECTION_MOVEUP: g_pParentWnd->OnSelectionMoveup (); break; + case ID_SELECTION_PRINT: g_pParentWnd->OnSelectionPrint (); break; + case ID_SELECTION_TOGGLESIZEPAINT: g_pParentWnd->OnSelectionTogglesizepaint (); break; + case ID_PATCH_NATURALIZE: g_pParentWnd->OnPatchNaturalize (); break; + case ID_SELECT_SNAPTOGRID: g_pParentWnd->OnSnapToGrid (); break; + case ID_SELECT_ALL: g_pParentWnd->OnSelectAll (); break; + case ID_SELECTION_INVERT: g_pParentWnd->OnSelectionInvert (); break; + } + + return TRUE; +} + +static gint timer (gpointer data) +{ + MainFrame *wnd = (MainFrame*)data; + wnd->OnTimer (); + return TRUE; +} + +static gint mainframe_delete (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + MainFrame *wnd = (MainFrame*)data; + + wnd->OnDelete(); + + if (ConfirmModified()) + return FALSE; + + g_qeglobals_gui.d_edit = NULL; + + return TRUE; +} + +static void mainframe_destroy (GtkWidget *widget, gpointer data) +{ + MainFrame *wnd = (MainFrame*)data; + + // avoid saving prefs when the app is minimized + if (g_pParentWnd->IsSleeping()) + { + Sys_Printf("Shutdown while sleeping, not saving prefs\n"); + g_qeglobals.disable_ini = true; + } + + // NOTE TTimo this is very clumsy, in MainFrame::OnDestroy we might call SavePrefs again + // we will do more stuff in OnDestroy for window position saving too, so I guess this call is still relevant? + g_PrefsDlg.SavePrefs (); + + wnd->OnDestroy (); + + // shutdown modules + // NOTE: I've decided to do this before SavePrefs in case we broadcast some shutdown info + // and modules / plugins decide to save some stuff + g_pParentWnd->GetPlugInMgr().Shutdown(); + + delete wnd; + + QGL_Shutdown(); + g_PrefsDlg.Destroy (); + g_dlgSurface.Destroy (); + g_dlgFind.Destroy (); + g_PatchDialog.Destroy (); + + gtk_main_quit (); +} + +static gint mainframe_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper(event->keyval); + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=924 + if(code == GDK_ISO_Left_Tab) { + code = GDK_Tab; + } + +#ifdef DBG_KBD + Sys_Printf("key: %d (keyval: %d) (ctrl: %d)\n", code, event->keyval, event->state & GDK_CONTROL_MASK); +#endif + + // BUG: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=865 + // return only if Texture Viewport is in main window, otherwise if Tex viewport is in it's own window + // the Filter GtkEntry won't release focus + if ( g_pParentWnd->GetTexWnd()->m_pFilter == gtk_window_get_focus(GTK_WINDOW(widget)) ) + if ( gtk_widget_is_focus( g_pParentWnd->GetTexWnd()->m_pFilter ) ) + return FALSE; + +#ifdef DBG_KBD + Sys_Printf("mainframe_keypress processing into a command\n"); +#endif + for (int i = 0; i < g_nCommandCount; i++) + { + if (g_Commands[i].m_nKey == code) // find a match? + { + // check modifiers + unsigned int nState = 0; + if (Sys_AltDown ()) + nState |= RAD_ALT; + if ((event->state & GDK_CONTROL_MASK) != 0) + nState |= RAD_CONTROL; + if ((event->state & GDK_SHIFT_MASK) != 0) + nState |= RAD_SHIFT; + if ((g_Commands[i].m_nModifiers & 0x7) == nState) + { + HandleCommand (NULL, GINT_TO_POINTER (g_Commands[i].m_nCommand)); + gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "key_press_event"); + return FALSE; + } + } + } + + return TRUE; +} + +static gint mainframe_keyrelease (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper(event->keyval); + + if (gtk_accelerator_valid (event->keyval, (GdkModifierType)0)) + return TRUE; + + for (int i = 0; i < g_nCommandCount; i++) + { + if (g_Commands[i].m_nKey == code) // find a match? + { + if(!g_Commands[i].m_nModifiers) + { + // Gef: Only call the handler if it's a key that needs keyup events + switch (g_Commands[i].m_nCommand) + { + case ID_CAMERA_FORWARD: + case ID_CAMERA_BACK: + case ID_CAMERA_LEFT: + case ID_CAMERA_RIGHT: + case ID_CAMERA_STRAFELEFT: + case ID_CAMERA_STRAFERIGHT: + { + HandleKeyUp (NULL, GINT_TO_POINTER (g_Commands[i].m_nCommand)); + gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "key_release_event"); + } + + } + return FALSE; + } + } + } + + return TRUE; +} + + +// ============================================================================= +// Window creation functions + +void AddMenuItem (GtkWidget* item, unsigned int id) +{ + for (int i = 0; i < g_nCommandCount; i++) + if (g_Commands[i].m_nCommand == id) + { + g_object_set_data (G_OBJECT (g_pParentWnd->m_pWidget), g_Commands[i].m_strMenu, item); + break; + } +} + +void MainFrame::handle_help_command(int id) +{ + OpenURL(mHelpURLs[id]->GetBuffer()); +} + +/*! +needed for hooking in Gtk+ +*/ +void HandleHelpCommand (GtkWidget *widget, gpointer data) +{ + int id = GPOINTER_TO_INT (data); + g_pParentWnd->handle_help_command(id); +} + +void MainFrame::process_xlink (Str &FileName, char *menu_name, const char *base_url, GtkWidget *menu, GtkAccelGroup *accel) +{ + xmlDocPtr pDoc; + pDoc = xmlParseFile(FileName.GetBuffer()); + if (pDoc) + { + Sys_Printf("Processing .xlink file '%s'\n", FileName.GetBuffer()); + // create sub menu + GtkWidget* menu_in_menu = create_menu_in_menu_with_mnemonic(menu, menu_name); + // start walking the nodes, find the 'links' one + xmlNodePtr pNode = pDoc->children; + while (pNode && strcmp((const char*)pNode->name, "links")) + pNode=pNode->next; + if (pNode) + { + pNode = pNode->children; + while(pNode) + { + if (!strcmp((const char*)pNode->name, "item")) + { + // process the URL + Str *url; + if (strstr((char *)xmlGetProp(pNode, (xmlChar *)"url"), "http://")) + { + // complete URL + url = new Str; + *url = (char *)xmlGetProp(pNode, (xmlChar *)"url"); + } + else + { + // relative URL + url = new Str; + *url = base_url; + *url += (char *)xmlGetProp(pNode, (xmlChar *)"url"); + } + mHelpURLs.push_back(url); + create_menu_item_with_mnemonic (menu_in_menu, (char *)xmlGetProp(pNode, (xmlChar *)"name"), GTK_SIGNAL_FUNC(HandleHelpCommand), mHelpURLs.size()-1); + } + pNode=pNode->next; + } + } + xmlFreeDoc(pDoc); + } + else + { + Sys_Printf("'%s' not found / parse failed\n", FileName.GetBuffer()); + } +} + +void MainFrame::create_game_help_menu (GtkWidget *menu, GtkAccelGroup *accel) +{ + Str FileName; + list::iterator iGame; + + // start in the global dir + FileName = g_strAppPath; + FileName += "global.xlink"; + process_xlink(FileName, "General", g_strAppPath.GetBuffer(), menu, accel); + + for (iGame = g_PrefsDlg.mGamesDialog.mGames.begin(); iGame != g_PrefsDlg.mGamesDialog.mGames.end(); iGame++) + { + FileName = (*iGame)->mGameToolsPath; + FileName += "game.xlink"; + process_xlink(FileName, (*iGame)->mGameName, (*iGame)->mGameToolsPath.GetBuffer(), menu, accel); + } +} + +void MainFrame::create_main_menu (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *handle_box, *menu_bar, *menu, *menu_in_menu, *menu_3, *item; + GtkAccelGroup *accel; + + g_bIgnoreCommands++; + accel = gtk_accel_group_new (); + global_accel = accel; + gtk_window_add_accel_group (GTK_WINDOW (window), accel); + + handle_box = gtk_handle_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); + gtk_widget_show (handle_box); + + menu_bar = gtk_menu_bar_new (); + gtk_container_add (GTK_CONTAINER (handle_box), menu_bar); + gtk_widget_show (menu_bar); + + // File menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_File"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "_New Map", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_NEW); + menu_separator (menu); + + //++timo temporary experimental stuff for sleep mode.. + item = create_menu_item_with_mnemonic (menu, "_Sleep", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SLEEP); + g_object_set_data (G_OBJECT (window), "menu_file_sleep", item ); + menu_separator (menu); + // end experimental + + item = create_menu_item_with_mnemonic (menu, "_Open...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_OPEN); + g_object_set_data (G_OBJECT (window), "menu_file_open", item); + create_menu_item_with_mnemonic (menu, "_Import...", // Hydra: give it it's proper name + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_IMPORTMAP); + item = create_menu_item_with_mnemonic (menu, "_Save", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVE); + g_object_set_data (G_OBJECT (window), "menu_file_save", item); + create_menu_item_with_mnemonic (menu, "Save _as...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVEAS); + create_menu_item_with_mnemonic (menu, "Save s_elected...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_EXPORTMAP); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "Save re_gion...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVEREGION); + g_object_set_data (G_OBJECT (window), "menu_file_saveregion", item); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "New p_roject...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_NEWPROJECT); + create_menu_item_with_mnemonic (menu, "Load _project...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_LOADPROJECT); + create_menu_item_with_mnemonic (menu, "Pro_ject settings...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_PROJECTSETTINGS); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "_Pointfile...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_POINTFILE); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "Recent Files", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT1); + g_object_set_data (G_OBJECT (item), "accel", accel); + gtk_widget_set_sensitive (item, FALSE); + MRU_AddWidget (item, 0); + item = create_menu_item_with_mnemonic (menu, "2", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT2); + gtk_widget_hide (item); + MRU_AddWidget (item, 1); + item = create_menu_item_with_mnemonic (menu, "3", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT3); + gtk_widget_hide (item); + MRU_AddWidget (item, 2); + item = create_menu_item_with_mnemonic (menu, "4", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT4); + gtk_widget_hide (item); + MRU_AddWidget (item, 3); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Check for GtkRadiant update (web)", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_CHECKUPDATE); + + create_menu_item_with_mnemonic (menu, "E_xit", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_EXIT); + + // Edit menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Edit"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + item = create_menu_item_with_mnemonic (menu, "_Undo", + GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_UNDO); + g_object_set_data (G_OBJECT (window), "menu_edit_undo", item); + item = create_menu_item_with_mnemonic (menu, "_Redo", + GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_REDO); + g_object_set_data (G_OBJECT (window), "menu_edit_redo", item); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "_Copy", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_COPYBRUSH); + item = create_menu_item_with_mnemonic (menu, "_Paste", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_PASTEBRUSH); + item = create_menu_item_with_mnemonic (menu, "P_aste To Camera", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_PASTEBRUSHTOCAMERA); + item = create_menu_item_with_mnemonic (menu, "_Delete", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DELETE); + g_object_set_data (G_OBJECT (window), "menu_selection_delete", item); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Map Info...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_MAPINFO); + create_menu_item_with_mnemonic (menu, "Entity Info...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_ENTITYINFO); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Brush Scripts...", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_SCRIPTS); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Load Pre_fab...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_LOADPREFAB); + create_menu_item_with_mnemonic (menu, "Save Selection as Prefab...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_SAVEPREFAB); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Preferences...", GTK_SIGNAL_FUNC (HandleCommand), ID_PREFS); + + // View menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_View"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Toggle"); + create_menu_item_with_mnemonic (menu_in_menu, "Camera View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLECAMERA); + create_menu_item_with_mnemonic (menu_in_menu, "Console View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLECONSOLE); + item = create_menu_item_with_mnemonic (menu_in_menu, "Entity View", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITY); + g_object_set_data (G_OBJECT (window), "menu_view_entity", item); + // create_menu_item_with_mnemonic (menu_in_menu, "Groups View", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_GROUPS); + create_menu_item_with_mnemonic (menu_in_menu, "XY (Top)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW); + create_menu_item_with_mnemonic (menu_in_menu, "YZ (Side)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW_YZ); + create_menu_item_with_mnemonic (menu_in_menu, "XZ (Front)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW_XZ); + create_menu_item_with_mnemonic (menu_in_menu, "Z View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEZ); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "_Center", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CENTER); + item = create_menu_item_with_mnemonic (menu, "_Center 2d", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CENTERVIEW); + item = create_menu_item_with_mnemonic (menu, "_Up Floor", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_UPFLOOR); + item = create_menu_item_with_mnemonic (menu, "_Down Floor", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_DOWNFLOOR); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "_Next (XY, YZ, XY)", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEXTVIEW); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Layout"); + create_menu_item_with_mnemonic (menu_in_menu, "XY (Top)", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_XY); + create_menu_item_with_mnemonic (menu_in_menu, "YZ", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SIDE); + create_menu_item_with_mnemonic (menu_in_menu, "XZ", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_FRONT); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Zoom"); + create_menu_item_with_mnemonic (menu_in_menu, "_XY 100%", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_100); + item = create_menu_item_with_mnemonic (menu_in_menu, "XY Zoom _In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZOOMIN); + item = create_menu_item_with_mnemonic (menu_in_menu, "XY Zoom _Out", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZOOMOUT); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "_Z 100%", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_Z100); + item = create_menu_item_with_mnemonic (menu_in_menu, "Z Zoo_m In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZZOOMIN); + g_object_set_data (G_OBJECT (window), "menu_view_zzoomin", item); + item = create_menu_item_with_mnemonic (menu_in_menu, "Z Zoom O_ut", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZZOOMOUT); + g_object_set_data (G_OBJECT (window), "menu_view_zzoomout", item); + menu_separator (menu_in_menu); + item = create_menu_item_with_mnemonic (menu_in_menu, "Cubic Clip Zoom In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBEIN); + item = create_menu_item_with_mnemonic (menu_in_menu, "Cubic Clip Zoom Out", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBEOUT); + menu_separator (menu); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Show"); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show _Angles", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWANGLES, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_showangles", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show _Names", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWNAMES, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_shownames", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Blocks", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWBLOCKS, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_showblocks", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show C_oordinates", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWCOORDINATES, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_showcoordinates", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Window Outline", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWOUTLINE, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_showoutline", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show ZBuffered Outline", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_NOOUTLINE, TRUE); + g_object_set_data (G_OBJECT (window), "menu_selection_nooutline", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Axes", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWAXES, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_showaxes", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Workzone", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWWORKZONE, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_showworkzone", item); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Filter"); + create_check_menu_item_with_mnemonic (menu_in_menu, "World", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_WORLD, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Entities", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_ENTITIES, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Areaportals", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_AREAPORTALS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Translucent", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_TRANSLUCENT, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Liquids", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIQUIDS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Caulk", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CAULK, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Clips", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CLIPS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Paths", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_PATHS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Clusterportals", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CLUSTERPORTALS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Lights", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIGHTS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Structural", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_STRUCTURAL, FALSE); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Lightgrid", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIGHTGRID, FALSE); + g_object_set_data (G_OBJECT (window), "menu_filter_lightgrid", item); + create_check_menu_item_with_mnemonic (menu_in_menu, "Patches", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_PATCHES, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Details", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_DETAILS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Hints", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_HINTSSKIPS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Models", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_MODELS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Triggers", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_TRIGGERS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Botclips", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_BOTCLIPS, FALSE); + + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Hide/Show"); + create_menu_item_with_mnemonic (menu_in_menu, "Hide Selected", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_HIDESHOW_HIDESELECTED); + create_menu_item_with_mnemonic (menu_in_menu, "Show Hidden", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_HIDESHOW_SHOWHIDDEN); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Entities as"); + g_object_set_data (G_OBJECT (window), "view_entitiesas_menu", menu_in_menu); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "Bounding box", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_BOUNDINGBOX,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_boundingbox", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Wireframe", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_WIREFRAME,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_wireframe", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Selected Wireframe", + GTK_SIGNAL_FUNC (HandleCommand),ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_selectedwireframe", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Selected Skinned", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SELECTEDSKINNED,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_selectedskinned", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Skinned", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SKINNED,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_skinned", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Skinned and Boxed", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SKINNEDANDBOXED,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_skinnedandboxed", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "Cubic Clipping", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBICCLIPPING, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_cubicclipping", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "OpenGL Lighting", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_OPENGLLIGHTING, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_opengllighting", item); + + // Selection menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Selection"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Drag"); + create_menu_item_with_mnemonic (menu_in_menu, "Drag _Edges", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DRAGEDGES); + create_menu_item_with_mnemonic (menu_in_menu, "Drag _Vertices", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DRAGVERTECIES); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "_Clone", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CLONE); + item = create_menu_item_with_mnemonic (menu, "Deselect", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DESELECT); + item = create_menu_item_with_mnemonic (menu, "Invert", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_INVERT); +#ifndef QUAKE3 + create_menu_item_with_mnemonic (menu, "_Delete", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DELETE); +#endif + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Flip"); + create_menu_item_with_mnemonic (menu_in_menu, "Flip _X", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPX); + create_menu_item_with_mnemonic (menu_in_menu, "Flip _Y", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPY); + create_menu_item_with_mnemonic (menu_in_menu, "Flip _Z", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPZ); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Rotate"); + create_menu_item_with_mnemonic (menu_in_menu, "Rotate X", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEX); + create_menu_item_with_mnemonic (menu_in_menu, "Rotate Y", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEY); + create_menu_item_with_mnemonic (menu_in_menu, "Rotate Z", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEZ); + create_menu_item_with_mnemonic (menu_in_menu, "Arbitrary rotation...", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_ARBITRARYROTATION); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Scale...", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_SCALE); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "CSG"); + create_menu_item_with_mnemonic (menu_in_menu, "Make _Hollow", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKEHOLLOW); + create_menu_item_with_mnemonic (menu_in_menu, "CSG _Subtract", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CSGSUBTRACT); + create_menu_item_with_mnemonic (menu_in_menu, "CSG _Merge", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CSGMERGE); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select"); + create_menu_item_with_mnemonic (menu_in_menu, "Select Complete _Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select T_ouching", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING); + create_menu_item_with_mnemonic (menu_in_menu, "Select _Partial Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select _Inside", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE); +#ifndef QUAKE3 + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Left", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGELEFT); + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Right", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGERIGHT); + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Up", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEUP); + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Down", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEDOWN); +#endif + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Clipper"); + create_menu_item_with_mnemonic (menu_in_menu, "Toggle Clipper", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CLIPPER); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "Clip selection", + GTK_SIGNAL_FUNC (HandleCommand), ID_CLIP_SELECTED); + create_menu_item_with_mnemonic (menu_in_menu, "Split selection", + GTK_SIGNAL_FUNC (HandleCommand), ID_SPLIT_SELECTED); + create_menu_item_with_mnemonic (menu_in_menu, "Flip Clip orientation", + GTK_SIGNAL_FUNC (HandleCommand), ID_FLIP_CLIP); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Connect entities", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CONNECT); + create_menu_item_with_mnemonic (menu, "Ungroup entity", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY); + create_menu_item_with_mnemonic (menu, "Make detail", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL); + create_menu_item_with_mnemonic (menu, "Make structural", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL); + + // BSP menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Bsp"); + + menu_separator (menu); + g_object_set_data (G_OBJECT (window), "menu_bsp", menu); + + // Grid menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Grid"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_radio_menu_item_with_mnemonic (menu, NULL, "Grid0.25", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_025, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_025", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid0.5", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_05, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_05", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid1", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_1, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_1", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid2", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_2, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_2", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid4", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_4, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_4", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid8", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_8, TRUE); + g_object_set_data (G_OBJECT (window), "menu_grid_8", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid16", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_16, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_16", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid32", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_32, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_32", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid64", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_64, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_64", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid128", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_128, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_128", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid256", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_256, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_256", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "Snap to grid", + GTK_SIGNAL_FUNC (HandleCommand), ID_SNAPTOGRID, TRUE); + g_object_set_data (G_OBJECT (window), "menu_snaptogrid", item); + + // Textures menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Textures"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_check_menu_item_with_mnemonic (menu, "Show In _Use", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHOWINUSE, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_showinuse", item); + item = create_check_menu_item_with_mnemonic (menu, "Show _All", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHOWALL, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_showall", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "Show shaders", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHADERS_SHOW, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_shaders_show", item); + item = create_menu_item_with_mnemonic (menu, "Flush & Reload Shaders", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_RELOADSHADERS); + g_object_set_data (G_OBJECT (window), "menu_textures_reloadshaders", item); + item = create_menu_item_with_mnemonic (menu, "Load directory...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_LOAD); + g_object_set_data (G_OBJECT (window), "menu_textures_load", item); + item = create_menu_item_with_mnemonic (menu, "Directory list...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_LOADLIST); + menu_separator (menu); + + item = create_menu_item_with_mnemonic (menu, "_Surface Inspector", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_INSPECTOR); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Render Quality"); + g_object_set_data (G_OBJECT (window), "render_quality_menu", menu_in_menu); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "_Wireframe", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_WIREFRAME, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_wireframe", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Flat shade", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_FLATSHADE, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_flatshade", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Nearest", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEAREST, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_nearest", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Nearest _Mipmap", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEARESTMIPMAP, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_nearestmipmap", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Linear", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_LINEAR, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_linear", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Bilinear", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_BILINEAR, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_bilinear", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "B_ilinear Mipmap", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_BILINEARMIPMAP, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_bilinearmipmap", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "T_rilinear", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_TRILINEAR, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_trilinear", item); + create_menu_item_with_mnemonic (menu, "Find / Replace...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURE_REPLACEALL); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Texture Lock"); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Moves", + GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLE_LOCK, TRUE); + g_object_set_data (G_OBJECT (window), "menu_toggle_lock", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Rotations", + GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLE_ROTATELOCK, TRUE); + g_object_set_data (G_OBJECT (window), "menu_toggle_rotatelock", item); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Texture Window Scale"); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "200%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_200, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_200", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "100%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_100, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_100", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "50%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_50, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_50", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "25%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_25, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_25", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "10%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_10, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_10", item); + item = menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "shaderlist.txt only", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHADERLISTONLY, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_shaderlistonly", item); + item = menu_separator (menu); + g_object_set_data (G_OBJECT (window), "menu_textures_separator", item); + g_object_set_data (G_OBJECT (window), "menu_textures", menu); + + // Misc menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Misc"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "_Benchmark", GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_BENCHMARK); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Colors"); + menu_3 = create_menu_in_menu_with_mnemonic (menu_in_menu, "Themes"); + create_menu_item_with_mnemonic (menu_3, "QE4 Original", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETORIGINAL); + create_menu_item_with_mnemonic (menu_3, "Q3Radiant Original", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETQER); + create_menu_item_with_mnemonic (menu_3, "Black and Green", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETBLACK); + create_menu_item_with_mnemonic (menu_3, "Maya/Max/Lightwave Emulation", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETYDNAR); + + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "_Texture Background...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREBK); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Background...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_XYBK); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Major...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MAJOR); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Minor...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MINOR); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Major Small...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MAJOR_ALT); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Minor Small...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MINOR_ALT); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Text...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_GRIDTEXT); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Block...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_GRIDBLOCK); + create_menu_item_with_mnemonic (menu_in_menu, "Default Brush...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_BRUSH); + create_menu_item_with_mnemonic (menu_in_menu, "Camera Background...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_CAMERABACK); + create_menu_item_with_mnemonic (menu_in_menu, "Selected Brush...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_SELECTEDBRUSH); + create_menu_item_with_mnemonic (menu_in_menu, "Selected Brush (Camera)...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_SELECTEDBRUSH3D); + create_menu_item_with_mnemonic (menu_in_menu, "Clipper...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_CLIPPER); + create_menu_item_with_mnemonic (menu_in_menu, "Active View name...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_VIEWNAME); + + create_menu_item_with_mnemonic (menu, "_Gamma...", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_GAMMA); + create_menu_item_with_mnemonic (menu, "Find brush...", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_FINDBRUSH); + item = create_menu_item_with_mnemonic (menu, "Next leak spot", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_NEXTLEAKSPOT); + item = create_menu_item_with_mnemonic (menu, "Previous leak spot", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_PREVIOUSLEAKSPOT); + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 +// create_menu_item_with_mnemonic (menu, "_Print XY View", GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_PRINTXY); + item = create_menu_item_with_mnemonic (menu, "_Select Entity Color...", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_SELECTENTITYCOLOR); + g_object_set_data (G_OBJECT (window), "menu_misc_selectentitycolor", item); + + // Region menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Region"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "_Off", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_OFF); + create_menu_item_with_mnemonic (menu, "_Set XY", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETXY); + create_menu_item_with_mnemonic (menu, "Set _Tall Brush", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETTALLBRUSH); + create_menu_item_with_mnemonic (menu, "Set _Brush", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETBRUSH); + create_menu_item_with_mnemonic (menu, "Set Se_lected Brushes", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETSELECTION); + + // Brush menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Brush"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_menu_item_with_mnemonic (menu, "3 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_3SIDED); + item = create_menu_item_with_mnemonic (menu, "4 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_4SIDED); + item = create_menu_item_with_mnemonic (menu, "5 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_5SIDED); + item = create_menu_item_with_mnemonic (menu, "6 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_6SIDED); + item = create_menu_item_with_mnemonic (menu, "7 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_7SIDED); + item = create_menu_item_with_mnemonic (menu, "8 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_8SIDED); + item = create_menu_item_with_mnemonic (menu, "9 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_9SIDED); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Arbitrary sided...", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ARBITRARYSIDED); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Primitives"); + create_menu_item_with_mnemonic (menu_in_menu, "Cone...", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_MAKECONE); + create_menu_item_with_mnemonic (menu_in_menu, "Sphere...", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_PRIMITIVES_SPHERE); + + // Curve menu + if (!g_pGameDescription->mNoPatch) + { + menu = create_sub_menu_with_mnemonic (menu_bar, "_Curve"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "Cylinder", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHTUBE); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "More Cylinders"); + create_menu_item_with_mnemonic (menu_in_menu, "Dense Cylinder", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHDENSETUBE); + create_menu_item_with_mnemonic (menu_in_menu, "Very Dense Cylinder", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHVERYDENSETUBE); + create_menu_item_with_mnemonic (menu_in_menu, "Square Cylinder", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHSQUARE); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "End cap", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHENDCAP); + create_menu_item_with_mnemonic (menu, "Bevel", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHBEVEL); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "More End caps, Bevels"); + create_menu_item_with_mnemonic (menu_in_menu, "Square Endcap", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL); + create_menu_item_with_mnemonic (menu_in_menu, "Square Bevel", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Cone", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHCONE); + item = create_menu_item_with_mnemonic (menu, "Sphere", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PRIMITIVES_SPHERE); + gtk_widget_set_sensitive (item, FALSE); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "Simple Patch Mesh...", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_SIMPLEPATCHMESH); + g_object_set_data (G_OBJECT (window), "menu_simplepatchmesh", item); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Insert"); + create_menu_item_with_mnemonic (menu_in_menu, "Insert (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_INSERTCOLUMN); + create_menu_item_with_mnemonic (menu_in_menu, "Add (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_ADDCOLUMN); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "Insert (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_INSERTROW); + create_menu_item_with_mnemonic (menu_in_menu, "Add (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_ADDROW); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Delete"); + create_menu_item_with_mnemonic (menu_in_menu, "First (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_FIRSTCOLUMN); + create_menu_item_with_mnemonic (menu_in_menu, "Last (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_LASTCOLUMN); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "First (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_FIRSTROW); + create_menu_item_with_mnemonic (menu_in_menu, "Last (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_LASTROW); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Matrix"); + create_menu_item_with_mnemonic (menu_in_menu, "Invert", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVE); + menu_3 = create_menu_in_menu_with_mnemonic (menu_in_menu, "Re-disperse"); + create_menu_item_with_mnemonic (menu_3, "Rows", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_ROWS); + create_menu_item_with_mnemonic (menu_3, "Cols (Intermediate)", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_INTERMEDIATE_COLS); + create_menu_item_with_mnemonic (menu_3, "Rows (Intermediate)", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS); + create_menu_item_with_mnemonic (menu_in_menu, "Transpose", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MATRIX_TRANSPOSE); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Cap Selection", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_CAP); + create_menu_item_with_mnemonic (menu, "Cycle Cap Texture", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_CYCLECAP); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Overlay"); + create_menu_item_with_mnemonic (menu_in_menu, "Set", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_OVERLAY_SET); + create_menu_item_with_mnemonic (menu_in_menu, "Clear", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_OVERLAY_CLEAR); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Thicken...", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_THICKEN); + } + // Plugins menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Plugins"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + /* + create_menu_item_with_mnemonic (menu, "Refresh", GTK_SIGNAL_FUNC (HandleCommand), ID_PLUGINS_REFRESH); + */ + // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed + item = menu_separator (menu); + g_object_set_data (G_OBJECT (window), "menu_plugin_separator", item); + g_object_set_data (G_OBJECT (window), "menu_plugin", menu); + + // Help menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Help"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_menu_item_with_mnemonic (menu, "Manual", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP); + gtk_widget_add_accelerator (item, "activate", accel, GDK_F1, (GdkModifierType)0, GTK_ACCEL_VISIBLE); + + // this creates all the per-game drop downs for the game pack helps + // it will take care of hooking the Sys_OpenURL calls etc. + create_game_help_menu(menu, accel); + + // TTimo: this is in global.xlink now + //create_menu_item_with_mnemonic (menu, "Links", + // GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_LINKS); + create_menu_item_with_mnemonic (menu, "Bug report", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_BUGREPORT); + create_menu_item_with_mnemonic (menu, "Shortcuts list", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_COMMANDLIST); + create_menu_item_with_mnemonic (menu, "_About", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_ABOUT); + + + // leo: Hidden menu to make the accelerators work, + // this is a hack that needs to be changed later if someone has a better idea. + // NOTE TTimo + // maybe the better idea would be NOT to use any such accelerator scheme and do all key listening and interpret ourselves + menu = create_sub_menu_with_mnemonic (menu_bar, "Hidden"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + gtk_widget_hide (gtk_menu_get_attach_widget (GTK_MENU (menu))); + + create_menu_item_with_mnemonic (menu, "BendMode", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_BEND); + create_menu_item_with_mnemonic (menu, "FitTexture", GTK_SIGNAL_FUNC (HandleCommand), IDC_BTN_FACEFIT); + create_menu_item_with_mnemonic (menu, "ViewTextures", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_TEXTURE); + create_menu_item_with_mnemonic (menu, "PatchInspector", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_INSPECTOR); + create_menu_item_with_mnemonic (menu, "InvertCurveTextureX", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVETEXTUREY); + create_menu_item_with_mnemonic (menu, "InvertCurveTextureY", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVETEXTUREX); + create_menu_item_with_mnemonic (menu, "IncPatchColumn", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERTCOLUMN); + create_menu_item_with_mnemonic (menu, "IncPatchRow", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERTROW); + create_menu_item_with_mnemonic (menu, "DecPatchColumn", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETECOLUMN); + create_menu_item_with_mnemonic (menu, "DecPatchRow", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETEROW); + create_menu_item_with_mnemonic (menu, "Patch TAB", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_TAB); + create_menu_item_with_mnemonic (menu, "Patch TAB", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_TAB); + create_menu_item_with_mnemonic (menu, "SelectNudgeDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEDOWN); + create_menu_item_with_mnemonic (menu, "CameraForward", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_FORWARD); + create_menu_item_with_mnemonic (menu, "CameraBack", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_BACK); + create_menu_item_with_mnemonic (menu, "CameraLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_LEFT); + create_menu_item_with_mnemonic (menu, "CameraRight", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_RIGHT); + create_menu_item_with_mnemonic (menu, "CameraUp", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_UP); + create_menu_item_with_mnemonic (menu, "CameraDown", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_DOWN); + create_menu_item_with_mnemonic (menu, "CameraAngleUp", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_ANGLEUP); + create_menu_item_with_mnemonic (menu, "CameraAngleDown", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_ANGLEDOWN); + create_menu_item_with_mnemonic (menu, "CameraStrafeRight", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_STRAFERIGHT); + create_menu_item_with_mnemonic (menu, "CameraStrafeLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_STRAFELEFT); + create_menu_item_with_mnemonic (menu, "ToggleGrid", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_TOGGLE); + create_menu_item_with_mnemonic (menu, "ToggleCrosshairs", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CROSSHAIR); + create_menu_item_with_mnemonic (menu, "ToggleRealtime", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CAMERAUPDATE); + create_menu_item_with_mnemonic (menu, "MouseRotate", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_MOUSEROTATE); + create_menu_item_with_mnemonic (menu, "TexRotateClock", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_ROTATECLOCK); + create_menu_item_with_mnemonic (menu, "TexRotateCounter", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_ROTATECOUNTER); + create_menu_item_with_mnemonic (menu, "TexScaleUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALEUP); + create_menu_item_with_mnemonic (menu, "TexScaleDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALEDOWN); + create_menu_item_with_mnemonic (menu, "TexShiftLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTLEFT); + create_menu_item_with_mnemonic (menu, "TexShiftRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTRIGHT); + create_menu_item_with_mnemonic (menu, "TexShiftUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTUP); + create_menu_item_with_mnemonic (menu, "TexShiftDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTDOWN); + create_menu_item_with_mnemonic (menu, "GridDown", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_PREV); + create_menu_item_with_mnemonic (menu, "GridUp", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_NEXT); + create_menu_item_with_mnemonic (menu, "TexScaleLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALELEFT); + create_menu_item_with_mnemonic (menu, "TexScaleRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALERIGHT); + create_menu_item_with_mnemonic (menu, "MoveSelectionDOWN", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MOVEDOWN); + create_menu_item_with_mnemonic (menu, "MoveSelectionUP", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MOVEUP); + create_menu_item_with_mnemonic (menu, "DumpSelectedBrush", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_PRINT); + create_menu_item_with_mnemonic (menu, "ToggleSizePaint", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TOGGLESIZEPAINT); + create_menu_item_with_mnemonic (menu, "SelectNudgeLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGELEFT); + create_menu_item_with_mnemonic (menu, "SelectNudgeRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGERIGHT); + create_menu_item_with_mnemonic (menu, "SelectNudgeUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEUP); + create_menu_item_with_mnemonic (menu, "NaturalizePatch", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_NATURALIZE); + create_menu_item_with_mnemonic (menu, "SnapPatchToGrid", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_SNAPTOGRID); + create_menu_item_with_mnemonic (menu, "SelectAllOfType", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_ALL); + create_menu_item_with_mnemonic (menu, "CycleOutlineStyle", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_OUTLINESTYLE); + create_menu_item_with_mnemonic (menu, "TextureWindowScaleup", GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREWINDOW_SCALEUP); + create_menu_item_with_mnemonic (menu, "TextureWindowScaledown", GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREWINDOW_SCALEDOWN); + + g_bIgnoreCommands--; +} + +void MainFrame::create_main_toolbar (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *handle_box, *toolbar, *w; + + handle_box = gtk_handle_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); + gtk_widget_show (handle_box); + g_object_set_data (G_OBJECT (window), "tb_handle_box", handle_box); + + toolbar = gtk_toolbar_new (); + gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); + gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); + // gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style); + gtk_container_add (GTK_CONTAINER (handle_box), toolbar); + + gtk_widget_show (toolbar); + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "Open", "Open an existing map", "", + new_pixmap (window, "file_open.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_FILE_OPEN)); + g_object_set_data (G_OBJECT (window), "tb_file_open", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "Save", "Save the active map", "", + new_pixmap (window, "file_save.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_FILE_SAVE)); + g_object_set_data (G_OBJECT (window), "tb_file_save", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "x-axis Flip", "", + new_pixmap (window, "brush_flipx.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_FLIPX)); + g_object_set_data (G_OBJECT (window), "tb_brush_flipx", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "x-axis Rotate", "", + new_pixmap (window, "brush_rotatex.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_ROTATEX)); + g_object_set_data (G_OBJECT (window), "tb_brush_rotatex", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "y-axis Flip", "", + new_pixmap (window, "brush_flipy.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_FLIPY)); + g_object_set_data (G_OBJECT (window), "tb_brush_flipy", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "y-axis Rotate", "", + new_pixmap (window, "brush_rotatey.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_ROTATEY)); + g_object_set_data (G_OBJECT (window), "tb_brush_rotatey", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "z-axis Flip", "", + new_pixmap (window, "brush_flipz.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_FLIPZ)); + g_object_set_data (G_OBJECT (window), "tb_brush_flipz", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "z-axis Rotate", "", + new_pixmap (window, "brush_rotatez.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_ROTATEZ)); + g_object_set_data (G_OBJECT (window), "tb_brush_rotatez", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Complete Tall", "", + new_pixmap (window, "selection_selectcompletetall.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTCOMPLETETALL)); + g_object_set_data (G_OBJECT (window), "tb_selection_selectcompletetall", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Touching", "", + new_pixmap (window, "selection_selecttouching.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTTOUCHING)); + g_object_set_data (G_OBJECT (window), "tb_selection_selecttouching", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Partial Tall", "", + new_pixmap (window, "selection_selectpartialtall.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTPARTIALTALL)); + g_object_set_data (G_OBJECT (window), "tb_selection_selectpartialtall", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Inside", "", + new_pixmap (window, "selection_selectinside.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTINSIDE)); + g_object_set_data (G_OBJECT (window), "tb_selection_selectinside", w); + } else + { + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Selection", "", + new_pixmap (window, "popup_selection.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_POPUP_SELECTION)); + g_object_set_data (G_OBJECT (window), "tb_popup_selection", w); + } + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "CSG Subtract", "", + new_pixmap (window, "selection_csgsubtract.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_CSGSUBTRACT)); + g_object_set_data (G_OBJECT (window), "tb_selection_csgsubtract", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "CSG Merge", "", + new_pixmap (window, "selection_csgmerge.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_CSGMERGE)); + g_object_set_data (G_OBJECT (window), "tb_selection_csgmerge", w); + } + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Hollow", "", + new_pixmap (window, "selection_makehollow.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_MAKEHOLLOW)); + g_object_set_data (G_OBJECT (window), "tb_selection_makehollow", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Clipper", "", new_pixmap (window, "view_clipper.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CLIPPER)); + g_object_set_data (G_OBJECT (window), "tb_view_clipper", w); + } + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Change views", "", + new_pixmap (window, "view_change.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_VIEW_CHANGE)); + g_object_set_data (G_OBJECT (window), "tb_view_change", w); + + if (!g_PrefsDlg.m_bWideToolbar) + { + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + } + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Texture view mode", "", + new_pixmap (window, "textures_popup.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_TEXTURES_POPUP)); + g_object_set_data (G_OBJECT (window), "tb_textures_popup", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Cubic clip the camera view", "", + new_pixmap (window, "view_cubicclipping.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CUBICCLIPPING)); + g_object_set_data (G_OBJECT (window), "tb_view_cubicclipping", w); + } + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + if (!g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Camera preview", "", new_pixmap (window, "view_cameratoggle.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CAMERATOGGLE)); + g_object_set_data (G_OBJECT (window), "tb_view_cameratoggle", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Update Camera", "", + new_pixmap (window, "view_cameraupdate.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_VIEW_CAMERAUPDATE)); + g_object_set_data (G_OBJECT (window), "tb_view_cameraupdate", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Cubic clip the camera view", "", + new_pixmap (window, "view_cubicclipping.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CUBICCLIPPING)); + g_object_set_data (G_OBJECT (window), "tb_view_cubicclipping", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Entity inspector", "", new_pixmap (window, "view_entity.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_ENTITY)); + g_object_set_data (G_OBJECT (window), "tb_view_entity", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Clipper", "", new_pixmap (window, "view_clipper.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CLIPPER)); + g_object_set_data (G_OBJECT (window), "tb_view_clipper", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + } + + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Free Rotation", "", new_pixmap (window, "select_mouserotate.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECT_MOUSEROTATE)); + g_object_set_data (G_OBJECT (window), "tb_select_mouserotate", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Free Scaling", "", new_pixmap (window, "select_mousescale.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECT_MOUSESCALE)); + g_object_set_data (G_OBJECT (window), "tb_select_mousescale", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Scale X", "", new_pixmap (window, "scalelockx.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKX)); + g_object_set_data (G_OBJECT (window), "tb_scalelockx", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Scale Y", "", new_pixmap (window, "scalelocky.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKY)); + g_object_set_data (G_OBJECT (window), "tb_scalelocky", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Scale Z", "", new_pixmap (window, "scalelockz.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKZ)); + g_object_set_data (G_OBJECT (window), "tb_scalelockz", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Don't select model brushes", "", + new_pixmap (window, "dontselectmodel.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_DONTSELECTMODEL)); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + g_object_set_data (G_OBJECT (window), "tb_dontselectmodel", w); + + if (!g_pGameDescription->mNoPatch) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Don't select curved brushes", "", + new_pixmap (window, "dontselectcurve.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_DONTSELECTCURVE)); + g_object_set_data (G_OBJECT (window), "tb_dontselectcurve", w); + } + } + + // bug #292, patch toolbar option + if (g_PrefsDlg.m_bPatchToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Show patch bounding box", "", + new_pixmap (window, "patch_showboundingbox.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_PATCH_SHOWBOUNDINGBOX)); + g_object_set_data (G_OBJECT (window), "tb_patch_showboundingbox", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Show patches as wireframes", "", + new_pixmap (window, "patch_wireframe.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_PATCH_WIREFRAME)); + g_object_set_data (G_OBJECT (window), "tb_patch_wireframe", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Patch Bend mode", "", + new_pixmap (window, "patch_bend.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_PATCH_BEND)); + g_object_set_data (G_OBJECT (window), "tb_patch_bend", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Put caps on the current patch", "", + new_pixmap (window, "curve_cap.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_CURVE_CAP)); + g_object_set_data (G_OBJECT (window), "tb_curve_cap", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Welds equal patch points during moves", "", + new_pixmap (window, "patch_weld.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_PATCH_WELD)); + g_object_set_data (G_OBJECT (window), "tb_patch_weld", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Selects drill down rows and columns", "", + new_pixmap (window, "patch_drilldown.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_PATCH_DRILLDOWN)); + g_object_set_data (G_OBJECT (window), "tb_patch_drilldown", w); + } + + if (g_PrefsDlg.m_bWideToolbar) + { + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Show Entities as", "", + new_pixmap (window, "show_entities.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SHOW_ENTITIES)); + g_object_set_data (G_OBJECT (window), "tb_show_entities", w); + } + + /* + uh? that is OLD +#ifndef QUAKE3 + w = g_object_get_data (G_OBJECT (window), "tb_dontselectcurve"); + gtk_widget_hide (w); + w = g_object_get_data (G_OBJECT (window), "tb_patch_showboundingbox"); + gtk_widget_hide (w); + w = g_object_get_data (G_OBJECT (window), "tb_patch_weld"); + gtk_widget_hide (w); + w = g_object_get_data (G_OBJECT (window), "tb_patch_wireframe"); + gtk_widget_hide (w); +#endif + */ + + m_bCamPreview = true; + g_nScaleHow = (SCALE_X | SCALE_Y | SCALE_Z); +} + +void MainFrame::create_plugin_toolbar (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *handle_box, *toolbar; + + handle_box = gtk_handle_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); + if (g_PrefsDlg.m_bPluginToolbar) + gtk_widget_show (handle_box); + g_object_set_data (G_OBJECT (window), "tb_handle_box", handle_box); + + toolbar = gtk_toolbar_new(); + gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); + gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); + // gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style); + gtk_container_add (GTK_CONTAINER (handle_box), toolbar); + g_object_set_data (G_OBJECT (window), "toolbar_plugin", toolbar); + gtk_widget_show (toolbar); +} + +void MainFrame::create_main_statusbar (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *hbox, *hbox1; + GtkWidget *frame; + GtkWidget *label; + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_widget_set_usize (hbox, -1, 24); + gtk_container_border_width (GTK_CONTAINER (hbox), 1); + gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, TRUE, 2); + + frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (frame), hbox1); + gtk_container_border_width (GTK_CONTAINER (hbox1), 0); + gtk_widget_show (hbox1); + + label = gtk_label_new (" Label "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_padding (GTK_MISC (label), 3, 0); + m_pStatusLabel[0] = label; + + for (int i = 1; i < 6; i++) + { + frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + label = gtk_label_new (" Label "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (frame), label); + m_pStatusLabel[i] = label; + } +} + +guint s_idle_id; +static gint mainframe_idle (gpointer user_data) +{ + g_pParentWnd->RoutineProcessing (); + return TRUE; +} + +static void Sys_Iconify (GtkWidget *w); +static void Sys_Restore (GtkWidget *w); + +inline void CHECK_RESTORE(GtkWidget* w) +{ + if (g_object_get_data (G_OBJECT (w), "was_mapped") != NULL) + gtk_widget_show (w); +} + + +// this is called when the window is restored from the iconified state +static void mainframe_map (GtkWidget *widget) +{ + if (g_pParentWnd->IsSleeping ()) + g_pParentWnd->OnSleep (); + + if ((g_pParentWnd->CurrentStyle() == MainFrame::eFloating) && (widget == g_pParentWnd->m_pWidget)) + { + // restore previously visible windows + CHECK_RESTORE (g_pParentWnd->GetCamWnd ()->m_pParent); + if (g_PrefsDlg.m_bFloatingZ) + CHECK_RESTORE (g_pParentWnd->GetZWnd ()->m_pParent); + CHECK_RESTORE (g_pParentWnd->GetXYWnd ()->m_pParent); + CHECK_RESTORE (g_pParentWnd->GetXZWnd ()->m_pParent); + CHECK_RESTORE (g_pParentWnd->GetYZWnd ()->m_pParent); + CHECK_RESTORE (g_pGroupDlg->m_pWidget); + } +} + +inline void CHECK_MINIMIZE(GtkWidget* w) +{ + g_object_set_data (G_OBJECT (w), "was_mapped", (void*)(GTK_WIDGET_VISIBLE (w) != 0)); + gtk_widget_hide (w); +} + +static void mainframe_unmap (GtkWidget *widget) +{ + + if ((g_pParentWnd->CurrentStyle() == MainFrame::eFloating) && (widget == g_pParentWnd->m_pWidget)) + { + // minimize all other windows when the main window is minimized + CHECK_MINIMIZE (g_pParentWnd->GetCamWnd ()->m_pParent); + if (g_PrefsDlg.m_bFloatingZ) + CHECK_MINIMIZE (g_pParentWnd->GetZWnd ()->m_pParent); + CHECK_MINIMIZE (g_pParentWnd->GetXYWnd ()->m_pParent); + CHECK_MINIMIZE (g_pParentWnd->GetXZWnd ()->m_pParent); + CHECK_MINIMIZE (g_pParentWnd->GetYZWnd ()->m_pParent); + CHECK_MINIMIZE (g_pGroupDlg->m_pWidget); + } +} + +static GtkWidget* create_floating (MainFrame* mainframe) +{ + GtkWidget *wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); + //if (mainframe->CurrentStyle() != MainFrame::eFloating) + gtk_window_set_transient_for (GTK_WINDOW (wnd), GTK_WINDOW (mainframe->m_pWidget)); + gtk_widget_set_events (wnd, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); + gtk_signal_connect (GTK_OBJECT (wnd), "delete_event", GTK_SIGNAL_FUNC (widget_delete_hide), NULL); + gtk_signal_connect (GTK_OBJECT (wnd), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (wnd), "key_press_event", + GTK_SIGNAL_FUNC (mainframe_keypress), mainframe); + gtk_signal_connect (GTK_OBJECT (wnd), "key_release_event", + GTK_SIGNAL_FUNC (mainframe_keyrelease), mainframe); + gtk_signal_connect (GTK_OBJECT (wnd), "map_event", + GTK_SIGNAL_FUNC (mainframe_map), mainframe); + + gtk_window_set_default_size (GTK_WINDOW (wnd), 100, 100); + +#ifdef DBG_WINDOWPOS + Sys_Printf("create_floating: %p, gtk_window_set_default_size 100, 100\n", wnd); +#endif + + return wnd; +} + +void console_populate_popup(GtkTextView* textview, GtkMenu* menu, gpointer user_data) +{ + menu_separator(GTK_WIDGET(menu)); + + GtkWidget* item = gtk_menu_item_new_with_label ("Clear"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Sys_ClearPrintf), NULL); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); +} + +void console_construct(GtkWidget* textview) +{ + g_signal_connect(G_OBJECT(textview), "populate-popup", G_CALLBACK(console_populate_popup), NULL); +} + +extern MemStream g_Clipboard; + +void Clipboard_CopyMap() +{ + g_Clipboard.SetLength(0); + Map_Export (&g_Clipboard, "xmap", false, true); +} + +void Clipboard_PasteMap() +{ + if (g_Clipboard.GetLength() > 0) + { + g_Clipboard.Seek(0, SEEK_SET); + Map_Import(&g_Clipboard, "xmap", true); + } +} + +/*! +Platform-independent GTK clipboard support. +\todo Using GDK_SELECTION_CLIPBOARD fails on win32, so we use the win32 API directly for now. +*/ +#if defined (__linux__) || defined (__APPLE__) + +enum +{ + RADIANT_CLIPPINGS = 23, +}; + +static const GtkTargetEntry clipboard_targets[] = { + { "RADIANT_CLIPPINGS", 0, RADIANT_CLIPPINGS, }, +}; + +static void clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data_or_owner) +{ + guchar *buffer; + gint len; + GdkAtom type = GDK_NONE; + + len = g_Clipboard.GetLength(); + + if (!len) + { + buffer = NULL; + } else + { + buffer = g_Clipboard.GetBuffer (); + } + + if(info == clipboard_targets[0].info) + { + type = gdk_atom_intern(clipboard_targets[0].target, FALSE); + } + + gtk_selection_data_set (selection_data, type, 8, buffer, len); +} + +static void clipboard_clear (GtkClipboard *clipboard, gpointer user_data_or_owner) +{ +} + +static void clipboard_received (GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data) +{ + g_Clipboard.SetLength (0); + + if (data->length < 0) + Sys_FPrintf(SYS_ERR, "Error retrieving selection\n"); + else if(strcmp(gdk_atom_name(data->type), clipboard_targets[0].target) == 0) + g_Clipboard.Write (data->data, data->length); + + Clipboard_PasteMap(); +} + +void clipboard_copy() +{ + Clipboard_CopyMap(); + + GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_set_with_data (clipboard, clipboard_targets, 1, clipboard_get, clipboard_clear, NULL); +} + +void clipboard_paste() +{ + GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_request_contents (clipboard, gdk_atom_intern(clipboard_targets[0].target, FALSE), clipboard_received, NULL); +} + + +#elif defined(WIN32) + +void clipboard_copy() +{ + Clipboard_CopyMap(); + + bool bClipped = false; + UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings"); + if (nClipboard > 0) + { + if (::OpenClipboard(NULL)) + { + EmptyClipboard(); + long lSize = g_Clipboard.GetLength(); + HANDLE h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, lSize + sizeof(long)); + if (h != NULL) + { + unsigned char *cp = reinterpret_cast(::GlobalLock(h)); + memcpy(cp, &lSize, sizeof(long)); + cp += sizeof(long); + g_Clipboard.Seek(0, SEEK_SET); + g_Clipboard.Read(cp, lSize); + ::GlobalUnlock(h); + ::SetClipboardData(nClipboard, h); + ::CloseClipboard(); + bClipped = true; + } + } + } + + if (!bClipped) + { + Sys_Printf("Unable to register Windows clipboard formats, copy/paste between editors will not be possible\n"); + } +} + +void clipboard_paste() +{ + bool bPasted = false; + UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings"); + if (nClipboard > 0 && ::OpenClipboard(NULL)) + { + if(IsClipboardFormatAvailable(nClipboard)) + { + HANDLE h = ::GetClipboardData(nClipboard); + if (h) + { + g_Clipboard.SetLength(0); + unsigned char *cp = reinterpret_cast(::GlobalLock(h)); + long lSize = 0; + memcpy(&lSize, cp, sizeof(long)); + cp += sizeof(long); + g_Clipboard.Write(cp, lSize); + ::GlobalUnlock(h); + } + } + ::CloseClipboard(); + } + + Clipboard_PasteMap(); +} + +#endif + +void MainFrame::Copy() +{ + clipboard_copy(); +} + +void MainFrame::Paste() +{ + clipboard_paste(); + UpdateSurfaceDialog(); +} + + +#ifdef DBG_WINDOWPOS +GtkWidget *watchit = NULL; + +void CheckWatchit(char *msg) +{ + static int width = 0; + if ((watchit!=NULL) && (watchit->allocation.width != width)) + { + Sys_Printf("CheckWatchit %s: %d\n", msg, watchit->allocation.width); + width = watchit->allocation.width; + } +} +#endif + +#ifdef _WIN32 +BOOL CALLBACK m_pCountMonitor (HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + int *n = (int *) dwData; + + (*n)++; + + return TRUE; +} + +struct monitorInfo_s { + GdkRectangle *win_monitors; + int i_win_mon; +}; + +BOOL CALLBACK m_pEnumMonitor (HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + monitorInfo_s *monitorInfo = (monitorInfo_s *) dwData; + GdkRectangle *monitor; + MONITORINFOEX lpmi; + + monitor = monitorInfo->win_monitors + monitorInfo->i_win_mon; + + memset(&lpmi, 0, sizeof(MONITORINFOEX)); + lpmi.cbSize = sizeof(MONITORINFOEX); + + GetMonitorInfo( hMonitor, &lpmi ); + + if( lpmi.dwFlags & MONITORINFOF_PRIMARY ) { + RECT rect; + + SystemParametersInfo (SPI_GETWORKAREA, 0, &rect, 0); + monitor->x = rect.left; + monitor->y = rect.top; + monitor->width = rect.right - rect.left; + monitor->height = rect.bottom - rect.top; + + if (monitorInfo->i_win_mon != 0) + { + GdkRectangle temp = *monitor; + *monitor = monitorInfo->win_monitors[0]; + monitorInfo->win_monitors[0] = temp; + } + } else { + monitor->x = lpmi.rcMonitor.left; + monitor->y = lpmi.rcMonitor.top; + monitor->width = lpmi.rcMonitor.right - lpmi.rcMonitor.left; + monitor->height = lpmi.rcMonitor.bottom - lpmi.rcMonitor.top; + } + + monitorInfo->i_win_mon++; + + return TRUE; +} + +void PositionWindowOnPrimaryScreen(window_position_t& position) +{ + const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); + + if( position.x <= primaryMonitorRect.x + 6 ) + position.x = primaryMonitorRect.x + 6; + else if( position.x >= ( primaryMonitorRect.x + primaryMonitorRect.width ) - 6 ) + position.x = primaryMonitorRect.x + 6; + + if( position.y <= primaryMonitorRect.y + 6 ) + position.y = primaryMonitorRect.y + 6; + else if( position.y >= ( primaryMonitorRect.y + primaryMonitorRect.height ) - 6 ) + position.y = primaryMonitorRect.y + 6; + + if( position.x + position.w >= ( primaryMonitorRect.x + primaryMonitorRect.width ) - 18 ) + position.w = primaryMonitorRect.width - 18; + if( position.y + position.h >= ( primaryMonitorRect.y + primaryMonitorRect.height ) - 18 ) + position.h = primaryMonitorRect.height - 18; +} +#endif + +GtkWidget* create_framed_widget(GtkWidget* widget) +{ + GtkWidget* frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (frame), widget); + gtk_widget_show(widget); + return frame; +} + +gboolean entry_focus_in(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +{ + gtk_window_remove_accel_group (GTK_WINDOW (g_pParentWnd->m_pWidget), global_accel); + return FALSE; +} + +gboolean entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +{ + gtk_window_add_accel_group (GTK_WINDOW (g_pParentWnd->m_pWidget), global_accel); + return FALSE; +} + +GtkWidget* create_framed_texwnd(TexWnd* texwnd) +{ + GtkWidget* frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + GtkWidget* hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + GtkWidget* w = gtk_vscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0,0,0,1,1,1))); + gtk_widget_show (w); + gtk_box_pack_end (GTK_BOX (hbox), w, FALSE, TRUE, 0); + g_qeglobals_gui.d_texture_scroll = w; + + GtkWidget* texbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (texbox); + gtk_box_pack_start (GTK_BOX (hbox), texbox, TRUE, TRUE, 0); + + w = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (texbox), w, FALSE, FALSE, 0); + texwnd->m_pFilter = w; + g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(entry_focus_in), NULL); + g_signal_connect(G_OBJECT(w), "focus_out_event", G_CALLBACK(entry_focus_out), NULL); + + w = texwnd->GetWidget (); + gtk_box_pack_start (GTK_BOX (texbox), w, TRUE, TRUE, 0); + gtk_widget_show (w); + + return frame; +} + +static ZWnd *create_floating_zwnd(MainFrame *mainframe) +{ + ZWnd *pZWnd = new ZWnd (); + GtkWidget* wnd = create_floating (mainframe); + + gtk_window_set_title (GTK_WINDOW (wnd), "Z"); + + pZWnd->m_pParent = wnd; + + { + GtkWidget* frame = create_framed_widget(pZWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + gtk_widget_realize (wnd); + + // turn OFF minimize and maximize boxes. + // Must be *after* realize, or wnd->window is NULL + // should do the right thing on *nix, need to verify. + gdk_window_set_decorations ( wnd->window, + GdkWMDecoration(GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE ) ); + //TODO 50 by observation, will vary depending on decoration sizes + { + GdkGeometry geometry; + geometry.min_width = 50; + //we only care about width, but have to set this too, or get nasty bugs + geometry.min_height = 10; + gdk_window_set_geometry_hints( wnd->window,&geometry,GDK_HINT_MIN_SIZE); + } + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posZWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posZWnd); + + if (g_PrefsDlg.m_bZVis) + gtk_widget_show (wnd); + + return pZWnd; +} + +static const int gutter = 12; + +void MainFrame::Create () +{ + GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + m_pWidget = window; + gtk_widget_set_events (window, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (mainframe_delete), this); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (mainframe_destroy), this); + gtk_signal_connect (GTK_OBJECT (window), "key_press_event", + GTK_SIGNAL_FUNC (mainframe_keypress), this); + gtk_signal_connect (GTK_OBJECT (window), "key_release_event", + GTK_SIGNAL_FUNC (mainframe_keyrelease), this); + gtk_signal_connect (GTK_OBJECT (window), "map_event", + GTK_SIGNAL_FUNC (mainframe_map), this); + gtk_signal_connect (GTK_OBJECT (window), "unmap_event", + GTK_SIGNAL_FUNC (mainframe_unmap), this); + + g_qeglobals_gui.d_main_window = window; + +#ifdef _WIN32 + // calculate gdk offset + int n_win_monitors = 0; + + monitorInfo_s monitorInfo; + + // detect multiple monitors + EnumDisplayMonitors (NULL, NULL, m_pCountMonitor, reinterpret_cast(&n_win_monitors)); + + monitorInfo.win_monitors = new GdkRectangle [ n_win_monitors ]; + monitorInfo.i_win_mon = 0; + EnumDisplayMonitors (NULL, NULL, m_pEnumMonitor, reinterpret_cast(&monitorInfo)); + + gdk_offset_x = G_MININT; + gdk_offset_y = G_MININT; + + // calculate offset + for( monitorInfo.i_win_mon = 0; monitorInfo.i_win_mon < n_win_monitors; monitorInfo.i_win_mon++ ) { + gdk_offset_x = MAX (gdk_offset_x, -monitorInfo.win_monitors[monitorInfo.i_win_mon].x); + gdk_offset_y = MAX (gdk_offset_y, -monitorInfo.win_monitors[monitorInfo.i_win_mon].y); + } + + Sys_Printf( "GDK's coordinate system is offset by %d over the x-axis and %d over the y-axis from Windows' coordinate system.\n", gdk_offset_x, gdk_offset_y ); + + if( g_PrefsDlg.m_bStartOnPrimMon ) + { + // get gdk monitors + GdkDisplay *display; + GdkScreen *screen; + gint n_gdk_monitors = 0; + gint i_mon; + GdkRectangle rect; + + // detect multiple monitors + display = gdk_display_get_default (); + Sys_Printf( "GDK detects that server %s manages %d screens\n", gdk_display_get_name (display), gdk_display_get_n_screens (display) ); + + screen = gdk_display_get_screen( display, 1 ); + n_gdk_monitors = gdk_screen_get_n_monitors( screen ); + + Sys_Printf( "GDK detects that screen 1 has %d monitors\n", n_gdk_monitors ); + + for( i_mon = 0; i_mon < n_gdk_monitors; i_mon++ ) { + memset( &rect, 0, sizeof(rect) ); + gdk_screen_get_monitor_geometry( screen, i_mon, &rect ); + Sys_Printf( " monitor %d: x: %d y: %d w: %d h: %d\n", i_mon, rect.x, rect.y, rect.width, rect.height ); + + if( i_mon == 0 ) { + memcpy( &primaryMonitorRect, &rect, sizeof(primaryMonitorRect) ); + } + } + + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.position ); + } + else { + primaryMonitorRect.x = primaryMonitorRect.y = 0; + primaryMonitorRect.width = gdk_screen_width (); + primaryMonitorRect.height = gdk_screen_height (); + } + +#endif + + load_window_pos(window, g_PrefsDlg.mWindowInfo.position); + + GtkWidget* vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + create_main_menu (window, vbox); + MRU_Load (); + create_main_toolbar (window, vbox); + create_plugin_toolbar (window,vbox); + + m_nCurrentStyle = g_PrefsDlg.m_nView; + + g_pGroupDlg->Create (); + OnPluginsRefresh(); + + CreateQEChildren(); + + gtk_widget_show (window); + + // not needed on win32, it's in the .rc +#ifndef _WIN32 + { + GdkPixmap *pixmap; + GdkBitmap *mask; + load_pixmap ("icon.bmp", window, &pixmap, &mask); + gdk_window_set_icon (window->window, NULL, pixmap, mask); + } +#endif + + if (CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft) + { + { + GtkWidget* vsplit = gtk_vpaned_new (); + m_pSplits[0] = vsplit; + gtk_box_pack_start (GTK_BOX (vbox), vsplit, TRUE, TRUE, 0); + gtk_widget_show (vsplit); + + { + GtkWidget* hsplit = gtk_hpaned_new (); + m_pSplits[2] = hsplit; + gtk_paned_add1 (GTK_PANED (vsplit), hsplit); + gtk_widget_show (hsplit); + + { + GtkWidget* hsplit2 = gtk_hpaned_new (); + m_pSplits[3] = hsplit2; + gtk_paned_add2 (GTK_PANED (hsplit), hsplit2); + gtk_widget_show (hsplit2); + + { + GtkWidget* vsplit2 = gtk_vpaned_new (); + m_pSplits[1] = vsplit2; + if (CurrentStyle() == eRegular) + gtk_paned_add2 (GTK_PANED (hsplit2), vsplit2); + else + gtk_paned_add1 (GTK_PANED (hsplit), vsplit2); + gtk_widget_show (vsplit2); + + // camera + m_pCamWnd = new CamWnd (); + { + GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (vsplit2), frame); + } + + // xy + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget ()); + gtk_paned_add1 (GTK_PANED (hsplit2), frame); + } + + // z + m_pZWnd = new ZWnd (); + { + GtkWidget* frame = create_framed_widget(m_pZWnd->GetWidget ()); + if (CurrentStyle() == eRegular) + gtk_paned_add1 (GTK_PANED (hsplit), frame); + else + gtk_paned_add2 (GTK_PANED (hsplit2), frame); + } + + // textures + m_pTexWnd = new TexWnd (); + { + GtkWidget* frame = create_framed_texwnd(m_pTexWnd); + gtk_paned_add2 (GTK_PANED (vsplit2), frame); + } + + // console + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + gtk_widget_show (scr); + gtk_paned_pack2 (GTK_PANED (vsplit), scr, FALSE, TRUE); + + { + GtkWidget* text = gtk_text_view_new (); + gtk_widget_set_size_request(text, 0, -1); // allow shrinking + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable (GTK_TEXT_VIEW(text), FALSE); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + g_qeglobals_gui.d_edit = text; + } + } + } + } + } + } + + gtk_paned_set_position (GTK_PANED (m_pSplits[0]), g_PrefsDlg.mWindowInfo.nXYHeight+28); + + if (CurrentStyle() == eRegular) + { + gtk_paned_set_position (GTK_PANED (m_pSplits[2]), g_PrefsDlg.mWindowInfo.nZWidth); + gtk_paned_set_position (GTK_PANED (m_pSplits[3]), g_PrefsDlg.mWindowInfo.nXYWidth); + } + else + { + gtk_paned_set_position (GTK_PANED (m_pSplits[2]), g_PrefsDlg.mWindowInfo.nCamWidth); + while (gtk_events_pending ()) gtk_main_iteration (); + gtk_paned_set_position (GTK_PANED (m_pSplits[3]), g_PrefsDlg.mWindowInfo.nXYWidth); + } + + while (gtk_events_pending ()) gtk_main_iteration (); + + gtk_paned_set_position (GTK_PANED (m_pSplits[1]), g_PrefsDlg.mWindowInfo.nCamHeight); + } + else if (CurrentStyle() == eFloating) + { + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "Camera"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posCamWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posCamWnd); + + gtk_widget_show (wnd); + + m_pCamWnd = new CamWnd (); + + { + GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget ()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + m_pCamWnd->m_pParent = wnd; + } + + if (g_PrefsDlg.m_bFloatingZ) + { + m_pZWnd = create_floating_zwnd(this); + + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "XY View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXYWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXYWnd); + + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + m_pXYWnd->m_pParent = wnd; + + gtk_widget_show (wnd); + } + } + else + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "XY View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXYWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXYWnd); + + m_pZWnd = new ZWnd (); + m_pZWnd->m_pParent = wnd; + + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + m_pXYWnd->m_pParent = wnd; + + + { + GtkWidget* hsplit = gtk_hpaned_new (); + m_pSplits[0] = hsplit; + gtk_container_add (GTK_CONTAINER (wnd), hsplit); + gtk_widget_show (hsplit); + + { + GtkWidget* frame = create_framed_widget(m_pZWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (hsplit), frame); + } + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); + gtk_paned_add2 (GTK_PANED (hsplit), frame); + } + } + + gtk_widget_show (wnd); + + gtk_paned_set_position (GTK_PANED (m_pSplits[0]), g_PrefsDlg.mWindowInfo.nZFloatWidth); + } + + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "XZ View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXZWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXZWnd); + + m_pXZWnd = new XYWnd (); + m_pXZWnd->m_pParent = wnd; + m_pXZWnd->SetViewType(XZ); + + { + GtkWidget* frame = create_framed_widget(m_pXZWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + if (g_PrefsDlg.m_bXZVis) + gtk_widget_show (wnd); + } + + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "YZ View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posYZWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posYZWnd); + + m_pYZWnd = new XYWnd (); + m_pYZWnd->m_pParent = wnd; + m_pYZWnd->SetViewType(YZ); + + { + GtkWidget* frame = create_framed_widget(m_pYZWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + if (g_PrefsDlg.m_bYZVis) + gtk_widget_show (wnd); + } + + m_pTexWnd = new TexWnd (); + { + GtkWidget* frame = create_framed_texwnd(m_pTexWnd); + m_pTexWnd->m_pParent = g_pGroupDlg->m_pWidget; + + { + GtkWidget* w = gtk_label_new ("Textures"); + gtk_widget_show (w); + gtk_notebook_insert_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), frame, w, 1); + } + } + + g_pGroupDlg->Show (); + } + else // 4 way + { + { + GtkWidget* hsplit = gtk_hpaned_new (); + m_pSplits[0] = hsplit; + gtk_box_pack_start (GTK_BOX (vbox), hsplit, TRUE, TRUE, 0); + gtk_widget_show (hsplit); + + { + GtkWidget* vsplit1 = gtk_vpaned_new (); + m_pSplits[1] = vsplit1; + gtk_paned_add1 (GTK_PANED (hsplit), vsplit1); + gtk_widget_show (vsplit1); + + { + GtkWidget* vsplit2 = gtk_vpaned_new (); + m_pSplits[2] = vsplit2; + gtk_paned_add2 (GTK_PANED (hsplit), vsplit2); + gtk_widget_show (vsplit2); + + m_pCamWnd = new CamWnd (); + { + GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (vsplit1), frame); + } + + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (vsplit2), frame); + } + + m_pYZWnd = new XYWnd (); + m_pYZWnd->SetViewType(YZ); + { + GtkWidget* frame = create_framed_widget(m_pYZWnd->GetWidget()); + gtk_paned_add2 (GTK_PANED (vsplit1), frame); + } + + m_pXZWnd = new XYWnd (); + m_pXZWnd->SetViewType(XZ); + { + GtkWidget* frame = create_framed_widget(m_pXZWnd->GetWidget()); + gtk_paned_add2 (GTK_PANED (vsplit2), frame); + } + } + } + } + + // g_qeglobals_gui.d_edit = NULL; + + { + m_pTexWnd = new TexWnd (); + GtkWidget* frame = create_framed_texwnd(m_pTexWnd); + + { + GtkWidget* w = gtk_label_new ("Textures"); + gtk_widget_show (w); + gtk_notebook_insert_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), frame, w, 1); + } + } + + m_pTexWnd->m_pParent = g_pGroupDlg->m_pWidget; +// gtk_widget_realize (m_pTexWnd->GetWidget ()); + m_pZWnd = create_floating_zwnd(this); + + while (gtk_events_pending ()) + gtk_main_iteration (); + + { + int x = GTK_PANED (m_pSplits[0])->max_position/2 - gutter; + gtk_paned_set_position (GTK_PANED (m_pSplits[0]), x); + } + + { + int y = GTK_PANED (m_pSplits[1])->max_position/2 - gutter; + gtk_paned_set_position (GTK_PANED (m_pSplits[1]), y); + gtk_paned_set_position (GTK_PANED (m_pSplits[2]), y); + } + } + + if(g_PrefsDlg.mWindowInfo.nState & GDK_WINDOW_STATE_MAXIMIZED) + gtk_window_maximize(GTK_WINDOW(window)); + + gtk_widget_show (window); + + Texture_Init(); + + if (m_pXYWnd) // this is always true? + { + m_pXYWnd->SetActive(true); + } + m_bSplittersOK = true; + Texture_SetMode(g_qeglobals.d_savedinfo.iTexMenu); + + g_pParentWnd->OnEntitiesSetViewAs(0); + +// m_wndTextureBar.Create (vbox); + create_main_statusbar (window, vbox); + + LoadCommandMap(); + ShowMenuItemKeyBindings(window); + + if (g_qeglobals_gui.d_edit != NULL) + console_construct(g_qeglobals_gui.d_edit); + + // bool load_last = FALSE; + + SetGridStatus(); + SetButtonMenuStates(); + + // m_bShowShader and m_bTextureShaderlistOnly have a menu checkbox, update it now + GtkWidget *item; + g_bIgnoreCommands++; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaders_show")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaderlistonly")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE); + g_bIgnoreCommands--; + +// if (g_PrefsDlg.m_bTextureBar) +// gtk_widget_show (m_wndTextureBar.m_pWidget); + + SetActiveXY(m_pXYWnd); + + s_idle_id = gtk_timeout_add (25, mainframe_idle, this); + + QGL_InitExtensions (); + + if (g_PrefsDlg.mLocalPrefs.mbEmpty) + { + g_PrefsDlg.mLocalPrefs.mbEmpty = false; + g_PrefsDlg.SavePrefs(); + } + + // remove the pid file + remove (g_pidGameFile.GetBuffer ()); + + Sys_Printf ("Entering message loop\n"); + + m_bDoLoop = true; + + m_nTimer = gtk_timeout_add (1000, timer, this); +} + +// ============================================================================= +// MainFrame class + +MainFrame::MainFrame() +{ + m_bDoLoop = false; + m_bSplittersOK = false; + g_pParentWnd = this; + m_pXYWnd = (XYWnd*)NULL; + m_pCamWnd = NULL; + m_pTexWnd = (TexWnd*)NULL; + m_pZWnd = (ZWnd*)NULL; + m_pYZWnd = (XYWnd*)NULL; + m_pXZWnd = (XYWnd*)NULL; + m_pActiveXY = (XYWnd*)NULL; + m_bCamPreview = true; + m_pWatchBSP = NULL; + for (int n = 0; n < 6; n++) + m_pStatusLabel[n] = NULL; + m_bNeedStatusUpdate = false; + m_nTimer = 0; + m_bSleeping = false; + Create (); +} + +MainFrame::~MainFrame() +{ + while (g_BSPFrontendCommands) + { + free (g_BSPFrontendCommands->data); + g_BSPFrontendCommands = g_slist_remove (g_BSPFrontendCommands, g_BSPFrontendCommands->data); + } +} + +void MainFrame::ReleaseContexts () +{ + if (m_pXYWnd) + m_pXYWnd->DestroyContext (); + if (m_pYZWnd) + m_pYZWnd->DestroyContext (); + if (m_pXZWnd) + m_pXZWnd->DestroyContext (); + if (m_pCamWnd) + m_pCamWnd->DestroyContext (); + if (m_pTexWnd) + m_pTexWnd->DestroyContext (); + if (m_pZWnd) + m_pZWnd->DestroyContext (); +} + +void MainFrame::CreateContexts () +{ + if (m_pCamWnd) + m_pCamWnd->CreateContext (); + if (m_pXYWnd) + m_pXYWnd->CreateContext (); + if (m_pYZWnd) + m_pYZWnd->CreateContext (); + if (m_pXZWnd) + m_pXZWnd->CreateContext (); + if (m_pTexWnd) + m_pTexWnd->CreateContext (); + if (m_pZWnd) + m_pZWnd->CreateContext (); +} + +static void Sys_Iconify (GtkWidget *w) +{ + // we might not have been realized yet + if (w->window == NULL) + return; + + if (!GTK_WIDGET_MAPPED (w)) + return; + +#if defined (__linux__) || defined (__APPLE__) + Sys_FPrintf(SYS_WRN, "FIXME: Sys_Iconify\n"); +#if 0 + XWindowAttributes xattr; + GdkWindowPrivate *Private; + + Private = (GdkWindowPrivate*)w->window; + g_object_set_data (G_OBJECT (w), "was_mapped", GINT_TO_POINTER (0)); + + if (!Private->destroyed) + { + xattr.map_state = IsUnmapped; + XGetWindowAttributes(Private->xdisplay, Private->xwindow, &xattr); + + if (xattr.map_state != IsUnmapped) + g_object_set_data (G_OBJECT (w), "was_mapped", GINT_TO_POINTER (1)); + + XIconifyWindow (Private->xdisplay, Private->xwindow, 0); + } +#endif +#endif + +#ifdef _WIN32 + ShowWindow ((HWND)GDK_WINDOW_HWND (w->window), SW_MINIMIZE); +#endif +} + +static void Sys_Restore (GtkWidget *w) +{ + // we might not have been realized yet + if (w->window == NULL) + return; + + if (!GTK_WIDGET_VISIBLE (w)) + return; + +#if defined (__linux__) || defined (__APPLE__) + Sys_FPrintf(SYS_WRN, "FIXME: Sys_Restore\n"); + #if 0 + XWindowAttributes xattr; + GdkWindowPrivate *Private; + + Private = (GdkWindowPrivate*)w->window; + + xattr.map_state = IsUnmapped; + XGetWindowAttributes(Private->xdisplay, Private->xwindow, &xattr); + + if (xattr.map_state == IsUnmapped) + XMapRaised (Private->xdisplay, Private->xwindow); + #endif +#endif + +#ifdef _WIN32 + ShowWindow ((HWND)GDK_WINDOW_HWND (w->window), SW_RESTORE); +#endif +} + +#ifdef _DEBUG +//#define DBG_SLEEP +#endif + +void RefreshModelSkin (GSList **pModels, entitymodel_t *model) +{ + //++timo FIXME: the are some bogus entitymodel_t that appear in the list cause of buggy HasModel + // so we avoid the fucked up ones, assuming they are at the end + if (!model->strSkin) + { +#ifdef DBG_SLEEP + Sys_Printf("Dropping model %p with empty skin in RefreshModelSkin\n", model); +#endif + + // and also keeping it so we have an actual count of empty models + g_slist_append (*pModels, model); + return; + } + // do we have this model already? + if (g_slist_find (*pModels, model)) + { +#ifdef DBG_SLEEP + + // looks like we don't have the filename for the model, only the skin name and tris.. so we put the adress + Sys_Printf("Already processed model: %p %s\n", model, ((GString *)model->strSkin)->str); +#endif + return; + } + model->nTextureBind = Texture_LoadSkin(((GString *)model->strSkin)->str, &model->nSkinWidth, &model->nSkinHeight ); + if (model->nTextureBind != -1) + Sys_Printf("LOADED SKIN: %s\n", ((GString *)model->strSkin)->str ); + else + Sys_Printf("Load skin failed: %s\n", ((GString *)model->strSkin)->str ); + *pModels = g_slist_append (*pModels, model); +#ifdef DBG_SLEEP + Sys_Printf("Processed model %p %s\n", model, ((GString *)model->strSkin)->str); +#endif +} + +void MainFrame::OnSleep() +{ + m_bSleeping ^= 1; + if (m_bSleeping) + { + // useful when trying to debug crashes in the sleep code + Sys_Printf("Going into sleep mode..\n"); + + Sys_Printf("Dispatching sleep msg..."); + DispatchRadiantMsg (RADIANT_SLEEP); + Sys_Printf("Done.\n"); + + if (CurrentStyle() == eSplit) + Sys_Iconify (m_pZWnd->m_pParent); + + Sys_Iconify (m_pWidget); + Select_Deselect(); + QERApp_FreeShaders (); + g_bScreenUpdates = false; + + // release contexts + Sys_Printf("Releasing contexts..."); + ReleaseContexts(); + Sys_Printf("Done.\n"); + + // free all the skins in the caches + // their GL resources have been freed but the structs are not, so Radiant would think they are still valid + g_lstSkinCache.RemoveAll(); + } else + { + Sys_Printf("Waking up\n"); + if (CurrentStyle() == eSplit) + Sys_Restore (m_pZWnd->m_pParent); + + Sys_Restore (m_pWidget); + + // create contexts + Sys_Printf("Creating contexts..."); + CreateContexts(); + Sys_Printf("Done.\n"); + + Sys_Printf("Making current on camera..."); + m_pCamWnd->MakeCurrent (); + Sys_Printf("Done.\n"); + + Sys_Printf("Reloading shaders..."); + // reload the shader scripts and textures + QERApp_ReloadShaders (); + // current shader + // NOTE: we are kinda making it loop on itself, it will update the pShader and scroll the texture window + Texture_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, NULL, false); + Sys_Printf("Done.\n"); + + // rebuild the patches by setting the bDirty flag on them + for (brush_t* b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (b->patchBrush) + b->pPatch->bDirty = true; + } + + Sys_Printf("Reloading skins..."); + // we have purged all the skins before going to sleep + // to rebuild, go through everything that needs a skin and call Texture_LoadSkin + // namely, all entitymodel_t + // since there's no direct list we go through entities to get the eclass_t and from there the entitymodel_t + // (a single eclass_t can reference several entitymodel_t) + // FIXME: and what's up with md3Class then? what is it used for? +/* + eclass_t *e; + entity_t *ent; + GSList *Models = NULL; + for (ent = entities.next; ent != &entities; ent = ent->next) + { + // if it's a model with skin then the fixedsize flag must be on + // only if there IS a model .. we are not trying to load + if (ent->eclass->fixedsize) + { + if (ent->eclass->model) + { +#ifdef DBG_SLEEP + if (ent->md3Class) + Sys_Printf("WARNING: unexpected ent->md3Class!=NULL with ent->eclass->model!=NULL\n"); +#endif + entitymodel_t *model; + for (model = ent->eclass->model; model; model=model->pNext) + RefreshModelSkin (&Models, model); + } else if (ent->md3Class) + { + entitymodel_t *model; + for (model = ent->md3Class->model; model; model=model->pNext) + RefreshModelSkin (&Models, model); + } +#ifdef DBG_SLEEP + else + Sys_Printf("WARNING: entity %p %s with fixedsize and no model no md3Class\n", ent, ent->eclass->name); +#endif + } + } +#ifdef DBG_SLEEP + for (e = g_md3Cache; e ; e = e->next) + { + entitymodel_t *model; + for (model = e->model; model; model=model->pNext) + if (!g_slist_find (Models, model)) + { + Sys_Printf("model %p ", model); + if (model->strSkin) + Sys_Printf("%s not found in main loop\n", ((GString *)model->strSkin)->str); + else + Sys_Printf("not found in main loop (no skin)\n"); + } + } +#endif + // clean the model list + g_slist_free (Models); +*/ + Sys_Printf("Done.\n"); + + // bring back the GL font + gtk_glwidget_create_font (m_pCamWnd->GetWidget ()); + + g_bScreenUpdates = true; + + Sys_Printf("Dispatching wake msg..."); + DispatchRadiantMsg (RADIANT_WAKEUP); + Sys_Printf("Done\n"); + } +} + +void WINAPI QERApp_Sleep() +{ + g_pParentWnd->OnSleep(); +} + +/*! +NOTE TTimo +the exit path is a bit complicated, I guess we have to run the window pos saving in OnDelete +and not in OnDestroy because the info may be lost already? +\todo try sinking OnDelete into OnDestroy and see if it breaks anything +*/ +void MainFrame::OnDelete () +{ + save_window_pos(m_pWidget, g_PrefsDlg.mWindowInfo.position); + + // surface inspector and patch inspector + save_window_pos (g_dlgSurface.GetWidget(), g_PrefsDlg.mWindowInfo.posSurfaceWnd); + save_window_pos (g_PatchDialog.GetWidget(), g_PrefsDlg.mWindowInfo.posPatchWnd); + + // entity inspector / group dialog + // NOTE TTimo do we have to save a different window depending on the view mode? + save_window_pos (g_pGroupDlg->m_pWidget, g_PrefsDlg.mWindowInfo.posEntityWnd); + + if (g_PrefsDlg.m_bFloatingZ) + save_window_pos (m_pZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posZWnd); + else + g_PrefsDlg.mWindowInfo.nZFloatWidth = GTK_PANED (m_pSplits[0])->child1_size; + + if (CurrentStyle() == eFloating) + { + save_window_pos (m_pCamWnd->m_pParent, g_PrefsDlg.mWindowInfo.posCamWnd); + save_window_pos (m_pXYWnd->m_pParent, g_PrefsDlg.mWindowInfo.posXYWnd); + save_window_pos (m_pXZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posXZWnd); + save_window_pos (m_pYZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posYZWnd); + } + + g_PrefsDlg.mWindowInfo.nState = gdk_window_get_state(g_pParentWnd->m_pWidget->window); +} + +void MainFrame::OnDestroy () +{ + // shut down console output first + // (we'll still get the info if we are running a log file anyway) + g_qeglobals_gui.d_edit = NULL; + +#ifdef _DEBUG + Sys_Printf("MainFrame::OnDestroy\n"); +#endif + if (s_idle_id) + gtk_timeout_remove (s_idle_id); + if (m_nTimer) + gtk_timeout_remove (m_nTimer); + + if (!g_qeglobals.disable_ini) + { + Sys_Printf("Start writing prefs\n"); + Sys_Printf("MRU_Save... "); + MRU_Save (); + Sys_Printf("OK\n"); + + gpointer w; + + w = g_object_get_data (G_OBJECT (g_pGroupDlg->m_pWidget), "split1"); + g_PrefsDlg.mWindowInfo.nEntitySplit1 = GTK_PANED (w)->child1_size; + w = g_object_get_data (G_OBJECT (g_pGroupDlg->m_pWidget), "split2"); + g_PrefsDlg.mWindowInfo.nEntitySplit2 = GTK_PANED (w)->child1_size; + + if (!FloatingGroupDialog()) + { + GtkWidget *vsplit, *hsplit, *vsplit2, *hsplit2; + + vsplit = m_pSplits[0]; + vsplit2 = m_pSplits[1]; + hsplit = m_pSplits[2]; + hsplit2 = m_pSplits[3]; + + g_PrefsDlg.mWindowInfo.nXYHeight = GTK_PANED (vsplit)->child1_size; + g_PrefsDlg.mWindowInfo.nXYWidth = GTK_PANED (hsplit2)->child1_size; + + if(CurrentStyle() == eRegular) + g_PrefsDlg.mWindowInfo.nZWidth = GTK_PANED (hsplit)->child1_size; + else + g_PrefsDlg.mWindowInfo.nCamWidth = GTK_PANED (hsplit)->child1_size; + + g_PrefsDlg.mWindowInfo.nCamHeight = GTK_PANED (vsplit2)->child1_size; + } else + { + if (g_PrefsDlg.m_bFloatingZ || CurrentStyle() == eSplit) + { + if (GTK_WIDGET_VISIBLE (m_pZWnd->m_pParent)) + g_PrefsDlg.m_bZVis = TRUE; + else + g_PrefsDlg.m_bZVis = FALSE; + } + } + g_PrefsDlg.SavePrefs(); + Sys_Printf("Done prefs\n"); + } + + // spog - this may be better in another place.. + // deletes filters list and assigns g_qeglobals.d_savedinfo.filters = NULL + g_qeglobals.d_savedinfo.filters = FilterListDelete(g_qeglobals.d_savedinfo.filters); + + delete m_pXYWnd; m_pXYWnd = NULL; + delete m_pYZWnd; m_pYZWnd = NULL; + delete m_pXZWnd; m_pXZWnd = NULL; + delete m_pZWnd; m_pZWnd = NULL; + delete m_pTexWnd; m_pTexWnd = NULL; + delete m_pCamWnd; m_pCamWnd = NULL; + + if (g_pGroupDlg->m_pWidget) + { + //!\todo fix "Gtk-CRITICAL **: file gtknotebook.c: line 4643 (gtk_notebook_get_tab_label): assertion `GTK_IS_WIDGET (child)' failed" + gtk_widget_destroy (g_pGroupDlg->m_pWidget); + g_pGroupDlg->m_pWidget = NULL; + } + + if (strcmpi(currentmap, "unnamed.map") != 0) + { + g_PrefsDlg.m_strLastMap = currentmap; + g_PrefsDlg.SavePrefs (); + } + Sys_Printf("CleanUpEntities..."); + CleanUpEntities(); + Sys_Printf("Done.\n"); + + Sys_Printf("Releasing brushes..."); + while (active_brushes.next != &active_brushes) + Brush_Free (active_brushes.next, false); + while (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next, false); + while (filtered_brushes.next != &filtered_brushes) + Brush_Free (filtered_brushes.next, false); + Sys_Printf("Done.\n"); + + Sys_Printf("Releasing entities..."); + while (entities.next != &entities) + Entity_Free (entities.next); + Sys_Printf("Done.\n"); + + epair_t* pEPair = g_qeglobals.d_project_entity->epairs; + while (pEPair) + { + epair_t* pNextEPair = pEPair->next; + free (pEPair->key); + free (pEPair->value); + free (pEPair); + pEPair = pNextEPair; + } + + entity_t* pEntity = g_qeglobals.d_project_entity->next; + while (pEntity != NULL && pEntity != g_qeglobals.d_project_entity) + { + entity_t* pNextEntity = pEntity->next; + Entity_Free(pEntity); + pEntity = pNextEntity; + } + + Sys_Printf("Freeing world entity..."); + if (world_entity) + Entity_Free(world_entity); + Sys_Printf("Done.\n"); + + Sys_Printf("Shutdown VFS..."); + vfsShutdown (); + Sys_Printf("Done.\n"); + + Sys_Printf("FreeShaders..."); + QERApp_FreeShaders(); + Sys_Printf("Done.\n"); +} + +// TTimo: now using profile.cpp code +void MainFrame::LoadCommandMap() +{ + FILE *f; + CString strINI; + bool bUserCmdList = false; + int nLen; + // verbose a little: count of user commands we recognized + int iCount = 0; + int iOverrideCount = 0; + int j; + + +#if defined (__linux__) || defined (__APPLE__) + strINI = g_PrefsDlg.m_rc_path->str; +#elif defined(WIN32) + strINI = g_strGameToolsPath; +#else +#error "WTF are you compiling this on" +#endif + AddSlash (strINI); + strINI += "shortcuts.ini"; + + f = fopen (strINI.GetBuffer(), "r"); + if (f != NULL) + { + fclose(f); + // loop through all the commands + for (int i = 0; i < g_nCommandCount; i++) + { + char value[1024]; + if (read_var( strINI.GetBuffer(), "Commands", g_Commands[i].m_strCommand, value )) + { + if (!bUserCmdList) + { + Sys_Printf("Found user's shortcuts list at %s\n", strINI.GetBuffer() ); + bUserCmdList = true; + } + CString strBuff; + strBuff = value; + strBuff.TrimLeft(); + strBuff.TrimRight(); + strBuff.MakeLower(); + int nSpecial = strBuff.Find("+alt"); + g_Commands[i].m_nModifiers = 0; + if (nSpecial >= 0) + { + g_Commands[i].m_nModifiers |= RAD_ALT; + FindReplace(strBuff, "+alt", ""); + } + nSpecial = strBuff.Find("+ctrl"); + if (nSpecial >= 0) + { + g_Commands[i].m_nModifiers |= RAD_CONTROL; + FindReplace(strBuff, "+ctrl", ""); + } + nSpecial = strBuff.Find("+shift"); + if (nSpecial >= 0) + { + g_Commands[i].m_nModifiers |= RAD_SHIFT; + FindReplace(strBuff, "+shift", ""); + } + strBuff.TrimLeft(); + strBuff.TrimRight(); + strBuff.MakeUpper(); + // strBuff has been cleaned of it's modifiers .. switch between a regular key and a virtual one + // based on length + nLen = strBuff.GetLength(); + if (nLen == 1) // most often case.. deal with first + { + g_Commands[i].m_nKey = __toascii(strBuff.GetAt(0)); + iCount++; + } else // special key + { + for (j = 0; j < g_nKeyCount; j++) + { + if (strBuff.CompareNoCase(g_Keys[j].m_strName) == 0) + { + g_Commands[i].m_nKey = g_Keys[j].m_nVKKey; + iCount++; + break; + } + } + if (j == g_nKeyCount) + { + Sys_Printf("WARNING: failed to parse user command %s\n", value); + continue; + } + } + // maybe this new shortcut is overriding another one + // then we need to disable the other binded key + for (j = 0; j < g_nCommandCount; j++) + { + if (j == i) + continue; + if (g_Commands[i].m_nKey == g_Commands[j].m_nKey && g_Commands[i].m_nModifiers == g_Commands[j].m_nModifiers) + { + // found! + g_Commands[j].m_nKey = 0; + // verbose + iOverrideCount++; + // it's the only one + break; + } + } + } + } + if (iOverrideCount) + Sys_Printf("User's command list overrides %d default commands\n", iOverrideCount); + Sys_Printf("Parsed %d custom shortcuts\n", iCount ); + } + else + Sys_Printf("Looked for a '%s' keyboard shortcuts file, not found\n", strINI.GetBuffer()); +} + +// TTimo: an m_nKey can be set to zero if there's no shorcut binded +// we also output the count of commands that are not binded .. dunno if it's much use .. +// (non-binded keys are usually keys that were defined by shortcuts overriden by user prefs) +void MainFrame::ShowMenuItemKeyBindings(GtkWidget* window) +{ + //!\todo Find a better way to get the global accelerator group.. + GtkAccelGroup *accel = GTK_ACCEL_GROUP(gtk_accel_groups_from_object(G_OBJECT(window))->data); + gpointer item; + guint mods; + int i; + int iCount = 0; + + for (i = 0; i < g_nCommandCount; i++) + { + if (g_Commands[i].m_nKey == 0) + { + iCount++; + continue; + } + + item = g_object_get_data (G_OBJECT (m_pWidget), g_Commands[i].m_strMenu); + if (item == NULL) + { + Sys_FPrintf (SYS_WRN, "WARNING: keyboard shortcuts init, no menu item found for command: \"%s\"\n", + g_Commands[i].m_strCommand); + continue; + } + + mods = 0; + if (g_Commands[i].m_nModifiers) // are there modifiers present? + { + if (g_Commands[i].m_nModifiers & RAD_SHIFT) + mods |= GDK_SHIFT_MASK; + if (g_Commands[i].m_nModifiers & RAD_ALT) + mods |= GDK_MOD1_MASK; + if (g_Commands[i].m_nModifiers & RAD_CONTROL) + mods |= GDK_CONTROL_MASK; + } + + // GTK won't add accelerators for some keys (ex.: delete), so we have to do it manually + if (gtk_accelerator_valid (g_Commands[i].m_nKey, (GdkModifierType)mods)) + { +#ifdef DBG_KBD + // NOTE TTimo this is the important place where all the shortcuts are binded + Sys_Printf("Calling gtk_widget_add_accelerator on command: %s menu: %s key: %d mods: %d\n", g_Commands[i].m_strCommand, g_Commands[i].m_strMenu, g_Commands[i].m_nKey, mods); +#endif + gtk_widget_add_accelerator (GTK_WIDGET (item), "activate", accel, g_Commands[i].m_nKey, + (GdkModifierType)mods, GTK_ACCEL_VISIBLE); + } else + { + GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (GTK_BIN (item)->child); + GString *gstring; + gboolean had_mod; + + g_free (accel_label->accel_string); + accel_label->accel_string = NULL; + + gstring = g_string_new (accel_label->accel_string); + g_string_append (gstring, " "); + + had_mod = FALSE; + if (mods & GDK_SHIFT_MASK) + { + g_string_append (gstring, "Shft"); + had_mod = TRUE; + } + if (mods & GDK_CONTROL_MASK) + { + if (had_mod) + g_string_append (gstring, "+"); + g_string_append (gstring, "Ctl"); + had_mod = TRUE; + } + if (mods & GDK_MOD1_MASK) + { + if (had_mod) + g_string_append (gstring, "+"); + g_string_append (gstring, "Alt"); + had_mod = TRUE; + } + + if (had_mod) + g_string_append (gstring, "+"); + if (g_Commands[i].m_nKey < 0x80 || (g_Commands[i].m_nKey > 0x80 && g_Commands[i].m_nKey <= 0xff)) + { + switch (g_Commands[i].m_nKey) + { + case ' ': + g_string_append (gstring, "Space"); + break; + case '\\': + g_string_append (gstring, "Backslash"); + break; + default: + g_string_append_c (gstring, toupper (g_Commands[i].m_nKey)); + break; + } + } else + { + gchar *tmp; + + tmp = gtk_accelerator_name (g_Commands[i].m_nKey, (GdkModifierType)0); + if (tmp[0] != 0 && tmp[1] == 0) + tmp[0] = toupper (tmp[0]); + g_string_append (gstring, tmp); + g_free (tmp); + } + + g_free (accel_label->accel_string); + accel_label->accel_string = gstring->str; + g_string_free (gstring, FALSE); + + if (!accel_label->accel_string) + accel_label->accel_string = g_strdup (""); + + gtk_widget_queue_resize (GTK_WIDGET (accel_label)); + } + } + + if (iCount) + Sys_Printf("%d commands not bound to a key\n", iCount); +} + +void MainFrame::CreateQEChildren() +{ + // load the project file + if (g_argc > 1) + { + Sys_Printf("loading project file from the command line: %s\n", g_argv[1]); + if (!QE_LoadProject(g_argv[1])) + Error("Unable to load project file %s\n", g_argv[1]); + } + else + { + const char* filename = NULL; + char buf[PATH_MAX]; + const char *r; + bool bTriedTemplate = false; + + if (g_PrefsDlg.m_nLastProjectVer != 0 && g_PrefsDlg.m_nLastProjectVer != PROJECT_VERSION) { + // we need to regenerate from template + Sys_Printf("last project has version %d, this binary wants version %d - regenerating from the template\n", g_PrefsDlg.m_nLastProjectVer, PROJECT_VERSION); + g_PrefsDlg.m_strLastProject = ""; + } + + r = g_PrefsDlg.m_strLastProject.GetBuffer(); + + while(r == NULL || *r == '\0' || access(r, R_OK) != 0 || !QE_LoadProject(r)) + { + if(!bTriedTemplate) + { + // try default project location + bTriedTemplate = true; + // for all OSes, we look for the template in the base installation (no homepath here) + strcpy(buf, g_pGameDescription->mEnginePath.GetBuffer()); + strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); + strcat(buf, "/scripts/"); + strcat(buf, PROJECT_TEMPLATE_NAME); + r = buf; + } + else + { + gtk_MessageBox (NULL, "Failed to load project file.\nPlease enter a valid project file.", "Load Project"); + + filename = file_dialog (m_pWidget, TRUE, "Choose Project File", buf, "project"); + if (filename != NULL) + r = filename; + else + Error("Cannot continue without loading a project..."); + } + } + } + + QE_Init (); +} + +void MainFrame::OnTimer() +{ + GdkModifierType mask; + + gdk_window_get_pointer (NULL, NULL, NULL, &mask); + + if ((mask & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK)) == 0) + { + QE_CountBrushesAndUpdateStatusBar(); + QE_CheckAutoSave(); + } + + // see MainFrame::UpdateStatusText below + if (m_bNeedStatusUpdate) + { + for (int n = 0; n < 6; n++) + { + if (m_strStatus[n].GetLength() >= 0 && m_pStatusLabel[n] != NULL) + gtk_label_set_text (GTK_LABEL (m_pStatusLabel[n]), m_strStatus[n]); + } + m_bNeedStatusUpdate = false; + } +} + +void MainFrame::UpdateStatusText() +{ + m_bNeedStatusUpdate = true; +} + +void MainFrame::SetStatusText(int nPane, const char* pText) +{ + if (pText && nPane <= 5 && nPane >= 0) + { + m_strStatus[nPane] = pText; + UpdateStatusText(); + } +} +void MainFrame::SetButtonMenuStates() +{ + GtkWidget *item; + g_bIgnoreCommands++; + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showangles")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_angles); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_shownames")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_names); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showcoordinates")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_coordinates); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showoutline")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_outline); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showaxes")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_axis); + //item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showpath")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) ? FALSE : TRUE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLUSTERPORTALS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTGRID) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_world")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_entities")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_areaportals")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_AREAPORTALS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_translucent")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRANSLUCENT) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_liquids")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIQUIDS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_caulk")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clips")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_botclips")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_structural")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_paths")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLUSTERPORTALS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTGRID) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lights")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_patches")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_details")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_hintsskips")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_HINTSSKIPS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_models")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_MODELS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_triggers")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRIGGERS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_lock")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bTextureLock) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_rotatelock")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bRotateLock) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cubicclipping")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bGLLighting) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE); + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectmodel")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectModels) ? FALSE : TRUE); + + if (!g_pGameDescription->mNoPatch) + { + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectcurve")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectCurves) ? FALSE : TRUE); + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_showboundingbox")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchShowBounds) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_weld")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWeld) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_drilldown")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchDrillDown) ? TRUE : FALSE); + } + + int id, n = g_PrefsDlg.m_nTextureScale; + switch (n) + { + case 10 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_10; break; + case 25 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_25; break; + case 50 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_50; break; + case 200 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_200; break; + default : id = ID_TEXTURES_TEXTUREWINDOWSCALE_100; break; + } + SetTextureScale (id); + + // FIXME TTimo cleaned up .. the right place to do this in QE_LoadProject? +/* + if (g_qeglobals.d_project_entity) + { + FillTextureMenu(); // redundant but i'll clean it up later.. yeah right.. + FillBSPMenu(); + } + */ + g_bIgnoreCommands--; +} + +void MainFrame::UpdateWindows(int nBits) +{ + if (!g_bScreenUpdates) + return; +#ifdef DBG_WINDOWPOS + static int bean_count = 0; + char bean_buf[100]; + sprintf(bean_buf,"UpdateWindows %d",bean_count); + CheckWatchit(bean_buf); + bean_count++; +#endif + + if (nBits & (W_XY | W_XY_OVERLAY)) + { + if (m_pXYWnd) + m_pXYWnd->RedrawWindow (); + if (m_pXZWnd) + m_pXZWnd->RedrawWindow (); + if (m_pYZWnd) + m_pYZWnd->RedrawWindow (); + } + + if (nBits & W_CAMERA || ((nBits & W_CAMERA_IFON) && m_bCamPreview)) + { + if (m_pCamWnd) + m_pCamWnd->RedrawWindow (); + } + + if (nBits & (W_Z | W_Z_OVERLAY)) + { + if (m_pZWnd) + m_pZWnd->RedrawWindow (); + } + + if (nBits & W_TEXTURE) + { + if (m_pTexWnd) + m_pTexWnd->RedrawWindow (); + } +#ifdef DBG_WINDOWPOS + sprintf(bean_buf,"%d (end UpdateWidows)",bean_count); + CheckWatchit(bean_buf); +#endif +} + +void MainFrame::RoutineProcessing() +{ +#ifdef DBG_WINDOWPOS + static int bean_count = 0; + char bean_buf[100]; + sprintf(bean_buf,"RoutineProcessing %d",bean_count); + CheckWatchit(bean_buf); + bean_count++; +#endif + + if (m_bDoLoop) + { + double time = 0.0; + double oldtime = 0.0; + double delta= 0.0; + +/* // checking KeyState works right + static short a1,a2; + a2 = GetKeyState(VK_MENU); + if (a1!=a2) + { + Sys_Printf("VK_MENU: %d\n",a2); + a1 = a2; + } + static short b1,b2; + b2 = GetKeyState(VK_UP); + if (b1!=b2) + { + Sys_Printf("VK_UP: %d\n",b2); + b1 = b2; + } */ + + time = Sys_DoubleTime (); + delta = time - oldtime; + oldtime = time; + if (delta > 0.2) + delta = 0.2; + + // update the BSP process watcher + if (m_pWatchBSP) + m_pWatchBSP->RoutineProcessing(); + + // run time dependant behavior + if (m_pCamWnd) + m_pCamWnd->Cam_MouseControl(delta); + + if (g_nUpdateBits) + { + int nBits = g_nUpdateBits; // this is done to keep this routine from being + g_nUpdateBits = 0; // re-entered due to the paint process.. only + UpdateWindows(nBits); // happens in rare cases but causes a stack overflow + } +/* + // Enable/disable the menu items + GtkWidget *item; + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cameraupdate")); + gtk_widget_set_sensitive (item, (m_bCamPreview == false)); + if (!g_PrefsDlg.m_bWideToolbar) + { + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cameraupdate")); + gtk_widget_set_sensitive (item, (m_bCamPreview == false)); + } + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_edit_undo")); + gtk_widget_set_sensitive (item, Undo_UndoAvailable()); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_edit_redo")); + gtk_widget_set_sensitive (item, Undo_RedoAvailable()); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_file_saveregion")); + gtk_widget_set_sensitive (item, region_active); + g_bIgnoreCommands++; + // update the toolbar before displaying the menu: + // show in use check box + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_showinuse")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), !g_bShowAllShaders); + // show all check box + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_showall")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_bShowAllShaders); + g_bIgnoreCommands--; + */ + } +#ifdef DBG_WINDOWPOS + sprintf(bean_buf,"%d (end RoutineProcessing)",bean_count); + CheckWatchit(bean_buf); +#endif +} + +void MainFrame::DoWatchBSP() +{ + // network monitoring of the BSP process + if (!m_pWatchBSP) + m_pWatchBSP = new CWatchBSP(); +} + +void MainFrame::CleanPlugInMenu() +{ + GtkWidget *menu, *sep; + GList *lst; + + // delete everything after the separator + menu = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin")); + sep = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin_separator")); + m_nNextPlugInID = ID_PLUGIN_START; + + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + while (lst->next) + { + gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->next->data)); + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + } +} + +void MainFrame::AddPlugInMenuItem(IPlugIn* pPlugIn) +{ + GtkWidget *menu, *item, *parent; + const char *menuText; + + parent = gtk_menu_item_new_with_label (pPlugIn->getMenuName()); + gtk_widget_show (parent); + gtk_container_add (GTK_CONTAINER (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin")), parent); + + int nCount = pPlugIn->getCommandCount(); + if (nCount > 0) + { + menu = gtk_menu_new (); + while (nCount > 0) + { + menuText = pPlugIn->getCommand(--nCount); + if (menuText != NULL && strlen(menuText) > 0) + { + if (!strcmp(menuText, "-")) + { + item = gtk_menu_item_new (); + gtk_widget_set_sensitive (item, FALSE); + } else + { + item = gtk_menu_item_new_with_label (menuText); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (m_nNextPlugInID)); + } + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + pPlugIn->addMenuID(m_nNextPlugInID++); + } + } + gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), menu); + } +} + +void MainFrame::OnPlugIn(unsigned int nID, char* str) +{ + m_PlugInMgr.Dispatch(nID, str); +} + +inline GtkToolbarChildType gtktoolbarchildtype_for_toolbarbuttontype(IToolbarButton::EType type) +{ + switch(type) + { + case IToolbarButton::eSpace: + return GTK_TOOLBAR_CHILD_SPACE; + case IToolbarButton::eButton: + return GTK_TOOLBAR_CHILD_BUTTON; + case IToolbarButton::eToggleButton: + return GTK_TOOLBAR_CHILD_TOGGLEBUTTON; + case IToolbarButton::eRadioButton: + return GTK_TOOLBAR_CHILD_RADIOBUTTON; + } + Error("invalid toolbar button type"); + return (GtkToolbarChildType)0; +} + +void toolbar_insert(GtkWidget *toolbar, const char* image, const char* text, const char* tooltip, IToolbarButton::EType type, GtkSignalFunc handler, gpointer data) +{ + GtkWidget *w, *pixmap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + + load_plugin_bitmap(image, (void **)&gdkpixmap, (void **)&mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_pixmap_unref (mask); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), gtktoolbarchildtype_for_toolbarbuttontype(type), NULL, text, tooltip, "", GTK_WIDGET (pixmap), handler, data); +} + +void SignalToolbarButton(GtkWidget *widget, gpointer data) +{ + const_cast(reinterpret_cast(data))->activate(); +} + +void MainFrame::AddPlugInToolbarButton(const IToolbarButton* button) +{ + GtkWidget*const toolbar = GTK_WIDGET(g_object_get_data (G_OBJECT (m_pWidget), "toolbar_plugin")); + toolbar_insert(toolbar, button->getImage(), button->getText(), button->getTooltip(), button->getType(), GTK_SIGNAL_FUNC(SignalToolbarButton), reinterpret_cast(const_cast(button))); +} + +void MainFrame::OnSelectionSelectNudgedown() +{ + NudgeSelection(3, g_qeglobals.d_gridsize); +} + +void MainFrame::OnSelectionSelectNudgeleft() +{ + NudgeSelection(0, g_qeglobals.d_gridsize); +} + +void MainFrame::OnSelectionSelectNudgeright() +{ + NudgeSelection(2, g_qeglobals.d_gridsize); +} + +void MainFrame::OnSelectionSelectNudgeup() +{ + NudgeSelection(1, g_qeglobals.d_gridsize); +} + +void MainFrame::NudgeSelection(int nDirection, float fAmount) +{ + if (ActiveXY()->RotateMode()) + { + int nAxis = 0; + if (ActiveXY()->GetViewType() == XY) + { + nAxis = 2; + } else + if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) + { + nAxis = 1; + fAmount = -fAmount; + } + + if (nDirection == 2 || nDirection == 3) + { + fAmount = -fAmount; + } + + float fDeg = -fAmount; + float fAdj = fAmount; + + g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; + CString strStatus; + strStatus.Format("Rotation x:: %.1f y:: %.1f z:: %.1f", g_pParentWnd->ActiveXY()->Rotation()[0], + g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); + g_pParentWnd->SetStatusText(2, strStatus); + Select_RotateAxis(nAxis, fDeg, false, true); + Sys_UpdateWindows (W_ALL); + } else + if (ActiveXY()->ScaleMode()) + { + if (nDirection == 0 || nDirection == 3) + { + fAmount = -fAmount; + } + vec3_t v; + v[0] = v[1] = v[2] = 1.0; + if (fAmount > 0) + { + v[0] = 1.1f; + v[1] = 1.1f; + v[2] = 1.1f; + } else + { + v[0] = 0.9f; + v[1] = 0.9f; + v[2] = 0.9f; + } + + Select_Scale((g_nScaleHow & SCALE_X) ? v[0] : 1.0, + (g_nScaleHow & SCALE_Y) ? v[1] : 1.0, + (g_nScaleHow & SCALE_Z) ? v[2] : 1.0); + Sys_UpdateWindows (W_ALL); + } else + { + // 0 - left, 1 - up, 2 - right, 3 - down + int nDim; + if (nDirection == 0) + { + nDim = ActiveXY()->GetViewType() == YZ ? 1 : 0; + fAmount = -fAmount; + } else if (nDirection == 1) + { + nDim = ActiveXY()->GetViewType() == XY ? 1 : 2; + } else if (nDirection == 2) + { + nDim = ActiveXY()->GetViewType() == YZ ? 1 : 0; + } else + { + nDim = ActiveXY()->GetViewType() == XY ? 1 : 2; + fAmount = -fAmount; + } + Nudge(nDim, fAmount); + } +} + +void MainFrame::Nudge(int nDim, float fNudge) +{ + vec3_t vMove; + vMove[0] = vMove[1] = vMove[2] = 0; + vMove[nDim] = fNudge; + + if((g_qeglobals.d_select_mode == sel_vertex || + g_qeglobals.d_select_mode == sel_curvepoint) + && g_qeglobals.d_num_move_points) + Select_NudgePoint(vMove, true); + else + Select_Move(vMove, true); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::SetGridStatus() +{ + CString strStatus; + char c1; + char c2; + c1 = (g_PrefsDlg.m_bTextureLock) ? 'M' : ' '; + c2 = (g_PrefsDlg.m_bRotateLock) ? 'R' : ' '; + strStatus.Format("G:%g R:%i C:%i L:%c%c", g_qeglobals.d_gridsize, + g_PrefsDlg.m_nRotation, g_PrefsDlg.m_nCubicScale, c1, c2); + SetStatusText(4, strStatus); +} + +void MainFrame::UpdatePatchToolbarButtons() +{ + GtkWidget *item; + g_bIgnoreCommands++; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_bend")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchBendMode) ? TRUE : FALSE); +// item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_insdel")); +// gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchInsertMode) ? TRUE : FALSE); + g_bIgnoreCommands--; +} + +// ============================================================================= +// Command handlers + +void MainFrame::OnFileNew() +{ + if (ConfirmModified()) + Map_New (); +} + +void MainFrame::OnFileOpen() +{ + if (!ConfirmModified()) + return; + + const char *str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (m_pWidget, TRUE, "Open Map", buf, MAP_MAJOR); + + if (str != NULL) + { + strcpy(currentmap,str); + MRU_AddFile (str); + Map_LoadFile(str); + } +} + +void MainFrame::OnFileImportmap() +{ + const char *str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (m_pWidget, TRUE, "Import Map", buf, MAP_MAJOR); + + if (str != NULL) + { + Map_ImportFile(str); + } +} + +void MainFrame::OnFileSave() +{ + if (!strcmp(currentmap, "unnamed.map")) + OnFileSaveas(); + else + Map_SaveFile (currentmap, false); +} + +void MainFrame::OnFileSaveas() +{ + const char* str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Save Map", buf, MAP_MAJOR); + + if (str != NULL) + { + strcpy (currentmap, str); + MRU_AddFile (str); + Map_SaveFile (str, false); // ignore region + } +} + +void MainFrame::OnFileExportmap() +{ + const char* str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (m_pWidget, FALSE, "Export Selection", buf, MAP_MAJOR); + + if (str != NULL) + { + Map_SaveSelected (str); + } +} + +void MainFrame::OnFileSaveregion() +{ + const char* str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Export Region", buf, MAP_MAJOR); + + if (str != NULL) + { + Map_SaveFile (str, true); // ignore region + } +} + +void MainFrame::OnFileNewproject() +{ + char* name = DoNewProjectDlg (); + + // create a new project: + // create directories and grab current project, save it in new project tree in scripts/user.qe4 + // on linux we create under ~/.q3a, on win32 under strEnginePath + // NOTE: working on a seperate project file might be broken, never did much experiment with that.. + if ((name != NULL) && (strlen (name) > 0)) + { + CString strNewBasePath; + + // NOTE TTimo this would probably not work right on *nix + strNewBasePath = g_pGameDescription->mEnginePath.GetBuffer(); // assume paths end with '/' + strNewBasePath += name; + strNewBasePath += "/"; + + CString strProjToLoad; + CString strMapToLoad; + + // if the dir exists, ask the user if they want to continue anyway + if (Q_mkdir (strNewBasePath.GetBuffer(), 0755) != 0) + { + CString strMsg; + strMsg.Format("The directory name %s already exists\nContinue anyway ?\n", strNewBasePath.GetBuffer ()); + Sys_Printf(strMsg); + if (gtk_MessageBox(m_pWidget, strMsg, "Error", MB_YESNO) != IDYES) + { + Sys_Printf("New Project cancelled, directory already exists for project\n"); + free (name); + return; + } + } + + CString strDir; + strDir = strNewBasePath; + strDir += "maps/"; + Q_mkdir (strDir.GetBuffer(), 0755); + + strDir = strNewBasePath; + strDir += "textures/"; + Q_mkdir (strDir.GetBuffer(), 0755); + + strDir = strNewBasePath; + strDir += "scripts/"; + Q_mkdir (strDir.GetBuffer(), 0755); + + // print a warning for total conversions, since setting the basepath when required files are + // not there _will_ break things (ie; textures/radiant/notex.tga, scripts/entities.def) + Sys_FPrintf(SYS_WRN, "*** Note: basepath unchanged\n"); + + SetKeyValue( g_qeglobals.d_project_entity, "gamename", name); + + strDir = strNewBasePath; + strDir += "maps/autosave.map"; + SetKeyValue( g_qeglobals.d_project_entity, "autosave", strDir.GetBuffer() ); + + // state that this is a user project file, no templating + SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); + // create the project file + strProjToLoad = strNewBasePath; + strProjToLoad += "scripts/"; + strProjToLoad += name; + strProjToLoad += "."; + strProjToLoad += PROJECT_FILETYPE; + QE_SaveProject(strProjToLoad.GetBuffer()); + free (name); + } +} + +void MainFrame::OnFileLoadproject() +{ + if (ConfirmModified()) + ProjectDialog (); +} + +void MainFrame::OnFileProjectsettings() +{ + DoProjectSettings(); +} + +void MainFrame::OnFilePointfile() +{ + if (g_qeglobals.d_pointfile_display_list) + Pointfile_Clear (); + else + Pointfile_Check (); +} + +void MainFrame::OnMru(unsigned int nID) +{ + if (ConfirmModified()) + MRU_Activate (nID - ID_FILE_RECENT1); +} + +void MainFrame::OnFileExit() +{ + if (ConfirmModified()) + { + // stop printing during shutdown + // NOTE: we should cleanly release GL contexts and stuff when exiting + + OnDelete(); + + g_qeglobals_gui.d_edit = NULL; + gtk_widget_destroy (m_pWidget); + } +} + +void MainFrame::OnFileCheckUpdate() + +{ + // build the URL + Str URL; + URL = "http://www.qeradiant.com/index.php?data=dlupdate&query_dlup=1"; +#ifdef _WIN32 + URL += "&OS_dlup=1"; +#else + URL += "&OS_dlup=2"; +#endif + URL += "&Version_dlup=" RADIANT_VERSION; + g_PrefsDlg.mGamesDialog.AddPacksURL(URL); + OpenURL(URL.GetBuffer()); +} + +void MainFrame::OnEditUndo() +{ + Undo_Undo(); +} + +void MainFrame::OnEditRedo() +{ + Undo_Redo(); +} + +void MainFrame::OnEditCopybrush() +{ + Copy(); +} + +void MainFrame::OnEditPastebrush() +{ + Select_Deselect(); + + Undo_Start("paste"); + + Paste(); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnEditPastebrushToCamera() +{ + Select_Deselect(); + if (ActiveXY()) + { + vec3_t mid, camorigin, delta; + + ActiveXY()->Paste(); + + // Work out the delta + Select_GetMid( mid ); + + // Snap camera origin to grid + VectorCopy( m_pCamWnd->Camera()->origin, camorigin ); + camorigin[0] = floor(camorigin[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + camorigin[1] = floor(camorigin[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + camorigin[2] = floor(camorigin[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + + VectorSubtract( camorigin, mid, delta ); + + // Move to camera + Select_Move( delta, false ); + + Undo_Start("paste to camera"); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + } +} + +void MainFrame::OnSelectionDelete() +{ + brush_t *brush; + //if (ActiveXY()) + // ActiveXY()->UndoCopy(); + Undo_Start("delete"); + Undo_AddBrushList(&selected_brushes); + //add all deleted entities to the undo + for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) + { + Undo_AddEntity(brush->owner); + } + // NOTE: Select_Delete does NOT delete entities + Select_Delete(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnEditMapinfo() +{ + DoMapInfo (); +} + +void MainFrame::OnEditEntityinfo() +{ + DoEntityList (); +} + +void MainFrame::OnBrushScripts() +{ + DoScriptsDlg (); +} + +void MainFrame::OnEditLoadprefab() +{ + const char *filename; + CString CurPath; + + if (g_PrefsDlg.m_strPrefabPath.GetLength() > 0) + { + CurPath = g_PrefsDlg.m_strPrefabPath; + AddSlash (CurPath); + } + + filename = file_dialog (m_pWidget, TRUE, "Import Prefab", CurPath.GetBuffer(), MAP_MAJOR); + + if (filename != NULL) + { + Map_ImportFile(filename); + } +} + +void MainFrame::OnEditSaveprefab() +{ + const char *filename; + CString CurPath; + + if (g_PrefsDlg.m_strPrefabPath.GetLength() > 0) + { + CurPath = g_PrefsDlg.m_strPrefabPath; + } else + { + char tmp[PATH_MAX]; + getcwd (tmp, PATH_MAX); + CurPath = tmp; + } + AddSlash (CurPath); + + filename = file_dialog (m_pWidget, FALSE, "Export Prefab", CurPath.GetBuffer(), MAP_MAJOR); + if (filename != NULL) + { + Map_SaveSelected(filename); + } +} + +void MainFrame::OnPrefs() +{ + int nView = g_PrefsDlg.m_nView; + bool bToolbar = g_PrefsDlg.m_bWideToolbar; + bool bPluginToolbar = g_PrefsDlg.m_bPluginToolbar; + int nShader = g_PrefsDlg.m_nShader; + int nTextureQuality = g_PrefsDlg.m_nTextureQuality; + int nLightRadiuses = g_PrefsDlg.m_nLightRadiuses; + g_PrefsDlg.LoadPrefs(); + + if (g_PrefsDlg.DoModal() == IDOK) + { + if ((g_PrefsDlg.m_nLatchedView != nView) || + (g_PrefsDlg.m_bLatchedDetachableMenus != g_PrefsDlg.m_bDetachableMenus) || + (g_PrefsDlg.m_bLatchedWideToolbar != bToolbar) || + (g_PrefsDlg.m_bLatchedPatchToolbar != bToolbar) || + (g_PrefsDlg.m_bLatchedPluginToolbar != bPluginToolbar) || + (g_PrefsDlg.m_nLatchedShader != nShader) || + (g_PrefsDlg.m_nLatchedTextureQuality != nTextureQuality) + || (g_PrefsDlg.m_bLatchedFloatingZ != g_PrefsDlg.m_bFloatingZ) + ) + gtk_MessageBox(m_pWidget, "You must restart Radiant for the changes to take effect."); + + // if the view mode was switched to floating, set the Z window on by default + // this was originally intended as a bug fix, but the fix is elsewhere .. anyway making sure we force Z on each time is good + // (and we simply hope there will be a SavePrefs before we die) + if ((g_PrefsDlg.m_nView != nView) && ((EViewStyle)g_PrefsDlg.m_nView == (EViewStyle)eFloating)) + { + g_PrefsDlg.m_bZVis = true; + } + + if (m_pTexWnd) + m_pTexWnd->UpdatePrefs(); + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE); + g_bIgnoreCommands--; + } +} + +void MainFrame::OnTogglecamera() +{ + if (CurrentStyle() == eFloating) // floating views + { + if (m_pCamWnd && m_pCamWnd->m_pParent) + { + if (GTK_WIDGET_VISIBLE (m_pCamWnd->m_pParent)) + widget_delete_hide (m_pCamWnd->m_pParent); + else + gtk_widget_show (m_pCamWnd->m_pParent); + } + } else + { + if (GTK_WIDGET_VISIBLE (m_pCamWnd->GetWidget ())) + gtk_widget_hide (m_pCamWnd->GetWidget ()); + else + gtk_widget_show (m_pCamWnd->GetWidget ()); + } +} + +void MainFrame::OnToggleconsole() +{ + if (FloatingGroupDialog()) // QE4 style + { + if (inspector_mode == W_CONSOLE) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_CONSOLE); + } + } +} + +// trigger the entity inspector on/off +void MainFrame::OnViewEntity() +{ + // make sure we're working with the current selection (bugzilla #436) + if( ! GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + Select_Reselect(); + + if (!FloatingGroupDialog()) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity) && inspector_mode == W_ENTITY) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_ENTITY); + } + } else + { + if (inspector_mode == W_ENTITY) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_ENTITY); + } + } +} + +void MainFrame::OnViewGroups() +{ + if (!FloatingGroupDialog()) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity) && inspector_mode == W_GROUP) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_GROUP); + } + } else + { + if (inspector_mode == W_GROUP && CurrentStyle() != MainFrame::eFloating) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_GROUP); + } + } +} + +void MainFrame::OnToggleview() +{ + if (CurrentStyle() == eFloating) // QE4 style + { + if (m_pXYWnd && m_pXYWnd->m_pParent) + { + if (GTK_WIDGET_VISIBLE (m_pXYWnd->m_pParent)) + widget_delete_hide (m_pXYWnd->m_pParent); + else + gtk_widget_show (m_pXYWnd->m_pParent); + } + } +} + +void MainFrame::OnToggleviewXz() +{ + if (CurrentStyle() == eFloating) // QE4 style + { + if (m_pXZWnd && m_pXZWnd->m_pParent) + { + // get windowplacement doesn't actually save this so we will here + g_PrefsDlg.m_bXZVis = GTK_WIDGET_VISIBLE (m_pXZWnd->m_pParent); + if (g_PrefsDlg.m_bXZVis) + widget_delete_hide (m_pXZWnd->m_pParent); + else + gtk_widget_show (m_pXZWnd->m_pParent); + g_PrefsDlg.m_bXZVis ^= 1; + g_PrefsDlg.SavePrefs (); + } + } +} + +void MainFrame::OnToggleviewYz() +{ + if (CurrentStyle() == eFloating) // QE4 style + { + if (m_pYZWnd && m_pYZWnd->m_pParent) + { + g_PrefsDlg.m_bYZVis = GTK_WIDGET_VISIBLE (m_pYZWnd->m_pParent); + if (g_PrefsDlg.m_bYZVis) + widget_delete_hide (m_pYZWnd->m_pParent); + else + gtk_widget_show (m_pYZWnd->m_pParent); + g_PrefsDlg.m_bYZVis ^= 1; + g_PrefsDlg.SavePrefs (); + } + } +} + +void MainFrame::OnTogglez() +{ + if ( g_pParentWnd->FloatingGroupDialog() ) // QE4 style + { + if (m_pZWnd && m_pZWnd->m_pParent) + { + if (GTK_WIDGET_VISIBLE (m_pZWnd->m_pParent)) + widget_delete_hide (m_pZWnd->m_pParent); + else + gtk_widget_show (m_pZWnd->m_pParent); + g_PrefsDlg.m_bZVis ^= 1; + g_PrefsDlg.SavePrefs (); + } + } else { + Sys_FPrintf( SYS_WRN, "Z view toggle is only valid in floating views\n" ); + } +} + +void MainFrame::OnViewCenter() +{ + m_pCamWnd->Camera()->angles[ROLL] = m_pCamWnd->Camera()->angles[PITCH] = 0; + m_pCamWnd->Camera()->angles[YAW] = 22.5 * floor((m_pCamWnd->Camera()->angles[YAW]+11)/22.5); + Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); +} + +void MainFrame::OnViewUpfloor() +{ + m_pCamWnd->Cam_ChangeFloor (true); +} + +void MainFrame::OnViewDownfloor() +{ + m_pCamWnd->Cam_ChangeFloor (false); +} + +void MainFrame::OnViewCenterview() +{ + if(CurrentStyle() == eSplit) + { + GetXYWnd()->PositionView(); + GetXZWnd()->PositionView(); + GetYZWnd()->PositionView(); + Sys_UpdateWindows (W_XY|W_XZ|W_YZ); + } + else { + m_pXYWnd->PositionView(); + Sys_UpdateWindows (W_XY); + } +} + +void MainFrame::OnViewNextview() +{ + if (CurrentStyle() == eSplit) + { + GetXYWnd()->PositionView(); + GetXZWnd()->PositionView(); + GetYZWnd()->PositionView(); + Sys_UpdateWindows (W_XY|W_XZ|W_YZ); + } + else { + if (m_pXYWnd->GetViewType() == XY) + m_pXYWnd->SetViewType(XZ); + else + if (m_pXYWnd->GetViewType() == XZ) + m_pXYWnd->SetViewType(YZ); + else + m_pXYWnd->SetViewType(XY); + m_pXYWnd->PositionView(); + Sys_UpdateWindows (W_XY); + } +} + +void MainFrame::OnViewXy() +{ + if(!FloatingGroupDialog()) + { + m_pXYWnd->SetViewType(XY); + m_pXYWnd->PositionView(); + } + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewSide() +{ + if (!FloatingGroupDialog()) + { + m_pXYWnd->SetViewType(XZ); + m_pXYWnd->PositionView(); + } + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewFront() +{ + if (!FloatingGroupDialog()) + { + m_pXYWnd->SetViewType(YZ); + m_pXYWnd->PositionView(); + } + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnView100() +{ + if (m_pXYWnd) + m_pXYWnd->SetScale(1); + if (m_pXZWnd) + m_pXZWnd->SetScale(1); + if (m_pYZWnd) + m_pYZWnd->SetScale(1); + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); +} + +void MainFrame::OnViewZoomin() +{ + if (m_pXYWnd && m_pXYWnd->Active()) + { + m_pXYWnd->SetScale(m_pXYWnd->Scale() * 5.0 / 4); + if (m_pXYWnd->Scale() > 30) + m_pXYWnd->SetScale(30); + } + + if (m_pXZWnd && m_pXZWnd->Active()) + { + m_pXZWnd->SetScale(m_pXZWnd->Scale() * 5.0 / 4); + if (m_pXZWnd->Scale() > 30) + m_pXZWnd->SetScale(30); + } + + if (m_pYZWnd && m_pYZWnd->Active()) + { + m_pYZWnd->SetScale(m_pYZWnd->Scale() * 5.0 / 4); + if (m_pYZWnd->Scale() > 30) + m_pYZWnd->SetScale(30); + } + + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); +} + +// NOTE: the zoom out factor is 4/5, we could think about customizing it +// we don't go below a zoom factor corresponding to 10% of the max world size +// (this has to be computed against the window size) +void MainFrame::OnViewZoomout() +{ + float min_scale; + if (m_pXYWnd && m_pXYWnd->Active()) + { + m_pXYWnd->SetScale(m_pXYWnd->Scale() * 4.0 / 5); + min_scale = MIN(m_pXYWnd->Width(),m_pXYWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); + if (m_pXYWnd->Scale() < min_scale) m_pXYWnd->SetScale (min_scale); + } + + if (m_pXZWnd && m_pXZWnd->Active()) + { + m_pXZWnd->SetScale(m_pXZWnd->Scale() * 4.0 / 5); + min_scale = MIN(m_pXZWnd->Width(),m_pXZWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); + if (m_pXZWnd->Scale() < min_scale) m_pXZWnd->SetScale (min_scale); + } + + if (m_pYZWnd && m_pYZWnd->Active()) + { + m_pYZWnd->SetScale(m_pYZWnd->Scale() * 4.0 / 5); + min_scale = MIN(m_pYZWnd->Width(),m_pYZWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); + if (m_pYZWnd->Scale() < min_scale) m_pYZWnd->SetScale (min_scale); + } + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); +} + +void MainFrame::OnViewZ100() +{ + z.scale = 1; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); +} + +void MainFrame::OnViewZzoomin() +{ + z.scale *= 5.0/4; + if (z.scale > 4) + z.scale = 4; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); +} + +void MainFrame::OnViewZzoomout() +{ + z.scale *= 4.0f/5; + if (z.scale < 0.125) + z.scale = 0.125; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); +} + +void MainFrame::OnViewCubein() +{ + g_PrefsDlg.m_nCubicScale--; + if (g_PrefsDlg.m_nCubicScale < 1) + g_PrefsDlg.m_nCubicScale = 1; + g_PrefsDlg.SavePrefs (); + Sys_UpdateWindows(W_CAMERA); + SetGridStatus(); +} + +void MainFrame::OnViewCubeout() +{ + g_PrefsDlg.m_nCubicScale++; + if (g_PrefsDlg.m_nCubicScale > 22) + g_PrefsDlg.m_nCubicScale = 22; + g_PrefsDlg.SavePrefs (); + Sys_UpdateWindows(W_CAMERA); + SetGridStatus(); +} + +void MainFrame::OnViewShownames() +{ + g_qeglobals.d_savedinfo.show_names = !g_qeglobals.d_savedinfo.show_names; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_shownames")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_names ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowAngles() +{ + g_qeglobals.d_savedinfo.show_angles = !g_qeglobals.d_savedinfo.show_angles; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showangles")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_angles ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowblocks() +{ + g_qeglobals.show_blocks ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showblocks")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.show_blocks ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowcoordinates() +{ + g_qeglobals.d_savedinfo.show_coordinates ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showcoordinates")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_coordinates ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY|W_Z); +} + +void MainFrame::OnViewShowOutline() +{ + g_qeglobals.d_savedinfo.show_outline ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showoutline")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_outline ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowAxes() +{ + g_qeglobals.d_savedinfo.show_axis ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showaxes")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_axis ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowWorkzone() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showworkzone")); + g_bIgnoreCommands++; + if (g_qeglobals.d_show_work) + { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_qeglobals.d_show_work = false; + } else + { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_qeglobals.d_show_work = true; + } + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewHideshowHideselected() +{ + Select_Hide(); + Select_Deselect(); +} + +void MainFrame::OnViewHideshowShowhidden() +{ + Select_ShowAllHidden(); +} + +/** +sets the view mode for the entities +called upon LoadPrefs too +NOTE TTimo previous implementation had a SavePrefs call + .. I don't think it is relevant, removed (the prefs are saved upon exit) +NOTE TTimo we activate the menu item, this is only needed when we are called upon a prefs load + (otherwise we are always called following user action on the widget) +*/ +void MainFrame::OnEntitiesSetViewAs(int mode) +{ + gpointer item = NULL; + if (mode == 0) + { + switch (g_PrefsDlg.m_nEntityShowState) + { + case ENTITY_BOX: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_boundingbox"); + break; + case ENTITY_WIRE: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_wireframe"); + break; + case ENTITY_SELECTED: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedwireframe"); + break; + case ENTITY_SELECTED_SKIN: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedskinned"); + break; + case ENTITY_SKINNED: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinned"); + break; + case ENTITY_SKINNED_BOXED: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinnedandboxed"); + break; + } + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + return; + } + + switch (mode) + { + case ID_VIEW_ENTITIESAS_BOUNDINGBOX: + g_PrefsDlg.m_nEntityShowState = ENTITY_BOX; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_boundingbox"); + break; + case ID_VIEW_ENTITIESAS_WIREFRAME: + g_PrefsDlg.m_nEntityShowState = ENTITY_WIRE; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_wireframe"); + break; + case ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME: + g_PrefsDlg.m_nEntityShowState = ENTITY_SELECTED; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedwireframe"); + break; + case ID_VIEW_ENTITIESAS_SELECTEDSKINNED: + g_PrefsDlg.m_nEntityShowState = ENTITY_SELECTED_SKIN; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedskinned"); + break; + case ID_VIEW_ENTITIESAS_SKINNED: + g_PrefsDlg.m_nEntityShowState = ENTITY_SKINNED; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinned"); + break; + case ID_VIEW_ENTITIESAS_SKINNEDANDBOXED: + g_PrefsDlg.m_nEntityShowState = ENTITY_SKINNED_BOXED; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinnedandboxed"); + break; + default: + Sys_FPrintf(SYS_ERR, "Entity mode ID_ not found in MainFrame::Entities_SetViewAs\n"); + return; + } + + if (!item) + { + Sys_FPrintf(SYS_ERR, "menu not found in MainFrame::Entities_SetViewAs\n"); + return; + } + + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnViewCubicclipping() +{ + GtkWidget *w; + + g_PrefsDlg.m_bCubicClipping ^= 1; + g_bIgnoreCommands++; + w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cubicclipping")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), g_PrefsDlg.m_bCubicClipping ? TRUE : FALSE); + w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), g_PrefsDlg.m_bCubicClipping ? TRUE : FALSE); + g_bIgnoreCommands--; + g_PrefsDlg.SavePrefs (); + //Map_BuildBrushData (); + Sys_UpdateWindows(W_CAMERA); +} + +void MainFrame::OnViewOpengllighting() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting")); + g_PrefsDlg.m_bGLLighting ^= 1; + g_PrefsDlg.SavePrefs (); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bGLLighting ? TRUE : FALSE); + Sys_UpdateWindows (W_XY|W_CAMERA); + g_bIgnoreCommands--; +} + +void MainFrame::OnSelectionDragedges() +{ + if (g_qeglobals.d_select_mode == sel_edge) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } else + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_edge; + Sys_UpdateWindows (W_ALL); + } +} + +void MainFrame::OnSelectionDragvertecies() +{ + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_curvepoint) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } else + { + //--if (QE_SingleBrush() && selected_brushes.next->patchBrush) + if (OnlyPatchesSelected()) + { + Patch_EditPatch(); + } else //if (!AnyPatchesSelected()) // allows vertex mode when patches are selected + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_vertex; + } + Sys_UpdateWindows (W_ALL); + } +} + +void MainFrame::OnSelectionClone() +{ + Select_Clone(); +} + +// called when the escape key is used (either on the main window or on an inspector) +void MainFrame::OnSelectionDeselect() +{ + if (g_bClipMode) + OnViewClipper(); + else + if (g_bRotateMode) + OnSelectMouserotate(); + else + if (g_bScaleMode) + OnSelectMousescale(); + else + if (g_bPathMode) + { + if (ActiveXY()) + ActiveXY()->KillPathMode(); + } else + { + if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points > 0) + { + g_qeglobals.d_num_move_points = 0; + Sys_UpdateWindows(W_ALL); + } else + { + Select_Deselect (); + SetStatusText(2, " "); + } + } +} + +void MainFrame::OnBrushFlipx() +{ + Undo_Start("flip X"); + Undo_AddBrushList(&selected_brushes); + + Select_FlipAxis (0); + // spog - this does not work - it's a rotate not a flip + /* + for (brush_t *b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->owner->eclass->fixedsize) + { + char buf[16]; + float a = FloatForKey(b->owner, "angle"); + a = div ((int)(180 - a), 180).rem; + sprintf (buf, "%d", (int)a); + SetKeyValue(b->owner, "angle", buf); + Brush_Build(b,true,true,false,false); // don't filter + } + } + */ + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushFlipy() +{ + Undo_Start("flip Y"); + Undo_AddBrushList(&selected_brushes); + + Select_FlipAxis (1); + // spog - this does not work - it's a rotate not a flip + /* + for (brush_t *b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->owner->eclass->fixedsize) + { + float a = FloatForKey(b->owner, "angle"); + if (a == 0 || a == 180 || a == 360) + continue; + if ( a == 90 || a == 270) + { + a += 180; + } + else if (a > 270) + a += 90; + else if (a > 180) + a -= 90; + else if (a > 90) + a += 90; + else + a -= 90; + a = (int)a % 360; + char buf[16]; + sprintf (buf, "%d", (int)a); + SetKeyValue(b->owner, "angle", buf); + Brush_Build(b,true,true,false,false); // don't filter + } + + } + */ + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushFlipz() +{ + Undo_Start("flip Z"); + Undo_AddBrushList(&selected_brushes); + Select_FlipAxis (2); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushRotatex() +{ + Undo_Start("rotate X"); + Undo_AddBrushList(&selected_brushes); + Select_RotateAxis (0, 90); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushRotatey() +{ + Undo_Start("rotate Y"); + Undo_AddBrushList(&selected_brushes); + Select_RotateAxis (1, 90); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushRotatez() +{ + Undo_Start("rotate Z"); + Undo_AddBrushList(&selected_brushes); + Select_RotateAxis (2, 90); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionArbitraryrotation() +{ + Undo_Start("arbitrary rotation"); + Undo_AddBrushList(&selected_brushes); + + DoRotateDlg (); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectScale() +{ + Undo_Start("scale"); + Undo_AddBrushList(&selected_brushes); + DoScaleDlg (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMakehollow() +{ + //if (ActiveXY()) + // ActiveXY()->UndoCopy(); + Undo_Start("hollow"); + Undo_AddBrushList(&selected_brushes); + CSG_MakeHollow (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionCsgsubtract() +{ + Undo_Start("CSG subtract"); + CSG_Subtract(); + Undo_End(); +} + +void MainFrame::OnSelectionCsgmerge() +{ + Undo_Start("CSG merge"); + Undo_AddBrushList(&selected_brushes); + CSG_Merge(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionNoOutline() +{ + //g_qeglobals.d_savedinfo.bNoSelectedOutlines ^= 1; + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle = (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) ^ OUTLINE_ZBUF; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_CAMERA); +} + +void MainFrame::OnSelectionOutlineStyle() +{ + if ((g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) && (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL)) + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle &= ~OUTLINE_ZBUF; + else if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle &= ~OUTLINE_BSEL; + else if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle |= OUTLINE_BSEL; + else + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle |= OUTLINE_ZBUF; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_CAMERA); +} + +void MainFrame::OnSelectionSelectcompletetall() +{ + if (ActiveXY()) + ActiveXY()->UndoCopy(); + Select_CompleteTall (); +} + +void MainFrame::OnSelectionSelecttouching() +{ + Select_Touching(); +} + +void MainFrame::OnSelectionSelectpartialtall() +{ + Select_PartialTall(); +} + +void MainFrame::OnSelectionSelectinside() +{ + Select_Inside (); +} + +void MainFrame::OnViewClipper() +{ + GtkWidget *w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_clipper")); + g_bIgnoreCommands++; + + if (ActiveXY()) + { + if (ActiveXY()->ClipMode()) + { + ActiveXY()->SetClipMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), FALSE); + } else + { + if (ActiveXY()->RotateMode()) + OnSelectMouserotate(); + ActiveXY()->SetClipMode(true); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE); + } + } + g_bIgnoreCommands--; +} + +void MainFrame::OnClipSelected() +{ + if (m_pActiveXY && m_pActiveXY->ClipMode()) + { + Undo_Start("clip selected"); + Undo_AddBrushList(&selected_brushes); + m_pActiveXY->Clip(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + } else + { + if (g_bPatchBendMode) + Patch_BendHandleENTER(); +// else if (g_bPatchBendMode) +// Patch_InsDelHandleENTER(); + } +} + +void MainFrame::OnSplitSelected() +{ + if (m_pActiveXY) + { + Undo_Start("split selected"); + Undo_AddBrushList(&selected_brushes); + m_pActiveXY->SplitClip(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + } +} + +void MainFrame::OnFlipClip() +{ + if (m_pActiveXY) + m_pActiveXY->FlipClip(); +} + +void MainFrame::OnSelectionConnect() +{ + Undo_Start("connect selected entities"); + Undo_AddBrushList(&selected_brushes); + ConnectEntities(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionUngroupentity() +{ + Undo_Start("ungroup selected entities"); + Undo_AddBrushList(&selected_brushes); + Select_Ungroup(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMergeentity() +{ + Undo_Start("merge entity"); + Undo_AddBrushList(&selected_brushes); + Select_MergeEntity(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionGroupworld() +{ + Undo_Start("group world"); + Undo_AddBrushList(&selected_brushes); + Select_GroupEntity(world_entity); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMakeDetail() +{ + Undo_Start("make detail"); + Undo_AddBrushList(&selected_brushes); + Select_MakeDetail (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMakeStructural() +{ + Undo_Start("make structural"); + Undo_AddBrushList(&selected_brushes); + Select_MakeStructural (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBspCommand (unsigned int nID) +{ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // make sure we don't attempt to region compile a map with the camera outside the region + if (region_active) + { + vec3_t vOrig; + VectorSet(vOrig, + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); + + int i; + for (i=0 ; i<3 ; i++) + { + if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) + { + Sys_FPrintf(SYS_ERR, "The camera must be in the region to start a region compile.\n"); + return; + } + } + } + + // if the map has not been saved yet we need to handle it now before we start processing the BSP commands + if (stricmp( currentmap, "unnamed.map") == 0) + { + OnFileSaveas(); + } + + if (g_PrefsDlg.m_bSnapShots && (stricmp (currentmap, "unnamed.map") != 0)) + Map_Snapshot(); + + if (g_qeglobals.bBSPFrontendPlugin) + { + char *cmd = (char*)g_slist_nth_data (g_BSPFrontendCommands, nID-CMD_BSPCOMMAND); + g_BSPFrontendTable.m_pfnDispatchBSPCommand (cmd); + } else + { + RunBsp (bsp_commands[nID-CMD_BSPCOMMAND]); + } +} + +void MainFrame::OnGrid (unsigned int nID) +{ + if (nID == ID_GRID_025) + { + g_qeglobals.d_gridsize = 0.25f; + g_qeglobals.d_bSmallGrid = true; + } else if (nID == ID_GRID_05) + { + g_qeglobals.d_gridsize = 0.5f; + g_qeglobals.d_bSmallGrid = true; + } else + { + switch (nID) + { + case ID_GRID_1: g_qeglobals.d_gridsize = 0; break; + case ID_GRID_2: g_qeglobals.d_gridsize = 1; break; + case ID_GRID_4: g_qeglobals.d_gridsize = 2; break; + case ID_GRID_8: g_qeglobals.d_gridsize = 3; break; + case ID_GRID_16: g_qeglobals.d_gridsize = 4; break; + case ID_GRID_32: g_qeglobals.d_gridsize = 5; break; + case ID_GRID_64: g_qeglobals.d_gridsize = 6; break; + case ID_GRID_128: g_qeglobals.d_gridsize = 7; break; + case ID_GRID_256: g_qeglobals.d_gridsize = 8; break; + } + g_qeglobals.d_gridsize = 1 << (int)g_qeglobals.d_gridsize; + g_qeglobals.d_bSmallGrid = false; + } + + SetGridStatus(); + + // SnapTToGrid option: need to check everywhere the grid size is changed + // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext + if (g_PrefsDlg.m_bSnapTToGrid) + DoSnapTToGrid(); + + Sys_UpdateWindows (W_XY|W_Z); +} + +void MainFrame::OnSnaptogrid() +{ + g_PrefsDlg.m_bNoClamp ^= 1; + g_PrefsDlg.SavePrefs (); + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bNoClamp ? FALSE : TRUE); + g_bIgnoreCommands--; +} + +void MainFrame::OnTexturesShowinuse() +{ + Sys_BeginWait (); + Texture_ShowInuse (); +#ifdef _DEBUG + if (!g_bShowAllShaders) + Sys_Printf("Already showing only in-use textures.\n"); +#endif + Sys_UpdateWindows( W_TEXTURE ); + Sys_EndWait (); +} + +void MainFrame::OnTexturesShowall() +{ + Texture_ShowAll(); +} + +// do some triggering on/off, if the inspector is already up then hide it +void MainFrame::OnTexturesInspector() +{ + ToggleSurface(); +} + +void MainFrame::OnViewNearest(unsigned int nID) +{ + Texture_SetMode(nID); +} + +void MainFrame::OnTextureReplaceall() +{ + FindTextureDialog::show(); +} + +void MainFrame::OnToggleLock() +{ + g_PrefsDlg.m_bTextureLock = !g_PrefsDlg.m_bTextureLock; + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_lock")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTextureLock ? TRUE : FALSE); + g_bIgnoreCommands--; + g_PrefsDlg.SavePrefs (); + SetGridStatus(); +} + +void MainFrame::OnToggleRotatelock() +{ + g_PrefsDlg.m_bRotateLock ^= 1; + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_rotatelock")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bRotateLock ? TRUE : FALSE); + g_bIgnoreCommands--; + g_PrefsDlg.SavePrefs (); + SetGridStatus(); +} + +// use a dialog for direct selection of a texture menu +// the API is a bit crappy, we need to set texture_directory to the directory name in /textures/ +void MainFrame::OnTexturesLoad() +{ + char def_path[NAME_MAX]; + + // FIXME + // check if that works with fs_game (I suspect some more design is needed) + // see how this is done in 1.2? + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=507 + strcpy (def_path, g_pGameDescription->mEnginePath.GetBuffer()); + strcat (def_path, g_pGameDescription->mBaseGame.GetBuffer()); + strcat (def_path, "/"); + + char *dir = dir_dialog (m_pWidget, "Load textures from path", def_path); + + if (dir != NULL) + { + // very uncertain task, let's hope the guy pointed to somewhere below the dir we gave him + Sys_Printf("user select: '%s'\n", dir); + // remove a potential trailing slash? + if (dir[strlen(dir)-1]=='/' || dir[strlen(dir)-1]=='\\') + dir[strlen(dir)-1] = '\0'; + char *pouic = MAX(strrchr(dir, '/'),strrchr(dir, '\\')); + if (pouic) + { + strcpy(texture_directory, pouic+1); + Sys_Printf("Loading '%s'\n", texture_directory); + Texture_ShowDirectory(); + } + else + Sys_FPrintf(SYS_WRN, "Failed to extract the directory\n"); + g_free(dir); + } + else + Sys_FPrintf(SYS_WRN, "texture load dialog cancelled\n"); +} + +void MainFrame::OnTexturesReloadshaders() +{ + Sys_BeginWait (); + QERApp_ReloadShaders(); + // current shader + // NOTE: we are kinda making it loop on itself, it will update the pShader and scroll the texture window + Texture_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, NULL, false); + Sys_UpdateWindows (W_ALL); + Sys_EndWait(); +} + +void MainFrame::OnTexturesShadersShow() +{ + g_PrefsDlg.m_bShowShaders ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaders_show")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_TEXTURE); +} + +void MainFrame::SetTextureScale(int id) +{ + GtkWidget *item; + + switch (id) + { + case ID_TEXTURES_TEXTUREWINDOWSCALE_10: + g_PrefsDlg.m_nTextureScale = 10; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_10")); + break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_25: + g_PrefsDlg.m_nTextureScale = 25; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_25")); + break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_50: + g_PrefsDlg.m_nTextureScale = 50; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_50")); + break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_200: + g_PrefsDlg.m_nTextureScale = 200; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_200")); + break; + default: + g_PrefsDlg.m_nTextureScale = 100; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_100")); + break; + } + + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Texture_ResetPosition(); +} + +void MainFrame::OnTexturewindowScaleup() +{ + switch(g_PrefsDlg.m_nTextureScale) { + // 200, all the way in, don't do anything + case 100: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_200); + break; + case 50: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_100); + break; + case 25: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_50); + break; + case 10: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_25); + break; + } +} + +void MainFrame::OnTexturewindowScaledown() +{ + switch(g_PrefsDlg.m_nTextureScale) { + case 200: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_100); + break; + case 100: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_50); + break; + case 50: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_25); + break; + case 25: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_10); + break; + // 10, all the way out, don't do anything + } +} + +void MainFrame::OnTexturesLoadlist() +{ + DoTextureListDlg (); +} + +void MainFrame::OnTexturesShaderlistonly() +{ + g_PrefsDlg.m_bTexturesShaderlistOnly ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget),"menu_textures_shaderlistonly")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE); + g_bIgnoreCommands--; + FillTextureMenu(); +} + +void MainFrame::OnTextureWad(unsigned int nID) +{ + Sys_BeginWait (); + Texture_ShowDirectory (nID); + Sys_UpdateWindows (W_ALL); + Sys_EndWait (); +} + +void MainFrame::OnMiscBenchmark() +{ + m_pCamWnd->BenchMark(); +} + +void MainFrame::OnColorSetoriginal() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.75f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + //djbob + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][2] = 0.0f; + //-djbob + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorSetqer() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorSetblack() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.2f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][0] = 0.3f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][1] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][2] = 0.5f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.7f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.7f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +/* ydnar: to emulate maya/max/lightwave color schemes */ +void MainFrame::OnColorSetydnar() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 0.77f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.83f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.89f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnTexturebk() +{ + DoColor(COLOR_TEXTUREBACK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsXybk() +{ + DoColor(COLOR_GRIDBACK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMajor() +{ + DoColor(COLOR_GRIDMAJOR); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMinor() +{ + DoColor(COLOR_GRIDMINOR); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMajor_Alt() +{ + DoColor(COLOR_GRIDMAJOR_ALT); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMinor_Alt() +{ + DoColor(COLOR_GRIDMINOR_ALT); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsGridtext() +{ + DoColor(COLOR_GRIDTEXT); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsGridblock() +{ + DoColor(COLOR_GRIDBLOCK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsCameraBack() +{ + DoColor(COLOR_CAMERABACK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsBrush() +{ + DoColor(COLOR_BRUSHES); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsSelectedbrush() +{ + DoColor(COLOR_SELBRUSHES); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsSelectedbrush3D() +{ + DoColor(COLOR_SELBRUSHES3D); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsClipper() +{ + DoColor(COLOR_CLIPPER); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsViewname() +{ + DoColor(COLOR_VIEWNAME); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnMiscGamma() +{ + float fSave = g_qeglobals.d_savedinfo.fGamma; + DoGamma(); + if (fSave != g_qeglobals.d_savedinfo.fGamma) + { + gtk_MessageBox(m_pWidget, "You must restart Radiant for Gamma settings to take effect."); + } +} +void MainFrame::OnMiscFindbrush() +{ + DoFind(); +} + +void MainFrame::OnMiscNextleakspot() +{ + Pointfile_Next(); +} + +void MainFrame::OnMiscPreviousleakspot() +{ + Pointfile_Prev(); +} + +void MainFrame::OnMiscPrintxy() +{ +// WXY_Print(); +} + +void MainFrame::OnMiscSelectentitycolor() +{ + if (edit_entity) + { + CString strColor = ValueForKey(edit_entity, "_color"); + if (strColor.GetLength() > 0) + { + float fR, fG, fB; + int n = sscanf(strColor,"%f %f %f", &fR, &fG, &fB); + if (n == 3) + { + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0] = fR; + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1] = fG; + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2] = fB; + } + } + + if (inspector_mode == W_ENTITY && (DoColor(COLOR_ENTITY))) + { + char buffer[100]; + sprintf(buffer, "%f %f %f", g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2]); + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), buffer); + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "_color"); + AddProp(); + //DK - SOF change to get color to entity quickly + //--::SetWindowText( hwndEnt[EntValueField], buffer ); + //--::SetWindowText( hwndEnt[EntKeyField], "color" ); + //--AddProp(); + } + Sys_UpdateWindows( W_ALL ); + } +} + +void MainFrame::OnConvertcurves() +{ +#if 0 + Select_Deselect(); + for (brush_t* pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->curveBrush) + { + for (face_t* f = pb->brush_faces ; f ; f=f->next) + { + if (f->texdef.contents & CONTENTS_LADDER) + { + f->texdef.contents &= ~CONTENTS_LADDER; + f->texdef.contents |= CONTENTS_NEGATIVE_CURVE; + } + } + } + } + Map_BuildBrushData(); +#endif +} + +void MainFrame::OnRegionOff() +{ + Map_RegionOff (); +} + +void MainFrame::OnRegionSetxy() +{ + Map_RegionXY (); +} + +void MainFrame::OnRegionSettallbrush() +{ + Map_RegionTallBrush (); +} + +void MainFrame::OnRegionSetbrush() +{ + Map_RegionBrush (); +} + +void MainFrame::OnRegionSetselection() +{ + Map_RegionSelectedBrushes (); +} + +void MainFrame::OnBrush3sided() +{ + Undo_Start("3 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(3); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush4sided() +{ + Undo_Start("4 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(4); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush5sided() +{ + Undo_Start("5 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(5); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush6sided() +{ + Undo_Start("6 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(6); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush7sided() +{ + Undo_Start("7 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(7); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush8sided() +{ + Undo_Start("8 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(8); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush9sided() +{ + Undo_Start("9 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(9); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushArbitrarysided() +{ + Undo_Start("arbitrary sided"); + Undo_AddBrushList(&selected_brushes); + DoSides(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushMakecone() +{ + Undo_Start("make cone"); + Undo_AddBrushList(&selected_brushes); + DoSides(true); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushPrimitivesSphere() +{ + Undo_Start("make sphere"); + Undo_AddBrushList(&selected_brushes); + + DoSides(false, true); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchtube() +{ + Undo_Start("make curve cylinder"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(false); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchdensetube() +{ + Undo_Start("dense cylinder"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false); + OnCurveInsertAddrow(); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchverydensetube() +{ + Undo_Start("very dense cylinder"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false); + OnCurveInsertAddrow(); + OnCurveInsertInsertrow(); + OnCurveInsertAddrow(); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchsquare() +{ + Undo_Start("square cylinder"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false, false, false, true); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchendcap() +{ + Undo_Start("make end cap"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(false, false, true); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchbevel() +{ + Undo_Start("make bevel"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(false, true, false); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveMoreendcapsbevelsSquarebevel() +{ + Undo_Start("square bevel"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false, true, false, true); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveMoreendcapsbevelsSquareendcap() +{ + Undo_Start("square endcap"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false, false, true, true); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchcone() +{ + Undo_Start("make curve cone"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(true); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveSimplepatchmesh() +{ + Undo_Start("make simpe patch mesh"); + Undo_AddBrushList(&selected_brushes); + DoNewPatchDlg (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertInsertcolumn() +{ + Undo_Start("insert (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, true, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertAddcolumn() +{ + Undo_Start("add (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertInsertrow() +{ + Undo_Start("insert (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, false, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertAddrow() +{ + Undo_Start("add (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteFirstcolumn() +{ + Undo_Start("delete first (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteLastcolumn() +{ + Undo_Start("delete last (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, true, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteFirstrow() +{ + Undo_Start("delete first (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteLastrow() +{ + Undo_Start("delete last (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, false, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveNegative() +{ + Patch_ToggleInverted(); + //Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveRedisperseRows() +{ + Undo_Start("redisperse rows"); + Undo_AddBrushList(&selected_brushes); + Patch_DisperseRows(); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveRedisperseIntermediateCols() +{ + Undo_Start("redisperse im cols"); + Undo_AddBrushList(&selected_brushes); + Patch_DisperseIntermediateColumns(); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveRedisperseIntermediateRows() +{ + Undo_Start("redisperse im rows"); + Undo_AddBrushList(&selected_brushes); + Patch_DisperseIntermediateRows(); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveMatrixTranspose() +{ + Patch_Transpose(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnCurveCap() +{ + Patch_CapCurrent(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnCurveCyclecap() +{ + Patch_CycleCapSelected(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnCurveOverlaySet() +{ + Patch_SetOverlays(); + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveOverlayClear() +{ + Patch_ClearOverlays(); + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveThicken() +{ + Undo_Start("curve thicken"); + Undo_AddBrushList(&selected_brushes); + DoThickenDlg (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +/*! +this can no longer be trigger manually from the menu +happens only once at startup +*/ +void MainFrame::OnPluginsRefresh() +{ + CleanPlugInMenu(); + m_PlugInMgr.Init(); +} + +// open the Q3Rad manual +void MainFrame::OnHelp() +{ + // at least on win32, g_strGameToolsPath + "Q3Rad_Manual/index.htm" + Str help; + help = g_strAppPath; + help += "Q3Rad_Manual/index.htm"; + OpenURL(help.GetBuffer()); +} + +// FIXME: we'll go towards a unified help thing soon +void MainFrame::OnHelpLinks() +{ + Str link; + link = g_strAppPath; + link += "links.htm"; + OpenURL(link.GetBuffer()); +} + +void MainFrame::OnHelpBugreport() +{ + OpenURL("http://www.qeradiant.com/faq/fom-serve/cache/138.html"); +} + +void MainFrame::OnHelpCommandlist() +{ + DoCommandListDlg (); +} + +void MainFrame::OnHelpAbout() +{ + DoAbout(); +} + +void MainFrame::OnPopupSelection() +{ + GtkWidget *menu, *item; + char *labels[] = { "Select Complete Tall", "Select Touching", "Select Partial Tall", "Select Inside"}; + int ids[] = { ID_SELECTION_SELECTCOMPLETETALL, ID_SELECTION_SELECTTOUCHING, + ID_SELECTION_SELECTPARTIALTALL, ID_SELECTION_SELECTINSIDE}; + + menu = gtk_menu_new (); + + for (int i = 0; i < 4; i++) + { + item = gtk_menu_item_new_with_label (labels[i]); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ids[i])); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +void MainFrame::OnViewChange() +{ + OnViewNextview(); + //HandlePopup(this, IDR_POPUP_VIEW); +} + +void MainFrame::OnTexturesPopup() +{ + gpointer item = g_object_get_data (G_OBJECT (m_pWidget), "render_quality_menu"); + gtk_menu_popup (GTK_MENU (item), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +void MainFrame::ToggleCamera() +{ + if (m_bCamPreview) + m_bCamPreview = false; + else + m_bCamPreview = true; +} + +void MainFrame::OnViewCameraupdate() +{ + Sys_UpdateWindows(W_CAMERA); +} + +void MainFrame::OnSelectMouserotate() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_select_mouserotate")); + g_bIgnoreCommands++; + + if (ActiveXY()) + { + if (ActiveXY()->ClipMode()) + OnViewClipper(); + if (ActiveXY()->RotateMode()) + { + // SetRotateMode(false) always works + ActiveXY()->SetRotateMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + // may not work if no brush selected, see return value + if (ActiveXY()->SetRotateMode(true)) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + else + // if MFC called, we need to set back to FALSE ourselves + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } + } + g_bIgnoreCommands--; +} + +void MainFrame::OnSelectMousescale() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_select_mousescale")); + g_bIgnoreCommands++; + + if (ActiveXY()) + { + if (ActiveXY()->ClipMode()) + OnViewClipper(); + if (ActiveXY()->RotateMode()) + { + // SetRotateMode(false) always works + ActiveXY()->SetRotateMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } + if (ActiveXY()->ScaleMode()) + { + ActiveXY()->SetScaleMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + ActiveXY()->SetScaleMode(true); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + } + g_bIgnoreCommands--; +} + +void MainFrame::OnScalelockx() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelockx")); + g_bIgnoreCommands++; + + if (g_nScaleHow & SCALE_X) + { + g_nScaleHow ^= SCALE_X; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + g_nScaleHow |= SCALE_X; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + g_bIgnoreCommands--; +} + +void MainFrame::OnScalelocky() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelocky")); + g_bIgnoreCommands++; + + if (g_nScaleHow & SCALE_Y) + { + g_nScaleHow ^= SCALE_Y; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + g_nScaleHow |= SCALE_Y; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + g_bIgnoreCommands--; +} + +void MainFrame::OnScalelockz() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelockz")); + g_bIgnoreCommands++; + + if (g_nScaleHow & SCALE_Z) + { + g_nScaleHow ^= SCALE_Z; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + g_nScaleHow |= SCALE_Z; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + g_bIgnoreCommands--; +} + +void MainFrame::OnDontselectcurve() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectcurve")); + g_bIgnoreCommands++; + g_PrefsDlg.m_bSelectCurves ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectCurves) ? FALSE : TRUE); + g_bIgnoreCommands--; +} + +void MainFrame::OnPatchToggleBox() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_showboundingbox")); + g_bIgnoreCommands++; + g_bPatchShowBounds ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchShowBounds) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchWireframe() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_wireframe")); + g_bIgnoreCommands++; + g_bPatchWireFrame ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWireFrame) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchBend() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_bend")); + g_bIgnoreCommands++; + Patch_BendToggle(); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchBendMode) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchWeld() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_weld")); + g_bIgnoreCommands++; + g_bPatchWeld ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWeld) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchDrilldown() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_drilldown")); + g_bIgnoreCommands++; + g_bPatchDrillDown ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchDrillDown) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnShowEntities() +{ + gpointer item = g_object_get_data (G_OBJECT (m_pWidget), "view_entitiesas_menu"); // use pointer to existing menu object + gtk_menu_popup (GTK_MENU (item), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +void MainFrame::OnDropGroupName() +{ + /* + char* name = DoNameDlg ("Name Selection"); + + if (name != NULL) + { + Select_Name (name); + Sys_UpdateWindows (W_ALL); + free (name); + } + */ +} + +void MainFrame::OnDropGroupNewgroup() +{ + +} + +void MainFrame::OnDropGroupRemove() +{ + /* + Select_AddToGroup("World"); + Sys_UpdateWindows (W_ALL); + */ +} + +// NOTE: it's called OnFaceFit() but we want to process everything here, faces and patches +void MainFrame::OnFaceFit() +{ + SurfaceDlgFitAll(); +} + +void MainFrame::OnDontselectmodel() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectmodel")); + g_bIgnoreCommands++; + g_PrefsDlg.m_bSelectModels ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectModels) ? FALSE : TRUE); + g_bIgnoreCommands--; +} + +void MainFrame::OnViewTexture() +{ + if (FloatingGroupDialog()) // QE4 style + { + if (inspector_mode == W_TEXTURE) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode (W_TEXTURE); + } + } +} + +void MainFrame::OnPatchInspector() +{ + TogglePatchInspector(); +} + +void MainFrame::OnCurveNegativeTextureX() +{ + Patch_InvertTexture(false); + //Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveNegativeTextureY() +{ + Patch_InvertTexture(true); + //Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveInsertcolumn() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("insert colum"); + Undo_AddBrushList(&selected_brushes); + //Patch_AdjustSelectedRowCols(0, 2); + Patch_AdjustSelected(true, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertrow() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("insert row"); + Undo_AddBrushList(&selected_brushes); + //Patch_AdjustSelectedRowCols(2, 0); + Patch_AdjustSelected(true, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeletecolumn() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("delete column"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleterow() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("delete row"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnPatchTab() +{ + if (g_bPatchBendMode) + Patch_BendHandleTAB(); +// else if (g_bPatchInsertMode) +// Patch_InsDelHandleTAB(); + else + { + // check to see if the selected brush is part of a func group + // if it is, deselect everything and reselect the next brush + // in the group + brush_t *b2, *b = selected_brushes.next; + entity_t * e; + if (b != &selected_brushes) + { + if (strcmpi(b->owner->eclass->name, "worldspawn") != 0) + { + e = b->owner; + Select_Deselect(); + for (b2 = e->brushes.onext ; b2 != &e->brushes ; b2 = b2->onext) + { + if (b == b2) + { + b2 = b2->onext; + break; + } + } + if (b2 == &e->brushes) + b2 = b2->onext; + + Select_Brush(b2, false); + Sys_UpdateWindows(W_ALL); + } + } + } +} + +void MainFrame::OnCameraForward(bool keydown) +{ + if (g_PrefsDlg.m_bCamDiscrete && (m_pCamWnd && !m_pCamWnd->m_bFreeMove) ) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, SPEED_MOVE, m_pCamWnd->Camera()->forward, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_FORWARD; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_FORWARD; + } +} + +void MainFrame::OnCameraBack(bool keydown) +{ + if (g_PrefsDlg.m_bCamDiscrete && (m_pCamWnd && !m_pCamWnd->m_bFreeMove) ) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, -SPEED_MOVE, m_pCamWnd->Camera()->forward, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_BACK; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_BACK; + } +} + +void MainFrame::OnCameraLeft(bool keydown) +{ + if (m_pCamWnd) + { + if (m_pCamWnd->m_bFreeMove) + { + OnCameraStrafeleft(keydown); + return; + } + } + + if (g_PrefsDlg.m_bCamDiscrete) + { + if(keydown) + { + m_pCamWnd->Camera()->angles[1] += SPEED_TURN; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_ROTLEFT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_ROTLEFT; + } +} + +void MainFrame::OnCameraRight(bool keydown) +{ + if (m_pCamWnd) + { + if (m_pCamWnd->m_bFreeMove) + { + OnCameraStraferight(keydown); + return; + } + } + + if (g_PrefsDlg.m_bCamDiscrete) + { + if(keydown) + { + m_pCamWnd->Camera()->angles[1] -= SPEED_TURN; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_ROTRIGHT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_ROTRIGHT; + } +} + +void MainFrame::OnCameraUp() +{ + m_pCamWnd->Camera()->origin[2] += SPEED_MOVE; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY | W_Z) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); +} + +void MainFrame::OnCameraDown() +{ + m_pCamWnd->Camera()->origin[2] -= SPEED_MOVE; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY | W_Z) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); +} + +void MainFrame::OnCameraAngleup() +{ + m_pCamWnd->Camera()->angles[0] += SPEED_TURN; + if (m_pCamWnd->Camera()->angles[0] > 85) + m_pCamWnd->Camera()->angles[0] = 85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); +} + +void MainFrame::OnCameraAngledown() +{ + m_pCamWnd->Camera()->angles[0] -= SPEED_TURN; + if (m_pCamWnd->Camera()->angles[0] < -85) + m_pCamWnd->Camera()->angles[0] = -85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); +} + +void MainFrame::OnCameraStrafeleft(bool keydown) +{ + // FIXME: as soon as gtk supports proper keyup/down support, remove this bit + if (m_pCamWnd) + { + if (!m_pCamWnd->m_bFreeMove) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, -SPEED_MOVE, m_pCamWnd->Camera()->right, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + return; + } + } + + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_STRAFELEFT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_STRAFELEFT; +} + +void MainFrame::OnCameraStraferight(bool keydown) +{ + // FIXME: as soon as gtk supports proper keyup/down support, remove this bit + if (m_pCamWnd) + { + if (!m_pCamWnd->m_bFreeMove) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, SPEED_MOVE, m_pCamWnd->Camera()->right, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + return; + } + } + + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_STRAFERIGHT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_STRAFERIGHT; +} + +void MainFrame::OnGridToggle() +{ + g_qeglobals.d_showgrid = !g_qeglobals.d_showgrid; + Sys_UpdateWindows (W_XY|W_Z); +} + +void MainFrame::OnViewCrosshair() +{ + g_bCrossHairs ^= 1; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnSelectionTextureRotateclock() +{ + Select_RotateTexture(abs(g_PrefsDlg.m_nRotation)); +} + +void MainFrame::OnSelectionTextureRotatecounter() +{ + Select_RotateTexture(-abs(g_PrefsDlg.m_nRotation)); +} + +void MainFrame::OnSelectionTextureScaleup() +{ + Select_ScaleTexture(0, g_qeglobals.d_savedinfo.m_SIIncrement.scale[1]); +} + +void MainFrame::OnSelectionTextureScaledown() +{ + Select_ScaleTexture(0, -g_qeglobals.d_savedinfo.m_SIIncrement.scale[1]); +} + +void MainFrame::OnSelectionTextureScaleLeft() +{ + Select_ScaleTexture(-g_qeglobals.d_savedinfo.m_SIIncrement.scale[0],0); +} + +void MainFrame::OnSelectionTextureScaleRight() +{ + Select_ScaleTexture(g_qeglobals.d_savedinfo.m_SIIncrement.scale[0],0); +} + +void MainFrame::OnSelectionTextureShiftleft() +{ + Select_ShiftTexture((int)-g_qeglobals.d_savedinfo.m_SIIncrement.shift[0], 0); +} + +void MainFrame::OnSelectionTextureShiftright() +{ + Select_ShiftTexture((int)g_qeglobals.d_savedinfo.m_SIIncrement.shift[0], 0); +} + +void MainFrame::OnSelectionTextureShiftup() +{ + Select_ShiftTexture(0, (int)g_qeglobals.d_savedinfo.m_SIIncrement.shift[1]); +} + +void MainFrame::OnSelectionTextureShiftdown() +{ + Select_ShiftTexture(0, (int)-g_qeglobals.d_savedinfo.m_SIIncrement.shift[1]); +} + +void MainFrame::OnGridPrev() +{ + GtkWidget *item; + if (g_qeglobals.d_gridsize == 1) + { + g_qeglobals.d_gridsize = 0.5; + g_qeglobals.d_bSmallGrid = true; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_05")); + } else if (g_qeglobals.d_gridsize == 0.5) + { + g_qeglobals.d_gridsize = 0.25; + g_qeglobals.d_bSmallGrid = true; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_025")); + } else if (g_qeglobals.d_gridsize > 1) + { + g_qeglobals.d_gridsize = (int)g_qeglobals.d_gridsize >> 1; + g_qeglobals.d_bSmallGrid = false; + + switch ((int)g_qeglobals.d_gridsize) + { + case 1: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); break; + case 2: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_2")); break; + case 4: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_4")); break; + case 8: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_8")); break; + case 16: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_16")); break; + case 32: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_32")); break; + case 64: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_64")); break; + case 128: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_128")); break; + case 256: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_256")); break; + } + + } else + return; + + // SnapTToGrid option: need to check everywhere the grid size is changed + // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext + if (g_PrefsDlg.m_bSnapTToGrid) + DoSnapTToGrid(); + + SetGridStatus(); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Sys_UpdateWindows(W_XY | W_Z); +} + +void MainFrame::OnGridNext() +{ + GtkWidget *item; + if (g_qeglobals.d_gridsize == 0.25) + { + g_qeglobals.d_gridsize = 0.5; + g_qeglobals.d_bSmallGrid = true; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_05")); + } else if (g_qeglobals.d_gridsize == 0.5) + { + g_qeglobals.d_gridsize = 1; + g_qeglobals.d_bSmallGrid = false; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); + } else if (g_qeglobals.d_gridsize < 256) + { + g_qeglobals.d_gridsize = (int)g_qeglobals.d_gridsize << 1; + g_qeglobals.d_bSmallGrid = false; + + switch ((int)g_qeglobals.d_gridsize) + { + case 1: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); break; + case 2: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_2")); break; + case 4: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_4")); break; + case 8: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_8")); break; + case 16: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_16")); break; + case 32: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_32")); break; + case 64: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_64")); break; + case 128: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_128")); break; + case 256: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_256")); break; + } + + } else + return; + + // SnapTToGrid option: need to check everywhere the grid size is changed + // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext + if (g_PrefsDlg.m_bSnapTToGrid) + DoSnapTToGrid(); + + SetGridStatus(); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Sys_UpdateWindows(W_XY | W_Z); +} + +void MainFrame::OnSelectionMovedown() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("move down"); + Undo_AddBrushList(&selected_brushes); + + vec3_t vAmt; + vAmt[0] = vAmt[1] = 0.0; + vAmt[2] = -g_qeglobals.d_gridsize; + Select_Move (vAmt); + Sys_UpdateWindows(W_CAMERA | W_XY | W_Z); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMoveup() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("move up"); + Undo_AddBrushList(&selected_brushes); + + vec3_t vAmt; + vAmt[0] = vAmt[1] = 0.0; + vAmt[2] = g_qeglobals.d_gridsize; + Select_Move (vAmt); + Sys_UpdateWindows(W_CAMERA | W_XY | W_Z); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionPrint() +{ + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + Brush_Print(b); +} + +void MainFrame::OnSelectionTogglesizepaint() +{ + g_PrefsDlg.m_bSizePaint = !g_PrefsDlg.m_bSizePaint; + Sys_UpdateWindows(W_XY); +} + +void MainFrame::OnPatchNaturalize() +{ + Patch_NaturalizeSelected(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnSnapToGrid() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("snap selection to grid"); + Undo_AddBrushList(&selected_brushes); + //Select_SnapToGrid(); + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + Patch_SnapToGrid(pb->pPatch); + else + Brush_SnapToGrid(pb); + } + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectAll() +{ + Select_AllOfType(); +} + +void MainFrame::OnSelectionInvert() +{ + Select_Invert(); + Sys_UpdateWindows(W_XY | W_Z | W_CAMERA); +} + + +void PerformFiltering () +{ + brush_t *brush; + + // spog - deletes old filters list and creates new one when + // g_qeglobals.d_savedinfo.exclude is updated + g_qeglobals.d_savedinfo.filters = FilterListDelete(g_qeglobals.d_savedinfo.filters); + g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters); + + for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) + brush->bFiltered = FilterBrush( brush ); + + for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next ) + brush->bFiltered = FilterBrush( brush ); +} + +void MainFrame::OnFilterAreaportals() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_areaportals")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_AREAPORTALS) & EXCLUDE_AREAPORTALS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterCaulk() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_caulk")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CAULK) & EXCLUDE_CAULK) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterClips() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clips")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLIP) & EXCLUDE_CLIP) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterBotClips() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_botclips")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_BOTCLIP) & EXCLUDE_BOTCLIP) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterStructural() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_structural")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_STRUCTURAL) & EXCLUDE_STRUCTURAL) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterDetails() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_details")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_DETAILS) & EXCLUDE_DETAILS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterEntities() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_entities")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT) & EXCLUDE_ENT) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterHintsskips() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_hintsskips")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_HINTSSKIPS) & EXCLUDE_HINTSSKIPS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterLights() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lights")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTS) & EXCLUDE_LIGHTS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterLiquids() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_liquids")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIQUIDS) & EXCLUDE_LIQUIDS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterModels() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_models")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_MODELS) & EXCLUDE_MODELS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterPatches() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_patches")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CURVES) & EXCLUDE_CURVES) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterPaths() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_paths")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_PATHS) & EXCLUDE_PATHS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterClusterportals() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLUSTERPORTALS) & EXCLUDE_CLUSTERPORTALS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterLightgrid() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTGRID) & EXCLUDE_LIGHTGRID) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterTranslucent() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_translucent")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRANSLUCENT) & EXCLUDE_TRANSLUCENT) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterTriggers() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_triggers")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRIGGERS) & EXCLUDE_TRIGGERS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterWorld() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_world")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WORLD) & EXCLUDE_WORLD) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + + + + + + + + +// ============================================================================= +// leo: Unused functions, not called anywhere from the code (need to check) + +void MainFrame::OnViewConsole() +{ + if (FloatingGroupDialog()) // QE4 style + { + if (inspector_mode == W_CONSOLE && CurrentStyle() != MainFrame::eFloating) // are we in console mode already? + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_CONSOLE); + } + } +} + +void MainFrame::OnCurveFreeze() +{ + Patch_Freeze(); +} + +void MainFrame::OnCurveUnFreeze() +{ + Patch_UnFreeze(false); +} + +void MainFrame::OnCurveUnFreezeAll() +{ + Patch_UnFreeze(true); +} + +void MainFrame::OnSelectReselect() +{ + Select_Reselect(); +} + +void MainFrame::OnSelectionTextureFit() +{ + // TODO: Add your command handler code here +} + +void MainFrame::OnPatchEnter() +{ + +} + +void MainFrame::OnDropGroupAddtoWorld() +{ + /* + Select_AddToGroup("World"); + Sys_UpdateWindows (W_ALL); + */ +} diff --git a/radiant/mainframe.h b/radiant/mainframe.h new file mode 100644 index 00000000..7b2cb63f --- /dev/null +++ b/radiant/mainframe.h @@ -0,0 +1,909 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _MAINFRAME_H_ +#define _MAINFRAME_H_ + +#include "xywindow.h" +#include "texwindow.h" +#include "zwindow.h" +#include "camwindow.h" +#include "watchbsp.h" + +#include "pluginmanager.h" +#include "plugin.h" + +#include "gtkr_vector.h" + +#ifdef __APPLE__ +#define __toascii(c) ((c) & 0x7f) +#endif + +const int RAD_SHIFT = 0x01; +const int RAD_ALT = 0x02; +const int RAD_CONTROL = 0x04; +const int RAD_PRESS = 0x08; + +struct SCommandInfo +{ + char* m_strCommand; + unsigned int m_nKey; + unsigned int m_nModifiers; + unsigned int m_nCommand; + char* m_strMenu; +}; + +struct SKeyInfo +{ + char* m_strName; + unsigned int m_nVKKey; +}; + +#define ID_FILE_NEW 0xE100 +#define ID_FILE_OPEN 0xE101 +#define ID_FILE_SAVE 0xE103 +#define ID_EDIT_UNDO 0xE12B +#define ID_EDIT_REDO 0xE12C +#define ID_HELP 0xE146 +#define ID_FILE_RECENT1 0xE110 +#define ID_FILE_RECENT2 0xE111 +#define ID_FILE_RECENT3 0xE112 +#define ID_FILE_RECENT4 0xE113 + +#define IDC_BTN_FACEFIT 1143 +#define ID_ENTITY_START 22800 +#define ID_ENTITY_END 32000 //leo +//#define ID_ENTITY_END 33500 +#define ID_VIEW_XY 32772 +#define ID_VIEW_SIDE 32773 +#define ID_VIEW_FRONT 32774 +#define ID_CAMERATOGGLE 32775 +#define ID_VIEW_CAMERATOGGLE 32776 +#define ID_BUTTON32777 32777 +#define ID_BUTTON32778 32778 +#define ID_TEXTURES_POPUP 32780 +#define ID_POPUP_SELECTION 32782 +#define ID_VIEW_CHANGE 32783 +#define ID_VIEW_CAMERAUPDATE 32784 +#define ID_VIEW_CLIPPER 32785 +#define ID_PREFS 32786 +#define ID_TOGGLE_LOCK 32787 +#define ID_EDIT_MAPINFO 32788 +#define ID_EDIT_ENTITYINFO 32789 +#define ID_BRUSH_SCRIPTS 32790 +#define ID_VIEW_NEXTVIEW 32791 +#define ID_HELP_COMMANDLIST 32792 +#define ID_FILE_NEWPROJECT 32793 +#define ID_SNAPTOGRID 32795 +#define ID_VIEW_CENTERVIEW 32796 +#define ID_SPLIT_SELECTED 32823 +#define ID_CLIP_SELECTED 32824 +#define ID_FLIP_CLIP 32825 +#define ID_TOGGLEVIEW_YZ 32831 +#define ID_TOGGLEVIEW_XZ 32832 +#define ID_COLORS_GRIDTEXT 32833 +#define ID_COLORS_BRUSH 32834 +#define ID_COLORS_SELECTEDBRUSH 32835 +#define ID_COLORS_CLIPPER 32836 +#define ID_COLORS_GRIDBLOCK 32837 +#define ID_COLORS_VIEWNAME 32838 +#define ID_COLOR_SETORIGINAL 32839 +#define ID_COLOR_SETQER 32840 +#define ID_COLOR_SETBLACK 32841 +#define ID_COLOR_SETYDNAR 37001 /* ydnar */ +#define ID_BYEBYE 32842 +#define ID_SELECT_SCALE 32843 +#define ID_SELECT_MOUSEROTATE 32844 +#define ID_COLORS_SELECTEDBRUSH3D 32845 +#define ID_COLORS_CAMERABACK 32846 +#define ID_TEXTURE_REPLACESELECTED 32859 +#define ID_TEXTURE_REPLACEALL 32860 +#define ID_SELECT_MOUSESCALE 32866 +#define ID_SCALELOCKX 32867 +#define ID_SCALELOCKY 32868 +#define ID_SCALELOCKZ 32869 +#define ID_VIEW_CUBICCLIPPING 32870 +#define ID_FILE_PROJECTSETTINGS 32875 +#define ID_VIEW_CUBEOUT 32876 +#define ID_VIEW_CUBEIN 32877 +#define ID_NODES_LOADNODES 32878 +#define ID_NODES_SHOWNODES 32879 +#define ID_NODES_SHOWLINKS 32880 +#define ID_NODES_REMOVEALLNODES 32881 +#define ID_NODES_COUNTNODES 32882 +#define ID_NODES_GIVEMONEYTONELNO 32883 +#define ID_FILE_SAVEREGION 32887 +#define ID_FILE_LOADREGION 32888 +#define ID_SELECTION_MOVEDOWN 32890 +#define ID_TOOLBAR_MAIN 32891 +#define ID_SELECTION_MOVEUP 32892 +//#define ID_TOOLBAR_TEXTURE 32892 +#define ID_BRUSH_MAKECONE 32896 +#define ID_TEXTURES_LOAD 32897 +#define ID_TOGGLE_ROTATELOCK 32898 +#define ID_FILE_IMPORTMAP 32911 +#define ID_FILE_EXPORTMAP 32912 +#define ID_EDIT_LOADPREFAB 32913 +#define ID_SELECTION_SELECT_NUDGELEFT 32916 +#define ID_SELECTION_SELECT_NUDGERIGHT 32917 +#define ID_SELECTION_SELECT_NUDGEUP 32918 +#define ID_SELECTION_SELECT_NUDGEDOWN 32919 +#define ID_TEXTURES_LOADLIST 32920 +#define ID_DONTSELECTCURVE 32923 +#define ID_CONVERTCURVES 32924 +#define ID_PATCH_SHOWBOUNDINGBOX 32926 +#define ID_CURVE_SIMPLEPATCHMESH 32927 +#define ID_PATCH_WIREFRAME 32928 +#define ID_PATCH_WELD 32929 +#define ID_CURVE_PATCHTUBE 32930 +#define ID_CURVE_PATCHCONE 32931 +#define ID_CURVE_PATCHENDCAP 32932 +#define ID_CURVE_PATCHBEVEL 32933 +#define ID_PATCH_DRILLDOWN 32936 +#define ID_CURVE_LOADPATCHFILE 32937 +#define ID_CURVE_INSERTROW 32938 +#define ID_CURVE_INSERTCOLUMN 32939 +#define ID_CURVE_DELETEROW 32940 +#define ID_CURVE_DELETECOLUMN 32941 +#define ID_BUTTON32942 32942 +//#define ID_PATCH_INSDEL 32942 +#define ID_CURVE_INSERT_ADDCOLUMN 32943 +#define ID_CURVE_INSERT_INSERTCOLUMN 32944 +#define ID_CURVE_INSERT_ADDROW 32945 +#define ID_CURVE_INSERT_INSERTROW 32946 +#define ID_CURVE_DELETE_FIRSTCOLUMN 32947 +#define ID_CURVE_DELETE_LASTCOLUMN 32948 +#define ID_CURVE_DELETE_FIRSTROW 32949 +#define ID_CURVE_DELETE_LASTROW 32950 +#define ID_CURVE_NEGATIVE 32951 +#define ID_PATCH_BEND 32952 +#define ID_CURVE_PATCHDENSETUBE 32955 +#define ID_CURVE_PATCHVERYDENSETUBE 32956 +#define ID_CURVE_CAP 32957 +#define ID_CURVE_REDISPERSE_ROWS 32961 +#define ID_PATCH_NATURALIZE 32963 +#define ID_CURVE_PATCHSQUARE 32964 +#define ID_BRUSH_PRIMITIVES_SPHERE 32965 +#define ID_BRUSH_PRIMITIVES_TORUS 32966 +#define ID_TEXTURES_TEXTUREWINDOWSCALE_200 32967 +#define ID_TEXTURES_TEXTUREWINDOWSCALE_100 32968 +#define ID_TEXTURES_TEXTUREWINDOWSCALE_50 32969 +#define ID_TEXTURES_TEXTUREWINDOWSCALE_25 32970 +#define ID_TEXTURES_TEXTUREWINDOWSCALE_10 32971 +#define ID_CURVE_NEGATIVETEXTUREX 32972 +#define ID_TEXTURES_FLUSH 32973 +#define ID_CURVE_OVERLAY_SET 32974 +#define ID_CURVE_OVERLAY_CLEAR 32975 +#define ID_CURVE_NEGATIVETEXTUREY 32976 +#define ID_CURVE_THICKEN 32977 +#define ID_CURVE_CYCLECAP 32978 +#define ID_CURVE_MATRIX_TRANSPOSE 32981 +#define ID_PLUGINS_REFRESH 32982 +#define ID_TEXTURES_RELOADSHADERS 32983 +#define ID_VIEW_ENTITIESAS_BOUNDINGBOX 32984 +#define ID_VIEW_ENTITIESAS_WRITEFRAME 32985 +#define ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME 32986 +#define ID_VIEW_ENTITIESAS_SELECTEDSKINNED 32987 +#define ID_VIEW_ENTITIESAS_SKINNED 32988 +#define ID_VIEW_ENTITIESAS_SKINNEDANDBOXED 32989 +#define ID_SHOW_ENTITIES 32990 +#define ID_VIEW_ENTITIESAS_WIREFRAME 32991 +#define ID_VIEW_OPENGLLIGHTING 32998 +#define ID_EDIT_SAVEPREFAB 33001 +#define ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP 33002 +#define ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL 33003 +#define ID_CURVE_PRIMITIVES_SPHERE 33005 +#define ID_VIEW_HIDESHOW_HIDESELECTED 33006 +#define ID_VIEW_HIDESHOW_SHOWHIDDEN 33007 +#define ID_TEXTURES_SHADERS_SHOW 33008 +//#define ID_SELECTION_CSGADD 33009 +#define ID_SELECTION_CSGMERGE 33011 +#define ID_TEXTURES_FLUSH_UNUSED 33014 +#define ID_DROP_GROUP_REMOVE 33016 +#define ID_DROP_GROUP_ADDTO_WORLD 33017 +#define ID_DROP_GROUP_NEWGROUP 33018 +#define ID_DROP_GROUP_NAME 33019 +#define ID_DROP_GROUP_ADDTO 33020 +#define ID_VIEW_SHOWANGLES 33021 +#define ID_VIEW_SHOWWORKZONE 33022 +#define ID_TEXTURE_FLUSH 33023 +#define ID_TEXTURES_SHOWSHADERS 33025 +#define ID_DONTSELECTMODEL 33027 +#define ID_TEXTURES_SHADERLISTONLY 33030 +#define ID_PLUGIN_START 33800 +#define ID_PLUGIN_END 33999 +#define ID_FILE_EXIT 40002 +#define ID_FILE_SAVEAS 40004 +#define ID_VIEW_CENTER 40005 +#define ID_VIEW_UPFLOOR 40006 +#define ID_VIEW_DOWNFLOOR 40007 +#define ID_BRUSH_FLIPX 40008 +#define ID_BRUSH_FLIPY 40009 +#define ID_BRUSH_FLIPZ 40010 +#define ID_BRUSH_ROTATEX 40011 +#define ID_BRUSH_ROTATEY 40012 +#define ID_BRUSH_ROTATEZ 40013 +#define ID_BSP_FULLVIS 40016 +#define ID_BSP_FASTVIS 40017 +#define ID_BSP_NOVIS 40018 +#define ID_BSP_RELIGHT 40019 +#define ID_BSP_ENTITIES 40020 +#define ID_FILE_POINTFILE 40021 +#define ID_VIEW_100 40022 +#define ID_VIEW_75 40023 +#define ID_VIEW_50 40024 +#define ID_VIEW_25 40025 +#define ID_VIEW_12 40026 +#define ID_TEXTURES_SHOWALL 40033 +#define ID_TEXTURES_SHOWINUSE 40034 +#define ID_TEXTURES_TOGGLEVIEW 40037 +#define ID_SELECTION_CREATEENTITY 40039 +#define ID_SELECTION_EDITENTITY 40040 +#define ID_MISC_BENCHMARK 40041 +#define ID_REGION_OFF 40043 +#define ID_REGION_SETXY 40044 +#define ID_REGION_SETBRUSH 40045 +#define ID_SELECTION_MAKEHOLLOW 40046 +#define ID_SELECTION_SELECTPARTIALTALL 40047 +#define ID_SELECTION_SELECTCOMPLETETALL 40048 +#define ID_SELECTION_CSGSUBTRACT 40049 +#define ID_SELECTION_SELECTTOUCHING 40050 +#define ID_VIEW_NEAREST 40052 +#define ID_VIEW_NEARESTMIPMAP 40053 +#define ID_VIEW_LINEAR 40054 +#define ID_VIEW_BILINEAR 40055 +#define ID_VIEW_BILINEARMIPMAP 40056 +#define ID_VIEW_TRILINEAR 40057 +#define ID_TEXTURES_WIREFRAME 40058 +#define ID_TEXTURES_FLATSHADE 40059 +#define ID_VIEW_SHOWNAMES 40060 +#define ID_VIEW_ZOOMIN 40061 +#define ID_VIEW_ZOOMOUT 40062 +#define ID_VIEW_SHOWCOORDINATES 40063 +#define ID_VIEW_Z100 40064 +#define ID_VIEW_ZZOOMIN 40065 +#define ID_VIEW_ZZOOMOUT 40066 +#define ID_SELECTION_CLONE 40067 +#define ID_SELECTION_DESELECT 40068 +#define ID_SELECTION_DELETE 40069 +#define ID_BUTTON40068 40070 +#define ID_SELECTION_DRAGVERTECIES 40074 +#define ID_SELECTION_DRAGEDGES 40075 +#define ID_REGION_SETTALLBRUSH 40076 +#define ID_SELECTION_SELECTINSIDE 40092 +#define ID_PROJECT_RELEAD 40094 +#define ID_PROJECT_CHANGE 40095 +#define ID_MISC_GAMMA 40097 +#define ID_MISC_TEXTUREBACKGROUN 40104 +#define ID_TEXTUREBK 40105 +#define ID_COLORS_XYBK 40106 +#define ID_FILE_ABOUT 40107 +#define ID_VIEW_CONSOLE 40108 +#define ID_VIEW_ENTITY 40109 +#define ID_VIEW_TEXTURE 40110 +#define ID_COLORS_MAJOR 40111 +#define ID_COLORS_MINOR 40113 +#define ID_SELECTION_CONNECT 40114 +#define ID_FILE_LOADPROJECT 40115 +#define ID_MISC_FINDBRUSH 40116 +#define ID_MISC_NEXTLEAKSPOT 40117 +#define ID_MISC_PREVIOUSLEAKSPOT 40118 +#define ID_BRUSH_3SIDED 40119 +#define ID_BRUSH_4SIDED 40120 +#define ID_BRUSH_5SIDED 40121 +#define ID_BRUSH_6SIDED 40122 +#define ID_BRUSH_7SIDED 40123 +#define ID_BRUSH_8SIDED 40124 +#define ID_BRUSH_9SIDED 40125 +#define ID_SELECTION_ARBITRARYROTATION 40126 +#define ID_BRUSH_ARBITRARYSIDED 40127 +#define ID_SELECTION_UNGROUPENTITY 40130 +#define ID_MISC_SELECTENTITYCOLOR 40131 +#define ID_MISC_PRINTXY 40132 +#define ID_HELP_ABOUT 40134 +#define ID_EDIT_COPYBRUSH 40135 +#define ID_EDIT_PASTEBRUSH 40136 +#define ID_TEXTURES_INSPECTOR 40137 +#define ID_SELECTION_MAKE_DETAIL 40139 +#define ID_SELECTION_MAKE_STRUCTURAL 40140 +#define ID_REGION_SETSELECTION 40141 +#define ID_VIEW_SHOWBLOCKS 40142 +#define ID_CAMERA_UP 40152 +#define ID_CAMERA_DOWN 40153 +#define ID_CAMERA_LEFT 40154 +#define ID_CAMERA_RIGHT 40155 +#define ID_CAMERA_FORWARD 40156 +#define ID_CAMERA_BACK 40157 +#define ID_CAMERA_ANGLEUP 40158 +#define ID_CAMERA_ANGLEDOWN 40159 +#define ID_CAMERA_STRAFELEFT 40160 +#define ID_CAMERA_STRAFERIGHT 40161 +#define ID_GRID_TOGGLE 40162 +#define ID_ENTITYLIST 40163 +#define ID_MAPINFO 40164 +#define ID_TOGGLECONSOLE 40165 +#define ID_TOGGLECAMERA 40166 +#define ID_TOGGLEZ 40167 +#define ID_TOGGLEVIEW 40168 +#define ID_SELECTION_TEXTURE_FIT 40171 +#define ID_SELECTION_TEXTURE_ROTATECLOCK 40172 +#define ID_SELECTION_TEXTURE_ROTATECOUNTER 40173 +#define ID_SELECTION_TEXTURE_SCALEUP 40174 +#define ID_SELECTION_TEXTURE_SCALEDOWN 40175 +#define ID_SELECTION_TEXTURE_SHIFTLEFT 40176 +#define ID_SELECTION_TEXTURE_SHIFTRIGHT 40177 +#define ID_SELECTION_TEXTURE_SHIFTUP 40178 +#define ID_SELECTION_TEXTURE_SHIFTDOWN 40179 +#define ID_GRID_NEXT 40180 +#define ID_GRID_PREV 40181 +#define ID_SELECTION_TEXTURE_SCALELEFT 40182 +#define ID_SELECTION_TEXTURE_SCALERIGHT 40183 +#define ID_SELECTION_PRINT 40184 +#define ID_SELECTION_TOGGLESIZEPAINT 40185 +#define ID_PATCH_TAB 40186 +#define ID_PATCH_ENTER 40187 +#define ID_SELECT_SNAPTOGRID 40188 +#define ID_PATCH_INSPECTOR 40189 +#define ID_SELECT_ALL 40190 +#define ID_CURVE_FREEZE 40191 +#define ID_CURVE_UNFREEZE 40192 +#define ID_CURVE_UNFREEZEALL 40193 +#define ID_SELECT_RESELECT 40194 +#define ID_FITFACE 40196 +#define ID_VIEW_CROSSHAIR 40197 +#define ID_SELECTION_INVERT 40198 +#define ID_VIEW_GROUPS 40199 +#define ID_FILE_SLEEP 40200 +#define ID_HELP_LINKS 40201 +#define ID_VIEW_SHOWOUTLINE 40202 // TTimo: outline as in colored outline around the window to quickly guess the orientation +#define ID_VIEW_SHOWAXES 40203 +#define ID_SELECTION_NOOUTLINE 40204 // TTimo: outline as in zbuffered outline toggle on camera view (TA Q3Radiant 200f addition) +#define ID_SELECTION_OUTLINESTYLE 40205 // Arnout: cycles through selection styles (extended 'nooutline') +#define ID_SELECTION_SEPERATE 40206 // TTimo: split brushes out of an entity back into worldspawn +#define ID_SELECTION_MERGE 40207 // TTimo: merge brushes from worldspawn into entity +#define ID_HELP_BUGREPORT 40208 + +#define ID_FILTER_WORLD 40209 +#define ID_FILTER_PATCHES 40210 +#define ID_FILTER_DETAILS 40211 +#define ID_FILTER_ENTITIES 40212 +#define ID_FILTER_MODELS 40213 +#define ID_FILTER_HINTSSKIPS 40214 +#define ID_FILTER_CLIPS 40215 +#define ID_FILTER_LIQUIDS 40216 +#define ID_FILTER_TRIGGERS 40217 +#define ID_FILTER_AREAPORTALS 40218 +#define ID_FILTER_TRANSLUCENT 40219 +#define ID_FILTER_CAULK 40220 +#define ID_FILTER_LIGHTS 40221 +#define ID_FILTER_PATHS 40223 +#define ID_FILTER_CLUSTERPORTALS 40224 +#define ID_FILTER_LIGHTGRID 40225 +#define ID_FILTER_STRUCTURAL 40226 +#define ID_FILTER_BOTCLIPS 40227 + +#define ID_CURVE_REDISPERSE_INTERMEDIATE_COLS 40230 +#define ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS 40231 +#define ID_EDIT_PASTEBRUSHTOCAMERA 40232 + +#define ID_COLORS_MINOR_ALT 40230 +#define ID_COLORS_MAJOR_ALT 40231 + +// those must have their own ID chunk ID_GRID_025 <= ID_GRID <= ID_GRID_256 +#define ID_GRID_025 40300 +#define ID_GRID_05 40301 +#define ID_GRID_1 40302 +#define ID_GRID_2 40303 +#define ID_GRID_4 40304 +#define ID_GRID_8 40305 +#define ID_GRID_16 40306 +#define ID_GRID_32 40307 +#define ID_GRID_64 40308 +#define ID_GRID_128 40309 +#define ID_GRID_256 40310 + +#define ID_FILE_CHECKUPDATE 40320 + +#define ID_TEXTUREWINDOW_SCALEUP 40321 +#define ID_TEXTUREWINDOW_SCALEDOWN 40322 + +class CSynapseClientRadiant : public CSynapseClient +{ +public: + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + void ImportMap(IDataStream *in, CPtrArray *ents, const char *type); + void ExportMap(CPtrArray *ents, IDataStream *out, const char *type); + + CSynapseClientRadiant() { } + virtual ~CSynapseClientRadiant() { } +}; + +class MainFrame +{ +public: + enum EViewStyle + { + eRegular, + eFloating, + eSplit, + eRegularLeft, + }; + + MainFrame(); + GtkWidget *m_pWidget; + + /*! + called to fire up the help links + */ + void handle_help_command(int id); + +protected: + + /*! + the urls to fire up in the game packs help menus + */ + vector mHelpURLs; + + /*! + scan the .game files for game install packs + look there for help description nodes + build the corresponding menus in Radiant + */ + void create_game_help_menu (GtkWidget *menu, GtkAccelGroup *accel); + + /*! + build the menu once the filename is found + */ + void process_xlink (Str &FileName, char *menu_name, const char *base_url, GtkWidget *menu, GtkAccelGroup *accel); + + void Create (); + void create_main_menu (GtkWidget *window, GtkWidget *vbox); + void create_main_toolbar (GtkWidget *window, GtkWidget *vbox); + void create_plugin_toolbar (GtkWidget *window, GtkWidget *vbox); + void create_main_statusbar (GtkWidget *window, GtkWidget *vbox); + GtkWidget *m_pStatusLabel[6]; + GtkWidget *m_pSplits[4]; + XYWnd* m_pXYWnd; + XYWnd* m_pYZWnd; + XYWnd* m_pXZWnd; + CamWnd* m_pCamWnd; + TexWnd* m_pTexWnd; + ZWnd* m_pZWnd; + CWatchBSP* m_pWatchBSP; + + XYWnd* m_pActiveXY; + bool m_bCamPreview; + CPlugInManager m_PlugInMgr; + int m_nNextPlugInID; + guint m_nTimer; + bool m_bSleeping; + + CString m_strStatus[15]; + bool m_bNeedStatusUpdate; + + /*! + synapse server + deals with dynamically loading the modules, initializing them, requesting the APIs + */ + CSynapseServer m_SynapseServer; + /*! + we are also a synapse client in that we provide and require some APIs as well + */ + CSynapseClientRadiant m_SynapseClient; + +public: + + // BSP window + // trigger network listen + void DoWatchBSP(); + bool IsSleeping () + { return m_bSleeping; } + + void UpdatePatchToolbarButtons(); + // Gef: Changed to float for sub-integer grid size + void NudgeSelection(int nDirection, float nAmount); + void SetButtonMenuStates(); + void SetGridStatus(); + void RoutineProcessing(); + XYWnd* ActiveXY() { return m_pActiveXY; }; + void UpdateWindows(int nBits); + void SetStatusText(int nPane, const char* pText); + void UpdateStatusText(); + void SetWindowStyle(int nStyle); + virtual ~MainFrame(); + XYWnd* GetXYWnd() {return m_pXYWnd;} + XYWnd* GetXZWnd() {return m_pXZWnd;} + XYWnd* GetYZWnd() {return m_pYZWnd;} + ZWnd* GetZWnd() {return m_pZWnd;} + CamWnd* GetCamWnd() {return m_pCamWnd;} + TexWnd* GetTexWnd() {return m_pTexWnd;} + CWatchBSP *GetWatchBSP() { return m_pWatchBSP; } + void ReleaseContexts (); + void CreateContexts (); + + void SetActiveXY(XYWnd* p) + { + if (m_pActiveXY) + m_pActiveXY->SetActive(false); + + m_pActiveXY = p; + + if (m_pActiveXY) + m_pActiveXY->SetActive(true); + + }; + + EViewStyle CurrentStyle() + { + return m_nCurrentStyle; + }; + + bool FloatingGroupDialog() + { + return CurrentStyle() == eFloating || CurrentStyle() == eSplit; + }; + +#ifdef _WIN32 + const GdkRectangle & GetPrimaryMonitorRect( void ) const { return primaryMonitorRect; } + const int GetGDKOffsetX( void ) const { return gdk_offset_x; } + const int GetGDKOffsetY( void ) const { return gdk_offset_y; } +#endif + +protected: + bool m_bDoLoop; + bool m_bSplittersOK; + void CreateQEChildren(); + void LoadCommandMap(); + void ShowMenuItemKeyBindings(GtkWidget* window); + +public: + void Copy(); + void Paste(); + void Nudge(int nDim, float fNudge); + CPlugInManager &GetPlugInMgr() {return m_PlugInMgr;}; + CSynapseServer &GetSynapseServer() {return m_SynapseServer;}; + CSynapseClientRadiant &GetSynapseClient() {return m_SynapseClient;}; + void AddPlugInToolbarButton(const IToolbarButton* button); + void AddPlugInMenuItem(IPlugIn* pPlugIn); + void CleanPlugInMenu(); + + // these are public so i can easily reflect messages + // from child windows.. + void OnTimer(); + void OnDelete(); + void OnDestroy(); + void ToggleCamera(); + + void OnFileExit(); + void OnFileLoadproject(); + void OnFileNew(); + void OnFileOpen(); + void OnFilePointfile(); + void OnFileSave(); + void OnFileSaveas(); + void OnFileCheckUpdate(); + void OnView100(); + void OnViewCenter(); + void OnViewConsole(); + void OnViewDownfloor(); + void OnViewEntity(); + void OnViewFront(); + void OnViewShowblocks(); + void OnViewShowclip(); + void OnViewShowcoordinates(); + void OnViewShowOutline(); + void OnViewShowAxes(); + void OnViewShowdetail(); + void OnViewShowent(); + void OnViewShowlights(); + void OnViewShownames(); + void OnViewShowpath(); + void OnViewShowwater(); + void OnViewShowworld(); + void OnViewTexture(); + void OnViewUpfloor(); + void OnViewXy(); + void OnViewZ100(); + void OnViewZoomin(); + void OnViewZoomout(); + void OnViewZzoomin(); + void OnViewZzoomout(); + void OnViewSide(); + void OnTexturesShowinuse(); + void OnTexturesInspector(); + void OnMiscBenchmark(); + void OnMiscFindbrush(); + void OnMiscGamma(); + void OnMiscNextleakspot(); + void OnMiscPreviousleakspot(); + void OnMiscPrintxy(); + void OnMiscSelectentitycolor(); + void OnTexturebk(); + void OnColorsMajor(); + void OnColorsMinor(); + void OnColorsMajor_Alt(); + void OnColorsMinor_Alt(); + void OnColorsXybk(); + void OnBrush3sided(); + void OnBrush4sided(); + void OnBrush5sided(); + void OnBrush6sided(); + void OnBrush7sided(); + void OnBrush8sided(); + void OnBrush9sided(); + void OnBrushArbitrarysided(); + void OnBrushFlipx(); + void OnBrushFlipy(); + void OnBrushFlipz(); + void OnBrushRotatex(); + void OnBrushRotatey(); + void OnBrushRotatez(); + void OnRegionOff(); + void OnRegionSetbrush(); + void OnRegionSetselection(); + void OnRegionSettallbrush(); + void OnRegionSetxy(); + void OnSelectionArbitraryrotation(); + void OnSelectionClone(); + void OnSelectionConnect(); + void OnSelectionCsgsubtract(); + void OnSelectionCsgmerge(); + void OnSelectionNoOutline(); + void OnSelectionOutlineStyle(); + void OnSelectionDelete(); + void OnSelectionDeselect(); + void OnSelectionDragedges(); + void OnSelectionDragvertecies(); + void OnSelectionMakeDetail(); + void OnSelectionMakeStructural(); + void OnSelectionMakehollow(); + void OnSelectionSelectcompletetall(); + void OnSelectionSelectinside(); + void OnSelectionSelectpartialtall(); + void OnSelectionSelecttouching(); + void OnSelectionUngroupentity(); + void OnSelectionMergeentity(); + void OnSelectionGroupworld(); + void OnTexturesPopup(); + void OnPopupSelection(); + void OnViewChange(); + void OnViewCameraupdate(); + void OnHelpAbout(); + void OnHelp(); + void OnHelpLinks(); + void OnHelpBugreport(); + void OnViewClipper(); + void OnCameraAngledown(); + void OnCameraAngleup(); + void OnCameraBack(bool keydown); + void OnCameraDown(); + void OnCameraForward(bool keydown); + void OnCameraLeft(bool keydown); + void OnCameraRight(bool keydown); + void OnCameraStrafeleft(bool keydown); + void OnCameraStraferight(bool keydown); + void OnCameraUp(); + void OnGridToggle(); + void OnPrefs(); + void OnTogglecamera(); + void OnToggleconsole(); + void OnToggleview(); + void OnTogglez(); + void OnToggleLock(); + void OnEditMapinfo(); + void OnEditEntityinfo(); + void OnBrushScripts(); + void OnViewCenterview(); + void OnViewNextview(); + void OnHelpCommandlist(); + void OnFileNewproject(); + void OnFlipClip(); + void OnClipSelected(); + void OnSplitSelected(); + void OnToggleviewXz(); + void OnToggleviewYz(); + void OnColorsBrush(); + void OnColorsClipper(); + void OnColorsGridtext(); + void OnColorsSelectedbrush(); + void OnColorsSelectedbrush3D(); + void OnColorsCameraBack(); + void OnColorsGridblock(); + void OnColorsViewname(); + void OnColorSetoriginal(); + void OnColorSetqer(); + void OnColorSetblack(); + void OnColorSetydnar(); /* ydnar */ + void OnSnaptogrid(); + void OnSelectScale(); + void OnSelectMouserotate(); + void OnEditCopybrush(); + void OnEditPastebrush(); + void OnEditPastebrushToCamera(); + void OnEditUndo(); + void OnEditRedo(); + void OnSelectionInvert(); +// void OnSelectionTextureDec(); + void OnSelectionTextureFit(); +// void OnSelectionTextureInc(); + void OnSelectionTextureRotateclock(); + void OnSelectionTextureRotatecounter(); + void OnSelectionTextureScaledown(); + void OnSelectionTextureScaleup(); + void OnSelectionTextureShiftdown(); + void OnSelectionTextureShiftleft(); + void OnSelectionTextureShiftright(); + void OnSelectionTextureShiftup(); + void OnGridNext(); + void OnGridPrev(); + void OnSelectionTextureScaleLeft(); + void OnSelectionTextureScaleRight(); + void OnTextureReplaceall(); + void OnScalelockx(); + void OnScalelocky(); + void OnScalelockz(); + void OnSelectMousescale(); + void OnViewCubicclipping(); + void OnFileProjectsettings(); + void OnViewCubein(); + void OnViewCubeout(); + void OnFileSaveregion(); + void OnSelectionMovedown(); + void OnSelectionMoveup(); + void OnToolbarMain(); + void OnToolbarTexture(); + void OnSelectionPrint(); + void OnSelectionTogglesizepaint(); + void OnBrushMakecone(); + void OnTexturesLoad(); + void OnToggleRotatelock(); + void OnFileImportmap(); + void OnFileExportmap(); + void OnEditLoadprefab(); + void OnSelectionSelectNudgedown(); + void OnSelectionSelectNudgeleft(); + void OnSelectionSelectNudgeright(); + void OnSelectionSelectNudgeup(); + void OnTexturesLoadlist(); + void OnDontselectcurve(); + void OnConvertcurves(); + void OnCurveSimplepatchmesh(); + void OnPatchToggleBox(); + void OnPatchWireframe(); + void OnCurvePatchcone(); + void OnCurvePatchtube(); + void OnPatchWeld(); + void OnCurvePatchbevel(); + void OnCurvePatchendcap(); + void OnPatchDrilldown(); + void OnCurveInsertcolumn(); + void OnCurveInsertrow(); + void OnCurveDeletecolumn(); + void OnCurveDeleterow(); + void OnCurveInsertAddcolumn(); + void OnCurveInsertAddrow(); + void OnCurveInsertInsertcolumn(); + void OnCurveInsertInsertrow(); + void OnCurveNegative(); + void OnCurveNegativeTextureX(); + void OnCurveNegativeTextureY(); + void OnCurveDeleteFirstcolumn(); + void OnCurveDeleteFirstrow(); + void OnCurveDeleteLastcolumn(); + void OnCurveDeleteLastrow(); + void OnPatchBend(); +// void OnPatchInsdel(); + void OnPatchEnter(); + void OnPatchTab(); + void OnCurvePatchdensetube(); + void OnCurvePatchverydensetube(); + void OnCurveCap(); + void OnCurveCapInvertedbevel(); + void OnCurveCapInvertedendcap(); + void OnCurveRedisperseRows(); + void OnCurveRedisperseIntermediateCols(); + void OnCurveRedisperseIntermediateRows(); + void OnPatchNaturalize(); + void OnSnapToGrid(); + void OnCurvePatchsquare(); + void OnTexturewindowScaleup(); + void OnTexturewindowScaledown(); + void OnCurveOverlayClear(); + void OnCurveOverlaySet(); + void OnCurveThicken(); + void OnCurveCyclecap(); + void OnCurveMatrixTranspose(); + void OnTexturesReloadshaders(); + void OnShowEntities(); + // will set the view mode right, don't set the value for mode if you only want to update the radio item + void OnEntitiesSetViewAs(int mode = 0); + void OnPluginsRefresh(); + void OnTexturesShowall(); + void OnPatchInspector(); + void OnViewOpengllighting(); + void OnSelectAll(); + void OnCurveFreeze(); + void OnCurveUnFreeze(); + void OnCurveUnFreezeAll(); + void OnSelectReselect(); + void OnEditSaveprefab(); + void OnCurveMoreendcapsbevelsSquarebevel(); + void OnCurveMoreendcapsbevelsSquareendcap(); + void OnBrushPrimitivesSphere(); + void OnViewCrosshair(); + void OnViewHideshowHideselected(); + void OnViewHideshowShowhidden(); + void OnTexturesShadersShow(); + void OnViewGroups(); + void OnDropGroupAddtoWorld(); + void OnDropGroupName(); + void OnDropGroupNewgroup(); + void OnDropGroupRemove(); + void OnViewShowWorkzone(); + void OnViewShowAngles(); + void OnMru(unsigned int nID); + void OnViewNearest(unsigned int nID); + void OnTextureWad(unsigned int nID); + void OnBspCommand(unsigned int nID); + void OnGrid(unsigned int nID); + void OnPlugIn(unsigned int nID, char *str); + void OnFaceFit(); + void SetTextureScale(int id); + void OnDontselectmodel(); + void OnTexturesShaderlistonly(); + void OnSleep(); + void OnFilterAreaportals(); + void OnFilterCaulk(); + void OnFilterStructural(); + void OnFilterClips(); + void OnFilterBotClips(); + void OnFilterDetails(); + void OnFilterEntities(); + void OnFilterHintsskips(); + void OnFilterLights(); + void OnFilterLiquids(); + void OnFilterModels(); + void OnFilterPatches(); + void OnFilterTranslucent(); + void OnFilterTriggers(); + void OnFilterWorld(); + void OnFilterPaths(); + void OnFilterClusterportals(); + void OnFilterLightgrid(); + +private: + EViewStyle m_nCurrentStyle; + +#ifdef _WIN32 + GdkRectangle primaryMonitorRect; + int gdk_offset_x; + int gdk_offset_y; +#endif + +}; + +// some C API to the mainframe functions +void WINAPI QERApp_Sleep(); + +#endif // _MAINFRAME_H_ diff --git a/radiant/map.cpp b/radiant/map.cpp new file mode 100644 index 00000000..051c0a51 --- /dev/null +++ b/radiant/map.cpp @@ -0,0 +1,1322 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#include "preferences.h" +#include "mainframe.h" +#include "gtkmisc.h" +#include "filters.h" + +extern MainFrame* g_pParentWnd; + +int modified; // for quit confirmation (0 = clean, 1 = unsaved, + // 2 = autosaved, but not regular saved) + +char currentmap[1024]; + +brush_t active_brushes; // brushes currently being displayed +brush_t selected_brushes; // highlighted + +face_t *selected_face; +brush_t *selected_face_brush; + +brush_t filtered_brushes; // brushes that have been filtered or regioned + +entity_t entities; // head/tail of doubly linked list + +entity_t *world_entity = NULL; // "classname" "worldspawn" ! + +void Map_Init() +{ + Map_Free(); +} + + +bool g_bCancel_Map_LoadFile; // Hydra: moved this here + +// TTimo +// need that in a variable, will have to tweak depending on the game +int g_MaxWorldCoord = 64*1024; +int g_MinWorldCoord = -64*1024; + +// the max size we allow on brushes, this is dependant on world coords too +// makes more sense to say smaller I think? +int g_MaxBrushSize = (g_MaxWorldCoord-1)*2; + +void AddRegionBrushes (void); +void RemoveRegionBrushes (void); + +/* +============================================================= + + Cross map selection saving + + this could fuck up if you have only part of a complex entity selected... +============================================================= +*/ + +brush_t between_brushes; +entity_t between_entities; + +bool g_bRestoreBetween = false; + +void Map_SaveBetween (void) +{ + if (g_pParentWnd->ActiveXY()) + { + g_bRestoreBetween = true; + g_pParentWnd->ActiveXY()->Copy(); + } + return; +} + +void Map_RestoreBetween (void) +{ + if (g_pParentWnd->ActiveXY() && g_bRestoreBetween) + g_pParentWnd->ActiveXY()->Paste(); +} + +//============================================================================ + +bool CheckForTinyBrush(brush_t* b, int n, float fSize) +{ + bool bTiny = false; + for (int i=0 ; i<3 ; i++) + { + if (b->maxs[i] - b->mins[i] < fSize) + bTiny = true; + } + if (bTiny) + Sys_Printf("Possible problem brush (too small) #%i ", n); + return bTiny; +} + +void Map_BuildBrushData(void) +{ + brush_t *b, *next; + + if (active_brushes.next == NULL) + return; + + Sys_BeginWait (); // this could take a while + + int n = 0; + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + Brush_Build( b, true, false, false ); + if (!b->brush_faces || (g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush(b, n++, g_PrefsDlg.m_fTinySize))) + { + Brush_Free (b); + Sys_Printf ("Removed degenerate brush\n"); + } + } + Sys_EndWait(); +} + +entity_t *Map_FindClass (char *cname) +{ + entity_t *ent; + + for (ent = entities.next ; ent != &entities ; ent=ent->next) + { + if (!strcmp(cname, ValueForKey (ent, "classname"))) + return ent; + } + return NULL; +} + +/* +================ +Map_Free +free all map elements, reinitialize the structures that depend on them +================ +*/ +void Map_Free (void) +{ + g_bRestoreBetween = false; + if (selected_brushes.next && + (selected_brushes.next != &selected_brushes)) + { + if (gtk_MessageBox (g_pParentWnd->m_pWidget, "Copy selection?", " ", MB_YESNO) == IDYES) + Map_SaveBetween (); + } + + QERApp_ActiveShaders_SetInUse( false ); + Pointfile_Clear (); + g_qeglobals.d_num_entities = 0; + + if (!active_brushes.next) + { + // first map + active_brushes.prev = active_brushes.next = &active_brushes; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; + entities.prev = entities.next = &entities; + } + else + { + // free selected faces array + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + while (active_brushes.next != &active_brushes) + Brush_Free (active_brushes.next); + while (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + while (filtered_brushes.next != &filtered_brushes) + Brush_Free (filtered_brushes.next); + while (entities.next != &entities) + Entity_Free (entities.next); + } + + if (world_entity) + Entity_Free(world_entity); + world_entity = NULL; +} + +entity_t *AngledEntity() +{ + entity_t *ent = Map_FindClass ("info_player_start"); + if (!ent) + { + ent = Map_FindClass ("info_player_deathmatch"); + } + if (!ent) + { + ent = Map_FindClass ("info_player_deathmatch"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_redplayer"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_blueplayer"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_redspawn"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_bluespawn"); + } + return ent; +} + +// +// move the view to a start position +// +void Map_StartPosition() +{ + entity_t *ent = AngledEntity(); + + g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; + if (ent) + { + GetVectorForKey (ent, "origin", g_pParentWnd->GetCamWnd()->Camera()->origin); + GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); + g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = FloatForKey (ent, "angle"); + } + else + { + g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; + VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin); + VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); + } +} + +void Map_FreeEntities(CPtrArray *ents) +{ + int i, j, num_ents, num_brushes; + entity_t* e; + CPtrArray* brushes; + + num_ents = ents->GetSize(); + for(i=0; iGetAt(i); + brushes = (CPtrArray*)e->pData; + num_brushes = brushes->GetSize(); + for(j=0; jGetAt(j)); + brushes->RemoveAll(); + delete (CPtrArray*)e->pData; + e->pData = NULL; + Entity_Free(e); + } + ents->RemoveAll(); +} + +/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */ +void Map_ImportEntities(CPtrArray *ents, bool bAddSelected = false) +{ + int num_ents, num_brushes; + CPtrArray *brushes; + vec3_t mins, maxs; + entity_t *e; + brush_t *b; + face_t *f; + int i,j; + + GPtrArray *new_ents = g_ptr_array_new(); + + g_qeglobals.bPrimitBrushes = false; + + brush_t *pBrushList = (bAddSelected) ? &selected_brushes : &active_brushes; + + bool bDoneBPCheck = false; + g_qeglobals.bNeedConvert = false; + // HACK: find out if this map file was a BP one + // check the first brush in the file that is NOT a patch + // this will not be necessary when we allow both formats in the same file + num_ents = ents->GetSize(); + for(i=0; !bDoneBPCheck && iGetAt(i); + brushes = (CPtrArray*)e->pData; + num_brushes = brushes->GetSize(); + for(j=0; !bDoneBPCheck && jGetAt(j); + if(b->patchBrush) continue; + bDoneBPCheck = true; + int BP_param = -1; + if(b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode) + BP_param = 0; + else if(!b->bBrushDef && g_qeglobals.m_bBrushPrimitMode) + BP_param = 1; + + if(BP_param != -1) + { + switch(BP_MessageBox(BP_param)) + { + case 0: + Map_FreeEntities(ents); + return; + case 1: + g_qeglobals.bNeedConvert = true; + break; + case 2: + g_qeglobals.bNeedConvert = false; + break; + } + } + } + } + + // process the entities into the world geometry + num_ents = ents->GetSize(); + for(i=0; iGetAt(i); + brushes = (CPtrArray*)e->pData; + + num_brushes = brushes->GetSize(); + // link brushes into entity + for(j=0; jGetAt(j)); + g_qeglobals.d_parsed_brushes++; + } + brushes->RemoveAll(); + delete brushes; + e->pData = NULL; + + // set entity origin + GetVectorForKey (e, "origin", e->origin); + // set entity eclass + /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */ + e->eclass = Eclass_ForName (ValueForKey (e, "classname"), + (e->brushes.onext != &e->brushes)); + + // go through all parsed brushes and build stuff + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + { + for(f = b->brush_faces; f != NULL; f = f->next) + { + f->pShader = QERApp_Shader_ForName(f->texdef.GetName()); + f->d_texture = f->pShader->getTexture(); + } + + // when brushes are in final state, build the planes and windings + // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true + Brush_Build(b); + } + +//#define TERRAIN_HACK +#undef TERRAIN_HACK + +#ifdef TERRAIN_HACK + if ((strcmp(ValueForKey(e, "terrain"),"1") == 0 && strcmp(e->eclass->name,"func_group") == 0)) + { + + // two aux pointers to the shaders used in the terrain entity + // we don't keep refcount on them since they are only temporary + // this avoids doing expensive lookups by name for all faces + IShader *pTerrainShader, *pCaulk; + + pTerrainShader = NULL; + pCaulk = QERApp_Shader_ForName(SHADER_CAULK); + + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + { + if (pTerrainShader == NULL) + for(f = b->brush_faces; f != NULL; f = f->next) + if (strcmp(f->texdef.GetName(), SHADER_CAULK)!=0) + pTerrainShader = f->pShader; + + if (pTerrainShader) + { + for(f = b->brush_faces; f != NULL; f = f->next) + { + if (strcmp(f->texdef.GetName(), SHADER_CAULK)!=0) // not caulk + Face_SetShader(f, pTerrainShader->getName()); + else + Face_SetShader(f, pCaulk->getName()); + } + } + else + Sys_Printf("WARNING: no terrain shader found for brush\n"); + } + } +#endif + +#define PATCH_HACK +#ifdef PATCH_HACK + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + { + // patch hack, to be removed when dependency on brush_faces is removed + if (b->patchBrush) + { + Patch_CalcBounds(b->pPatch, mins, maxs); + for (int i=0; i<3; i++) + { + if ((int)mins[i] == (int)maxs[i]) + { + mins[i] -= 4; + maxs[i] += 4; + } + } + Brush_Resize(b, mins, maxs); + Brush_Build(b); + } + } +#endif + // add brush for fixedsize entity + if (e->eclass->fixedsize) + { + vec3_t mins, maxs; + VectorAdd (e->eclass->mins, e->origin, mins); + VectorAdd (e->eclass->maxs, e->origin, maxs); + b = Brush_Create (mins, maxs, &e->eclass->texdef); + Entity_LinkBrush(e, b); + Brush_Build(b); + } + + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + Brush_AddToList(b, pBrushList); + + if (strcmp(e->eclass->name, "worldspawn") == 0) + { + if (world_entity) + { + while(e->brushes.onext != &e->brushes) + { + b = e->brushes.onext; + Entity_UnlinkBrush(b); + Entity_LinkBrush(world_entity, b); + } + Entity_Free(e); + } + else + { + world_entity = e; + } + } + else if (strcmp(e->eclass->name, "group_info") == 0) + { + // it's a group thing! + Group_Add(e); + Entity_Free(e); + } + else + { + // fix target/targetname collisions + if ((g_PrefsDlg.m_bDoTargetFix) && (strcmp(ValueForKey(e, "target"), "") != 0)) + { + GPtrArray *t_ents = g_ptr_array_new(); + entity_t *e_target; + const char *target = ValueForKey(e, "target"); + qboolean bCollision=FALSE; + + // check the current map entities for an actual collision + for (e_target = entities.next; e_target != &entities; e_target = e_target->next) + { + if(!strcmp(target, ValueForKey(e_target, "target"))) + { + bCollision = TRUE; + // make sure the collision is not between two imported entities + for(j=0; j<(int)new_ents->len; j++) + { + if(e_target == g_ptr_array_index(new_ents, j)) + bCollision = FALSE; + } + } + } + + // find the matching targeted entity(s) + if(bCollision) + { + for(j=num_ents-1; j>0; j--) + { + e_target = (entity_t*)ents->GetAt(j); + if(e_target != NULL && e_target != e) + { + const char *targetname = ValueForKey(e_target, "targetname"); + if( (targetname != NULL) && (strcmp(target, targetname) == 0) ) + g_ptr_array_add(t_ents, (gpointer)e_target); + } + } + if(t_ents->len > 0) + { + // link the first to get a unique target/targetname + Entity_Connect(e, (entity_t*)g_ptr_array_index(t_ents,0)); + // set the targetname of the rest of them manually + for(j = 1; j < (int)t_ents->len; j++) + SetKeyValue( (entity_t*)g_ptr_array_index(t_ents, j), "targetname", ValueForKey(e, "target") ); + } + g_ptr_array_free(t_ents, FALSE); + } + } + + // add the entity to the end of the entity list + Entity_AddToList(e, &entities); + g_qeglobals.d_num_entities++; + + // keep a list of ents added to avoid testing collisions against them + g_ptr_array_add(new_ents, (gpointer)e); + } + } + g_ptr_array_free(new_ents, FALSE); + + ents->RemoveAll(); + + g_qeglobals.bNeedConvert = false; +} + +void Map_Import(IDataStream *in, const char *type, bool bAddSelected) +{ + CPtrArray ents; + + g_pParentWnd->GetSynapseClient().ImportMap(in, &ents, type); + Map_ImportEntities(&ents, bAddSelected); +} + +/* +================ +Map_LoadFile +================ +*/ +void Map_LoadFile (const char *filename) +{ + clock_t start, finish; + double elapsed_time; + start = clock(); + + Sys_BeginWait (); + Select_Deselect(); + /*! + \todo FIXME TTimo why is this commented out? + stability issues maybe? or duplicate feature? + forcing to show the console during map load was a good thing IMO + */ + //SetInspectorMode(W_CONSOLE); + Sys_Printf ("Loading map from %s\n", filename ); + + Map_Free (); + //++timo FIXME: maybe even easier to have Group_Init called from Map_Free? + Group_Init(); + g_qeglobals.d_num_entities = 0; + g_qeglobals.d_parsed_brushes = 0; + + + // cancel the map loading process + // used when conversion between standard map format and BP format is required and the user cancels the process + g_bCancel_Map_LoadFile = false; + + strcpy (currentmap, filename); + + g_bScreenUpdates = false; // leo: avoid redraws while loading the map (see fenris:1952) + + // prepare to let the map module do the parsing + FileStream file; + const char* type = strrchr(filename,'.'); + if(type!=NULL) type++; + // NOTE TTimo opening has binary doesn't make a lot of sense + // but opening as text confuses the scriptlib parser + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=261 + // this may be a problem if we "rb" and use the XML parser, might have an incompatibility + if (file.Open(filename, "rb")) + Map_Import(&file, type); + else + Sys_FPrintf(SYS_ERR, "ERROR: failed to open %s for read\n", filename); + file.Close(); + + g_bScreenUpdates = true; + + if (g_bCancel_Map_LoadFile) + { + Sys_Printf("Map_LoadFile canceled\n"); + Map_New(); + Sys_EndWait(); + return; + } + + if (!world_entity) + { + Sys_Printf ("No worldspawn in map.\n"); + Map_New (); + Sys_EndWait(); + return; + } + finish = clock(); + elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC; + + Sys_Printf ("--- LoadMapFile ---\n"); + Sys_Printf ("%s\n", filename ); + + Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); + Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); + Sys_Printf ("%5.2f second(s) load time\n", elapsed_time ); + + Sys_EndWait(); + + Map_RestoreBetween (); + + // + // move the view to a start position + // + Map_StartPosition(); + + Map_RegionOff (); + + modified = false; + Sys_SetTitle (filename); + + Texture_ShowInuse (); + QERApp_SortActiveShaders(); + + Sys_UpdateWindows (W_ALL); +} + +/*! +=========== +Supporting functions for Map_SaveFile, builds a CPtrArray with the filtered / non filtered brushes +=========== +*/ +void CleanFilter(entity_t *ent) +{ + if (ent->pData) + { + delete static_cast(ent->pData); + ent->pData = NULL; + } +} + +/*! +filters out the region brushes if necessary +returns true if this entity as a whole is out of the region +(if all brushes are filtered out, then the entity will be completely dropped .. except if it's worldspawn of course) +*/ +bool FilterChildren(entity_t *ent, bool bRegionOnly = false, bool bSelectedOnly = false) +{ + if(ent->brushes.onext == &ent->brushes) + return false; + // entity without a brush, ignore it... this can be caused by Undo + + // filter fixedsize ents by their eclass bounding box + // don't add their brushes + if (ent->eclass->fixedsize) + { + if(bSelectedOnly && !IsBrushSelected(ent->brushes.onext)) + return false; + + if(bRegionOnly && region_active) + { + for (int i=0 ; i<3 ; i++) + { + if ((ent->origin[i] + ent->eclass->mins[i]) > region_maxs[i]) + return false; + if ((ent->origin[i] + ent->eclass->maxs[i]) < region_mins[i]) + return false; + } + } + } + else + { + for (brush_t *b = ent->brushes.onext ; b != &ent->brushes ; b=b->onext) + { + // set flag to use brushprimit_texdef + if(g_qeglobals.m_bBrushPrimitMode) + b->bBrushDef = true; + else + b->bBrushDef = false; + + // add brush, unless it's excluded by region + if ( !(bRegionOnly && Map_IsBrushFiltered(b)) && + !(bSelectedOnly && !IsBrushSelected(b)) ) + ((CPtrArray*)ent->pData)->Add(b); + } + + if (((CPtrArray*)ent->pData)->GetSize() <= 0) + return false; + } + return true; +} + +entity_t *region_startpoint = NULL; +void Map_ExportEntities(CPtrArray* ents, bool bRegionOnly = false, bool bSelectedOnly = false) +{ + int i; + entity_t *e; + + /*! + \todo the entity_t needs to be reworked and asbtracted some more + + keeping the entity_t as the struct providing access to a list of map objects, a list of epairs and various other info? + but separating some more the data that belongs to the entity_t and the 'sons' data + on a side note, I don't think that doing that with linked list would be a good thing + + for now, we use the blind void* in entity_t casted to a CPtrArray of brush_t* to hand out a list of the brushes for map write + the next step is very likely to be a change of the brush_t* to a more abstract object? + */ + + FilterChildren(world_entity, bRegionOnly, bSelectedOnly); + ents->Add(world_entity); + + for (e=entities.next ; e!=&entities ; e=e->next) + { + // not sure this still happens, probably safe to leave it in + if ((!strcmp(ValueForKey (e, "classname"), "worldspawn")) && (e!=world_entity)) + { + Sys_FPrintf(SYS_ERR, "Dropping parasite worldspawn entity\n"); + continue; + } + + // entities which brushes are completely filtered out by regioning are not printed to the map + if (FilterChildren(e, bRegionOnly, bSelectedOnly)) + ents->Add(e); + } + + if (bRegionOnly && region_active) + { + for(i=0; i<6; i++) + ((CPtrArray*)world_entity->pData)->Add(region_sides[i]); + + ents->Add(region_startpoint); + } +} + +void Map_Export(IDataStream *out, const char *type, bool bRegionOnly, bool bSelectedOnly) +{ + entity_t *e; + + CPtrArray ents; + + if (bRegionOnly && region_active) + AddRegionBrushes(); + + // create the filters + world_entity->pData = new CPtrArray(); + for(e = entities.next; e != &entities; e = e->next) + e->pData = new CPtrArray(); + + Map_ExportEntities(&ents, bRegionOnly, bSelectedOnly); + + g_pParentWnd->GetSynapseClient().ExportMap(&ents, out, type); + + // cleanup the filters + CleanFilter(world_entity); + for (e=entities.next ; e!=&entities ; e=e->next) + CleanFilter(e); + + if (bRegionOnly && region_active) + RemoveRegionBrushes(); +} + +const char* filename_get_extension(const char* filename) +{ + const char* type = strrchr(filename,'.'); + if(type != NULL) + return ++type; + return ""; +} + +/* +=========== +Map_SaveFile +\todo FIXME remove the use_region, this is broken .. work with a global flag to set region mode or not +=========== +*/ +void Map_SaveFile (const char *filename, qboolean use_region ) +{ + clock_t start, finish; + double elapsed_time; + start = clock(); + Sys_Printf("Saving map to %s\n",filename); + + Pointfile_Clear (); + + if (!use_region) + { + char backup[1024]; + + // rename current to .bak + strcpy (backup, filename); + StripExtension (backup); + strcat (backup, ".bak"); + unlink (backup); + rename (filename, backup); + } + + Sys_Printf ("Map_SaveFile: %s\n", filename); + + // build the out data stream + FileStream file; + if (!file.Open(filename,"w")) + { + Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for write\n", filename); + return; + } + + // extract filetype + Map_Export(&file, filename_get_extension(filename), use_region); + + file.Close(); + + finish = clock(); + elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC; + + Sys_Printf ("Saved in %-.2f second(s).\n",elapsed_time); + modified = false; + + if ( !strstr( filename, "autosave" ) ) + Sys_SetTitle (filename); + + if (!use_region) + { + time_t timer; + + time (&timer); + + Sys_Beep (); + + Sys_Status ("Saved.", 0); + } +} + +/* +=========== +Map_New + +=========== +*/ +void Map_New (void) +{ + Sys_Printf ("Map_New\n"); + Map_Free (); + + strcpy (currentmap, "unnamed.map"); + Sys_SetTitle (currentmap); + + world_entity = (entity_s*)qmalloc(sizeof(*world_entity)); + world_entity->brushes.onext = + world_entity->brushes.oprev = &world_entity->brushes; + SetKeyValue (world_entity, "classname", "worldspawn"); + world_entity->eclass = Eclass_ForName ("worldspawn", true); + + g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; + g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; + VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin); + g_pParentWnd->GetCamWnd()->Camera()->origin[2] = 48; + VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); + + Map_RestoreBetween (); + + Group_Init(); + + Sys_UpdateWindows (W_ALL); + modified = false; +} + +/* +=========================================================== + + REGION + +=========================================================== +*/ +qboolean region_active; +vec3_t region_mins = {g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord}; +vec3_t region_maxs = {g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord}; + +brush_t *region_sides[6]; + +/* +=========== +AddRegionBrushes +a regioned map will have temp walls put up at the region boundary +\todo TODO TTimo old implementation of region brushes + we still add them straight in the worldspawn and take them out after the map is saved + with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module +=========== +*/ +void AddRegionBrushes (void) +{ + vec3_t mins, maxs; + int i; + texdef_t td; + + if (!region_active) + { +#ifdef _DEBUG + Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n"); +#endif + return; + } + + memset (&td, 0, sizeof(td)); + td.SetName(SHADER_NOT_FOUND); + + // set mins + VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); + + // vary maxs + for(i=0; i<3; i++) + { + VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); + maxs[i] = region_mins[i]; + region_sides[i] = Brush_Create (mins, maxs, &td); + } + + // set maxs + VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); + + // vary mins + for(i=0; i<3; i++) + { + VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); + mins[i] = region_maxs[i]; + region_sides[i+3] = Brush_Create (mins, maxs, &td); + } + + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // this is a safe check, but it should not really happen anymore + vec3_t vOrig; + VectorSet(vOrig, + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); + + for (i=0 ; i<3 ; i++) + { + if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) + { + Sys_FPrintf(SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n"); + } + } + + // write the info_playerstart + region_startpoint = Entity_Alloc(); + SetKeyValue(region_startpoint, "classname", "info_player_start"); + region_startpoint->eclass = Eclass_ForName ("info_player_start", false); + char sTmp[1024]; + sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]); + SetKeyValue(region_startpoint, "origin", sTmp); + sprintf(sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]); + SetKeyValue(region_startpoint, "angle", sTmp); + // empty array of children + region_startpoint->pData = new CPtrArray; +} + +void RemoveRegionBrushes (void) +{ + int i; + + if (!region_active) + return; + for (i=0 ; i<6 ; i++) + Brush_Free (region_sides[i]); + + CleanFilter(region_startpoint); + Entity_Free(region_startpoint); +} + +qboolean Map_IsBrushFiltered (brush_t *b) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] > region_maxs[i]) + return true; + if (b->maxs[i] < region_mins[i]) + return true; + } + return false; +} + +/* +=========== +Map_RegionOff + +Other filtering options may still be on +=========== +*/ +void Map_RegionOff (void) +{ + brush_t *b, *next; + int i; + + region_active = false; + for (i=0 ; i<3 ; i++) + { + region_maxs[i] = g_MaxWorldCoord-64; + region_mins[i] = g_MinWorldCoord+64; + } + + for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next) + { + next = b->next; + if (Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + if (active_brushes.next == NULL || active_brushes.prev == NULL) + { + active_brushes.next = &active_brushes; + active_brushes.prev = &active_brushes; + } + Brush_AddToList (b, &active_brushes); + b->bFiltered = FilterBrush(b); + } + Sys_UpdateWindows (W_ALL); +} + +void Map_ApplyRegion (void) +{ + brush_t *b, *next; + + region_active = true; + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + if (!Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + Brush_AddToList (b, &filtered_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + + +/* +======================== +Map_RegionSelectedBrushes +======================== +*/ +void Map_RegionSelectedBrushes (void) +{ + Map_RegionOff (); + + if (selected_brushes.next == &selected_brushes) // nothing selected + { + Sys_Printf("Tried to region with no selection...\n"); + return; + } + region_active = true; + Select_GetBounds (region_mins, region_maxs); + +#ifdef _DEBUG + if (filtered_brushes.next != &filtered_brushes) + Sys_Printf("WARNING: filtered_brushes list may not be empty in Map_RegionSelectedBrushes\n"); +#endif + + if (active_brushes.next == &active_brushes) + { + // just have an empty filtered_brushes list + // this happens if you set region after selecting all the brushes in your map (some weird people do that, ask MrE!) + filtered_brushes.next = filtered_brushes.prev = &filtered_brushes; + } + else + { + // move the entire active_brushes list to filtered_brushes + filtered_brushes.next = active_brushes.next; + filtered_brushes.prev = active_brushes.prev; + filtered_brushes.next->prev = &filtered_brushes; + filtered_brushes.prev->next = &filtered_brushes; + } + + // move the entire selected_brushes list to active_brushes + active_brushes.next = selected_brushes.next; + active_brushes.prev = selected_brushes.prev; + active_brushes.next->prev = &active_brushes; + active_brushes.prev->next = &active_brushes; + + // deselect patches + for (brush_t *b = active_brushes.next; b != &active_brushes; b = b->next) + if (b->patchBrush) + b->pPatch->bSelected = false; + + // clear selected_brushes + selected_brushes.next = selected_brushes.prev = &selected_brushes; + + Sys_UpdateWindows (W_ALL); +} + + +/* +=========== +Map_RegionXY +=========== +*/ +void Map_RegionXY (void) +{ + Map_RegionOff (); + + region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); + region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); + region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); + region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); + region_mins[2] = g_MinWorldCoord+64; + region_maxs[2] = g_MaxWorldCoord-64; + Map_ApplyRegion (); +} + +/* +=========== +Map_RegionTallBrush +=========== +*/ +void Map_RegionTallBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + region_mins[2] = g_MinWorldCoord+64; + region_maxs[2] = g_MaxWorldCoord-64; + + Undo_Start("delete"); + Undo_AddBrushList(&selected_brushes); + Undo_AddEntity(b->owner); + Select_Delete (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + + Map_ApplyRegion (); +} + +/* +=========== +Map_RegionBrush +=========== +*/ +void Map_RegionBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + + Undo_Start("delete"); + Undo_AddBrushList(&selected_brushes); + Undo_AddEntity(b->owner); + Select_Delete (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + + Map_ApplyRegion (); +} + +GList *find_string(GList *glist, const char *buf) +{ + while (glist) + { + if (strcmp((char *)glist->data, buf) == 0) + break; // this name is in our list already + glist = glist->next; + } + return glist; +} + +void Map_ImportBuffer(char *buf) +{ + Select_Deselect(); + + Undo_Start("import buffer"); + + MemStream stream; + + stream.Write(buf, strlen(buf)); + Map_Import(&stream, "xmap"); + stream.Close(); + + Sys_UpdateWindows (W_ALL); + Sys_MarkMapModified(); + + Undo_End(); +} + + +// +//================ +//Map_ImportFile +//================ +// +void Map_ImportFile (const char *filename) +{ + FileStream file; + Sys_BeginWait (); + + Sys_Printf("Importing map from %s\n",filename); + + const char* type = strrchr(filename,'.'); + if(type!=NULL) type++; + /*!\todo Resolve "r" problem in scriptlib" */ + if(file.Open(filename, "rb")) + Map_Import(&file, type, true); + else + Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for read\n", filename); + + file.Close(); + + Sys_UpdateWindows (W_ALL); + modified = true; + Sys_EndWait(); +} + +// +//=========== +//Map_SaveSelected +//=========== +// +// Saves selected world brushes and whole entities with partial/full selections +// +void Map_SaveSelected(const char* filename) +{ + FileStream file; + + Sys_Printf("Saving selection to %s\n",filename); + + const char* type = strrchr(filename,'.'); + if(type!=NULL) type++; + if(file.Open(filename, "w")) + Map_Export (&file, type, false, true); + else + Sys_FPrintf(SYS_ERR, "ERROR: failed to open %s for write\n", filename); + + file.Close(); + +} + +// +//=========== +//Map_SaveSelected +//=========== +// +// Saves selected world brushes and whole entities with partial/full selections +// +void Map_SaveSelected (MemStream* pMemFile, MemStream* pPatchFile) +{ + Map_Export (pMemFile, "xmap", false, true); + + /* + // write world entity first + Entity_WriteSelected(world_entity, pMemFile); + + // then write all other ents + count = 1; + for (e=entities.next ; e != &entities ; e=next) + { + MemFile_fprintf(pMemFile, "// entity %i\n", count); + count++; + Entity_WriteSelected(e, pMemFile); + next = e->next; + } + + //if (pPatchFile) + // Patch_WriteFile(pPatchFile); + */ +} + + +void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...) +{ + char Buffer[4096]; + va_list args; + va_start (args,pText); + vsprintf(Buffer, pText, args); + pMemFile->Write(Buffer, strlen(Buffer)); +} + +/*! +============== +Region_SpawnPoint +push the region spawn point +\todo FIXME TTimo this was in the #1 MAP module implementation (in the core) +not sure it has any use anymore, should prolly drop it +============== +*/ +void Region_SpawnPoint(FILE *f) +{ + // write the info_player_start, we use the camera position + fprintf (f, "{\n"); + fprintf (f, "\"classname\" \"info_player_start\"\n"); + fprintf (f, "\"origin\" \"%i %i %i\"\n", + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); + fprintf (f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]); + fprintf (f, "}\n"); +} diff --git a/radiant/map.h b/radiant/map.h new file mode 100644 index 00000000..efc8f68a --- /dev/null +++ b/radiant/map.h @@ -0,0 +1,72 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// map.h -- the state of the current world that all views are displaying + +extern char currentmap[1024]; + +// head/tail of doubly linked lists +extern brush_t active_brushes; // brushes currently being displayed +extern brush_t selected_brushes; // highlighted + +extern CPtrArray& g_ptrSelectedFaces; +extern CPtrArray& g_ptrSelectedFaceBrushes; + +extern brush_t filtered_brushes; // brushes that have been filtered or regioned + +extern entity_t entities; +extern entity_t *world_entity; // the world entity is NOT included in + // the entities chain + +extern int modified; // for quit confirmations + +extern vec3_t region_mins, region_maxs; +extern qboolean region_active; + +extern brush_t *region_sides[6]; + +void Map_Init(); + +void Map_LoadFile (const char *filename); +void Map_SaveFile (const char *filename, qboolean use_region); + +void Map_New (void); +void Map_Free (void); +void Map_BuildBrushData(void); + +void Map_RegionOff (void); +void Map_RegionXY (void); +void Map_RegionTallBrush (void); +void Map_RegionBrush (void); +void Map_RegionSelectedBrushes (void); +qboolean Map_IsBrushFiltered (brush_t *b); + +void Map_ImportFile (const char *filename); +void Map_SaveSelected(const char* filename); +//void Map_SaveSelected(MemStream* pMemFile, MemStream* pPatchFile = NULL); +//void Map_ImportBuffer (char* buf); + +void Map_StartPosition(void); +void Region_SpawnPoint(FILE *f); + +void Map_Import(IDataStream *in, const char* type, bool bAddSelected = false); +void Map_Export(IDataStream *out, const char* type, bool bRegionOnly = false , bool bSelectedOnly = false); + diff --git a/radiant/missing.cpp b/radiant/missing.cpp new file mode 100644 index 00000000..cf1c5b2d --- /dev/null +++ b/radiant/missing.cpp @@ -0,0 +1,203 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Missing functions +// +// Leonardo Zide (leo@lokigames.com) +// + +#if defined (__linux__) || defined (__APPLE__) + +#include +#include +#include +#include +#include "missing.h" + +bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName) +{ + FILE *src, *dst; + void* buf; + int l, ret = 0; + char realsrc[PATH_MAX], realdest[PATH_MAX]; + + realpath (lpExistingFileName, realsrc); + realpath (lpNewFileName, realdest); + + src = fopen (realsrc, "rb"); + if (!src) + return 0; + dst = fopen (realdest, "wb"); + if (!dst) + { + fclose (src); + return 0; + } + + fseek (src, 0, SEEK_END); + l = ftell (src); + rewind (src); + buf = g_malloc (l); + + if (buf != NULL) + if (fread (buf, l, 1, src) == 1) + if (fwrite (buf, l, 1, dst) == 1) + ret = 1; + + g_free (buf); + fclose (src); + fclose (dst); + + return ret; +} + +int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart) +{ + if (lpFileName[0] == '/') + { + strcpy (lpBuffer, lpFileName); + *lpFilePart = strrchr (lpBuffer, '/'); + return strlen (lpBuffer); + } + + if (getcwd (lpBuffer, nBufferLength) == NULL) + return 0; + + strcat (lpBuffer, "/"); + *lpFilePart = lpBuffer + strlen (lpBuffer); + strcat (lpBuffer, lpFileName); + + char *scr = lpBuffer, *dst = lpBuffer; + for (int i = 0; (i < nBufferLength) && (*scr != 0); i++) + { + if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') + { + scr += 4; + while (dst != lpBuffer && *dst != '/') + { + dst--; + i--; + } + } + + *dst = *scr; + + scr++; dst++; + } + *dst = 0; + + return strlen (lpBuffer); +} +/* +static void g_string_sprintfa_int (GString *string, const gchar *fmt, va_list args) +{ + gchar *buffer; + + buffer = g_strdup_vprintf (fmt, args); + g_string_append (string, buffer); + g_free (buffer); +} + +const CString& CString::operator=(const char* lpsz) +{ + g_string_assign (m_str, lpsz); + return *this; +} + +const CString& CString::operator+=(const char* lpsz) +{ + g_string_append (m_str, lpsz); + return *this; +} + +CString::operator char*() const +{ + return m_str->str; +} + +void CString::Format(const char* fmt, ...) +{ + va_list args; + + g_string_truncate (m_str, 0); + + va_start (args, fmt); + g_string_sprintfa_int (m_str, fmt, args); + va_end (args); +} + +CString CString::Right(int nCount) const +{ + if (nCount < 0) + nCount = 0; + else if (nCount > m_str->len) + nCount = m_str->len; + + CString dest (&m_str->str[m_str->len-nCount]); + return dest; +} + +CString CString::Left(int nCount) const +{ + if (nCount < 0) + nCount = 0; + else if (nCount > m_str->len) + nCount = m_str->len; + + CString dest; + dest.m_str = g_string_sized_new (nCount); + memcpy (dest.m_str->str, m_str->str, nCount); + dest.m_str->str[nCount] = 0; + return dest; +} + +void CString::SetAt(int nIndex, char ch) +{ + if (nIndex >= 0 && nIndex < m_str->len) + m_str->str[nIndex] = ch; +} + +char CString::GetAt(int nIndex) const +{ + if (nIndex >= 0 && nIndex < m_str->len) + return m_str->str[nIndex]; + return 0; +} + +char CString::operator[](int nIndex) const +{ + if (nIndex >= 0 && nIndex < m_str->len) + return m_str->str[nIndex]; + return 0; +} +*/ + +#endif diff --git a/radiant/parse.cpp b/radiant/parse.cpp new file mode 100644 index 00000000..be6d1586 --- /dev/null +++ b/radiant/parse.cpp @@ -0,0 +1,220 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" + +char token[MAXTOKEN]; +qboolean unget; +char* script_p; +int scriptline; + +// Hydra: added support for GetTokenExtra() +char *currentdelimiters; +qboolean script_keepdelimiter; + +void StartTokenParsing (char *data) +{ + scriptline = 1; + script_p = data; + unget = false; + + // Hydra: added support for GetTokenExtra() + currentdelimiters = NULL; + script_keepdelimiter = true; +} + + +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (unget) // is a token already waiting? + { + unget = false; + return true; + } + + // + // skip space + // +skipspace: + while (*script_p <= 32) + { + if (!*script_p) + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [01]\n",scriptline); + return false; + } + + if (*script_p++ == '\n') + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [02]\n",scriptline); + scriptline++; + } + } + + if (script_p[0] == '/' && script_p[1] == '/') // comment field + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [03]\n",scriptline); + while (*script_p++ != '\n') + if (!*script_p) + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [04]\n",scriptline); + return false; + } + scriptline++; // Hydra: fixed bad line numbers problem + goto skipspace; + } + + // + // copy token + // + token_p = token; + + if (*script_p == '"') + { + script_p++; + while ( *script_p != '"' ) + { + if (!*script_p) + Error ("EOF inside quoted token"); + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + } + script_p++; + } + else + while ( *script_p > 32 ) + { + // Hydra: added support for GetTokenExtra(), care was taken to maintain speed + if((currentdelimiters) && (!script_keepdelimiter) && (strchr(currentdelimiters,*(script_p)))) + break; + + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + + // Hydra: added support for GetTokenExtra() + if((currentdelimiters) && (strchr(currentdelimiters,*(script_p-1)))) + break; + + } + + *token_p = 0; + + return true; +} + +void UngetToken (void) +{ + unget = true; +} + +/* +============== +GetTokenExtra + +This function expands the use of GetToken() so it can be used to parse +more complex file formats. + +Hydra - Notes: +You can use this function to split a string like this + +string1:("string2") + +into two strings, like this: +string1 +string2 + +whilst still checking for the brackets and colons, like this: + +GetTokenExtra(false,":",false);// contains "string1" +GetTokenExtra(false,":",true); // contains ":" +GetTokenExtra(false,"(",true); // contains "(" +GetToken(false); // contains "string2" +GetTokenExtra(false,")",true); // contains ")" + +here's what you get, given the same string, with this code: + +GetToken(false); // contains "string1:("string2")" + +Parsing will end if any character in the script matches any one of the +characters in the "delimiters" string. + +it's also possible to do things like this: + +source strings: +1,2 +1:2 +1-2 +1*2 + +code: +GetTokenExtra(false,",:-*",false); // token contains "1" +GetTokenExtra(false,",:-*",false); // token contains the delimiter that was used +GetToken(false); // contains "2" +============== +*/ +qboolean GetTokenExtra (qboolean crossline,char *delimiters, qboolean keepdelimiter) +{ + qboolean result; + char *olddelimiters = currentdelimiters; // store it + + currentdelimiters = delimiters; // change the delimiters + script_keepdelimiter = keepdelimiter; // change the global flag + + result = GetToken(crossline); + currentdelimiters = olddelimiters; // restore it + return(result); +} + +/* +============== +TokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script_p; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + if (*search_p == 0) + return false; + search_p++; + } + + if (*search_p == ';') + return false; + + return true; +} diff --git a/radiant/parse.h b/radiant/parse.h new file mode 100644 index 00000000..de679de2 --- /dev/null +++ b/radiant/parse.h @@ -0,0 +1,35 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// parse.h -- text file parsing routines + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern int scriptline; + +// NOTE: added WINAPI call syntax to export these for plugins in _QERScripLibTable +void StartTokenParsing (char *data); +qboolean GetToken (qboolean crossline); +void UngetToken (void); +qboolean TokenAvailable (void); +qboolean GetTokenExtra (qboolean crossline,char *delimiters,qboolean keepdelimiter); // Hydra: added support for GetTokenExtra() + diff --git a/radiant/patchdialog.cpp b/radiant/patchdialog.cpp new file mode 100644 index 00000000..8a6ff7cd --- /dev/null +++ b/radiant/patchdialog.cpp @@ -0,0 +1,745 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Patch Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "stdafx.h" +#include "patchdialog.h" + +PatchDialog g_PatchDialog; +// is the patch inspector currently displayed/active? +bool l_bIsActive = false; +// the increment we are using for the patch inspector (this is saved in the prefs) +texdef_t *l_pPIIncrement = &g_qeglobals.d_savedinfo.m_PIIncrement; + +// ============================================================================= +// static functions + +static void OnDone (GtkWidget *widget, gpointer data) +{ + g_PatchDialog.m_Patch = NULL; + g_PatchDialog.HideDlg (); +} + +// memorize the current state (that is don't try to undo our do before changing something else) +static void OnApply (GtkWidget *widget, gpointer data) +{ + g_PatchDialog.UpdateData(TRUE); + if (g_PatchDialog.m_Patch != NULL) + { + int r = g_PatchDialog.m_nRow; + int c = g_PatchDialog.m_nCol; + if (r >= 0 && r < g_PatchDialog.m_Patch->height && c >= 0 && c < g_PatchDialog.m_Patch->width) + { + if (g_PatchDialog.m_Patch->pShader) + g_PatchDialog.m_Patch->pShader->DecRef(); + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=467 + if (g_PatchDialog.m_strName.Find(' ') >= 0) + { + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, dropping '%s'\n", g_PatchDialog.m_strName.GetBuffer()); + g_PatchDialog.m_strName = SHADER_NOT_FOUND; + } + g_PatchDialog.m_Patch->pShader = QERApp_Shader_ForName(g_PatchDialog.m_strName); + g_PatchDialog.m_Patch->d_texture = g_PatchDialog.m_Patch->pShader->getTexture(); + g_PatchDialog.m_Patch->ctrl[c][r].xyz[0] = g_PatchDialog.m_fX; + g_PatchDialog.m_Patch->ctrl[c][r].xyz[1] = g_PatchDialog.m_fY; + g_PatchDialog.m_Patch->ctrl[c][r].xyz[2] = g_PatchDialog.m_fZ; + g_PatchDialog.m_Patch->ctrl[c][r].st[0] = g_PatchDialog.m_fS; + g_PatchDialog.m_Patch->ctrl[c][r].st[1] = g_PatchDialog.m_fT; + g_PatchDialog.m_Patch->bDirty = true; + Sys_UpdateWindows(W_ALL); + } + } +} + +static void OnSelchangeComboColRow (GtkWidget *widget, gpointer data) +{ + if (!g_PatchDialog.m_bListenChanged) + return; +#ifdef DBG_PI + Sys_Printf("OnSelchangeComboColRow\n"); +#endif + // retrieve the current m_nRow and m_nCol, other params are not relevant + // (NOTE: UpdateData has a mechanism to avoid inifinite looping) + g_PatchDialog.UpdateData(TRUE); + // read the changed values ourselves + g_PatchDialog.UpdateRowColInfo(); + // now reflect our changes + g_PatchDialog.UpdateData(FALSE); +} + +static void OnBtnPatchdetails (GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(true); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchfit (GtkWidget *widget, gpointer data) +{ + Patch_ResetTexturing(1.0, 1.0); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchnatural (GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchreset (GtkWidget *widget, gpointer data) +{ + float fx, fy; + if (DoTextureLayout (&fx, &fy) == IDOK) + { + Patch_ResetTexturing(fx, fy); + } + Sys_UpdateWindows(W_ALL); +} + +static void OnSpinChanged (GtkAdjustment *adj, gpointer data) +{ + texdef_t td; + + td.rotate = 0; + td.scale[0] = td.scale[1] = 0; + td.shift[0] = td.shift[1] = 0; + td.contents = 0; + td.flags = 0; + td.value = 0; + + if (adj->value == 0) + return; + + if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hshift_adj")) + { + l_pPIIncrement->shift[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + + if (adj->value > 0) + td.shift[0] = l_pPIIncrement->shift[0]; + else + td.shift[0] = -l_pPIIncrement->shift[0]; + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vshift_adj")) + { + l_pPIIncrement->shift[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + + if (adj->value > 0) + td.shift[1] = l_pPIIncrement->shift[1]; + else + td.shift[1] = -l_pPIIncrement->shift[1]; + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hscale_adj")) + { + l_pPIIncrement->scale[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + if (l_pPIIncrement->scale[0] == 0.0f) + return; + // make sure scale factor is always >1 for increases and <1 for decreases + if (adj->value > 0) + { + if (l_pPIIncrement->scale[0] < 1) + td.scale[0] = l_pPIIncrement->scale[0]; + else + td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; + } + else + { + if (l_pPIIncrement->scale[0] < 1) + td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; + else + td.scale[0] = l_pPIIncrement->scale[0]; + } + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vscale_adj")) + { + l_pPIIncrement->scale[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + if (l_pPIIncrement->scale[1] == 0.0f) + return; + // make sure scale factor is always >1 for increases and <1 for decreases + if (adj->value > 0) + { + if (l_pPIIncrement->scale[1] < 1) + td.scale[1] = l_pPIIncrement->scale[1]; + else + td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; + } + else + { + if (l_pPIIncrement->scale[1] < 1) + td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; + else + td.scale[1] = l_pPIIncrement->scale[1]; + } + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "rotate_adj")) + { + l_pPIIncrement->rotate = atof (gtk_entry_get_text (GTK_ENTRY (data))); + + if (adj->value > 0) + td.rotate = l_pPIIncrement->rotate; + else + td.rotate = -l_pPIIncrement->rotate; + } + + adj->value = 0; + +#ifdef DBG_PI + Sys_Printf("Patch_SetTextureInfo: %g %g %g %g %g\n", td.shift[0], td.shift[1],td.scale[0],td.scale[1],td.rotate ); +#endif + // will scale shift rotate the patch accordingly + Patch_SetTextureInfo (&td); + // update the point-by-point view + OnSelchangeComboColRow(NULL,NULL); + Sys_UpdateWindows (W_CAMERA); +} + +static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ +#ifdef DBG_PI + Sys_Printf("OnDialogKey\n"); +#endif + if (event->keyval == GDK_Return) + { + OnApply (NULL, NULL); + return TRUE; + } + else if (event->keyval == GDK_Escape) + { + OnDone (NULL, NULL); + return TRUE; + } + return FALSE; +} + +// ============================================================================= +// Global Functions + +void DoPatchInspector() +{ + // do we need to create the dialog? + if (g_PatchDialog.GetWidget() == NULL) + { + g_PatchDialog.Create(); + g_PatchDialog.UpdateData (FALSE); + } + g_PatchDialog.GetPatchInfo(); + if (!l_bIsActive) + g_PatchDialog.ShowDlg (); +} + +void UpdatePatchInspector() +{ + if (l_bIsActive) + g_PatchDialog.GetPatchInfo(); +} + +void TogglePatchInspector() +{ + if (l_bIsActive) + OnDone(NULL,NULL); + else + DoPatchInspector(); +} + +// ============================================================================= +// PatchDialog class + +PatchDialog::PatchDialog () +{ + m_strName = ""; + m_fS = 0.0f; + m_fT = 0.0f; + m_fX = 0.0f; + m_fY = 0.0f; + m_fZ = 0.0f; + m_nCol = 0; + m_nRow = 0; + m_Patch = NULL; + m_bListenChanged = true; +} + +void PatchDialog::InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName(SHADER_NOT_FOUND); + tex->scale[0] = 0.5f; + tex->scale[1] = 0.5f; + tex->rotate = 45; + tex->shift[0] = 8.0f; + tex->shift[1] = 8.0f; +} + +// we plug into HideDlg and ShowDlg to maintain the l_bIsActive flag +void PatchDialog::HideDlg() +{ + l_bIsActive = false; + Dialog::HideDlg(); +} + +void PatchDialog::ShowDlg() +{ + l_bIsActive = true; + Dialog::ShowDlg(); +} + +void PatchDialog::BuildDialog () +{ + GtkWidget *dlg, *vbox, *vbox2, *hbox, *hbox2, *frame, *table, *label; + GtkWidget *button, *entry, *spin, *combo; + GtkObject *adj; + char buf[32]; + + dlg = m_pWidget; + + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posPatchWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Patch Properties"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (OnDone), NULL); + // catch 'Esc' and 'Enter' + gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + frame = gtk_frame_new ("Details"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Row:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Column:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + combo = gtk_combo_new (); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (combo, 60, -1); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", + GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); + AddDialogData (combo, &m_nRow, DLG_COMBO_INT); + m_pRowCombo = combo; + + combo = gtk_combo_new (); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (combo, 60, -1); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", + GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); + AddDialogData (combo, &m_nCol, DLG_COMBO_INT); + m_pColCombo = combo; + + table = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Z:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("S:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("T:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fX, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fY, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fZ, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fS, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fT, DLG_ENTRY_FLOAT); + + frame = gtk_frame_new ("Texturing"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label = gtk_label_new ("Name:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); +// gtk_entry_set_editable (GTK_ENTRY (entry), false); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox2), entry, TRUE, TRUE, 0); + AddDialogData (entry, &m_strName, DLG_ENTRY_TEXT); + + table = gtk_table_new (5, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Horizontal Shift Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Vertical Shift Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Horizontal Stretch Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Vertical Stretch Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Rotate Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (m_pWidget), "hshift_entry", entry); + // we fill in this data, if no patch is selected the widgets are unmodified when the inspector is raised + // so we need to have at least one initialisation somewhere + sprintf (buf, "%g", l_pPIIncrement->shift[0]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "hshift_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->shift[1]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "vshift_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->scale[0]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "hscale_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->scale[1]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "vscale_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->rotate); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); // NOTE: Arnout - this really should be 360 but can't change it anymore as it could break existing maps + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "rotate_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("CAP"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Set..."); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Natural"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Fit"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchfit), NULL); + gtk_widget_set_usize (button, 60, -1); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Done"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnDone), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnApply), NULL); + gtk_widget_set_usize (button, 60, -1); +} + +// sync the dialog our internal data structures +void PatchDialog::UpdateData (bool retrieve) +{ + if (m_pWidget == NULL) + return; + + m_bListenChanged = false; + Dialog::UpdateData (retrieve); + m_bListenChanged = true; +} + +// read the map and feed in the stuff to the dialog box +void PatchDialog::GetPatchInfo() +{ + m_Patch = SinglePatchSelected(); + if (m_Patch != NULL) + { + m_strName = m_Patch->pShader->getName(); + + GList *combo_list = NULL; + int i; + + // fill in the numbers for Row / Col selection + m_bListenChanged = false; + + for (i = 0; i < m_Patch->height; i++) + combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); // NOTE: leaving the g_strdup cause we free with g_free later on + gtk_combo_set_popdown_strings (GTK_COMBO (m_pRowCombo), combo_list); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pRowCombo)->entry), "0"); + + while (combo_list) + { + g_free (combo_list->data); + combo_list = g_list_remove (combo_list, combo_list->data); + } + + for (i = 0; i < m_Patch->width; i++) + combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); + gtk_combo_set_popdown_strings (GTK_COMBO (m_pColCombo), combo_list); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pColCombo)->entry), "0"); + + while (combo_list) + { + g_free (combo_list->data); + combo_list = g_list_remove (combo_list, combo_list->data); + } + + m_bListenChanged = true; + + } + else + Sys_Printf("WARNING: no patch\n"); + // fill in our internal structs + m_nRow = 0; m_nCol = 0; + UpdateRowColInfo(); + // now update the dialog box + UpdateData(false); +} + +// read the current patch on map and initialize m_fX m_fY accordingly +// NOTE: don't call UpdateData in there, it's not meant for +void PatchDialog::UpdateRowColInfo() +{ + m_fX = m_fY = m_fZ = m_fS = m_fT = 0.0; + + if (m_Patch != NULL) + { + // we rely on whatever active row/column has been set before we get called + int r = m_nRow; + int c = m_nCol; + if (r >= 0 && r < m_Patch->height && c >= 0 && c < m_Patch->width) + { + m_fX = m_Patch->ctrl[c][r].xyz[0]; + m_fY = m_Patch->ctrl[c][r].xyz[1]; + m_fZ = m_Patch->ctrl[c][r].xyz[2]; + m_fS = m_Patch->ctrl[c][r].st[0]; + m_fT = m_Patch->ctrl[c][r].st[1]; + } + } +} + diff --git a/radiant/patchdialog.h b/radiant/patchdialog.h new file mode 100644 index 00000000..04c4f6b6 --- /dev/null +++ b/radiant/patchdialog.h @@ -0,0 +1,85 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PATCHDIALOG_H_ +#define _PATCHDIALOG_H_ + +#include "dialog.h" + +#ifdef _DEBUG +//#define DBG_PI +#endif + +class PatchDialog : public Dialog +{ + public: + // overrides from Dialog + void HideDlg(); + void ShowDlg(); + +// void UpdateInfo(); +// void SetPatchInfo(); + void GetPatchInfo(); + void UpdateSpinners(bool bUp, int nID); + // read the current patch on map and initialize m_fX m_fY accordingly + void UpdateRowColInfo(); + // sync the dialog our internal data structures + // depending on the flag it will read or write + // we use m_nCol m_nRow m_fX m_fY m_fZ m_fS m_fT m_strName + // (NOTE: this doesn't actually commit stuff to the map or read from it) + void UpdateData (bool retrieve); + + void InitDefaultIncrement(texdef_t *); + + PatchDialog(); + patchMesh_t *m_Patch; + + Str m_strName; + float m_fS; + float m_fT; + float m_fX; + float m_fY; + float m_fZ; +/* float m_fHScale; + float m_fHShift; + float m_fRotate; + float m_fVScale; + float m_fVShift; */ + int m_nCol; + int m_nRow; + GtkWidget *m_pRowCombo; + GtkWidget *m_pColCombo; + + GtkWidget *GetWidget () { return m_pWidget; } + + // 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +// int m_nUndoId; + + // turn on/off processing of the "changed" "value_changed" messages + // (need to turn off when we are feeding data in) + // NOTE: much more simple than blocking signals + bool m_bListenChanged; + +protected: + void BuildDialog (); +}; + +#endif // _PATCHDIALOG_H_ diff --git a/radiant/plugin.h b/radiant/plugin.h new file mode 100644 index 00000000..9c903891 --- /dev/null +++ b/radiant/plugin.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/*! +\class IPlugin +pure virtual interface for a plugin +temporary solution for migration from old plugin tech to synapse plugins +FIXME/TODO: plugin toolbar +*/ +class IPlugIn +{ + +public: + IPlugIn() { } + virtual ~IPlugIn() { } + + virtual const char* getMenuName() = 0; + virtual int getCommandCount() = 0; + virtual const char* getCommand(int) = 0; + virtual void addMenuID(int) = 0; + virtual bool ownsCommandID(int n) = 0; +}; + +#endif // _PLUGIN_H_ diff --git a/radiant/pluginentities.cpp b/radiant/pluginentities.cpp new file mode 100644 index 00000000..563fa85a --- /dev/null +++ b/radiant/pluginentities.cpp @@ -0,0 +1,74 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// implementation of IPluginEntities specific interface +// + +#ifdef USEPLUGINENTITIES + +#include "stdafx.h" +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +//#include "qe3.h" + +int QERApp_EClassScanDir (char *path, void* hPlug) +{ + char temp[NAME_MAX]; + char filebase[NAME_MAX]; + char filename[NAME_MAX]; + char *s; + eclass_t *e; + DIR *dir; + struct dirent *dirlist; + + QE_ConvertDOSToUnixName( temp, path ); + strcpy (filebase, path); + s = filebase + strlen(filebase)-1; + while (*s != '\\' && *s != '/' && s!=filebase) + s--; + *s = 0; + + dir = opendir (path); + if (dir != NULL) + { + while ((dirlist = readdir (dir)) != NULL) + { + sprintf (filename, "%s/%s", filebase, dirlist->d_name); + Eclass_ScanFile (filename); + + if (eclass_found) + { + e = eclass_e; + e->modelpath = strdup(dirlist->d_name); + e->nShowFlags |= ECLASS_PLUGINENTITY; + e->hPlug = hPlug; + } + } + closedir (dir); + } + return 0; +} + +#endif // USEPLUGINENTITIES diff --git a/radiant/pluginmanager.cpp b/radiant/pluginmanager.cpp new file mode 100644 index 00000000..7840b0b5 --- /dev/null +++ b/radiant/pluginmanager.cpp @@ -0,0 +1,2522 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// PlugInManager.cpp: implementation of the CPlugInManager class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#if defined (__linux__) || defined (__APPLE__) + #include + #include +#endif +#ifdef __APPLE__ + #ifdef __cplusplus + extern "C" { + #endif + #include + #ifdef __cplusplus + } + #endif +#endif +#ifdef _WIN32 + #include "objbase.h" +#endif +#include "pluginmanager.h" +#include "plugin.h" +#include "missing.h" + +#include "version.h" + +CRadiantImageManager g_ImageManager; +CRadiantPluginManager g_PluginsManager; + +_QERPlugSurfaceTable g_SurfaceTable; +_QERFileSystemTable g_FileSystemTable; +_QERShadersTable g_ShadersTable; +_QERPlugMapTable g_MapTable; +_QERPlugMapTable g_MapTable2; +_QEREntityTable g_EntityTable; +_EClassTable g_EClassDefTable; + +/*! + extending entity class formats + this approach only allows a single additional format, but it is enough for now +*/ +bool g_bHaveEClassExt = false; +_EClassTable g_EClassExtTable; + + +filetype_t g_pattern_all("all files", "*.*"); +filetype_t g_pattern_projqe4v2("qe4 v2 project files", "*.qe4"); +filetype_t g_pattern_projxml("xml project files", "*.proj"); +filetype_t g_pattern_mapq3("quake3 maps", "*.map"); +filetype_t g_pattern_mapxml("xml quake3 maps", "*.xmap"); +filetype_t g_pattern_modelmd3("md3 models", "*.md3"); +filetype_t g_pattern_modelmdc("mdc models", "*.mdc"); +filetype_t g_pattern_modelmd2("md2 models", "*.md2"); +filetype_t g_pattern_modelmdl("mdl models", "*.mdl"); +//filetype_t g_pattern_modelea3("EA3 models", "*.ea3"); +filetype_t g_pattern_soundwav("PCM sound files", "*.wav"); +filetype_t g_pattern_regq3("quake3 region", "*.reg"); + +#include + +class RadiantFileTypeRegistry : public IFileTypeRegistry +{ +public: + virtual ~RadiantFileTypeRegistry() {} + virtual void addType(const char* key, filetype_t type) + { + m_typelists[key].push_back(type); + } + virtual void getTypeList(const char* key, IFileTypeList* typelist) + { + filetype_list_t& list_ref = m_typelists[key]; + for(unsigned int i=0; iaddType(list_ref[i].getType()); + } +private: + struct filetype_copy_t + { + inline filetype_copy_t(const filetype_t other) + : m_name(other.name), m_pattern(other.pattern) + {} + inline filetype_t getType() const + { + return filetype_t(m_name.c_str(), m_pattern.c_str()); + } + private: + string_t m_name; + string_t m_pattern; + }; + typedef vector filetype_list_t; + map m_typelists; +}; + +static RadiantFileTypeRegistry g_patterns; + +IFileTypeRegistry* GetFileTypeRegistry() +{ + return &g_patterns; +} + +void InitFileTypes() +{ + //GetFileTypeRegistry()->addType("project", g_pattern_projqe4v2); + GetFileTypeRegistry()->addType("project", g_pattern_projxml); + + GetFileTypeRegistry()->addType(MAP_MAJOR, g_pattern_mapq3); + GetFileTypeRegistry()->addType(MAP_MAJOR, g_pattern_mapxml); + + GetFileTypeRegistry()->addType("region", g_pattern_regq3); +/* + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmd3); + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmd2); + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmdl); + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmdc); + //GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelea3); + */ + + GetFileTypeRegistry()->addType("sound", g_pattern_soundwav); +} + + +class CRadiantModelModuleManager : public CSynapseAPIManager +{ + typedef list APIDescriptorList; + + APIDescriptorList mAPIs; +public: + CRadiantModelModuleManager() + { + SetMatchAPI(MODEL_MAJOR, "*"); + } + virtual ~CRadiantModelModuleManager() + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + { + delete (_QERPlugModelTable*)(*i)->mpTable; + delete *i; + *i = NULL; + } + mAPIs.clear(); + } + + // CSynapseAPIManager interface ------------------- + APIDescriptor_t* BuildRequireAPI(APIDescriptor_t* pAPI) + { + APIDescriptor_t* pRequireAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); + pRequireAPI->mpTable = new _QERPlugModelTable; + ((_QERPlugModelTable*)pRequireAPI->mpTable)->m_nSize = sizeof(_QERPlugModelTable); + pRequireAPI->mSize = sizeof(_QERPlugModelTable); + mAPIs.push_front(pRequireAPI); + return pRequireAPI; + } + + // Model Manager specific + const _QERPlugModelTable* GetModelTable(const char* version) + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + if(strcmp(version, (*i)->minor_name) == 0) + return ((_QERPlugModelTable*)(*i)->mpTable); + return NULL; + } +}; + +CRadiantModelModuleManager g_ModelManager; + +/*! One of these exists for each unique model ID in use */ +class CModelWrapper +{ + friend class CModelManager; +public: + CModelWrapper (const char *id, const char* version) : refcount(1) + { + copy(id, version); + construct(); + } + void Refresh() + { + destroy(); + construct(); + } + ~CModelWrapper () + { + destroy(); + } +private: + void copy(const char* id, const char* version) + { + m_id = id; + m_version = version; + } + void construct() + { + m_model.pRender = NULL; + m_model.pSelect = NULL; + m_model.pEdit = NULL; + + const _QERPlugModelTable* pTable = g_ModelManager.GetModelTable(m_version.c_str()); + + if(pTable != NULL) + pTable->m_pfnLoadModel(&m_model, m_id.c_str()); + } + void destroy() + { + if (m_model.pRender) m_model.pRender->DecRef(); + if (m_model.pSelect) m_model.pSelect->DecRef(); + if (m_model.pEdit) m_model.pEdit->DecRef(); + } + string_t m_id; + string_t m_version; + entity_interfaces_t m_model; + int refcount; +}; + +/*! Creates and tracks CModelWrapper instances. +Creates a new instance for each unique ID requested, keeps count of the number of +times an ID is being referenced, and destroys any instance that is no longer in use */ +class CModelManager : public IModelCache +{ +public: + CModelManager() + { + m_ptrs = g_ptr_array_new (); + } + virtual ~CModelManager() + { + g_ptr_array_free(m_ptrs, FALSE); + } + + virtual void DeleteByID(const char *id, const char* version) + { + unsigned int i; + CModelWrapper *elem; + for(i=0; ilen; i++) + { + elem = (CModelWrapper*)m_ptrs->pdata[i]; + if(strcmp(elem->m_version.c_str(), version) == 0 + && strcmp(elem->m_id.c_str(), id) == 0 + && --elem->refcount == 0) + { + g_ptr_array_remove_index_fast(m_ptrs, i); + delete elem; + return; + } + } + } + + virtual entity_interfaces_t *GetByID(const char *id, const char* version) + { + unsigned int i; + CModelWrapper *elem; + for(i=0; ilen; i++) + { + elem = (CModelWrapper*)m_ptrs->pdata[i]; + if(strcmp(elem->m_version.c_str(), version) == 0 + && strcmp(elem->m_id.c_str(), id) == 0) + { + elem->refcount++; + return &elem->m_model; + } + } + + elem = new CModelWrapper(id, version); + g_ptr_array_add(m_ptrs, elem); + + return &elem->m_model; + } + + virtual void RefreshAll() + { + for(unsigned int i=0; ilen; ++i) + ((CModelWrapper*)m_ptrs->pdata[i])->Refresh(); + } +private: + GPtrArray *m_ptrs; // array of CModelWrapper* +}; + +CModelManager g_model_cache; + +IModelCache* GetModelCache() +{ + return &g_model_cache; +} + +// toolbar manager +class CRadiantToolbarModuleManager : public CSynapseAPIManager +{ + typedef list APIDescriptorList; + + APIDescriptorList mAPIs; +public: + CRadiantToolbarModuleManager() + { + SetMatchAPI(TOOLBAR_MAJOR, "*"); + } + virtual ~CRadiantToolbarModuleManager() + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + { + delete (_QERPlugToolbarTable*)(*i)->mpTable; + delete *i; + *i = NULL; + } + mAPIs.clear(); + } + + // CSynapseAPIManager interface ------------------- + APIDescriptor_t* BuildRequireAPI(APIDescriptor_t* pAPI) + { + APIDescriptor_t* pRequireAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); + pRequireAPI->mpTable = new _QERPlugToolbarTable; + ((_QERPlugToolbarTable*)pRequireAPI->mpTable)->m_nSize = sizeof(_QERPlugToolbarTable); + pRequireAPI->mSize = sizeof(_QERPlugToolbarTable); + mAPIs.push_front(pRequireAPI); + return pRequireAPI; + } + + // Toolbar Manager specific + void ConstructToolbar() + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + AddItem((_QERPlugToolbarTable*)(*i)->mpTable); + } + +private: + + void AddItem(_QERPlugToolbarTable* pTable) + { + const unsigned int count = pTable->m_pfnToolbarButtonCount(); + for(unsigned int i=0; im_pfnGetToolbarButton(i); + g_pParentWnd->AddPlugInToolbarButton(button); + } + } +}; + +CRadiantToolbarModuleManager g_ToolbarModuleManager; + + +/* image manager ---------------------------------------- */ + +CRadiantImageManager::~CRadiantImageManager() +{ + list::iterator iSlot; + for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) + { + delete *iSlot; + *iSlot = NULL; + } +} + +void CImageTableSlot::InitForFillAPITable(APIDescriptor_t *pAPI) +{ + mpAPI = pAPI; + mpTable = new _QERPlugImageTable; + mpTable->m_nSize = sizeof(_QERPlugImageTable); + mpAPI->mSize = sizeof(_QERPlugImageTable); + mpAPI->mpTable = mpTable; +} + +void CRadiantImageManager::FillAPITable(APIDescriptor_t *pAPI) +{ + CImageTableSlot *pSlot = new CImageTableSlot(); + pSlot->InitForFillAPITable(pAPI); + mSlots.push_front(pSlot); +} + +/*! + Loads an image by calling the module that handles the extension extracted from the filename + \param name The filename to load. If no extension is provided, we walk the list of supported extensions. + \param pic The returned image data + \param width The returned width of the image + \param height The returned height of the image +*/ +void CRadiantImageManager::LoadImage(const char *name, byte **pic, int *width, int *height) +{ + const char *ext = NULL; + int len; + + // extract extension + len = strlen (name); + if ((len > 5) && (name[len-4] == '.')) + ext = &name[len-3]; + + if (ext == NULL) + { + // if no extension is provided, start walking through the list + Str fullname; + list::iterator iSlot; + for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) + { + APIDescriptor_t *pAPI = (*iSlot)->GetDescriptor(); + fullname.Format("%s.%s", name, pAPI->minor_name); + (*iSlot)->GetTable()->m_pfnLoadImage(fullname.GetBuffer(), pic, width, height); + if (*pic) + return; // this was the right extension, we loaded + } + return; + } + + // start walking the interfaces + list::iterator iSlot; + for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) + { + APIDescriptor_t *pAPI = (*iSlot)->GetDescriptor(); + if (!strcmp(pAPI->minor_name, ext)) + { + (*iSlot)->GetTable()->m_pfnLoadImage(name, pic, width, height); + return; + } + } + Sys_FPrintf(SYS_WRN, "WARNING: no image table for extension '%s'\n", ext); +} + +void CRadiantImageManager::BeginExtensionsScan() +{ + mExtScanSlot = mSlots.begin(); +} + +const char* CRadiantImageManager::GetNextExtension() +{ + if (mExtScanSlot != mSlots.end()) + { + char *ext = (*mExtScanSlot)->GetDescriptor()->minor_name; + mExtScanSlot++; + return ext; + } + return NULL; +} + +/* plugin manager --------------------------------------- */ +APIDescriptor_t* CRadiantPluginManager::BuildRequireAPI(APIDescriptor_t *pAPI) +{ + CPluginSlot *pSlot = new CPluginSlot(pAPI); + mSlots.push_front(pSlot); + return pSlot->GetDescriptor(); +} + +void CRadiantPluginManager::PopulateMenu() +{ + list::iterator iPlug; + for(iPlug=mSlots.begin(); iPlug != mSlots.end(); iPlug++) + { + g_pParentWnd->AddPlugInMenuItem(*iPlug); + } +} + +void CSynapseClientRadiant::ImportMap(IDataStream *in, CPtrArray *ents, const char *type) +{ + if (strcmp(type,"map")==0) + { + g_MapTable.m_pfnMap_Read(in, ents); + } + else if (strcmp(type,"xmap")==0) + { + g_MapTable2.m_pfnMap_Read(in, ents); + } + else + Sys_FPrintf(SYS_WRN, "WARNING: no module found for map interface type '%s'\n", type); +} + +void CSynapseClientRadiant::ExportMap(CPtrArray *ents, IDataStream *out, const char *type) +{ + if (strcmp(type,"map")==0) + { + g_MapTable.m_pfnMap_Write(ents, out); + } + else if (strcmp(type,"xmap")==0) + { + g_MapTable2.m_pfnMap_Write(ents, out); + } + else + Sys_FPrintf(SYS_WRN, "WARNING: no module found for map interface type '%s'\n", type); +} + +CPluginSlot::CPluginSlot(APIDescriptor_t *pAPI) +{ + mpAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); + mpTable = new _QERPluginTable; + mpTable->m_nSize = sizeof(_QERPluginTable); + mpAPI->mSize = sizeof(_QERPluginTable); + mpAPI->mpTable = mpTable; + m_CommandStrings = NULL; + m_CommandIDs = NULL; + m_bReady = false; +} + +CPluginSlot::~CPluginSlot() +{ + delete mpAPI; + delete mpTable; + while (m_CommandStrings) + { + ::free (m_CommandStrings->data); + m_CommandStrings = g_slist_remove (m_CommandStrings, m_CommandStrings->data); + } +} + +void CPluginSlot::Init() +{ + CString str = mpTable->m_pfnQERPlug_GetCommandList(); + char cTemp[1024]; + strcpy(cTemp, str); + char* token = strtok(cTemp, ",;"); + if (token && *token == ' ') + { + while (*token == ' ') + token++; + } + while (token != NULL) + { + m_CommandStrings = g_slist_append (m_CommandStrings, strdup (token)); + token = strtok(NULL, ",;"); + } + mpTable->m_pfnQERPlug_Init(NULL, (void*)g_pParentWnd->m_pWidget); + m_bReady = true; +} + +const char* CPluginSlot::getMenuName() +{ + return mpAPI->minor_name; +} + +int CPluginSlot::getCommandCount() +{ + if (!m_bReady) + Init(); + return g_slist_length (m_CommandStrings); +} + +const char* CPluginSlot::getCommand(int n) +{ + if (!m_bReady) + Init(); + return (char*)g_slist_nth_data (m_CommandStrings, n); +} + +void CPluginSlot::addMenuID(int n) +{ + m_CommandIDs = g_slist_append (m_CommandIDs, GINT_TO_POINTER (n)); +} + +bool CPluginSlot::ownsCommandID(int n) +{ + GSList* lst; + + for (lst = m_CommandIDs; lst != NULL; lst = g_slist_next (lst)) + { + if (GPOINTER_TO_INT (lst->data) == n) + return true; + } + return false; +} + +void CPluginSlot::Dispatch(const char *p) +{ + vec3_t vMin, vMax; + if (selected_brushes.next == &selected_brushes) + { + vMin[0] = vMin[1] = vMin[2] = 0; + VectorCopy(vMin, vMax); + } else + { + Select_GetBounds (vMin, vMax); + } + mpTable->m_pfnQERPlug_Dispatch(p, vMin, vMax, QE_SingleBrush(true)); +} + +CRadiantPluginManager::~CRadiantPluginManager() +{ + list::iterator iSlot; + for(iSlot=mSlots.begin(); iSlot!=mSlots.end(); iSlot++) + { + delete *iSlot; + *iSlot = NULL; + } +} + +bool CRadiantPluginManager::Dispatch(int n, const char* p) +{ + list::iterator iPlug; + for(iPlug=mSlots.begin(); iPlug!=mSlots.end(); iPlug++) + { + CPluginSlot *pPlug = *iPlug; + if (pPlug->ownsCommandID(n)) + { + pPlug->Dispatch(p); + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CPlugInManager::CPlugInManager() +{ + PatchesMode = EActivePatches; + m_PlugIns = NULL; +} + +CPlugInManager::~CPlugInManager() +{ + Cleanup(); +} + +void CPlugInManager::InitForDir(const Str &dir) +{ + Str path; + + path = dir; + path += g_strPluginsDir; + // SYNAPSE + g_pParentWnd->GetSynapseServer().AddSearchPath(path); + + if (strcmp(g_strPluginsDir.GetBuffer(), g_strModulesDir.GetBuffer()) != 0) + { + path = dir; + path += g_strModulesDir; + // SYNAPSE + g_pParentWnd->GetSynapseServer().AddSearchPath(path); + } +} + +static const XMLConfigEntry_t manager_entries[] = + { + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, + { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, + { MAP_MAJOR, SYN_REQUIRE, sizeof(g_MapTable), &g_MapTable }, + { ECLASS_MAJOR, SYN_REQUIRE, sizeof(g_EClassDefTable), &g_EClassDefTable }, + { SURFACEDIALOG_MAJOR, SYN_REQUIRE, sizeof(g_SurfaceTable), &g_SurfaceTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +void CPlugInManager::Init() +{ + Str synapse_config; + + Cleanup(); + + // set some globals + g_qeglobals.bBSPFrontendPlugin = false; + + InitForDir(g_strGameToolsPath); + InitForDir(g_strAppPath); + + synapse_config = g_strGameToolsPath; + synapse_config += "synapse.config"; + if (!g_pParentWnd->GetSynapseServer().Initialize(synapse_config.GetBuffer(), &Sys_Printf_VA)) + Error("Synpase server initialization failed (see console)\n"); + + // builtin modules + g_pParentWnd->GetSynapseServer().EnumerateBuiltinModule(&eclass_def); + + // APIs we provide + g_pParentWnd->GetSynapseClient().AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1)); + g_pParentWnd->GetSynapseClient().AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(_QERScripLibTable)); + g_pParentWnd->GetSynapseClient().AddAPI(BRUSH_MAJOR, NULL, sizeof(_QERBrushTable)); + g_pParentWnd->GetSynapseClient().AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable)); + g_pParentWnd->GetSynapseClient().AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable)); + g_pParentWnd->GetSynapseClient().AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable)); + g_pParentWnd->GetSynapseClient().AddAPI(PATCH_MAJOR, NULL, sizeof(_QERPatchTable)); + g_pParentWnd->GetSynapseClient().AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(_EClassManagerTable)); + g_pParentWnd->GetSynapseClient().AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable)); + g_pParentWnd->GetSynapseClient().AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable)); + g_pParentWnd->GetSynapseClient().AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable)); + g_pParentWnd->GetSynapseClient().AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable)); + g_pParentWnd->GetSynapseClient().AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable)); + g_pParentWnd->GetSynapseClient().AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable)); + + // modules configured by XML + if ( !g_pParentWnd->GetSynapseClient().ConfigXML( &g_pParentWnd->GetSynapseServer(), "core", manager_entries ) ) { + Error("Synapse server initialization failed (see console)\n"); + } + + // adding a manager is a special case that ConfigXML doesn't take care of + g_pParentWnd->GetSynapseServer().SelectClientConfig( "core" ); + char *minor; + if ( !g_pParentWnd->GetSynapseServer().GetConfigForAPI( IMAGE_MAJOR, &minor ) ) { + Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", IMAGE_MAJOR ); + Error("Synapse server initialization failed (see console)\n"); + } + g_ImageManager.SetMatchAPI( IMAGE_MAJOR, minor ); + g_pParentWnd->GetSynapseClient().AddManager( &g_ImageManager ); + + // SYN_REQUIRE entries which are still hardcoded + g_pParentWnd->GetSynapseClient().AddAPI(MAP_MAJOR, "mapxml", sizeof(g_MapTable2), SYN_REQUIRE, &g_MapTable2); + g_pParentWnd->GetSynapseClient().AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + + // plugins: load anything that claims to be a plugin + // minor becomes some kind of matching pattern + // g_PluginsManager is an API any class, it receives several function tables as needed + // you can't do a SYN_PROVIDE with that, has to be a SYN_REQUIRE ? + g_PluginsManager.SetMatchAPI(PLUGIN_MAJOR, "*"); + g_pParentWnd->GetSynapseClient().AddManager(&g_PluginsManager); + g_pParentWnd->GetSynapseClient().AddManager(&g_ToolbarModuleManager); + g_pParentWnd->GetSynapseClient().AddManager(&g_ModelManager); + if (!g_pParentWnd->GetSynapseServer().Resolve(&g_pParentWnd->GetSynapseClient())) + { + Error("synapse initialization fail (see console)"); + } + g_PluginsManager.PopulateMenu(); + g_ToolbarModuleManager.ConstructToolbar(); + InitFileTypes(); +} + +void CPlugInManager::Shutdown() +{ + g_pParentWnd->GetSynapseServer().Shutdown(); +} + +void CPlugInManager::Cleanup() +{ + int i; + + for (i = 0; i < m_BrushHandles.GetSize(); i++) + { + brush_t *pb = reinterpret_cast(m_BrushHandles.GetAt(i)); + Brush_Free(pb); + } + m_BrushHandles.RemoveAll(); + + for (i = 0; i < m_EntityHandles.GetSize(); i++) + { + entity_t *pe = reinterpret_cast(m_EntityHandles.GetAt(i)); + Entity_Free(pe); + } + m_EntityHandles.RemoveAll(); + + // patches + // these are linked into the map + m_PatchesHandles.RemoveAll(); + // these patches were allocated by Radiant on plugin request + // if the list is not empty, it means either the plugin asked for allocation and never commited them to the map + // in which case we are supposed to delete them + // or it commited them but never called m_pfnReleasePatchHandles, in case the patches may have already been + // erased and we are trying a second time, therefore crashing .. + //++timo FIXME: for now I leave a leak warning, we'd need a table to keep track of commited patches +#ifdef _DEBUG + if (m_PluginPatches.GetSize() != 0) + Sys_Printf("WARNING: m_PluginPatches.GetSize() != 0 in CPlugInManager::Cleanup, possible leak\n"); +#endif + +/* for (i = 0; i < m_PluginPatches.GetSize(); i++) + { + patchMesh_t *pMesh = reinterpret_cast(m_PluginPatches.GetAt(i)); + if (pMesh->pSymbiot) + delete pMesh; + } + m_PluginPatches.RemoveAll(); */ +} + +void CPlugInManager::Dispatch(int n, const char * p) +{ + g_PluginsManager.Dispatch(n, p); +} + +void WINAPI QERApp_GetDispatchParams(vec3_t vMin, vec3_t vMax, bool *bSingleBrush) +{ + if (selected_brushes.next == &selected_brushes) + { + vMin[0] = vMin[1] = vMin[2] = 0; + VectorCopy(vMin, vMax); + } else + { + Select_GetBounds (vMin, vMax); + } + + if( bSingleBrush ) + *bSingleBrush = QE_SingleBrush(true); +} + + +// creates a dummy brush in the active brushes list +// FIXME : is this one really USED ? +void WINAPI QERApp_CreateBrush(vec3_t vMin, vec3_t vMax) +{ + + brush_t* pBrush = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); + Entity_LinkBrush (world_entity, pBrush); + Brush_Build(pBrush); + Brush_AddToList (pBrush, &active_brushes); + Select_Brush(pBrush); + Sys_UpdateWindows(W_ALL); +} + +void* CPlugInManager::CreateBrushHandle() +{ + brush_t *pb = Brush_Alloc(); + pb->numberId = g_nBrushId++; + m_BrushHandles.Add(pb); + return(void*)pb; +} + +void CPlugInManager::DeleteBrushHandle(void * vp) +{ + CPtrArray* pHandles[3]; + pHandles[0] = &m_SelectedBrushHandles; + pHandles[1] = &m_ActiveBrushHandles; + pHandles[2] = &m_BrushHandles; + + for (int j = 0; j < 3; j++) + { + for (int i = 0; i < pHandles[j]->GetSize(); i++) + { + brush_t *pb = reinterpret_cast(pHandles[j]->GetAt(i)); + if (pb == reinterpret_cast(vp)) + { + if (j == 2) + { + // only remove it from the list if it is work area + // this allows the selected and active list indexes to remain constant + // throughout a session (i.e. between an allocate and release) + pHandles[j]->RemoveAt(i); + } + Brush_Free(pb); + Sys_MarkMapModified(); // PGM + return; + } + } + } +} + +void CPlugInManager::CommitBrushHandleToMap(void * vp) +{ + g_bScreenUpdates = false; + for (int i = 0; i < m_BrushHandles.GetSize(); i++) + { + brush_t *pb = reinterpret_cast(m_BrushHandles.GetAt(i)); + if (pb == reinterpret_cast(vp)) + { + m_BrushHandles.RemoveAt(i); + Entity_LinkBrush (world_entity, pb); + Brush_Build(pb); + Brush_AddToList (pb, &active_brushes); + Select_Brush(pb); + } + } + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); +} + +void CPlugInManager::AddFaceToBrushHandle(void * vp, vec3_t v1, vec3_t v2, vec3_t v3) +{ + brush_t *bp = FindBrushHandle(vp); + if (bp != NULL) + { + face_t *f = Face_Alloc(); + f->texdef = g_qeglobals.d_texturewin.texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = bp->brush_faces; + bp->brush_faces = f; + VectorCopy (v1, f->planepts[0]); + VectorCopy (v2, f->planepts[1]); + VectorCopy (v3, f->planepts[2]); + } +} + +brush_t* CPlugInManager::FindBrushHandle(void * vp) +{ + CPtrArray* pHandles[4]; + pHandles[0] = &m_SelectedBrushHandles; + pHandles[1] = &m_ActiveBrushHandles; + pHandles[2] = &m_BrushHandles; + pHandles[3] = &m_EntityBrushHandles; + + for (int j = 0; j < 4; j++) + { + for (int i = 0; i < pHandles[j]->GetSize(); i++) + { + brush_t *pb = reinterpret_cast(pHandles[j]->GetAt(i)); + if (pb == reinterpret_cast(vp)) + { + return pb; + } + } + } + return NULL; +} + +patchMesh_t* CPlugInManager::FindPatchHandle(int index) +{ + switch (PatchesMode) + { + case EActivePatches: + case ESelectedPatches: + if ( index < m_PatchesHandles.GetSize() ) + { + brush_t *pb = reinterpret_cast(m_PatchesHandles.GetAt(index)); + return pb->pPatch; + } +#ifdef _DEBUG + Sys_Printf("WARNING: out of bounds in CPlugInManager::FindPatchHandle\n"); +#endif + break; + case EAllocatedPatches: + if ( index < m_PluginPatches.GetSize() ) + { + patchMesh_t *pPatch = reinterpret_cast(m_PluginPatches.GetAt(index)); + return pPatch; + } +#ifdef _DEBUG + Sys_Printf("WARNING: out of bounds in CPlugInManager::FindPatchHandle\n"); +#endif + break; + } + return NULL; +} + +void* WINAPI QERApp_CreateBrushHandle() +{ + return g_pParentWnd->GetPlugInMgr().CreateBrushHandle(); +} + +void WINAPI QERApp_DeleteBrushHandle(void* vp) +{ + g_pParentWnd->GetPlugInMgr().DeleteBrushHandle(vp); +} + +void WINAPI QERApp_CommitBrushHandleToMap(void* vp) +{ + g_pParentWnd->GetPlugInMgr().CommitBrushHandleToMap(vp); +} + +void WINAPI QERApp_AddFace(void* vp, vec3_t v1, vec3_t v2, vec3_t v3) +{ + g_pParentWnd->GetPlugInMgr().AddFaceToBrushHandle(vp, v1, v2, v3); +} + +void WINAPI QERApp_DeleteSelection() +{ + Select_Delete(); +} + +void QERApp_GetCamera( vec3_t origin, vec3_t angles ) +{ + VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->origin, origin ); + VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->angles, angles ); +} + +void QERApp_SetCamera( vec3_t origin, vec3_t angles ) +{ + VectorCopy( origin, g_pParentWnd->GetCamWnd()->Camera()->origin ); + VectorCopy( angles, g_pParentWnd->GetCamWnd()->Camera()->angles ); + + Sys_UpdateWindows( W_ALL ); // specify + g_pParentWnd->OnTimer(); +} + +void QERApp_GetCamWindowExtents( int *x, int *y, int *width, int *height ) +{ + GtkWidget *widget; + + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + widget = g_pParentWnd->GetCamWnd()->m_pParent; + else + widget = g_pParentWnd->GetCamWnd()->GetWidget(); + + get_window_pos (widget, x, y); + + *width = g_pParentWnd->GetCamWnd()->Camera()->width; + *height = g_pParentWnd->GetCamWnd()->Camera()->height; +} + +//FIXME: this AcquirePath stuff is pretty much a mess and needs cleaned up +bool g_bPlugWait = false; +bool g_bPlugOK = false; +int g_nPlugCount = 0; + +void _PlugDone(bool b, int n) +{ + g_bPlugWait = false; + g_bPlugOK = b; + g_nPlugCount = n; +} + +void WINAPI QERApp_GetPoints(int nMax, _QERPointData *pData, char* pMsg) +{ + ShowInfoDialog(pMsg); + g_bPlugWait = true; + g_bPlugOK = false; + g_nPlugCount = 0; +// g_nPlugCount=nMax-1; + AcquirePath(nMax, &_PlugDone); + + while (g_bPlugWait) + gtk_main_iteration (); + + HideInfoDialog(); + + pData->m_nCount = 0; + pData->m_pVectors = NULL; + + if (g_bPlugOK && g_nPlugCount > 0) + { + pData->m_nCount = g_nPlugCount; + pData->m_pVectors = reinterpret_cast(qmalloc(g_nPlugCount * sizeof(vec3_t))); + vec3_t *pOut = pData->m_pVectors; + for (int i = 0; i < g_nPlugCount; i++) + { + memcpy(pOut, &g_PathPoints[i],sizeof(vec3_t)); + pOut++; + } + } +} + +//#define DBG_PAPI + +void CheckTexture(face_t *f) +{ + if (!f->d_texture) + { +#ifdef DBG_PAPI + Sys_Printf("CheckTexture: requesting %s\n", f->texdef.name); +#endif + f->pShader = QERApp_Shader_ForName (f->texdef.GetName()); + f->pShader->IncRef(); + f->d_texture = f->pShader->getTexture(); + } +} + +// expects pData->m_TextureName to be relative to "textures/" +void WINAPI QERApp_AddFaceData(void* pv, _QERFaceData *pData) +{ +#ifdef DBG_PAPI + Sys_Printf("FindBrushHandle..."); +#endif + brush_t* pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); +#ifdef DBG_PAPI + Sys_Printf("Done\n"); +#endif + if (pBrush != NULL) + { + face_t *f = Face_Alloc(); + f->texdef = g_qeglobals.d_texturewin.texdef; + f->texdef.flags = pData->m_nFlags; + f->texdef.contents = pData->m_nContents; + f->texdef.value = pData->m_nValue; + f->texdef.SetName(pData->m_TextureName); + f->next = pBrush->brush_faces; + pBrush->brush_faces = f; + VectorCopy (pData->m_v1, f->planepts[0]); + VectorCopy (pData->m_v2, f->planepts[1]); + VectorCopy (pData->m_v3, f->planepts[2]); + // we might need to convert one way or the other if the input and the brush coordinates setting don't match + if (pData->m_bBPrimit == true) + { + f->brushprimit_texdef = pData->brushprimit_texdef; + if (!g_qeglobals.m_bBrushPrimitMode) + { + // before calling into the conversion, make sure we have a texture! + CheckTexture (f); +#ifdef DBG_PAPI + Sys_Printf("BrushPrimitFaceToFace..."); +#endif + + // convert BP to regular + BrushPrimitFaceToFace (f); +#ifdef DBG_PAPI + Sys_Printf("Done\n"); +#endif + } + } else + { +#ifdef _DEBUG + if (pData->m_bBPrimit != false) + Sys_FPrintf (SYS_WRN, "non-initialized pData->m_bBPrimit in QERApp_AddFaceData\n"); +#endif + f->texdef.rotate = pData->m_fRotate; + f->texdef.shift[0] = pData->m_fShift[0]; + f->texdef.shift[1] = pData->m_fShift[1]; + f->texdef.scale[0] = pData->m_fScale[0]; + f->texdef.scale[1] = pData->m_fScale[1]; + if (g_qeglobals.m_bBrushPrimitMode) + { + CheckTexture (f); +#ifdef DBG_PAPI + Sys_Printf("FaceToBrushPrimitFace..."); +#endif + + // convert regular to BP + FaceToBrushPrimitFace (f); +#ifdef DBG_PAPI + Sys_Printf("Done\n"); +#endif + } + } + Sys_MarkMapModified(); // PGM + } +} + +int WINAPI QERApp_GetFaceCount(void* pv) +{ + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + n++; + } + } + return n; +} + +_QERFaceData* WINAPI QERApp_GetFaceData(void* pv, int nFaceIndex) +{ + static _QERFaceData face; + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + +#ifdef _DEBUG + if (!pBrush->brush_faces) + { + Sys_Printf( "Warning : pBrush->brush_faces is NULL in QERApp_GetFaceData\n" ); + return NULL; + } +#endif + + if (n == nFaceIndex) + { + face.m_nContents = f->texdef.contents; + face.m_nFlags = f->texdef.flags; + face.m_nValue = f->texdef.value; + if (g_qeglobals.m_bBrushPrimitMode) + { + //++timo NOTE: we may want to convert back to old format for backward compatibility with some old plugins? + face.m_bBPrimit = true; + face.brushprimit_texdef = f->brushprimit_texdef; + } else + { + face.m_fRotate = f->texdef.rotate; + face.m_fScale[0] = f->texdef.scale[0]; + face.m_fScale[1] = f->texdef.scale[1]; + face.m_fShift[0] = f->texdef.shift[0]; + face.m_fShift[1] = f->texdef.shift[1]; + } + strcpy(face.m_TextureName, f->texdef.GetName()); + VectorCopy(f->planepts[0], face.m_v1); + VectorCopy(f->planepts[1], face.m_v2); + VectorCopy(f->planepts[2], face.m_v3); + return &face; + } + n++; + } + } + return NULL; +} + +void WINAPI QERApp_SetFaceData(void* pv, int nFaceIndex, _QERFaceData *pData) +{ + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + if (n == nFaceIndex) + { + f->texdef.flags = pData->m_nFlags; + f->texdef.contents = pData->m_nContents; + f->texdef.value = pData->m_nValue; + f->texdef.rotate = pData->m_fRotate; + f->texdef.shift[0] = pData->m_fShift[0]; + f->texdef.shift[1] = pData->m_fShift[1]; + f->texdef.scale[0] = pData->m_fScale[0]; + f->texdef.scale[1] = pData->m_fScale[1]; + //strcpy(f->texdef.name, pData->m_TextureName); + f->texdef.SetName(pData->m_TextureName); + VectorCopy(pData->m_v1, f->planepts[0]); + VectorCopy(pData->m_v2, f->planepts[1]); + VectorCopy(pData->m_v3, f->planepts[2]); + Sys_MarkMapModified(); // PGM + return; // PGM + } + n++; + } + } +} + +void WINAPI QERApp_DeleteFace(void* pv, int nFaceIndex) +{ + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + face_t *pPrev = pBrush->brush_faces; + for (face_t *f = pBrush->brush_faces; f; f = f->next) + { + if (n == nFaceIndex) + { + pPrev->next = f->next; + Face_Free (f); + Sys_MarkMapModified(); // PGM + return; + } + n++; + pPrev = f; + } + } +} + +//========== +//PGM +void WINAPI QERApp_BuildBrush (void* pv) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + Brush_Build(pBrush); + Sys_UpdateWindows(W_ALL); + } +} + +//Timo : another version with bConvert flag +//++timo since 1.7 is not compatible with earlier plugin versions, remove this one and update QERApp_BuildBrush +void WINAPI QERApp_BuildBrush2 (void* pv, int bConvert) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + Brush_Build( pBrush, true, true, bConvert ); + Sys_UpdateWindows(W_ALL); + } +} + +void WINAPI QERApp_SelectBrush (void* pv) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + Select_Brush(pBrush, false); + Sys_UpdateWindows(W_ALL); + } + +} + +void WINAPI QERApp_DeselectBrush (void* pv) +{ + // FIXME - implement this! +} + +void WINAPI QERApp_ResetPlugins() +{ + g_pParentWnd->OnPluginsRefresh(); +} + +void WINAPI QERApp_DeselectAllBrushes () +{ + Select_Deselect(); + Sys_UpdateWindows(W_ALL); +} +//PGM +//========== + +void WINAPI QERApp_TextureBrush(void* pv, char* pName) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + //strcpy(f->texdef.name, pName); + f->texdef.SetName(pName); + } + Sys_MarkMapModified(); // PGM + } +} + +int WINAPI QERApp_SelectedBrushCount() +{ + int n = 0; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + n++; + } + return n; +} + +int WINAPI QERApp_ActiveBrushCount() +{ + int n = 0; + for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + n++; + } + return n; +} + +int WINAPI QERApp_AllocateSelectedBrushHandles() +{ + int n = 0; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + n++; + g_pParentWnd->GetPlugInMgr().GetSelectedHandles().Add(pb); + } + return n; +} + +int WINAPI QERApp_AllocateActiveBrushHandles() +{ + int n = 0; + for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + n++; + g_pParentWnd->GetPlugInMgr().GetActiveHandles().Add(pb); + } + return n; +} + +void WINAPI QERApp_ReleaseSelectedBrushHandles() +{ + g_pParentWnd->GetPlugInMgr().GetSelectedHandles().RemoveAll(); + Sys_UpdateWindows(W_ALL); +} + +void WINAPI QERApp_ReleaseActiveBrushHandles() +{ + g_pParentWnd->GetPlugInMgr().GetActiveHandles().RemoveAll(); + Sys_UpdateWindows(W_ALL); +} + +void* WINAPI QERApp_GetActiveBrushHandle(int nIndex) +{ + if (nIndex < g_pParentWnd->GetPlugInMgr().GetActiveHandles().GetSize()) + { + return reinterpret_cast(g_pParentWnd->GetPlugInMgr().GetActiveHandles().GetAt(nIndex)); + } + return NULL; +} + +void* WINAPI QERApp_GetSelectedBrushHandle(int nIndex) +{ + if (nIndex < g_pParentWnd->GetPlugInMgr().GetSelectedHandles().GetSize()) + { + return reinterpret_cast(g_pParentWnd->GetPlugInMgr().GetSelectedHandles().GetAt(nIndex)); + } + return NULL; +} + +int WINAPI QERApp_TextureCount() +{ + //++timo TODO: replace by QERApp_GetActiveShaderCount and verify + Texture_StartPos (); + int x, y; + int n = 0; + while (1) + { + IShader *pShader = Texture_NextPos (&x, &y); + if (!pShader) + break; + n++; + } + return n; +} + +char* WINAPI QERApp_GetTexture(int nIndex) +{ + //++timo TODO: replace by QERApp_ActiveShader_ForIndex + // these funcs would end up being provided for backward compatibility + static char name[QER_MAX_NAMELEN]; + Texture_StartPos (); + int x, y; + int n = 0; + while (1) + { + IShader *pShader = Texture_NextPos (&x, &y); + if (!pShader) + break; + if (n == nIndex) + { + strcpy(name, pShader->getName()); + return name; + } + n++; + } + return NULL; +} + +char* WINAPI QERApp_GetCurrentTexture() +{ + static char current_tex[1024]; + strcpy(current_tex,g_qeglobals.d_texturewin.texdef.GetName()); + return current_tex; +} + +void WINAPI QERApp_SetCurrentTexture(char* strName) +{ + //++timo hu ?? tex is not initialized ?? can be any value .. + texdef_t tex; + //++timo added a brushprimit_texdef .. + // smthg to be done here + brushprimit_texdef_t brushprimit_tex; + //strcpy(tex.name, strName); + tex.SetName(strName); + Texture_SetTexture(&tex,&brushprimit_tex); +} + +int WINAPI QERApp_GetEClassCount() +{ + int n = 0; + for (eclass_t *e = eclass ; e ; e = e->next) + { + n++; + } + return n; +} + +char* WINAPI QERApp_GetEClass(int nIndex) +{ + int n = 0; + for (eclass_t *e = eclass ; e ; e = e->next) + { + if (n == nIndex) + { + return e->name; + } + } + return NULL; +} + +// v1.70 code +// world_entity holds the worldspawn and is indexed as 0 +// other entities are in the entities doubly linked list +// QERApp_GetEntityCount counts the entities like in any C array: [0..length-1] +int WINAPI QERApp_GetEntityCount() +{ + int n = 1; + for (entity_t *pe = entities.next ; pe != &entities ; pe = pe->next) + { + n++; + } + return n; +} + +// We don't store entities in CPtrArray, we need to walk the list +void* WINAPI QERApp_GetEntityHandle(int nIndex) +{ + if (nIndex==0) + // looks for the worldspawn + return static_cast(world_entity); + entity_t *pe = &entities; + int n = 0; + while ( n < nIndex ) + { + pe = pe->next; + n++; + } + return static_cast(pe); +} + +epair_t* WINAPI QERApp_AllocateEpair( char *key, char *val ) +{ + epair_t *e = (epair_t*)qmalloc (sizeof(*e)); + e->key = (char*)qmalloc(strlen(key)+1); + strcpy (e->key, key); + e->value = (char*)qmalloc(strlen(val)+1); + strcpy (e->value, val); + return e; +} + +/* +IEpair* WINAPI QERApp_IEpairForEntityHandle(void *vp) +{ + entity_t *pe = static_cast(vp); + CEpairsWrapper *pEp = new CEpairsWrapper(pe); + pEp->IncRef(); + return pEp; +} + +IEpair* WINAPI QERApp_IEpairForProjectKeys() +{ + CEpairsWrapper *pEp = new CEpairsWrapper(g_qeglobals.d_project_entity); + pEp->IncRef(); + return pEp; +} +*/ + +int WINAPI QERApp_AllocateEntityBrushHandles(void* vp) +{ + entity_t *pe = static_cast(vp); + int n = 0; + if (!pe->brushes.onext) + return 0; + g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().RemoveAll(); + for (brush_t *pb = pe->brushes.onext ; pb != &pe->brushes ; pb=pb->onext) + { + n++; + g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().Add(pb); + } + return n; +} + +void WINAPI QERApp_ReleaseEntityBrushHandles() +{ + g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().RemoveAll(); +} + +void* WINAPI QERApp_GetEntityBrushHandle(int nIndex) +{ + if (nIndex < g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().GetSize()) + return g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().GetAt(nIndex); + return NULL; +} + +// FIXME TTimo that entity handles thing sucks .. we should get rid of it .. + +void* WINAPI QERApp_CreateEntityHandle() +{ + entity_t *pe = reinterpret_cast(qmalloc(sizeof(entity_t))); + pe->brushes.onext = pe->brushes.oprev = &pe->brushes; + g_pParentWnd->GetPlugInMgr().GetEntityHandles().Add(static_cast(pe)); + return static_cast(pe); +} + +// the vpBrush needs to be in m_BrushHandles +//++timo we don't have allocation nor storage for vpEntity, no checks for this one +void WINAPI QERApp_CommitBrushHandleToEntity(void* vpBrush, void* vpEntity) +{ + g_pParentWnd->GetPlugInMgr().CommitBrushHandleToEntity(vpBrush, vpEntity); + return; +} + +const char* QERApp_ReadProjectKey(const char* key) +{ + return ValueForKey(g_qeglobals.d_project_entity, key); +} + +#ifdef USEPLUGINENTITIES + +int WINAPI QERApp_ScanFileForEClass(char *filename ) +{ + // set single class parsing + parsing_single = true; + Eclass_ScanFile(filename); + if (eclass_found) + { + eclass_e->nShowFlags |= ECLASS_PLUGINENTITY; + return 1; + } + return 0; +} +#endif // USEPLUGINENTITIES + +// the vpBrush needs to be in m_BrushHandles +//++timo add a debug check to see if we found the brush handle +// NOTE : seems there's no way to check vpEntity is valid .. this is dangerous +// links the brush to its entity, everything else is done when commiting the entity to the map +void CPlugInManager::CommitBrushHandleToEntity(void* vpBrush, void* vpEntity) +{ + brush_t* pb; + entity_t* pe; + for (int i=0 ; i < m_BrushHandles.GetSize() ; i++) + { + if (vpBrush == m_BrushHandles.GetAt(i)) + { + m_BrushHandles.RemoveAt(i); + pb = reinterpret_cast(vpBrush); + pe = reinterpret_cast(vpEntity); + Entity_LinkBrush (pe, pb); + } + } + Sys_UpdateWindows(W_ALL); +} + +// the vpEntity must be in m_EntityHandles +void WINAPI QERApp_CommitEntityHandleToMap(void* vpEntity) +{ + g_pParentWnd->GetPlugInMgr().CommitEntityHandleToMap(vpEntity); + return; +} + +int WINAPI QERApp_LoadFile( const char *pLocation, void ** buffer ) +{ + int nSize = vfsLoadFile(pLocation, buffer, 0); + return nSize; +} + +char * WINAPI QERApp_ExpandReletivePath (char *p) +{ + return ExpandReletivePath(p); +} + +qtexture_t* WINAPI QERApp_Texture_ForName (const char *name) +{ + // if the texture is not loaded yet, this call will get it loaded + // but: when we assign a GL bind number, we need to be in the g_qeglobals.d_xxxBase GL context + // the plugin may set the GL context to whatever he likes, but then load would fail + // NOTE: is context switching time-consuming? then maybe the plugin could handle the context + // switch and only add a sanity check in debug mode here + // read current context + gtk_glwidget_make_current (g_qeglobals_gui.d_glBase); + + //++timo debugging + Sys_Printf("WARNING: QERApp_Texture_ForName ... don't call that!!\n"); + qtexture_t* qtex = QERApp_Texture_ForName2( name ); + return qtex; +} + +char* QERApp_Token() +{ + return token; +} + +int QERApp_ScriptLine() +{ + return scriptline; +} + +// we save the map and return the name .. either .map or .reg to support region compiling +char* QERApp_GetMapName() +{ + static char name[PATH_MAX]; + SaveWithRegion (name); + return name; +} + +void CPlugInManager::CommitEntityHandleToMap(void* vpEntity) +{ + entity_t *pe; + eclass_t *e; + brush_t *b; + vec3_t mins,maxs; + bool has_brushes; + for (int i=0 ; i < m_EntityHandles.GetSize() ; i++ ) + { + if (vpEntity == m_EntityHandles.GetAt(i)) + { + m_EntityHandles.RemoveAt(i); + pe = reinterpret_cast(vpEntity); + // fill additional fields + // straight copy from Entity_Parse + // entity_t::origin + GetVectorForKey (pe, "origin", pe->origin); + // entity_t::eclass + if (pe->brushes.onext == &pe->brushes) + has_brushes = false; + else + has_brushes = true; + e = Eclass_ForName (ValueForKey (pe, "classname"), has_brushes); + pe->eclass = e; + // fixedsize + if (e->fixedsize) + { + if (pe->brushes.onext != &pe->brushes) + { + Sys_Printf("Warning : Fixed size entity with brushes in CPlugInManager::CommitEntityHandleToMap\n"); + } + // create a custom brush + VectorAdd(e->mins, pe->origin, mins); + VectorAdd(e->maxs, pe->origin, maxs); +/* + float a = 0; + if (e->nShowFlags & ECLASS_MISCMODEL) + { + char* p = ValueForKey(pe, "model"); + if (p != NULL && strlen(p) > 0) + { + vec3_t vMin, vMax; + a = FloatForKey (pe, "angle"); + if (GetCachedModel(pe, p, vMin, vMax)) + { + // create a custom brush + VectorAdd (pe->md3Class->mins, pe->origin, mins); + VectorAdd (pe->md3Class->maxs, pe->origin, maxs); + } + } + } +*/ + b = Brush_Create (mins, maxs, &e->texdef); +/* + if (a) + { + vec3_t vAngle; + vAngle[0] = vAngle[1] = 0; + vAngle[2] = a; + Brush_Rotate(b, vAngle, pe->origin, false); + } +*/ + b->owner = pe; + + b->onext = pe->brushes.onext; + b->oprev = &pe->brushes; + pe->brushes.onext->oprev = b; + pe->brushes.onext = b; + } else + { // brush entity + if (pe->brushes.next == &pe->brushes) + Sys_Printf ("Warning: Brush entity with no brushes in CPlugInManager::CommitEntityHandleToMap\n"); + } + + // add brushes to the active brushes list + // and build them along the way + for (b=pe->brushes.onext ; b != &pe->brushes ; b=b->onext) + { + // convert between old brushes and brush primitive + if (g_qeglobals.m_bBrushPrimitMode) + { + // we only filled the shift scale rot fields, needs conversion + Brush_Build( b, true, true, true ); + } else + { + // we are using old brushes + Brush_Build( b ); + } + b->next = active_brushes.next; + active_brushes.next->prev = b; + b->prev = &active_brushes; + active_brushes.next = b; + } + + // handle worldspawn entities + // if worldspawn has no brushes, use the new one + if (!strcmp(ValueForKey (pe, "classname"), "worldspawn")) + { + if ( world_entity && ( world_entity->brushes.onext != &world_entity->brushes ) ) + { + // worldspawn already has brushes + Sys_Printf ("Commiting worldspawn as func_group\n"); + SetKeyValue(pe, "classname", "func_group"); + // add the entity to the end of the entity list + pe->next = &entities; + pe->prev = entities.prev; + entities.prev->next = pe; + entities.prev = pe; + g_qeglobals.d_num_entities++; + } else + { + // there's a worldspawn with no brushes, we assume the map is empty + if ( world_entity ) + { + Entity_Free( world_entity ); + world_entity = pe; + } else + Sys_Printf("Warning : unexpected world_entity == NULL in CommitEntityHandleToMap\n"); + } + } else + { + // add the entity to the end of the entity list + pe->next = &entities; + pe->prev = entities.prev; + entities.prev->next = pe; + entities.prev = pe; + g_qeglobals.d_num_entities++; + } + } + } +} + +void WINAPI QERApp_SetScreenUpdate(int bScreenUpdates) +{ + g_bScreenUpdates = bScreenUpdates; +} + +texturewin_t* QERApp_QeglobalsTexturewin() +{ + return &g_qeglobals.d_texturewin; +} + +texdef_t* QERApp_QeglobalsSavedinfo_SIInc() +{ + return &g_qeglobals.d_savedinfo.m_SIIncrement; +} + +patchMesh_t* QERApp_GetSelectedPatch( ) +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + return pb->pPatch; + } + } +#ifdef _DEBUG + Sys_Printf("WARNING: QERApp_GetSelectedPatchTexdef called with no patch selected\n"); +#endif + return NULL; +} + +const char* WINAPI QERApp_GetGamePath() +{ + return g_pGameDescription->mEnginePath.GetBuffer(); +} + +/*! +\todo the name of this API should prolly be changed +would also need to prompt g_strAppPath / g_strGameToolsPath independently? +*/ +// SPoG +// changed g_strGameToolsPath to g_strAppPath +const char* WINAPI QERApp_GetQERPath() +{ + return g_strAppPath.GetBuffer(); +} + +const char* WINAPI QERApp_GetGameFile() +{ + // FIXME: Arnout: temp solution, need proper 'which game is this' indicator or a different solution for plugins/modules + return g_pGameDescription->mGameFile.GetBuffer(); +} + +// patches in/out ----------------------------------- +int WINAPI QERApp_AllocateActivePatchHandles() +{ + return g_pParentWnd->GetPlugInMgr().AllocateActivePatchHandles(); +} + +// Grid Size +float QERApp_QeglobalsGetGridSize() +{ + return g_qeglobals.d_gridsize; +} + +int CPlugInManager::AllocateActivePatchHandles() +{ + int n = 0; + for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + n++; + m_PatchesHandles.Add(pb); + } + } + return n; +} + +int WINAPI QERApp_AllocateSelectedPatchHandles() +{ + return g_pParentWnd->GetPlugInMgr().AllocateSelectedPatchHandles(); +} + +int CPlugInManager::AllocateSelectedPatchHandles() +{ + int n = 0; + // change mode + PatchesMode = ESelectedPatches; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + n++; + m_PatchesHandles.Add(pb); + } + } + return n; +} + +void WINAPI QERApp_ReleasePatchHandles() +{ + g_pParentWnd->GetPlugInMgr().ReleasePatchesHandles(); +} + +patchMesh_t* WINAPI QERApp_GetPatchData(int index) +{ + static patchMesh_t patch; + patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); + if (pPatch) + { + memcpy( &patch, pPatch, sizeof(patchMesh_t) ); + return &patch; + } + return NULL; +} + +patchMesh_t* WINAPI QERApp_GetPatchHandle(int index) +{ + return g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); +} + +void WINAPI QERApp_DeletePatch(int index) +{ + patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); + if (pPatch) + { + brush_t *pb = pPatch->pSymbiot; + Patch_Delete( pPatch ); + if (pb) + Brush_Free( pb ); + } +#ifdef _DEBUG + Sys_Printf("Warning: QERApp_DeletePatch: FindPatchHandle failed\n"); +#endif +} + +int WINAPI QERApp_CreatePatchHandle() +{ + return g_pParentWnd->GetPlugInMgr().CreatePatchHandle(); +} + +int CPlugInManager::CreatePatchHandle() +{ + // NOTE: we can't call the AddBrushForPatch until we have filled the patchMesh_t structure + patchMesh_t *pPatch = MakeNewPatch(); + m_PluginPatches.Add( pPatch ); + // change mode + PatchesMode = EAllocatedPatches; + return m_PluginPatches.GetSize()-1; +} + +void WINAPI QERApp_CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName) +{ +#ifdef DBG_PAPI + Sys_Printf ("QERApp_CommitPatchHandleToMap %i..", index); +#endif + g_pParentWnd->GetPlugInMgr().CommitPatchHandleToMap(index, pMesh, texName); +#ifdef DBG_PAPI + Sys_Printf ("Done\n"); +#endif +} + +void WINAPI QERApp_CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void* vpEntity) +{ +#ifdef DBG_PAPI + Sys_Printf ("QERApp_CommitPatchHandleToEntity %i..", index); +#endif + g_pParentWnd->GetPlugInMgr().CommitPatchHandleToEntity(index, pMesh, texName, vpEntity); +#ifdef DBG_PAPI + Sys_Printf ("Done\n"); +#endif +} + +void CPlugInManager::CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName) +{ + if (PatchesMode==EAllocatedPatches) + { + patchMesh_t *pPatch = reinterpret_cast( m_PluginPatches.GetAt(index) ); + memcpy( pPatch, pMesh, sizeof( patchMesh_t ) ); + // patch texturing, if none given use current texture + if (texName) + pPatch->pShader = QERApp_Shader_ForName (texName); + else + pPatch->pShader = QERApp_Shader_ForName(g_qeglobals.d_texturewin.texdef.GetName()); + pPatch->d_texture = pPatch->pShader->getTexture(); + pPatch->pShader->IncRef(); + g_bScreenUpdates = false; + // the bLinkToWorld flag in AddBrushForPatch takes care of Brush_AddToList Entity_linkBrush and Brush_Build + brush_t *pb = AddBrushForPatch( pPatch, true ); + Select_Brush( pb ); + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); + } else + { + brush_t *pBrush = reinterpret_cast( m_PatchesHandles.GetAt(index) ); + patchMesh_t *pPatch = pBrush->pPatch; + pPatch->width = pMesh->width; + pPatch->height = pMesh->height; + pPatch->contents = pMesh->contents; + pPatch->flags = pMesh->flags; + pPatch->value = pMesh->value; + pPatch->type = pMesh->type; + memcpy( pPatch->ctrl, pMesh->ctrl, sizeof(drawVert_t)*MAX_PATCH_HEIGHT*MAX_PATCH_WIDTH ); + pPatch->bDirty = true; + } +} + +void CPlugInManager::CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void *vpEntity) +{ + entity_t* pe = reinterpret_cast(vpEntity); + + if (PatchesMode==EAllocatedPatches) + { + patchMesh_t *pPatch = reinterpret_cast( m_PluginPatches.GetAt(index) ); + memcpy( pPatch, pMesh, sizeof( patchMesh_t ) ); + // patch texturing, if none given use current texture + if (texName) + pPatch->pShader = QERApp_Shader_ForName (texName); + else + pPatch->pShader = QERApp_Shader_ForName(g_qeglobals.d_texturewin.texdef.GetName()); + pPatch->d_texture = pPatch->pShader->getTexture(); + pPatch->pShader->IncRef(); + g_bScreenUpdates = false; + brush_t *pb = AddBrushForPatch( pPatch, false ); // false, sp have to do the brush building/entity linking ourself + Brush_AddToList (pb, &active_brushes); + Entity_LinkBrush (pe, pb); + Brush_Build( pb ); + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); + } else + { + brush_t *pBrush = reinterpret_cast( m_PatchesHandles.GetAt(index) ); + patchMesh_t *pPatch = pBrush->pPatch; + pPatch->width = pMesh->width; + pPatch->height = pMesh->height; + pPatch->contents = pMesh->contents; + pPatch->flags = pMesh->flags; + pPatch->value = pMesh->value; + pPatch->type = pMesh->type; + memcpy( pPatch->ctrl, pMesh->ctrl, sizeof(drawVert_t)*MAX_PATCH_HEIGHT*MAX_PATCH_WIDTH ); + pPatch->bDirty = true; + } +} + +#if 0 + +#if defined (__linux__) || defined (__APPLE__) + #include + +XVisualInfo* QEX_ChooseVisual (bool zbuffer) +{ + int attrlist_z[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, 0}; + int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 0}; + XVisualInfo *vi; + Display *dpy; + + dpy = GDK_DISPLAY(); + if (dpy == NULL) + Error ("OpenGL fatal error: Cannot get display.\n"); + vi = qglXChooseVisual(dpy, DefaultScreen(dpy), zbuffer ? attrlist_z : attrlist); + if (vi == NULL) + Error ("OpenGL fatal error: glXChooseVisual failed.\n"); + + return vi; +} +#endif + +#endif + +/*! +\todo FIXME TTimo broken most likely +actually .. that's not enough, you have to go down for the game pack specific? +*/ +const char* WINAPI QERApp_ProfileGetDirectory () +{ + return g_strTempPath; +} + +GtkWidget* WINAPI QERApp_GetQeGlobalsGLWidget () +{ + return g_qeglobals_gui.d_glBase; +} + +qboolean WINAPI BrushPrimitMode () +{ + return g_qeglobals.m_bBrushPrimitMode; +} + +brush_t* WINAPI QERApp_ActiveBrushes() +{ + return &active_brushes; +} + +brush_t* WINAPI QERApp_SelectedBrushes() +{ + return &selected_brushes; +} + +brush_t* WINAPI QERApp_FilteredBrushes() +{ + return &filtered_brushes; +} + +CPtrArray* WINAPI QERApp_LstSkinCache() +{ + return &g_lstSkinCache; +} + +qtexture_t** WINAPI QERApp_QTextures() +{ + return &g_qeglobals.d_qtextures; +} + +GHashTable* WINAPI QERApp_QTexmap() +{ + return g_qeglobals.d_qtexmap; +} + +// a simplified version of Texture_SetTexture +void WINAPI QERApp_Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef) +{ + Texture_SetTexture (texdef, brushprimit_texdef); +} + +void QERApp_LoadImage (const char *name, unsigned char **pic, int *width, int *height) +{ + g_ImageManager.LoadImage(name, pic, width, height); +} + +unsigned long QERApp_GetTickCount() +{ +#ifdef _WIN32 + return GetTickCount(); +#else + struct timeval tp; + struct timezone tzp; + static int basetime=0; + + gettimeofday(&tp, &tzp); + if (!basetime) + basetime = tp.tv_sec; + return (tp.tv_sec-basetime) + tp.tv_usec/1000; +#endif +} + +bool CSynapseClientRadiant::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, RADIANT_MAJOR)) + { + _QERFuncTable_1* pTable= static_cast<_QERFuncTable_1*>(pAPI->mpTable); + pTable->m_pfnCreateBrush = &QERApp_CreateBrush; + pTable->m_pfnCreateBrushHandle = &QERApp_CreateBrushHandle; + pTable->m_pfnDeleteBrushHandle = &QERApp_DeleteBrushHandle; + pTable->m_pfnCommitBrushHandle = &QERApp_CommitBrushHandleToMap; + pTable->m_pfnAddFace = &QERApp_AddFace; + pTable->m_pfnAddFaceData = &QERApp_AddFaceData; + pTable->m_pfnGetFaceData = &QERApp_GetFaceData; + pTable->m_pfnGetFaceCount = &QERApp_GetFaceCount; + pTable->m_pfnSetFaceData = &QERApp_SetFaceData; + pTable->m_pfnDeleteFace = &QERApp_DeleteFace; + pTable->m_pfnTextureBrush = &QERApp_TextureBrush; + pTable->m_pfnBuildBrush = &QERApp_BuildBrush; // PGM + pTable->m_pfnSelectBrush = &QERApp_SelectBrush; // PGM + pTable->m_pfnDeselectBrush = &QERApp_DeselectBrush; // PGM + pTable->m_pfnDeselectAllBrushes = &QERApp_DeselectAllBrushes; // PGM + pTable->m_pfnDeleteSelection = &QERApp_DeleteSelection; + pTable->m_pfnGetPoints = &QERApp_GetPoints; + pTable->m_pfnSelectedBrushCount = &QERApp_SelectedBrushCount; + pTable->m_pfnAllocateSelectedBrushHandles = &QERApp_AllocateSelectedBrushHandles; + pTable->m_pfnReleaseSelectedBrushHandles = &QERApp_ReleaseSelectedBrushHandles; + pTable->m_pfnGetSelectedBrushHandle = &QERApp_GetSelectedBrushHandle; + pTable->m_pfnActiveBrushCount = &QERApp_ActiveBrushCount; + pTable->m_pfnAllocateActiveBrushHandles = &QERApp_AllocateActiveBrushHandles; + pTable->m_pfnReleaseActiveBrushHandles = &QERApp_ReleaseActiveBrushHandles; + pTable->m_pfnGetActiveBrushHandle = &QERApp_GetActiveBrushHandle; + pTable->m_pfnTextureCount = &QERApp_TextureCount; + pTable->m_pfnGetTexture = &QERApp_GetTexture; + pTable->m_pfnGetCurrentTexture = &QERApp_GetCurrentTexture; + pTable->m_pfnSetCurrentTexture = &QERApp_SetCurrentTexture; + pTable->m_pfnGetEClassCount = &QERApp_GetEClassCount; + pTable->m_pfnGetEClass = &QERApp_GetEClass; + pTable->m_pfnResetPlugins = &QERApp_ResetPlugins; + pTable->m_pfnLoadTextureRGBA = &QERApp_LoadTextureRGBA; + pTable->m_pfnGetEntityCount = &QERApp_GetEntityCount; + pTable->m_pfnGetEntityHandle = &QERApp_GetEntityHandle; + pTable->m_pfnAllocateEpair = &QERApp_AllocateEpair; + pTable->m_pfnAllocateEntityBrushHandles = &QERApp_AllocateEntityBrushHandles; + pTable->m_pfnReleaseEntityBrushHandles = &QERApp_ReleaseEntityBrushHandles; + pTable->m_pfnGetEntityBrushHandle = &QERApp_GetEntityBrushHandle; + pTable->m_pfnCreateEntityHandle = &QERApp_CreateEntityHandle; + pTable->m_pfnCommitBrushHandleToEntity = &QERApp_CommitBrushHandleToEntity; + pTable->m_pfnCommitEntityHandleToMap = &QERApp_CommitEntityHandleToMap; + pTable->m_pfnSetScreenUpdate = &QERApp_SetScreenUpdate; + pTable->m_pfnBuildBrush2 = &QERApp_BuildBrush2; + pTable->m_pfnGetDispatchParams = &QERApp_GetDispatchParams; +// pTable->m_pfnRequestInterface = &QERApp_RequestInterface; + pTable->m_pfnError = &Error; + pTable->m_pfnLoadFile = &QERApp_LoadFile; + pTable->m_pfnExpandReletivePath = &QERApp_ExpandReletivePath; + pTable->m_pfnQE_ConvertDOSToUnixName = &QE_ConvertDOSToUnixName; + pTable->m_pfnHasShader = QERApp_HasShader; + pTable->m_pfnTexture_LoadSkin = &Texture_LoadSkin; + pTable->m_pfnGetGamePath = &QERApp_GetGamePath; + pTable->m_pfnGetQERPath = &QERApp_GetQERPath; + pTable->m_pfnGetGameFile = &QERApp_GetGameFile; + pTable->m_pfnAllocateActivePatchHandles = &QERApp_AllocateActivePatchHandles; + pTable->m_pfnAllocateSelectedPatchHandles = &QERApp_AllocateSelectedPatchHandles; + pTable->m_pfnReleasePatchHandles = &QERApp_ReleasePatchHandles; + pTable->m_pfnGetPatchData = &QERApp_GetPatchData; + pTable->m_pfnGetPatchHandle = &QERApp_GetPatchHandle; + pTable->m_pfnDeletePatch = &QERApp_DeletePatch; + pTable->m_pfnCreatePatchHandle = &QERApp_CreatePatchHandle; + pTable->m_pfnCommitPatchHandleToMap = &QERApp_CommitPatchHandleToMap; + pTable->m_pfnLoadImage = &QERApp_LoadImage; + pTable->m_pfnMessageBox = >k_MessageBox; + pTable->m_pfnFileDialog = &file_dialog; + pTable->m_pfnColorDialog = &color_dialog; + pTable->m_pfnDirDialog = &dir_dialog; + pTable->m_pfnLoadBitmap = &load_plugin_bitmap; + pTable->m_pfnProfileGetDirectory = &QERApp_ProfileGetDirectory; + pTable->m_pfnProfileSaveInt = &profile_save_int; + pTable->m_pfnProfileSaveString = &profile_save_string; + pTable->m_pfnProfileLoadInt = &profile_load_int; + pTable->m_pfnProfileLoadString = &profile_load_string; + pTable->m_pfnSysUpdateWindows = &Sys_UpdateWindows; + pTable->m_pfnSysPrintf = &Sys_Printf; + pTable->m_pfnSysFPrintf = &Sys_FPrintf; + pTable->m_pfnSysBeginWait = &Sys_BeginWait; + pTable->m_pfnSysEndWait = &Sys_EndWait; + pTable->m_pfnSys_SetTitle = &Sys_SetTitle; + pTable->m_pfnSysBeep = &Sys_Beep; + pTable->m_pfnSys_Status = &Sys_Status; + pTable->m_pfnMapFree = &Map_Free; + pTable->m_pfnMapNew = &Map_New; + pTable->m_pfnMapBuildBrushData = &Map_BuildBrushData; + pTable->m_pfnMap_IsBrushFiltered = &Map_IsBrushFiltered; + pTable->m_pfnMapStartPosition = &Map_StartPosition; + pTable->m_pfnMapRegionOff = &Map_RegionOff; + pTable->m_pfnSetBuildWindingsNoTexBuild = &Brush_SetBuildWindingsNoTexBuild; + pTable->m_pfnPointFileClear = &Pointfile_Clear; + pTable->m_pfnCSG_MakeHollow = &CSG_MakeHollow; + pTable->m_pfnRegionSpawnPoint = &Region_SpawnPoint; + pTable->m_pfnQGetTickCount = &QERApp_GetTickCount; + pTable->m_pfnGetModelCache = &GetModelCache; + pTable->m_pfnGetFileTypeRegistry = &GetFileTypeRegistry; + pTable->m_pfnReadProjectKey = &QERApp_ReadProjectKey; + pTable->m_pfnGetMapName = &QERApp_GetMapName; + + return true; + } + if (!strcmp(pAPI->major_name, SCRIPLIB_MAJOR)) + { + _QERScripLibTable *pScripLibTable = static_cast<_QERScripLibTable *>(pAPI->mpTable); + pScripLibTable->m_pfnGetToken = &GetToken; + pScripLibTable->m_pfnGetTokenExtra = &GetTokenExtra; + pScripLibTable->m_pfnToken = &QERApp_Token; + pScripLibTable->m_pfnUnGetToken = &UngetToken; + pScripLibTable->m_pfnStartTokenParsing = &StartTokenParsing; + pScripLibTable->m_pfnScriptLine = &QERApp_ScriptLine; + pScripLibTable->m_pfnTokenAvailable = &TokenAvailable; + pScripLibTable->m_pfnCOM_Parse = &COM_Parse; + pScripLibTable->m_pfnGet_COM_Token = &Get_COM_Token; + + return true; + } + if (!strcmp(pAPI->major_name, BRUSH_MAJOR)) + { + _QERBrushTable *pBrushTable = static_cast<_QERBrushTable *>(pAPI->mpTable); + pBrushTable->m_pfnBP_MessageBox = &BP_MessageBox; + pBrushTable->m_pfnBrush_AddToList = &Brush_AddToList; + pBrushTable->m_pfnBrush_Build = &Brush_Build; + pBrushTable->m_pfnBrush_Create = &Brush_Create; + pBrushTable->m_pfnBrush_Free = &Brush_Free; + pBrushTable->m_pfnBrush_Rotate = &Brush_Rotate; + pBrushTable->m_pfnBrushAlloc = &Brush_Alloc; + pBrushTable->m_pfnFace_Alloc = &Face_Alloc; + pBrushTable->m_pfnHasModel = NULL;// &HasModel; + + return true; + } + if (!strcmp(pAPI->major_name, APPSHADERS_MAJOR)) + { + _QERAppShadersTable *pShadersTable = static_cast<_QERAppShadersTable*>(pAPI->mpTable); + pShadersTable->m_pfnQTextures = QERApp_QTextures; + pShadersTable->m_pfnQTexmap = QERApp_QTexmap; + pShadersTable->m_pfnQeglobalsTexturewin = QERApp_QeglobalsTexturewin; + pShadersTable->m_pfnTexture_SetTexture = QERApp_Texture_SetTexture; + pShadersTable->m_pfnTexture_ShowInuse = Texture_ShowInuse; + pShadersTable->m_pfnBuildShaderList = &BuildShaderList; + pShadersTable->m_pfnPreloadShaders = &PreloadShaders; + + return true; + } + if (!strcmp(pAPI->major_name, QGL_MAJOR)) + { + _QERQglTable *pQglTable = static_cast<_QERQglTable *>(pAPI->mpTable); + pQglTable->m_pfn_qglAlphaFunc = qglAlphaFunc; + pQglTable->m_pfn_qglBegin = qglBegin; + pQglTable->m_pfn_qglBindTexture = qglBindTexture; + pQglTable->m_pfn_qglBlendFunc = qglBlendFunc; + pQglTable->m_pfn_qglCallList = qglCallList; + pQglTable->m_pfn_qglCallLists = qglCallLists; + pQglTable->m_pfn_qglClear = qglClear; + pQglTable->m_pfn_qglClearColor = qglClearColor; + pQglTable->m_pfn_qglClearDepth = qglClearDepth; + pQglTable->m_pfn_qglColor3f = qglColor3f; + pQglTable->m_pfn_qglColor3fv = qglColor3fv; + pQglTable->m_pfn_qglColor4f = qglColor4f; + pQglTable->m_pfn_qglColor4fv = qglColor4fv; + pQglTable->m_pfn_qglColor4ubv = qglColor4ubv; + pQglTable->m_pfn_qglColorPointer = qglColorPointer; + pQglTable->m_pfn_qglCullFace = qglCullFace; + pQglTable->m_pfn_qglDepthFunc = qglDepthFunc; + pQglTable->m_pfn_qglDepthMask = qglDepthMask; + pQglTable->m_pfn_qglDisable = qglDisable; + pQglTable->m_pfn_qglDisableClientState = qglDisableClientState; + pQglTable->m_pfn_qglDeleteLists = qglDeleteLists; + pQglTable->m_pfn_qglDeleteTextures = qglDeleteTextures; + pQglTable->m_pfn_qglDrawElements = qglDrawElements; + pQglTable->m_pfn_qglEnable = qglEnable; + pQglTable->m_pfn_qglEnableClientState = qglEnableClientState; + pQglTable->m_pfn_qglEnd = qglEnd; + pQglTable->m_pfn_qglEndList = qglEndList; + pQglTable->m_pfn_qglFogf = qglFogf; + pQglTable->m_pfn_qglFogfv = qglFogfv; + pQglTable->m_pfn_qglFogi = qglFogi; + pQglTable->m_pfn_qglGenLists = qglGenLists; + pQglTable->m_pfn_qglGenTextures = qglGenTextures; + pQglTable->m_pfn_qglGetDoublev = qglGetDoublev; + pQglTable->m_pfn_qglGetIntegerv = qglGetIntegerv; + pQglTable->m_pfn_qglHint = qglHint; + pQglTable->m_pfn_qglLightfv = qglLightfv; + pQglTable->m_pfn_qglLineStipple = qglLineStipple; + pQglTable->m_pfn_qglLineWidth = qglLineWidth; + pQglTable->m_pfn_qglListBase = qglListBase; + pQglTable->m_pfn_qglLoadIdentity = qglLoadIdentity; + pQglTable->m_pfn_qglMaterialf = qglMaterialf; + pQglTable->m_pfn_qglMaterialfv = qglMaterialfv; + pQglTable->m_pfn_qglMatrixMode = qglMatrixMode; + pQglTable->m_pfn_qglMultMatrixf = qglMultMatrixf; + pQglTable->m_pfn_qglNewList = qglNewList; + pQglTable->m_pfn_qglNormal3f = qglNormal3f; + pQglTable->m_pfn_qglNormal3fv = qglNormal3fv; + pQglTable->m_pfn_qglNormalPointer = qglNormalPointer; + pQglTable->m_pfn_qglOrtho = qglOrtho; + pQglTable->m_pfn_qglPointSize = qglPointSize; + pQglTable->m_pfn_qglPolygonMode = qglPolygonMode; + pQglTable->m_pfn_qglPopAttrib = qglPopAttrib; + pQglTable->m_pfn_qglPopMatrix = qglPopMatrix; + pQglTable->m_pfn_qglPushAttrib = qglPushAttrib; + pQglTable->m_pfn_qglPushMatrix = qglPushMatrix; + pQglTable->m_pfn_qglRasterPos3fv = qglRasterPos3fv; + pQglTable->m_pfn_qglRotated = qglRotated; + pQglTable->m_pfn_qglRotatef = qglRotatef; + pQglTable->m_pfn_qglScalef = qglScalef; + pQglTable->m_pfn_qglScissor = qglScissor; + pQglTable->m_pfn_qglShadeModel = qglShadeModel; + pQglTable->m_pfn_qglTexCoord2f = qglTexCoord2f; + pQglTable->m_pfn_qglTexCoord2fv = qglTexCoord2fv; + pQglTable->m_pfn_qglTexCoordPointer = qglTexCoordPointer; + pQglTable->m_pfn_qglTexEnvf = qglTexEnvf; + pQglTable->m_pfn_qglTexGenf = qglTexGenf; + pQglTable->m_pfn_qglTexImage1D = qglTexImage1D; + pQglTable->m_pfn_qglTexImage2D = qglTexImage2D; + pQglTable->m_pfn_qglTexParameterf = qglTexParameterf; + pQglTable->m_pfn_qglTexParameterfv = qglTexParameterfv; + pQglTable->m_pfn_qglTexParameteri = qglTexParameteri; + pQglTable->m_pfn_qglTexParameteriv = qglTexParameteriv; + pQglTable->m_pfn_qglTexSubImage1D = qglTexSubImage1D; + pQglTable->m_pfn_qglTexSubImage2D = qglTexSubImage2D; + pQglTable->m_pfn_qglTranslated = qglTranslated; + pQglTable->m_pfn_qglTranslatef = qglTranslatef; + pQglTable->m_pfn_qglVertex2f = qglVertex2f; + pQglTable->m_pfn_qglVertex3f = qglVertex3f; + pQglTable->m_pfn_qglVertex3fv = qglVertex3fv; + pQglTable->m_pfn_qglVertexPointer = qglVertexPointer; + pQglTable->m_pfn_qglViewport = qglViewport; + + pQglTable->m_pfn_QE_CheckOpenGLForErrors = &QE_CheckOpenGLForErrors; + + pQglTable->m_pfn_qgluPerspective = qgluPerspective; + pQglTable->m_pfn_qgluLookAt = qgluLookAt; + pQglTable->m_pfnHookGL2DWindow = QERApp_HookGL2DWindow; + pQglTable->m_pfnUnHookGL2DWindow = QERApp_UnHookGL2DWindow; + pQglTable->m_pfnHookGL3DWindow = QERApp_HookGL3DWindow; + pQglTable->m_pfnUnHookGL3DWindow = QERApp_UnHookGL3DWindow; + + return true; + } + if (!strcmp(pAPI->major_name, DATA_MAJOR)) + { + _QERAppDataTable *pDataTable = static_cast<_QERAppDataTable *>(pAPI->mpTable); + pDataTable->m_pfnActiveBrushes = QERApp_ActiveBrushes; + pDataTable->m_pfnSelectedBrushes = QERApp_SelectedBrushes; + pDataTable->m_pfnFilteredBrushes = QERApp_FilteredBrushes; + pDataTable->m_pfnLstSkinCache = QERApp_LstSkinCache; + + return true; + } + if (!strcmp(pAPI->major_name, PATCH_MAJOR)) + { + _QERPatchTable *pPatchTable = static_cast<_QERPatchTable *>(pAPI->mpTable); + pPatchTable->m_pfnPatch_Alloc = &Patch_Alloc; + pPatchTable->m_pfnAddBrushForPatch = &AddBrushForPatch; + pPatchTable->m_pfnMakeNewPatch = &MakeNewPatch; + + return true; + } + if (!strcmp(pAPI->major_name, ECLASSMANAGER_MAJOR)) + { + _EClassManagerTable *pEClassManTable = static_cast<_EClassManagerTable *>(pAPI->mpTable); + + pEClassManTable->m_pfnEclass_InsertAlphabetized = &Eclass_InsertAlphabetized; + pEClassManTable->m_pfnGet_Eclass_E = &Get_EClass_E; + pEClassManTable->m_pfnSet_Eclass_Found = &Set_Eclass_Found; + pEClassManTable->m_pfnGet_Parsing_Single = &Get_Parsing_Single; + pEClassManTable->m_pfnEClass_Create = &EClass_Create; + pEClassManTable->m_pfnEclass_ForName = &Eclass_ForName; + + return true; + } + if (!strcmp(pAPI->major_name, SELECTEDFACE_MAJOR)) + { + _QERSelectedFaceTable *pSelectedFaceTable = static_cast<_QERSelectedFaceTable *>(pAPI->mpTable); + + pSelectedFaceTable->m_pfnGetSelectedFaceCount = &QERApp_GetSelectedFaceCount; + pSelectedFaceTable->m_pfnGetFaceBrush = &QERApp_GetSelectedFaceBrush; + pSelectedFaceTable->m_pfnGetFace = &QERApp_GetSelectedFace; + pSelectedFaceTable->m_pfnGetFaceInfo = &QERApp_GetFaceInfo; + pSelectedFaceTable->m_pfnSetFaceInfo = &QERApp_SetFaceInfo; + pSelectedFaceTable->m_pfnGetTextureNumber = &QERApp_ISelectedFace_GetTextureNumber; + pSelectedFaceTable->m_pfnGetTextureSize = &QERApp_GetTextureSize; + pSelectedFaceTable->m_pfnSelect_SetTexture = &Select_SetTexture; + return true; + } + if (!strcmp(pAPI->major_name, APPSURFACEDIALOG_MAJOR)) + { + _QERAppSurfaceTable *pSurfDialogTable = static_cast<_QERAppSurfaceTable *>(pAPI->mpTable); + pSurfDialogTable->m_pfnOnlyPatchesSelected = &OnlyPatchesSelected; + pSurfDialogTable->m_pfnAnyPatchesSelected = &AnyPatchesSelected; + pSurfDialogTable->m_pfnGetSelectedPatch = &QERApp_GetSelectedPatch; + pSurfDialogTable->m_pfnGetTwoSelectedPatch = &QERApp_GetTwoSelectedPatch; + pSurfDialogTable->m_pfnTexMatToFakeTexCoords = &TexMatToFakeTexCoords; + pSurfDialogTable->m_pfnConvertTexMatWithQTexture = &ConvertTexMatWithQTexture; + pSurfDialogTable->m_pfnFakeTexCoordsToTexMat = &FakeTexCoordsToTexMat; + pSurfDialogTable->m_pfnPatch_ResetTexturing = &Patch_ResetTexturing; + pSurfDialogTable->m_pfnPatch_FitTexturing = &Patch_FitTexturing; + pSurfDialogTable->m_pfnPatch_NaturalizeSelected = &Patch_NaturalizeSelected; + pSurfDialogTable->m_pfnPatch_GetTextureName = &Patch_GetTextureName; + pSurfDialogTable->m_pfnQE_SingleBrush = &QE_SingleBrush; + pSurfDialogTable->m_pfnIsBrushPrimitMode = &IsBrushPrimitMode; + pSurfDialogTable->m_pfnComputeAxisBase = &ComputeAxisBase; + pSurfDialogTable->m_pfnBPMatMul = &BPMatMul; + pSurfDialogTable->m_pfnEmitBrushPrimitTextureCoordinates = &EmitBrushPrimitTextureCoordinates; + pSurfDialogTable->m_pfnQeglobalsTexturewin = &QERApp_QeglobalsTexturewin; + pSurfDialogTable->m_pfnSelect_FitTexture = &Select_FitTexture; + pSurfDialogTable->m_pfnQERApp_QeglobalsSavedinfo_SIInc = &QERApp_QeglobalsSavedinfo_SIInc; + pSurfDialogTable->m_pfnQeglobalsGetGridSize = &QERApp_QeglobalsGetGridSize; + pSurfDialogTable->m_pfnFaceList_FitTexture = &SI_FaceList_FitTexture; + pSurfDialogTable->m_pfnGetMainWindow = &SI_GetMainWindow; + pSurfDialogTable->m_pfnSetWinPos_From_Prefs = &SI_SetWinPos_from_Prefs; + pSurfDialogTable->m_pfnGetSelectedFaceCountfromBrushes = &SI_GetSelectedFaceCountfromBrushes; + pSurfDialogTable->m_pfnGetSelFacesTexdef = &SI_GetSelFacesTexdef; + pSurfDialogTable->m_pfnSetTexdef_FaceList = &SI_SetTexdef_FaceList; + + return true; + } + if (!strcmp(pAPI->major_name, UNDO_MAJOR)) + { + _QERUndoTable *pUndoTable = static_cast<_QERUndoTable *>(pAPI->mpTable); + + pUndoTable->m_pfnUndo_Start = &Undo_Start; + pUndoTable->m_pfnUndo_End = &Undo_End; + pUndoTable->m_pfnUndo_AddBrush = &Undo_AddBrush; + pUndoTable->m_pfnUndo_EndBrush = &Undo_EndBrush; + pUndoTable->m_pfnUndo_AddBrushList = &Undo_AddBrushList; + pUndoTable->m_pfnUndo_EndBrushList = &Undo_EndBrushList; + pUndoTable->m_pfnUndo_AddEntity = &Undo_AddEntity; + pUndoTable->m_pfnUndo_EndEntity = &Undo_EndEntity; + pUndoTable->m_pfnUndo_Undo = &Undo_Undo; // Nurail + pUndoTable->m_pfnUndo_Redo = &Undo_Redo; // Nurail + pUndoTable->m_pfnUndo_GetUndoId = &Undo_GetUndoId; // Nurail + pUndoTable->m_pfnUndo_UndoAvailable = &Undo_UndoAvailable; // Nurail + pUndoTable->m_pfnUndo_RedoAvailable = &Undo_RedoAvailable; // Nurail + + return true; + } + if (!strcmp(pAPI->major_name, CAMERA_MAJOR)) + { + _QERCameraTable *pCameraTable = static_cast<_QERCameraTable *>(pAPI->mpTable); + + pCameraTable->m_pfnGetCamera = &QERApp_GetCamera; + pCameraTable->m_pfnSetCamera = &QERApp_SetCamera; + pCameraTable->m_pfnGetCamWindowExtents = &QERApp_GetCamWindowExtents; + + return true; + } + if (!strcmp(pAPI->major_name, UI_MAJOR)) + { + _QERUITable *pUITable = static_cast<_QERUITable *>(pAPI->mpTable); + + pUITable->m_pfnCreateGLWindow = QERApp_CreateGLWindow; + pUITable->m_pfnHookWindow = QERApp_HookWindow; + pUITable->m_pfnUnHookWindow = QERApp_UnHookWindow; + pUITable->m_pfnGetXYWndWrapper = QERApp_GetXYWndWrapper; + pUITable->m_pfnHookListener = QERApp_HookListener; + pUITable->m_pfnUnHookListener = QERApp_UnHookListener; + + return true; + } + if (!strcmp(pAPI->major_name, UIGTK_MAJOR)) + { + _QERUIGtkTable *pUIGtkTable = static_cast<_QERUIGtkTable *>(pAPI->mpTable); + + pUIGtkTable->m_pfn_GetQeglobalsGLWidget = &QERApp_GetQeGlobalsGLWidget; + pUIGtkTable->m_pfn_glwidget_new = >k_glwidget_new; + pUIGtkTable-> m_pfn_glwidget_swap_buffers = >k_glwidget_swap_buffers; + pUIGtkTable->m_pfn_glwidget_make_current = >k_glwidget_make_current; + pUIGtkTable->m_pfn_glwidget_destroy_context = >k_glwidget_destroy_context; + pUIGtkTable->m_pfn_glwidget_create_context = >k_glwidget_create_context; +#if 0 + pUIGtkTable->m_pfn_glwidget_get_context = >k_glwidget_get_context; +#endif + + return true; + } + + return false; +} + +const char* CSynapseClientRadiant::GetInfo() +{ + return "Radiant - synapse core built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientRadiant::GetName() +{ + return "core"; +} diff --git a/radiant/pluginmanager.h b/radiant/pluginmanager.h new file mode 100644 index 00000000..fe096e77 --- /dev/null +++ b/radiant/pluginmanager.h @@ -0,0 +1,212 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PLUGINMANAGER_H_ +#define _PLUGINMANAGER_H_ + +#include "plugin.h" + +// global interfaces we are using +extern _QERShadersTable g_ShadersTable; + +// NOTE: it's actually a module manager, the name should change to ModuleManager.. +class CPlugInManager +{ +private: + GSList* m_PlugIns; + CPtrArray m_BrushHandles; + CPtrArray m_SelectedBrushHandles; + CPtrArray m_ActiveBrushHandles; + + // v1.70 + //! brushes of the current entity ( see m_SelectedBrushHandles and m_ActiveBrushHandles ) + CPtrArray m_EntityBrushHandles; + //! allocated entities, not commited yet ( see m_BrushHandles ) + CPtrArray m_EntityHandles; + + //! tells in which array to look when given a patch index + enum EPatchesMode { EActivePatches, ESelectedPatches, EAllocatedPatches } PatchesMode; + //! patches handles (brush_t*) + CPtrArray m_PatchesHandles; + //! plugin-allocated patches, not commited yet (patchMesh_t*) + CPtrArray m_PluginPatches; + + void InitForDir(const Str &dir); ///< init for plguins/modules below this directory + +public: + CPtrArray& GetActiveHandles() {return m_ActiveBrushHandles; }; + CPtrArray& GetSelectedHandles() {return m_SelectedBrushHandles; }; + CPtrArray& GetPluginPatches() {return m_PluginPatches; }; + brush_t* FindBrushHandle(void *vp); + patchMesh_t* FindPatchHandle(int index); + int CreatePatchHandle(); + int AllocateActivePatchHandles(); + int AllocateSelectedPatchHandles(); + void CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName); + void CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void *vpEntity); + void ReleasePatchesHandles() { m_PatchesHandles.RemoveAll(); m_PluginPatches.RemoveAll(); } + void AddFaceToBrushHandle(void *vp, vec3_t v1, vec3_t v2, vec3_t v3); + void CommitBrushHandleToMap(void *vp); + void DeleteBrushHandle(void* vp); + void* CreateBrushHandle(); + void Dispatch(int n, const char *p); + void Cleanup(); ///< cleanup of data structures allocated for plugins, not a plugin reload + void Init(); ///< go through the path where we will find modules and plugins + void LoadImage (const char *name, unsigned char **pic, int *width, int *height); + void ImportMap (IDataStream *in, CPtrArray *ents, const char *type); + void ExportMap (CPtrArray *ents, IDataStream *out, const char *type); + void Shutdown(); ///< shutdown all the plugins/module subsystem + CPlugInManager(); + virtual ~CPlugInManager(); + + /*! + the texture manager front ends the single load + addins (texture, model, map formats.. etc.) + */ + _QERTextureInfo* GetTextureInfo(); + void LoadTexture(const char *pFilename); + +void* GetSurfaceFlags(); + + // v1.70 + CPtrArray& GetEntityBrushHandles() {return m_EntityBrushHandles; }; + CPtrArray& GetEntityHandles() {return m_EntityHandles; }; + //! the vpBrush needs to be in m_BrushHandles + void CommitBrushHandleToEntity(void* vpBrush, void* vpEntity ); + //! the vpEntity needs to be in m_EntityHandles + void CommitEntityHandleToMap( void* vpEntity ); + +protected: + //! read the interfaces this plugin implements + void LoadFromPath(const char *path); ///< load all modules/plugins in specified path + void RegisterInterfaces(); +}; + +class CPluginSlot : public IPlugIn +{ + APIDescriptor_t *mpAPI; + _QERPluginTable *mpTable; + /*! + is false until Init() happened + */ + bool m_bReady; + /*! + below is valid only if m_bReady = true + */ + GSList *m_CommandStrings; + GSList *m_CommandIDs; + +public: + /*! + build directly from a SYN_PROVIDE interface + */ + CPluginSlot(APIDescriptor_t *pAPI); + virtual ~CPluginSlot(); + + APIDescriptor_t* GetDescriptor() { return mpAPI; } + /*! + initialize some management data after the synapse interfaces have been hooked up + */ + void Init(); + /*! + dispatching a command by name to the plugin + */ + void Dispatch(const char *p); + + // IPlugIn ------------------------------------------------------------ + const char* getMenuName(); + int getCommandCount(); + const char* getCommand(int n); + void addMenuID(int n); + bool ownsCommandID(int n); + +}; + +class CRadiantPluginManager : public CSynapseAPIManager +{ + list mSlots; +public: + CRadiantPluginManager() {} + virtual ~CRadiantPluginManager(); + + // CSynapseAPIManager interface ------------------- + APIDescriptor_t *BuildRequireAPI(APIDescriptor_t *pAPI); + + // CRadiantPluginManager -------------------------- + void PopulateMenu(); + bool Dispatch(int n, const char* p); +}; + +class CImageTableSlot +{ + /*! + \todo this is a duplicate from the APIDescriptor_t* list that privately stored inside CSynapseAPIManager + this is probably useless to us in here? + */ + APIDescriptor_t *mpAPI; + /*! + shortcut to mpAPI->mpTable, with correct typing + this is what we allocate and should free locally + */ + _QERPlugImageTable *mpTable; +public: + CImageTableSlot() { } + virtual ~CImageTableSlot() { } ///\ \todo need to correctly free and release still.. + + APIDescriptor_t* GetDescriptor() { return mpAPI; } + _QERPlugImageTable* GetTable() { return mpTable; } + + /*! + don't go through PrepareRequireAPI for init, just get this API and add the table info + */ + void InitForFillAPITable(APIDescriptor_t *pAPI); +}; + +class CRadiantImageManager : public CSynapseAPIManager +{ + list mSlots; + + list::iterator mExtScanSlot; +public: + CRadiantImageManager() {} + virtual ~CRadiantImageManager(); + + // CSynapseAPIManager interface -------------------- + void FillAPITable(APIDescriptor_t *pAPI); + + // CRadiantImageManager ---------------------------- + /*! + extract the extension, go through the list of image interfaces, and load + */ + void LoadImage(const char *name, byte **pic, int *width, int *height); + + /*! + we often need to walk through the extensions + this used to be hardcoded in texwindow.cpp + the two functions are related, they use a static to go through the list + */ + void BeginExtensionsScan(); + const char* GetNextExtension(); ///< \return NULL when the list has been completely scanned +}; + +extern CRadiantImageManager g_ImageManager; + +#endif // _PLUGINMANAGER_H_ diff --git a/radiant/pmesh.cpp b/radiant/pmesh.cpp new file mode 100644 index 00000000..1cf2067b --- /dev/null +++ b/radiant/pmesh.cpp @@ -0,0 +1,6427 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Preliminary patch stuff +// +// + +#include "stdafx.h" +#include "gtkmisc.h" + +#include "gtkr_list.h" + +// externs +extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); +extern face_t *Face_Alloc( void ); +extern void DrawAlternatePoint(vec3_t v, float scale); + +void _Write3DMatrix (FILE *f, int y, int x, int z, float *m); +void _Write3DMatrix (MemStream *f, int y, int x, int z, float *m); + +void Patch_InitialiseLODPointers(patchMesh_t *p) +{ + int i; + int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT; + for (i=0; irowLOD[i] = NULL; + int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH; + for (i=0; icolLOD[i] = NULL; +} + +patchMesh_t* Patch_Alloc() +{ + patchMesh_t *pPatch = (patchMesh_t *)malloc(sizeof(patchMesh_t)); + pPatch->pShader = NULL; + pPatch->pSymbiot = NULL; // Hydra: added missing initialiser. + // spog - initialise patch LOD pointers + Patch_InitialiseLODPointers(pPatch); + pPatch->drawLists = NULL; + pPatch->bDirty = true; + pPatch->nListID = -1; + pPatch->bSelected = false; + pPatch->bOverlay = false; + pPatch->bDirty = true; + pPatch->LODUpdated = false; + + int i; + for (i=0; i<(((MAX_PATCH_WIDTH-1)-1)/2); i++) + pPatch->rowDirty[i] = false; + for (i=0; i<(((MAX_PATCH_HEIGHT-1)-1)/2); i++) + pPatch->colDirty[i] = false; + + return pPatch; +} + +patchMesh_t* MakeNewPatch() +{ + patchMesh_t *pm = reinterpret_cast(qmalloc(sizeof(patchMesh_t))); + + // spog - initialise patch LOD pointers + Patch_InitialiseLODPointers(pm); + pm->drawLists = NULL; + pm->bDirty = true; + + return pm; +} + +// FIXME: this needs to be dynamic +//#define MAX_PATCH_MESHES 4096 +//patchMesh_t patchMeshes[MAX_PATCH_MESHES]; +//int numPatchMeshes = 0; + +// used for a save spot +patchMesh_t patchSave; + +// Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized +// brush approach +//--int g_nSelectedPatch = -1; + +// HACK: for tracking which view generated the click +// as we dont want to deselect a point on a same point +// click if it is from a different view +int g_nPatchClickedView = -1; +bool g_bSameView = false; + +//typedef enum XFormType { TRANSLATE, SCALE, ROTATE }; + + +// globals +bool g_bPatchShowBounds = true; +bool g_bPatchWireFrame = false; +bool g_bPatchWeld = true; +bool g_bPatchDrillDown = true; +//bool g_bPatchInsertMode = false; +bool g_bPatchBendMode = false; +int g_nPatchBendState = -1; +int g_nPatchInsertState = -1; +int g_nBendOriginIndex = 0; +vec3_t g_vBendOrigin; + +bool g_bPatchAxisOnRow = true; +int g_nPatchAxisIndex = 0; +bool g_bPatchLowerEdge = true; + +vec3_t g_vCycleCapNormal; +// cycles when we use Patch_CycleCapSelected +VIEWTYPE g_nCycleCapIndex = XY; + +// BEND states +enum +{ + BEND_SELECT_ROTATION = 0, + BEND_SELECT_ORIGIN, + BEND_SELECT_EDGE, + BEND_BENDIT, + BEND_STATE_COUNT +}; + +const char *g_pBendStateMsg[] = +{ + "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.", + "Use TAB to cycle through available rotation axis. This will LOCK around that point. You may also use Shift + Middle Click to select an arbitrary point. Press ENTER when the desired one is highlighted", + "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.", + "Use the MOUSE to bend the patch. It uses the same ui rules as Free Rotation. Press ENTER to accept the bend, press ESC to abandon it and exit Bend mode", + "" +}; + +// INSERT states +enum +{ + INSERT_SELECT_EDGE = 0, + INSERT_STATE_COUNT +}; + +const char* g_pInsertStateMsg[] = +{ + "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair" +}; + + +float *g_InversePoints[1024]; + +const float fFullBright = 1.0; +const float fLowerLimit = .50; +const float fDec = .05f; +void _SetColor(face_t* f, float fColor[3]) +{ + return; + fColor[0] = f->d_color[0]; + fColor[1] = f->d_color[1]; + fColor[2] = f->d_color[2]; + qglColor3fv(fColor); +} + + +void _DecColor(float fColor[3]) +{ + return; + fColor[0] -= fDec; + fColor[1] -= fDec ; + fColor[2] -= fDec; + for (int i = 0; i < 3; i++) + { + if (fColor[i] <= fLowerLimit) + { + fColor[0] = fFullBright; + fColor[1] = fFullBright; + fColor[2] = fFullBright; + break; + } + } + qglColor3fv(fColor); +} + +vec_t __VectorNormalize (vec3_t in, vec3_t out) +{ + vec_t length, ilength; + + length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + + +void Patch_SetType(patchMesh_t *p, int nType) +{ + p->type = (p->type & PATCH_STYLEMASK) | nType; +} + +void Patch_SetStyle(patchMesh_t *p, int nStyle) +{ + p->type = (p->type & PATCH_TYPEMASK) | nStyle; +} + +/* +================== +Patch_MemorySize +================== +*/ +int Patch_MemorySize(patchMesh_t *p) +{ + // return _msize(p); + return 0; +} + + +/* +=============== +InterpolateInteriorPoints +=============== +*/ +void InterpolateInteriorPoints( patchMesh_t *p ) +{ + int i, j, k; + int next, prev; + + for ( i = 0 ; i < p->width ; i += 2 ) + { + + next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width; + prev = ( i == 0 ) ? p->width - 2 : i - 1; + +#if 0 + if ( i == 0 ) + { + next = ( i + 1 ) % p->width; + prev = p->width - 2; // joined wrap case + } + else if ( i == p->width - 1 ) + { + next = 1; + prev = i - 1; + } + else + { + next = ( i + 1 ) % p->width; + prev = i - 1; + } +#endif + + for ( j = 0 ; j < p->height ; j++ ) + { + for ( k = 0 ; k < 3 ; k++ ) + { + p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5; + } + } + } +} + +/* +================= +MakeMeshNormals + +================= +*/ +int neighbors[8][2] = { + {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} +}; + +void Patch_MeshNormals(patchMesh_t *in ) +{ + int i, j, k, dist; + vec3_t normal; + vec3_t sum; + int count; + vec3_t base; + vec3_t delta; + int x, y; + drawVert_t *dv; + vec3_t around[8], temp; + qboolean good[8]; + qboolean wrapWidth, wrapHeight; + float len; + + wrapWidth = false; + for ( i = 0 ; i < in->height ; i++ ) + { + + VectorSubtract( in->ctrl[0][i].xyz, + in->ctrl[in->width-1][i].xyz, delta ); + len = VectorLength( delta ); + if ( len > 1.0 ) + { + break; + } + } + if ( i == in->height ) + { + wrapWidth = true; + } + + wrapHeight = false; + for ( i = 0 ; i < in->width ; i++ ) + { + VectorSubtract( in->ctrl[i][0].xyz, + in->ctrl[i][in->height-1].xyz, delta ); + len = VectorLength( delta ); + if ( len > 1.0 ) + { + break; + } + } + if ( i == in->width) + { + wrapHeight = true; + } + + + for ( i = 0 ; i < in->width ; i++ ) + { + for ( j = 0 ; j < in->height ; j++ ) + { + count = 0; + //--dv = reinterpret_cast(in.ctrl[j*in.width+i]); + dv = &in->ctrl[i][j]; + VectorCopy( dv->xyz, base ); + for ( k = 0 ; k < 8 ; k++ ) + { + VectorClear( around[k] ); + good[k] = false; + + for ( dist = 1 ; dist <= 3 ; dist++ ) + { + x = i + neighbors[k][0] * dist; + y = j + neighbors[k][1] * dist; + if ( wrapWidth ) + { + if ( x < 0 ) + { + x = in->width - 1 + x; + } + else if ( x >= in->width ) + { + x = 1 + x - in->width; + } + } + if ( wrapHeight ) + { + if ( y < 0 ) + { + y = in->height - 1 + y; + } + else if ( y >= in->height ) + { + y = 1 + y - in->height; + } + } + + if ( x < 0 || x >= in->width || y < 0 || y >= in->height ) + { + break; // edge of patch + } + //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp ); + VectorSubtract( in->ctrl[x][y].xyz, base, temp ); + if ( __VectorNormalize( temp, temp ) == 0 ) + { + continue; // degenerate edge, get more dist + } + else + { + good[k] = true; + VectorCopy( temp, around[k] ); + break; // good edge + } + } + } + + VectorClear( sum ); + for ( k = 0 ; k < 8 ; k++ ) + { + if ( !good[k] || !good[(k+1)&7] ) + { + continue; // didn't get two points + } + CrossProduct( around[(k+1)&7], around[k], normal ); + if ( __VectorNormalize( normal, normal ) == 0 ) + { + continue; + } + VectorAdd( normal, sum, sum ); + count++; + } + if ( count == 0 ) + { + //printf("bad normal\n"); + count = 1; + //continue; + } + __VectorNormalize( sum, dv->normal ); + } + } +} + + + + +/* +================== +Patch_CalcBounds +================== +*/ +void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax) +{ + vMin[0] = vMin[1] = vMin[2] = 99999; + vMax[0] = vMax[1] = vMax[2] = -99999; + + p->bDirty = true; + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + for (int j = 0; j < 3; j++) + { + float f = p->ctrl[w][h].xyz[j]; + if (f < vMin[j]) + vMin[j] = f; + if (f > vMax[j]) + vMax[j] = f; + } + } + } +} + +/* +================== +Brush_RebuildBrush +================== +*/ +void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs) +{ + // + // Total hack job + // Rebuilds a brush + int i, j; + face_t *f, *next; + vec3_t pts[4][2]; + texdef_t texdef; + // free faces + + for (j = 0; j < 3; j++) + { + if ((int)vMins[j] == (int)vMaxs[j]) + { + vMins[j] -= 4; + vMaxs[j] += 4; + } + } + + + for (f=b->brush_faces ; f ; f=next) + { + next = f->next; + if (f) + texdef = f->texdef; + Face_Free( f ); + } + + b->brush_faces = NULL; + + // left the last face so we can use its texdef + + for (i=0 ; i<3 ; i++) + if (vMaxs[i] < vMins[i]) + Error ("Brush_RebuildBrush: backwards"); + + pts[0][0][0] = vMins[0]; + pts[0][0][1] = vMins[1]; + + pts[1][0][0] = vMins[0]; + pts[1][0][1] = vMaxs[1]; + + pts[2][0][0] = vMaxs[0]; + pts[2][0][1] = vMaxs[1]; + + pts[3][0][0] = vMaxs[0]; + pts[3][0][1] = vMins[1]; + + for (i=0 ; i<4 ; i++) + { + pts[i][0][2] = vMins[2]; + pts[i][1][0] = pts[i][0][0]; + pts[i][1][1] = pts[i][0][1]; + pts[i][1][2] = vMaxs[2]; + } + + for (i=0 ; i<4 ; i++) + { + f = Face_Alloc(); + f->texdef = texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; +// f->texdef.flags |= SURF_PATCH; + f->next = b->brush_faces; + b->brush_faces = f; + j = (i+1)%4; + + VectorCopy (pts[j][1], f->planepts[0]); + VectorCopy (pts[i][1], f->planepts[1]); + VectorCopy (pts[i][0], f->planepts[2]); + } + + f = Face_Alloc(); + f->texdef = texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; +// f->texdef.flags |= SURF_PATCH; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[0][1], f->planepts[0]); + VectorCopy (pts[1][1], f->planepts[1]); + VectorCopy (pts[2][1], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; +// f->texdef.flags |= SURF_PATCH; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[2][0], f->planepts[0]); + VectorCopy (pts[1][0], f->planepts[1]); + VectorCopy (pts[0][0], f->planepts[2]); + + Brush_Build(b); +} + +void WINAPI Patch_Rebuild(patchMesh_t *p) +{ + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + p->bDirty = true; +} + +/* +================== +AddBrushForPatch +================== + adds a patch brush and ties it to this patch id +*/ +brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld ) +{ + // find the farthest points in x,y,z + vec3_t vMin, vMax; + Patch_CalcBounds(pm, vMin, vMax); + + for (int j = 0; j < 3; j++) + { + if (vMin[j] == vMax[j]) + { + vMin[j] -= 4; + vMax[j] += 4; + } + } + + brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); + + // FIXME: this entire type of linkage needs to be fixed + b->patchBrush = true; + b->pPatch = pm; + pm->pSymbiot = b; + pm->bSelected = false; + pm->bOverlay = false; + pm->bDirty = true; + pm->nListID = -1; + + if (bLinkToWorld) + { + Brush_AddToList (b, &active_brushes); + Entity_LinkBrush (world_entity, b); + Brush_Build(b); + } + + return b; +} + +void Patch_SetPointIntensities(int n) +{ +#if 0 + patchMesh_t *p = patchMeshes[n]; + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + + } + } +#endif +} + +// very approximate widths and heights + +/* +================== +Patch_Width +================== +*/ +float Patch_Width(patchMesh_t *p) +{ + float f = 0; + for (int i = 0; i < p->width-1; i++) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp); + f += VectorLength(vTemp); + } + return f; +} + +float Patch_WidthDistanceTo(patchMesh_t *p, int j) +{ + float f = 0; + for (int i = 0; i < j; i++) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp); + f += VectorLength(vTemp); + } + return f; +} + + + +/* +================== +Patch_Height +================== +*/ +float Patch_Height(patchMesh_t *p) +{ + float f = 0; + for (int i = 0; i < p->height-1; i++) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp); + f += VectorLength(vTemp); + } + return f; +} + +float Patch_HeightDistanceTo(patchMesh_t *p, int j) +{ + float f = 0; + for (int i = p->height-1; i > j; i--) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i-1].xyz, vTemp); // reverse order for T coords + f += VectorLength(vTemp); + } + return f; +} + + + +/* +================== +Patch_Naturalize +================== +texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength + +dist( this control point to first control point ) / dist ( last control pt to first) +*/ +void WINAPI Patch_Naturalize(patchMesh_t *p) +{ + int nWidth = (int)(p->d_texture->width * g_pGameDescription->mTextureDefaultScale); + int nHeight = (int)(p->d_texture->height * g_pGameDescription->mTextureDefaultScale); + float fPWidth = Patch_Width(p); + float fPHeight = Patch_Height(p); + float xAccum = 0.0f; + + for ( int i = 0; i < p->width ; i++ ) + { + float yAccum = 0.0f; + for ( int j = p->height-1; j >= 0 ; j-- ) + { + p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth; + p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight; + yAccum = Patch_HeightDistanceTo(p,j-1); + //p->ctrl[i][j][3] = (fPWidth / nWidth) * (float)i / (p->width - 1); + //p->ctrl[i][j][4] = (fPHeight/ nHeight) * (float)j / (p->height - 1); + } + xAccum = Patch_WidthDistanceTo(p,i+1); + } + p->bDirty = true; +} + +/* + if (bIBevel) + { + VectorCopy(p->ctrl[1][0], p->ctrl[1][1]); + } + + if (bIEndcap) + { + VectorCopy(p->ctrl[3][0], p->ctrl[4][1]); + VectorCopy(p->ctrl[2][0], p->ctrl[3][1]); + VectorCopy(p->ctrl[2][0], p->ctrl[2][1]); + VectorCopy(p->ctrl[2][0], p->ctrl[1][1]); + VectorCopy(p->ctrl[1][0], p->ctrl[0][1]); + VectorCopy(p->ctrl[1][0], p->ctrl[0][2]); + VectorCopy(p->ctrl[1][0], p->ctrl[1][2]); + VectorCopy(p->ctrl[2][0], p->ctrl[2][2]); + VectorCopy(p->ctrl[3][0], p->ctrl[3][2]); + VectorCopy(p->ctrl[3][0], p->ctrl[4][2]); + } +*/ + +int Index3By[][2] = +{ + {0,0}, + {1,0}, + {2,0}, + {2,1}, + {2,2}, + {1,2}, + {0,2}, + {0,1}, + {0,0}, + {0,0}, + {0,0}, + {0,0}, + {0,0}, + {0,0}, + {0,0} +}; + +int Index5By[][2] = +{ + {0,0}, + {1,0}, + {2,0}, + {3,0}, + {4,0}, + {4,1}, + {4,2}, + {4,3}, + {4,4}, + {3,4}, + {2,4}, + {1,4}, + {0,4}, + {0,3}, + {0,2}, + {0,1} +}; + + + +int Interior3By[][2] = +{ + {1,1} +}; + +int Interior5By[][2] = +{ + {1,1}, + {2,1}, + {3,1}, + {1,2}, + {2,2}, + {3,2}, + {1,3}, + {2,3}, + {3,3} +}; + +int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]); +int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]); + +extern int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane); +// the bFaceCycle only means we are going through a patch cycling loop +// then we rely on g_vCycleCapNormal to compute the cap + +void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false) +{ + vec3_t vProjection, vX, vY; + qtexture_t *texture = p->pShader->getTexture(); + plane_t Plane1, Plane2, Plane3; + bool bThing=true; + + if (bFaceCycle) + VectorCopy (g_vCycleCapNormal, vProjection); + + else + { + VectorClear ( vProjection ); + + // find normal for plane from first 3 corner points + if (!Plane_FromPoints(p->ctrl[0][0].xyz,p->ctrl[0][p->height-1].xyz,p->ctrl[p->width-1][p->height-1].xyz,&Plane1)) + { + VectorClear ( Plane3.normal ); + bThing = false; + } + + // find normal for plane from next 3 corner points + if (!Plane_FromPoints(p->ctrl[p->width-1][p->height-1].xyz,p->ctrl[p->width-1][0].xyz,p->ctrl[0][0].xyz,&Plane2)) + { + if (bThing) + { + VectorCopy ( Plane1.normal, Plane3.normal ); + Plane3.dist = Plane1.dist; + } + } + + else + { + if (bThing) + // find average plane for all 4 corner points + { + for (int n = 0; n <= 2; n++) + { + Plane3.normal[n] = (Plane1.normal[n] + Plane2.normal[n]) / 2; + } + Plane3.dist = (Plane1.dist + Plane2.dist) / 2; + } + else + { + VectorCopy ( Plane2.normal, Plane3.normal ); + Plane3.dist = Plane2.dist; + } + } + + // get best axis for projection from average plane + //Sys_Printf("surface normal1: (%f,%f,%f)\n",Plane1.normal[0],Plane1.normal[1],Plane1.normal[0]); + //Sys_Printf("surface normal2: (%f,%f,%f)\n",Plane2.normal[0],Plane2.normal[1],Plane2.normal[0]); + //Sys_Printf("surface normal3: (%f,%f,%f)\n",Plane3.normal[0],Plane3.normal[1],Plane3.normal[0]); + TextureAxisFromPlane(&Plane3, vX, vY); + } + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (vProjection[2] == 1.0f || (vX[0] == 1.0f && vY[1] == -1.0f)) + { + p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale); + p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[1] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; + } + else if (vProjection[0] == 1.0f || (vX[1] == 1.0f && vY[2] == -1.0f)) + { + p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[1] / (texture->width * g_pGameDescription->mTextureDefaultScale); + p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; + } + else if (vProjection[1] == 1.0f || (vX[0] == 1.0f && vY[2] == -1.0f)) + { + p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale); + p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; + } + //Sys_Printf("(%i,%i) (%f,%f,%f) (%f,%f) %f\n",w,h, + // p->ctrl[w][h].xyz[0],p->ctrl[w][h].xyz[1],p->ctrl[w][h].xyz[2], + // p->ctrl[w][h].st[0],p->ctrl[w][h].st[1],p->ctrl[w][h].normal); + } + } + // make sure it will rebuild + p->bDirty = true; +} + +void FillPatch(patchMesh_t *p, vec3_t v) +{ + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + VectorCopy(v, p->ctrl[i][j].xyz); + } + } +} + +// temporarily moved function to allow use in Cap() and CapSpecial() +void patchInvert(patchMesh_t *p) +{ + drawVert_t vertTemp; + p->bDirty = true; + for ( int i = 0 ; i < p->width ; i++ ) + { + for (int j = 0; j < p->height / 2; j++) + { + memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); + memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); + } + } +} + +brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst) +{ + brush_t *b; + patchMesh_t *p; + vec3_t vMin, vMax; + int i, j; + + bool bSmall = true; + // make a generic patch + if (pParent->width <= 9) + { + b = Patch_GenericMesh(3, 3, 2, false); + } + else + { + b = Patch_GenericMesh(5, 5, 2, false); + bSmall = false; + } + + if (!b) + { + Sys_Printf("Unable to cap. You may need to ungroup the patch.\n"); + return NULL; + } + + p = b->pPatch; + p->type |= PATCH_CAP; + + vMin[0] = vMin[1] = vMin[2] = 9999; + vMax[0] = vMax[1] = vMax[2] = -9999; + + // we seam the column edge, FIXME: this might need to be able to seem either edge + // + int nSize = (bByColumn) ? pParent->width : pParent->height; + int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1; + + FillPatch(p, pParent->ctrl[0][nIndex].xyz); + + for (i = 0; i < nSize; i++) + { + if (bByColumn) + { + if (bSmall) + { + VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz); + } + else + { + VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz); + } + } + else + { + if (bSmall) + { + VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz); + } + else + { + VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz); + } + } + + for (j = 0; j < 3; j++) + { + float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j]; + if (f < vMin[j]) + vMin[j] = f; + if (f > vMax[j]) + vMax[j] = f; + } + } + + vec3_t vTemp; + for (j = 0; j < 3; j++) + { + vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5); + } + int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount; + for (j = 0; j < nCount; j++) + { + if (bSmall) + { + VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz); + } + else + { + VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz); + } + } + + if (bFirst) + patchInvert(p); + /* + { + drawVert_t vertTemp; + for (i = 0; i < p->width; i++) + { + for (j = 0; j < p->height / 2; j++) + { + memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); + memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); + } + } + } + */ + + Patch_Rebuild(p); + Patch_CapTexture(p); + return p->pSymbiot; +} + +brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst) +{ + + brush_t *b; + patchMesh_t *p; + vec3_t vMin, vMax, vTemp; + int i, j; + + if (nType == IENDCAP) + b = Patch_GenericMesh(5, 3, 2, false); + else + b = Patch_GenericMesh(3, 3, 2, false); + + if (!b) + { + Sys_Printf("Unable to cap. Make sure you ungroup before re-capping."); + return NULL; + } + + p = b->pPatch; + p->type |= PATCH_CAP; + + vMin[0] = vMin[1] = vMin[2] = 9999; + vMax[0] = vMax[1] = vMax[2] = -9999; + + // int nSize = pParent->width; + int nIndex = (bFirst) ? 0 : pParent->height-1; + + // parent bounds are used for some things + Patch_CalcBounds(pParent, vMin, vMax); + + for (j = 0; j < 3; j++) + { + vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5); + } + + if (nType == IBEVEL) + { + VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz); + } + else if (nType == BEVEL) + { + vec3_t p1, p2, p3, p4; //, temp, dir; + + VectorCopy(pParent->ctrl[0][nIndex].xyz, p3); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p1); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p2); + + //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]); + //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]); + //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]); + + VectorSubtract(p2, p1, p4); + VectorAdd(p3, p4, p4); + // spog - use opposite-point-on-parallelogram to find p4 + /* + VectorSubtract(p3, p2, dir); + VectorNormalize(dir); + VectorSubtract(p1, p2, temp); + vec_t dist = _DotProduct(temp, dir); + VectorScale(dir, dist, temp); + VectorAdd(p2, temp, temp); + VectorSubtract(temp, p1, temp); + VectorScale(temp, 2, temp); + VectorAdd(p1, temp, p4); + */ + + //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]); + //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]); + //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]); + //Sys_Printf("CapSpecial() p4: %f %f %f\n",p4[0],p4[1],p4[2]); + + VectorCopy(p4, p->ctrl[0][0].xyz); + VectorCopy(p4, p->ctrl[1][0].xyz); + VectorCopy(p4, p->ctrl[0][1].xyz); + VectorCopy(p4, p->ctrl[1][1].xyz); + VectorCopy(p4, p->ctrl[0][2].xyz); + VectorCopy(p4, p->ctrl[1][2].xyz); + VectorCopy(p2, p->ctrl[2][0].xyz); + VectorCopy(p1, p->ctrl[2][1].xyz); + VectorCopy(p3, p->ctrl[2][2].xyz); + + } + else if (nType == ENDCAP) + { + VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp); + VectorScale(vTemp, 0.5, vTemp); + VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz); + VectorCopy(vTemp, p->ctrl[1][0].xyz); + VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz); + + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz); + + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz); + } + else + { + VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[0][0].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][0].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][0].xyz); + VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[4][0].xyz); + + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][1].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][1].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][1].xyz); + + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][2].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][2].xyz); + } + + + if (!bFirst) + { + drawVert_t vertTemp; + for (i = 0; i < p->width; i++) + { + for (j = 0; j < p->height / 2; j++) + { + memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); + memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); + } + } + } + + //--Patch_CalcBounds(p, vMin, vMax); + //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + Patch_Rebuild(p); + Patch_CapTexture(p); + return p->pSymbiot; +} + +void Patch_CapCurrent() +{ + patchMesh_t *pParent = NULL; + brush_t *b[4]; + brush_t *pCap = NULL; + b[0] = b[1] = b[2] = b[3] = NULL; + int nIndex = 0; + bool b_GroupResult = TRUE; + + if (!QE_SingleBrush(true)) + { + Sys_Printf("Patch_CapCurrent: you must have a single patch selected\n"); + return; + } + + + for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pParent = pb->pPatch; + // decide which if any ends we are going to cap + // if any of these compares hit, it is a closed patch and as such + // the generic capping will work.. if we do not find a closed edge + // then we need to ask which kind of cap to add + if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz)) + { + pCap = Cap(pParent, true, false); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz)) + { + pCap = Cap(pParent, true, true); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz)) + { + pCap = Cap(pParent, false, false); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz)) + { + pCap = Cap(pParent, false, true); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + } + } + + if (pParent) + { + // if we did not cap anything with the above tests + if (nIndex == 0) + { + int type; + + if (DoCapDlg (&type, &b_GroupResult) == IDOK) + { + b[nIndex++] = CapSpecial(pParent, type, false); + b[nIndex++] = CapSpecial(pParent, type, true); + } + } + + if (nIndex > 0) + { + while (nIndex > 0) + { + nIndex--; + if (b[nIndex]) + { + Select_Brush(b[nIndex]); + } + } + // Gef: Added toggle for capped patch func_group + if(b_GroupResult) { + entity_t *e = Entity_Alloc(); + SetKeyValue(e, "classname", "func_group"); + SetKeyValue(e, "type", "patchCapped"); + Select_GroupEntity(e); + Entity_AddToList(e, &entities); + } + } + } +} + +/* +=============== +BrushToPatchMesh +=============== +*/ +void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight) +{ + brush_t *b; + patchMesh_t *p; + int i,j; + + if (!QE_SingleBrush()) + return; + + b = selected_brushes.next; + + p = MakeNewPatch(); + + p->d_texture = b->brush_faces->d_texture; + p->pShader = b->brush_faces->pShader; + + p->height = nHeight; + + p->type = PATCH_CYLINDER; + if (bBevel & !bSquare) + { + p->type = PATCH_BEVEL; + p->width = 3; + int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1)); + int nStart = (int)(b->mins[2]); + for (i = 0; i < p->height; i++) + { + p->ctrl[0][i].xyz[0] = b->mins[0]; + p->ctrl[0][i].xyz[1] = b->mins[1]; + p->ctrl[0][i].xyz[2] = nStart; + + p->ctrl[1][i].xyz[0] = b->maxs[0]; + p->ctrl[1][i].xyz[1] = b->mins[1]; + p->ctrl[1][i].xyz[2] = nStart; + + p->ctrl[2][i].xyz[0] = b->maxs[0]; + p->ctrl[2][i].xyz[1] = b->maxs[1]; + p->ctrl[2][i].xyz[2] = nStart; + nStart += nStep; + } + } + else if (bEndcap & !bSquare) + { + p->type = PATCH_ENDCAP; + p->width = 5; + int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1)); + int nStart = (int)(b->mins[2]); + for (i = 0; i < p->height; i++) + { + p->ctrl[0][i].xyz[0] = b->mins[0]; + p->ctrl[0][i].xyz[1] = b->mins[1]; + p->ctrl[0][i].xyz[2] = nStart; + + p->ctrl[1][i].xyz[0] = b->mins[0]; + p->ctrl[1][i].xyz[1] = b->maxs[1]; + p->ctrl[1][i].xyz[2] = nStart; + + p->ctrl[2][i].xyz[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5); + p->ctrl[2][i].xyz[1] = b->maxs[1]; + p->ctrl[2][i].xyz[2] = nStart; + + p->ctrl[3][i].xyz[0] = b->maxs[0]; + p->ctrl[3][i].xyz[1] = b->maxs[1]; + p->ctrl[3][i].xyz[2] = nStart; + + p->ctrl[4][i].xyz[0] = b->maxs[0]; + p->ctrl[4][i].xyz[1] = b->mins[1]; + p->ctrl[4][i].xyz[2] = nStart; + nStart += nStep; + } + } + else + { + p->width = 9; + p->ctrl[1][0].xyz[0] = b->mins[0]; + p->ctrl[1][0].xyz[1] = b->mins[1]; + + p->ctrl[3][0].xyz[0] = b->maxs[0]; + p->ctrl[3][0].xyz[1] = b->mins[1]; + + p->ctrl[5][0].xyz[0] = b->maxs[0]; + p->ctrl[5][0].xyz[1] = b->maxs[1]; + + p->ctrl[7][0].xyz[0] = b->mins[0]; + p->ctrl[7][0].xyz[1] = b->maxs[1]; + + for ( i = 1 ; i < p->width - 1 ; i += 2 ) + { + + p->ctrl[i][0].xyz[2] = b->mins[2]; + + VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz ); + + p->ctrl[i][2].xyz[2] = b->maxs[2]; + + p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5; + p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5; + p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5; + } + InterpolateInteriorPoints( p ); + + if (bSquare) + { + if (bBevel || bEndcap) + { + if (bBevel) + { + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz); + VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz); + } + } + else + { + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz); + VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz); + VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz); + VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz); + } + } + } + else + { + for (i = 0; i < p->width-1; i ++) + { + for (j = 0; j < p->height; j++) + { + VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz); + } + } + for (j = 0; j < p->height; j++) + { + VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz); + } + } + } + } + + + Patch_Naturalize(p); + + if (bCone) + { + p->type = PATCH_CONE; + float xc = (b->maxs[0] + b->mins[0]) * 0.5; + float yc = (b->maxs[1] + b->mins[1]) * 0.5; + + for ( i = 0 ; i < p->width ; i ++) + { + p->ctrl[i][2].xyz[0] = xc; + p->ctrl[i][2].xyz[1] = yc; + } + } + + b = AddBrushForPatch(p); + + Select_Delete(); + Select_Brush(b); + +} + +/* +================== +Patch_GenericMesh +================== +*/ +brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride) +{ + int i,j; + + if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15) + { + Sys_Printf("Invalid patch width or height.\n"); + return NULL; + } + + if (! bOverride && !QE_SingleBrush()) + { + Sys_Printf("Error: you must have a single brush selected\n"); + return NULL; + } + + patchMesh_t* p = MakeNewPatch(); + p->pShader = g_qeglobals.d_texturewin.pShader; + p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture(); + + p->width = nWidth; + p->height = nHeight; + p->type = PATCH_GENERIC; + + int nFirst = 0; + int nSecond = 1; + if (nOrientation == 0) + { + nFirst = 1; + nSecond = 2; + } + else if (nOrientation == 1) + { + nSecond = 2; + } + + brush_t *b = selected_brushes.next; + // set the workzone to this brush, use it later to create the patch points + UpdateWorkzone_ForBrush( b ); + + int xStep = (int)(b->mins[nFirst]); + float xAdj = fabs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1)); + float yAdj = fabs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1)); + + for (i = 0; i < nWidth; i++) + { + int yStep = (int)(b->mins[nSecond]); + for (j = 0; j < nHeight; j++) + { + p->ctrl[i][j].xyz[nFirst] = xStep; + p->ctrl[i][j].xyz[nSecond] = yStep; + // create patch based on workzone + p->ctrl[i][j].xyz[nOrientation] = g_qeglobals.d_work_max[nOrientation]; + yStep += (int)yAdj; + } + xStep += (int)xAdj; + } + + Patch_Naturalize(p); + + b = AddBrushForPatch(p); + if (bDeleteSource) + { + Select_Delete(); + Select_Brush(b); + } + + return b; + //g_qeglobals.d_select_mode = sel_curvepoint; +} + +/* +================== +PointInMoveList +================== +*/ +int PointInMoveList(float *pf) +{ + for (int i = 0; i < g_qeglobals.d_num_move_points; i++) + { + if (pf == &g_qeglobals.d_move_points[i][0]) + return i; + } + return -1; +} + +/* +================== +PointValueInMoveList +================== +*/ +int PointValueInMoveList(vec3_t v) +{ + for (int i = 0; i < g_qeglobals.d_num_move_points; i++) + { + if (VectorCompare(v, g_qeglobals.d_move_points[i])) + return i; + } + return -1; +} + + +/* +================== +RemovePointFromMoveList +================== +*/ +void RemovePointFromMoveList(vec3_t v) +{ + int n; + while ( (n = PointValueInMoveList(v)) >= 0) + { + for (int i = n; i < g_qeglobals.d_num_move_points-1; i++) + { + g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1]; + } + g_qeglobals.d_num_move_points--; + } +} + +/* +================== +ColumnSelected +================== +*/ +bool ColumnSelected(patchMesh_t* p, int nCol) +{ + for (int i = 0; i < p->height; i++) + { + if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1) + return false; + } + return true; +} + +/* +================== +AddPoint +================== +*/ +void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true) +{ + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v; + if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill) + { + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + if (g_bPatchWeld) + { + if ( VectorCompare(v, p->ctrl[i][j].xyz) + && PointInMoveList(p->ctrl[i][j].xyz) == -1) + { + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + continue; + } + } + if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA) + { + if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON) + &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON)) + { + if (PointInMoveList(p->ctrl[i][j].xyz) == -1) + { + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + continue; + } + } + } + } + } + } +} + +/* +================== +SelectRow +================== +*/ +void SelectRow(patchMesh_t* p, int nRow, bool bMulti) +{ + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + for (int i = 0; i < p->width; i++) + { + AddPoint(p, p->ctrl[i][nRow].xyz, false); + } + //Sys_Printf("Selected Row %d\n", nRow); +} + +/* +================== +SelectColumn +================== +*/ +void SelectColumn(patchMesh_t* p, int nCol, bool bMulti) +{ + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + for (int i = 0; i < p->height; i++) + { + AddPoint(p, p->ctrl[nCol][i].xyz, false); + } + //Sys_Printf("Selected Col %d\n", nCol); +} + + +/* +================== +AddPatchMovePoint +================== +*/ +void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull) +{ + if (!g_bSameView && !bMulti && !bFull) + { + g_bSameView = true; + //return; // was causing odd behaviour on patch vertex selection + } + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + if (VectorCompare(v, p->ctrl[i][j].xyz)) + { + if (PointInMoveList(p->ctrl[i][j].xyz) == -1) + { + if (bFull) // if we want the full row/col this is on + { + SelectColumn(p, i, bMulti); + } + else + { + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + AddPoint(p, p->ctrl[i][j].xyz); + //Sys_Printf("Selected col:row %d:%d\n", i, j); + } + //--if (!bMulti) + return; + } + else + { + if (bFull) + { + if (ColumnSelected(p, i)) + { + SelectRow(p, j, bMulti); + } + else + { + SelectColumn(p, i, bMulti); + } + return; + } + //if (!bMulti) + //{ + // g_qeglobals.d_num_move_points = 0; + // AddPoint(p, p->ctrl[i][j].xyz); + //} + if (bMulti)// if (g_bSameView) // this is not having desired effect + { + RemovePointFromMoveList(v); + return; + } + } + } + } + } + } + } +} + +/* +================== +Patch_UpdateSelected +================== +*/ +void Patch_UpdateSelected(vec3_t vMove) +{ + int i;//, j; + for (i=0 ; i < g_qeglobals.d_num_move_points ; i++) + { + VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]); + if (g_qeglobals.d_num_move_points == 1) + { + } + } + + //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch]; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + +#if 0 //moving to SelectCurvePointByRay + g_qeglobals.d_numpoints = 0; + for (i = 0 ; i < p->width ; i++ ) + { + for ( j = 0 ; j < p->height ; j++ ) + { + VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + if (g_qeglobals.d_numpoints < MAX_POINTS-1) + { + g_qeglobals.d_numpoints++; + } + } + } +#endif + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + } + } + //Brush_Free(p->pSymbiot); + //Select_Brush(AddBrushForPatch(g_nSelectedPatch)); +} + + + +/* +=============== +SampleSinglePatch +=============== +*/ +void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) { + float vCtrl[3][5]; + int vPoint; + int axis; + + // find the control points for the v coordinate + for (vPoint = 0 ; vPoint < 3 ; vPoint++) + { + for (axis = 0 ; axis < 5 ; axis++) + { + float a, b, c; + float qA, qB, qC; + + a = ctrl[0][vPoint][axis]; + b = ctrl[1][vPoint][axis]; + c = ctrl[2][vPoint][axis]; + qA = a - 2 * b + c; + qB = 2 * b - 2 * a; + qC = a; + + vCtrl[vPoint][axis] = qA * u * u + qB * u + qC; + } + } + + // interpolate the v value + for (axis = 0 ; axis < 5 ; axis++) + { + float a, b, c; + float qA, qB, qC; + + a = vCtrl[0][axis]; + b = vCtrl[1][axis]; + c = vCtrl[2][axis]; + qA = a - 2 * b + c; + qB = 2 * b - 2 * a; + qC = a; + + out[axis] = qA * v * v + qB * v + qC; + } +} + +//spog - Curve LOD stuff starts + +float ShadeForNormal(vec3_t normal) +{ + float f; + + vec3_t L; + L[0] = 1.0f; + L[1] = 1.0f; + L[2] = 1.0f; + + + // quick diffuse shading + f = DotProduct(L, normal); + + // range 0.5 to 1.0 + f = (f+1)/4.0f; + //if (f < 0.0f) f = 0.0f; + + f += 0.5f; + + return f; +} + +void ShadeVertex (drawVert_t &p) +{ + p.lightmap[0] = ShadeForNormal(p.normal); +} + + +void Patch_DrawNormals(patchMesh_t *patch) +{ + int row, col; + vec3_t vNormal; + + qglBegin (GL_LINES); + for (col=0; colwidth; col++) + { + for (row=0; rowheight; row++) + { + VectorAdd(patch->ctrl[col][row].xyz, patch->ctrl[col][row].normal, vNormal); + qglVertex3fv (patch->ctrl[col][row].xyz); + qglVertex3fv (vNormal); + } + } + qglEnd (); +} + + +// take an array of three drawVerts, and the addresses of three more drawVerts +// interpolate new XYZST values from the three drawVerts, these are: +// the left sub-control-point, the right sub-control-point and the midpoint of the curve respectively +// store these values in the drawVerts passed to the function +void Patch_CurveSplit(drawVert_t *vCurve[3], drawVert_t &pLeft, drawVert_t &pRight, drawVert_t &pMid, float u) +{ + int i; + //float u = 0.5f; +// float a, b; + drawVert_t v1, v2, v3; +// vec3_t v4; + + for (i=0; i<3; i++) + { + // xyz + v1.xyz[i] = vCurve[1]->xyz[i] - vCurve[0]->xyz[i]; + v2.xyz[i] = vCurve[2]->xyz[i] - vCurve[1]->xyz[i]; + v1.xyz[i] *= u; + v2.xyz[i] *= u; + pLeft.xyz[i] = vCurve[0]->xyz[i] + v1.xyz[i]; + pRight.xyz[i] = vCurve[1]->xyz[i] + v2.xyz[i]; + + v3.xyz[i] = pRight.xyz[i] - pLeft.xyz[i]; + v3.xyz[i] *= u; + pMid.xyz[i] = pLeft.xyz[i] + v3.xyz[i]; + + // normal (weighted average) // no, that's b0rked + //a = 1 / u; // total + //b = u * a; // component 2 + //a = u - b; // component 1 + //pMid.normal[i] = u * ((vCurve[0]->normal[i] * b) + (vCurve[2]->normal[i] * a)); + + if (i==2) continue; + + // st + v1.st[i] = vCurve[1]->st[i] - vCurve[0]->st[i]; + v2.st[i] = vCurve[2]->st[i] - vCurve[1]->st[i]; + v1.st[i] *= u; + v2.st[i] *= u; + pLeft.st[i] = vCurve[0]->st[i] + v1.st[i]; + pRight.st[i] = vCurve[1]->st[i] + v2.st[i]; + + v3.st[i] = pRight.st[i] - pLeft.st[i]; + v3.st[i] *= u; + pMid.st[i] = pLeft.st[i] + v3.st[i]; + } +} + +// take an array of three points, return an index representing the curvature of those three points +// return zero if the curve is a straight line, unless the midpoint is not between the endpoints +float Patch_CurveIndex(vec3_t vCurve[]) +{ + vec3_t vTemp, v1, v2, v3, vClear; +// int i; + float width, angle; + float index, dot; + + VectorClear(vClear); + + VectorSubtract(vCurve[2], vCurve[0], vTemp); + VectorSubtract(vCurve[1], vCurve[0], v1); + VectorSubtract(vCurve[2], vCurve[1], v2); + + if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return 0 if 1->2 == 0 or 1->2 == 1->3 + return 0.0f; + + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + if (VectorCompare(v1, v2)) + return 0.0f; + + VectorCopy(vTemp, v3); + width = VectorNormalize(v3, v3); + + if (VectorCompare(v1, v3) && VectorCompare(v2, v3)) + return 0.0f; + + dot = DotProduct(v1, v2); + + angle = acos(dot) / Q_PI; + + index = width * angle; + + return index; +} + + +// create a new tree root, give it the coordinate values of the drawVert +// return a pointer to the new tree root +BTNode_t *BTree_Create(drawVert_t info) +{ + BTNode_t *BTree = new BTNode_t; + BTree->left = BTree->right = NULL; + VectorCopy(info.xyz, BTree->info.xyz); + VectorCopy(info.xyz, BTree->vMid.xyz); + for (int i=0; i<2; i++) + { + BTree->info.st[i] = info.st[i]; + BTree->vMid.st[i] = info.st[i]; + } + return BTree; +} + +// take ownership of the subtree +// delete the entire subtree +// return a NULL pointer +BTNode_t *BTree_Delete(BTNode_t *pBT) +{ + if (pBT != NULL) + { + BTree_Delete(pBT->left); + BTree_Delete(pBT->right); + delete pBT; + } + return NULL; +} + +// NOT currently used +BTNode_t *BTree_Clear(BTNode_t *pBT, bool bFirst = true) +{ + if (pBT != NULL) + { + BTree_Clear(pBT->left, false); + BTree_Clear(pBT->right, false); + if (!bFirst) delete pBT; + } + return pBT; +} + +// take a pointer to the last item added to the list (this can also be a NULL pointer) +// take a pointer to the root of a subtree, and the patch points to the left and right of it +// add a new item to the subtree list, and add the subtree and its adjacent points to the new item +// return a pointer to the last item added to the subtree list +BTreeList_t *BTree_AddToList(BTreeList_t *pBTList, BTNode_t *pBT, drawVert_t &pLeft, drawVert_t &pRight) +{ + BTreeList_t *newBTList = new BTreeList_t; + newBTList->next = pBTList; + newBTList->pBT = pBT; + VectorCopy(pLeft.xyz, newBTList->vLeft.xyz); + VectorCopy(pRight.xyz, newBTList->vRight.xyz); + VectorCopy(pLeft.normal, newBTList->vLeft.normal); + VectorCopy(pRight.normal, newBTList->vRight.normal); + for (int i=0; i<2; i++) + { + newBTList->vLeft.st[i] = pLeft.st[i]; + newBTList->vRight.st[i] = pRight.st[i]; + } + return newBTList; +} + +// NOT currently used, subtrees are now stored on the patch +// take ownership of the subtree list +// delete the entire list and the subtrees it points to +// return a NULL pointer +BTreeList_t *BTree_DeleteList(BTreeList_t *pBTList) +{ + if (pBTList != NULL) + { + BTree_DeleteList(pBTList->next); + pBTList->pBT = BTree_Delete(pBTList->pBT); + delete pBTList; + } + return NULL; +} + +// take ownership of the subtree list +// delete the entire subtree list, but not the subtrees themselves +// return a NULL pointer +BTreeList_t *BTree_DeletePointerList(BTreeList_t *pBTList) +{ + if (pBTList != NULL) + { + BTree_DeletePointerList(pBTList->next); + delete pBTList; + } + return NULL; +} + +// take a pointer to the last item added to the list of subtree lists +// add a subtree list to the list +// return a pointer to the last item added +BTListList_t *BTree_AddListToList(BTListList_t *pBTListList, BTreeList_t *pBTList) +{ + BTListList_t *newBTListList = new BTListList_t; + newBTListList->next = pBTListList; + newBTListList->list = pBTList; + return newBTListList; +} + + +// take ownership of the list of subtree lists +// delete the entire list of lists, but not the subtrees themselves +// return a NULL pointer +BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList) +{ + if (pBTListList != NULL) + { + BTree_DeleteListFromList(pBTListList->next); + pBTListList->list = BTree_DeletePointerList(pBTListList->list); + delete pBTListList; + } + return NULL; +} + +// take a pointer to the last item in the list +// add a NULL linker subtree to the list, setting the "flipped" flag using the left curvepoint normal .. er.. hacky? +BTreeList_t *BTree_AddLinkToList(BTreeList_t *pBTList, bool bFlipped = false) +{ + BTreeList_t *linkBTList = new BTreeList_t; + linkBTList->pBT = NULL; + linkBTList->next = pBTList; + linkBTList->vLeft.normal[0] = (bFlipped) ? 1.0f : 0.0f; + return linkBTList; +} + + +// take an array of three points and the address of a vector +// store midpoint of the bezier curve formed by the three points, in the vector +void Patch_BezierInterpolate(vec3_t vCurve[], vec3_t &pMid) +{ + vec3_t vTemp; + int i; + VectorSubtract(vCurve[2], vCurve[0], vTemp); // Start->End + for (i=0; i<3; i++) + vTemp[i] /= 2; + VectorAdd(vCurve[0], vTemp, vTemp); // midpoint of Start->End + + VectorSubtract(vTemp, vCurve[1], vTemp); // Mid->(midpoint of Start->End) + for (i=0; i<3; i++) + vTemp[i] /= 2; + VectorAdd(vCurve[1], vTemp, pMid); // midpoint of Mid->(midpoint of Start->End) +} + + +// take a pointer to the list of subtrees, and a threshold value +// generate REAL surface curvature for the subtree curves, using bezier interpolation +// if any of the real curves has an index greater than the threshold, return true +bool Patch_MostCurvedRow(BTreeList_t *pBTList, int threshold) +{ + BTreeList_t *p; + float index;//, bestindex = 0; + vec3_t vCurve[3]; + vec3_t vRow[3]; +// int i; + + for (p = pBTList; p != NULL; p = p->next->next) + { + // this row + VectorCopy(p->vLeft.xyz, vCurve[0]); + VectorCopy(p->pBT->info.xyz, vCurve[1]); + VectorCopy(p->vRight.xyz, vCurve[2]); + + index = Patch_CurveIndex(vCurve); + if (index > threshold) + return true; + + if (p->next == NULL) + break; + + if (p->next->pBT == NULL) continue; + + VectorCopy(p->vLeft.xyz, vCurve[0]); + VectorCopy(p->next->vLeft.xyz, vCurve[1]); + VectorCopy(p->next->next->vLeft.xyz, vCurve[2]); + Patch_BezierInterpolate(vCurve, vRow[0]); + + VectorCopy(p->pBT->info.xyz, vCurve[0]); + VectorCopy(p->next->pBT->info.xyz, vCurve[1]); + VectorCopy(p->next->next->pBT->info.xyz, vCurve[2]); + Patch_BezierInterpolate(vCurve, vRow[1]); + + VectorCopy(p->vRight.xyz, vCurve[0]); + VectorCopy(p->next->vRight.xyz, vCurve[1]); + VectorCopy(p->next->next->vRight.xyz, vCurve[2]); + Patch_BezierInterpolate(vCurve, vRow[2]); + + index = Patch_CurveIndex(vRow); + if (index > threshold) + return true; + } + return false; +} + + +// take a pointer to a list of subtrees.. each subtree in the list is a 3-point bezier curve formed by two endpoints owned by the list, and a midpoint subtree node owned by a patch. +// if any of the subtrees are curved above a threshold, create a left and right subsubtree for each subtree in the list. +// if a NULL linker subtree is found, check for an orientation flip - ie. an inverted LOD-match - and create a NULL subsubtree with the same orientation flip +// this effectively generates trees for multiple patches at the same time.. the subtrees are always owned by their respective patches though +void BTree_ListCurveRecurse(BTreeList_t *pBTList) +{ + BTreeList_t *p; + BTreeList_t *leftBTList, *rightBTList; + //drawVert_t pLeft, pRight, pMid; + drawVert_t *vCurve[3]; + int threshold; + //int i; + bool bFlipped = false; + + if (g_PrefsDlg.m_nSubdivisions >= 1) + threshold = g_PrefsDlg.m_nSubdivisions; + + leftBTList = rightBTList = NULL; + + if (Patch_MostCurvedRow(pBTList, threshold)) // split all subtrees in list if any subtree is above threshold + { + //Sys_Printf("| "); + // traverse nodes in list + for (p = pBTList; p != NULL; p=p->next) + { + if (p->pBT == NULL) + { + leftBTList = BTree_AddLinkToList(leftBTList, (p->vLeft.normal[0] == 1.0f)); + rightBTList = BTree_AddLinkToList(rightBTList, (p->vLeft.normal[0] == 1.0f)); + if (p->vLeft.normal[0] == 1.0f) bFlipped = (!bFlipped) ? true : false; // switch bFlipped if true + continue; + } + + // create left node for this subtree + BTNode_t *newLeft = new BTNode_t; + p->pBT->left = newLeft; + newLeft->left = newLeft->right = NULL; + + // create right node for this subtree + BTNode_t *newRight = new BTNode_t; + p->pBT->right = newRight; + newRight->left = newRight->right = NULL; + + // split this node + vCurve[0] = &p->vLeft; + vCurve[1] = &p->pBT->info; + vCurve[2] = &p->vRight; + Patch_CurveSplit(vCurve, newLeft->info, newRight->info, p->pBT->vMid, 0.5); + + memcpy(&newLeft->vMid, &newLeft->info, sizeof(drawVert_t)); + memcpy(&newRight->vMid, &newRight->info, sizeof(drawVert_t)); + + + if (!bFlipped) + { + // add new left subtree to left subtree list + leftBTList = BTree_AddToList(leftBTList, newLeft, p->vLeft, p->pBT->vMid); + + // add new right subtree to right subtree list + rightBTList = BTree_AddToList(rightBTList, newRight, p->pBT->vMid, p->vRight); + } + else + { + // add new left subtree to right subtree list + rightBTList = BTree_AddToList(rightBTList, newLeft, p->vLeft, p->pBT->vMid); + + // add new right subtree to left subtree list + leftBTList = BTree_AddToList(leftBTList, newRight, p->pBT->vMid, p->vRight); + } + } + + // continue tree left + BTree_ListCurveRecurse(leftBTList); + leftBTList = BTree_DeletePointerList(leftBTList); + + // continue tree right + BTree_ListCurveRecurse(rightBTList); + rightBTList = BTree_DeletePointerList(rightBTList); + } +} + +// take mins and maxs values from two brushes +// return true if they intersect on every axis +bool TouchingAABBs(vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2) +{ + //bool xyz[3]; + vec3_t v1, v2, p1, p2, T; + for (int i=0; i<3; i++) + { + v1[i] = maxs1[i] - mins1[i]; + v2[i] = maxs2[i] - mins2[i]; + v1[i] /=2; + v2[i] /=2; + p1[i] = mins1[i] + v1[i]; + p2[i] = mins2[i] + v2[i]; + // p1 == origin of aabb1 + // p2 == origin of aabb1 + // v1 == displacement of aabb1 + // v1 == displacement of aabb2 + T[i] = p2[i] - p1[i]; // T == vector from aabb1 to aabb2 + if ( fabs(T[i]) > (fabs(v1[i]) + fabs(v2[i])) ) + return false; + } + return true; +} + +// take a pointer to the last item added to pBTList, a pointer to the patch, a row index (start) and a column index +// generate a row of row-curve tree roots, owned by the patch and add the entire column of row-curves to the list, using the row index to decide the order to add +// return a pointer to the last item added to the list +BTreeList_t *Patch_CreateBTListForRows(BTreeList_t *pBTList, patchMesh_t *patch, int start, int col) +{ + int row, pos; + patch->colDirty[(col-1)/2] = true; + + if (start == 0) + { + for (row=0; rowheight; row++) + { + pos = (((col-1)/2)*patch->height)+row; + patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); + patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); + } + } + else + { + for (row=patch->height-1; row>=0; row--) + { + pos = (((col-1)/2)*patch->height)+row; + patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); + patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); + } + } + return pBTList; +} + +// take a pointer to the last item added to pBTList, a pointer to the patch, a row index and a column index (start) +// generate a row of column-curve tree roots, owned by the patch and add the entire row of column-curves to the list, using the column index to decide the order to add +// return a pointer to the last item added to the list +BTreeList_t *Patch_CreateBTListForCols(BTreeList_t *pBTList, patchMesh_t *patch, int row, int start) +{ + int col, pos; + patch->rowDirty[(row-1)/2] = true; + + if (start == 0) + { + for (col=0; colwidth; col++) + { + pos = (((row-1)/2)*patch->width)+col; + patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); + patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); + } + } + else + { + for (col=patch->width-1; col>=0; col--) + { + pos = (((row-1)/2)*patch->width)+col; + patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); + patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); + } + + } + return pBTList; +} + +bool BTree_IsInList(BTreeList_t *pBTList, BTNode_t *pBT) +{ + BTreeList_t *p; + if (pBTList == NULL) return false; + + for (p=pBTList; p != NULL; p=p->next) + { + if (p->pBT != NULL) + { + if (p->pBT == pBT) + return true; + } + } + return false; +} + +int Patch_DegenCurve(vec3_t &start, vec3_t &mid, vec3_t &end) +{ + if (VectorCompare(start, mid) || VectorCompare(end, mid)) + { + if (VectorCompare(start, end)) return 2; + else return 1; + } + else return 0; +} + +// take a pointer to the last item added to the list, and a pointer to a patch (this patch is the owner of the three drawverts) +// take the addresses of three drawVerts, and compare them with the edges of all patches that touch the patch +// if they match an edge, add the tree roots for that section of the matched patch to the list, and recurse for the opposite edge of that patch section. Also, set the matched patch Dirty, so that its drawlists will be rebuilt +// return a pointer to the last item added +BTreeList_t *Patch_FindLODMatches(patchMesh_t *patch, BTreeList_t *pBTList, drawVert_t &pMid, drawVert_t &pLeft, drawVert_t &pRight) +{ + brush_t *pb, *brushlist; + int row, col, i;//, pos; + vec3_t vTemp, v1, v2;//, vClear; + bool bAlreadyAdded; + + //Sys_Printf("Patch_FindLODMatches: called\n"); + + if (VectorCompare(pMid.xyz, pLeft.xyz) && VectorCompare(pMid.xyz, pRight.xyz)) + return pBTList; + + //VectorClear(vClear); + VectorSubtract(pRight.xyz, pLeft.xyz, vTemp); + VectorSubtract(pMid.xyz, pLeft.xyz, v1); + VectorSubtract(pRight.xyz, pMid.xyz, v2); + + //if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return null if 1->2 == 0 or 1->2 == 1->3 + // return pBTList; + + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + if (VectorCompare(v1, v2)) + return pBTList; + + VectorNormalize(vTemp, vTemp); + if (VectorCompare(v1, vTemp) && VectorCompare(v2, vTemp)) + return pBTList; + + brushlist = &active_brushes; + for (i=0; i<2; i++) + { + for (pb = brushlist->next; pb != brushlist; pb=pb->next) + { + if (!pb->patchBrush || pb->pPatch == patch) + continue; + + // ignore this patch if its AABB does not touch the subject patch + if (!TouchingAABBs(patch->pSymbiot->maxs, patch->pSymbiot->mins, pb->maxs, pb->mins)) + continue; + + // all columns of curves + for (col=1; colpPatch->width; col+=2) + { + if (pb->pPatch->colDirty[(col-1)/2]) continue; + + bAlreadyAdded = false; + + // top and bottom curves of this column + for (row=0; rowpPatch->height; row+=pb->pPatch->height-1) + { + if (bAlreadyAdded) + continue; + //if (!BTree_IsInList(pBTList, pb->pPatch->rowLOD[(((col-1)/2)*patch->height)+row])) + // continue; + // ignore this curve if it shares no mid ctrl point with the test curve + if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz)) + continue; + // ignore this curve if it is degenerate + if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col-1][row].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col+1][row].xyz)) + continue; + // if curve matches the test curve directly + if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pRight.xyz)) + { + // add a blank link as separator + pBTList = BTree_AddLinkToList(pBTList); + // add this entire column, if top, top-to-bottom, else bottom to top + pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col); + // continue checking from last curve added to list + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + // set flag + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + // if curve matches test curve but flipped + else if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pLeft.xyz)) + { + pBTList = BTree_AddLinkToList(pBTList, true); // flip + pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col); + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + } + } + + // all rows of curves + for (row=1; rowpPatch->height; row+=2) + { + if (pb->pPatch->rowDirty[(row-1)/2]) continue; + + bAlreadyAdded = false; + + for (col=0; colpPatch->width; col+=pb->pPatch->width-1) + { + if (bAlreadyAdded) + continue; + //if (BTree_IsInList(pBTList, pb->pPatch->colLOD[(((row-1)/2)*patch->width)+col])) + // continue; + if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz)) + continue; + if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row-1].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row+1].xyz)) + continue; + if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pRight.xyz)) + { + pBTList = BTree_AddLinkToList(pBTList); + pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col); + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + else if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pLeft.xyz)) + { + pBTList = BTree_AddLinkToList(pBTList, true); // flip + pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col); + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + } + } + } + brushlist = &selected_brushes; + } + return pBTList; +} + +// take a pointer to a patch +// create tree roots for all the rows and columns of curves in the patch, the patch takes ownership of these new tree roots +// generate lists of pointers to all the trees in all the patches in the map which need to match the LOD of trees owned by this patch +// store all the lists in a list of lists +// recursively generate the rest of every tree in each list in the list +void Patch_CreateLODTrees(patchMesh_t *patch) +{ + BTreeList_t *pBTList; + int col, row, pos;//, rowcount, colcount; + BTListList_t *pLists; + + //Sys_Printf("Patch_CreateMatchedLODTrees: called\n"); + + BTListList_t *LODLists; + LODLists = NULL; + + pBTList = NULL; + + patch->bDirty = false; + patch->LODUpdated = true; + + for(col=1; colwidth; col+=2) + { + if (patch->colDirty[(col-1)/2]) continue; + else patch->colDirty[(col-1)/2] = true; + + // create list for rows of current patch + for(row=0; rowheight; row++) + { + pos = (((col-1)/2)*patch->height)+row; + patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); + patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); + } + + //create connection list for first row + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][0], patch->ctrl[col-1][0], patch->ctrl[col+1][0]); + //create connection list for last row + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][row-1], patch->ctrl[col-1][row-1], patch->ctrl[col+1][row-1]); + + LODLists = BTree_AddListToList(LODLists, pBTList); + pBTList = NULL; + } + + pBTList = NULL; + for(row=1; rowheight; row+=2) + { + if (patch->rowDirty[(row-1)/2]) continue; + else patch->rowDirty[(row-1)/2] = true; + + // create list for cols of current patch + for(col=0; colwidth; col++) + { + pos = (((row-1)/2)*patch->width)+col; + patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); + patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); + } + + //create connection list for first col + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[0][row], patch->ctrl[0][row-1], patch->ctrl[0][row+1]); + //create connection list for last col + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col-1][row], patch->ctrl[col-1][row-1], patch->ctrl[col-1][row+1]); + + LODLists = BTree_AddListToList(LODLists, pBTList); + pBTList = NULL; + } + + for (pLists = LODLists; pLists != NULL; pLists=pLists->next) + BTree_ListCurveRecurse(pLists->list); + LODLists = BTree_DeleteListFromList(LODLists); +} + +int Patch_GetCVTangent(vec3_t &v1, vec3_t &p1, vec3_t &p2, vec3_t &p3) +{ + if (VectorCompare(p1, p2)) + { + if (VectorCompare(p1, p3)) + { + return 2; + } + else VectorSubtract(p3, p1, v1); + return 1; + } + else VectorSubtract(p2, p1, v1); + return 0; +} + +void Patch_CVNormal(vec3_t ctrl[3][3], vec3_t &normal) +{ + vec3_t v1, v2, vTemp1, vTemp2; + int a, b; + + a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][0], ctrl[2][0]); + b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[0][1], ctrl[0][2]); + + //Sys_Printf("p1: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f)\n", + // ctrl[0][0][0], ctrl[0][0][1], ctrl[0][0][2], ctrl[0][2][0], ctrl[0][2][1], ctrl[0][2][2], ctrl[2][0][0], ctrl[2][0][1], ctrl[2][0][2]); + + if (a == 2) + { + a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][1], ctrl[1][2]); + } + if (b == 2) + { + b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][1], ctrl[2][1]); + } + + if (a == 2) + { + a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]); + } + if (b == 2) + { + b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]); + } + + CrossProduct(v1, v2, normal); + + + if (normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f) + { + // more degenerate cases + vec3_t pMid; + vec3_t vCurve[3]; + /* + if (VectorCompare(ctrl[0][0], ctrl[2][0])) // endcap left + { + if (VectorCompare(ctrl[0][2], ctrl[1][2])) + { + VectorSubtract(ctrl[2][2], ctrl[0][0], v2); + } + else if (VectorCompare(ctrl[1][2], ctrl[2][2])) + { + VectorSubtract(ctrl[0][2], ctrl[0][0], v2); + } + else + a = Patch_DegenCurve(ctrl[0][2], ctrl[1][2], ctrl[2][2]); + if (a == 0) + { + VectorCopy(ctrl[0][2], vCurve[0]); + VectorCopy(ctrl[1][2], vCurve[1]); + VectorCopy(ctrl[2][2], vCurve[2]); + Patch_BezierInterpolate(vCurve, pMid); + VectorSubtract(pMid, ctrl[0][0], v1); + } + + + } + else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // endcap right + { + + if (VectorCompare(ctrl[2][0], ctrl[2][1])) + { + VectorSubtract(ctrl[2][2], ctrl[0][0], v2); + } + else if (VectorCompare(ctrl[2][1], ctrl[2][2])) + { + VectorSubtract(ctrl[2][0], ctrl[0][0], v2); + } + else + + b = Patch_DegenCurve(ctrl[2][0], ctrl[2][1], ctrl[2][2]); + if (b == 0) + { + VectorCopy(ctrl[2][0], vCurve[0]); + VectorCopy(ctrl[2][1], vCurve[1]); + VectorCopy(ctrl[2][2], vCurve[2]); + Patch_BezierInterpolate(vCurve, pMid); + VectorSubtract(pMid, ctrl[0][0], v2); + } + + } + */ + if (VectorCompare(ctrl[0][0], ctrl[2][0])) // bottom degen + { + Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]); + } + else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // left degen + { + Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]); + } + else if (VectorCompare(ctrl[0][2], ctrl[2][2])) // top degen + { + VectorSubtract(ctrl[2][0], ctrl[0][0], v1); + } + else if (VectorCompare(ctrl[2][0], ctrl[2][2])) // right degen + { + VectorSubtract(ctrl[0][2], ctrl[0][0], v2); + } + else // tangents parallel + { + VectorCopy(v1, vTemp1); + VectorCopy(v2, vTemp2); + VectorNormalize(vTemp1, vTemp1); + VectorNormalize(vTemp2, vTemp2); + if (VectorCompare(vTemp1, vTemp2)) // parallel same way + { + VectorSubtract(ctrl[2][0], ctrl[0][0], vTemp1); + VectorNormalize(vTemp1, vTemp1); + if (VectorCompare(vTemp1, vTemp2)) + { + VectorSubtract(ctrl[0][2], ctrl[0][0], v2); + } + else + { + VectorCopy(vTemp1, v1); + } + } + else // parallel opposite way + { + VectorCopy(ctrl[2][0], vCurve[0]); + VectorCopy(ctrl[1][1], vCurve[1]); + VectorCopy(ctrl[0][2], vCurve[2]); + Patch_BezierInterpolate(vCurve, pMid); + VectorSubtract(pMid, ctrl[0][0], v2); + } + } + + CrossProduct(v1, v2, normal); + } +} + +void Patch_CalcCVNormals(patchMesh_t *patch) +{ + int row, col, i, j, n; + vec3_t ctrl[3][3]; + vec3_t normals[4]; + + for (col=0; colwidth; col+=2) + { + for (row=0; rowheight; row+=2) + { + n=0; + if (col+1 != patch->width && row+1 != patch->height) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col+i][row+j].xyz, ctrl[i][j]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + + if (col-1 >= 0 && row-1 >= 0) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col-i][row-j].xyz, ctrl[i][j]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + if (col-1 >= 0 && row+1 != patch->height) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col-i][row+j].xyz, ctrl[j][i]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + if (col+1 != patch->width && row-1 >= 0) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col+i][row-j].xyz, ctrl[j][i]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + + for (i=0; i<3; i++) + { + if (n == 1) patch->ctrl[col][row].normal[i] = normals[0][i]; + if (n == 2) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i]) / n; + //if (n == 3) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i]) / n; + if (n == 4) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i] + normals[3][i]) / n; + } + VectorNormalize(patch->ctrl[col][row].normal, patch->ctrl[col][row].normal); + //if (!g_PrefsDlg.m_bGLLighting) + // ShadeVertex(patch->ctrl[col][row]); + } + } +} + + +void BTree_SetNormals(BTNode_t *pBT, vec3_t &normal) +{ + if (pBT != NULL) + { + if (pBT->left != NULL && pBT->right != NULL) + { + VectorCopy(normal, pBT->vMid.normal); + //if (!g_PrefsDlg.m_bGLLighting) + // ShadeVertex(pBT->vMid); + } + BTree_SetNormals(pBT->left, normal); + BTree_SetNormals(pBT->right, normal); + } +} + + +void NormalFromPoints(vec3_t p1, vec3_t p2, vec3_t p3, vec3_t &normal, bool flip = false) +{ + vec3_t v1, v2; + + if (flip) + { + VectorSubtract(p2, p3, v1); //p3->p2 + VectorSubtract(p1, p2, v2); //p2->p1 + } + else + { + VectorSubtract(p2, p1, v1); //p1->p2 + VectorSubtract(p3, p2, v2); //p2->p3 + } + CrossProduct(v1, v2, normal); +} + + +void BTree_GenerateNormals(BTNode_t *pBTMid, BTNode_t *pBTLeft, BTNode_t *pBTRight, bool avg, bool flat, bool nomid, bool noleft, bool noright, /*bool endcap, vec3_t &n1, vec3_t &n2,*/ bool flip) +{ + if (pBTMid != NULL) + { + if (pBTMid->left != NULL && pBTMid->right != NULL) + { + vec3_t normal; + + if (noleft) // left curve is degenerate + { + if (nomid) // mid curve is degenerate + { + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + //else if (endcap) + //{ + // VectorCopy(n1, normal); + // NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + //} + else + { + NormalFromPoints(pBTMid->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + } + else if (noright) // right curve is degenerate + { + if (nomid) // mid curve is degenerate + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + //else if (endcap) + //{ + // NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + // VectorCopy(n2, pBTRight->vMid.normal); + //} + else + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTMid->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + } + else + { + if (flat) // all curves are semi-degenerate (flat) or degenerate + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.normal, flip); + } + else + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + } + + VectorNormalize(normal, normal); + if (avg) + for (int i=0; i<3; i++) + pBTLeft->vMid.normal[i] = (normal[i] + pBTLeft->vMid.normal[i]) / 2.0f; + else VectorCopy(normal, pBTLeft->vMid.normal); + + VectorNormalize(pBTLeft->vMid.normal, pBTLeft->vMid.normal); + VectorNormalize(pBTRight->vMid.normal, pBTRight->vMid.normal); + + } + BTree_GenerateNormals(pBTMid->left, pBTLeft->left, pBTRight->left, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip); + BTree_GenerateNormals(pBTMid->right, pBTLeft->right, pBTRight->right, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip); + } +} + + + +void Patch_GenerateLODNormals(patchMesh_t *patch) +{ + int col, row, rowpos, colpos, i; + BTNode_t *tree[2][3]; + int degen[2][3]; + bool rowAvg, colAvg; + + for(col=0; col+2width; col+=2) + { + for(row=0; row+2height; row+=2) + { + if (!patch->colDirty[col/2] && !patch->rowDirty[row/2]) continue; + + rowpos = ((col/2)*patch->height)+row; + colpos = ((row/2)*patch->width)+col; + + if (row==0) rowAvg = false; + else rowAvg = true; + if (col==0) colAvg = false; + else colAvg = true; + + for (i=0; i<3; i++) + { + tree[0][i] = patch->rowLOD[rowpos+i]; + tree[1][i] = patch->colLOD[colpos+i]; + + degen[0][i] = Patch_DegenCurve(patch->ctrl[col][row+i].xyz, patch->ctrl[col+1][row+i].xyz, patch->ctrl[col+2][row+i].xyz); + degen[1][i] = Patch_DegenCurve(patch->ctrl[col+i][row].xyz, patch->ctrl[col+i][row+1].xyz, patch->ctrl[col+i][row+2].xyz); + } + + BTree_GenerateNormals(tree[0][1], tree[0][0], tree[0][2], rowAvg, (degen[1][0] && degen[1][1] && degen[1][2]), degen[0][1] == 2, degen[0][0] == 2, degen[0][2] == 2, /*degen[1][1], patch->ctrl[col][row].normal, patch->ctrl[col][row+2].normal,*/ false); + BTree_GenerateNormals(tree[1][1], tree[1][0], tree[1][2], colAvg, (degen[0][0] && degen[0][1] && degen[0][2]), degen[1][1] == 2, degen[1][0] == 2, degen[1][2] == 2, /*degen[0][1], patch->ctrl[col][row].normal, patch->ctrl[col+2][row].normal,*/ true); + } + } +} + + +void Patch_ClearLODFlags(patchMesh_t *p) +{ + int i; + + for (i=0;i<(p->width-1)/2; i++) + p->colDirty[i] = false; + + for (i=0;i<(p->height-1)/2; i++) + p->rowDirty[i] = false; +} + +// reset the lodDirty flags owned by all patches in the map +// create new LOD trees for all dirty patches, matched with all other patches in the map +void Patch_LODMatchAll() +{ + brush_t *pb, *brushlist; + int i; + + // create LOD tree roots and LOD tree lists for all patches that are dirty + + brushlist = &active_brushes; + for (i=0; i<2; i++) + { + for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next) + { + // create lod for selected patches when patches are filtered + if (pb->bFiltered && (pb->patchBrush && !pb->pPatch->bSelected)) + continue; + if (!pb->patchBrush) + continue; + if (!pb->pPatch->bDirty) + continue; + + Patch_CalcCVNormals(pb->pPatch); + Patch_CreateLODTrees(pb->pPatch); + } + brushlist = &selected_brushes; + } + + brushlist = &active_brushes; + for (i=0; i<2; i++) + { + for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next) + { + if (!pb->patchBrush) + continue; + + if (pb->pPatch->LODUpdated) + Patch_GenerateLODNormals(pb->pPatch); + + Patch_ClearLODFlags(pb->pPatch); + } + brushlist = &selected_brushes; + } + +} + +void Vertex_TransformTexture(drawVert_t *pVert, float fx, float fy, transformtype xform) +{ + switch(xform) + { + case TRANSLATE: + pVert->st[0] += fx; + pVert->st[1] += fy; + break; + case SCALE: + pVert->st[0] *= fx; + pVert->st[1] *= fy; + break; + case ROTATE: + float x = pVert->st[0]; + float y = pVert->st[1]; + pVert->st[0] = x * fx - y * fy; + pVert->st[1] = y * fx + x * fy; + } +} + +void BTree_TransformTexture(BTNode_t *pBT, float fx, float fy, transformtype xform) +{ + if (pBT != NULL) + { // PreOrder traversal + Vertex_TransformTexture(&pBT->info, fx, fy, xform); + Vertex_TransformTexture(&pBT->vMid, fx, fy, xform); + BTree_TransformTexture(pBT->left, fx, fy, xform); + BTree_TransformTexture(pBT->right, fx, fy, xform); + } +} + +void Patch_TransformLODTexture(patchMesh_t *p, float fx, float fy, transformtype xform) +{ + int col, row; + + for(col=1; colwidth; col+=2) + for(row=0; rowheight; row++) + BTree_TransformTexture(p->rowLOD[(((col-1)/2)*p->height)+row], fx, fy, xform); + + for(row=1; rowheight; row+=2) + for(col=0; colwidth; col++) + BTree_TransformTexture(p->colLOD[(((row-1)/2)*p->width)+col], fx, fy, xform); +} + +void Patch_AddBTreeToDrawListInOrder(list *drawList, BTNode_t *pBT) +{ + if (pBT != NULL) //traverse InOrder + { + Patch_AddBTreeToDrawListInOrder(drawList, pBT->left); + if (pBT->left != NULL && pBT->right != NULL) + drawList->push_back(pBT->vMid); + Patch_AddBTreeToDrawListInOrder(drawList, pBT->right); + } +} + +void Patch_InterpolateListFromRowBT(list *drawList, BTNode_t *rowBT, BTNode_t *rowBTLeft, drawVert_t *vCurve[], float u, float n, float v) +{ + if (rowBT != NULL) + { + Patch_InterpolateListFromRowBT(drawList, rowBT->left, rowBTLeft->left, vCurve, u-n, n*0.5f, v); + if (rowBT->left != NULL && rowBT->right != NULL) + { + vec3_t v1, v2; + drawVert_t newVert, vTemp1, vTemp2; + Patch_CurveSplit(vCurve, vTemp1, vTemp2, newVert, u); + for (int i=0; i<3; i++) + { + v1[i] = rowBT->vMid.xyz[i] - rowBTLeft->vMid.xyz[i]; // left -> mid + v1[i] = rowBTLeft->vMid.xyz[i] + (v1[i] * v); + v1[i] = newVert.xyz[i] - v1[i]; + } + VectorSubtract(vTemp1.xyz, newVert.xyz, v2); + CrossProduct(v1, v2, newVert.normal); + VectorNormalize(newVert.normal, newVert.normal); + //if (!g_PrefsDlg.m_bGLLighting) + // ShadeVertex(newVert); + drawList->push_back(newVert); + } + Patch_InterpolateListFromRowBT(drawList, rowBT->right, rowBTLeft->right, vCurve, u+n, n*0.5f, v); + } +} + +void Patch_TraverseColBTInOrder(list*>::iterator& iter, BTNode_t *colBTLeft, BTNode_t *colBT, BTNode_t *colBTRight, BTNode_t *rowBT, BTNode_t *rowBTLeft, float v, float n) +{ + if (colBT != NULL) + { + //traverse subtree In Order + Patch_TraverseColBTInOrder(iter, colBTLeft->left, colBT->left, colBTRight->left, rowBT, rowBTLeft, v-n, n*0.5f); + if (colBT->left != NULL && colBT->right != NULL) + { + drawVert_t *vCurve[3]; + vCurve[0] = &colBTLeft->vMid; + vCurve[1] = &colBT->vMid; + vCurve[2] = &colBTRight->vMid; + Patch_InterpolateListFromRowBT((*iter), rowBT, rowBTLeft, vCurve, 0.5f, 0.25f, v); + + (*iter)->push_back(colBTRight->vMid); + iter++; + } + Patch_TraverseColBTInOrder(iter, colBTLeft->right, colBT->right, colBTRight->right, rowBT, rowBTLeft, v+n, n*0.5f); + } +} + + +void Patch_StartDrawLists(list*> *drawLists, BTNode_t *colBT) +{ + if (colBT != NULL) + { + //traverse subtree In Order + Patch_StartDrawLists(drawLists, colBT->left); + if (colBT->left != NULL && colBT->right != NULL) + { + list *newList = new list; + drawLists->push_back(newList); // add empty list to back + drawLists->back()->push_back(colBT->vMid); + } + Patch_StartDrawLists(drawLists, colBT->right); + } +} + +typedef list drawList_t; +typedef list*> drawLists_t; + +void Patch_CreateDrawLists(patchMesh_t *patch) +{ + int col, row, colpos, rowpos; + + drawLists_t *drawLists = new drawLists_t; + + drawLists_t::iterator iter1, iter2; + + for (row=0; rowheight; row+=2) + { + colpos = (row/2)*patch->width; + drawList_t *newList = new drawList_t; + drawLists->push_back(newList); // add a new empty list to back + drawLists->back()->push_back(patch->ctrl[0][row]); // fill list at back + + if (row+1 == patch->height) + continue; + Patch_StartDrawLists(drawLists, patch->colLOD[colpos]); + } + + iter1 = drawLists->begin(); + for (row=0; rowheight; row+=2) + { + iter2 = iter1; + for (col=0; col+1width; col+=2) + { + iter1 = iter2; + colpos = ((row/2)*patch->width)+col; + rowpos = ((col/2)*patch->height)+row; + + Patch_AddBTreeToDrawListInOrder((*iter1), patch->rowLOD[rowpos]); + (*iter1)->push_back(patch->ctrl[col+2][row]); + + if (row+1 == patch->height) + continue; + + iter1++; + + Patch_TraverseColBTInOrder(iter1, patch->colLOD[colpos], patch->colLOD[colpos+1], patch->colLOD[colpos+2], patch->rowLOD[rowpos+1], patch->rowLOD[rowpos], 0.5, 0.25); + } + } + + patch->drawLists = drawLists; +} + + +void Patch_DeleteDrawLists(patchMesh_t *patch) +{ + drawLists_t *drawLists; + drawLists_t::iterator iter; + + if (patch->drawLists == NULL) + return; + + drawLists = (drawLists_t *)patch->drawLists; + + for (iter=drawLists->begin(); iter != drawLists->end(); iter++) + { + delete (*iter); + } + + delete drawLists; + patch->drawLists = NULL; +} + + +void Patch_DrawLODPatchMesh(patchMesh_t *patch) +{ + drawLists_t *drawLists; + + drawLists_t::iterator iterLists, iterListsNext; + drawList_t::iterator iterList, iterListNext; + + //int nGLState = g_pParentWnd->GetCamera()->Camera()->draw_glstate; + + if (patch->drawLists == NULL) + return; + + drawLists = (drawLists_t *)patch->drawLists; + + iterListsNext=drawLists->begin(); + iterListsNext++; + for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++) + { + // traverse two drawlists at once to draw a strip + //if (nGLState & DRAW_GL_LINE) + qglBegin(GL_QUAD_STRIP); + //else + // qglBegin(GL_TRIANGLE_STRIP); + for (iterList=(*iterLists)->begin(), iterListNext=(*iterListsNext)->begin(); iterList != (*iterLists)->end() && iterListNext != (*iterListsNext)->end(); iterList++, iterListNext++) + { + //if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv((*iterList).normal); + //else if (bShade && !g_PrefsDlg.m_bDisplayLists) + // qglColor3f((*iterList).lightmap[0], (*iterList).lightmap[0], (*iterList).lightmap[0]); + + qglTexCoord2fv((*iterList).st); + qglVertex3fv((*iterList).xyz); + + //if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv((*iterListNext).normal); + //else if (bShade && !g_PrefsDlg.m_bDisplayLists) + // qglColor3f((*iterListNext).lightmap[0], (*iterListNext).lightmap[0], (*iterListNext).lightmap[0]); + + qglTexCoord2fv((*iterListNext).st); + qglVertex3fv((*iterListNext).xyz); + } + qglEnd(); + } +/* +#ifdef _DEBUG + vec3_t vNormal; + for (iterLists=drawLists->begin(); iterLists != drawLists->end(); iterLists++) + { + qglBegin (GL_LINES); // draw normals + //qglColor3f(1,1,1); + for (iterList=(*iterLists)->begin(); iterList != (*iterLists)->end(); iterList++) + { + VectorAdd((*iterList).xyz, (*iterList).normal, vNormal); + qglVertex3fv ((*iterList).xyz); + qglVertex3fv (vNormal); + } + qglEnd (); + } + + Patch_DrawNormals(patch); + +#endif + */ +} + +/* +// fast memory-efficient ray-triangle intersection - MollerTrumbore97 + +#define EPSILON 0.000001 +#define CROSS(dest,v1,v2) {dest[0]=v1[1]*v2[2]-v1[2]*v2[1];dest[1]=v1[2]*v2[0]-v1[0]*v2[2];dest[2]=v1[0]*v2[1]-v1[1]*v2[0];} +#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) +#define SUB(dest,v1,v2) {dest[0]=v1[0]-v2[0];dest[1]=v1[1]-v2[1];dest[2]=v1[2]-v2[2];} + +int intersect_triangle(float orig[3], float dir[3], + float vert0[3], float vert1[3], float vert2[3], + double *t, double *u, double *v) +{ + double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + // find vectors for two edges sharing vert0 + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + + // begin calculating determinant - also used to calculate U parameter + CROSS(pvec, dir, edge2); + + // if determinant is near zero, ray lies in plane of triangle + det = DOT(edge1, pvec); + +#ifdef TEST_CULL // define TEST_CULL if culling is desired + if (det < EPSILON) + return 0; + + // calculate distance from vert0 to ray origin + SUB(tvec, orig, vert0); + + // calculate U parameter and test bounds + *u = DOT(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + // prepare to test V parameter + CROSS(qvec, tvec, edge1); + + // calculate V parameter and test bounds + *v = DOT(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + // calculate t, scale parameters, ray intersects triangle + *t = DOT(edge2, qvec); + inv_det = 1.0 / det; + *t *= inv_det; + *u *= inv_det; + *v *= inv_det; +#else // the non-culling branch + if (det > -EPSILON && det < EPSILON) + return 0; + inv_det = 1.0 / det; + + // calculate distance from vert0 to ray origin + SUB(tvec, orig, vert0); + + // calculate U parameter and test bounds + *u = DOT(tvec, pvec) * inv_det; + if (*u < 0.0 || *u > 1.0) + return 0; + + // prepare to test V parameter + CROSS(qvec, tvec, edge1); + + // calculate V parameter and test bounds + *v = DOT(dir, qvec) * inv_det; + if (*v < 0.0 || *u + *v > 1.0) + return 0; + + // calculate t, ray intersects triangle + *t = DOT(edge2, qvec) * inv_det; +#endif + return 1; +} +*/ + +int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, + float vert0[3], float vert1[3], float vert2[3], + double *t, double *u, double *v) +{ + float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + /* find vectors for two edges sharing vert0 */ + VectorSubtract(vert1, vert0, edge1); + VectorSubtract(vert2, vert0, edge2); + + /* begin calculating determinant - also used to calculate U parameter */ + CrossProduct(dir, edge2, pvec); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = DotProduct(edge1, pvec); + + if (bCullBack) + { + if (det < 0.000001) + return 0; + + // calculate distance from vert0 to ray origin + VectorSubtract(orig, vert0, tvec); + + // calculate U parameter and test bounds + *u = DotProduct(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + // prepare to test V parameter + CrossProduct(tvec, edge1, qvec); + + // calculate V parameter and test bounds + *v = DotProduct(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + // calculate t, scale parameters, ray intersects triangle + *t = DotProduct(edge2, qvec); + inv_det = 1.0 / det; + *t *= inv_det; + *u *= inv_det; + *v *= inv_det; + } + else + { + /* the non-culling branch */ + if (det > -0.000001 && det < 0.000001) + return 0; + inv_det = 1.0 / det; + + /* calculate distance from vert0 to ray origin */ + VectorSubtract(orig, vert0, tvec); + + /* calculate U parameter and test bounds */ + *u = DotProduct(tvec, pvec) * inv_det; + if (*u < 0.0 || *u > 1.0) + return 0; + + /* prepare to test V parameter */ + CrossProduct(tvec, edge1, qvec); + + /* calculate V parameter and test bounds */ + *v = DotProduct(dir, qvec) * inv_det; + if (*v < 0.0 || *u + *v > 1.0) + return 0; + + /* calculate t, ray intersects triangle */ + *t = DotProduct(edge2, qvec) * inv_det; + } + return 1; +} + +bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v) +{ + drawLists_t *drawLists; + + drawLists_t::iterator iterLists, iterListsNext; + drawList_t::iterator i1, i2, i3, i4; + +// vec3_t tris[2][3]; + bool bIntersect = false; + float tBest = FLT_MAX; + + if (patch->drawLists == NULL) + return false; + + drawLists = (drawLists_t *)patch->drawLists; + + iterListsNext=drawLists->begin(); + iterListsNext++; + for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++) + { + // traverse two drawlists at once with two iterators each to triangulate + i1 = i3 = (*iterLists)->begin(); + i2 = i4 = (*iterListsNext)->begin(); + i3++; + i4++; + while (i3 != (*iterLists)->end() && i4 != (*iterListsNext)->end()) + { + if (Triangle_Ray(origin, dir, false, (*i1).xyz, (*i2).xyz, (*i3).xyz, t, u, v)) + { + bIntersect = true; + if (*t < tBest) + tBest = *t; + } + if (Triangle_Ray(origin, dir, false, (*i3).xyz, (*i4).xyz, (*i2).xyz, t, u, v)) + { + bIntersect = true; + if (*t < tBest) + tBest = *t; + } + i1++; + i2++; + i3++; + i4++; + } + } + if (bIntersect) + { + *t = tBest; + return true; + } + else + { + *t = 0; + return false; + } +} + +// spog - curve LOD stuff ends + +/* +================= +DrawPatchMesh +================= +*/ +void DrawPatchMesh(patchMesh_t *pm) +{ + if (g_PrefsDlg.m_bDisplayLists) + { + if (pm->bDirty || pm->nListID <= 0 || pm->LODUpdated) + { + if (pm->nListID <= 0) + pm->nListID = qglGenLists(1); + if (pm->nListID > 0) + { + qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE); + } + + Patch_DeleteDrawLists(pm); + Patch_CreateDrawLists(pm); + + Patch_DrawLODPatchMesh(pm); + + if (pm->nListID > 0) + { + qglEndList(); + } + + pm->bDirty = false; + pm->LODUpdated = false; + } + else + { + qglCallList(pm->nListID); + } + } + else + { + if (pm->bDirty || pm->LODUpdated) + { + Patch_DeleteDrawLists(pm); + Patch_CreateDrawLists(pm); + pm->bDirty = false; + pm->LODUpdated = false; + } + Patch_DrawLODPatchMesh(pm); + } +} + +/* +================= +DrawPatchControls +================= +*/ +void DrawPatchControls(patchMesh_t *pm) +{ + int i, j; + bool bSelectedPoints[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + + bool bOverlay = pm->bOverlay; + + // bending + if (g_bPatchBendMode) + { + qglPointSize(6); + if (g_bPatchAxisOnRow) + { + qglColor3f(1, 0, 1); + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglBegin(GL_POINTS); + for (i = 0; i < pm->width; i++) + { + qglVertex3fv(pm->ctrl[i][g_nPatchAxisIndex].xyz); + } + qglEnd(); + } + else + { + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->width; i++) + { + DrawAlternatePoint(pm->ctrl[i][g_nPatchAxisIndex].xyz, 0); + } + qglEnd(); + qglLineWidth(1.0); + } + + if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglColor3f(0, 0, 1); + qglBegin(GL_POINTS); + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + qglVertex3fv(g_vBendOrigin); + } + else + { + for (i = 0; i < pm->width; i++) + { + if (g_bPatchLowerEdge) + { + for (j = 0; j < g_nPatchAxisIndex; j++) + qglVertex3fv(pm->ctrl[i][j].xyz); + } + else + { + for (j = pm->height-1; j > g_nPatchAxisIndex; j--) + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + } + qglEnd(); + } + else { + qglColor3f(0, 0, 1); + qglLineWidth(2.0); + qglBegin(GL_LINES); + if(g_nPatchBendState == BEND_SELECT_ORIGIN) + { + DrawAlternatePoint(g_vBendOrigin, 0); + } + else + { + for(i = 0; i < pm->width; i++) + { + if(g_bPatchLowerEdge) + { + for(j = 0; j < g_nPatchAxisIndex; j++) + { + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + else + { + for (j = pm->height-1; j > g_nPatchAxisIndex; j--) + { + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + } + else + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglColor3f(1, 0, 1); + qglBegin(GL_POINTS); + for (i = 0; i < pm->height; i++) + { + qglVertex3fv(pm->ctrl[g_nPatchAxisIndex][i].xyz); + } + qglEnd(); + } + else { + qglColor3f(1, 0, 1); + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->height; i++) + { + DrawAlternatePoint(pm->ctrl[g_nPatchAxisIndex][i].xyz, 0); + } + qglEnd(); + qglLineWidth(1.0); + } + + if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglColor3f(0, 0, 1); + qglBegin(GL_POINTS); + for (i = 0; i < pm->height; i++) + { + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + qglVertex3fv(pm->ctrl[g_nBendOriginIndex][i].xyz); + } + else + { + if (g_bPatchLowerEdge) + { + for (j = 0; j < g_nPatchAxisIndex; j++) + qglVertex3fv(pm->ctrl[j][i].xyz); + } + else + { + for (j = pm->width-1; j > g_nPatchAxisIndex; j--) + qglVertex3fv(pm->ctrl[j][i].xyz); + } + } + } + qglEnd(); + } + else { + qglColor3f(0, 0, 1); + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->height; i++) + { + if(g_nPatchBendState == BEND_SELECT_ORIGIN) + { + DrawAlternatePoint(pm->ctrl[g_nBendOriginIndex][i].xyz, 0); + } + else + { + if(g_bPatchLowerEdge) + { + for(j = 0; j < g_nPatchAxisIndex; j++) + { + DrawAlternatePoint(pm->ctrl[j][i].xyz, 0); + } + } + else + { + for(j = pm->width-1; j > g_nPatchAxisIndex; j--) + { + DrawAlternatePoint(pm->ctrl[j][i].xyz, 0); + } + } + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + } + } + else + { + //qglDisable(GL_TEXTURE_2D); // stops point colours being multiplied by texture colour.. + //draw CV lattice - could be made optional + //qglDisable( GL_CULL_FACE ); + // qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglEnable (GL_POLYGON_OFFSET_LINE); + if (g_PrefsDlg.m_bNoStipple == FALSE) + qglDisable (GL_LINE_STIPPLE); + qglLineWidth (1); + qglColor3f(1.0f, 0.75f, 0.0f); + for ( i = 0 ; i+1 < pm->width ; i++ ) + { + qglBegin(GL_QUAD_STRIP); + for ( j = 0 ; j < pm->height ; j++ ) + { + qglVertex3fv(pm->ctrl[i][j].xyz); + qglVertex3fv(pm->ctrl[i+1][j].xyz); + } + qglEnd(); + } + qglDisable (GL_POLYGON_OFFSET_LINE); + //if (g_PrefsDlg.m_bNoStipple == FALSE) + // qglEnable (GL_LINE_STIPPLE); + + // draw selection handles + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglPointSize(6); + qglBegin(GL_POINTS); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (PointInMoveList(pm->ctrl[i][j].xyz) != -1) + { + bSelectedPoints[i][j] = true; + } + else + { + bSelectedPoints[i][j] = false; + if (i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + } + qglColor3f(0, 0, 1); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (bSelectedPoints[i][j]) + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + qglEnd(); + } + else + { + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->width; i++) + { + for(j = 0; j < pm->height; j++) + { + if(PointInMoveList(pm->ctrl[i][j].xyz) != -1) + { + bSelectedPoints[i][j] = true; + } + else + { + bSelectedPoints[i][j] = false; + if(i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + + // draw verts + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + } + qglColor3f(0, 0, 1); + for(i = 0; i < pm->width; i++) + { + for(j = 0; j < pm->height; j++) + { + if(bSelectedPoints[i][j]) + { + // draw verts + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + if (bOverlay) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglPointSize(6); + qglBegin(GL_POINTS); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + qglEnd(); + } + else + { + qglLineWidth(2.0); + qglBegin(GL_LINES); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + // draw verts + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + //qglPopAttrib(); +} + +/* +================== +Patch_DrawXY +================== +*/ +void Patch_DrawXY(patchMesh_t *pm) +{ + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + if (pm->bSelected) + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); + if (g_PrefsDlg.m_bNoStipple == FALSE) + qglEnable (GL_LINE_STIPPLE); + qglLineWidth (2); + } + + DrawPatchMesh(pm); + + if ( (pm->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint + || g_qeglobals.d_select_mode == sel_area + || g_bPatchBendMode)) + || pm->bOverlay ) + DrawPatchControls(pm); +} + +/* +================== +Patch_DrawCam +================== +*/ +void Patch_DrawCam(patchMesh_t *pm) +{ + qglPushAttrib(GL_ALL_ATTRIB_BITS); // save the current state + + if (g_bPatchWireFrame) + { + qglDisable( GL_CULL_FACE ); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglDisable(GL_TEXTURE_2D); + if (g_PrefsDlg.m_bGLLighting) + qglDisable(GL_LIGHTING); + + DrawPatchMesh(pm); + + //if (g_PrefsDlg.m_bGLLighting) + // qglEnable(GL_LIGHTING); + //qglEnable( GL_CULL_FACE ); + } + else + { + qglDisable(GL_CULL_FACE); + qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number); + qglPolygonMode (GL_FRONT, GL_FILL); + qglPolygonMode (GL_BACK, GL_LINE); + + if (pm->pShader->getTrans() < 1.0f) + { + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->pShader->getTrans()); + } + + DrawPatchMesh(pm); // both sides + } + + qglPopAttrib(); // restore saved state +} + +void ConvexHullForSection( float section[2][4][7] ) { +} + +void BrushesForSection( float section[2][4][7] ) { +} + +/* +================ +Patch_BuildPoints +================ +*/ +void Patch_BuildPoints (brush_t *b) +{ + face_t *f; + b->patchBrush = false; + for (f=b->brush_faces ; f ; f=f->next) + { + if (f->texdef.flags & SURF_PATCH) + { + b->patchBrush = true; + //vec3_t vMin, vMax; + //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax); + //VectorCopy(vMin, b->mins); + //VectorCopy(vMax, b->maxs); + break; + } + } +} + +/* +================== +Patch_Move +================== +*/ +void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild) +{ + pm->bDirty = true; + for (int w = 0; w < pm->width; w++) + { + for (int h = 0; h < pm->height; h++) + { + VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz); + } + } + // bRebuild is never true + if (bRebuild) + { + vec3_t vMin, vMax; + Patch_CalcBounds(pm, vMin, vMax); + //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax); + } + UpdatePatchInspector(); + +} + +/* +================== +Patch_ApplyMatrix +================== +*/ +void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap) +{ + vec3_t vTemp; + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode) + && PointInMoveList(p->ctrl[w][h].xyz) == -1) // snap selected points only, if selected + continue; + VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp); + for (int j = 0; j < 3; j++) + { + p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j]; + if (bSnap) + { + p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5); + } + } + } + } + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); +} + +/* +================== +Patch_EditPatch +================== +*/ +void Patch_EditPatch() +{ + //--patchMesh_t* p = &patchMeshes[n]; + g_qeglobals.d_numpoints = 0; + g_qeglobals.d_num_move_points = 0; + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + if (g_qeglobals.d_numpoints < MAX_POINTS-1) + { + g_qeglobals.d_numpoints++; + } + } + } + } + } + g_qeglobals.d_select_mode = sel_curvepoint; + //--g_nSelectedPatch = n; +} + + + +/* +================== +Patch_Deselect +================== +*/ +//FIXME: need all sorts of asserts throughout a lot of this crap +void Patch_Deselect() +{ + //--g_nSelectedPatch = -1; + g_qeglobals.d_select_mode = sel_brush; + + for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (b->patchBrush) + { + b->pPatch->bSelected = false; + } + } + + //for (int i = 0; i < numPatchMeshes; i++) + // patchMeshes[i].bSelected = false; + + if (g_bPatchBendMode) + Patch_BendToggle(); +// if (g_bPatchInsertMode) +// Patch_InsDelToggle(); +} + + +/* +================== +Patch_Select +================== +*/ +void Patch_Select(patchMesh_t *p) +{ + // maintained for point manip.. which i need to fix as this + // is pf error prone + //--g_nSelectedPatch = n; + p->bSelected = true; +} + + +/* +================== +Patch_Deselect +================== +*/ +void Patch_Deselect(patchMesh_t *p) +{ + p->bSelected = false; +} + + +/* +================== +Patch_Delete +================== +*/ +extern BTNode_t *BTree_Delete(BTNode_t *pBT); +extern BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList); + +void Patch_Delete(patchMesh_t *p) +{ + if (p->pSymbiot) // Hydra - added a check to prevent access violations. + { + p->pSymbiot->pPatch = NULL; + p->pSymbiot->patchBrush = false; + } + + // spog - free dynamically allocated memory used by LODs + int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT; + int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH; + int i; + for (i=0; irowLOD[i] = BTree_Delete(p->rowLOD[i]); + for (i=0; icolLOD[i] = BTree_Delete(p->colLOD[i]); + + // delete display list associated with patch + if (p->nListID != -1) + qglDeleteLists (p->nListID, 1); // list#, number of lists + + // delete LOD drawLists + Patch_DeleteDrawLists(p); + + + free(p); + p = NULL; + + + UpdatePatchInspector(); +} + + +/* +================== +Patch_Scale +================== +*/ +void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild) +{ + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + continue; + for (int i=0 ; i<3 ; i++) + { + p->ctrl[w][h].xyz[i] -= vOrigin[i]; + p->ctrl[w][h].xyz[i] *= vAmt[i]; + p->ctrl[w][h].xyz[i] += vOrigin[i]; + } + } + } + if (bRebuild) + { + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + } + UpdatePatchInspector(); +} + + +/* +================== +Patch_SetView +================== +*/ +void Patch_SetView(int n) +{ + g_bSameView = (n == g_nPatchClickedView); + g_nPatchClickedView = n; +} + + +/* +================== +Patch_SetTexture +================== +*/ +// FIXME: need array validation throughout +void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef) +{ + // NOTE: I don't know for sure if this happens + if (p->pShader) + p->pShader->DecRef(); + p->pShader = QERApp_Shader_ForName(tex_def->GetName()); + p->pShader->IncRef(); + p->d_texture = p->pShader->getTexture(); + + UpdatePatchInspector(); +} + + +/* +================== +Patch_DragScale +================== +*/ +bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove) +{ + vec3_t vMin, vMax, vScale, vTemp, vMid; + int i; + + Patch_CalcBounds(p, vMin, vMax); + + VectorSubtract(vMax, vMin, vTemp); + + // if we are scaling in the same dimension the patch has no depth + for (i = 0; i < 3; i ++) + { + if (vTemp[i] == 0 && vMove[i] != 0) + { + //Patch_Move(n, vMove, true); + return false; + } + } + + for (i=0 ; i<3 ; i++) + vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2)); + + for (i = 0; i < 3; i++) + { + if (vAmt[i] != 0) + { + vScale[i] = 1.0 + vAmt[i] / vTemp[i]; + } + else + { + vScale[i] = 1.0; + } + } + + Patch_Scale(p, vMid, vScale, false); + + VectorSubtract(vMax, vMin, vTemp); + + Patch_CalcBounds(p, vMin, vMax); + + VectorSubtract(vMax, vMin, vMid); + + VectorSubtract(vMid, vTemp, vTemp); + + VectorScale(vTemp, 0.5, vTemp); + + // abs of both should always be equal + if (!VectorCompare(vMove, vAmt)) + { + for (i = 0; i < 3; i++) + { + if (vMove[i] != vAmt[i]) + vTemp[i] = -(vTemp[i]); + } + } + + Patch_Move(p, vTemp); + return true; +} + +/* +================== +Patch_InsertColumn +================== +*/ +void Patch_InsertColumn(patchMesh_t *p, bool bAdd) +{ + int w, h, i, width; + vec3_t vTemp; + float stTemp[2]; + + if (p->width + 2 >= MAX_PATCH_WIDTH) + return; + + // check for selected column points + for (h = 0; h < p->height; h++) + { + for (w = 1; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + for (w = 0; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + } + + if (w >= p->width) + { + if (bAdd) w=p->width-1; + else w=2; + } + else if (w==0) w=2; + else if (w%2) w++; + + // add columns at w + for (h = 0; h < p->height; h++) + { + for (width = p->width-1; width > w; width--) + memcpy(&p->ctrl[width+2][h],&p->ctrl[width][h], sizeof(drawVert_t)); + + // set two new column points + memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t)); + memcpy(&p->ctrl[w+1][h],&p->ctrl[w-1][h], sizeof(drawVert_t)); + + for (i=0; i<3; i++) // xyz + { + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w+1][h].xyz[i] = p->ctrl[w+1][h].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w-2][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w+1][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2); + } + for (i=0; i<2; i++) // st + { + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w+1][h].st[i] = p->ctrl[w+1][h].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w-2][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w+1][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2); + } + } + + p->width += 2; + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_InsertRow +================== +*/ + +void Patch_InsertRow(patchMesh_t *p, bool bAdd) +{ + int h, w, i, height; + vec3_t vTemp; + float stTemp[2]; + + if (p->height + 2 >= MAX_PATCH_HEIGHT) + return; + + // check for selected row points + for (w = 0; w < p->width; w++) + { + for (h = 1; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + for (h = 0; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + } + if (h >= p->height) + { + if (bAdd) h=p->height-1; + else h=2; + } + else if (h==0) h=2; + else if (h%2) h++; + + // add rows at h + for (w = 0; w < p->width; w++) + { + for (height = p->height-1; height > h; height--) + memcpy(&p->ctrl[w][height+2],&p->ctrl[w][height], sizeof(drawVert_t)); + + // set two new row points + memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t)); + memcpy(&p->ctrl[w][h+1],&p->ctrl[w][h-1], sizeof(drawVert_t)); + + for (i=0; i<3; i++) // xyz + { + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h+1].xyz[i] = p->ctrl[w][h+1].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h-2].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h+1].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2); + } + for (i=0; i<2; i++) // st + { + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h+1].st[i] = p->ctrl[w][h+1].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h-2].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h+1].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2); + } + } + + p->height += 2; + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_RemoveRow +================== +*/ +void Patch_RemoveRow(patchMesh_t *p, bool bFirst) +{ + int w, h, i, height; + vec3_t vTemp; + float stTemp[2]; + bool bExtrapolate = true; + + if (p->height <= MIN_PATCH_HEIGHT) + return; + + for (w = 0; w < p->width; w++) + { + for (h = 0; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + for (h = 1; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + } + + if (h >= p->height) + { + bExtrapolate = false; + if (bFirst) h=p->height-3; + else h=2; + } + else if (h <= 0) h=2; + else if (h > p->height-3) h = p->height-3; + else if (h%2) h++; + + p->height -= 2; + + for (w = 0; w < p->width; w++) + { + if (bExtrapolate) + { + for (i = 0; i < 3; i++) // xyz + { + vTemp[i] = p->ctrl[w][h+2].xyz[i] - p->ctrl[w][h-2].xyz[i]; + p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-2].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] * 2); + } + + for (i = 0; i < 2; i++) // st + { + stTemp[i] = p->ctrl[w][h+2].st[i] - p->ctrl[w][h-2].st[i]; + p->ctrl[w][h-1].st[i] = p->ctrl[w][h-2].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] * 2); + } + } + else + { + if (!bFirst) + continue; + else h=0; + } + for (height = h; height < p->height; height++) + memcpy(&p->ctrl[w][height], &p->ctrl[w][height+2], sizeof(drawVert_t)); + } + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_RemoveColumn +================== +*/ +void Patch_RemoveColumn(patchMesh_t *p, bool bFirst) +{ + int w, h, i, width; + vec3_t vTemp; + float stTemp[2]; + bool bExtrapolate = true; + + if (p->width <= MIN_PATCH_WIDTH) + return; + + for (h = 0; h < p->height; h++) + { + for (w = 0; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + for (w = 1; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + } + + if (w >= p->width) + { + bExtrapolate = false; + if (bFirst) w=p->width-3; + else w=2; + } + else if (w<=0) w=2; + else if (w > p->width-3) w = p->width-3; + else if (w%2) w++; + + p->width -= 2; + + for (h = 0; h < p->height; h++) + { + if (bExtrapolate) + { + for (i = 0; i < 3; i++) // xyz + { + vTemp[i] = p->ctrl[w+2][h].xyz[i] - p->ctrl[w-2][h].xyz[i]; + p->ctrl[w-1][h].xyz[i] = p->ctrl[w-2][h].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] * 2); + } + + for (i = 0; i < 2; i++) // st + { + stTemp[i] = p->ctrl[w+2][h].st[i] - p->ctrl[w-2][h].st[i]; + p->ctrl[w-1][h].st[i] = p->ctrl[w-2][h].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] * 2); + } + } + else + { + if (!bFirst) + continue; + else w=0; + } + + for (width = w; width < p->width; width++) + memcpy(&p->ctrl[width][h], &p->ctrl[width+2][h], sizeof(drawVert_t)); + } + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_AdjustColumns +================== +*/ +/* +void Patch_AdjustColumns(patchMesh_t *p, int nCols) +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH) + return; + + // add in column adjustment + p->width += nCols; + + for (h = 0; h < p->height; h++) + { + // for each column, we need to evenly disperse p->width number + // of points across the old bounds + + // calc total distance to interpolate + VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp); + + // amount per cycle + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / (p->width - 1); + } + + // move along + for (w = 0; w < p->width-1; w++) + { + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz); + } + + } + for ( w = 0 ; w < p->width ; w++ ) + { + for ( h = 0 ; h < p->height ; h++ ) + { + p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1); + p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1); + } + } + UpdatePatchInspector(); +} +*/ + +/* +================== +Patch_AdjustRows +================== +*/ +/* +void Patch_AdjustRows(patchMesh_t *p, int nRows) +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT) + return; + + // add in column adjustment + p->height += nRows; + + for (w = 0; w < p->width; w++) + { + // for each row, we need to evenly disperse p->height number + // of points across the old bounds + + // calc total distance to interpolate + VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp); + + //vTemp[0] = vTemp[1] = vTemp[2] = 0; + //for (h = 0; h < p->height - nRows; h ++) + //{ + // VectorAdd(vTemp, p->ctrl[w][h], vTemp); + //} + + // amount per cycle + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / (p->height - 1); + } + + // move along + for (h = 0; h < p->height-1; h++) + { + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); + } + + } + for ( w = 0 ; w < p->width ; w++ ) + { + for ( h = 0 ; h < p->height ; h++ ) + { + p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1); + p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1); + } + } + UpdatePatchInspector(); +} +*/ + +/* +================== +Patch_DisperseRows +================== +*/ + +void Patch_DisperseRows() +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_Rebuild(p); + for (w = 0; w < p->width; w++) + { + // for each row, we need to evenly disperse p->height number + // of points across the old bounds + + // calc total distance to interpolate + VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp); + + //vTemp[0] = vTemp[1] = vTemp[2] = 0; + //for (h = 0; h < p->height - nRows; h ++) + //{ + // VectorAdd(vTemp, p->ctrl[w][h], vTemp); + //} + + // amount per cycle + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / (p->height - 1); + } + + // move along + for (h = 0; h < p->height-1; h++) + { + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); + } + Patch_Naturalize(p); + + } + } + } + UpdatePatchInspector(); +} + +/* +================== +Patch_DisperseIntermediateRows +================== +*/ + +void Patch_DisperseIntermediateRows() +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_Rebuild(p); + for (w = 0; w < p->width; w++) + { + // move along + for (h = 0; h < p->height; h+=2) + { + // calc distance to interpolate + VectorSubtract(p->ctrl[w][h+2].xyz, p->ctrl[w][h].xyz, vTemp); + + // halve distance + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / 2; + } + + // move control points + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); + } + } + } + } + UpdatePatchInspector(); +} + +/* +================== +Patch_DisperseIntermediateColumns +================== +*/ +void Patch_DisperseIntermediateColumns() +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_Rebuild(p); + for (h = 0; h < p->height; h++) + { + // move along + for (w = 0; w < p->width; w+=2) + { + // calc distance to interpolate + VectorSubtract(p->ctrl[w+2][h].xyz, p->ctrl[w][h].xyz, vTemp); + + // halve distance + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / 2; + } + + // move control points + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz); + } + } + } + } + UpdatePatchInspector(); +} + + + +/* +================== +Patch_AdjustSelected +================== +*/ +void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag) +{ + bool bUpdate = false; + for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (bInsert) + { + if (bColumn) + { + Patch_InsertColumn(pb->pPatch, bFlag); + } + else + { + Patch_InsertRow(pb->pPatch, bFlag); + } + } + else + { + if (bColumn) + { + Patch_RemoveColumn(pb->pPatch, bFlag); + } + else + { + Patch_RemoveRow(pb->pPatch, bFlag); + } + } + bUpdate = true; + vec3_t vMin, vMax; + patchMesh_t *p = pb->pPatch; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + pb->pPatch->bDirty = true; // rebuild LOD trees and their normals + } + } + if (bUpdate) + { + Sys_UpdateWindows(W_ALL); + } +} + + +/* +================== +Patch_AdjustSelectedRowCols +================== +*/ +/* +void Patch_AdjustSelectedRowCols(int nRows, int nCols) +{ + for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + Patch_InsertColumn(pb->pPatch, false); + if (nRows != 0) + { + Patch_AdjustRows(pb->pPatch, nRows); + } + + if (nCols != 0) + { + Patch_AdjustColumns(pb->pPatch, nCols); + } + } + } + UpdatePatchInspector(); +} +*/ + +/* +================= +CheckName +temporary stuff, detect potential problems when saving the texture name +will correct the patch on the fly if problem detected +================= +*/ +/*! +\todo performance issue with CheckName calls +don't call this too much, only when absolutely necessary +strategies that call here too much are known to be slow +patch 84 to bug 253 adds an additionnal check for textures/ +*/ +void CheckName( patchMesh_t *p, char *pname ) +{ + if(strncmp(p->pShader->getName(), "textures/", 9) != 0) + p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); + + // some manage to get long filename textures (with spaces) in their maps + if (strchr( p->pShader->getName(), ' ' )) + { + char Msg1[1024]; + sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", p->pShader->getName() ); + Sys_Printf("%s\n", Msg1 ); + gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); + strcpy( pname, SHADER_NOT_FOUND ); + p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); + p->d_texture = p->pShader->getTexture(); + return; + } + strcpy( pname, p->pShader->getName()+9 ); // remove "textures/" +} + +/* +================== +Patch_Write +================== +*/ +void Patch_Write (patchMesh_t *p, MemStream *file) +{ + char pname[1024]; + + MemFile_fprintf(file, " {\n patchDef2\n {\n"); + + CheckName( p, pname ); + MemFile_fprintf(file, " %s\n", pname ); + MemFile_fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value); + + + float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5]; + + int w, h; + for (w = 0; w < p->width; w++) + { + for (h = 0; h < p->height; h++) + { + ctrl[w][h][0] = p->ctrl[w][h].xyz[0]; + ctrl[w][h][1] = p->ctrl[w][h].xyz[1]; + ctrl[w][h][2] = p->ctrl[w][h].xyz[2]; + ctrl[w][h][3] = p->ctrl[w][h].st[0]; + ctrl[w][h][4] = p->ctrl[w][h].st[1]; + } + } + + _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast(&ctrl)); + + if (g_qeglobals.m_bBrushPrimitMode) + { + if (p->epairs) + { + for (epair_t *ep = p->epairs ; ep ; ep=ep->next) + { + MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value); + } + } + } + + MemFile_fprintf(file, " }\n }\n"); +} + +void Patch_Write (patchMesh_t *p, FILE *file) +{ + char pname[1024]; + + fprintf(file, " {\n patchDef2\n {\n"); + { + CheckName( p, pname ); + fprintf(file, " %s\n", pname ); + fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value); + } + + float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5]; + + int w, h; + for (w = 0; w < p->width; w++) + { + for (h = 0; h < p->height; h++) + { + ctrl[w][h][0] = p->ctrl[w][h].xyz[0]; + ctrl[w][h][1] = p->ctrl[w][h].xyz[1]; + ctrl[w][h][2] = p->ctrl[w][h].xyz[2]; + ctrl[w][h][3] = p->ctrl[w][h].st[0]; + ctrl[w][h][4] = p->ctrl[w][h].st[1]; + } + } + + _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast(&ctrl)); + + if (g_qeglobals.m_bBrushPrimitMode) + { + if (p->epairs) + { + for (epair_t *ep = p->epairs ; ep ; ep=ep->next) + { + fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value); + } + } + } + + fprintf(file, " }\n }\n"); +} + + +/* +================== +Patch_RotateTexture +================== +*/ +void Patch_RotateTexture(patchMesh_t *p, float fAngle) +{ + p->bDirty = true; + float c = cos(fAngle * Q_PI / 180); + float s = sin(fAngle * Q_PI / 180); + + Patch_TransformLODTexture(p, c, s, ROTATE); + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + //if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + // continue; + + float x = p->ctrl[w][h].st[0]; + float y = p->ctrl[w][h].st[1]; + p->ctrl[w][h].st[0] = x * c - y * s; + p->ctrl[w][h].st[1] = y * c + x * s; + } + } +} + + +/* +================== +Patch_ScaleTexture +================== +*/ +void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup) +{ + // FIXME: + // this hack turns scales into 1.1 or 0.9 + if (bFixup) + { + fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10; + fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10; + } + else + { + if (fx == 0) + fx = 1.0; + if (fy == 0) + fy = 1.0; + } + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + continue; + + p->ctrl[w][h].st[0] *= fx; + p->ctrl[w][h].st[1] *= fy; + } + } + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + p->bDirty = true; + Patch_LODMatchAll(); + } + else + { + Patch_TransformLODTexture(p, fx, fy, SCALE); + p->LODUpdated = true; + } +} + + +/* +================== +Patch_ShiftTexture +shift a texture given a pixel count +================== +*/ +void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy) +{ + qtexture_t *pTex; + pTex = p->pShader->getTexture(); + fx = -1 * fx / pTex->width; + fy = fy / pTex->height; + Patch_ShiftTextureST(p, fx, fy); +} + +/* +==================== +Patch_ShiftTextureST +shift a patch texture given an ST increment +==================== +*/ +void Patch_ShiftTextureST(patchMesh_t *p, float fx, float fy) +{ +#ifdef _DEBUG + // NOTE: when called by Patch_ShiftTexture this warning may be bogus + if ((ABS(fx) >= 1) || (ABS(fy) >= 1)) + Sys_Printf("WARNING: increments exceed 1 in Patch_ShiftTextureST\n"); +#endif + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + continue; + + p->ctrl[w][h].st[0] += fx; + p->ctrl[w][h].st[1] += fy; + } + } + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + p->bDirty = true; + Patch_LODMatchAll(); + } + else + { + Patch_TransformLODTexture(p, fx, fy, TRANSLATE); + p->LODUpdated = true; + } +} + +/* +================== +Patch_ToggleInverted +================== +*/ +void Patch_ToggleInverted() +{ + bool bUpdate = false; + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + bUpdate = true; + patchInvert(pb->pPatch); + } + } + + if (bUpdate) + { + Sys_UpdateWindows(W_ALL); + } + UpdatePatchInspector(); +} + +/* +================== +Patch_ToggleInverted +================== +*/ +void Patch_InvertTexture(bool bY) +{ + bool bUpdate = false; + + float fTemp[2]; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + bUpdate = true; + patchMesh_t *p = pb->pPatch; + p->bDirty = true; + if (bY) + { + for ( int i = 0 ; i < p->height ; i++ ) + { + for (int j = 0; j < p->width / 2; j++) + { + memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2])); + memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2])); + memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2])); + } + } + } + else + { + for ( int i = 0 ; i < p->width ; i++ ) + { + for (int j = 0; j < p->height / 2; j++) + { + memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2])); + memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2])); + memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2])); + } + } + } + } + } + + if (bUpdate) + { + Sys_UpdateWindows(W_ALL); + } + UpdatePatchInspector(); +} + + + + +/* +================== +Patch_Save +================== + Saves patch ctrl info (originally to deal with a + cancel in the surface dialog +*/ +void Patch_Save(patchMesh_t *p) +{ + patchSave.width = p->width; + patchSave.height = p->height; + memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl)); +} + + +/* +================== +Patch_Restore +================== +*/ +void Patch_Restore(patchMesh_t *p) +{ + p->width = patchSave.width; + p->height = patchSave.height; + memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl)); +} + +void Patch_ResetTexturing(float fx, float fy) +{ + for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + p->bDirty = true; + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1); + p->ctrl[i][j].st[1] = 1 - fy * (float)j / (p->height - 1); + } + } + } + } +} + +// NOTE TTimo stub! +void Patch_FitTexturing() +{ + Patch_ResetTexturing(1.0f, 1.0f); +} + +void Patch_SetTextureInfo(texdef_t *pt) +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (pt->rotate) + Patch_RotateTexture(pb->pPatch, pt->rotate); + + if (pt->shift[0] || pt->shift[1]) + Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]); + + if (pt->scale[0] || pt->scale[1]) + Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false); + + patchMesh_t *p = pb->pPatch; + p->contents = pt->contents; + p->flags = pt->flags; + p->value = pt->value; + } + } +} + +bool OnlyPatchesSelected() +{ + if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes) + return false; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (!pb->patchBrush) + { + return false; + } + } + return true; +} + +bool AnyPatchesSelected() +{ + if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes) + return false; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + return true; + } + } + return false; +} + +patchMesh_t* SinglePatchSelected() +{ + if (selected_brushes.next->patchBrush) + { + return selected_brushes.next->pPatch; + } + return NULL; +} + +void Patch_BendToggle() +{ + if (g_bPatchBendMode) + { + g_bPatchBendMode = false; + HideInfoDialog(); + g_pParentWnd->UpdatePatchToolbarButtons() ; + return; + } + + brush_t* b = selected_brushes.next; + + if (!QE_SingleBrush(true) || !b->patchBrush) + { + Sys_Printf("Patch_BendToggle: you must have a single patch selected\n"); + return; + } + + Patch_Save(b->pPatch); + g_bPatchBendMode = true; + g_nPatchBendState = BEND_SELECT_ROTATION; + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = 1; + ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]); +} + +void Patch_BendHandleTAB() +{ + if (!g_bPatchBendMode) + { + return; + } + + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + Patch_BendToggle(); + Sys_Printf("No patch to bend!"); + return; + } + + patchMesh_t *p = b->pPatch; + + bool bShift = Sys_ShiftDown (); + + if (g_nPatchBendState == BEND_SELECT_ROTATION) + { + // only able to deal with odd numbered rows/cols + g_nPatchAxisIndex += (bShift) ? -2 : 2; + if (g_bPatchAxisOnRow) + { + if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height) + { + g_bPatchAxisOnRow = false; + g_nPatchAxisIndex = (bShift) ? p->width-1 : 1; + } + } + else + { + if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width) + { + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = (bShift) ? p->height-1 : 1; + } + } + } + else + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + g_nBendOriginIndex += (bShift) ? -1 : 1; + if (g_bPatchAxisOnRow) + { + if (bShift) + { + if (g_nBendOriginIndex < 0) + g_nBendOriginIndex = p->width-1; + } + else + { + if (g_nBendOriginIndex > p->width-1) + g_nBendOriginIndex = 0; + } + VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin); + } + else + { + if (bShift) + { + if (g_nBendOriginIndex < 0) + g_nBendOriginIndex = p->height-1; + } + else + { + if (g_nBendOriginIndex > p->height-1) + g_nBendOriginIndex = 0; + } + VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin); + } + } + else + if (g_nPatchBendState == BEND_SELECT_EDGE) + { + g_bPatchLowerEdge ^= 1; + } + Sys_UpdateWindows(W_ALL); +} + +void Patch_BendHandleENTER() +{ + if (!g_bPatchBendMode) + { + return; + } + + if (g_nPatchBendState < BEND_BENDIT) + { + g_nPatchBendState++; + ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]); + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0; + g_nBendOriginIndex = 0; + Patch_BendHandleTAB(); + } + else + if (g_nPatchBendState == BEND_SELECT_EDGE) + { + g_bPatchLowerEdge = true; + } + else + if (g_nPatchBendState == BEND_BENDIT) + { + // basically we go into rotation mode, set the axis to the center of the + } + } + else + { + // done + Patch_BendToggle(); + } + Sys_UpdateWindows(W_ALL); + +} + + +void Patch_BendHandleESC() +{ + if (!g_bPatchBendMode) + { + return; + } + Patch_BendToggle(); + brush_t* b = selected_brushes.next; + if (QE_SingleBrush() && b->patchBrush) + { + Patch_Restore(b->pPatch); + } + Sys_UpdateWindows(W_ALL); +} + +void Patch_SetBendRotateOrigin(patchMesh_t *p) +{ +#if 1 + int nType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1; + + g_vBendOrigin[nDim3] = 0; + VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin()); + return; +#else + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + float fxLo, fyLo, fxHi, fyHi; + fxLo = fyLo = 9999; + fxHi = fyHi = -9999; + + if (g_bPatchAxisOnRow) + { + for (int i = 0; i < p->width; i++) + { + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo) + fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1]; + + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi) + fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1]; + + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo) + fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2]; + + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi) + fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2]; + } + } + else + { + for (int i = 0; i < p->height; i++) + { + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo) + fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1]; + + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi) + fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1]; + + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo) + fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2]; + + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi) + fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2]; + } + } + + g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0; + g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5; + g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5; +#endif +} + +// also sets the rotational origin +void Patch_SelectBendAxis() +{ + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + // should not ever happen + Patch_BendToggle(); + return; + } + + patchMesh_t *p = b->pPatch; + if (g_bPatchAxisOnRow) + { + SelectRow(p, g_nPatchAxisIndex, false); + } + else + { + SelectColumn(p, g_nPatchAxisIndex, false); + } + + //FIXME: this only needs to be set once... + Patch_SetBendRotateOrigin(p); + +} + +void Patch_SelectBendNormal() +{ + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + // should not ever happen + Patch_BendToggle(); + return; + } + + patchMesh_t *p = b->pPatch; + + g_qeglobals.d_num_move_points = 0; + if (g_bPatchAxisOnRow) + { + if (g_bPatchLowerEdge) + { + for (int j = 0; j < g_nPatchAxisIndex; j++) + SelectRow(p, j, true); + } + else + { + for (int j = p->height-1; j > g_nPatchAxisIndex; j--) + SelectRow(p, j, true); + } + } + else + { + if (g_bPatchLowerEdge) + { + for (int j = 0; j < g_nPatchAxisIndex; j++) + SelectColumn(p, j, true); + } + else + { + for (int j = p->width-1; j > g_nPatchAxisIndex; j--) + SelectColumn(p, j, true); + } + } + Patch_SetBendRotateOrigin(p); +} + + + +/* +void Patch_InsDelToggle() +{ + if (g_bPatchInsertMode) + { + g_bPatchInsertMode = false; + HideInfoDialog(); + g_pParentWnd->UpdatePatchToolbarButtons() ; + return; + } + + brush_t* b = selected_brushes.next; + + if (!QE_SingleBrush(true) || !b->patchBrush) + { + Sys_Printf("Patch_InsDelToggle: you must have a single patch selected\n"); + return; + } + + Patch_Save(b->pPatch); + g_bPatchInsertMode = true; + g_nPatchInsertState = INSERT_SELECT_EDGE; + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = 0; + ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]); + +} + +void Patch_InsDelESC() +{ + if (!g_bPatchInsertMode) + { + return; + } + Patch_InsDelToggle(); + Sys_UpdateWindows(W_ALL); +} + + +void Patch_InsDelHandleENTER() +{ +} + +void Patch_InsDelHandleTAB() +{ + if (!g_bPatchInsertMode) + { + Patch_InsDelToggle(); + return; + } + + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + Patch_BendToggle(); + Sys_Printf("No patch to bend!"); + return; + } + + patchMesh_t *p = b->pPatch; + + // only able to deal with odd numbered rows/cols + g_nPatchAxisIndex += 2; + if (g_bPatchAxisOnRow) + { + if (g_nPatchAxisIndex >= p->height-1) + { + g_bPatchAxisOnRow = false; + g_nPatchAxisIndex = 0; + } + } + else + { + if (g_nPatchAxisIndex >= p->width-1) + { + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = 0; + } + } + Sys_UpdateWindows(W_ALL); +} +*/ + + +void _Write1DMatrix (FILE *f, int x, float *m) { + int i; + + fprintf (f, "( "); + for (i = 0 ; i < x ; i++) { + if (m[i] == (int)m[i] ) { + fprintf (f, "%i ", (int)m[i]); + } else { + fprintf (f, "%f ", m[i]); + } + } + fprintf (f, ")"); +} + +void _Write2DMatrix (FILE *f, int y, int x, float *m) { + int i; + + fprintf (f, "( "); + for (i = 0 ; i < y ; i++) { + _Write1DMatrix (f, x, m + i*x); + fprintf (f, " "); + } + fprintf (f, ")\n"); +} + + +void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) { + int i; + + fprintf (f, "(\n"); + for (i = 0 ; i < z ; i++) { + _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) ); + } + fprintf (f, ")\n"); +} + +void _Write1DMatrix (MemStream *f, int x, float *m) { + int i; + + MemFile_fprintf (f, "( "); + for (i = 0 ; i < x ; i++) { + if (m[i] == (int)m[i] ) { + MemFile_fprintf (f, "%i ", (int)m[i]); + } else { + MemFile_fprintf (f, "%f ", m[i]); + } + } + MemFile_fprintf (f, ")"); +} + +void _Write2DMatrix (MemStream *f, int y, int x, float *m) { + int i; + + MemFile_fprintf (f, "( "); + for (i = 0 ; i < y ; i++) { + _Write1DMatrix (f, x, m + i*x); + MemFile_fprintf (f, " "); + } + MemFile_fprintf (f, ")\n"); +} + + +void _Write3DMatrix (MemStream *f, int z, int y, int x, float *m) { + int i; + + MemFile_fprintf (f, "(\n"); + for (i = 0 ; i < z ; i++) { + _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) ); + } + MemFile_fprintf (f, ")\n"); +} + +// NOTE: why the hell is this called Naturalize? +// we dispatch either to Patch+Naturalize or Patch_CapTexture.. +void Patch_NaturalizeSelected(bool bCap) +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (bCap) + Patch_CapTexture(pb->pPatch);//, bCycleCap); + else + Patch_Naturalize(pb->pPatch); + } + } +} + +// go through the selected patches and call Patch_CapTexture +// deal with cycling +void Patch_CycleCapSelected() +{ + // compute the g_vCycleCapNormal according to g_nCycleCapIndex + VectorClear (g_vCycleCapNormal); + g_vCycleCapNormal[g_nCycleCapIndex] = 1.0f; // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + Patch_CapTexture(pb->pPatch, true); + } + } + switch (g_nCycleCapIndex) + { + case YZ: + g_nCycleCapIndex = XZ; + break; + case XZ: + g_nCycleCapIndex = XY; + break; + case XY: + g_nCycleCapIndex = YZ; + break; + } +} + +bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR) +{ + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) || + (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1])) + { + if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) || + (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2])) + return true; + } + return false; +} + + +void Patch_SelectAreaPoints(bool bMulti) +{ + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + + if( g_nPatchClickedView == W_CAMERA ) { + // Clip against a pyramid + // Create our 5 normals (that are pointing to the inside) + camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera(); + vec3_t norm[5]; + float r[2], u[2], hh, hw; + int idx; + vec_t corners[2][2]; + vec3_t ray[4]; + vec3_t check; + + VectorCopy( m_pCamera->vpn, norm[0] ); // only points in front of the camera + + // get our rectangle + corners[0][0] = MIN( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] ); + corners[0][1] = MAX( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] ); + corners[1][0] = MAX( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] ); + corners[1][1] = MIN( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] ); + + // calculate our four ray vectors + hh = m_pCamera->height/2; + hw = m_pCamera->width/2; + u[0] = (float)(corners[0][1] - hh) / (hw); + r[0] = (float)(corners[0][0] - hw) / (hw); + u[1] = (float)(corners[1][1] - hh) / (hw); + r[1] = (float)(corners[1][0] - hw) / (hw); + + for (idx=0 ; idx<3; idx++) + ray[0][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[0]; + for (idx=0 ; idx<3; idx++) + ray[1][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[0]; + for (idx=0 ; idx<3; idx++) + ray[2][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[1]; + for (idx=0 ; idx<3; idx++) + ray[3][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[1]; + + // Create our four other directions from these + CrossProduct( ray[0], ray[1], norm[1] ); VectorNormalize( norm[1], norm[1] ); + CrossProduct( ray[1], ray[2], norm[2] ); VectorNormalize( norm[2], norm[2] ); + CrossProduct( ray[2], ray[3], norm[3] ); VectorNormalize( norm[3], norm[3] ); + CrossProduct( ray[3], ray[0], norm[4] ); VectorNormalize( norm[4], norm[4] ); + + // 3D clipping + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + VectorSubtract( m_pCamera->origin, p->ctrl[i][j].xyz, check ); + VectorNormalize( check, check ); + for (idx=0 ; idx<5; idx++) + { + if (DotProduct(check, norm[idx])>=0) + break; + } + if (idx == 5) // all test were good + { + if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1) + RemovePointFromMoveList(p->ctrl[i][j].xyz); + else + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + } + } + } + } + } + } else + { + // Simple 2D clipping + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR)) + { + if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1) + RemovePointFromMoveList(p->ctrl[i][j].xyz); + else + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + } + } + } + } + } + } + + g_nPatchClickedView = -1; +} + +// TTimo: return the shader name for a patch +const char* Patch_GetTextureName() +{ + brush_t* b = selected_brushes.next; + if (b->patchBrush) + { + patchMesh_t *p = b->pPatch; + return p->pShader->getName(); + } + return ""; +} + +patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom) +{ + patchMesh_t* p = MakeNewPatch(); + memcpy(p, pFrom , sizeof(patchMesh_t)); + + // spog - initialise patch LOD pointers (again) + Patch_InitialiseLODPointers(p); + p->drawLists = NULL; + + p->bSelected = false; + p->bDirty = true; + p->bOverlay = false; + p->nListID = -1; + AddBrushForPatch(p); + + return p; +} + + +void Patch_Thicken(int nAmount, bool bSeam, qboolean bGroupResult) +{ + int i, j, h, w; + brush_t *b; + patchMesh_t *pSeam; + vec3_t vMin, vMax; + CPtrArray brushes; + + nAmount = -nAmount; + + + if (!QE_SingleBrush()) + { + Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n"); + return; + } + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_MeshNormals(p); + patchMesh_t *pNew = Patch_Duplicate(p); + for (i = 0; i < p->width; i++) + { + for (j = 0; j < p->height; j++) + { + VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz); + } + } + + Patch_Rebuild(pNew); + pNew->type |= PATCH_THICK; + brushes.Add(pNew->pSymbiot); + + if (bSeam) + { + + // FIXME: this should detect if any edges of the patch are closed and act appropriately + // + if (!(p->type & PATCH_CYLINDER)) + { + b = Patch_GenericMesh(3, p->height, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz); + VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz); + VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz); + VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz); + } + + + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + patchInvert(pSeam); + brushes.Add(b); + + w = p->width - 1; + b = Patch_GenericMesh(3, p->height, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz); + VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz); + VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz); + VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz); + } + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + brushes.Add(b); + } + + //--{ + // otherwise we will add one per end + b = Patch_GenericMesh(p->width, 3, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->width; i++) + { + VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz); + VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz); + VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz); + VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz); + } + + + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + patchInvert(pSeam); + brushes.Add(b); + + h = p->height - 1; + b = Patch_GenericMesh(p->width, 3, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->width; i++) + { + VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz); + VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz); + VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz); + VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz); + } + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + brushes.Add(b); + + } + patchInvert(pNew); + } + } + + for (i = 0; i < brushes.GetSize(); i++) + { + Select_Brush(reinterpret_cast(brushes.GetAt(i))); + } + + if(bGroupResult) + { + entity_t *e = Entity_Alloc(); + SetKeyValue(e, "classname", "func_group"); + SetKeyValue(e, "type", "patchThick"); + Select_GroupEntity(e); + Entity_AddToList(e, &entities); + } + + UpdatePatchInspector(); +} + + +/* +lets get another list together as far as necessities.. + +*snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything) + +capping bevels/endcaps + +hot keys + +texture fix for caps + +clear clipboard + +*region fix + +*surface dialog + +*/ + +void Patch_SetOverlays() +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = true; + } + } +} + + + +void Patch_ClearOverlays() +{ + brush_t *pb; + for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + + for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + +} + +// FIXME: spog - er, someone forgot to finish their patch point freezing feature? +// freezes selected vertices +void Patch_Freeze() +{ + brush_t *pb; + for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + + for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + +} + +void Patch_UnFreeze(bool bAll) +{ +} + +void Patch_Transpose() +{ + int i, j, w; + drawVert_t dv; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + + if ( p->width > p->height ) + { + for ( i = 0 ; i < p->height ; i++ ) + { + for ( j = i + 1 ; j < p->width ; j++ ) + { + if ( j < p->height ) + { + // swap the value + memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t)); + memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t)); + } + } + } + } + else + { + for ( i = 0 ; i < p->width ; i++ ) + { + for ( j = i + 1 ; j < p->height ; j++ ) + { + if ( j < p->width ) + { + // swap the value + memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t)); + memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t)); + } + } + } + } + + w = p->width; + p->width = p->height; + p->height = w; + patchInvert(p); + Patch_Rebuild(p); + } + } +} + + + +void Patch_SnapToGrid(patchMesh_t *p) +{ + int i,j,k; + + // if patch points selected, snap only selected points + if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) + for (i=0; iwidth; i++) + for (j = 0; j < p->height; j++) + for (k = 0; k < 3; k++) + p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); +} + + +void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce) +{ + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + if (bForce || strcmpi(p->pShader->getName(), pFind) == 0) + { + p->pShader->DecRef(); + p->pShader = QERApp_Shader_ForName(pReplace); + p->d_texture = p->pShader->getTexture(); + } + } +} + +/* uncomment if necessary, currently not used +void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz) +{ + patchMesh_t* p = MakeNewPatch(); + p->pShader = g_qeglobals.d_texturewin.pShader; + p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture(); + p->width = 3; + p->height = 3; + p->type = PATCH_TRIANGLE; + + // 0 0 goes to x + // 0 1 goes to x + // 0 2 goes to x + + // 1 0 goes to mid of x and z + // 1 1 goes to mid of x y and z + // 1 2 goes to mid of x and y + + // 2 0 goes to z + // 2 1 goes to mid of y and z + // 2 2 goes to y + + vec5_t vMidXZ; + vec5_t vMidXY; + vec5_t vMidYZ; + int j; + + for (j = 0; j < 3; j++) + { + _Vector5Add(vx, vz, vMidXZ); + _Vector5Scale(vMidXZ, 0.5, vMidXZ); + //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5); + } + + for (j = 0; j < 3; j++) + { + _Vector5Add(vx, vy, vMidXY); + _Vector5Scale(vMidXY, 0.5, vMidXY); + //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5); + } + + for (j = 0; j < 3; j++) + { + _Vector5Add(vy, vz, vMidYZ); + _Vector5Scale(vMidYZ, 0.5, vMidYZ); + //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5); + } + + _Vector53Copy(vx, p->ctrl[0][0].xyz); + _Vector53Copy(vx, p->ctrl[0][1].xyz); + _Vector53Copy(vx, p->ctrl[0][2].xyz); + p->ctrl[0][0].st[0] = vx[3]; + p->ctrl[0][0].st[1] = vx[4]; + p->ctrl[0][1].st[0] = vx[3]; + p->ctrl[0][1].st[1] = vx[4]; + p->ctrl[0][2].st[0] = vx[3]; + p->ctrl[0][2].st[1] = vx[4]; + + _Vector53Copy(vMidXY, p->ctrl[1][0].xyz); + _Vector53Copy(vx, p->ctrl[1][1].xyz); + _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz); + p->ctrl[1][0].st[0] = vMidXY[3]; + p->ctrl[1][0].st[1] = vMidXY[4]; + p->ctrl[1][1].st[0] = vx[3]; + p->ctrl[1][1].st[1] = vx[4]; + p->ctrl[1][2].st[0] = vMidXZ[3]; + p->ctrl[1][2].st[1] = vMidXZ[4]; + + _Vector53Copy(vy, p->ctrl[2][0].xyz); + _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz); + _Vector53Copy(vz, p->ctrl[2][2].xyz); + p->ctrl[2][0].st[0] = vy[3]; + p->ctrl[2][0].st[1] = vy[4]; + p->ctrl[2][1].st[0] = vMidYZ[3]; + p->ctrl[2][1].st[1] = vMidYZ[4]; + p->ctrl[2][2].st[0] = vz[3]; + p->ctrl[2][2].st[1] = vz[4]; + + + //Patch_Naturalize(p); + + // brush_t *b = + AddBrushForPatch(p); + +} +*/ + +#ifdef ENABLE_GROUPS +/* +============== +Patch_SetEpair +sets an epair for the given patch +============== +*/ +void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + SetKeyValue(p->epairs, pKey, pValue); + } +} + +/* +================= +Patch_GetKeyValue +================= +*/ +const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + return ValueForKey(p->epairs, pKey); + } + return ""; +} +#endif + + +//Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save) +/* +Feature addition. +When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as; + +g:\quake3\baseq3\textures\common + + So that, when I'm reading in, lets say, my \eerie directory, it goes through and adds my textures to the palette, along with everything in common. + + Don't forget to add "Finer texture alignment" to the list. I'd like to be able to move in 0.1 increments using the Shift-Arrow Keys. + + No. Sometimes textures are drawn the wrong way on patches. We'd like the ability to flip a texture. Like the way X/Y scale -1 used to worked. + + 1) Easier way of deleting rows, columns +2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog) +2) Patch matrix transposition + + 1) Actually, bump texture flipping on patches to the top of the list of things to do. +2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S +3) Brandon has a wierd anomoly. He fine-tunes a patch with caps. It looks fine when the patch is selected, but as soon as he escapes out, it reverts to it's pre-tuned state. When he selects the patch again, it looks tuned + + +*1) Flipping textures on patches +*2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S +3) Easier way of deleting rows columns +*4) Thick Curves +5) Patch matrix transposition +6) Inverted cylinder capping +*7) bugs +*8) curve speed + + Have a new feature request. "Compute Bounding Box" for mapobjects (md3 files). This would be used for misc_mapobject (essentially, drop in 3DS Max models into our maps) + + Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model + + Feature Addition: View/Hide Hint Brushes -- This should be a specific case. +*/ diff --git a/radiant/points.cpp b/radiant/points.cpp new file mode 100644 index 00000000..64e67667 --- /dev/null +++ b/radiant/points.cpp @@ -0,0 +1,249 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" + +#define MAX_POINTFILE 8192 +static vec3_t s_pointvecs[MAX_POINTFILE]; +static int s_num_points, s_check_point; + +CPointfile g_pointfile; + +// CPointfile routine used by the standard code --------------------------------- + +void CPointfile::Init() +{ + s_num_points = 0; +} + +void CPointfile::PushPoint (vec3_t v) +{ + if (s_num_points < MAX_POINTFILE) + { + VectorCopy (v, s_pointvecs[s_num_points]); + s_num_points++; + } +} + +// create the display list at the end +void CPointfile::GenerateDisplayList() +{ + int i; + + if (!g_qeglobals.d_pointfile_display_list) + g_qeglobals.d_pointfile_display_list = qglGenLists(1); + + qglNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE); + + qglColor3f (1, 0, 0); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglLineWidth (4); + qglBegin(GL_LINE_STRIP); + for (i=0;i= s_num_points-2) + { + Sys_Status ("End of pointfile", 0); + return; + } + s_check_point++; + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin); + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin()); + VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir); + VectorNormalize (dir, dir); + g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +// advance camera to previous point +void Pointfile_Prev (void) +{ + vec3_t dir; + + if ( s_check_point == 0) + { + Sys_Status ("Start of pointfile", 0); + return; + } + s_check_point--; + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin); + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin()); + VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir); + VectorNormalize (dir, dir); + g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +void WINAPI Pointfile_Check (void) +{ + char name[1024]; + int size; + char *data; + char *text; + int line = 1; + vec3_t v; + + strcpy (name, currentmap); + StripExtension (name); + strcat (name, ".lin"); + + size = vfsLoadFullPathFile (name, (void**)&data); + if (size <= 0) + { + Sys_FPrintf (SYS_ERR, "Pointfile %s not found\n", name); + return; + } + + // store a pointer + text = data; + + Sys_Printf ("Reading pointfile %s\n", name); + + g_pointfile.Init(); + + while (*data) + { + if (sscanf(data,"%f %f %f", &v[0], &v[1], &v[2]) != 3) + { + Sys_Printf("Corrupt point file, line %d\n",line); + break; + } + + while (*data && *data != '\n') + { + if (*(data-1) == ' ' && *(data) == '-' && *(data+1) == ' ') + break; + data++; + } + // deal with zhlt style point files. + if (*data == '-') + { + if (sscanf(data,"- %f %f %f", &v[0], &v[1], &v[2]) != 3) + { + Sys_Printf("Corrupt point file, line %d\n",line); + break; + } + + while (*data && *data != '\n') + data++; + + } + while (*data == '\n') + { + data++; // skip the \n + line++; + } + g_pointfile.PushPoint (v); + } + + g_free(text); + + g_pointfile.GenerateDisplayList(); + + Sys_UpdateWindows (W_ALL); +} + +void Pointfile_Draw( void ) +{ + qglCallList (g_qeglobals.d_pointfile_display_list); +} + +void Pointfile_Clear (void) +{ + if (!g_qeglobals.d_pointfile_display_list) + return; + + qglDeleteLists (g_qeglobals.d_pointfile_display_list, 1); + g_qeglobals.d_pointfile_display_list = 0; + Sys_UpdateWindows (W_ALL); +} + +// CPointfile implementation for SAX speicific stuff ------------------------------- +void CPointfile::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "polyline")==0) + { + Init(); + // there's a prefs setting to avoid stopping on leak + if (!g_PrefsDlg.m_bLeakStop) + ctx->stop_depth = 0; + } +} + +void CPointfile::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "polyline")==0) + { + // we are done + GenerateDisplayList(); + ctx->bGeometry = false; + } +} + +// only "point" is expected to have characters around here +void CPointfile::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + vec3_t v; + + sscanf ((char *)ch, "%f %f %f\n", &v[0], &v[1], &v[2]); + PushPoint (v); +} + +char * CPointfile::getName() +{ + return "Map is leaked"; +} diff --git a/radiant/points.h b/radiant/points.h new file mode 100644 index 00000000..bc44cb8a --- /dev/null +++ b/radiant/points.h @@ -0,0 +1,57 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// header for Pointfile stuff (adding a C++ class to wrap the pointfile thing in the SAX parser) +// + +#ifndef __POINTS__ +#define __POINTS__ + +void Pointfile_Delete (void); +void WINAPI Pointfile_Check (void); +void Pointfile_Next (void); +void Pointfile_Prev (void); +void Pointfile_Clear (void); +void Pointfile_Draw( void ); +void Pointfile_Load( void ); + +class CPointfile : public ISAXHandler +{ +public: + CPointfile() { } + void Init(); + void PushPoint (vec3_t v); + void GenerateDisplayList(); + // SAX interface + void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs); + void saxEndElement (message_info_t *ctx, const xmlChar *name); + void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len); + char *getName(); +}; + +// instead of using Pointfile_Load you can do it by hand through g_pointfile +// but the usual pointfile mechanism remains the same, use Pointfile_Draw etc. +extern CPointfile g_pointfile; + +#endif diff --git a/radiant/preferences.cpp b/radiant/preferences.cpp new file mode 100644 index 00000000..e49a0b43 --- /dev/null +++ b/radiant/preferences.cpp @@ -0,0 +1,3102 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// User preferences +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#include +#include +#include +#endif +#include "missing.h" +#include "gtkmisc.h" + +#ifdef _WIN32 +#include +#define X_OK 0 +#include +#endif + +#define PREF_SECTION "Prefs" +#define INTERNAL_SECTION "Internals" +#define MOUSE_KEY "MouseButtons" +#define WINDOW_KEY "QE4StyleWindows" +#define LAYOUT_KEY "WindowLayout" +#define RUNQ2_KEY "RunQuake2Run" +#define TLOCK_KEY "TextureLock" +#define RLOCK_KEY "RotateLock" +#define LOADLAST_KEY "LoadLast" +#define LOADLASTMAP_KEY "LoadLastMap" +#define LASTPROJ_KEY "LastProject" +#define LASTPROJVER_KEY "LastProjectKey" +#define LASTMAP_KEY "LastMap" +#define FACE_KEY "NewFaceGrab" +#define BSP_KEY "InternalBSP" +#define RCLICK_KEY "NewRightClick" +#define VERTEX_KEY "NewVertex" +#define AUTOSAVE_KEY "Autosave" +#define AUTOSAVETIME_KEY "AutosaveMinutes" +#define PAK_KEY "UsePAK" +#define NEWAPPLY_KEY "ApplyDismissesSurface" +#define HACK_KEY "Gatewayescapehack" +#define TEXTURE_KEY "NewTextureWindowStuff" +#define TINYBRUSH_KEY "CleanTinyBrushes" +#define TINYSIZE_KEY "CleanTinyBrusheSize" +#define SNAPSHOT_KEY "Snapshots" +#define MOVESPEED_KEY "MoveSpeed" +#define ANGLESPEED_KEY "AngleSpeed" +#define SETGAME_KEY "UseSetGame" +#define CAMXYUPDATE_KEY "CamXYUpdate" +#define CAMDRAGMULTISELECT_KEY "CamDragMultiSelect" +#define CAMFREELOOK_KEY "CamFreeLook" +#define CAMINVERSEMOUSE_KEY "CamInverseMouse" +#define CAMDISCRETE_KEY "CamDiscrete" +#define LIGHTDRAW_KEY "NewLightStyle" +#define WHATGAME_KEY "WhichGame" +#define CUBICCLIP_KEY "CubicClipping" +#define CUBICSCALE_KEY "CubicScale" +#define ALTEDGE_KEY "ALTEdgeDrag" +#define FACECOLORS_KEY "FaceColors" +#define SNAPT_KEY "SnapT" +#define XZVIS_KEY "XZVIS" +#define YZVIS_KEY "YZVIS" +#define ZVIS_KEY "ZVIS" +#define SIZEPAINT_KEY "SizePainting" +#define DLLENTITIES_KEY "DLLEntities" +#define DETACHABLEMENUS_KEY "DetachableMenus" +#define PATCHTOOLBAR_KEY "PatchToolBar" +#define WIDETOOLBAR_KEY "WideToolBar" +#define PLUGINTOOLBAR_KEY "PluginToolBar" +#define NOCLAMP_KEY "NoClamp" +#define PREFAB_KEY "PrefabPath" +#define USERINI_KEY "UserINIPath" +#define ROTATION_KEY "Rotation" +#define BUGGYICD_KEY "BuggyICD" +#define CHASEMOUSE_KEY "ChaseMouse" +#define ENTITYSHOW_KEY "EntityShow" +#define TEXTURESCALE_KEY "TextureScale" +#define TEXTURESCROLLBAR_KEY "TextureScrollbar" +#define DISPLAYLISTS_KEY "UseDisplayLists" +#define ANTIALIASEDLINES_KEY "UseAntialiasedPointsAndLines" // Fishman - Add antialiazed points and lines support. 09/03/00 +#define NORMALIZECOLORS_KEY "NormalizeColors" +#define SHADERS_KEY "UseShaders" +#define SWITCHCLIP_KEY "SwitchClipKey" +#define SELWHOLEENTS_KEY "SelectWholeEntitiesKey" +#define TEXTURESUBSET_KEY "UseTextureSubsetLoading" +#define TEXTUREQUALITY_KEY "TextureQuality" +#define SHOWSHADERS_KEY "ShowShaders" +#define SHADERTEST_KEY "ShaderTest" +#define GLLIGHTING_KEY "UseGLLighting" +#define LOADSHADERS_KEY "LoadShaders" +#define NOSTIPPLE_KEY "NoStipple" +#define UNDOLEVELS_KEY "UndoLevels" +#define VERTEXMODE_KEY "VertexSplit" +#define ENGINEPATH_KEY "EnginePath" +#define ENGINE_KEY "Engine" +#define LOGCONSOLE_KEY "LogConsole" +#define SELECTCURVES_KEY "SelectCurves" +#define SELECTMODELS_KEY "SelectModels" +#define SHADERLISTONLY_KEY "ShowShaderlistOnly" +#define WATCHBSP_KEY "WatchBSP" +#define LEAKSTOP_KEY "LeakStop" +#define DOSLEEP_KEY "SleepMode" +#define SUBDIVISIONS_KEY "Subdivisions" +#define CLIPCAULK_KEY "ClipCaulk" +#define PATCHSHOWBOUNDS_KEY "PatchShowBounds" +#define NATIVEGUI_KEY "NativeGUI" +#define STARTONPRIMMON_KEY "StartOnPrimMon" +#define NOSYSMENUPOPUPS_KEY "NoSysMenuPopups" +#define SNAPTTOGRID_KEY "SnapTToGrid" +#define FLOATINGZ_KEY "FloatingZ" +#define TARGETFIX_KEY "TargetFix" +#define GLPOINTWORKAROUND_KEY "GlPointWorkaround" // Gef: Workaround for broken Kyro * gl driver 25-aug-2001 +#define WHEELINC_KEY "WheelMouseInc" +#define PATCHBBOXSEL_KEY "PatchBBoxSel" +#define LASTLIGHTINTENSITY_KEY "LastLightIntensity" +#define CUSTOMSHADEREDITOR_KEY "UseCustomShaderEditor" +#define CUSTOMSHADEREDITORCOMMAND_KEY "CustomShaderEditorCommand" +#define TEXTURECOMPRESSIONFORMAT_KEY "TextureCompressionFormat" +#define LIGHTRADIUS_KEY "LightRadiuses" +#define Q3MAP2TEX_KEY "Q3Map2Tex" +#define ATIHACK_KEY "ATIHack" + +// window stuff +#define ENTITYSPLIT1_KEY "EntitySplit1" +#define ENTITYSPLIT2_KEY "EntitySplit2" +#define POSITIONX_KEY "PositionX" +#define POSITIONY_KEY "PositionY" +#define ENTITYWND_KEY "EntityWnd" +#define MAPINFOWND_KEY "MapInfoDlg" +#define CAMWND_KEY "CamWnd" +#define ZWND_KEY "ZWnd" +#define XYWND_KEY "XYWnd" +#define XZWND_KEY "XZWnd" +#define YZWND_KEY "YZWnd" +#define PATCHWND_KEY "PatchWnd" +#define SURFACEWND_KEY "SurfaceWnd" +#define ENTITYINFOWND_KEY "EntityInfoDlg" +#define WIDTH_KEY "Width" +#define HEIGHT_KEY "Height" +#define ZWIDTH_KEY "ZWidth" +#define XYHEIGHT_KEY "XYHeight" +#define XYWIDTH_KEY "XYWidth" +#define CAMWIDTH_KEY "CamWidth" +#define CAMHEIGHT_KEY "CamHeight" +#define ZFLOATWIDTH_KEY "ZWidthFloating" +#define STATE_KEY "State" + +// menu stuff +#define COUNT_KEY "Count" +#define FILE_KEY "File" + +//saved info +#define SI_TEXMENU_KEY "SI_TexMenu" +#define SI_GAMMA_KEY "SI_Gamma" +#define SI_COLORS_KEY "SI_Colors" +#define SI_EXCLUDE_KEY "SI_Exclude" +#define SI_INCLUDE_KEY "SI_Include" +#define SI_SURFACE_TEXDEF_KEY "SI_SurfaceTexdef" +#define SI_PATCH_TEXDEF_KEY "SI_PatchTexdef" +#define SI_AXISCOLORS_KEY "SI_AxisColors" +#define SI_SHOWNAMES_KEY "SI_ShowNames" +#define SI_SHOWCOORDS_KEY "SI_ShowCoords" +#define SI_SHOWANGLES_KEY "SI_ShowAngles" +#define SI_SHOWOUTLINES_KEY "SI_ShowOutlines" +#define SI_SHOWAXIS_KEY "SI_ShowAxis" +#define SI_NOSELOUTLINES_KEY "SI_NoSelectedOutlines" +#define SI_OUTLINESTYLE_KEY "SI_OutLineStyle" + +//for texdefs +#define TD_SCALE1_KEY "_Scale1" +#define TD_SCALE2_KEY "_Scale2" +#define TD_SHIFT1_KEY "_Shift1" +#define TD_SHIFT2_KEY "_Shift2" +#define TD_ROTATE_KEY "_Rotate" + +#define MOUSE_DEF 1 +#define WINDOW_DEF 0 +#define RUNQ2_DEF 0 +#define WATCHBSP_DEF 1 +#define TLOCK_DEF 1 +#define LOADLAST_DEF 1 +#define RUN_DEF 0 +#define SUBDIVISIONS_DEF 4 + +void WindowPosition_Parse(window_position_t& m_value, const CString& value) +{ + if(sscanf(value.GetBuffer(), "%d %d %d %d", &m_value.x, &m_value.y, &m_value.w, &m_value.h) != 4) + m_value.x = m_value.y = m_value.w = m_value.h = -1; +} + +void WindowPosition_Write(const window_position_t& m_value, CString& value) +{ + char buffer[64]; + sprintf(buffer, "%d %d %d %d", m_value.x, m_value.y, m_value.w, m_value.h); + value = buffer; +} + + +CXMLPropertyBag::CXMLPropertyBag() { + mStrFilename = ""; + mpDoc = NULL; + mbEmpty = false; +} + +// generic preference functions + +void CXMLPropertyBag::PushAssignment(char *name, PrefTypes_t type, void *pV) +{ + list::iterator iAssign; + for(iAssign=mPrefAssignments.begin(); iAssign!=mPrefAssignments.end(); iAssign++) + { + if ((*iAssign).mName == name) + { + // we have it already, check anyway + if (pV != (*iAssign).mVal) + { + Sys_FPrintf(SYS_ERR, "PushAssignment, '%s' has different mVal\n", name); + return; + } + } + } + // ok, it's not in our list yet + mPrefAssignments.push_front(CPrefAssignment(name, type, pV)); +} + +xmlNodePtr CXMLPropertyBag::EpairForName(const char *name) +{ + xmlNodePtr ret = NULL; + + xmlNodePtr pNode = mpDocNode->children; + while (pNode != NULL) + { + if(pNode->type == XML_ELEMENT_NODE) + { + xmlAttrPtr tmp_attr_ptr = xmlHasProp(pNode, (xmlChar *)"name"); + if (tmp_attr_ptr != NULL && !strcmp(name, (char *)tmp_attr_ptr->children->content)) + { + if ( ret ) { + Sys_FPrintf( SYS_WRN, "WARNING: dupe property in CXMLPropertyBag::EpairForName '%s'\n", name ); + } else { + ret = pNode; + } + } + } + pNode = pNode->next; + } + return ret; +} + +void CXMLPropertyBag::GetPref(char *name, Str *pV, char *V) +{ + xmlNodePtr pNode = EpairForName( name ); + if ( pNode ) + { + if ( pNode->children && pNode->children->content ) { + *pV = pNode->children->content; + } else { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=427 + // means the pref exists, and that the value is "" + *pV = ""; + } + } + else + { + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)V); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + } + // push the pref assignment if needed + PushAssignment(name, PREF_STR, pV); +} + +void CXMLPropertyBag::GetPref(char *name, int *pV, int V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + *pV = atoi((char *)pNode->children->content); + } + else + { + char s[10]; + sprintf(s, "%d", V); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV=V; + } + // push the pref assignment if needed + PushAssignment(name, PREF_INT, pV); +} + +void CXMLPropertyBag::GetPref(char *name, bool *pV, bool V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + if (!strcmp((char *)pNode->children->content, "true")) + { + *pV = true; + } + else + { + *pV = false; + } + } + else + { + char s[10]; + V ? strcpy(s, "true") : strcpy(s, "false"); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV=V; + } + // push the pref assignment + PushAssignment(name, PREF_BOOL, pV); +} + +void CXMLPropertyBag::GetPref(char *name, float *pV, float V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + *pV = atof((char *)pNode->children->content); + } + else + { + char s[10]; + sprintf(s, "%f", V); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV=V; + } + // push the pref assignment if needed + PushAssignment(name, PREF_FLOAT, pV); +} + +void CXMLPropertyBag::GetPref(char *name, float* pV, float* V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + sscanf((char *)pNode->children->content, "%f %f %f", &pV[0], &pV[1], &pV[2]); + } + else + { + char s[128]; + sprintf(s, "%f %f %f", V[0], V[1], V[2]); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + pV[0] = V[0]; + pV[1] = V[1]; + pV[2] = V[2]; + } + // push the pref assignment if needed + PushAssignment(name, PREF_VEC3, pV); +} + +void CXMLPropertyBag::GetPref(char *name, window_position_t* pV, window_position_t V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + WindowPosition_Parse(*pV, CString((xmlChar *)pNode->children->content)); + } + else + { + CString str; + WindowPosition_Write(V, str); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)str.GetBuffer()); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV = V; + } + // push the pref assignment if needed + PushAssignment(name, PREF_WNDPOS, pV); +} + +void CXMLPropertyBag::UpdatePrefTree() +{ + // read the assignments and update the tree + list::iterator iPref; + for(iPref = mPrefAssignments.begin(); iPref != mPrefAssignments.end(); iPref++) + { + CPrefAssignment *pPref = &(*iPref); + // look for the node + xmlNodePtr pNode; + char s[64]; + + pNode = EpairForName(pPref->mName.GetBuffer()); + // we never expect that the node could not be found, because this is supposed to happen + // after the tree was built with GetPref calls, never on a blank tree + if (!pNode) + { + Sys_FPrintf(SYS_ERR, "Unexpected EpairForName '%s' not found in UpdatePrefTree\n", pPref->mName.GetBuffer()); + return; + } + switch ((*iPref).mType) + { + case PREF_STR: + xmlNodeSetContent(pNode, (const xmlChar *)((Str *)pPref->mVal)->GetBuffer()); + break; + case PREF_INT: + sprintf(s, "%d", *(int *)pPref->mVal); + xmlNodeSetContent(pNode, (xmlChar *)s); + break; + case PREF_FLOAT: + sprintf(s, "%f", *(float *)pPref->mVal); + xmlNodeSetContent(pNode, (xmlChar *)s); + break; + case PREF_BOOL: + *(bool *)pPref->mVal ? strcpy(s, "true") : strcpy(s, "false"); + xmlNodeSetContent(pNode, (xmlChar *)s); + break; + case PREF_VEC3: + { + float* v = (float*)pPref->mVal; + sprintf(s, "%f %f %f", v[0], v[1], v[2]); + xmlNodeSetContent(pNode, (xmlChar *)s); + } + break; + case PREF_WNDPOS: + { + CString str; + WindowPosition_Write(*(window_position_t*)pPref->mVal, str); + xmlNodeSetContent(pNode, (xmlChar*)str.GetBuffer()); + } + break; + } + } +} + +void CXMLPropertyBag::Clear() +{ + if(!InUse()) + return; + + xmlFreeDoc(mpDoc); + mpDoc = NULL; + mpDocNode = NULL; + mbEmpty = false; +} + +void CXMLPropertyBag::ReadXMLFile(const char* pFilename) +{ + mpDoc = xmlParseFile(pFilename); + + // basic checks + if (mpDoc) + { + mpDocNode = mpDoc->children; + xmlAttrPtr tmp_attr_ptr = xmlHasProp(mpDocNode, (xmlChar *)"version"); + if (strcmp((char *)mpDocNode->name, "qpref")) + { + Sys_FPrintf(SYS_ERR, "Unrecognized node '%s' in '%s'\n", mpDocNode->name, mpDoc->URL); + xmlFreeDoc(mpDoc); + mpDoc = NULL; + } + else if (tmp_attr_ptr != NULL && strcmp((char*)tmp_attr_ptr->children->content, "1")) + { + Sys_FPrintf(SYS_ERR, "Wrong version '%s' in node for '%s'\n", (char*)tmp_attr_ptr->children->content, mpDoc->URL); + xmlFreeDoc(mpDoc); + mpDoc = NULL; + } + Sys_Printf("Opened XML property file: '%s'\n", pFilename); + } + + if (!mpDoc) + { + mbEmpty = true; + // no document, create one + mpDoc = xmlNewDoc((xmlChar *)"1.0"); + mpDocNode = xmlNewDocNode(mpDoc, NULL, (xmlChar *)"qpref", NULL); + xmlDocSetRootElement(mpDoc, mpDocNode); + xmlSetProp(mpDocNode, (xmlChar *)"version", (xmlChar *)"1"); + Sys_Printf("XML property file '%s' invalid/not found, creating blank properties tree\n", pFilename); + } +} + +qboolean CXMLPropertyBag::WriteXMLFile(const char* pFilename) +{ + int res = xmlSaveFormatFile(pFilename, mpDoc, 1); + + if(res == -1) + return false; + + Sys_Printf("Wrote XML property file '%s'\n", pFilename); + return true; +} + +// ============================================================================= +// Widget callbacks for PrefsDlg + +#if !defined(WIN32) +// browse for custom editor executable +static void OnBtnBrowseEditor (GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + + const char *filename = file_dialog(g_PrefsDlg.GetWidget(), TRUE, "Executable for Custom Editor"); + + if(filename != NULL) + { + dlg->m_strEditorCommand = filename; + dlg->UpdateData(FALSE); + } +} +#endif + +static void OnBtnBrowseprefab (GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + char *path = dlg->m_strPrefabPath; + if (strlen (path) == 0) + path = g_strGameToolsPath; + char *dir = dir_dialog (g_PrefsDlg.GetWidget (), "Set prefab path", path); + dlg->UpdateData(TRUE); + + if (dir != NULL) + { + CString strPath; + strPath = dir; + AddSlash(strPath); + dlg->m_strPrefabPath = strPath; + dlg->UpdateData(FALSE); + free (dir); + } +} + +static void OnBtnBrowseuserini (GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + char *path = dlg->m_strUserPath; + if (strlen (path) == 0) + path = g_strGameToolsPath; + // TODO: INI filter? + const char *filename = file_dialog (g_PrefsDlg.GetWidget(), TRUE, "Find INI file", path); + + if (filename != NULL) + { + dlg->UpdateData(TRUE); + dlg->m_strUserPath = filename; + dlg->UpdateData(FALSE); + } +} + +static void OnButtonClean (GtkWidget *widget, gpointer data) +{ + // make sure this is what the user wants + if (gtk_MessageBox (g_PrefsDlg.GetWidget (), "This will close Radiant and clean the corresponding registry entries.\n" + "Next time you start Radiant it will be good as new. Do you wish to continue?", + "Reset Registry", MB_YESNO) == IDYES) + { + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->EndModal (IDCANCEL); + + g_qeglobals.disable_ini = true; + remove (dlg->m_inipath->str); + char buf[PATH_MAX]; + sprintf(buf, "%sSavedInfo.bin", dlg->m_rc_path->str); + remove(buf); + HandleCommand (NULL, GINT_TO_POINTER (ID_FILE_EXIT)); + _exit (0); + } +} + +// ============================================================================= +// PrefsDlg class + +// IMPORTANT NOTE: the values here don't matter very much +// the actual intialization if you start with an empty .ini is done when loading the prefs for the first time +// profile_load_int takes an argument to use if the value is not found +PrefsDlg::PrefsDlg () +{ + m_bWarn = TRUE; + m_nMouse = 1; + m_nView = MainFrame::eRegular; + m_bLoadLast = FALSE; + m_bInternalBSP = FALSE; + m_bRightClick = FALSE; + m_bSetGame = FALSE; + m_bAutoSave = TRUE; + m_nAutoSave = 5; + m_bLoadLastMap = FALSE; + m_bTextureWindow = FALSE; + m_bSnapShots = FALSE; + m_fTinySize = 0.5; + m_bCleanTiny = FALSE; + m_bCamXYUpdate = TRUE; + m_bCamDragMultiSelect = FALSE; + m_bCamFreeLook = TRUE; + m_bCamFreeLookStrafe = FALSE; + m_bCamInverseMouse = FALSE; + m_bCamDiscrete = TRUE; + m_bNewLightDraw = FALSE; + m_strPrefabPath = ""; + m_nWhatGame = 0; + m_bALTEdge = FALSE; + m_bFaceColors = FALSE; + m_bXZVis = FALSE; + m_bYZVis = FALSE; + m_bZVis = FALSE; + m_bSizePaint = FALSE; + m_bDLLEntities = FALSE; +#ifdef _WIN32 + m_bDetachableMenus = FALSE; // Most win32 users will find detachable menus annoying +#else + m_bDetachableMenus = TRUE; // Linux/Apple users are used to them... +#endif + m_bPatchToolbar = TRUE; + m_bWideToolbar = TRUE; + m_bPluginToolbar = TRUE; + m_bNoClamp = FALSE; + m_strUserPath = ""; + m_nRotation = 0; + m_bChaseMouse = FALSE; + m_bTextureScrollbar = TRUE; + m_bDisplayLists = TRUE; + m_bAntialiasedPointsAndLines = FALSE; // Fishman - Add antialiazed points and lines support. 09/03/00 + m_bShowShaders = FALSE; + m_nShader = -1; + m_bNoStipple = FALSE; + m_bVertexSplit = FALSE; + m_bSelectCurves = TRUE; + m_bSelectModels = TRUE; + m_nEntityShowState = ENTITY_SKINNED_BOXED; + m_nTextureScale = 2; + m_bSwitchClip = FALSE; + m_bSelectWholeEntities = TRUE; + m_nTextureQuality = 3; + m_bShowShaders = TRUE; + m_bGLLighting = FALSE; + m_nShader = 0; + m_nUndoLevels = 30; + m_bTexturesShaderlistOnly = FALSE; + // paths to ini files + m_rc_path = NULL; + m_inipath = NULL; + m_bWatchBSP = TRUE; + m_bLeakStop = TRUE; + m_iTimeout = 15; + m_bRunQuake = TRUE; + m_bDoSleep = FALSE; + m_nSubdivisions = 4; + // not prefs + m_bFloatingZ = FALSE; + m_bGlPtWorkaround = FALSE; // Gef: Kyro/GL_POINTS workaround 25-aug-2001 +#ifdef _WIN32 + m_bNativeGUI = FALSE; + m_bStartOnPrimMon = FALSE; +#endif + m_global_rc_path = NULL; +#ifdef _WIN32 + m_bUseWin32Editor = TRUE; +#else + // custom shader editor options + m_bUseCustomEditor = FALSE; + m_strEditorCommand = ""; +#endif + m_nLightRadiuses = 1; + m_bQ3Map2Texturing = TRUE; +#ifdef ATIHACK_812 + m_bGlATIHack = FALSE; +#endif +} + +/*! +========================================================= +Games selection dialog +========================================================= +*/ + +CGameDescription::CGameDescription(xmlDocPtr pDoc, const Str &GameFile) +{ + char *p, *prop; + mpDoc = pDoc; + // read the user-friendly game name + xmlNodePtr pNode = mpDoc->children; + + while (strcmp((const char*)pNode->name, "game") && pNode != NULL) pNode=pNode->next; + if (!pNode) + { + ///< \todo add the file name (this node and gametools should all be part of CGameDescription anyway) + Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL); + } + // on win32, game tools path can now be specified relative to the exe's cwd + prop = (char*)xmlGetProp( pNode, (xmlChar*)"gametools" ); + if ( prop == NULL ) { + Error( "Didn't find 'gametools' node in the game description file '%s'\n", pDoc->URL ); + } + { + char full[PATH_MAX]; +#ifdef _WIN32 + _fullpath( full, prop, PATH_MAX ); +#else + strncpy( full, prop, PATH_MAX ); +#endif + xmlFree( prop ); + prop = NULL; + for ( p = full; *p != '\0'; p++ ) { + if ( *p == '\\' ) { + *p = '/'; + } + mGameToolsPath = full; + if ( p != full && *(p-1) != '/' ) { + mGameToolsPath += "/"; + } + } + } + + prop = (char*)xmlGetProp(pNode, (xmlChar*)"name"); + if (prop == NULL) + { + Sys_FPrintf(SYS_WRN, "Warning, 'name' attribute not found in '%s'\n", pDoc->URL); + mGameName = pDoc->URL; + } + else + { + mGameName = prop; + xmlFree(prop); + } + + mGameFile = GameFile; + + prop = (char*)xmlGetProp(pNode, (xmlChar*)"basegame"); + if (prop == NULL) + { + // default + mBaseGame = "baseq3"; + } + else + { + mBaseGame = prop; + xmlFree(prop); + } + + // on win32, engine path can now be specified relative to the exe's cwd + prop = (char*)xmlGetProp(pNode, (const xmlChar *)"enginepath"); + if ( prop != NULL ) { + char full[PATH_MAX]; +#ifdef _WIN32 + _fullpath( full, prop, PATH_MAX ); +#else + strncpy( full, prop, PATH_MAX ); +#endif + xmlFree( prop ); + prop = NULL; + // process seperators + for ( p = full; *p != '\0'; p++ ) { + if ( *p == '\\' ) { + *p = '/'; + } + } + mEnginePath = full; + if ( p != full && *(p-1) != '/' ) { + mEnginePath += "/"; + } + } + else + { + // if engine path was not specified in the .game, it implies we can guess it from the gametools path + // on win32, and for most game package, the gametools are installed with the game + char aux_path[PATH_MAX]; // aux + strcpy( aux_path, mGameToolsPath.GetBuffer() ); + if ( ( aux_path[ strlen(aux_path)-1 ] == '/' ) || ( aux_path[ strlen(aux_path)-1 ] == '\\' ) ) { + aux_path[strlen(aux_path)-1] = '\0'; // strip ending '/' if any + } + char up_path[PATH_MAX]; // up one level + ExtractFilePath( aux_path, up_path ); + mEnginePath = up_path; + } + + prop = (char*)xmlGetProp(pNode, (xmlChar*)"engine"); + if (prop == NULL) + { +#ifdef _WIN32 + mEngine = "quake3.exe"; +#elif __linux__ + mEngine = "quake3"; +#elif __APPLE__ + mEngine = "Quake3.app"; +#endif + } + else + { + mEngine = prop; + xmlFree(prop); + } + +#if defined (__linux__) || defined (__APPLE__) + // *nix specific + prop = (char*)xmlGetProp(pNode, (const xmlChar *)"prefix"); + if(prop != NULL) + { + mUserPathPrefix = prop; + xmlFree(prop); + } +#endif + mShaderPath = xmlGetProp(pNode, (const xmlChar *)"shaderpath"); + if (!mShaderPath.GetLength()) + { + mShaderPath = "scripts/"; + mShaderlist = "scripts/shaderlist.txt"; + } + else + { + AddSlash(mShaderPath); + mShaderlist = mShaderPath; + mShaderlist += "shaderlist.txt"; + } + xmlChar* default_scale = xmlGetProp(pNode, (const xmlChar *)"default_scale"); + if (default_scale) + { + mTextureDefaultScale = atof((const char *)default_scale); + xmlFree(default_scale); + } + else + mTextureDefaultScale = 0.5f; + xmlChar* eclass_singleload = xmlGetProp(pNode, (const xmlChar*)"eclass_singleload"); + if (eclass_singleload) + { + mEClassSingleLoad = true; + xmlFree(eclass_singleload); + } + else + mEClassSingleLoad = false; + xmlChar* no_patch = xmlGetProp(pNode, (const xmlChar *)"no_patch"); + if (no_patch) + { + mNoPatch = true; + xmlFree(no_patch); + } + else + mNoPatch = false; + xmlChar* caulk_shader = xmlGetProp(pNode, (const xmlChar *)"caulk_shader"); + if (caulk_shader) + { + mCaulkShader = caulk_shader; + xmlFree(caulk_shader); + } + else + mCaulkShader = "textures/common/caulk"; +} + +void CGameDescription::Dump() +{ +#ifdef _WIN32 + if (CGameDialog::GetNetrun()) + Sys_Printf("Running in network mode, prefs path set to '%s'\n", g_strTempPath.GetBuffer()); +#endif + Sys_Printf("game name : '%s'\n", mGameName.GetBuffer()); + Sys_Printf("game file : '%s'\n", mGameFile.GetBuffer()); + Sys_Printf("game path : '%s'\n", mGameToolsPath.GetBuffer()); + Sys_Printf("base game : '%s'\n", mBaseGame.GetBuffer()); + Sys_Printf("engine path : '%s'\n", mEnginePath.GetBuffer()); + Sys_Printf("engine : '%s'\n", mEngine.GetBuffer()); + Sys_Printf("shaderlist : '%s'\n", mShaderlist.GetBuffer()); + Sys_Printf("caulk shader: '%s'\n", mCaulkShader.GetBuffer()); +#if defined (__linux__) || defined (__APPLE__) + Sys_Printf("prefix : '%s'\n", mUserPathPrefix.GetBuffer()); +#endif + Sys_Printf("default texture scale: %g\n", mTextureDefaultScale); + Sys_Printf("single eclass load : %s\n", mEClassSingleLoad ? "Yes" : "No"); + Sys_Printf("patches supported : %s\n", mNoPatch ? "No" : "Yes"); +} + +CPrefAssignment& CPrefAssignment::operator = (const CPrefAssignment& ass) +{ + if (&ass != this) + { + mName = ass.mName; + mType = ass.mType; + mVal = ass.mVal; + } + return *this; +} + +CPrefAssignment::CPrefAssignment(const CPrefAssignment& ass) +{ + *this = ass; +} + +void CGameDialog::LoadPrefs() +{ + bool bEmpty = false; + + // if we already have a document loaded, we will free and reload from file + if (mGlobalPrefs.InUse()) + { + Sys_Printf("Reloading global prefs from file\n"); + mGlobalPrefs.Clear(); + } + + // load global .pref file + CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; + strGlobalPref += "global.pref"; + + mGlobalPrefs.ReadXMLFile(strGlobalPref.GetBuffer()); + + mGlobalPrefs.GetPref("gamefile", &m_sGameFile, ""); // NOTE: there's no default, user HAS to select something + mGlobalPrefs.GetPref("autoload", &m_bAutoLoadGame, false); + mGlobalPrefs.GetPref("log console", &m_bLogConsole, false); + // in a very particular post-.pid startup + // we may have the console turned on and want to keep it that way + // so we use a latching system + if (m_bForceLogConsole) + { + m_bLogConsole = true; + Sys_Printf("console logging has been latched on, saving prefs\n"); + SavePrefs(); + m_bForceLogConsole = false; + } + + // console logging: call Sys_LogConsole to check console logging status + // it is important that we would log console as early as possible to make it useful + Sys_LogFile(); + + if (mGlobalPrefs.mbEmpty) + { + Sys_Printf("Saving global.pref with default pref values\n"); + SavePrefs(); + } +} + +void CGameDialog::SavePrefs() +{ + // update the tree and save it + mGlobalPrefs.UpdatePrefTree(); + + CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; + strGlobalPref += "global.pref"; + + if (!mGlobalPrefs.WriteXMLFile(strGlobalPref.GetBuffer())) + Sys_FPrintf(SYS_ERR, "Error occured while saving global prefs file '%s'\n", strGlobalPref.GetBuffer()); +} + +void CGameDialog::DoGameDialog() +{ + // show the UI + DoModal(); + + // unhook so we can use in other places + // we manually incref'ed it when creating, it won't be freed (destructor) + gtk_container_remove (GTK_CONTAINER (mTopBox), GetGlobalFrame()); + + // we save the prefs file + SavePrefs(); +} + +GtkWidget* CGameDialog::GetGlobalFrame() +{ + GtkWidget *vbox, *text, *combo, *check; + + if (mFrame) + return mFrame; + + mFrame = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(mFrame), 5); + gtk_widget_show(mFrame); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (mFrame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + text = gtk_label_new("Select the game:"); + gtk_widget_show(text); + gtk_box_pack_start (GTK_BOX(vbox), text, FALSE, FALSE, 0); + + combo = gtk_combo_new(); + gtk_widget_show(combo); + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); + + // fill in with the game descriptions + GList *combo_list = (GList*)NULL; + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + combo_list = g_list_append (combo_list, (void *)(*iGame)->mGameName.GetBuffer()); + } + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + g_list_free (combo_list); + + AddDialogData (combo, &m_nComboSelect, DLG_COMBO_INT); + + check = gtk_check_button_new_with_label("Auto load selected game on startup"); + gtk_widget_show(check); + gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bAutoLoadGame, DLG_CHECK_BOOL); + + text = gtk_label_new("(this frame is available in the prefs menu if you set auto-select)"); + gtk_widget_show(text); + gtk_box_pack_start (GTK_BOX(vbox), text, FALSE, FALSE, 0); + +#ifdef _WIN32 + check = gtk_check_button_new_with_label("Networked install - per-user settings"); + gtk_widget_show(check); + gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNetRun, DLG_CHECK_BOOL); +#endif + + check = gtk_check_button_new_with_label("Log the console to radiant.log"); + gtk_widget_show(check); + gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLogConsole, DLG_CHECK_BOOL); + + // incref it so we can pass it around + gtk_widget_ref (GTK_WIDGET(mFrame)); + + return mFrame; +} + +void CGameDialog::UpdateData (bool retrieve) +{ + if (!retrieve) + { + // use m_sGameFile to set m_nComboSelect + list::iterator iGame; + int i = 0; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + if ((*iGame)->mGameFile == m_sGameFile) + { + m_nComboSelect = i; + break; + } + i++; + } +#ifdef _WIN32 + UpdateNetrun(false); +#endif + } + Dialog::UpdateData(retrieve); + if (retrieve) + { + // use m_nComboSelect to set m_sGameFile + list::iterator iGame = mGames.begin(); + int i; + for(i=0; imGameFile; +#ifdef _WIN32 + UpdateNetrun(true); +#endif + } +} + +void CGameDialog::BuildDialog() +{ + GtkWidget *dlg, *vbox1, *button; + + dlg = m_pWidget; + gtk_window_set_title (GTK_WINDOW (dlg), "Select Game"); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show(vbox1); + gtk_container_add (GTK_CONTAINER (dlg), vbox1); + + gtk_container_add (GTK_CONTAINER (vbox1), GetGlobalFrame()); + mTopBox = vbox1; + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 0); + AddModalButton(button, IDOK); + gtk_widget_set_usize (button, 60, -2); +} + +void CGameDialog::ScanForGames() +{ + CString strPath; + char *dirlist; + GDir *dir; + CString strGamesPath = g_strAppPath.GetBuffer(); + strGamesPath += "games"; + const char *path = strGamesPath.GetBuffer(); + + Sys_Printf("Scanning for game description files: %s\n", path); + + /*! + \todo FIXME LINUX: + do we put game description files below g_strAppPath, or in ~/.radiant + i.e. read only or read/write? + my guess .. readonly cause it's an install + we will probably want to add ~/.radiant//games/ scanning on top of that for developers + (if that's really needed) + */ + + // FIXME need to catch the 'no game description' situation and exit with a clean error + + dir = g_dir_open(path, 0, NULL); + + if (dir != NULL) + { + while (1) + { + const gchar* name = g_dir_read_name(dir); + if(name == NULL) + break; + + dirlist = g_strdup(name); +#ifdef _WIN32 + strlwr (dirlist); +#endif + char *ext = strrchr (dirlist, '.'); + if ((ext == NULL) || (strcmp (ext, ".game") != 0)) + continue; + strPath.Format("%s/%s", path, dirlist); + Sys_Printf("%s\n", strPath.GetBuffer()); + // got one, load it + xmlDocPtr pDoc = xmlParseFile(strPath.GetBuffer()); + if (pDoc) + { + mGames.push_front(new CGameDescription(pDoc, dirlist)); + } + else + { + Sys_FPrintf(SYS_ERR, "XML parser failed on '%s'\n", strPath.GetBuffer()); + } + + g_free(dirlist); + } + g_dir_close (dir); + } +} + +CGameDescription* CGameDialog::GameDescriptionForComboItem() +{ + list::iterator iGame; + int i=0; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++,i++) + { + if (i == m_nComboSelect) + { + return (*iGame); + } + } + return NULL; // not found +} + +/*GString* CGameDialog::InitGlobalPrefPath() +{ + GString* global_rc_path; + // configure m_global_rc_path +#if defined (__linux__) || defined (__APPLE__) + global_rc_path = g_string_new (g_get_home_dir ()); + + if (global_rc_path->str[global_rc_path->len-1] != '/') + g_string_append (global_rc_path, "/"); + + g_string_append (global_rc_path, ".radiant/"); + mkdir (global_rc_path->str, 0775); + g_string_append (global_rc_path, RADIANT_VERSION); + g_string_append (global_rc_path, "/"); + mkdir (global_rc_path->str, 0775); +#elif WIN32 + global_rc_path = g_string_new (g_strAppPath.GetBuffer() ); +#else +#error "WTF are you compiling under" +#endif + return global_rc_path; +}*/ + +void CGameDialog::InitGlobalPrefPath() +{ + GString *global_rc_path; + // configure m_global_rc_path + // this is the g_strTempPath, and it has already been mkdir'ed + global_rc_path = g_string_new(g_strTempPath.GetBuffer()); + g_PrefsDlg.m_global_rc_path = global_rc_path; +} + +void CGameDialog::Reset() +{ + if (!g_PrefsDlg.m_global_rc_path) + InitGlobalPrefPath(); + CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; + strGlobalPref += "global.pref"; + remove(strGlobalPref.GetBuffer()); +} + +void CGameDialog::Init() +{ + InitGlobalPrefPath(); + ScanForGames(); + if (mGames.empty()) + { + Error("Didn't find any valid game file descriptions, aborting\n"); + } + LoadPrefs(); + if (m_bAutoLoadGame) + { + // search by .game name + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + if ((*iGame)->mGameFile == m_sGameFile) + { + m_pCurrentGameDescription = (*iGame); + break; + } + } + } + if (!m_bAutoLoadGame || !m_pCurrentGameDescription) + { + DoGameDialog(); + // use m_nComboSelect to identify the game to run as and set the globals + m_pCurrentGameDescription = GameDescriptionForComboItem(); + if (!m_pCurrentGameDescription) + Error("Lookup of game description object failed, can't continue\n"); + } + g_pGameDescription = m_pCurrentGameDescription; + + g_strGameToolsPath = g_pGameDescription->mGameToolsPath; + + // NOTE TTimo: this is moved from QE_LoadProject in 1.2 + // (probably broken) + // NOTE Hydra: was broken for win32, we don't use m_strHomeGame or m_strFSBasePath +#if defined (__linux__) || defined (__APPLE__) + g_qeglobals.m_strHomeGame = g_get_home_dir(); + g_qeglobals.m_strHomeGame += "/"; + g_qeglobals.m_strHomeGame += m_pCurrentGameDescription->mUserPathPrefix.GetBuffer(); + g_qeglobals.m_strHomeGame += "/"; +#else + g_qeglobals.m_strHomeGame = g_pGameDescription->mEnginePath.GetBuffer(); +#endif + + g_pGameDescription->Dump(); +} + +CGameDialog::~CGameDialog() +{ + if (mFrame) + { + // NOTE I'm not too sure how reliable this is + gtk_widget_unref(GTK_WIDGET(mFrame)); + } + // free all the game descriptions + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + delete (*iGame); + *iGame = NULL; + } +} + +void CGameDialog::AddPacksURL(Str &URL) +{ + // add the URLs for the list of game packs installed + // FIXME: this is kinda hardcoded for now.. + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + if ((*iGame)->mGameFile == "q3.game") + URL += "&Games_dlup%5B%5D=1"; + else if ((*iGame)->mGameFile == "wolf.game") + URL += "&Games_dlup%5B%5D=2"; + else if ((*iGame)->mGameFile == "wolf.game") + URL += "&Games_dlup%5B%5D=3"; + else if ((*iGame)->mGameFile == "jk2.game") + URL += "&Games_dlup%5B%5D=4"; + else if ((*iGame)->mGameFile == "stvef.game") + URL += "&Games_dlup%5B%5D=5"; + else if ((*iGame)->mGameFile == "sof2.game") + URL += "&Games_dlup%5B%5D=6"; + else if ((*iGame)->mGameFile == "ja.game") + URL += "&Games_dlup%5B%5D=7"; + } +} + +#ifdef _WIN32 + +#define NETRUN_FILENAME "netrun.conf" + +bool CGameDialog::m_bNetRun; + +void CGameDialog::UpdateNetrun(bool retrieve) +{ + FILE *f_netrun; + CString strNetrun; + strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; + if (!retrieve) + { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + // now check if we are running from a network installation + // use a dummy file as the flag + f_netrun = fopen(strNetrun.GetBuffer(), "r"); + if (f_netrun) + { + fclose(f_netrun); + m_bNetRun = true; + } + else + m_bNetRun = false; + } + else + { + if (m_bNetRun) + { + f_netrun = fopen(strNetrun.GetBuffer(), "w"); + if (!f_netrun) + { + Sys_FPrintf(SYS_ERR, "ERROR: Failed to create netrun file '%s'\n", strNetrun.GetBuffer()); + m_bNetRun = false; + } + else + { + fclose(f_netrun); + Sys_Printf("Created/Checked '%s'\n", strNetrun.GetBuffer()); + } + } + else + { + if (remove(strNetrun.GetBuffer()) == -1) + { + if (errno != ENOENT) + Sys_FPrintf(SYS_ERR, "Failed to remove netrun file '%s'\n", strNetrun.GetBuffer()); + m_bNetRun = true; + } + else + { + Sys_Printf("Netrun mode is disabled\n"); + } + } + } +} + +bool CGameDialog::GetNetrun() +{ + return m_bNetRun; +} +#endif + +/* +======== + +very first prefs init deals with selecting the game and the game tools path +then we can load .ini stuff + +using prefs / ini settings: +those are per-game + +win32: +look in g_strGameToolsPath for .ini + +linux: +look in ~/.radiant//gamename +======== +*/ + +#define PREFS_LOCAL_FILENAME "local.pref" + +void PrefsDlg::Init() +{ + mGamesDialog.Init(); + + // m_global_rc_path has been set above, do m_rc_path with game specific stuff now + // the win32 and linux versions have been unified for network mode +#ifdef _WIN32 + if (!CGameDialog::GetNetrun()) + { + // legacy prefs settings, this goes where the game pack is installed + m_rc_path = g_string_new (g_strGameToolsPath.GetBuffer() ); + m_inipath = g_string_new (m_rc_path->str); + g_string_append (m_inipath, PREFS_LOCAL_FILENAME); + return; + } +#endif + // this is common to win32 and Linux init now + m_rc_path = g_string_new (m_global_rc_path->str); + + // game sub-dir + g_string_append (m_rc_path, g_pGameDescription->mGameFile.GetBuffer()); + g_string_append (m_rc_path, "/"); + Q_mkdir (m_rc_path->str, 0775); + + // then the ini file + m_inipath = g_string_new (m_rc_path->str); + g_string_append (m_inipath, PREFS_LOCAL_FILENAME); + +} + +void PrefsDlg::UpdateData (bool retrieve) +{ + // leo: the "changed" signal confuses the update function + if (m_pWidget == NULL) + return; + mGamesDialog.UpdateData (retrieve); + Dialog::UpdateData (retrieve); +} + +#ifdef _WIN32 +#define PREFSHSPACE 5 +#else +#define PREFSHSPACE 0 +#endif + +static void UpdateSensitivity( GtkWidget *widget, gpointer data ) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->DoSensitivity(); +} + +static void UpdateEditorSensitivity(GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->DoEditorSensitivity(); +} + +// start new prefs dialog + +/*! Utility function for swapping notebook pages for tree list selections */ +void PrefsDlg::showPrefPage(int prefpage) +{ + if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != prefpage) + gtk_notebook_set_page(GTK_NOTEBOOK(notebook), prefpage); + + return; +} + +static void treeSelection(GtkTreeSelection* selection, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + int prefpage; + gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1); + dlg->showPrefPage(prefpage); + } +} + +void PrefsDlg::BuildDialog () +{ + // Main Preferences dialog + GtkWidget *dialog, *mainvbox, *hbox, *sc_win, *preflabel; + + // Widgets on notebook pages + GtkWidget *check, *label, *scale, *hbox2, *combo, + *table, *spin, *entry, *pixmap, + *radio, *button, *pageframe, *vbox; + + GList *combo_list = (GList*)NULL; + + GtkObject *adj; + + dialog = m_pWidget; + gtk_window_set_title(GTK_WINDOW(dialog), "GtkRadiant Preferences"); + gtk_widget_realize(dialog); + + mainvbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(dialog), mainvbox); + gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5); + gtk_widget_show(mainvbox); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_widget_show(hbox); + gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label("OK"); + gtk_widget_show(button); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize(button, 60, -2); + AddModalButton(button, IDOK); + + button = gtk_button_new_with_label("Cancel"); + gtk_widget_show(button); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize(button, 60, -2); + AddModalButton (button, IDCANCEL); + + button = gtk_button_new_with_label ("Clean"); + gtk_widget_show(button); + gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(OnButtonClean), this); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0); + gtk_widget_show(hbox); + + sc_win = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0); + gtk_widget_show(sc_win); + + // prefs pages notebook + notebook = gtk_notebook_new(); + // hide the notebook tabs since its not supposed to look like a notebook + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE); + gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 0); + gtk_widget_show(notebook); + + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN); + + { + GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (sc_win), view); + + { + /********************************************************************/ + /* Add preference tree options */ + /********************************************************************/ + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Globals", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Game settings", 1, (gpointer)PTAB_GAME_SETTINGS, -1); + } + } + + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Display", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "2D Display/Rendering", 1, (gpointer)PTAB_2D, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "3D View", 1, (gpointer)PTAB_CAMERA, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Texture Settings", 1, (gpointer)PTAB_TEXTURE, -1); + } + } + + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Interface", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Layout", 1, (gpointer)PTAB_LAYOUT, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Mouse", 1, (gpointer)PTAB_MOUSE, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Editing", 1, (gpointer)PTAB_EDITING, -1); + } + } + + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Other", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Startup/Auto save", 1, (gpointer)PTAB_STARTUP, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Paths", 1, (gpointer)PTAB_PATHS, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Misc", 1, (gpointer)PTAB_MISC, -1); + } + if (!g_qeglobals.bBSPFrontendPlugin) + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "BSP Monitoring", 1, (gpointer)PTAB_BSPMONITOR, -1); + } + } + } + + gtk_tree_view_expand_all(GTK_TREE_VIEW(view)); + + g_object_unref(G_OBJECT(store)); + } + + /**********************************************************************/ + /* build the prefs pages */ + /**********************************************************************/ + + // Front page... + // todo : add something interesting here + // NOTE TTimo: tip of the day? or a logo? + preflabel = gtk_label_new("Front Page"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_widget_set_usize(GTK_WIDGET(vbox), 350, -2); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** global preferences group ****************************/ + preflabel = gtk_label_new("Globals"); + gtk_widget_show(preflabel); + + pageframe = mGamesDialog.GetGlobalFrame(); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** 2D prefs group (xy views/rendering options) *********/ + preflabel = gtk_label_new("2D Display"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("2D Display"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // OpenGL Display Lists + check = gtk_check_button_new_with_label("OpenGL Display Lists"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData(check, &m_bDisplayLists, DLG_CHECK_BOOL); + + // Antialiased points & lines + // Fishman - Add antialiazed points and lines support. 09/03/00 + check = gtk_check_button_new_with_label ("OpenGL antialiased points and lines"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bAntialiasedPointsAndLines, DLG_CHECK_BOOL); + + // Solid selection boxes + check = gtk_check_button_new_with_label ("Solid selection boxes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNoStipple, DLG_CHECK_BOOL); + + // Display size info + check = gtk_check_button_new_with_label ("Display size info"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bSizePaint, DLG_CHECK_BOOL); + + // Alternate vertex/edge handles + // Gef: Kyro GL_POINT work around 25-aug-2001 + check = gtk_check_button_new_with_label ("Alternate vertex/edge handles"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData(check, &m_bGlPtWorkaround, DLG_CHECK_BOOL); + + g_list_free (combo_list); + +#ifdef ATIHACK_812 + // ATI bugs + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=812 + check = gtk_check_button_new_with_label ("ATI cards with broken drivers - bug #802"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData(check, &m_bGlATIHack, DLG_CHECK_BOOL); +#endif + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** 3D Camera view group *********/ + preflabel = gtk_label_new("3D View"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("3D View"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Directional velocity (Movement Velocity) + // label container + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new("Movement Velocity"); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); + + // adjustment + adj = gtk_adjustment_new(100, 50, 300, 1, 10, 10); + AddDialogData(adj, &m_nMoveSpeed, DLG_ADJ_INT); + + // scale + scale = gtk_hscale_new(GTK_ADJUSTMENT(adj)); + gtk_widget_show(scale); + gtk_box_pack_start(GTK_BOX (vbox), scale, FALSE, TRUE, 2); + + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + + // Angular velocity (Rotational Velocity) + // label container + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("Rotational Velocity"); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_widget_show (label); + gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); + + // adjustment + adj = gtk_adjustment_new (3, 1, 180, 1, 10, 10); // value, low, high, step, page_step, page_size + AddDialogData (adj, &m_nAngleSpeed, DLG_ADJ_INT); + + // scale + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 2); + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + + // Text under the velocity sliders + // container + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("slow"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("fast"); + gtk_widget_show (label); + gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // Allow drag to select multiple faces/brushes + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Use paint-select in camera view:"); + gtk_widget_show (label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)"No"); + combo_list = g_list_append (combo_list, (void *)"Yes"); + combo_list = g_list_append (combo_list, (void *)"Yes (Classic Key Setup)"); + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nCamDragMultiSelect, DLG_COMBO_INT); + + // Freelook in Camera view + check = gtk_check_button_new_with_label ("Freelook in Camera view"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamFreeLook, DLG_CHECK_BOOL); + + // Freelook in Camera view w/ forward & back strafing instead of up and down looking + check = gtk_check_button_new_with_label ("Freelook strafes Forward and Back"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamFreeLookStrafe, DLG_CHECK_BOOL); + + // Invert mouse in freelook + check = gtk_check_button_new_with_label ("Invert mouse in freelook"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamInverseMouse, DLG_CHECK_BOOL); + + // Discrete movement + check = gtk_check_button_new_with_label ("Discrete movement"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamDiscrete, DLG_CHECK_BOOL); + + // Update XY views on camera move + check = gtk_check_button_new_with_label ("Update XY views on camera move"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamXYUpdate, DLG_CHECK_BOOL); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Texture group *********/ + preflabel = gtk_label_new("Textures"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Textures"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 6); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Texture quality slider + // label + label = gtk_label_new ("Texture quality"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + // adjustment + adj = gtk_adjustment_new (0, 0, 4, 1, 1, 1); + AddDialogData (adj, &m_nLatchedTextureQuality, DLG_ADJ_INT); + + // scale + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0); + gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); + + // text under the texture slider + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + label = gtk_label_new ("low"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + label = gtk_label_new ("high"); + gtk_widget_show (label); + gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // texture subsets + check = gtk_check_button_new_with_label ("Texture subsets"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bTextureWindow, DLG_CHECK_BOOL); + + // texture scrollbar + check = gtk_check_button_new_with_label ("Texture scrollbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bTextureScrollbar, DLG_CHECK_BOOL); + + // texture increment matches grid + check = gtk_check_button_new_with_label ("Tex increment matches grid"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bSnapTToGrid, DLG_CHECK_BOOL); + + // RIANT + // Texture compression choice label + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Texture Compression (if available):"); + gtk_widget_show (label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + // Texture compression choice label + combo_list = NULL; + // NONE will always be in pos 0 + combo_list = g_list_append (combo_list, (void *)"None"); + + // if OpenGL compression is enabled it will always be + // in pos 1 + if (g_qeglobals.m_bOpenGLCompressionSupported) + { + combo_list = g_list_append (combo_list, (void *)"OpenGL ARB"); + } + + // If S3 is enabled offer all 3 valid compression schemes in RGBA + if (g_qeglobals.m_bS3CompressionSupported) + { + combo_list = g_list_append (combo_list, (void *)"S3TC DXT1"); + combo_list = g_list_append (combo_list, (void *)"S3TC DXT3"); + combo_list = g_list_append (combo_list, (void *)"S3TC DXT5"); + } + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nTextureCompressionFormat, DLG_COMBO_INT); + g_list_free (combo_list); + + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // Startup shaders + // label + label = gtk_label_new ("Startup Shaders:"); + gtk_widget_show (label); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + // combo list + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)"None"); + if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + combo_list = g_list_append (combo_list, (void *)"System"); + else if (g_pGameDescription->mGameFile == "sof2.game") + combo_list = g_list_append (combo_list, (void *)"Tools"); + else + combo_list = g_list_append (combo_list, (void *)"Common"); + combo_list = g_list_append (combo_list, (void *)"All"); + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nLatchedShader, DLG_COMBO_INT); + g_list_free (combo_list); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Layout group *********/ + preflabel = gtk_label_new("Layout"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Layout"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // View types + // table + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // view type 1 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window1.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 2 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window2.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 3 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window3.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 4 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window4.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 3, 4, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 1 selector + radio = gtk_radio_button_new (NULL); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 2 selector + radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 3 selector + radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 2, 3, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 4 selector + radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 3, 4, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (radio, &m_nLatchedView, DLG_RADIO_INT); + + // Floating Z window + check = gtk_check_button_new_with_label ("Floating Z Window"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedFloatingZ, DLG_CHECK_BOOL); + + // show menu tear-off seperators + check = gtk_check_button_new_with_label ("Detachable Menus"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedDetachableMenus, DLG_CHECK_BOOL); + + if (!g_pGameDescription->mNoPatch) + { + // show patch toolbar + check = gtk_check_button_new_with_label ("Patch Toolbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_patchtoolbar", check); // Allow to be disabled for Q1/Q2 + AddDialogData (check, &m_bLatchedPatchToolbar, DLG_CHECK_BOOL); + } + + // use wide toolbar + check = gtk_check_button_new_with_label ("Wide Toolbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedWideToolbar, DLG_CHECK_BOOL); + + // use plugin toolbar + check = gtk_check_button_new_with_label ("Plugin Toolbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedPluginToolbar, DLG_CHECK_BOOL); + +#ifdef _WIN32 + // win32 file dialog + check = gtk_check_button_new_with_label ("Use win32 file load dialog"); + gtk_widget_show (check); + // gtk_container_add (GTK_CONTAINER (vbox), check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNativeGUI, DLG_CHECK_BOOL); + + // position on primary monitor + check = gtk_check_button_new_with_label ("Start on Primary Monitor"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_startonprimary", check); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); + AddDialogData (check, &m_bStartOnPrimMon, DLG_CHECK_BOOL); +#endif + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Mouse group *********/ + preflabel = gtk_label_new("Mouse"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Mouse"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Buttons + // container + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); + + // 2 button radio + radio = gtk_radio_button_new_with_label (NULL, "2 button"); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (hbox2), radio, FALSE, FALSE, 0); + + // 3 button radio + radio = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio), "3 button"); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (hbox2), radio, FALSE, FALSE, 0); + AddDialogData (radio, &m_nMouse, DLG_RADIO_INT); + + // right click to drop entity + check = gtk_check_button_new_with_label ("Right click to drop entities"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bRightClick, DLG_CHECK_BOOL); + + // Mouse chaser (and this does what?) + check = gtk_check_button_new_with_label ("Mouse chaser"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bChaseMouse, DLG_CHECK_BOOL); + + // Alt + multi-drag + check = gtk_check_button_new_with_label ("ALT + multi-drag"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bALTEdge, DLG_CHECK_BOOL); + + // Mouse wheel increments + // container + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("Wheel Mouse inc:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize (entry, 40, -2); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + AddDialogData (entry, &m_nWheelInc, DLG_ENTRY_INT); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Editing group *********/ + preflabel = gtk_label_new("Editing"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Editing"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Vertex editing splits faces + check = gtk_check_button_new_with_label ("Vertex editing splits face"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bVertexSplit, DLG_CHECK_BOOL); + + // Fix target/targetname collisions + check = gtk_check_button_new_with_label ("Fix target/targetname collisions"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bDoTargetFix, DLG_CHECK_BOOL); + + // Clipper tool uses caulk + check = gtk_check_button_new_with_label ("Clipper tool uses caulk"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bClipCaulk, DLG_CHECK_BOOL); + + // Don't clamp plane points + check = gtk_check_button_new_with_label ("Don't clamp plane points"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNoClamp, DLG_CHECK_BOOL); + + // Select patch by bounding box + check = gtk_check_button_new_with_label ("Select patches by bounding box"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bPatchBBoxSelect, DLG_CHECK_BOOL); + + // Rotation increment + // container + table = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // label + label = gtk_label_new ("Rotation increment:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize (entry, 60, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_nRotation, DLG_ENTRY_INT); + + // Undo levels + // label + label = gtk_label_new ("Undo Levels:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // spinner (allows undo levels to be set to zero) + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 0, 64, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nUndoLevels, DLG_SPIN_INT); + + // Patch subdivisions + // label + label = gtk_label_new ("Patch subdivisions:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // entry (spinner perhaps? [2-16]) + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize (entry, 60, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_nSubdivisions, DLG_ENTRY_INT); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Save/Load group *********/ + preflabel = gtk_label_new("Startup/Auto save"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Startup/Auto save"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Snapshots + check = gtk_check_button_new_with_label ("Snapshots"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bSnapShots, DLG_CHECK_BOOL); + + // load last project on open + check = gtk_check_button_new_with_label ("Load last project on open"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLoadLast, DLG_CHECK_BOOL); + + // load last map on open + check = gtk_check_button_new_with_label ("Load last map on open"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLoadLastMap, DLG_CHECK_BOOL); + + // Auto save.. + // container + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0); + + // label + check = gtk_check_button_new_with_label ("Auto save every"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (hbox2), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bAutoSave, DLG_CHECK_BOOL); + + // spinner + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 60, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, FALSE, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nAutoSave, DLG_SPIN_INT); + + // label + label = gtk_label_new ("minutes"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Paths group *********/ + preflabel = gtk_label_new("Paths"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Paths"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // prefab path + // table + table = gtk_table_new (3, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // label + label = gtk_label_new ("Prefab path:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + // path entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize(GTK_WIDGET(entry), 240, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 1, 0); + AddDialogData (entry, &m_strPrefabPath, DLG_ENTRY_TEXT); + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=805 +#if 0 + // browse button + button = gtk_button_new_with_label ("..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseprefab), this); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); +#endif + + // User ini path + // label + label = gtk_label_new ("User INI path:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + // user ini path entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 1, 0); + AddDialogData (entry, &m_strUserPath, DLG_ENTRY_TEXT); + + // user ini browse button + button = gtk_button_new_with_label ("..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseuserini), this); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Misc group *********/ + preflabel = gtk_label_new("Misc"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Misc"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Light drawing + check = gtk_check_button_new_with_label ("Light drawing"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNewLightDraw, DLG_CHECK_BOOL); + + // Light radiuses + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Light radiuses:"); + gtk_widget_show (label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)"Disabled"); + combo_list = g_list_append (combo_list, (void *)"True Q3Map2 Style"); + combo_list = g_list_append (combo_list, (void *)"Classic Style"); + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nLightRadiuses, DLG_COMBO_INT); + +#ifdef _WIN32 + check = gtk_check_button_new_with_label ("Use win32 file associations to open text files instead of builtin editor"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &g_PrefsDlg.m_bUseWin32Editor, DLG_CHECK_BOOL); +#else + // use custom shader editor + check = gtk_check_button_new_with_label ("Use Custom Shader Editor"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateEditorSensitivity), this); + g_object_set_data (G_OBJECT(dialog), "check_customeditor", check); + AddDialogData (check, &g_PrefsDlg.m_bUseCustomEditor, DLG_CHECK_BOOL); + + // custom shader editor executable + // table + table = gtk_table_new (3, 1, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // label + label = gtk_label_new("Custom Editor Command"); + gtk_widget_show(label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT(dialog), "label_customeditor", label); + gtk_widget_set_sensitive (label, g_PrefsDlg.m_bUseCustomEditor); + + // custom editor command entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize(GTK_WIDGET(entry), 240, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 1, 0); + AddDialogData (entry, &m_strEditorCommand, DLG_ENTRY_TEXT); + gtk_widget_set_sensitive (entry, g_PrefsDlg.m_bUseCustomEditor); + g_object_set_data (G_OBJECT(dialog), "entry_customeditor", entry); + + // browse button + button = gtk_button_new_with_label ("..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseEditor), this); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + g_object_set_data (G_OBJECT(dialog), "button_customeditor", button); + gtk_widget_set_sensitive (button, g_PrefsDlg.m_bUseCustomEditor); +#endif + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** BSP Monitoring group *********/ + // this is never displayed if the plugin isn't available + preflabel = gtk_label_new("BSP Monitoring"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("BSP Monitoring"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Enable BSP process monitoring + check = gtk_check_button_new_with_label ("Enable BSP process monitoring"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_monitorbsp", check); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); + AddDialogData (check, &g_PrefsDlg.m_bWatchBSP, DLG_CHECK_BOOL); + + // Stop on leak + check = gtk_check_button_new_with_label ("Stop compilation on leak"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_leakstop", check); + AddDialogData (check, &g_PrefsDlg.m_bLeakStop, DLG_CHECK_BOOL); + + // engine after compile + check = gtk_check_button_new_with_label ("Run engine after compile"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_runengine", check); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); + AddDialogData( check, &g_PrefsDlg.m_bRunQuake, DLG_CHECK_BOOL ); + + // sleep mode when running engine + check = gtk_check_button_new_with_label ("Activate sleep mode when running the engine"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_sleep", check); + AddDialogData( check, &g_PrefsDlg.m_bDoSleep, DLG_CHECK_BOOL ); + + // use q3map2's texture projection + check = gtk_check_button_new_with_label ("Texturing compatible with q3map2"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_q3map2", check); + AddDialogData( check, &g_PrefsDlg.m_bQ3Map2Texturing, DLG_CHECK_BOOL ); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + gtk_notebook_set_page(GTK_NOTEBOOK(notebook), PTAB_FRONT); + + return; +} + +// end new prefs dialog + +void PrefsDlg::LoadTexdefPref(texdef_t* pTexdef, char* pName) +{ + char buffer[256]; + + memset(pTexdef, 0, sizeof(texdef_t)); + + sprintf(buffer, "%s%s", pName, TD_SCALE1_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->scale[0], 0.5f); + + sprintf(buffer, "%s%s", pName, TD_SCALE2_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->scale[1], 0.5f); + + sprintf(buffer, "%s%s", pName, TD_SHIFT1_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->shift[0], 8.f); + + sprintf(buffer, "%s%s", pName, TD_SHIFT2_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->shift[1], 8.f); + + sprintf(buffer, "%s%s", pName, TD_ROTATE_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->rotate, 45); +} + +void PrefsDlg::UpdateTextureCompression() +{ + // if OpenGL is not ready yet, don't do anything + if (!g_qeglobals.m_bOpenGLReady) { + Sys_Printf("OpenGL not ready - postpone texture compression capability check\n"); + return; + } + + if (g_qeglobals.bTextureCompressionSupported) + { + if (m_nTextureCompressionFormat >= 2 && !g_qeglobals.m_bS3CompressionSupported) + { + Sys_Printf("Inconsistant pref setting for texture compression (%d), rolling back\n", m_nTextureCompressionFormat); + m_nTextureCompressionFormat = 1; // if this is not supported either, see below + } + if (m_nTextureCompressionFormat == 1 && !g_qeglobals.m_bOpenGLCompressionSupported) + { + Sys_Printf("Inconsistant pref setting for texture compression (GL_COMPRESSED_RGBA), rolling back\n"); + m_nTextureCompressionFormat = 0; + } + switch (m_nTextureCompressionFormat) + { + case (0): + { + g_qeglobals.texture_components = GL_RGBA; + Sys_Printf("texture compression disabled by preferences settings\n"); + break; + } + case (1): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA; + Sys_Printf("OpenGL texture compression enabled\n"); + break; + } + case (2): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + Sys_Printf("S3TC DXT1 texture compression enabled\n"); + break; + } + case (3): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + Sys_Printf("S3TC DXT3 texture compression enabled\n"); + break; + } + case (4): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + Sys_Printf("S3TC DXT5 texture compression enabled\n"); + break; + } + } + } + else + { + Sys_Printf("texture compression is not supported by your current graphic card/drivers\n"); + g_qeglobals.texture_components = GL_RGBA; + m_nTextureCompressionFormat = 0; + } +} + +#ifdef ATIHACK_812 +void PrefsDlg::UpdateATIHack() { + // if OpenGL is not ready yet, don't do anything + if (!g_qeglobals.m_bOpenGLReady) { + Sys_Printf("OpenGL not ready - postpone ATI bug workaround setup\n"); + return; + } + + if (m_bGlATIHack) { + qglCullFace = &qglCullFace_ATIHack; + qglDisable = &qglDisable_ATIHack; + qglEnable = &qglEnable_ATIHack; + qglPolygonMode = &qglPolygonMode_ATIHack; + Sys_Printf("ATI bug workaround enabled\n"); + } else { + qglCullFace = qglCullFace_real; + qglDisable = qglDisable_real; + qglEnable = qglEnable_real; + qglPolygonMode = qglPolygonMode_real; + Sys_Printf("ATI bug workaround disabled\n"); + } +} +#endif + +// TTimo: m_strEnginePath has a special status, if not found in registry we need to +// initiliaze it for sure. It is not totally failsafe but we can use the same +// code than in q3map, expecting to find some "quake" above us. If not, we prompt +// for the engine executable path +void PrefsDlg::LoadPrefs () +{ + int i; + + // first things first, load prefs from global prefs + mGamesDialog.LoadPrefs(); + + // if we already have a document loaded, we will free and reload from file + if (mLocalPrefs.InUse()) { + mLocalPrefs.Clear(); + } + + // load local.pref file + mLocalPrefs.ReadXMLFile(m_inipath->str); + + mLocalPrefs.GetPref(PATCHSHOWBOUNDS_KEY, &g_bPatchShowBounds, FALSE); + mLocalPrefs.GetPref(MOUSE_KEY, &m_nMouse, MOUSE_DEF); + m_nMouseButtons = m_nMouse ? 3 : 2; + + // project file + // if it's not found here, mainframe.cpp will take care of finding one + mLocalPrefs.GetPref(LASTPROJ_KEY, &m_strLastProject, ""); + mLocalPrefs.GetPref(LASTPROJVER_KEY, &m_nLastProjectVer, -1); + + // prefab path + // NOTE TTimo: I'm not sure why this is in prefs + // should probably be a project setting + // and I'm not sure that we really have a way to set this reliably either + CString strPrefab; + strPrefab = g_qeglobals.m_strHomeGame.GetBuffer(); + strPrefab += g_pGameDescription->mBaseGame.GetBuffer(); + strPrefab += "/prefabs/"; + mLocalPrefs.GetPref(PREFAB_KEY, &m_strPrefabPath, strPrefab); + + mLocalPrefs.GetPref(LASTLIGHTINTENSITY_KEY, &m_iLastLightIntensity, 300); + mLocalPrefs.GetPref(TLOCK_KEY, &m_bTextureLock, TLOCK_DEF); + mLocalPrefs.GetPref(RLOCK_KEY, &m_bRotateLock, TLOCK_DEF); + mLocalPrefs.GetPref(LASTMAP_KEY, &m_strLastMap, ""); + mLocalPrefs.GetPref(LOADLAST_KEY, &m_bLoadLast, LOADLAST_DEF); + mLocalPrefs.GetPref(BSP_KEY, &m_bInternalBSP, FALSE); + mLocalPrefs.GetPref(RCLICK_KEY, &m_bRightClick, TRUE); + mLocalPrefs.GetPref(AUTOSAVE_KEY, &m_bAutoSave, TRUE); + mLocalPrefs.GetPref(LOADLASTMAP_KEY, &m_bLoadLastMap, FALSE); + mLocalPrefs.GetPref(TINYBRUSH_KEY, &m_bCleanTiny, FALSE); + mLocalPrefs.GetPref(TINYSIZE_KEY, &m_fTinySize, 0.5f); + mLocalPrefs.GetPref(AUTOSAVETIME_KEY, &m_nAutoSave, 5); + mLocalPrefs.GetPref(SNAPSHOT_KEY, &m_bSnapShots, FALSE); + mLocalPrefs.GetPref(MOVESPEED_KEY, &m_nMoveSpeed, 100); + mLocalPrefs.GetPref(ANGLESPEED_KEY, &m_nAngleSpeed, 3); + mLocalPrefs.GetPref(SETGAME_KEY, &m_bSetGame, FALSE); + mLocalPrefs.GetPref(CAMXYUPDATE_KEY, &m_bCamXYUpdate, TRUE); + mLocalPrefs.GetPref(CAMDRAGMULTISELECT_KEY, &m_nCamDragMultiSelect, TRUE); + mLocalPrefs.GetPref(CAMFREELOOK_KEY, &m_bCamFreeLook, TRUE); + mLocalPrefs.GetPref(CAMINVERSEMOUSE_KEY, &m_bCamInverseMouse, FALSE); + mLocalPrefs.GetPref(CAMDISCRETE_KEY, &m_bCamDiscrete, TRUE); + mLocalPrefs.GetPref(LIGHTDRAW_KEY, &m_bNewLightDraw, TRUE); + mLocalPrefs.GetPref(CUBICCLIP_KEY, &m_bCubicClipping, TRUE); + mLocalPrefs.GetPref(CUBICSCALE_KEY, &m_nCubicScale, 13); + mLocalPrefs.GetPref(ALTEDGE_KEY, &m_bALTEdge, FALSE); + mLocalPrefs.GetPref(FACECOLORS_KEY, &m_bFaceColors, FALSE); + mLocalPrefs.GetPref(XZVIS_KEY, &m_bXZVis, FALSE); + mLocalPrefs.GetPref(YZVIS_KEY, &m_bYZVis, FALSE); + mLocalPrefs.GetPref(ZVIS_KEY, &m_bZVis, FALSE); + mLocalPrefs.GetPref(SIZEPAINT_KEY, &m_bSizePaint, FALSE); + mLocalPrefs.GetPref(DLLENTITIES_KEY, &m_bDLLEntities, FALSE); + + mLocalPrefs.GetPref(DETACHABLEMENUS_KEY, &m_bLatchedDetachableMenus, TRUE); + m_bDetachableMenus = m_bLatchedDetachableMenus; + + if (g_pGameDescription->mNoPatch) + { + m_bPatchToolbar = false; + } + else + { + mLocalPrefs.GetPref(PATCHTOOLBAR_KEY, &m_bLatchedPatchToolbar, TRUE); + m_bPatchToolbar = m_bLatchedPatchToolbar; + } + + mLocalPrefs.GetPref(WIDETOOLBAR_KEY, &m_bLatchedWideToolbar, TRUE); + m_bWideToolbar = m_bLatchedWideToolbar; + + mLocalPrefs.GetPref(PLUGINTOOLBAR_KEY, &m_bLatchedPluginToolbar, TRUE); + m_bPluginToolbar = m_bLatchedPluginToolbar; + + mLocalPrefs.GetPref(WINDOW_KEY, (int*)&m_nLatchedView, WINDOW_DEF); + m_nView = m_nLatchedView; + + mLocalPrefs.GetPref(FLOATINGZ_KEY, &m_bLatchedFloatingZ, FALSE); + m_bFloatingZ = m_bLatchedFloatingZ; + + mLocalPrefs.GetPref(TEXTUREQUALITY_KEY, &m_nLatchedTextureQuality, 3); + m_nTextureQuality = m_nLatchedTextureQuality; + + mLocalPrefs.GetPref(LOADSHADERS_KEY, &m_nLatchedShader, 0); + m_nShader = m_nLatchedShader; + + mLocalPrefs.GetPref(NOCLAMP_KEY, &m_bNoClamp, FALSE); + mLocalPrefs.GetPref(USERINI_KEY, &m_strUserPath, ""); + mLocalPrefs.GetPref(ROTATION_KEY, &m_nRotation, 45); + mLocalPrefs.GetPref(CHASEMOUSE_KEY, &m_bChaseMouse, TRUE); + mLocalPrefs.GetPref(ENTITYSHOW_KEY, &m_nEntityShowState, ENTITY_SKINNED_BOXED); + + // this will probably need to be 75 or 100 for Q1. + mLocalPrefs.GetPref(TEXTURESCALE_KEY, &m_nTextureScale, 50); + + // FIXME: Hydra - actually, this stuff is Q1,Q2 and HL specific. + if ( (g_pGameDescription->mGameFile == "hl.game") ) + { + // No BSP monitoring in the default compiler tools for Half-life (yet) + mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, FALSE); + + // Texture subset on by default (HL specific really, because of halflife.wad's size) + mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, TRUE); + } + else if ( ( g_pGameDescription->mGameFile == "q2.game" ) || ( g_pGameDescription->mGameFile == "heretic2.game" ) ) + { + // BSP monitoring is implemented in Quake2 and Heretic2 tools + mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, TRUE); + + // Texture subset on by default (HL specific really, because of halflife.wad's size) + mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, TRUE); + } + else + { + mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, WATCHBSP_DEF); + mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, FALSE); + } + + + mLocalPrefs.GetPref(TEXTURESCROLLBAR_KEY, &m_bTextureScrollbar, TRUE); + mLocalPrefs.GetPref(DISPLAYLISTS_KEY, &m_bDisplayLists, TRUE); + mLocalPrefs.GetPref(ANTIALIASEDLINES_KEY, &m_bAntialiasedPointsAndLines, FALSE); + mLocalPrefs.GetPref(SWITCHCLIP_KEY, &m_bSwitchClip, TRUE); + mLocalPrefs.GetPref(SELWHOLEENTS_KEY, &m_bSelectWholeEntities, TRUE); + mLocalPrefs.GetPref(SHOWSHADERS_KEY, &m_bShowShaders, TRUE); + mLocalPrefs.GetPref(GLLIGHTING_KEY, &m_bGLLighting, FALSE); + mLocalPrefs.GetPref(NOSTIPPLE_KEY, &m_bNoStipple, FALSE); + mLocalPrefs.GetPref(UNDOLEVELS_KEY, &m_nUndoLevels, 30); + mLocalPrefs.GetPref(VERTEXMODE_KEY, &m_bVertexSplit, TRUE); + mLocalPrefs.GetPref(RUNQ2_KEY, &m_bRunQuake, RUNQ2_DEF); + mLocalPrefs.GetPref(LEAKSTOP_KEY, &m_bLeakStop, TRUE); + mLocalPrefs.GetPref(DOSLEEP_KEY, &m_bDoSleep, FALSE); + mLocalPrefs.GetPref(SELECTCURVES_KEY, &m_bSelectCurves, TRUE); + mLocalPrefs.GetPref(SELECTMODELS_KEY, &m_bSelectModels, TRUE); + mLocalPrefs.GetPref(SHADERLISTONLY_KEY, &m_bTexturesShaderlistOnly, FALSE); + mLocalPrefs.GetPref(SUBDIVISIONS_KEY, &m_nSubdivisions, SUBDIVISIONS_DEF); + mLocalPrefs.GetPref(CLIPCAULK_KEY, &m_bClipCaulk, FALSE); + mLocalPrefs.GetPref(SNAPTTOGRID_KEY, &m_bSnapTToGrid, FALSE); + mLocalPrefs.GetPref(TARGETFIX_KEY, &m_bDoTargetFix, TRUE); + mLocalPrefs.GetPref(WHEELINC_KEY, &m_nWheelInc, 64); + mLocalPrefs.GetPref(PATCHBBOXSEL_KEY, &m_bPatchBBoxSelect, FALSE); + + // Gef: Kyro GL_POINT workaround + mLocalPrefs.GetPref(GLPOINTWORKAROUND_KEY, &m_bGlPtWorkaround, FALSE); + + // window positioning + mLocalPrefs.GetPref(ENTITYSPLIT1_KEY, &mWindowInfo.nEntitySplit1, -1); + mLocalPrefs.GetPref(ENTITYSPLIT2_KEY, &mWindowInfo.nEntitySplit2, -1); + + mLocalPrefs.GetPref(POSITIONX_KEY, &mWindowInfo.position.x, -1); + mLocalPrefs.GetPref(POSITIONY_KEY, &mWindowInfo.position.y, -1); + mLocalPrefs.GetPref(WIDTH_KEY, &mWindowInfo.position.w, -1); + mLocalPrefs.GetPref(HEIGHT_KEY, &mWindowInfo.position.h, 450); + + const window_position_t default_window_pos = { 0, 0, 200, 200, }; + + mLocalPrefs.GetPref(ENTITYWND_KEY, &mWindowInfo.posEntityWnd, default_window_pos); + mLocalPrefs.GetPref(MAPINFOWND_KEY, &mWindowInfo.posMapInfoWnd, default_window_pos); + mLocalPrefs.GetPref(CAMWND_KEY, &mWindowInfo.posCamWnd, default_window_pos); + mLocalPrefs.GetPref(ZWND_KEY, &mWindowInfo.posZWnd, default_window_pos); + mLocalPrefs.GetPref(XYWND_KEY, &mWindowInfo.posXYWnd, default_window_pos); + mLocalPrefs.GetPref(YZWND_KEY, &mWindowInfo.posYZWnd, default_window_pos); + mLocalPrefs.GetPref(XZWND_KEY, &mWindowInfo.posXZWnd, default_window_pos); + mLocalPrefs.GetPref(PATCHWND_KEY, &mWindowInfo.posPatchWnd, default_window_pos); + mLocalPrefs.GetPref(SURFACEWND_KEY, &mWindowInfo.posSurfaceWnd, default_window_pos); + mLocalPrefs.GetPref(ENTITYINFOWND_KEY, &mWindowInfo.posEntityInfoWnd, default_window_pos); + + mLocalPrefs.GetPref(ZWIDTH_KEY, &mWindowInfo.nZWidth, 30); + mLocalPrefs.GetPref(XYHEIGHT_KEY, &mWindowInfo.nXYHeight, 300); + mLocalPrefs.GetPref(XYWIDTH_KEY, &mWindowInfo.nXYWidth, 300); + mLocalPrefs.GetPref(CAMWIDTH_KEY, &mWindowInfo.nCamWidth, 200); + mLocalPrefs.GetPref(CAMHEIGHT_KEY, &mWindowInfo.nCamHeight, 200); + mLocalPrefs.GetPref(ZFLOATWIDTH_KEY, &mWindowInfo.nZFloatWidth, 300); +#ifdef _WIN32 + mLocalPrefs.GetPref(STATE_KEY, &mWindowInfo.nState, SW_SHOW); +#endif + + // menu stuff + mLocalPrefs.GetPref(COUNT_KEY, &m_nMRUCount, 0); + for(i = 0; i < 4; i++) + { + char buf[64]; + sprintf (buf, "%s%d", FILE_KEY, i); + mLocalPrefs.GetPref(buf, &m_strMRUFiles[i], ""); + } + + // some platform specific prefs +#ifdef _WIN32 + mLocalPrefs.GetPref(NATIVEGUI_KEY, &m_bNativeGUI, TRUE); + mLocalPrefs.GetPref(STARTONPRIMMON_KEY, &m_bStartOnPrimMon, FALSE); +#endif + + mLocalPrefs.GetPref(SI_TEXMENU_KEY, &g_qeglobals.d_savedinfo.iTexMenu, ID_VIEW_BILINEARMIPMAP); + mLocalPrefs.GetPref(SI_GAMMA_KEY, &g_qeglobals.d_savedinfo.fGamma, 1.0f); + mLocalPrefs.GetPref(SI_EXCLUDE_KEY, &g_qeglobals.d_savedinfo.exclude, 0); // nothing filtered by default + mLocalPrefs.GetPref(SI_INCLUDE_KEY, &g_qeglobals.d_savedinfo.include, INCLUDE_NAMES | INCLUDE_COORDS | INCLUDE_ANGLES | INCLUDE_CAMERATINT); + mLocalPrefs.GetPref(SI_SHOWNAMES_KEY, &g_qeglobals.d_savedinfo.show_names, FALSE); + mLocalPrefs.GetPref(SI_SHOWCOORDS_KEY, &g_qeglobals.d_savedinfo.show_coordinates, TRUE); + mLocalPrefs.GetPref(SI_SHOWANGLES_KEY, &g_qeglobals.d_savedinfo.show_angles, TRUE); + mLocalPrefs.GetPref(SI_SHOWOUTLINES_KEY, &g_qeglobals.d_savedinfo.show_outline, FALSE); + mLocalPrefs.GetPref(SI_SHOWAXIS_KEY, &g_qeglobals.d_savedinfo.show_axis, TRUE); + mLocalPrefs.GetPref(SI_NOSELOUTLINES_KEY, &g_qeglobals.d_savedinfo.bNoSelectedOutlines, FALSE); + + mLocalPrefs.GetPref(SI_OUTLINESTYLE_KEY, &g_qeglobals.d_savedinfo.iSelectedOutlinesStyle, OUTLINE_ZBUF|OUTLINE_BSEL); + + LoadTexdefPref(&g_qeglobals.d_savedinfo.m_SIIncrement, SI_SURFACE_TEXDEF_KEY); + LoadTexdefPref(&g_qeglobals.d_savedinfo.m_PIIncrement, SI_PATCH_TEXDEF_KEY); + + // text editor binding +#ifdef _WIN32 + mLocalPrefs.GetPref(CUSTOMSHADEREDITOR_KEY, &m_bUseWin32Editor, TRUE); +#else + mLocalPrefs.GetPref(CUSTOMSHADEREDITOR_KEY, &m_bUseCustomEditor, FALSE); + mLocalPrefs.GetPref(CUSTOMSHADEREDITORCOMMAND_KEY, &m_strEditorCommand, ""); +#endif + + + vec3_t vDefaultAxisColours[3] = { + {0.f, 0.5f, 0.f}, + {0.f, 0.f, 1.f}, + {1.f, 0.f, 0.f}, + }; + + for(i = 0; i < 3; i++) { + char buf[64]; + sprintf(buf, "%s%d", SI_AXISCOLORS_KEY, i); + mLocalPrefs.GetPref(buf, g_qeglobals.d_savedinfo.AxisColors[i], vDefaultAxisColours[i]); + } + + vec3_t vDefaultColours[COLOR_LAST] = { + {0.25f, 0.25f, 0.25f}, + {1.f, 1.f, 1.f}, + {0.75f, 0.75f, 0.75f}, + {0.5f, 0.5f, 0.5f}, + {0.25f, 0.25f, 0.25f}, + {0.0f, 0.0f, 0.0f}, + {0.f, 0.f, 1.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {1.f, 0.f, 0.f}, + {0.f, 0.f, 1.f}, + {0.5f, 0.f, 0.75f}, + {1.0f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + }; + + for(i = 0; i < COLOR_LAST; i++) { + char buf[64]; + sprintf(buf, "%s%d", SI_COLORS_KEY, i); + mLocalPrefs.GetPref(buf, g_qeglobals.d_savedinfo.colors[i], vDefaultColours[i]); + } + + mLocalPrefs.GetPref(TEXTURECOMPRESSIONFORMAT_KEY, &m_nTextureCompressionFormat, 1); + + mLocalPrefs.GetPref(LIGHTRADIUS_KEY, &m_nLightRadiuses, TRUE); + + mLocalPrefs.GetPref(Q3MAP2TEX_KEY, &m_bQ3Map2Texturing, TRUE); + +#ifdef ATIHACK_812 + mLocalPrefs.GetPref(ATIHACK_KEY, &m_bGlATIHack, FALSE); +#endif + + Undo_SetMaxSize(m_nUndoLevels); // set it internally as well / FIXME: why not just have one global value? + + UpdateTextureCompression(); + +#ifdef ATIHACK_812 + UpdateATIHack(); +#endif + + if (mLocalPrefs.mbEmpty) + { + mLocalPrefs.mbEmpty = false; + Sys_Printf("Saving local.pref with default pref values\n"); + SavePrefs(); + } +} + +void PrefsDlg::SavePrefs () +{ + if (g_qeglobals.disable_ini) + return; + +#ifdef _DEBUG + Sys_Printf("PrefsDlg::SavePrefs\n"); +#endif + + // this will take care of copying back from the dialog to the variables + // NOTE: it may be overkill to call systematically before a SavePrefs, but it's safer + // this will also cause an UpdateData for the mGamesDialog + UpdateData(TRUE); + + mGamesDialog.SavePrefs(); + + // update the tree and save it + mLocalPrefs.UpdatePrefTree(); + if (!mLocalPrefs.WriteXMLFile(m_inipath->str)) + Sys_FPrintf(SYS_ERR, "Error occured while saving local prefs file '%s'\n", m_inipath->str); + + if (m_nMouse == 0) + m_nMouseButtons = 2; + else + m_nMouseButtons = 3; + +} + +void PrefsDlg::PostModal (int code) +{ + if (code == IDOK) + { + SavePrefs(); + // make sure the logfile is ok + Sys_LogFile(); + #ifdef ATIHACK_812 + UpdateATIHack(); + #endif + if (g_pParentWnd) + g_pParentWnd->SetGridStatus(); + Sys_UpdateWindows(W_ALL); + if (m_nUndoLevels != 0) + Undo_SetMaxSize(m_nUndoLevels); + } +} + +void PrefsDlg::DoEditorSensitivity() +{ + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data (G_OBJECT(m_pWidget), "check_customeditor")))) + { + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "label_customeditor")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "entry_customeditor")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "button_customeditor")), TRUE); + } + else + { + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "label_customeditor")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "entry_customeditor")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "button_customeditor")), FALSE); + } +} + +void PrefsDlg::DoSensitivity() +{ +#if 0 + // first, look at the project file version ... will monitoring work? + // project files now XML, guaranteed to be at least version 2 + if (0)//IntForKey( g_qeglobals.d_project_entity, "version" ) < 2) + { + if (m_bWarn) + { + Str Msg; + Msg = "The current project file ("; + Msg += g_PrefsDlg.m_strLastProject; + Msg += ") is not at least version 2.\nI need version 2 or above to setup BSP monitoring correctly."; + gtk_MessageBox(m_pWidget, Msg.GetBuffer(), MB_OK ); + + m_bWarn = false; + } + + // go ahead, disable everybuddy + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); + } + else + { +#endif +// m_bWarn = true; + + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), TRUE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" )), TRUE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), TRUE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), TRUE ); + + if ( ! gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" ) ) ) ) + { + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); + } else if (! gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" ) ) ) ) + { + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); + } +} diff --git a/radiant/preferences.h b/radiant/preferences.h new file mode 100644 index 00000000..7abd86eb --- /dev/null +++ b/radiant/preferences.h @@ -0,0 +1,628 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PREFERENCES_H_ +#define _PREFERENCES_H_ + +#include "dialog.h" +#include "gtkr_list.h" +//#include "profile.h" + +#define MAX_TEXTURE_QUALITY 3 + +enum PrefTypes_t +{ + PREF_STR, + PREF_INT, + PREF_BOOL, + PREF_FLOAT, + PREF_VEC3, + PREF_WNDPOS, +}; + +/*! +a preference assignment, name, type and pointer to value +we don't store the xmlNodePtr because the document itself can be thrown away upon any LoadPref +(see CGameDialog::UpdatePrefTree) +*/ +class CPrefAssignment +{ +public: + Str mName; + PrefTypes_t mType; + void *mVal; + + CPrefAssignment(char *name, PrefTypes_t Type, void *Val) + { + mName = name; mType = Type; mVal = Val; + } + CPrefAssignment() { mVal = NULL; } + CPrefAssignment(const CPrefAssignment& ass); + virtual ~CPrefAssignment() { } + virtual CPrefAssignment& operator =(const CPrefAssignment& ass); +}; + + +/*! +generic preferences storage class, using xml files +*/ +class CXMLPropertyBag +{ +private: + /*! + local prefs file + */ + xmlDocPtr mpDoc; + xmlNodePtr mpDocNode; + + /*! + prefs assignments (what pref name, what type, what variable) + */ + list mPrefAssignments; + + /*! + name of file to load/save as + */ + Str mStrFilename; + + /*! + store assignment in the property list if not already there + */ + void PushAssignment(char *name, PrefTypes_t type, void *pV); + + /*! + find the xmlnode relating to the epair name + */ + xmlNodePtr EpairForName(const char *name); + +public: + CXMLPropertyBag(); + virtual ~CXMLPropertyBag() + { + if (InUse()) + Clear(); + }; + + /*! + read a pref setting, if doesn't exist, will add it to the xml tree (using default value provided) + \arg name the name of the pref + \arg pV pointer to the value + \arg V default value + those functions will fill in the list of preferences assignments + (name, type and pointer to value) + this is used in UpdatePrefTree + */ + void GetPref(char *name, Str *pV, char *V); + void GetPref(char *name, int *pV, int V); + void GetPref(char *name, bool *pV, bool V); + void GetPref(char *name, float *pV, float V); + void GetPref(char *name, float *pV, float* V); + void GetPref(char *name, window_position_t* pV, window_position_t V); + + /*! + returns whether or not the property bag is already open + */ + qboolean InUse() { return (mpDoc != NULL); }; + + /*! + unload the xml doc, and free the tree + */ + void Clear(); + + /*| + read data from our XML file + */ + void ReadXMLFile(const char* pFilename); + + /*| + write out the property bag to an XML data file + return is success/fail + */ + qboolean WriteXMLFile(const char* pFilename); + + /*! + update the xml tree with data form the property list, usually in preparation for a write + */ + void UpdatePrefTree(); + + /*! + did the file have any data or not? + */ + qboolean mbEmpty; +}; + +/*! +holds information for a given game +I'm a bit unclear on that still +it holds game specific configuration stuff +such as base names, engine names, some game specific features to activate in the various modules +it is not strictly a prefs thing since the user is not supposed to edit that (unless he is hacking +support for a new game) + +what we do now is fully generate the information for this during the setup. We might want to +generate a piece that just says "the game pack is there", but put the rest of the config somwhere +else (i.e. not generated, copied over during setup .. for instance in the game tools directory) +*/ +class CGameDescription +{ +public: + xmlDocPtr mpDoc; ///< the game description xml tree + Str mGameToolsPath; ///< the explicit path to the game-dependent modules + Str mGameName; ///< name of the game used in dialogs + Str mGameFile; ///< the .game file that describes this game + Str mBaseGame; ///< basegame directory + Str mEnginePath; ///< path to the engine + Str mEngine; ///< engine name +#if defined (__linux__) || defined (__APPLE__) + Str mUserPathPrefix; ///< prefix for ~/.q3a ~/.wolf init, only on *nix +#endif + Str mShaderPath; ///< the path in which to look for shaders + Str mShaderlist; ///< shaderlist file + float mTextureDefaultScale; ///< default scale (0.5 in q3, 1.0 in q1/q2, 0.25 in JK2 ..) + bool mEClassSingleLoad; ///< only load a single eclass definition file + bool mNoPatch; ///< this game doesn't support patch technology + Str mCaulkShader; ///< the shader to use for caulking + + CGameDescription() { mpDoc = NULL; } + /*! + \todo parse basic info from the node + user-friendly name of the game + essential parameters (such as the start dir) + */ + CGameDescription(xmlDocPtr pDoc, const Str &GameFile); + virtual ~CGameDescription() { xmlFreeDoc(mpDoc); } + + void Dump(); +}; + +/*! +standalone dialog for games selection, and more generally global settings +*/ +class CGameDialog : public Dialog +{ + GtkWidget *mFrame; ///< this is built on-demand first time it's used + GtkWidget *mTopBox; ///< top level box used to store the dialog frame, must unhook after modal use + + + /*! + global prefs storage + */ + CXMLPropertyBag mGlobalPrefs; + +#ifdef _WIN32 + /*! + run from a network share + this one is not being saved out in prefs, since we need to know before we load prefs + we use a dummy file NETRUN_FILENAME as flag + all done with static stuff + */ + static bool m_bNetRun; +#endif + +protected: + + int m_nComboSelect; ///< intermediate int value for combo in dialog box + +public: + + /*! + those settings are saved in the global prefs file + I'm too lazy to wrap behind protected access, not sure this needs to be public + NOTE: those are preference settings. if you change them it is likely that you would + have to restart the editor for them to take effect + */ + /*@{*/ + /*! + what game has been selected + this is the name of the .game file + */ + Str m_sGameFile; + /*! + auto-load the game on startup + this is linked to auto-load checkbox + */ + bool m_bAutoLoadGame; + /*! + log console to radiant.log + m_bForceLogConsole is an obscure forced latching situation + */ + bool m_bLogConsole; + bool m_bForceLogConsole; + /*@}*/ + + /*! + points somewhere in mGames, set once at startup + */ + CGameDescription *m_pCurrentGameDescription; + + /*! + the list of game descriptions we scanned from the game/ dir + */ + list mGames; + + CGameDialog() { mFrame = NULL; m_pCurrentGameDescription = NULL; m_bLogConsole = false; m_bForceLogConsole = false; } + virtual ~CGameDialog(); + + void AddPacksURL(Str &s); + + /*! + intialize the game dialog, called at CPrefsDlg::Init + will scan for games, load prefs, and do game selection dialog if needed + */ + void Init(); + + /*! + reset the global settings by removing the file + */ + void Reset(); + + /*! + run the dialog UI for the list of games + */ + void DoGameDialog(); + + /*! + Dialog API + this is only called when the dialog is built at startup for main engine select + */ + void BuildDialog (); + void UpdateData (bool retrieve); + + /*! + construction of the dialog frame + this is the part to be re-used in prefs dialog + for the standalone dialog, we include this in a modal box + for prefs, we hook the frame in the main notebook + build the frame on-demand (only once) + */ + GtkWidget *GetGlobalFrame(); + + /*! + global preferences subsystem + XML-based this time, hopefully this will generalize to other prefs + LoadPrefs has hardcoded defaults + NOTE: it may not be strictly 'CGameDialog' to put the global prefs here + could have named the class differently I guess + */ + /*@{*/ + void LoadPrefs(); ///< load from file into variables + void SavePrefs(); ///< save pref variables to file + /*@}*/ + + /*! + read or set netrun (check file) + \param retrieve + if false, will check if netrun file is present and will set m_bNetRun + if true, will create/erase the netrun file depending on m_bNetRun + NOTE: this is not backwards, 'retrieve' means 'retrieve from settings dialog' - in terms of UI + */ + static void UpdateNetrun(bool retrieve); + /*! + get current netrun setting + */ + static bool GetNetrun(); + +private: + /*! + scan for .game files, load them + */ + void ScanForGames(); + + /*! + inits g_PrefsDlg.m_global_rc_path + */ + void InitGlobalPrefPath(); + + /*! + uses m_nComboItem to find the right mGames + */ + CGameDescription *GameDescriptionForComboItem(); +}; + +typedef struct { + int nEntitySplit1; + int nEntitySplit2; + + window_position_t position; + + window_position_t posEntityWnd; + window_position_t posMapInfoWnd; + window_position_t posCamWnd; + window_position_t posZWnd; + window_position_t posXYWnd; + window_position_t posXZWnd; + window_position_t posYZWnd; + window_position_t posPatchWnd; + window_position_t posSurfaceWnd; + window_position_t posEntityInfoWnd; + + int nXYHeight; + int nZWidth; + int nXYWidth; + int nCamWidth; + int nCamHeight; + int nZFloatWidth; + int nState; +} windowPosInfo_t; + +class PrefsDlg : public Dialog +{ + +public: + /*! + local prefs file + */ + CXMLPropertyBag mLocalPrefs; + + // will enable/disable stuff according to the situation + void DoSensitivity(); + void PreModal() { DoSensitivity(); } + + // enable/disable custom editor entry + void DoEditorSensitivity(); + + /*! + this holds global level preferences + */ + CGameDialog mGamesDialog; +protected: + // warning about old project files + bool m_bWarn; + list mGames; + +public: + // last light intensity used in the CLightPrompt dialog, stored in registry + int m_iLastLightIntensity; + // these mirror what goes in the combo box + // see PrefDlg::m_nShader, tells wether to load NONE / COMMON or ALL shaders at parsing stage + enum {SHADER_NONE = 0, SHADER_COMMON, SHADER_ALL}; + + // Gef: updated preferences dialog + /*! Preference notebook page numbers */ + enum {PTAB_FRONT = 0, PTAB_GAME_SETTINGS, PTAB_2D, PTAB_CAMERA, PTAB_TEXTURE, PTAB_LAYOUT, PTAB_MOUSE, + PTAB_EDITING, PTAB_STARTUP, PTAB_PATHS, PTAB_MISC, PTAB_BSPMONITOR} pref_tabs; + + GtkWidget *notebook; + + void UpdateTextureCompression(); + +#ifdef ATIHACK_812 + void UpdateATIHack(); +#endif + + void LoadPrefs(); + void SavePrefs(); + void LoadTexdefPref(texdef_t* pTexdef, char* pName); + + PrefsDlg (); + virtual ~PrefsDlg () + { + g_string_free (m_rc_path, true ); + g_string_free (m_inipath, true ); + } + + /*! + path for global settings + win32: g_strAppPath + linux: ~/.radiant// + */ + GString *m_global_rc_path; + + /*! + path to per-game settings + used for various game dependant storage + win32: g_strGameToolsPath + linux: ~/.radiant/// + */ + GString *m_rc_path; + + /*! + holds per-game settings + m_rc_path+"local.pref" + \todo FIXME at some point this should become XML property bag code too + */ + GString *m_inipath; + + // initialize the above paths + void Init(); + +#if 0 + // DEPRECATED: use engine path from the current game description instead + // path to the top-level installation + Str m_strEnginePath; + // name of executable + // quake2 quake3 etc + Str m_strEngine; + // we use this Str to store the full path to the engine: m_strEnginePath + m_strEngine + // it's not stored in the registry or anything, just ued for display in prefs + Str m_strPrefsDlgEngine; +#endif + + // Dialog Data + int m_nMouse; + MainFrame::EViewStyle m_nView; + bool m_bTextureLock; + bool m_bLoadLast; + // path to the project loaded at startup + // if g_PrefsDlg can't find the information in the ini file + // it will try to guess and eventually ask the user + Str m_strLastProject; + /*! + version of last loaded project file + says -1 if there's no version loaded + if it's a manually constructed project file, will be 0 + otherwise the actual 'version' epair + */ + int m_nLastProjectVer; + Str m_strLastMap; + bool m_bInternalBSP; + bool m_bRightClick; + bool m_bSetGame; + bool m_bAutoSave; + bool m_bLoadLastMap; + bool m_bTextureWindow; + bool m_bSnapShots; + float m_fTinySize; + bool m_bCleanTiny; + bool m_bCamXYUpdate; + int m_nCamDragMultiSelect; + bool m_bCamDragMultiSelect; + bool m_bCamFreeLook; + bool m_bCamFreeLookStrafe; + bool m_bCamInverseMouse; + bool m_bCamDiscrete; + bool m_bNewLightDraw; + Str m_strPrefabPath; + int m_nWhatGame; + bool m_bALTEdge; + bool m_bFaceColors; + bool m_bXZVis; + bool m_bYZVis; + bool m_bZVis; + bool m_bSizePaint; + bool m_bDLLEntities; + bool m_bRotateLock; + bool m_bDetachableMenus; + bool m_bPatchToolbar; + bool m_bWideToolbar; + bool m_bPluginToolbar; + bool m_bNoClamp; + //++timo this is most likely broken, I don't know what it's supposed to do + Str m_strUserPath; + int m_nRotation; + bool m_bChaseMouse; + bool m_bTextureScrollbar; + bool m_bDisplayLists; + bool m_bAntialiasedPointsAndLines; // Fishman - Add antialiazed points and lines support. 09/03/00 + bool m_bShowShaders; + int m_nShader; + bool m_bNoStipple; + int m_nUndoLevels; + bool m_bVertexSplit; + + int m_nMouseButtons; + int m_nAngleSpeed; + int m_nMoveSpeed; + int m_nAutoSave; + bool m_bCubicClipping; + int m_nCubicScale; + bool m_bSelectCurves; + bool m_bSelectModels; + int m_nEntityShowState; + int m_nTextureScale; + bool m_bNormalizeColors; + bool m_bSwitchClip; + bool m_bSelectWholeEntities; + int m_nTextureQuality; + bool m_bGLLighting; + bool m_bTexturesShaderlistOnly; + int m_nSubdivisions; + bool m_bFloatingZ; + bool m_bLatchedFloatingZ; + // Gef: Kyro GL_POINT workaround + bool m_bGlPtWorkaround; + + // how many menus in the texture thing before we split? + int m_nTextureMenuSplit; + + // watch the BSP process through network connections + // true: trigger the BSP steps one by one and monitor them through the network + // false: create a BAT / .sh file and execute it. don't bother monitoring it. + bool m_bWatchBSP; + // do we stop the compilation process if we come accross a leak? + bool m_bLeakStop; + // timeout when beginning a step (in seconds) + // if we don't get a connection quick enough we assume something failed and go back to idling + int m_iTimeout; + bool m_bRunQuake; + // store prefs setting for automatic sleep mode activation + bool m_bDoSleep; + + bool m_bClipCaulk; + + // make the texture increments match the grid changes + bool m_bSnapTToGrid; + + // try to fix the target/targetname conflicts when importing a map (default true) + bool m_bDoTargetFix; + + // the increment step we use against the wheel mouse + int m_nWheelInc; + +#ifdef _WIN32 + // use the file associations to open files instead of builtin Gtk editor + bool m_bUseWin32Editor; +#else + // custom shader editor + bool m_bUseCustomEditor; + Str m_strEditorCommand; // this is the command executed +#endif + +#ifdef _WIN32 + bool m_bNativeGUI; + bool m_bStartOnPrimMon; +#endif + + bool m_bPatchBBoxSelect; + + // RR2DO2: latched data, for settings that require a restart. We don't want to set + // these directly in case users set them under preferences and then continue working + // with the editor. + MainFrame::EViewStyle m_nLatchedView; + int m_nMRUCount; + Str m_strMRUFiles[4]; + + windowPosInfo_t mWindowInfo; + + bool m_bLatchedDetachableMenus; + bool m_bLatchedPatchToolbar; + bool m_bLatchedWideToolbar; + bool m_bLatchedPluginToolbar; + int m_nLatchedShader; + int m_nLatchedTextureQuality; + + // RIANT + // texture compression format + int m_nTextureCompressionFormat; + + int m_nLightRadiuses; + + bool m_bQ3Map2Texturing; + +#ifdef ATIHACK_812 + bool m_bGlATIHack; +#endif + + void UpdateData (bool retrieve); + + /*! Utility function for swapping notebook pages for tree list selections */ + void showPrefPage(int prefpage); + +protected: + /*! Scan for game description files and build a list */ + void ScanForGames(); + + /*! Dialog API */ + void BuildDialog (); + void PostModal (int code); +}; + +#endif // _PREFERENCES_H_ diff --git a/radiant/profile.cpp b/radiant/profile.cpp new file mode 100644 index 00000000..ed5357b6 --- /dev/null +++ b/radiant/profile.cpp @@ -0,0 +1,293 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Application settings load/save +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include "str.h" +#include "file.h" + +// ============================================================================= +// Static functions + +bool read_var (const char *filename, const char *section, const char *key, char *value) +{ + char line[1024], *ptr; + FILE *rc; + + rc = fopen (filename, "rt"); + + if (rc == NULL) + return false; + + while (fgets (line, 1024, rc) != 0) + { + // First we find the section + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + while (fgets (line, 1024, rc) != 0) + { + ptr = strchr (line, '='); + + if (ptr == NULL) + { + // reached the end of the section + fclose (rc); + return false; + } + *ptr = '\0'; + + // remove spaces + while (line[strlen(line)-1] == ' ') + line[strlen(line)-1] = '\0'; + + if (strcmp (line, key) == 0) + { + strcpy (value, ptr+1); + fclose (rc); + + if (value[strlen (value)-1] == 10 || value[strlen (value)-1] == 13 || value[strlen (value)-1] == 32) + value[strlen (value)-1] = 0; + + return true; + } + } + } + } + + fclose (rc); + return false; +} + +static bool save_var (const char *filename, const char *section, const char *key, const char *value) +{ + char line[1024], *ptr; + MemStream old_rc; + bool found; + FILE *rc; + + rc = fopen (filename, "rb"); + + if (rc != NULL) + { + guint32 len; + void *buf; + + fseek (rc, 0, SEEK_END); + len = ftell (rc); + rewind (rc); + buf = qmalloc (len); + fread (buf, len, 1, rc); + old_rc.Write (buf, len); + free (buf); + fclose (rc); + old_rc.Seek (0, SEEK_SET); + } + + // TTimo: changed to binary writing. It doesn't seem to affect linux version, and win32 version was happending a lot of '\n' + rc = fopen (filename, "wb"); + + if (rc == NULL) + return false; + + // First we need to find the section + found = false; + while (old_rc.ReadString (line, 1024) != NULL) + { + fputs (line, rc); + + if (line[0] == '[') + { + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + found = true; + break; + } + } + } + + if (!found) + { + fputs ("\n", rc); + fprintf (rc, "[%s]\n", section); + } + + fprintf (rc, "%s=%s\n", key, value); + + while (old_rc.ReadString (line, 1024) != NULL) + { + ptr = strchr (line, '='); + + if (ptr != NULL) + { + *ptr = '\0'; + + if (strcmp (line, key) == 0) + break; + + *ptr = '='; + fputs (line, rc); + } + else + { + fputs (line, rc); + break; + } + } + + while (old_rc.ReadString (line, 1024) != NULL) + fputs (line, rc); + + fclose (rc); + return true; +} + +// ============================================================================= +// Global functions + +bool WINAPI profile_save_int (const char *filename, const char *section, const char *key, int value) +{ + char buf[16]; + sprintf (buf, "%d", value); + return save_var (filename, section, key, buf); +} + +bool WINAPI profile_save_float (const char *filename, const char *section, const char *key, float value) +{ + char buf[16]; + sprintf (buf, "%f", value); + return save_var (filename, section, key, buf); +} + +bool WINAPI profile_save_string (const char * filename, const char *section, const char *key, const char *value) +{ + return save_var (filename, section, key, value); +} + +bool profile_save_buffer (const char * rc_path, const char *name, void *buffer, guint32 size) +{ + bool ret = false; + char filename[PATH_MAX]; + sprintf (filename, "%s/%s.bin", rc_path, name); + FILE *f; + + f = fopen (filename, "wb"); + + if (f != NULL) + { + if (fwrite (buffer, size, 1, f) == 1) + ret = true; + + fclose (f); + } + + return ret; +} + +bool profile_load_buffer (const char * rc_path, const char *name, void *buffer, guint32 *plSize) +{ + char filename[PATH_MAX]; + sprintf (filename, "%s/%s.bin", rc_path, name); + bool ret = false; + guint32 len; + FILE *f; + + f = fopen (filename, "rb"); + + if (f != NULL) + { + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + if (len > *plSize) + len = *plSize; + else + *plSize = len; + + if (fread (buffer, len, 1, f) == 1) + ret = true; + + fclose (f); + } + + return true; +} + +int WINAPI profile_load_int (const char *filename, const char *section, const char *key, int default_value) +{ + char value[1024]; + + if (read_var (filename, section, key, value)) + return atoi (value); + else + return default_value; +} + +float WINAPI profile_load_float (const char *filename, const char *section, const char *key, float default_value) +{ + char value[1024]; + + if (read_var (filename, section, key, value)) + return atof (value); + else + return default_value; +} + +char* WINAPI profile_load_string (const char *filename, const char *section, const char *key, const char *default_value) +{ + static Str ret; + char value[1024]; + + if (read_var (filename, section, key, value)) + ret = value; + else + ret = default_value; + + return (char*)ret.GetBuffer (); +} diff --git a/radiant/qe3.cpp b/radiant/qe3.cpp new file mode 100644 index 00000000..e3f9cec6 --- /dev/null +++ b/radiant/qe3.cpp @@ -0,0 +1,1797 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Linux stuff +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include "gtkmisc.h" +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#include +#include +#endif +// for the logging part +#include +#include + +QEGlobals_t g_qeglobals; +QEGlobals_GUI_t g_qeglobals_gui; + +// leo: Track memory allocations for debugging +// NOTE TTimo this was never used and probably not relevant +// there are tools to do that +#ifdef MEM_DEBUG + +static GList *memblocks; + +void* debug_malloc (size_t size, const char* file, int line) +{ + void *buf = g_malloc (size + 8); + + *((const char**)buf) = file; + buf = (char*)buf + 4; + *((int*)buf) = line; + buf = (char*)buf + 4; + + memblocks = g_list_append (memblocks, buf); + + return buf; +} + +void debug_free (void *buf, const char* file, int line) +{ + const char *f; + int l; + + if (g_list_find (memblocks, buf)) + { + memblocks = g_list_remove (memblocks, buf); + + buf = (char*)buf - 4; + l = *((int*)buf); + buf = (char*)buf - 4; + f = *((const char**)buf); + + Sys_FPrintf (SYS_DBG, "free: %s %d", file, line); + Sys_FPrintf (SYS_DBG, " allocated: %s %d\n", f, l); + + g_free (buf); + } +// else +// free (buf); // from qmalloc, will leak unless we add this same hack to cmdlib +} + +#endif + +vec_t Rad_rint (vec_t in) +{ + if (g_PrefsDlg.m_bNoClamp) + return in; + else + return (float)floor (in + 0.5); +} + +void WINAPI QE_CheckOpenGLForErrors(void) +{ + char strMsg[1024]; + int i = qglGetError(); + if (i != GL_NO_ERROR) + { + if (i == GL_OUT_OF_MEMORY) + { + sprintf(strMsg, "OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString((GLenum)i)); + if (gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg, "Radiant Error", MB_YESNO) == IDYES) + { + Map_SaveFile(NULL, false); + } + _exit(1); + } + else + { + Sys_Printf ("Warning: OpenGL Error %s\n", qgluErrorString((GLenum)i)); + } + } +} + +// NOTE: don't this function, use VFS instead +char *ExpandReletivePath (char *p) +{ + static char temp[1024]; + const char *base; + + if (!p || !p[0]) + return NULL; + if (p[0] == '/' || p[0] == '\\') + return p; + + base = ValueForKey(g_qeglobals.d_project_entity, "basepath"); + sprintf (temp, "%s/%s", base, p); + return temp; +} + +char *copystring (char *s) +{ + char *b; + b = (char*)malloc(strlen(s)+1); + strcpy (b,s); + return b; +} + + +bool DoesFileExist(const char* pBuff, long& lSize) +{ + FileStream file; + if (file.Open(pBuff, "r")) + { + lSize += file.GetLength(); + file.Close(); + return true; + } + return false; +} + + +void Map_Snapshot() +{ + CString strMsg; + + // I hope the modified flag is kept correctly up to date + if (!modified) + return; + + // we need to do the following + // 1. make sure the snapshot directory exists (create it if it doesn't) + // 2. find out what the lastest save is based on number + // 3. inc that and save the map + CString strOrgPath, strOrgFile; + ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile); + AddSlash(strOrgPath); + strOrgPath += "snapshots"; + bool bGo = true; + struct stat Stat; + if (stat(strOrgPath, &Stat) == -1) + { +#ifdef _WIN32 + bGo = (_mkdir(strOrgPath) != -1); +#endif + +#if defined (__linux__) || defined (__APPLE__) + bGo = (mkdir(strOrgPath,0755) != -1); +#endif + } + AddSlash(strOrgPath); + if (bGo) + { + int nCount = 0; + long lSize = 0; + CString strNewPath; + strNewPath = strOrgPath; + strNewPath += strOrgFile; + CString strFile; + while (bGo) + { + char buf[PATH_MAX]; + sprintf( buf, "%s.%i", strNewPath.GetBuffer(), nCount ); + strFile = buf; + bGo = DoesFileExist(strFile, lSize); + nCount++; + } + // strFile has the next available slot + Map_SaveFile(strFile, false); + // it is still a modified map (we enter this only if this is a modified map) + Sys_SetTitle (currentmap); + Sys_MarkMapModified(); + if (lSize > 12 * 1024 * 1024) // total size of saves > 4 mb + { + Sys_Printf("The snapshot files in %s total more than 4 megabytes. You might consider cleaning up.", strOrgPath.GetBuffer()); + } + } + else + { + strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetBuffer()); + gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg); + } + strOrgPath = ""; + strOrgFile = ""; +} +/* +=============== +QE_CheckAutoSave + +If five minutes have passed since making a change +and the map hasn't been saved, save it out. +=============== +*/ + + +void QE_CheckAutoSave( void ) +{ + static time_t s_start; + time_t now; + time (&now); + + if (modified != 1 || !s_start) + { + s_start = now; + return; + } + + if ((now - s_start) > (60 * g_PrefsDlg.m_nAutoSave)) + { + if (g_PrefsDlg.m_bAutoSave) + { + CString strMsg; + strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving..."; + Sys_Printf(strMsg); + Sys_Printf("\n"); + Sys_Status (strMsg,0); + + // only snapshot if not working on a default map + if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0) + { + Map_Snapshot(); + } + else + { + Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false); + } + + Sys_Status ("Autosaving...Saved.", 0 ); + modified = 2; + } + else + { + Sys_Printf ("Autosave skipped...\n"); + Sys_Status ("Autosave skipped...", 0 ); + } + s_start = now; + } +} + + +// NOTE TTimo we don't like that BuildShortPathName too much +// the VFS provides a vfsCleanFileName which should perform the cleanup tasks +// in the long run I'd like to completely get rid of this + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 +// used to be disabled, but caused problems + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 +// can't work with long win32 names until the BSP commands are not working differently +#ifdef _WIN32 +int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) +{ + char *pFile = NULL; + int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); + nResult = GetShortPathName(pPath, pBuffer, nBufferLen); + if (nResult == 0) + strcpy(pBuffer, pPath); // Use long filename + return nResult; +} +#endif + +#if defined (__linux__) || defined (__APPLE__) +int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) +{ + // remove /../ from directories + const char *scr = pPath; char *dst = pBuffer; + for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) + { + if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') + { + scr += 3; + while (dst != pBuffer && *(--dst) != '/') + { + i--; + } + } + + *dst = *scr; + + scr++; dst++; + } + *dst = 0; + + return strlen (pBuffer); +} +#endif + +/* +const char *g_pPathFixups[]= +{ + "basepath", + "autosave", +}; + +const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*); + +void QE_CheckProjectEntity() +{ + char *pFile; + char pBuff[PATH_MAX]; + char pNewPath[PATH_MAX]; + for (int i = 0; i < g_nPathFixupCount; i++) + { + char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]); + + strcpy (pNewPath, pPath); + if (pPath[0] != '\\' && pPath[0] != '/') + if (GetFullPathName(pPath, PATH_MAX, pBuff, &pFile)) + strcpy (pNewPath, pBuff); + + BuildShortPathName (pNewPath, pBuff, PATH_MAX); + + // check it's not ending with a filename seperator + if (pBuff[strlen(pBuff)-1] == '/' || pBuff[strlen(pBuff)-1] == '\\') + { + Sys_FPrintf(SYS_WRN, "WARNING: \"%s\" path in the project file has an ending file seperator, fixing.\n", g_pPathFixups[i]); + pBuff[strlen(pBuff)-1]=0; + } + + SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff); + } +} +*/ + +void HandleXMLError( void* ctxt, const char* text, ... ) +{ + va_list argptr; + static char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text, argptr); + Sys_FPrintf (SYS_ERR, "XML %s\n", buf); + va_end (argptr); +} + +#define DTD_BUFFER_LENGTH 1024 +xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false) +{ + xmlDocPtr doc = NULL; + bool wellFormed = false, valid = false; + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=433 + //if(validate) + // xmlDoValidityCheckingDefaultValue = 1; + //else + xmlDoValidityCheckingDefaultValue = 0; + xmlSetGenericErrorFunc(NULL, HandleXMLError); + + // SPoG + // HACK: use AppPath to resolve DTD location + // do a buffer-safe string copy and concatenate + int i; + char* w; + const char* r; + char buf[DTD_BUFFER_LENGTH]; + + w = buf; + i = 0; + // copy + //assert(g_strAppPath.GetBuffer() != NULL); + for(r = g_strAppPath.GetBuffer(); iRead(chars, 4); + if (res > 0) + { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf); + + while ((res = stream->Read(chars, size)) > 0) + { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + + wellFormed = (ctxt->wellFormed == 1); + valid = (ctxt->valid == 1); + + xmlFreeParserCtxt(ctxt); + } + + if(wellFormed && (!validate || (validate && valid))) + return doc; + + if(doc != NULL) + xmlFreeDoc(doc); + + return NULL; +} + +xmlDocPtr ParseXMLFile(const char* filename, bool validate = false) +{ + FileStream stream; + if (stream.Open(filename, "r")) + return ParseXMLStream(&stream, validate); + + Sys_FPrintf(SYS_ERR, "Failed to open file: %s\n",filename); + return NULL; +} + +// copy a string r to a buffer w +// replace $string as appropriate +void ReplaceTemplates(char* w, const char* r) +{ + const char *p; + const char *__ENGINEPATH = "TEMPLATEenginepath"; + const char *__USERHOMEPATH = "TEMPLATEuserhomepath"; + const char *__TOOLSPATH = "TEMPLATEtoolspath"; + const char *__BASEDIR = "TEMPLATEbasedir"; + const char *__APPPATH = "TEMPLATEapppath"; + + // iterate through string r + while(*r!='\0') + { + // check for special character + if(*r=='$') + { + if(strncmp(r+1, __ENGINEPATH, strlen(__ENGINEPATH)) == 0) + { + r+=strlen(__ENGINEPATH)+1; + p = g_pGameDescription->mEnginePath.GetBuffer(); + } + else if(strncmp(r+1, __USERHOMEPATH, strlen(__USERHOMEPATH)) == 0) + { + r+=strlen(__USERHOMEPATH)+1; + p = g_qeglobals.m_strHomeGame.GetBuffer(); + } + else if(strncmp(r+1, __BASEDIR, strlen(__BASEDIR)) == 0) + { + r+=strlen(__BASEDIR)+1; + p = g_pGameDescription->mBaseGame; + } + else if(strncmp(r+1, __TOOLSPATH, strlen(__TOOLSPATH)) == 0) + { + r+=strlen(__TOOLSPATH)+1; + p = g_strGameToolsPath.GetBuffer(); + } + else if(strncmp(r+1, __APPPATH, strlen(__APPPATH)) == 0) + { + r+=strlen(__APPPATH)+1; + p = g_strAppPath.GetBuffer(); + } + else + { + r++; + p = "$"; + } + + while(*p!='\0') *w++ = *p++; + } + else *w++ = *r++; + } + *w = '\0'; +} + +/* +=========== +QE_LoadProject +TODO TODO TODO (don't think this got fully merged in) +TTimo: added project file "version", version 2 adds '#' chars to the BSP command strings +version 3 was .. I don't remember .. version 4 adds q3map2 commands +TTimo: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk +=========== +*/ +/*\todo decide on a sensible location/name for project files.*/ +bool QE_LoadProject (const char *projectfile) +{ + char buf[1024]; + xmlDocPtr doc; + xmlNodePtr node, project; + + Sys_Printf("Loading project file: \"%s\"\n", projectfile); + doc = ParseXMLFile(projectfile, true); + + if(doc == NULL) return false; + + node=doc->children; + while(node != NULL && node->type != XML_DTD_NODE) node=node->next; + if(node == NULL || strcmp((char*)node->name, "project") != 0) + { + Sys_FPrintf(SYS_ERR, "ERROR: invalid file type\n"); + return false; + } + + while(node->type != XML_ELEMENT_NODE) node=node->next; + // + project = node; + + if(g_qeglobals.d_project_entity != NULL) Entity_Free(g_qeglobals.d_project_entity); + g_qeglobals.d_project_entity = Entity_Alloc(); + + for(node = project->children; node != NULL; node=node->next) + { + if(node->type != XML_ELEMENT_NODE) continue; + + // + ReplaceTemplates(buf, (char*)node->properties->next->children->content); + + SetKeyValue(g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf); + } + + xmlFreeDoc(doc); + + // project file version checking + // add a version checking to avoid people loading later versions of the project file and bitching + int ver = IntForKey( g_qeglobals.d_project_entity, "version" ); + if (ver > PROJECT_VERSION) + { + char strMsg[1024]; + sprintf (strMsg, "This is a version %d project file. This build only supports <=%d project files.\n" + "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION); + gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); + // set the project file to nothing so we are sure we'll ask next time? + g_PrefsDlg.m_strLastProject = ""; + g_PrefsDlg.SavePrefs(); + return false; + } + + // set here some default project settings you need + if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) + { + SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" ); + } + + g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" ); + + g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; + const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); + if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); + g_qeglobals.m_strHomeMaps += str; + g_qeglobals.m_strHomeMaps += '/'; + + // don't forget to create the dirs + Q_mkdir(g_qeglobals.m_strHomeGame.GetBuffer(), 0775); + Q_mkdir(g_qeglobals.m_strHomeMaps.GetBuffer(), 0775); + + // usefull for the log file and debuggin fucked up configurations from users: + // output the basic information of the .qe4 project file + // SPoG + // all these paths should be unix format, with a trailing slash at the end + // if not.. to debug, check that the project file paths are set up correctly + Sys_Printf("basepath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath") ); + Sys_Printf("entitypath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) ); + + + // check whether user_project key exists.. + // if not, save the current project under a new name + if (ValueForKey(g_qeglobals.d_project_entity, "user_project")[0] == '\0') + { + Sys_Printf("Loaded a template project file\n"); + + // create the user_project key + SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 + if (IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION) + { + char strMsg[2048]; + sprintf(strMsg, + "The template project '%s' has version %d. The editor binary is configured for version %d.\n" + "This indicates a problem in your setup. See http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672\n" + "I will keep going with this project till you fix this", + projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION); + gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); + } + + // create the writable project file path + strcpy(buf, g_qeglobals.m_strHomeGame.GetBuffer()); + strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); + strcat(buf, "/scripts/"); + // while the filename is already in use, increment the number we add to the end + int counter = 0; + char pUser[PATH_MAX]; + while (1) + { + sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter ); + counter++; + if (access( pUser, R_OK) != 0) + { + // this is the one + strcpy( buf, pUser ); + break; + } + } + // saving project will cause a save prefs + g_PrefsDlg.m_strLastProject = buf; + g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" ); + QE_SaveProject(buf); + } + else + { + // update preferences::LastProject with path of this successfully-loaded project + // save preferences + Sys_Printf("Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() ); + g_PrefsDlg.m_strLastProject = projectfile; + g_PrefsDlg.SavePrefs(); + } + + return true; +} + +/* +=========== +QE_SaveProject +TTimo: whenever QE_SaveProject is called, prefs are updated and saved with the path to the project +=========== +*/ +qboolean QE_SaveProject (const char* filename) +{ + Sys_Printf("Save project file '%s'\n", filename); + + xmlNodePtr node; + xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0"); + // create DTD node + xmlCreateIntSubset(doc, (xmlChar *)"project", NULL, (xmlChar *)"project.dtd"); + // create project node + doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"project", NULL); + + for(epair_t* epair = g_qeglobals.d_project_entity->epairs; epair != NULL; epair = epair->next) + { + node = xmlNewChild(doc->children->next, NULL, (xmlChar *)"key", NULL); + xmlSetProp(node, (xmlChar*)"name", (xmlChar*)epair->key); + xmlSetProp(node, (xmlChar*)"value", (xmlChar*)epair->value); + } + + CreateDirectoryPath(filename); + if (xmlSaveFormatFile(filename, doc, 1) != -1) + { + xmlFreeDoc(doc); + Sys_Printf("Setting current project in prefs to \"%s\"\n", filename ); + g_PrefsDlg.m_strLastProject = filename; + g_PrefsDlg.SavePrefs(); + return TRUE; + } + else + { + xmlFreeDoc(doc); + Sys_FPrintf(SYS_ERR, "failed to save project file: \"%s\"\n", filename); + return FALSE; + } +} + + + +/* +=========== +QE_KeyDown +=========== +*/ +#define SPEED_MOVE 32 +#define SPEED_TURN 22.5 + + +/* +=============== +ConnectEntities + +Sets target / targetname on the two entities selected +from the first selected to the secon +=============== +*/ +void ConnectEntities (void) +{ + entity_t *e1, *e2; + const char *target; + char *newtarg = NULL; + + if (g_qeglobals.d_select_count != 2) + { + Sys_Status ("Must have two brushes selected", 0); + Sys_Beep (); + return; + } + + e1 = g_qeglobals.d_select_order[0]->owner; + e2 = g_qeglobals.d_select_order[1]->owner; + + if (e1 == world_entity || e2 == world_entity) + { + Sys_Status ("Can't connect to the world", 0); + Sys_Beep (); + return; + } + + if (e1 == e2) + { + Sys_Status ("Brushes are from same entity", 0); + Sys_Beep (); + return; + } + + target = ValueForKey (e1, "target"); + if (target && target[0]) + newtarg = g_strdup(target); + else + { + target = ValueForKey(e2, "targetname"); + if(target && target[0]) + newtarg = g_strdup(target); + else + Entity_Connect(e1, e2); + } + + if(newtarg != NULL) + { + SetKeyValue(e1, "target", newtarg); + SetKeyValue(e2, "targetname", newtarg); + g_free(newtarg); + } + + Sys_UpdateWindows (W_XY | W_CAMERA); + + Select_Deselect(); + Select_Brush (g_qeglobals.d_select_order[1]); +} + +qboolean QE_SingleBrush (bool bQuiet) +{ + if ( (selected_brushes.next == &selected_brushes) + || (selected_brushes.next->next != &selected_brushes) ) + { + if (!bQuiet) + { + Sys_Printf ("Error: you must have a single brush selected\n"); + } + return false; + } + if (selected_brushes.next->owner->eclass->fixedsize) + { + if (!bQuiet) + { + Sys_Printf ("Error: you cannot manipulate fixed size entities\n"); + } + return false; + } + + return true; +} + +void QE_InitVFS (void) +{ + // VFS initialization ----------------------- + // we will call vfsInitDirectory, giving the directories to look in (for files in pk3's and for standalone files) + // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order + // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too + Str directory,prefabs; + + // TTimo: let's leave this to HL mode for now + if (g_pGameDescription->mGameFile == "hl.game") + { + // Hydra: we search the "gametools" path first so that we can provide editor + // specific pk3's wads and misc files for use by the editor. + // the relevant map compiler tools will NOT use this directory, so this helps + // to ensure that editor files are not used/required in release versions of maps + // it also helps keep your editor files all in once place, with the editor modules, + // plugins, scripts and config files. + // it also helps when testing maps, as you'll know your files won't/can't be used + // by the game engine itself. + + // + directory = g_pGameDescription->mGameToolsPath; + vfsInitDirectory(directory.GetBuffer()); + } + + // NOTE TTimo about the mymkdir calls .. this is a bit dirty, but a safe thing on *nix + + // if we have a mod dir + if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') + { + +#if defined (__linux__) || defined (__APPLE__) + // ~/./ + directory = g_qeglobals.m_strHomeGame.GetBuffer(); + Q_mkdir (directory.GetBuffer (), 0775); + directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); + Q_mkdir (directory.GetBuffer (), 0775); + vfsInitDirectory(directory.GetBuffer()); + AddSlash (directory); + prefabs = directory; + // also create the maps dir, it will be used as prompt for load/save + directory += "/maps"; + Q_mkdir (directory, 0775); + // and the prefabs dir + prefabs += "/prefabs"; + Q_mkdir (prefabs, 0775); + +#endif + + // / + directory = g_pGameDescription->mEnginePath; + directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); + Q_mkdir (directory.GetBuffer (), 0775); + vfsInitDirectory(directory.GetBuffer()); + AddSlash(directory); + prefabs = directory; + // also create the maps dir, it will be used as prompt for load/save + directory += "/maps"; + Q_mkdir (directory.GetBuffer (), 0775); + // and the prefabs dir + prefabs += "/prefabs"; + Q_mkdir (prefabs, 0775); + } + +#if defined (__linux__) || defined (__APPLE__) + // ~/./ + directory = g_qeglobals.m_strHomeGame.GetBuffer(); + directory += g_pGameDescription->mBaseGame; + vfsInitDirectory (directory.GetBuffer ()); +#endif + + // / + directory = g_pGameDescription->mEnginePath; + directory += g_pGameDescription->mBaseGame; + vfsInitDirectory(directory.GetBuffer()); +} + +void QE_Init (void) +{ + /* + ** initialize variables + */ + g_qeglobals.d_gridsize = 8; + g_qeglobals.d_showgrid = true; + + QE_InitVFS(); + + Eclass_Init(); + FillClassList(); // list in entity window + Map_Init(); + + FillTextureMenu(); + FillBSPMenu(); + + /* + ** other stuff + */ + Z_Init (); +} + +void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +int g_numbrushes, g_numentities; + +void QE_CountBrushesAndUpdateStatusBar( void ) +{ + static int s_lastbrushcount, s_lastentitycount; + static qboolean s_didonce; + + //entity_t *e; + brush_t *b, *next; + + g_numbrushes = 0; + g_numentities = 0; + + if ( active_brushes.next != NULL ) + { + for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + if (b->brush_faces ) + { + if ( !b->owner->eclass->fixedsize) + g_numbrushes++; + else + g_numentities++; + } + } + } +/* + if ( entities.next != NULL ) + { + for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) + { + g_numentities++; + } + } +*/ + if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) + { + Sys_UpdateStatusBar(); + + s_lastbrushcount = g_numbrushes; + s_lastentitycount = g_numentities; + s_didonce = true; + } +} + +char com_token[1024]; +qboolean com_eof; + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = true; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +char* Get_COM_Token() +{ + return com_token; +} + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +int argc; +char *argv[MAX_NUM_ARGVS]; + +/* +============ +ParseCommandLine +============ +*/ +void ParseCommandLine (char *lpCmdLine) +{ + argc = 1; + argv[0] = "programname"; + + while (*lpCmdLine && (argc < MAX_NUM_ARGVS)) + { + while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + argv[argc] = lpCmdLine; + argc++; + + while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + *lpCmdLine = 0; + lpCmdLine++; + } + + } + } +} + + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (char *check) +{ + int i; + + for (i = 1;i= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + +// BSP frontend plugin +// global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin +_QERPlugBSPFrontendTable g_BSPFrontendTable; + +// ============================================================================= +// Sys_ functions + +bool Sys_AltDown () +{ +#ifdef _WIN32 + return (GetKeyState(VK_MENU) & 0x8000) != 0; +#endif + +#if defined (__linux__) || defined (__APPLE__) + char keys[32]; + int x; + + XQueryKeymap(GDK_DISPLAY(), keys); + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L); + if (keys[x/8] & (1 << (x % 8))) + return true; + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R); + if (keys[x/8] & (1 << (x % 8))) + return true; + + return false; +#endif +} + +bool Sys_ShiftDown () +{ +#ifdef _WIN32 + return (GetKeyState(VK_SHIFT) & 0x8000) != 0; +#endif + +#if defined (__linux__) || defined (__APPLE__) + char keys[32]; + int x; + + XQueryKeymap(GDK_DISPLAY(), keys); + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_L); + if (keys[x/8] & (1 << (x % 8))) + return true; + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_R); + if (keys[x/8] & (1 << (x % 8))) + return true; + + return false; +#endif +} + +void Sys_MarkMapModified (void) +{ + char title[PATH_MAX]; + + if (modified != 1) + { + modified = true; // mark the map as changed + sprintf (title, "%s *", currentmap); + + QE_ConvertDOSToUnixName( title, title ); + Sys_SetTitle (title); + } +} + +void Sys_SetTitle (const char *text) +{ + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_main_window), text); +} + +bool g_bWaitCursor = false; + +void WINAPI Sys_BeginWait (void) +{ + GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + g_bWaitCursor = true; +} + +void WINAPI Sys_EndWait (void) +{ + GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); + gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + g_bWaitCursor = false; +} + +void Sys_GetCursorPos (int *x, int *y) +{ + // FIXME: not multihead safe + gdk_window_get_pointer (NULL, x, y, NULL); +} + +void Sys_SetCursorPos (int x, int y) +{ + // NOTE: coordinates are in GDK space, not OS space +#ifdef _WIN32 + int sys_x = x - g_pParentWnd->GetGDKOffsetX(); + int sys_y = y - g_pParentWnd->GetGDKOffsetY(); + + SetCursorPos (sys_x, sys_y); +#endif + +#if defined (__linux__) || defined (__APPLE__) + XWarpPointer (GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y); +#endif +} + +void Sys_Beep (void) +{ +#if defined (__linux__) || defined (__APPLE__) + gdk_beep (); +#else + MessageBeep (MB_ICONASTERISK); +#endif +} + +double Sys_DoubleTime (void) +{ + return clock()/ 1000.0; +} + +/* +=============================================================== + + STATUS WINDOW + +=============================================================== +*/ + +void Sys_UpdateStatusBar( void ) +{ + extern int g_numbrushes, g_numentities; + + char numbrushbuffer[100]=""; + + sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); + g_pParentWnd->SetStatusText(2, numbrushbuffer); + //Sys_Status( numbrushbuffer, 2 ); +} + +void Sys_Status(const char *psz, int part ) +{ + g_pParentWnd->SetStatusText (part, psz); +} + +// ============================================================================= +// MRU + +#define MRU_MAX 4 +static GtkWidget *MRU_items[MRU_MAX]; +static int MRU_used; +typedef char MRU_filename_t[PATH_MAX]; +MRU_filename_t MRU_filenames[MRU_MAX]; + +static char* MRU_GetText (int index) +{ + return MRU_filenames[index]; +} + +void buffer_write_escaped_mnemonic(char* buffer, const char* string) +{ + while(*string != '\0') + { + if(*string == '_') + { + *buffer++ = '_'; + } + + *buffer++ = *string++; + } + *buffer = '\0'; +} + +static void MRU_SetText (int index, const char *filename) +{ + strcpy(MRU_filenames[index], filename); + + char mnemonic[PATH_MAX * 2 + 4]; + mnemonic[0] = '_'; + sprintf(mnemonic+1, "%d", index+1); + mnemonic[2] = '-'; + mnemonic[3] = ' '; + buffer_write_escaped_mnemonic(mnemonic+4, filename); + gtk_label_set_text_with_mnemonic(GTK_LABEL (GTK_BIN (MRU_items[index])->child), mnemonic); +} + +void MRU_Load () +{ + int i = g_PrefsDlg.m_nMRUCount; + + if(i > 4) + i = 4; //FIXME: make this a define + + for (; i > 0; i--) + MRU_AddFile (g_PrefsDlg.m_strMRUFiles[i-1].GetBuffer()); +} + +void MRU_Save () +{ + g_PrefsDlg.m_nMRUCount = MRU_used; + + for (int i = 0; i < MRU_used; i++) + g_PrefsDlg.m_strMRUFiles[i] = MRU_GetText (i); +} + +void MRU_AddWidget (GtkWidget *widget, int pos) +{ + if (pos < MRU_MAX) + MRU_items[pos] = widget; +} + +void MRU_AddFile (const char *str) +{ + int i; + char* text; + + // check if file is already in our list + for (i = 0; i < MRU_used; i++) + { + text = MRU_GetText (i); + + if (strcmp (text, str) == 0) + { + // reorder menu + for (; i > 0; i--) + MRU_SetText (i, MRU_GetText (i-1)); + + MRU_SetText (0, str); + + return; + } + } + + if (MRU_used < MRU_MAX) + MRU_used++; + + // move items down + for (i = MRU_used-1; i > 0; i--) + MRU_SetText (i, MRU_GetText (i-1)); + + MRU_SetText (0, str); + gtk_widget_set_sensitive (MRU_items[0], TRUE); + gtk_widget_show (MRU_items[MRU_used-1]); +} + +void MRU_Activate (int index) +{ + char *text = MRU_GetText (index); + + if (access (text, R_OK) == 0) + { + text = strdup (text); + MRU_AddFile (text); + Map_LoadFile (text); + free (text); + } + else + { + MRU_used--; + + for (int i = index; i < MRU_used; i++) + MRU_SetText (i, MRU_GetText (i+1)); + + if (MRU_used == 0) + { + gtk_label_set_text (GTK_LABEL (GTK_BIN (MRU_items[0])->child), "Recent Files"); + gtk_widget_set_sensitive (MRU_items[0], FALSE); + } + else + { + gtk_widget_hide (MRU_items[MRU_used]); + } + } +} + +/* +====================================================================== + +FILE DIALOGS + +====================================================================== +*/ + +qboolean ConfirmModified () +{ + if (!modified) + return true; + + if (gtk_MessageBox (g_pParentWnd->m_pWidget, "This will lose changes to the map", "warning", MB_OKCANCEL) == IDCANCEL) + return false; + return true; +} + +void ProjectDialog () +{ + const char *filename; + char buffer[NAME_MAX]; + + /* + * Obtain the system directory name and + * store it in buffer. + */ + + strcpy(buffer, g_qeglobals.m_strHomeGame.GetBuffer()); + strcat(buffer, g_pGameDescription->mBaseGame.GetBuffer()); + strcat (buffer, "/scripts/"); + + // Display the Open dialog box + filename = file_dialog (NULL, TRUE, "Open File", buffer, "project"); + + if (filename == NULL) + return; // canceled + + // Open the file. + // NOTE: QE_LoadProject takes care of saving prefs with new path to the project file + if (!QE_LoadProject(filename)) + Sys_Printf ("Failed to load project from file: %s\n", filename); + else + // FIXME TTimo QE_Init is probably broken if you don't call it during startup right now .. + QE_Init(); +} + +/* +======================================================= + +Menu modifications + +======================================================= +*/ + +/* +================== +FillBSPMenu + +================== +*/ +char *bsp_commands[256]; + +void FillBSPMenu () +{ + GtkWidget *item, *menu; // menu points to a GtkMenu (not an item) + epair_t *ep; + GList *lst; + int i; + + menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_bsp")); + + while ((lst = gtk_container_children (GTK_CONTAINER (menu))) != NULL) + gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->data)); + + if (g_PrefsDlg.m_bDetachableMenus) { + item = gtk_tearoff_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), item); + gtk_widget_set_sensitive (item, TRUE); + gtk_widget_show (item); + } + + if (g_qeglobals.bBSPFrontendPlugin) + { + CString str = g_BSPFrontendTable.m_pfnGetBSPMenu(); + char cTemp[1024]; + strcpy(cTemp, str); + char* token = strtok(cTemp, ",;"); + if (token && *token == ' ') + { + while (*token == ' ') + token++; + } + i = 0; + + // first token is menu name + item = gtk_menu_get_attach_widget (GTK_MENU (menu)); + gtk_label_set_text (GTK_LABEL (GTK_BIN (item)->child), token); + + token = strtok(NULL, ",;"); + while (token != NULL) + { + g_BSPFrontendCommands = g_slist_append (g_BSPFrontendCommands, g_strdup (token)); + item = gtk_menu_item_new_with_label (token); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); + token = strtok(NULL, ",;"); + i++; + } + } + else + { + i = 0; + for (ep = g_qeglobals.d_project_entity->epairs; ep; ep = ep->next) + { + if (strncmp(ep->key, "bsp_", 4)==0) + { + bsp_commands[i] = ep->key; + item = gtk_menu_item_new_with_label (ep->key+4); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); + i++; + } + } + } +} + +//============================================== + +void AddSlash(CString& strPath) +{ + if (strPath.GetLength() > 0) + { + if ((strPath.GetAt(strPath.GetLength()-1) != '/') && + (strPath.GetAt(strPath.GetLength()-1) != '\\')) + strPath += '/'; + } +} + +bool ExtractPath_and_Filename(const char* pPath, CString& strPath, CString& strFilename) +{ + CString strPathName; + strPathName = pPath; + int nSlash = strPathName.ReverseFind('\\'); + if (nSlash == -1) + // TTimo: try forward slash, some are using forward + nSlash = strPathName.ReverseFind('/'); + if (nSlash >= 0) + { + strPath = strPathName.Left(nSlash+1); + strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1); + } + // TTimo: try forward slash, some are using forward + else + strFilename = pPath; + return true; +} + +//=========================================== + +//++timo FIXME: no longer used .. remove! +char *TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; i +#include +#include + +#include + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 +// this is the version to expect from template projects +#define PROJECT_VERSION 2 + +//#define MEM_DEBUG +#ifdef MEM_DEBUG + +#define malloc(a) debug_malloc(a, __FILE__, __LINE__) +#define free(a) debug_free(a, __FILE__, __LINE__) + +void* debug_malloc (size_t size, const char* file, int line); +void debug_free (void *buf, const char* file, int line); + +#endif + +#ifdef _DEBUG +//#define DBG_WINDOWPOS +#endif + +#ifdef DBG_WINDOWPOS +void CheckWatchit(char *msg); +#endif + +// those two files are generated +// if they are missing, you NEED to run makeversion.sh +// NOTE: for win32 users, cygwin installation is REQUIRED to run makeversion.sh +// NOTE TTimo if any of those changes (they might change a lot), then the whole app is rebuilt. +// very often it's not necessary +#include "version.h" +#include "aboutmsg.h" + +// synapse is our utility lib for dynamic shared objects management +#include "synapse.h" + +#include "qertypes.h" +#include "cmdlib.h" +#include "mathlib.h" +#include "parse.h" + +#include "qedefs.h" +#include "qfiles.h" +#include "textures.h" +#include "brush.h" +//#include "entity.h" +#define USE_ENTITYTABLE_DEFINE +#include "ientity.h" +extern _QEREntityTable __ENTITYTABLENAME; +// wrappers for brush access +#include "ibrush.h" +// wrappers for patch access +#include "ipatch.h" + +#include "imodel.h" + +#include "imap.h" + +#include "iundo.h" + +extern _QERPlugMapTable g_MapTable; + +//++timo for BP conversion escaping FIXME: remove when mixing two formats! +extern bool g_bCancel_Map_LoadFile; +// used to be #defines, multiple engine support suggests we should go towards dynamic +extern int g_MaxWorldCoord; +extern int g_MinWorldCoord; +extern int g_MaxBrushSize; +/* +// set to true when we are parsing a terrain entity +extern bool g_bParseTerrain; +extern IShader *g_pTerrainShader, *g_pCaulk; +*/ +#include "map.h" + +#include "select.h" + +#include "camera.h" +#include "z.h" + +#include "undo.h" +#include "glwidget.h" + +// the dec offsetof macro doesn't work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +// our own implementation of Q_int, clamping can be disabled on prefs +vec_t Rad_rint (vec_t in); + +double I_FloatTime (void); + +void Error (char *error, ...); +int CheckParm (char *check); +void ParseCommandLine (char *lpCmdLine); + +int ParseNum (char *str); + +char* COM_Parse (char *data); +char* Get_COM_Token(); + +extern char com_token[1024]; +extern qboolean com_eof; + +#define MAX_NUM_ARGVS 32 +extern int argc; +extern char *argv[MAX_NUM_ARGVS]; + +// +// system functions +// +// TTimo NOTE: WINAPI funcs can be accessed by plugins +void Sys_UpdateStatusBar( void ); +void WINAPI Sys_UpdateWindows (int bits); +void Sys_Beep (void); +void Sys_ClearPrintf (void); +double Sys_DoubleTime (void); +void Sys_GetCursorPos (int *x, int *y); +void Sys_SetCursorPos (int x, int y); +void Sys_SetTitle (const char *text); +void WINAPI Sys_BeginWait (void); +void WINAPI Sys_EndWait (void); +void Sys_Status(const char *psz, int part); +bool Sys_AltDown (); +bool Sys_ShiftDown (); +// will open/close/check the log file based on the following globals: +// g_PrefsDlg.m_bLogConsole g_qeglobals.hLogFile +void Sys_LogFile (void); + +extern qboolean verbose; +#include "qsysprintf.h" + +// NOTE TTimo I split out the GUI-depependant stuff from QEGlobals_t into a seperate struct +typedef struct +{ + // GL widget of the camera view + // all textures are binded in this context and shared with the others + GtkWidget *d_glBase; + + GtkWidget *d_main_window; // d_hwndMain + GtkWidget *d_edit; // d_hwndEdit + GtkWidget *d_entity; // d_hwndEntity + GtkWidget *d_camera; // d_hwndCamera; + GtkWidget *d_texture; // d_hwndTexture; + GtkWidget *d_texture_scroll; + GtkWidget *d_z; // d_hwndZ; + +} QEGlobals_GUI_t; + +// usefull portability stuff +//++timo move them somewhere +bool DoesFileExist(const char* pBuff, long& lSize); + +char *copystring (char *s); +char *ExpandReletivePath (char *p); + +#include "xmlstuff.h" +#include "points.h" + +// +// drag.c +// +void Drag_Begin (int x, int y, int buttons, vec3_t xaxis, vec3_t yaxis, vec3_t origin, vec3_t dir, bool sf_camera = false); +void Drag_MouseMoved (int x, int y, int buttons); +void Drag_MouseUp (int nButtons = 0); + +// +// csg.c +// +void CSG_MakeHollow (void); +void CSG_Subtract (void); +void CSG_Merge (void); + +// +// vertsel.c +// + +void SetupVertexSelection (void); +void SelectEdgeByRay (vec3_t org, vec3_t dir); +void SelectVertexByRay (vec3_t org, vec3_t dir); + +void ConnectEntities (void); + +extern int update_bits; + +extern int screen_width; +extern int screen_height; + +char *TranslateString (char *buf); + +// +// linux_qe3.cc +// +//void OpenDialog (); +//void SaveAsDialog (bool bRegion); +void ProjectDialog (void); +void MRU_Load (); +void MRU_Save (); +void MRU_AddWidget (GtkWidget *widget, int pos); +void MRU_AddFile (const char *str); +void MRU_Activate (int index); + + +void FillTextureMenu (GSList** pArray = NULL); +void FillBSPMenu (void); + +// profile functions - kind of utility lib +// they are kind of dumb, they expect to get the path to the .ini file or to the prefs directory when called +// load_buffer and save_buffer expect the path only, theyll build a $(pszName).bin file +bool WINAPI profile_save_int (const char *filename, const char *section, const char *key, int value); +bool WINAPI profile_save_float (const char *filename, const char *section, const char *key, float value); +bool WINAPI profile_save_string (const char *filename, const char *section, const char *key, const char *value); +bool profile_save_buffer (const char *rc_path, const char *pszName, void *pvBuf, guint32 lSize); +bool profile_load_buffer (const char *rc_path, const char *pszName, void *pvBuf, guint32 *plSize); +int WINAPI profile_load_int (const char *filename, const char *section, const char *key, int default_value); +float WINAPI profile_load_float (const char *filename, const char *section, const char *key, float default_value); +char* WINAPI profile_load_string (const char *filename, const char *section, const char *key, const char *default_value); +// used in the command map code +bool read_var (const char *filename, const char *section, const char *key, char *value); + +// +// entityw.c +// +void FillClassList (void); +bool UpdateEntitySel(eclass_t *pec); +void SetInspectorMode(int iType); +void SetSpawnFlags(void); +void GetSpawnFlags(void); +void SetKeyValuePairs(bool bClearMD3 = false); +extern void BuildGammaTable(float g); +bool GetSelectAllCriteria(CString &strKey, CString &strVal); + +// linux_dlg.c + +typedef enum { + BEVEL = 0, + ENDCAP, + IBEVEL, + IENDCAP +} CapDialog; + +int DoCapDlg (int *type, bool *b_GroupResul); +int DoBSInputDlg (const char *fields[5], float values[5]); +int DoTextureLayout (float *fx, float *fy); +char* DoNameDlg (const char* title); +char* DoNewProjectDlg (); +/* +text editor, open filename at given line +opening at line works only for win32 / editpad and builtin Gtk editor + +we only allow one instance of the Gtk editor widget opened at a given time +if we get called with an existing instance, switch to new file .. +*/ +void DoTextEditor (const char* filename, int cursorpos); +int DoLightIntensityDlg (int *intensity); + +void DoMapInfo (); +void DoEntityList (); +void DoGamma(); +void DoFind(); +void DoRotateDlg (); +void DoSides(bool bCone = false, bool bSphere = false, bool bTorus = false); +void DoAbout(); +void DoSnapTToGrid(float hscale = 0.0f, float vscale = 0.0f); +void DoSurface(); +void ToggleSurface(); // will show/hide depending on the current state +void DoNewPatchDlg (); +void DoThickenDlg (); +void DoCommandListDlg (); +void DoScaleDlg ();; +void DoTextureListDlg (); +void DoScriptsDlg (); + +// QE function declarations +void QE_CheckAutoSave( void ); +void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ); +void QE_CountBrushesAndUpdateStatusBar( void ); +void WINAPI QE_CheckOpenGLForErrors(void); +void QE_ExpandBspString (char *bspaction, GPtrArray & out, char *mapname); +// initialise the VFS from current project settings +void QE_InitVFS(); +// do all initialisations that should happen after a project is load (during startup or project change) +void QE_Init (void); +qboolean QE_KeyDown (int key, int nFlags = 0); +// does some sanity checks on the project entity, such as removing ending filename seperators from paths +// (this usually gets propagated to the actual project file since most of the time we save right after calling the check) +void QE_CheckProjectEntity(); +// this will load a new project entity in memory, and potentially process it from a template +// NOTE TTimo calling QE_LoadProject won't take care of the various initialisation that are performed depending on the project settings +// you should then call QE_Init for that +#define PROJECT_TEMPLATE_NAME "default_project.proj" +#define PROJECT_USER_NAME "user_project.proj" +#define PROJECT_FILETYPE "proj" +qboolean QE_LoadProject (const char *projectfile); +qboolean QE_SingleBrush (bool bQuiet = false); + + +// sys stuff +void Sys_MarkMapModified (void); + +#if 0 // no longer used + +// QE Win32 function declarations +#ifdef _WIN32 +int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ); +void QEW_StopGL( HWND hWnd, HGLRC hGLRC, HDC hDC ); +#endif + +#endif + +// extern declarations +extern QEGlobals_t g_qeglobals; +extern QEGlobals_GUI_t g_qeglobals_gui; + +qboolean IsBrushSelected(brush_t* bSel); + +// curve brushes + +void Curve_MakeCurvedBrush (qboolean negative, qboolean top, qboolean bottom, + qboolean s1, qboolean s2, qboolean s3, qboolean s4); + +void Curve_Invert (void); + +void Curve_AddFakePlanes( brush_t *B ); +void Curve_StripFakePlanes( brush_t *B ); +void Curve_BuildPoints (brush_t *b); +void Curve_XYDraw (brush_t *b); +void Curve_CameraDraw (brush_t *b); + +void Curve_WriteFile (char *name); + + +// patch stuff +patchMesh_t *Patch_Alloc(); +patchMesh_t* MakeNewPatch(); +brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld = true); +brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation = 2, bool bDeleteSource = true, bool bOverride = false); +//void Patch_ReadFile (char *name); +//void Patch_WriteFile (char *name); +void Patch_BuildPoints (brush_t *b); +void Patch_Move(patchMesh_t *p, const vec3_t vMove, bool bRebuild = false); +//++timo had to add a default value for bSnap (see Patch_ApplyMatrix call from Select_ApplyMatrix in select.cpp) +void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap = false); +void Patch_EditPatch(); +void Patch_Deselect(); +void Patch_Deselect(patchMesh_t *p); +void Patch_Delete(patchMesh_t *p); +int Patch_MemorySize(patchMesh_t *p); +void Patch_Select(patchMesh_t *p); +void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuilt = true); +void Patch_Cleanup(); +void Patch_SetView(int n); +void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef = NULL); +void Patch_BrushToMesh(bool bCone = false, bool bBevel = false, bool bEndcap = false, bool bSquare = false, int nHeight = 3); +bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove); +//void Patch_ReadBuffer(char* pBuff, bool bSelect = false); +//void Patch_WriteFile (MemStream* pMemFile); +void Patch_UpdateSelected(vec3_t vMove); +//brush_t* Patch_Parse(bool bOld); +//void Patch_Write (patchMesh_t *p, FILE *f); +//void Patch_Write (patchMesh_t *p, MemStream *file); +//void Patch_AdjustColumns(patchMesh_t *p, int nCols); +//void Patch_AdjustRows(patchMesh_t *p, int nRows); +void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag); +patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom); +void Patch_RotateTexture(patchMesh_t *p, float fAngle); +void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup = true); +// shift of some pixel amount +void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy); +// shift of ST increments +void Patch_ShiftTextureST(patchMesh_t *p, float fx, float fy); +void Patch_DrawCam(patchMesh_t *p); +void Patch_DrawXY(patchMesh_t *p); +void Patch_InsertColumn(patchMesh_t *p, bool bAdd); +void Patch_InsertRow(patchMesh_t *p, bool bAdd); +void Patch_RemoveRow(patchMesh_t *p, bool bFirst); +void Patch_RemoveColumn(patchMesh_t *p, bool bFirst); +void Patch_ToggleInverted(); +void Patch_Restore(patchMesh_t *p); +void Patch_Save(patchMesh_t *p); +void Patch_SetTextureInfo(texdef_t* pt); +void Patch_NaturalTexturing(); +void Patch_ResetTexturing(float fx, float fy); +void Patch_FitTexturing(); +void Patch_BendToggle(); +//void Patch_StartInsDel(); +void Patch_BendHandleTAB(); +void Patch_BendHandleENTER(); +void Patch_SelectBendNormal(); +void Patch_SelectBendAxis(); +bool OnlyPatchesSelected(); +bool AnyPatchesSelected(); +patchMesh_t* SinglePatchSelected(); +void Patch_CapCurrent(); +void Patch_DisperseRows(); +void Patch_DisperseIntermediateRows(); +void Patch_DisperseIntermediateColumns(); +void Patch_CycleCapSelected(); +void Patch_NaturalizeSelected(bool bCap = false);//, bool bCycleCap = false); +void Patch_SelectAreaPoints(bool bMulti); +void Patch_InvertTexture(bool bY); +void patchInvert(patchMesh_t *p); +//void Patch_InsDelToggle(); +//void Patch_InsDelHandleTAB(); +//void Patch_InsDelHandleENTER(); +void Patch_SetOverlays(); +void Patch_ClearOverlays(); +void Patch_Thicken(int nAmount, bool bSeam, qboolean bGroupResult); +void Patch_Transpose(); +void Patch_Freeze(); +void Patch_UnFreeze(bool bAll); +const char* Patch_GetTextureName(); +void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce); +void Patch_SnapToGrid(patchMesh_t *p); +extern bool g_bPatchShowBounds; +extern bool g_bPatchWireFrame; +extern bool g_bPatchWeld; +extern bool g_bPatchDrillDown; +//extern bool g_bPatchInsertMode; +extern bool g_bPatchBendMode; +extern vec3_t g_vBendOrigin; +//void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz); +const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey); +void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue); +void Patch_LODMatchAll(); +void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax); + + + + +// group stuff +// group_t are loaded / saved through "group_info" entities +// they hold epairs for group settings and additionnal access info (tree nodes) +typedef struct group_s +{ + struct group_s *next; + epair_t *epairs; +#if 0 //! Deprecated in gtk 2.x. + GtkCTreeNode *itemOwner; +#endif +} group_t; + +// NOTES: grouping only enabled in brush primitives mode +// grouping works by naming brushes and setting display properties +// the group hierarchy is not related with the map hierarchy (entity list, brushes etc.) +// brushes with no group are under the "world" node (default for all brushes) +// void Group_GetListFromWorld(CStringArray *pArray); +void Group_RemoveListFromWorld(); +// void Group_SetListToWorld(CStringArray *pArray); +// void Group_BuildTree(CTreeCtrl *pTree); +// void Group_DecomposeTree(CTreeCtrl *pTree); +// save group_t as "classname" "group_info" things +void Group_Save(FILE *f); +// clean the brushes ownerItem, clean the treeview and rebuild everything +// is usually called when loading a new map, but may be called anytime +void Group_Init(); +void Group_Add(entity_t *e); + +// remove a brush from it's current group, will erase the "group" epair if any, and delete the tree control node +void Group_RemoveBrush(brush_t *b); +void Group_AddToWorld(brush_t *b); +// will remove brush of it's current group if any, and will add it wherever needed according to it's "group" key +void Group_AddToProperGroup(brush_t *b); +void Group_AddToSelected(brush_t *b); +// allocate a new group, set name +group_t* Group_Alloc(const char *name); +// we use entities to store information about the groups +// these entities are not linked into the world, and they have no brushes +// only loaded / saved in map file +group_t* Group_ForName(const char *name); + +// TTimo +// new brush primitive stuff + +#ifdef _DEBUG +//#define DBG_BP +#endif + +// get the relative axes of the current texturing +void BrushPrimit_GetRelativeAxes(face_t *f, vec3_t vecS, vec3_t vecT); +// brush primitive stuff +void ComputeAxisBase(vec3_t normal, vec3_t texS, vec3_t texT ); +void FaceToBrushPrimitFace(face_t *f); +void BrushPrimitFaceToFace(face_t *f); +void EmitBrushPrimitTextureCoordinates(face_t *, winding_t *); +// EmitTextureCoordinates, is old code used for brush to brush primitive conversion +void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f); +//void BrushPrimit_Parse(brush_t *); +// compute a fake shift scale rot representation from the texture matrix +void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] ); +void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] ); +void ConvertTexMatWithQTexture( vec_t texMat1[2][3], qtexture_t *qtex1, vec_t texMat2[2][3], qtexture_t *qtex2 ); +// NOTE: this is a wrapper over the vec_t mat[2][3] version +void ConvertTexMatWithQTexture( brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2 ); +// texture locking +void ShiftTextureGeometric_BrushPrimit(face_t *f, vec3_t delta); +void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y ); +void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin ); +// used in CCamWnd::ShiftTexture_BrushPrimit +void ComputeBest2DVector( vec3_t v, vec3_t X, vec3_t Y, int &x, int &y ); +void Face_FitTexture_BrushPrimit( face_t *face, vec3_t minx, vec3_t maxs, int nHeight, int nWidth ); +// lock textures on a random transformation +void ApplyMatrix_BrushPrimit(face_t *f, vec3_t matrix[3], vec3_t origin); +// low level functions .. put in mathlib? +#define BPMatCopy(a,b) {b[0][0] = a[0][0]; b[0][1] = a[0][1]; b[0][2] = a[0][2]; b[1][0] = a[1][0]; b[1][1] = a[1][1]; b[1][2] = a[1][2];} +// apply a scale transformation to the BP matrix +#define BPMatScale(m,sS,sT) {m[0][0]*=sS; m[1][0]*=sS; m[0][1]*=sT; m[1][1]*=sT;} +// apply a translation transformation to a BP matrix +#define BPMatTranslate(m,s,t) {m[0][2] += m[0][0]*s + m[0][1]*t; m[1][2] += m[1][0]*s+m[1][1]*t;} +// 2D homogeneous matrix product C = A*B +void BPMatMul(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]); +// apply a rotation (degrees) +void BPMatRotate(vec_t A[2][3], float theta); +#ifdef _DEBUG +void BPMatDump(vec_t A[2][3]); +#endif +// GL matrix product +void GLMatMul(vec_t M[4][4], vec_t A[4], vec_t B[4]); +qboolean IsBrushPrimitMode(); +// +// eclass.cpp +// +#include "ieclass.h" + +/*! + \todo those are at the eclass manager level, but some documentation about what they do will be helpful +*/ +extern qboolean parsing_single; +extern qboolean eclass_found; +extern eclass_t *eclass_e; +extern eclass_t *g_md3Cache; + +/*! +eclass manager API +*/ +void Eclass_InsertAlphabetized(eclass_t *e); +eclass_t** Get_EClass_E(); +void Set_Eclass_Found(qboolean); +qboolean Get_Parsing_Single(); + +// .def loading, builtin module +#include "eclass_def.h" +extern CSynapseBuiltinClientDef eclass_def; + +/*! +global table to .def entity class description +this is a builtin module, even if we rely on fgd, we still use this one in cases such as entities not found etc. +*/ +extern _EClassTable g_EClassDefTable; + +/*! +support for one additional/optional entity format +*/ +extern bool g_bHaveEClassExt; +extern _EClassTable g_EClassExtTable; + + +#include "iplugin.h" +// for interfaces, we require main plugin header included +#include "qerplugin.h" + +// +// SurfaceDlg.cpp and surface properties plugin +// +//++timo some patch in/out stuff is in there, needs to be moved out in a dedicated interface +#include "isurfaceplugin.h" +#include "surfaceplugin.h" +void WINAPI Patch_Rebuild(patchMesh_t *p); +#include "isurfaceplugin.h" +extern _QERPlugSurfaceTable g_SurfaceTable; +void SurfaceDlgFitAll(); + +// +// OpenGL interface +// +#include "igl.h" + +GtkWidget* WINAPI QERApp_GetQeglobalsGLWidget(); +void WINAPI QERApp_HookGL2DWindow(IGL2DWindow* pGLW); +void WINAPI QERApp_UnHookGL2DWindow(IGL2DWindow* pGLW); +void WINAPI QERApp_HookGL3DWindow(IGL3DWindow* pGLW); +void WINAPI QERApp_UnHookGL3DWindow(IGL3DWindow* pGLW); +void Draw2DPluginEntities( VIEWTYPE vt ); +void Draw3DPluginEntities(); + +// +// IShaders interface +// +#define USE_SHADERSTABLE_DEFINE +#include "ishaders.h" +extern _QERShadersTable g_ShadersTable; + +// +// ISelectedFace interface +// +#include "iselectedface.h" +int WINAPI QERApp_GetSelectedFaceCount(); +// NOTE: it's the brush corresponding to the selected face below! +brush_t* WINAPI QERApp_GetSelectedFaceBrush(int iface); +face_t* WINAPI QERApp_GetSelectedFace(int iface); +int WINAPI QERApp_GetFaceInfo(int iface, _QERFaceData *pFaceData, winding_t *pWinding); +int WINAPI QERApp_SetFaceInfo(int iface, _QERFaceData *pFaceData); +int WINAPI QERApp_ISelectedFace_GetTextureNumber(int iface); +void WINAPI QERApp_GetTextureSize(int iface, int Size[2]); + +// +// IEpairs interface +// +//#include "iepairs.h" +//#include "epairswrapper.h" + +// +// IImage interface +// +#include "iimage.h" + +// +// IFileSystem interface +// +#define USE_VFSTABLE_DEFINE +#include "ifilesystem.h" + +extern _QERFileSystemTable g_FileSystemTable; + +// +// TexWnd.cpp +// +extern qboolean g_bShowAllShaders; + +// +// texwindow.cpp +// +//++timo TODO: we can probably raise the MAX_TEXTUREDIRS limit? +#define MAX_TEXTUREDIRS 256 + +extern CPtrArray g_lstSkinCache; +qtexture_t *QERApp_LoadTextureRGBA(unsigned char* pPixels, int nWidth, int nHeight); + +// +// IScripLib interface +// GetToken, UnGetToken, etc. +#include "iscriplib.h" +extern FILE *g_File; +void WINAPI QERApp_MapPrintf_FILE( char *text, ... ); + +// +// ISurfacePlugin interface +// +void QERApp_GetTwoSelectedPatch( patchMesh_t **p1, patchMesh_t **p2 ); + +// +// IBSPFrontend interface +// +#include "ibspfrontend.h" +extern _QERPlugBSPFrontendTable g_BSPFrontendTable; +extern GSList *g_BSPFrontendCommands; + +// +// IToolbar +// +#include "itoolbar.h" + +// +// IMessaging interface +#include "iui.h" +#include "iui_gtk.h" +#include "ui.h" +IWindow* WINAPI QERApp_CreateGLWindow(); +void WINAPI QERApp_HookWindow(IWindowListener* pListen); +void WINAPI QERApp_UnHookWindow(IWindowListener* pListen); +IXYWndWrapper* WINAPI QERApp_GetXYWndWrapper(); +void WINAPI QERApp_HookListener(IListener* pListen, int Msg); +int WINAPI QERApp_UnHookListener(IListener* pListen); +void DispatchRadiantMsg( int Msg ); +// dispatch for IWindowListener entities +void DispatchOnMouseMove(guint32 nFlags, int x, int y); +bool DispatchOnLButtonDown(guint32 nFlags, int x, int y); +bool DispatchOnLButtonUp(guint32 nFlags, int x, int y); + +// +// IData interface +// +#include "idata.h" + +// +// ICamera interface +// +#include "icamera.h" + +// Some declarations that were in stdafx.h + +// main.cpp +extern gint try_destroy_splash(gpointer); + +#include "mainframe.h" +#include "preferences.h" +#include "findtexturedialog.h" +#include "surfacedialog.h" +#include "patchdialog.h" + +class MainFrame; +class ClipPoint; + +extern MainFrame* g_pParentWnd; +extern CString g_strAppPath; +extern CString g_strDTDPath; +extern CString g_pidFile; +extern CString g_pidGameFile; +extern CString g_strBitmapsPath; +extern CString g_strPluginsDir; +extern CString g_strModulesDir; + +extern CGameDescription *g_pGameDescription; +extern CString g_strGameToolsPath; + +extern CString g_strTempPath; +extern PrefsDlg& g_PrefsDlg; +extern FindTextureDialog& g_dlgFind; +extern SurfaceDlg g_dlgSurface; +extern PatchDialog g_PatchDialog; + +extern int g_bIgnoreCommands; + +void HideInfoDialog(); +void ShowInfoDialog(const char* pText); + +// externs +//extern void HandleCommand (GtkWidget *widget, gpointer data, bool keydown); +extern gint HandleCommand (GtkWidget *widget, gpointer data); +extern void AddSlash(CString&); +extern void DLLBuildDone(); +extern void CleanUpEntities(); +extern void FindReplace(CString& strContents, const char* pTag, const char* pValue); +extern void CheckBspProcess(); +extern void QE_CountBrushesAndUpdateStatusBar(); +extern void QE_CheckAutoSave(); +extern qtexture_t *current_texture; +extern void SaveWithRegion(char *name); // save the current map, sets the map name in the name buffer (deals with regioning) +extern void RunBsp (char *command); +extern void Map_Snapshot(); +//extern void WXY_Print(); +extern void AddProp( void ); +extern qboolean DoColor(int iIndex); +extern entity_t *edit_entity; +extern int inspector_mode; +extern bool g_bRotateMode; +extern bool g_bClipMode; +extern bool g_bScaleMode; +extern int g_nScaleHow; +extern bool g_bPathMode; +extern void RunScript(char* pBuffer); +extern bool ExtractPath_and_Filename(const char* pPath, CString& strPath, CString& strFilename); +extern void Select_Scale(float x, float y, float z); +extern void Select_RotateTexture(int amt); +extern void Select_ScaleTexture(float x, float y); +extern void Select_ShiftTexture(int x, int y); +extern void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected, bool bForce, bool bSelectMatchingFaces); +/*! +\fn DoProjectSettings shows the dialog for per-game configurable settings by the user +typically this sets up things like mod editing configuration +those a per-project, not the same thing as preferences which are global to the game conf +this is still being worked on, as we have several issues with how things are configured +we also have a number of behaviours defined in the .game, which can't be edited graphically +we dump those properties to the console when the project settings dialog shows up +*/ +extern void DoProjectSettings(); +extern qboolean region_active; +extern void Brush_Print(brush_t* b); +extern void Texture_ShowStartupShaders(); +extern void Map_ImportFile (char *filename); +extern void Map_SaveSelected(char* pFilename); +extern void UpdateSurfaceDialog(); +extern void Select_GetTrueMid (vec3_t mid); +extern bool g_bSwitch; +extern brush_t g_brFrontSplits; +extern brush_t g_brBackSplits; +extern ClipPoint g_Clip1; +extern ClipPoint g_Clip2; +extern brush_t* g_pSplitList; +extern ClipPoint g_PathPoints[256]; +extern void AcquirePath(int nCount, PFNPathCallback* pFunc); +extern bool g_bScreenUpdates; +extern SCommandInfo g_Commands[]; +extern int g_nCommandCount; +extern SKeyInfo g_Keys[]; +extern int g_nKeyCount; +extern int inspector_mode; +extern char *bsp_commands[256]; +extern void RunScriptByName(char*, bool); +extern void DoNewColor(int* i1, int* i2, int* i3); +extern void UpdateSurfaceDialog(); +extern void CSG_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back); +//extern void HandlePopup(CWnd* pWindow, unsigned int uId); +extern z_t z; +extern void Select_Scale(float x, float y, float z); +extern void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv); +//extern void VectorRotate (vec3_t va, vec3_t vb, vec3_t out); +//extern void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out); +extern qboolean QE_SaveProject (const char* pProjectFile); +//extern void NewBSP(char* pCommandLine, HWND); +//extern void NewVIS(char* pCommandLine, HWND); +//extern void NewRAD(char* pCommandLine, HWND); +extern void RunTools(char* pCommandLine, GtkWidget* hwnd, const char* pPAKFile); +extern void Clamp(float& f, int nClamp); +extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); +//extern void SaveWindowPlacement(HWND hwnd, const char* pName); +//extern bool LoadWindowPlacement(HWND hwnd, const char* pName); +extern qboolean ConfirmModified (void); +extern void DoPatchInspector(); +extern void TogglePatchInspector(); +void UpdatePatchInspector(); +extern int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen); +extern int g_nBrushId; + +// defined in gtkdlgs.cpp, we might want to move declaration and implementatin with other Select_ stuff.. +// NOTE: there's also a Select_Brush(brush_t *b) function.. unrelated +extern void SelectBrush (int entitynum, int brushnum); + +// bp_dlg.cpp +// ret: 0 = abort, 1 = load and convert, 2 = changed project settings, load and don't convert +// the user might decide to switch the BP mode in project settings +// status: 0 = loading regular, got conflict 1 = loading BP, got conflict +extern int BP_MessageBox (int status); + +// main.cpp +extern gint try_destroy_splash(gpointer); + +// SPoG +// targetname.cpp +void Entity_Connect(entity_t *e1, entity_t *e2); +int GetUniqueTargetId(int iHint); + +// xywindow.cpp +void CreateEntityFromName(const char* name, const vec3_t origin); + +// eclass.cpp +/*! +\brief initialization of the eclass manager +general guidelines about eclass.cpp implementation: +- we don't support unlimited number of eclass file formats together + currently limited to two + support for .def is builtin to the core, but you may choose not to activate it +- search and load of the files: + the manager is in charge of scanning for eclass definition files to load + there is a general configuration setting for games which use a different set of + entities between single player mode and multiplayer mode (TODO: the code doing + this needs to be abstracted some more) +- duplicate files / multiple files: + if two files with the same name exist (for instance in the basegame, and in fs_game) + then only the first one found in the scan order is loaded + if several files are found, they are all loaded + this allows mods to either replace or extend the list of eclass +- if eclass_singleload prop is used in the .game, then there is no multiple files check + the first file found is loaded, and there is no further search for the given extension + (this was an addition for HL support) +*/ +void Eclass_Init (); +eclass_t *Eclass_ForName (const char *name, qboolean has_brushes); +eclass_t * EClass_Create( const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments ); + +#endif // _QE3_H_ diff --git a/radiant/qedefs.h b/radiant/qedefs.h new file mode 100644 index 00000000..463fcc29 --- /dev/null +++ b/radiant/qedefs.h @@ -0,0 +1,128 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __QEDEFS_H__ +#define __QEDEFS_H__ + +#define _3DFXCAMERA_WINDOW_CLASS "Q3DFXCamera" +#define CAMERA_WINDOW_CLASS "QCamera" +#define XY_WINDOW_CLASS "QXY" +#define Z_WINDOW_CLASS "QZ" +#define ENT_WINDOW_CLASS "QENT" +#define TEXTURE_WINDOW_CLASS "QTEX" + +#define ZWIN_WIDTH 40 +#define CWIN_SIZE (0.4) + +#define MAX_EDGES 512 +#define MAX_POINTS 1024 + +#define CMD_TEXTUREWAD 60000 +#define CMD_BSPCOMMAND 61000 + +#define PITCH 0 +#define YAW 1 +#define ROLL 2 + +#define QE_TIMER0 1 + +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +#define ON_EPSILON 0.01 + +#define KEY_FORWARD 1 +#define KEY_BACK 2 +#define KEY_TURNLEFT 4 +#define KEY_TURNRIGHT 8 +#define KEY_LEFT 16 +#define KEY_RIGHT 32 +#define KEY_LOOKUP 64 +#define KEY_LOOKDOWN 128 +#define KEY_UP 256 +#define KEY_DOWN 512 + +// xy.c +#define EXCLUDE_WORLD 0x00000001 +#define EXCLUDE_ENT 0x00000002 +#define EXCLUDE_CURVES 0x00000004 +#define EXCLUDE_TRANSLUCENT 0x00000008 +#define EXCLUDE_LIQUIDS 0x00000010 +#define EXCLUDE_CAULK 0x00000020 +#define EXCLUDE_CLIP 0x00000040 +#define EXCLUDE_PATHS 0x00000080 +#define EXCLUDE_LIGHTS 0x00000100 +#define EXCLUDE_DETAILS 0x00000200 +#define EXCLUDE_HINTSSKIPS 0x00000400 +#define EXCLUDE_MODELS 0x00000800 +#define EXCLUDE_AREAPORTALS 0x00001000 +#define EXCLUDE_TRIGGERS 0x00002000 +#define EXCLUDE_CLUSTERPORTALS 0x00004000 +#define EXCLUDE_TERRAIN 0x00008000 +#define EXCLUDE_LIGHTGRID 0x00010000 +#define EXCLUDE_STRUCTURAL 0x00020000 +#define EXCLUDE_BOTCLIP 0x00040000 + +#define INCLUDE_EASY 0x00000001 +#define INCLUDE_NORMAL 0x00000002 +#define INCLUDE_HARD 0x00000004 +#define INCLUDE_DEATHMATCH 0x00000008 +#define INCLUDE_NAMES 0x00000010 +#define INCLUDE_COORDS 0x00000020 +#define INCLUDE_BLOCKS 0x00000040 +#define INCLUDE_ANGLES 0x00000080 +#define INCLUDE_PATCHBBOXES 0x00000100 +#define INCLUDE_PATCHWIREFRAME 0x00000200 +#define INCLUDE_CAMERATINT 0x00000400 +#define INCLUDE_MODELBOXONLY 0x00000800 + +// +// menu indexes for modifying menus +// +#define MENU_VIEW 2 +#define MENU_BSP 4 +#define MENU_TEXTURE 6 +#define MENU_PLUGIN 11 + +// odd things not in windows header... +#define VK_COMMA 188 +#define VK_PERIOD 190 + +// ShowEntitiesAs flags +// used in camera code, not menus +#define ENTITY_WIREFRAME 0x00001 +#define ENTITY_SKIN_MODEL 0x00010 +#define ENTITY_SELECTED_ONLY 0x00100 +#define ENTITY_BOXED 0x01000 + +// ShowEntitiesAs menu settings .. combinations of the above settings +#define ENTITY_BOX 0x01000 +#define ENTITY_WIRE 0x00001 +#define ENTITY_SELECTED 0x00101 +#define ENTITY_SKINNED 0x00010 +#define ENTITY_SKINNED_BOXED 0x01010 +#define ENTITY_SELECTED_SKIN 0x00110 + +#endif diff --git a/radiant/qfiles.h b/radiant/qfiles.h new file mode 100644 index 00000000..b339d3d1 --- /dev/null +++ b/radiant/qfiles.h @@ -0,0 +1,480 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 32 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} dtrivertx_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I') +#define MAX_QPATH 64 // max length of a quake game pathname +#define MD3_XYZ_SCALE (1.0/64) + +typedef struct { + int ident; + int version; + + char name[MAX_QPATH]; // model name + + int flags; + + int numFrames; + int numTags; + int numSurfaces; + + int numSkins; + + int ofsFrames; // offset for first frame + int ofsTags; // numFrames * numTags + int ofsSurfaces; // first surface, others follow + + int ofsEnd; // end of file +} md3Header_t; + +typedef struct { + int ident; // + + char name[MAX_QPATH]; // polyset name + + int flags; + int numFrames; // all surfaces in a model should have the same + + int numShaders; // all surfaces in a model should have the same + int numVerts; + + int numTriangles; + int ofsTriangles; + + int ofsShaders; // offset from start of md3Surface_t + int ofsSt; // texture coords are common for all frames + int ofsXyzNormals; // numVerts * numFrames + + int ofsEnd; // next surface follows + +} md3Surface_t; + +typedef struct { + char name[MAX_QPATH]; + int shaderIndex; // for in-game use +} md3Shader_t; + +typedef struct { + int indexes[3]; +} md3Triangle_t; + +typedef struct { + float st[2]; +} md3St_t; + +typedef struct { + short xyz[3]; + short normal; +} md3XyzNormal_t; + + +typedef struct +{ + float st[2]; + int nVertIndex; +} glst_t; + +typedef struct +{ + int nCount; + int ObjectIndex; + glst_t GlSt; +} gl_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .WAL texture file format + +============================================================================== +*/ + + +#define MIPLEVELS 4 +#ifndef __MIPTEX_S_ +#define __MIPTEX_S_ +typedef struct miptex_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + int flags; + int contents; + int value; +} miptex_t; +#endif + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 36 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x20000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +// we are using g_MaxBrushSize now, cleanme +/* #define MAX_BRUSH_SIZE 8192 */ + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 + +#define HEADER_LUMPS 17 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 2 // translucent, but not watery +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define CONTENTS_DEADMONSTER 0x4000000 // corpse +#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTS_LADDER 0x20000000 // ladder +#define CONTENTS_NEGATIVE_CURVE 0x40000000 // reverse inside / outside + +#define CONTENTS_KEEP (CONTENTS_DETAIL | CONTENTS_NEGATIVE_CURVE) + + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +#define SURF_LIGHT 0x1 // value will hold the light strength + +#define SURF_SLICK 0x2 // effects game physics + +#define SURF_SKY 0x4 // don't draw, but add to skybox +#define SURF_WARP 0x8 // turbulent water warp +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 // scroll towards angle +#define SURF_NODRAW 0x80 // don't bother referencing the texture + +#define SURF_PATCH 0x20000000 +#define SURF_CURVE_FAKE 0x40000000 +#define SURF_CURVE 0x80000000 +#define SURF_KEEP (SURF_CURVE | SURF_CURVE_FAKE | SURF_PATCH) + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + int pvsofs; // -1 = no info + int phsofs; // -1 = no info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + diff --git a/radiant/qgl-mac.c b/radiant/qgl-mac.c new file mode 100644 index 00000000..5b769090 --- /dev/null +++ b/radiant/qgl-mac.c @@ -0,0 +1,1775 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +** QGL_WIN.C +** +** This file implements the operating system binding of GL to QGL function +** pointers. When doing a port of Quake2 you must implement the following +** two functions: +** +** QGL_Init() - loads libraries, assigns function pointers, etc. +** QGL_Shutdown() - unloads libraries, NULLs function pointers +*/ +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) +//#include +#endif +#ifdef _WIN32 +#include +#endif +#include "qgl.h" +#include +void Sys_Printf(const char *format, ...); + +#ifdef _WIN32 +HMODULE g_hGLDLL = NULL; + +#pragma warning (disable : 4113 4133 4047 4018 ) + +int ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *); +int ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); +int ( WINAPI * qwglGetPixelFormat)(HDC); +BOOL ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); +BOOL ( WINAPI * qwglSwapBuffers)(HDC); + +BOOL ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT); +HGLRC ( WINAPI * qwglCreateContext)(HDC); +HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int); +BOOL ( WINAPI * qwglDeleteContext)(HGLRC); +HGLRC ( WINAPI * qwglGetCurrentContext)(VOID); +HDC ( WINAPI * qwglGetCurrentDC)(VOID); +PROC ( WINAPI * qwglGetProcAddress)(LPCSTR); +BOOL ( WINAPI * qwglMakeCurrent)(HDC, HGLRC); +BOOL ( WINAPI * qwglShareLists)(HGLRC, HGLRC); +BOOL ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD); + +BOOL ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT, + FLOAT, int, LPGLYPHMETRICSFLOAT); + +BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT, LPLAYERPLANEDESCRIPTOR); +int ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int, CONST COLORREF *); +int ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int, COLORREF *); +BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL); +BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT); + +BOOL ( WINAPI * qwglGetDeviceGammaRampEXT)( unsigned char *, unsigned char *, unsigned char * ); +BOOL ( WINAPI * qwglSetDeviceGammaRampEXT)( const unsigned char *, const unsigned char *, + const unsigned char * ); +BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval ); + +#else +#define WINAPI +#endif + +#if defined (__linux__) || defined (__APPLE__) +void* g_hGLDLL; + +XVisualInfo* (*qglXChooseVisual)(Display *dpy, int screen, int *attribList); +GLXContext (*qglXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +void (*qglXDestroyContext)(Display *dpy, GLXContext ctx); +Bool (*qglXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx); +void (*qglXCopyContext)(Display *dpy, GLXContext src, GLXContext dst, GLuint mask); +void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); +GLXPixmap (*qglXCreateGLXPixmap)( Display *dpy, XVisualInfo *visual, Pixmap pixmap ); +void (*qglXDestroyGLXPixmap)( Display *dpy, GLXPixmap pixmap ); +Bool (*qglXQueryExtension)( Display *dpy, int *errorb, int *event ); +Bool (*qglXQueryVersion)( Display *dpy, int *maj, int *min ); +Bool (*qglXIsDirect)( Display *dpy, GLXContext ctx ); +int (*qglXGetConfig)( Display *dpy, XVisualInfo *visual, int attrib, int *value ); +GLXContext (*qglXGetCurrentContext)( void ); +GLXDrawable (*qglXGetCurrentDrawable)( void ); +void (*qglXWaitGL)( void ); +void (*qglXWaitX)( void ); +void (*qglXUseXFont)( Font font, int first, int count, int list ); +void* (*qglXGetProcAddressARB) (const GLubyte *procName); +#endif + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); + +void ( APIENTRY * qglActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglClientActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglMultiTexCoord1dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord1dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord1fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord1fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord1iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord1ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord1sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord1svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord2dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord2dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord2fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord2fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord2iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord2ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord2sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord2svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord3dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord3dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord3fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord3fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord3iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord3ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord3sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord3svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord4dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord4dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord4fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord4fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord4iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord4ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord4sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord4svARB) (GLenum target, const GLshort *v); + +// glu stuff +void (APIENTRY * qgluPerspective) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); +int (APIENTRY * qgluBuild2DMipmaps) (GLenum target, GLint components, GLint width, GLint height, GLenum format, GLenum type, const void *data); +// added for plugins +void (APIENTRY * qgluLookAt)( + GLdouble eyex, + GLdouble eyey, + GLdouble eyez, + GLdouble centerx, + GLdouble centery, + GLdouble centerz, + GLdouble upx, + GLdouble upy, + GLdouble upz); +const GLubyte* (APIENTRY * qgluErrorString) (GLenum errCode ); + +/* +** QGL_Shutdown +** +** Unloads the specified DLL then nulls out all the proc pointers. +*/ +void QGL_Shutdown() +{ + Sys_Printf("Shutting down GL ..."); + + if (g_hGLDLL) + { +#ifdef _WIN32 + FreeLibrary(g_hGLDLL); +#endif + +//#if defined (__linux__) || defined (__APPLE__) +// dlclose (g_hGLDLL); +//#endif + + g_hGLDLL = NULL; + } + + Sys_Printf("Done.\n"); + + qglAccum = NULL; + qglAlphaFunc = NULL; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = NULL; + qglBindTexture = NULL; + qglBitmap = NULL; + qglBlendFunc = NULL; + qglCallList = NULL; + qglCallLists = NULL; + qglClear = NULL; + qglClearAccum = NULL; + qglClearColor = NULL; + qglClearDepth = NULL; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = NULL; + qglColor3fv = NULL; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = NULL; + qglColor4fv = NULL; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = NULL; + qglDeleteLists = NULL; + qglDeleteTextures = NULL; + qglDepthFunc = NULL; + qglDepthMask = NULL; + qglDepthRange = NULL; + qglDisable = NULL; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = NULL; + qglEnableClientState = NULL; + qglEnd = NULL; + qglEndList = NULL; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f = NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = NULL; + qglFogfv = NULL; + qglFogi = NULL; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = NULL; + qglGenTextures = NULL; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = NULL; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = NULL; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = NULL; + qglLineWidth = NULL; + qglListBase = NULL; + qglLoadIdentity = NULL; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = NULL; + qglMaterialfv = NULL; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = NULL; + qglMultMatrixd = NULL; + qglMultMatrixf = NULL; + qglNewList = NULL; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = NULL; + qglNormal3fv = NULL; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = NULL; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = NULL; + qglPolygonMode = NULL; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = NULL; + qglPopClientAttrib = NULL; + qglPopMatrix = NULL; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = NULL; + qglPushClientAttrib = NULL; + qglPushMatrix = NULL; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = NULL; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = NULL; + qglRotatef = NULL; + qglScaled = NULL; + qglScalef = NULL; + qglScissor = NULL; + qglSelectBuffer = NULL; + qglShadeModel = NULL; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = NULL; + qglTexCoord2fv = NULL; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = NULL; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = NULL; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = NULL; + qglTexImage2D = NULL; + qglTexParameterf = NULL; + qglTexParameterfv = NULL; + qglTexParameteri = NULL; + qglTexParameteriv = NULL; + qglTexSubImage1D = NULL; + qglTexSubImage2D = NULL; + qglTranslated = NULL; + qglTranslatef = NULL; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = NULL; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = NULL; + qglVertex3fv = NULL; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = NULL; + + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord1dARB = NULL; + qglMultiTexCoord1dvARB = NULL; + qglMultiTexCoord1fARB = NULL; + qglMultiTexCoord1fvARB = NULL; + qglMultiTexCoord1iARB = NULL; + qglMultiTexCoord1ivARB = NULL; + qglMultiTexCoord1sARB = NULL; + qglMultiTexCoord1svARB = NULL; + qglMultiTexCoord2dARB = NULL; + qglMultiTexCoord2dvARB = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord2fvARB = NULL; + qglMultiTexCoord2iARB = NULL; + qglMultiTexCoord2ivARB = NULL; + qglMultiTexCoord2sARB = NULL; + qglMultiTexCoord2svARB = NULL; + qglMultiTexCoord3dARB = NULL; + qglMultiTexCoord3dvARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMultiTexCoord3fvARB = NULL; + qglMultiTexCoord3iARB = NULL; + qglMultiTexCoord3ivARB = NULL; + qglMultiTexCoord3sARB = NULL; + qglMultiTexCoord3svARB = NULL; + qglMultiTexCoord4dARB = NULL; + qglMultiTexCoord4dvARB = NULL; + qglMultiTexCoord4fARB = NULL; + qglMultiTexCoord4fvARB = NULL; + qglMultiTexCoord4iARB = NULL; + qglMultiTexCoord4ivARB = NULL; + qglMultiTexCoord4sARB = NULL; + qglMultiTexCoord4svARB = NULL; + +#ifdef _WIN32 + qwglCopyContext = NULL; + qwglCreateContext = NULL; + qwglCreateLayerContext = NULL; + qwglDeleteContext = NULL; + qwglDescribeLayerPlane = NULL; + qwglGetCurrentContext = NULL; + qwglGetCurrentDC = NULL; + qwglGetLayerPaletteEntries = NULL; + qwglGetProcAddress = NULL; + qwglMakeCurrent = NULL; + qwglRealizeLayerPalette = NULL; + qwglSetLayerPaletteEntries = NULL; + qwglShareLists = NULL; + qwglSwapLayerBuffers = NULL; + qwglUseFontBitmaps = NULL; + qwglUseFontOutlines = NULL; + + qwglChoosePixelFormat = NULL; + qwglDescribePixelFormat = NULL; + qwglGetPixelFormat = NULL; + qwglSetPixelFormat = NULL; + qwglSwapBuffers = NULL; + + qwglSwapIntervalEXT = NULL; + + qwglGetDeviceGammaRampEXT = NULL; + qwglSetDeviceGammaRampEXT = NULL; +#endif + +#if defined (__linux__) || defined (__APPLE__) + qglXChooseVisual = NULL; + qglXCreateContext = NULL; + qglXDestroyContext = NULL; + qglXMakeCurrent = NULL; + qglXCopyContext = NULL; + qglXSwapBuffers = NULL; + qglXCreateGLXPixmap = NULL; + qglXDestroyGLXPixmap = NULL; + qglXQueryExtension = NULL; + qglXQueryVersion = NULL; + qglXIsDirect = NULL; + qglXGetConfig = NULL; + qglXGetCurrentContext = NULL; + qglXGetCurrentDrawable = NULL; + qglXWaitGL = NULL; + qglXWaitX = NULL; + qglXUseXFont = NULL; + qglXGetProcAddressARB = NULL; +#endif + + qgluPerspective = NULL; + qgluBuild2DMipmaps = NULL; + qgluErrorString = NULL; + qgluLookAt = NULL; +} + +/* +** QGL_Init +** +** This is responsible for binding our qgl function pointers to +** the appropriate GL stuff. In Windows this means doing a +** LoadLibrary and a bunch of calls to GetProcAddress. On other +** operating systems we need to do the right thing, whatever that +** might be. +** +*/ +static int init_error; + +//static void* safe_dlsym (void *handle, char *symbol) +//{ +//#ifdef _WIN32 +// return GetProcAddress (handle, symbol); +//#endif + +//#if defined (__linux__) || defined (__APPLE__) +// void* ret = dlsym (handle, symbol); +// char *err = dlerror(); +// if (err) +//{ +// init_error = 1; +// printf ("Error loading OpenGL libraries: %s %s\n", err, symbol); +// } +// return ret; +//#endif +//} + +#include +#include +#ifdef _WIN32 +#define M_PI 3.14159 +#endif + +void WINAPI gluLookAt2 (GLdouble ex, GLdouble ey, GLdouble ez, GLdouble cx, GLdouble cy, GLdouble cz, + GLdouble ux, GLdouble uy, GLdouble uz) +{ + GLdouble x[3], y[3], z[3] = { ex-cx, ey-cy, ez-cz }; + GLdouble inv; + + inv = sqrt (z[0]*z[0] + z[1]*z[1] + z[2]*z[2]); + if (inv) + { + inv = 1.0/inv; + z[0] *= inv; + z[1] *= inv; + z[2] *= inv; + } + + x[0] = uy*z[2] - uz*z[1]; + x[1] = -ux*z[2] + uz*z[0]; + x[2] = ux*z[1] - uy*z[0]; + + y[0] = z[1]*x[2] - z[2]*x[1]; + y[1] = -z[0]*x[2] + z[2]*x[0]; + y[2] = z[0]*x[1] - z[1]*x[0]; + + inv = sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); + if (inv) + { + x[0] *= inv; + x[1] *= inv; + x[2] *= inv; + } + + inv = sqrt(y[0]*y[0] + y[1]*y[1] + y[2]*y[2]); + if (inv) + { + y[0] *= inv; + y[1] *= inv; + y[2] *= inv; + } + + { + GLdouble m[16] = { x[0], y[0], z[0], 0, x[1], y[1], z[1], 0, x[2], y[2], z[2], 0, 0, 0, 0, 1 }; + qglMultMatrixd(m); + qglTranslated(-ex, -ey, -ez); + } +} + +void WINAPI gluPerspective2 (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) +{ + GLdouble y = zNear * tan (fovy * M_PI / 360.0); + qglFrustum (-y*aspect, y*aspect, -y, y, zNear, zFar); +} + +static void* WINAPI ResizeImage (GLubyte* old_image, int srcw, int srch, int destw, int desth) +{ + int i, j; + float sx, sy; + + GLubyte* new_image = malloc (destw*desth*4*sizeof(GLubyte)); + if (new_image == NULL) + return NULL; + + if (destw > 1) + sx = (GLfloat) (srcw-1) / (GLfloat) (destw-1); + else + sx = (GLfloat) (srcw-1); + if (desth > 1) + sy = (GLfloat) (srch-1) / (GLfloat) (desth-1); + else + sy = (GLfloat) (srch-1); + + for (i = 0; i < desth; i++) + { + GLint ii = (GLint)(i * sy); + for (j = 0; j < destw; j++) + { + GLint jj = (GLint)(j * sx); + GLubyte *src = old_image + (ii * srcw + jj) * 4; + GLubyte *dst = new_image + (i * destw + j) * 4; + + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + } + + return new_image; +} + +#define CEILING(A, B) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + +// NOTE: only supports RGBA, UNSIGNED_BYTE images. +GLint WINAPI gluBuild2DMipmaps2 (GLenum target, GLint components, GLsizei width, GLsizei height, GLenum format, + GLenum type, const void *data) +{ + GLint w, h, level, maxsize, sizein = 1; + GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels; + GLint packrowlength, packalignment, packskiprows, packskippixels; + GLint rowstride, rowlen; + GLuint i, j, k, pow2; + GLubyte *image, *tmp; + + if (width < 1 || height < 1) + return GLU_INVALID_VALUE; + + qglGetIntegerv (GL_UNPACK_ROW_LENGTH, &unpackrowlength); + qglGetIntegerv (GL_UNPACK_ALIGNMENT, &unpackalignment); + qglGetIntegerv (GL_UNPACK_SKIP_ROWS, &unpackskiprows); + qglGetIntegerv (GL_UNPACK_SKIP_PIXELS, &unpackskippixels); + qglGetIntegerv (GL_PACK_ROW_LENGTH, &packrowlength); + qglGetIntegerv (GL_PACK_ALIGNMENT, &packalignment); + qglGetIntegerv (GL_PACK_SKIP_ROWS, &packskiprows); + qglGetIntegerv (GL_PACK_SKIP_PIXELS, &packskippixels); + qglGetIntegerv (GL_MAX_TEXTURE_SIZE, &maxsize); + + for (pow2 = 1; pow2 < width; pow2 = pow2 << 1); + w = (pow2 == width) ? width : (pow2 << 1); + + for (pow2 = 1; pow2 < height; pow2 = pow2 << 1); + h = (pow2 == height) ? height : (pow2 << 1); + + if (w > maxsize) w = maxsize; + if (h > maxsize) h = maxsize; + + // Build RGBA packed image + image = malloc (width*height*4); + if (image == NULL) + return GLU_OUT_OF_MEMORY; + + if ((format != GL_RGBA) || (type != GL_UNSIGNED_BYTE)) + return GLU_INVALID_ENUM; + + rowlen = (unpackrowlength > 0) ? unpackrowlength : width; + + if (sizein >= unpackalignment) + rowstride = components * rowlen; + else + rowstride = unpackalignment/sizein * CEILING (components * rowlen * sizein, unpackalignment); + + k = 0; + for (i = 0; i < height; i++) + { + GLubyte *ubptr = (GLubyte*)data + i * rowstride + + unpackskiprows * rowstride + unpackskippixels * components; + + for (j = 0; j < width*components; j++) + image[k++] = *ubptr++; + } + + if (w != width || h != height) + { + tmp = ResizeImage (image, width, height, w, h); + free (image); + image = tmp; + + if (image == NULL) + return GLU_OUT_OF_MEMORY; + } + + qglPixelStorei (GL_PACK_ROW_LENGTH, 0); + qglPixelStorei (GL_PACK_ALIGNMENT, 1); + qglPixelStorei (GL_PACK_SKIP_ROWS, 0); + qglPixelStorei (GL_PACK_SKIP_PIXELS, 0); + qglPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + qglPixelStorei (GL_UNPACK_ALIGNMENT, 1); + qglPixelStorei (GL_UNPACK_SKIP_ROWS, 0); + qglPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); + + qglTexImage2D (target, 0, components, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); + + for (level = 1; ((w != 1) || (h != 1)); level++) + { + GLubyte *out, *in; + int row; + + row = w * 4; + if (w != 1) w >>= 1; + if (h != 1) h >>= 1; + in = out = image; + + for (i = 0; i < h; i++, in+=row) + for (j = 0; j < w; j++, out+=4, in+=8) + { + out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2; + out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2; + out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2; + out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2; + } + + qglTexImage2D (target, level, components, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); + } + + free (image); + qglPixelStorei (GL_UNPACK_ROW_LENGTH, unpackrowlength); + qglPixelStorei (GL_UNPACK_ALIGNMENT, unpackalignment); + qglPixelStorei (GL_UNPACK_SKIP_ROWS, unpackskiprows); + qglPixelStorei (GL_UNPACK_SKIP_PIXELS, unpackskippixels); + qglPixelStorei (GL_PACK_ROW_LENGTH, packrowlength); + qglPixelStorei (GL_PACK_ALIGNMENT, packalignment); + qglPixelStorei (GL_PACK_SKIP_ROWS, packskiprows); + qglPixelStorei (GL_PACK_SKIP_PIXELS, packskippixels); + + return 0; +} + +typedef struct glu_error_struct +{ + int errnum; + const char *errstr; +} GLU_ERROR_STRUCT; + +GLU_ERROR_STRUCT glu_errlist[] = { + {GL_NO_ERROR, "GL_NO_ERROR - no error"}, + {GL_INVALID_ENUM, "GL_INVALID_ENUM - An unacceptable value is specified for an enumerated argument."}, + {GL_INVALID_VALUE, "GL_INVALID_VALUE - A numeric argument is out of range."}, + {GL_INVALID_OPERATION, "GL_INVALID_OPERATION - The specified operation is not allowed in the current state."}, + {GL_STACK_OVERFLOW, "GL_STACK_OVERFLOW - Function would cause a stack overflow."}, + {GL_STACK_UNDERFLOW, "GL_STACK_UNDERFLOW - Function would cause a stack underflow."}, + {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY - There is not enough memory left to execute the function."}, + {-1, NULL} +}; + +const GLubyte* WINAPI gluErrorString(GLenum errCode ) +{ + int search = 0; + for (search = 0; glu_errlist[search].errstr; search++) + { + if (errCode == glu_errlist[search].errnum) + return (const char *)glu_errlist[search].errstr; + } //end for + return "Unknown error"; +} + +int QGL_Init(const char *dllname, const char* gluname) +{ +#ifdef _WIN32 + g_hGLDLL = LoadLibrary(dllname); +#endif + +#if defined (__linux__) + char* err; + + g_hGLDLL = dlopen(dllname, RTLD_LAZY|RTLD_GLOBAL); + err = dlerror(); + if (err) + printf ("Error loading GL lib:\n%s\n", err); +#endif + init_error = 0; + +#ifndef __APPLE__ + if (g_hGLDLL == NULL) + return 0; +#endif + + Sys_Printf("Loading GL library: %s ...", dllname); + + qgluPerspective = &gluPerspective2; + qgluBuild2DMipmaps = &gluBuild2DMipmaps2; + qgluLookAt = &gluLookAt2; + qgluErrorString = &gluErrorString; + + qglAccum = glAccum; + qglAlphaFunc = glAlphaFunc; + qglAreTexturesResident = glAreTexturesResident; + qglArrayElement = glArrayElement; + qglBegin = glBegin; + qglBindTexture = glBindTexture; + qglBitmap = glBitmap; + qglBlendFunc = glBlendFunc; + qglCallList = glCallList; + qglCallLists = glCallLists; + qglClear = glClear; + qglClearAccum = glClearAccum; + qglClearColor = glClearColor; + qglClearDepth = glClearDepth; + qglClearIndex = glClearIndex; + qglClearStencil = glClearStencil; + qglClipPlane = glClipPlane; + qglColor3b = glColor3b; + qglColor3bv = glColor3bv; + qglColor3d = glColor3d; + qglColor3dv = glColor3dv; + qglColor3f = glColor3f; + qglColor3fv = glColor3fv; + qglColor3i = glColor3i; + qglColor3iv = glColor3iv; + qglColor3s = glColor3s; + qglColor3sv = glColor3sv; + qglColor3ub = glColor3ub; + qglColor3ubv = glColor3ubv; + qglColor3ui = glColor3ui; + qglColor3uiv = glColor3uiv; + qglColor3us = glColor3us; + qglColor3usv = glColor3usv; + qglColor4b = glColor4b; + qglColor4bv = glColor4bv; + qglColor4d = glColor4d; + qglColor4dv = glColor4dv; + qglColor4f = glColor4f; + qglColor4fv = glColor4fv; + qglColor4i = glColor4i; + qglColor4iv = glColor4iv; + qglColor4s = glColor4s; + qglColor4sv = glColor4sv; + qglColor4ub = glColor4ub; + qglColor4ubv = glColor4ubv; + qglColor4ui = glColor4ui; + qglColor4uiv = glColor4uiv; + qglColor4us = glColor4us; + qglColor4usv = glColor4usv; + qglColorMask = glColorMask; + qglColorMaterial = glColorMaterial; + qglColorPointer = glColorPointer; + qglCopyPixels = glCopyPixels; + qglCopyTexImage1D = glCopyTexImage1D; + qglCopyTexImage2D = glCopyTexImage2D; + qglCopyTexSubImage1D = glCopyTexSubImage1D; + qglCopyTexSubImage2D = glCopyTexSubImage2D; + qglCullFace = glCullFace; + qglDeleteLists = glDeleteLists; + qglDeleteTextures = glDeleteTextures; + qglDepthFunc = glDepthFunc; + qglDepthMask = glDepthMask; + qglDepthRange = glDepthRange; + qglDisable = glDisable; + qglDisableClientState = glDisableClientState; + qglDrawArrays = glDrawArrays; + qglDrawBuffer = glDrawBuffer; + qglDrawElements = glDrawElements; + qglDrawPixels = glDrawPixels; + qglEdgeFlag = glEdgeFlag; + qglEdgeFlagPointer = glEdgeFlagPointer; + qglEdgeFlagv = glEdgeFlagv; + qglEnable = glEnable; + qglEnableClientState = glEnableClientState; + qglEnd = glEnd; + qglEndList = glEndList; + qglEvalCoord1d = glEvalCoord1d; + qglEvalCoord1dv = glEvalCoord1dv; + qglEvalCoord1f = glEvalCoord1f; + qglEvalCoord1fv = glEvalCoord1fv; + qglEvalCoord2d = glEvalCoord2d; + qglEvalCoord2dv = glEvalCoord2dv; + qglEvalCoord2f = glEvalCoord2f; + qglEvalCoord2fv = glEvalCoord2fv; + qglEvalMesh1 = glEvalMesh1; + qglEvalMesh2 = glEvalMesh2; + qglEvalPoint1 = glEvalPoint1; + qglEvalPoint2 = glEvalPoint2; + qglFeedbackBuffer = glFeedbackBuffer; + qglFinish = glFinish; + qglFlush = glFlush; + qglFogf = glFogf; + qglFogfv = glFogfv; + qglFogi = glFogi; + qglFogiv = glFogiv; + qglFrontFace = glFrontFace; + qglFrustum = glFrustum; + qglGenLists = glGenLists; + qglGenTextures = glGenTextures; + qglGetBooleanv = glGetBooleanv; + qglGetClipPlane = glGetClipPlane; + qglGetDoublev = glGetDoublev; + qglGetError = glGetError; + qglGetFloatv = glGetFloatv; + qglGetIntegerv = glGetIntegerv; + qglGetLightfv = glGetLightfv; + qglGetLightiv = glGetLightiv; + qglGetMapdv = glGetMapdv; + qglGetMapfv = glGetMapfv; + qglGetMapiv = glGetMapiv; + qglGetMaterialfv = glGetMaterialfv; + qglGetMaterialiv = glGetMaterialiv; + qglGetPixelMapfv = glGetPixelMapfv; + qglGetPixelMapuiv = glGetPixelMapuiv; + qglGetPixelMapusv = glGetPixelMapusv; + qglGetPointerv = glGetPointerv; + qglGetPolygonStipple = glGetPolygonStipple; + qglGetString = glGetString; + qglGetTexEnvfv = glGetTexEnvfv; + qglGetTexEnviv = glGetTexEnviv; + qglGetTexGendv = glGetTexGendv; + qglGetTexGenfv = glGetTexGenfv; + qglGetTexGeniv = glGetTexGeniv; + qglGetTexImage = glGetTexImage; + qglGetTexLevelParameterfv = glGetTexLevelParameterfv; + qglGetTexLevelParameteriv = glGetTexLevelParameteriv; + qglGetTexParameterfv = glGetTexParameterfv; + qglGetTexParameteriv = glGetTexParameteriv; + qglHint = glHint; + qglIndexMask = glIndexMask; + qglIndexPointer = glIndexPointer; + qglIndexd = glIndexd; + qglIndexdv = glIndexdv; + qglIndexf = glIndexf; + qglIndexfv = glIndexfv; + qglIndexi = glIndexi; + qglIndexiv = glIndexiv; + qglIndexs = glIndexs; + qglIndexsv = glIndexsv; + qglIndexub = glIndexub; + qglIndexubv = glIndexubv; + qglInitNames = glInitNames; + qglInterleavedArrays = glInterleavedArrays; + qglIsEnabled = glIsEnabled; + qglIsList = glIsList; + qglIsTexture = glIsTexture; + qglLightModelf = glLightModelf; + qglLightModelfv = glLightModelfv; + qglLightModeli = glLightModeli; + qglLightModeliv = glLightModeliv; + qglLightf = glLightf; + qglLightfv = glLightfv; + qglLighti = glLighti; + qglLightiv = glLightiv; + qglLineStipple = glLineStipple; + qglLineWidth = glLineWidth; + qglListBase = glListBase; + qglLoadIdentity = glLoadIdentity; + qglLoadMatrixd = glLoadMatrixd; + qglLoadMatrixf = glLoadMatrixf; + qglLoadName = glLoadName; + qglLogicOp = glLogicOp; + qglMap1d = glMap1d; + qglMap1f = glMap1f; + qglMap2d = glMap2d; + qglMap2f = glMap2f; + qglMapGrid1d = glMapGrid1d; + qglMapGrid1f = glMapGrid1f; + qglMapGrid2d = glMapGrid2d; + qglMapGrid2f = glMapGrid2f; + qglMaterialf = glMaterialf; + qglMaterialfv = glMaterialfv; + qglMateriali = glMateriali; + qglMaterialiv = glMaterialiv; + qglMatrixMode = glMatrixMode; + qglMultMatrixd = glMultMatrixd; + qglMultMatrixf = glMultMatrixf; + qglNewList = glNewList; + qglNormal3b = glNormal3b; + qglNormal3bv = glNormal3bv; + qglNormal3d = glNormal3d; + qglNormal3dv = glNormal3dv; + qglNormal3f = glNormal3f; + qglNormal3fv = glNormal3fv; + qglNormal3i = glNormal3i; + qglNormal3iv = glNormal3iv; + qglNormal3s = glNormal3s; + qglNormal3sv = glNormal3sv; + qglNormalPointer = glNormalPointer; + qglOrtho = glOrtho; + qglPassThrough = glPassThrough; + qglPixelMapfv = glPixelMapfv; + qglPixelMapuiv = glPixelMapuiv; + qglPixelMapusv = glPixelMapusv; + qglPixelStoref = glPixelStoref; + qglPixelStorei = glPixelStorei; + qglPixelTransferf = glPixelTransferf; + qglPixelTransferi = glPixelTransferi; + qglPixelZoom = glPixelZoom; + qglPointSize = glPointSize; + qglPolygonMode = glPolygonMode; + qglPolygonOffset = glPolygonOffset; + qglPolygonStipple = glPolygonStipple; + qglPopAttrib = glPopAttrib; + qglPopClientAttrib = glPopClientAttrib; + qglPopMatrix = glPopMatrix; + qglPopName = glPopName; + qglPrioritizeTextures = glPrioritizeTextures; + qglPushAttrib = glPushAttrib; + qglPushClientAttrib = glPushClientAttrib; + qglPushMatrix = glPushMatrix; + qglPushName = glPushName; + qglRasterPos2d = glRasterPos2d; + qglRasterPos2dv = glRasterPos2dv; + qglRasterPos2f = glRasterPos2f; + qglRasterPos2fv = glRasterPos2fv; + qglRasterPos2i = glRasterPos2i; + qglRasterPos2iv = glRasterPos2iv; + qglRasterPos2s = glRasterPos2s; + qglRasterPos2sv = glRasterPos2sv; + qglRasterPos3d = glRasterPos3d; + qglRasterPos3dv = glRasterPos3dv; + qglRasterPos3f = glRasterPos3f; + qglRasterPos3fv = glRasterPos3fv; + qglRasterPos3i = glRasterPos3i; + qglRasterPos3iv = glRasterPos3iv; + qglRasterPos3s = glRasterPos3s; + qglRasterPos3sv = glRasterPos3sv; + qglRasterPos4d = glRasterPos4d; + qglRasterPos4dv = glRasterPos4dv; + qglRasterPos4f = glRasterPos4f; + qglRasterPos4fv = glRasterPos4fv; + qglRasterPos4i = glRasterPos4i; + qglRasterPos4iv = glRasterPos4iv; + qglRasterPos4s = glRasterPos4s; + qglRasterPos4sv = glRasterPos4sv; + qglReadBuffer = glReadBuffer; + qglReadPixels = glReadPixels; + qglRectd = glRectd; + qglRectdv = glRectdv; + qglRectf = glRectf; + qglRectfv = glRectfv; + qglRecti = glRecti; + qglRectiv = glRectiv; + qglRects = glRects; + qglRectsv = glRectsv; + qglRenderMode = glRenderMode; + qglRotated = glRotated; + qglRotatef = glRotatef; + qglScaled = glScaled; + qglScalef = glScalef; + qglScissor = glScissor; + qglSelectBuffer = glSelectBuffer; + qglShadeModel = glShadeModel; + qglStencilFunc = glStencilFunc; + qglStencilMask = glStencilMask; + qglStencilOp = glStencilOp; + qglTexCoord1d = glTexCoord1d; + qglTexCoord1dv = glTexCoord1dv; + qglTexCoord1f = glTexCoord1f; + qglTexCoord1fv = glTexCoord1fv; + qglTexCoord1i = glTexCoord1i; + qglTexCoord1iv = glTexCoord1iv; + qglTexCoord1s = glTexCoord1s; + qglTexCoord1sv = glTexCoord1sv; + qglTexCoord2d = glTexCoord2d; + qglTexCoord2dv = glTexCoord2dv; + qglTexCoord2f = glTexCoord2f; + qglTexCoord2fv = glTexCoord2fv; + qglTexCoord2i = glTexCoord2i; + qglTexCoord2iv = glTexCoord2iv; + qglTexCoord2s = glTexCoord2s; + qglTexCoord2sv = glTexCoord2sv; + qglTexCoord3d = glTexCoord3d; + qglTexCoord3dv = glTexCoord3dv; + qglTexCoord3f = glTexCoord3f; + qglTexCoord3fv = glTexCoord3fv; + qglTexCoord3i = glTexCoord3i; + qglTexCoord3iv = glTexCoord3iv; + qglTexCoord3s = glTexCoord3s; + qglTexCoord3sv = glTexCoord3sv; + qglTexCoord4d = glTexCoord4d; + qglTexCoord4dv = glTexCoord4dv; + qglTexCoord4f = glTexCoord4f; + qglTexCoord4fv = glTexCoord4fv; + qglTexCoord4i = glTexCoord4i; + qglTexCoord4iv = glTexCoord4iv; + qglTexCoord4s = glTexCoord4s; + qglTexCoord4sv = glTexCoord4sv; + qglTexCoordPointer = glTexCoordPointer; + qglTexEnvf = glTexEnvf; + qglTexEnvfv = glTexEnvfv; + qglTexEnvi = glTexEnvi; + qglTexEnviv = glTexEnviv; + qglTexGend = glTexGend; + qglTexGendv = glTexGendv; + qglTexGenf = glTexGenf; + qglTexGenfv = glTexGenfv; + qglTexGeni = glTexGeni; + qglTexGeniv = glTexGeniv; + qglTexImage1D = glTexImage1D; + qglTexImage2D = glTexImage2D; + qglTexParameterf = glTexParameterf; + qglTexParameterfv = glTexParameterfv; + qglTexParameteri = glTexParameteri; + qglTexParameteriv = glTexParameteriv; + qglTexSubImage1D = glTexSubImage1D; + qglTexSubImage2D = glTexSubImage2D; + qglTranslated = glTranslated; + qglTranslatef = glTranslatef; + qglVertex2d = glVertex2d; + qglVertex2dv = glVertex2dv; + qglVertex2f = glVertex2f; + qglVertex2fv = glVertex2fv; + qglVertex2i = glVertex2i; + qglVertex2iv = glVertex2iv; + qglVertex2s = glVertex2s; + qglVertex2sv = glVertex2sv; + qglVertex3d = glVertex3d; + qglVertex3dv = glVertex3dv; + qglVertex3f = glVertex3f; + qglVertex3fv = glVertex3fv; + qglVertex3i = glVertex3i; + qglVertex3iv = glVertex3iv; + qglVertex3s = glVertex3s; + qglVertex3sv = glVertex3sv; + qglVertex4d = glVertex4d; + qglVertex4dv = glVertex4dv; + qglVertex4f = glVertex4f; + qglVertex4fv = glVertex4fv; + qglVertex4i = glVertex4i; + qglVertex4iv = glVertex4iv; + qglVertex4s = glVertex4s; + qglVertex4sv = glVertex4sv; + qglVertexPointer = glVertexPointer; + qglViewport = glViewport; + + // must be init with an active context + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord1dARB = NULL; + qglMultiTexCoord1dvARB = NULL; + qglMultiTexCoord1fARB = NULL; + qglMultiTexCoord1fvARB = NULL; + qglMultiTexCoord1iARB = NULL; + qglMultiTexCoord1ivARB = NULL; + qglMultiTexCoord1sARB = NULL; + qglMultiTexCoord1svARB = NULL; + qglMultiTexCoord2dARB = NULL; + qglMultiTexCoord2dvARB = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord2fvARB = NULL; + qglMultiTexCoord2iARB = NULL; + qglMultiTexCoord2ivARB = NULL; + qglMultiTexCoord2sARB = NULL; + qglMultiTexCoord2svARB = NULL; + qglMultiTexCoord3dARB = NULL; + qglMultiTexCoord3dvARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMultiTexCoord3fvARB = NULL; + qglMultiTexCoord3iARB = NULL; + qglMultiTexCoord3ivARB = NULL; + qglMultiTexCoord3sARB = NULL; + qglMultiTexCoord3svARB = NULL; + qglMultiTexCoord4dARB = NULL; + qglMultiTexCoord4dvARB = NULL; + qglMultiTexCoord4fARB = NULL; + qglMultiTexCoord4fvARB = NULL; + qglMultiTexCoord4iARB = NULL; + qglMultiTexCoord4ivARB = NULL; + qglMultiTexCoord4sARB = NULL; + qglMultiTexCoord4svARB = NULL; + +#ifdef _WIN32 + qwglCopyContext = safe_dlsym(g_hGLDLL, "wglCopyContext" ); + qwglCreateContext = safe_dlsym(g_hGLDLL, "wglCreateContext"); + qwglCreateLayerContext = safe_dlsym(g_hGLDLL, "wglCreateLayerContext" ); + qwglDeleteContext = safe_dlsym(g_hGLDLL, "wglDeleteContext"); + qwglDescribeLayerPlane = safe_dlsym(g_hGLDLL, "wglDescribeLayerPlane" ); + qwglGetCurrentContext = safe_dlsym(g_hGLDLL, "wglGetCurrentContext" ); + qwglGetCurrentDC = safe_dlsym(g_hGLDLL, "wglGetCurrentDC" ); + qwglGetLayerPaletteEntries = safe_dlsym(g_hGLDLL, "wglGetLayerPaletteEntries" ); + qwglGetProcAddress = safe_dlsym(g_hGLDLL, "wglGetProcAddress" ); + qwglMakeCurrent = safe_dlsym(g_hGLDLL, "wglMakeCurrent" ); + qwglRealizeLayerPalette = safe_dlsym(g_hGLDLL, "wglRealizeLayerPalette" ); + qwglSetLayerPaletteEntries = safe_dlsym(g_hGLDLL, "wglSetLayerPaletteEntries" ); + qwglShareLists = safe_dlsym(g_hGLDLL, "wglShareLists" ); + qwglSwapLayerBuffers = safe_dlsym(g_hGLDLL, "wglSwapLayerBuffers" ); + qwglUseFontBitmaps = safe_dlsym(g_hGLDLL, "wglUseFontBitmapsA" ); + qwglUseFontOutlines = safe_dlsym(g_hGLDLL, "wglUseFontOutlinesA" ); + + qwglChoosePixelFormat = safe_dlsym(g_hGLDLL, "wglChoosePixelFormat" ); + qwglDescribePixelFormat = safe_dlsym(g_hGLDLL, "wglDescribePixelFormat" ); + qwglGetPixelFormat = safe_dlsym(g_hGLDLL, "wglGetPixelFormat" ); + qwglSetPixelFormat = safe_dlsym(g_hGLDLL, "wglSetPixelFormat" ); + qwglSwapBuffers = safe_dlsym(g_hGLDLL, "wglSwapBuffers" ); + + qwglSwapIntervalEXT = 0; + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; +#endif + +#if defined (__linux__) || defined (__APPLE__) + qglXChooseVisual = glXChooseVisual; + qglXCreateContext = glXCreateContext; + qglXDestroyContext = glXDestroyContext; + qglXMakeCurrent = glXMakeCurrent; + qglXCopyContext = glXCopyContext; + qglXSwapBuffers = glXSwapBuffers; + qglXCreateGLXPixmap = glXCreateGLXPixmap; + qglXDestroyGLXPixmap = glXDestroyGLXPixmap; + qglXQueryExtension = glXQueryExtension; + qglXQueryVersion = glXQueryVersion; + qglXIsDirect = glXIsDirect; + qglXGetConfig = glXGetConfig; + qglXGetCurrentContext = glXGetCurrentContext; + qglXGetCurrentDrawable = glXGetCurrentDrawable; + qglXWaitGL = glXWaitGL; + qglXWaitX = glXWaitX; + qglXUseXFont = glXUseXFont; + qglXGetProcAddressARB = glXGetProcAddressARB; // Utah-GLX fix +#endif + + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; + + Sys_Printf("Done.\n"); + + if (init_error == 1) + return 0; + + return 1; +} + +static int GL_ExtensionSupported (const char *extension) +{ + const GLubyte *extensions = NULL; + const GLubyte *start; + GLubyte *where, *terminator; + + // Extension names should not have spaces. + where = (GLubyte *) strchr (extension, ' '); + if (where || *extension == '\0') + return 0; + + extensions = qglGetString (GL_EXTENSIONS); + + // It takes a bit of care to be fool-proof about parsing the + // OpenGL extensions string. Don't be fooled by sub-strings, etc. + for (start = extensions; ;) + { + where = (GLubyte *) strstr ((const char *) start, extension); + if (!where) + break; + + terminator = where + strlen (extension); + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') + return 1; + + start = terminator; + } + + return 0; +} + +void* Sys_GLGetExtension (const char *symbol) +{ +#if defined (__linux__) || defined (__APPLE__) + if (qglXGetProcAddressARB == NULL) + return NULL; + else + return qglXGetProcAddressARB ((GLubyte*)symbol); +#else + return qwglGetProcAddress (symbol); +#endif +} + +void QGL_InitExtensions () +{ + if (GL_ExtensionSupported ("GL_ARB_multitexture")) + { + qglActiveTextureARB = Sys_GLGetExtension ("glActiveTextureARB"); + qglClientActiveTextureARB = Sys_GLGetExtension ("glClientActiveTextureARB"); + qglMultiTexCoord1dARB = Sys_GLGetExtension ("glMultiTexCoord1dARB"); + qglMultiTexCoord1dvARB = Sys_GLGetExtension ("glMultiTexCoord1dvARB"); + qglMultiTexCoord1fARB = Sys_GLGetExtension ("glMultiTexCoord1fARB"); + qglMultiTexCoord1fvARB = Sys_GLGetExtension ("glMultiTexCoord1fvARB"); + qglMultiTexCoord1iARB = Sys_GLGetExtension ("glMultiTexCoord1iARB"); + qglMultiTexCoord1ivARB = Sys_GLGetExtension ("glMultiTexCoord1ivARB"); + qglMultiTexCoord1sARB = Sys_GLGetExtension ("glMultiTexCoord1sARB"); + qglMultiTexCoord1svARB = Sys_GLGetExtension ("glMultiTexCoord1svARB"); + qglMultiTexCoord2dARB = Sys_GLGetExtension ("glMultiTexCoord2dARB"); + qglMultiTexCoord2dvARB = Sys_GLGetExtension ("glMultiTexCoord2dvARB"); + qglMultiTexCoord2fARB = Sys_GLGetExtension ("glMultiTexCoord2fARB"); + qglMultiTexCoord2fvARB = Sys_GLGetExtension ("glMultiTexCoord2fvARB"); + qglMultiTexCoord2iARB = Sys_GLGetExtension ("glMultiTexCoord2iARB"); + qglMultiTexCoord2ivARB = Sys_GLGetExtension ("glMultiTexCoord2ivARB"); + qglMultiTexCoord2sARB = Sys_GLGetExtension ("glMultiTexCoord2sARB"); + qglMultiTexCoord2svARB = Sys_GLGetExtension ("glMultiTexCoord2svARB"); + qglMultiTexCoord3dARB = Sys_GLGetExtension ("glMultiTexCoord3dARB"); + qglMultiTexCoord3dvARB = Sys_GLGetExtension ("glMultiTexCoord3dvARB"); + qglMultiTexCoord3fARB = Sys_GLGetExtension ("glMultiTexCoord3fARB"); + qglMultiTexCoord3fvARB = Sys_GLGetExtension ("glMultiTexCoord3fvARB"); + qglMultiTexCoord3iARB = Sys_GLGetExtension ("glMultiTexCoord3iARB"); + qglMultiTexCoord3ivARB = Sys_GLGetExtension ("glMultiTexCoord3ivARB"); + qglMultiTexCoord3sARB = Sys_GLGetExtension ("glMultiTexCoord3sARB"); + qglMultiTexCoord3svARB = Sys_GLGetExtension ("glMultiTexCoord3svARB"); + qglMultiTexCoord4dARB = Sys_GLGetExtension ("glMultiTexCoord4dARB"); + qglMultiTexCoord4dvARB = Sys_GLGetExtension ("glMultiTexCoord4dvARB"); + qglMultiTexCoord4fARB = Sys_GLGetExtension ("glMultiTexCoord4fARB"); + qglMultiTexCoord4fvARB = Sys_GLGetExtension ("glMultiTexCoord4fvARB"); + qglMultiTexCoord4iARB = Sys_GLGetExtension ("glMultiTexCoord4iARB"); + qglMultiTexCoord4ivARB = Sys_GLGetExtension ("glMultiTexCoord4ivARB"); + qglMultiTexCoord4sARB = Sys_GLGetExtension ("glMultiTexCoord4sARB"); + qglMultiTexCoord4svARB = Sys_GLGetExtension ("glMultiTexCoord4svARB"); + } +} diff --git a/radiant/qgl.c b/radiant/qgl.c new file mode 100644 index 00000000..6fb4eb5d --- /dev/null +++ b/radiant/qgl.c @@ -0,0 +1,1797 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +** QGL_WIN.C +** +** This file implements the operating system binding of GL to QGL function +** pointers. When doing a port of Quake2 you must implement the following +** two functions: +** +** QGL_Init() - loads libraries, assigns function pointers, etc. +** QGL_Shutdown() - unloads libraries, NULLs function pointers +*/ + +/* + * This causes glDisable(), glEnable(), glCullFace() and glPolygonMode() to + * be wrapped in order to get around a bug in ATI's FireGL drivers. + */ +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#ifdef _WIN32 +#include +#endif + +#include "qgl.h" +void Sys_Printf(const char *format, ...); + +#ifdef _WIN32 +HMODULE g_hGLDLL = NULL; + +#pragma warning (disable : 4113 4133 4047 4018 ) + +int ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *); +int ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); +int ( WINAPI * qwglGetPixelFormat)(HDC); +BOOL ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); +BOOL ( WINAPI * qwglSwapBuffers)(HDC); + +BOOL ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT); +HGLRC ( WINAPI * qwglCreateContext)(HDC); +HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int); +BOOL ( WINAPI * qwglDeleteContext)(HGLRC); +HGLRC ( WINAPI * qwglGetCurrentContext)(VOID); +HDC ( WINAPI * qwglGetCurrentDC)(VOID); +PROC ( WINAPI * qwglGetProcAddress)(LPCSTR); +BOOL ( WINAPI * qwglMakeCurrent)(HDC, HGLRC); +BOOL ( WINAPI * qwglShareLists)(HGLRC, HGLRC); +BOOL ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD); + +BOOL ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT, + FLOAT, int, LPGLYPHMETRICSFLOAT); + +BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT, LPLAYERPLANEDESCRIPTOR); +int ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int, CONST COLORREF *); +int ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int, COLORREF *); +BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL); +BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT); + +BOOL ( WINAPI * qwglGetDeviceGammaRampEXT)( unsigned char *, unsigned char *, unsigned char * ); +BOOL ( WINAPI * qwglSetDeviceGammaRampEXT)( const unsigned char *, const unsigned char *, + const unsigned char * ); +BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval ); + +#else +#define WINAPI +#endif + +#if defined (__linux__) || defined (__APPLE__) +void* g_hGLDLL; + +XVisualInfo* (*qglXChooseVisual)(Display *dpy, int screen, int *attribList); +GLXContext (*qglXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +void (*qglXDestroyContext)(Display *dpy, GLXContext ctx); +Bool (*qglXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx); +void (*qglXCopyContext)(Display *dpy, GLXContext src, GLXContext dst, GLuint mask); +void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); +GLXPixmap (*qglXCreateGLXPixmap)( Display *dpy, XVisualInfo *visual, Pixmap pixmap ); +void (*qglXDestroyGLXPixmap)( Display *dpy, GLXPixmap pixmap ); +Bool (*qglXQueryExtension)( Display *dpy, int *errorb, int *event ); +Bool (*qglXQueryVersion)( Display *dpy, int *maj, int *min ); +Bool (*qglXIsDirect)( Display *dpy, GLXContext ctx ); +int (*qglXGetConfig)( Display *dpy, XVisualInfo *visual, int attrib, int *value ); +GLXContext (*qglXGetCurrentContext)( void ); +GLXDrawable (*qglXGetCurrentDrawable)( void ); +void (*qglXWaitGL)( void ); +void (*qglXWaitX)( void ); +void (*qglXUseXFont)( Font font, int first, int count, int list ); +void* (*qglXGetProcAddressARB) (const GLubyte *procName); +#endif + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); + +void ( APIENTRY * qglActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglClientActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglMultiTexCoord1dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord1dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord1fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord1fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord1iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord1ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord1sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord1svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord2dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord2dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord2fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord2fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord2iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord2ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord2sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord2svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord3dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord3dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord3fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord3fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord3iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord3ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord3sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord3svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord4dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord4dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord4fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord4fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord4iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord4ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord4sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord4svARB) (GLenum target, const GLshort *v); + +// glu stuff +void (APIENTRY * qgluPerspective) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); + +// added for plugins +void (APIENTRY * qgluLookAt)( + GLdouble eyex, + GLdouble eyey, + GLdouble eyez, + GLdouble centerx, + GLdouble centery, + GLdouble centerz, + GLdouble upx, + GLdouble upy, + GLdouble upz); +const GLubyte* (APIENTRY * qgluErrorString) (GLenum errCode ); + +#ifdef ATIHACK_812 +void ( APIENTRY * qglCullFace_real )(GLenum mode); +void ( APIENTRY * qglDisable_real )(GLenum cap); +void ( APIENTRY * qglEnable_real )(GLenum cap); +void ( APIENTRY * qglPolygonMode_real )(GLenum face, GLenum mode); +#endif + +/* +** QGL_Shutdown +** +** Unloads the specified DLL then nulls out all the proc pointers. +*/ +void QGL_Shutdown() +{ + Sys_Printf("Shutting down GL ..."); + + if (g_hGLDLL) + { +#ifdef _WIN32 + FreeLibrary(g_hGLDLL); +#endif + +#if defined (__linux__) || defined (__APPLE__) + dlclose (g_hGLDLL); +#endif + + g_hGLDLL = NULL; + } + + Sys_Printf("Done.\n"); + + qglAccum = NULL; + qglAlphaFunc = NULL; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = NULL; + qglBindTexture = NULL; + qglBitmap = NULL; + qglBlendFunc = NULL; + qglCallList = NULL; + qglCallLists = NULL; + qglClear = NULL; + qglClearAccum = NULL; + qglClearColor = NULL; + qglClearDepth = NULL; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = NULL; + qglColor3fv = NULL; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = NULL; + qglColor4fv = NULL; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = NULL; + qglDeleteLists = NULL; + qglDeleteTextures = NULL; + qglDepthFunc = NULL; + qglDepthMask = NULL; + qglDepthRange = NULL; + qglDisable = NULL; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = NULL; + qglEnableClientState = NULL; + qglEnd = NULL; + qglEndList = NULL; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f = NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = NULL; + qglFogfv = NULL; + qglFogi = NULL; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = NULL; + qglGenTextures = NULL; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = NULL; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = NULL; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = NULL; + qglLineWidth = NULL; + qglListBase = NULL; + qglLoadIdentity = NULL; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = NULL; + qglMaterialfv = NULL; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = NULL; + qglMultMatrixd = NULL; + qglMultMatrixf = NULL; + qglNewList = NULL; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = NULL; + qglNormal3fv = NULL; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = NULL; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = NULL; + qglPolygonMode = NULL; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = NULL; + qglPopClientAttrib = NULL; + qglPopMatrix = NULL; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = NULL; + qglPushClientAttrib = NULL; + qglPushMatrix = NULL; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = NULL; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = NULL; + qglRotatef = NULL; + qglScaled = NULL; + qglScalef = NULL; + qglScissor = NULL; + qglSelectBuffer = NULL; + qglShadeModel = NULL; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = NULL; + qglTexCoord2fv = NULL; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = NULL; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = NULL; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = NULL; + qglTexImage2D = NULL; + qglTexParameterf = NULL; + qglTexParameterfv = NULL; + qglTexParameteri = NULL; + qglTexParameteriv = NULL; + qglTexSubImage1D = NULL; + qglTexSubImage2D = NULL; + qglTranslated = NULL; + qglTranslatef = NULL; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = NULL; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = NULL; + qglVertex3fv = NULL; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = NULL; + + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord1dARB = NULL; + qglMultiTexCoord1dvARB = NULL; + qglMultiTexCoord1fARB = NULL; + qglMultiTexCoord1fvARB = NULL; + qglMultiTexCoord1iARB = NULL; + qglMultiTexCoord1ivARB = NULL; + qglMultiTexCoord1sARB = NULL; + qglMultiTexCoord1svARB = NULL; + qglMultiTexCoord2dARB = NULL; + qglMultiTexCoord2dvARB = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord2fvARB = NULL; + qglMultiTexCoord2iARB = NULL; + qglMultiTexCoord2ivARB = NULL; + qglMultiTexCoord2sARB = NULL; + qglMultiTexCoord2svARB = NULL; + qglMultiTexCoord3dARB = NULL; + qglMultiTexCoord3dvARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMultiTexCoord3fvARB = NULL; + qglMultiTexCoord3iARB = NULL; + qglMultiTexCoord3ivARB = NULL; + qglMultiTexCoord3sARB = NULL; + qglMultiTexCoord3svARB = NULL; + qglMultiTexCoord4dARB = NULL; + qglMultiTexCoord4dvARB = NULL; + qglMultiTexCoord4fARB = NULL; + qglMultiTexCoord4fvARB = NULL; + qglMultiTexCoord4iARB = NULL; + qglMultiTexCoord4ivARB = NULL; + qglMultiTexCoord4sARB = NULL; + qglMultiTexCoord4svARB = NULL; + +#ifdef _WIN32 + qwglCopyContext = NULL; + qwglCreateContext = NULL; + qwglCreateLayerContext = NULL; + qwglDeleteContext = NULL; + qwglDescribeLayerPlane = NULL; + qwglGetCurrentContext = NULL; + qwglGetCurrentDC = NULL; + qwglGetLayerPaletteEntries = NULL; + qwglGetProcAddress = NULL; + qwglMakeCurrent = NULL; + qwglRealizeLayerPalette = NULL; + qwglSetLayerPaletteEntries = NULL; + qwglShareLists = NULL; + qwglSwapLayerBuffers = NULL; + qwglUseFontBitmaps = NULL; + qwglUseFontOutlines = NULL; + + qwglChoosePixelFormat = NULL; + qwglDescribePixelFormat = NULL; + qwglGetPixelFormat = NULL; + qwglSetPixelFormat = NULL; + qwglSwapBuffers = NULL; + + qwglSwapIntervalEXT = NULL; + + qwglGetDeviceGammaRampEXT = NULL; + qwglSetDeviceGammaRampEXT = NULL; +#endif + +#if defined (__linux__) || defined (__APPLE__) + qglXChooseVisual = NULL; + qglXCreateContext = NULL; + qglXDestroyContext = NULL; + qglXMakeCurrent = NULL; + qglXCopyContext = NULL; + qglXSwapBuffers = NULL; + qglXCreateGLXPixmap = NULL; + qglXDestroyGLXPixmap = NULL; + qglXQueryExtension = NULL; + qglXQueryVersion = NULL; + qglXIsDirect = NULL; + qglXGetConfig = NULL; + qglXGetCurrentContext = NULL; + qglXGetCurrentDrawable = NULL; + qglXWaitGL = NULL; + qglXWaitX = NULL; + qglXUseXFont = NULL; + qglXGetProcAddressARB = NULL; +#endif + + qgluPerspective = NULL; + qgluErrorString = NULL; + qgluLookAt = NULL; + +#ifdef ATIHACK_812 + qglCullFace_real = NULL; + qglDisable_real = NULL; + qglEnable_real = NULL; + qglPolygonMode_real = NULL; +#endif +} + +/* +** QGL_Init +** +** This is responsible for binding our qgl function pointers to +** the appropriate GL stuff. In Windows this means doing a +** LoadLibrary and a bunch of calls to GetProcAddress. On other +** operating systems we need to do the right thing, whatever that +** might be. +** +*/ +static int init_error; + +static void* safe_dlsym (void *handle, char *symbol) +{ +#ifdef _WIN32 + return GetProcAddress (handle, symbol); +#endif + +#if defined (__linux__) || defined (__APPLE__) + void* ret = dlsym (handle, symbol); + const char *err = dlerror(); + if (err) + { + init_error = 1; +#ifndef __APPLE__ + printf ("Error loading OpenGL libraries: %s\n", err); +#else + printf ("Error loading OpenGL libraries: %s %s\n", err, symbol); +#endif + } + return ret; +#endif +} + +#include +#include +#ifdef _WIN32 +#define M_PI 3.14159 +#endif + +void WINAPI gluLookAt2 (GLdouble ex, GLdouble ey, GLdouble ez, GLdouble cx, GLdouble cy, GLdouble cz, + GLdouble ux, GLdouble uy, GLdouble uz) +{ + GLdouble x[3], y[3], z[3] = { ex-cx, ey-cy, ez-cz }; + GLdouble inv; + + inv = sqrt (z[0]*z[0] + z[1]*z[1] + z[2]*z[2]); + if (inv) + { + inv = 1.0/inv; + z[0] *= inv; + z[1] *= inv; + z[2] *= inv; + } + + x[0] = uy*z[2] - uz*z[1]; + x[1] = -ux*z[2] + uz*z[0]; + x[2] = ux*z[1] - uy*z[0]; + + y[0] = z[1]*x[2] - z[2]*x[1]; + y[1] = -z[0]*x[2] + z[2]*x[0]; + y[2] = z[0]*x[1] - z[1]*x[0]; + + inv = sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); + if (inv) + { + x[0] *= inv; + x[1] *= inv; + x[2] *= inv; + } + + inv = sqrt(y[0]*y[0] + y[1]*y[1] + y[2]*y[2]); + if (inv) + { + y[0] *= inv; + y[1] *= inv; + y[2] *= inv; + } + + { + GLdouble m[16] = { x[0], y[0], z[0], 0, x[1], y[1], z[1], 0, x[2], y[2], z[2], 0, 0, 0, 0, 1 }; + qglMultMatrixd(m); + qglTranslated(-ex, -ey, -ez); + } +} + +void WINAPI gluPerspective2 (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) +{ + GLdouble y = zNear * tan (fovy * M_PI / 360.0); + qglFrustum (-y*aspect, y*aspect, -y, y, zNear, zFar); +} + +static void* WINAPI ResizeImage (GLubyte* old_image, int srcw, int srch, int destw, int desth) +{ + int i, j; + float sx, sy; + GLubyte* new_image = (GLubyte *)malloc (destw*desth*4*sizeof(GLubyte)); + if (new_image == NULL) + return NULL; + + if (destw > 1) + sx = (GLfloat) (srcw-1) / (GLfloat) (destw-1); + else + sx = (GLfloat) (srcw-1); + if (desth > 1) + sy = (GLfloat) (srch-1) / (GLfloat) (desth-1); + else + sy = (GLfloat) (srch-1); + + for (i = 0; i < desth; i++) + { + GLint ii = (GLint)(i * sy); + for (j = 0; j < destw; j++) + { + GLint jj = (GLint)(j * sx); + GLubyte *src = old_image + (ii * srcw + jj) * 4; + GLubyte *dst = new_image + (i * destw + j) * 4; + + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + } + + return new_image; +} + +#define CEILING(A, B) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + +typedef struct glu_error_struct +{ + int errnum; + const char *errstr; +} GLU_ERROR_STRUCT; + +GLU_ERROR_STRUCT glu_errlist[] = { + {GL_NO_ERROR, "GL_NO_ERROR - no error"}, + {GL_INVALID_ENUM, "GL_INVALID_ENUM - An unacceptable value is specified for an enumerated argument."}, + {GL_INVALID_VALUE, "GL_INVALID_VALUE - A numeric argument is out of range."}, + {GL_INVALID_OPERATION, "GL_INVALID_OPERATION - The specified operation is not allowed in the current state."}, + {GL_STACK_OVERFLOW, "GL_STACK_OVERFLOW - Function would cause a stack overflow."}, + {GL_STACK_UNDERFLOW, "GL_STACK_UNDERFLOW - Function would cause a stack underflow."}, + {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY - There is not enough memory left to execute the function."}, + {-1, NULL} +}; + +const GLubyte* WINAPI gluErrorString(GLenum errCode ) +{ + int search = 0; + for (search = 0; glu_errlist[search].errstr; search++) + { + if (errCode == glu_errlist[search].errnum) + return (const char *)glu_errlist[search].errstr; + } //end for + return "Unknown error"; +} + +#ifdef ATIHACK_812 +int ATIhack_culling; +GLenum ATIhack_cullmode; +GLenum ATIhack_backmode; +GLenum ATIhack_frontmode; + +static void ATIhack_update(void) +{ + if(!ATIhack_culling || (GL_FRONT_AND_BACK == ATIhack_cullmode)) + { + qglPolygonMode_real(GL_FRONT, ATIhack_frontmode); + qglPolygonMode_real(GL_BACK, ATIhack_backmode); + } + else + switch(ATIhack_cullmode) + { + case GL_FRONT: + qglPolygonMode_real(GL_FRONT_AND_BACK, ATIhack_backmode); + break; + case GL_BACK: + qglPolygonMode_real(GL_FRONT_AND_BACK, ATIhack_frontmode); + default: + break; + } +} + +void APIENTRY qglEnable_ATIHack(GLenum cap) +{ + qglEnable_real(cap); + if(GL_CULL_FACE != cap) + return; + if(ATIhack_culling) + return; + ATIhack_culling = 1; + ATIhack_update(); +} + +void APIENTRY qglDisable_ATIHack(GLenum cap) +{ + qglDisable_real(cap); + if(GL_CULL_FACE != cap) + return; + if(!ATIhack_culling) + return; + ATIhack_culling = 0; + ATIhack_update(); +} + +void APIENTRY qglCullFace_ATIHack(GLenum mode) +{ + if(ATIhack_cullmode == mode) + return; + qglCullFace_real(mode); + ATIhack_cullmode = mode; + ATIhack_update(); +} + +void APIENTRY qglPolygonMode_ATIHack(GLenum face, GLenum mode) +{ + switch(face) + { + case GL_FRONT: + if(ATIhack_frontmode == mode) + return; + ATIhack_frontmode = mode; + break; + case GL_BACK: + if(ATIhack_backmode == mode) + return; + ATIhack_backmode = mode; + break; + case GL_FRONT_AND_BACK: + if((ATIhack_frontmode == mode) && (ATIhack_backmode == mode)) + return; + ATIhack_frontmode = ATIhack_backmode = mode; + default: + break; + } + ATIhack_update(); +} +#endif + +int QGL_Init(const char *dllname, const char* gluname) +{ +#ifdef _WIN32 + g_hGLDLL = LoadLibrary(dllname); +#endif + +#if defined (__linux__) || (__APPLE__) + const char *err; + + // NOTE TTimo + // I don't like RTLD_LAZY|RTLD_GLOBAL too much .. it's dangerous + // maybe try RTLD_NOW? or would that break compatibility .. you never know when that stuff is going to explode + g_hGLDLL = dlopen(dllname, RTLD_LAZY|RTLD_GLOBAL); + err = dlerror(); + if (err) + printf ("Error loading GL lib:\n%s\n", err); +#endif + init_error = 0; + + if (g_hGLDLL == NULL) + return 0; + + Sys_Printf ("Loading GL library: %s ...", dllname); + + qgluPerspective = &gluPerspective2; + + qgluLookAt = &gluLookAt2; + qgluErrorString = &gluErrorString; + qglAccum = safe_dlsym (g_hGLDLL, "glAccum" ); + qglAlphaFunc = safe_dlsym (g_hGLDLL, "glAlphaFunc" ); + qglAreTexturesResident = safe_dlsym (g_hGLDLL, "glAreTexturesResident" ); + qglArrayElement = safe_dlsym (g_hGLDLL, "glArrayElement" ); + qglBegin = safe_dlsym (g_hGLDLL, "glBegin" ); + qglBindTexture = safe_dlsym (g_hGLDLL, "glBindTexture" ); + qglBitmap = safe_dlsym (g_hGLDLL, "glBitmap" ); + qglBlendFunc = safe_dlsym (g_hGLDLL, "glBlendFunc" ); + qglCallList = safe_dlsym (g_hGLDLL, "glCallList" ); + qglCallLists = safe_dlsym (g_hGLDLL, "glCallLists" ); + qglClear = safe_dlsym (g_hGLDLL, "glClear" ); + qglClearAccum = safe_dlsym (g_hGLDLL, "glClearAccum" ); + qglClearColor = safe_dlsym (g_hGLDLL, "glClearColor" ); + qglClearDepth = safe_dlsym (g_hGLDLL, "glClearDepth" ); + qglClearIndex = safe_dlsym (g_hGLDLL, "glClearIndex" ); + qglClearStencil = safe_dlsym (g_hGLDLL, "glClearStencil" ); + qglClipPlane = safe_dlsym (g_hGLDLL, "glClipPlane" ); + qglColor3b = safe_dlsym (g_hGLDLL, "glColor3b" ); + qglColor3bv = safe_dlsym (g_hGLDLL, "glColor3bv" ); + qglColor3d = safe_dlsym (g_hGLDLL, "glColor3d" ); + qglColor3dv = safe_dlsym (g_hGLDLL, "glColor3dv" ); + qglColor3f = safe_dlsym (g_hGLDLL, "glColor3f" ); + qglColor3fv = safe_dlsym (g_hGLDLL, "glColor3fv" ); + qglColor3i = safe_dlsym (g_hGLDLL, "glColor3i" ); + qglColor3iv = safe_dlsym (g_hGLDLL, "glColor3iv" ); + qglColor3s = safe_dlsym (g_hGLDLL, "glColor3s" ); + qglColor3sv = safe_dlsym (g_hGLDLL, "glColor3sv" ); + qglColor3ub = safe_dlsym (g_hGLDLL, "glColor3ub" ); + qglColor3ubv = safe_dlsym (g_hGLDLL, "glColor3ubv" ); + qglColor3ui = safe_dlsym (g_hGLDLL, "glColor3ui" ); + qglColor3uiv = safe_dlsym (g_hGLDLL, "glColor3uiv" ); + qglColor3us = safe_dlsym (g_hGLDLL, "glColor3us" ); + qglColor3usv = safe_dlsym (g_hGLDLL, "glColor3usv" ); + qglColor4b = safe_dlsym (g_hGLDLL, "glColor4b" ); + qglColor4bv = safe_dlsym (g_hGLDLL, "glColor4bv" ); + qglColor4d = safe_dlsym (g_hGLDLL, "glColor4d" ); + qglColor4dv = safe_dlsym (g_hGLDLL, "glColor4dv" ); + qglColor4f = safe_dlsym (g_hGLDLL, "glColor4f" ); + qglColor4fv = safe_dlsym (g_hGLDLL, "glColor4fv" ); + qglColor4i = safe_dlsym (g_hGLDLL, "glColor4i" ); + qglColor4iv = safe_dlsym (g_hGLDLL, "glColor4iv" ); + qglColor4s = safe_dlsym (g_hGLDLL, "glColor4s" ); + qglColor4sv = safe_dlsym (g_hGLDLL, "glColor4sv" ); + qglColor4ub = safe_dlsym (g_hGLDLL, "glColor4ub" ); + qglColor4ubv = safe_dlsym (g_hGLDLL, "glColor4ubv" ); + qglColor4ui = safe_dlsym (g_hGLDLL, "glColor4ui" ); + qglColor4uiv = safe_dlsym (g_hGLDLL, "glColor4uiv" ); + qglColor4us = safe_dlsym (g_hGLDLL, "glColor4us" ); + qglColor4usv = safe_dlsym (g_hGLDLL, "glColor4usv" ); + qglColorMask = safe_dlsym (g_hGLDLL, "glColorMask" ); + qglColorMaterial = safe_dlsym (g_hGLDLL, "glColorMaterial" ); + qglColorPointer = safe_dlsym (g_hGLDLL, "glColorPointer" ); + qglCopyPixels = safe_dlsym (g_hGLDLL, "glCopyPixels" ); + qglCopyTexImage1D = safe_dlsym (g_hGLDLL, "glCopyTexImage1D" ); + qglCopyTexImage2D = safe_dlsym (g_hGLDLL, "glCopyTexImage2D" ); + qglCopyTexSubImage1D = safe_dlsym (g_hGLDLL, "glCopyTexSubImage1D" ); + qglCopyTexSubImage2D = safe_dlsym (g_hGLDLL, "glCopyTexSubImage2D" ); +#ifdef ATIHACK_812 + qglCullFace_real = safe_dlsym (g_hGLDLL, "glCullFace" ); + qglCullFace = qglCullFace_real; +#else + qglCullFace = safe_dlsym (g_hGLDLL, "glCullFace" ); +#endif + qglDeleteLists = safe_dlsym (g_hGLDLL, "glDeleteLists" ); + qglDeleteTextures = safe_dlsym (g_hGLDLL, "glDeleteTextures" ); + qglDepthFunc = safe_dlsym (g_hGLDLL, "glDepthFunc" ); + qglDepthMask = safe_dlsym (g_hGLDLL, "glDepthMask" ); + qglDepthRange = safe_dlsym (g_hGLDLL, "glDepthRange" ); +#ifdef ATIHACK_812 + qglDisable_real = safe_dlsym (g_hGLDLL, "glDisable" ); + qglDisable = qglDisable_real; +#else + qglDisable = safe_dlsym (g_hGLDLL, "glDisable" ); +#endif + qglDisableClientState = safe_dlsym (g_hGLDLL, "glDisableClientState" ); + qglDrawArrays = safe_dlsym (g_hGLDLL, "glDrawArrays" ); + qglDrawBuffer = safe_dlsym (g_hGLDLL, "glDrawBuffer" ); + qglDrawElements = safe_dlsym (g_hGLDLL, "glDrawElements" ); + qglDrawPixels = safe_dlsym (g_hGLDLL, "glDrawPixels" ); + qglEdgeFlag = safe_dlsym (g_hGLDLL, "glEdgeFlag" ); + qglEdgeFlagPointer = safe_dlsym (g_hGLDLL, "glEdgeFlagPointer" ); + qglEdgeFlagv = safe_dlsym (g_hGLDLL, "glEdgeFlagv" ); +#ifdef ATIHACK_812 + qglEnable_real = safe_dlsym (g_hGLDLL, "glEnable" ); + qglEnable = qglEnable_real; +#else + qglEnable = safe_dlsym (g_hGLDLL, "glEnable" ); +#endif + qglEnableClientState = safe_dlsym (g_hGLDLL, "glEnableClientState" ); + qglEnd = safe_dlsym (g_hGLDLL, "glEnd" ); + qglEndList = safe_dlsym (g_hGLDLL, "glEndList" ); + qglEvalCoord1d = safe_dlsym (g_hGLDLL, "glEvalCoord1d" ); + qglEvalCoord1dv = safe_dlsym (g_hGLDLL, "glEvalCoord1dv" ); + qglEvalCoord1f = safe_dlsym (g_hGLDLL, "glEvalCoord1f" ); + qglEvalCoord1fv = safe_dlsym (g_hGLDLL, "glEvalCoord1fv" ); + qglEvalCoord2d = safe_dlsym (g_hGLDLL, "glEvalCoord2d" ); + qglEvalCoord2dv = safe_dlsym (g_hGLDLL, "glEvalCoord2dv" ); + qglEvalCoord2f = safe_dlsym (g_hGLDLL, "glEvalCoord2f" ); + qglEvalCoord2fv = safe_dlsym (g_hGLDLL, "glEvalCoord2fv" ); + qglEvalMesh1 = safe_dlsym (g_hGLDLL, "glEvalMesh1" ); + qglEvalMesh2 = safe_dlsym (g_hGLDLL, "glEvalMesh2" ); + qglEvalPoint1 = safe_dlsym (g_hGLDLL, "glEvalPoint1" ); + qglEvalPoint2 = safe_dlsym (g_hGLDLL, "glEvalPoint2" ); + qglFeedbackBuffer = safe_dlsym (g_hGLDLL, "glFeedbackBuffer" ); + qglFinish = safe_dlsym (g_hGLDLL, "glFinish" ); + qglFlush = safe_dlsym (g_hGLDLL, "glFlush" ); + qglFogf = safe_dlsym (g_hGLDLL, "glFogf" ); + qglFogfv = safe_dlsym (g_hGLDLL, "glFogfv" ); + qglFogi = safe_dlsym (g_hGLDLL, "glFogi" ); + qglFogiv = safe_dlsym (g_hGLDLL, "glFogiv" ); + qglFrontFace = safe_dlsym (g_hGLDLL, "glFrontFace" ); + qglFrustum = safe_dlsym (g_hGLDLL, "glFrustum" ); + qglGenLists = safe_dlsym (g_hGLDLL, "glGenLists" ); + qglGenTextures = safe_dlsym (g_hGLDLL, "glGenTextures" ); + qglGetBooleanv = safe_dlsym (g_hGLDLL, "glGetBooleanv" ); + qglGetClipPlane = safe_dlsym (g_hGLDLL, "glGetClipPlane" ); + qglGetDoublev = safe_dlsym (g_hGLDLL, "glGetDoublev" ); + qglGetError = safe_dlsym (g_hGLDLL, "glGetError" ); + qglGetFloatv = safe_dlsym (g_hGLDLL, "glGetFloatv" ); + qglGetIntegerv = safe_dlsym (g_hGLDLL, "glGetIntegerv" ); + qglGetLightfv = safe_dlsym (g_hGLDLL, "glGetLightfv" ); + qglGetLightiv = safe_dlsym (g_hGLDLL, "glGetLightiv" ); + qglGetMapdv = safe_dlsym (g_hGLDLL, "glGetMapdv" ); + qglGetMapfv = safe_dlsym (g_hGLDLL, "glGetMapfv" ); + qglGetMapiv = safe_dlsym (g_hGLDLL, "glGetMapiv" ); + qglGetMaterialfv = safe_dlsym (g_hGLDLL, "glGetMaterialfv" ); + qglGetMaterialiv = safe_dlsym (g_hGLDLL, "glGetMaterialiv" ); + qglGetPixelMapfv = safe_dlsym (g_hGLDLL, "glGetPixelMapfv" ); + qglGetPixelMapuiv = safe_dlsym (g_hGLDLL, "glGetPixelMapuiv" ); + qglGetPixelMapusv = safe_dlsym (g_hGLDLL, "glGetPixelMapusv" ); + qglGetPointerv = safe_dlsym (g_hGLDLL, "glGetPointerv" ); + qglGetPolygonStipple = safe_dlsym (g_hGLDLL, "glGetPolygonStipple" ); + qglGetString = safe_dlsym (g_hGLDLL, "glGetString" ); + qglGetTexEnvfv = safe_dlsym (g_hGLDLL, "glGetTexEnvfv" ); + qglGetTexEnviv = safe_dlsym (g_hGLDLL, "glGetTexEnviv" ); + qglGetTexGendv = safe_dlsym (g_hGLDLL, "glGetTexGendv" ); + qglGetTexGenfv = safe_dlsym (g_hGLDLL, "glGetTexGenfv" ); + qglGetTexGeniv = safe_dlsym (g_hGLDLL, "glGetTexGeniv" ); + qglGetTexImage = safe_dlsym (g_hGLDLL, "glGetTexImage" ); + qglGetTexLevelParameterfv = safe_dlsym (g_hGLDLL, "glGetTexLevelParameterfv" ); + qglGetTexLevelParameteriv = safe_dlsym (g_hGLDLL, "glGetTexLevelParameteriv" ); + qglGetTexParameterfv = safe_dlsym (g_hGLDLL, "glGetTexParameterfv" ); + qglGetTexParameteriv = safe_dlsym (g_hGLDLL, "glGetTexParameteriv" ); + qglHint = safe_dlsym (g_hGLDLL, "glHint" ); + qglIndexMask = safe_dlsym (g_hGLDLL, "glIndexMask" ); + qglIndexPointer = safe_dlsym (g_hGLDLL, "glIndexPointer" ); + qglIndexd = safe_dlsym (g_hGLDLL, "glIndexd" ); + qglIndexdv = safe_dlsym (g_hGLDLL, "glIndexdv" ); + qglIndexf = safe_dlsym (g_hGLDLL, "glIndexf" ); + qglIndexfv = safe_dlsym (g_hGLDLL, "glIndexfv" ); + qglIndexi = safe_dlsym (g_hGLDLL, "glIndexi" ); + qglIndexiv = safe_dlsym (g_hGLDLL, "glIndexiv" ); + qglIndexs = safe_dlsym (g_hGLDLL, "glIndexs" ); + qglIndexsv = safe_dlsym (g_hGLDLL, "glIndexsv" ); + qglIndexub = safe_dlsym (g_hGLDLL, "glIndexub" ); + qglIndexubv = safe_dlsym (g_hGLDLL, "glIndexubv" ); + qglInitNames = safe_dlsym (g_hGLDLL, "glInitNames" ); + qglInterleavedArrays = safe_dlsym (g_hGLDLL, "glInterleavedArrays" ); + qglIsEnabled = safe_dlsym (g_hGLDLL, "glIsEnabled" ); + qglIsList = safe_dlsym (g_hGLDLL, "glIsList" ); + qglIsTexture = safe_dlsym (g_hGLDLL, "glIsTexture" ); + qglLightModelf = safe_dlsym (g_hGLDLL, "glLightModelf" ); + qglLightModelfv = safe_dlsym (g_hGLDLL, "glLightModelfv" ); + qglLightModeli = safe_dlsym (g_hGLDLL, "glLightModeli" ); + qglLightModeliv = safe_dlsym (g_hGLDLL, "glLightModeliv" ); + qglLightf = safe_dlsym (g_hGLDLL, "glLightf" ); + qglLightfv = safe_dlsym (g_hGLDLL, "glLightfv" ); + qglLighti = safe_dlsym (g_hGLDLL, "glLighti" ); + qglLightiv = safe_dlsym (g_hGLDLL, "glLightiv" ); + qglLineStipple = safe_dlsym (g_hGLDLL, "glLineStipple" ); + qglLineWidth = safe_dlsym (g_hGLDLL, "glLineWidth" ); + qglListBase = safe_dlsym (g_hGLDLL, "glListBase" ); + qglLoadIdentity = safe_dlsym (g_hGLDLL, "glLoadIdentity" ); + qglLoadMatrixd = safe_dlsym (g_hGLDLL, "glLoadMatrixd" ); + qglLoadMatrixf = safe_dlsym (g_hGLDLL, "glLoadMatrixf" ); + qglLoadName = safe_dlsym (g_hGLDLL, "glLoadName" ); + qglLogicOp = safe_dlsym (g_hGLDLL, "glLogicOp" ); + qglMap1d = safe_dlsym (g_hGLDLL, "glMap1d" ); + qglMap1f = safe_dlsym (g_hGLDLL, "glMap1f" ); + qglMap2d = safe_dlsym (g_hGLDLL, "glMap2d" ); + qglMap2f = safe_dlsym (g_hGLDLL, "glMap2f" ); + qglMapGrid1d = safe_dlsym (g_hGLDLL, "glMapGrid1d" ); + qglMapGrid1f = safe_dlsym (g_hGLDLL, "glMapGrid1f" ); + qglMapGrid2d = safe_dlsym (g_hGLDLL, "glMapGrid2d" ); + qglMapGrid2f = safe_dlsym (g_hGLDLL, "glMapGrid2f" ); + qglMaterialf = safe_dlsym (g_hGLDLL, "glMaterialf" ); + qglMaterialfv = safe_dlsym (g_hGLDLL, "glMaterialfv" ); + qglMateriali = safe_dlsym (g_hGLDLL, "glMateriali" ); + qglMaterialiv = safe_dlsym (g_hGLDLL, "glMaterialiv" ); + qglMatrixMode = safe_dlsym (g_hGLDLL, "glMatrixMode" ); + qglMultMatrixd = safe_dlsym (g_hGLDLL, "glMultMatrixd" ); + qglMultMatrixf = safe_dlsym (g_hGLDLL, "glMultMatrixf" ); + qglNewList = safe_dlsym (g_hGLDLL, "glNewList" ); + qglNormal3b = safe_dlsym (g_hGLDLL, "glNormal3b" ); + qglNormal3bv = safe_dlsym (g_hGLDLL, "glNormal3bv" ); + qglNormal3d = safe_dlsym (g_hGLDLL, "glNormal3d" ); + qglNormal3dv = safe_dlsym (g_hGLDLL, "glNormal3dv" ); + qglNormal3f = safe_dlsym (g_hGLDLL, "glNormal3f" ); + qglNormal3fv = safe_dlsym (g_hGLDLL, "glNormal3fv" ); + qglNormal3i = safe_dlsym (g_hGLDLL, "glNormal3i" ); + qglNormal3iv = safe_dlsym (g_hGLDLL, "glNormal3iv" ); + qglNormal3s = safe_dlsym (g_hGLDLL, "glNormal3s" ); + qglNormal3sv = safe_dlsym (g_hGLDLL, "glNormal3sv" ); + qglNormalPointer = safe_dlsym (g_hGLDLL, "glNormalPointer" ); + qglOrtho = safe_dlsym (g_hGLDLL, "glOrtho" ); + qglPassThrough = safe_dlsym (g_hGLDLL, "glPassThrough" ); + qglPixelMapfv = safe_dlsym (g_hGLDLL, "glPixelMapfv" ); + qglPixelMapuiv = safe_dlsym (g_hGLDLL, "glPixelMapuiv" ); + qglPixelMapusv = safe_dlsym (g_hGLDLL, "glPixelMapusv" ); + qglPixelStoref = safe_dlsym (g_hGLDLL, "glPixelStoref" ); + qglPixelStorei = safe_dlsym (g_hGLDLL, "glPixelStorei" ); + qglPixelTransferf = safe_dlsym (g_hGLDLL, "glPixelTransferf" ); + qglPixelTransferi = safe_dlsym (g_hGLDLL, "glPixelTransferi" ); + qglPixelZoom = safe_dlsym (g_hGLDLL, "glPixelZoom" ); + qglPointSize = safe_dlsym (g_hGLDLL, "glPointSize" ); +#ifdef ATIHACK_812 + qglPolygonMode_real = safe_dlsym (g_hGLDLL, "glPolygonMode" ); + qglPolygonMode = qglPolygonMode_real; +#else + qglPolygonMode = safe_dlsym (g_hGLDLL, "glPolygonMode" ); +#endif + qglPolygonOffset = safe_dlsym (g_hGLDLL, "glPolygonOffset" ); + qglPolygonStipple = safe_dlsym (g_hGLDLL, "glPolygonStipple" ); + qglPopAttrib = safe_dlsym (g_hGLDLL, "glPopAttrib" ); + qglPopClientAttrib = safe_dlsym (g_hGLDLL, "glPopClientAttrib" ); + qglPopMatrix = safe_dlsym (g_hGLDLL, "glPopMatrix" ); + qglPopName = safe_dlsym (g_hGLDLL, "glPopName" ); + qglPrioritizeTextures = safe_dlsym (g_hGLDLL, "glPrioritizeTextures" ); + qglPushAttrib = safe_dlsym (g_hGLDLL, "glPushAttrib" ); + qglPushClientAttrib = safe_dlsym (g_hGLDLL, "glPushClientAttrib" ); + qglPushMatrix = safe_dlsym (g_hGLDLL, "glPushMatrix" ); + qglPushName = safe_dlsym (g_hGLDLL, "glPushName" ); + qglRasterPos2d = safe_dlsym (g_hGLDLL, "glRasterPos2d" ); + qglRasterPos2dv = safe_dlsym (g_hGLDLL, "glRasterPos2dv" ); + qglRasterPos2f = safe_dlsym (g_hGLDLL, "glRasterPos2f" ); + qglRasterPos2fv = safe_dlsym (g_hGLDLL, "glRasterPos2fv" ); + qglRasterPos2i = safe_dlsym (g_hGLDLL, "glRasterPos2i" ); + qglRasterPos2iv = safe_dlsym (g_hGLDLL, "glRasterPos2iv" ); + qglRasterPos2s = safe_dlsym (g_hGLDLL, "glRasterPos2s" ); + qglRasterPos2sv = safe_dlsym (g_hGLDLL, "glRasterPos2sv" ); + qglRasterPos3d = safe_dlsym (g_hGLDLL, "glRasterPos3d" ); + qglRasterPos3dv = safe_dlsym (g_hGLDLL, "glRasterPos3dv" ); + qglRasterPos3f = safe_dlsym (g_hGLDLL, "glRasterPos3f" ); + qglRasterPos3fv = safe_dlsym (g_hGLDLL, "glRasterPos3fv" ); + qglRasterPos3i = safe_dlsym (g_hGLDLL, "glRasterPos3i" ); + qglRasterPos3iv = safe_dlsym (g_hGLDLL, "glRasterPos3iv" ); + qglRasterPos3s = safe_dlsym (g_hGLDLL, "glRasterPos3s" ); + qglRasterPos3sv = safe_dlsym (g_hGLDLL, "glRasterPos3sv" ); + qglRasterPos4d = safe_dlsym (g_hGLDLL, "glRasterPos4d" ); + qglRasterPos4dv = safe_dlsym (g_hGLDLL, "glRasterPos4dv" ); + qglRasterPos4f = safe_dlsym (g_hGLDLL, "glRasterPos4f" ); + qglRasterPos4fv = safe_dlsym (g_hGLDLL, "glRasterPos4fv" ); + qglRasterPos4i = safe_dlsym (g_hGLDLL, "glRasterPos4i" ); + qglRasterPos4iv = safe_dlsym (g_hGLDLL, "glRasterPos4iv" ); + qglRasterPos4s = safe_dlsym (g_hGLDLL, "glRasterPos4s" ); + qglRasterPos4sv = safe_dlsym (g_hGLDLL, "glRasterPos4sv" ); + qglReadBuffer = safe_dlsym (g_hGLDLL, "glReadBuffer" ); + qglReadPixels = safe_dlsym (g_hGLDLL, "glReadPixels" ); + qglRectd = safe_dlsym (g_hGLDLL, "glRectd" ); + qglRectdv = safe_dlsym (g_hGLDLL, "glRectdv" ); + qglRectf = safe_dlsym (g_hGLDLL, "glRectf" ); + qglRectfv = safe_dlsym (g_hGLDLL, "glRectfv" ); + qglRecti = safe_dlsym (g_hGLDLL, "glRecti" ); + qglRectiv = safe_dlsym (g_hGLDLL, "glRectiv" ); + qglRects = safe_dlsym (g_hGLDLL, "glRects" ); + qglRectsv = safe_dlsym (g_hGLDLL, "glRectsv" ); + qglRenderMode = safe_dlsym (g_hGLDLL, "glRenderMode" ); + qglRotated = safe_dlsym (g_hGLDLL, "glRotated" ); + qglRotatef = safe_dlsym (g_hGLDLL, "glRotatef" ); + qglScaled = safe_dlsym (g_hGLDLL, "glScaled" ); + qglScalef = safe_dlsym (g_hGLDLL, "glScalef" ); + qglScissor = safe_dlsym (g_hGLDLL, "glScissor" ); + qglSelectBuffer = safe_dlsym (g_hGLDLL, "glSelectBuffer" ); + qglShadeModel = safe_dlsym (g_hGLDLL, "glShadeModel" ); + qglStencilFunc = safe_dlsym (g_hGLDLL, "glStencilFunc" ); + qglStencilMask = safe_dlsym (g_hGLDLL, "glStencilMask" ); + qglStencilOp = safe_dlsym (g_hGLDLL, "glStencilOp" ); + qglTexCoord1d = safe_dlsym (g_hGLDLL, "glTexCoord1d" ); + qglTexCoord1dv = safe_dlsym (g_hGLDLL, "glTexCoord1dv" ); + qglTexCoord1f = safe_dlsym (g_hGLDLL, "glTexCoord1f" ); + qglTexCoord1fv = safe_dlsym (g_hGLDLL, "glTexCoord1fv" ); + qglTexCoord1i = safe_dlsym (g_hGLDLL, "glTexCoord1i" ); + qglTexCoord1iv = safe_dlsym (g_hGLDLL, "glTexCoord1iv" ); + qglTexCoord1s = safe_dlsym (g_hGLDLL, "glTexCoord1s" ); + qglTexCoord1sv = safe_dlsym (g_hGLDLL, "glTexCoord1sv" ); + qglTexCoord2d = safe_dlsym (g_hGLDLL, "glTexCoord2d" ); + qglTexCoord2dv = safe_dlsym (g_hGLDLL, "glTexCoord2dv" ); + qglTexCoord2f = safe_dlsym (g_hGLDLL, "glTexCoord2f" ); + qglTexCoord2fv = safe_dlsym (g_hGLDLL, "glTexCoord2fv" ); + qglTexCoord2i = safe_dlsym (g_hGLDLL, "glTexCoord2i" ); + qglTexCoord2iv = safe_dlsym (g_hGLDLL, "glTexCoord2iv" ); + qglTexCoord2s = safe_dlsym (g_hGLDLL, "glTexCoord2s" ); + qglTexCoord2sv = safe_dlsym (g_hGLDLL, "glTexCoord2sv" ); + qglTexCoord3d = safe_dlsym (g_hGLDLL, "glTexCoord3d" ); + qglTexCoord3dv = safe_dlsym (g_hGLDLL, "glTexCoord3dv" ); + qglTexCoord3f = safe_dlsym (g_hGLDLL, "glTexCoord3f" ); + qglTexCoord3fv = safe_dlsym (g_hGLDLL, "glTexCoord3fv" ); + qglTexCoord3i = safe_dlsym (g_hGLDLL, "glTexCoord3i" ); + qglTexCoord3iv = safe_dlsym (g_hGLDLL, "glTexCoord3iv" ); + qglTexCoord3s = safe_dlsym (g_hGLDLL, "glTexCoord3s" ); + qglTexCoord3sv = safe_dlsym (g_hGLDLL, "glTexCoord3sv" ); + qglTexCoord4d = safe_dlsym (g_hGLDLL, "glTexCoord4d" ); + qglTexCoord4dv = safe_dlsym (g_hGLDLL, "glTexCoord4dv" ); + qglTexCoord4f = safe_dlsym (g_hGLDLL, "glTexCoord4f" ); + qglTexCoord4fv = safe_dlsym (g_hGLDLL, "glTexCoord4fv" ); + qglTexCoord4i = safe_dlsym (g_hGLDLL, "glTexCoord4i" ); + qglTexCoord4iv = safe_dlsym (g_hGLDLL, "glTexCoord4iv" ); + qglTexCoord4s = safe_dlsym (g_hGLDLL, "glTexCoord4s" ); + qglTexCoord4sv = safe_dlsym (g_hGLDLL, "glTexCoord4sv" ); + qglTexCoordPointer = safe_dlsym (g_hGLDLL, "glTexCoordPointer" ); + qglTexEnvf = safe_dlsym (g_hGLDLL, "glTexEnvf" ); + qglTexEnvfv = safe_dlsym (g_hGLDLL, "glTexEnvfv" ); + qglTexEnvi = safe_dlsym (g_hGLDLL, "glTexEnvi" ); + qglTexEnviv = safe_dlsym (g_hGLDLL, "glTexEnviv" ); + qglTexGend = safe_dlsym (g_hGLDLL, "glTexGend" ); + qglTexGendv = safe_dlsym (g_hGLDLL, "glTexGendv" ); + qglTexGenf = safe_dlsym (g_hGLDLL, "glTexGenf" ); + qglTexGenfv = safe_dlsym (g_hGLDLL, "glTexGenfv" ); + qglTexGeni = safe_dlsym (g_hGLDLL, "glTexGeni" ); + qglTexGeniv = safe_dlsym (g_hGLDLL, "glTexGeniv" ); + qglTexImage1D = safe_dlsym (g_hGLDLL, "glTexImage1D" ); + qglTexImage2D = safe_dlsym (g_hGLDLL, "glTexImage2D" ); + qglTexParameterf = safe_dlsym (g_hGLDLL, "glTexParameterf" ); + qglTexParameterfv = safe_dlsym (g_hGLDLL, "glTexParameterfv" ); + qglTexParameteri = safe_dlsym (g_hGLDLL, "glTexParameteri" ); + qglTexParameteriv = safe_dlsym (g_hGLDLL, "glTexParameteriv" ); + qglTexSubImage1D = safe_dlsym (g_hGLDLL, "glTexSubImage1D" ); + qglTexSubImage2D = safe_dlsym (g_hGLDLL, "glTexSubImage2D" ); + qglTranslated = safe_dlsym (g_hGLDLL, "glTranslated" ); + qglTranslatef = safe_dlsym (g_hGLDLL, "glTranslatef" ); + qglVertex2d = safe_dlsym (g_hGLDLL, "glVertex2d" ); + qglVertex2dv = safe_dlsym (g_hGLDLL, "glVertex2dv" ); + qglVertex2f = safe_dlsym (g_hGLDLL, "glVertex2f" ); + qglVertex2fv = safe_dlsym (g_hGLDLL, "glVertex2fv" ); + qglVertex2i = safe_dlsym (g_hGLDLL, "glVertex2i" ); + qglVertex2iv = safe_dlsym (g_hGLDLL, "glVertex2iv" ); + qglVertex2s = safe_dlsym (g_hGLDLL, "glVertex2s" ); + qglVertex2sv = safe_dlsym (g_hGLDLL, "glVertex2sv" ); + qglVertex3d = safe_dlsym (g_hGLDLL, "glVertex3d" ); + qglVertex3dv = safe_dlsym (g_hGLDLL, "glVertex3dv" ); + qglVertex3f = safe_dlsym (g_hGLDLL, "glVertex3f" ); + qglVertex3fv = safe_dlsym (g_hGLDLL, "glVertex3fv" ); + qglVertex3i = safe_dlsym (g_hGLDLL, "glVertex3i" ); + qglVertex3iv = safe_dlsym (g_hGLDLL, "glVertex3iv" ); + qglVertex3s = safe_dlsym (g_hGLDLL, "glVertex3s" ); + qglVertex3sv = safe_dlsym (g_hGLDLL, "glVertex3sv" ); + qglVertex4d = safe_dlsym (g_hGLDLL, "glVertex4d" ); + qglVertex4dv = safe_dlsym (g_hGLDLL, "glVertex4dv" ); + qglVertex4f = safe_dlsym (g_hGLDLL, "glVertex4f" ); + qglVertex4fv = safe_dlsym (g_hGLDLL, "glVertex4fv" ); + qglVertex4i = safe_dlsym (g_hGLDLL, "glVertex4i" ); + qglVertex4iv = safe_dlsym (g_hGLDLL, "glVertex4iv" ); + qglVertex4s = safe_dlsym (g_hGLDLL, "glVertex4s" ); + qglVertex4sv = safe_dlsym (g_hGLDLL, "glVertex4sv" ); + qglVertexPointer = safe_dlsym (g_hGLDLL, "glVertexPointer" ); + qglViewport = safe_dlsym (g_hGLDLL, "glViewport" ); + + // must be init with an active context + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord1dARB = NULL; + qglMultiTexCoord1dvARB = NULL; + qglMultiTexCoord1fARB = NULL; + qglMultiTexCoord1fvARB = NULL; + qglMultiTexCoord1iARB = NULL; + qglMultiTexCoord1ivARB = NULL; + qglMultiTexCoord1sARB = NULL; + qglMultiTexCoord1svARB = NULL; + qglMultiTexCoord2dARB = NULL; + qglMultiTexCoord2dvARB = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord2fvARB = NULL; + qglMultiTexCoord2iARB = NULL; + qglMultiTexCoord2ivARB = NULL; + qglMultiTexCoord2sARB = NULL; + qglMultiTexCoord2svARB = NULL; + qglMultiTexCoord3dARB = NULL; + qglMultiTexCoord3dvARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMultiTexCoord3fvARB = NULL; + qglMultiTexCoord3iARB = NULL; + qglMultiTexCoord3ivARB = NULL; + qglMultiTexCoord3sARB = NULL; + qglMultiTexCoord3svARB = NULL; + qglMultiTexCoord4dARB = NULL; + qglMultiTexCoord4dvARB = NULL; + qglMultiTexCoord4fARB = NULL; + qglMultiTexCoord4fvARB = NULL; + qglMultiTexCoord4iARB = NULL; + qglMultiTexCoord4ivARB = NULL; + qglMultiTexCoord4sARB = NULL; + qglMultiTexCoord4svARB = NULL; + +#ifdef _WIN32 + qwglCopyContext = safe_dlsym(g_hGLDLL, "wglCopyContext" ); + qwglCreateContext = safe_dlsym(g_hGLDLL, "wglCreateContext"); + qwglCreateLayerContext = safe_dlsym(g_hGLDLL, "wglCreateLayerContext" ); + qwglDeleteContext = safe_dlsym(g_hGLDLL, "wglDeleteContext"); + qwglDescribeLayerPlane = safe_dlsym(g_hGLDLL, "wglDescribeLayerPlane" ); + qwglGetCurrentContext = safe_dlsym(g_hGLDLL, "wglGetCurrentContext" ); + qwglGetCurrentDC = safe_dlsym(g_hGLDLL, "wglGetCurrentDC" ); + qwglGetLayerPaletteEntries = safe_dlsym(g_hGLDLL, "wglGetLayerPaletteEntries" ); + qwglGetProcAddress = safe_dlsym(g_hGLDLL, "wglGetProcAddress" ); + qwglMakeCurrent = safe_dlsym(g_hGLDLL, "wglMakeCurrent" ); + qwglRealizeLayerPalette = safe_dlsym(g_hGLDLL, "wglRealizeLayerPalette" ); + qwglSetLayerPaletteEntries = safe_dlsym(g_hGLDLL, "wglSetLayerPaletteEntries" ); + qwglShareLists = safe_dlsym(g_hGLDLL, "wglShareLists" ); + qwglSwapLayerBuffers = safe_dlsym(g_hGLDLL, "wglSwapLayerBuffers" ); + qwglUseFontBitmaps = safe_dlsym(g_hGLDLL, "wglUseFontBitmapsA" ); + qwglUseFontOutlines = safe_dlsym(g_hGLDLL, "wglUseFontOutlinesA" ); + + qwglChoosePixelFormat = safe_dlsym(g_hGLDLL, "wglChoosePixelFormat" ); + qwglDescribePixelFormat = safe_dlsym(g_hGLDLL, "wglDescribePixelFormat" ); + qwglGetPixelFormat = safe_dlsym(g_hGLDLL, "wglGetPixelFormat" ); + qwglSetPixelFormat = safe_dlsym(g_hGLDLL, "wglSetPixelFormat" ); + qwglSwapBuffers = safe_dlsym(g_hGLDLL, "wglSwapBuffers" ); + + qwglSwapIntervalEXT = 0; + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; +#endif + +#if defined (__linux__) || defined (__APPLE__) + qglXChooseVisual = safe_dlsym (g_hGLDLL, "glXChooseVisual"); + qglXCreateContext = safe_dlsym (g_hGLDLL, "glXCreateContext"); + qglXDestroyContext = safe_dlsym (g_hGLDLL, "glXDestroyContext"); + qglXMakeCurrent = safe_dlsym (g_hGLDLL, "glXMakeCurrent"); + qglXCopyContext = safe_dlsym (g_hGLDLL, "glXCopyContext"); + qglXSwapBuffers = safe_dlsym (g_hGLDLL, "glXSwapBuffers"); + qglXCreateGLXPixmap = safe_dlsym (g_hGLDLL, "glXCreateGLXPixmap"); + qglXDestroyGLXPixmap = safe_dlsym (g_hGLDLL, "glXDestroyGLXPixmap"); + qglXQueryExtension = safe_dlsym (g_hGLDLL, "glXQueryExtension"); + qglXQueryVersion = safe_dlsym (g_hGLDLL, "glXQueryVersion"); + qglXIsDirect = safe_dlsym (g_hGLDLL, "glXIsDirect"); + qglXGetConfig = safe_dlsym (g_hGLDLL, "glXGetConfig"); + qglXGetCurrentContext = safe_dlsym (g_hGLDLL, "glXGetCurrentContext"); + qglXGetCurrentDrawable = safe_dlsym (g_hGLDLL, "glXGetCurrentDrawable"); + qglXWaitGL = safe_dlsym (g_hGLDLL, "glXWaitGL"); + qglXWaitX = safe_dlsym (g_hGLDLL, "glXWaitX"); + qglXUseXFont = safe_dlsym (g_hGLDLL, "glXUseXFont"); +// qglXGetProcAddressARB = dlsym (g_hGLDLL, "glXGetProcAddressARB"); // Utah-GLX fix +#endif + + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; + + // texture compression + Sys_Printf ("Done.\n"); + +#ifdef ATIHACK_812 + ATIhack_culling = 0; + ATIhack_cullmode = GL_BACK; + ATIhack_backmode = GL_FILL; + ATIhack_frontmode = GL_FILL; +#endif + + if (init_error == 1) + return 0; + + return 1; +} + +int GL_ExtensionSupported (const char *extension) +{ + const GLubyte *extensions = NULL; + const GLubyte *start; + GLubyte *where, *terminator; + + // Extension names should not have spaces. + where = (GLubyte *) strchr (extension, ' '); + if (where || *extension == '\0') + return 0; + + extensions = qglGetString (GL_EXTENSIONS); +#ifndef __APPLE__ + if (!extensions) + return 0; +#endif + + // It takes a bit of care to be fool-proof about parsing the + // OpenGL extensions string. Don't be fooled by sub-strings, etc. + for (start = extensions; ;) + { + where = (GLubyte *) strstr ((const char *) start, extension); + if (!where) + break; + + terminator = where + strlen (extension); + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') + return 1; + + start = terminator; + } + + return 0; +} + +void* Sys_GLGetExtension (const char *symbol) +{ +#if defined (__linux__) || defined (__APPLE__) + if (qglXGetProcAddressARB == NULL) + return NULL; + else + return qglXGetProcAddressARB ((GLubyte*)symbol); +#else + return qwglGetProcAddress (symbol); +#endif +} + +void QGL_InitExtensions () +{ + if (GL_ExtensionSupported ("GL_ARB_multitexture")) + { + qglActiveTextureARB = Sys_GLGetExtension ("glActiveTextureARB"); + qglClientActiveTextureARB = Sys_GLGetExtension ("glClientActiveTextureARB"); + qglMultiTexCoord1dARB = Sys_GLGetExtension ("glMultiTexCoord1dARB"); + qglMultiTexCoord1dvARB = Sys_GLGetExtension ("glMultiTexCoord1dvARB"); + qglMultiTexCoord1fARB = Sys_GLGetExtension ("glMultiTexCoord1fARB"); + qglMultiTexCoord1fvARB = Sys_GLGetExtension ("glMultiTexCoord1fvARB"); + qglMultiTexCoord1iARB = Sys_GLGetExtension ("glMultiTexCoord1iARB"); + qglMultiTexCoord1ivARB = Sys_GLGetExtension ("glMultiTexCoord1ivARB"); + qglMultiTexCoord1sARB = Sys_GLGetExtension ("glMultiTexCoord1sARB"); + qglMultiTexCoord1svARB = Sys_GLGetExtension ("glMultiTexCoord1svARB"); + qglMultiTexCoord2dARB = Sys_GLGetExtension ("glMultiTexCoord2dARB"); + qglMultiTexCoord2dvARB = Sys_GLGetExtension ("glMultiTexCoord2dvARB"); + qglMultiTexCoord2fARB = Sys_GLGetExtension ("glMultiTexCoord2fARB"); + qglMultiTexCoord2fvARB = Sys_GLGetExtension ("glMultiTexCoord2fvARB"); + qglMultiTexCoord2iARB = Sys_GLGetExtension ("glMultiTexCoord2iARB"); + qglMultiTexCoord2ivARB = Sys_GLGetExtension ("glMultiTexCoord2ivARB"); + qglMultiTexCoord2sARB = Sys_GLGetExtension ("glMultiTexCoord2sARB"); + qglMultiTexCoord2svARB = Sys_GLGetExtension ("glMultiTexCoord2svARB"); + qglMultiTexCoord3dARB = Sys_GLGetExtension ("glMultiTexCoord3dARB"); + qglMultiTexCoord3dvARB = Sys_GLGetExtension ("glMultiTexCoord3dvARB"); + qglMultiTexCoord3fARB = Sys_GLGetExtension ("glMultiTexCoord3fARB"); + qglMultiTexCoord3fvARB = Sys_GLGetExtension ("glMultiTexCoord3fvARB"); + qglMultiTexCoord3iARB = Sys_GLGetExtension ("glMultiTexCoord3iARB"); + qglMultiTexCoord3ivARB = Sys_GLGetExtension ("glMultiTexCoord3ivARB"); + qglMultiTexCoord3sARB = Sys_GLGetExtension ("glMultiTexCoord3sARB"); + qglMultiTexCoord3svARB = Sys_GLGetExtension ("glMultiTexCoord3svARB"); + qglMultiTexCoord4dARB = Sys_GLGetExtension ("glMultiTexCoord4dARB"); + qglMultiTexCoord4dvARB = Sys_GLGetExtension ("glMultiTexCoord4dvARB"); + qglMultiTexCoord4fARB = Sys_GLGetExtension ("glMultiTexCoord4fARB"); + qglMultiTexCoord4fvARB = Sys_GLGetExtension ("glMultiTexCoord4fvARB"); + qglMultiTexCoord4iARB = Sys_GLGetExtension ("glMultiTexCoord4iARB"); + qglMultiTexCoord4ivARB = Sys_GLGetExtension ("glMultiTexCoord4ivARB"); + qglMultiTexCoord4sARB = Sys_GLGetExtension ("glMultiTexCoord4sARB"); + qglMultiTexCoord4svARB = Sys_GLGetExtension ("glMultiTexCoord4svARB"); + } +} diff --git a/radiant/qgl.h b/radiant/qgl.h new file mode 100644 index 00000000..6f4decc6 --- /dev/null +++ b/radiant/qgl.h @@ -0,0 +1,600 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +** QGL.H +*/ + +#ifndef __QGL_H__ +#define __QGL_H__ + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=812 +#define ATIHACK_812 + +#include + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#if defined (__APPLE__) +#include +#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_VERSION_1_3 +// this is hacky, I'd recommend people having GL 1.3 headers instead +#define GL_COMPRESSED_RGBA 0x84EE +// RIANT +// this would be the appropriate place for this +#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 + +#ifdef __cplusplus +extern "C" { +#endif + +int QGL_Init( const char *dllname, const char* pGluName ); +void QGL_InitExtensions (); +void QGL_Shutdown(); + +// silent query, see Sys_QGL_ExtensionSupported +int GL_ExtensionSupported (const char *extension); + +#ifndef APIENTRY +# define APIENTRY +#endif + +extern void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +extern void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +extern GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +extern void ( APIENTRY * qglArrayElement )(GLint i); +extern void ( APIENTRY * qglBegin )(GLenum mode); +extern void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +extern void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +extern void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +extern void ( APIENTRY * qglCallList )(GLuint list); +extern void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +extern void ( APIENTRY * qglClear )(GLbitfield mask); +extern void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +extern void ( APIENTRY * qglClearDepth )(GLclampd depth); +extern void ( APIENTRY * qglClearIndex )(GLfloat c); +extern void ( APIENTRY * qglClearStencil )(GLint s); +extern void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +extern void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +extern void ( APIENTRY * qglColor3bv )(const GLbyte *v); +extern void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +extern void ( APIENTRY * qglColor3dv )(const GLdouble *v); +extern void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +extern void ( APIENTRY * qglColor3fv )(const GLfloat *v); +extern void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +extern void ( APIENTRY * qglColor3iv )(const GLint *v); +extern void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +extern void ( APIENTRY * qglColor3sv )(const GLshort *v); +extern void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +extern void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +extern void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +extern void ( APIENTRY * qglColor3uiv )(const GLuint *v); +extern void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +extern void ( APIENTRY * qglColor3usv )(const GLushort *v); +extern void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +extern void ( APIENTRY * qglColor4bv )(const GLbyte *v); +extern void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +extern void ( APIENTRY * qglColor4dv )(const GLdouble *v); +extern void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void ( APIENTRY * qglColor4fv )(const GLfloat *v); +extern void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +extern void ( APIENTRY * qglColor4iv )(const GLint *v); +extern void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +extern void ( APIENTRY * qglColor4sv )(const GLshort *v); +extern void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +extern void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +extern void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +extern void ( APIENTRY * qglColor4uiv )(const GLuint *v); +extern void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +extern void ( APIENTRY * qglColor4usv )(const GLushort *v); +extern void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +extern void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +extern void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +extern void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +extern void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +extern void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +extern void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +extern void ( APIENTRY * qglCullFace )(GLenum mode); +extern void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +extern void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +extern void ( APIENTRY * qglDepthFunc )(GLenum func); +extern void ( APIENTRY * qglDepthMask )(GLboolean flag); +extern void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +extern void ( APIENTRY * qglDisable )(GLenum cap); +extern void ( APIENTRY * qglDisableClientState )(GLenum array); +extern void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +extern void ( APIENTRY * qglDrawBuffer )(GLenum mode); +extern void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +extern void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +extern void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +extern void ( APIENTRY * qglEnable )(GLenum cap); +extern void ( APIENTRY * qglEnableClientState )(GLenum array); +extern void ( APIENTRY * qglEnd )(void); +extern void ( APIENTRY * qglEndList )(void); +extern void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +extern void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +extern void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +extern void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +extern void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +extern void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +extern void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +extern void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +extern void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +extern void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +extern void ( APIENTRY * qglEvalPoint1 )(GLint i); +extern void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +extern void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +extern void ( APIENTRY * qglFinish )(void); +extern void ( APIENTRY * qglFlush )(void); +extern void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +extern void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +extern void ( APIENTRY * qglFrontFace )(GLenum mode); +extern void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +extern GLuint ( APIENTRY * qglGenLists )(GLsizei range); +extern void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +extern void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +extern void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +extern void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +extern GLenum ( APIENTRY * qglGetError )(void); +extern void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +extern void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +extern void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +extern void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +extern void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +extern void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +extern void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +extern void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +extern const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +extern void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +extern void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +extern void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +extern void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +extern void ( APIENTRY * qglIndexMask )(GLuint mask); +extern void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglIndexd )(GLdouble c); +extern void ( APIENTRY * qglIndexdv )(const GLdouble *c); +extern void ( APIENTRY * qglIndexf )(GLfloat c); +extern void ( APIENTRY * qglIndexfv )(const GLfloat *c); +extern void ( APIENTRY * qglIndexi )(GLint c); +extern void ( APIENTRY * qglIndexiv )(const GLint *c); +extern void ( APIENTRY * qglIndexs )(GLshort c); +extern void ( APIENTRY * qglIndexsv )(const GLshort *c); +extern void ( APIENTRY * qglIndexub )(GLubyte c); +extern void ( APIENTRY * qglIndexubv )(const GLubyte *c); +extern void ( APIENTRY * qglInitNames )(void); +extern void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +extern GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +extern GLboolean ( APIENTRY * qglIsList )(GLuint list); +extern GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +extern void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +extern void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +extern void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +extern void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +extern void ( APIENTRY * qglLineWidth )(GLfloat width); +extern void ( APIENTRY * qglListBase )(GLuint base); +extern void ( APIENTRY * qglLoadIdentity )(void); +extern void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +extern void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +extern void ( APIENTRY * qglLoadName )(GLuint name); +extern void ( APIENTRY * qglLogicOp )(GLenum opcode); +extern void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +extern void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +extern void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +extern void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +extern void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +extern void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +extern void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +extern void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +extern void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +extern void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglMatrixMode )(GLenum mode); +extern void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +extern void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +extern void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +extern void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +extern void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +extern void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +extern void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +extern void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +extern void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +extern void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +extern void ( APIENTRY * qglNormal3iv )(const GLint *v); +extern void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +extern void ( APIENTRY * qglNormal3sv )(const GLshort *v); +extern void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +extern void ( APIENTRY * qglPassThrough )(GLfloat token); +extern void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +extern void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +extern void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +extern void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +extern void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +extern void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +extern void ( APIENTRY * qglPointSize )(GLfloat size); +extern void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +extern void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +extern void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +extern void ( APIENTRY * qglPopAttrib )(void); +extern void ( APIENTRY * qglPopClientAttrib )(void); +extern void ( APIENTRY * qglPopMatrix )(void); +extern void ( APIENTRY * qglPopName )(void); +extern void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +extern void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +extern void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +extern void ( APIENTRY * qglPushMatrix )(void); +extern void ( APIENTRY * qglPushName )(GLuint name); +extern void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +extern void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +extern void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +extern void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +extern void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +extern void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +extern void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +extern void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +extern void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +extern void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +extern void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +extern void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +extern void ( APIENTRY * qglReadBuffer )(GLenum mode); +extern void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +extern void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +extern void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +extern void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +extern void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +extern void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +extern void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +extern void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +extern void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +extern GLint ( APIENTRY * qglRenderMode )(GLenum mode); +extern void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +extern void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +extern void ( APIENTRY * qglShadeModel )(GLenum mode); +extern void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +extern void ( APIENTRY * qglStencilMask )(GLuint mask); +extern void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +extern void ( APIENTRY * qglTexCoord1d )(GLdouble s); +extern void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord1f )(GLfloat s); +extern void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord1i )(GLint s); +extern void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord1s )(GLshort s); +extern void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +extern void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +extern void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +extern void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +extern void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +extern void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +extern void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +extern void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +extern void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +extern void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +extern void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +extern void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +extern void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +extern void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +extern void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +extern void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +extern void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +extern void ( APIENTRY * qglVertex2iv )(const GLint *v); +extern void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +extern void ( APIENTRY * qglVertex2sv )(const GLshort *v); +extern void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +extern void ( APIENTRY * qglVertex3iv )(const GLint *v); +extern void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +extern void ( APIENTRY * qglVertex3sv )(const GLshort *v); +extern void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +extern void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +extern void ( APIENTRY * qglVertex4iv )(const GLint *v); +extern void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +extern void ( APIENTRY * qglVertex4sv )(const GLshort *v); +extern void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +extern void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +extern void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +extern void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); + +extern void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); +extern void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); + +extern void ( APIENTRY * qglActiveTextureARB) (GLenum texture); +extern void ( APIENTRY * qglClientActiveTextureARB) (GLenum texture); +extern void ( APIENTRY * qglMultiTexCoord1dARB) (GLenum target, GLdouble s); +extern void ( APIENTRY * qglMultiTexCoord1dvARB) (GLenum target, const GLdouble *v); +extern void ( APIENTRY * qglMultiTexCoord1fARB) (GLenum target, GLfloat s); +extern void ( APIENTRY * qglMultiTexCoord1fvARB) (GLenum target, const GLfloat *v); +extern void ( APIENTRY * qglMultiTexCoord1iARB) (GLenum target, GLint s); +extern void ( APIENTRY * qglMultiTexCoord1ivARB) (GLenum target, const GLint *v); +extern void ( APIENTRY * qglMultiTexCoord1sARB) (GLenum target, GLshort s); +extern void ( APIENTRY * qglMultiTexCoord1svARB) (GLenum target, const GLshort *v); +extern void ( APIENTRY * qglMultiTexCoord2dARB) (GLenum target, GLdouble s); +extern void ( APIENTRY * qglMultiTexCoord2dvARB) (GLenum target, const GLdouble *v); +extern void ( APIENTRY * qglMultiTexCoord2fARB) (GLenum target, GLfloat s); +extern void ( APIENTRY * qglMultiTexCoord2fvARB) (GLenum target, const GLfloat *v); +extern void ( APIENTRY * qglMultiTexCoord2iARB) (GLenum target, GLint s); +extern void ( APIENTRY * qglMultiTexCoord2ivARB) (GLenum target, const GLint *v); +extern void ( APIENTRY * qglMultiTexCoord2sARB) (GLenum target, GLshort s); +extern void ( APIENTRY * qglMultiTexCoord2svARB) (GLenum target, const GLshort *v); +extern void ( APIENTRY * qglMultiTexCoord3dARB) (GLenum target, GLdouble s); +extern void ( APIENTRY * qglMultiTexCoord3dvARB) (GLenum target, const GLdouble *v); +extern void ( APIENTRY * qglMultiTexCoord3fARB) (GLenum target, GLfloat s); +extern void ( APIENTRY * qglMultiTexCoord3fvARB) (GLenum target, const GLfloat *v); +extern void ( APIENTRY * qglMultiTexCoord3iARB) (GLenum target, GLint s); +extern void ( APIENTRY * qglMultiTexCoord3ivARB) (GLenum target, const GLint *v); +extern void ( APIENTRY * qglMultiTexCoord3sARB) (GLenum target, GLshort s); +extern void ( APIENTRY * qglMultiTexCoord3svARB) (GLenum target, const GLshort *v); +extern void ( APIENTRY * qglMultiTexCoord4dARB) (GLenum target, GLdouble s); +extern void ( APIENTRY * qglMultiTexCoord4dvARB) (GLenum target, const GLdouble *v); +extern void ( APIENTRY * qglMultiTexCoord4fARB) (GLenum target, GLfloat s); +extern void ( APIENTRY * qglMultiTexCoord4fvARB) (GLenum target, const GLfloat *v); +extern void ( APIENTRY * qglMultiTexCoord4iARB) (GLenum target, GLint s); +extern void ( APIENTRY * qglMultiTexCoord4ivARB) (GLenum target, const GLint *v); +extern void ( APIENTRY * qglMultiTexCoord4sARB) (GLenum target, GLshort s); +extern void ( APIENTRY * qglMultiTexCoord4svARB) (GLenum target, const GLshort *v); + + + +#ifdef _WIN32 + +extern int ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *); +extern int ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); +extern int ( WINAPI * qwglGetPixelFormat)(HDC); +extern BOOL ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); +extern BOOL ( WINAPI * qwglSwapBuffers)(HDC); + +extern BOOL ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT); +extern HGLRC ( WINAPI * qwglCreateContext)(HDC); +extern HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int); +extern BOOL ( WINAPI * qwglDeleteContext)(HGLRC); +extern HGLRC ( WINAPI * qwglGetCurrentContext)(VOID); +extern HDC ( WINAPI * qwglGetCurrentDC)(VOID); +extern PROC ( WINAPI * qwglGetProcAddress)(LPCSTR); +extern BOOL ( WINAPI * qwglMakeCurrent)(HDC, HGLRC); +extern BOOL ( WINAPI * qwglShareLists)(HGLRC, HGLRC); +extern BOOL ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD); + +extern BOOL ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT, + FLOAT, int, LPGLYPHMETRICSFLOAT); + +extern BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT, + LPLAYERPLANEDESCRIPTOR); +extern int ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int, + CONST COLORREF *); +extern int ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int, + COLORREF *); +extern BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL); +extern BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT); + +extern BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval ); + +extern BOOL ( WINAPI * qwglGetDeviceGammaRampEXT ) ( unsigned char *pRed, unsigned char *pGreen, unsigned char *pBlue ); +extern BOOL ( WINAPI * qwglSetDeviceGammaRampEXT ) ( const unsigned char *pRed, const unsigned char *pGreen, const unsigned char *pBlue ); + +#endif + +#if defined (__linux__) || defined (__APPLE__) +extern XVisualInfo* (*qglXChooseVisual)(Display *dpy, int screen, int *attribList); +extern GLXContext (*qglXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +extern void (*qglXDestroyContext)(Display *dpy, GLXContext ctx); +extern Bool (*qglXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx); +extern void (*qglXCopyContext)(Display *dpy, GLXContext src, GLXContext dst, GLuint mask); +extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); +extern GLXPixmap (*qglXCreateGLXPixmap)( Display *dpy, XVisualInfo *visual, Pixmap pixmap ); +extern void (*qglXDestroyGLXPixmap)( Display *dpy, GLXPixmap pixmap ); +extern Bool (*qglXQueryExtension)( Display *dpy, int *errorb, int *event ); +extern Bool (*qglXQueryVersion)( Display *dpy, int *maj, int *min ); +extern Bool (*qglXIsDirect)( Display *dpy, GLXContext ctx ); +extern int (*qglXGetConfig)( Display *dpy, XVisualInfo *visual, int attrib, int *value ); +extern GLXContext (*qglXGetCurrentContext)( void ); +extern GLXDrawable (*qglXGetCurrentDrawable)( void ); +extern void (*qglXWaitGL)( void ); +extern void (*qglXWaitX)( void ); +extern void (*qglXUseXFont)( Font font, int first, int count, int list ); +extern void* (*qglXGetProcAddressARB) (const GLubyte *procName); +#endif + +#ifdef ATIHACK_812 +extern void ( APIENTRY * qglCullFace_real )(GLenum mode); +extern void ( APIENTRY * qglDisable_real )(GLenum cap); +extern void ( APIENTRY * qglEnable_real )(GLenum cap); +extern void ( APIENTRY * qglPolygonMode_real )(GLenum face, GLenum mode); + +extern void APIENTRY qglCullFace_ATIHack(GLenum mode); +extern void APIENTRY qglDisable_ATIHack(GLenum cap); +extern void APIENTRY qglEnable_ATIHack(GLenum cap); +extern void APIENTRY qglPolygonMode_ATIHack(GLenum face, GLenum mode); +#endif + +// glu stuff.. radiant only uses a couple +extern void (APIENTRY* qgluPerspective) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); +extern void (APIENTRY* qgluLookAt)( + GLdouble eyex, + GLdouble eyey, + GLdouble eyez, + GLdouble centerx, + GLdouble centery, + GLdouble centerz, + GLdouble upx, + GLdouble upy, + GLdouble upz); +extern const GLubyte * (APIENTRY * qgluErrorString) (GLenum errCode ); + + +// end of glu stuff + + +/* +** extension constants +*/ +#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 + +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB + +#define GL_TEXTURE0_SGIS 0x835E +#define GL_TEXTURE1_SGIS 0x835F + + +#ifdef __cplusplus +} +#endif // extern "C" + +// ------------------------------------------------------------------------------------------- +// qgl_ext.cpp API +// ------------------------------------------------------------------------------------------- + +int Sys_QGL_ExtensionSupported (const char *extension); + +#endif diff --git a/radiant/qgl_ext.cpp b/radiant/qgl_ext.cpp new file mode 100644 index 00000000..8361ebbe --- /dev/null +++ b/radiant/qgl_ext.cpp @@ -0,0 +1,46 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +** qgl_ext.cpp +** +** TTimo +** I wanted a C++ file for some new qgl stuff +*/ + +#include "stdafx.h" + +int Sys_QGL_ExtensionSupported (const char *extension) +{ + int ret; + + Sys_Printf("Checking for extension '%s'...", extension); + ret = GL_ExtensionSupported(extension); + if (ret) + { + Sys_Printf("Found\n"); + } + else + { + Sys_Printf("Not Found\n"); + } + return ret; +} diff --git a/radiant/queuedraw.cpp b/radiant/queuedraw.cpp new file mode 100644 index 00000000..0e1bfb30 --- /dev/null +++ b/radiant/queuedraw.cpp @@ -0,0 +1,158 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Try to sort the faces by texture and make rendering faster +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" + +typedef struct +{ + qtexture_t* texture; + GPtrArray* faces; +} windingsort_t; + +static windingsort_t* sort; +static guint32 alloc, len; +static GPtrArray* notex_faces; + +void QueueClear () +{ + len = 0; + + if (notex_faces == NULL) + notex_faces = g_ptr_array_new (); + g_ptr_array_set_size (notex_faces, 0); +} + +void QueueFace (face_t *face) +{ + guint32 i; + + if (face->d_texture->name[0] == '(') + { + g_ptr_array_add (notex_faces, face); + return; + } + + for (i = 0; i < len; i++) + if (sort[i].texture == face->d_texture) + { + g_ptr_array_add (sort[i].faces, face); + return; + } + + if (len == alloc) + { + alloc += 8; + sort = (windingsort_t*)realloc (sort, alloc*sizeof(windingsort_t)); + + for (i = len; i < alloc; i++) + sort[i].faces = g_ptr_array_new (); + } + g_ptr_array_set_size (sort[len].faces, 0); + g_ptr_array_add (sort[len].faces, face); + sort[len].texture = face->d_texture; + len++; +} + +void QueueDraw () +{ + guint32 i, k; + face_t *face; + winding_t *w; + int j, nDrawMode = g_pParentWnd->GetCamera().draw_mode; + + if (notex_faces->len) + { + qglDisable (GL_TEXTURE_2D); + + for (i = 0; i < notex_faces->len; i++) + { + face = (face_t*)notex_faces->pdata[i]; + w = face->face_winding; + + qglBegin (GL_POLYGON); + + /* + if (b->patchBrush) + //++timo FIXME: find a use case for this?? + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); + else + */ + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans ()); + + if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv (face->plane.normal); + + for (j = 0; j < w->numpoints; j++) + { + if (nDrawMode == cd_texture || nDrawMode == cd_light) + qglTexCoord2fv( &w->points[j][3] ); + qglVertex3fv(w->points[j]); + } + + qglEnd (); + } + } + + if (!len) + return; + + if (nDrawMode == cd_texture || nDrawMode == cd_light) + qglEnable (GL_TEXTURE_2D); + + for (k = 0; k < len; k++) + { + qglBindTexture (GL_TEXTURE_2D, sort[k].texture->texture_number); + + for (i = 0; i < sort[k].faces->len; i++) + { + face = (face_t*)sort[k].faces->pdata[i]; + w = face->face_winding; + + qglBegin (GL_POLYGON); + /* + if (b->patchBrush) + //++timo FIXME: find a use case for this?? + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); + else + */ + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans ()); + + if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv (face->plane.normal); + + for (j = 0; j < w->numpoints; j++) + { + if (nDrawMode == cd_texture || nDrawMode == cd_light) + qglTexCoord2fv( &w->points[j][3] ); + qglVertex3fv(w->points[j]); + } + + qglEnd (); + } + } + qglBindTexture (GL_TEXTURE_2D, 0); +} diff --git a/radiant/radiant.ico b/radiant/radiant.ico new file mode 100644 index 0000000000000000000000000000000000000000..cca8503f29cc380b4e6cfb47603492ee03ea0198 GIT binary patch literal 1078 zcmbtTy-wUf5dQYq6mH;FvLd$PXb=qr4*<83-17*jqk94*BwIAs+NB$K3?wLUNrkBB z5k*o)>5>pH-*|T~;dCNGj6FZ!%;s}?Y zO-W+zYN`OfsH&hSX`<^oY69lr&K`S355j!rCe2~P2;}8fIDe=GS3&)-4A?dJx%;$N` ze?jT|7fu4sfcJeF_}6Fe6aP5!{xv>z{`<&nbR)Mm@5_hlzWj6Emp{Mu-Zcex zgOLU#>4rza*rsU=j4_HcBDu1T100+0icdKkhC;i%V6zH9dL>KaIbxzOfv2fePgBu} eiMLok|9PRq6PukK19u;Q8~Sb!Y$ogEH+=>l`@}5( literal 0 HcmV?d00001 diff --git a/radiant/radiant.rc b/radiant/radiant.rc new file mode 100644 index 00000000..b38337f7 --- /dev/null +++ b/radiant/radiant.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_RADIANT ICON DISCARDABLE "radiant.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/radiant/radiant.vcproj b/radiant/radiant.vcproj new file mode 100644 index 00000000..481dcb1e --- /dev/null +++ b/radiant/radiant.vcproj @@ -0,0 +1,991 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/radiant/resource.h b/radiant/resource.h new file mode 100644 index 00000000..770c06b9 --- /dev/null +++ b/radiant/resource.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Q3Radiant.rc +// +#define IDI_RADIANT 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/radiant/select.cpp b/radiant/select.cpp new file mode 100644 index 00000000..72637684 --- /dev/null +++ b/radiant/select.cpp @@ -0,0 +1,2125 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// select.c +#include "stdafx.h" +#include +#include "filters.h" + +// externs +CPtrArray g_SelectedFaces; +CPtrArray g_SelectedFaceBrushes; +CPtrArray& g_ptrSelectedFaces = g_SelectedFaces; +CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes; + +/* +=========== +Test_Ray +=========== +*/ +#define DIST_START 999999 +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags) +{ + brush_t *brush; + face_t *face; + float dist; + trace_t t; + + memset (&t, 0, sizeof(t)); + t.dist = DIST_START; + + if (flags & SF_CYCLE) + { + CPtrArray array; + brush_t *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL; + Select_Deselect(); + + // go through active brushes and accumulate all "hit" brushes + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + //if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) + // continue; + + if (brush->bFiltered) + continue; + + if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) + continue; + + if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) + continue; + + //if (!g_bShowPatchBounds && brush->patchBrush) + // continue; + + face = Brush_Ray (origin, dir, brush, &dist, flags); + + if (face) + array.Add(brush); + } + + int nSize = array.GetSize(); + if (nSize > 0) + { + bool bFound = false; + for (int i = 0; i < nSize; i++) + { + brush_t *b = reinterpret_cast(array.GetAt(i)); + // did we hit the last one selected yet ? + if (b == pToSelect) + { + // yes we want to select the next one in the list + int n = (i > 0) ? i-1 : nSize-1; + pToSelect = reinterpret_cast(array.GetAt(n)); + bFound = true; + break; + } + } + if (!bFound) + pToSelect = reinterpret_cast(array.GetAt(0)); + } + if (pToSelect) + { + face = Brush_Ray (origin, dir, pToSelect, &dist, flags); + t.dist = dist; + t.brush = pToSelect; + t.face = face; + t.selected = false; + return t; + } + } + + if (! (flags & SF_SELECTED_ONLY) ) + { + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && (brush->owner == world_entity || !brush->owner->eclass->fixedsize)) + continue; + + if (brush->bFiltered) + continue; + + if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) + continue; + + if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) + continue; + + //if (!g_bShowPatchBounds && brush->patchBrush) + // continue; + + face = Brush_Ray (origin, dir, brush, &dist, flags); + if (face && dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = false; + } + } + } + + + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && (brush->owner == world_entity || !brush->owner->eclass->fixedsize)) + continue; + + if (brush->bFiltered) + continue; + + if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) + continue; + + if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) + continue; + + face = Brush_Ray (origin, dir, brush, &dist, flags); + if (dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = true; + } + } + + // if entites first, but didn't find any, check regular + + if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) + return Test_Ray (origin, dir, flags & ~SF_ENTITIES_FIRST); + + return t; + +} + + +/* +============ +Select_Brush + +============ +*/ +void Select_Brush (brush_t *brush, bool bComplete, bool bStatus) +{ + brush_t *b; + entity_t *e; + + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + if (g_qeglobals.d_select_count < 2) + g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush; + g_qeglobals.d_select_count++; + + e = brush->owner; + if (e) + { + // select complete entity on first click + if (e != world_entity && bComplete == true) + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (b->owner == e) + goto singleselect; + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + if( b == brush ) // make sure we add the actual selected brush last, mainly for cycle select + continue; + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + Brush_RemoveFromList (brush); + Brush_AddToList (brush, &selected_brushes); + } + else + { + singleselect: + Brush_RemoveFromList (brush); + Brush_AddToList (brush, &selected_brushes); + UpdatePatchInspector(); + } + + if (e->eclass) + { + UpdateEntitySel(brush->owner->eclass); + } + + UpdateSurfaceDialog(); + } + + if (bStatus) + { + vec3_t vMin, vMax, vSize; + Select_GetBounds (vMin, vMax); + VectorSubtract(vMax, vMin, vSize); + CString strStatus; + strStatus.Format("Selection X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]); + g_pParentWnd->SetStatusText(2, strStatus); + } +} + +/* +============= +Select_FaceInSelectedBrushes +============= +*/ +bool Select_FaceInSelectedBrushes( face_t *face ) +{ + brush_t *brush; + face_t *tface; + + for(brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) + { + for(tface = brush->brush_faces; tface; tface = tface->next) + { + if(tface == face) + { + return true; + } + } + } + + return false; +} + +/* +============ +Select_Ray + +If the origin is inside a brush, that brush will be ignored. +============ +*/ +void Select_Ray (vec3_t origin, vec3_t dir, int flags) +{ + trace_t t; + face_t *tface; + bool bOk; + static trace_t lastTrace = { + NULL, // brush + NULL, // face + 0, // dist + false // selected + }; + + t = Test_Ray (origin, dir, flags); + if (!t.brush) + return; + + if (flags & SF_SINGLEFACE) + { + if( flags & SF_DRAG ) + { + if ( t.brush == lastTrace.brush && t.face == lastTrace.face ) + return; + } + lastTrace = t; + + if(Select_FaceInSelectedBrushes(t.face)) + { + // Deselect the brush + Brush_RemoveFromList (t.brush); + Brush_AddToList (t.brush, &active_brushes); + UpdatePatchInspector(); + + // Select all of the brush's faces except the one we are pointing at + for( tface = t.brush->brush_faces; tface; tface = tface->next ) + { + if( tface == t.face ) + continue; + + bOk = true; + // NOTE: keep the size check in the loop, we remove stuff inside + for (int i = 0; i < g_SelectedFaces.GetSize(); i++) + { + if (tface == reinterpret_cast(g_SelectedFaces.GetAt(i))) + bOk = false; + } + + if(bOk) + { + g_SelectedFaces.Add(tface); + g_SelectedFaceBrushes.Add(t.brush); + } + } + g_qeglobals.d_select_mode = sel_facets_off; + } + else + { + bOk = true; + // NOTE: keep the size check in the loop, we remove stuff inside + for (int i = 0; i < g_SelectedFaces.GetSize(); i++) + { + if (t.face == reinterpret_cast(g_SelectedFaces.GetAt(i))) + { + bOk = false; + if( flags & SF_DRAG_ON ) + continue; + + g_qeglobals.d_select_mode = sel_facets_off; + // need to remove i'th entry + g_SelectedFaces.RemoveAt(i, 1); + g_SelectedFaceBrushes.RemoveAt(i, 1); + } + } + + if (bOk && !(flags & SF_DRAG_OFF)) + { + g_SelectedFaces.Add(t.face); + g_SelectedFaceBrushes.Add(t.brush); + g_qeglobals.d_select_mode = sel_facets_on; + } + } + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); + //g_qeglobals.d_select_mode = sel_brush; + // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture + brushprimit_texdef_t brushprimit_texdef; + ConvertTexMatWithQTexture ( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL ); + Texture_SetTexture ( &t.face->texdef, &brushprimit_texdef, false, NULL, false ); + return; + } + + // move the brush to the other list + if (t.selected) + { + if( flags & SF_DRAG_ON ) + return; + + g_qeglobals.d_select_mode = sel_brush_off; + Brush_RemoveFromList (t.brush); + Brush_AddToList (t.brush, &active_brushes); + + UpdatePatchInspector(); + } + else + { + if( flags & SF_DRAG_OFF ) + return; + + g_qeglobals.d_select_mode = sel_brush_on; + Select_Brush (t.brush, g_PrefsDlg.m_nCamDragMultiSelect == 1 ? Sys_AltDown () : !Sys_AltDown ()); + } + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); +} + + +void Select_Delete (void) +{ + brush_t *brush; + entity_t *e; + + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + + g_qeglobals.d_select_mode = sel_brush; + + g_qeglobals.d_select_count = 0; + g_qeglobals.d_num_move_points = 0; + while (selected_brushes.next != &selected_brushes) + { + brush = selected_brushes.next; + if (brush->patchBrush) + { + Patch_Delete(brush->pPatch); + } + e = brush->owner; + Brush_Free (brush); + // remove if no brushes + if (e != world_entity && e->brushes.onext == &e->brushes) + Entity_Free(e); + } + + Sys_MarkMapModified (); + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); +} + +// update the workzone to a given brush +void UpdateWorkzone_ForBrush( brush_t* b ) +{ + VectorCopy( b->mins, g_qeglobals.d_work_min ); + VectorCopy( b->maxs, g_qeglobals.d_work_max ); + //++timo clean +#if 0 + // will update the workzone to the given brush + // g_pParentWnd->ActiveXY()->GetViewType() + // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; + // we fit our work zone to the last brush on the list (b) + int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim1 = (nViewType == YZ) ? 1 : 0; + int nDim2 = (nViewType == XY) ? 1 : 2; + g_qeglobals.d_work_min[nDim1] = b->mins[nDim1]; + g_qeglobals.d_work_max[nDim1] = b->maxs[nDim1]; + g_qeglobals.d_work_min[nDim2] = b->mins[nDim2]; + g_qeglobals.d_work_max[nDim2] = b->maxs[nDim2]; +#endif +} + +// here to filter new brushes once unselected +extern void PerformFiltering(); + +void Select_Deselect (bool bDeselectFaces) +{ + brush_t *b; + + Patch_Deselect(); + + g_pParentWnd->ActiveXY()->UndoClear(); + + g_qeglobals.d_workcount++; + g_qeglobals.d_select_count = 0; + g_qeglobals.d_num_move_points = 0; + b = selected_brushes.next; + + if (b == &selected_brushes) + { + if (bDeselectFaces) + { + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + } + PerformFiltering(); + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); + return; + } + + if (bDeselectFaces) + { + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + } + + g_qeglobals.d_select_mode = sel_brush; + + UpdateWorkzone_ForBrush(b); + + selected_brushes.next->prev = &active_brushes; + selected_brushes.prev->next = active_brushes.next; + active_brushes.next->prev = selected_brushes.prev; + active_brushes.next = selected_brushes.next; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + + // filter newly created stuff once it's unselected + PerformFiltering(); + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); +} + +/* +============ +Select_Move +============ +*/ +/*! Moves the currently selected brush/patch + \param delta How far to move the selection (x,y,z) + \param bSnap If the move should snap to grid points +*/ +void Select_Move (vec3_t delta, bool bSnap) +{ + brush_t *b; + + // actually move the selected brushes + for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next) + Brush_Move (b, delta, bSnap); + + vec3_t vMin, vMax; + Select_GetBounds (vMin, vMax); + CString strStatus; + strStatus.Format("Origin X:: %.1f Y:: %.1f Z:: %.1f", vMin[0], vMax[1], vMax[2]); + g_pParentWnd->SetStatusText(2, strStatus); + + //Sys_UpdateWindows (W_ALL); +} + +/* +================= +Select_NudgeVerts +================= +*/ +/*! Moves the currently selected brush/patch vertices + \param delta How far to move the vertices (x,y,z) + \param bSnap If the move should snap to grid points +*/ +void Select_NudgePoint(vec3_t delta, qboolean bSnap) +{ + if (g_qeglobals.d_select_mode == sel_vertex) + { + // move selected verts + brush_t *b; + vec3_t end; + qboolean success = true; + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + success &= (qboolean)Brush_MoveVertex(b, g_qeglobals.d_move_points[0], delta, end, bSnap); + } + if (success) + VectorCopy(end, g_qeglobals.d_move_points[0]); + } + else if (g_qeglobals.d_select_mode == sel_curvepoint) + { + // move selected patch control points + Patch_UpdateSelected(delta); + } +} + +/* +============ +Select_Clone + +Creates an exact duplicate of the selection in place, then moves +the selected brushes off of their old positions +============ +*/ +void Select_Clone (void) +{ + g_bScreenUpdates = false; + g_pParentWnd->Copy(); + Select_Deselect(); + g_pParentWnd->Paste(); + g_pParentWnd->NudgeSelection(2, g_qeglobals.d_gridsize); + g_pParentWnd->NudgeSelection(3, g_qeglobals.d_gridsize); + Undo_Start("clone"); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); +} + +//++timo clean +#if 0 +/* +============ +Select_SetTexture +Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping +Timo : brush primitive texturing + the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes ) +Timo : texture plugin, added an IPluginTexdef* parameter + must be casted to an IPluginTexdef! + if not NULL, get ->Copy() of it into each face or brush ( and remember to hook ) + if NULL, means we have no information, ask for a default +TTimo - shader code cleanup + added IShader* parameter +============ +*/ +void WINAPI Select_SetTexture2 (IShader* pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ) +{ + brush_t *b; + int nCount = g_ptrSelectedFaces.GetSize(); + if (nCount > 0) + { + Undo_Start("set face textures"); + ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize()); + for (int i = 0; i < nCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + Undo_AddBrush(selBrush); + //++timo TODO: propagate the IShader* .. + SetFaceTexdef (selFace, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Brush_Build(selBrush, bFitScale); + Undo_EndBrush(selBrush); + } + Undo_End(); + } + else if (selected_brushes.next != &selected_brushes) + { + Undo_Start("set brush textures"); + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (!b->owner->eclass->fixedsize) + { + Undo_AddBrush(b); + Brush_SetTexture2 (b, pShader, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Undo_EndBrush(b); + } + Undo_End(); + } + Sys_UpdateWindows (W_ALL); +} +#endif + +/* +============ +Select_SetTexture +Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping +Timo : brush primitive texturing + the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes ) +Timo : texture plugin, added an IPluginTexdef* parameter + must be casted to an IPluginTexdef! + if not NULL, get ->Copy() of it into each face or brush ( and remember to hook ) + if NULL, means we have no information, ask for a default +============ +*/ +void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ) +{ + /* +#ifdef _DEBUG + static int count = 0; +#endif + */ + brush_t *b; + /* +#ifdef _DEBUG + count++; + Sys_Printf("count: %d\n", count); + if(count==4) + Sys_Printf("break!\n"); +#endif + */ + int nCount = g_ptrSelectedFaces.GetSize(); + if (nCount > 0) + { + Undo_Start("set face textures"); + assert(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize()); + for (int i = 0; i < nCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + Undo_AddBrush(selBrush); + SetFaceTexdef (selFace, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Brush_Build(selBrush, bFitScale); + Undo_EndBrush(selBrush); + } + Undo_End(); + } + else if (selected_brushes.next != &selected_brushes) + { + Undo_Start("set brush textures"); + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (!b->owner->eclass->fixedsize) + { + Undo_AddBrush(b); + Brush_SetTexture (b, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Undo_EndBrush(b); + } + Undo_End(); + } + //++timo FIXME: not necessary in every cases, write a message defering / move one level up + Sys_UpdateWindows (W_ALL); +} + + +/* +================================================================ + + TRANSFORMATIONS + +================================================================ +*/ + +void Select_GetBounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + + for (i=0 ; i<3 ; i++) + { + mins[i] = 99999; + maxs[i] = -99999; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (b->owner->eclass->fixedsize) + { + for (i=0 ; i<3 ; i++) + { + if (b->owner->origin[i] < mins[i]) + mins[i] = b->owner->origin[i]; + if (b->owner->origin[i] > maxs[i]) + maxs[i] = b->owner->origin[i]; + } + } + else + { + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] < mins[i]) + mins[i] = b->mins[i]; + if (b->maxs[i] > maxs[i]) + maxs[i] = b->maxs[i]; + } + } + } +} + +void Select_GetTrueMid (vec3_t mid) +{ + vec3_t mins, maxs; + Select_GetBounds (mins, maxs); + + for (int i=0 ; i<3 ; i++) + mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2)); +} + +void Select_GetMid (vec3_t mid) +{ + vec3_t mins, maxs; + int i; + + if (g_PrefsDlg.m_bNoClamp) + { + Select_GetTrueMid(mid); + return; + } + + Select_GetBounds (mins, maxs); + + for (i=0 ; i<3 ; i++) + mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize ); +} + +vec3_t select_origin; +vec3_t select_matrix[3]; +qboolean select_fliporder; + +// FIXME: bApplyBPrimit is supposed to be temporary +// TODO: manage Brush_Build calls, too many of them with the texture processing +// FIXME: the undo doesn't seem to work correctly on texturing and flip/rotate operations?? this is not supposed to be related to the texture locking code, so what is happening? +// FIXME: ApplyMatrix works on flipping operation, b0rks on Rotations (so does the "regular" rotation code??) +// FIXME: what is getting called in free rotation mode? that used to work right? +void Select_ApplyMatrix (bool bSnap, bool bRotation, int nAxis, float fDeg)//, qboolean bApplyBPrimit) +{ + brush_t *b; + face_t *f; + int i, j; + vec3_t temp, tmporigin; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->owner->eclass->fixedsize) + { + VectorCopy (b->owner->origin, tmporigin); + // transform the origin point + VectorSubtract (b->owner->origin, select_origin, temp); + for (j=0 ; j<3 ; j++) + b->owner->origin[j] = DotProduct(temp, select_matrix[j]) + select_origin[j]; + + // update the origin key + char text[64]; + sprintf (text, "%i %i %i", + (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); + SetKeyValue(b->owner, "origin", text); + + /*\todo remove brush-based bounding box for fixedsize entities */ + VectorSubtract (b->owner->origin, tmporigin, temp); + for (f=b->brush_faces ; f ; f=f->next) + { + // move fixedsize bbox to new origin + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], temp, f->planepts[i]); + } + Brush_Build(b, bSnap,true,false,false); // don't filter + + } + else if (b->patchBrush) + { + if (!bRotation && !((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode)) + // invert patch if this is a mirroring operation, unless points are selected or bendmode is active + patchInvert(b->pPatch); + // NOTE: does not clamp points to integers + Patch_ApplyMatrix(b->pPatch, select_origin, select_matrix, false); + } + else + { + for (f=b->brush_faces ; f ; f=f->next) + { + // FIXME: only in BP mode! + // if we are using Brush Primitives texturing, we need to compute the texture matrix after the geometric transformation + // (with the default texturing you don't need to compute anything for flipping and mirroring operations) + // if (bApplyBPrimit) { + // ApplyMatrix_BrushPrimit (f, select_matrix, select_origin, select_fliporder); + // } + for (i=0 ; i<3 ; i++) + { + VectorSubtract (f->planepts[i], select_origin, temp); + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + select_origin[j]; + } + if (select_fliporder) + { + VectorCopy (f->planepts[0], temp); + VectorCopy (f->planepts[2], f->planepts[0]); + VectorCopy (temp, f->planepts[2]); + } + } + Brush_Build(b, bSnap,true,false,false); // don't filter + } + } +} + +void ProjectOnPlane(vec3_t& normal,float dist,vec3_t& ez, vec3_t& p) +{ + if (fabs(ez[0]) == 1) + p[0] = (dist - normal[1] * p[1] - normal[2] * p[2]) / normal[0]; + else if (fabs(ez[1]) == 1) + p[1] = (dist - normal[0] * p[0] - normal[2] * p[2]) / normal[1]; + else + p[2] = (dist - normal[0] * p[0] - normal[1] * p[1]) / normal[2]; +} + +void Back(vec3_t& dir, vec3_t& p) +{ + if (fabs(dir[0]) == 1) + p[0] = 0; + else if (fabs(dir[1]) == 1) + p[1] = 0; + else p[2] = 0; +} + + + +// using scale[0] and scale[1] +void ComputeScale(vec3_t& rex, vec3_t& rey, vec3_t& p, face_t* f) +{ + float px = DotProduct(rex, p); + float py = DotProduct(rey, p); + px *= f->texdef.scale[0]; + py *= f->texdef.scale[1]; + vec3_t aux; + VectorCopy(rex, aux); + VectorScale(aux, px, aux); + VectorCopy(aux, p); + VectorCopy(rey, aux); + VectorScale(aux, py, aux); + VectorAdd(p, aux, p); +} + +void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) +{ + vec3_t ex,ey,ez; // local axis base + +#ifdef _DEBUG + if (g_qeglobals.m_bBrushPrimitMode) + Sys_Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n"); +#endif + + // compute first local axis base + TextureAxisFromPlane(&f->plane, ex, ey); + CrossProduct(ex, ey, ez); + + vec3_t aux; + VectorCopy(ex, aux); + VectorScale(aux, -f->texdef.shift[0], aux); + VectorCopy(aux, p1); + VectorCopy(ey, aux); + VectorScale(aux, -f->texdef.shift[1], aux); + VectorAdd(p1, aux, p1); + VectorCopy(p1, p2); + VectorAdd(p2, ex, p2); + VectorCopy(p1, p3); + VectorAdd(p3, ey, p3); + VectorCopy(ez, aux); + VectorScale(aux, -f->texdef.rotate, aux); + VectorRotate(p1, aux, p1); + VectorRotate(p2, aux, p2); + VectorRotate(p3, aux, p3); + // computing rotated local axis base + vec3_t rex,rey; + VectorCopy(ex, rex); + VectorRotate(rex, aux, rex); + VectorCopy(ey, rey); + VectorRotate(rey, aux, rey); + + ComputeScale(rex,rey,p1,f); + ComputeScale(rex,rey,p2,f); + ComputeScale(rex,rey,p3,f); + + // project on normal plane + // along ez + // assumes plane normal is normalized + ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1); + ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2); + ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3); +}; + + +void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) +{ + vec3_t ex,ey,ez; + +#ifdef _DEBUG + if (g_qeglobals.m_bBrushPrimitMode) + Sys_Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n"); +#endif + + // computing new local axis base + TextureAxisFromPlane(&normal2, ex, ey); + CrossProduct(ex, ey, ez); + + // projecting back on (ex,ey) + Back(ez,p1); + Back(ez,p2); + Back(ez,p3); + + vec3_t aux; + // rotation + VectorCopy(p2, aux); + VectorSubtract(aux, p1,aux); + + float x = DotProduct(aux,ex); + float y = DotProduct(aux,ey); + f->texdef.rotate = 180 * atan2(y,x) / Q_PI; + + vec3_t rex,rey; + // computing rotated local axis base + VectorCopy(ez, aux); + VectorScale(aux, f->texdef.rotate, aux); + VectorCopy(ex, rex); + VectorRotate(rex, aux, rex); + VectorCopy(ey, rey); + VectorRotate(rey, aux, rey); + + // scale + VectorCopy(p2, aux); + VectorSubtract(aux, p1, aux); + f->texdef.scale[0] = DotProduct(aux, rex); + VectorCopy(p3, aux); + VectorSubtract(aux, p1, aux); + f->texdef.scale[1] = DotProduct(aux, rey); + + // shift + // only using p1 + x = DotProduct(rex,p1); + y = DotProduct(rey,p1); + x /= f->texdef.scale[0]; + y /= f->texdef.scale[1]; + + VectorCopy(rex, p1); + VectorScale(p1, x, p1); + VectorCopy(rey, aux); + VectorScale(aux, y, aux); + VectorAdd(p1, aux, p1); + VectorCopy(ez, aux); + VectorScale(aux, -f->texdef.rotate, aux); + VectorRotate(p1, aux, p1); + f->texdef.shift[0] = -DotProduct(p1, ex); + f->texdef.shift[1] = -DotProduct(p1, ey); + + // stored rot is good considering local axis base + // change it if necessary + f->texdef.rotate = -f->texdef.rotate; + + Clamp(f->texdef.shift[0], f->d_texture->width); + Clamp(f->texdef.shift[1], f->d_texture->height); + Clamp(f->texdef.rotate, 360); + +} + +void RotateFaceTexture(face_t* f, int nAxis, float fDeg) +{ + vec3_t p1,p2,p3, rota; + p1[0] = p1[1] = p1[2] = 0; + VectorCopy(p1, p2); + VectorCopy(p1, p3); + VectorCopy(p1, rota); + ComputeAbsolute(f, p1, p2, p3); + + rota[nAxis] = fDeg; + VectorRotateOrigin (p1, rota, select_origin, p1); + VectorRotateOrigin (p2, rota, select_origin, p2); + VectorRotateOrigin (p3, rota, select_origin, p3); + + plane_t normal2; + vec3_t vNormal; + vNormal[0] = f->plane.normal[0]; + vNormal[1] = f->plane.normal[1]; + vNormal[2] = f->plane.normal[2]; + VectorRotate(vNormal, rota, vNormal); + normal2.normal[0] = vNormal[0]; + normal2.normal[1] = vNormal[1]; + normal2.normal[2] = vNormal[2]; + AbsoluteToLocal(normal2, f, p1, p2 ,p3); + +} + +void RotateTextures(int nAxis, float fDeg, vec3_t vOrigin) +{ + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + RotateFaceTexture_BrushPrimit (f, nAxis, fDeg, vOrigin); + else + RotateFaceTexture (f, nAxis, fDeg); + } + Brush_Build(b, false,true,false,false); // don't filter + } +} + +void Select_ApplyMatrix_BrushPrimit() +{ + #ifdef _DEBUG + if (!g_qeglobals.m_bBrushPrimitMode) { + Sys_FPrintf(SYS_ERR,"ERROR: Select_ApplyMatrix_BrushPrimit called in non-BP mode\n"); + } + #endif + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + ApplyMatrix_BrushPrimit (f, select_matrix, select_origin); + } + } +} + +void Select_FlipAxis (int axis) +{ + int i; + + Select_GetMid (select_origin); + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + select_matrix[axis][axis] = -1; + select_fliporder = true; + + // texture locking + if (g_PrefsDlg.m_bRotateLock) { + // axis flipping inverts space orientation, we have to use a general texture locking algorithm instead of the RotateFaceTexture + if (g_qeglobals.m_bBrushPrimitMode) { + Select_ApplyMatrix_BrushPrimit(); + } + else + { + // there's never been flip locking for non BP mode, this would be tricky to write and there's not much interest for it with the coming of BP format + // what could be done is converting regular to BP, locking, then back to regular :) + Sys_FPrintf(SYS_WRN, "WARNING: regular texturing doesn't have texture lock on flipping operations\n"); + } + } + // geometric transformation + Select_ApplyMatrix (true, false, 0, 0); + Sys_UpdateWindows (W_ALL); +} + + +void Select_Scale(float x, float y, float z) +{ + Select_GetMid (select_origin); + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + // ignore fixedsize entities + if(b->owner->eclass->fixedsize) continue; + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + for (int i=0 ; i<3 ; i++) + { + f->planepts[i][0] -= select_origin[0]; + f->planepts[i][1] -= select_origin[1]; + f->planepts[i][2] -= select_origin[2]; + f->planepts[i][0] *= x; + f->planepts[i][1] *= y; + f->planepts[i][2] *= z; + + f->planepts[i][0] += select_origin[0]; + f->planepts[i][1] += select_origin[1]; + f->planepts[i][2] += select_origin[2]; + } + } + Brush_Build(b, false,true,false,false); // don't filter + if (b->patchBrush) + { + vec3_t v; + v[0] = x; + v[1] = y; + v[2] = z; + Patch_Scale(b->pPatch, select_origin, v); + } + } +} + +void Select_RotateAxis (int axis, float deg, bool bPaint, bool bMouse) +{ + int i; + vec_t c, s; + + if (deg == 0) + { + return; + } + + if (bMouse) + { + VectorCopy(g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin); + } + else + { + Select_GetMid (select_origin); + } + + /* + if(axis == 2) + { + vec3_t rotation; + VectorSet(rotation, 0, 0, 360 - deg); + for(brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) + if(b->owner->model.pEdit) + b->owner->model.pEdit->Rotate(select_origin, rotation); + } + */ + + select_fliporder = false; + + // the "90" degrees algorithm is mostly used on axis rotate as a speedup and possibly avoiding rounding errors as much as possible + // previous implementation was doing an indirect-oriented rotation over the plane whereas the general algo below was doing a direct-oriented rotation + // this was confusing the texture locking algorithms, fixed it to be direct-oriented (side consequence is that the axis rotate toolbar button rotates the other way now) + // NOTE: previous algo was using vec3_origin in the matrix computation.. + // I don't see what an origin does in linear transformations (3x3 matrixes always relate to a (0,0,0) origin) + // in Radiant it's initialized as (0,0,0) and never set to another value + // so I got rid of it when it's not used for initialisation tasks (and even if it's not (0,0,0) it should not matter + if (deg == 90) + { + c = 0; + s = 1; + } + else + { + c = cos(deg * Q_PI / 180.0); + s = sin(deg * Q_PI / 180.0); + } + + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + + switch (axis) + { + case 0: + select_matrix[1][1] = c; + select_matrix[1][2] = s; + select_matrix[2][1] = -s; + select_matrix[2][2] = c; + break; + case 1: + select_matrix[0][0] = c; + select_matrix[0][2] = s; + select_matrix[2][0] = -s; + select_matrix[2][2] = c; + break; + case 2: + select_matrix[0][0] = c; + select_matrix[0][1] = s; + select_matrix[1][0] = -s; + select_matrix[1][1] = c; + break; + } + + + // texture locking + if (g_PrefsDlg.m_bRotateLock) + { + // Terrible hack, reversing input rotation angle to correct + // texture rotation direction for X and Z axes. + // RotateTextures needs to be changed to fix this properly? + if (axis == 1) + RotateTextures(axis, deg, select_origin); + else + RotateTextures(axis, deg * -1, select_origin); + } + // geometric transformation + Select_ApplyMatrix(!bMouse, true, axis, deg);//, false); + + if (bPaint) + Sys_UpdateWindows (W_ALL); +} + +/* +================================================================ + +GROUP SELECTIONS + +================================================================ +*/ + +void Select_RealCompleteTall(vec3_t mins, vec3_t maxs) +{ + brush_t *b, *next; + + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + g_qeglobals.d_select_mode = sel_brush; + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + if ( (b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) + || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2]) ) + continue; + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } +} + +void Select_CompleteTall (void) +{ + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + Undo_Start ("select complete tall"); + Undo_AddBrushList (&selected_brushes); + Undo_End(); + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + Select_RealCompleteTall(mins, maxs); + Sys_UpdateWindows (W_ALL); +} + +void Select_PartialTall (void) +{ + brush_t *b, *next; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + Undo_Start ("select complete tall"); + Undo_AddBrushList (&selected_brushes); + Undo_End(); + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + if ( (b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1]) + || (b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2]) ) + continue; + + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + +void Select_Touching (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + for (i=0 ; i<3 ; i++) + if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1) + break; + + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + + Sys_UpdateWindows (W_ALL); +} + +void Select_Inside (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + Undo_Start ("select inside"); + Undo_AddBrushList (&selected_brushes); + Undo_End(); + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + for (i=0 ; i<3 ; i++) + if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) + break; + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + + Sys_UpdateWindows (W_ALL); +} + +void Select_Ungroup(void) +{ + int numselectedgroups; + entity_t *e; + brush_t *b,* sb; + + numselectedgroups = 0; + for (sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next) + { + e = sb->owner; + + if (e == world_entity || e->eclass->fixedsize) + { + continue; + } + + for (b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext) + { + Entity_UnlinkBrush (b); + Entity_LinkBrush (world_entity, b); + } + Entity_Free (e); + numselectedgroups++; + } + + if (numselectedgroups <= 0) + { + Sys_Printf("No grouped entities selected.\n"); + return; + } + Sys_Printf("Ungrouped %d entit%s.\n", numselectedgroups, (numselectedgroups == 1)?"y":"ies"); + Sys_UpdateWindows (W_ALL); +} + +/*! +group selected brushes into specified entity +if an entity is empty afterwards, destroy it +*/ +void Select_GroupEntity(entity_t* group) +{ + entity_t* e; + brush_t *b; + + if(group->eclass->fixedsize) + { + Sys_FPrintf (SYS_ERR, "Select_GroupEntity: can't group anything to a fixedsize entity\n"); + return; + } + + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + if(b->owner->eclass->fixedsize) continue; + e = b->owner; + Entity_UnlinkBrush(b); + Entity_LinkBrush(group, b); + if(e != world_entity && e->brushes.onext == &e->brushes) + { + Undo_AddEntity(e); + Entity_Free(e); + } + } +} + +/*! +merge all selected entities together into the first one selected +NOTE: makes use of order of selected_brushes list +can be used to move world brushes in an entity, or to merge several ents together +NOTE: didn't devise a strategy on the epairs, we merge into the first entity and use those +*/ +void Select_MergeEntity() +{ + entity_t* e = NULL; + brush_t* b; + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + if(!b->owner->eclass->fixedsize) + { + e = b->owner; + break; + } + } + + if(e != NULL) + { + Select_GroupEntity(e); + + int count = 0; + for(b = e->brushes.onext; b != &e->brushes; b=b->onext) + { + //Brush_RemoveFromList (b); + //Brush_AddToList(b, &active_brushes); + count++; + } + Sys_Printf ("Merged %d brushes into %s entity\n", count, ValueForKey (e, "classname")); + } +} + +/* +==================== +Select_Seperate +==================== +*/ +void Select_Seperate( void ) { + Select_GroupEntity( world_entity ); +} + +/* +==================== +Select_MakeStructural +==================== +*/ +void Select_MakeStructural (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents &= ~CONTENTS_DETAIL; + b->bFiltered = FilterBrush(b); + } + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + +void Select_MakeDetail (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents |= CONTENTS_DETAIL; + b->bFiltered = FilterBrush(b); + } + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + +// brush primitive texture adjustments, use the camera view to map adjustments +// ShiftTextureRelative_BrushPrimit ( s , t ) will shift relative to the texture +void ShiftTextureRelative_Camera(face_t *f, int x, int y) +{ + vec3_t vecS, vecT; + vec_t XY[2]; // the values we are going to send for translation + vec_t sgn[2]; // +1 or -1 + int axis[2]; + CamWnd* pCam; + + // get the two relative texture axes for the current texturing + BrushPrimit_GetRelativeAxes(f, vecS, vecT); + + // center point of the face, project it on the camera space + vec3_t C; + VectorClear(C); + int i; + for (i=0; iface_winding->numpoints; i++) + { + VectorAdd(C,f->face_winding->points[i],C); + } + VectorScale(C,1.0/f->face_winding->numpoints,C); + + pCam = g_pParentWnd->GetCamWnd(); + pCam->MatchViewAxes(C, vecS, axis[0], sgn[0]); + pCam->MatchViewAxes(C, vecT, axis[1], sgn[1]); + + // this happens when the two directions can't be mapped on two different directions on the screen + // then the move will occur against a single axis + // (i.e. the user is not positioned well enough to send understandable shift commands) + // NOTE: in most cases this warning is not very relevant because the user would use one of the two axes + // for which the solution is easy (the other one being unknown) + // so this warning could be removed + if (axis[0] == axis[1]) + Sys_FPrintf(SYS_WRN, "Warning: degenerate in ShiftTextureRelative_Camera\n"); + + // compute the X Y geometric increments + // those geometric increments will be applied along the texture axes (the ones we computed above) + XY[0] = 0; + XY[1] = 0; + if (x!=0) + { + // moving right/left + XY[axis[0]] += sgn[0]*x; + } + if (y!=0) + { + XY[axis[1]] += sgn[1]*y; + } + // we worked out a move along vecS vecT, and we now it's geometric amplitude + // apply it + ShiftTextureRelative_BrushPrimit(f, XY[0], XY[1]); +} + +void Select_ShiftTexture(int x, int y) +{ + brush_t *b; + face_t *f; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + return; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + { + ShiftTextureRelative_Camera( f, x, y ); + } + else + { + f->texdef.shift[0] += x; + f->texdef.shift[1] += y; + } + } + Brush_Build(b,true,true,false,false); // don't filter + if (b->patchBrush) + { + Patch_ShiftTexture(b->pPatch, x, y); + } + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + if (g_qeglobals.m_bBrushPrimitMode) + { + ShiftTextureRelative_Camera( selFace, x, y ); + } + else + { + selFace->texdef.shift[0] += x; + selFace->texdef.shift[1] += y; + } + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +// setting float as input +void Select_ScaleTexture(float x, float y) +{ + brush_t *b; + face_t *f; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + { + return; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + { + // apply same scale as the spinner button of the surface inspector + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + // compute normalized texture matrix + ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL ); + // compute fake shift scale rot + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + // update + scale[0]+=static_cast(x)*0.1; + scale[1]+=static_cast(y)*0.1; + // compute new normalized texture matrix + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + // apply to face texture matrix + ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture ); + } + else + { + f->texdef.scale[0] += x; + f->texdef.scale[1] += y; + } + } + Brush_Build(b,true,true,false,false); // don't filter + if (b->patchBrush) + { + Patch_ScaleTexture(b->pPatch, x, y); + } + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + if (g_qeglobals.m_bBrushPrimitMode) + { + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL ); + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + scale[0]+=static_cast(x)*0.1; + scale[1]+=static_cast(y)*0.1; + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture ); + } + else + { + selFace->texdef.scale[0] += x; + selFace->texdef.scale[1] += y; + } + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +void Select_RotateTexture(int amt) +{ + brush_t *b; + face_t *f; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + { + return; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + { + // apply same scale as the spinner button of the surface inspector + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + // compute normalized texture matrix + ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL ); + // compute fake shift scale rot + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + // update + rotate += amt; + // compute new normalized texture matrix + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + // apply to face texture matrix + ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture ); + } + else + { + f->texdef.rotate += amt; + f->texdef.rotate = static_cast(f->texdef.rotate) % 360; + } + } + Brush_Build(b,true,true,false,false); // don't filter + if (b->patchBrush) + { + //Patch_RotateTexture(b->nPatchID, amt); + Patch_RotateTexture(b->pPatch, amt); + } + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + if (g_qeglobals.m_bBrushPrimitMode) + { + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL ); + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + rotate += amt; + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture ); + } + else + { + selFace->texdef.rotate += amt; + selFace->texdef.rotate = static_cast(selFace->texdef.rotate) % 360; + } + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +// TTimo modified to handle shader architecture: +// expects shader names at input, comparison relies on shader names .. texture names no longer relevant +void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected, bool bForce, bool bSelectMatchingFaces) +{ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=391 + if (strchr(pFind, ' ') || strchr(pReplace, ' ')) + { + Sys_FPrintf(SYS_WRN, "FindReplaceTextures: '%s' or '%s' have spaces, aborted\n", pFind, pReplace); + return; + } + + brush_t* pList = (bSelected) ? &selected_brushes : &active_brushes; + if (!bSelected) + Select_Deselect(); + + //++timo BP mode: replacing a texture in BP mode is not that easy, you need to recompute the texture matrix + // if the size of the replacing texture differs, otherwise you get wrong scaling + if (g_qeglobals.m_bBrushPrimitMode) + Sys_Printf("TODO: finalize find/replace code for brush primitives"); + + CPtrArray mFaces; + for (brush_t* pBrush = pList->next ; pBrush != pList; pBrush = pBrush->next) + { + if (!bSelectMatchingFaces && pBrush->patchBrush) + { + Patch_FindReplaceTexture(pBrush, pFind, pReplace, bForce); + } + + bool found = false; //spog + for (face_t* pFace = pBrush->brush_faces; pFace; pFace = pFace->next) + { + if(bForce || strcmpi(pFace->pShader->getName(), pFind) == 0) + { + if (!bSelectMatchingFaces) { + pFace->pShader->DecRef(); + pFace->pShader = QERApp_Shader_ForName( pReplace ); + pFace->pShader->IncRef(); + pFace->d_texture = pFace->pShader->getTexture(); + pFace->texdef.SetName(pReplace); + found = true; + } else if (bSelectMatchingFaces) { + mFaces.Add(pFace); + } + } + } + + if (found) // spog - speed increase, only build brushes that changed + Brush_Build(pBrush); + + } + + if (bSelectMatchingFaces) { + if (bSelected) + Select_Deselect(); + + int nSize = mFaces.GetSize(); + for (int i = 0; i < nSize; i++) { + g_SelectedFaces.Add(reinterpret_cast(mFaces.GetAt(i))); + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +void Select_AllOfType() +{ + brush_t *b, *next; + entity_t *e; + // if no brush selected, we will select based on texture + // the first selected face's texture if any, or the current texture + // if a brush is selected, we will select entities (first non-worldspawn owner in selected brushes) + if (selected_brushes.next == &selected_brushes) + { + + CString strName; + if (g_ptrSelectedFaces.GetSize() == 0) + { + strName = g_qeglobals.d_texturewin.texdef.GetName(); + } + else + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + strName = selFace->texdef.GetName(); + } + + Sys_Printf("Selecting all brushes with the texture %s\n", strName.GetBuffer()); + + Select_Deselect(); + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + if (b->patchBrush) + { + if (strcmpi(strName, b->pPatch->pShader->getName()) == 0) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + else + { + for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) + { + if (strcmpi(strName, pFace->texdef.GetName()) == 0) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + } + } + Sys_UpdateWindows(W_ALL); + return; + } + + + b = selected_brushes.next; + e = b->owner; + + if (e != NULL) + { + if (e != world_entity) + { + CString strName = e->eclass->name; + CString strKey, strVal; + bool bCriteria = GetSelectAllCriteria(strKey, strVal); + Sys_Printf("Selecting all %s entities\n", strName.GetBuffer()); + Select_Deselect(); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + e = b->owner; + if (e != NULL) + { + if (strcmpi(e->eclass->name, strName) == 0) + { + bool doIt = true; + if (bCriteria) { + CString str = ValueForKey (e, strKey); + if (str.CompareNoCase(strVal) != 0) { + doIt = false; + } + } + if (doIt) { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + } + } + } + } + Sys_UpdateWindows (W_ALL); + +} + +void Select_Reselect() +{ + Select_Brush(selected_brushes.next); + Sys_UpdateWindows (W_ALL); +} + + +void Select_FitTexture(int nHeight, int nWidth) +{ + brush_t *b; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + return; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + Brush_FitTexture(b, nHeight, nWidth); + Brush_Build(b,true,true,false,false); // don't filter + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + Face_FitTexture(selFace, nHeight, nWidth); + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +void Select_Hide() +{ + for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + b->hiddenBrush = true; + b->bFiltered = true; + } + Sys_UpdateWindows (W_ALL); +} + +void Select_ShowAllHidden() +{ + brush_t* b; + for (b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + if (b->hiddenBrush) + { + b->hiddenBrush = false; + b->bFiltered = FilterBrush(b); + } + } + for (b=active_brushes.next ; b && b != &active_brushes ; b=b->next) + { + if (b->hiddenBrush) + { + b->hiddenBrush = false; + b->bFiltered = FilterBrush(b); + } + } + Sys_UpdateWindows (W_ALL); +} + + +/* +============ +Select_Invert +============ +*/ +void Select_Invert(void) +{ + brush_t *next, *prev, *b; + + Sys_Printf("inverting selection...\n"); + + next = active_brushes.next; + prev = active_brushes.prev; + if (selected_brushes.next != &selected_brushes) + { + active_brushes.next = selected_brushes.next; + active_brushes.prev = selected_brushes.prev; + active_brushes.next->prev = &active_brushes; + active_brushes.prev->next = &active_brushes; + } + else + { + active_brushes.next = &active_brushes; + active_brushes.prev = &active_brushes; + } + if (next != &active_brushes) + { + selected_brushes.next = next; + selected_brushes.prev = prev; + selected_brushes.next->prev = &selected_brushes; + selected_brushes.prev->next = &selected_brushes; + } + else + { + selected_brushes.next = &selected_brushes; + selected_brushes.prev = &selected_brushes; + } + + // now check if any hidden brush is selected + for (b = selected_brushes.next; b != &selected_brushes; ) + { + if (b->patchBrush) + b->pPatch->bSelected = true; + + if (b->bFiltered) + { + brush_t *pb = b; + b = b->next; + Brush_RemoveFromList (pb); + Brush_AddToList (pb, &active_brushes); + } + else b = b->next; + + } + + for (b = active_brushes.next; b != &active_brushes; b = b->next) + { + if (b->patchBrush) + { + b->pPatch->bSelected = false; + } + } + + // since invert selection only works at the brush level, + // set g_qeglobals.d_select_mode accordingly + g_qeglobals.d_select_mode = sel_brush; + + // since invert selection only works at the brush level, + // set g_qeglobals.d_select_mode accordingly + g_qeglobals.d_select_mode = sel_brush; + + Sys_UpdateWindows(W_ALL); + + Sys_Printf("done.\n"); +} + +#ifdef ENABLE_GROUPS +/* +=========== +Select_Name +=========== +*/ +void Select_Name(const char *pName) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + Brush_SetEpair(b, "Name", pName); + } + } +} + +/* +================= +Select_AddToGroup +add selected brushes to a group, update the tree +================= +*/ +void Select_AddToGroup(const char *pName) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + Brush_SetEpair(b, "group", pName); + Group_AddToProperGroup(b); + } + } +} +#endif diff --git a/radiant/select.h b/radiant/select.h new file mode 100644 index 00000000..8bcafff1 --- /dev/null +++ b/radiant/select.h @@ -0,0 +1,82 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +typedef struct +{ + brush_t *brush; + face_t *face; + float dist; + qboolean selected; +} trace_t; + +#define SF_SELECTED_ONLY 0x0001 +#define SF_ENTITIES_FIRST 0x0002 +#define SF_SINGLEFACE 0x0004 +#define SF_IGNORECURVES 0x0008 +#define SF_IGNOREGROUPS 0x0010 +#define SF_CYCLE 0x0020 +#define SF_CAMERA 0x0040 // set when the operation happens through camera view, otherwise XY +#define SF_DRAG_ON 0x0080 +#define SF_DRAG_OFF 0x0100 +#define SF_DRAG (SF_DRAG_ON | SF_DRAG_OFF) + +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags); + +void Select_GetBounds (vec3_t mins, vec3_t maxs); +void Select_GetMid (vec3_t mid); +void Select_Brush (brush_t *b, bool bComplete = true, bool bStatus = true); +void Select_Ray (vec3_t origin, vec3_t dir, int flags); +void Select_Delete (void); +void Select_Deselect (bool bDeselectFaces = true); +void Select_Invert(void); +void Select_Clone (void); +void Select_Move (vec3_t delta, bool bSnap = true); +void Select_NudgePoint(vec3_t delta, qboolean bSnap = true); +void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, void* pPlugTexdef = NULL); +void Select_FlipAxis (int axis); +void Select_RotateAxis (int axis, float deg, bool bPaint = true, bool bMouse = false); +void Select_RealCompleteTall(vec3_t mins, vec3_t maxs); +void Select_CompleteTall (void); +void Select_PartialTall (void); +void Select_Touching (void); +void Select_Inside (void); +void Select_Seperate (void); +void Select_MakeStructural (void); +void Select_MakeDetail (void); +void Select_AllOfType(); +void Select_Reselect(); +void Select_FitTexture(int nHeight = 1, int nWidth = 1); + +// absolute texture coordinates +// TTimo NOTE: this is stuff for old brushes format and rotation texture lock .. sort of in-between with bush primitives +void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3); +void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3); +void Select_Hide(); +void Select_ShowAllHidden(); +// add selected brushes to a group, update the tree +//void Select_AddToGroup(const char *pName); +//void Select_Name(const char *pName); + +// updating workzone to a given brush (depends on current view) +void UpdateWorkzone_ForBrush( brush_t* b ); + +void Select_GroupEntity(entity_t* e); +void Select_MergeEntity(); diff --git a/radiant/selectedface.cpp b/radiant/selectedface.cpp new file mode 100644 index 00000000..3954a035 --- /dev/null +++ b/radiant/selectedface.cpp @@ -0,0 +1,128 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// Quick interface hack for selected face interface +// this one really needs more work, but I'm in a hurry with TexTool + +#include "stdafx.h" + +int WINAPI QERApp_GetSelectedFaceCount() +{ + return g_ptrSelectedFaces.GetSize(); +} + +face_t* WINAPI QERApp_GetSelectedFace(int iface) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetFace: selected faces count exceeded\n"); + return NULL; + } + return reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); +} + +brush_t* WINAPI QERApp_GetSelectedFaceBrush(int iface) +{ + if (iface>=g_ptrSelectedFaceBrushes.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetFace: selected faces count exceeded\n"); + return NULL; + } + return reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(iface)); +} + +// NOTE: we expect pWinding to have MAX_POINTS_ON_WINDING points ready for writing +int WINAPI QERApp_GetFaceInfo(int iface, _QERFaceData *pFaceData, winding_t *pWinding) +{ + int size; + + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetFaceInfo: selected faces count exceeded\n"); + return 0; + } + if (!g_qeglobals.m_bBrushPrimitMode) + { + Sys_Printf("Warning: unexpected QERApp_GetFaceInfo out of brush primitive mode\n"); + return 0; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + strcpy( pFaceData->m_TextureName, selFace->texdef.GetName() ); + VectorCopy( selFace->planepts[0], pFaceData->m_v1 ); + VectorCopy( selFace->planepts[1], pFaceData->m_v2 ); + VectorCopy( selFace->planepts[2], pFaceData->m_v3 ); + pFaceData->m_bBPrimit = true; + memcpy( &pFaceData->brushprimit_texdef, &selFace->brushprimit_texdef, sizeof(brushprimit_texdef_t) ); + size = (int)((winding_t *)0)->points[selFace->face_winding->numpoints]; + memcpy( pWinding, selFace->face_winding, size ); + return 1; +} + +int WINAPI QERApp_SetFaceInfo(int iface, _QERFaceData *pFaceData) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_SetFaceInfo: selected faces count exceeded\n"); + return 0; + } + if (!g_qeglobals.m_bBrushPrimitMode) + { + Sys_Printf("Warning: unexpected QERApp_SetFaceInfo out of brush primitive mode\n"); + return 0; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(iface)); + //strcpy( selected_face->texdef.name, pFaceData->m_TextureName ); + selFace->texdef.SetName(pFaceData->m_TextureName); + VectorCopy( pFaceData->m_v1, selFace->planepts[0] ); + VectorCopy( pFaceData->m_v2, selFace->planepts[1] ); + VectorCopy( pFaceData->m_v3, selFace->planepts[2] ); + memcpy( &selFace->brushprimit_texdef, &pFaceData->brushprimit_texdef, sizeof(brushprimit_texdef_t) ); + Brush_Build( selBrush ); + Sys_UpdateWindows(W_ALL); + return 1; +} + +int WINAPI QERApp_ISelectedFace_GetTextureNumber(int iface) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_ISelectedFace_GetTextureNumber: selected faces count exceeded\n"); + return 0; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + return selFace->d_texture->texture_number; +} + +void WINAPI QERApp_GetTextureSize (int iface, int Size[2]) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetTextureSize: selected faces count exceeded\n"); + return; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + Size[0] = selFace->d_texture->width; + Size[1] = selFace->d_texture->height; +} diff --git a/radiant/stdafx.cpp b/radiant/stdafx.cpp new file mode 100644 index 00000000..c10d9ae3 --- /dev/null +++ b/radiant/stdafx.cpp @@ -0,0 +1,35 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// TTimo +// precompiled headers stuff +// NOTE: this file is useless on non-MSVC builds + +#include "stdafx.h" diff --git a/radiant/stdafx.h b/radiant/stdafx.h new file mode 100644 index 00000000..cb6c327f --- /dev/null +++ b/radiant/stdafx.h @@ -0,0 +1,39 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// TTimo +// included by most files +// on Win32 builds this one is used for precompiled headers + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include "qe3.h" diff --git a/radiant/surfacedialog.cpp b/radiant/surfacedialog.cpp new file mode 100644 index 00000000..31e65284 --- /dev/null +++ b/radiant/surfacedialog.cpp @@ -0,0 +1,1134 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Surface Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "stdafx.h" +#include "surfacedialog.h" + +SurfaceDlg g_dlgSurface; + +///////////////////////////////////////////////////////////////////////////// +// surface properties plugin + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; +// when != NULL, this thing means the surface inspector is currently being displayed +// NOTE a boolean flag would have been more explicit, this is totally so ugly +GtkWidget* g_surfwin = NULL; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// the struct used to store the increments (saved in registry) +texdef_t *l_pIncrement = &g_qeglobals.d_savedinfo.m_SIIncrement; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +#ifdef _DEBUG +// experimental stuff, work directly on BP +static void OnTest(GtkWidget *widget, gpointer data) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + Sys_FPrintf(SYS_WRN, "BP mode required\n"); + return; + } + if (g_ptrSelectedFaces.GetSize() != 1) + { + Sys_FPrintf(SYS_WRN, "Expected single face selection\n"); + return; + } + brush_t *b = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(0)); + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + // get the ST axis base for the face + vec3_t texS,texT; + ComputeAxisBase(selFace->plane.normal, texS, texT); + // find ST coordinates for the center of the face + float Os=0,Ot=0; + int i; + for (i=0; iface_winding->numpoints; i++) + { + Os += DotProduct(selFace->face_winding->points[i],texS); + Ot += DotProduct(selFace->face_winding->points[i],texT); + } + Os /= selFace->face_winding->numpoints; + Ot /= selFace->face_winding->numpoints; + brushprimit_texdef_t *pBP = &selFace->brushprimit_texdef; + + // (FIXME: initial version, before axis base change optimize) + + // we need to compute our BP matrix in this new axis base (O,texS,texT) + // the general case if BPO = M * BP * M^-1 + // where BPO is transformation expressed in (O,texS,texT) + // M is the axis base change from (origin,texS,texT) to (O,texS,texT) + // here we have a special case, M is a translation and it's inverse is easy + vec_t BPO[2][3]; + vec_t aux[2][3]; + vec_t m[2][3]; + memset(&m, 0, sizeof(vec_t)*6); + m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(m, pBP->coords, aux); + m[0][2] = Os; m[1][2] = Ot; // now M^-1 + BPMatMul(aux, m, BPO); + +#if 0 + // apply a scaling + // scale factors against S and T axis, we apply on top of the existing matrix + // <1 will decrease the texel/world resolution, >1 will increase + float sS = 1.025,sT = 1.025; + BPMatScale(BPO,sS,sT); +#endif +#if 0 + // apply a rotation + float theta = 5; + BPMatRotate(BPO,theta); +#endif +#if 0 + // read the scale + ConvertTexMatWithQTexture(BPO, selFace->d_texture, aux, NULL); + // reset the scale (normalize the matrix) + vec_t v1,v2; + v1 = sqrt(aux[0][0]*aux[0][0]+aux[1][0]*aux[1][0]); + v2 = sqrt(aux[0][1]*aux[0][1]+aux[1][1]*aux[1][1]); + // if reading the scale values, we have them here: + Sys_Printf("Current Scale: S: %g T: %g\n", v1, v2); + return; +#endif +#if 1 + // apply a given scale (on S and T) + ConvertTexMatWithQTexture(BPO, selFace->d_texture, aux, NULL); + // reset the scale (normalize the matrix) + vec_t v1,v2; + v1 = sqrt(aux[0][0]*aux[0][0]+aux[1][0]*aux[1][0]); + v2 = sqrt(aux[0][1]*aux[0][1]+aux[1][1]*aux[1][1]); + vec_t sS,sT; + // put the values for scale on S and T here: + sS = 1.2 / v1; + sT = 0.8 / v2; + aux[0][0] *= sS; aux[1][0] *= sS; + aux[0][1] *= sT; aux[1][1] *= sT; + ConvertTexMatWithQTexture(aux, NULL, BPO, selFace->d_texture); +#endif + + // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M + BPMatMul(m, BPO, aux); // m is M^-1 + m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(aux, m, pBP->coords); + + // now emit the coordinates on the winding + EmitBrushPrimitTextureCoordinates(selFace, selFace->face_winding); + Sys_UpdateWindows(W_CAMERA); +} + +/* + FIXME: try again, there must be a silly mistake in the formula expansion + // we need to compute our BP matrix in this new axis base (O,texS,texT) + // the general case is BPO = M * BP * M^-1 + // where BPO is transformation expressed in (O,texS,texT) + // M is the axis base change from (origin,texS,texT) to (O,texS,texT) + // here we have a special case, M is a translation and it's inverse is easy + // the M * BP * M^-1 formula can be expanded and simplified + vec_t BPO[2][3]; + memcpy(&BPO, &pBP->coords, sizeof(vec_t)*6); + BPO[0][2] = Os*(pBP->coords[0][0]-1.0) + Ot*pBP->coords[0][1] + pBP->coords[0][2]; + BPO[1][2] = Os*pBP->coords[1][0] + Ot*(pBP->coords[1][1]-1.0) + Ot*pBP->coords[1][2]; + + // apply a scaling + // scale factors against S and T axis, we apply on top of the existing matrix + // <1 will decrease the texel/world resolution, >1 will increase + float sS = 1.025,sT = 1.025; + BPMatScale(BPO,sS,sT); + + // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M + // same expanded formula as above + memcpy(&pBP->coords, &BPO, sizeof(vec_t)*6); + pBP->coords[0][2] = Os*(1.0-BPO[0][0]) - Ot*BPO[0][1] + BPO[0][2]; + pBP->coords[1][2] = -Os*BPO[1][0] + Ot*(1.0-BPO[1][1]) + BPO[1][2]; +*/ + +/* + // initial version, before axis base change optimize + + // we need to compute our BP matrix in this new axis base (O,texS,texT) + // the general case if BPO = M * BP * M^-1 + // where BPO is transformation expressed in (O,texS,texT) + // M is the axis base change from (origin,texS,texT) to (O,texS,texT) + // here we have a special case, M is a translation and it's inverse is easy + vec_t BPO[2][3]; + vec_t aux[2][3]; + vec_t m[2][3]; + memset(&m, 0, sizeof(vec_t)*6); + m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(m, pBP->coords, aux); + m[0][2] = Os; m[1][2] = Ot; // now M^-1 + BPMatMul(aux, m, BPO); + + // apply a scaling + // scale factors against S and T axis, we apply on top of the existing matrix + // <1 will decrease the texel/world resolution, >1 will increase + float sS = 1.025,sT = 1.025; + BPMatScale(BPO,sS,sT); + + // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M + BPMatMul(m, BPO, aux); // m is M^-1 + m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(aux, m, pBP->coords); +*/ +#endif + +static void OnDone(GtkWidget *widget, gpointer data) +{ + g_dlgSurface.GetTexMods(); + g_dlgSurface.HideDlg (); + Sys_UpdateWindows(W_ALL); +} + +// OnUpdate is called when something is changed in the dialog +// and must be reflected in the views. But it's not a change +// so important, so the system will try to undo our last do before applying the new changes +static void OnUpdate (GtkWidget *widget, gpointer data) +{ + if (!g_bListenChanged) + return; + + if (OnlyPatchesSelected()) + { + //++timo possible bug or misfeature in our gtk_MessageBox here.. +// gtk_MessageBox("The surface inspector doesn't work for patches, use the patch inspector instead (Shift+S)", "Surface Inspector", MB_OK ); + Sys_Printf("The surface inspector doesn't work for patches, use the patch inspector instead (Shift+S)\n"); + return; + } + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + g_dlgSurface.GetTexMods (); + Sys_UpdateWindows(W_CAMERA); +} + +// reflect the current changes in the views, and make sure +// the changes are stored in the undo. +static void OnApply (GtkWidget *widget, gpointer data) +{ + if (!g_bListenChanged) + return; + + g_dlgSurface.GetTexMods (); + g_dlgSurface.m_nUndoId = 0; // that way we are sure we won't call undo + Sys_UpdateWindows(W_CAMERA); +} + +// we use OnTextureKey to detect when the user edits something in the texture widget +// in which case next 'Enter' will be interpreted as a OnApply instead of a OnDone +static gint OnTextureKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ +#ifdef DBG_SI + Sys_Printf("OnTextureKey\n"); +#endif + if (event->keyval != GDK_Return) + g_dlgSurface.m_bEditingTextureWidget = true; + return FALSE; +} + +static void OnCancel(GtkWidget *widget, gpointer data) +{ + g_qeglobals.d_texturewin.texdef = g_old_texdef; + // cancel the last do if we own it + if (g_dlgSurface.m_nUndoId == Undo_GetUndoId()) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(); + g_bListenUpdate = true; + g_dlgSurface.m_nUndoId = 0; + } + g_dlgSurface.HideDlg (); +} + +static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + if (g_surfwin) + { + if (event->keyval == GDK_Return) + { + if (g_dlgSurface.m_bEditingTextureWidget) + { + OnApply (NULL, NULL); + g_dlgSurface.m_bEditingTextureWidget = false; + } + else + { + OnDone (NULL, NULL); + } + return TRUE; + } + if (event->keyval == GDK_Escape) + { + OnCancel (NULL, NULL); + return TRUE; + } + } + return FALSE; +} + +// the widget can be one of hshift, vshift, hscale, vscale, rotate +// we use the g_bListenChanged flag to ignore when changing stuff ourselves +static void OnIncrementChanged(GtkWidget *widget, gpointer data) +{ + if (!g_bListenChanged) + return; + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged\n"); +#endif + + gfloat val = 0; + sscanf( gtk_entry_get_text (GTK_ENTRY (widget)), "%g", &val); + // now push it into the appropriate spin button + GtkAdjustment * adjust; + if (widget == g_dlgSurface.GetDlgWidget ("hshift_inc")) + { + l_pIncrement->shift[0] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hshift"))); + adjust->step_increment = l_pIncrement->shift[0]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("vshift_inc")) + { + l_pIncrement->shift[1] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vshift"))); + adjust->step_increment = l_pIncrement->shift[1]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("hscale_inc")) + { + l_pIncrement->scale[0] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hscale"))); + adjust->step_increment = l_pIncrement->scale[0]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("vscale_inc")) + { + l_pIncrement->scale[1] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vscale"))); + adjust->step_increment = l_pIncrement->scale[1]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("rotate_inc")) + { + l_pIncrement->rotate = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("rotate"))); + adjust->step_increment = l_pIncrement->rotate; + } +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + if (hscale == 0.0f) + { + (g_qeglobals.m_bBrushPrimitMode) ? hscale = 1.0f : hscale = 0.5f; + } + if (vscale == 0.0f) + { + (g_qeglobals.m_bBrushPrimitMode) ? vscale = 1.0f : vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = (int) ( (float)g_qeglobals.d_gridsize / hscale ); + l_pIncrement->shift[1] = (int) ( (float)g_qeglobals.d_gridsize / vscale ); + // now some update work + // FIXME: doesn't look good here, seems to be called several times + g_dlgSurface.SetTexMods(); +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on the current texture scale used? +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +static void OnBtnMatchGrid(GtkWidget *widget, gpointer data) +{ + float hscale, vscale; + hscale = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hscale"))); + vscale = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vscale"))); + if (hscale == 0.0f || vscale == 0.0f) + { + Sys_Printf("ERROR: unexpected scale == 0.0f\n"); + return; + } + DoSnapTToGrid (hscale, vscale); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + g_SurfaceTable.m_pfnUpdateSurfaceDialog(); +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + g_SurfaceTable.m_pfnDoSurface(); + return; +} + +void ToggleSurface() +{ + g_SurfaceTable.m_pfnToggleSurface(); + return; +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + g_SurfaceTable.m_pfnSurfaceDlgFitAll(); + return; +} + +static void OnBtnPatchdetails(GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(true); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchnatural(GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchreset(GtkWidget *widget, gpointer data) +{ + float fx, fy; + + if (DoTextureLayout (&fx, &fy) == IDOK) + Patch_ResetTexturing (fx, fy); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchFit(GtkWidget *widget, gpointer data) +{ + Patch_ResetTexturing(1.0, 1.0); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnAxial(GtkWidget *widget, gpointer data) +{ + Select_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, true); + g_dlgSurface.SetTexMods(); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnFaceFit(GtkWidget *widget, gpointer data) +{ + g_dlgSurface.UpdateData(TRUE); + if (g_ptrSelectedFaces.GetSize() == 0) + { + brush_t *b; + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) + { + g_ptrSelectedFaces.Add(pFace); + g_ptrSelectedFaceBrushes.Add(b); + } + } + Select_FitTexture(g_dlgSurface.m_nHeight, g_dlgSurface.m_nWidth); + g_dlgSurface.SetTexMods(); + g_ptrSelectedFaces.RemoveAll(); + } + else + { + Select_FitTexture(g_dlgSurface.m_nHeight, g_dlgSurface.m_nWidth); + g_dlgSurface.SetTexMods(); + } + Sys_UpdateWindows(W_ALL); +} + +// ============================================================================= +// SurfaceDialog class + +SurfaceDlg::SurfaceDlg () +{ + m_nHeight = 1; + m_nWidth = 1; + m_nUndoId = 0; +} + +void SurfaceDlg::ShowDlg() +{ + Dialog::ShowDlg(); + if(GetWidget() == NULL) + Create(); + g_surfwin = GetWidget (); +} +void SurfaceDlg::HideDlg() +{ + g_surfwin = NULL; + Dialog::HideDlg(); +} + +GtkWidget* SurfaceDlg::GetWidget() +{ + return g_SurfaceTable.m_pfnGet_SI_Module_Widget(); +} + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void SurfaceDlg::InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void SurfaceDlg::BuildDialog () +{ + GtkWidget *dlg, *vbox, *hbox2, *frame, *table, *label; + GtkWidget *button, *entry, *spin; + + dlg = m_pWidget; + + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posSurfaceWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Surface inspector"); + //g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (OnCancel), NULL); + // we catch 'Enter' and interpret is as OnDone + gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + // replaced by only the vbox: + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + label = gtk_label_new ("Texture"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", GTK_SIGNAL_FUNC (OnTextureKey), NULL); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, TRUE, TRUE, 0); + g_object_set_data (G_OBJECT (m_pWidget), "texture", entry); + +// table = gtk_table_new (5, 4, FALSE); + table = gtk_table_new (6, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Horizontal shift"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -8192, 8192, 2, 8, 8)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hshift", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "hshift_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Vertical shift"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -8192, 8192, 2, 8, 8)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vshift", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "vshift_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Horizontal stretch"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -1000, 1000, 1, 10, 10)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hscale", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 2, 3); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "hscale_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 2, 3); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Vertical stretch"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -1000, 1000, 1, 10, 10)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vscale", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "vscale_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Rotate"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -360, 360, 1, 10, 10)), 1, 0); + g_object_set_data (G_OBJECT (dlg), "rotate", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "rotate_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + // match grid button + button = gtk_button_new_with_label ("Match Grid"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 4, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnMatchGrid), NULL); + + frame = gtk_frame_new ("Texturing"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (4, 4, FALSE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + label = gtk_label_new ("Brush"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Patch"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + button = gtk_button_new_with_label ("Axial"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnAxial), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Fit"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnFaceFit), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("CAP"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Set..."); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Natural"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Fit"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchFit), NULL); + gtk_widget_set_usize (button, 60, -2); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 32, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nWidth, DLG_SPIN_INT); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 32, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nHeight, DLG_SPIN_INT); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Done"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnDone), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnApply), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnCancel), NULL); + gtk_widget_set_usize (button, 60, -2); + + // that's a bit of trashy stuff from Textool-v2 branch +#ifdef _DEBUG + // FIXME: testing only, scaling in BP mode + button = gtk_button_new_with_label ("Test"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnTest), NULL); + gtk_widget_set_usize (button, 60, -2); +#endif + + // Initialize + SetTexMods (); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +if faces selected (instead of brushes) -> will read this face texdef, else current texdef +if only patches selected, will read the patch texdef +=============== +*/ + +void SurfaceDlg::SetTexMods() +{ + texdef_t *pt; + brushprimit_texdef_t *bpt; + // local copy if a width=2 height=2 qtetxture_t is needed + brushprimit_texdef_t local_bp; + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg::SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + if (g_ptrSelectedFaces.GetSize() > 0) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + pt = &selFace->texdef; + if (g_qeglobals.m_bBrushPrimitMode) + { + // compute a texture matrix related to the default matrix width=2 height=2 + ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &local_bp, NULL ); + bpt = &local_bp; + } + } + else + { + pt = &g_qeglobals.d_texturewin.texdef; + if (g_qeglobals.m_bBrushPrimitMode) + { + bpt = &g_qeglobals.d_texturewin.brushprimit_texdef; + } + } + // brush primitive mode : compute fake shift scale rot representation + if (g_qeglobals.m_bBrushPrimitMode) + TexMatToFakeTexCoords( bpt->coords, m_shift, &m_rotate, m_scale ); + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + pt->SetName(SHADER_NOT_FOUND); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("texture")), pt->GetName()+9); + + GtkSpinButton *spin; + spin = GTK_SPIN_BUTTON (GetDlgWidget ("hshift")); + gtk_spin_button_set_digits (spin, 2); + if (g_qeglobals.m_bBrushPrimitMode) + gtk_spin_button_set_value (spin, m_shift[0]); + else + gtk_spin_button_set_value (spin, pt->shift[0]); + GtkAdjustment *adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + char buf[10]; // got into snprintf paranoia after BoundChecker detected a stack overrun +#ifdef _WIN32 + // TTimo: THIS IS UGLY +#define snprintf _snprintf +#endif + snprintf (buf, 10, "%g", l_pIncrement->shift[0]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("hshift_inc")), buf); + + spin = GTK_SPIN_BUTTON (GetDlgWidget ("vshift")); + gtk_spin_button_set_digits (spin, 2); + if (g_qeglobals.m_bBrushPrimitMode) + gtk_spin_button_set_value (spin, m_shift[1]); + else + gtk_spin_button_set_value (spin, pt->shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + snprintf (buf, 10, "%g", l_pIncrement->shift[1]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("vshift_inc")), buf); + + spin = GTK_SPIN_BUTTON (GetDlgWidget ("hscale")); + gtk_spin_button_set_digits (spin, 5); + gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_scale[0] : pt->scale[0]); + + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + snprintf (buf, 10, "%g", l_pIncrement->scale[0]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("hscale_inc")), buf); + + spin = GTK_SPIN_BUTTON (GetDlgWidget ("vscale")); + gtk_spin_button_set_digits (spin, 5); + gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_scale[1] : pt->scale[1]); + + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + snprintf (buf, 10, "%g", l_pIncrement->scale[1]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("vscale_inc")), buf); + + //++timo compute BProtate as int .. + spin = GTK_SPIN_BUTTON (GetDlgWidget ("rotate")); + gtk_spin_button_set_digits (spin, 2); + gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_rotate : pt->rotate); + + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + snprintf (buf, 10, "%g", l_pIncrement->rotate); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("rotate_inc")), buf); + + g_bListenChanged = true; + + // undo tricks: set the undo id to zero so we don't attempt to undo something that does not belong to us + m_nUndoId = 0; + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = g_qeglobals.d_texturewin.texdef; + // reset the Enter key behaviour flag + m_bEditingTextureWidget = false; +} + +/* +============== +GetTexMods + +Reads the fields to get the current texdef (i.e. widgets -> MAP) +in brush primitive mode, grab the fake shift scale rot and compute a new texture matrix +=============== +*/ +void SurfaceDlg::GetTexMods() +{ + char buffer[1024]; + texdef_t *pt; + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg::GetTexMods\n"); +#endif + + if (g_ptrSelectedFaces.GetSize() > 0) + { + //++timo just a test, we disable the undo when working on selected faces + m_nUndoId=0; + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + g_qeglobals.d_texturewin.texdef = selFace->texdef; +#ifdef DBG_SI + Sys_Printf("g_qeglobals.d_texturewin.texdef = selFace->texdef\n"); +#endif + } +// else +// { + pt = &g_qeglobals.d_texturewin.texdef; +#ifdef DBG_SI + Sys_Printf("pt = &g_qeglobals.d_texturewin.texdef\n"); +#endif +// } + + const char* text = gtk_entry_get_text (GTK_ENTRY (GetDlgWidget ("texture"))); + +#ifdef DBG_SI + Sys_Printf("pt->SetName(%s)\n", text ); +#endif + + // TTimo: detect and refuse invalid texture names (at least the ones with spaces) + if (text[0] <= ' ' || strchr(text, ' ')) + { + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + pt->SetName(SHADER_NOT_FOUND); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("texture")), pt->GetName()); + } + else + { + strcpy(buffer, "textures/"); + strcpy(buffer+9, text); + pt->SetName(buffer); + } + + + (g_qeglobals.m_bBrushPrimitMode ? m_shift[0] : pt->shift[0]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("hshift"))); + (g_qeglobals.m_bBrushPrimitMode ? m_shift[1] : pt->shift[1]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("vshift"))); + (g_qeglobals.m_bBrushPrimitMode ? m_scale[0] : pt->scale[0]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("hscale"))); + (g_qeglobals.m_bBrushPrimitMode ? m_scale[1] : pt->scale[1]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("vscale"))); + (g_qeglobals.m_bBrushPrimitMode ? m_rotate : pt->rotate) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("rotate"))); + + // a local copy of the texture matrix, given for a qtexture_t with width=2 height=2 + brushprimit_texdef_t local_bp; + brushprimit_texdef_t *bpt; + if (g_qeglobals.m_bBrushPrimitMode) + { + face_t *selFace = NULL; + if (g_ptrSelectedFaces.GetSize() > 0) + { + selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + bpt = &selFace->brushprimit_texdef; + } + else + { + bpt = &g_qeglobals.d_texturewin.brushprimit_texdef; + } + // compute texture matrix + // the matrix returned must be understood as a qtexture_t with width=2 height=2 + FakeTexCoordsToTexMat( m_shift, m_rotate, m_scale, local_bp.coords ); + // copy the texture matrix in the global struct + // fit the qtexture if we have a face selected, otherwise g_qeglobals.d_texturewin.brushprimit_texdef uses the basic qtexture_t with width=2 height=2 + + ConvertTexMatWithQTexture( &local_bp, NULL, bpt, ( (selFace) ? selFace->d_texture : NULL ) ); + } + // we are gonna do stuff, if we own the last do we undo it first + if (m_nUndoId != 0) + { + // check the do we're about to undo is the one we pushed earlier + if (m_nUndoId == Undo_GetUndoId()) + { +#ifdef DBG_SI + Sys_Printf("GetTexMods calling Undo_Undo (silent)\n"); +#endif + g_bListenUpdate=false; + Undo_Undo(true); + g_bListenUpdate=true; + } + } + Select_SetTexture(pt,&local_bp); + m_nUndoId = Undo_GetUndoId(); +} + +void SurfaceDlg::FitAll() +{ + OnBtnFaceFit(NULL, NULL); + OnBtnPatchFit(NULL, NULL); +} diff --git a/radiant/surfacedialog.h b/radiant/surfacedialog.h new file mode 100644 index 00000000..6d5d48a1 --- /dev/null +++ b/radiant/surfacedialog.h @@ -0,0 +1,69 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SURFACEDIALOG_H_ +#define _SURFACEDIALOG_H_ + +#include "dialog.h" + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +class SurfaceDlg : public Dialog +{ + bool m_bPatchMode; + // brush primitive fake shift scale rot coords + float m_shift[2]; + float m_rotate; + float m_scale[2]; + +public: + SurfaceDlg (); + + virtual void ShowDlg(); + virtual void HideDlg(); + void SetTexMods(); + void GetTexMods(); + + void InitDefaultIncrement(texdef_t *); + + // Dialog Data + int m_nHeight; + int m_nWidth; + + // 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for + int m_nUndoId; + + // is the user editing the texture widget (that changes the behaviour of 'Enter' key from OnDone to OnApply + // reset to false at each SetTexMods or when dealing with Enter key + bool m_bEditingTextureWidget; + +protected: + void BuildDialog (); + +public: + // called to perform a fitting from the outside (shortcut key) + void FitAll(); + GtkWidget *GetWidget (); // { return m_pWidget; } +}; + +#endif // _SURFACEDIALOG_H_ diff --git a/radiant/surfaceplugin.cpp b/radiant/surfaceplugin.cpp new file mode 100644 index 00000000..b4b73217 --- /dev/null +++ b/radiant/surfaceplugin.cpp @@ -0,0 +1,259 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// implementation of isurfaceplugin-interface specifics + +#include "stdafx.h" + +void QERApp_GetTwoSelectedPatch( patchMesh_t **p1, patchMesh_t **p2 ) +{ + *p1 = NULL; *p2 = NULL; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (!(*p1)) + *p1 = pb->pPatch; + else if (!(*p2)) + { + *p2 = pb->pPatch; + return; + } + } + } +#ifdef _DEBUG + Sys_Printf("WARNING: QERApp_GetTwoSelectedPatch failed (did not find two patches)\n"); +#endif + return; +} + +// Nurail: The following functions are used by the Surface Inspector module + +// Queries the number of faces from selected brushes +int SI_GetSelectedFaceCountfromBrushes(void) +{ + face_t *f; + brush_t *b; + int num_of_faces = 0; + + if(selected_brushes.next == &selected_brushes) + return(0); + + for(b=selected_brushes.next; b!=&selected_brushes; b=b->next) + if (!(b->patchBrush)) + for(f=b->brush_faces; f ; f=f->next, num_of_faces++); + + return num_of_faces; +} + +void SI_GetSelFacesTexdef(texdef_to_face_t *allocd_block_texdef) +{ + int i; + face_t *f; + brush_t *b; + texdef_to_face_t *position, *prev_pos; + + if(selected_brushes.next != &selected_brushes) + { + prev_pos = position = allocd_block_texdef; + for(b=selected_brushes.next; b!=&selected_brushes; b=b->next) + { + if ( !(b->patchBrush) ) + { + for(f=b->brush_faces; f ; f = f->next) + { + position->face = f; + position->brush = b; + position->texdef = f->texdef; + position->orig_texdef = f->texdef; + prev_pos->next = position; + prev_pos = position; + position++; + } + prev_pos->next = NULL; + } + } + } + else if(g_ptrSelectedFaces.GetSize() != 0) + { + f = (face_t *) g_ptrSelectedFaces.GetAt(0); + b = (brush_t *) g_ptrSelectedFaceBrushes.GetAt(0); + position = (texdef_to_face_t*) allocd_block_texdef; + position->face = f; + position->brush = b; + position->texdef = f->texdef; + position->orig_texdef = f->texdef; + prev_pos = position; + for(i=1; iface = f; + position->brush = b; + position->texdef = f->texdef; + position->orig_texdef = f->texdef; + prev_pos->next = position; + prev_pos = position; + } + position->next = NULL; + } + +} + +/* +SetFaceTexdef_Q2 + +This doesn't mess with CONTENTS_DETAIL needed for Quake2 content flag + +*/ +void SetFaceTexdef_Q2 (face_t *f, texdef_t *texdef, bool bFitScale) +{ + + if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build + Face_SetShader(f, texdef->GetName()); + + if (bFitScale) + { + f->texdef = *texdef; + // fit the scaling of the texture on the actual plane + vec3_t p1,p2,p3; // absolute coordinates + // compute absolute coordinates + ComputeAbsolute(f,p1,p2,p3); + // compute the scale + vec3_t vx,vy; + VectorSubtract(p2,p1,vx); + VectorNormalize(vx, vx); + VectorSubtract(p3,p1,vy); + VectorNormalize(vy, vy); + // assign scale + VectorScale(vx,texdef->scale[0],vx); + VectorScale(vy,texdef->scale[1],vy); + VectorAdd(p1,vx,p2); + VectorAdd(p1,vy,p3); + // compute back shift scale rot + AbsoluteToLocal(f->plane,f,p1,p2,p3); + } + else + { + f->texdef = *texdef; + } + } + + + +void SI_SetTexdef_FaceList(texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale) +{ + texdef_to_face_t* texdef_to_face; + bool b_isQuake2; + + if ( ( g_pGameDescription->mGameFile == "q2.game" ) || ( g_pGameDescription->mGameFile == "heretic2.game" ) ) + b_isQuake2 = true; + else + b_isQuake2 = false; + + if (!texdef_face_list) + return; + + if (b_SetUndoPoint) + { + if(g_ptrSelectedFaces.GetSize() > 1) + Sys_FPrintf(SYS_WRN, "WARNING: Undo NOT supported for multiple face selections\n"); + else if( (selected_brushes.next != &selected_brushes) || (g_ptrSelectedFaces.GetSize() == 1)) + { + // Give something to undo to + for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) + if (b_isQuake2) + SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->orig_texdef, bFit_to_Scale); + else + SetFaceTexdef(texdef_to_face->face, &texdef_to_face->orig_texdef, NULL); + + Undo_Start("set facelist texdefs"); + + if( selected_brushes.next != &selected_brushes ) + Undo_AddBrushList(&selected_brushes); + else + Undo_AddBrush(texdef_face_list->brush); + + } + } + + for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) + { + if (b_isQuake2) + SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->texdef, bFit_to_Scale); + else + SetFaceTexdef(texdef_to_face->face, &texdef_to_face->texdef, NULL , bFit_to_Scale); + Brush_Build(texdef_to_face->brush); + if(bFit_to_Scale) + texdef_to_face->texdef = texdef_to_face->face->texdef; + } + + if ( b_SetUndoPoint ) + { + if( (selected_brushes.next != &selected_brushes) || (g_ptrSelectedFaces.GetSize() == 1) ) + { + if(selected_brushes.next != &selected_brushes) + Undo_EndBrushList(&selected_brushes); + else + Undo_EndBrush(texdef_face_list->brush); + + Undo_End(); + // Over-write the orig_texdef list, cementing the change. + for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) + texdef_to_face->orig_texdef = texdef_to_face->texdef; + } + } + + Sys_UpdateWindows (W_ALL); +} + +void SI_FaceList_FitTexture(texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth) +{ + texdef_to_face_t* temp_texdef_face_list; + + if (!si_texdef_face_list) + return; + + for (temp_texdef_face_list = si_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + Face_FitTexture(temp_texdef_face_list->face, nHeight, nWidth); + Brush_Build(temp_texdef_face_list->brush,true,true,false,false); + // Write changes to our working Texdef list + temp_texdef_face_list->texdef = temp_texdef_face_list->face->texdef; + } + + Sys_UpdateWindows (W_CAMERA); + +} + +GtkWindow* SI_GetMainWindow(void) +{ + return GTK_WINDOW(g_qeglobals_gui.d_main_window); +} + +void SI_SetWinPos_from_Prefs(GtkWidget *win) +{ + load_window_pos (win, g_PrefsDlg.mWindowInfo.posSurfaceWnd); +} diff --git a/radiant/surfaceplugin.h b/radiant/surfaceplugin.h new file mode 100644 index 00000000..6f08c227 --- /dev/null +++ b/radiant/surfaceplugin.h @@ -0,0 +1,11 @@ +#ifndef _SURFACEPLUGIN_H +#define _SURFACEPLUGIN_H + +int SI_GetSelectedFaceCountfromBrushes(void); +void SI_GetSelFacesTexdef(texdef_to_face_t *allocd_block_texdef); +void SI_SetTexdef_FaceList(texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint = FALSE, bool bFit_to_Scale = FALSE); +void SI_FaceList_FitTexture(texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth); +GtkWindow* SI_GetMainWindow(void); +void SI_SetWinPos_from_Prefs(GtkWidget *win); + +#endif // _SURFACEPLUGIN_H diff --git a/radiant/targetname.cpp b/radiant/targetname.cpp new file mode 100644 index 00000000..f64089bb --- /dev/null +++ b/radiant/targetname.cpp @@ -0,0 +1,90 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" + +/*! +connects two entities creating a unique target/targetname value +*/ +void Entity_Connect(entity_t *e1, entity_t *e2) +{ + const char *maptarget; + char newtarget[16]; + int maxtarget=0; // highest t# value in the map + entity_t *e; // map entities + + if (e1 == e2) + { +#ifdef _DEBUG + Sys_Status ("Entity_Connect: Brushes are from same entity.", 0); +#endif + return; + } + + for (e=entities.next ; e != &entities ; e=e->next) + { + maptarget = ValueForKey (e, "target"); + if (maptarget && maptarget[0]) + { + int targetnum = atoi(maptarget+1); + if (targetnum > maxtarget) + maxtarget = targetnum; + } + } + sprintf (newtarget, "t%i", maxtarget+1); + +#ifdef _DEBUG + Sys_Printf("Connecting entities with new target/targetname: %s\n", newtarget); +#endif + + SetKeyValue (e1, "target", newtarget); + SetKeyValue (e2, "targetname", newtarget); +} + +int GetUniqueTargetId(int iHint) +{ + int iMin, iMax, i; + bool fFound; + entity_t *pe; + + fFound = FALSE; + pe = entities.next; + iMin = 0; + iMax = 0; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + i = IntForKey(pe, "target"); + if (i) + { + iMin = MIN(i, iMin); + iMax = MAX(i, iMax); + if (i == iHint) + fFound = TRUE; + } + } + + if (fFound) + return iMax + 1; + else + return iHint; +} + diff --git a/radiant/texmanip.cpp b/radiant/texmanip.cpp new file mode 100644 index 00000000..1e0c62ac --- /dev/null +++ b/radiant/texmanip.cpp @@ -0,0 +1,380 @@ +/* +Copyright (c) 2002 Forest "LordHavoc" Hale + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Forest Hale nor the names of other contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "stdafx.h" +#include "str.h" + +static byte *row1 = NULL, *row2 = NULL; +static int rowsize = 0; + +void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel) +{ + int j, xi, oldx = 0, f, fstep, endx, lerp; +#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) + + fstep = (int) (inwidth * 65536.0f / outwidth); + endx = (inwidth - 1); + if (bytesperpixel == 4) + { + for (j = 0,f = 0;j < outwidth;j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 4; + oldx = xi; + } + + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]); + *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + *out++ = in[3]; + } + } + } + else if (bytesperpixel == 3) + { + for (j = 0, f = 0; j < outwidth; j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 3; + oldx = xi; + } + + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (byte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (byte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (byte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + } + } + } + else + Sys_Printf("R_ResampleTextureLerpLine: unsupported bytesperpixel %i\n", bytesperpixel); +} + +/* +================ +R_ResampleTexture +================ +*/ +void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight, int bytesperpixel) +{ + if (rowsize < outwidth * bytesperpixel) + { + if (row1) + free(row1); + if (row2) + free(row2); + + rowsize = outwidth * bytesperpixel; + row1 = (byte *)malloc(rowsize); + row2 = (byte *)malloc(rowsize); + } + + if (bytesperpixel == 4) + { + int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4; + byte *inrow, *out; + out = (byte *)outdata; + fstep = (int) (inheight * 65536.0f / outheight); +#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) + + inrow = (byte *)indata; + oldy = 0; + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel); + + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (byte *)indata + inwidth4 * yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth4); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + LERPBYTE(12); + LERPBYTE(13); + LERPBYTE(14); + LERPBYTE(15); + out += 16; + row1 += 16; + row2 += 16; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + out += 8; + row1 += 8; + row2 += 8; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + out += 4; + row1 += 4; + row2 += 4; + } + row1 -= outwidth4; + row2 -= outwidth4; + } + else + { + if (yi != oldy) + { + inrow = (byte *)indata + inwidth4*yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth4); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + oldy = yi; + } + memcpy(out, row1, outwidth4); + } + } + } + else if (bytesperpixel == 3) + { + int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3; + byte *inrow, *out; + out = (byte *)outdata; + fstep = (int) (inheight*65536.0f/outheight); +#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) + + inrow = (byte *)indata; + oldy = 0; + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel); + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (byte *)indata + inwidth3*yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth3); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + out += 12; + row1 += 12; + row2 += 12; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + out += 6; + row1 += 6; + row2 += 6; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + out += 3; + row1 += 3; + row2 += 3; + } + row1 -= outwidth3; + row2 -= outwidth3; + } + else + { + if (yi != oldy) + { + inrow = (byte *)indata + inwidth3*yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth3); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + oldy = yi; + } + memcpy(out, row1, outwidth3); + } + } + } + else + Sys_Printf("R_ResampleTexture: unsupported bytesperpixel %i\n", bytesperpixel); +} + +// in can be the same as out +void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight) +{ + int x, y, width2, height2, nextrow; + if (width > destwidth) + { + if (height > destheight) + { + // reduce both + width2 = width >> 1; + height2 = height >> 1; + nextrow = width << 2; + for (y = 0;y < height2;y++) + { + for (x = 0;x < width2;x++) + { + out[0] = (byte) ((in[0] + in[4] + in[nextrow ] + in[nextrow+4]) >> 2); + out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2); + out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2); + out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2); + out += 4; + in += 8; + } + in += nextrow; // skip a line + } + } + else + { + // reduce width + width2 = width >> 1; + for (y = 0;y < height;y++) + { + for (x = 0;x < width2;x++) + { + out[0] = (byte) ((in[0] + in[4]) >> 1); + out[1] = (byte) ((in[1] + in[5]) >> 1); + out[2] = (byte) ((in[2] + in[6]) >> 1); + out[3] = (byte) ((in[3] + in[7]) >> 1); + out += 4; + in += 8; + } + } + } + } + else + { + if (height > destheight) + { + // reduce height + height2 = height >> 1; + nextrow = width << 2; + for (y = 0;y < height2;y++) + { + for (x = 0;x < width;x++) + { + out[0] = (byte) ((in[0] + in[nextrow ]) >> 1); + out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1); + out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1); + out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1); + out += 4; + in += 4; + } + in += nextrow; // skip a line + } + } + else + Sys_Printf("GL_MipReduce: desired size already achieved\n"); + } +} diff --git a/radiant/texmanip.h b/radiant/texmanip.h new file mode 100644 index 00000000..f3e0b5c3 --- /dev/null +++ b/radiant/texmanip.h @@ -0,0 +1,39 @@ +/* +Copyright (c) 2002 Forest "LordHavoc" Hale + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Forest Hale nor the names of other contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _TEXMANIP_H_ +#define _TEXMANIP_H_ + +void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel); +void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight, int bytesperpixel); +void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight); + +#endif // _TEXMANIP_H_ diff --git a/radiant/textures.h b/radiant/textures.h new file mode 100644 index 00000000..571319a4 --- /dev/null +++ b/radiant/textures.h @@ -0,0 +1,52 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +// a texturename of the form (0 0 0) will +// create a solid color texture + +void Texture_Init(); +void Texture_ShowDirectory (int menunum); +void Texture_ShowDirectory (); +void Texture_ShowAll(); +void WINAPI Texture_ShowInuse(); +extern char texture_directory[]; + +// Timo +// added an optional IPluginTexdef when one is available +// we need a forward declaration, this is crap +class IPluginTexdef; +//++timo clean +void Texture_SetTexture2 (IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, IPluginTexdef *pTexdef = NULL, bool bSetSelection = true); +void WINAPI Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, IPluginTexdef *pTexdef = (IPluginTexdef*)NULL, bool bSetSelection = true); + +void Texture_SetMode(int iMenu); // GL_TEXTURE_NEAREST, etc.. +void Texture_ResetPosition(); + +// build the list of shader files used by PreloadShaders +void BuildShaderList(); +// preload the shaders: build a list of shader names and properties .. don't load their assets +void PreloadShaders(); +int WINAPI Texture_LoadSkin(char *pName, int *pnWidth, int *pnHeight); +qtexture_t* Texture_LoadFromPlugIn(void* vp); +void Texture_StartPos (void); +IShader* Texture_NextPos (int *x, int *y); + diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp new file mode 100644 index 00000000..acc259b5 --- /dev/null +++ b/radiant/texwindow.cpp @@ -0,0 +1,1965 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Texture Window +// +// Leonardo Zide (leo@lokigames.com) +// + +/*!\todo +Clean up texture menu. +- Remove all global variables and use some objects instead. +- Create an interface for a plugin to add texture menu items. +- Make sure the interface is not dependent on gtk. +*/ + +#ifdef _WIN32 +//#include +#include +#endif +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#endif +#include +#include +#include +#include "stdafx.h" +#include "texwindow.h" +#include "str.h" +#include "missing.h" +#include "texmanip.h" + +#define TYP_MIPTEX 68 +static unsigned tex_palette[256]; + +#define FONT_HEIGHT 10 + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +//int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int g_nTextureOffset = 0; + +// current active texture directory +//++timo FIXME: I'm not sure this is used anymore +char texture_directory[128]; +// if true, the texture window will only display in-use shaders +// if false, all the shaders in memory are displayed +qboolean g_bShowAllShaders; + +bool g_bFilterEnabled = false; +CString g_strFilter; + +// texture layout functions +// TTimo: now based on shaders +int nActiveShadersCount; +int nCurrentShader; +IShader* pCurrentShader; +qtexture_t *current_texture = NULL; +int current_x, current_y, current_row; + +// globals for textures +int texture_nummenus; +char texture_menunames[MAX_TEXTUREDIRS][128]; + +// the list of scripts/*.shader files we need to work with +// those are listed in shaderlist file +// FIXME TTimo I get the feeling that those would need to move to the shaders module +// for now it's still more simple to just keep it here +GSList *l_shaderfiles = NULL; + +void SelectTexture (int mx, int my, bool bShift, bool bFitScale=false); + +void Texture_MouseDown (int x, int y, int buttons); +void Texture_MouseMoved (int x, int y, int buttons); + +CPtrArray g_lstSkinCache; + +// TTimo: modifed to add a qtexture_t, Texture_LoadSkin loads using the shader API / QERApp_TryTexture_ForName +// m_strName is a copy of qtex->name +struct SkinInfo +{ + CString m_strName; + int m_nTextureBind; + qtexture_t *m_qtex; + SkinInfo(const char *pName, int n, qtexture_t *qtex) + { + m_strName = pName; + m_nTextureBind = n; + m_qtex = qtex; + }; + SkinInfo(){}; +}; + +// ============================================================================= +// global functions + +// gets active texture extension +// +// FIXME: fix this to be generic from project file +// +int GetTextureExtensionCount() +{ + // hardcoded hack for png support + if (g_pGameDescription->mGameFile == "sof2.game") + return 3; + else + return 2; +} + +const char* GetTextureExtension(int nIndex) +{ + switch(nIndex) + { + case 0: + return "tga"; + break; + case 1: + return "jpg"; + break; + case 2: + return "png"; + break; + default: + return NULL; + } +} + +/* +============== +Texture_InitPalette +============== +*/ +void Texture_InitPalette (byte *pal) +{ + int r,g,b; + int i; + int inf; + byte gammatable[256]; + float gamma; + + gamma = g_qeglobals.d_savedinfo.fGamma; + + if (gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + gammatable[i] = i; + } else + { + for (i=0 ; i<256 ; i++) + { + inf = (int)( 255.0f * pow( ( i + 0.5f ) / 255.5f , gamma ) + 0.5f ); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } + } + + for (i=0 ; i<256 ; i++) + { + r = gammatable[pal[0]]; + g = gammatable[pal[1]]; + b = gammatable[pal[2]]; + pal += 3; + + //v = (r<<24) + (g<<16) + (b<<8) + 255; + //v = BigLong (v); + + //tex_palette[i] = v; + tex_palette[i*3+0] = r; + tex_palette[i*3+1] = g; + tex_palette[i*3+2] = b; + } +} + +void SetTexParameters (void) +{ + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode ); + + switch ( texture_mode ) + { + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + } +} + +/* +============ +Texture_SetMode +============ +*/ +void Texture_SetMode(int iMenu) +{ + int iMode; + qboolean texturing = true; + gpointer item = NULL; + + switch (iMenu) + { + case ID_VIEW_NEAREST: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearest"); + iMode = GL_NEAREST; + break; + case ID_VIEW_NEARESTMIPMAP: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearestmipmap"); + iMode = GL_NEAREST_MIPMAP_NEAREST; + break; + case ID_VIEW_LINEAR: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_linear"); + iMode = GL_LINEAR; + break; + case ID_VIEW_BILINEAR: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinear"); + iMode = GL_NEAREST_MIPMAP_LINEAR; + break; + case ID_VIEW_BILINEARMIPMAP: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinearmipmap"); + iMode = GL_LINEAR_MIPMAP_NEAREST; + break; + case ID_VIEW_TRILINEAR: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_trilinear"); + iMode = GL_LINEAR_MIPMAP_LINEAR; + break; + case ID_TEXTURES_WIREFRAME: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_wireframe"); + iMode = -1; + texturing = false; + break; + case ID_TEXTURES_FLATSHADE: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_flatshade"); + iMode = -1; + texturing = false; + break; + } + + g_qeglobals.d_savedinfo.iTexMenu = iMenu; + // NOTE: texture_mode is a GLenum used directly in glTexParameter + if(iMode!=-1) texture_mode = iMode; + + g_bIgnoreCommands++; + if (item != NULL) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + if (texturing) + SetTexParameters (); + + if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME) + { + g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_wire; + Map_BuildBrushData(); + Sys_UpdateWindows (W_ALL); + return; + } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE) + { + g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_solid; + Map_BuildBrushData(); + Sys_UpdateWindows (W_ALL); + return; + } + + for (qtexture_t *q = g_qeglobals.d_qtextures; q; q = q->next) + { + qglBindTexture (GL_TEXTURE_2D, q->texture_number); + SetTexParameters (); + } + + // select the default texture + qglBindTexture( GL_TEXTURE_2D, 0 ); + + qglFinish(); + + if (g_pParentWnd->GetCamWnd()->Camera()->draw_mode != cd_texture) + { + g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_texture; + Map_BuildBrushData(); + } + + Sys_UpdateWindows (W_ALL); +} + +/*! +gamma correction stuff +took out of QERApp_LoadTextureRGBA for clarity +*/ +byte g_gammatable[256]; +void ResampleGamma(float fGamma) +{ + int i,inf; + if (fGamma == 1.0) + { + for (i = 0; i < 256; i++) + g_gammatable[i] = i; + } else + { + for (i = 0; i < 256; i++) + { + inf = (int)( 255.0f * pow( (i + 0.5f) / 255.5f , fGamma ) + 0.5f ); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + g_gammatable[i] = inf; + } + } +} + +/*! +this function does the actual processing of raw RGBA data into a GL texture +it will also generate the mipmaps +it looks like pPixels nWidth nHeight are the only relevant parameters +*/ +qtexture_t *QERApp_LoadTextureRGBA(unsigned char* pPixels, int nWidth, int nHeight) +{ + static float fGamma = -1; + float total[3]; + byte *outpixels = NULL; + int i, j, resampled, width2, height2, width3, height3; + int max_tex_size = 0, mip = 0; + int nCount = nWidth * nHeight; + + if (fGamma != g_qeglobals.d_savedinfo.fGamma) + { + fGamma = g_qeglobals.d_savedinfo.fGamma; + ResampleGamma(fGamma); + } + + qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); + if (!max_tex_size) + max_tex_size = 1024; + + qtexture_t *q = (qtexture_t*)g_malloc(sizeof(*q)); + q->width = nWidth; + q->height = nHeight; + + total[0] = total[1] = total[2] = 0.0f; + + // resample texture gamma according to user settings + for (i = 0; i < (nCount * 4); i += 4) + { + for (j = 0; j < 3; j++) + { + total[j] += (pPixels + i)[j]; + byte b = (pPixels + i)[j]; + (pPixels + i)[j] = g_gammatable[b]; + } + } + + q->color[0] = total[0] / (nCount * 255); + q->color[1] = total[1] / (nCount * 255); + q->color[2] = total[2] / (nCount * 255); + + qglGenTextures (1, &q->texture_number); + + qglBindTexture( GL_TEXTURE_2D, q->texture_number ); + + SetTexParameters(); + + width2 = 1; while (width2 < nWidth) width2 <<= 1; + height2 = 1; while (height2 < nHeight) height2 <<= 1; + + width3 = width2; + height3 = height2; + while (width3 > max_tex_size) width3 >>= 1; + while (height3 > max_tex_size) height3 >>= 1; + if (width3 < 1) width3 = 1; + if (height3 < 1) height3 = 1; + + if (!(width2 == nWidth && height2 == nHeight)) { + resampled = 1; + outpixels = (byte *)malloc(width2 * height2 * 4); + R_ResampleTexture(pPixels, nWidth, nHeight, outpixels, width2, height2, 4); + } else { + resampled = 0; + outpixels = pPixels; + } + + while (width2 > width3 || height2 > height3) + { + GL_MipReduce(outpixels, outpixels, width2, height2, width3, height3); + + if (width2 > width3) + width2 >>= 1; + if (height2 > height3) + height2 >>= 1; + } + + qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels); + while (width2 > 1 || height2 > 1) + { + GL_MipReduce(outpixels, outpixels, width2, height2, 1, 1); + + if (width2 > 1) + width2 >>= 1; + if (height2 > 1) + height2 >>= 1; + + qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels); + } + + qglBindTexture(GL_TEXTURE_2D, 0); + if (resampled) + free(outpixels); + + return q; +} + +/* +================== +DumpUnreferencedShaders +usefull function: dumps the list of .shader files that are not referenced to the console +================== +*/ +void DumpUnreferencedShaders() +{ + GSList *lst, *sh, *files; + bool bFound = false; + + files = vfsGetFileList ("scripts", "shader"); + for (lst = files; lst; lst = lst->next) + { + bool listed = false; + + for (sh = l_shaderfiles; sh != NULL; sh = g_slist_next (sh)) + if (!strcmp ((char*)sh->data, (char*)lst->data)) + { + listed = true; + break; + } + + if (!listed) + { + if (!bFound) + { + bFound = true; + Sys_FPrintf (SYS_WRN, "Following shader files are not referenced in shaderlist.txt:\n"); + } + Sys_FPrintf (SYS_WRN, "%s\n", (char*)lst->data); + } + } + + vfsClearFileDirList (&files); +} + +/* +================== +BuildShaderList +build a CStringList of shader names +================== +*/ +void BuildShaderList() +{ + int count; + char filename[1024]; + char *pBuff; + char dirstring[NAME_MAX]; + int nLen; + if (l_shaderfiles!=NULL) + { + g_slist_free(l_shaderfiles); + l_shaderfiles = NULL; + } + + if (g_pGameDescription->mGameFile != "hl.game") + { + strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer()); + count = vfsGetFileCount(filename, 0 ); + if (count==0) + { + Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + return; + } + // NOTE TTimo we use vfsGetFullPath solely to get the full path of the shader list we are gonna load + // but we actually send the relative path to vfsLoadFile + // so let's hope there is no disparity between the two functions + if (!vfsGetFullPath(filename, 0, 0)) + { + Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + return; + } + Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0)); + nLen = vfsLoadFile (filename, reinterpret_cast(&pBuff), 0); + if (nLen > 0) + { + StartTokenParsing(pBuff); + nLen = 0; + while (GetToken(true)) + { + GSList *tmp; + bool found = false; + + // each token should be a shader filename + sprintf(dirstring, "%s.shader", token); + + for (tmp = l_shaderfiles; tmp != NULL; tmp = tmp->next) + { + if (!strcmp (dirstring, (char*)tmp->data)) + { + found = true; + Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data); + break; + } + } + + if (!found) + { + l_shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring)); + nLen++; + } + } + g_free(pBuff); + } + } +} + +/* +================== +FillTextureMenu + +================== +*/ +void ClearGSList (GSList* lst) +{ + GSList *p = lst; + while (p) + { + free (p->data); + p = g_slist_remove (p, p->data); + } +} + +void FillTextureMenu (GSList** pArray) +{ + GtkWidget *menu, *sep, *item; // point to the Textures GtkMenu and to the last separator + GList *lst; + GSList *texdirs = NULL; + GSList *texdirs_tmp = NULL; + GSList *p; + char dirRoot[NAME_MAX]; + // this is an index used to count the number of texture items (for splitting/avoiding to get out of window) + // we start with a != 0 value to compensate for the initial number of items in the texture menu + int nMenuCount = 12; + + // delete everything + menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures")); + sep = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures_separator")); + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + while (lst->next) + { + // these delete functions are recursive, it's gonna free all submenus + gtk_widget_destroy (GTK_WIDGET (lst->next->data)); + // lst is no longer relevant, need to get it again + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + } + + texture_nummenus = 0; + + // add everything + if (!g_qeglobals.d_project_entity) + return; + + // scan texture dirs and pak files only if not restricting to shaderlist + if (!g_PrefsDlg.m_bTexturesShaderlistOnly) + { + texdirs_tmp = vfsGetDirList ("textures/"); + for (p=texdirs_tmp; p; p=g_slist_next(p)) + { + // Hydra: erm, this didn't used to do anything except leak memory... + // For Halflife support this is required to work however. + // g_slist_append(texdirs, p->data); + texdirs = g_slist_append(texdirs, strdup((char *)p->data)); + } + vfsClearFileDirList (&texdirs_tmp); + } + + // scan the shaders in shaderlist.txt + BuildShaderList (); + PreloadShaders (); + DumpUnreferencedShaders (); + while (l_shaderfiles != NULL) + { + char shaderfile[PATH_MAX]; + gboolean found = FALSE; + + ExtractFileName ((char*)l_shaderfiles->data, shaderfile); + StripExtension (shaderfile); + g_strdown (shaderfile); + + for (GSList *tmp = texdirs; tmp; tmp = g_slist_next (tmp)) + if (!strcasecmp ((char*)tmp->data, shaderfile)) + { + found = TRUE; + break; + } + + if (!found) + texdirs = g_slist_prepend (texdirs, strdup (shaderfile)); + + free (l_shaderfiles->data); + l_shaderfiles = g_slist_remove (l_shaderfiles, l_shaderfiles->data); + } + + // sort the list + texdirs = g_slist_sort (texdirs, (GCompareFunc)strcmp); + + GSList *temp = texdirs; + while (temp) + { + char* ptr = strchr ((char*)temp->data, '_'); + + // do we shrink the menus? + if (ptr != NULL) + { + // extract the root + strcpy (dirRoot, (char*)temp->data); + dirRoot[ptr - (char*)temp->data + 1] = 0; + + // we shrink only if we have at least two things to shrink :-) + if (temp->next && (strstr ((char*)temp->next->data, dirRoot) == (char*)temp->next->data)) + { + GtkWidget *pSubMenu = gtk_menu_new (); + GtkWidget *pSubMenuRef = pSubMenu; + // keep going... + do + { + item = gtk_menu_item_new_with_label ((char*)temp->data); + gtk_widget_show (item); + CheckMenuSplitting (pSubMenu); + gtk_container_add (GTK_CONTAINER (pSubMenu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus)); + + strcpy (texture_menunames[texture_nummenus], (char*)temp->data); + strcat (texture_menunames[texture_nummenus], "/"); + if (pArray) + *pArray = g_slist_append (*pArray, strdup ((char*)temp->data)); + if (++texture_nummenus == MAX_TEXTUREDIRS) + { + Sys_Printf("WARNING: max texture directories count has been reached!\n"); + // push submenu and get out + item = gtk_menu_item_new_with_label (dirRoot); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenu); + ClearGSList (texdirs); + return; + } + temp = temp->next; + } + while (temp && (strstr((char*)temp->data, dirRoot)==temp->data)); + + ptr = strchr (dirRoot, '_'); + *ptr = 0; + item = gtk_menu_item_new_with_label (dirRoot); + gtk_widget_show (item); + CheckMenuSplitting (menu); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenuRef); + continue; + } + } + + item = gtk_menu_item_new_with_label ((char*)temp->data); + gtk_widget_show (item); + CheckMenuSplitting (menu); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus)); + + strcpy (texture_menunames[texture_nummenus], (char*)temp->data); + strcat (texture_menunames[texture_nummenus], "/"); + if (pArray) + *pArray = g_slist_append (*pArray, strdup ((char*)temp->data)); + if (++texture_nummenus == MAX_TEXTUREDIRS) + { + Sys_Printf("WARNING: max texture directories count has been reached!\n"); + ClearGSList (texdirs); + return; + } + + temp = temp->next; + } + ClearGSList (texdirs); +} + +/* +============== +Texture_ShowDirectory +relies on texture_directory global for the directory to use +called by + void Texture_ShowDirectory (int menunum, bool bLinked) + void Texture_ShowDirectory (char* pPath, bool bLinked) +1) Load the shaders for the given directory +2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader) +NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made + available through the IShaders interface +NOTE: for texture window layout: + all shaders are stored with alphabetical order after load + previously loaded and displayed stuff is hidden, only in-use and newly loaded is shown + ( the GL textures are not flushed though) +============== +*/ +void Texture_ShowDirectory () +{ + char name[1024]; + char dirstring[1024]; + CString strTemp; + int shaders_count = 0; + int textures_count = 0; + GSList *files = NULL, *temp; + + g_bScreenUpdates = false; + + // refresh the in-use textures: that will clear the IsDisplayed flag on unused stuff + // and leave it on in-use so they'll still be displayed + Texture_ShowInuse(); + // and textures loaded in the following lines will be displayed as well... + // NOTE: shaders that are not in use but have been loaded previously are still in memory. But they don't get displayed. + + g_qeglobals.d_texturewin.originy = 0; + // load texture_directory.shader + // NOTE: because of above call to Texture_ClearInuse, g_ActiveShaders will have the newly loaded shaders only + // we'll use that later to check if textures have a shader associated or not + // NOTE: all shaders loaded through QERApp_LoadShadersFromDir will get their InUse flag to True, we'll need a call to Texture_ShowInUse for later cleanup/adjustment + // NOTE: QERApp_LoadShadersFromDir has two criterions for loading a shader: + // the shaderfile is texture_directory (like "museum" will load everything in museum.shader) + // the shader name contains texture_directory (like "base_floor" will load museum.shader::base_floor/concfloor_rain) + shaders_count = QERApp_LoadShadersFromDir(texture_directory); + // load remaining texture files + // if a texture is already in use to represent a shader, ignore it + + // need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);" + + sprintf (dirstring, "textures/%s", texture_directory); + g_ImageManager.BeginExtensionsScan(); + const char* ext; + while(ext=g_ImageManager.GetNextExtension()) + { + files = g_slist_concat(files, vfsGetFileList (dirstring, ext)); + } + + for (temp = files; temp; temp = temp->next) + { + sprintf(name, "%s%s", texture_directory, (char*)temp->data); + + StripExtension (name); + strTemp = name; + strTemp.MakeLower(); + + if (strTemp.Find(".specular") >= 0 || + strTemp.Find(".glow") >= 0 || + strTemp.Find(".bump") >= 0 || + strTemp.Find(".diffuse") >= 0 || + strTemp.Find(".blend") >= 0 || + strTemp.Find(".alpha") >= 0) + continue; + + // avoid ever loading a texture name with spaces + if (strTemp.Find(" ") >= 0) + { + Sys_FPrintf(SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer()); + continue; + } + + // build a texture name that fits the conventions for qtexture_t::name + char stdName[1024]; + sprintf( stdName, "textures/%s", name ); + // check if this texture doesn't have a shader + if (!QERApp_ActiveShader_ForTextureName( stdName )) + { + QERApp_CreateShader_ForTextureName (stdName); + textures_count++; + } + } + + Sys_Printf("Loaded %d shaders and created default shader for %d orphan textures.\n", + shaders_count, textures_count ); + + vfsClearFileDirList (&files); + + // sort for displaying + QERApp_SortActiveShaders(); + + sprintf (name, "Textures: %s", texture_directory); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) + SelectTexture (16, g_qeglobals.d_texturewin.height -16, false); + + g_bScreenUpdates = true; + + Sys_UpdateWindows (W_TEXTURE); +} + +/* +============== +Texture_ShowDirectory +1) Load the shaders for the given directory +2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader) +NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made + available through the IShaders interface +============== +*/ +void Texture_ShowDirectory (int menunum) +{ + strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]); + Texture_ShowDirectory(); +} + +// scroll origin so the current texture is completely on screen +// if current texture is not displayed, nothing is changed +void Texture_ResetPosition() +{ + qtexture_t *q; + int x,y; + + //this shouldn't ever happen, we startup with notex + if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) { + return; + } + + // otherwise position with current texture shown + // this used to be in Texture_SetTexture + Texture_StartPos (); + while (1) + { + // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture + Texture_NextPos (&x, &y); + q = current_texture; + // if the current texture never found (because // 'show shaders' is off, + // for example), do nothing + if (!q) + break; + + int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + // we have found when texdef->name and the shader name match + // NOTE: as everywhere else for our comparisons, we are not case sensitive + if (!strcmpi( g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName() )) + { + // take care of calls before initialized + if ( !g_qeglobals.d_texturewin.height) { + g_qeglobals.d_texturewin.originy = 0; + break; + } + // if the bottom of our selected texture will fit with origin 0, use that + // to prevent scrolling uglyness (stuff scrolled off screen when + // everything would fit) + if ( -(y -nHeight-2*FONT_HEIGHT) < g_qeglobals.d_texturewin.height) { + g_qeglobals.d_texturewin.originy = 0; + break; + } + // if current is off the top of the window, move it to the top + if (y > g_qeglobals.d_texturewin.originy) + { + g_qeglobals.d_texturewin.originy = y; + break; + } + + // if current is off the bottom, put it on the bottom + if (y-nHeight-2*FONT_HEIGHT < g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height) + { + g_qeglobals.d_texturewin.originy = y-nHeight-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height; + break; + } + // if we made it here, it should already be in view + break; + } + } + Sys_UpdateWindows (W_TEXTURE); +} + +/* +============== +Texture_ShowAll +will set the IsDisplayed flag on all the active shaders, so we see everything that's currently in memory +============== +*/ +void Texture_ShowAll() +{ + char name[1024]; + +#ifdef _DEBUG + if (g_bShowAllShaders) + Sys_Printf("WARNING: already showing all shaders\n"); +#endif + QERApp_ActiveShaders_SetDisplayed(true); + g_bShowAllShaders = true; + // put some information in the texture window title? + sprintf (name, "Textures: in use"); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); + Sys_UpdateWindows (W_TEXTURE); +} + +/* +============== +Texture_ShowInuse +clear all IsDisplayed flags +scan the map, set IsInUse (will set IsDisplayed on the way) +NOTE: don't sort the textures, don't update the windows (it's used in several contexts, not always necessary to do either) +============== +*/ +void WINAPI Texture_ShowInuse (void) +{ + face_t *f; + brush_t *b; + char name[1024]; + + g_qeglobals.d_texturewin.originy = 0; + + // purge + QERApp_ActiveShaders_SetDisplayed(false); + // scan and only display in-use stuff + Sys_Status("Selecting active textures", 0); + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) + { + if (b->patchBrush) + { + b->pPatch->pShader->SetInUse(true); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + f->pShader->SetInUse(true); + } + } + } + for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next) + { + if (b->patchBrush) + { + b->pPatch->pShader->SetInUse(true); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + f->pShader->SetInUse(true); + } + } + } + + // we are no longer showing everything + g_bShowAllShaders = false; + // put some information in the texture window title? + sprintf (name, "Textures: in use"); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); + + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) + { + SelectTexture (16, g_qeglobals.d_texturewin.height -16, false); + } +} + +void Texture_ShowStartupShaders() +{ + if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_COMMON) + { + // RIANT + // HACK FOR JK2 SUPPORT + if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + { + strcpy (texture_directory, "system/"); + } + // RIANT + // HACK FOR SOF2 SUPPORT + else if (g_pGameDescription->mGameFile == "sof2.game") + { + strcpy (texture_directory, "tools/"); + } + else strcpy (texture_directory, "common/"); + Texture_ShowDirectory (); + } + + if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_ALL) { + int count; + char filename[1024]; + char *pBuff; + char dirstring[NAME_MAX]; + int nLen; + GSList *shaderfiles = NULL; + + strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer()); + count = vfsGetFileCount(filename, 0); + if (count == 0) + { + Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + return; + } + + if (!vfsGetFullPath(filename, 0, 0)) + { + Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + return; + } + + Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0)); + nLen = vfsLoadFile (filename, reinterpret_cast(&pBuff), 0); + if (nLen > 0) + { + StartTokenParsing(pBuff); + nLen = 0; + while (GetToken(true)) + { + GSList *tmp; + bool found = false; + + // each token should be a shader filename + sprintf(dirstring, "%s.shader", token); + + for (tmp = shaderfiles; tmp != NULL; tmp = tmp->next) + { + if (!strcmp (dirstring, (char*)tmp->data)) + { + found = true; + Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data); + break; + } + } + + if (!found) + { + shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring)); + strcpy (texture_directory, dirstring); + Texture_ShowDirectory (); + nLen++; + } + } + g_free(pBuff); + } + } +} + +/* +============================================================================ + +TEXTURE LAYOUT + +TTimo: now based on a rundown through all the shaders +nActiveShadersCount: number of shader that have a qtexture_t and may be displayed in the tex window +nCurrentShader: index of active shader that has the current_texture +pCurrentShader: IShader* for current shader +NOTE: we expect the Active shaders count doesn't change during a Texture_StartPos .. Texture_NextPos cycle + otherwise we may need to rely on a list instead of an array storage +============================================================================ +*/ + +void Texture_StartPos (void) +{ + //++timo TODO: check use of current_texture and current_row? + current_x = 8; + current_y = -8; + current_row = 0; + nActiveShadersCount = QERApp_GetActiveShaderCount(); + nCurrentShader = -1; + current_texture = NULL; + pCurrentShader = NULL; +} + +// if texture_showinuse jump over non in-use textures +// it's not very clear what should be done here and what in Texture_Draw .. maybe merging the two would do good +IShader* Texture_NextPos (int *x, int *y) +{ + qtexture_t* q; + while (1) + { + if (nCurrentShader >= nActiveShadersCount - 1) + { + // no more shaders + current_texture = NULL; + pCurrentShader = NULL; + return NULL; + } + nCurrentShader++; + pCurrentShader = QERApp_ActiveShader_ForIndex(nCurrentShader); + if (pCurrentShader == NULL) + { + Sys_Printf("ERROR: unexpected pCurrentShader == NULL in Texture_NextPos\n"); + return NULL; + } + current_texture = pCurrentShader->getTexture(); + q = current_texture; + + if (!q) + { + Sys_Printf("WARNING: found an IShader without qtexture_t in Texture_NextPos\n"); + return NULL; + } + + /* + Never show anything other than "textures/" path, + This is for q1/q2/q3 .map format, which expects "textures/" path on everything we apply + */ + if(strncmp(pCurrentShader->getName(), "textures/", 9) != 0) + continue; + + // don't show shaders? + if (!(g_PrefsDlg.m_bShowShaders || pCurrentShader->IsDefault())) + continue; + + if (g_PrefsDlg.m_bTextureWindow) + { + // some basic filtering + if (!g_pParentWnd->GetTexWnd()->CheckFilter( pCurrentShader->getName() )) + continue; + } + + //++timo FIXME: texture_showinuse is useless? with the menu and reload we just refresh the IsDisplayed flag + // but the IsInUse is only relevant to draw the green outline + if (pCurrentShader->IsDisplayed()) + break; + + continue; + } + + int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); + int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + if (current_x + nWidth > g_qeglobals.d_texturewin.width-8 && current_row) + { // go to the next row unless the texture is the first on the row + current_x = 8; + current_y -= current_row + FONT_HEIGHT + 4; + current_row = 0; + } + + *x = current_x; + *y = current_y; + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (current_row < nHeight) + current_row = nHeight; + + // never go less than 64, or the names get all crunched up + current_x += nWidth < 64 ? 64 : nWidth; + current_x += 8; + + return pCurrentShader; +} + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int textures_cursorx, textures_cursory; + +/* +============ +Texture_SetTexture + +brushprimit_texdef must be understood as a qtexture_t with width=2 height=2 ( the default one ) +============ +*/ + +//++timo NOTE: this is a mix of Shader module stuff and texture explorer +// it might need to be split in parts or moved out .. dunno +void WINAPI Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef *pTexdef, bool bSetSelection ) +{ + if (texdef->GetName()[0] == '(') + { + Sys_Status("Can't select an entity texture", 0); + return; + } + g_qeglobals.d_texturewin.texdef = *texdef; + g_qeglobals.d_texturewin.texdef.flags &= ~SURF_KEEP; + g_qeglobals.d_texturewin.texdef.contents &= ~CONTENTS_KEEP; + // store the shader pointer + // NOTE: maybe passing the shader pointer would help? + g_qeglobals.d_texturewin.pShader->DecRef(); + g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(texdef->GetName()); + g_qeglobals.d_texturewin.pShader->IncRef(); + // set this shader as in use + g_qeglobals.d_texturewin.pShader->SetInUse( true ); + // store the texture coordinates for new brush primitive mode + // be sure that all the callers are using the default 2x2 texture + if (g_qeglobals.m_bBrushPrimitMode) + { + g_qeglobals.d_texturewin.brushprimit_texdef = *brushprimit_texdef; + } + + g_dlgFind.updateTextures(texdef->GetName()); + if (!g_dlgFind.isOpen() && bSetSelection) + { + Select_SetTexture(texdef,brushprimit_texdef,bFitScale); + } + + //plugins: send a message telling that the selected texture may have changed + DispatchRadiantMsg( RADIANT_TEXTURE ); + + // scroll origin so the texture is completely on screen + // takes texdef from g_qeglobals.d_texturewin.texdef, set above + Texture_ResetPosition(); +} + +void ViewShader(const char *pFile, const char *pName) +{ + // ask the vfs to build the full path to the file + // (i.e. the first one found) + char *fullName = vfsGetFullPath(pFile,0,0); + if (fullName == NULL) + { + Sys_FPrintf (SYS_ERR, "Couldn't get a full path to the shader file: %s\n", pFile); + return; + } + + char* pBuff = NULL; + int nSize = vfsLoadFullPathFile(fullName, reinterpret_cast(&pBuff)); + if (nSize <= 0) + { + Sys_FPrintf (SYS_ERR, "Failed to load shader file %s\n", fullName); + return; + } + // look for the shader declaration + int nStart; + CString strFind = pName; + CString strLook = pBuff; + strLook.MakeLower(); + strFind.MakeLower(); + // offset used when jumping over commented out definitions + int nOffset = 0; + while (true) + { + nStart = strLook.Find(strFind, nOffset); + if (nStart == -1) + break; + // we have found something, maybe it's a commented out shader name? + char *strCheck = new char[strLook.GetLength()+1]; + strcpy( strCheck, strLook.GetBuffer() ); + strCheck[nStart] = 0; + char *pCheck = strrchr( strCheck, '\n' ); + // if there's a commentary sign in-between we'll continue + if (pCheck && strstr( pCheck, "//" )) + { + delete[] strCheck; + nOffset = nStart + 1; + continue; + } + delete[] strCheck; + nOffset = nStart; + break; + } + // now close the file + g_free(pBuff); + + DoTextEditor (fullName, nOffset); +} + +/* +============== +SelectTexture + + By mouse click +============== +*/ +void SelectTexture (int mx, int my, bool bShift, bool bFitScale) +{ + int x, y; + qtexture_t *q; + texdef_t tex; + brushprimit_texdef_t brushprimit_tex; + + my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height; + + Texture_StartPos (); + while (1) + { + // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture + Texture_NextPos (&x, &y); + q = current_texture; + if (!q) + break; + int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); + int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + if (mx > x && mx - x < nWidth + && my < y && y - my < nHeight + FONT_HEIGHT) + { + if (bShift) + { + if (pCurrentShader->IsDefault()) + Sys_Printf("ERROR: %s is not a shader, it's a texture.\n", pCurrentShader->getName() ); + else + ViewShader( pCurrentShader->getShaderFileName(), pCurrentShader->getName() ); + } + else + { + memset (&tex, 0, sizeof(tex)); + memset (&brushprimit_tex, 0, sizeof(brushprimit_tex)); + if (g_qeglobals.m_bBrushPrimitMode) + { + // brushprimit fitted to a 2x2 texture + brushprimit_tex.coords[0][0] = 1.0f; + brushprimit_tex.coords[1][1] = 1.0f; + } + else + { + tex.scale[0] = g_pGameDescription->mTextureDefaultScale; + tex.scale[1] = g_pGameDescription->mTextureDefaultScale; + } + tex.flags = pCurrentShader->getFlags(); + // TTimo - shader code cleanup + // texdef.name is the name of the shader, not the name of the actual texture file + tex.SetName(pCurrentShader->getName()); + // NOTE WARNING: Texture_SetTexture uses Texture_NextPos stuff to move the window position on to the texture + // if there's some kind of fuckup in Texture_SetTexture you may end up with different pCurrentShader or even pCurrentShader == NULL + // so we just consider pCurrentShader and current_texture are not valid after this point + IShader *pAuxShader = pCurrentShader; + Texture_SetTexture ( &tex, &brushprimit_tex, bFitScale, NULL); // Nurail + CString strTex; + CString strName; + // if shader, print shader name, otherwise texture name + //++timo FIXME: maybe CShader needs some properties between color / default / actual shader +#ifdef _DEBUG + // this one is never supposed to be set as current one + if (pAuxShader->IsColor()) + Sys_Printf("ERROR: unexpected pCurrentShader->IsColor() in SelectTexture\n"); +#endif + // NOTE: IsColor is false, IsDefault the only remaining property + if (pAuxShader->IsDefault()) + { + strName = q->name; + // remove the "textures/" if needed + if (strName.Find("textures/")!=-1) + strName = strName.Mid(9); + } + else + { + strName = pAuxShader->getName(); + } + strTex.Format("%s W: %i H: %i", strName.GetBuffer(), q->width, q->height); + g_pParentWnd->SetStatusText(3, strTex); + } + return; + } + } + + Sys_Status("Did not select a texture", 0); +} + +/* +============== +Texture_MouseDown +============== +*/ +void Texture_MouseDown (int x, int y, int buttons) +{ + Sys_GetCursorPos (&textures_cursorx, &textures_cursory); + + // lbutton = select texture + if (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_SHIFT) || buttons == (MK_LBUTTON | MK_CONTROL)) + { + SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y, buttons & MK_SHIFT, buttons & MK_CONTROL); + UpdateSurfaceDialog(); + UpdatePatchInspector(); + } +} + +/* +============== +Texture_MouseMoved +============== +*/ + +void Texture_MouseMoved (int x, int y, int buttons) +{ + int scale = 1; + + if ( buttons & MK_SHIFT ) + scale = 4; + + // rbutton = drag texture origin + if (buttons & MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != textures_cursory) + { + g_qeglobals.d_texturewin.originy += ( y-textures_cursory) * scale; + if (g_qeglobals.d_texturewin.originy > 0) + g_qeglobals.d_texturewin.originy = 0; + Sys_SetCursorPos (textures_cursorx, textures_cursory); + + // (g_PrefsDlg.m_bTextureScrollbar && g_qeglobals_gui.d_texture_scroll != NULL) + // fixes broken texture scrolling when scrollbar is disabled + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy)); + // + } + return; + } +} + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + +int imax(int iFloor, int i) { if (i>iFloor) return iFloor;return i;} + +/* +============ +Texture_Draw +TTimo: relying on the shaders list to display the textures +we must query all qtexture_t* to manage and display through the IShaders interface +this allows a plugin to completely override the texture system +============ +*/ +void Texture_Draw (int width, int height) +{ + int x, y, last_y = 0, last_height = 0, nWidth, nHeight; + qtexture_t *q; + char *name; + + qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], 0); + qglViewport (0,0,width,height); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + qglDisable (GL_DEPTH_TEST); + qglDisable(GL_BLEND); + qglOrtho (0, width, g_qeglobals.d_texturewin.originy-height, g_qeglobals.d_texturewin.originy, -100, 100); + qglEnable (GL_TEXTURE_2D); + + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + g_qeglobals.d_texturewin.width = width; + g_qeglobals.d_texturewin.height = height; + + Texture_StartPos(); + for (;;) + { + // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture + Texture_NextPos (&x, &y); + q = current_texture; + if (!q) + break; + + nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); + nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + + if (y != last_y) + { + last_y = y; + last_height = 0; + } + last_height = MAX (nHeight, last_height); + + // Is this texture visible? + if ((y-nHeight-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) + && (y > g_qeglobals.d_texturewin.originy - height)) + { + // borders rules: + // if it's the current texture, draw a thick red line, else: + // shaders have a white border, simple textures don't + // if !texture_showinuse: (some textures displayed may not be in use) + // draw an additional square around with 0.5 1 0.5 color + if (!strcmpi(g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName())) + { + qglLineWidth (3); + qglColor3f (1,0,0); + qglDisable (GL_TEXTURE_2D); + + qglBegin (GL_LINE_LOOP); + qglVertex2f (x-4,y-FONT_HEIGHT+4); + qglVertex2f (x-4,y-FONT_HEIGHT-nHeight-4); + qglVertex2f (x+4+nWidth,y-FONT_HEIGHT-nHeight-4); + qglVertex2f (x+4+nWidth,y-FONT_HEIGHT+4); + qglEnd (); + + qglEnable (GL_TEXTURE_2D); + qglLineWidth (1); + } + else + { + qglLineWidth (1); + // shader border: + if (!pCurrentShader->IsDefault()) + { + qglColor3f (1,1,1); + qglDisable (GL_TEXTURE_2D); + + qglBegin (GL_LINE_LOOP); + qglVertex2f (x-1,y+1-FONT_HEIGHT); + qglVertex2f (x-1,y-nHeight-1-FONT_HEIGHT); + qglVertex2f (x+1+nWidth,y-nHeight-1-FONT_HEIGHT); + qglVertex2f (x+1+nWidth,y+1-FONT_HEIGHT); + qglEnd (); + qglEnable (GL_TEXTURE_2D); + } + + // highlight in-use textures + if (pCurrentShader->IsInUse()) + { + qglColor3f (0.5,1,0.5); + qglDisable (GL_TEXTURE_2D); + qglBegin (GL_LINE_LOOP); + qglVertex2f (x-3,y+3-FONT_HEIGHT); + qglVertex2f (x-3,y-nHeight-3-FONT_HEIGHT); + qglVertex2f (x+3+nWidth,y-nHeight-3-FONT_HEIGHT); + qglVertex2f (x+3+nWidth,y+3-FONT_HEIGHT); + qglEnd (); + qglEnable (GL_TEXTURE_2D); + } + } + + // Draw the texture + qglBindTexture (GL_TEXTURE_2D, q->texture_number); + QE_CheckOpenGLForErrors(); + qglColor3f (1,1,1); + qglBegin (GL_QUADS); + qglTexCoord2f (0,0); + qglVertex2f (x,y-FONT_HEIGHT); + qglTexCoord2f (1,0); + qglVertex2f (x+nWidth,y-FONT_HEIGHT); + qglTexCoord2f (1,1); + qglVertex2f (x+nWidth,y-FONT_HEIGHT-nHeight); + qglTexCoord2f (0,1); + qglVertex2f (x,y-FONT_HEIGHT-nHeight); + qglEnd (); + + // draw the texture name + qglDisable (GL_TEXTURE_2D); + qglColor3f (1,1,1); + + qglRasterPos2f (x, y-FONT_HEIGHT+2); + + // don't draw the directory name + name = (char*)pCurrentShader->getName(); + name += strlen(name); + while(name != (char*)pCurrentShader->getName() && *(name-1) != '/' && *(name-1) != '\\') + name--; + + gtk_glwidget_print_string(name); + qglEnable (GL_TEXTURE_2D); + } + } + + g_qeglobals.d_texturewin.m_nTotalHeight = abs(y) + last_height + FONT_HEIGHT + 4; + + // reset the current texture + qglBindTexture(GL_TEXTURE_2D, 0); + qglFinish(); +} + +//++timo seems we only know hard inits now.. +//void Texture_Init (bool bHardInit) +void Texture_Init() +{ + g_qeglobals.d_qtextures = NULL; + // initialize the qtexture map + if (g_qeglobals.d_qtexmap) + { + Sys_FPrintf(SYS_ERR, "TODO: delete g_qeglobals.d_qtexmap in Texture_Init\n"); + } + g_qeglobals.d_qtexmap = g_hash_table_new (g_str_hash, g_str_equal); + // initialize .. in some cases if no default texture / project loaded it crashes + memset( &g_qeglobals.d_texturewin.texdef, 0, sizeof(g_qeglobals.d_texturewin.texdef) ); + g_qeglobals.d_texturewin.texdef.SetName(SHADER_NOT_FOUND); + g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); +} + +// FIXME TTimo this needs to move to the shader module along with l_shaderlist move +// preload shader files that have been listed in shaderlist.txt +void PreloadShaders() +{ + GSList *lst = l_shaderfiles; + Str shadername; + while (lst) + { + shadername = g_pGameDescription->mShaderPath; + shadername += (char*)lst->data; + QERApp_LoadShaderFile(shadername.GetBuffer()); + lst = lst->next; + } +} + +// TTimo: modified to expect the reletive path to the skin as input +// will look into pak files if necessary +// uses the shader code to load the texture Try_Texture_ForName +// modified SkinInfo accordingly to store the qtexture_t and shader name (reletive version) +// the .md3 have bundled filetype extension, but they don't fit with the actual data +// ex: models/mapobjects/gargoyle.tga doesn't exist, but models/mapobjects/gargoyle.jpg can be used instead +// so we remove the extension before load attempt +int WINAPI Texture_LoadSkin(char *pName, int *pnWidth, int *pnHeight) +{ + // byte *pic = NULL; + // byte *pic32 = NULL; + int nTex = -1; + qtexture_t *qtex; + SkinInfo *pInfo; + const char *pCleanName; + + int nSize = g_lstSkinCache.GetSize(); + pCleanName = QERApp_CleanTextureName( pName, false ); + for (int i = 0; i < nSize; i++) + { + SkinInfo *pInfo = reinterpret_cast(g_lstSkinCache.GetAt(i)); + if (pInfo) + { + if (stricmp(pCleanName, pInfo->m_strName) == 0) + { + return pInfo->m_nTextureBind; + } + } + } + + // if the load is successfull, we get back a qtexture_t + // we don't need to free it, it's in g_qeglobals.d_qtextures + // NOTE: we need to free the SkinInfo though.. + qtex = QERApp_Try_Texture_ForName( pCleanName ); + if (qtex) + { + nTex = qtex->texture_number; + pInfo = new SkinInfo(qtex->name, nTex, qtex); + } else + { + pInfo = new SkinInfo(pCleanName, -1, NULL); + } + g_lstSkinCache.Add(pInfo); + + return nTex; +} + +bool TexWnd::CheckFilter( const char* name ) +{ + const char* buf = gtk_entry_get_text (GTK_ENTRY (m_pFilter)); + if (strstr( name, buf ) != 0) + return true; + return false; +} + +// ============================================================================= +// static functions + +static void vertical_scroll (GtkWidget *widget, gpointer data) +{ + ((TexWnd*)data)->OnVScroll (); +} + +static void filter_changed (GtkWidget *widget, gpointer data) +{ + CString str; + str = gtk_entry_get_text (GTK_ENTRY (widget)); + ((TexWnd*)data)->UpdateFilter (str); +} + +// ============================================================================= +// TexWnd class + +TexWnd::TexWnd() +: GLWindow (FALSE) +{ + m_pFilter = NULL; + m_bNeedRange = true; +} + +TexWnd::~TexWnd() +{ +} + +void TexWnd::OnCreate () +{ + if (!MakeCurrent ()) + Error ("glMakeCurrent in TexWnd::OnCreate failed"); + + g_qeglobals_gui.d_texture = m_pWidget; + g_nTextureOffset = 0; + + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + gtk_signal_connect (GTK_OBJECT (vadjustment), "value_changed", GTK_SIGNAL_FUNC (vertical_scroll), this); + + if (g_PrefsDlg.m_bTextureScrollbar) + gtk_widget_show (g_qeglobals_gui.d_texture_scroll); + else + gtk_widget_hide (g_qeglobals_gui.d_texture_scroll); + m_bNeedRange = true; + + gtk_signal_connect (GTK_OBJECT (m_pFilter), "changed", GTK_SIGNAL_FUNC (filter_changed), this); + if (g_PrefsDlg.m_bTextureWindow) + gtk_widget_show (m_pFilter); +} + +void TexWnd::UpdateFilter(const char* pFilter) +{ + g_bFilterEnabled = false; + if (pFilter) + { + g_strFilter = pFilter; + if (g_strFilter.GetLength() > 0) + g_bFilterEnabled = true; + QERApp_SortActiveShaders(); + } + Sys_UpdateWindows (W_TEXTURE); +} + +void TexWnd::OnSize (int cx, int cy) +{ + m_bNeedRange = true; +} + +void TexWnd::OnExpose () +{ + int nOld = g_qeglobals.d_texturewin.m_nTotalHeight; + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: glXMakeCurrent failed..\n "); + Sys_Printf("Please restart Radiant if the Texture view is not working\n"); + } else + { + QE_CheckOpenGLForErrors(); + Texture_Draw (m_pWidget->allocation.width, m_pWidget->allocation.height - g_nTextureOffset); + QE_CheckOpenGLForErrors(); + SwapBuffers (); + } + if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld)) + { + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + + vadjustment->value = -g_qeglobals.d_texturewin.originy; + vadjustment->page_size = m_pWidget->allocation.height; + vadjustment->page_increment = m_pWidget->allocation.height/2; + vadjustment->step_increment = 20; + vadjustment->lower = 0; + vadjustment->upper = g_qeglobals.d_texturewin.m_nTotalHeight; + + gtk_signal_emit_by_name (GTK_OBJECT (vadjustment), "changed"); + + m_bNeedRange = false; + } +} + +void TexWnd::OnLButtonDown (guint32 flags, int pointx, int pointy) +{ + SetCapture (); + Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); +} + +void TexWnd::OnRButtonDown (guint32 flags, int pointx, int pointy) +{ + SetCapture (); + Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); +} + +void TexWnd::OnMButtonDown (guint32 flags, int pointx, int pointy) +{ + SetCapture (); + Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); +} + +void TexWnd::OnLButtonUp (guint32 flags, int pointx, int pointy) +{ + ReleaseCapture (); + // NOTE TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + DragDropTexture (flags, pointx, pointy); +} + +void TexWnd::OnRButtonUp (guint32 flags, int pointx, int pointy) +{ + ReleaseCapture (); +} + +void TexWnd::OnMButtonUp (guint32 flags, int pointx, int pointy) +{ + ReleaseCapture (); +} + +void TexWnd::OnMouseMove (guint32 flags, int pointx, int pointy) +{ + Texture_MouseMoved (pointx, pointy - g_nTextureOffset, flags); + // if scrollbar is hidden, we don't seem to get an update + if( !g_PrefsDlg.m_bTextureScrollbar ) + RedrawWindow (); +} + +void TexWnd::OnVScroll () +{ + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + + g_qeglobals.d_texturewin.originy = - (int)vadjustment->value; + RedrawWindow (); +} + +void TexWnd::UpdatePrefs() +{ + if (g_PrefsDlg.m_bTextureWindow) + gtk_widget_show (m_pFilter); + else + gtk_widget_hide (m_pFilter); + + if (g_PrefsDlg.m_bTextureScrollbar) + gtk_widget_show (g_qeglobals_gui.d_texture_scroll); + else + gtk_widget_hide (g_qeglobals_gui.d_texture_scroll); + m_bNeedRange = true; + RedrawWindow (); +} + +void TexWnd::FocusEdit() +{ + if (GTK_WIDGET_VISIBLE (m_pFilter)) + gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), m_pFilter); +} + +void TexWnd::OnMouseWheel(bool bUp) +{ + if (bUp) + { + if(g_qeglobals.d_texturewin.originy < 0) { + g_qeglobals.d_texturewin.originy += g_PrefsDlg.m_nWheelInc; + // clamp so we don't get jiggle if moved by less than scrollwheel increment + if(g_qeglobals.d_texturewin.originy > 0) { + g_qeglobals.d_texturewin.originy = 0; + } + } + } + else + { + if(g_qeglobals.d_texturewin.originy > (-g_qeglobals.d_texturewin.m_nTotalHeight + g_qeglobals.d_texturewin.height)) + g_qeglobals.d_texturewin.originy -= g_PrefsDlg.m_nWheelInc; + } + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy)); + + RedrawWindow(); +} + +// NOTE TTimo +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 +void TexWnd::DragDropTexture (guint32 flags, int pointx, int pointy) +{ + // This gets called from leftmouse up event. We see if the mouseup is above + // the camwindow. If this is the case do a trace for a surface. If we hit a + // surface, texture it with the current texture. + + int m_ptXcheck, m_ptYcheck; + int m_ptX, m_ptY; + GtkWidget *widget; + gint x, y; + vec3_t dir; + float f, r, u; + int i; + + // we only want to catch a plain mouseevent + if (flags) + return; + + // see if we are above the camwindow + Sys_GetCursorPos (&m_ptX, &m_ptY); + + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + widget = g_pParentWnd->GetCamWnd()->m_pParent; + else + widget = g_pParentWnd->GetCamWnd()->GetWidget(); + + get_window_pos (widget, &x, &y); + + if (m_ptX < x || m_ptY < y || + m_ptX > x + widget->allocation.width || + m_ptY > y + widget->allocation.height) + return; + + // check if the camwindow isn't being partially hidden by another window at this point + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=187 + m_ptXcheck = m_ptX; + m_ptYcheck = m_ptY; + + if( g_pParentWnd->GetCamWnd()->GetWidget()->window != gdk_window_at_pointer( &m_ptXcheck, &m_ptYcheck ) ) + return; + + // calc ray direction + x = m_ptX - x; + y = g_pParentWnd->GetCamWnd()->Camera()->height - 1 - (m_ptY - y); + u = (float)( y - ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ); + r = (float)( x - ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = g_pParentWnd->GetCamWnd()->Camera()->vpn[i] * f + + g_pParentWnd->GetCamWnd()->Camera()->vright[i] * r + + g_pParentWnd->GetCamWnd()->Camera()->vup[i] * u; + VectorNormalize (dir, dir); + + // do a trace for a surface + trace_t t; + + t = Test_Ray (g_pParentWnd->GetCamWnd()->Camera()->origin, dir, SF_SINGLEFACE); + + if (t.brush) + { + texdef_t tex; + brushprimit_texdef_t brushprimit_tex; + + memset (&tex, 0, sizeof(tex)); + memset (&brushprimit_tex, 0, sizeof(brushprimit_tex)); + if (g_qeglobals.m_bBrushPrimitMode) + { + // brushprimit fitted to a 2x2 texture + brushprimit_tex.coords[0][0] = 1.0f; + brushprimit_tex.coords[1][1] = 1.0f; + } else + { + tex.scale[0] = g_pGameDescription->mTextureDefaultScale; + tex.scale[1] = g_pGameDescription->mTextureDefaultScale; + } + tex.flags = g_qeglobals.d_texturewin.texdef.flags; + tex.value = g_qeglobals.d_texturewin.texdef.value; + tex.contents = g_qeglobals.d_texturewin.texdef.contents; + // TTimo - shader code cleanup + // texdef.name is the name of the shader, not the name of the actual texture file + tex.SetName(g_qeglobals.d_texturewin.texdef.GetName()); + + Undo_Start("set face textures"); + Undo_AddBrush(t.brush); + SetFaceTexdef (t.face, &tex, &brushprimit_tex, false, NULL ); + Brush_Build(t.brush, false); + Undo_EndBrush(t.brush); + Undo_End(); + + Sys_UpdateWindows (W_CAMERA); + g_pParentWnd->OnTimer (); + } +} diff --git a/radiant/texwindow.h b/radiant/texwindow.h new file mode 100644 index 00000000..7f6e9260 --- /dev/null +++ b/radiant/texwindow.h @@ -0,0 +1,62 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _TEXWINDOW_H_ +#define _TEXWINDOW_H_ + +#include "glwindow.h" + +class TexWnd : public GLWindow +{ +public: + TexWnd(); + void UpdateFilter(const char* pFilter); + void UpdatePrefs(); + void FocusEdit(); + bool CheckFilter( const char* ); + virtual ~TexWnd(); + + GtkWidget *m_pFilter; + +protected: + bool m_bNeedRange; + + void OnCreate (); + void OnExpose (); + void OnLButtonDown (guint32 flags, int x, int y); + void OnRButtonDown (guint32 flags, int x, int y); + void OnMButtonDown (guint32 flags, int x, int y); + void OnLButtonUp (guint32 flags, int pointx, int pointy); + void OnRButtonUp (guint32 flags, int pointx, int pointy); + void OnMButtonUp (guint32 flags, int pointx, int pointy); + void OnMouseMove (guint32 flags, int pointx, int pointy); + void OnSize (int cx, int cy); + + void OnMouseWheel(bool bUp); + + public: + void OnVScroll (); + + private: + void DragDropTexture (guint32 flags, int pointx, int pointy); +}; + +#endif // _TEXWINDOW_H_ diff --git a/radiant/ui.cpp b/radiant/ui.cpp new file mode 100644 index 00000000..661c6f9b --- /dev/null +++ b/radiant/ui.cpp @@ -0,0 +1,268 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// implementation of IMessaging specific interface +// + +#include "stdafx.h" + +CPtrArray l_Listeners[RADIANT_MSGCOUNT]; +CPtrArray l_WindowListeners; +CXYWndWrapper l_XYWndWrapper; + +// CGtkWindow implementation ------------------------------------- + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + IWindowListener *pListen = static_cast(data); + switch (event->button) + { + case 1: + pListen->OnLButtonDown(event->state, event->x, event->y); break; + case 3: + pListen->OnRButtonDown(event->state, event->x, event->y); break; + } +} + +static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + IWindowListener *pListen = static_cast(data); + switch (event->button) + { + case 1: + pListen->OnLButtonUp(event->state, event->x, event->y); break; + case 3: + pListen->OnRButtonUp(event->state, event->x, event->y); break; + } +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + IWindowListener *pListen = static_cast(data); + pListen->OnMouseMove(event->state, event->x, event->y); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + CGtkWindow *pWindow = static_cast(data); + pWindow->DoExpose(); + + return TRUE; +} + +// we use the string versions of the keys for now.. +static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + gint ret; + + IWindowListener *pListen = static_cast(data); + ret = pListen->OnKeyPressed(gdk_keyval_name(event->keyval)); + if (ret) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + } + return ret; +} + +// close_widget is not hooked on the listener but on the CGtkWindow object to handle the closure +static gint close_widget (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + CGtkWindow *pWindow = static_cast(data); + pWindow->Close(); + + return TRUE; +} + +void CGtkWindow::DoExpose() +{ + gtk_glwidget_make_current(m_pGLWidget); + if (m_pListen->Paint()) + gtk_glwidget_swap_buffers(m_pGLWidget); +} + +void CGtkWindow::Redraw() +{ + gtk_widget_queue_draw(m_pGLWidget); +} + +void CGtkWindow::Close() +{ + // similar to a destructor, except we warn first + m_pListen->Close(); + m_pListen->DecRef(); m_pListen = NULL; + gtk_widget_destroy(m_pWnd); m_pWnd = NULL; +} + +bool CGtkWindow::Show() +{ + // check we got everything and are reading to instanciate + if (m_nWidthParam == 0 || m_nHeightParam == 0) + { + Sys_FPrintf(SYS_ERR, "Height and Width params not set in CGtkWindow::Show\n"); + return false; + } + if (!m_pListen) + { + Sys_FPrintf(SYS_ERR, "No listener set in CGtkWindow::Show\n"); + return false; + } + + // seems all good, here we go + m_pWnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (m_pWnd), m_Name.GetBuffer()); + gtk_window_set_default_size (GTK_WINDOW (m_pWnd), m_nWidthParam, m_nHeightParam); + gtk_widget_show (m_pWnd); + + // GL widget creation + m_pGLWidget = gtk_glwidget_new(FALSE, g_qeglobals_gui.d_glBase); + + gtk_widget_set_events (m_pGLWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); + + // Connect signal handlers + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "expose_event", GTK_SIGNAL_FUNC (expose), this); + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "motion_notify_event", + GTK_SIGNAL_FUNC (motion), m_pListen); + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), m_pListen); + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "button_release_event", + GTK_SIGNAL_FUNC (button_release), m_pListen); + + gtk_signal_connect (GTK_OBJECT (m_pWnd), "delete_event", GTK_SIGNAL_FUNC (close_widget), this); + gtk_signal_connect (GTK_OBJECT (m_pWnd), "key_press_event", + GTK_SIGNAL_FUNC (keypress), m_pListen); + + gtk_widget_show (m_pGLWidget); + gtk_container_add (GTK_CONTAINER (m_pWnd), m_pGLWidget); + + return true; +} + +IWindow* WINAPI QERApp_CreateGLWindow() +{ + return new CGtkWindow; +} + +void WINAPI QERApp_HookWindow(IWindowListener* pListen) +{ + l_WindowListeners.Add( pListen ); + pListen->IncRef(); +} + +void WINAPI QERApp_UnHookWindow(IWindowListener* pListen) +{ + for ( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + { + if (l_WindowListeners.GetAt(i) == pListen) + { + l_WindowListeners.RemoveAt(i); + pListen->DecRef(); + return; + } + } +#ifdef _DEBUG + Sys_Printf("WARNING: IWindowListener not found in QERApp_UnHookWindow\n"); +#endif +} + +void DispatchOnMouseMove(guint32 nFlags, int x, int y) +{ + for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + static_cast(l_WindowListeners.GetAt(i))->OnMouseMove( nFlags, x, y ); +} + +bool DispatchOnLButtonDown(guint32 nFlags, int x, int y) +{ + for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + if (static_cast(l_WindowListeners.GetAt(i))->OnLButtonDown( nFlags, x, y )) + return true; + return false; +} + +bool DispatchOnLButtonUp(guint32 nFlags, int x, int y) +{ + for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + if (static_cast(l_WindowListeners.GetAt(i))->OnLButtonUp( nFlags, x, y )) + return true; + return false; +} + +void WINAPI QERApp_HookListener(IListener* pListen, int Msg) +{ +#ifdef _DEBUG + if (Msg >= RADIANT_MSGCOUNT) + { + Sys_Printf("ERROR: bad index in QERApp_HookListener\n"); + return; + } +#endif + l_Listeners[Msg].Add( pListen ); + pListen->IncRef(); +} + +int WINAPI QERApp_UnHookListener(IListener* pListen) +{ + int count = 0; + for( int i = 0; iDecRef(); + count++; + } + return count; +} + +void DispatchRadiantMsg( int Msg ) +{ +#ifdef _DEBUG + if (Msg >= RADIANT_MSGCOUNT) + { + Sys_Printf("ERROR: bad index in DispatchRadiantMsg\n"); + return; + } +#endif + for(int i = 0; i(l_Listeners[Msg].GetAt(i))->DispatchRadiantMsg(Msg); +} + +void CXYWndWrapper::SnapToGrid( int x1, int y1, vec3_t pt ) +{ + int height = g_pParentWnd->ActiveXY()->GetWidget()->allocation.height; + g_pParentWnd->ActiveXY()->SnapToPoint( x1, height - 1 - y1, pt ); +} + +VIEWTYPE CXYWndWrapper::GetViewType( void ) +{ + return (VIEWTYPE)g_pParentWnd->ActiveXY()->GetViewType(); +} + +IXYWndWrapper* WINAPI QERApp_GetXYWndWrapper() +{ + return &l_XYWndWrapper; +} diff --git a/radiant/ui.h b/radiant/ui.h new file mode 100644 index 00000000..135ed93e --- /dev/null +++ b/radiant/ui.h @@ -0,0 +1,84 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// headers for internal classes used in Messaging.cpp +// + +#ifndef __MESSAGING_H_ +#define __MESSAGING_H_ + +class CXYWndWrapper : public IXYWndWrapper +{ +public: + void SnapToGrid( int x1, int y1, vec3_t pt ); + VIEWTYPE GetViewType( void ); +}; + +// implementation of the IWindow API +class CGtkWindow : public IWindow +{ + int refCount; + GtkWidget *m_pWnd; + GtkWidget *m_pGLWidget; + int m_nWidthParam,m_nHeightParam; + IWindowListener *m_pListen; + Str m_Name; +public: + CGtkWindow() { refCount = 0; m_pWnd = NULL; m_pGLWidget = NULL; m_nWidthParam = 0; m_nHeightParam = 0; m_pListen = 0; m_Name = "CGtkWindow"; } + virtual ~CGtkWindow() + { + if (m_pListen) { m_pListen->DecRef(); m_pListen = NULL; } + if (m_pWnd) { gtk_widget_destroy(m_pWnd); m_pWnd = NULL; } + } + // refcounting ---------------------------------------- + // Increment the number of references to this object + void IncRef () { refCount++; } + // Decrement the reference count + void DecRef () + { if ( --refCount <= 0 ) + delete this; + } + // IWindow -------------------------------------------- + // get pixel size + int getHeight() { return m_pWnd->allocation.height; } + int getWidth() { return m_pWnd->allocation.width; } + // set pixel size and other parameters before showing it + void setSizeParm(int width, int height) { m_nWidthParam = width; m_nHeightParam = height; } + // set the IWindowListener (implemented by the plugin using this window) + void setListener(IWindowListener * pListen) { m_pListen = pListen; m_pListen->IncRef(); } + // set the name (optional) + void setName(char *name) { m_Name = name; } + // will actually create the GL and the window based on the parameters + bool Show(); + // CGtkWindow ----------------------------------------- + // called upon a closure of the widget + void Close(); + // called to manage GL context and buffer swapping before display + void DoExpose(); + // commands ------------------------------------------- + // call this to ask for a Redraw + void Redraw(); +}; + +#endif diff --git a/radiant/undo.cpp b/radiant/undo.cpp new file mode 100644 index 00000000..d1465af1 --- /dev/null +++ b/radiant/undo.cpp @@ -0,0 +1,973 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +/* + + QERadiant Undo/Redo + + +basic setup: + +<-g_undolist---------g_lastundo> <---map data---> <-g_lastredo---------g_redolist-> + + + undo/redo on the world_entity is special, only the epair changes are remembered + and the world entity never gets deleted. + + FIXME: maybe reset the Undo system at map load + maybe also reset the entityId at map load +*/ + +#include "stdafx.h" + +typedef struct undo_s +{ + double time; //time operation was performed + int id; //every undo has an unique id + int done; //true when undo is build + char *operation; //name of the operation + brush_t brushlist; //deleted brushes + entity_t entitylist; //deleted entities + struct undo_s *prev, *next; //next and prev undo in list +} undo_t; + +undo_t *g_undolist; //first undo in the list +undo_t *g_lastundo; //last undo in the list +undo_t *g_redolist; //first redo in the list +undo_t *g_lastredo; //last undo in list +int g_undoMaxSize = 64; //maximum number of undos +int g_undoSize = 0; //number of undos in the list +int g_undoMaxMemorySize = 2*1024*1024; //maximum undo memory (default 2 MB) +int g_undoMemorySize = 0; //memory size of undo buffer +int g_undoId = 1; //current undo ID (zero is invalid id) +int g_redoId = 1; //current redo ID (zero is invalid id) + +/* +============= +Undo_MemorySize +============= +*/ +int Undo_MemorySize(void) +{ + return g_undoMemorySize; +} + +/* +============= +Undo_ClearRedo +============= +*/ +void Undo_ClearRedo(void) +{ + undo_t *redo, *nextredo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity; + + for (redo = g_redolist; redo; redo = nextredo) + { + nextredo = redo->next; + for (pBrush = redo->brushlist.next ; pBrush != NULL && pBrush != &redo->brushlist ; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + Brush_Free(pBrush); + } + for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + Entity_Free(pEntity); + } + free(redo); + } + g_redolist = NULL; + g_lastredo = NULL; + g_redoId = 1; +} + +/* +============= +Undo_Clear + + Clears the undo buffer. +============= +*/ +void Undo_Clear(void) +{ + undo_t *undo, *nextundo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity; + + Undo_ClearRedo(); + for (undo = g_undolist; undo; undo = nextundo) + { + nextundo = undo->next; + for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + g_undoMemorySize -= Brush_MemorySize(pBrush); + Brush_Free(pBrush); + } + for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + g_undoMemorySize -= Entity_MemorySize(pEntity); + Entity_Free(pEntity); + } + g_undoMemorySize -= sizeof(undo_t); + free(undo); + } + g_undolist = NULL; + g_lastundo = NULL; + g_undoSize = 0; + g_undoMemorySize = 0; + g_undoId = 1; +} + +/* +============= +Undo_SetMaxSize +============= +*/ +void Undo_SetMaxSize(int size) +{ + Undo_Clear(); + if (size < 1) g_undoMaxSize = 1; + else g_undoMaxSize = size; +} + +/* +============= +Undo_GetMaxSize +============= +*/ +int Undo_GetMaxSize(void) +{ + return g_undoMaxSize; +} + +/* +============= +Undo_SetMaxMemorySize +============= +*/ +void Undo_SetMaxMemorySize(int size) +{ + Undo_Clear(); + if (size < 1024) g_undoMaxMemorySize = 1024; + else g_undoMaxMemorySize = size; +} + +/* +============= +Undo_GetMaxMemorySize +============= +*/ +int Undo_GetMaxMemorySize(void) +{ + return g_undoMaxMemorySize; +} + +/* +============= +Undo_FreeFirstUndo +============= +*/ +void Undo_FreeFirstUndo(void) +{ + undo_t *undo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity; + + //remove the oldest undo from the undo buffer + undo = g_undolist; + g_undolist = g_undolist->next; + g_undolist->prev = NULL; + // + for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + g_undoMemorySize -= Brush_MemorySize(pBrush); + Brush_Free(pBrush); + } + for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + g_undoMemorySize -= Entity_MemorySize(pEntity); + Entity_Free(pEntity); + } + g_undoMemorySize -= sizeof(undo_t); + free(undo); + g_undoSize--; +} + +/* +============= +Undo_GeneralStart +============= +*/ +void Undo_GeneralStart(char *operation) +{ + undo_t *undo; + brush_t *pBrush; + entity_t *pEntity; + + + if (g_lastundo) + { + if (!g_lastundo->done) + { + Sys_Printf("Undo_Start: WARNING last undo not finished.\n"); + } + } + + undo = (undo_t *) malloc(sizeof(undo_t)); + if (!undo) + return; + memset(undo, 0, sizeof(undo_t)); + undo->brushlist.next = &undo->brushlist; + undo->brushlist.prev = &undo->brushlist; + undo->entitylist.next = &undo->entitylist; + undo->entitylist.prev = &undo->entitylist; + if (g_lastundo) + g_lastundo->next = undo; + else + g_undolist = undo; + undo->prev = g_lastundo; + undo->next = NULL; + g_lastundo = undo; + + undo->time = Sys_DoubleTime(); + // + if (g_undoId > g_undoMaxSize * 2) g_undoId = 1; + if (g_undoId <= 0) g_undoId = 1; + undo->id = g_undoId++; + undo->done = false; + undo->operation = operation; + //reset the undo IDs of all brushes using the new ID + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) + { + if (pBrush->undoId == undo->id) + { + pBrush->undoId = 0; + } + } + for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) + { + if (pBrush->undoId == undo->id) + { + pBrush->undoId = 0; + } + } + //reset the undo IDs of all entities using thew new ID + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) + { + if (pEntity->undoId == undo->id) + { + pEntity->undoId = 0; + } + } + g_undoMemorySize += sizeof(undo_t); + g_undoSize++; + //undo buffer is bound to a max + if (g_undoSize > g_undoMaxSize) + { + Undo_FreeFirstUndo(); + } +} + +/* +============= +Undo_BrushInUndo +============= +*/ +int Undo_BrushInUndo(undo_t *undo, brush_t *brush) +{ +/* brush_t *b; + + for (b = undo->brushlist.next; b != &undo->brushlist; b = b->next) + { + // Arnout: NOTE - can't do a pointer compare as the brushes get cloned into the undo brushlist, and not just referenced from it + // For entities we have a unique ID, for brushes we have numberID - but brush full clone increases that anyway so it's useless right now. + if (b == brush) return true; + }*/ + // Arnout: function is pointless right now, see above explanation + return false; +} + +/* +============= +Undo_EntityInUndo +============= +*/ +int Undo_EntityInUndo(undo_t *undo, entity_t *ent) +{ + entity_t *e; + + for (e = undo->entitylist.next; e != &undo->entitylist; e = e->next) + { + // Arnout: NOTE - can't do a pointer compare as the entities get cloned into the undo entitylist, and not just referenced from it + //if (e == ent) return true; + if( e->entityId == ent->entityId ) return true; + } + return false; +} + +/* +============= +Undo_Start +============= +*/ +void Undo_Start(char *operation) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_Start: undo is disabled.\n"); +#endif + return; + } + + Undo_ClearRedo(); + Undo_GeneralStart(operation); +} + +/* +============= +Undo_AddBrush +============= +*/ +void Undo_AddBrush(brush_t *pBrush) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_AddBrush: undo is disabled.\n"); +#endif + return; + } + + if (!g_lastundo) + { + Sys_Printf("Undo_AddBrushList: no last undo.\n"); + return; + } + if (g_lastundo->entitylist.next != &g_lastundo->entitylist) + { + Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n"); + } + //if the brush is already in the undo + if (Undo_BrushInUndo(g_lastundo, pBrush)) + return; + //clone the brush + brush_t* pClone = Brush_FullClone(pBrush); + //save the ID of the owner entity + pClone->ownerId = pBrush->owner->entityId; + //save the old undo ID for previous undos + pClone->undoId = pBrush->undoId; + Brush_AddToList (pClone, &g_lastundo->brushlist); + // + g_undoMemorySize += Brush_MemorySize(pClone); +} + +/* +============= +Undo_AddBrushList +TTimo: some brushes are just there for UI, and the information is somewhere else +for patches it's in the patchMesh_t structure, so when we clone the brush we get that information (brush_t::pPatch) +but: models are stored in pBrush->owner->md3Class, and owner epairs and origin parameters are important + so, we detect models and push the entity in the undo session (as well as it's BBox brush) + same for other items like weapons and ammo etc. +============= +*/ +void Undo_AddBrushList(brush_t *brushlist) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_AddBrushList: undo is disabled.\n"); +#endif + return; + } + + brush_t *pBrush; + + if (!g_lastundo) + { + Sys_Printf("Undo_AddBrushList: no last undo.\n"); + return; + } + if (g_lastundo->entitylist.next != &g_lastundo->entitylist) + { + Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n"); + } + //copy the brushes to the undo + for (pBrush = brushlist->next ; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next) + { + //if the brush is already in the undo + //++timo FIXME: when does this happen? + if (Undo_BrushInUndo(g_lastundo, pBrush)) + continue; + // do we need to store this brush's entity in the undo? + // if it's a fixed size entity, the brush that reprents it is not really relevant, it's used for selecting and moving around + // what we want to store for undo is the owner entity, epairs and origin/angle stuff + //++timo FIXME: if the entity is not fixed size I don't know, so I don't do it yet + if (pBrush->owner->eclass->fixedsize == 1) + Undo_AddEntity( pBrush->owner ); + // clone the brush + brush_t* pClone = Brush_FullClone(pBrush); + // save the ID of the owner entity + pClone->ownerId = pBrush->owner->entityId; + // save the old undo ID from previous undos + pClone->undoId = pBrush->undoId; + Brush_AddToList (pClone, &g_lastundo->brushlist); + // track memory size used by undo + g_undoMemorySize += Brush_MemorySize(pClone); + } +} + +/* +============= +Undo_EndBrush +============= +*/ +void Undo_EndBrush(brush_t *pBrush) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_EndBrush: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { + //Sys_Printf("Undo_End: no last undo.\n"); + return; + } + if (g_lastundo->done) + { + //Sys_Printf("Undo_End: last undo already finished.\n"); + return; + } + pBrush->undoId = g_lastundo->id; +} + +/* +============= +Undo_EndBrushList +============= +*/ +void Undo_EndBrushList(brush_t *brushlist) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_EndBrushList: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { + //Sys_Printf("Undo_End: no last undo.\n"); + return; + } + if (g_lastundo->done) + { + //Sys_Printf("Undo_End: last undo already finished.\n"); + return; + } + for (brush_t* pBrush = brushlist->next; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next) + { + pBrush->undoId = g_lastundo->id; + } +} + +/* +============= +Undo_AddEntity +============= +*/ +void Undo_AddEntity(entity_t *entity) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_AddEntity: undo is disabled.\n"); +#endif + return; + } + + + entity_t* pClone; + + if (!g_lastundo) + { + Sys_Printf("Undo_AddEntity: no last undo.\n"); + return; + } + //if the entity is already in the undo + if (Undo_EntityInUndo(g_lastundo, entity)) + return; + //clone the entity + pClone = Entity_Clone(entity); + //save the old undo ID for previous undos + pClone->undoId = entity->undoId; + //save the entity ID (we need a full clone) + pClone->entityId = entity->entityId; + // + Entity_AddToList(pClone, &g_lastundo->entitylist); + // + g_undoMemorySize += Entity_MemorySize(pClone); +} + +/* +============= +Undo_EndEntity +============= +*/ +void Undo_EndEntity(entity_t *entity) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_EndEntity: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { +#ifdef _DEBUG + Sys_Printf("Undo_End: no last undo.\n"); +#endif + return; + } + if (g_lastundo->done) + { +#ifdef _DEBUG + Sys_Printf("Undo_End: last undo already finished.\n"); +#endif + return; + } + if (entity == world_entity) + { + //Sys_Printf("Undo_AddEntity: undo on world entity.\n"); + //NOTE: we never delete the world entity when undoing an operation + // we only transfer the epairs + return; + } + entity->undoId = g_lastundo->id; +} + +/* +============= +Undo_End +============= +*/ +void Undo_End(void) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_End: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { + //Sys_Printf("Undo_End: no last undo.\n"); + return; + } + if (g_lastundo->done) + { + //Sys_Printf("Undo_End: last undo already finished.\n"); + return; + } + g_lastundo->done = true; + + //undo memory size is bound to a max + while (g_undoMemorySize > g_undoMaxMemorySize) + { + //always keep one undo + if (g_undolist == g_lastundo) break; + Undo_FreeFirstUndo(); + } + // + //Sys_Printf("undo size = %d, undo memory = %d\n", g_undoSize, g_undoMemorySize); +} + +/* +============= +Undo_Undo +============= +*/ +void Undo_Undo(boolean bSilent) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { + Sys_Printf("Undo_Undo: undo is disabled.\n"); + return; + } + + undo_t *undo, *redo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity, *pUndoEntity; + + if (!g_lastundo) + { + Sys_Printf("Nothing left to undo.\n"); + return; + } + if (!g_lastundo->done) + { + Sys_Printf("Undo_Undo: WARNING: last undo not yet finished!\n"); + } + // get the last undo + undo = g_lastundo; + if (g_lastundo->prev) g_lastundo->prev->next = NULL; + else g_undolist = NULL; + g_lastundo = g_lastundo->prev; + + //allocate a new redo + redo = (undo_t *) malloc(sizeof(undo_t)); + if (!redo) return; + memset(redo, 0, sizeof(undo_t)); + redo->brushlist.next = &redo->brushlist; + redo->brushlist.prev = &redo->brushlist; + redo->entitylist.next = &redo->entitylist; + redo->entitylist.prev = &redo->entitylist; + if (g_lastredo) g_lastredo->next = redo; + else g_redolist = redo; + redo->prev = g_lastredo; + redo->next = NULL; + g_lastredo = redo; + redo->time = Sys_DoubleTime(); + redo->id = g_redoId++; + redo->done = true; + redo->operation = undo->operation; + + //reset the redo IDs of all brushes using the new ID + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) + { + if (pBrush->redoId == redo->id) + { + pBrush->redoId = 0; + } + } + for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) + { + if (pBrush->redoId == redo->id) + { + pBrush->redoId = 0; + } + } + //reset the redo IDs of all entities using thew new ID + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) + { + if (pEntity->redoId == redo->id) + { + pEntity->redoId = 0; + } + } + + // deselect current sutff + Select_Deselect(); + // move "created" brushes to the redo + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) + { + pNextBrush = pBrush->next; + if (pBrush->undoId == undo->id) + { + //Brush_Free(pBrush); + //move the brush to the redo + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &redo->brushlist); + //make sure the ID of the owner is stored + pBrush->ownerId = pBrush->owner->entityId; + //unlink the brush from the owner entity + Entity_UnlinkBrush(pBrush); + } + } + // move "created" entities to the redo + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + if (pEntity->undoId == undo->id) + { + // check if this entity is in the undo + for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) + { + // move brushes to the undo entity + if (pUndoEntity->entityId == pEntity->entityId) + { + pUndoEntity->brushes.next = pEntity->brushes.next; + pUndoEntity->brushes.prev = pEntity->brushes.prev; + pEntity->brushes.next = &pEntity->brushes; + pEntity->brushes.prev = &pEntity->brushes; + } + } + // + //Entity_Free(pEntity); + //move the entity to the redo + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &redo->entitylist); + } + } + // add the undo entities back into the entity list + for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) + { + g_undoMemorySize -= Entity_MemorySize(pEntity); + //if this is the world entity + if (pEntity->entityId == world_entity->entityId) + { + epair_t* tmp = world_entity->epairs; + world_entity->epairs = pEntity->epairs; + pEntity->epairs = tmp; + Entity_Free(pEntity); + } + else + { + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &entities); + pEntity->redoId = redo->id; + } + } + // add the undo brushes back into the selected brushes + for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) + { + //Sys_Printf("Owner ID: %i\n",pBrush->ownerId); + g_undoMemorySize -= Brush_MemorySize(pBrush); + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &active_brushes); + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities + { + //Sys_Printf("Entity ID: %i\n",pEntity->entityId); + if (pEntity->entityId == pBrush->ownerId) + { + Entity_LinkBrush(pEntity, pBrush); + break; + } + } + //if the brush is not linked then it should be linked into the world entity + //++timo FIXME: maybe not, maybe we've lost this entity's owner! + if (pEntity == NULL || pEntity == &entities) + { + Entity_LinkBrush(world_entity, pBrush); + } + //build the brush + //Brush_Build(pBrush); + Select_Brush(pBrush); + pBrush->redoId = redo->id; + } + if (!bSilent) + Sys_Printf("%s undone.\n", undo->operation); + // free the undo + g_undoMemorySize -= sizeof(undo_t); + free(undo); + g_undoSize--; + g_undoId--; + if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; + // + g_bScreenUpdates = true; + UpdateSurfaceDialog(); + Sys_UpdateWindows(W_ALL); +} + +/* +============= +Undo_Redo +============= +*/ +void Undo_Redo(void) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { + Sys_Printf("Undo_Redo: undo is disabled.\n"); + return; + } + + undo_t *redo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity, *pRedoEntity; + + if (!g_lastredo) + { + Sys_Printf("Nothing left to redo.\n"); + return; + } + if (g_lastundo) + { + if (!g_lastundo->done) + { + Sys_Printf("WARNING: last undo not finished.\n"); + } + } + // get the last redo + redo = g_lastredo; + if (g_lastredo->prev) g_lastredo->prev->next = NULL; + else g_redolist = NULL; + g_lastredo = g_lastredo->prev; + // + Undo_GeneralStart(redo->operation); + // remove current selection + Select_Deselect(); + // move "created" brushes back to the last undo + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + if (pBrush->redoId == redo->id) + { + //move the brush to the undo + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &g_lastundo->brushlist); + g_undoMemorySize += Brush_MemorySize(pBrush); + pBrush->ownerId = pBrush->owner->entityId; + Entity_UnlinkBrush(pBrush); + } + } + // move "created" entities back to the last undo + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + if (pEntity->redoId == redo->id) + { + // check if this entity is in the redo + for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next) + { + // move brushes to the redo entity + if (pRedoEntity->entityId == pEntity->entityId) + { + pRedoEntity->brushes.next = pEntity->brushes.next; + pRedoEntity->brushes.prev = pEntity->brushes.prev; + pEntity->brushes.next = &pEntity->brushes; + pEntity->brushes.prev = &pEntity->brushes; + } + } + // + //Entity_Free(pEntity); + //move the entity to the redo + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &g_lastundo->entitylist); + g_undoMemorySize += Entity_MemorySize(pEntity); + } + } + // add the undo entities back into the entity list + for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next) + { + //if this is the world entity + if (pEntity->entityId == world_entity->entityId) + { + epair_t* tmp = world_entity->epairs; + world_entity->epairs = pEntity->epairs; + pEntity->epairs = tmp; + Entity_Free(pEntity); + } + else + { + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &entities); + } + } + // add the redo brushes back into the selected brushes + for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next) + { + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &active_brushes); + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities + { + if (pEntity->entityId == pBrush->ownerId) + { + Entity_LinkBrush(pEntity, pBrush); + break; + } + } + //if the brush is not linked then it should be linked into the world entity + if (pEntity == NULL || pEntity == &entities) + { + Entity_LinkBrush(world_entity, pBrush); + } + //build the brush + //Brush_Build(pBrush); + Select_Brush(pBrush); + } + // + Undo_End(); + // + Sys_Printf("%s redone.\n", redo->operation); + // + g_redoId--; + // free the undo + free(redo); + // + g_bScreenUpdates = true; + UpdateSurfaceDialog(); + Sys_UpdateWindows(W_ALL); +} + +/* +============= +Undo_RedoAvailable +============= +*/ +int Undo_RedoAvailable(void) +{ + if (g_lastredo) return true; + return false; +} + +int Undo_GetUndoId(void) +{ + if (g_lastundo) + return g_lastundo->id; + return 0; +} + +/* +============= +Undo_UndoAvailable +============= +*/ +int Undo_UndoAvailable(void) +{ + if (g_lastundo) + { + if (g_lastundo->done) + return true; + } + return false; +} diff --git a/radiant/undo.h b/radiant/undo.h new file mode 100644 index 00000000..21ec93f4 --- /dev/null +++ b/radiant/undo.h @@ -0,0 +1,66 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// +// QERadiant Multilevel Undo/Redo +// +// + +//start operation +void Undo_Start(char *operation); +//end operation +void Undo_End(void); +//add brush to the undo +void Undo_AddBrush(brush_t *pBrush); +//add a list with brushes to the undo +void Undo_AddBrushList(brush_t *brushlist); +//end a brush after the operation is performed +void Undo_EndBrush(brush_t *pBrush); +//end a list with brushes after the operation is performed +void Undo_EndBrushList(brush_t *brushlist); +//add entity to undo +void Undo_AddEntity(entity_t *entity); +//end an entity after the operation is performed +void Undo_EndEntity(entity_t *entity); +//undo last operation (bSilent == true -> will not print the "undone blah blah message") +void Undo_Undo(boolean bSilent = false); +//redo last undone operation +void Undo_Redo(void); +//get the undo Id of the next undo (0 if none available) +int Undo_GetUndoId(void); +//returns true if there is something to be undone available +int Undo_UndoAvailable(void); +//returns true if there is something to redo available +int Undo_RedoAvailable(void); +//clear the undo buffer +void Undo_Clear(void); +//set maximum undo size (default 64) +void Undo_SetMaxSize(int size); +//get maximum undo size +int Undo_GetMaxSize(void); +//set maximum undo memory in bytes (default 2 MB) +void Undo_SetMaxMemorySize(int size); +//get maximum undo memory in bytes +int Undo_GetMaxMemorySize(void); +//returns the amount of memory used by undo +int Undo_MemorySize(void); + diff --git a/radiant/vertsel.cpp b/radiant/vertsel.cpp new file mode 100644 index 00000000..75b968e7 --- /dev/null +++ b/radiant/vertsel.cpp @@ -0,0 +1,386 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +//#include "qe3.h" +#include "winding.h" + +int FindPoint (vec3_t point) +{ + int i, j; + + for (i=0 ; i 0.1) + break; + if (j == 3) + return i; + } + + VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + //qeglobals.d_points[g_qeglobals.d_numpoints] = point; + if (g_qeglobals.d_numpoints < MAX_POINTS-1) + { + g_qeglobals.d_numpoints++; + } + + return g_qeglobals.d_numpoints-1; +} + +//#define DBG_WNDG +int FindEdge (int p1, int p2, face_t *f) +{ + int i; + + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + for (i=0 ; inumpoints ; i++) + FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f); + + free (w); +} + +void SetupVertexSelection (void) +{ + face_t *f; + brush_t *b; + + g_qeglobals.d_numpoints = 0; + g_qeglobals.d_numedges = 0; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (b->patchBrush || b->owner->eclass->fixedsize) + continue; // don't make edge and vertex handles for patchbrushes + for (f=b->brush_faces ; f ; f=f->next) + MakeFace (b,f); + } +} + +void SelectFaceEdge (brush_t* b, face_t *f, int p1, int p2) +{ + winding_t *w; + int i, j, k; + int pnum[128]; + +#ifdef DBG_WNDG + if (f==NULL) + Sys_Printf("SelectFaceEdge %p %p\n", b, f); +#endif + + w = Winding_Clone(f->face_winding);//Brush_MakeFaceWinding (b, f); + if (!w) + return; + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + + for (i=0 ; inumpoints ; i++) + if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2) + { + VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]); + VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]); + VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]); + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + + AddPlanept (f->planepts[0]); + AddPlanept (f->planepts[1]); + break; + } + + if (i == w->numpoints) + Sys_Printf ("SelectFaceEdge: failed\n"); + Winding_Free (w); +} + + +void SelectVertex (int p1) +{ + brush_t *b; + winding_t *w; + int i; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + w = Brush_MakeFaceWinding (b, f); + if (!w) + continue; + for (i=0 ; inumpoints ; i++) + { + if (FindPoint (w->points[i]) == p1) + { + VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]); + VectorCopy (w->points[i], f->planepts[1]); + VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]); + // NOTE: used to be a planepts clamping to grid here + + AddPlanept (f->planepts[1]); + + break; + } + } + free (w); + } + } +} + +#define SELECT_EPSILON 8 + +void SelectVertexByRay (vec3_t org, vec3_t dir) +{ + int i, besti; + float d, bestd = VEC_MAX; + vec_t epsilon, divergence; + ray_t ray; + ray_construct_for_vec3(&ray, org, dir); + + // find the point closest to the ray + besti = -1; + if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord) + && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view + { + divergence = 0; + epsilon = SELECT_EPSILON / g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level + } + else + { + divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length + epsilon = 0; + } + + for (i=0 ; iGetXYWnd()->Scale(); // compensate for zoom level + } + else + { + divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length + epsilon = 0; + } + + + g_qeglobals.d_numpoints = 0; + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + + for (i = 0 ; i < p->width ; i++ ) + { + for ( j = 0 ; j < p->height ; j++ ) + { + d = ray_intersect_point(&ray, p->ctrl[i][j].xyz, epsilon, divergence); + + if (d >= bestd) + continue; + + bestd = d; + + if (PointInMoveList(*pPointBest) != -1 && PointInMoveList(p->ctrl[i][j].xyz) == -1) + continue; // choose selected points with preference over unselected + + pPointBest = &p->ctrl[i][j].xyz; + + } + } + } + } + + if (pPointBest == NULL) + { + if (g_pParentWnd->ActiveXY()->AreaSelectOK()) + { + g_qeglobals.d_select_mode = sel_area; + VectorCopy(org, g_qeglobals.d_vAreaTL); + VectorCopy(org, g_qeglobals.d_vAreaBR); + } + return; + } + else + AddPatchMovePoint(pPointBest[0], buttons & MK_CONTROL, buttons & MK_SHIFT); +} + +// optimization bug: +// had to use the #define DBG_WNDG to identify +// the first loop that checks the best edge is broken in release-optimized build +// unrolled the mid[] loop and forced floating consistency on seems to fix +#ifdef _WIN32 +#pragma optimize( "p", on ) +#endif +void SelectEdgeByRay (vec3_t org, vec3_t dir) +{ + int i, besti; + float d, bestd = VEC_MAX; + vec3_t mid; + pedge_t *e; + vec_t epsilon, divergence; + ray_t ray; + ray_construct_for_vec3(&ray, org, dir); + + // find the edge closest to the ray + besti = -1; + if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord) + && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view + { + divergence = 0; + epsilon = SELECT_EPSILON / g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level + } + else + { + divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length + epsilon = 0; + } + + for (i=0 ; if1 == NULL) + { + Sys_Printf ("e->f1 == NULL e->f2 %p\n", e->f2); + } + if (e->f2 == NULL) + { + Sys_Printf ("e->f1 %p e->f2 == NULL\n",e->f1); + } +#endif + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + SelectFaceEdge (b, e->f1, e->p1, e->p2); + SelectFaceEdge (b, e->f2, e->p2, e->p1); + } +} diff --git a/radiant/watchbsp.cpp b/radiant/watchbsp.cpp new file mode 100644 index 00000000..08e3ce31 --- /dev/null +++ b/radiant/watchbsp.cpp @@ -0,0 +1,774 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// monitoring window for running BSP processes (and possibly various other stuff) + +#include "stdafx.h" +#include "watchbsp.h" +#include "feedback.h" + +#ifdef _WIN32 +#include +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include +#define SOCKET_ERROR -1 +#endif + +#ifdef __APPLE__ +#include +#endif + +#include + +// Static functions for the SAX callbacks ------------------------------------------------------- + +// utility for saxStartElement below +static void abortStream(message_info_t *data) +{ + g_pParentWnd->GetWatchBSP()->Reset(); + // tell there has been an error + if (g_pParentWnd->GetWatchBSP()->HasBSPPlugin ()) + g_BSPFrontendTable.m_pfnEndListen(2); + // yeah this doesn't look good.. but it's needed so that everything will be ignored until the stream goes out + data->ignore_depth = -1; + data->recurse++; +} + +#include "stream_version.h" + +static void saxStartElement(message_info_t *data, const xmlChar *name, const xmlChar **attrs) +{ + if (data->ignore_depth == 0) + { + if (data->bGeometry) + // we have a handler + { + data->pGeometry->saxStartElement (data, name, attrs); + } + else + { + if (strcmp ((char *)name, "q3map_feedback") == 0) + { + // check the correct version + // old q3map don't send a version attribute + // the ones we support .. send Q3MAP_STREAM_VERSION + if (!attrs[0] || !attrs[1] || (strcmp((char*)attrs[0],"version") != 0)) + { + Sys_FPrintf(SYS_ERR, "No stream version given in the feedback stream, this is an old q3map version.\n" + "Please turn off monitored compiling if you still wish to use this q3map executable\n"); + abortStream(data); + return; + } + else if (strcmp((char*)attrs[1],Q3MAP_STREAM_VERSION) != 0) + { + Sys_FPrintf(SYS_ERR, + "This version of Radiant reads version %s debug streams, I got an incoming connection with version %s\n" + "Please make sure your versions of Radiant and q3map are matching.\n", Q3MAP_STREAM_VERSION, (char*)attrs[1]); + abortStream(data); + return; + } + } + // we don't treat locally + else if (strcmp ((char *)name, "message") == 0) + { + data->msg_level = atoi ((char *)attrs[1]); + } + else if (strcmp ((char *)name, "polyline") == 0) + // polyline has a particular status .. right now we only use it for leakfile .. + { + data->bGeometry = true; + data->pGeometry = &g_pointfile; + data->pGeometry->saxStartElement (data, name, attrs); + } + else if (strcmp ((char *)name, "select") == 0) + { + CSelectMsg *pSelect = new CSelectMsg(); + data->bGeometry = true; + data->pGeometry = pSelect; + data->pGeometry->saxStartElement (data, name, attrs); + } + else if (strcmp ((char *)name, "pointmsg") == 0) + { + CPointMsg *pPoint = new CPointMsg(); + data->bGeometry = true; + data->pGeometry = pPoint; + data->pGeometry->saxStartElement (data, name, attrs); + } + else if (strcmp ((char *)name, "windingmsg") == 0) + { + CWindingMsg *pWinding = new CWindingMsg(); + data->bGeometry = true; + data->pGeometry = pWinding; + data->pGeometry->saxStartElement (data, name, attrs); + } + else + { + Sys_FPrintf (SYS_WRN, "WARNING: ignoring unrecognized node in XML stream (%s)\n", name); + // we don't recognize this node, jump over it + // (NOTE: the ignore mechanism is a bit screwed, only works when starting an ignore at the highest level) + data->ignore_depth = data->recurse; + } + } + } + data->recurse++; +} + +static void saxEndElement(message_info_t *data, const xmlChar *name) +{ + data->recurse--; + // we are out of an ignored chunk + if (data->recurse == data->ignore_depth) + { + data->ignore_depth = 0; + return; + } + if (data->bGeometry) + { + data->pGeometry->saxEndElement (data, name); + // we add the object to the debug window + if (!data->bGeometry) + { + g_DbgDlg.Push (data->pGeometry); + } + } + if (data->recurse == data->stop_depth) + { +#ifdef _DEBUG + Sys_Printf ("Received error msg .. shutting down..\n"); +#endif + g_pParentWnd->GetWatchBSP()->Reset(); + // tell there has been an error + if (g_pParentWnd->GetWatchBSP()->HasBSPPlugin ()) + g_BSPFrontendTable.m_pfnEndListen(2); + return; + } +} + +static void saxCharacters(message_info_t *data, const xmlChar *ch, int len) +{ + if (data->bGeometry) + { + data->pGeometry->saxCharacters (data, ch, len); + } + else + { + if (data->ignore_depth != 0) + return; + // output the message using the level + char buf[1024]; + memcpy( buf, ch, len ); + buf[len] = '\0'; + Sys_FPrintf (data->msg_level, "%s", buf); + // if this message has error level flag, we mark the depth to stop the compilation when we get out + // we don't set the msg level if we don't stop on leak + if (data->msg_level == 3) + { + data->stop_depth = data->recurse-1; + } + } +} + +static void saxComment(void *ctx, const xmlChar *msg) +{ + Sys_Printf("XML comment: %s\n", msg); +} + +static void saxWarning(void *ctx, const char *msg, ...) +{ + char saxMsgBuffer[4096]; + va_list args; + + va_start(args, msg); + vsprintf (saxMsgBuffer, msg, args); + va_end(args); + Sys_FPrintf(SYS_WRN, "XML warning: %s\n", saxMsgBuffer); +} + +static void saxError(void *ctx, const char *msg, ...) +{ + char saxMsgBuffer[4096]; + va_list args; + + va_start(args, msg); + vsprintf (saxMsgBuffer, msg, args); + va_end(args); + Sys_FPrintf(SYS_ERR, "XML error: %s\n", saxMsgBuffer); +} + +static void saxFatal(void *ctx, const char *msg, ...) +{ + char buffer[4096]; + + va_list args; + + va_start(args, msg); + vsprintf (buffer, msg, args); + va_end(args); + Sys_FPrintf(SYS_ERR, "XML fatal error: %s\n", buffer); +} + +static xmlSAXHandler saxParser = { + 0, /* internalSubset */ + 0, /* isStandalone */ + 0, /* hasInternalSubset */ + 0, /* hasExternalSubset */ + 0, /* resolveEntity */ + 0, /* getEntity */ + 0, /* entityDecl */ + 0, /* notationDecl */ + 0, /* attributeDecl */ + 0, /* elementDecl */ + 0, /* unparsedEntityDecl */ + 0, /* setDocumentLocator */ + 0, /* startDocument */ + 0, /* endDocument */ + (startElementSAXFunc)saxStartElement, /* startElement */ + (endElementSAXFunc)saxEndElement, /* endElement */ + 0, /* reference */ + (charactersSAXFunc)saxCharacters, /* characters */ + 0, /* ignorableWhitespace */ + 0, /* processingInstruction */ + (commentSAXFunc)saxComment, /* comment */ + (warningSAXFunc)saxWarning, /* warning */ + (errorSAXFunc)saxError, /* error */ + (fatalErrorSAXFunc)saxFatal, /* fatalError */ +}; + +// ------------------------------------------------------------------------------------------------ + +CWatchBSP::~CWatchBSP() +{ + Reset(); + if (m_sBSPName) + { + delete[] m_sBSPName; + m_sBSPName = NULL; + } + Net_Shutdown(); +} + +void CWatchBSP::Reset() +{ + if (m_pInSocket) + { + Net_Disconnect(m_pInSocket); + m_pInSocket = NULL; + } + if (m_pListenSocket) + { + Net_Disconnect(m_pListenSocket); + m_pListenSocket = NULL; + } + if (m_xmlInputBuffer) + { + xmlFreeParserInputBuffer (m_xmlInputBuffer); + m_xmlInputBuffer = NULL; + } + m_eState = EIdle; +} + +bool CWatchBSP::SetupListening() +{ +#ifdef _DEBUG + if (m_pListenSocket) + { + Sys_Printf("ERROR: m_pListenSocket != NULL in CWatchBSP::SetupListening\n"); + return false; + } +#endif + Sys_Printf("Setting up\n"); + Net_Setup(); + m_pListenSocket = Net_ListenSocket(39000); + if (m_pListenSocket == NULL) + return false; + Sys_Printf("Listening...\n"); + return true; +} + +void CWatchBSP::DoEBeginStep() +{ + Reset(); + if (SetupListening() == false) + { + CString msg; + msg = "Failed to get a listening socket on port 39000.\nTry running with BSP monitoring disabled if you can't fix this.\n"; + Sys_Printf (msg); + gtk_MessageBox (g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR); + return; + } + // set the timer for timeouts and step cancellation + g_timer_reset( m_pTimer ); + g_timer_start( m_pTimer ); + + if (!m_bBSPPlugin) + { + Sys_Printf("=== running BSP command ===\n%s\n", g_ptr_array_index( m_pCmd, m_iCurrentStep ) ); + + if (!Q_Exec(NULL, (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ), NULL, true )) + { + CString msg; + msg = "Failed to execute the following command: "; + msg += (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ); + msg += "\nCheck that the file exists and that you don't run out of system resources.\n"; + Sys_Printf(msg); + gtk_MessageBox(g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR ); + return; + } + // re-initialise the debug window + if (m_iCurrentStep == 0) + g_DbgDlg.Init(); + } + m_eState = EBeginStep; +} + +void CWatchBSP::RoutineProcessing() +{ + // used for select() +#ifdef _WIN32 + TIMEVAL tout = { 0, 0 }; +#endif +#if defined (__linux__) || defined (__APPLE__) + timeval tout; + tout.tv_sec = 0; + tout.tv_usec = 0; +#endif + + switch (m_eState) + { + case EBeginStep: + // timeout: if we don't get an incoming connection fast enough, go back to idle + if ( g_timer_elapsed( m_pTimer, NULL ) > g_PrefsDlg.m_iTimeout ) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "The connection timed out, assuming the BSP process failed\nMake sure you are using a networked version of Q3Map?\nOtherwise you need to disable BSP Monitoring in prefs.", "BSP process monitoring", MB_OK ); + Reset(); + if (m_bBSPPlugin) + { + // status == 1 : didn't get the connection + g_BSPFrontendTable.m_pfnEndListen(1); + } + return; + } +#ifdef _DEBUG + // some debug checks + if (!m_pListenSocket) + { + Sys_Printf("ERROR: m_pListenSocket == NULL in CWatchBSP::RoutineProcessing EBeginStep state\n"); + return; + } +#endif + // we are not connected yet, accept any incoming connection + m_pInSocket = Net_Accept(m_pListenSocket); + if (m_pInSocket) + { + Sys_Printf("Connected.\n"); + // prepare the message info struct for diving in + memset (&m_message_info, 0, sizeof(message_info_s)); + // a dumb flag to make sure we init the push parser context when first getting a msg + m_bNeedCtxtInit = true; + m_eState = EWatching; + } + break; + case EWatching: +#ifdef _DEBUG + // some debug checks + if (!m_pInSocket) + { + Sys_Printf("ERROR: m_pInSocket == NULL in CWatchBSP::RoutineProcessing EWatching state\n"); + return; + } +#endif + // select() will identify if the socket needs an update + // if the socket is identified that means there's either a message or the connection has been closed/reset/terminated + fd_set readfds; + int ret; + FD_ZERO(&readfds); + FD_SET(((unsigned int)m_pInSocket->socket), &readfds); + // from select man page: + // n is the highest-numbered descriptor in any of the three sets, plus 1 + // (no use on windows) + ret = select( m_pInSocket->socket + 1, &readfds, NULL, NULL, &tout ); + if (ret == SOCKET_ERROR) + { + Sys_Printf("WARNING: SOCKET_ERROR in CWatchBSP::RoutineProcessing\n"); + Sys_Printf("Terminating the connection.\n"); + Reset(); + return; + } +#ifdef _DEBUG + if (ret == -1) + { + // we are non-blocking?? we should never get timeout errors + Sys_Printf("WARNING: unexpected timeout expired in CWatchBSP::Processing\n"); + Sys_Printf("Terminating the connection.\n"); + Reset(); + return; + } +#endif + if (ret == 1) + { + // the socket has been identified, there's something (message or disconnection) + // see if there's anything in input + ret = Net_Receive( m_pInSocket, &msg ); + if (ret > 0) + { + // unsigned int size = msg.size; //++timo just a check + strcpy (m_xmlBuf, NMSG_ReadString (&msg)); + if (m_bNeedCtxtInit) + { + m_xmlParserCtxt = NULL; + m_xmlParserCtxt = xmlCreatePushParserCtxt (&saxParser, &m_message_info, m_xmlBuf, strlen(m_xmlBuf), NULL); + if (m_xmlParserCtxt == NULL) + { + Sys_FPrintf (SYS_ERR, "Failed to create the XML parser (incoming stream began with: %s)\n", m_xmlBuf); + Reset(); + } + m_bNeedCtxtInit = false; + } + else + { + xmlParseChunk (m_xmlParserCtxt, m_xmlBuf, strlen(m_xmlBuf), 0); + } + } + else + { + // error or connection closed/reset + // NOTE: if we get an error down the XML stream we don't reach here + Net_Disconnect( m_pInSocket ); + m_pInSocket = NULL; + Sys_Printf("Connection closed.\n"); + if (m_bBSPPlugin) + { + Reset(); + // let the BSP plugin know that the job is done + g_BSPFrontendTable.m_pfnEndListen(0); + return; + } + // move to next step or finish + m_iCurrentStep++; + if (m_iCurrentStep < m_pCmd->len ) + { + DoEBeginStep(); + } + else + { + // release the GPtrArray and the strings + if (m_pCmd != NULL) + { + for (m_iCurrentStep=0; m_iCurrentStep < m_pCmd->len; m_iCurrentStep++ ) + { + delete[] (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ); + } + g_ptr_array_free( m_pCmd, false ); + } + m_pCmd = NULL; + // launch the engine .. OMG + if (g_PrefsDlg.m_bRunQuake) + { + // do we enter sleep mode before? + if (g_PrefsDlg.m_bDoSleep) + { + Sys_Printf("Going into sleep mode..\n"); + g_pParentWnd->OnSleep(); + } + Sys_Printf("Running engine...\n"); + Str cmd; + // build the command line + cmd = g_pGameDescription->mEnginePath.GetBuffer(); + // this is game dependant + //!\todo Read the engine binary name from a config file. + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "WolfMP.exe"; +#elif defined(__linux__) + cmd += "wolfmp"; +#elif defined(__APPLE__) + cmd += "wolfmp.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "WolfSP.exe"; +#elif defined(__linux__) + cmd += "wolfsp"; +#elif defined(__APPLE__) + cmd += "wolfsp.app"; +#else +#error "WTF are you compiling on" +#endif + } + } else if (g_pGameDescription->mGameFile == "et.game") + { +#if defined(WIN32) + cmd += "et.exe"; +#elif defined(__linux__) + cmd += "et"; +#elif defined(__APPLE__) + cmd += "et.app"; +#else +#error "WTF are you compiling on" +#endif + } + // RIANT + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "jk2MP.exe"; +#elif defined(__linux__) + cmd += "jk2mp"; +#elif defined(__APPLE__) + cmd += "jk2mp.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "jk2SP.exe"; +#elif defined(__linux__) + cmd += "jk2sp"; +#elif defined(__APPLE__) + cmd += "jk2sp.app"; +#else +#error "WTF are you compiling on" +#endif + } + } + // TTimo + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "jamp.exe"; +#elif !defined(__linux__) && !defined(__APPLE__) +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "jasp.exe"; +#elif !defined(__linux__) && !defined(__APPLE__) +#error "WTF are you compiling on" +#endif + } + } + // RIANT + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "stvoyHM.exe"; +#elif defined(__linux__) + cmd += "stvoyHM"; +#elif defined(__APPLE__) + cmd += "stvoyHM.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "stvoy.exe"; +#elif defined(__linux__) + cmd += "stvoy"; +#elif defined(__APPLE__) + cmd += "stvoy.app"; +#else +#error "WTF are you compiling on" +#endif + } + } + // RIANT + // SOF2 HACK + else if (g_pGameDescription->mGameFile == "sof2.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "sof2MP.exe"; +#elif defined(__linux__) + cmd += "b00gus"; +#elif defined(__APPLE__) + cmd += "sof2MP.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "sof2.exe"; +#elif defined(__linux__) + cmd += "b00gus"; +#elif defined(__APPLE__) + cmd += "sof2.app"; +#else +#error "WTF are you compiling on" +#endif + } + } + else + { + cmd += g_pGameDescription->mEngine.GetBuffer(); + } +#ifdef _WIN32 + // NOTE: we are using unix pathnames and CreateProcess doesn't like / in the program path + FindReplace( cmd, "/", "\\" ); +#endif + Str cmdline; + if ( (g_pGameDescription->mGameFile == "q2.game") || (g_pGameDescription->mGameFile == "heretic2.game") ) + { + cmdline = ". +exec radiant.cfg +map "; + cmdline += m_sBSPName; + } + else + { + cmdline = "+set sv_pure 0 "; + // TTimo: a check for vm_* but that's all fine + //cmdline = "+set sv_pure 0 +set vm_ui 0 +set vm_cgame 0 +set vm_game 0 "; + if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') + { + cmdline += "+set fs_game "; + cmdline += ValueForKey(g_qeglobals.d_project_entity, "gamename"); + cmdline += " "; + } + //!\todo Read the start-map args from a config file. + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP + cmdline += "+devmap "; + cmdline += m_sBSPName; + } + else + { + // SP + cmdline += "+set nextmap \"spdevmap "; + cmdline += m_sBSPName; + cmdline += "\""; + } + } + else + { + cmdline += "+devmap "; + cmdline += m_sBSPName; + } + } + + Sys_Printf("%s %s\n", cmd.GetBuffer(), cmdline.GetBuffer()); + + // execute now + if (!Q_Exec(cmd.GetBuffer(), (char *)cmdline.GetBuffer(), g_pGameDescription->mEnginePath.GetBuffer(), false)) + { + CString msg; + msg = "Failed to execute the following command: "; + msg += cmd; msg += cmdline; + Sys_Printf(msg); + gtk_MessageBox(g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR ); + } + } + Reset(); + } + } + } + break; + default: + break; + } +} + +void CWatchBSP::DoMonitoringLoop( GPtrArray *pCmd, char *sBSPName ) +{ + if (m_sBSPName) + { + delete[] m_sBSPName; + } + m_sBSPName = sBSPName; + if (m_eState != EIdle) + { + Sys_Printf("WatchBSP got a monitoring request while not idling...\n"); + // prompt the user, should we cancel the current process and go ahead? + if (gtk_MessageBox(g_pParentWnd->m_pWidget, "I am already monitoring a BSP process.\nDo you want me to override and start a new compilation?", + "BSP process monitoring", MB_YESNO ) == IDYES) + { + // disconnect and set EIdle state + Reset(); + } + } + m_pCmd = pCmd; + m_iCurrentStep = 0; + DoEBeginStep(); +} + +void CWatchBSP::ExternalListen() +{ + m_bBSPPlugin = true; + DoEBeginStep (); +} + +// the part of the watchbsp interface we export to plugins +// NOTE: in the long run, the whole watchbsp.cpp interface needs to go out and be handled at the BSP plugin level +// for now we provide something really basic and limited, the essential is to have something that works fine and fast (for 1.1 final) +void WINAPI QERApp_Listen() +{ + // open the listening socket + g_pParentWnd->GetWatchBSP()->ExternalListen(); +} diff --git a/radiant/watchbsp.h b/radiant/watchbsp.h new file mode 100644 index 00000000..c124c54f --- /dev/null +++ b/radiant/watchbsp.h @@ -0,0 +1,91 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _BSPWINDOW_H_ +#define _BSPWINDOW_H_ + +#include "l_net/l_net.h" + +class CWatchBSP +{ +private: + // a flag we have set to true when using an external BSP plugin + // the resulting code with that is a bit dirty, cleaner solution would be to seperate the succession of commands from the listening loop + // (in two seperate classes probably) + bool m_bBSPPlugin; + + // EIdle: we are not listening + // DoMonitoringLoop will change state to EBeginStep + // EBeginStep: the socket is up for listening, we are expecting incoming connection + // incoming connection will change state to EWatching + // EWatching: we have a connection, monitor it + // connection closed will see if we start a new step (EBeginStep) or launch Quake3 and end (EIdle) + enum EWatchBSPState { EIdle, EBeginStep, EWatching } m_eState; + socket_t *m_pListenSocket; + socket_t *m_pInSocket; + netmessage_t msg; + GPtrArray *m_pCmd; + // used to timeout EBeginStep + GTimer *m_pTimer; + unsigned int m_iCurrentStep; + // name of the map so we can run the engine + char *m_sBSPName; + // buffer we use in push mode to receive data directly from the network + xmlParserInputBufferPtr m_xmlInputBuffer; + xmlParserInputPtr m_xmlInput; + xmlParserCtxtPtr m_xmlParserCtxt; + // call this to switch the set listening mode + bool SetupListening(); + // start a new EBeginStep + void DoEBeginStep(); + // the xml and sax parser state + char m_xmlBuf[MAX_NETMESSAGE]; + bool m_bNeedCtxtInit; + message_info_s m_message_info; + +public: + CWatchBSP() { m_bBSPPlugin = false; m_pListenSocket = NULL; m_pInSocket = NULL; m_eState = EIdle; m_pTimer = g_timer_new(); m_sBSPName = NULL; m_xmlInputBuffer = NULL; m_bNeedCtxtInit = true; } + virtual ~CWatchBSP(); + bool HasBSPPlugin () const + { return m_bBSPPlugin; } + + // called regularly to keep listening + void RoutineProcessing(); + // start a monitoring loop with the following steps + void DoMonitoringLoop( GPtrArray *pCmd, char *sBSPName ); + // close everything - may be called from the outside to abort the process + void Reset(); + // start a listening loop for an external process, possibly a BSP plugin + void ExternalListen(); +}; + +void WINAPI QERApp_Listen(); + +#endif diff --git a/radiant/winding.cpp b/radiant/winding.cpp new file mode 100644 index 00000000..65393ce9 --- /dev/null +++ b/radiant/winding.cpp @@ -0,0 +1,822 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + + +#include "stdafx.h" +#include +#include "winding.h" + +#define BOGUS_RANGE (g_MaxWorldCoord+1) + +/* +============= +Plane_Equal +============= +*/ +#define NORMAL_EPSILON 0.0001 +#define DIST_EPSILON 0.02 + +int Plane_Equal(plane_t *a, plane_t *b, int flip) +{ + vec3_t normal; + float dist; + + if (flip) { + normal[0] = - b->normal[0]; + normal[1] = - b->normal[1]; + normal[2] = - b->normal[2]; + dist = - b->dist; + } + else { + normal[0] = b->normal[0]; + normal[1] = b->normal[1]; + normal[2] = b->normal[2]; + dist = b->dist; + } + if ( + fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON + && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON + && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON + && fabs(a->dist - dist) < DIST_EPSILON ) + return true; + return false; +} + +/* +============ +Plane_FromPoints +============ +*/ +int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane) +{ + vec3_t v1, v2; + + VectorSubtract(p2, p1, v1); + VectorSubtract(p3, p1, v2); + //CrossProduct(v2, v1, plane->normal); + CrossProduct(v1, v2, plane->normal); + if (VectorNormalize(plane->normal, plane->normal) < 0.1) return false; + plane->dist = DotProduct(p1, plane->normal); + return true; +} + +/* +================= +Point_Equal +================= +*/ +int Point_Equal(vec3_t p1, vec3_t p2, float epsilon) +{ + int i; + + for (i = 0; i < 3; i++) + { + if (fabs(p1[i] - p2[i]) > epsilon) return false; + } + return true; +} + + +/* +================= +Winding_BaseForPlane +================= +*/ +//#define DBG_WNDG +winding_t *Winding_BaseForPlane (plane_t *p) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + + // find the major axis +#ifdef DBG_WNDG + Sys_Printf("Winding_BaseForPlane %p\n",p); +#endif + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(p->normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("Winding_BaseForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + + v = DotProduct (vup, p->normal); + VectorMA (vup, -v, p->normal, vup); + VectorNormalize (vup, vup); + + VectorScale (p->normal, p->dist, org); + + CrossProduct (vup, p->normal, vright); + + VectorScale (vup, BOGUS_RANGE, vup); + VectorScale (vright, BOGUS_RANGE, vright); + + // project a really big axis aligned box onto the plane + w = Winding_Alloc (4); + + VectorSubtract (org, vright, w->points[0]); + VectorAdd (w->points[0], vup, w->points[0]); + + VectorAdd (org, vright, w->points[1]); + VectorAdd (w->points[1], vup, w->points[1]); + + VectorAdd (org, vright, w->points[2]); + VectorSubtract (w->points[2], vup, w->points[2]); + + VectorSubtract (org, vright, w->points[3]); + VectorSubtract (w->points[3], vup, w->points[3]); + + w->numpoints = 4; + + return w; +} + +// macro to compute winding size +#define WINDING_SIZE(pt) (sizeof(int)*2+sizeof(float)*5*(pt)) + +/* +================== +Winding_Alloc +================== +*/ +winding_t *Winding_Alloc (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("Winding_Alloc: %i points", points); + +// size = (int)((winding_t *)0)->points[points]; + size = WINDING_SIZE(points); + w = (winding_t*) malloc (size); + memset (w, 0, size); + w->maxpoints = points; + + return w; +} + +void Winding_Free (winding_t *w) +{ + free(w); +} + +/* +================== +Winding_Clone +================== +*/ +winding_t *Winding_Clone(winding_t *w) +{ + int size; + winding_t *c; + +// size = (int)((winding_t *)0)->points[w->numpoints]; + size = WINDING_SIZE(w->numpoints); + c = (winding_t*)qmalloc (size); + memcpy (c, w, size); + return c; +} + +/* +================== +ReverseWinding +================== +*/ +winding_t *Winding_Reverse(winding_t *w) +{ + int i; + winding_t *c; + + c = Winding_Alloc(w->numpoints); + for (i = 0; i < w->numpoints; i++) + { + VectorCopy (w->points[w->numpoints-1-i], c->points[i]); + } + c->numpoints = w->numpoints; + return c; +} + +/* +============== +Winding_RemovePoint +============== +*/ +void Winding_RemovePoint(winding_t *w, int point) +{ + if (point < 0 || point >= w->numpoints) + Error("Winding_RemovePoint: point out of range"); + + if (point < w->numpoints-1) + { + memmove(&w->points[point], &w->points[point+1], (int)((winding_t *)0)->points[w->numpoints - point - 1]); + } + w->numpoints--; +} + +/* +============= +Winding_InsertPoint +============= +*/ +winding_t *Winding_InsertPoint(winding_t *w, vec3_t point, int spot) +{ + int i, j; + winding_t *neww; + + if (spot > w->numpoints) + { + Error("Winding_InsertPoint: spot > w->numpoints"); + } //end if + if (spot < 0) + { + Error("Winding_InsertPoint: spot < 0"); + } //end if + neww = Winding_Alloc(w->numpoints + 1); + neww->numpoints = w->numpoints + 1; + for (i = 0, j = 0; i < neww->numpoints; i++) + { + if (i == spot) + { + VectorCopy(point, neww->points[i]); + } + else + { + VectorCopy(w->points[j], neww->points[i]); + j++; + } + } + return neww; +} + +/* +============== +Winding_IsTiny +============== +*/ +#define EDGE_LENGTH 0.2 + +int Winding_IsTiny (winding_t *w) +{ + int i, j; + vec_t len; + vec3_t delta; + int edges; + + edges = 0; + for (i=0 ; inumpoints ; i++) + { + j = i == w->numpoints - 1 ? 0 : i+1; + VectorSubtract (w->points[j], w->points[i], delta); + len = VectorLength (delta); + if (len > EDGE_LENGTH) + { + if (++edges == 3) + return false; + } + } + return true; +} + +/* +============== +Winding_IsHuge +============== +*/ +int Winding_IsHuge(winding_t *w) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->points[i][j] < -BOGUS_RANGE+1 || w->points[i][j] > BOGUS_RANGE-1) + return true; + } + return false; +} + +/* +============= +Winding_PlanesConcave +============= +*/ +#define WCONVEX_EPSILON 0.2 + +int Winding_PlanesConcave(winding_t *w1, winding_t *w2, + vec3_t normal1, vec3_t normal2, + float dist1, float dist2) +{ + int i; + + if (!w1 || !w2) return false; + + // check if one of the points of winding 1 is at the back of the plane of winding 2 + for (i = 0; i < w1->numpoints; i++) + { + if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return true; + } + // check if one of the points of winding 2 is at the back of the plane of winding 1 + for (i = 0; i < w2->numpoints; i++) + { + if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return true; + } + + return false; +} + +/* +================== +Winding_Clip + +Clips the winding to the plane, returning the new winding on the positive side +Frees the input winding. +If keepon is true, an exactly on-plane winding will be saved, otherwise +it will be clipped away. +================== +*/ +winding_t *Winding_Clip (winding_t *in, plane_t *split, qboolean keepon) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (keepon && !counts[0] && !counts[1]) + return in; + + if (!counts[0]) + { + Winding_Free (in); + return NULL; + } + if (!counts[1]) + return in; + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + neww = Winding_Alloc (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (neww->numpoints > maxpts) + Error ("Winding_Clip: points exceeded estimate"); + + // free the original winding + Winding_Free (in); + + return neww; +} + +/* +============= +Winding_SplitEpsilon + + split the input winding with the plane + the input winding stays untouched +============= +*/ +void Winding_SplitEpsilon (winding_t *in, vec3_t normal, double dist, + vec_t epsilon, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for (i = 0; i < in->numpoints; i++) + { + dot = DotProduct (in->points[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = Winding_Clone(in); + return; + } + if (!counts[1]) + { + *front = Winding_Clone(in); + return; + } + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + *front = f = Winding_Alloc (maxpts); + *back = b = Winding_Alloc (maxpts); + + for (i = 0; i < in->numpoints; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->points[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->points[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->points[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->points[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j = 0; j < 3; j++) + { + // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->points[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->points[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("Winding_Clip: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("Winding_Clip: MAX_POINTS_ON_WINDING"); +} + +/* +============= +Winding_TryMerge + +If two windings share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the windings couldn't be merged, or the new winding. +The originals will NOT be freed. + +if keep is true no points are ever removed +============= +*/ +#define CONTINUOUS_EPSILON 0.005 + +winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep) +{ + vec_t *p1, *p2, *p3, *p4, *back; + winding_t *newf; + int i, j, k, l; + vec3_t normal, delta; + vec_t dot; + qboolean keep1, keep2; + + + // + // find a common edge + // + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for (i = 0; i < f1->numpoints; i++) + { + p1 = f1->points[i]; + p2 = f1->points[(i+1) % f1->numpoints]; + for (j = 0; j < f2->numpoints; j++) + { + p3 = f2->points[j]; + p4 = f2->points[(j+1) % f2->numpoints]; + for (k = 0; k < 3; k++) + { + if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME + break; + if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME + break; + } //end for + if (k==3) + break; + } //end for + if (j < f2->numpoints) + break; + } //end for + + if (i == f1->numpoints) + return NULL; // no matching edges + + // + // check slope of connected lines + // if the slopes are colinear, the point can be removed + // + back = f1->points[(i+f1->numpoints-1)%f1->numpoints]; + VectorSubtract (p1, back, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->points[(j+2)%f2->numpoints]; + VectorSubtract (back, p1, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + back = f1->points[(i+2)%f1->numpoints]; + VectorSubtract (back, p2, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->points[(j+f2->numpoints-1)%f2->numpoints]; + VectorSubtract (back, p2, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + // + // build the new polygon + // + newf = Winding_Alloc (f1->numpoints + f2->numpoints); + + // copy first polygon + for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) + { + if (!keep && k==(i+1)%f1->numpoints && !keep2) + continue; + + VectorCopy (f1->points[k], newf->points[newf->numpoints]); + newf->numpoints++; + } + + // copy second polygon + for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) + { + if (!keep && l==(j+1)%f2->numpoints && !keep1) + continue; + VectorCopy (f2->points[l], newf->points[newf->numpoints]); + newf->numpoints++; + } + + return newf; +} + +/* +============ +Winding_Plane +============ +*/ +void Winding_Plane (winding_t *w, vec3_t normal, double *dist) +{ + vec3_t v1, v2; + int i; + + //find two vectors each longer than 0.5 units + for (i = 0; i < w->numpoints; i++) + { + VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], v1); + VectorSubtract(w->points[(i+2) % w->numpoints], w->points[i], v2); + if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break; + } + CrossProduct(v2, v1, normal); + VectorNormalize(normal, normal); + *dist = DotProduct(w->points[0], normal); +} + +/* +============= +Winding_Area +============= +*/ +float Winding_Area (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + float total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->points[i-1], w->points[0], d1); + VectorSubtract (w->points[i], w->points[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +/* +============= +Winding_Bounds +============= +*/ +void Winding_Bounds (winding_t *w, vec3_t mins, vec3_t maxs) +{ + vec_t v; + int i,j; + + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->points[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + + +/* +================= +Winding_PointInside +================= +*/ +int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon) +{ + int i; + vec3_t dir, normal, pointvec; + + for (i = 0; i < w->numpoints; i++) + { + VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], dir); + VectorSubtract(point, w->points[i], pointvec); + // + CrossProduct(dir, plane->normal, normal); + // + if (DotProduct(pointvec, normal) < -epsilon) return false; + } + return true; +} + +/* +================= +Winding_VectorIntersect +================= +*/ +int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon) +{ + float front, back, frac; + vec3_t mid; + + front = DotProduct(p1, plane->normal) - plane->dist; + back = DotProduct(p2, plane->normal) - plane->dist; + //if both points at the same side of the plane + if (front < -epsilon && back < -epsilon) return false; + if (front > epsilon && back > epsilon) return false; + //get point of intersection with winding plane + if (fabs(front-back) < 0.001) + { + VectorCopy(p2, mid); + } + else + { + frac = front/(front-back); + mid[0] = p1[0] + (p2[0] - p1[0]) * frac; + mid[1] = p1[1] + (p2[1] - p1[1]) * frac; + mid[2] = p1[2] + (p2[2] - p1[2]) * frac; + } + return Winding_PointInside(w, plane, mid, epsilon); +} + diff --git a/radiant/winding.h b/radiant/winding.h new file mode 100644 index 00000000..3f21a204 --- /dev/null +++ b/radiant/winding.h @@ -0,0 +1,70 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + + + +//returns true if the planes are equal +int Plane_Equal(plane_t *a, plane_t *b, int flip); +//returns false if the points are colinear +int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane); +//returns true if the points are equal +int Point_Equal(vec3_t p1, vec3_t p2, float epsilon); + +//allocate a winding +winding_t* Winding_Alloc(int points); +//free the winding +void Winding_Free(winding_t *w); +//create a base winding for the plane +winding_t* Winding_BaseForPlane (plane_t *p); +//make a winding clone +winding_t* Winding_Clone(winding_t *w ); +//creates the reversed winding +winding_t* Winding_Reverse(winding_t *w); +//remove a point from the winding +void Winding_RemovePoint(winding_t *w, int point); +//inserts a point to a winding, creating a new winding +winding_t* Winding_InsertPoint(winding_t *w, vec3_t point, int spot); +//returns true if the planes are concave +int Winding_PlanesConcave(winding_t *w1, winding_t *w2, + vec3_t normal1, vec3_t normal2, + float dist1, float dist2); +//returns true if the winding is tiny +int Winding_IsTiny(winding_t *w); +//returns true if the winding is huge +int Winding_IsHuge(winding_t *w); +//clip the winding with the plane +winding_t* Winding_Clip(winding_t *in, plane_t *split, qboolean keepon); +//split the winding with the plane +void Winding_SplitEpsilon(winding_t *in, vec3_t normal, double dist, + vec_t epsilon, winding_t **front, winding_t **back); +//try to merge the windings, returns the new merged winding or NULL +winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep); +//create a plane for the winding +void Winding_Plane(winding_t *w, vec3_t normal, double *dist); +//returns the winding area +float Winding_Area(winding_t *w); +//returns the bounds of the winding +void Winding_Bounds(winding_t *w, vec3_t mins, vec3_t maxs); +//returns true if the point is inside the winding +int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon); +//returns true if the vector intersects with the winding +int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon); diff --git a/radiant/xmlstuff.h b/radiant/xmlstuff.h new file mode 100644 index 00000000..dc23f644 --- /dev/null +++ b/radiant/xmlstuff.h @@ -0,0 +1,70 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// header for xml stuff used in radiant +// + +#ifndef __XMLSTUFF__ +#define __XMLSTUFF__ + +#include "libxml/parser.h" + +struct message_info_s; + +class ISAXHandler +{ +public: + virtual void saxStartElement (struct message_info_s *ctx, const xmlChar *name, const xmlChar **attrs) = 0; + virtual void saxEndElement (struct message_info_s *ctx, const xmlChar *name) = 0; + virtual void saxCharacters (struct message_info_s *ctx, const xmlChar *ch, int len) = 0; + virtual char *getName() { return NULL; } + virtual void Highlight() { } + virtual void DropHighlight() { } +}; + +// a 'user data' structure we pass along in the SAX callbacks to represent the current state +// the recurse value tracks the current depth in the tree +// message_info also stores information to exit the stream listening cleanly with an error: +// if msg_level == SYS_ERR, then we will reset the listening at the end of the current node +// the level for stopping the feed is stored in stop_depth +// unkown nodes are ignored, we use ignore_depth to track the level we start ignoring from +typedef struct message_info_s { + int msg_level; // current message level (SYS_MSG, SYS_WRN, SYS_ERR) + int recurse; // current recursion depth (used to track various things) + int ignore_depth; // the ignore depth limit when we are jumping over unknown nodes (0 means we are not ignoring) + int stop_depth; // the depth we need to stop at the end + bool bGeometry; // are we parsing some geometry information (i.e. do we forward the SAX calls?) + ISAXHandler *pGeometry; // the handler +} message_info_t; + +#endif diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp new file mode 100644 index 00000000..fabc809f --- /dev/null +++ b/radiant/xywindow.cpp @@ -0,0 +1,3462 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// XY Window +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +// ============================================================================= +// variables + +#define PAGEFLIPS 2 + +CString g_strStatus; +bool g_bCrossHairs = false; +bool g_bScaleMode; +int g_nScaleHow; +bool g_bRotateMode; +bool g_bClipMode; +bool g_bRogueClipMode; +bool g_bSwitch; +ClipPoint g_Clip1; +ClipPoint g_Clip2; +ClipPoint g_Clip3; +ClipPoint* g_pMovingClip; +brush_t g_brFrontSplits; +brush_t g_brBackSplits; + +brush_t g_brClipboard; +brush_t g_brUndo; +entity_t g_enClipboard; + +vec3_t g_vRotateOrigin; +vec3_t g_vRotation; + +bool g_bPathMode; +ClipPoint g_PathPoints[256]; // this limit isn't enforced? +ClipPoint* g_pMovingPath; +int g_nPathCount; +int g_nPathLimit; + +bool g_bSmartGo; + +bool g_bPointMode; +ClipPoint g_PointPoints[512]; +ClipPoint* g_pMovingPoint; +int g_nPointCount; +int g_nPointLimit; + +const int XY_LEFT = 0x01; +const int XY_RIGHT = 0x02; +const int XY_UP = 0x04; +const int XY_DOWN = 0x08; + +PFNPathCallback* g_pPathFunc = NULL; + +static unsigned s_stipple[32] = +{ + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, +}; + +void AcquirePath(int nCount, PFNPathCallback* pFunc) +{ + g_nPathCount = 0; + g_nPathLimit = nCount; + g_pPathFunc = pFunc; + g_bPathMode = true; +} + + +CPtrArray g_ptrMenus; + +MemStream g_Clipboard(4096); +MemStream g_PatchClipboard(4096); + +extern int pressx; +extern int pressy; +extern bool g_bWaitCursor; + +vec3_t tdp; + +GtkWidget* XYWnd::m_mnuDrop = NULL; + +extern int g_nPatchClickedView; + +// ============================================================================= +// global functions + +// this is disabled, and broken +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 +#if 0 +void WXY_Print () +{ + long width, height; + width = g_pParentWnd->ActiveXY()->Width(); + height = g_pParentWnd->ActiveXY()->Height(); + unsigned char* img; + const char* filename; + + filename = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Save Image", NULL, FILTER_BMP); + if (!filename) + return; + + g_pParentWnd->ActiveXY()->MakeCurrent(); + img = (unsigned char*)malloc (width*height*3); + qglReadPixels (0,0,width,height,GL_RGB,GL_UNSIGNED_BYTE,img); + + FILE *fp; + fp = fopen(filename, "wb"); + if (fp) + { + unsigned short bits; + unsigned long cmap, bfSize; + + bits = 24; + cmap = 0; + bfSize = 54 + width*height*3; + + long byteswritten = 0; + long pixoff = 54 + cmap*4; + short res = 0; + char m1 ='B', m2 ='M'; + fwrite(&m1, 1, 1, fp); byteswritten++; // B + fwrite(&m2, 1, 1, fp); byteswritten++; // M + fwrite(&bfSize, 4, 1, fp); byteswritten+=4;// bfSize + fwrite(&res, 2, 1, fp); byteswritten+=2;// bfReserved1 + fwrite(&res, 2, 1, fp); byteswritten+=2;// bfReserved2 + fwrite(&pixoff, 4, 1, fp); byteswritten+=4;// bfOffBits + + unsigned long biSize = 40, compress = 0, size = 0; + long pixels = 0; + unsigned short planes = 1; + fwrite(&biSize, 4, 1, fp); byteswritten+=4;// biSize + fwrite(&width, 4, 1, fp); byteswritten+=4;// biWidth + fwrite(&height, 4, 1, fp); byteswritten+=4;// biHeight + fwrite(&planes, 2, 1, fp); byteswritten+=2;// biPlanes + fwrite(&bits, 2, 1, fp); byteswritten+=2;// biBitCount + fwrite(&compress, 4, 1, fp);byteswritten+=4;// biCompression + fwrite(&size, 4, 1, fp); byteswritten+=4;// biSizeImage + fwrite(&pixels, 4, 1, fp); byteswritten+=4;// biXPelsPerMeter + fwrite(&pixels, 4, 1, fp); byteswritten+=4;// biYPelsPerMeter + fwrite(&cmap, 4, 1, fp); byteswritten+=4;// biClrUsed + fwrite(&cmap, 4, 1, fp); byteswritten+=4;// biClrImportant + + unsigned long widthDW = (((width*24) + 31) / 32 * 4); + long row, row_size = width*3; + for (row = 0; row < height; row++) + { + unsigned char* buf = img+row*row_size; + + // write a row + int col; + for (col = 0; col < row_size; col += 3) + { + putc(buf[col+2], fp); + putc(buf[col+1], fp); + putc(buf[col], fp); + } + byteswritten += row_size; + + unsigned long count; + for (count = row_size; count < widthDW; count++) + { + putc(0, fp); // dummy + byteswritten++; + } + } + + fclose(fp); + } + + free (img); +} +#endif + +float ptSum(vec3_t pt) +{ + return pt[0] + pt[1] + pt[2]; +} + +float Betwixt(float f1, float f2) +{ + if (f1 > f2) + return f2 + ((f1 - f2) / 2); + else + return f1 + ((f2 - f1) / 2); +} + +void CleanList(brush_t* pList) +{ + brush_t* pBrush = pList->next; + while (pBrush != NULL && pBrush != pList) + { + brush_t* pNext = pBrush->next; + Brush_Free(pBrush); + pBrush = pNext; + } +} + +void Brush_CopyList (brush_t* pFrom, brush_t* pTo) +{ + brush_t* pBrush = pFrom->next; + while (pBrush != NULL && pBrush != pFrom) + { + brush_t* pNext = pBrush->next; + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, pTo); + pBrush = pNext; + } +} + +float fDiff(float f1, float f2) +{ + if (f1 > f2) + return f1 - f2; + else + return f2 - f1; +} + +/* +============================================================= + + PATH LINES + +============================================================= +*/ + +/* +================== +DrawPathLines + +Draws connections between entities. +Needs to consider all entities, not just ones on screen, +because the lines can be visible when neither end is. +Called for both camera view and xy view. +================== +*/ +void DrawPathLines (void) +{ + int i, j, k; + vec3_t mid, mid1; + entity_t *se, *te; + brush_t *sb, *tb; + const char *psz; + vec3_t dir, s1, s2; + vec_t len, f; + int arrows; + int num_entities; + const char *ent_target[MAX_MAP_ENTITIES]; + entity_t *ent_entity[MAX_MAP_ENTITIES]; + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) + { + return; + } + + num_entities = 0; + for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next) + { + ent_target[num_entities] = ValueForKey (te, "target"); + if (ent_target[num_entities][0]) + { + ent_entity[num_entities] = te; + num_entities++; + } + } + + for (se = entities.next ; se != &entities ; se = se->next) + { + psz = ValueForKey(se, "targetname"); + + if (psz == NULL || psz[0] == '\0') + continue; + + sb = se->brushes.onext; + if (sb == &se->brushes) + continue; + + for (k=0 ; kbrushes.onext; + if (tb == &te->brushes) + continue; + + for (i=0 ; i<3 ; i++) + mid[i] = (sb->mins[i] + sb->maxs[i])*0.5; + + for (i=0 ; i<3 ; i++) + mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5; + + VectorSubtract (mid1, mid, dir); + len = VectorNormalize (dir, dir); + s1[0] = -dir[1]*8 + dir[0]*8; + s2[0] = dir[1]*8 + dir[0]*8; + s1[1] = dir[0]*8 + dir[1]*8; + s2[1] = -dir[0]*8 + dir[1]*8; + + qglColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]); + + qglBegin(GL_LINES); + qglVertex3fv(mid); + qglVertex3fv(mid1); + + arrows = (int)(len / 256) + 1; + + for (i=0 ; im_pWidget, "Can't create an entity with worldspawn.", "info", 0); + return; + } + + e = Entity_Alloc(); + SetKeyValue(e, "classname", name); + + if(e->eclass->fixedsize) + { + Select_Delete(); + b = Brush_Create(e->eclass->mins, e->eclass->maxs, &e->eclass->texdef); + Entity_LinkBrush(e, b); + Brush_AddToList(b, &active_brushes); + Select_Brush(b); + Brush_Move(b, origin, true); + } + else + { + Select_GroupEntity(e); + if(e->brushes.onext == &e->brushes) + { + Sys_FPrintf(SYS_ERR, "CreateEntityFromName: selection could not be grouped\n"); + Entity_Free(e); + return; + } + } + + Entity_AddToList(e, &entities); + Undo_EndEntity(e); + + Select_Deselect (); + + // tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box + // see SF bug 105383 + + if (g_pGameDescription->mGameFile == "hl.game") + { + // FIXME - Hydra: really we need a combined light AND color dialog for halflife. + if ((stricmp(name, "light") == 0) || + (stricmp(name, "light_environment") == 0) || + (stricmp(name, "light_spot") == 0) ) + { + int intensity = g_PrefsDlg.m_iLastLightIntensity; + + // Create and show the dialog box + // CWnd *pWnd; + // pWnd = prompt.GetDlgItem( IDC_EDIT1 ); + // prompt.GotoDlgCtrl( pWnd ); + if (DoLightIntensityDlg (&intensity) == IDOK) + { + g_PrefsDlg.m_iLastLightIntensity = intensity; + char buf[30]; + sprintf( buf, "255 255 255 %d", intensity ); + SetKeyValue(e, "_light", buf); + } + } + } + else + { + if (stricmp(name, "light") == 0) + { + int intensity = g_PrefsDlg.m_iLastLightIntensity; + + // Create and show the dialog box + // CWnd *pWnd; + // pWnd = prompt.GetDlgItem( IDC_EDIT1 ); + // prompt.GotoDlgCtrl( pWnd ); + if (DoLightIntensityDlg (&intensity) == IDOK) + { + g_PrefsDlg.m_iLastLightIntensity = intensity; + char buf[10]; + sprintf( buf, "%d", intensity ); + SetKeyValue(e, "light", buf); + } + } + } + Select_Brush (e->brushes.onext); + + if ( (stricmp(name, "misc_model") == 0) || (stricmp(name, "misc_gamemodel") == 0) || (strcmpi(name, "model_static") == 0) ) + { + SetInspectorMode(W_ENTITY); + AssignModel(); + } +} + +void CreateRightClickEntity(XYWnd* pWnd, int x, int y, char* pName) +{ + int height = pWnd->GetWidget()->allocation.height; + vec3_t point; + pWnd->SnapToPoint (x, height - 1 - y, point); + + int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1; + float fWorkMid = (g_qeglobals.d_work_min[nDim] + g_qeglobals.d_work_max[nDim]) * 0.5; + point[nDim] = g_qeglobals.d_gridsize * ((int)(fWorkMid/g_qeglobals.d_gridsize)); + + CreateEntityFromName(pName, point); +} + + +brush_t* CreateSmartBrush(vec3_t v) +{ + vec3_t mins, maxs; + int i; + brush_t *n; + + for (i=0 ; i<3 ; i++) + { + mins[i] = v[i] - 16; + maxs[i] = v[i] + 16; + } + + n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); + if (!n) + return NULL; + + Brush_AddToList(n, &selected_brushes); + //Entity_LinkBrush(world_entity, n); + Brush_Build(n); + return n; +} + +CString g_strSmartEntity; +int g_nSmartX; +int g_nSmartY; +bool g_bSmartWaiting; +void _SmartPointDone(bool b, int n) +{ + g_bSmartWaiting = false; +} + +void CreateSmartEntity(XYWnd* pWnd, int x, int y, const char* pName) +{ + g_nSmartX = x; + g_nSmartY = y; + g_strSmartEntity = pName; + if (g_strSmartEntity.Find("Smart_Train") >= 0) + { + ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation"); + g_bPathMode = true; + g_nPathLimit = 0; + g_nPathCount = 0; + g_bSmartGo = true; + } + else + if (g_strSmartEntity.Find("Smart_Monster...") >= 0) + { + g_bPathMode = true; + g_nPathLimit = 0; + g_nPathCount = 0; + } + else + if (g_strSmartEntity.Find("Smart_Rotating") >= 0) + { + g_bSmartWaiting = true; + ShowInfoDialog("Left click to specify the rotation origin"); + AcquirePath(1, &_SmartPointDone); + while (g_bSmartWaiting) + gtk_main_iteration (); + HideInfoDialog(); + CPtrArray array; + g_bScreenUpdates = false; + CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating"); + array.Add(reinterpret_cast(selected_brushes.next)); + Select_Deselect(); + brush_t* pBrush = CreateSmartBrush(g_PathPoints[0]); + array.Add(pBrush); + Select_Deselect(); + Select_Brush(reinterpret_cast(array.GetAt(0))); + Select_Brush(reinterpret_cast(array.GetAt(1))); + ConnectEntities(); + g_bScreenUpdates = true; + } +} + +void FinishSmartCreation() +{ + CPtrArray array; + HideInfoDialog(); + // brush_t* pEntities = NULL; + int n; + + if (g_strSmartEntity.Find("Smart_Train") >= 0) + { + g_bScreenUpdates = false; + CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train"); + array.Add(reinterpret_cast(selected_brushes.next)); + for (n = 0; n < g_nPathCount; n++) + { + Select_Deselect(); + CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_PathPoints[n].m_ptScreenX, + g_PathPoints[n].m_ptScreenY, "path_corner"); + array.Add(reinterpret_cast(selected_brushes.next)); + } + + for (n = 0; n < g_nPathCount; n++) + { + Select_Deselect(); + Select_Brush(reinterpret_cast(array.GetAt(n))); + Select_Brush(reinterpret_cast(array.GetAt(n+1))); + ConnectEntities(); + } + g_bScreenUpdates = true; + + } + g_nPathCount = 0; + g_bPathMode = false; + Sys_UpdateWindows(W_ALL); +} + +void CleanCopyEntities() +{ + entity_t* pe = g_enClipboard.next; + while (pe != NULL && pe != &g_enClipboard) + { + entity_t* next = pe->next; + epair_t* enext = NULL; + for (epair_t* ep = pe->epairs ; ep ; ep=enext) + { + enext = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + free (pe); + pe = next; + } + g_enClipboard.next = g_enClipboard.prev = &g_enClipboard; +} + +entity_t *Entity_CopyClone (entity_t *e) +{ + entity_t *n; + epair_t *ep, *np; + + n = (entity_t*)qmalloc(sizeof(*n)); + n->brushes.onext = n->brushes.oprev = &n->brushes; + n->eclass = e->eclass; + + // add the entity to the entity list + n->next = g_enClipboard.next; + g_enClipboard.next = n; + n->next->prev = n; + n->prev = &g_enClipboard; + + for (ep = e->epairs ; ep ; ep=ep->next) + { + np = (epair_t*)qmalloc(sizeof(*np)); + np->key = copystring(ep->key); + np->value = copystring(ep->value); + np->next = n->epairs; + n->epairs = np; + } + return n; +} + +bool OnList(entity_t* pFind, CPtrArray* pList) +{ + int nSize = pList->GetSize(); + while (nSize-- > 0) + { + entity_t* pEntity = reinterpret_cast(pList->GetAt(nSize)); + if (pEntity == pFind) + return true; + } + return false; +} + +// ============================================================================= +// XYWnd class + +XYWnd::XYWnd () + : GLWindow (FALSE), m_XORRectangle(m_pWidget) +{ + g_brClipboard.next = &g_brClipboard; + g_brUndo.next = &g_brUndo; + g_nScaleHow = 0; + g_bRotateMode = false; + g_bClipMode = false; + g_bRogueClipMode = false; + g_bSwitch = true; + g_pMovingClip = (ClipPoint*)NULL; + g_pMovingPath = (ClipPoint*)NULL; + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + m_bActive = false; + //m_bTiming = true; + m_bTiming = false; + m_bRButtonDown = false; + m_nUpdateBits = W_XY; + g_bPathMode = false; + g_nPathCount = 0; + g_nPathLimit = 0; + m_nButtonstate = 0; +// m_mnuDrop = (GtkWidget*)NULL; + XY_Init(); +} + +vec3_t& XYWnd::Rotation() +{ + return g_vRotation; +} + +vec3_t& XYWnd::RotateOrigin() +{ + return g_vRotateOrigin; +} + +/* +============== +XY_Overlay +============== +*/ +void XYWnd::XY_Overlay() +{ + int w, h; + int r[4]; + static vec3_t lastz; + static vec3_t lastcamera; + + qglViewport(0, 0, m_nWidth, m_nHeight); + + // + // set up viewpoint + // + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + w = (int)(m_nWidth / 2 / m_fScale); + h = (int)(m_nHeight / 2 / m_fScale); + + qglOrtho (m_vOrigin[0] - w, m_vOrigin[0] + w , m_vOrigin[1] - h, m_vOrigin[1] + h, g_MinWorldCoord, g_MaxWorldCoord); + // + // erase the old camera and z checker positions + // if the entire xy hasn't been redrawn + // + if (m_bDirty) + { + qglReadBuffer (GL_BACK); + qglDrawBuffer (GL_FRONT); + + qglRasterPos2f (lastz[0]-9, lastz[1]-9); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 18,18, GL_COLOR); + + qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 100,100, GL_COLOR); + } + m_bDirty = true; + + // + // save off underneath where we are about to draw + // + VectorCopy (z.origin, lastz); + VectorCopy (g_pParentWnd->GetCamWnd()->Camera()->origin, lastcamera); + + qglReadBuffer (GL_FRONT); + qglDrawBuffer (GL_BACK); + + qglRasterPos2f (lastz[0]-9, lastz[1]-9); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 18,18, GL_COLOR); + + qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 100,100, GL_COLOR); + + // + // draw the new icons + // + qglDrawBuffer (GL_FRONT); + + qglShadeModel (GL_FLAT); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + qglColor3f(0, 0, 0); + + DrawCameraIcon (); + DrawZIcon (); + + qglDrawBuffer (GL_BACK); + qglFinish(); +} + +vec3_t& XYWnd::GetOrigin() +{ + return m_vOrigin; +} + +void XYWnd::SetOrigin(vec3_t org) +{ + m_vOrigin[0] = org[0]; + m_vOrigin[1] = org[1]; + m_vOrigin[2] = org[2]; +} + +void XYWnd::OnSize(int cx, int cy) +{ + m_nWidth = cx; + m_nHeight = cy; +} + +brush_t hold_brushes; + +void XYWnd::Clip() +{ + if (ClipMode()) + { + hold_brushes.next = &hold_brushes; + ProduceSplitLists(); + brush_t* pList; + if (g_PrefsDlg.m_bSwitchClip) + pList = (!g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits; + else + pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits; + + if (pList->next != pList) + { + Brush_CopyList(pList, &hold_brushes); + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + Select_Delete(); + Brush_CopyList(&hold_brushes, &selected_brushes); + if (RogueClipMode()) + RetainClipMode(false); + else + RetainClipMode(true); + Sys_UpdateWindows(W_ALL); + } + } + else if (PathMode()) + { + FinishSmartCreation(); + if (g_pPathFunc) + g_pPathFunc(true, g_nPathCount); + g_pPathFunc = NULL; + g_nPathCount = 0; + g_bPathMode = false; + } +} + +void XYWnd::SplitClip() +{ + ProduceSplitLists(); + if ((g_brFrontSplits.next != &g_brFrontSplits) && + (g_brBackSplits.next != &g_brBackSplits)) + { + Select_Delete(); + Brush_CopyList(&g_brFrontSplits, &selected_brushes); + Brush_CopyList(&g_brBackSplits, &selected_brushes); + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + if (RogueClipMode()) + RetainClipMode(false); + else + RetainClipMode(true); + } +} + +void XYWnd::FlipClip() +{ + g_bSwitch = !g_bSwitch; + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +// makes sure the selected brush or camera is in view +void XYWnd::PositionView() +{ + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + brush_t* b = selected_brushes.next; + if (b && b->next != b) + { + Select_GetMid (m_vOrigin); + } + else + { + m_vOrigin[nDim1] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim1]; + m_vOrigin[nDim2] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim2]; + } +} + +void XYWnd::VectorCopyXY(vec3_t in, vec3_t out) +{ + if (m_nViewType == XY) + { + out[0] = in[0]; + out[1] = in[1]; + } + else if (m_nViewType == XZ) + { + out[0] = in[0]; + out[2] = in[2]; + } + else + { + out[1] = in[1]; + out[2] = in[2]; + } +} + +void XYWnd::RetainClipMode(bool bMode) +{ + bool bSave = g_bRogueClipMode; + SetClipMode(bMode); + if (bMode == true) + g_bRogueClipMode = bSave; + else + g_bRogueClipMode = false; +} + +void XYWnd::SetClipMode(bool bMode) +{ + g_bClipMode = bMode; + g_bRogueClipMode = false; + if (bMode) + { + g_Clip1.Reset(); + g_Clip2.Reset(); + g_Clip3.Reset(); + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + + // ydnar: set clipper points based on first selected patch mesh + if( selected_brushes.next != &selected_brushes ) + { + bool found = false; + for( brush_t *pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) + { + if( pb->patchBrush ) + { + found = true; + VectorCopy( pb->pPatch->ctrl[ 0 ][ 0 ].xyz, g_Clip1.m_ptClip ); + VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ pb->pPatch->height - 1 ].xyz, g_Clip2.m_ptClip ); + VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ 0 ].xyz, g_Clip3.m_ptClip ); + g_Clip1.Set( true ); + g_Clip2.Set( true ); + g_Clip3.Set( true ); + break; + } + } + + if( found ) + { + // SetClipMode( true ); + Sys_UpdateWindows( XY | W_CAMERA_IFON ); + } + } + } + else + { + if (g_pMovingClip) + { + ReleaseCapture(); + g_pMovingClip = NULL; + } + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } +} + +bool XYWnd::ClipMode() +{ + return g_bClipMode; +} + +bool XYWnd::RogueClipMode() +{ + return g_bRogueClipMode; +} + +bool XYWnd::PathMode() +{ + return g_bPathMode; +} + +bool XYWnd::PointMode() +{ + return g_bPointMode; +} + +void XYWnd::SetPointMode(bool b) +{ + g_bPointMode = b; + if (!b) + g_nPointCount = 0; +} + +void XYWnd::SetViewType(int n) +{ + m_nViewType = n; + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + { + char* str = "YZ Side"; + if (m_nViewType == XY) + str = "XY Top"; + else if (m_nViewType == XZ) + str = "XZ Front"; + + if (m_pParent != NULL) + gtk_window_set_title (GTK_WINDOW (m_pParent), str); + } +} + +void XYWnd::Redraw(unsigned int nBits) +{ + m_nUpdateBits = nBits; + gtk_widget_queue_draw(m_pWidget); + m_nUpdateBits = W_XY; +} + +bool XYWnd::RotateMode() +{ + return g_bRotateMode; +} + +bool XYWnd::ScaleMode() +{ + return g_bScaleMode; +} + +bool XYWnd::SetRotateMode(bool bMode) +{ + if (bMode && selected_brushes.next != &selected_brushes) + { + g_bRotateMode = true; + Select_GetTrueMid(g_vRotateOrigin); + g_vRotation[0] = g_vRotation[1] = g_vRotation[2] = 0.0; + } + else + { + if (bMode) + Sys_Printf("Need a brush selected to turn on Mouse Rotation mode\n"); + g_bRotateMode = false; + } + RedrawWindow(); + return g_bRotateMode; +} + +void XYWnd::SetScaleMode(bool bMode) +{ + g_bScaleMode = bMode; + RedrawWindow(); +} + +rectangle_t rectangle_from_area_xy() +{ + XYWnd* xy = g_pParentWnd->ActiveXY(); + int nDim1 = (xy->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (xy->GetViewType() == XY) ? 1 : 2; + float origin_left = xy->GetOrigin()[nDim1] - (xy->Width() / 2) / xy->Scale(); + float origin_bottom = xy->GetOrigin()[nDim2] - (xy->Height() / 2) / xy->Scale(); + float left = MIN(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left; + float top = MAX(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom; + float right = MAX(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left; + float bottom = MIN(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom; + left *= xy->Scale(); + top *= xy->Scale(); + right *= xy->Scale(); + bottom *= xy->Scale(); + return rectangle_t(left, bottom, right - left, top - bottom); +} + +void update_xor_rectangle_xy(XORRectangle& xor_rectangle) +{ + rectangle_t rectangle; + if ((g_qeglobals.d_select_mode == sel_area)) + rectangle = rectangle_from_area_xy(); + xor_rectangle.set(rectangle); +} + +void XYWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy) +{ + // plugin entities + // TODO TTimo handle return code + DispatchOnMouseMove (nFlags, pointx, pointy); + + m_ptDownX = 0; + m_ptDownY = 0; + + if (g_PrefsDlg.m_bChaseMouse == TRUE && + (pointx < 0 || pointy < 0 || pointx > m_nWidth || pointy > m_nHeight) && + HasCapture ()) + { + float fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale; + //m_ptDrag = point; + m_ptDragAdjX = 0; + m_ptDragAdjY = 0; + + if (pointx < 0) + { + m_ptDragAdjX = (int)(-fAdjustment); + } + else if (pointx > m_nWidth) + { + m_ptDragAdjX = (int)(fAdjustment); + } + + if (pointy < 0) + { + m_ptDragAdjY = (int)(-fAdjustment); + } + else if (pointy > m_nHeight) + { + m_ptDragAdjY = (int)(fAdjustment); + } + + if (!HasTimer ()) + { + SetTimer (50); + m_ptDragX = pointx; + m_ptDragY = pointy; + m_ptDragTotalX = 0; + m_ptDragTotalY = 0; + } + return; + } + + if (HasTimer ()) + { + KillTimer (); + pressx -= m_ptDragTotalX; + pressy += m_ptDragTotalY; + } + + bool bCrossHair = false; + if (!m_bRButtonDown) + { + tdp[0] = tdp[1] = tdp[2] = 0.0; + SnapToPoint (pointx, m_nHeight - 1 - pointy , tdp); + + g_strStatus.Format("x:: %.1f y:: %.1f z:: %.1f", tdp[0], tdp[1], tdp[2]); + g_pParentWnd->SetStatusText(1, g_strStatus); + + // i need to generalize the point code.. having 3 flavors pretty much sucks.. + // once the new curve stuff looks like it is going to stick i will + // rationalize this down to a single interface.. + if (PointMode()) + { + if (g_pMovingPoint && HasCapture ()) + { + bCrossHair = true; + SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPoint->m_ptClip); + g_pMovingPoint->UpdatePointPtr(); + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } + else + { + g_pMovingPoint = NULL; + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + for (int n = 0; n < g_nPointCount; n++) + { + if ( fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingPoint = &g_PointPoints[n]; + } + } + } + } + else if (ClipMode()) + { + if (g_pMovingClip && HasCapture ()) + { + bCrossHair = true; + SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingClip->m_ptClip); + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } + else + { + g_pMovingClip = NULL; + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + if (g_Clip1.Set()) + { + if ( fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingClip = &g_Clip1; + } + } + if (g_Clip2.Set()) + { + if ( fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingClip = &g_Clip2; + } + } + if (g_Clip3.Set()) + { + if ( fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingClip = &g_Clip3; + } + } + } + if (bCrossHair == false) + XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); + } + else if (PathMode()) + { + if (g_pMovingPath && HasCapture ()) + { + bCrossHair = true; + SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPath->m_ptClip); + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } + else + { + g_pMovingPath = NULL; + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + for (int n = 0; n < g_nPathCount; n++) + { + if ( fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingPath = &g_PathPoints[n]; + } + } + } + } + else + { + XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); + } + } + else + { + XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); + } + + if ((nFlags & MK_RBUTTON) == 0) + { + if (bCrossHair && !g_bWaitCursor) + { + GdkCursor *cursor; + cursor = gdk_cursor_new (GDK_CROSSHAIR); + gdk_window_set_cursor (m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + } + else + { + gdk_window_set_cursor (m_pWidget->window, NULL); + } + } + + update_xor_rectangle_xy(m_XORRectangle); +} + +void XYWnd::OnMouseWheel(bool bUp) +{ + if (bUp) + g_pParentWnd->OnViewZoomin (); + else + g_pParentWnd->OnViewZoomout (); + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); +} + +void XYWnd::OnTimer () +{ + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + m_vOrigin[nDim1] += m_ptDragAdjX / m_fScale; + m_vOrigin[nDim2] -= m_ptDragAdjY / m_fScale; + Sys_UpdateWindows(W_XY | W_CAMERA); + m_ptDragX += m_ptDragAdjX; + m_ptDragY += m_ptDragAdjY; + m_ptDragTotalX += m_ptDragAdjX; + m_ptDragTotalY += m_ptDragAdjY; + XY_MouseMoved (m_ptDragX, m_nHeight - 1 - m_ptDragY , m_nScrollFlags); +} + +void XYWnd::OnLButtonDown(guint32 flags, int pointx, int pointy) +{ + g_pParentWnd->SetActiveXY(this); + UndoCopy(); + + // plugin entities + if (DispatchOnLButtonDown(flags, pointx, pointy)) + return; + + if (ClipMode() && !RogueClipMode()) + { + DropClipPoint(flags, pointx, pointy); + } + else if (PathMode()) + { + DropPathPoint(flags, pointx, pointy); + } + else OriginalButtonDown(flags, pointx, pointy); +} + +void XYWnd::OnMButtonDown(guint32 flags, int pointx, int pointy) +{ + OriginalButtonDown(flags, pointx, pointy); +} + +void XYWnd::OnRButtonDown(guint32 flags, int pointx, int pointy) +{ + g_pParentWnd->SetActiveXY(this); + m_ptDownX = pointx; + m_ptDownY = pointy; + m_bRButtonDown = true; + + if (g_PrefsDlg.m_nMouseButtons == 3) // 3 button mouse + { + if (flags & MK_CONTROL) + { + if (ClipMode()) // already there? + DropClipPoint(flags, pointx, pointy); + else + { + SetClipMode(true); + g_bRogueClipMode = true; + DropClipPoint(flags, pointx, pointy); + } + return; + } + } + OriginalButtonDown(flags, pointx, pointy); +} + +void XYWnd::OnLButtonUp(guint32 flags, int pointx, int pointy) +{ + // plugin entities + if (DispatchOnLButtonUp(flags, pointx, pointy)) + return; + + if (ClipMode()) + { + if (g_pMovingClip) + { + ReleaseCapture(); + g_pMovingClip = NULL; + } + } + OriginalButtonUp(flags, pointx, pointy); +} + +void XYWnd::OnMButtonUp(guint32 flags, int pointx, int pointy) +{ + OriginalButtonUp(flags, pointx, pointy); +} + +void XYWnd::OnRButtonUp(guint32 flags, int pointx, int pointy) +{ + m_bRButtonDown = false; + if ((pointx == m_ptDownX) && (pointy == m_ptDownY)) // mouse didn't move + { + bool bGo = true; + if (Sys_AltDown ()) + bGo = false; + if (flags & MK_CONTROL) + bGo = false; + if (flags & MK_SHIFT) + bGo = false; + if (bGo) + HandleDrop(); + } + OriginalButtonUp(flags, pointx, pointy); +} + +void XYWnd::XY_MouseDown (int x, int y, int buttons) +{ + vec3_t point; + vec3_t origin, dir, right, up; + + m_nButtonstate = buttons; + m_nPressx = x; + m_nPressy = y; + VectorCopy (vec3_origin, m_vPressdelta); + + VectorClear(point); + XY_ToPoint (x, y, point); + + VectorCopy (point, origin); + + VectorClear (dir); + if (m_nViewType == XY) // view facing dir = negative Z + { + origin[2] = g_MaxWorldCoord; + dir[2] = -1; + right[0] = 1 / m_fScale; + right[1] = 0; + right[2] = 0; + up[0] = 0; + up[1] = 1 / m_fScale; + up[2] = 0; + } + else if (m_nViewType == XZ) + { + origin[1] = g_MinWorldCoord; // view facing dir = positive Y + dir[1] = 1; + right[0] = 1 / m_fScale; + right[1] = 0; + right[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = 1 / m_fScale; + } + else // if (m_nViewType == YZ) // view facing dir = negative X + { + origin[0] = g_MaxWorldCoord; + dir[0] = -1; + right[0] = 0; + right[1] = 1 / m_fScale; + right[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = 1 / m_fScale; + } + + m_bPress_selection = (selected_brushes.next != &selected_brushes); + + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + // lbutton = manipulate selection + // shift-LBUTTON = select + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) + { + Patch_SetView( (m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ); + Drag_Begin (x, y, buttons, right, up, origin, dir); + return; + } + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + + // control mbutton = move camera + if (m_nButtonstate == (MK_CONTROL|nMouseButton) ) + { + VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + } + + // mbutton = angle camera + if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) || + (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON))) + { + VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point); + + int n1 = (m_nViewType == XY) ? 1 : 2; + int n2 = (m_nViewType == YZ) ? 1 : 0; + int nAngle = (m_nViewType == XY) ? YAW : PITCH; + if (point[n1] || point[n2]) + { + g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]); + Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY); + } + } + + // shift mbutton = move z checker + if (m_nButtonstate == (MK_SHIFT | nMouseButton)) + { + if (RotateMode() || g_bPatchBendMode) + { + SnapToPoint (x, y, point); + VectorCopyXY(point, g_vRotateOrigin); + if (g_bPatchBendMode) + { + VectorCopy(point, g_vBendOrigin); + } + Sys_UpdateWindows (W_XY); + return; + } + else + { + SnapToPoint (x, y, point); + if (m_nViewType == XY) + { + z.origin[0] = point[0]; + z.origin[1] = point[1]; + } + else if (m_nViewType == YZ) + { + z.origin[0] = point[1]; + z.origin[1] = point[2]; + } + else + { + z.origin[0] = point[0]; + z.origin[1] = point[2]; + } + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + } + + update_xor_rectangle_xy(m_XORRectangle); +} + +void XYWnd::XY_MouseUp(int x, int y, int buttons) +{ + Drag_MouseUp (buttons); + if (!m_bPress_selection) + Sys_UpdateWindows (W_ALL); + m_nButtonstate = 0; + + gdk_window_set_cursor (m_pWidget->window, NULL); + + update_xor_rectangle_xy(m_XORRectangle); +} + +qboolean XYWnd::DragDelta (int x, int y, vec3_t move) +{ + vec3_t xvec, yvec, delta; + int i; + + xvec[0] = 1 / m_fScale; + xvec[1] = xvec[2] = 0; + yvec[1] = 1 / m_fScale; + yvec[0] = yvec[2] = 0; + + for (i=0 ; i<3 ; i++) + { + delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy); + if (!g_PrefsDlg.m_bNoClamp) + { + delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } + } + VectorSubtract (delta, m_vPressdelta, move); + VectorCopy (delta, m_vPressdelta); + + if (move[0] || move[1] || move[2]) + return true; + return false; +} + +void XYWnd::HandleDrop() +{ + if (g_PrefsDlg.m_bRightClick == false) + return; + + if (m_mnuDrop == NULL) // first time, load it up + { + int nID = ID_ENTITY_START; + GtkWidget *menu, *menu_in_menu, *item, *submenu, *submenu_root; + + menu = m_mnuDrop = gtk_menu_new (); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select"); + create_menu_item_with_mnemonic (menu_in_menu, "Select Complete Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select Touching", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING); + create_menu_item_with_mnemonic (menu_in_menu, "Select Partial Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select Inside", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE); + menu_separator (menu); nID++; + // NOTE: temporary commented out until we put it back in for good (that is with actual features) + /* + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Group",); + create_menu_item_with_mnemonic (menu_in_menu, "Add to...", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_ADDTO); + create_menu_item_with_mnemonic (menu_in_menu, "Remove", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_REMOVE); + create_menu_item_with_mnemonic (menu_in_menu, "Name...", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NAME); + menu_separator (menu_in_menu); nID++; + create_menu_item_with_mnemonic (menu_in_menu, "New Group...", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NEWGROUP); + */ + create_menu_item_with_mnemonic (menu, "Ungroup Entity", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY); + + create_menu_item_with_mnemonic (menu, "Move into entity", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MERGE); + create_menu_item_with_mnemonic (menu, "Move into worldspawn", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SEPERATE); + + create_menu_item_with_mnemonic (menu, "Make Detail", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL); + create_menu_item_with_mnemonic (menu, "Make Structural", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL); + menu_separator (menu); nID++; + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Smart Entities"); + create_menu_item_with_mnemonic (menu_in_menu, "Smart__Train", + GTK_SIGNAL_FUNC (HandleCommand), nID++); + menu_separator (menu); nID++; + + submenu = NULL; + submenu_root = NULL; + eclass_t *e; + CString strActive; + CString strLast; + CString strName; + for (e=eclass ; e ; e=e->next) + { + strLast = strName; + strName = e->name; + int n_ = strName.Find("_"); + if (n_ > 0) + { + CString strLeft = strName.Left(n_); + CString strRight = strName.Right(strName.GetLength() - n_ - 1); + if (strLeft == strActive) // this is a child + { + assert (submenu); + item = gtk_menu_item_new_with_label (strName); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (nID++)); + gtk_widget_show (item); + CheckMenuSplitting(submenu); + gtk_menu_append (GTK_MENU (submenu), item); + } + else + { + if (submenu) + { + // this is submenu from previous main_item, hook it back + // we use submenu_root cause we may have been cascading submenu + item = gtk_menu_item_new_with_label (strActive); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root); + g_ptrMenus.Add(submenu_root); + submenu = NULL; + submenu_root = NULL; + } + strActive = strLeft; + + submenu = gtk_menu_new (); + submenu_root = submenu; + item = gtk_menu_item_new_with_label (strName); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (nID++)); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (submenu), item); + } + } + else + { + if (submenu) + { + // this is submenu from previous main_item, hook it back + // we use submenu_root cause we may have been cascading submenu + item = gtk_menu_item_new_with_label (strActive); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root); + g_ptrMenus.Add(submenu_root); + submenu = NULL; + submenu_root = NULL; + } + strActive = ""; + + item = gtk_menu_item_new_with_label (strName); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (nID++)); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + } + } + } + + gtk_menu_popup (GTK_MENU (m_mnuDrop), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +/* +============== +NewBrushDrag +============== +*/ +void XYWnd::NewBrushDrag (int x, int y) +{ + vec3_t mins, maxs, junk; + int i; + float temp; + brush_t *n; + + if (!DragDelta (x,y, junk)) + return; + + // delete the current selection + if (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + + SnapToPoint (m_nPressx, m_nPressy, mins); + + int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1; + + //++timo clean +// mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z / g_qeglobals.d_gridsize)); + mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_min[nDim]/g_qeglobals.d_gridsize)); + + SnapToPoint (x, y, maxs); +// maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z / g_qeglobals.d_gridsize)); + maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_max[nDim]/g_qeglobals.d_gridsize)); + if (maxs[nDim] <= mins[nDim]) + maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize; + + for (i=0 ; i<3 ; i++) + { + if (mins[i] == maxs[i]) + return; // don't create a degenerate brush + if (mins[i] > maxs[i]) + { + temp = mins[i]; + mins[i] = maxs[i]; + maxs[i] = temp; + } + } + + n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); + if (!n) + return; + + vec3_t vSize; + VectorSubtract(maxs, mins, vSize); + g_strStatus.Format("Size X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]); + g_pParentWnd->SetStatusText(2, g_strStatus); + + Brush_AddToList (n, &selected_brushes); + + Entity_LinkBrush (world_entity, n); + + Brush_Build( n ); + + // Sys_UpdateWindows (W_ALL); + Sys_UpdateWindows (W_XY| W_CAMERA); + +} + +/* +============== +XY_MouseMoved +============== +*/ +void XYWnd::XY_MouseMoved (int x, int y, int buttons) +{ + vec3_t point; + + if (!m_nButtonstate) + { + if (g_bCrossHairs) + { + Sys_UpdateWindows (W_XY | W_XY_OVERLAY); + } + return; + } + + // lbutton without selection = drag new brush + if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint && g_qeglobals.d_select_mode != sel_areatall) + { + NewBrushDrag (x, y); + return; + } + + // lbutton (possibly with control and or shift) + // with selection = drag selection + if (m_nButtonstate & MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + if(g_qeglobals.d_select_mode != sel_area) + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA_IFON | W_Z); + return; + } + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + // control mbutton = move camera + if (m_nButtonstate == (MK_CONTROL|nMouseButton) ) + { + SnapToPoint (x, y, point); + VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin); + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + return; + } + + // shift mbutton = move z checker + if (m_nButtonstate == (MK_SHIFT|nMouseButton) ) + { + if (RotateMode() || g_bPatchBendMode) + { + SnapToPoint (x, y, point); + VectorCopyXY(point, g_vRotateOrigin); + if (g_bPatchBendMode) + { + VectorCopy(point, g_vBendOrigin); + } + Sys_UpdateWindows (W_XY); + return; + } + else + { + SnapToPoint (x, y, point); + if (m_nViewType == XY) + { + z.origin[0] = point[0]; + z.origin[1] = point[1]; + } + else if (m_nViewType == YZ) + { + z.origin[0] = point[1]; + z.origin[1] = point[2]; + } + else + { + z.origin[0] = point[0]; + z.origin[1] = point[2]; + } + } + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + + // mbutton = angle camera + if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) || + (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON))) + { + SnapToPoint (x, y, point); + VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point); + + int n1 = (m_nViewType == XY) ? 1 : 2; + int n2 = (m_nViewType == YZ) ? 1 : 0; + int nAngle = (m_nViewType == XY) ? YAW : PITCH; + if (point[n1] || point[n2]) + { + g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]); + Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY); + } + return; + } + + // rbutton = drag xy origin + if (m_nButtonstate == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if (x != m_ptCursorX || y != m_ptCursorY) + { + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + m_vOrigin[nDim1] -= (x - m_ptCursorX) / m_fScale; + m_vOrigin[nDim2] += (y - m_ptCursorY) / m_fScale; + Sys_SetCursorPos (m_ptCursorX, m_ptCursorY); + + // create an empty cursor + if (!g_bWaitCursor) + { + GdkPixmap *pixmap; + GdkBitmap *mask; + char buffer [(32 * 32)/8]; + memset (buffer, 0, (32 * 32)/8); + GdkColor white = {0, 0xffff, 0xffff, 0xffff}; + GdkColor black = {0, 0x0000, 0x0000, 0x0000}; + pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); + gdk_window_set_cursor (m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + gdk_drawable_unref (pixmap); + gdk_drawable_unref (mask); + } + + Sys_UpdateWindows (W_XY | W_XY_OVERLAY); + } + return; + } + + // zoom in/out + if (m_nButtonstate == (MK_SHIFT | MK_RBUTTON)) + { + Sys_GetCursorPos (&x, &y); + if (y != m_ptCursorY) + { + if (abs (m_ptCursorY - y) > 10) + { + if (m_ptCursorY < y) + g_pParentWnd->OnViewZoomout (); + else + g_pParentWnd->OnViewZoomin (); + + Sys_SetCursorPos (m_ptCursorX, m_ptCursorY); + } + } + return; + } +} + +void XYWnd::OriginalButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + XY_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); + m_nScrollFlags = nFlags; +} + +void XYWnd::OriginalButtonUp(guint32 nFlags, int pointx, int pointy) +{ + XY_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); + ReleaseCapture (); +} + +void XYWnd::DropClipPoint(guint32 nFlags, int pointx, int pointy) +{ + if (g_pMovingClip) + { + SetCapture(); + SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingClip); + } + else + { + vec3_t* pPt = NULL; + if (g_Clip1.Set() == false) + { + pPt = g_Clip1; + g_Clip1.Set(true); + g_Clip1.m_ptScreenX = pointx; + g_Clip1.m_ptScreenY = pointy; + } + else + if (g_Clip2.Set() == false) + { + pPt = g_Clip2; + g_Clip2.Set(true); + g_Clip2.m_ptScreenX = pointx; + g_Clip2.m_ptScreenY = pointy; + } + else + if (g_Clip3.Set() == false) + { + pPt = g_Clip3; + g_Clip3.Set(true); + g_Clip3.m_ptScreenX = pointx; + g_Clip3.m_ptScreenY = pointy; + } + else + { + RetainClipMode(true); + pPt = g_Clip1; + g_Clip1.Set(true); + g_Clip1.m_ptScreenX = pointx; + g_Clip1.m_ptScreenY = pointy; + } + SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *pPt); + // third coordinates for clip point: use d_work_max + // Arnout: changed to use center of selection for clipping, saves level designers moving points all over the map + // g_pParentWnd->ActiveXY()->GetViewType() + // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; + int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 ); + //(*pPt)[nDim] = g_qeglobals.d_work_max[nDim]; + vec3_t mid; + Select_GetMid( mid ); + (*pPt)[nDim] = mid[nDim]; + } + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +void XYWnd::DropPathPoint(guint32 nFlags, int pointx, int pointy) +{ + if (g_pMovingPath) + { + SetCapture(); + SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingPath); + } + else + { + g_PathPoints[g_nPathCount].Set(true); + g_PathPoints[g_nPathCount].m_ptScreenX = pointx; + g_PathPoints[g_nPathCount].m_ptScreenY = pointy; + SnapToPoint(pointx, m_pWidget->allocation.height - 1 - pointy, g_PathPoints[g_nPathCount]); + // third coordinates for dropped point: use d_work_max + // g_pParentWnd->ActiveXY()->GetViewType() + // cf VIEWTYPE definition: enum VIEWTYPE {YZ, XZ, XY}; + int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 ); + g_PathPoints[g_nPathCount].m_ptClip[nDim] = g_qeglobals.d_work_max[nDim]; + + g_nPathCount++; + if (g_nPathCount == g_nPathLimit) + { + if (g_pPathFunc) + g_pPathFunc(true, g_nPathCount); + g_nPathCount = 0; + g_bPathMode = false; + g_pPathFunc = NULL; + } + } + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +// FIXME: AddPointPoint() redundant function never called +#if 0 +void XYWnd::AddPointPoint(guint32 nFlags, vec3_t* pVec) +{ + g_PointPoints[g_nPointCount].Set(true); + //g_PointPoints[g_nPointCount].m_ptScreen = point; + _VectorCopy(*pVec, g_PointPoints[g_nPointCount]); + g_PointPoints[g_nPointCount].SetPointPtr(pVec); + g_nPointCount++; + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +// FIXME: ProduceSplits() redundant function never called +void XYWnd::ProduceSplits(brush_t** pFront, brush_t** pBack) +{ + *pFront = NULL; + *pBack = NULL; + if (ClipMode()) + { + if (g_Clip1.Set() && g_Clip2.Set()) + { + face_t face; + VectorCopy(g_Clip1.m_ptClip,face.planepts[0]); + VectorCopy(g_Clip2.m_ptClip,face.planepts[1]); + VectorCopy(g_Clip3.m_ptClip,face.planepts[2]); + if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes)) + { + if (g_Clip3.Set() == false) + { + if (m_nViewType == XY) + { + face.planepts[0][2] = selected_brushes.next->mins[2]; + face.planepts[1][2] = selected_brushes.next->mins[2]; + face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]); + face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]); + face.planepts[2][2] = selected_brushes.next->maxs[2]; + } + else if (m_nViewType == YZ) + { + face.planepts[0][0] = selected_brushes.next->mins[0]; + face.planepts[1][0] = selected_brushes.next->mins[0]; + face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]); + face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]); + face.planepts[2][0] = selected_brushes.next->maxs[0]; + } + else + { + face.planepts[0][1] = selected_brushes.next->mins[1]; + face.planepts[1][1] = selected_brushes.next->mins[1]; + face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]); + face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]); + face.planepts[2][1] = selected_brushes.next->maxs[1]; + } + } + + Brush_SplitBrushByFace (selected_brushes.next, &face, pFront, pBack); + } + + } + } +} +#endif + +void XYWnd::PlanePointsFromClipPoints(vec3_t planepts[3], brush_t *pBrush) +{ + VectorCopy(g_Clip1.m_ptClip,planepts[0]); + VectorCopy(g_Clip2.m_ptClip,planepts[1]); + VectorCopy(g_Clip3.m_ptClip,planepts[2]); + if (g_Clip3.Set() == false) + { + int n = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 2 : (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 0 : 1; + int x = (n == 0) ? 1 : 0; + int y = (n == 2) ? 1 : 2; + + if (n == 1) // on viewtype XZ, flip clip points + { + planepts[0][n] = pBrush->maxs[n]; + planepts[1][n] = pBrush->maxs[n]; + planepts[2][x] = g_Clip1.m_ptClip[x]; + planepts[2][y] = g_Clip1.m_ptClip[y]; + planepts[2][n] = pBrush->mins[n]; + } + else + { + planepts[0][n] = pBrush->mins[n]; + planepts[1][n] = pBrush->mins[n]; + planepts[2][x] = g_Clip1.m_ptClip[x]; + planepts[2][y] = g_Clip1.m_ptClip[y]; + planepts[2][n] = pBrush->maxs[n]; + } + } +} + +void XYWnd::ProduceSplitLists() +{ + bool bCaulk = false; + int nFlags; + + if (AnyPatchesSelected()) + { + Sys_Printf("Deselecting patches for clip operation.\n"); + brush_t *next; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = next) + { + next = pb->next; + if (pb->patchBrush) + { + Brush_RemoveFromList (pb); + Brush_AddToList (pb, &active_brushes); + UpdatePatchInspector(); + } + } + // ydnar: update the window if any patches are selected + Sys_UpdateWindows( XY | W_CAMERA_IFON ); + } + + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + if (ClipMode() && (g_Clip1.Set() && g_Clip2.Set())) + { + brush_t* pBrush; + for (pBrush = selected_brushes.next ; pBrush != NULL && pBrush != &selected_brushes ; pBrush=pBrush->next) + { + brush_t* pFront = NULL; + brush_t* pBack = NULL; + + face_t face; + memset(&face,0,sizeof(face_t)); + PlanePointsFromClipPoints(face.planepts, pBrush); + + // decide wether caulking should be applied on the splits + // FIXME: hack + // this should take the first brush face, check shader for NODRAW, if it isn't nodraw then find the appropriate + // common/ shader to use, out of solid+nodraw, nonsolid+nodraw, water+nodraw, lava+nodraw, nonsolid+nodraw+trans, water+nodraw+trans, lava+nodraw+trans.. and fog.. etc + // or if none of those apply (unlikely), construct a new shader (shadername_nodraw) based on the shader of the first face, but with surfaceparm nodraw + if (g_PrefsDlg.m_bClipCaulk) + { + nFlags = pBrush->brush_faces->pShader->getFlags(); + if ((nFlags & QER_NODRAW) || (nFlags & QER_NONSOLID) || (nFlags & QER_WATER) || (nFlags & QER_LAVA) || (nFlags & QER_FOG)) // first face shader is anything other than solid AND opaque like caulk + bCaulk = false; // use first face's shader for the splitting face + else + bCaulk = true; // use caulk + } + + Brush_SplitBrushByFace (pBrush, &face, &pFront, &pBack, bCaulk); + if (pBack) + Brush_AddToList(pBack, &g_brBackSplits); + if (pFront) + Brush_AddToList(pFront, &g_brFrontSplits); + + } + } +} + +void XYWnd::XY_Init() +{ + m_vOrigin[0] = 0; + m_vOrigin[1] = 20; + m_vOrigin[2] = 46; + m_fScale = 1; +} + +void XYWnd::SnapToPoint (int x, int y, vec3_t point) +{ + if (g_PrefsDlg.m_bNoClamp) + { + XY_ToPoint(x, y, point); + } + else + { + XY_ToGridPoint(x, y, point); + } +} + +// TTimo: watch it, this doesn't init one of the 3 coords +void XYWnd::XY_ToPoint (int x, int y, vec3_t point) +{ + float fx = x; + float fy = y; + float fw = m_nWidth; + float fh = m_nHeight; + if (m_nViewType == XY) + { + point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; + point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale; + } + else if (m_nViewType == YZ) + { + point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale; + point[2] = m_vOrigin[2] + (fy - fh / 2 ) / m_fScale; + } + else + { + point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; + point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale; + } +} + +void XYWnd::XY_ToGridPoint (int x, int y, vec3_t point) +{ + if (m_nViewType == XY) + { + point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; + point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale; + point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } + else if (m_nViewType == YZ) + { + point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale; + point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale; + point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } + else + { + point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; + point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale; + point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } +} + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + +/* +============== +XY_DrawGrid +============== +*/ +void XYWnd::XY_DrawGrid() +{ + float x, y, xb, xe, yb, ye; + float w, h; + char text[32]; + int step, stepx, stepy, colour; + step = stepx = stepy = MAX (64, (int)g_qeglobals.d_gridsize); + + /* + int stepSize = (int)(8 / m_fScale); + if (stepSize > step) + { + int i; + for (i = 1; i < stepSize; i <<= 1) + ; + step = i; + } + */ + + //Sys_Printf("scale: %f\n", m_fScale); + //Sys_Printf("step before: %i\n", step); + //Sys_Printf("scaled step: %f\n", step * m_fScale); + while ((step * m_fScale) < 4.0f) // make sure major grid spacing is at least 4 pixels on the screen + step *= 8; + //Sys_Printf("step after: %i\n", step); + while ((stepx * m_fScale) < 32.0f) // text step x must be at least 32 + stepx *= 2; + while ((stepy * m_fScale) < 32.0f) // text step y must be at least 32 + stepy *= 2; + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + + w = (m_nWidth / 2 / m_fScale); + h = (m_nHeight / 2 / m_fScale); + + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + + xb = m_vOrigin[nDim1] - w; + if (xb < region_mins[nDim1]) + xb = region_mins[nDim1]; + xb = step * floor (xb/step); + + xe = m_vOrigin[nDim1] + w; + if (xe > region_maxs[nDim1]) + xe = region_maxs[nDim1]; + xe = step * ceil (xe/step); + + yb = m_vOrigin[nDim2] - h; + if (yb < region_mins[nDim2]) + yb = region_mins[nDim2]; + yb = step * floor (yb/step); + + ye = m_vOrigin[nDim2] + h; + if (ye > region_maxs[nDim2]) + ye = region_maxs[nDim2]; + ye = step * ceil (ye/step); + +#define COLORS_DIFFER(a,b) \ + (g_qeglobals.d_savedinfo.colors[a][0] != g_qeglobals.d_savedinfo.colors[b][0] || \ + g_qeglobals.d_savedinfo.colors[a][1] != g_qeglobals.d_savedinfo.colors[b][1] || \ + g_qeglobals.d_savedinfo.colors[a][2] != g_qeglobals.d_savedinfo.colors[b][2]) + + // djbob + // draw minor blocks + if (m_fScale > .1 && g_qeglobals.d_showgrid && g_qeglobals.d_gridsize * m_fScale >= 4) + { + if (g_qeglobals.d_gridsize < 1) + colour = COLOR_GRIDMINOR_ALT; + else + colour = COLOR_GRIDMINOR; + + if (COLORS_DIFFER(colour, COLOR_GRIDBACK)) + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[colour]); + + qglBegin (GL_LINES); + for (x=xb ; x 65536 || g_qeglobals.blockSize < 1024) + // don't use custom blocksize if it is less than the default, or greater than the maximum world coordinate + g_qeglobals.blockSize = 1024; + + float x, y, xb, xe, yb, ye; + float w, h; + char text[32]; + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + + w = (m_nWidth / 2 / m_fScale); + h = (m_nHeight / 2 / m_fScale); + + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + + xb = m_vOrigin[nDim1] - w; + if (xb < region_mins[nDim1]) + xb = region_mins[nDim1]; + xb = g_qeglobals.blockSize * floor (xb/g_qeglobals.blockSize); + + xe = m_vOrigin[nDim1] + w; + if (xe > region_maxs[nDim1]) + xe = region_maxs[nDim1]; + xe = g_qeglobals.blockSize * ceil (xe/g_qeglobals.blockSize); + + yb = m_vOrigin[nDim2] - h; + if (yb < region_mins[nDim2]) + yb = region_mins[nDim2]; + yb = g_qeglobals.blockSize * floor (yb/g_qeglobals.blockSize); + + ye = m_vOrigin[nDim2] + h; + if (ye > region_maxs[nDim2]) + ye = region_maxs[nDim2]; + ye = g_qeglobals.blockSize * ceil (ye/g_qeglobals.blockSize); + + // draw major blocks + + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK]); + qglLineWidth (2); + + qglBegin (GL_LINES); + + for (x=xb ; x<=xe ; x+=g_qeglobals.blockSize) + { + qglVertex2f (x, yb); + qglVertex2f (x, ye); + } + + if (m_nViewType == XY) + { + for (y=yb ; y<=ye ; y+=g_qeglobals.blockSize) + { + qglVertex2f (xb, y); + qglVertex2f (xe, y); + } + } + + qglEnd (); + qglLineWidth (1); + + // draw coordinate text if needed + + if (m_nViewType == XY && m_fScale > .1) + { + for (x=xb ; xGetCamWnd()->Camera()->origin[0]; + y = g_pParentWnd->GetCamWnd()->Camera()->origin[1]; + a = g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]/180*Q_PI; + } + else if (m_nViewType == YZ) + { + x = g_pParentWnd->GetCamWnd()->Camera()->origin[1]; + y = g_pParentWnd->GetCamWnd()->Camera()->origin[2]; + a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI; + } + else + { + x = g_pParentWnd->GetCamWnd()->Camera()->origin[0]; + y = g_pParentWnd->GetCamWnd()->Camera()->origin[2]; + a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI; + } + + qglColor3f (0.0, 0.0, 1.0); + qglBegin(GL_LINE_STRIP); + qglVertex3f (x-box,y,0); + qglVertex3f (x,y+(box/2),0); + qglVertex3f (x+box,y,0); + qglVertex3f (x,y-(box/2),0); + qglVertex3f (x-box,y,0); + qglVertex3f (x+box,y,0); + qglEnd (); + + qglBegin(GL_LINE_STRIP); + qglVertex3f (x+fov*cos(a+Q_PI/4), y+fov*sin(a+Q_PI/4), 0); + qglVertex3f (x, y, 0); + qglVertex3f (x+fov*cos(a-Q_PI/4), y+fov*sin(a-Q_PI/4), 0); + qglEnd (); + +} + +void XYWnd::DrawZIcon (void) +{ + if (m_nViewType == XY) + { + float x = z.origin[0]; + float y = z.origin[1]; + float zdim = 8 / m_fScale; + qglEnable (GL_BLEND); + qglDisable (GL_TEXTURE_2D); + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + qglDisable (GL_CULL_FACE); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglColor4f (0.0, 0.0, 1.0, 0.25); + qglBegin(GL_QUADS); + qglVertex3f (x-zdim,y-zdim,0); + qglVertex3f (x+zdim,y-zdim,0); + qglVertex3f (x+zdim,y+zdim,0); + qglVertex3f (x-zdim,y+zdim,0); + qglEnd (); + qglDisable (GL_BLEND); + + qglColor4f (0.0, 0.0, 1.0, 1); + + qglBegin(GL_LINE_LOOP); + qglVertex3f (x-zdim,y-zdim,0); + qglVertex3f (x+zdim,y-zdim,0); + qglVertex3f (x+zdim,y+zdim,0); + qglVertex3f (x-zdim,y+zdim,0); + qglEnd (); + + qglBegin(GL_LINE_STRIP); + qglVertex3f (x-(zdim/2),y+(zdim/2),0); + qglVertex3f (x+(zdim/2),y+(zdim/2),0); + qglVertex3f (x-(zdim/2),y-(zdim/2),0); + qglVertex3f (x+(zdim/2),y-(zdim/2),0); + qglEnd (); + } +} + +// can be greatly simplified but per usual i am in a hurry +// which is not an excuse, just a fact +void XYWnd::PaintSizeInfo(int nDim1, int nDim2, vec3_t vMinBounds, vec3_t vMaxBounds) +{ + const char* g_pDimStrings[] = {"x:%.f", "y:%.f", "z:%.f"}; + const char* g_pOrgStrings[] = {"(x:%.f y:%.f)", "(x:%.f z:%.f)", "(y:%.f z:%.f)"}; + + CString g_strDim; + + vec3_t vSize; + VectorSubtract(vMaxBounds, vMinBounds, vSize); + + qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65, + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65, + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65); + + if (m_nViewType == XY) + { + qglBegin (GL_LINES); + + qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f); + qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + + qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + + qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f); + qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f); + + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f); + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f); + + qglEnd(); + + qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale, 0.0f); + g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f); + g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f); + g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + } + else if (m_nViewType == XZ) + { + qglBegin (GL_LINES); + + qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(vMinBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); + qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); + + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMinBounds[nDim2]); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2]); + + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2]); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2]); + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMaxBounds[nDim2]); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2]); + + qglEnd(); + + qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0 / m_fScale); + g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMaxBounds[nDim1] + 16.0 / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2])); + g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale); + g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + } + else + { + qglBegin (GL_LINES); + + qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + + + qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2]); + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]); + + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]); + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]); + + qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2]); + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]); + + qglEnd(); + + qglRasterPos3f (0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale); + g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (0, vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2])); + g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale); + g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + } +} + +/* +============== +XY_Draw +============== +*/ +#define ALT_POINT_SIZE 4 +// Alternative to GL_POINTS (for; vertex handles, patch handles, clip points, path points) +void DrawAlternatePoint(vec3_t v, float scale) +{ + if(scale == 0) + { + scale = g_pParentWnd->GetXYWnd()->Scale(); + //scale = g_qeglobals.d_xyOld.scale; + } + + // ugly gl_line cross + qglVertex3f ( v[0]+(ALT_POINT_SIZE/scale), v[1], v[2] ); + qglVertex3f ( v[0]-(ALT_POINT_SIZE/scale), v[1], v[2] ); + qglVertex3f ( v[0], v[1]+(ALT_POINT_SIZE/scale), v[2] ); + qglVertex3f ( v[0], v[1]-(ALT_POINT_SIZE/scale), v[2] ); + qglVertex3f ( v[0], v[1], v[2]+(ALT_POINT_SIZE/scale) ); + qglVertex3f ( v[0], v[1], v[2]-(ALT_POINT_SIZE/scale) ); +} + + +long g_lCount = 0; +long g_lTotal = 0; +extern void DrawBrushEntityName (brush_t *b); + +//#define DBG_SCENEDUMP + +void XYWnd::XY_Draw() +{ +#ifdef DBG_SCENEDUMP + static time_t s_start = 0; // we use that to dump the selected stuff every 2 seconds + time_t now; + time (&now); + bool bDump; + + if ((now - s_start) > 3) + { + bDump = true; + s_start = now; + Sys_FPrintf(SYS_WRN, "Starting scene dump\n"); + } + else bDump = false; +#endif + + brush_t *brush; + float w, h; + entity_t *e; + double start, end; + double start2, end2; + vec3_t mins, maxs; + int drawn, culled; + int i; + + if (!active_brushes.next) + return; // not valid yet + + Patch_LODMatchAll(); // spog + + if (m_bTiming) + start = Sys_DoubleTime(); + // + // clear + // + m_bDirty = false; + + qglViewport(0, 0, m_nWidth, m_nHeight); + qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],0); + + qglClear(GL_COLOR_BUFFER_BIT); + + // + // set up viewpoint + // + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + w = m_nWidth / 2 / m_fScale; + h = m_nHeight / 2/ m_fScale; + + // fix GL_INVALID_VALUE error on first time the window is updated (win32) + if (w == 0) + w = 1; + + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + mins[0] = m_vOrigin[nDim1] - w; + maxs[0] = m_vOrigin[nDim1] + w; + mins[1] = m_vOrigin[nDim2] - h; + maxs[1] = m_vOrigin[nDim2] + h; + + qglOrtho (mins[0], maxs[0], mins[1], maxs[1], g_MinWorldCoord, g_MaxWorldCoord); + + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + + // + // now draw the grid + // + XY_DrawGrid (); + + // + // draw block grid + // + if ( g_qeglobals.show_blocks) + XY_DrawBlockGrid (); + + if (m_nViewType != XY) + { + qglPushMatrix(); + if (m_nViewType == YZ) + qglRotatef (-90, 0, 1, 0); // put Z going up + qglRotatef (-90, 1, 0, 0); // put Z going up + } + + // + // draw stuff + // + qglShadeModel (GL_FLAT); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + qglDisable(GL_CULL_FACE); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglColor3f(0, 0, 0); + qglEnableClientState(GL_VERTEX_ARRAY); + + // Fishman - Add antialiazed points and lines support. 09/15/00 + if (g_PrefsDlg.m_bAntialiasedPointsAndLines) + { + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglEnable(GL_POINT_SMOOTH); + qglEnable(GL_LINE_SMOOTH); + } + + drawn = culled = 0; + + e = world_entity; + + if (m_bTiming) + start2 = Sys_DoubleTime(); + + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if (brush->bFiltered) + continue; + + if (brush->mins[nDim1] > maxs[0] || + brush->mins[nDim2] > maxs[1] || + brush->maxs[nDim1] < mins[0] || + brush->maxs[nDim2] < mins[1]) + { + culled++; + continue; // off screen + } + + drawn++; + + if (brush->owner != e && brush->owner) + { + qglColor3fv(brush->owner->eclass->color); + } + else + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]); + } + +#ifdef DBG_SCENEDUMP + if (bDump) + { + Sys_FPrintf(SYS_WRN, "Active brush: %p ", brush); + Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name); + } +#endif + + Brush_DrawXY(brush, m_nViewType); + } + + if (m_bTiming) + end2 = Sys_DoubleTime(); + + DrawPathLines (); + + // + // draw pointfile + // + //++timo why is the display list broken? + if ( g_qeglobals.d_pointfile_display_list) + Pointfile_Draw(); + + // + // now draw selected brushes + // + + if (RotateMode()) + qglColor3f(0.8f, 0.1f, 0.9f); + else + if (ScaleMode()) + qglColor3f(0.1f, 0.8f, 0.1f); + else + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); + + + if (g_PrefsDlg.m_bNoStipple == FALSE) + { + qglEnable (GL_LINE_STIPPLE); + qglLineStipple (3, 0xaaaa); + } + qglLineWidth (2); + + vec3_t vMinBounds; + vec3_t vMaxBounds; + vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = g_MaxWorldCoord; + vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = g_MinWorldCoord; + + int nSaveDrawn = drawn; + bool bFixedSize = false; + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + // spog - added culling of selected brushes in XY window + if (brush->mins[nDim1] > maxs[0] || + brush->mins[nDim2] > maxs[1] || + brush->maxs[nDim1] < mins[0] || + brush->maxs[nDim2] < mins[1]) + { + culled++; + continue; // off screen + } + drawn++; +#ifdef DBG_SCENEDUMP + if (bDump) + { + Sys_FPrintf(SYS_WRN, "Selected brush: %p ", brush); + Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name); + } +#endif + Brush_DrawXY(brush, m_nViewType); + + if (!bFixedSize) + { + if (brush->owner->eclass->fixedsize) + bFixedSize = true; + if (g_PrefsDlg.m_bSizePaint) + { + for (i = 0; i < 3; i ++) + { + if (brush->mins[i] < vMinBounds[i]) + vMinBounds[i] = brush->mins[i]; + if (brush->maxs[i] > vMaxBounds[i]) + vMaxBounds[i] = brush->maxs[i]; + } + } + } + } + + if (g_PrefsDlg.m_bNoStipple == FALSE) + { + qglDisable (GL_LINE_STIPPLE); + } + qglLineWidth (1); + + if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint) + PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds); + + // edge / vertex flags + if (g_qeglobals.d_select_mode == sel_vertex) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + // brush verts + qglPointSize (4); + qglColor3f (0,1,0); + qglBegin (GL_POINTS); + for (i=0 ; iCurrentStyle() == MainFrame::eSplit) + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME]); + else + qglColor3fv( g_qeglobals.d_savedinfo.AxisColors[m_nViewType]); + qglBegin (GL_LINE_LOOP); + qglVertex2i (0, 0); + qglVertex2i (m_nWidth-1, 0); + qglVertex2i (m_nWidth-1, m_nHeight-1); + qglVertex2i (0, m_nHeight-1); + qglEnd (); + + qglMatrixMode (GL_PROJECTION); + qglPopMatrix (); + qglMatrixMode (GL_MODELVIEW); + qglPopMatrix (); + } + } + + qglFinish(); + + if (m_bTiming) + { + end = Sys_DoubleTime (); + i = (int)(1000*(end-start)); + int i3 = (int)(1000*(end2-start2)); + g_lCount++; + g_lTotal += i; + int i2 = g_lTotal / g_lCount; + Sys_Printf ("xy: %i ab: %i avg: %i\n", i, i3, i2); + } + + // Fishman - Add antialiazed points and lines support. 09/03/00 + if (g_PrefsDlg.m_bAntialiasedPointsAndLines) + { + qglDisable(GL_POINT_SMOOTH); + qglDisable(GL_LINE_SMOOTH); + qglDisable(GL_BLEND); + } +} + +void XYWnd::Copy() +{ +} + +void XYWnd::Undo() +{ +} + +void XYWnd::UndoClear() +{ +} + +void XYWnd::UndoCopy() +{ +} + +bool XYWnd::UndoAvailable() +{ + return (g_brUndo.next != &g_brUndo); +} + +void XYWnd::Paste() +{ +} + +// should be static as should be the rotate scale stuff +bool XYWnd::AreaSelectOK() +{ + return RotateMode() ? false : ScaleMode() ? false : true; +} + +void XYWnd::OnCreate () +{ + if (!MakeCurrent ()) + Error ("glXMakeCurrent failed"); + + qglPolygonStipple ((unsigned char *)s_stipple); + qglLineStipple (3, 0xaaaa); +} + +void XYWnd::OnExpose () +{ + bool bPaint = true; + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: glXMakeCurrent failed.. Error:%i\n",qglGetError()); + Sys_Printf("Please restart Radiant if the Map view is not working\n"); + bPaint = false; + } + if (bPaint) + { + QE_CheckOpenGLForErrors(); + XY_Draw (); + QE_CheckOpenGLForErrors(); + + if (m_nViewType != XY) + { + qglPushMatrix(); + if (m_nViewType == YZ) + qglRotatef (-90, 0, 1, 0); // put Z going up + qglRotatef (-90, 1, 0, 0); // put Z going up + } + + if (g_bCrossHairs) + { + qglColor4f(0.2f, 0.9f, 0.2f, 0.8f); + qglBegin (GL_LINES); + if (m_nViewType == XY) + { + qglVertex2f(2*g_MinWorldCoord, tdp[1]); + qglVertex2f(2*g_MaxWorldCoord, tdp[1]); + qglVertex2f(tdp[0], 2*g_MinWorldCoord); + qglVertex2f(tdp[0], 2*g_MaxWorldCoord); + } + else if (m_nViewType == YZ) + { + qglVertex3f(tdp[0], 2*g_MinWorldCoord, tdp[2]); + qglVertex3f(tdp[0], 2*g_MaxWorldCoord, tdp[2]); + qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord); + qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord); + } + else + { + qglVertex3f (2*g_MinWorldCoord, tdp[1], tdp[2]); + qglVertex3f (2*g_MaxWorldCoord, tdp[1], tdp[2]); + qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord); + qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord); + } + qglEnd(); + } + + if (ClipMode()) + { + // Draw clip points + if (g_Clip1.Set()) + g_Clip1.Draw(m_fScale, 1); // qglVertex3fv (g_Clip1); + if (g_Clip2.Set()) + g_Clip2.Draw(m_fScale, 2); // qglVertex3fv (g_Clip2); + if (g_Clip3.Set()) + g_Clip3.Draw(m_fScale, 3); // qglVertex3fv (g_Clip3); + if (g_Clip1.Set() && g_Clip2.Set()) + { + ProduceSplitLists(); + brush_t* pBrush; + brush_t* pList = (g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits; + for (pBrush = pList->next ; pBrush != NULL && pBrush != pList ; pBrush=pBrush->next) + { + qglColor3f (1,1,0); + face_t *face; + int order; + for (face = pBrush->brush_faces,order = 0 ; face ; face=face->next, order++) + { + winding_t* w = face->face_winding; + if (!w) + continue; + // draw the polygon + qglBegin(GL_LINE_LOOP); + for (int i=0 ; inumpoints ; i++) + qglVertex3fv(w->points[i]); + qglEnd(); + } + } + } + } + + if (PathMode()) + { + int n; + for (n = 0; n < g_nPathCount; n++) + g_PathPoints[n].Draw(m_fScale, n+1); // qglVertex3fv(g_PathPoints[n]); + } + if (m_nViewType != XY) + qglPopMatrix(); + + m_XORRectangle.set(rectangle_t()); + SwapBuffers (); + } +} + +void XYWnd::KillPathMode() +{ + g_bSmartGo = false; + g_bPathMode = false; + if (g_pPathFunc) + g_pPathFunc(false, g_nPathCount); + g_nPathCount = 0; + g_pPathFunc = NULL; + Sys_UpdateWindows(W_ALL); +} + +// gets called for drop down menu messages +// TIP: it's not always about EntityCreate +void XYWnd::OnEntityCreate (const char* item) +{ + Undo_Start("create entity"); + Undo_AddBrushList(&selected_brushes); + + if (m_mnuDrop != NULL) + { + CString strItem; + strItem = item; + + if (strItem.CompareNoCase("Add to...") == 0) + { + //++timo TODO: fill the menu with current groups? + // this one is for adding to existing groups only + Sys_Printf("TODO: Add to... in XYWnd::OnEntityCreate\n"); + } + else if (strItem.CompareNoCase("Remove") == 0) + { + // remove selected brushes from their current group + brush_t *b; + for( b = selected_brushes.next; b != &selected_brushes; b = b->next ) + { + + } + } + + //++timo FIXME: remove when all hooks are in + if (strItem.CompareNoCase("Add to...") == 0 + || strItem.CompareNoCase("Remove") == 0 + || strItem.CompareNoCase("Name...") == 0 + || strItem.CompareNoCase("New group...") == 0) + { + Sys_Printf("TODO: hook drop down group menu\n"); + return; + } + + if (strItem.Find("Smart_") >= 0) + { + CreateSmartEntity(this, m_ptDownX, m_ptDownY, strItem); + } + else + { + CreateRightClickEntity(this, m_ptDownX, m_ptDownY, (char*)strItem.GetBuffer()); + } + + Sys_UpdateWindows(W_ALL); + //OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2)); + } + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +/* Drawing clip points */ +void ClipPoint::Draw(float fScale, int num) +{ + CString strLabel; + strLabel.Format("%d", num); + Draw(fScale, strLabel.GetBuffer()); +} + +#define ALT_POINT_VERTS 6 + +void ClipPoint::Draw(float fScale, const char *label) +{ + // draw point + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglPointSize (4); + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]); + qglBegin (GL_POINTS); + qglVertex3fv (m_ptClip); + qglEnd(); + qglPointSize (1); + } + else + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]); + qglLineWidth(2.0); + qglBegin (GL_LINES); + DrawAlternatePoint(m_ptClip, fScale); + qglEnd(); + qglLineWidth(1.0); + } + + // draw label + qglRasterPos3f (m_ptClip[0]+2, m_ptClip[1]+2, m_ptClip[2]+2); + qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label); +} + diff --git a/radiant/xywindow.h b/radiant/xywindow.h new file mode 100644 index 00000000..a81acadd --- /dev/null +++ b/radiant/xywindow.h @@ -0,0 +1,194 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _XYWINDOW_H_ +#define _XYWINDOW_H_ + +#include "qe3.h" +#include "camwindow.h" +#include "glwindow.h" + +const int SCALE_X = 0x01; +const int SCALE_Y = 0x02; +const int SCALE_Z = 0x04; + +typedef void (PFNPathCallback)(bool, int); +// as i didn't really encapsulate anything this +// should really be a struct.. +class ClipPoint +{ +public: + ClipPoint(){ Reset(); }; + void Reset(){ m_ptClip[0] = m_ptClip[1] = m_ptClip[2] = 0.0; m_bSet = false; m_pVec3 = NULL;}; + bool Set(){ return m_bSet; }; + void Set(bool b) { m_bSet = b; }; + void UpdatePointPtr() { if (m_pVec3) VectorCopy(m_ptClip, *m_pVec3); }; + void SetPointPtr(vec3_t* p) { m_pVec3 = p; }; + vec3_t m_ptClip; // the 3d point + vec3_t* m_pVec3; // optional ptr for 3rd party updates + int m_ptScreenX, m_ptScreenY; // the onscreen xy point (for mousability) + bool m_bSet; + operator vec3_t&() {return m_ptClip;}; + operator vec3_t*() {return &m_ptClip;}; + + /*! Draw clip/path point with rasterized number label */ + void Draw(float fScale, int num); + /*! Draw clip/path point with rasterized string label */ + void Draw(float fScale, const char *label); +}; + +class XYWnd : public GLWindow +{ +public: + XYWnd(); + virtual ~XYWnd() { } + +public: + bool AreaSelectOK(); + vec3_t& RotateOrigin(); + vec3_t& Rotation(); + void UndoClear(); + bool UndoAvailable(); + void KillPathMode(); + void Undo(); + void UndoCopy(); + void Copy(); + void Paste(); + void Redraw(unsigned int nBits); + void VectorCopyXY(vec3_t in, vec3_t out); + void PositionView(); + void FlipClip(); + void SplitClip(); + void Clip(); + vec3_t& GetOrigin(); + void SetOrigin(vec3_t org); // PGM + void XY_Init(); + void XY_Overlay(); + void XY_Draw(); + void DrawZIcon(); + void DrawRotateIcon(); + void DrawCameraIcon(); + void XY_DrawBlockGrid(); + void XY_DrawGrid(); + void XY_MouseMoved (int x, int y, int buttons); +// TTimo: FIXME: was experimental stuff to track possible endless loop issues +// void XY_MouseMovedRec (int x, int y, int buttons); + void NewBrushDrag (int x, int y); + qboolean DragDelta (int x, int y, vec3_t move); + void XY_MouseUp(int x, int y, int buttons); + void XY_MouseDown (int x, int y, int buttons); + void XY_ToGridPoint (int x, int y, vec3_t point); + void XY_ToPoint (int x, int y, vec3_t point); + void SnapToPoint (int x, int y, vec3_t point); + void SetActive(bool b) {m_bActive = b;}; + bool Active() {return m_bActive;}; + + void DropClipPoint(guint32 nFlags, int pointx, int pointy); + bool RogueClipMode(); + bool ClipMode(); + void SetClipMode(bool bMode); + void RetainClipMode(bool bMode); + + bool RotateMode(); + bool SetRotateMode(bool bMode); + bool ScaleMode(); + void SetScaleMode(bool bMode); + + bool PathMode(); + void DropPathPoint(guint32 nFlags, int pointx, int pointy); + bool PointMode(); +// void AddPointPoint(guint32 nFlags, vec3_t* pVec); + void SetPointMode(bool b); + + void SetViewType(int n); + bool m_bActive; + +protected: + int m_nUpdateBits; + int m_nWidth; + int m_nHeight; + bool m_bTiming; + float m_fScale; + float m_TopClip; + float m_BottomClip; + bool m_bDirty; + vec3_t m_vOrigin; + + int m_ptCursorX, m_ptCursorY; + bool m_bRButtonDown; + + int m_nButtonstate; + int m_nPressx; + int m_nPressy; + vec3_t m_vPressdelta; + bool m_bPress_selection; + + friend class CamWnd; + +private: + // this is unique for all views + static GtkWidget* m_mnuDrop; + + int m_nViewType; + + int m_nScrollFlags; + int m_ptDragX, m_ptDragY; + int m_ptDragAdjX, m_ptDragAdjY; + int m_ptDragTotalX, m_ptDragTotalY; + + void OriginalButtonUp(guint32 nFlags, int point, int pointy); + void OriginalButtonDown(guint32 nFlags, int point, int pointy); +// void ProduceSplits(brush_t** pFront, brush_t** pBack); + void PlanePointsFromClipPoints(vec3_t planepts[3], brush_t *pBrush); + void ProduceSplitLists(); + void HandleDrop(); + void PaintSizeInfo(int nDim1, int nDim2, vec3_t vMinBounds, vec3_t vMaxBounds); + + int m_ptDownX, m_ptDownY; + +public: + void OnEntityCreate(const char* item); + int GetViewType() {return m_nViewType; } + void SetScale(float f) {m_fScale = f;} + float Scale() {return m_fScale;} + int Width() {return m_nWidth;} + int Height() {return m_nHeight;} + +protected: + + void OnCreate (); + void OnExpose (); + void OnLButtonDown(guint32 flags, int pointx, int pointy); + void OnRButtonDown(guint32 flags, int pointx, int pointy); + void OnMButtonDown(guint32 flags, int pointx, int pointy); + void OnLButtonUp(guint32 flags, int pointx, int pointy); + void OnRButtonUp(guint32 flags, int pointx, int pointy); + void OnMButtonUp(guint32 flags, int pointx, int pointy); + void OnMouseMove(guint32 nFlags, int pointx, int pointy); + void OnMouseWheel(bool bUp); + void OnSize (int cx, int cy); + void OnTimer(); + +private: + XORRectangle m_XORRectangle; +}; + +#endif // _XYWINDOW_H_ diff --git a/radiant/z.cpp b/radiant/z.cpp new file mode 100644 index 00000000..b5806cba --- /dev/null +++ b/radiant/z.cpp @@ -0,0 +1,466 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stdafx.h" +//#include "qe3.h" + +#define PAGEFLIPS 2 + +z_t z; + +/* +============ +Z_Init +============ +*/ +void Z_Init (void) +{ + z.origin[0] = 0; + z.origin[1] = 20; + z.origin[2] = 46; + + z.scale = 1; +} + + + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int cursorx, cursory; + +/* +============== +Z_MouseDown +============== +*/ +void Z_MouseDown (int x, int y, int buttons) +{ + vec3_t org, dir, vup, vright; + brush_t *b; + + Sys_GetCursorPos (&cursorx, &cursory); + + vup[0] = 0; vup[1] = 0; vup[2] = 1/z.scale; + + VectorCopy (z.origin, org); + org[2] += (y - (z.height/2))/z.scale; + org[1] = g_MinWorldCoord; + + b = selected_brushes.next; + if (b != &selected_brushes) + { + org[0] = (b->mins[0] + b->maxs[0])/2; + } + + dir[0] = 0; dir[1] = 1; dir[2] = 0; + + vright[0] = 0; vright[1] = 0; vright[2] = 0; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == MK_MBUTTON) +// || (buttons == (MK_MBUTTON|MK_CONTROL)) + || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL)) ) + { + Drag_Begin (x, y, buttons, + vright, vup, + org, dir); + return; + } + + // control mbutton = move camera + if ((buttons == (MK_CONTROL|nMouseButton) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + g_pParentWnd->GetCamWnd()->Camera()->origin[2] = org[2] ; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + + +} + +/* +============== +Z_MouseUp +============== +*/ +void Z_MouseUp (int x, int y, int buttons) +{ + Drag_MouseUp (); +} + +/* +============== +Z_MouseMoved +============== +*/ +void Z_MouseMoved (int x, int y, int buttons) +{ + if (!buttons) + return; + if (buttons == MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_Z|W_CAMERA_IFON|W_XY); + return; + } + // rbutton = drag z origin + if (buttons == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != cursory) + { + z.origin[2] += y-cursory; + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_Z); + } + return; + } + // control mbutton = move camera + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + if ((buttons == (MK_CONTROL|nMouseButton) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + g_pParentWnd->GetCamWnd()->Camera()->origin[2] = (y - (z.height/2))/z.scale; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + + +/* +============== +Z_DrawGrid +============== +*/ +void Z_DrawGrid (void) +{ + float zz, zb, ze; + float w, h; + char text[32]; + + w = (z.width/2 / z.scale); + h = (z.height/2 / z.scale); + + zb = z.origin[2] - h; + if (zb < region_mins[2]) + zb = region_mins[2]; + zb = 64 * floor (zb/64); + + ze = z.origin[2] + h; + if (ze > region_maxs[2]) + ze = region_maxs[2]; + ze = 64 * ceil (ze/64); + + // draw major blocks + + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); + + if ( g_qeglobals.d_showgrid ) + { + if (g_qeglobals.d_gridsize < 128) + { + qglBegin (GL_LINES); + + qglVertex2f (0, zb); + qglVertex2f (0, ze); + + for (zz=zb ; zz= 128 .. it's an int for sure + if ( ((int)zz & ((int)g_qeglobals.d_gridsize-1)) != 0 ) + continue; + + qglVertex2f (-w, zz); + qglVertex2f (w, zz); + } + + qglEnd (); + } + } + + // draw minor blocks + if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 && + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK]) + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); + + qglBegin (GL_LINES); + for (zz=zb ; zz 64 ? g_qeglobals.d_gridsize : 64); + zb = z.origin[2] - h; + if (zb < region_mins[2]) + zb = region_mins[2]; + zb = step * floor (zb/step); + + for (zz=zb ; zzGetCamWnd()->Camera()->origin[2]; + + qglColor3f (0.0, 0.0, 1.0); + qglBegin(GL_LINE_STRIP); + qglVertex3f (x-xCam,y,0); + qglVertex3f (x,y+gizmo,0); + qglVertex3f (x+xCam,y,0); + qglVertex3f (x,y-gizmo,0); + qglVertex3f (x-xCam,y,0); + qglVertex3f (x+xCam,y,0); + qglVertex3f (x+xCam,y-height,0); + qglVertex3f (x-xCam,y-height,0); + qglVertex3f (x-xCam,y,0); + qglEnd (); + +} + +GLbitfield glbitClear = GL_COLOR_BUFFER_BIT; //HACK + +/* +============== +Z_Draw +============== +*/ +void Z_Draw (void) +{ +#ifdef DBG_WINDOWPOS + CheckWatchit ("Z_Draw"); +#endif + brush_t *brush; + float w, h; + double start, end; + qtexture_t *q; + float top, bottom; + vec3_t org_top, org_bottom, dir_up, dir_down; + int xCam = z.width/3; + + if (!active_brushes.next) + return; // not valid yet + + if (z.timing) + start = Sys_DoubleTime (); + + // + // clear + // + qglViewport(0, 0, z.width, z.height); + + qglClearColor ( + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], + 0); + + /* GL Bug */ + /* When not using hw acceleration, gl will fault if we clear the depth + buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT + only after Z_Draw() has been called once. Yeah, right. */ + qglClear(glbitClear); + glbitClear |= GL_DEPTH_BUFFER_BIT; + qglMatrixMode(GL_PROJECTION); + + qglLoadIdentity (); + w = z.width/2 / z.scale; + h = z.height/2 / z.scale; + qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8); + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + + + // + // now draw the grid + // + Z_DrawGrid (); + + // + // draw stuff + // + + qglDisable(GL_CULL_FACE); + + qglShadeModel (GL_FLAT); + + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_BLEND); + qglDisable(GL_DEPTH_TEST); + + + // draw filled interiors and edges + dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1; + dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1; + VectorCopy (z.origin, org_top); + org_top[2] = g_MaxWorldCoord; + VectorCopy (z.origin, org_bottom); + org_bottom[2] = g_MinWorldCoord; + + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if (brush->bFiltered) + continue; + + if (brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) + continue; + + if (!Brush_Ray (org_top, dir_down, brush, &top)) + continue; + top = org_top[2] - top; + if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) + continue; + bottom = org_bottom[2] + bottom; + + q = brush->brush_faces->pShader->getTexture(); + qglColor3f (q->color[0], q->color[1], q->color[2]); + qglBegin (GL_QUADS); + qglVertex2f (-xCam, bottom); + qglVertex2f (xCam, bottom); + qglVertex2f (xCam, top); + qglVertex2f (-xCam, top); + qglEnd (); + + qglColor3f (1,1,1); + qglBegin (GL_LINE_LOOP); + qglVertex2f (-xCam, bottom); + qglVertex2f (xCam, bottom); + qglVertex2f (xCam, top); + qglVertex2f (-xCam, top); + qglEnd (); + } + + // + // now draw selected brushes + // + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( !(brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) ) + { + if (Brush_Ray (org_top, dir_down, brush, &top)) + { + top = org_top[2] - top; + if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) + { + bottom = org_bottom[2] + bottom; + + q = brush->brush_faces->pShader->getTexture(); + qglColor3f (q->color[0], q->color[1], q->color[2]); + qglBegin (GL_QUADS); + qglVertex2f (-xCam, bottom); + qglVertex2f (xCam, bottom); + qglVertex2f (xCam, top); + qglVertex2f (-xCam, top); + qglEnd (); + } + } + } + + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); + qglBegin (GL_LINE_LOOP); + qglVertex2f (-xCam, brush->mins[2]); + qglVertex2f (xCam, brush->mins[2]); + qglVertex2f (xCam, brush->maxs[2]); + qglVertex2f (-xCam, brush->maxs[2]); + qglEnd (); + } + + + ZDrawCameraIcon (); + + qglFinish(); + QE_CheckOpenGLForErrors(); + + if (z.timing) + { + end = Sys_DoubleTime (); + Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); + } +} + diff --git a/radiant/z.h b/radiant/z.h new file mode 100644 index 00000000..acf12a89 --- /dev/null +++ b/radiant/z.h @@ -0,0 +1,42 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +// window system independent camera view code + +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; // at center of window + float scale; +} z_t; + +extern z_t z; + +void Z_Init (void); +void Z_MouseDown (int x, int y, int buttons); +void Z_MouseUp (int x, int y, int buttons); +void Z_MouseMoved (int x, int y, int buttons); +void Z_Draw (void); + diff --git a/radiant/zwindow.cpp b/radiant/zwindow.cpp new file mode 100644 index 00000000..3da6284d --- /dev/null +++ b/radiant/zwindow.cpp @@ -0,0 +1,125 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Z Window +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include "zwindow.h" + +// ============================================================================= +// ZWnd class + +ZWnd::ZWnd () + : GLWindow (FALSE) +{ +} + +ZWnd::~ZWnd() +{ +} + +void ZWnd::OnCreate () +{ + g_qeglobals_gui.d_z = m_pWidget; + + if (!MakeCurrent()) + Error ("wglMakeCurrent in CZWnd::OnCreate failed"); +} + +void ZWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); +} + +void ZWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); +} + +void ZWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); +} + +void ZWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) +{ + Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); + ReleaseCapture (); +} + +void ZWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) +{ + Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); + ReleaseCapture (); +} + +void ZWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) +{ + Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); + ReleaseCapture (); +} + +void ZWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy) +{ + float fz = z.origin[2] + ((m_pWidget->allocation.height - 1 - pointy) - (z.height/2)) / z.scale; + fz = floor(fz / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + CString strStatus; + strStatus.Format("Z:: %.1f", fz); + g_pParentWnd->SetStatusText(1, strStatus); + Z_MouseMoved (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); +} + +void ZWnd::OnExpose() +{ + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: wglMakeCurrent failed..\n "); + Sys_Printf("Please restart Radiant if the Z view is not working\n"); + } + else + { + QE_CheckOpenGLForErrors(); + Z_Draw (); + QE_CheckOpenGLForErrors(); + SwapBuffers(); + } +} + +void ZWnd::OnSize(int cx, int cy) +{ + z.width = cx; + z.height = cy; + if (z.width < 10) + z.width = 10; + if (z.height < 10) + z.height = 10; + RedrawWindow (); +} diff --git a/radiant/zwindow.h b/radiant/zwindow.h new file mode 100644 index 00000000..d1f42bbd --- /dev/null +++ b/radiant/zwindow.h @@ -0,0 +1,46 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ZWINDOW_H_ +#define _ZWINDOW_H_ + +#include "glwindow.h" + +class ZWnd : public GLWindow +{ + public: + ZWnd (); + virtual ~ZWnd (); + + void OnCreate (); + void OnExpose (); + void OnLButtonDown (guint32 flags, int x, int y); + void OnRButtonDown (guint32 flags, int x, int y); + void OnMButtonDown (guint32 flags, int x, int y); + void OnLButtonUp (guint32 flags, int pointx, int pointy); + void OnRButtonUp (guint32 flags, int pointx, int pointy); + void OnMButtonUp (guint32 flags, int pointx, int pointy); + void OnMouseMove (guint32 flags, int pointx, int pointy); + void OnSize (int cx, int cy); +}; + + +#endif // _ZWINDOW_H_ diff --git a/run_python.bat b/run_python.bat new file mode 100644 index 00000000..ac0aebbc --- /dev/null +++ b/run_python.bat @@ -0,0 +1,9 @@ +python.exe -V +if errorlevel=1 echo please install python and add python.exe to the path (http://www.python.org) +if errorlevel=1 goto end + +echo python.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 +rem FIXME: for some wacked reason, output of the python script doesn't get back to VC window .. +python.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 + +:end \ No newline at end of file diff --git a/tools/quake2/common/bspfile.c b/tools/quake2/common/bspfile.c new file mode 100644 index 00000000..eac27aff --- /dev/null +++ b/tools/quake2/common/bspfile.c @@ -0,0 +1,789 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" +#include "scriplib.h" +#include "inout.h" + +void GetLeafNums (void); + +//============================================================================= + +int nummodels; +dmodel_t dmodels[MAX_MAP_MODELS]; + +int visdatasize; +byte dvisdata[MAX_MAP_VISIBILITY]; +dvis_t *dvis = (dvis_t *)dvisdata; + +int lightdatasize; +byte dlightdata[MAX_MAP_LIGHTING]; + +int entdatasize; +char dentdata[MAX_MAP_ENTSTRING]; + +int numleafs; +dleaf_t dleafs[MAX_MAP_LEAFS]; + +int numplanes; +dplane_t dplanes[MAX_MAP_PLANES]; + +int numvertexes; +dvertex_t dvertexes[MAX_MAP_VERTS]; + +int numnodes; +dnode_t dnodes[MAX_MAP_NODES]; + +int numtexinfo; +texinfo_t texinfo[MAX_MAP_TEXINFO]; + +int numfaces; +dface_t dfaces[MAX_MAP_FACES]; + +int numedges; +dedge_t dedges[MAX_MAP_EDGES]; + +int numleaffaces; +unsigned short dleaffaces[MAX_MAP_LEAFFACES]; + +int numleafbrushes; +unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +int numsurfedges; +int dsurfedges[MAX_MAP_SURFEDGES]; + +int numbrushes; +dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +int numbrushsides; +dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +int numareas; +darea_t dareas[MAX_MAP_AREAS]; + +int numareaportals; +dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; + +byte dpop[256]; + +/* +=============== +CompressVis + +=============== +*/ +int CompressVis (byte *vis, byte *dest) +{ + int j; + int rep; + int visrow; + byte *dest_p; + + dest_p = dest; +// visrow = (r_numvisleafs + 7)>>3; + visrow = (dvis->numclusters + 7)>>3; + + for (j=0 ; j>3; + row = (dvis->numclusters+7)>>3; + out = decompressed; + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + if (!c) + Error ("DecompressVis: 0 repeat"); + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +} + +//============================================================================= + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile (qboolean todisk) +{ + int i, j; + dmodel_t *d; + + +// models + for (i=0 ; ifirstface = LittleLong (d->firstface); + d->numfaces = LittleLong (d->numfaces); + d->headnode = LittleLong (d->headnode); + + for (j=0 ; j<3 ; j++) + { + d->mins[j] = LittleFloat(d->mins[j]); + d->maxs[j] = LittleFloat(d->maxs[j]); + d->origin[j] = LittleFloat(d->origin[j]); + } + } + +// +// vertexes +// + for (i=0 ; inumclusters; + else + j = LittleLong(dvis->numclusters); + dvis->numclusters = LittleLong (dvis->numclusters); + for (i=0 ; ibitofs[i][0] = LittleLong (dvis->bitofs[i][0]); + dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]); + } +} + + +dheader_t *header; + +int CopyLump (int lump, void *dest, int size) +{ + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if (length % size) + Error ("LoadBSPFile: odd lump size"); + + memcpy (dest, (byte *)header + ofs, length); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +void LoadBSPFile (char *filename) +{ + int i; + +// +// load the file header +// + LoadFile (filename, (void **)&header); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->ident != IDBSPHEADER) + Error ("%s is not a IBSP file", filename); + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, header->version, BSPVERSION); + + nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t)); + numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t)); + numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t)); + numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t)); + numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t)); + numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t)); + numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t)); + numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0])); + numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0])); + numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0])); + numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t)); + numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t)); + numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t)); + numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t)); + numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t)); + + visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1); + lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1); + entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1); + + CopyLump (LUMP_POP, dpop, 1); + + free (header); // everything has been copied out + +// +// swap everything +// + SwapBSPFile (false); +} + + +/* +============= +LoadBSPFileTexinfo + +Only loads the texinfo lump, so qdata can scan for textures +============= +*/ +void LoadBSPFileTexinfo (char *filename) +{ + int i; + FILE *f; + int length, ofs; + + header = malloc(sizeof(dheader_t)); + + f = fopen (filename, "rb"); + fread (header, sizeof(dheader_t), 1, f); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->ident != IDBSPHEADER) + Error ("%s is not a IBSP file", filename); + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, header->version, BSPVERSION); + + + length = header->lumps[LUMP_TEXINFO].filelen; + ofs = header->lumps[LUMP_TEXINFO].fileofs; + + fseek (f, ofs, SEEK_SET); + fread (texinfo, length, 1, f); + fclose (f); + + numtexinfo = length / sizeof(texinfo_t); + + free (header); // everything has been copied out + + SwapBSPFile (false); +} + + +//============================================================================ + +FILE *wadfile; +dheader_t outheader; + +void AddLump (int lumpnum, void *data, int len) +{ + lump_t *lump; + + lump = &header->lumps[lumpnum]; + + lump->fileofs = LittleLong( ftell(wadfile) ); + lump->filelen = LittleLong(len); + SafeWrite (wadfile, data, (len+3)&~3); +} + +/* +============= +WriteBSPFile + +Swaps the bsp file in place, so it should not be referenced again +============= +*/ +void WriteBSPFile (char *filename) +{ + header = &outheader; + memset (header, 0, sizeof(dheader_t)); + + SwapBSPFile (true); + + header->ident = LittleLong (IDBSPHEADER); + header->version = LittleLong (BSPVERSION); + + wadfile = SafeOpenWrite (filename); + SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later + + AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t)); + AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t)); + AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t)); + AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t)); + AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t)); + AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t)); + AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t)); + AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t)); + AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0])); + AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0])); + AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0])); + AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t)); + AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t)); + AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t)); + AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t)); + + AddLump (LUMP_LIGHTING, dlightdata, lightdatasize); + AddLump (LUMP_VISIBILITY, dvisdata, visdatasize); + AddLump (LUMP_ENTITIES, dentdata, entdatasize); + AddLump (LUMP_POP, dpop, sizeof(dpop)); + + fseek (wadfile, 0, SEEK_SET); + SafeWrite (wadfile, header, sizeof(dheader_t)); + fclose (wadfile); +} + +//============================================================================ + +/* +============= +PrintBSPFileSizes + +Dumps info about current file +============= +*/ +void PrintBSPFileSizes (void) +{ + if (!num_entities) + ParseEntities (); + + printf ("%5i models %7i\n" + ,nummodels, (int)(nummodels*sizeof(dmodel_t))); + printf ("%5i brushes %7i\n" + ,numbrushes, (int)(numbrushes*sizeof(dbrush_t))); + printf ("%5i brushsides %7i\n" + ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t))); + printf ("%5i planes %7i\n" + ,numplanes, (int)(numplanes*sizeof(dplane_t))); + printf ("%5i texinfo %7i\n" + ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t))); + printf ("%5i entdata %7i\n", num_entities, entdatasize); + + printf ("\n"); + + printf ("%5i vertexes %7i\n" + ,numvertexes, (int)(numvertexes*sizeof(dvertex_t))); + printf ("%5i nodes %7i\n" + ,numnodes, (int)(numnodes*sizeof(dnode_t))); + printf ("%5i faces %7i\n" + ,numfaces, (int)(numfaces*sizeof(dface_t))); + printf ("%5i leafs %7i\n" + ,numleafs, (int)(numleafs*sizeof(dleaf_t))); + printf ("%5i leaffaces %7i\n" + ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0]))); + printf ("%5i leafbrushes %7i\n" + ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0]))); + printf ("%5i surfedges %7i\n" + ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0]))); + printf ("%5i edges %7i\n" + ,numedges, (int)(numedges*sizeof(dedge_t))); + printf (" lightdata %7i\n", lightdatasize); + printf (" visdata %7i\n", visdatasize); +} + + +//============================================ + +int num_entities; +entity_t entities[MAX_MAP_ENTITIES]; + +void StripTrailing (char *e) +{ + char *s; + + s = e + strlen(e)-1; + while (s >= e && *s <= 32) + { + *s = 0; + s--; + } +} + +/* +================= +ParseEpair +================= +*/ +epair_t *ParseEpair (void) +{ + epair_t *e; + + e = malloc (sizeof(epair_t)); + memset (e, 0, sizeof(epair_t)); + + if (strlen(token) >= MAX_KEY-1) + Error ("ParseEpar: token too long"); + e->key = copystring(token); + GetToken (false); + if (strlen(token) >= MAX_VALUE-1) + Error ("ParseEpar: token too long"); + e->value = copystring(token); + + // strip trailing spaces + StripTrailing (e->key); + StripTrailing (e->value); + + return e; +} + + +/* +================ +ParseEntity +================ +*/ +qboolean ParseEntity (void) +{ + epair_t *e; + entity_t *mapent; + + if (!GetToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + mapent = &entities[num_entities]; + num_entities++; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } while (1); + + return true; +} + +/* +================ +ParseEntities + +Parses the dentdata string into entities +================ +*/ +void ParseEntities (void) +{ + num_entities = 0; + ParseFromMemory (dentdata, entdatasize); + + while (ParseEntity ()) + { + } +} + + +/* +================ +UnparseEntities + +Generates the dentdata string from all the entities +================ +*/ +void UnparseEntities (void) +{ + char *buf, *end; + epair_t *ep; + char line[2048]; + int i; + char key[1024], value[1024]; + + buf = dentdata; + end = buf; + *end = 0; + + for (i=0 ; inext) + { + strcpy (key, ep->key); + StripTrailing (key); + strcpy (value, ep->value); + StripTrailing (value); + + sprintf (line, "\"%s\" \"%s\"\n", key, value); + strcat (end, line); + end += strlen(line); + } + strcat (end,"}\n"); + end += 2; + + if (end > buf + MAX_MAP_ENTSTRING) + Error ("Entity text too long"); + } + entdatasize = end - buf + 1; +} + +void PrintEntity (entity_t *ent) +{ + epair_t *ep; + + printf ("------- entity %p -------\n", ent); + for (ep=ent->epairs ; ep ; ep=ep->next) + { + printf ("%s = %s\n", ep->key, ep->value); + } + +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = copystring(value); + return; + } + ep = malloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = copystring(key); + ep->value = copystring(value); +} + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +vec_t FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + double v1, v2, v3; + + k = ValueForKey (ent, key); +// scanf into doubles, then assign, so it is vec_t size independent + v1 = v2 = v3 = 0; + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + vec[0] = v1; + vec[1] = v2; + vec[2] = v3; +} + + diff --git a/tools/quake2/common/bspfile.h b/tools/quake2/common/bspfile.h new file mode 100644 index 00000000..b4d6b355 --- /dev/null +++ b/tools/quake2/common/bspfile.h @@ -0,0 +1,128 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qfiles.h" + + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; +extern dvis_t *dvis; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int numleaffaces; +extern unsigned short dleaffaces[MAX_MAP_LEAFFACES]; + +extern int numleafbrushes; +extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + +extern int numareas; +extern darea_t dareas[MAX_MAP_AREAS]; + +extern int numareaportals; +extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; + +extern int numbrushes; +extern dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +extern int numbrushsides; +extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +extern byte dpop[256]; + +void DecompressVis (byte *in, byte *decompressed); +int CompressVis (byte *vis, byte *dest); + +void LoadBSPFile (char *filename); +void LoadBSPFileTexinfo (char *filename); // just for qdata +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +//=============== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + int firstbrush; + int numbrushes; + epair_t *epairs; + +// only valid for func_areaportals + int areaportalnum; + int portalareas[2]; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities (void); +void UnparseEntities (void); + +void SetKeyValue (entity_t *ent, char *key, char *value); +char *ValueForKey (entity_t *ent, char *key); +// will return "" if not present + +vec_t FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +epair_t *ParseEpair (void); + +void PrintEntity (entity_t *ent); + diff --git a/tools/quake2/common/cmdlib.c b/tools/quake2/common/cmdlib.c new file mode 100644 index 00000000..6a005e32 --- /dev/null +++ b/tools/quake2/common/cmdlib.c @@ -0,0 +1,1221 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Nurail: Swiped from quake3/common + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#ifdef NeXT +#include +#endif + +#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following +#define HERETIC2_BASEDIRNAME "h" +#define PATHSEPERATOR '/' + +// qboolean verbose = false; + +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ) +{ + void *p; + + p = malloc(size); + if(!p) + Error ("safe_malloc failed on allocation of %i bytes", size); + + memset(p, 0, size); + return p; +} + +void *safe_malloc_info( size_t size, char* info ) +{ + void *p; + + p = malloc(size); + if(!p) + Error ("%s: safe_malloc failed on allocation of %i bytes", info, size); + + memset(p, 0, size); + return p; +} +#endif + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; +qboolean com_eof; + +qboolean archive; +char archivedir[1024]; + + +/* +=================== +ExpandWildcards + +Mimic unix command line expansion +=================== +*/ +#define MAX_EX_ARGC 1024 +int ex_argc; +char *ex_argv[MAX_EX_ARGC]; +#ifdef _WIN32 +#include "io.h" +void ExpandWildcards( int *argc, char ***argv ) +{ + struct _finddata_t fileinfo; + int handle; + int i; + char filename[1024]; + char filebase[1024]; + char *path; + + ex_argc = 0; + for (i=0 ; i<*argc ; i++) + { + path = (*argv)[i]; + if ( path[0] == '-' + || ( !strstr(path, "*") && !strstr(path, "?") ) ) + { + ex_argv[ex_argc++] = path; + continue; + } + + handle = _findfirst (path, &fileinfo); + if (handle == -1) + return; + + ExtractFilePath (path, filebase); + + do + { + sprintf (filename, "%s%s", filebase, fileinfo.name); + ex_argv[ex_argc++] = copystring (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + + *argc = ex_argc; + *argv = ex_argv; +} +#else +void ExpandWildcards (int *argc, char ***argv) +{ +} +#endif + +/* + +qdir will hold the path up to the quake directory, including the slash + + f:\quake\ + /raid/quake/ + +gamedir will hold qdir + the game directory (id1, id2, etc) + +*/ + +char qdir[1024]; +char gamedir[1024]; +char writedir[1024]; + +void SetQdirFromPath( const char *path ) +{ + char temp[1024]; + const char *c; + const char *sep; + int len, count; + char basedirname[256]; + + if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) + { // path is partial + Q_getwd (temp); + strcat (temp, path); + path = temp; + } + + // search for "quake2" in path + + if ( !strcmp( game, "heretic2" ) ) + strncpy(basedirname, HERETIC2_BASEDIRNAME, 256); + else + strncpy(basedirname, BASEDIRNAME, 256); + + len = strlen(basedirname); + for (c=path+strlen(path)-1 ; c != path ; c--) + { + int i; + + if (!Q_strncasecmp (c, basedirname, len)) + { + // + //strncpy (qdir, path, c+len+2-path); + // the +2 assumes a 2 or 3 following quake which is not the + // case with a retail install + // so we need to add up how much to the next separator + sep = c + len; + count = 1; + while (*sep && *sep != '/' && *sep != '\\') + { + sep++; + count++; + } + strncpy (qdir, path, c+len+count-path); + Sys_FPrintf( SYS_VRB, "qdir: %s\n", qdir); + for ( i = 0; i < strlen( qdir ); i++ ) + { + if ( qdir[i] == '\\' ) + qdir[i] = '/'; + } + + c += len+count; + while (*c) + { + if (*c == '/' || *c == '\\') + { + strncpy (gamedir, path, c+1-path); + + for ( i = 0; i < strlen( gamedir ); i++ ) + { + if ( gamedir[i] == '\\' ) + gamedir[i] = '/'; + } + + Sys_FPrintf( SYS_VRB, "gamedir: %s\n", gamedir); + + if ( !writedir[0] ) + strcpy( writedir, gamedir ); + else if ( writedir[strlen( writedir )-1] != '/' ) + { + writedir[strlen( writedir )] = '/'; + writedir[strlen( writedir )+1] = 0; + } + + return; + } + c++; + } + Error ("No gamedir in %s", path); + return; + } + } + Error ("SetQdirFromPath: no '%s' in %s", basedirname, path); +} + +char *ExpandArg (const char *path) +{ + static char full[1024]; + + if (path[0] != '/' && path[0] != '\\' && path[1] != ':') + { + Q_getwd (full); + strcat (full, path); + } + else + strcpy (full, path); + return full; +} + +char *ExpandPath (const char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandPath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { + strcpy( full, path ); + return full; + } + sprintf (full, "%s%s", qdir, path); + return full; +} + +char *ExpandGamePath (const char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandGamePath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { + strcpy( full, path ); + return full; + } + sprintf (full, "%s%s", gamedir, path); + return full; +} + +char *ExpandPathAndArchive (const char *path) +{ + char *expanded; + char archivename[1024]; + + expanded = ExpandPath (path); + + if (archive) + { + sprintf (archivename, "%s/%s", archivedir, path); + QCopyFile (expanded, archivename); + } + return expanded; +} + + +char *copystring(const char *s) +{ + char *b; + b = safe_malloc(strlen(s)+1); + strcpy (b, s); + return b; +} + + + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + +void Q_getwd (char *out) +{ + int i = 0; + +#ifdef _WIN32 + _getcwd (out, 256); + strcat (out, "\\"); +#else + // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow + getcwd (out, 256); + strcat (out, "/"); +#endif + while ( out[i] != 0 ) + { + if ( out[i] == '\\' ) + out[i] = '/'; + i++; + } +} + + +void Q_mkdir (const char *path) +{ +#ifdef _WIN32 + if (_mkdir (path) != -1) + return; +#else + if (mkdir (path, 0777) != -1) + return; +#endif + if (errno != EEXIST) + Error ("mkdir %s: %s",path, strerror(errno)); +} + +/* +============ +FileTime + +returns -1 if not present +============ +*/ +int FileTime (const char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = true; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +int Q_strncasecmp (const char *s1, const char *s2, int n) +{ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + } while (c1); + + return 0; // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + +int Q_strcasecmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + + +// NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config +// started getting warnings about that function, prolly a duplicate with the runtime function +// maybe we still need to have it in linux builds +/* +char *strupr (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; +} +*/ + +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (const char *check) +{ + int i; + + for (i = 1;i 0) { + nAllocSize += MEM_BLOCKSIZE - nBlock; + } + buffer = safe_malloc (nAllocSize+1); + memset(buffer, 0, nAllocSize+1); + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +TryLoadFile + +Allows failure +============== +*/ +int TryLoadFile (const char *filename, void **bufferptr) +{ + FILE *f; + int length; + void *buffer; + + *bufferptr = NULL; + + f = fopen (filename, "rb"); + if (!f) + return -1; + length = Q_filelength (f); + buffer = safe_malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +SaveFile +============== +*/ +void SaveFile (const char *filename, const void *buffer, int count) +{ + FILE *f; + + f = SafeOpenWrite (filename); + SafeWrite (f, buffer, count); + fclose (f); +} + + + +void DefaultExtension (char *path, const char *extension) +{ + char *src; +// +// if path doesnt have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && *src != '\\' && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + + +void DefaultPath (char *path, const char *basepath) +{ + char temp[128]; + + if( path[ 0 ] == '/' || path[ 0 ] == '\\' ) + return; // absolute path location + strcpy (temp,path); + strcpy (path,basepath); + strcat (path,temp); +} + + +void StripFilename (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '/' && path[ length ] != '\\' ) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/' || path[ length ] == '\\' ) + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '\\' && *(src-1) != '/') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (const char *hex) +{ + const char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (const char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} +/* +// all output ends up through here +void FPrintf (int flag, char *buf) +{ + printf(buf); + +} + +void Sys_FPrintf (int flag, const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + if ((flag == SYS_VRB) && (verbose == false)) + return; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (flag, out_buffer); +} + +void Sys_Printf (const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (SYS_STD, out_buffer); +} + + +//================= +//Error +// +//For abnormal program terminations +//================= + +void Error( const char *error, ...) +{ + char out_buffer[4096]; + char tmp[4096]; + va_list argptr; + + va_start (argptr,error); + vsprintf (tmp, error, argptr); + va_end (argptr); + + sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); + + FPrintf( SYS_ERR, out_buffer ); + + exit (1); +} +*/ + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* +============ +CreatePath +============ +*/ +void CreatePath (const char *path) +{ + const char *ofs; + char c; + char dir[1024]; + +#ifdef _WIN32 + int olddrive = -1; + + if ( path[1] == ':' ) + { + olddrive = _getdrive(); + _chdrive( toupper( path[0] ) - 'A' + 1 ); + } +#endif + + if (path[1] == ':') + path += 2; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + memcpy( dir, path, ofs - path ); + dir[ ofs - path ] = 0; + Q_mkdir( dir ); + } + } + +#ifdef _WIN32 + if ( olddrive != -1 ) + { + _chdrive( olddrive ); + } +#endif +} + + +/* +============ +QCopyFile + + Used to archive source files +============ +*/ +void QCopyFile (const char *from, const char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} + +void Sys_Sleep(int n) +{ +#ifdef _WIN32 + Sleep (n); +#endif +#if defined (__linux__) || defined (__APPLE__) + usleep (n * 1000); +#endif +} diff --git a/tools/quake2/common/cmdlib.h b/tools/quake2/common/cmdlib.h new file mode 100644 index 00000000..c3a5698f --- /dev/null +++ b/tools/quake2/common/cmdlib.h @@ -0,0 +1,170 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + #ifdef NDEBUG // Don't show in a Release build + #pragma warning(disable : 4305) // truncate from double to float + #pragma warning(disable : 4244) // conversion from double to float + #pragma warning(disable : 4018) // signed/unsigned mismatch + #endif +#endif + +#ifdef _WIN32 + #pragma intrinsic( memset, memcpy ) +#endif + +#ifndef __BYTEBOOL__ + #define __BYTEBOOL__ + typedef enum {false, true} qboolean; + typedef unsigned char byte; +#endif + +#define MAX_OS_PATH 1024 +#define MEM_BLOCKSIZE 4096 + +/* +extern qboolean verbose; +#define SYS_VRB 0 // verbose support (on/off) +#define SYS_STD 1 // standard print level +#define SYS_WRN 2 // warnings +#define SYS_ERR 3 // error +*/ + +// the dec offsetof macro doesnt work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + +#define SAFE_MALLOC +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ); +void *safe_malloc_info( size_t size, char* info ); +#else +#define safe_malloc(a) malloc(a) +#endif /* SAFE_MALLOC */ + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +char *strlower (char *in); +int Q_strncasecmp( const char *s1, const char *s2, int n ); +int Q_strcasecmp( const char *s1, const char *s2 ); +int Q_stricmp( const char *s1, const char *s2 ); +void Q_getwd( char *out ); + +int Q_filelength (FILE *f); +int FileTime( const char *path ); + +void Q_mkdir( const char *path ); + +extern char qdir[1024]; +extern char gamedir[1024]; +extern char writedir[1024]; +extern char *moddirparam; +void SetQdirFromPath( const char *path); +char *ExpandArg( const char *path ); // from cmd line +char *ExpandPath( const char *path ); // from scripts +char *ExpandGamePath (const char *path); +char *ExpandPathAndArchive( const char *path ); +void ExpandWildcards( int *argc, char ***argv ); + + +double I_FloatTime( void ); + +int CheckParm( const char *check ); + +FILE *SafeOpenWrite( const char *filename ); +FILE *SafeOpenRead( const char *filename ); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, const void *buffer, int count); + +int LoadFile( const char *filename, void **bufferptr ); +int LoadFileBlock( const char *filename, void **bufferptr ); +int TryLoadFile( const char *filename, void **bufferptr ); +void SaveFile( const char *filename, const void *buffer, int count ); +qboolean FileExists( const char *filename ); + +void DefaultExtension( char *path, const char *extension ); +void DefaultPath( char *path, const char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); + +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); + +int ParseNum (const char *str); + +//void Sys_Printf (const char *text, ...); +//void Sys_FPrintf (int flag, const char *text, ...); +//void Error( const char *error, ... ); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +char *copystring(const char *s); + + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); + +void CreatePath( const char *path ); +void QCopyFile( const char *from, const char *to ); + +extern qboolean archive; +extern char archivedir[1024]; + +// sleep for the given amount of milliseconds +void Sys_Sleep(int n); + +// for compression routines +typedef struct +{ + byte *data; + int count; +} cblock_t; + +extern char game[64]; + +#endif diff --git a/tools/quake2/common/inout.c b/tools/quake2/common/inout.c new file mode 100644 index 00000000..ef21edea --- /dev/null +++ b/tools/quake2/common/inout.c @@ -0,0 +1,367 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// deal with in/out tasks, for either stdin/stdout or network/XML stream +// + +#include "cmdlib.h" +#include "mathlib.h" +#include "polylib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +// network broadcasting +#include "l_net/l_net.h" +#include "libxml/tree.h" + +#ifdef _WIN32 +HWND hwndOut = NULL; +qboolean lookedForServer = false; +UINT wm_BroadcastCommand = -1; +#endif + +socket_t *brdcst_socket; +netmessage_t msg; + +qboolean verbose = false; + +// our main document +// is streamed through the network to Radiant +// possibly written to disk at the end of the run +//++timo FIXME: need to be global, required when creating nodes? +xmlDocPtr doc; +xmlNodePtr tree; + +// some useful stuff +xmlNodePtr xml_NodeForVec( vec3_t v ) +{ + xmlNodePtr ret; + char buf[1024]; + + sprintf (buf, "%f %f %f", v[0], v[1], v[2]); + ret = xmlNewNode (NULL, "point"); + xmlNodeSetContent (ret, buf); + return ret; +} + +// send a node down the stream, add it to the document +void xml_SendNode (xmlNodePtr node) +{ + xmlBufferPtr xml_buf; + char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks .. + // this index loops through the node buffer + int pos = 0; + int size; + + xmlAddChild( doc->children, node ); + + if (brdcst_socket) + { + xml_buf = xmlBufferCreate(); + xmlNodeDump( xml_buf, doc, node, 0, 0 ); + + // the XML node might be too big to fit in a single network message + // l_net library defines an upper limit of MAX_NETMESSAGE + // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe + // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages + while (pos < xml_buf->use) + { + // what size are we gonna send now? + (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10); + //++timo just a debug thing + if (size == MAX_NETMESSAGE - 10) + Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n"); + memcpy( xmlbuf, xml_buf->content+pos, size); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); + // now that the thing is sent prepare to loop again + pos += size; + } + +#if 0 + // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE + // we will need to split into chunks + // (we could also go lower level, in the end it's using send and receiv which are not size limited) + //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message + // there's some tweaking to do in l_net for that .. so let's give us a margin for now + + //++timo we need to handle the case of a buffer too big to fit in a single message + // try without checks for now + if (xml_buf->use > MAX_NETMESSAGE-10 ) + { + // if we send that we are probably gonna break the stream at the other end.. + // and Error will call right there + //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing + Sys_FPrintf (SYS_NOXML, xml_buf->content); + + } + + size = xml_buf->use; + memcpy( xmlbuf, xml_buf->content, size ); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); +#endif + + xmlBufferFree( xml_buf ); + } +} + +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError) +{ + xmlNodePtr node, select; + char buf[1024]; + char level[2]; + + // now build a proper "select" XML node + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + node = xmlNewNode (NULL, "select"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'select' information + sprintf (buf, "%i %i", entitynum, brushnum); + select = xmlNewNode (NULL, "brush"); + xmlNodeSetContent (select, buf); + xmlAddChild (node, select); + xml_SendNode (node); + + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + if (bError) + Error(buf); + else + Sys_FPrintf (SYS_NOXML, "%s\n", buf); + +} + +void xml_Point (char *msg, vec3_t pt) +{ + xmlNodePtr node, point; + char buf[1024]; + char level[2]; + + node = xmlNewNode (NULL, "pointmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'point' node + sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]); + point = xmlNewNode (NULL, "point"); + xmlNodeSetContent (point, buf); + xmlAddChild (node, point); + xml_SendNode (node); + + sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]); + Error (buf); +} + +#define WINDING_BUFSIZE 2048 +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die) +{ + xmlNodePtr node, winding; + char buf[WINDING_BUFSIZE]; + char smlbuf[128]; + char level[2]; + int i; + + node = xmlNewNode (NULL, "windingmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'winding' node + sprintf( buf, "%i ", numpoints); + for(i = 0; i < numpoints; i++) + { + sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]); + // don't overflow + if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE) + break; + strcat( buf, smlbuf); + } + + winding = xmlNewNode (NULL, "winding"); + xmlNodeSetContent (winding, buf); + xmlAddChild (node, winding); + xml_SendNode (node); + + if(die) + Error (msg); + else + { + Sys_Printf(msg); + Sys_Printf("\n"); + } +} + +// in include +#include "stream_version.h" + +void Broadcast_Setup( const char *dest ) +{ + address_t address; + char sMsg[1024]; + + Net_Setup(); + Net_StringToAddress((char *)dest, &address); + brdcst_socket = Net_Connect(&address, 0); + if (brdcst_socket) + { + // send in a header + sprintf (sMsg, ""); + NMSG_Clear( &msg ); + NMSG_WriteString(&msg, sMsg ); + Net_Send(brdcst_socket, &msg ); + } +} + +void Broadcast_Shutdown() +{ + if (brdcst_socket) + { + Sys_Printf("Disconnecting\n"); + Net_Disconnect(brdcst_socket); + brdcst_socket = NULL; + } +} + +// all output ends up through here +void FPrintf (int flag, char *buf) +{ + xmlNodePtr node; + static qboolean bGotXML = false; + char level[2]; + + printf(buf); + + // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe? + if (flag == SYS_NOXML) + return; + + // ouput an XML file of the run + // use the DOM interface to build a tree + /* + + message string + .. various nodes to describe corresponding geometry .. + + */ + if (!bGotXML) + { + // initialize + doc = xmlNewDoc("1.0"); + doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL); + bGotXML = true; + } + node = xmlNewNode (NULL, "message"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + flag; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level ); + + xml_SendNode (node); +} + +#ifdef DBG_XML +void DumpXML() +{ + xmlSaveFile( "XMLDump.xml", doc ); +} +#endif + +void Sys_FPrintf (int flag, const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + if ((flag == SYS_VRB) && (verbose == false)) + return; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (flag, out_buffer); +} + +void Sys_Printf (const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (SYS_STD, out_buffer); +} + +/* +================= +Error + +For abnormal program terminations +================= +*/ +void Error( const char *error, ...) +{ + char out_buffer[4096]; + char tmp[4096]; + va_list argptr; + + va_start (argptr,error); + vsprintf (tmp, error, argptr); + va_end (argptr); + + sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); + + FPrintf( SYS_ERR, out_buffer ); + +#ifdef DBG_XML + DumpXML(); +#endif + + //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener. + // a clean solution is to send a sync request node in the stream and wait for an answer before exiting + Sys_Sleep( 1000 ); + + Broadcast_Shutdown(); + + exit (1); +} + diff --git a/tools/quake2/common/inout.h b/tools/quake2/common/inout.h new file mode 100644 index 00000000..4843a7b6 --- /dev/null +++ b/tools/quake2/common/inout.h @@ -0,0 +1,63 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __INOUT__ +#define __INOUT__ + +// inout is the only stuff relying on xml, include the headers there +#include "libxml/tree.h" +#include "mathlib.h" + +// some useful xml routines +xmlNodePtr xml_NodeForVec( vec3_t v ); +void xml_SendNode (xmlNodePtr node); +// print a message in q3map output and send the corresponding select information down the xml stream +// bError: do we end with an error on this one or do we go ahead? +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError); +// end q3map with an error message and send a point information in the xml stream +// note: we might want to add a boolean to use this as a warning or an error thing.. +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die); +void xml_Point (char *msg, vec3_t pt); + +extern qboolean bNetworkBroadcast; +void Broadcast_Setup( const char *dest ); +void Broadcast_Shutdown(); + +#define SYS_VRB 0 // verbose support (on/off) +#define SYS_STD 1 // standard print level +#define SYS_WRN 2 // warnings +#define SYS_ERR 3 // error +#define SYS_NOXML 4 // don't send that down the XML stream + +extern qboolean verbose; +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); +void Error( const char *error, ...); + +#ifdef _DEBUG +#define DBG_XML 1 +#endif + +#ifdef DBG_XML +void DumpXML(); +#endif + +#endif diff --git a/tools/quake2/common/l3dslib.c b/tools/quake2/common/l3dslib.c new file mode 100644 index 00000000..7a551b11 --- /dev/null +++ b/tools/quake2/common/l3dslib.c @@ -0,0 +1,300 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// +// l3dslib.c: library for loading triangles from an Alias triangle file +// + +#include +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "trilib.h" +#include "l3dslib.h" + +#define MAIN3DS 0x4D4D +#define EDIT3DS 0x3D3D // this is the start of the editor config +#define EDIT_OBJECT 0x4000 +#define OBJ_TRIMESH 0x4100 +#define TRI_VERTEXL 0x4110 +#define TRI_FACEL1 0x4120 + +#define MAXVERTS 2000 + +typedef struct { + int v[4]; +} tri; + +float fverts[MAXVERTS][3]; +tri tris[MAXTRIANGLES]; + +int bytesread, level, numtris, totaltris; +int vertsfound, trisfound; + +triangle_t *ptri; + + +// Alias stores triangles as 3 explicit vertices in .tri files, so even though we +// start out with a vertex pool and vertex indices for triangles, we have to convert +// to raw, explicit triangles +void StoreAliasTriangles (void) +{ + int i, j, k; + + if ((totaltris + numtris) > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0; i MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i 0) + { + w -= ParseChunk (input); + } + + retval = length; + goto Done; + + default: + // skip other chunks + while (w > 0) + { + t = w; + + if (t > BLOCK_SIZE) + t = BLOCK_SIZE; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp, t, 1, input); + bytesread += t; + + w -= t; + } + + retval = length; + goto Done; + } + +Done: + level--; + return retval; +} + + +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles) +{ + FILE *input; + short int tshort; + + bytesread = 0; + level = 0; + numtris = 0; + totaltris = 0; + vertsfound = 0; + trisfound = 0; + + if ((input = fopen(filename, "rb")) == 0) { + fprintf(stderr,"reader: could not open file '%s'\n", filename); + exit(0); + } + + fread(&tshort, sizeof(tshort), 1, input); + +// should only be MAIN3DS, but some files seem to start with EDIT3DS, with +// no MAIN3DS + if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) { + fprintf(stderr,"File is not a 3DS file.\n"); + exit(0); + } + +// back to top of file so we can parse the first chunk descriptor + fseek(input, 0, SEEK_SET); + + ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); + + *pptri = ptri; + +// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT | +// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks + ParseChunk (input); + + if (vertsfound || trisfound) + Error ("Incomplete triangle set"); + + *numtriangles = totaltris; + + fclose (input); +} + diff --git a/tools/quake2/common/l3dslib.h b/tools/quake2/common/l3dslib.h new file mode 100644 index 00000000..528adc1d --- /dev/null +++ b/tools/quake2/common/l3dslib.h @@ -0,0 +1,25 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// +// l3dslib.h: header file for loading triangles from a 3DS triangle file +// +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles); + diff --git a/tools/quake2/common/lbmlib.c b/tools/quake2/common/lbmlib.c new file mode 100644 index 00000000..e157b94c --- /dev/null +++ b/tools/quake2/common/lbmlib.c @@ -0,0 +1,837 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// lbmlib.c + +#include "cmdlib.h" +#include "inout.h" +#include "lbmlib.h" + + + +/* +============================================================================ + + LBM STUFF + +============================================================================ +*/ + + +typedef unsigned char UBYTE; +//conflicts with windows typedef short WORD; +typedef unsigned short UWORD; +typedef long LONG; + +typedef enum +{ + ms_none, + ms_mask, + ms_transcolor, + ms_lasso +} mask_t; + +typedef enum +{ + cm_none, + cm_rle1 +} compress_t; + +typedef struct +{ + UWORD w,h; + short x,y; + UBYTE nPlanes; + UBYTE masking; + UBYTE compression; + UBYTE pad1; + UWORD transparentColor; + UBYTE xAspect,yAspect; + short pageWidth,pageHeight; +} bmhd_t; + +extern bmhd_t bmhd; // will be in native byte order + + + +#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) +#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) +#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) +#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) +#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) +#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) + + +bmhd_t bmhd; + +int Align (int l) +{ + if (l&1) + return l+1; + return l; +} + + + +/* +================ +LBMRLEdecompress + +Source must be evenly aligned! +================ +*/ +byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) +{ + int count; + byte b,rept; + + count = 0; + + do + { + rept = *source++; + + if (rept > 0x80) + { + rept = (rept^0xff)+2; + b = *source++; + memset(unpacked,b,rept); + unpacked += rept; + } + else if (rept < 0x80) + { + rept++; + memcpy(unpacked,source,rept); + unpacked += rept; + source += rept; + } + else + rept = 0; // rept of 0x80 is NOP + + count += rept; + + } while (countbpwidth) + Error ("Decompression exceeded width!\n"); + + + return source; +} + + +/* +================= +LoadLBM +================= +*/ +void LoadLBM (char *filename, byte **picture, byte **palette) +{ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + + int formtype,formlength; + int chunktype,chunklength; + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + +// +// load the LBM +// + LoadFile (filename, (void **)&LBMbuffer); + +// +// parse the LBM header +// + LBM_P = LBMbuffer; + if ( *(int *)LBMbuffer != LittleLong(FORMID) ) + Error ("No FORM ID at start of file!\n"); + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align(formlength); + + formtype = LittleLong(*(int *)LBM_P); + + if (formtype != ILBMID && formtype != PBMID) + Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff + ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + + LBM_P += 4; + +// +// parse chunks +// + + while (LBM_P < LBMEND_P) + { + chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + LBM_P += 4; + chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + LBM_P += 4; + + switch ( chunktype ) + { + case BMHDID: + memcpy (&bmhd,LBM_P,sizeof(bmhd)); + bmhd.w = BigShort(bmhd.w); + bmhd.h = BigShort(bmhd.h); + bmhd.x = BigShort(bmhd.x); + bmhd.y = BigShort(bmhd.y); + bmhd.pageWidth = BigShort(bmhd.pageWidth); + bmhd.pageHeight = BigShort(bmhd.pageHeight); + break; + + case CMAPID: + cmapbuffer = malloc (768); + memset (cmapbuffer, 0, 768); + memcpy (cmapbuffer, LBM_P, chunklength); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = malloc (bmhd.w*bmhd.h); + if (formtype == PBMID) + { + // + // unpack PBM + // + for (y=0 ; ydata; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + Error ("Bad pcx file %s", filename); + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + if (!out) + Error ("Skin_Cache: couldn't allocate"); + + *pic = out; + + pix = out; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + Error ("PCX file %s was malformed", filename); + + free (pcx); +} + +/* +============== +WritePCXfile +============== +*/ +void WritePCXfile (char *filename, byte *data, + int width, int height, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = malloc (width*height*2+1000); + memset (pcx, 0, sizeof(*pcx)); + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(2); // not a grey scale + + // pack the image + pack = &pcx->data; + + for (i=0 ; i=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + // vertically flipped + if ( (targa_header.attributes & (1<<5)) ) { + int flip; + for (row = 0; row < .5f * rows; row++) + { + for (column = 0; column < columns; column++) + { + flip = *( (int*)targa_rgba + row * columns + column); + *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); + *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; + } + } + } + + fclose(fin); +} diff --git a/tools/quake2/common/lbmlib.h b/tools/quake2/common/lbmlib.h new file mode 100644 index 00000000..b2055225 --- /dev/null +++ b/tools/quake2/common/lbmlib.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// piclib.h + + +void LoadLBM (char *filename, byte **picture, byte **palette); +void WriteLBMfile (char *filename, byte *data, int width, int height + , byte *palette); +void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height); +void WritePCXfile (char *filename, byte *data, int width, int height + , byte *palette); + +// loads / saves either lbm or pcx, depending on extension +void Load256Image (char *name, byte **pixels, byte **palette, + int *width, int *height); +void Save256Image (char *name, byte *pixels, byte *palette, + int width, int height); + + +void LoadTGA (char *filename, byte **pixels, int *width, int *height); diff --git a/tools/quake2/common/mathlib.c b/tools/quake2/common/mathlib.c new file mode 100644 index 00000000..7c06a477 --- /dev/null +++ b/tools/quake2/common/mathlib.c @@ -0,0 +1,172 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// mathlib.c -- math primitives + +#include "cmdlib.h" +#include "mathlib.h" + +vec3_t vec3_origin = {0,0,0}; + + +double VectorLength(vec3_t v) +{ + int i; + double length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return false; + + return true; +} + +vec_t Q_rint (vec_t in) +{ + return floor (in + 0.5); +} + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void _VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} + +vec_t VectorNormalize (vec3_t in, vec3_t out) +{ + vec_t length, ilength; + + length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +vec_t ColorNormalize (vec3_t in, vec3_t out) +{ + float max, scale; + + max = in[0]; + if (in[1] > max) + max = in[1]; + if (in[2] > max) + max = in[2]; + + if (max == 0) + return 0; + + scale = 1.0 / max; + + VectorScale (in, scale, out); + + return max; +} + + + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void ClearBounds (vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} diff --git a/tools/quake2/common/mathlib.h b/tools/quake2/common/mathlib.h new file mode 100644 index 00000000..f6d13483 --- /dev/null +++ b/tools/quake2/common/mathlib.h @@ -0,0 +1,75 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h + +#include + +#ifdef DOUBLEVEC_T +typedef double vec_t; +#else +typedef float vec_t; +#endif +typedef vec_t vec3_t[3]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +#define Q_PI 3.14159265358979323846 + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];} + +vec_t Q_rint (vec_t in); +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); +void _VectorScale (vec3_t v, vec_t scale, vec3_t out); + +double VectorLength(vec3_t v); + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc); + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (vec3_t in, vec3_t out); +vec_t ColorNormalize (vec3_t in, vec3_t out); +void VectorInverse (vec3_t v); + +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +#endif diff --git a/tools/quake2/common/md4.c b/tools/quake2/common/md4.c new file mode 100644 index 00000000..e69de29b diff --git a/tools/quake2/common/path_init.c b/tools/quake2/common/path_init.c new file mode 100644 index 00000000..6e01d3fd --- /dev/null +++ b/tools/quake2/common/path_init.c @@ -0,0 +1,400 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + + +/* marker */ +#define PATH_INIT_C + +#if defined( __linux__ ) || defined( __APPLE__ ) + #define Q_UNIX +#endif + +#ifdef Q_UNIX + #include + #include + #include +#endif + + +/* dependencies */ +#include "cmdlib.h" +#include "inout.h" + + + +/* path support */ +#define MAX_BASE_PATHS 10 +#define MAX_GAME_PATHS 10 + +char *homePath; +char installPath[ MAX_OS_PATH ]; + +int numBasePaths; +char *basePaths[ MAX_BASE_PATHS ]; +int numGamePaths; +char *gamePaths[ MAX_GAME_PATHS ]; + +/* +some of this code is based off the original q3map port from loki +and finds various paths. moved here from bsp.c for clarity. +*/ + +/* +PathLokiGetHomeDir() +gets the user's home dir (for ~/.q3a) +*/ + +char *LokiGetHomeDir( void ) +{ + #ifndef Q_UNIX + return NULL; + #else + char *home; + uid_t id; + struct passwd *pwd; + + + /* get the home environment variable */ + home = getenv( "HOME" ); + if( home == NULL ) + { + /* do some more digging */ + id = getuid(); + setpwent(); + while( (pwd = getpwent()) != NULL ) + { + if( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + } + endpwent(); + } + + /* return it */ + return home; + #endif +} + + + +/* +PathLokiInitPaths() +initializes some paths on linux/os x +*/ + +void LokiInitPaths( char *argv0 ) +{ + #ifndef Q_UNIX + /* this is kinda crap, but hey */ + strcpy( installPath, "../" ); + #else + char temp[ MAX_OS_PATH ]; + char *home; + char *path; + char *last; + qboolean found; + + + /* get home dir */ + home = LokiGetHomeDir(); + if( home == NULL ) + home = "."; + + /* do some path divining */ + strcpy( temp, argv0 ); + if( strrchr( temp, '/' ) ) + argv0 = strrchr( argv0, '/' ) + 1; + else + { + /* get path environment variable */ + path = getenv( "PATH" ); + + /* minor setup */ + last[ 0 ] = path[ 0 ]; + last[ 1 ] = '\0'; + found = false; + + /* go through each : segment of path */ + while( last[ 0 ] != '\0' && found == false ) + { + /* null out temp */ + temp[ 0 ] = '\0'; + + /* find next chunk */ + last = strchr( path, ':' ); + if( last == NULL ) + last = path + strlen( path ); + + /* found home dir candidate */ + if( *path == '~' ) + { + strcpy( temp, home ); + path++; + } + + /* concatenate */ + if( last > (path + 1) ) + { + strncat( temp, path, (last - path) ); + strcat( temp, "/" ); + } + strcat( temp, "./" ); + strcat( temp, argv0 ); + + /* verify the path */ + if( access( temp, X_OK ) == 0 ) + found++; + path = last + 1; + } + } + + /* flake */ + if( realpath( temp, installPath ) ) + { + /* q3map is in "tools/" */ + *(strrchr( installPath, '/' )) = '\0'; + *(strrchr( installPath, '/' ) + 1) = '\0'; + } + + /* set home path */ + homePath = home; + #endif +} + + + +/* +CleanPath() - ydnar +cleans a dos path \ -> / +*/ + +void CleanPath( char *path ) +{ + while( *path ) + { + if( *path == '\\' ) + *path = '/'; + path++; + } +} + +/* +AddBasePath() - ydnar +adds a base path to the list +*/ + +void AddBasePath( char *path ) +{ + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS ) + return; + + /* add it to the list */ + basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 ); + strcpy( basePaths[ numBasePaths ], path ); + CleanPath( basePaths[ numBasePaths ] ); + numBasePaths++; +} + + + +/* +AddHomeBasePath() - ydnar +adds a base path to the beginning of the list, prefixed by ~/ +*/ + +void AddHomeBasePath( char *path ) +{ + #ifdef Q_UNIX + int i; + char temp[ MAX_OS_PATH ]; + + + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' ) + return; + + /* make a hole */ + for( i = 0; i < (MAX_BASE_PATHS - 1); i++ ) + basePaths[ i + 1 ] = basePaths[ i ]; + + /* concatenate home dir and path */ + sprintf( temp, "%s/%s", homePath, path ); + + /* add it to the list */ + basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 ); + strcpy( basePaths[ 0 ], temp ); + CleanPath( basePaths[ 0 ] ); + numBasePaths++; + #endif +} + + + +/* +AddGamePath() - ydnar +adds a game path to the list +*/ + +void AddGamePath( char *path ) +{ + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS ) + return; + + /* add it to the list */ + gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 ); + strcpy( gamePaths[ numGamePaths ], path ); + CleanPath( gamePaths[ numGamePaths ] ); + numGamePaths++; +} + + + + +/* +InitPaths() - ydnar +cleaned up some of the path initialization code from bsp.c +will remove any arguments it uses +*/ + +void InitPaths( int *argc, char **argv ) +{ + int i, j, k, len, len2; + char temp[ MAX_OS_PATH ]; + char gamePath[MAX_OS_PATH], homeBasePath[MAX_OS_PATH], game_magic[10]; + + strcpy(gamePath, "baseq2"); + strcpy(game_magic, "quake"); + strcpy(homeBasePath, ".quake2"); + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" ); + + /* get the install path for backup */ + LokiInitPaths( argv[ 0 ] ); + + /* set game to default (q3a) */ + numBasePaths = 0; + numGamePaths = 0; + + /* parse through the arguments and extract those relevant to paths */ + for( i = 0; i < *argc; i++ ) + { + /* check for null */ + if( argv[ i ] == NULL ) + continue; + + /* -fs_basepath */ + if( strcmp( argv[ i ], "-fs_basepath" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + AddBasePath( argv[ i ] ); + argv[ i ] = NULL; + } + + } + + /* remove processed arguments */ + for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ ) + { + for( j; j < *argc && argv[ j ] == NULL; j++ ); + argv[ i ] = argv[ j ]; + if( argv[ i ] != NULL ) + k++; + } + *argc = k; + + /* add standard game path */ + AddGamePath( gamePath ); + + /* if there is no base path set, figure it out */ + if( numBasePaths == 0 ) + { + /* this is another crappy replacement for SetQdirFromPath() */ + len2 = strlen( game_magic ); + for( i = 0; i < *argc && numBasePaths == 0; i++ ) + { + /* extract the arg */ + strcpy( temp, argv[ i ] ); + CleanPath( temp ); + len = strlen( temp ); + Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game_magic, temp, i ); + + /* this is slow, but only done once */ + for( j = 0; j < (len - len2); j++ ) + { + /* check for the game's magic word */ + if( Q_strncasecmp( &temp[ j ], game_magic, len2 ) == 0 ) + { + /* now find the next slash and nuke everything after it */ + while( temp[ ++j ] != '/' && temp[ j ] != '\0' ); + temp[ j ] = '\0'; + + /* add this as a base path */ + AddBasePath( temp ); + break; + } + } + } + + /* add install path */ + if( numBasePaths == 0 ) + AddBasePath( installPath ); + + /* check again */ + if( numBasePaths == 0 ) + Error( "Failed to find a valid base path." ); + } + + /* this only affects unix */ + AddHomeBasePath( homeBasePath ); + + /* initialize vfs paths */ + if( numBasePaths > MAX_BASE_PATHS ) + numBasePaths = MAX_BASE_PATHS; + if( numGamePaths > MAX_GAME_PATHS ) + numGamePaths = MAX_GAME_PATHS; + + /* walk the list of game paths */ + //for( j = 0; j < numGamePaths; j++ ) + //{ + /* walk the list of base paths */ + // for( i = 0; i < numBasePaths; i++ ) + // { + /* create a full path and initialize it */ + // sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] ); + // vfsInitDirectory( temp ); + // } + //} + + /* done */ + Sys_Printf( "\n" ); +} + + + + diff --git a/tools/quake2/common/polylib.c b/tools/quake2/common/polylib.c new file mode 100644 index 00000000..47b2007e --- /dev/null +++ b/tools/quake2/common/polylib.c @@ -0,0 +1,642 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "polylib.h" + + +extern int numthreads; + +// counters are only bumped when running single threaded, +// because they are an awefull coherence problem +int c_active_windings; +int c_peak_windings; +int c_winding_allocs; +int c_winding_points; + +#define BOGUS_RANGE 8192 + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]); +} + + +/* +============= +AllocWinding +============= +*/ +winding_t *AllocWinding (int points) +{ + winding_t *w; + int s; + + if (numthreads == 1) + { + c_winding_allocs++; + c_winding_points += points; + c_active_windings++; + if (c_active_windings > c_peak_windings) + c_peak_windings = c_active_windings; + } + s = sizeof(vec_t)*3*points + sizeof(int); + w = malloc (s); + memset (w, 0, s); + return w; +} + +void FreeWinding (winding_t *w) +{ + if (*(unsigned *)w == 0xdeaddead) + Error ("FreeWinding: freed a freed winding"); + *(unsigned *)w = 0xdeaddead; + + if (numthreads == 1) + c_active_windings--; + free (w); +} + +/* +============ +RemoveColinearPoints +============ +*/ +int c_removed; + +void RemoveColinearPoints (winding_t *w) +{ + int i, j, k; + vec3_t v1, v2; + int nump; + vec3_t p[MAX_POINTS_ON_WINDING]; + + nump = 0; + for (i=0 ; inumpoints ; i++) + { + j = (i+1)%w->numpoints; + k = (i+w->numpoints-1)%w->numpoints; + VectorSubtract (w->p[j], w->p[i], v1); + VectorSubtract (w->p[i], w->p[k], v2); + VectorNormalize(v1,v1); + VectorNormalize(v2,v2); + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (w->p[i], p[nump]); + nump++; + } + } + + if (nump == w->numpoints) + return; + + if (numthreads == 1) + c_removed += w->numpoints - nump; + w->numpoints = nump; + memcpy (w->p, p, nump*sizeof(p[0])); +} + +/* +============ +WindingPlane +============ +*/ +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist) +{ + vec3_t v1, v2; + + VectorSubtract (w->p[1], w->p[0], v1); + VectorSubtract (w->p[2], w->p[0], v2); + CrossProduct (v2, v1, normal); + VectorNormalize (normal, normal); + *dist = DotProduct (w->p[0], normal); + +} + +/* +============= +WindingArea +============= +*/ +vec_t WindingArea (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->p[i-1], w->p[0], d1); + VectorSubtract (w->p[i], w->p[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs) +{ + vec_t v; + int i,j; + + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +/* +============= +WindingCenter +============= +*/ +void WindingCenter (winding_t *w, vec3_t center) +{ + int i; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; inumpoints ; i++) + VectorAdd (w->p[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + +/* +================= +BaseWindingForPlane +================= +*/ +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + c = AllocWinding (w->numpoints); + size = (int)((winding_t *)0)->p[w->numpoints]; + memcpy (c, w, size); + return c; +} + +/* +================== +ReverseWinding +================== +*/ +winding_t *ReverseWinding (winding_t *w) +{ + int i; + winding_t *c; + + c = AllocWinding (w->numpoints); + for (i=0 ; inumpoints ; i++) + { + VectorCopy (w->p[w->numpoints-1-i], c->p[i]); + } + c->numpoints = w->numpoints; + return c; +} + + +/* +============= +ClipWindingEpsilon +============= +*/ +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding (in); + return; + } + if (!counts[1]) + { + *front = CopyWinding (in); + return; + } + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + *front = f = AllocWinding (maxpts); + *back = b = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon) +{ + winding_t *in; + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding (in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding (in); + *inout = f; +} + + +/* +================= +ChopWinding + +Returns the fragment of in that is on the front side +of the cliping plane. The original is freed. +================= +*/ +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) +{ + winding_t *f, *b; + + ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b); + FreeWinding (in); + if (b) + FreeWinding (b); + return f; +} + + +/* +================= +CheckWinding + +================= +*/ +void CheckWinding (winding_t *w) +{ + int i, j; + vec_t *p1, *p2; + vec_t d, edgedist; + vec3_t dir, edgenormal, facenormal; + vec_t area; + vec_t facedist; + + if (w->numpoints < 3) + Error ("CheckWinding: %i points",w->numpoints); + + area = WindingArea(w); + if (area < 1) + Error ("CheckWinding: %f area", area); + + WindingPlane (w, facenormal, &facedist); + + for (i=0 ; inumpoints ; i++) + { + p1 = w->p[i]; + + for (j=0 ; j<3 ; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Error ("CheckFace: BUGUS_RANGE: %f",p1[j]); + + j = i+1 == w->numpoints ? 0 : i+1; + + // check the point is on the face plane + d = DotProduct (p1, facenormal) - facedist; + if (d < -ON_EPSILON || d > ON_EPSILON) + Error ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = w->p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Error ("CheckWinding: degenerate edge"); + + CrossProduct (facenormal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + edgedist += ON_EPSILON; + + // all other points must be on front side + for (j=0 ; jnumpoints ; j++) + { + if (j == i) + continue; + d = DotProduct (w->p[j], edgenormal); + if (d > edgedist) + Error ("CheckWinding: non-convex"); + } + } +} + + +/* +============ +WindingOnPlaneSide +============ +*/ +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist) +{ + qboolean front, back; + int i; + vec_t d; + + front = false; + back = false; + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = true; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = true; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + diff --git a/tools/quake2/common/polylib.h b/tools/quake2/common/polylib.h new file mode 100644 index 00000000..6c21fc95 --- /dev/null +++ b/tools/quake2/common/polylib.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +typedef struct +{ + int numpoints; + vec3_t p[4]; // variable sized +} winding_t; + +#define MAX_POINTS_ON_WINDING 64 + +// you can define on_epsilon in the makefile as tighter +#ifndef ON_EPSILON +#define ON_EPSILON 0.1 +#endif + +winding_t *AllocWinding (int points); +vec_t WindingArea (winding_t *w); +void WindingCenter (winding_t *w, vec3_t center); +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back); +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist); +winding_t *CopyWinding (winding_t *w); +winding_t *ReverseWinding (winding_t *w); +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist); +void CheckWinding (winding_t *w); +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist); +void RemoveColinearPoints (winding_t *w); +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist); +void FreeWinding (winding_t *w); +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs); + +void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon); +// frees the original if clipped + +void pw(winding_t *w); diff --git a/tools/quake2/common/q2_threads.h b/tools/quake2/common/q2_threads.h new file mode 100644 index 00000000..e919c264 --- /dev/null +++ b/tools/quake2/common/q2_threads.h @@ -0,0 +1,34 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _THREADS_H + +#define _THREADS_H + +extern int numthreads; + +void ThreadSetDefault (void); +int GetThreadWork (void); +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)); +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)); +void ThreadLock (void); +void ThreadUnlock (void); + +#endif // _THREADS_H diff --git a/tools/quake2/common/qfiles.h b/tools/quake2/common/qfiles.h new file mode 100644 index 00000000..434accc7 --- /dev/null +++ b/tools/quake2/common/qfiles.h @@ -0,0 +1,563 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +The .pak files are just a linear collapse of a directory tree + +======================================================================== +*/ + +#ifdef _WIN32 + #ifdef NDEBUG // Don't show in a Release build + #pragma warning(disable : 4305) // truncate from double to float + #pragma warning(disable : 4244) // conversion from double to float + #pragma warning(disable : 4018) // signed/unsigned mismatch + #endif +#endif + +#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 4096 + + +/* +======================================================================== + +PCX files are used for as many images as possible + +======================================================================== +*/ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 32 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .WAL texture file format + +============================================================================== +*/ + + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + int flags; + int contents; + int value; +} miptex_t; + + /* + ============================================================================== + +- .WAL texture file format ++ .M8 texture file format + + ============================================================================== + */ + +typedef struct palette_s +{ + union + { + struct + { + byte r,g,b; + }; + }; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define H2_MIPLEVELS 16 + + typedef struct miptex_m8_s + { + int version; + char name[32]; + unsigned width[H2_MIPLEVELS], height[H2_MIPLEVELS]; + unsigned offsets[H2_MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; + } miptex_m8_t; + + +#define MIP32_VERSION 4 + +#define MIP32_NOMIP_FLAG2 0x00000001 +#define MIP32_DETAILER_FLAG2 0x00000002 + +typedef struct miptex_m32_s +{ + int version; + char name[128]; + char altname[128]; // texture substitution + char animname[128]; // next frame in animation chain + char damagename[128]; // image that should be shown when damaged + unsigned width[H2_MIPLEVELS], height[H2_MIPLEVELS]; + unsigned offsets[H2_MIPLEVELS]; + int flags; + int contents; + int value; + float scale_x, scale_y; + int mip_scale; + + // detail texturing info + char dt_name[128]; // detailed texture name + float dt_scale_x, dt_scale_y; + float dt_u, dt_v; + float dt_alpha; + int dt_src_blend_mode, dt_dst_blend_mode; + + int flags2; + int unused[19]; // future expansion to maintain compatibility with h2 +} miptex_m32_t; + + + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 38 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// these definitions also need to be in q_shared.h! + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 2 // translucent, but not watery +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes + +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define CONTENTS_DEADMONSTER 0x4000000 +#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTS_LADDER 0x20000000 + + + +#define SURF_LIGHT 0x1 // value will hold the light strength + +#define SURF_SLICK 0x2 // effects game physics + +#define SURF_SKY 0x4 // don't draw, but add to skybox +#define SURF_WARP 0x8 // turbulent water warp +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 // scroll towards angle +#define SURF_NODRAW 0x80 // don't bother referencing the texture + +#define SURF_HINT 0x100 // make a primary bsp splitter +#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes + + + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; diff --git a/tools/quake2/common/scriplib.c b/tools/quake2/common/scriplib.c new file mode 100644 index 00000000..986f381c --- /dev/null +++ b/tools/quake2/common/scriplib.c @@ -0,0 +1,296 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// scriplib.c + +#include "cmdlib.h" +#include "inout.h" +#include "scriplib.h" + +/* +============================================================================= + + PARSING STUFF + +============================================================================= +*/ + +typedef struct +{ + char filename[1024]; + char *buffer,*script_p,*end_p; + int line; +} script_t; + +#define MAX_INCLUDES 8 +script_t scriptstack[MAX_INCLUDES]; +script_t *script; +int scriptline; + +char token[MAXTOKEN]; +qboolean endofscript; +qboolean tokenready; // only true if UnGetToken was just called + +/* +============== +AddScriptToStack +============== +*/ +void AddScriptToStack (char *filename) +{ + int size; + + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, ExpandPath (filename) ); + + size = LoadFile (script->filename, (void **)&script->buffer); + + printf ("entering %s\n", script->filename); + + script->line = 1; + + script->script_p = script->buffer; + script->end_p = script->buffer + size; +} + + +/* +============== +LoadScriptFile +============== +*/ +void LoadScriptFile (char *filename) +{ + script = scriptstack; + AddScriptToStack (filename); + + endofscript = false; + tokenready = false; +} + + +/* +============== +ParseFromMemory +============== +*/ +void ParseFromMemory (char *buffer, int size) +{ + script = scriptstack; + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, "memory buffer" ); + + script->buffer = buffer; + script->line = 1; + script->script_p = script->buffer; + script->end_p = script->buffer + size; + + endofscript = false; + tokenready = false; +} + + +/* +============== +UnGetToken + +Signals that the current token was not used, and should be reported +for the next GetToken. Note that + +GetToken (true); +UnGetToken (); +GetToken (false); + +could cross a line boundary. +============== +*/ +void UnGetToken (void) +{ + tokenready = true; +} + + +qboolean EndOfScript (qboolean crossline) +{ + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + + if (!strcmp (script->filename, "memory buffer")) + { + endofscript = true; + return false; + } + + free (script->buffer); + if (script == scriptstack+1) + { + endofscript = true; + return false; + } + script--; + scriptline = script->line; + printf ("returning to %s\n", script->filename); + return GetToken (crossline); +} + +/* +============== +GetToken +============== +*/ +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (tokenready) // is a token allready waiting? + { + tokenready = false; + return true; + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + +// +// skip space +// +skipspace: + while (*script->script_p <= 32) + { + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + if (*script->script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + scriptline = script->line++; + } + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + + // ; # // comments + if (*script->script_p == ';' || *script->script_p == '#' + || ( script->script_p[0] == '/' && script->script_p[1] == '/') ) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script->script_p++ != '\n') + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + goto skipspace; + } + + // /* */ comments + if (script->script_p[0] == '/' && script->script_p[1] == '*') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + script->script_p+=2; + while (script->script_p[0] != '*' && script->script_p[1] != '/') + { + script->script_p++; + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + } + script->script_p += 2; + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script->script_p == '"') + { + // quoted token + script->script_p++; + while (*script->script_p != '"') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + script->script_p++; + } + else // regular token + while ( *script->script_p > 32 && *script->script_p != ';') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + + *token_p = 0; + + if (!strcmp (token, "$include")) + { + GetToken (false); + AddScriptToStack (token); + return GetToken (crossline); + } + + return true; +} + + +/* +============== +TokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script->script_p; + + if (search_p >= script->end_p) + return false; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + search_p++; + if (search_p == script->end_p) + return false; + + } + + if (*search_p == ';') + return false; + + return true; +} + + diff --git a/tools/quake2/common/scriplib.h b/tools/quake2/common/scriplib.h new file mode 100644 index 00000000..05b67ce0 --- /dev/null +++ b/tools/quake2/common/scriplib.h @@ -0,0 +1,43 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// scriplib.h + +#ifndef __CMDLIB__ +#include "cmdlib.h" +#endif + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern char *scriptbuffer,*script_p,*scriptend_p; +extern int grabbed; +extern int scriptline; +extern qboolean endofscript; + + +void LoadScriptFile (char *filename); +void ParseFromMemory (char *buffer, int size); + +qboolean GetToken (qboolean crossline); +void UnGetToken (void); +qboolean TokenAvailable (void); + + diff --git a/tools/quake2/common/threads.c b/tools/quake2/common/threads.c new file mode 100644 index 00000000..9de00199 --- /dev/null +++ b/tools/quake2/common/threads.c @@ -0,0 +1,622 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIN32 +// The below define is necessary to use +// pthreads extensions like pthread_mutexattr_settype +#define _GNU_SOURCE +#include +#endif + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include "q2_threads.h" + +#define MAX_THREADS 64 + +int dispatch; +int workcount; +int oldf; +qboolean pacifier; + +qboolean threaded; + +/* +============= +GetThreadWork + +============= +*/ +int GetThreadWork (void) +{ + int r; + int f; + + ThreadLock (); + + if (dispatch == workcount) + { + ThreadUnlock (); + return -1; + } + + f = 10*dispatch / workcount; + if (f != oldf) + { + oldf = f; + if (pacifier) + { + Sys_Printf ("%i...", f); + fflush( stdout ); /* ydnar */ + } + } + + r = dispatch; + dispatch++; + ThreadUnlock (); + + return r; +} + + +void (*workfunction) (int); + +void ThreadWorkerFunction (int threadnum) +{ + int work; + + while (1) + { + work = GetThreadWork (); + if (work == -1) + break; + //Sys_FPrintf( SYS_VRB,"thread %i, work %i\n", threadnum, work); + workfunction(work); + } +} + +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + if (numthreads == -1) + ThreadSetDefault (); + workfunction = func; + RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); +} + + +/* +=================================================================== + +WIN32 + +=================================================================== +*/ +#ifdef _WIN32 + +#define USED + +#include + +// Setting default Threads to 1 +int numthreads = 1; +CRITICAL_SECTION crit; +static int enter; + +void ThreadSetDefault (void) +{ + SYSTEM_INFO info; + + if (numthreads == -1) // not set manually + { + GetSystemInfo (&info); + numthreads = info.dwNumberOfProcessors; + if (numthreads < 1 || numthreads > 32) + numthreads = 1; + } + + Sys_Printf ("%i threads\n", numthreads); +} + + +void ThreadLock (void) +{ + if (!threaded) + return; + EnterCriticalSection (&crit); + if (enter) + Error ("Recursive ThreadLock\n"); + enter = 1; +} + +void ThreadUnlock (void) +{ + if (!threaded) + return; + if (!enter) + Error ("ThreadUnlock without lock\n"); + enter = 0; + LeaveCriticalSection (&crit); +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int threadid[MAX_THREADS]; + HANDLE threadhandle[MAX_THREADS]; + int i; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + // + // run threads in parallel + // + InitializeCriticalSection (&crit); + + if (numthreads == 1) + { // use same thread + func (0); + } + else + { + for (i=0 ; i + +pthread_mutex_t *my_mutex; + +void ThreadLock (void) +{ + if (my_mutex) + pthread_mutex_lock (my_mutex); +} + +void ThreadUnlock (void) +{ + if (my_mutex) + pthread_mutex_unlock (my_mutex); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + pthread_t work_threads[MAX_THREADS]; + pthread_addr_t status; + pthread_attr_t attrib; + pthread_mutexattr_t mattrib; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + if (pacifier) + setbuf (stdout, NULL); + + if (!my_mutex) + { + my_mutex = safe_malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); + } + + if (pthread_attr_create (&attrib) == -1) + Error ("pthread_attr_create failed"); + if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) + Error ("pthread_attr_setstacksize failed"); + + for (i=0 ; i +#include +#include +#include + + +int numthreads = -1; +abilock_t lck; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) + numthreads = prctl(PR_MAXPPROCS); + Sys_Printf ("%i threads\n", numthreads); + usconfig (CONF_INITUSERS, numthreads); +} + + +void ThreadLock (void) +{ + spin_lock (&lck); +} + +void ThreadUnlock (void) +{ + release_lock (&lck); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int pid[MAX_THREADS]; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + if (pacifier) + setbuf (stdout, NULL); + + init_lock (&lck); + + for (i=0 ; i 1) + Sys_Printf("threads: %d\n", numthreads); +} + +#include + +typedef struct pt_mutex_s +{ + pthread_t *owner; + pthread_mutex_t a_mutex; + pthread_cond_t cond; + unsigned int lock; +} pt_mutex_t; + +pt_mutex_t global_lock; + +void ThreadLock(void) +{ + pt_mutex_t *pt_mutex = &global_lock; + + if(!threaded) + return; + + pthread_mutex_lock(&pt_mutex->a_mutex); + if(pthread_equal(pthread_self(), (pthread_t)&pt_mutex->owner)) + pt_mutex->lock++; + else + { + if((!pt_mutex->owner) && (pt_mutex->lock == 0)) + { + pt_mutex->owner = (pthread_t *)pthread_self(); + pt_mutex->lock = 1; + } + else + { + while(1) + { + pthread_cond_wait(&pt_mutex->cond, &pt_mutex->a_mutex); + if((!pt_mutex->owner) && (pt_mutex->lock == 0)) + { + pt_mutex->owner = (pthread_t *)pthread_self(); + pt_mutex->lock = 1; + break; + } + } + } + } + pthread_mutex_unlock(&pt_mutex->a_mutex); +} + +void ThreadUnlock(void) +{ + pt_mutex_t *pt_mutex = &global_lock; + + if(!threaded) + return; + + pthread_mutex_lock(&pt_mutex->a_mutex); + pt_mutex->lock--; + + if(pt_mutex->lock == 0) + { + pt_mutex->owner = NULL; + pthread_cond_signal(&pt_mutex->cond); + } + + pthread_mutex_unlock(&pt_mutex->a_mutex); +} + +void recursive_mutex_init(pthread_mutexattr_t attribs) +{ + pt_mutex_t *pt_mutex = &global_lock; + + pt_mutex->owner = NULL; + if(pthread_mutex_init(&pt_mutex->a_mutex, &attribs) != 0) + Error("pthread_mutex_init failed\n"); + if(pthread_cond_init(&pt_mutex->cond, NULL) != 0) + Error("pthread_cond_init failed\n"); + + pt_mutex->lock = 0; +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + pthread_mutexattr_t mattrib; + pthread_t work_threads[MAX_THREADS]; + + int start, end; + int i=0, status=0; + + start = I_FloatTime (); + pacifier = showpacifier; + + dispatch = 0; + oldf = -1; + workcount = workcnt; + + if(numthreads == 1) + func(0); + else + { + threaded = true; + + if(pacifier) + setbuf(stdout, NULL); + + if(pthread_mutexattr_init(&mattrib) != 0) + Error("pthread_mutexattr_init failed"); +#if __GLIBC_MINOR__ == 1 + if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_FAST_NP) != 0) +#else + if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_ADAPTIVE_NP) != 0) +#endif + Error ("pthread_mutexattr_settype failed"); + recursive_mutex_init(mattrib); + + for (i=0 ; i +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "trilib.h" + +// on disk representation of a face + + +#define FLOAT_START 99999.0 +#define FLOAT_END -FLOAT_START +#define MAGIC 123322 + +//#define NOISY 1 + +typedef struct { + float v[3]; +} vector; + +typedef struct +{ + vector n; /* normal */ + vector p; /* point */ + vector c; /* color */ + float u; /* u */ + float v; /* v */ +} aliaspoint_t; + +typedef struct { + aliaspoint_t pt[3]; +} tf_triangle; + + +void ByteSwapTri (tf_triangle *tri) +{ + int i; + + for (i=0 ; iverts[j][k] = tri.pt[j].p.v[k]; + } + } + + ptri++; + + if ((ptri - *pptri) >= MAXTRIANGLES) + Error ("Error: too many triangles; increase MAXTRIANGLES\n"); + } + } + + *numtriangles = ptri - *pptri; + + fclose (input); +} + diff --git a/tools/quake2/common/trilib.h b/tools/quake2/common/trilib.h new file mode 100644 index 00000000..406ae1d9 --- /dev/null +++ b/tools/quake2/common/trilib.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// +// trilib.h: header file for loading triangles from an Alias triangle file +// +#define MAXTRIANGLES 2048 + +typedef struct { + vec3_t verts[3]; +} triangle_t; + +void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles); + diff --git a/tools/quake2/q2map/brushbsp.c b/tools/quake2/q2map/brushbsp.c new file mode 100644 index 00000000..64ebd48e --- /dev/null +++ b/tools/quake2/q2map/brushbsp.c @@ -0,0 +1,1329 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + + +int c_nodes; +int c_nonvis; +int c_active_brushes; + +// if a brush just barely pokes onto the other side, +// let it slide by without chopping +#define PLANESIDE_EPSILON 0.001 +//0.1 + +#define PSIDE_FRONT 1 +#define PSIDE_BACK 2 +#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK) +#define PSIDE_FACING 4 + + +void FindBrushInTree (node_t *node, int brushnum) +{ + bspbrush_t *b; + + if (node->planenum == PLANENUM_LEAF) + { + for (b=node->brushlist ; b ; b=b->next) + if (b->original->brushnum == brushnum) + Sys_Printf ("here\n"); + return; + } + FindBrushInTree (node->children[0], brushnum); + FindBrushInTree (node->children[1], brushnum); +} + +//================================================== + +/* +================ +DrawBrushList +================ +*/ +void DrawBrushList (bspbrush_t *brush, node_t *node) +{ + int i; + side_t *s; + + GLS_BeginScene (); + for ( ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + if (!s->winding) + continue; + if (s->texinfo == TEXINFO_NODE) + GLS_Winding (s->winding, 1); + else if (!s->visible) + GLS_Winding (s->winding, 2); + else + GLS_Winding (s->winding, 0); + } + } + GLS_EndScene (); +} + +/* +================ +WriteBrushList +================ +*/ +void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis) +{ + int i; + side_t *s; + FILE *f; + + Sys_FPrintf( SYS_VRB, "writing %s\n", name); + f = SafeOpenWrite (name); + + for ( ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + if (!s->winding) + continue; + if (onlyvis && !s->visible) + continue; + OutputWinding (brush->sides[i].winding, f); + } + } + + fclose (f); +} + +void PrintBrush (bspbrush_t *brush) +{ + int i; + + Sys_Printf ("brush: %p\n", brush); + for (i=0;inumsides ; i++) + { + pw(brush->sides[i].winding); + Sys_Printf ("\n"); + } +} + +/* +================== +BoundBrush + +Sets the mins/maxs based on the windings +================== +*/ +void BoundBrush (bspbrush_t *brush) +{ + int i, j; + winding_t *w; + + ClearBounds (brush->mins, brush->maxs); + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + AddPointToBounds (w->p[j], brush->mins, brush->maxs); + } +} + +/* +================== +CreateBrushWindings + +================== +*/ +void CreateBrushWindings (bspbrush_t *brush) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + for (i=0 ; inumsides ; i++) + { + side = &brush->sides[i]; + plane = &mapplanes[side->planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; jnumsides && w; j++) + { + if (i == j) + continue; + if (brush->sides[j].bevel) + continue; + plane = &mapplanes[brush->sides[j].planenum^1]; + ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); + } + + side->winding = w; + } + + BoundBrush (brush); +} + +/* +================== +BrushFromBounds + +Creates a new axial brush +================== +*/ +bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs) +{ + bspbrush_t *b; + int i; + vec3_t normal; + vec_t dist; + + b = AllocBrush (6); + b->numsides = 6; + for (i=0 ; i<3 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = maxs[i]; + b->sides[i].planenum = FindFloatPlane (normal, dist); + + normal[i] = -1; + dist = -mins[i]; + b->sides[3+i].planenum = FindFloatPlane (normal, dist); + } + + CreateBrushWindings (b); + + return b; +} + +/* +================== +BrushVolume + +================== +*/ +vec_t BrushVolume (bspbrush_t *brush) +{ + int i; + winding_t *w; + vec3_t corner; + vec_t d, area, volume; + plane_t *plane; + + if (!brush) + return 0; + + // grab the first valid point as the corner + + w = NULL; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (w) + break; + } + if (!w) + return 0; + VectorCopy (w->p[0], corner); + + // make tetrahedrons to all other faces + + volume = 0; + for ( ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + plane = &mapplanes[brush->sides[i].planenum]; + d = -(DotProduct (corner, plane->normal) - plane->dist); + area = WindingArea (w); + volume += d*area; + } + + volume /= 3; + return volume; +} + +/* +================ +CountBrushList +================ +*/ +int CountBrushList (bspbrush_t *brushes) +{ + int c; + + c = 0; + for ( ; brushes ; brushes = brushes->next) + c++; + return c; +} + +/* +================ +AllocTree +================ +*/ +tree_t *AllocTree (void) +{ + tree_t *tree; + + tree = malloc(sizeof(*tree)); + memset (tree, 0, sizeof(*tree)); + ClearBounds (tree->mins, tree->maxs); + + return tree; +} + +/* +================ +AllocNode +================ +*/ +node_t *AllocNode (void) +{ + node_t *node; + + node = malloc(sizeof(*node)); + memset (node, 0, sizeof(*node)); + + return node; +} + + +/* +================ +AllocBrush +================ +*/ +bspbrush_t *AllocBrush (int numsides) +{ + bspbrush_t *bb; + int c; + + c = (int)&(((bspbrush_t *)0)->sides[numsides]); + bb = malloc(c); + memset (bb, 0, c); + if (numthreads == 1) + c_active_brushes++; + return bb; +} + +/* +================ +FreeBrush +================ +*/ +void FreeBrush (bspbrush_t *brushes) +{ + int i; + + for (i=0 ; inumsides ; i++) + if (brushes->sides[i].winding) + FreeWinding(brushes->sides[i].winding); + free (brushes); + if (numthreads == 1) + c_active_brushes--; +} + + +/* +================ +FreeBrushList +================ +*/ +void FreeBrushList (bspbrush_t *brushes) +{ + bspbrush_t *next; + + for ( ; brushes ; brushes = next) + { + next = brushes->next; + + FreeBrush (brushes); + } +} + +/* +================== +CopyBrush + +Duplicates the brush, the sides, and the windings +================== +*/ +bspbrush_t *CopyBrush (bspbrush_t *brush) +{ + bspbrush_t *newbrush; + int size; + int i; + + size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); + + newbrush = AllocBrush (brush->numsides); + memcpy (newbrush, brush, size); + + for (i=0 ; inumsides ; i++) + { + if (brush->sides[i].winding) + newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); + } + + return newbrush; +} + + +/* +================== +PointInLeaf + +================== +*/ +node_t *PointInLeaf (node_t *node, vec3_t point) +{ + vec_t d; + plane_t *plane; + + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (point, plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return node; +} + +//======================================================== + +/* +============== +BoxOnPlaneSide + +Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH +============== +*/ +int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane) +{ + int side; + int i; + vec3_t corners[2]; + vec_t dist1, dist2; + + // axial planes are easy + if (plane->type < 3) + { + side = 0; + if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON) + side |= PSIDE_FRONT; + if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON) + side |= PSIDE_BACK; + return side; + } + + // create the proper leading and trailing verts for the box + + for (i=0 ; i<3 ; i++) + { + if (plane->normal[i] < 0) + { + corners[0][i] = mins[i]; + corners[1][i] = maxs[i]; + } + else + { + corners[1][i] = mins[i]; + corners[0][i] = maxs[i]; + } + } + + dist1 = DotProduct (plane->normal, corners[0]) - plane->dist; + dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; + side = 0; + if (dist1 >= PLANESIDE_EPSILON) + side = PSIDE_FRONT; + if (dist2 < PLANESIDE_EPSILON) + side |= PSIDE_BACK; + + return side; +} + +/* +============ +QuickTestBrushToPlanenum + +============ +*/ +int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits) +{ + int i, num; + plane_t *plane; + int s; + + *numsplits = 0; + + // if the brush actually uses the planenum, + // we can tell the side for sure + for (i=0 ; inumsides ; i++) + { + num = brush->sides[i].planenum; + if (num >= 0x10000) + Error ("bad planenum"); + if (num == planenum) + return PSIDE_BACK|PSIDE_FACING; + if (num == (planenum ^ 1) ) + return PSIDE_FRONT|PSIDE_FACING; + } + + // box on plane side + plane = &mapplanes[planenum]; + s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); + + // if both sides, count the visible faces split + if (s == PSIDE_BOTH) + { + *numsplits += 3; + } + + return s; +} + +/* +============ +TestBrushToPlanenum + +============ +*/ +int TestBrushToPlanenum (bspbrush_t *brush, int planenum, + int *numsplits, qboolean *hintsplit, int *epsilonbrush) +{ + int i, j, num; + plane_t *plane; + int s; + winding_t *w; + vec_t d, d_front, d_back; + int front, back; + + *numsplits = 0; + *hintsplit = false; + + // if the brush actually uses the planenum, + // we can tell the side for sure + for (i=0 ; inumsides ; i++) + { + num = brush->sides[i].planenum; + if (num >= 0x10000) + Error ("bad planenum"); + if (num == planenum) + return PSIDE_BACK|PSIDE_FACING; + if (num == (planenum ^ 1) ) + return PSIDE_FRONT|PSIDE_FACING; + } + + // box on plane side + plane = &mapplanes[planenum]; + s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); + + if (s != PSIDE_BOTH) + return s; + +// if both sides, count the visible faces split + d_front = d_back = 0; + + for (i=0 ; inumsides ; i++) + { + if (brush->sides[i].texinfo == TEXINFO_NODE) + continue; // on node, don't worry about splits + if (!brush->sides[i].visible) + continue; // we don't care about non-visible + w = brush->sides[i].winding; + if (!w) + continue; + front = back = 0; + for (j=0 ; jnumpoints; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > d_front) + d_front = d; + if (d < d_back) + d_back = d; + + if (d > 0.1) // PLANESIDE_EPSILON) + front = 1; + if (d < -0.1) // PLANESIDE_EPSILON) + back = 1; + } + if (front && back) + { + if ( !(brush->sides[i].surf & SURF_SKIP) ) + { + (*numsplits)++; + if (brush->sides[i].surf & SURF_HINT) + *hintsplit = true; + } + } + } + + if ( (d_front > 0.0 && d_front < 1.0) + || (d_back < 0.0 && d_back > -1.0) ) + (*epsilonbrush)++; + +#if 0 + if (*numsplits == 0) + { // didn't really need to be split + if (front) + s = PSIDE_FRONT; + else if (back) + s = PSIDE_BACK; + else + s = 0; + } +#endif + + return s; +} + +//======================================================== + +/* +================ +WindingIsTiny + +Returns true if the winding would be crunched out of +existance by the vertex snapping. +================ +*/ +#define EDGE_LENGTH 0.2 +qboolean WindingIsTiny (winding_t *w) +{ +#if 0 + if (WindingArea (w) < 1) + return true; + return false; +#else + int i, j; + vec_t len; + vec3_t delta; + int edges; + + edges = 0; + for (i=0 ; inumpoints ; i++) + { + j = i == w->numpoints - 1 ? 0 : i+1; + VectorSubtract (w->p[j], w->p[i], delta); + len = (float) VectorLength (delta); + if (len > EDGE_LENGTH) + { + if (++edges == 3) + return false; + } + } + return true; +#endif +} + +/* +================ +WindingIsHuge + +Returns true if the winding still has one of the points +from basewinding for plane +================ +*/ +qboolean WindingIsHuge (winding_t *w) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->p[i][j] < -8000 || w->p[i][j] > 8000) + return true; + } + return false; +} + +//============================================================ + +/* +================ +Leafnode +================ +*/ +void LeafNode (node_t *node, bspbrush_t *brushes) +{ + bspbrush_t *b; + int i; + + node->planenum = PLANENUM_LEAF; + node->contents = 0; + + for (b=brushes ; b ; b=b->next) + { + // if the brush is solid and all of its sides are on nodes, + // it eats everything + if (b->original->contents & CONTENTS_SOLID) + { + for (i=0 ; inumsides ; i++) + if (b->sides[i].texinfo != TEXINFO_NODE) + break; + if (i == b->numsides) + { + node->contents = CONTENTS_SOLID; + break; + } + } + node->contents |= b->original->contents; + } + + node->brushlist = brushes; +} + + +//============================================================ + +void CheckPlaneAgainstParents (int pnum, node_t *node) +{ + node_t *p; + + for (p=node->parent ; p ; p=p->parent) + { + if (p->planenum == pnum) + Error ("Tried parent"); + } +} + +qboolean CheckPlaneAgainstVolume (int pnum, node_t *node) +{ + bspbrush_t *front, *back; + qboolean good; + + SplitBrush (node->volume, pnum, &front, &back); + + good = (front && back); + + if (front) + FreeBrush (front); + if (back) + FreeBrush (back); + + return good; +} + +/* +================ +SelectSplitSide + +Using a hueristic, choses one of the sides out of the brushlist +to partition the brushes with. +Returns NULL if there are no valid planes to split with.. +================ +*/ +side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node) +{ + int value, bestvalue; + bspbrush_t *brush, *test; + side_t *side, *bestside; + int i, j, pass, numpasses; + int pnum; + int s; + int front, back, both, facing, splits; + int bsplits; + int bestsplits; + int epsilonbrush; + qboolean hintsplit; + + bestside = NULL; + bestvalue = -99999; + bestsplits = 0; + + // the search order goes: visible-structural, visible-detail, + // nonvisible-structural, nonvisible-detail. + // If any valid plane is available in a pass, no further + // passes will be tried. + numpasses = 4; + for (pass = 0 ; pass < numpasses ; pass++) + { + for (brush = brushes ; brush ; brush=brush->next) + { + if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) ) + continue; + if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) ) + continue; + for (i=0 ; inumsides ; i++) + { + side = brush->sides + i; + if (side->bevel) + continue; // never use a bevel as a spliter + if (!side->winding) + continue; // nothing visible, so it can't split + if (side->texinfo == TEXINFO_NODE) + continue; // allready a node splitter + if (side->tested) + continue; // we allready have metrics for this plane + if (side->surf & SURF_SKIP) + continue; // skip surfaces are never chosen + if ( side->visible ^ (pass<2) ) + continue; // only check visible faces on first pass + + pnum = side->planenum; + pnum &= ~1; // allways use positive facing plane + + CheckPlaneAgainstParents (pnum, node); + + if (!CheckPlaneAgainstVolume (pnum, node)) + continue; // would produce a tiny volume + + front = 0; + back = 0; + both = 0; + facing = 0; + splits = 0; + epsilonbrush = 0; + + for (test = brushes ; test ; test=test->next) + { + s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush); + + splits += bsplits; + if (bsplits && (s&PSIDE_FACING) ) + Error ("PSIDE_FACING with splits"); + + test->testside = s; + // if the brush shares this face, don't bother + // testing that facenum as a splitter again + if (s & PSIDE_FACING) + { + facing++; + for (j=0 ; jnumsides ; j++) + { + if ( (test->sides[j].planenum&~1) == pnum) + test->sides[j].tested = true; + } + } + if (s & PSIDE_FRONT) + front++; + if (s & PSIDE_BACK) + back++; + if (s == PSIDE_BOTH) + both++; + } + + // give a value estimate for using this plane + + value = 5*facing - 5*splits - abs(front-back); +// value = -5*splits; +// value = 5*facing - 5*splits; + if (mapplanes[pnum].type < 3) + value+=5; // axial is better + value -= epsilonbrush*1000; // avoid! + + // never split a hint side except with another hint + if (hintsplit && !(side->surf & SURF_HINT) ) + value = -9999999; + + // save off the side test so we don't need + // to recalculate it when we actually seperate + // the brushes + if (value > bestvalue) + { + bestvalue = value; + bestside = side; + bestsplits = splits; + for (test = brushes ; test ; test=test->next) + test->side = test->testside; + } + } + } + + // if we found a good plane, don't bother trying any + // other passes + if (bestside) + { + if (pass > 1) + { + if (numthreads == 1) + c_nonvis++; + } + if (pass > 0) + node->detail_seperator = true; // not needed for vis + break; + } + } + + // + // clear all the tested flags we set + // + for (brush = brushes ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + brush->sides[i].tested = false; + } + + return bestside; +} + + +/* +================== +BrushMostlyOnSide + +================== +*/ +int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane) +{ + int i, j; + winding_t *w; + vec_t d, max; + int side; + + max = 0; + side = PSIDE_FRONT; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > max) + { + max = d; + side = PSIDE_FRONT; + } + if (-d > max) + { + max = -d; + side = PSIDE_BACK; + } + } + } + return side; +} + +/* +================ +SplitBrush + +Generates two new brushes, leaving the original +unchanged +================ +*/ +void SplitBrush (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back) +{ + bspbrush_t *b[2]; + int i, j; + winding_t *w, *cw[2], *midwinding; + plane_t *plane, *plane2; + side_t *s, *cs; + float d, d_front, d_back; + + *front = *back = NULL; + plane = &mapplanes[planenum]; + + // check all points + d_front = d_back = 0; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > 0 && d > d_front) + d_front = d; + if (d < 0 && d < d_back) + d_back = d; + } + } + if (d_front < 0.1) // PLANESIDE_EPSILON) + { // only on back + *back = CopyBrush (brush); + return; + } + if (d_back > -0.1) // PLANESIDE_EPSILON) + { // only on front + *front = CopyBrush (brush); + return; + } + + // create a new winding from the split plane + + w = BaseWindingForPlane (plane->normal, plane->dist); + for (i=0 ; inumsides && w ; i++) + { + plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; + ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); + } + + if (!w || WindingIsTiny (w) ) + { // the brush isn't really split + int side; + + side = BrushMostlyOnSide (brush, plane); + if (side == PSIDE_FRONT) + *front = CopyBrush (brush); + if (side == PSIDE_BACK) + *back = CopyBrush (brush); + return; + } + + if (WindingIsHuge (w)) + { + Sys_FPrintf( SYS_VRB, "WARNING: huge winding\n"); + } + + midwinding = w; + + // split it for real + + for (i=0 ; i<2 ; i++) + { + b[i] = AllocBrush (brush->numsides+1); + b[i]->original = brush->original; + } + + // split all the current windings + + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + w = s->winding; + if (!w) + continue; + ClipWindingEpsilon (w, plane->normal, plane->dist, + 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); + for (j=0 ; j<2 ; j++) + { + if (!cw[j]) + continue; +#if 0 + if (WindingIsTiny (cw[j])) + { + FreeWinding (cw[j]); + continue; + } +#endif + cs = &b[j]->sides[b[j]->numsides]; + b[j]->numsides++; + *cs = *s; +// cs->planenum = s->planenum; +// cs->texinfo = s->texinfo; +// cs->visible = s->visible; +// cs->original = s->original; + cs->winding = cw[j]; + cs->tested = false; + } + } + + + // see if we have valid polygons on both sides + + for (i=0 ; i<2 ; i++) + { + BoundBrush (b[i]); + for (j=0 ; j<3 ; j++) + { + if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096) + { + Sys_FPrintf( SYS_VRB, "bogus brush after clip\n"); + break; + } + } + + if (b[i]->numsides < 3 || j < 3) + { + FreeBrush (b[i]); + b[i] = NULL; + } + } + + if ( !(b[0] && b[1]) ) + { + if (!b[0] && !b[1]) + Sys_FPrintf( SYS_VRB, "split removed brush\n"); + else + Sys_FPrintf( SYS_VRB, "split not on both sides\n"); + if (b[0]) + { + FreeBrush (b[0]); + *front = CopyBrush (brush); + } + if (b[1]) + { + FreeBrush (b[1]); + *back = CopyBrush (brush); + } + return; + } + + // add the midwinding to both sides + for (i=0 ; i<2 ; i++) + { + cs = &b[i]->sides[b[i]->numsides]; + b[i]->numsides++; + + cs->planenum = planenum^i^1; + cs->texinfo = TEXINFO_NODE; + cs->visible = false; + cs->tested = false; + if (i==0) + cs->winding = CopyWinding (midwinding); + else + cs->winding = midwinding; + } + +{ + vec_t v1; + int i; + + for (i=0 ; i<2 ; i++) + { + v1 = BrushVolume (b[i]); + if (v1 < 1.0) + { + FreeBrush (b[i]); + b[i] = NULL; + Sys_FPrintf( SYS_VRB, "tiny volume after clip\n"); + } + } +} + + *front = b[0]; + *back = b[1]; +} + +/* +================ +SplitBrushList +================ +*/ +void SplitBrushList (bspbrush_t *brushes, + node_t *node, bspbrush_t **front, bspbrush_t **back) +{ + bspbrush_t *brush, *newbrush, *newbrush2; + side_t *side; + int sides; + int i; + + *front = *back = NULL; + + for (brush = brushes ; brush ; brush=brush->next) + { + sides = brush->side; + + if (sides == PSIDE_BOTH) + { // split into two brushes + SplitBrush (brush, node->planenum, &newbrush, &newbrush2); + if (newbrush) + { + newbrush->next = *front; + *front = newbrush; + } + if (newbrush2) + { + newbrush2->next = *back; + *back = newbrush2; + } + continue; + } + + newbrush = CopyBrush (brush); + + // if the planenum is actualy a part of the brush + // find the plane and flag it as used so it won't be tried + // as a splitter again + if (sides & PSIDE_FACING) + { + for (i=0 ; inumsides ; i++) + { + side = newbrush->sides + i; + if ( (side->planenum& ~1) == node->planenum) + side->texinfo = TEXINFO_NODE; + } + } + + + if (sides & PSIDE_FRONT) + { + newbrush->next = *front; + *front = newbrush; + continue; + } + if (sides & PSIDE_BACK) + { + newbrush->next = *back; + *back = newbrush; + continue; + } + } +} + + +/* +================ +BuildTree_r +================ +*/ +node_t *BuildTree_r (node_t *node, bspbrush_t *brushes) +{ + node_t *newnode; + side_t *bestside; + int i; + bspbrush_t *children[2]; + + if (numthreads == 1) + c_nodes++; + + if (drawflag) + DrawBrushList (brushes, node); + + // find the best plane to use as a splitter + bestside = SelectSplitSide (brushes, node); + if (!bestside) + { + // leaf node + node->side = NULL; + node->planenum = -1; + LeafNode (node, brushes); + return node; + } + + // this is a splitplane node + node->side = bestside; + node->planenum = bestside->planenum & ~1; // always use front facing + + SplitBrushList (brushes, node, &children[0], &children[1]); + FreeBrushList (brushes); + + // allocate children before recursing + for (i=0 ; i<2 ; i++) + { + newnode = AllocNode (); + newnode->parent = node; + node->children[i] = newnode; + } + + SplitBrush (node->volume, node->planenum, &node->children[0]->volume, + &node->children[1]->volume); + + // recursively process children + for (i=0 ; i<2 ; i++) + { + node->children[i] = BuildTree_r (node->children[i], children[i]); + } + + return node; +} + +//=========================================================== + +/* +================= +BrushBSP + +The incoming list will be freed before exiting +================= +*/ +tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs) +{ + node_t *node; + bspbrush_t *b; + int c_faces, c_nonvisfaces; + int c_brushes; + tree_t *tree; + int i; + vec_t volume; + + Sys_FPrintf( SYS_VRB, "--- BrushBSP ---\n"); + + tree = AllocTree (); + + c_faces = 0; + c_nonvisfaces = 0; + c_brushes = 0; + for (b=brushlist ; b ; b=b->next) + { + c_brushes++; + + volume = BrushVolume (b); + if (volume < microvolume) + { + Sys_Printf ("WARNING: entity %i, brush %i: microbrush\n", + b->original->entitynum, b->original->brushnum); + } + + for (i=0 ; inumsides ; i++) + { + if (b->sides[i].bevel) + continue; + if (!b->sides[i].winding) + continue; + if (b->sides[i].texinfo == TEXINFO_NODE) + continue; + if (b->sides[i].visible) + c_faces++; + else + c_nonvisfaces++; + } + + AddPointToBounds (b->mins, tree->mins, tree->maxs); + AddPointToBounds (b->maxs, tree->mins, tree->maxs); + } + + Sys_FPrintf( SYS_VRB, "%5i brushes\n", c_brushes); + Sys_FPrintf( SYS_VRB, "%5i visible faces\n", c_faces); + Sys_FPrintf( SYS_VRB, "%5i nonvisible faces\n", c_nonvisfaces); + + c_nodes = 0; + c_nonvis = 0; + node = AllocNode (); + + node->volume = BrushFromBounds (mins, maxs); + + tree->headnode = node; + + node = BuildTree_r (node, brushlist); + Sys_FPrintf( SYS_VRB, "%5i visible nodes\n", c_nodes/2 - c_nonvis); + Sys_FPrintf( SYS_VRB, "%5i nonvis nodes\n", c_nonvis); + Sys_FPrintf( SYS_VRB, "%5i leafs\n", (c_nodes+1)/2); +#if 0 +{ // debug code +static node_t *tnode; +vec3_t p; + +p[0] = -1469; +p[1] = -118; +p[2] = 119; +tnode = PointInLeaf (tree->headnode, p); +Sys_Printf ("contents: %i\n", tnode->contents); +p[0] = 0; +} +#endif + return tree; +} + diff --git a/tools/quake2/q2map/csg.c b/tools/quake2/q2map/csg.c new file mode 100644 index 00000000..6e750be7 --- /dev/null +++ b/tools/quake2/q2map/csg.c @@ -0,0 +1,634 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + +/* + +tag all brushes with original contents +brushes may contain multiple contents +there will be no brush overlap after csg phase + + + + +each side has a count of the other sides it splits + +the best split will be the one that minimizes the total split counts +of all remaining sides + +precalc side on plane table + +evaluate split side +{ +cost = 0 +for all sides + for all sides + get + if side splits side and splitside is on same child + cost++; +} + + + */ + +void SplitBrush2 (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back) +{ + SplitBrush (brush, planenum, front, back); +#if 0 + if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1) + (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1 + if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1) + (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1 +#endif +} + +/* +=============== +SubtractBrush + +Returns a list of brushes that remain after B is subtracted from A. +May by empty if A is contained inside B. + +The originals are undisturbed. +=============== +*/ +bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b) +{ // a - b = out (list) + int i; + bspbrush_t *front, *back; + bspbrush_t *out, *in; + + in = a; + out = NULL; + for (i=0 ; inumsides && in ; i++) + { + SplitBrush2 (in, b->sides[i].planenum, &front, &back); + if (in != a) + FreeBrush (in); + if (front) + { // add to list + front->next = out; + out = front; + } + in = back; + } + if (in) + FreeBrush (in); + else + { // didn't really intersect + FreeBrushList (out); + return a; + } + return out; +} + +/* +=============== +IntersectBrush + +Returns a single brush made up by the intersection of the +two provided brushes, or NULL if they are disjoint. + +The originals are undisturbed. +=============== +*/ +bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b) +{ + int i; + bspbrush_t *front, *back; + bspbrush_t *in; + + in = a; + for (i=0 ; inumsides && in ; i++) + { + SplitBrush2 (in, b->sides[i].planenum, &front, &back); + if (in != a) + FreeBrush (in); + if (front) + FreeBrush (front); + in = back; + } + + if (in == a) + return NULL; + + in->next = NULL; + return in; +} + + +/* +=============== +BrushesDisjoint + +Returns true if the two brushes definately do not intersect. +There will be false negatives for some non-axial combinations. +=============== +*/ +qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b) +{ + int i, j; + + // check bounding boxes + for (i=0 ; i<3 ; i++) + if (a->mins[i] >= b->maxs[i] + || a->maxs[i] <= b->mins[i]) + return true; // bounding boxes don't overlap + + // check for opposing planes + for (i=0 ; inumsides ; i++) + { + for (j=0 ; jnumsides ; j++) + { + if (a->sides[i].planenum == + (b->sides[j].planenum^1) ) + return true; // opposite planes, so not touching + } + } + + return false; // might intersect +} + +/* +=============== +IntersectionContents + +Returns a content word for the intersection of two brushes. +Some combinations will generate a combination (water + clip), +but most will be the stronger of the two contents. +=============== +*/ +int IntersectionContents (int c1, int c2) +{ + int out; + + out = c1 | c2; + + if (out & CONTENTS_SOLID) + out = CONTENTS_SOLID; + + return out; +} + + +int minplanenums[3]; +int maxplanenums[3]; + +/* +=============== +ClipBrushToBox + +Any planes shared with the box edge will be set to no texinfo +=============== +*/ +bspbrush_t *ClipBrushToBox (bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs) +{ + int i, j; + bspbrush_t *front, *back; + int p; + + for (j=0 ; j<2 ; j++) + { + if (brush->maxs[j] > clipmaxs[j]) + { + SplitBrush (brush, maxplanenums[j], &front, &back); + if (front) + FreeBrush (front); + brush = back; + if (!brush) + return NULL; + } + if (brush->mins[j] < clipmins[j]) + { + SplitBrush (brush, minplanenums[j], &front, &back); + if (back) + FreeBrush (back); + brush = front; + if (!brush) + return NULL; + } + } + + // remove any colinear faces + + for (i=0 ; inumsides ; i++) + { + p = brush->sides[i].planenum & ~1; + if (p == maxplanenums[0] || p == maxplanenums[1] + || p == minplanenums[0] || p == minplanenums[1]) + { + brush->sides[i].texinfo = TEXINFO_NODE; + brush->sides[i].visible = false; + } + } + return brush; +} + +/* +=============== +MakeBspBrushList +=============== +*/ +bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, + vec3_t clipmins, vec3_t clipmaxs) +{ + mapbrush_t *mb; + bspbrush_t *brushlist, *newbrush; + int i, j; + int c_faces; + int c_brushes; + int numsides; + int vis; + vec3_t normal; + float dist; + + for (i=0 ; i<2 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = clipmaxs[i]; + maxplanenums[i] = FindFloatPlane (normal, dist); + dist = clipmins[i]; + minplanenums[i] = FindFloatPlane (normal, dist); + } + + brushlist = NULL; + c_faces = 0; + c_brushes = 0; + + for (i=startbrush ; inumsides; + if (!numsides) + continue; + // make sure the brush has at least one face showing + vis = 0; + for (j=0 ; joriginal_sides[j].visible && mb->original_sides[j].winding) + vis++; +#if 0 + if (!vis) + continue; // no faces at all +#endif + // if the brush is outside the clip area, skip it + for (j=0 ; j<3 ; j++) + if (mb->mins[j] >= clipmaxs[j] + || mb->maxs[j] <= clipmins[j]) + break; + if (j != 3) + continue; + + // + // make a copy of the brush + // + newbrush = AllocBrush (mb->numsides); + newbrush->original = mb; + newbrush->numsides = mb->numsides; + memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t)); + for (j=0 ; jsides[j].winding) + newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding); + if (newbrush->sides[j].surf & SURF_HINT) + newbrush->sides[j].visible = true; // hints are always visible + } + VectorCopy (mb->mins, newbrush->mins); + VectorCopy (mb->maxs, newbrush->maxs); + + // + // carve off anything outside the clip box + // + newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs); + if (!newbrush) + continue; + + c_faces += vis; + c_brushes++; + + newbrush->next = brushlist; + brushlist = newbrush; + } + + return brushlist; +} + +/* +=============== +AddBspBrushListToTail +=============== +*/ +bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail) +{ + bspbrush_t *walk, *next; + + for (walk=list ; walk ; walk=next) + { // add to end of list + next = walk->next; + walk->next = NULL; + tail->next = walk; + tail = walk; + } + + return tail; +} + +/* +=========== +CullList + +Builds a new list that doesn't hold the given brush +=========== +*/ +bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip1) +{ + bspbrush_t *newlist; + bspbrush_t *next; + + newlist = NULL; + + for ( ; list ; list = next) + { + next = list->next; + if (list == skip1) + { + FreeBrush (list); + continue; + } + list->next = newlist; + newlist = list; + } + return newlist; +} + + +/* +================== +WriteBrushMap +================== +*/ +void WriteBrushMap (char *name, bspbrush_t *list) +{ + FILE *f; + side_t *s; + int i; + winding_t *w; + + Sys_Printf ("writing %s\n", name); + f = fopen (name, "wb"); + if (!f) + Error ("Can't write %s\b", name); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for ( ; list ; list=list->next ) + { + fprintf (f, "{\n"); + for (i=0,s=list->sides ; inumsides ; i++,s++) + { + w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + +} + +/* +================== +BrushGE + +Returns true if b1 is allowed to bite b2 +================== +*/ +qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2) +{ + // detail brushes never bite structural brushes + if ( (b1->original->contents & CONTENTS_DETAIL) + && !(b2->original->contents & CONTENTS_DETAIL) ) + return false; + if (b1->original->contents & CONTENTS_SOLID) + return true; + return false; +} + +/* +================= +ChopBrushes + +Carves any intersecting solid brushes into the minimum number +of non-intersecting brushes. +================= +*/ +bspbrush_t *ChopBrushes (bspbrush_t *head) +{ + bspbrush_t *b1, *b2, *next; + bspbrush_t *tail; + bspbrush_t *keep; + bspbrush_t *sub, *sub2; + int c1, c2; + + Sys_FPrintf( SYS_VRB, "---- ChopBrushes ----\n"); + Sys_FPrintf( SYS_VRB, "original brushes: %i\n", CountBrushList (head)); + +#if 0 + if (startbrush == 0) + WriteBrushList ("before.gl", head, false); +#endif + keep = NULL; + +newlist: + // find tail + if (!head) + return NULL; + for (tail=head ; tail->next ; tail=tail->next) + ; + + for (b1=head ; b1 ; b1=next) + { + next = b1->next; + for (b2=b1->next ; b2 ; b2 = b2->next) + { + if (BrushesDisjoint (b1, b2)) + continue; + + sub = NULL; + sub2 = NULL; + c1 = 999999; + c2 = 999999; + + if ( BrushGE (b2, b1) ) + { + sub = SubtractBrush (b1, b2); + if (sub == b1) + continue; // didn't really intersect + if (!sub) + { // b1 is swallowed by b2 + head = CullList (b1, b1); + goto newlist; + } + c1 = CountBrushList (sub); + } + + if ( BrushGE (b1, b2) ) + { + sub2 = SubtractBrush (b2, b1); + if (sub2 == b2) + continue; // didn't really intersect + if (!sub2) + { // b2 is swallowed by b1 + FreeBrushList (sub); + head = CullList (b1, b2); + goto newlist; + } + c2 = CountBrushList (sub2); + } + + if (!sub && !sub2) + continue; // neither one can bite + + // only accept if it didn't fragment + // (commening this out allows full fragmentation) + if (c1 > 1 && c2 > 1) + { + if (sub2) + FreeBrushList (sub2); + if (sub) + FreeBrushList (sub); + continue; + } + + if (c1 < c2) + { + if (sub2) + FreeBrushList (sub2); + tail = AddBrushListToTail (sub, tail); + head = CullList (b1, b1); + goto newlist; + } + else + { + if (sub) + FreeBrushList (sub); + tail = AddBrushListToTail (sub2, tail); + head = CullList (b1, b2); + goto newlist; + } + } + + if (!b2) + { // b1 is no longer intersecting anything, so keep it + b1->next = keep; + keep = b1; + } + } + + Sys_FPrintf( SYS_VRB, "output brushes: %i\n", CountBrushList (keep)); +#if 0 + { + WriteBrushList ("after.gl", keep, false); + WriteBrushMap ("after.map", keep); + } +#endif + return keep; +} + + +/* +================= +InitialBrushList +================= +*/ +bspbrush_t *InitialBrushList (bspbrush_t *list) +{ + bspbrush_t *b; + bspbrush_t *out, *newb; + int i; + + // only return brushes that have visible faces + out = NULL; + for (b=list ; b ; b=b->next) + { +#if 0 + for (i=0 ; inumsides ; i++) + if (b->sides[i].visible) + break; + if (i == b->numsides) + continue; +#endif + newb = CopyBrush (b); + newb->next = out; + out = newb; + + // clear visible, so it must be set by MarkVisibleFaces_r + // to be used in the optimized list + for (i=0 ; inumsides ; i++) + { + newb->sides[i].original = &b->sides[i]; +// newb->sides[i].visible = true; + b->sides[i].visible = false; + } + } + + return out; +} + +/* +================= +OptimizedBrushList +================= +*/ +bspbrush_t *OptimizedBrushList (bspbrush_t *list) +{ + bspbrush_t *b; + bspbrush_t *out, *newb; + int i; + + // only return brushes that have visible faces + out = NULL; + for (b=list ; b ; b=b->next) + { + for (i=0 ; inumsides ; i++) + if (b->sides[i].visible) + break; + if (i == b->numsides) + continue; + newb = CopyBrush (b); + newb->next = out; + out = newb; + } + +// WriteBrushList ("vis.gl", out, true); + + return out; +} diff --git a/tools/quake2/q2map/faces.c b/tools/quake2/q2map/faces.c new file mode 100644 index 00000000..0b7ba80f --- /dev/null +++ b/tools/quake2/q2map/faces.c @@ -0,0 +1,1076 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// faces.c + +#include "qbsp.h" + +/* + + some faces will be removed before saving, but still form nodes: + + the insides of sky volumes + meeting planes of different water current volumes + +*/ + +// undefine for dumb linear searches +#define USE_HASHING + +#define INTEGRAL_EPSILON 0.01 +#define POINT_EPSILON 0.5 +#define OFF_EPSILON 0.5 + +int c_merge; +int c_subdivide; + +int c_totalverts; +int c_uniqueverts; +int c_degenerate; +int c_tjunctions; +int c_faceoverflows; +int c_facecollapse; +int c_badstartverts; + +#define MAX_SUPERVERTS 512 +int superverts[MAX_SUPERVERTS]; +int numsuperverts; + +face_t *edgefaces[MAX_MAP_EDGES][2]; +int firstmodeledge = 1; +int firstmodelface; + +int c_tryedges; + +vec3_t edge_dir; +vec3_t edge_start; +vec_t edge_len; + +int num_edge_verts; +int edge_verts[MAX_MAP_VERTS]; + + +float subdivide_size = 240; + + +face_t *NewFaceFromFace (face_t *f); + +//=========================================================================== + +typedef struct hashvert_s +{ + struct hashvert_s *next; + int num; +} hashvert_t; + + +#define HASH_SIZE 64 + + +int vertexchain[MAX_MAP_VERTS]; // the next vertex in a hash chain +int hashverts[HASH_SIZE*HASH_SIZE]; // a vertex number, or 0 for no verts + +face_t *edgefaces[MAX_MAP_EDGES][2]; + +//============================================================================ + + +unsigned HashVec (vec3_t vec) +{ + int x, y; + + x = (4096 + (int)(vec[0]+0.5)) >> 7; + y = (4096 + (int)(vec[1]+0.5)) >> 7; + + if ( x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE ) + Error ("HashVec: point outside valid range"); + + return y*HASH_SIZE + x; +} + +#ifdef USE_HASHING +/* +============= +GetVertex + +Uses hashing +============= +*/ +int GetVertexnum (vec3_t in) +{ + int h; + int i; + float *p; + vec3_t vert; + int vnum; + + c_totalverts++; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(in[i] - Q_rint(in[i])) < INTEGRAL_EPSILON) + vert[i] = Q_rint(in[i]); + else + vert[i] = in[i]; + } + + h = HashVec (vert); + + for (vnum=hashverts[h] ; vnum ; vnum=vertexchain[vnum]) + { + p = dvertexes[vnum].point; + if ( fabs(p[0]-vert[0]) 4096) + Error ("GetVertexnum: outside +/- 4096"); + } + + // search for an existing vertex match + for (i=0, dv=dvertexes ; ipoint[j]; + if ( d > POINT_EPSILON || d < -POINT_EPSILON) + break; + } + if (j == 3) + return i; // a match + } + + // new point + if (numvertexes == MAX_MAP_VERTS) + Error ("MAX_MAP_VERTS"); + VectorCopy (v, dv->point); + numvertexes++; + c_uniqueverts++; + + return numvertexes-1; +} +#endif + + +/* +================== +FaceFromSuperverts + +The faces vertexes have beeb added to the superverts[] array, +and there may be more there than can be held in a face (MAXEDGES). + +If less, the faces vertexnums[] will be filled in, otherwise +face will reference a tree of split[] faces until all of the +vertexnums can be added. + +superverts[base] will become face->vertexnums[0], and the others +will be circularly filled in. +================== +*/ +void FaceFromSuperverts (node_t *node, face_t *f, int base) +{ + face_t *newf; + int remaining; + int i; + + remaining = numsuperverts; + while (remaining > MAXEDGES) + { // must split into two faces, because of vertex overload + c_faceoverflows++; + + newf = f->split[0] = NewFaceFromFace (f); + newf = f->split[0]; + newf->next = node->faces; + node->faces = newf; + + newf->numpoints = MAXEDGES; + for (i=0 ; ivertexnums[i] = superverts[(i+base)%numsuperverts]; + + f->split[1] = NewFaceFromFace (f); + f = f->split[1]; + f->next = node->faces; + node->faces = f; + + remaining -= (MAXEDGES-2); + base = (base+MAXEDGES-1)%numsuperverts; + } + + // copy the vertexes back to the face + f->numpoints = remaining; + for (i=0 ; ivertexnums[i] = superverts[(i+base)%numsuperverts]; +} + + +/* +================== +EmitFaceVertexes +================== +*/ +void EmitFaceVertexes (node_t *node, face_t *f) +{ + winding_t *w; + int i; + + if (f->merged || f->split[0] || f->split[1]) + return; + + w = f->w; + for (i=0 ; inumpoints ; i++) + { + if (noweld) + { // make every point unique + if (numvertexes == MAX_MAP_VERTS) + Error ("MAX_MAP_VERTS"); + superverts[i] = numvertexes; + VectorCopy (w->p[i], dvertexes[numvertexes].point); + numvertexes++; + c_uniqueverts++; + c_totalverts++; + } + else + superverts[i] = GetVertexnum (w->p[i]); + } + numsuperverts = w->numpoints; + + // this may fragment the face if > MAXEDGES + FaceFromSuperverts (node, f, 0); +} + +/* +================== +EmitVertexes_r +================== +*/ +void EmitVertexes_r (node_t *node) +{ + int i; + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + { + EmitFaceVertexes (node, f); + } + + for (i=0 ; i<2 ; i++) + EmitVertexes_r (node->children[i]); +} + + +#ifdef USE_HASHING +/* +========== +FindEdgeVerts + +Uses the hash tables to cut down to a small number +========== +*/ +void FindEdgeVerts (vec3_t v1, vec3_t v2) +{ + int x1, x2, y1, y2, t; + int x, y; + int vnum; + +#if 0 +{ + int i; + num_edge_verts = numvertexes-1; + for (i=0 ; i> 7; + y1 = (4096 + (int)(v1[1]+0.5)) >> 7; + x2 = (4096 + (int)(v2[0]+0.5)) >> 7; + y2 = (4096 + (int)(v2[1]+0.5)) >> 7; + + if (x1 > x2) + { + t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) + { + t = y1; + y1 = y2; + y2 = t; + } +#if 0 + x1--; + x2++; + y1--; + y2++; + if (x1 < 0) + x1 = 0; + if (x2 >= HASH_SIZE) + x2 = HASH_SIZE; + if (y1 < 0) + y1 = 0; + if (y2 >= HASH_SIZE) + y2 = HASH_SIZE; +#endif + num_edge_verts = 0; + for (x=x1 ; x <= x2 ; x++) + { + for (y=y1 ; y <= y2 ; y++) + { + for (vnum=hashverts[y*HASH_SIZE+x] ; vnum ; vnum=vertexchain[vnum]) + { + edge_verts[num_edge_verts++] = vnum; + } + } + } +} + +#else +/* +========== +FindEdgeVerts + +Forced a dumb check of everything +========== +*/ +void FindEdgeVerts (vec3_t v1, vec3_t v2) +{ + int i; + + num_edge_verts = numvertexes-1; + for (i=0 ; i= end) + continue; // off an end + VectorMA (edge_start, dist, edge_dir, exact); + VectorSubtract (p, exact, off); + error = VectorLength (off); + + if (fabs(error) > OFF_EPSILON) + continue; // not on the edge + + // break the edge + c_tjunctions++; + TestEdge (start, dist, p1, j, k+1); + TestEdge (dist, end, j, p2, k+1); + return; + } + + // the edge p1 to p2 is now free of tjunctions + if (numsuperverts >= MAX_SUPERVERTS) + Error ("MAX_SUPERVERTS"); + superverts[numsuperverts] = p1; + numsuperverts++; +} + +/* +================== +FixFaceEdges + +================== +*/ +void FixFaceEdges (node_t *node, face_t *f) +{ + int p1, p2; + int i; + vec3_t e2; + vec_t len; + int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS]; + int base; + + if (f->merged || f->split[0] || f->split[1]) + return; + + numsuperverts = 0; + + for (i=0 ; inumpoints ; i++) + { + p1 = f->vertexnums[i]; + p2 = f->vertexnums[(i+1)%f->numpoints]; + + VectorCopy (dvertexes[p1].point, edge_start); + VectorCopy (dvertexes[p2].point, e2); + + FindEdgeVerts (edge_start, e2); + + VectorSubtract (e2, edge_start, edge_dir); + len = VectorNormalize (edge_dir, edge_dir); + + start[i] = numsuperverts; + TestEdge (0, len, p1, p2, 0); + + count[i] = numsuperverts - start[i]; + } + + if (numsuperverts < 3) + { // entire face collapsed + f->numpoints = 0; + c_facecollapse++; + return; + } + + // we want to pick a vertex that doesn't have tjunctions + // on either side, which can cause artifacts on trifans, + // especially underwater + for (i=0 ; inumpoints ; i++) + { + if (count[i] == 1 && count[(i+f->numpoints-1)%f->numpoints] == 1) + break; + } + if (i == f->numpoints) + { + f->badstartvert = true; + c_badstartverts++; + base = 0; + } + else + { // rotate the vertex order + base = start[i]; + } + + // this may fragment the face if > MAXEDGES + FaceFromSuperverts (node, f, base); +} + +/* +================== +FixEdges_r +================== +*/ +void FixEdges_r (node_t *node) +{ + int i; + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + FixFaceEdges (node, f); + + for (i=0 ; i<2 ; i++) + FixEdges_r (node->children[i]); +} + +/* +=========== +FixTjuncs + +=========== +*/ +void FixTjuncs (node_t *headnode) +{ + // snap and merge all vertexes + Sys_FPrintf( SYS_VRB, "---- snap verts ----\n"); + memset (hashverts, 0, sizeof(hashverts)); + c_totalverts = 0; + c_uniqueverts = 0; + c_faceoverflows = 0; + EmitVertexes_r (headnode); + Sys_FPrintf( SYS_VRB, "%i unique from %i\n", c_uniqueverts, c_totalverts); + + // break edges on tjunctions + Sys_FPrintf( SYS_VRB, "---- tjunc ----\n"); + c_tryedges = 0; + c_degenerate = 0; + c_facecollapse = 0; + c_tjunctions = 0; + if (!notjunc) + FixEdges_r (headnode); + Sys_FPrintf( SYS_VRB, "%5i edges degenerated\n", c_degenerate); + Sys_FPrintf( SYS_VRB, "%5i faces degenerated\n", c_facecollapse); + Sys_FPrintf( SYS_VRB, "%5i edges added by tjunctions\n", c_tjunctions); + Sys_FPrintf( SYS_VRB, "%5i faces added by tjunctions\n", c_faceoverflows); + Sys_FPrintf( SYS_VRB, "%5i bad start verts\n", c_badstartverts); +} + + +//======================================================== + +int c_faces; + +face_t *AllocFace (void) +{ + face_t *f; + + f = malloc(sizeof(*f)); + memset (f, 0, sizeof(*f)); + c_faces++; + + return f; +} + +face_t *NewFaceFromFace (face_t *f) +{ + face_t *newf; + + newf = AllocFace (); + *newf = *f; + newf->merged = NULL; + newf->split[0] = newf->split[1] = NULL; + newf->w = NULL; + return newf; +} + +void FreeFace (face_t *f) +{ + if (f->w) + FreeWinding (f->w); + free (f); + c_faces--; +} + +//======================================================== + +/* +================== +GetEdge + +Called by writebsp. +Don't allow four way edges +================== +*/ +int GetEdge2 (int v1, int v2, face_t *f) +{ + dedge_t *edge; + int i; + + c_tryedges++; + + if (!noshare) + { + for (i=firstmodeledge ; i < numedges ; i++) + { + edge = &dedges[i]; + if (v1 == edge->v[1] && v2 == edge->v[0] + && edgefaces[i][0]->contents == f->contents) + { + if (edgefaces[i][1]) + // Sys_Printf ("WARNING: multiple backward edge\n"); + continue; + edgefaces[i][1] = f; + return -i; + } + #if 0 + if (v1 == edge->v[0] && v2 == edge->v[1]) + { + Sys_Printf ("WARNING: multiple forward edge\n"); + return i; + } + #endif + } + } + +// emit an edge + if (numedges >= MAX_MAP_EDGES) + Error ("numedges == MAX_MAP_EDGES"); + edge = &dedges[numedges]; + numedges++; + edge->v[0] = v1; + edge->v[1] = v2; + edgefaces[numedges-1][0] = f; + + return numedges-1; +} + +/* +=========================================================================== + +FACE MERGING + +=========================================================================== +*/ + +#define CONTINUOUS_EPSILON 0.001 + +/* +============= +TryMergeWinding + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal) +{ + vec_t *p1, *p2, *p3, *p4, *back; + winding_t *newf; + int i, j, k, l; + vec3_t normal, delta; + vec_t dot; + qboolean keep1, keep2; + + + // + // find a common edge + // + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for (i=0 ; inumpoints ; i++) + { + p1 = f1->p[i]; + p2 = f1->p[(i+1)%f1->numpoints]; + for (j=0 ; jnumpoints ; j++) + { + p3 = f2->p[j]; + p4 = f2->p[(j+1)%f2->numpoints]; + for (k=0 ; k<3 ; k++) + { + if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON) + break; + if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON) + break; + } + if (k==3) + break; + } + if (j < f2->numpoints) + break; + } + + if (i == f1->numpoints) + return NULL; // no matching edges + + // + // check slope of connected lines + // if the slopes are colinear, the point can be removed + // + back = f1->p[(i+f1->numpoints-1)%f1->numpoints]; + VectorSubtract (p1, back, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->p[(j+2)%f2->numpoints]; + VectorSubtract (back, p1, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + back = f1->p[(i+2)%f1->numpoints]; + VectorSubtract (back, p2, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->p[(j+f2->numpoints-1)%f2->numpoints]; + VectorSubtract (back, p2, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + // + // build the new polygon + // + newf = AllocWinding (f1->numpoints + f2->numpoints); + + // copy first polygon + for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) + { + if (k==(i+1)%f1->numpoints && !keep2) + continue; + + VectorCopy (f1->p[k], newf->p[newf->numpoints]); + newf->numpoints++; + } + + // copy second polygon + for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) + { + if (l==(j+1)%f2->numpoints && !keep1) + continue; + VectorCopy (f2->p[l], newf->p[newf->numpoints]); + newf->numpoints++; + } + + return newf; +} + +/* +============= +TryMerge + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +face_t *TryMerge (face_t *f1, face_t *f2, vec3_t planenormal) +{ + face_t *newf; + winding_t *nw; + + if (!f1->w || !f2->w) + return NULL; + if (f1->texinfo != f2->texinfo) + return NULL; + if (f1->planenum != f2->planenum) // on front and back sides + return NULL; + if (f1->contents != f2->contents) + return NULL; + + + nw = TryMergeWinding (f1->w, f2->w, planenormal); + if (!nw) + return NULL; + + c_merge++; + newf = NewFaceFromFace (f1); + newf->w = nw; + + f1->merged = newf; + f2->merged = newf; + + return newf; +} + +/* +=============== +MergeNodeFaces +=============== +*/ +void MergeNodeFaces (node_t *node) +{ + face_t *f1, *f2, *end; + face_t *merged; + plane_t *plane; + + plane = &mapplanes[node->planenum]; + merged = NULL; + + for (f1 = node->faces ; f1 ; f1 = f1->next) + { + if (f1->merged || f1->split[0] || f1->split[1]) + continue; + for (f2 = node->faces ; f2 != f1 ; f2=f2->next) + { + if (f2->merged || f2->split[0] || f2->split[1]) + continue; + merged = TryMerge (f1, f2, plane->normal); + if (!merged) + continue; + + // add merged to the end of the node face list + // so it will be checked against all the faces again + for (end = node->faces ; end->next ; end = end->next) + ; + merged->next = NULL; + end->next = merged; + break; + } + } +} + +//===================================================================== + +/* +=============== +SubdivideFace + +Chop up faces that are larger than we want in the surface cache +=============== +*/ +void SubdivideFace (node_t *node, face_t *f) +{ + float mins, maxs; + vec_t v; + int axis, i; + texinfo_t *tex; + vec3_t temp; + vec_t dist; + winding_t *w, *frontw, *backw; + + if (f->merged) + return; + +// special (non-surface cached) faces don't need subdivision + tex = &texinfo[f->texinfo]; + + if ( tex->flags & (SURF_WARP|SURF_SKY) ) + { + return; + } + + for (axis = 0 ; axis < 2 ; axis++) + { + while (1) + { + mins = 999999; + maxs = -999999; + + VectorCopy (tex->vecs[axis], temp); + w = f->w; + for (i=0 ; inumpoints ; i++) + { + v = DotProduct (w->p[i], temp); + if (v < mins) + mins = v; + if (v > maxs) + maxs = v; + } +#if 0 + if (maxs - mins <= 0) + Error ("zero extents"); +#endif + if (axis == 2) + { // allow double high walls + if (maxs - mins <= subdivide_size/* *2 */) + break; + } + else if (maxs - mins <= subdivide_size) + break; + + // split it + c_subdivide++; + + v = VectorNormalize (temp, temp); + + dist = (mins + subdivide_size - 16)/v; + + ClipWindingEpsilon (w, temp, dist, ON_EPSILON, &frontw, &backw); + if (!frontw || !backw) + Error ("SubdivideFace: didn't split the polygon"); + + f->split[0] = NewFaceFromFace (f); + f->split[0]->w = frontw; + f->split[0]->next = node->faces; + node->faces = f->split[0]; + + f->split[1] = NewFaceFromFace (f); + f->split[1]->w = backw; + f->split[1]->next = node->faces; + node->faces = f->split[1]; + + SubdivideFace (node, f->split[0]); + SubdivideFace (node, f->split[1]); + return; + } + } +} + +void SubdivideNodeFaces (node_t *node) +{ + face_t *f; + + for (f = node->faces ; f ; f=f->next) + { + SubdivideFace (node, f); + } +} + +//=========================================================================== + +int c_nodefaces; + + +/* +============ +FaceFromPortal + +============ +*/ +face_t *FaceFromPortal (portal_t *p, int pside) +{ + face_t *f; + side_t *side; + + side = p->side; + if (!side) + return NULL; // portal does not bridge different visible contents + + f = AllocFace (); + + f->texinfo = side->texinfo; + f->planenum = (side->planenum & ~1) | pside; + f->portal = p; + + if ( (p->nodes[pside]->contents & CONTENTS_WINDOW) + && VisibleContents(p->nodes[!pside]->contents^p->nodes[pside]->contents) == CONTENTS_WINDOW ) + return NULL; // don't show insides of windows + + if (pside) + { + f->w = ReverseWinding(p->winding); + f->contents = p->nodes[1]->contents; + } + else + { + f->w = CopyWinding(p->winding); + f->contents = p->nodes[0]->contents; + } + return f; +} + + +/* +=============== +MakeFaces_r + +If a portal will make a visible face, +mark the side that originally created it + + solid / empty : solid + solid / water : solid + water / empty : water + water / water : none +=============== +*/ +void MakeFaces_r (node_t *node) +{ + portal_t *p; + int s; + + // recurse down to leafs + if (node->planenum != PLANENUM_LEAF) + { + MakeFaces_r (node->children[0]); + MakeFaces_r (node->children[1]); + + // merge together all visible faces on the node + if (!nomerge) + MergeNodeFaces (node); + if (!nosubdiv) + SubdivideNodeFaces (node); + + return; + } + + // solid leafs never have visible faces + if (node->contents & CONTENTS_SOLID) + return; + + // see which portals are valid + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + + p->face[s] = FaceFromPortal (p, s); + if (p->face[s]) + { + c_nodefaces++; + p->face[s]->next = p->onnode->faces; + p->onnode->faces = p->face[s]; + } + } +} + +/* +============ +MakeFaces +============ +*/ +void MakeFaces (node_t *node) +{ + Sys_FPrintf( SYS_VRB, "--- MakeFaces ---\n"); + c_merge = 0; + c_subdivide = 0; + c_nodefaces = 0; + + MakeFaces_r (node); + + Sys_FPrintf( SYS_VRB, "%5i makefaces\n", c_nodefaces); + Sys_FPrintf( SYS_VRB, "%5i merged\n", c_merge); + Sys_FPrintf( SYS_VRB, "%5i subdivided\n", c_subdivide); +} diff --git a/tools/quake2/q2map/flow.c b/tools/quake2/q2map/flow.c new file mode 100644 index 00000000..9a34f6f9 --- /dev/null +++ b/tools/quake2/q2map/flow.c @@ -0,0 +1,787 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "qvis.h" + +/* + + each portal will have a list of all possible to see from first portal + + if (!thread->portalmightsee[portalnum]) + + portal mightsee + + for p2 = all other portals in leaf + get sperating planes + for all portals that might be seen by p2 + mark as unseen if not present in seperating plane + flood fill a new mightsee + save as passagemightsee + + + void CalcMightSee (leaf_t *leaf, +*/ + +int CountBits (byte *bits, int numbits) +{ + int i; + int c; + + c = 0; + for (i=0 ; i>3] & (1<<(i&7)) ) + c++; + + return c; +} + +int c_fullskip; +int c_portalskip, c_leafskip; +int c_vistest, c_mighttest; + +int c_chop, c_nochop; + +int active; + +void CheckStack (leaf_t *leaf, threaddata_t *thread) +{ + pstack_t *p, *p2; + + for (p=thread->pstack_head.next ; p ; p=p->next) + { +// printf ("="); + if (p->leaf == leaf) + Error ("CheckStack: leaf recursion"); + for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next) + if (p2->leaf == p->leaf) + Error ("CheckStack: late leaf recursion"); + } +// printf ("\n"); +} + + +winding_t *AllocStackWinding (pstack_t *stack) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (stack->freewindings[i]) + { + stack->freewindings[i] = 0; + return &stack->windings[i]; + } + } + + Error ("AllocStackWinding: failed"); + + return NULL; +} + +void FreeStackWinding (winding_t *w, pstack_t *stack) +{ + int i; + + i = w - stack->windings; + + if (i<0 || i>2) + return; // not from local + + if (stack->freewindings[i]) + Error ("FreeStackWinding: allready free"); + stack->freewindings[i] = 1; +} + +/* +============== +Vis_ChopWinding + +============== +*/ +winding_t *Vis_ChopWinding (winding_t *in, pstack_t *stack, plane_t *split) +{ + vec_t dists[128]; + int sides[128]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + + if (!counts[1]) + return in; // completely on front side + + if (!counts[0]) + { + FreeStackWinding (in, stack); + return NULL; + } + + sides[i] = sides[0]; + dists[i] = dists[0]; + + neww = AllocStackWinding (stack); + + neww->numpoints = 0; + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + +// free the original winding + FreeStackWinding (in, stack); + + return neww; +} + + +/* +============== +ClipToSeperators + +Source, pass, and target are an ordering of portals. + +Generates seperating planes canidates by taking two points from source and one +point from pass, and clips target by them. + +If target is totally clipped away, that portal can not be seen through. + +Normal clip keeps target on the same side as pass, which is correct if the +order goes source, pass, target. If the order goes pass, source, target then +flipclip should be set. +============== +*/ +winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack) +{ + int i, j, k, l; + plane_t plane; + vec3_t v1, v2; + float d; + vec_t length; + int counts[3]; + qboolean fliptest; + +// check all combinations + for (i=0 ; inumpoints ; i++) + { + l = (i+1)%source->numpoints; + VectorSubtract (source->points[l] , source->points[i], v1); + + // fing a vertex of pass that makes a plane that puts all of the + // vertexes of pass on the front side and all of the vertexes of + // source on the back side + for (j=0 ; jnumpoints ; j++) + { + VectorSubtract (pass->points[j], source->points[i], v2); + + plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; + plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; + plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; + + // if points don't make a valid plane, skip it + + length = plane.normal[0] * plane.normal[0] + + plane.normal[1] * plane.normal[1] + + plane.normal[2] * plane.normal[2]; + + if (length < ON_EPSILON) + continue; + + length = 1/sqrt(length); + + plane.normal[0] *= length; + plane.normal[1] *= length; + plane.normal[2] *= length; + + plane.dist = DotProduct (pass->points[j], plane.normal); + + // + // find out which side of the generated seperating plane has the + // source portal + // +#if 1 + fliptest = false; + for (k=0 ; knumpoints ; k++) + { + if (k == i || k == l) + continue; + d = DotProduct (source->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + { // source is on the negative side, so we want all + // pass and target on the positive side + fliptest = false; + break; + } + else if (d > ON_EPSILON) + { // source is on the positive side, so we want all + // pass and target on the negative side + fliptest = true; + break; + } + } + if (k == source->numpoints) + continue; // planar with source portal +#else + fliptest = flipclip; +#endif + // + // flip the normal if the source portal is backwards + // + if (fliptest) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } +#if 1 + // + // if all of the pass portal points are now on the positive side, + // this is the seperating plane + // + counts[0] = counts[1] = counts[2] = 0; + for (k=0 ; knumpoints ; k++) + { + if (k==j) + continue; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + break; + else if (d > ON_EPSILON) + counts[0]++; + else + counts[2]++; + } + if (k != pass->numpoints) + continue; // points on negative side, not a seperating plane + + if (!counts[0]) + continue; // planar with seperating plane +#else + k = (j+1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + continue; + k = (j+pass->numpoints-1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + continue; +#endif + // + // flip the normal if we want the back side + // + if (flipclip) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // clip target by the seperating plane + // + target = Vis_ChopWinding (target, stack, &plane); + if (!target) + return NULL; // target is not visible + } + } + + return target; +} + + + +/* +================== +RecursiveLeafFlow + +Flood fill through the leafs +If src_portal is NULL, this is the originating leaf +================== +*/ +void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) +{ + pstack_t stack; + portal_t *p; + plane_t backplane; + leaf_t *leaf; + int i, j; + long *test, *might, *vis, more; + int pnum; + + thread->c_chains++; + + leaf = &leafs[leafnum]; +// CheckStack (leaf, thread); + + prevstack->next = &stack; + + stack.next = NULL; + stack.leaf = leaf; + stack.portal = NULL; + + might = (long *)stack.mightsee; + vis = (long *)thread->base->portalvis; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) + { + continue; // can't possibly see it + } + + // if the portal can't see anything we haven't allready seen, skip it + if (p->status == stat_done) + { + test = (long *)p->portalvis; + } + else + { + test = (long *)p->portalflood; + } + + more = 0; + for (j=0 ; jmightsee)[j] & test[j]; + more |= (might[j] & ~vis[j]); + } + + if (!more && + (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) ) + { // can't see anything new + continue; + } + + // get plane of portal, point normal into the neighbor leaf + stack.portalplane = p->plane; + VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); + backplane.dist = -p->plane.dist; + +// c_portalcheck++; + + stack.portal = p; + stack.next = NULL; + stack.freewindings[0] = 1; + stack.freewindings[1] = 1; + stack.freewindings[2] = 1; + +#if 1 +{ +float d; + + d = DotProduct (p->origin, thread->pstack_head.portalplane.normal); + d -= thread->pstack_head.portalplane.dist; + if (d < -p->radius) + { + continue; + } + else if (d > p->radius) + { + stack.pass = p->winding; + } + else + { + stack.pass = Vis_ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; + } +} +#else + stack.pass = Vis_ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; +#endif + + +#if 1 +{ +float d; + + d = DotProduct (thread->base->origin, p->plane.normal); + d -= p->plane.dist; + if (d > p->radius) + { + continue; + } + else if (d < -p->radius) + { + stack.source = prevstack->source; + } + else + { + stack.source = Vis_ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; + } +} +#else + stack.source = Vis_ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; +#endif + + if (!prevstack->pass) + { // the second leaf can only be blocked if coplanar + + // mark the portal as visible + thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); + + RecursiveLeafFlow (p->leaf, thread, &stack); + continue; + } + + stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack); + if (!stack.pass) + continue; + + stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack); + if (!stack.pass) + continue; + + // mark the portal as visible + thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); + + // flow through it for real + RecursiveLeafFlow (p->leaf, thread, &stack); + } +} + + +/* +=============== +PortalFlow + +generates the portalvis bit vector +=============== +*/ +void PortalFlow (int portalnum) +{ + threaddata_t data; + int i; + portal_t *p; + int c_might, c_can; + + p = sorted_portals[portalnum]; + p->status = stat_working; + + c_might = CountBits (p->portalflood, numportals*2); + + memset (&data, 0, sizeof(data)); + data.base = p; + + data.pstack_head.portal = p; + data.pstack_head.source = p->winding; + data.pstack_head.portalplane = p->plane; + for (i=0 ; iportalflood)[i]; + RecursiveLeafFlow (p->leaf, &data, &data.pstack_head); + + p->status = stat_done; + + c_can = CountBits (p->portalvis, numportals*2); + + Sys_FPrintf ( SYS_VRB, "portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", + (int)(p - portals), c_might, c_can, data.c_chains); +} + + +/* +=============================================================================== + +This is a rough first-order aproximation that is used to trivially reject some +of the final calculations. + + +Calculates portalfront and portalflood bit vectors + +thinking about: + +typedef struct passage_s +{ + struct passage_s *next; + struct portal_s *to; + stryct sep_s *seperators; + byte *mightsee; +} passage_t; + +typedef struct portal_s +{ + struct passage_s *passages; + int leaf; // leaf portal faces into +} portal_s; + +leaf = portal->leaf +clear +for all portals + + +calc portal visibility + clear bit vector + for all passages + passage visibility + + +for a portal to be visible to a passage, it must be on the front of +all seperating planes, and both portals must be behind the mew portal + +=============================================================================== +*/ + +int c_flood, c_vis; + + +/* +================== +SimpleFlood + +================== +*/ +void SimpleFlood (portal_t *srcportal, int leafnum) +{ + int i; + leaf_t *leaf; + portal_t *p; + int pnum; + + leaf = &leafs[leafnum]; + + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) ) + continue; + + if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) ) + continue; + + srcportal->portalflood[pnum>>3] |= (1<<(pnum&7)); + + SimpleFlood (srcportal, p->leaf); + } +} + +/* +============== +BasePortalVis +============== +*/ +void BasePortalVis (int portalnum) +{ + int j, k; + portal_t *tp, *p; + float d; + winding_t *w; + + p = portals+portalnum; + + p->portalfront = malloc (portalbytes); + memset (p->portalfront, 0, portalbytes); + + p->portalflood = malloc (portalbytes); + memset (p->portalflood, 0, portalbytes); + + p->portalvis = malloc (portalbytes); + memset (p->portalvis, 0, portalbytes); + + for (j=0, tp = portals ; jwinding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], p->plane.normal) + - p->plane.dist; + if (d > ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + w = p->winding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], tp->plane.normal) + - tp->plane.dist; + if (d < -ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + p->portalfront[j>>3] |= (1<<(j&7)); + } + + SimpleFlood (p, p->leaf); + + p->nummightsee = CountBits (p->portalflood, numportals*2); +// printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee); + c_flood += p->nummightsee; +} + + + + + +/* +=============================================================================== + +This is a second order aproximation + +Calculates portalvis bit vector + +WAAAAAAY too slow. + +=============================================================================== +*/ + +/* +================== +RecursiveLeafBitFlow + +================== +*/ +void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee) +{ + portal_t *p; + leaf_t *leaf; + int i, j; + long more; + int pnum; + byte newmight[MAX_PORTALS/8]; + + leaf = &leafs[leafnum]; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + // if some previous portal can't see it, skip + if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) ) + continue; + + // if this portal can see some portals we mightsee, recurse + more = 0; + for (j=0 ; jportalflood)[j]; + more |= ((long *)newmight)[j] & ~((long *)cansee)[j]; + } + + if (!more) + continue; // can't see anything new + + cansee[pnum>>3] |= (1<<(pnum&7)); + + RecursiveLeafBitFlow (p->leaf, newmight, cansee); + } +} + +/* +============== +BetterPortalVis +============== +*/ +void BetterPortalVis (int portalnum) +{ + portal_t *p; + + p = portals+portalnum; + + RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis); + + // build leaf vis information + p->nummightsee = CountBits (p->portalvis, numportals*2); + c_vis += p->nummightsee; +} + + diff --git a/tools/quake2/q2map/gldraw.c b/tools/quake2/q2map/gldraw.c new file mode 100644 index 00000000..d3f78f53 --- /dev/null +++ b/tools/quake2/q2map/gldraw.c @@ -0,0 +1,231 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include "qbsp.h" + +// can't use the glvertex3fv functions, because the vec3_t fields +// could be either floats or doubles, depending on DOUBLEVEC_T + +qboolean drawflag; +vec3_t draw_mins, draw_maxs; + + +#define WIN_SIZE 512 + +void InitWindow (void) +{ + auxInitDisplayMode (AUX_SINGLE | AUX_RGB); + auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE); + auxInitWindow ("qcsg"); +} + +void Draw_ClearWindow (void) +{ + static int init; + int w, h, g; + vec_t mx, my; + + if (!drawflag) + return; + + if (!init) + { + init = true; + InitWindow (); + } + + glClearColor (1,0.8,0.8,0); + glClear (GL_COLOR_BUFFER_BIT); + + w = (draw_maxs[0] - draw_mins[0]); + h = (draw_maxs[1] - draw_mins[1]); + + mx = draw_mins[0] + w/2; + my = draw_mins[1] + h/2; + + g = w > h ? w : h; + + glLoadIdentity (); + gluPerspective (90, 1, 2, 16384); + gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0); + + glColor3f (0,0,0); +// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisable (GL_DEPTH_TEST); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +#if 0 + glColor4f (1,0,0,0.5); + glBegin (GL_POLYGON); + + glVertex3f (0, 500, 0); + glVertex3f (0, 900, 0); + glVertex3f (0, 900, 100); + glVertex3f (0, 500, 100); + + glEnd (); +#endif + + glFlush (); + +} + +void Draw_SetRed (void) +{ + if (!drawflag) + return; + + glColor3f (1,0,0); +} + +void Draw_SetGrey (void) +{ + if (!drawflag) + return; + + glColor3f (0.5,0.5,0.5); +} + +void Draw_SetBlack (void) +{ + if (!drawflag) + return; + + glColor3f (0,0,0); +} + +void DrawWinding (winding_t *w) +{ + int i; + + if (!drawflag) + return; + + glColor4f (0,0,0,0.5); + glBegin (GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glColor4f (0,1,0,0.3); + glBegin (GL_POLYGON); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glFlush (); +} + +void DrawAuxWinding (winding_t *w) +{ + int i; + + if (!drawflag) + return; + + glColor4f (0,0,0,0.5); + glBegin (GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glColor4f (1,0,0,0.3); + glBegin (GL_POLYGON); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glFlush (); +} + +//============================================================ + +#define GLSERV_PORT 25001 + +qboolean wins_init; +int draw_socket; + +void GLS_BeginScene (void) +{ + WSADATA winsockdata; + WORD wVersionRequested; + struct sockaddr_in address; + int r; + + if (!wins_init) + { + wins_init = true; + + wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (MAKEWORD(1, 1), &winsockdata); + + if (r) + Error ("Winsock initialization failed."); + + } + + // connect a socket to the server + + draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (draw_socket == -1) + Error ("draw_socket failed"); + + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + address.sin_port = GLSERV_PORT; + r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address)); + if (r == -1) + { + closesocket (draw_socket); + draw_socket = 0; + } +} + +void GLS_Winding (winding_t *w, int code) +{ + byte buf[1024]; + int i, j; + + if (!draw_socket) + return; + + ((int *)buf)[0] = w->numpoints; + ((int *)buf)[1] = code; + for (i=0 ; inumpoints ; i++) + for (j=0 ; j<3 ; j++) + ((float *)buf)[2+i*3+j] = w->p[i][j]; + + send (draw_socket, buf, w->numpoints*12+8, 0); +} + +void GLS_EndScene (void) +{ + closesocket (draw_socket); + draw_socket = 0; +} diff --git a/tools/quake2/q2map/glfile.c b/tools/quake2/q2map/glfile.c new file mode 100644 index 00000000..a5c0e30b --- /dev/null +++ b/tools/quake2/q2map/glfile.c @@ -0,0 +1,148 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + +int c_glfaces; + +int PortalVisibleSides (portal_t *p) +{ + int fcon, bcon; + + if (!p->onnode) + return 0; // outside + + fcon = p->nodes[0]->contents; + bcon = p->nodes[1]->contents; + + // same contents never create a face + if (fcon == bcon) + return 0; + + // FIXME: is this correct now? + if (!fcon) + return 1; + if (!bcon) + return 2; + return 0; +} + +void OutputWinding (winding_t *w, FILE *glview) +{ + static int level = 128; + vec_t light; + int i; + + fprintf (glview, "%i\n", w->numpoints); + level+=28; + light = (level&255)/255.0; + for (i=0 ; inumpoints ; i++) + { + fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + light, + light, + light); + } + fprintf (glview, "\n"); +} + +/* +============= +OutputPortal +============= +*/ +void OutputPortal (portal_t *p, FILE *glview) +{ + winding_t *w; + int sides; + + sides = PortalVisibleSides (p); + if (!sides) + return; + + c_glfaces++; + + w = p->winding; + + if (sides == 2) // back side + w = ReverseWinding (w); + + OutputWinding (w, glview); + + if (sides == 2) + FreeWinding(w); +} + +/* +============= +WriteGLView_r +============= +*/ +void WriteGLView_r (node_t *node, FILE *glview) +{ + portal_t *p, *nextp; + + if (node->planenum != PLANENUM_LEAF) + { + WriteGLView_r (node->children[0], glview); + WriteGLView_r (node->children[1], glview); + return; + } + + // write all the portals + for (p=node->portals ; p ; p=nextp) + { + if (p->nodes[0] == node) + { + OutputPortal (p, glview); + nextp = p->next[0]; + } + else + nextp = p->next[1]; + } +} + +/* +============= +WriteGLView +============= +*/ +void WriteGLView (tree_t *tree, char *source) +{ + char name[1024]; + FILE *glview; + + c_glfaces = 0; + sprintf (name, "%s%s.gl",outbase, source); + Sys_Printf ("Writing %s\n", name); + + glview = fopen (name, "w"); + if (!glview) + Error ("Couldn't open %s", name); + WriteGLView_r (tree->headnode, glview); + fclose (glview); + + Sys_Printf ("%5i c_glfaces\n", c_glfaces); +} + diff --git a/tools/quake2/q2map/leakfile.c b/tools/quake2/q2map/leakfile.c new file mode 100644 index 00000000..32d57b9c --- /dev/null +++ b/tools/quake2/q2map/leakfile.c @@ -0,0 +1,180 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + +/* +============================================================================== + +LEAF FILE GENERATION + +Save out name.line for qe3 to read +============================================================================== +*/ + + +/* +============= +LeakFile + +Finds the shortest possible chain of portals +that leads from the outside leaf to a specifically +occupied leaf +============= +*/ + +/* +void LeakFile (tree_t *tree) +{ + vec3_t mid; + FILE *linefile; + char filename[1024]; + node_t *node; + int count; + + if (!tree->outside_node.occupied) + return; + + Sys_Printf ("--- LeakFile ---\n"); + + // + // write the points to the file + // + sprintf (filename, "%s.lin", source); + linefile = fopen (filename, "w"); + if (!linefile) + Error ("Couldn't open %s\n", filename); + + count = 0; + node = &tree->outside_node; + while (node->occupied > 1) + { + int next; + portal_t *p, *nextportal; + node_t *nextnode; + int s; + + // find the best portal exit + next = node->occupied; + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (p->nodes[s]->occupied + && p->nodes[s]->occupied < next) + { + nextportal = p; + nextnode = p->nodes[s]; + next = nextnode->occupied; + } + } + node = nextnode; + WindingCenter (nextportal->winding, mid); + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + count++; + } + // add the occupant center + GetVectorForKey (node->occupant, "origin", mid); + + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + Sys_Printf ("%5i point linefile\n", count+1); + + fclose (linefile); +} +*/ + +/* +============= +LeakFile + +Finds the shortest possible chain of portals +that leads from the outside leaf to a specifically +occupied leaf + +TTimo: builds a polyline xml node +============= +*/ +xmlNodePtr LeakFile (tree_t *tree) +{ + vec3_t mid; + FILE *linefile; + char filename[1024]; + node_t *node; + int count; + xmlNodePtr xml_node, point; + + if (!tree->outside_node.occupied) + return NULL; + + Sys_FPrintf (SYS_VRB,"--- LeakFile ---\n"); + + // + // write the points to the file + // + sprintf (filename, "%s.lin", source); + linefile = fopen (filename, "w"); + if (!linefile) + Error ("Couldn't open %s\n", filename); + + xml_node = xmlNewNode (NULL, "polyline"); + + count = 0; + node = &tree->outside_node; + while (node->occupied > 1) + { + int next; + portal_t *p, *nextportal; + node_t *nextnode; + int s; + + // find the best portal exit + next = node->occupied; + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (p->nodes[s]->occupied + && p->nodes[s]->occupied < next) + { + nextportal = p; + nextnode = p->nodes[s]; + next = nextnode->occupied; + } + } + node = nextnode; + WindingCenter (nextportal->winding, mid); + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + point = xml_NodeForVec(mid); + xmlAddChild(xml_node, point); + count++; + } + // add the occupant center + GetVectorForKey (node->occupant, "origin", mid); + + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + point = xml_NodeForVec(mid); + xmlAddChild(xml_node, point); + Sys_FPrintf( SYS_VRB, "%9d point linefile\n", count+1); + + fclose (linefile); + + return xml_node; +} + + diff --git a/tools/quake2/q2map/lightmap.c b/tools/quake2/q2map/lightmap.c new file mode 100644 index 00000000..62a61ebd --- /dev/null +++ b/tools/quake2/q2map/lightmap.c @@ -0,0 +1,1315 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "qrad.h" + +#define MAX_LSTYLES 256 + +typedef struct +{ + dface_t *faces[2]; + qboolean coplanar; +} edgeshare_t; + +edgeshare_t edgeshare[MAX_MAP_EDGES]; + +int facelinks[MAX_MAP_FACES]; +int planelinks[2][MAX_MAP_PLANES]; + +/* +============ +LinkPlaneFaces +============ +*/ +void LinkPlaneFaces (void) +{ + int i; + dface_t *f; + + f = dfaces; + for (i=0 ; iside][f->planenum]; + planelinks[f->side][f->planenum] = i; + } +} + +/* +============ +PairEdges +============ +*/ +void PairEdges (void) +{ + int i, j, k; + dface_t *f; + edgeshare_t *e; + + f = dfaces; + for (i=0 ; inumedges ; j++) + { + k = dsurfedges[f->firstedge + j]; + if (k < 0) + { + e = &edgeshare[-k]; + e->faces[1] = f; + } + else + { + e = &edgeshare[k]; + e->faces[0] = f; + } + + if (e->faces[0] && e->faces[1]) + { + // determine if coplanar + if (e->faces[0]->planenum == e->faces[1]->planenum) + e->coplanar = true; + } + } + } +} + +/* +================================================================= + + POINT TRIANGULATION + +================================================================= +*/ + +typedef struct triedge_s +{ + int p0, p1; + vec3_t normal; + vec_t dist; + struct triangle_s *tri; +} triedge_t; + +typedef struct triangle_s +{ + triedge_t *edges[3]; +} triangle_t; + +#define MAX_TRI_POINTS 1024 +#define MAX_TRI_EDGES (MAX_TRI_POINTS*6) +#define MAX_TRI_TRIS (MAX_TRI_POINTS*2) + +typedef struct +{ + int numpoints; + int numedges; + int numtris; + dplane_t *plane; + triedge_t *edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS]; + patch_t *points[MAX_TRI_POINTS]; + triedge_t edges[MAX_TRI_EDGES]; + triangle_t tris[MAX_TRI_TRIS]; +} triangulation_t; + +/* +=============== +AllocTriangulation +=============== +*/ +triangulation_t *AllocTriangulation (dplane_t *plane) +{ + triangulation_t *t; + + t = malloc(sizeof(triangulation_t)); + t->numpoints = 0; + t->numedges = 0; + t->numtris = 0; + + t->plane = plane; + +// memset (t->edgematrix, 0, sizeof(t->edgematrix)); + + return t; +} + +/* +=============== +FreeTriangulation +=============== +*/ +void FreeTriangulation (triangulation_t *tr) +{ + free (tr); +} + + +triedge_t *FindEdge (triangulation_t *trian, int p0, int p1) +{ + triedge_t *e, *be; + vec3_t v1; + vec3_t normal; + vec_t dist; + + if (trian->edgematrix[p0][p1]) + return trian->edgematrix[p0][p1]; + + if (trian->numedges > MAX_TRI_EDGES-2) + Error ("trian->numedges > MAX_TRI_EDGES-2"); + + VectorSubtract (trian->points[p1]->origin, trian->points[p0]->origin, v1); + VectorNormalize (v1, v1); + CrossProduct (v1, trian->plane->normal, normal); + dist = DotProduct (trian->points[p0]->origin, normal); + + e = &trian->edges[trian->numedges]; + e->p0 = p0; + e->p1 = p1; + e->tri = NULL; + VectorCopy (normal, e->normal); + e->dist = dist; + trian->numedges++; + trian->edgematrix[p0][p1] = e; + + be = &trian->edges[trian->numedges]; + be->p0 = p1; + be->p1 = p0; + be->tri = NULL; + VectorSubtract (vec3_origin, normal, be->normal); + be->dist = -dist; + trian->numedges++; + trian->edgematrix[p1][p0] = be; + + return e; +} + +triangle_t *AllocTriangle (triangulation_t *trian) +{ + triangle_t *t; + + if (trian->numtris >= MAX_TRI_TRIS) + Error ("trian->numtris >= MAX_TRI_TRIS"); + + t = &trian->tris[trian->numtris]; + trian->numtris++; + + return t; +} + +/* +============ +TriEdge_r +============ +*/ +void TriEdge_r (triangulation_t *trian, triedge_t *e) +{ + int i, bestp; + vec3_t v1, v2; + vec_t *p0, *p1, *p; + vec_t best, ang; + triangle_t *nt; + + if (e->tri) + return; // allready connected by someone + + // find the point with the best angle + p0 = trian->points[e->p0]->origin; + p1 = trian->points[e->p1]->origin; + best = 1.1; + for (i=0 ; i< trian->numpoints ; i++) + { + p = trian->points[i]->origin; + // a 0 dist will form a degenerate triangle + if (DotProduct(p, e->normal) - e->dist < 0) + continue; // behind edge + VectorSubtract (p0, p, v1); + VectorSubtract (p1, p, v2); + if (!VectorNormalize (v1,v1)) + continue; + if (!VectorNormalize (v2,v2)) + continue; + ang = DotProduct (v1, v2); + if (ang < best) + { + best = ang; + bestp = i; + } + } + if (best >= 1) + return; // edge doesn't match anything + + // make a new triangle + nt = AllocTriangle (trian); + nt->edges[0] = e; + nt->edges[1] = FindEdge (trian, e->p1, bestp); + nt->edges[2] = FindEdge (trian, bestp, e->p0); + for (i=0 ; i<3 ; i++) + nt->edges[i]->tri = nt; + TriEdge_r (trian, FindEdge (trian, bestp, e->p1)); + TriEdge_r (trian, FindEdge (trian, e->p0, bestp)); +} + +/* +============ +TriangulatePoints +============ +*/ +void TriangulatePoints (triangulation_t *trian) +{ + vec_t d, bestd; + vec3_t v1; + int bp1, bp2, i, j; + vec_t *p1, *p2; + triedge_t *e, *e2; + + if (trian->numpoints < 2) + return; + + // find the two closest points + bestd = 9999; + for (i=0 ; inumpoints ; i++) + { + p1 = trian->points[i]->origin; + for (j=i+1 ; jnumpoints ; j++) + { + p2 = trian->points[j]->origin; + VectorSubtract (p2, p1, v1); + d = VectorLength (v1); + if (d < bestd) + { + bestd = d; + bp1 = i; + bp2 = j; + } + } + } + + e = FindEdge (trian, bp1, bp2); + e2 = FindEdge (trian, bp2, bp1); + TriEdge_r (trian, e); + TriEdge_r (trian, e2); +} + +/* +=============== +AddPointToTriangulation +=============== +*/ +void AddPointToTriangulation (patch_t *patch, triangulation_t *trian) +{ + int pnum; + + pnum = trian->numpoints; + if (pnum == MAX_TRI_POINTS) + Error ("trian->numpoints == MAX_TRI_POINTS"); + trian->points[pnum] = patch; + trian->numpoints++; +} + +/* +=============== +LerpTriangle +=============== +*/ +void LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color) +{ + patch_t *p1, *p2, *p3; + vec3_t base, d1, d2; + float x, y, x1, y1, x2, y2; + + p1 = trian->points[t->edges[0]->p0]; + p2 = trian->points[t->edges[1]->p0]; + p3 = trian->points[t->edges[2]->p0]; + + VectorCopy (p1->totallight, base); + VectorSubtract (p2->totallight, base, d1); + VectorSubtract (p3->totallight, base, d2); + + x = DotProduct (point, t->edges[0]->normal) - t->edges[0]->dist; + y = DotProduct (point, t->edges[2]->normal) - t->edges[2]->dist; + + x1 = 0; + y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist; + + x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist; + y2 = 0; + + if (fabs(y1)edges[i]; + d = DotProduct (e->normal, point) - e->dist; + if (d < 0) + return false; // not inside + } + + return true; +} + +/* +=============== +SampleTriangulation +=============== +*/ +void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color) +{ + triangle_t *t; + triedge_t *e; + vec_t d, best; + patch_t *p0, *p1; + vec3_t v1, v2; + int i, j; + + if (trian->numpoints == 0) + { + VectorClear (color); + return; + } + if (trian->numpoints == 1) + { + VectorCopy (trian->points[0]->totallight, color); + return; + } + + // search for triangles + for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++) + { + if (!PointInTriangle (point, t)) + continue; + + // this is it + LerpTriangle (trian, t, point, color); + return; + } + + // search for exterior edge + for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++) + { + if (e->tri) + continue; // not an exterior edge + + d = DotProduct (point, e->normal) - e->dist; + if (d < 0) + continue; // not in front of edge + + p0 = trian->points[e->p0]; + p1 = trian->points[e->p1]; + + VectorSubtract (p1->origin, p0->origin, v1); + VectorNormalize (v1, v1); + VectorSubtract (point, p0->origin, v2); + d = DotProduct (v2, v1); + if (d < 0) + continue; + if (d > 1) + continue; + for (i=0 ; i<3 ; i++) + color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]); + return; + } + + // search for nearest point + best = 99999; + p1 = NULL; + for (j=0 ; jnumpoints ; j++) + { + p0 = trian->points[j]; + VectorSubtract (point, p0->origin, v1); + d = VectorLength (v1); + if (d < best) + { + best = d; + p1 = p0; + } + } + + if (!p1) + Error ("SampleTriangulation: no points"); + + VectorCopy (p1->totallight, color); +} + +/* +================================================================= + + LIGHTMAP SAMPLE GENERATION + +================================================================= +*/ + + +#define SINGLEMAP (64*64*4) + +typedef struct +{ + vec_t facedist; + vec3_t facenormal; + + int numsurfpt; + vec3_t surfpt[SINGLEMAP]; + + vec3_t modelorg; // for origined bmodels + + vec3_t texorg; + vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0] + vec3_t textoworld[2]; // world = texorg + s * textoworld[0] + + vec_t exactmins[2], exactmaxs[2]; + + int texmins[2], texsize[2]; + int surfnum; + dface_t *face; +} lightinfo_t; + + +/* +================ +CalcFaceExtents + +Fills in s->texmins[] and s->texsize[] +also sets exactmins[] and exactmaxs[] +================ +*/ +void CalcFaceExtents (lightinfo_t *l) +{ + dface_t *s; + vec_t mins[2], maxs[2], val; + int i,j, e; + dvertex_t *v; + texinfo_t *tex; + vec3_t vt; + + s = l->face; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = &texinfo[s->texinfo]; + + for (i=0 ; inumedges ; i++) + { + e = dsurfedges[s->firstedge+i]; + if (e >= 0) + v = dvertexes + dedges[e].v[0]; + else + v = dvertexes + dedges[-e].v[1]; + +// VectorAdd (v->point, l->modelorg, vt); + VectorCopy (v->point, vt); + + for (j=0 ; j<2 ; j++) + { + val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + l->exactmins[i] = mins[i]; + l->exactmaxs[i] = maxs[i]; + + mins[i] = floor(mins[i]/16); + maxs[i] = ceil(maxs[i]/16); + + l->texmins[i] = mins[i]; + l->texsize[i] = maxs[i] - mins[i]; + if (l->texsize[0] * l->texsize[1] > SINGLEMAP/4) // div 4 for extrasamples + Error ("Surface to large to map"); + } +} + +/* +================ +CalcFaceVectors + +Fills in texorg, worldtotex. and textoworld +================ +*/ +void CalcFaceVectors (lightinfo_t *l) +{ + texinfo_t *tex; + int i, j; + vec3_t texnormal; + vec_t distscale; + vec_t dist, len; + int w, h; + + tex = &texinfo[l->face->texinfo]; + +// convert from float to double + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + l->worldtotex[i][j] = tex->vecs[i][j]; + +// calculate a normal to the texture axis. points can be moved along this +// without changing their S/T + texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2] + - tex->vecs[1][2]*tex->vecs[0][1]; + texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0] + - tex->vecs[1][0]*tex->vecs[0][2]; + texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1] + - tex->vecs[1][1]*tex->vecs[0][0]; + VectorNormalize (texnormal, texnormal); + +// flip it towards plane normal + distscale = DotProduct (texnormal, l->facenormal); + if (!distscale) + { + Sys_FPrintf( SYS_VRB, "WARNING: Texture axis perpendicular to face\n"); + distscale = 1; + } + if (distscale < 0) + { + distscale = -distscale; + VectorSubtract (vec3_origin, texnormal, texnormal); + } + +// distscale is the ratio of the distance along the texture normal to +// the distance along the plane normal + distscale = 1/distscale; + + for (i=0 ; i<2 ; i++) + { + len = VectorLength (l->worldtotex[i]); + dist = DotProduct (l->worldtotex[i], l->facenormal); + dist *= distscale; + VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]); + VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]); + } + + +// calculate texorg on the texture plane + for (i=0 ; i<3 ; i++) + l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i]; + +// project back to the face plane + dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; + dist *= distscale; + VectorMA (l->texorg, -dist, texnormal, l->texorg); + + // compensate for org'd bmodels + VectorAdd (l->texorg, l->modelorg, l->texorg); + + // total sample count + h = l->texsize[1]+1; + w = l->texsize[0]+1; + l->numsurfpt = w * h; +} + +/* +================= +CalcPoints + +For each texture aligned grid point, back project onto the plane +to get the world xyz value of the sample point +================= +*/ +void CalcPoints (lightinfo_t *l, float sofs, float tofs) +{ + int i; + int s, t, j; + int w, h, step; + vec_t starts, startt, us, ut; + vec_t *surf; + vec_t mids, midt; + vec3_t facemid; + dleaf_t *leaf; + + surf = l->surfpt[0]; + mids = (l->exactmaxs[0] + l->exactmins[0])/2; + midt = (l->exactmaxs[1] + l->exactmins[1])/2; + + for (j=0 ; j<3 ; j++) + facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt; + + h = l->texsize[1]+1; + w = l->texsize[0]+1; + l->numsurfpt = w * h; + + starts = l->texmins[0]*16; + startt = l->texmins[1]*16; + step = 16; + + + for (t=0 ; ttexorg[j] + l->textoworld[0][j]*us + + l->textoworld[1][j]*ut; + + leaf = Rad_PointInLeaf (surf); + if (leaf->contents != CONTENTS_SOLID) + { + if (!TestLine_r (0, facemid, surf)) + break; // got it + } + + // nudge it + if (i & 1) + { + if (us > mids) + { + us -= 8; + if (us < mids) + us = mids; + } + else + { + us += 8; + if (us > mids) + us = mids; + } + } + else + { + if (ut > midt) + { + ut -= 8; + if (ut < midt) + ut = midt; + } + else + { + ut += 8; + if (ut > midt) + ut = midt; + } + } + } + } + } + +} + + +//============================================================== + + + +#define MAX_STYLES 32 +typedef struct +{ + int numsamples; + float *origins; + int numstyles; + int stylenums[MAX_STYLES]; + float *samples[MAX_STYLES]; +} facelight_t; + +directlight_t *directlights[MAX_MAP_LEAFS]; +facelight_t facelight[MAX_MAP_FACES]; +int numdlights; + +/* +================== +FindTargetEntity +================== +*/ +entity_t *FindTargetEntity (char *target) +{ + int i; + char *n; + + for (i=0 ; itotallight[0] < DIRECT_LIGHT + && p->totallight[1] < DIRECT_LIGHT + && p->totallight[2] < DIRECT_LIGHT) + continue; + + numdlights++; + dl = malloc(sizeof(directlight_t)); + memset (dl, 0, sizeof(*dl)); + + VectorCopy (p->origin, dl->origin); + + leaf = Rad_PointInLeaf (dl->origin); + cluster = leaf->cluster; + dl->next = directlights[cluster]; + directlights[cluster] = dl; + + dl->type = emit_surface; + VectorCopy (p->plane->normal, dl->normal); + + dl->intensity = ColorNormalize (p->totallight, dl->color); + dl->intensity *= p->area * direct_scale; + VectorClear (p->totallight); // all sent now + } + + // + // entities + // + for (i=0 ; iorigin); + dl->style = FloatForKey (e, "_style"); + if (!dl->style) + dl->style = FloatForKey (e, "style"); + if (dl->style < 0 || dl->style >= MAX_LSTYLES) + dl->style = 0; + + leaf = Rad_PointInLeaf (dl->origin); + cluster = leaf->cluster; + + dl->next = directlights[cluster]; + directlights[cluster] = dl; + + intensity = FloatForKey (e, "light"); + if (!intensity) + intensity = FloatForKey (e, "_light"); + if (!intensity) + intensity = 300; + _color = ValueForKey (e, "_color"); + if (_color && _color[0]) + { + sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]); + ColorNormalize (dl->color, dl->color); + } + else + dl->color[0] = dl->color[1] = dl->color[2] = 1.0; + dl->intensity = intensity*entity_scale; + dl->type = emit_point; + + target = ValueForKey (e, "target"); + + if (!strcmp (name, "light_spot") || target[0]) + { + dl->type = emit_spotlight; + dl->stopdot = FloatForKey (e, "_cone"); + if (!dl->stopdot) + dl->stopdot = 10; + dl->stopdot = cos(dl->stopdot/180*3.14159); + if (target[0]) + { // point towards target + e2 = FindTargetEntity (target); + if (!e2) + Sys_Printf ("WARNING: light at (%i %i %i) has missing target\n", + (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]); + else + { + GetVectorForKey (e2, "origin", dest); + VectorSubtract (dest, dl->origin, dl->normal); + VectorNormalize (dl->normal, dl->normal); + } + } + else + { // point down angle + angle = FloatForKey (e, "angle"); + if (angle == ANGLE_UP) + { + dl->normal[0] = dl->normal[1] = 0; + dl->normal[2] = 1; + } + else if (angle == ANGLE_DOWN) + { + dl->normal[0] = dl->normal[1] = 0; + dl->normal[2] = -1; + } + else + { + dl->normal[2] = 0; + dl->normal[0] = cos (angle/180*3.14159); + dl->normal[1] = sin (angle/180*3.14159); + } + } + } + } + + Sys_FPrintf( SYS_VRB, "%i direct lights\n", numdlights); +} + +/* +============= +GatherSampleLight + +Lightscale is the normalizer for multisampling +============= +*/ +void GatherSampleLight (vec3_t pos, vec3_t normal, + float **styletable, int offset, int mapsize, float lightscale) +{ + int i; + directlight_t *l; + byte pvs[(MAX_MAP_LEAFS+7)/8]; + vec3_t delta; + float dot, dot2; + float dist; + float scale; + float *dest; + + // get the PVS for the pos to limit the number of checks + if (!PvsForOrigin (pos, pvs)) + { + return; + } + + for (i = 0 ; inumclusters ; i++) + { + if ( ! (pvs[ i>>3] & (1<<(i&7))) ) + continue; + + for (l=directlights[i] ; l ; l=l->next) + { + VectorSubtract (l->origin, pos, delta); + dist = VectorNormalize (delta, delta); + dot = DotProduct (delta, normal); + if (dot <= 0.001) + continue; // behind sample surface + + switch (l->type) + { + case emit_point: + // linear falloff + scale = (l->intensity - dist) * dot; + break; + + case emit_surface: + dot2 = -DotProduct (delta, l->normal); + if (dot2 <= 0.001) + goto skipadd; // behind light surface + scale = (l->intensity / (dist*dist) ) * dot * dot2; + break; + + case emit_spotlight: + // linear falloff + dot2 = -DotProduct (delta, l->normal); + if (dot2 <= l->stopdot) + goto skipadd; // outside light cone + scale = (l->intensity - dist) * dot; + break; + default: + Error ("Bad l->type"); + } + + if (TestLine_r (0, pos, l->origin)) + continue; // occluded + + if (scale <= 0) + continue; + + // if this style doesn't have a table yet, allocate one + if (!styletable[l->style]) + { + styletable[l->style] = malloc (mapsize); + memset (styletable[l->style], 0, mapsize); + } + + dest = styletable[l->style] + offset; + // add some light to it + VectorMA (dest, scale*lightscale, l->color, dest); + +skipadd: ; + } + } + +} + +/* +============= +AddSampleToPatch + +Take the sample's collected light and +add it back into the apropriate patch +for the radiosity pass. + +The sample is added to all patches that might include +any part of it. They are counted and averaged, so it +doesn't generate extra light. +============= +*/ +void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum) +{ + patch_t *patch; + vec3_t mins, maxs; + int i; + + if (numbounce == 0) + return; + if (color[0] + color[1] + color[2] < 3) + return; + + for (patch = face_patches[facenum] ; patch ; patch=patch->next) + { + // see if the point is in this patch (roughly) + WindingBounds (patch->winding, mins, maxs); + for (i=0 ; i<3 ; i++) + { + if (mins[i] > pos[i] + 16) + goto nextpatch; + if (maxs[i] < pos[i] - 16) + goto nextpatch; + } + + // add the sample to the patch + patch->samples++; + VectorAdd (patch->samplelight, color, patch->samplelight); +nextpatch:; + } + +} + + +/* +============= +BuildFacelights +============= +*/ +float sampleofs[5][2] = +{ {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} }; + + +void BuildFacelights (int facenum) +{ + dface_t *f; + lightinfo_t l[5]; + float *styletable[MAX_LSTYLES]; + int i, j; + float *spot; + patch_t *patch; + int numsamples; + int tablesize; + facelight_t *fl; + + f = &dfaces[facenum]; + + if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) ) + return; // non-lit texture + + memset (styletable,0, sizeof(styletable)); + + if (extrasamples) + numsamples = 5; + else + numsamples = 1; + for (i=0 ; iplanenum].normal, l[i].facenormal); + l[i].facedist = dplanes[f->planenum].dist; + if (f->side) + { + VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal); + l[i].facedist = -l[i].facedist; + } + + // get the origin offset for rotating bmodels + VectorCopy (face_offset[facenum], l[i].modelorg); + + CalcFaceVectors (&l[i]); + CalcFaceExtents (&l[i]); + CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]); + } + + tablesize = l[0].numsurfpt * sizeof(vec3_t); + styletable[0] = malloc(tablesize); + memset (styletable[0], 0, tablesize); + + fl = &facelight[facenum]; + fl->numsamples = l[0].numsurfpt; + fl->origins = malloc (tablesize); + memcpy (fl->origins, l[0].surfpt, tablesize); + + for (i=0 ; inext) + { + if (patch->samples) + { + VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight); + } + else + { +// printf ("patch with no samples\n"); + } + } + + for (i=0 ; inumstyles == MAX_STYLES) + break; + fl->samples[fl->numstyles] = styletable[i]; + fl->stylenums[fl->numstyles] = i; + fl->numstyles++; + } + + // the light from DIRECT_LIGHTS is sent out, but the + // texture itself should still be full bright + + if (face_patches[facenum]->baselight[0] >= DIRECT_LIGHT || + face_patches[facenum]->baselight[1] >= DIRECT_LIGHT || + face_patches[facenum]->baselight[2] >= DIRECT_LIGHT + ) + { + spot = fl->samples[0]; + for (i=0 ; ibaselight, spot); + } + } +} + + +/* +============= +FinalLightFace + +Add the indirect lighting on top of the direct +lighting and save into final map format +============= +*/ +void FinalLightFace (int facenum) +{ + dface_t *f; + int i, j, k, st; + vec3_t lb; + patch_t *patch; + triangulation_t *trian; + facelight_t *fl; + float minlight; + float max, newmax; + byte *dest; + int pfacenum; + vec3_t facemins, facemaxs; + + f = &dfaces[facenum]; + fl = &facelight[facenum]; + + if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) ) + return; // non-lit texture + + ThreadLock (); + f->lightofs = lightdatasize; + lightdatasize += fl->numstyles*(fl->numsamples*3); + +// add green sentinals between lightmaps +#if 0 +lightdatasize += 64*3; +for (i=0 ; i<64 ; i++) +dlightdata[lightdatasize-(i+1)*3 + 1] = 255; +#endif + + if (lightdatasize > MAX_MAP_LIGHTING) + Error ("MAX_MAP_LIGHTING"); + ThreadUnlock (); + + f->styles[0] = 0; + f->styles[1] = f->styles[2] = f->styles[3] = 0xff; + + // + // set up the triangulation + // + if (numbounce > 0) + { + ClearBounds (facemins, facemaxs); + for (i=0 ; inumedges ; i++) + { + int ednum; + + ednum = dsurfedges[f->firstedge+i]; + if (ednum >= 0) + AddPointToBounds (dvertexes[dedges[ednum].v[0]].point, + facemins, facemaxs); + else + AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point, + facemins, facemaxs); + } + + trian = AllocTriangulation (&dplanes[f->planenum]); + + // for all faces on the plane, add the nearby patches + // to the triangulation + for (pfacenum = planelinks[f->side][f->planenum] + ; pfacenum ; pfacenum = facelinks[pfacenum]) + { + for (patch = face_patches[pfacenum] ; patch ; patch=patch->next) + { + for (i=0 ; i < 3 ; i++) + { + if (facemins[i] - patch->origin[i] > subdiv*2) + break; + if (patch->origin[i] - facemaxs[i] > subdiv*2) + break; + } + if (i != 3) + continue; // not needed for this face + AddPointToTriangulation (patch, trian); + } + } + for (i=0 ; inumpoints ; i++) + memset (trian->edgematrix[i], 0, trian->numpoints*sizeof(trian->edgematrix[0][0]) ); + TriangulatePoints (trian); + } + + // + // sample the triangulation + // + + // _minlight allows models that have faces that would not be + // illuminated to receive a mottled light pattern instead of + // black + minlight = FloatForKey (face_entity[facenum], "_minlight") * 128; + + dest = &dlightdata[f->lightofs]; + + if (fl->numstyles > MAXLIGHTMAPS) + { + fl->numstyles = MAXLIGHTMAPS; + Sys_Printf ("face with too many lightstyles: (%f %f %f)\n", + face_patches[facenum]->origin[0], + face_patches[facenum]->origin[1], + face_patches[facenum]->origin[2] + ); + } + + for (st=0 ; stnumstyles ; st++) + { + f->styles[st] = fl->stylenums[st]; + for (j=0 ; jnumsamples ; j++) + { + VectorCopy ( (fl->samples[st]+j*3), lb); + if (numbounce > 0 && st == 0) + { + vec3_t add; + + SampleTriangulation (fl->origins + j*3, trian, add); + VectorAdd (lb, add, lb); + } + // add an ambient term if desired + lb[0] += ambient; + lb[1] += ambient; + lb[2] += ambient; + + VectorScale (lb, lightscale, lb); + + // we need to clamp without allowing hue to change + for (k=0 ; k<3 ; k++) + if (lb[k] < 1) + lb[k] = 1; + max = lb[0]; + if (lb[1] > max) + max = lb[1]; + if (lb[2] > max) + max = lb[2]; + newmax = max; + if (newmax < 0) + newmax = 0; // roundoff problems + if (newmax < minlight) + { + newmax = minlight + (rand()%48); + } + if (newmax > maxlight) + newmax = maxlight; + + for (k=0 ; k<3 ; k++) + { + *dest++ = lb[k]*newmax/max; + } + } + } + + if (numbounce > 0) + FreeTriangulation (trian); +} diff --git a/tools/quake2/q2map/main.c b/tools/quake2/q2map/main.c new file mode 100644 index 00000000..6edcc21c --- /dev/null +++ b/tools/quake2/q2map/main.c @@ -0,0 +1,721 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +/* marker */ +#define MAIN_C + + + +/* dependencies */ +#include "q2map.h" + +#define qtrue true +#define qfalse false + +char *mapname; +char game[64]; +extern qboolean verbose; + +/// BSP +extern qboolean drawflag; +extern qboolean noprune; +extern qboolean glview; +extern qboolean nodetail; +extern qboolean fulldetail; +extern qboolean onlyents; +extern qboolean nomerge; +extern qboolean nowater; +extern qboolean nofill; +extern qboolean nocsg; +extern qboolean noweld; +extern qboolean noshare; +extern qboolean nosubdiv; +extern qboolean notjunc; +extern qboolean noopt; +extern qboolean leaktest; +extern qboolean verboseentities; +extern char outbase[32]; +extern int block_xl, block_xh, block_yl, block_yh; +extern vec_t microvolume; +extern float subdivide_size; + +// VIS +extern char inbase[32]; +extern qboolean fastvis; +extern qboolean nosort; +extern int testlevel; + +// RAD +extern qboolean dumppatches; +extern int numbounce; +extern qboolean extrasamples; +extern float subdiv; +extern float lightscale; +extern float direct_scale; +extern float entity_scale; +extern qboolean nopvs; +extern float ambient; +extern float maxlight; + + +void InitPaths( int *argc, char **argv ); + +/* +Random() +returns a pseudorandom number between 0 and 1 +*/ +/* +vec_t Random( void ) +{ + return (vec_t) rand() / RAND_MAX; +} +*/ + + +/* +ExitQ2Map() +cleanup routine +*/ +/* +static void ExitQ2Map( void ) +{ + BSPFilesCleanup(); + if( mapDrawSurfs != NULL ) + free( mapDrawSurfs ); +} +*/ + + +/* +BSPInfo() +emits statistics about the bsp file +*/ + +int BSPInfo() +{ + char source[ 1024 ], ext[ 64 ]; + int size; + FILE *f; + + Sys_Printf ("\n----- INFO ----\n\n"); + + /* dummy check */ + if( mapname == NULL ) + { + Sys_Printf( "No files to dump info for.\n"); + return -1; + } + + /* enable info mode */ + //infoMode = qtrue; + + + /* mangle filename and get size */ + strcpy( source, mapname ); + ExtractFileExtension( source, ext ); + if( !Q_stricmp( ext, "map" ) ) + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + f = fopen( source, "rb" ); + if( f ) + { + size = Q_filelength (f); + fclose( f ); + } + else + size = 0; + + /* load the bsp file and print lump sizes */ + Sys_Printf( "Map: %s\n\n", source ); + + Sys_Printf( "-----------------------------------------------------\n" ); + + LoadBSPFile( source ); + PrintBSPFileSizes(); + + Sys_Printf( "-----------------------------------------------------\n" ); + + /* print sizes */ + Sys_Printf( "Total: %d B = %.3f kB = %.3f MB\n", size, size / 1024.0, size / (1024.0 * 1024.0) ); + + Sys_Printf( "-----------------------------------------------------\n" ); + + /* return count */ + return 0; +} + + + +/* +ScaleBSPMain() +amaze and confuse your enemies with wierd scaled maps! +*/ +/* +int ScaleBSPMain( int argc, char **argv ) +{ + int i; + float f, scale; + vec3_t vec; + char str[ 1024 ]; + + + // arg checking + if( argc < 2 ) + { + Sys_Printf( "Usage: q3map -scale [-v] \n" ); + return 0; + } + + // get scale + scale = atof( argv[ argc - 2 ] ); + if( scale == 0.0f ) + { + Sys_Printf( "Usage: q3map -scale [-v] \n" ); + Sys_Printf( "Non-zero scale value required.\n" ); + return 0; + } + + // do some path mangling + strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + + // load the bsp + Sys_Printf( "Loading %s\n", source ); + LoadBSPFile( source ); + ParseEntities(); + + // note it + Sys_Printf( "--- ScaleBSP ---\n" ); + Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities ); + + // scale entity keys + for( i = 0; i < numBSPEntities && i < numEntities; i++ ) + { + // scale origin + GetVectorForKey( &entities[ i ], "origin", vec ); + if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) ) + { + VectorScale( vec, scale, vec ); + sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); + SetKeyValue( &entities[ i ], "origin", str ); + } + + // scale door lip + f = FloatForKey( &entities[ i ], "lip" ); + if( f ) + { + f *= scale; + sprintf( str, "%f", f ); + SetKeyValue( &entities[ i ], "lip", str ); + } + } + + // scale models + for( i = 0; i < numBSPModels; i++ ) + { + VectorScale( bspModels[ i ].mins, scale, bspModels[ i ].mins ); + VectorScale( bspModels[ i ].maxs, scale, bspModels[ i ].maxs ); + } + + // scale nodes + for( i = 0; i < numBSPNodes; i++ ) + { + VectorScale( bspNodes[ i ].mins, scale, bspNodes[ i ].mins ); + VectorScale( bspNodes[ i ].maxs, scale, bspNodes[ i ].maxs ); + } + + // scale leafs + for( i = 0; i < numBSPLeafs; i++ ) + { + VectorScale( bspLeafs[ i ].mins, scale, bspLeafs[ i ].mins ); + VectorScale( bspLeafs[ i ].maxs, scale, bspLeafs[ i ].maxs ); + } + + // scale drawverts + for( i = 0; i < numBSPDrawVerts; i++ ) + VectorScale( bspDrawVerts[ i ].xyz, scale, bspDrawVerts[ i ].xyz ); + + // scale planes + for( i = 0; i < numBSPPlanes; i++ ) + bspPlanes[ i ].dist *= scale; + + // scale gridsize + GetVectorForKey( &entities[ 0 ], "gridsize", vec ); + if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f ) + VectorCopy( gridSize, vec ); + VectorScale( vec, scale, vec ); + sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); + SetKeyValue( &entities[ 0 ], "gridsize", str ); + + // write the bsp + UnparseEntities(); + StripExtension( source ); + DefaultExtension( source, "_s.bsp" ); + Sys_Printf( "Writing %s\n", source ); + WriteBSPFile( source ); + + // return to sender + return 0; +} +*/ + + +/* +ConvertBSPMain() +main argument processing function for bsp conversion +*/ +/* +int ConvertBSPMain( int argc, char **argv ) +{ + int i; + int (*convertFunc)( char * ); + + + // set default + convertFunc = ConvertBSPToASE; + + // arg checking + if( argc < 1 ) + { + Sys_Printf( "Usage: q3map -scale [-v] \n" ); + return 0; + } + + // process arguments + for( i = 1; i < (argc - 1); i++ ) + { + // -format map|ase|... + if( !strcmp( argv[ i ], "-format" ) ) + { + i++; + if( !Q_stricmp( argv[ i ], "ase" ) ) + convertFunc = ConvertBSPToASE; + else if( !Q_stricmp( argv[ i ], "map" ) ) + convertFunc = ConvertBSPToMap; + else + Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); + } + } + + // clean up map name + strcpy( source, ExpandArg( argv[ i ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + + LoadShaderInfo(); + + Sys_Printf( "Loading %s\n", source ); + + // ydnar: load surface file + //% LoadSurfaceExtraFile( source ); + + LoadBSPFile( source ); + + // parse bsp entities + ParseEntities(); + + // convert + return convertFunc( source ); +} +*/ + +int Check_BSP_Options( int argc, char **argv ) +{ + int i; + + for (i=1 ; i 59 ) + Sys_Printf("%d Minutes ", total_time/60 ); + Sys_Printf( "%d Seconds\n", total_time%60 ); + + /* shut down connection */ + Broadcast_Shutdown(); + + /* return any error code */ + return r; +} diff --git a/tools/quake2/q2map/map.c b/tools/quake2/q2map/map.c new file mode 100644 index 00000000..ac3be9d8 --- /dev/null +++ b/tools/quake2/q2map/map.c @@ -0,0 +1,1017 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// map.c + +#include "qbsp.h" + +extern qboolean onlyents; + +int nummapbrushes; +mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +int nummapbrushsides; +side_t brushsides[MAX_MAP_SIDES]; +brush_texture_t side_brushtextures[MAX_MAP_SIDES]; + +int nummapplanes; +plane_t mapplanes[MAX_MAP_PLANES]; + +#define PLANE_HASHES 1024 +plane_t *planehash[PLANE_HASHES]; + +vec3_t map_mins, map_maxs; + +// undefine to make plane finding use linear sort +#define USE_HASHING + +void TestExpandBrushes (void); + +int c_boxbevels; +int c_edgebevels; + +int c_areaportals; + +int c_clipbrushes; + +/* +============================================================================= + +PLANE FINDING + +============================================================================= +*/ + + +/* +================= +PlaneTypeForNormal +================= +*/ +int PlaneTypeForNormal (vec3_t normal) +{ + vec_t ax, ay, az; + +// NOTE: should these have an epsilon around 1.0? + if (normal[0] == 1.0 || normal[0] == -1.0) + return PLANE_X; + if (normal[1] == 1.0 || normal[1] == -1.0) + return PLANE_Y; + if (normal[2] == 1.0 || normal[2] == -1.0) + return PLANE_Z; + + ax = fabs(normal[0]); + ay = fabs(normal[1]); + az = fabs(normal[2]); + + if (ax >= ay && ax >= az) + return PLANE_ANYX; + if (ay >= ax && ay >= az) + return PLANE_ANYY; + return PLANE_ANYZ; +} + +/* +================ +PlaneEqual +================ +*/ +#define NORMAL_EPSILON 0.00001 +#define DIST_EPSILON 0.01 +qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist) +{ +#if 1 + if ( + fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON + && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON + && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON + && fabs(p->dist - dist) < DIST_EPSILON ) + return true; +#else + if (p->normal[0] == normal[0] + && p->normal[1] == normal[1] + && p->normal[2] == normal[2] + && p->dist == dist) + return true; +#endif + return false; +} + +/* +================ +AddPlaneToHash +================ +*/ +void AddPlaneToHash (plane_t *p) +{ + int hash; + + hash = (int)fabs(p->dist) / 8; + hash &= (PLANE_HASHES-1); + + p->hash_chain = planehash[hash]; + planehash[hash] = p; +} + +/* +================ +CreateNewFloatPlane +================ +*/ +int CreateNewFloatPlane (vec3_t normal, vec_t dist) +{ + plane_t *p, temp; + + if (VectorLength(normal) < 0.5) + Error ("FloatPlane: bad normal"); + // create a new plane + if (nummapplanes+2 > MAX_MAP_PLANES) + Error ("MAX_MAP_PLANES"); + + p = &mapplanes[nummapplanes]; + VectorCopy (normal, p->normal); + p->dist = dist; + p->type = (p+1)->type = PlaneTypeForNormal (p->normal); + + VectorSubtract (vec3_origin, normal, (p+1)->normal); + (p+1)->dist = -dist; + + nummapplanes += 2; + + // allways put axial planes facing positive first + if (p->type < 3) + { + if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) + { + // flip order + temp = *p; + *p = *(p+1); + *(p+1) = temp; + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 1; + } + } + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 2; +} + +/* +============== +SnapVector +============== +*/ +void SnapVector (vec3_t normal) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(normal[i] - 1) < NORMAL_EPSILON ) + { + VectorClear (normal); + normal[i] = 1; + break; + } + if ( fabs(normal[i] - -1) < NORMAL_EPSILON ) + { + VectorClear (normal); + normal[i] = -1; + break; + } + } +} + +/* +============== +SnapPlane +============== +*/ +void SnapPlane (vec3_t normal, vec_t *dist) +{ + SnapVector (normal); + + if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON) + *dist = Q_rint(*dist); +} + +/* +============= +FindFloatPlane + +============= +*/ +#ifndef USE_HASHING +int FindFloatPlane (vec3_t normal, vec_t dist) +{ + int i; + plane_t *p; + + SnapPlane (normal, &dist); + for (i=0, p=mapplanes ; ihash_chain) + { + if (PlaneEqual (p, normal, dist)) + return p-mapplanes; + } + } + + return CreateNewFloatPlane (normal, dist); +} +#endif + +/* +================ +PlaneFromPoints +================ +*/ +int PlaneFromPoints (int *p0, int *p1, int *p2) +{ + vec3_t t1, t2, normal; + vec_t dist; + + VectorSubtract (p0, p1, t1); + VectorSubtract (p2, p1, t2); + CrossProduct (t1, t2, normal); + VectorNormalize (normal, normal); + + dist = DotProduct (p0, normal); + + return FindFloatPlane (normal, dist); +} + + +//==================================================================== + + +/* +=========== +BrushContents +=========== +*/ +int BrushContents (mapbrush_t *b) +{ + int contents; + side_t *s; + int i; + int trans; + + s = &b->original_sides[0]; + contents = s->contents; + trans = texinfo[s->texinfo].flags; + for (i=1 ; inumsides ; i++, s++) + { + s = &b->original_sides[i]; + trans |= texinfo[s->texinfo].flags; + if (s->contents != contents) + { + Sys_Printf ("Entity %i, Brush %i: mixed face contents\n" + , b->entitynum, b->brushnum); + break; + } + } + + // if any side is translucent, mark the contents + // and change solid to window + if ( trans & (SURF_TRANS33|SURF_TRANS66) ) + { + contents |= CONTENTS_TRANSLUCENT; + if (contents & CONTENTS_SOLID) + { + contents &= ~CONTENTS_SOLID; + contents |= CONTENTS_WINDOW; + } + } + + return contents; +} + + +//============================================================================ + +/* +================= +AddBrushBevels + +Adds any additional planes necessary to allow the brush to be expanded +against axial bounding boxes +================= +*/ +void AddBrushBevels (mapbrush_t *b) +{ + int axis, dir; + int i, j, k, l, order; + side_t sidetemp; + brush_texture_t tdtemp; + side_t *s, *s2; + vec3_t normal; + float dist; + winding_t *w, *w2; + vec3_t vec, vec2; + float d; + + // + // add the axial planes + // + order = 0; + for (axis=0 ; axis <3 ; axis++) + { + for (dir=-1 ; dir <= 1 ; dir+=2, order++) + { + // see if the plane is allready present + for (i=0, s=b->original_sides ; inumsides ; i++,s++) + { + if (mapplanes[s->planenum].normal[axis] == dir) + break; + } + + if (i == b->numsides) + { // add a new side + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + nummapbrushsides++; + b->numsides++; + VectorClear (normal); + normal[axis] = dir; + if (dir == 1) + dist = b->maxs[axis]; + else + dist = -b->mins[axis]; + s->planenum = FindFloatPlane (normal, dist); + s->texinfo = b->original_sides[0].texinfo; + s->contents = b->original_sides[0].contents; + s->bevel = true; + c_boxbevels++; + } + + // if the plane is not in it canonical order, swap it + if (i != order) + { + sidetemp = b->original_sides[order]; + b->original_sides[order] = b->original_sides[i]; + b->original_sides[i] = sidetemp; + + j = b->original_sides - brushsides; + tdtemp = side_brushtextures[j+order]; + side_brushtextures[j+order] = side_brushtextures[j+i]; + side_brushtextures[j+i] = tdtemp; + } + } + } + + // + // add the edge bevels + // + if (b->numsides == 6) + return; // pure axial + + // test the non-axial plane edges + for (i=6 ; inumsides ; i++) + { + s = b->original_sides + i; + w = s->winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + k = (j+1)%w->numpoints; + VectorSubtract (w->p[j], w->p[k], vec); + if (VectorNormalize (vec, vec) < 0.5) + continue; + SnapVector (vec); + for (k=0 ; k<3 ; k++) + if ( vec[k] == -1 || vec[k] == 1) + break; // axial + if (k != 3) + continue; // only test non-axial edges + + // try the six possible slanted axials from this edge + for (axis=0 ; axis <3 ; axis++) + { + for (dir=-1 ; dir <= 1 ; dir+=2) + { + // construct a plane + VectorClear (vec2); + vec2[axis] = dir; + CrossProduct (vec, vec2, normal); + if (VectorNormalize (normal, normal) < 0.5) + continue; + dist = DotProduct (w->p[j], normal); + + // if all the points on all the sides are + // behind this plane, it is a proper edge bevel + for (k=0 ; knumsides ; k++) + { + // if this plane has allready been used, skip it + if (PlaneEqual (&mapplanes[b->original_sides[k].planenum] + , normal, dist) ) + break; + + w2 = b->original_sides[k].winding; + if (!w2) + continue; + for (l=0 ; lnumpoints ; l++) + { + d = DotProduct (w2->p[l], normal) - dist; + if (d > 0.1) + break; // point in front + } + if (l != w2->numpoints) + break; + } + + if (k != b->numsides) + continue; // wasn't part of the outer hull + // add this plane + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + nummapbrushsides++; + s2 = &b->original_sides[b->numsides]; + s2->planenum = FindFloatPlane (normal, dist); + s2->texinfo = b->original_sides[0].texinfo; + s2->contents = b->original_sides[0].contents; + s2->bevel = true; + c_edgebevels++; + b->numsides++; + } + } + } + } +} + + +/* +================ +MakeBrushWindings + +makes basewindigs for sides and mins / maxs for the brush +================ +*/ +qboolean MakeBrushWindings (mapbrush_t *ob) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + ClearBounds (ob->mins, ob->maxs); + + for (i=0 ; inumsides ; i++) + { + plane = &mapplanes[ob->original_sides[i].planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; jnumsides && w; j++) + { + if (i == j) + continue; + if (ob->original_sides[j].bevel) + continue; + plane = &mapplanes[ob->original_sides[j].planenum^1]; + ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); + } + + side = &ob->original_sides[i]; + side->winding = w; + if (w) + { + side->visible = true; + for (j=0 ; jnumpoints ; j++) + AddPointToBounds (w->p[j], ob->mins, ob->maxs); + } + } + + for (i=0 ; i<3 ; i++) + { + if (ob->mins[0] < -4096 || ob->maxs[0] > 4096) + Sys_Printf ("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum); + if (ob->mins[0] > 4096 || ob->maxs[0] < -4096) + Sys_Printf ("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum); + } + + return true; +} + + +/* +================= +ParseBrush +================= +*/ +void ParseBrush (entity_t *mapent) +{ + mapbrush_t *b; + int i,j, k; + int mt; + side_t *side, *s2; + int planenum; + brush_texture_t td; + int planepts[3][3]; + + if (nummapbrushes == MAX_MAP_BRUSHES) + Error ("nummapbrushes == MAX_MAP_BRUSHES"); + + b = &mapbrushes[nummapbrushes]; + b->original_sides = &brushsides[nummapbrushsides]; + b->entitynum = num_entities-1; + b->brushnum = nummapbrushes - mapent->firstbrush; + + do + { + if (!GetToken (true)) + break; + if (!strcmp (token, "}") ) + break; + + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + side = &brushsides[nummapbrushsides]; + + // read the three point plane definition + for (i=0 ; i<3 ; i++) + { + if (i != 0) + GetToken (true); + if (strcmp (token, "(") ) + Error ("parsing brush"); + + for (j=0 ; j<3 ; j++) + { + GetToken (false); + planepts[i][j] = atoi(token); + } + + GetToken (false); + if (strcmp (token, ")") ) + Error ("parsing brush"); + + } + + + // + // read the texturedef + // + GetToken (false); + strcpy (td.name, token); + + GetToken (false); + td.shift[0] = atoi(token); + GetToken (false); + td.shift[1] = atoi(token); + GetToken (false); + td.rotate = atoi(token); + GetToken (false); + td.scale[0] = atof(token); + GetToken (false); + td.scale[1] = atof(token); + + // find default flags and values + mt = FindMiptex (td.name); + td.flags = textureref[mt].flags; + td.value = textureref[mt].value; + side->contents = textureref[mt].contents; + side->surf = td.flags = textureref[mt].flags; + + if (TokenAvailable()) + { + GetToken (false); + side->contents = atoi(token); + GetToken (false); + side->surf = td.flags = atoi(token); + GetToken (false); + td.value = atoi(token); + } + + // translucent objects are automatically classified as detail + if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) + side->contents |= CONTENTS_DETAIL; + if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) + side->contents |= CONTENTS_DETAIL; + if (fulldetail) + side->contents &= ~CONTENTS_DETAIL; + if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) + | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) ) + side->contents |= CONTENTS_SOLID; + + // hints and skips are never detail, and have no content + if (side->surf & (SURF_HINT|SURF_SKIP) ) + { + side->contents = 0; + side->surf &= ~CONTENTS_DETAIL; + } + + + // + // find the plane number + // + planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]); + if (planenum == -1) + { + Sys_Printf ("Entity %i, Brush %i: plane with no normal\n" + , b->entitynum, b->brushnum); + continue; + } + + // + // see if the plane has been used already + // + for (k=0 ; knumsides ; k++) + { + s2 = b->original_sides + k; + if (s2->planenum == planenum) + { + Sys_Printf ("Entity %i, Brush %i: duplicate plane\n" + , b->entitynum, b->brushnum); + break; + } + if ( s2->planenum == (planenum^1) ) + { + Sys_Printf ("Entity %i, Brush %i: mirrored plane\n" + , b->entitynum, b->brushnum); + break; + } + } + if (k != b->numsides) + continue; // duplicated + + // + // keep this side + // + + side = b->original_sides + b->numsides; + side->planenum = planenum; + side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum], + &td, vec3_origin); + + // save the td off in case there is an origin brush and we + // have to recalculate the texinfo + side_brushtextures[nummapbrushsides] = td; + + nummapbrushsides++; + b->numsides++; + } while (1); + + // get the content for the entire brush + b->contents = BrushContents (b); + + // allow detail brushes to be removed + if (nodetail && (b->contents & CONTENTS_DETAIL) ) + { + b->numsides = 0; + return; + } + + // allow water brushes to be removed + if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) + { + b->numsides = 0; + return; + } + + // create windings for sides and bounds for brush + MakeBrushWindings (b); + + // brushes that will not be visible at all will never be + // used as bsp splitters + if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) + { + c_clipbrushes++; + for (i=0 ; inumsides ; i++) + b->original_sides[i].texinfo = TEXINFO_NODE; + } + + // + // origin brushes are removed, but they set + // the rotation origin for the rest of the brushes + // in the entity. After the entire entity is parsed, + // the planenums and texinfos will be adjusted for + // the origin brush + // + if (b->contents & CONTENTS_ORIGIN) + { + char string[32]; + vec3_t origin; + + if (num_entities == 1) + { + Error ("Entity %i, Brush %i: origin brushes not allowed in world" + , b->entitynum, b->brushnum); + return; + } + + VectorAdd (b->mins, b->maxs, origin); + VectorScale (origin, 0.5, origin); + + sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); + SetKeyValue (&entities[b->entitynum], "origin", string); + + VectorCopy (origin, entities[b->entitynum].origin); + + // don't keep this brush + b->numsides = 0; + + return; + } + + AddBrushBevels (b); + + nummapbrushes++; + mapent->numbrushes++; +} + +/* +================ +MoveBrushesToWorld + +Takes all of the brushes from the current entity and +adds them to the world's brush list. + +Used by func_group and func_areaportal +================ +*/ +void MoveBrushesToWorld (entity_t *mapent) +{ + int newbrushes; + int worldbrushes; + mapbrush_t *temp; + int i; + + // this is pretty gross, because the brushes are expected to be + // in linear order for each entity + + newbrushes = mapent->numbrushes; + worldbrushes = entities[0].numbrushes; + + temp = malloc(newbrushes*sizeof(mapbrush_t)); + memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t)); + +#if 0 // let them keep their original brush numbers + for (i=0 ; inumbrushes = 0; +} + +/* +================ +ParseMapEntity +================ +*/ +qboolean ParseMapEntity (void) +{ + entity_t *mapent; + epair_t *e; + side_t *s; + int i, j; + int startbrush, startsides; + vec_t newdist; + mapbrush_t *b; + + if (!GetToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + startbrush = nummapbrushes; + startsides = nummapbrushsides; + + mapent = &entities[num_entities]; + num_entities++; + memset (mapent, 0, sizeof(*mapent)); + mapent->firstbrush = nummapbrushes; + mapent->numbrushes = 0; +// mapent->portalareas[0] = -1; +// mapent->portalareas[1] = -1; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + if (!strcmp (token, "{") ) + ParseBrush (mapent); + else + { + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } + } while (1); + + GetVectorForKey (mapent, "origin", mapent->origin); + + // + // if there was an origin brush, offset all of the planes and texinfo + // + if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) + { + for (i=0 ; inumbrushes ; i++) + { + b = &mapbrushes[mapent->firstbrush + i]; + for (j=0 ; jnumsides ; j++) + { + s = &b->original_sides[j]; + newdist = mapplanes[s->planenum].dist - + DotProduct (mapplanes[s->planenum].normal, mapent->origin); + s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist); + s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum], + &side_brushtextures[s-brushsides], mapent->origin); + } + MakeBrushWindings (b); + } + } + + // group entities are just for editor convenience + // toss all brushes into the world entity + if (!strcmp ("func_group", ValueForKey (mapent, "classname"))) + { + MoveBrushesToWorld (mapent); + mapent->numbrushes = 0; + return true; + } + + // areaportal entities move their brushes, but don't eliminate + // the entity + if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) + { + char str[128]; + + if (mapent->numbrushes != 1) + Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1); + + b = &mapbrushes[nummapbrushes-1]; + b->contents = CONTENTS_AREAPORTAL; + c_areaportals++; + mapent->areaportalnum = c_areaportals; + // set the portal number as "style" + sprintf (str, "%i", c_areaportals); + SetKeyValue (mapent, "style", str); + MoveBrushesToWorld (mapent); + return true; + } + + return true; +} + +//=================================================================== + +/* +================ +LoadMapFile +================ +*/ +void LoadMapFile (char *filename) +{ + int i; + + Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n"); + + LoadScriptFile (filename); + + nummapbrushsides = 0; + num_entities = 0; + + while (ParseMapEntity ()) + { + } + + ClearBounds (map_mins, map_maxs); + for (i=0 ; i 4096) + continue; // no valid points + AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs); + AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs); + } + + Sys_FPrintf( SYS_VRB, "%5i brushes\n", nummapbrushes); + Sys_FPrintf( SYS_VRB, "%5i clipbrushes\n", c_clipbrushes); + Sys_FPrintf( SYS_VRB, "%5i total sides\n", nummapbrushsides); + Sys_FPrintf( SYS_VRB, "%5i boxbevels\n", c_boxbevels); + Sys_FPrintf( SYS_VRB, "%5i edgebevels\n", c_edgebevels); + Sys_FPrintf( SYS_VRB, "%5i entities\n", num_entities); + Sys_FPrintf( SYS_VRB, "%5i planes\n", nummapplanes); + Sys_FPrintf( SYS_VRB, "%5i areaportals\n", c_areaportals); + Sys_FPrintf( SYS_VRB, "size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], + map_maxs[0],map_maxs[1],map_maxs[2]); + +// TestExpandBrushes (); +} + + +//==================================================================== + + +/* +================ +TestExpandBrushes + +Expands all the brush planes and saves a new map out +================ +*/ +void TestExpandBrushes (void) +{ + FILE *f; + side_t *s; + int i, j, bn; + winding_t *w; + char *name = "expanded.map"; + mapbrush_t *brush; + vec_t dist; + + Sys_Printf ("writing %s\n", name); + f = fopen (name, "wb"); + if (!f) + Error ("Can't write %s\b", name); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for (bn=0 ; bnnumsides ; i++) + { + s = brush->original_sides + i; + dist = mapplanes[s->planenum].dist; + for (j=0 ; j<3 ; j++) + dist += fabs( 16 * mapplanes[s->planenum].normal[j] ); + + w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + + Error ("can't proceed after expanding brushes"); +} diff --git a/tools/quake2/q2map/nodraw.c b/tools/quake2/q2map/nodraw.c new file mode 100644 index 00000000..e3f3680b --- /dev/null +++ b/tools/quake2/q2map/nodraw.c @@ -0,0 +1,46 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + +vec3_t draw_mins, draw_maxs; +qboolean drawflag; + +void Draw_ClearWindow (void) +{ +} + +//============================================================ + +#define GLSERV_PORT 25001 + + +void GLS_BeginScene (void) +{ +} + +void GLS_Winding (winding_t *w, int code) +{ +} + +void GLS_EndScene (void) +{ +} diff --git a/tools/quake2/q2map/patches.c b/tools/quake2/q2map/patches.c new file mode 100644 index 00000000..eb76bc39 --- /dev/null +++ b/tools/quake2/q2map/patches.c @@ -0,0 +1,603 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qrad.h" + +vec3_t texture_reflectivity[MAX_MAP_TEXINFO]; + +/* +=================================================================== + + TEXTURE LIGHT VALUES + +=================================================================== +*/ + +/* +====================== +CalcTextureReflectivity_Quake2 +====================== +*/ +void CalcTextureReflectivity_Quake2 (void) +{ + int i; + int j, k, texels; + int color[3]; + int texel; + byte *palette; + char path[1024]; + float r, scale; + miptex_t *mt; + + sprintf (path, "%spics/colormap.pcx", gamedir); + + // get the game palette + Load256Image (path, NULL, &palette, NULL, NULL); + + // allways set index 0 even if no textures + texture_reflectivity[0][0] = 0.5; + texture_reflectivity[0][1] = 0.5; + texture_reflectivity[0][2] = 0.5; + + for (i=0 ; iwidth)*LittleLong(mt->height); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; joffsets[0]) + j]; + for (k=0 ; k<3 ; k++) + color[k] += palette[texel*3+k]; + } + + for (j=0 ; j<3 ; j++) + { + r = color[j]/texels/255.0; + texture_reflectivity[i][j] = r; + } + // scale the reflectivity up, because the textures are + // so dim + scale = ColorNormalize (texture_reflectivity[i], + texture_reflectivity[i]); + if (scale < 0.5) + { + scale *= 2; + VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]); + } +#if 0 +texture_reflectivity[i][0] = 0.5; +texture_reflectivity[i][1] = 0.5; +texture_reflectivity[i][2] = 0.5; +#endif + } +} + +/* +====================== +CalcTextureReflectivity_Heretic2 +====================== +*/ +void CalcTextureReflectivity_Heretic2 (void) +{ + int i; + int j, texels; + int color[3]; + int texel; + char path[1024]; + float r; + miptex_m8_t *mt; + miptex_m32_t *mt32; + byte *pos; + + + // allways set index 0 even if no textures + texture_reflectivity[0][0] = 0.5; + texture_reflectivity[0][1] = 0.5; + texture_reflectivity[0][2] = 0.5; + + for (i=0 ; iwidth[0])*LittleLong(mt->height[0]); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; joffsets[0]) + j]; + color[0] += mt->palette[texel].r; + color[1] += mt->palette[texel].g; + color[2] += mt->palette[texel].b; + } + + free(mt); + } + else + { + texels = LittleLong(mt32->width[0])*LittleLong(mt32->height[0]); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; joffsets[0] + (j<<2); + color[0] += *pos++; // r + color[1] += *pos++; // g + color[2] += *pos++; // b + } + + free(mt32); + } + + + for (j=0 ; j<3 ; j++) + { + r = color[j]/((float) texels*255.0); + texture_reflectivity[i][j] = r; + } + } +} + +/* +======================================================================= + +MAKE FACES + +======================================================================= +*/ + +/* +============= +WindingFromFace +============= +*/ +winding_t *WindingFromFace (dface_t *f) +{ + int i; + int se; + dvertex_t *dv; + int v; + winding_t *w; + + w = AllocWinding (f->numedges); + w->numpoints = f->numedges; + + for (i=0 ; inumedges ; i++) + { + se = dsurfedges[f->firstedge + i]; + if (se < 0) + v = dedges[-se].v[1]; + else + v = dedges[se].v[0]; + + dv = &dvertexes[v]; + VectorCopy (dv->point, w->p[i]); + } + + RemoveColinearPoints (w); + + return w; +} + +/* +============= +BaseLightForFace +============= +*/ +void BaseLightForFace (dface_t *f, vec3_t color) +{ + texinfo_t *tx; + + // + // check for light emited by texture + // + tx = &texinfo[f->texinfo]; + if (!(tx->flags & SURF_LIGHT) || tx->value == 0) + { + VectorClear (color); + return; + } + + VectorScale (texture_reflectivity[f->texinfo], tx->value, color); +} + +qboolean IsSky (dface_t *f) +{ + texinfo_t *tx; + + tx = &texinfo[f->texinfo]; + if (tx->flags & SURF_SKY) + return true; + return false; +} + +/* +============= +MakePatchForFace +============= +*/ +float totalarea; +void MakePatchForFace (int fn, winding_t *w) +{ + dface_t *f; + float area; + patch_t *patch; + dplane_t *pl; + int i; + vec3_t color; + dleaf_t *leaf; + + f = &dfaces[fn]; + + area = WindingArea (w); + totalarea += area; + + patch = &patches[num_patches]; + if (num_patches == MAX_PATCHES) + Error ("num_patches == MAX_PATCHES"); + patch->next = face_patches[fn]; + face_patches[fn] = patch; + + patch->winding = w; + + if (f->side) + patch->plane = &backplanes[f->planenum]; + else + patch->plane = &dplanes[f->planenum]; + if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) + { // origin offset faces must create new planes + if (numplanes + fakeplanes >= MAX_MAP_PLANES) + Error ("numplanes + fakeplanes >= MAX_MAP_PLANES"); + pl = &dplanes[numplanes + fakeplanes]; + fakeplanes++; + + *pl = *(patch->plane); + pl->dist += DotProduct (face_offset[fn], pl->normal); + patch->plane = pl; + } + + WindingCenter (w, patch->origin); + VectorAdd (patch->origin, patch->plane->normal, patch->origin); + leaf = Rad_PointInLeaf(patch->origin); + patch->cluster = leaf->cluster; + if (patch->cluster == -1) + Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n"); + + patch->area = area; + if (patch->area <= 1) + patch->area = 1; + patch->sky = IsSky (f); + + VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity); + + // non-bmodel patches can emit light + if (fn < dmodels[0].numfaces) + { + BaseLightForFace (f, patch->baselight); + + ColorNormalize (patch->reflectivity, color); + + for (i=0 ; i<3 ; i++) + patch->baselight[i] *= color[i]; + + VectorCopy (patch->baselight, patch->totallight); + } + num_patches++; +} + + +entity_t *EntityForModel (int modnum) +{ + int i; + char *s; + char name[16]; + + sprintf (name, "*%i", modnum); + // search the entities for one using modnum + for (i=0 ; inumfaces ; j++) + { + fn = mod->firstface + j; + face_entity[fn] = ent; + VectorCopy (origin, face_offset[fn]); + f = &dfaces[fn]; + w = WindingFromFace (f); + for (k=0 ; knumpoints ; k++) + { + VectorAdd (w->p[k], origin, w->p[k]); + } + MakePatchForFace (fn, w); + } + } + + Sys_FPrintf( SYS_VRB, "%i sqaure feet\n", (int)(totalarea/64)); +} + +/* +======================================================================= + +SUBDIVIDE + +======================================================================= +*/ + +void FinishSplit (patch_t *patch, patch_t *newp) +{ + dleaf_t *leaf; + + VectorCopy (patch->baselight, newp->baselight); + VectorCopy (patch->totallight, newp->totallight); + VectorCopy (patch->reflectivity, newp->reflectivity); + newp->plane = patch->plane; + newp->sky = patch->sky; + + patch->area = WindingArea (patch->winding); + newp->area = WindingArea (newp->winding); + + if (patch->area <= 1) + patch->area = 1; + if (newp->area <= 1) + newp->area = 1; + + WindingCenter (patch->winding, patch->origin); + VectorAdd (patch->origin, patch->plane->normal, patch->origin); + leaf = Rad_PointInLeaf(patch->origin); + patch->cluster = leaf->cluster; + if (patch->cluster == -1) + Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n"); + + WindingCenter (newp->winding, newp->origin); + VectorAdd (newp->origin, newp->plane->normal, newp->origin); + leaf = Rad_PointInLeaf(newp->origin); + newp->cluster = leaf->cluster; + if (newp->cluster == -1) + Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n"); +} + +/* +============= +SubdividePatch + +Chops the patch only if its local bounds exceed the max size +============= +*/ +void SubdividePatch (patch_t *patch) +{ + winding_t *w, *o1, *o2; + vec3_t mins, maxs, total; + vec3_t split; + vec_t dist; + int i, j; + vec_t v; + patch_t *newp; + + w = patch->winding; + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } + VectorSubtract (maxs, mins, total); + for (i=0 ; i<3 ; i++) + if (total[i] > (subdiv+1) ) + break; + if (i == 3) + { + // no splitting needed + return; + } + + // + // split the winding + // + VectorCopy (vec3_origin, split); + split[i] = 1; + dist = (mins[i] + maxs[i])*0.5; + ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); + + // + // create a new patch + // + if (num_patches == MAX_PATCHES) + Error ("MAX_PATCHES"); + newp = &patches[num_patches]; + num_patches++; + + newp->next = patch->next; + patch->next = newp; + + patch->winding = o1; + newp->winding = o2; + + FinishSplit (patch, newp); + + SubdividePatch (patch); + SubdividePatch (newp); +} + + +/* +============= +DicePatch + +Chops the patch by a global grid +============= +*/ +void DicePatch (patch_t *patch) +{ + winding_t *w, *o1, *o2; + vec3_t mins, maxs; + vec3_t split; + vec_t dist; + int i; + patch_t *newp; + + w = patch->winding; + WindingBounds (w, mins, maxs); + for (i=0 ; i<3 ; i++) + if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv)) + break; + if (i == 3) + { + // no splitting needed + return; + } + + // + // split the winding + // + VectorCopy (vec3_origin, split); + split[i] = 1; + dist = subdiv*(1+floor((mins[i]+1)/subdiv)); + ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); + + // + // create a new patch + // + if (num_patches == MAX_PATCHES) + Error ("MAX_PATCHES"); + newp = &patches[num_patches]; + num_patches++; + + newp->next = patch->next; + patch->next = newp; + + patch->winding = o1; + newp->winding = o2; + + FinishSplit (patch, newp); + + DicePatch (patch); + DicePatch (newp); +} + + +/* +============= +SubdividePatches +============= +*/ +void SubdividePatches (void) +{ + int i, num; + + if (subdiv < 1) + return; + + num = num_patches; // because the list will grow + for (i=0 ; i c_peak_portals) + c_peak_portals = c_active_portals; + + p = malloc (sizeof(portal_t)); + memset (p, 0, sizeof(portal_t)); + + return p; +} + +void FreePortal (portal_t *p) +{ + if (p->winding) + FreeWinding (p->winding); + if (numthreads == 1) + c_active_portals--; + free (p); +} + +//============================================================== + +/* +============== +VisibleContents + +Returns the single content bit of the +strongest visible content present +============== +*/ +int VisibleContents (int contents) +{ + int i; + + for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1) + if (contents & i ) + return i; + + return 0; +} + + +/* +=============== +ClusterContents +=============== +*/ +int ClusterContents (node_t *node) +{ + int c1, c2, c; + + if (node->planenum == PLANENUM_LEAF) + return node->contents; + + c1 = ClusterContents(node->children[0]); + c2 = ClusterContents(node->children[1]); + c = c1|c2; + + // a cluster may include some solid detail areas, but + // still be seen into + if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) ) + c &= ~CONTENTS_SOLID; + return c; +} + +/* +============= +Portal_VisFlood + +Returns true if the portal is empty or translucent, allowing +the PVS calculation to see through it. +The nodes on either side of the portal may actually be clusters, +not leafs, so all contents should be ored together +============= +*/ +qboolean Portal_VisFlood (portal_t *p) +{ + int c1, c2; + + if (!p->onnode) + return false; // to global outsideleaf + + c1 = ClusterContents(p->nodes[0]); + c2 = ClusterContents(p->nodes[1]); + + if (!VisibleContents (c1^c2)) + return true; + + if (c1 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL)) + c1 = 0; + if (c2 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL)) + c2 = 0; + + if ( (c1|c2) & CONTENTS_SOLID ) + return false; // can't see through solid + + if (! (c1 ^ c2)) + return true; // identical on both sides + + if (!VisibleContents (c1^c2)) + return true; + return false; +} + + +/* +=============== +Portal_EntityFlood + +The entity flood determines which areas are +"outside" on the map, which are then filled in. +Flowing from side s to side !s +=============== +*/ +qboolean Portal_EntityFlood (portal_t *p, int s) +{ + if (p->nodes[0]->planenum != PLANENUM_LEAF + || p->nodes[1]->planenum != PLANENUM_LEAF) + Error ("Portal_EntityFlood: not a leaf"); + + // can never cross to a solid + if ( (p->nodes[0]->contents & CONTENTS_SOLID) + || (p->nodes[1]->contents & CONTENTS_SOLID) ) + return false; + + // can flood through everything else + return true; +} + + +//============================================================================= + +int c_tinyportals; + +/* +============= +AddPortalToNodes +============= +*/ +void AddPortalToNodes (portal_t *p, node_t *front, node_t *back) +{ + if (p->nodes[0] || p->nodes[1]) + Error ("AddPortalToNode: allready included"); + + p->nodes[0] = front; + p->next[0] = front->portals; + front->portals = p; + + p->nodes[1] = back; + p->next[1] = back->portals; + back->portals = p; +} + + +/* +============= +RemovePortalFromNode +============= +*/ +void RemovePortalFromNode (portal_t *portal, node_t *l) +{ + portal_t **pp, *t; + +// remove reference to the current portal + pp = &l->portals; + while (1) + { + t = *pp; + if (!t) + Error ("RemovePortalFromNode: portal not in leaf"); + + if ( t == portal ) + break; + + if (t->nodes[0] == l) + pp = &t->next[0]; + else if (t->nodes[1] == l) + pp = &t->next[1]; + else + Error ("RemovePortalFromNode: portal not bounding leaf"); + } + + if (portal->nodes[0] == l) + { + *pp = portal->next[0]; + portal->nodes[0] = NULL; + } + else if (portal->nodes[1] == l) + { + *pp = portal->next[1]; + portal->nodes[1] = NULL; + } +} + +//============================================================================ + +void PrintPortal (portal_t *p) +{ + int i; + winding_t *w; + + w = p->winding; + for (i=0 ; inumpoints ; i++) + Sys_Printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0] + , w->p[i][1], w->p[i][2]); +} + +/* +================ +MakeHeadnodePortals + +The created portals will face the global outside_node +================ +*/ +#define SIDESPACE 8 +void MakeHeadnodePortals (tree_t *tree) +{ + vec3_t bounds[2]; + int i, j, n; + portal_t *p, *portals[6]; + plane_t bplanes[6], *pl; + node_t *node; + + node = tree->headnode; + +// pad with some space so there will never be null volume leafs + for (i=0 ; i<3 ; i++) + { + bounds[0][i] = tree->mins[i] - SIDESPACE; + bounds[1][i] = tree->maxs[i] + SIDESPACE; + } + + tree->outside_node.planenum = PLANENUM_LEAF; + tree->outside_node.brushlist = NULL; + tree->outside_node.portals = NULL; + tree->outside_node.contents = 0; + + for (i=0 ; i<3 ; i++) + for (j=0 ; j<2 ; j++) + { + n = j*3 + i; + + p = AllocPortal (); + portals[n] = p; + + pl = &bplanes[n]; + memset (pl, 0, sizeof(*pl)); + if (j) + { + pl->normal[i] = -1; + pl->dist = -bounds[j][i]; + } + else + { + pl->normal[i] = 1; + pl->dist = bounds[j][i]; + } + p->plane = *pl; + p->winding = BaseWindingForPlane (pl->normal, pl->dist); + AddPortalToNodes (p, node, &tree->outside_node); + } + +// clip the basewindings by all the other planes + for (i=0 ; i<6 ; i++) + { + for (j=0 ; j<6 ; j++) + { + if (j == i) + continue; + ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON); + } + } +} + +//=================================================== + + +/* +================ +BaseWindingForNode +================ +*/ +#define BASE_WINDING_EPSILON 0.001 +#define SPLIT_WINDING_EPSILON 0.001 + +winding_t *BaseWindingForNode (node_t *node) +{ + winding_t *w; + node_t *n; + plane_t *plane; + vec3_t normal; + vec_t dist; + + w = BaseWindingForPlane (mapplanes[node->planenum].normal + , mapplanes[node->planenum].dist); + + // clip by all the parents + for (n=node->parent ; n && w ; ) + { + plane = &mapplanes[n->planenum]; + + if (n->children[0] == node) + { // take front + ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); + } + else + { // take back + VectorSubtract (vec3_origin, plane->normal, normal); + dist = -plane->dist; + ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON); + } + node = n; + n = n->parent; + } + + return w; +} + +//============================================================ + +qboolean WindingIsTiny (winding_t *w); + +/* +================== +MakeNodePortal + +create the new portal by taking the full plane winding for the cutting plane +and clipping it by all of parents of this node +================== +*/ +void MakeNodePortal (node_t *node) +{ + portal_t *new_portal, *p; + winding_t *w; + vec3_t normal; + float dist; + int side; + + w = BaseWindingForNode (node); + + // clip the portal by all the other portals in the node + for (p = node->portals ; p && w; p = p->next[side]) + { + if (p->nodes[0] == node) + { + side = 0; + VectorCopy (p->plane.normal, normal); + dist = p->plane.dist; + } + else if (p->nodes[1] == node) + { + side = 1; + VectorSubtract (vec3_origin, p->plane.normal, normal); + dist = -p->plane.dist; + } + else + Error ("CutNodePortals_r: mislinked portal"); + + ChopWindingInPlace (&w, normal, dist, 0.1); + } + + if (!w) + { + return; + } + + if (WindingIsTiny (w)) + { + c_tinyportals++; + FreeWinding (w); + return; + } + + + new_portal = AllocPortal (); + new_portal->plane = mapplanes[node->planenum]; + new_portal->onnode = node; + new_portal->winding = w; + AddPortalToNodes (new_portal, node->children[0], node->children[1]); +} + + +/* +============== +SplitNodePortals + +Move or split the portals that bound node so that the node's +children have portals instead of node. +============== +*/ +void SplitNodePortals (node_t *node) +{ + portal_t *p, *next_portal, *new_portal; + node_t *f, *b, *other_node; + int side; + plane_t *plane; + winding_t *frontwinding, *backwinding; + + plane = &mapplanes[node->planenum]; + f = node->children[0]; + b = node->children[1]; + + for (p = node->portals ; p ; p = next_portal) + { + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + side = 1; + else + Error ("CutNodePortals_r: mislinked portal"); + next_portal = p->next[side]; + + other_node = p->nodes[!side]; + RemovePortalFromNode (p, p->nodes[0]); + RemovePortalFromNode (p, p->nodes[1]); + +// +// cut the portal into two portals, one on each side of the cut plane +// + ClipWindingEpsilon (p->winding, plane->normal, plane->dist, + SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); + + if (frontwinding && WindingIsTiny(frontwinding)) + { + FreeWinding (frontwinding); + frontwinding = NULL; + c_tinyportals++; + } + + if (backwinding && WindingIsTiny(backwinding)) + { + FreeWinding (backwinding); + backwinding = NULL; + c_tinyportals++; + } + + if (!frontwinding && !backwinding) + { // tiny windings on both sides + continue; + } + + if (!frontwinding) + { + FreeWinding (backwinding); + if (side == 0) + AddPortalToNodes (p, b, other_node); + else + AddPortalToNodes (p, other_node, b); + continue; + } + if (!backwinding) + { + FreeWinding (frontwinding); + if (side == 0) + AddPortalToNodes (p, f, other_node); + else + AddPortalToNodes (p, other_node, f); + continue; + } + + // the winding is split + new_portal = AllocPortal (); + *new_portal = *p; + new_portal->winding = backwinding; + FreeWinding (p->winding); + p->winding = frontwinding; + + if (side == 0) + { + AddPortalToNodes (p, f, other_node); + AddPortalToNodes (new_portal, b, other_node); + } + else + { + AddPortalToNodes (p, other_node, f); + AddPortalToNodes (new_portal, other_node, b); + } + } + + node->portals = NULL; +} + + +/* +================ +CalcNodeBounds +================ +*/ +void CalcNodeBounds (node_t *node) +{ + portal_t *p; + int s; + int i; + + // calc mins/maxs for both leafs and nodes + ClearBounds (node->mins, node->maxs); + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + for (i=0 ; iwinding->numpoints ; i++) + AddPointToBounds (p->winding->p[i], node->mins, node->maxs); + } +} + + +/* +================== +MakeTreePortals_r +================== +*/ +void MakeTreePortals_r (node_t *node) +{ + int i; + + CalcNodeBounds (node); + if (node->mins[0] >= node->maxs[0]) + { + Sys_Printf ("WARNING: node without a volume\n"); + } + + for (i=0 ; i<3 ; i++) + { + if (node->mins[i] < -8000 || node->maxs[i] > 8000) + { + Sys_Printf ("WARNING: node with unbounded volume\n"); + break; + } + } + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + MakeTreePortals_r (node->children[0]); + MakeTreePortals_r (node->children[1]); +} + +/* +================== +MakeTreePortals +================== +*/ +void MakeTreePortals (tree_t *tree) +{ + MakeHeadnodePortals (tree); + MakeTreePortals_r (tree->headnode); +} + +/* +========================================================= + +FLOOD ENTITIES + +========================================================= +*/ + +/* +============= +FloodPortals_r +============= +*/ +void FloodPortals_r (node_t *node, int dist) +{ + portal_t *p; + int s; + + node->occupied = dist; + + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + + if (p->nodes[!s]->occupied) + continue; + + if (!Portal_EntityFlood (p, s)) + continue; + + FloodPortals_r (p->nodes[!s], dist+1); + } +} + +/* +============= +PlaceOccupant +============= +*/ +qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant) +{ + node_t *node; + vec_t d; + plane_t *plane; + + // find the leaf to start in + node = headnode; + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if (d >= 0) + node = node->children[0]; + else + node = node->children[1]; + } + + if (node->contents == CONTENTS_SOLID) + return false; + node->occupant = occupant; + + FloodPortals_r (node, 1); + + return true; +} + +/* +============= +FloodEntities + +Marks all nodes that can be reached by entites +============= +*/ +qboolean FloodEntities (tree_t *tree) +{ + int i; + vec3_t origin; + char *cl; + qboolean inside; + node_t *headnode; + + headnode = tree->headnode; + Sys_FPrintf( SYS_VRB, "--- FloodEntities ---\n"); + inside = false; + tree->outside_node.occupied = 0; + + for (i=1 ; ioutside_node.occupied) + { + Sys_FPrintf( SYS_VRB, "entity reached from outside -- no filling\n"); + } + + return (qboolean)(inside && !tree->outside_node.occupied); +} + +/* +========================================================= + +FLOOD AREAS + +========================================================= +*/ + +int c_areas; + +/* +============= +FloodAreas_r +============= +*/ +void FloodAreas_r (node_t *node) +{ + portal_t *p; + int s; + bspbrush_t *b; + entity_t *e; + + if (node->contents == CONTENTS_AREAPORTAL) + { + // this node is part of an area portal + b = node->brushlist; + e = &entities[b->original->entitynum]; + + // if the current area has allready touched this + // portal, we are done + if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas) + return; + + // note the current area as bounding the portal + if (e->portalareas[1]) + { + Sys_Printf ("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum); + return; + } + if (e->portalareas[0]) + e->portalareas[1] = c_areas; + else + e->portalareas[0] = c_areas; + + return; + } + + if (node->area) + return; // allready got it + node->area = c_areas; + + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); +#if 0 + if (p->nodes[!s]->occupied) + continue; +#endif + if (!Portal_EntityFlood (p, s)) + continue; + + FloodAreas_r (p->nodes[!s]); + } +} + +/* +============= +FindAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void FindAreas_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FindAreas_r (node->children[0]); + FindAreas_r (node->children[1]); + return; + } + + if (node->area) + return; // allready got it + + if (node->contents & CONTENTS_SOLID) + return; + + if (!node->occupied) + return; // not reachable by entities + + // area portals are allways only flooded into, never + // out of + if (node->contents == CONTENTS_AREAPORTAL) + return; + + c_areas++; + FloodAreas_r (node); +} + +/* +============= +SetAreaPortalAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void SetAreaPortalAreas_r (node_t *node) +{ + bspbrush_t *b; + entity_t *e; + + if (node->planenum != PLANENUM_LEAF) + { + SetAreaPortalAreas_r (node->children[0]); + SetAreaPortalAreas_r (node->children[1]); + return; + } + + if (node->contents == CONTENTS_AREAPORTAL) + { + if (node->area) + return; // allready set + + b = node->brushlist; + e = &entities[b->original->entitynum]; + node->area = e->portalareas[0]; + if (!e->portalareas[1]) + { + Sys_Printf ("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum); + return; + } + } +} + +/* +============= +EmitAreaPortals + +============= +*/ +void EmitAreaPortals (node_t *headnode) +{ + int i, j; + entity_t *e; + dareaportal_t *dp; + + if (c_areas > MAX_MAP_AREAS) + Error ("MAX_MAP_AREAS"); + numareas = c_areas+1; + numareaportals = 1; // leave 0 as an error + + for (i=1 ; i<=c_areas ; i++) + { + dareas[i].firstareaportal = numareaportals; + for (j=0 ; jareaportalnum) + continue; + dp = &dareaportals[numareaportals]; + if (e->portalareas[0] == i) + { + dp->portalnum = e->areaportalnum; + dp->otherarea = e->portalareas[1]; + numareaportals++; + } + else if (e->portalareas[1] == i) + { + dp->portalnum = e->areaportalnum; + dp->otherarea = e->portalareas[0]; + numareaportals++; + } + } + dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal; + } + + Sys_FPrintf( SYS_VRB, "%5i numareas\n", numareas); + Sys_FPrintf( SYS_VRB, "%5i numareaportals\n", numareaportals); +} + +/* +============= +FloodAreas + +Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL +============= +*/ +void FloodAreas (tree_t *tree) +{ + Sys_FPrintf( SYS_VRB, "--- FloodAreas ---\n"); + FindAreas_r (tree->headnode); + SetAreaPortalAreas_r (tree->headnode); + Sys_FPrintf( SYS_VRB, "%5i areas\n", c_areas); +} + +//====================================================== + +int c_outside; +int c_inside; +int c_solid; + +void FillOutside_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FillOutside_r (node->children[0]); + FillOutside_r (node->children[1]); + return; + } + + // anything not reachable by an entity + // can be filled away + if (!node->occupied) + { + if (node->contents != CONTENTS_SOLID) + { + c_outside++; + node->contents = CONTENTS_SOLID; + } + else + c_solid++; + } + else + c_inside++; + +} + +/* +============= +FillOutside + +Fill all nodes that can't be reached by entities +============= +*/ +void FillOutside (node_t *headnode) +{ + c_outside = 0; + c_inside = 0; + c_solid = 0; + Sys_FPrintf( SYS_VRB, "--- FillOutside ---\n"); + FillOutside_r (headnode); + Sys_FPrintf( SYS_VRB, "%5i solid leafs\n", c_solid); + Sys_FPrintf( SYS_VRB, "%5i leafs filled\n", c_outside); + Sys_FPrintf( SYS_VRB, "%5i inside leafs\n", c_inside); +} + + +//============================================================== + +/* +============ +FindPortalSide + +Finds a brush side to use for texturing the given portal +============ +*/ +void FindPortalSide (portal_t *p) +{ + int viscontents; + bspbrush_t *bb; + mapbrush_t *brush; + node_t *n; + int i,j; + int planenum; + side_t *side, *bestside; + float dot, bestdot; + plane_t *p1, *p2; + + // decide which content change is strongest + // solid > lava > water, etc + viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents); + if (!viscontents) + return; + + planenum = p->onnode->planenum; + bestside = NULL; + bestdot = 0; + + for (j=0 ; j<2 ; j++) + { + n = p->nodes[j]; + p1 = &mapplanes[p->onnode->planenum]; + for (bb=n->brushlist ; bb ; bb=bb->next) + { + brush = bb->original; + if ( !(brush->contents & viscontents) ) + continue; + for (i=0 ; inumsides ; i++) + { + side = &brush->original_sides[i]; + if (side->bevel) + continue; + if (side->texinfo == TEXINFO_NODE) + continue; // non-visible + if ((side->planenum&~1) == planenum) + { // exact match + bestside = &brush->original_sides[i]; + goto gotit; + } + // see how close the match is + p2 = &mapplanes[side->planenum&~1]; + dot = DotProduct (p1->normal, p2->normal); + if (dot > bestdot) + { + bestdot = dot; + bestside = side; + } + } + } + } + +gotit: + if (!bestside) + Sys_FPrintf( SYS_VRB, "WARNING: side not found for portal\n"); + + p->sidefound = true; + p->side = bestside; +} + + +/* +=============== +MarkVisibleSides_r + +=============== +*/ +void MarkVisibleSides_r (node_t *node) +{ + portal_t *p; + int s; + + if (node->planenum != PLANENUM_LEAF) + { + MarkVisibleSides_r (node->children[0]); + MarkVisibleSides_r (node->children[1]); + return; + } + + // empty leafs are never boundary leafs + if (!node->contents) + return; + + // see if there is a visible face + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (!p->onnode) + continue; // edge of world + if (!p->sidefound) + FindPortalSide (p); + if (p->side) + p->side->visible = true; + } + +} + +/* +============= +MarkVisibleSides + +============= +*/ +void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush) +{ + int i, j; + mapbrush_t *mb; + int numsides; + + Sys_FPrintf( SYS_VRB, "--- MarkVisibleSides ---\n"); + + // clear all the visible flags + for (i=startbrush ; inumsides; + for (j=0 ; joriginal_sides[j].visible = false; + } + + // set visible flags on the sides that are used by portals + MarkVisibleSides_r (tree->headnode); +} + diff --git a/tools/quake2/q2map/prtfile.c b/tools/quake2/q2map/prtfile.c new file mode 100644 index 00000000..c88e039c --- /dev/null +++ b/tools/quake2/q2map/prtfile.c @@ -0,0 +1,286 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + +/* +============================================================================== + +PORTAL FILE GENERATION + +Save out name.prt for qvis to read +============================================================================== +*/ + + +#define PORTALFILE "PRT1" + +FILE *pf; +int num_visclusters; // clusters the player can be in +int num_visportals; + +void WriteFloat (FILE *f, vec_t v) +{ + if ( fabs(v - Q_rint(v)) < 0.001 ) + fprintf (f,"%i ",(int)Q_rint(v)); + else + fprintf (f,"%f ",v); +} + +/* +================= +WritePortalFile_r +================= +*/ +void WritePortalFile_r (node_t *node) +{ + int i, s; + portal_t *p; + winding_t *w; + vec3_t normal; + vec_t dist; + + // decision node + if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) + { + WritePortalFile_r (node->children[0]); + WritePortalFile_r (node->children[1]); + return; + } + + if (node->contents & CONTENTS_SOLID) + return; + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w && p->nodes[0] == node) + { + if (!Portal_VisFlood (p)) + continue; + // write out to the file + + // sometimes planes get turned around when they are very near + // the changeover point between different axis. interpret the + // plane the same way vis will, and flip the side orders if needed + // FIXME: is this still relevent? + WindingPlane (w, normal, &dist); + if ( DotProduct (p->plane.normal, normal) < 0.99 ) + { // backwards... + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster); + } + else + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster); + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->p[i][0]); + WriteFloat (pf, w->p[i][1]); + WriteFloat (pf, w->p[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + } + +} + +/* +================ +FillLeafNumbers_r + +All of the leafs under node will have the same cluster +================ +*/ +void FillLeafNumbers_r (node_t *node, int num) +{ + if (node->planenum == PLANENUM_LEAF) + { + if (node->contents & CONTENTS_SOLID) + node->cluster = -1; + else + node->cluster = num; + return; + } + node->cluster = num; + FillLeafNumbers_r (node->children[0], num); + FillLeafNumbers_r (node->children[1], num); +} + +/* +================ +NumberLeafs_r +================ +*/ +void NumberLeafs_r (node_t *node) +{ + portal_t *p; + + if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) + { // decision node + node->cluster = -99; + NumberLeafs_r (node->children[0]); + NumberLeafs_r (node->children[1]); + return; + } + + // either a leaf or a detail cluster + + if ( node->contents & CONTENTS_SOLID ) + { // solid block, viewpoint never inside + node->cluster = -1; + return; + } + + FillLeafNumbers_r (node, num_visclusters); + num_visclusters++; + + // count the portals + for (p = node->portals ; p ; ) + { + if (p->nodes[0] == node) // only write out from first leaf + { + if (Portal_VisFlood (p)) + num_visportals++; + p = p->next[0]; + } + else + p = p->next[1]; + } + +} + + +/* +================ +CreateVisPortals_r +================ +*/ +void CreateVisPortals_r (node_t *node) +{ + // stop as soon as we get to a detail_seperator, which + // means that everything below is in a single cluster + if (node->planenum == PLANENUM_LEAF || node->detail_seperator ) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + CreateVisPortals_r (node->children[0]); + CreateVisPortals_r (node->children[1]); +} + +/* +================ +FinishVisPortals_r +================ +*/ +void FinishVisPortals2_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + FinishVisPortals2_r (node->children[0]); + FinishVisPortals2_r (node->children[1]); +} + +void FinishVisPortals_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + return; + + if (node->detail_seperator) + { + FinishVisPortals2_r (node); + return; + } + + FinishVisPortals_r (node->children[0]); + FinishVisPortals_r (node->children[1]); +} + + +int clusterleaf; +void SaveClusters_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + { + dleafs[clusterleaf++].cluster = node->cluster; + return; + } + SaveClusters_r (node->children[0]); + SaveClusters_r (node->children[1]); +} + +/* +================ +WritePortalFile +================ +*/ +void WritePortalFile (tree_t *tree) +{ + char filename[1024]; + node_t *headnode; + + Sys_FPrintf( SYS_VRB, "--- WritePortalFile ---\n"); + + headnode = tree->headnode; + num_visclusters = 0; + num_visportals = 0; + + FreeTreePortals_r (headnode); + + MakeHeadnodePortals (tree); + + CreateVisPortals_r (headnode); + +// set the cluster field in every leaf and count the total number of portals + + NumberLeafs_r (headnode); + +// write the file + sprintf (filename, "%s.prt", source); + Sys_Printf ("writing %s\n", filename); + pf = fopen (filename, "w"); + if (!pf) + Error ("Error opening %s", filename); + + fprintf (pf, "%s\n", PORTALFILE); + fprintf (pf, "%i\n", num_visclusters); + fprintf (pf, "%i\n", num_visportals); + + Sys_FPrintf( SYS_VRB, "%5i visclusters\n", num_visclusters); + Sys_FPrintf( SYS_VRB, "%5i visportals\n", num_visportals); + + WritePortalFile_r (headnode); + + fclose (pf); + + // we need to store the clusters out now because ordering + // issues made us do this after writebsp... + clusterleaf = 1; + SaveClusters_r (headnode); +} + diff --git a/tools/quake2/q2map/q2map.h b/tools/quake2/q2map/q2map.h new file mode 100644 index 00000000..159232d8 --- /dev/null +++ b/tools/quake2/q2map/q2map.h @@ -0,0 +1,50 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// q2map.h + +/* platform-specific */ +#if defined( __linux__ ) || defined( __APPLE__ ) + #define Q_UNIX +#endif + +#ifdef Q_UNIX + #include + #include + #include +#endif + +#ifdef _WIN32 + #include +#endif + +#include + +#include "cmdlib.h" +#include "mathlib.h" +#include "scriplib.h" +#include "polylib.h" +#include "q2_threads.h" +#include "bspfile.h" +#include "inout.h" + +int BSP_Main (); +int VIS_Main (); +int RAD_Main (); diff --git a/tools/quake2/q2map/q2map.vcproj b/tools/quake2/q2map/q2map.vcproj new file mode 100644 index 00000000..90818f91 --- /dev/null +++ b/tools/quake2/q2map/q2map.vcproj @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/quake2/q2map/qbsp.c b/tools/quake2/q2map/qbsp.c new file mode 100644 index 00000000..84e4570c --- /dev/null +++ b/tools/quake2/q2map/qbsp.c @@ -0,0 +1,426 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// csg4.c + +#include "qbsp.h" + +extern float subdivide_size; + +char source[1024]; +char name[1024]; + +vec_t microvolume = 1.0; +qboolean noprune; +qboolean glview; +qboolean nodetail; +qboolean fulldetail; +qboolean onlyents; +qboolean nomerge; +qboolean nowater; +qboolean nofill; +qboolean nocsg; +qboolean noweld; +qboolean noshare; +qboolean nosubdiv; +qboolean notjunc; +qboolean noopt; +qboolean leaktest; +qboolean verboseentities; + +char outbase[32]; + +int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7; + +int entity_num; + + +node_t *block_nodes[10][10]; + + +/* +============ +BlockTree + +============ +*/ +node_t *BlockTree (int xl, int yl, int xh, int yh) +{ + node_t *node; + vec3_t normal; + float dist; + int mid; + + if (xl == xh && yl == yh) + { + node = block_nodes[xl+5][yl+5]; + if (!node) + { // return an empty leaf + node = AllocNode (); + node->planenum = PLANENUM_LEAF; + node->contents = 0; //CONTENTS_SOLID; + return node; + } + return node; + } + + // create a seperator along the largest axis + node = AllocNode (); + + if (xh - xl > yh - yl) + { // split x axis + mid = xl + (xh-xl)/2 + 1; + normal[0] = 1; + normal[1] = 0; + normal[2] = 0; + dist = mid*1024; + node->planenum = FindFloatPlane (normal, dist); + node->children[0] = BlockTree ( mid, yl, xh, yh); + node->children[1] = BlockTree ( xl, yl, mid-1, yh); + } + else + { + mid = yl + (yh-yl)/2 + 1; + normal[0] = 0; + normal[1] = 1; + normal[2] = 0; + dist = mid*1024; + node->planenum = FindFloatPlane (normal, dist); + node->children[0] = BlockTree ( xl, mid, xh, yh); + node->children[1] = BlockTree ( xl, yl, xh, mid-1); + } + + return node; +} + +/* +============ +ProcessBlock_Thread + +============ +*/ +int brush_start, brush_end; +void ProcessBlock_Thread (int blocknum) +{ + int xblock, yblock; + vec3_t mins, maxs; + bspbrush_t *brushes; + tree_t *tree; + node_t *node; + + yblock = block_yl + blocknum / (block_xh-block_xl+1); + xblock = block_xl + blocknum % (block_xh-block_xl+1); + + Sys_FPrintf( SYS_VRB, "############### block %2i,%2i ###############\n", xblock, yblock); + + mins[0] = xblock*1024; + mins[1] = yblock*1024; + mins[2] = -4096; + maxs[0] = (xblock+1)*1024; + maxs[1] = (yblock+1)*1024; + maxs[2] = 4096; + + // the makelist and chopbrushes could be cached between the passes... + brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs); + if (!brushes) + { + node = AllocNode (); + node->planenum = PLANENUM_LEAF; + node->contents = CONTENTS_SOLID; + block_nodes[xblock+5][yblock+5] = node; + return; + } + + if (!nocsg) + brushes = ChopBrushes (brushes); + + tree = BrushBSP (brushes, mins, maxs); + + block_nodes[xblock+5][yblock+5] = tree->headnode; +} + +/* +============ +ProcessWorldModel + +============ +*/ +void ProcessWorldModel (void) +{ + entity_t *e; + tree_t *tree; + qboolean leaked; + qboolean optimize; + xmlNodePtr polyline, leaknode; + char level[ 2 ]; + + e = &entities[entity_num]; + + brush_start = e->firstbrush; + brush_end = brush_start + e->numbrushes; + leaked = false; + + // + // perform per-block operations + // + if (block_xh * 1024 > map_maxs[0]) + block_xh = floor(map_maxs[0]/1024.0); + if ( (block_xl+1) * 1024 < map_mins[0]) + block_xl = floor(map_mins[0]/1024.0); + if (block_yh * 1024 > map_maxs[1]) + block_yh = floor(map_maxs[1]/1024.0); + if ( (block_yl+1) * 1024 < map_mins[1]) + block_yl = floor(map_mins[1]/1024.0); + + if (block_xl <-4) + block_xl = -4; + if (block_yl <-4) + block_yl = -4; + if (block_xh > 3) + block_xh = 3; + if (block_yh > 3) + block_yh = 3; + + for (optimize = false ; optimize <= true ; optimize++) + { + Sys_FPrintf( SYS_VRB, "--------------------------------------------\n"); + + RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1), + !verbose, ProcessBlock_Thread); + + // + // build the division tree + // oversizing the blocks guarantees that all the boundaries + // will also get nodes. + // + + Sys_FPrintf( SYS_VRB, "--------------------------------------------\n"); + + tree = AllocTree (); + tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1); + + tree->mins[0] = (block_xl)*1024; + tree->mins[1] = (block_yl)*1024; + tree->mins[2] = map_mins[2] - 8; + + tree->maxs[0] = (block_xh+1)*1024; + tree->maxs[1] = (block_yh+1)*1024; + tree->maxs[2] = map_maxs[2] + 8; + + // + // perform the global operations + // + MakeTreePortals (tree); + + if (FloodEntities (tree)) + FillOutside (tree->headnode); + else + { + + Sys_FPrintf( SYS_NOXML, "**********************\n" ); + Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" ); + Sys_FPrintf( SYS_NOXML, "**********************\n" ); + polyline = LeakFile( tree ); + leaknode = xmlNewNode( NULL, "message" ); + xmlNodeSetContent( leaknode, "MAP LEAKED\n" ); + xmlAddChild( leaknode, polyline ); + level[0] = (int) '0' + SYS_ERR; + level[1] = 0; + xmlSetProp( leaknode, "level", (char*) &level ); + xml_SendNode( leaknode ); + if( leaktest ) + { + Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n"); + exit( 0 ); + } + leaked = true; +/* + Sys_Printf ("**** leaked ****\n"); + leaked = true; + LeakFile (tree); + if (leaktest) + { + Sys_Printf ("--- MAP LEAKED ---\n"); + exit (0); + } */ + } + + MarkVisibleSides (tree, brush_start, brush_end); + if (noopt || leaked) + break; + if (!optimize) + { + FreeTree (tree); + } + } + + FloodAreas (tree); + if (glview) + WriteGLView (tree, source); + MakeFaces (tree->headnode); + FixTjuncs (tree->headnode); + + if (!noprune) + PruneNodes (tree->headnode); + + WriteBSP (tree->headnode); + + if (!leaked) + WritePortalFile (tree); + + FreeTree (tree); +} + +/* +============ +ProcessSubModel + +============ +*/ +void ProcessSubModel (void) +{ + entity_t *e; + int start, end; + tree_t *tree; + bspbrush_t *list; + vec3_t mins, maxs; + + e = &entities[entity_num]; + + start = e->firstbrush; + end = start + e->numbrushes; + + mins[0] = mins[1] = mins[2] = -4096; + maxs[0] = maxs[1] = maxs[2] = 4096; + list = MakeBspBrushList (start, end, mins, maxs); + if (!nocsg) + list = ChopBrushes (list); + tree = BrushBSP (list, mins, maxs); + MakeTreePortals (tree); + MarkVisibleSides (tree, start, end); + MakeFaces (tree->headnode); + FixTjuncs (tree->headnode); + WriteBSP (tree->headnode); + FreeTree (tree); +} + +/* +============ +ProcessModels +============ +*/ +void ProcessModels (void) +{ + BeginBSPFile (); + + for (entity_num=0 ; entity_num< num_entities ; entity_num++) + { + if (!entities[entity_num].numbrushes) + continue; + + Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", nummodels); + BeginModel (); + if (entity_num == 0) + ProcessWorldModel (); + else + ProcessSubModel (); + EndModel (); + + //if (!verboseentities) + // verbose = false; // don't bother printing submodels + } + + EndBSPFile (); +} + + +/* +============ +main +============ +*/ +int BSP_Main () +{ + double start, end; + char path[1024]; + int total_bsp_time; + + Sys_Printf ("\n----- BSP ----\n\n"); + + + start = I_FloatTime (); + + ThreadSetDefault (); + SetQdirFromPath (mapname); + + strcpy (source, ExpandArg (mapname)); + StripExtension (source); + + // delete portal and line files + sprintf (path, "%s.prt", source); + remove (path); + sprintf (path, "%s.lin", source); + remove (path); + + strcpy (name, ExpandArg (mapname)); + DefaultExtension (name, ".map"); // might be .reg + + // + // if onlyents, just grab the entites and resave + // + if (onlyents) + { + char out[1024]; + + sprintf (out, "%s.bsp", source); + LoadBSPFile (out); + num_entities = 0; + + LoadMapFile (name); + SetModelNumbers (); + SetLightStyles (); + + UnparseEntities (); + + WriteBSPFile (out); + } + else + { + // + // start from scratch + // + LoadMapFile (name); + SetModelNumbers (); + SetLightStyles (); + + ProcessModels (); + } + + end = I_FloatTime (); + total_bsp_time = (int) (end-start); + Sys_Printf("\nBSP Time: "); + if ( total_bsp_time > 59 ) + Sys_Printf("%d Minutes ", total_bsp_time/60 ); + Sys_Printf( "%d Seconds\n", total_bsp_time%60 ); + + + return 0; +} + diff --git a/tools/quake2/q2map/qbsp.h b/tools/quake2/q2map/qbsp.h new file mode 100644 index 00000000..ecfaa7ca --- /dev/null +++ b/tools/quake2/q2map/qbsp.h @@ -0,0 +1,390 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Files: + +brushbsp.c +csg.c +faces.c +gldraw.c +glfile.c +leakfile.c +map.c +nodraw.c +portals.c +prtfile.c +qbsp3.c +textures.c +tree.c +writebsp.c + +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "scriplib.h" +#include "polylib.h" +#include "q2_threads.h" +#include "bspfile.h" +#include "inout.h" + +#ifdef _WIN32 + #ifdef NDEBUG // Don't show in a Release build + #pragma warning(disable : 4305) // truncate from double to float + #pragma warning(disable : 4244) // conversion from double to float + #pragma warning(disable : 4018) // signed/unsigned mismatch + #endif +#endif + +#define MAX_BRUSH_SIDES 128 +#define CLIP_EPSILON 0.1 + +#define BOGUS_RANGE 8192 + +#define TEXINFO_NODE -1 // side is allready on a node + +typedef struct plane_s +{ + vec3_t normal; + vec_t dist; + int type; + struct plane_s *hash_chain; +} plane_t; + +typedef struct +{ + vec_t shift[2]; + vec_t rotate; + vec_t scale[2]; + char name[32]; + int flags; + int value; +} brush_texture_t; + +typedef struct side_s +{ + int planenum; + int texinfo; + winding_t *winding; + struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides + int contents; // from miptex + int surf; // from miptex + qboolean visible; // choose visble planes first + qboolean tested; // this plane allready checked as a split + qboolean bevel; // don't ever use for bsp splitting +} side_t; + +typedef struct brush_s +{ + int entitynum; + int brushnum; + + int contents; + + vec3_t mins, maxs; + + int numsides; + side_t *original_sides; +} mapbrush_t; + +#define PLANENUM_LEAF -1 + +#define MAXEDGES 20 + +typedef struct face_s +{ + struct face_s *next; // on node + + // the chain of faces off of a node can be merged or split, + // but each face_t along the way will remain in the chain + // until the entire tree is freed + struct face_s *merged; // if set, this face isn't valid anymore + struct face_s *split[2]; // if set, this face isn't valid anymore + + struct portal_s *portal; + int texinfo; + int planenum; + int contents; // faces in different contents can't merge + int outputnumber; + winding_t *w; + int numpoints; + qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex + int vertexnums[MAXEDGES]; +} face_t; + + + +typedef struct bspbrush_s +{ + struct bspbrush_s *next; + vec3_t mins, maxs; + int side, testside; // side of node during construction + mapbrush_t *original; + int numsides; + side_t sides[6]; // variably sized +} bspbrush_t; + + + +#define MAX_NODE_BRUSHES 8 +typedef struct node_s +{ + // both leafs and nodes + int planenum; // -1 = leaf node + struct node_s *parent; + vec3_t mins, maxs; // valid after portalization + bspbrush_t *volume; // one for each leaf/node + + // nodes only + qboolean detail_seperator; // a detail brush caused the split + side_t *side; // the side that created the node + struct node_s *children[2]; + face_t *faces; + + // leafs only + bspbrush_t *brushlist; // fragments of all brushes in this leaf + int contents; // OR of all brush contents + int occupied; // 1 or greater can reach entity + entity_t *occupant; // for leak file testing + int cluster; // for portalfile writing + int area; // for areaportals + struct portal_s *portals; // also on nodes during construction +} node_t; + +typedef struct portal_s +{ + plane_t plane; + node_t *onnode; // NULL = outside box + node_t *nodes[2]; // [0] = front side of plane + struct portal_s *next[2]; + winding_t *winding; + + qboolean sidefound; // false if ->side hasn't been checked + side_t *side; // NULL = non-visible + face_t *face[2]; // output face in bsp file +} portal_t; + +typedef struct +{ + node_t *headnode; + node_t outside_node; + vec3_t mins, maxs; +} tree_t; + +extern int entity_num; + +extern plane_t mapplanes[MAX_MAP_PLANES]; +extern int nummapplanes; + +extern int nummapbrushes; +extern mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +extern vec3_t map_mins, map_maxs; + +#define MAX_MAP_SIDES (MAX_MAP_BRUSHES*6) + +extern int nummapbrushsides; +extern side_t brushsides[MAX_MAP_SIDES]; + +extern qboolean noprune; +extern qboolean nodetail; +extern qboolean fulldetail; +extern qboolean nomerge; +extern qboolean nosubdiv; +extern qboolean nowater; +extern qboolean noweld; +extern qboolean noshare; +extern qboolean notjunc; + +extern vec_t microvolume; + +extern char outbase[32]; + +extern char source[1024]; + +void LoadMapFile (char *filename); +int FindFloatPlane (vec3_t normal, vec_t dist); + +//============================================================================= + +// textures.c + +typedef struct +{ + char name[64]; + int flags; + int value; + int contents; + char animname[64]; +} textureref_t; + +#define MAX_MAP_TEXTURES 1024 + +extern textureref_t textureref[MAX_MAP_TEXTURES]; + +int FindMiptex (char *name); + +int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin); + +//============================================================================= + +void FindGCD (int *v); + +mapbrush_t *Brush_LoadEntity (entity_t *ent); +int PlaneTypeForNormal (vec3_t normal); +qboolean MakeBrushPlanes (mapbrush_t *b); +int FindIntPlane (int *inormal, int *iorigin); +void CreateBrush (int brushnum); + + +//============================================================================= + +// draw.c + +extern vec3_t draw_mins, draw_maxs; +extern qboolean drawflag; + +void Draw_ClearWindow (void); +void DrawWinding (winding_t *w); + +void GLS_BeginScene (void); +void GLS_Winding (winding_t *w, int code); +void GLS_EndScene (void); + +//============================================================================= + +// csg + +bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, + vec3_t clipmins, vec3_t clipmaxs); +bspbrush_t *ChopBrushes (bspbrush_t *head); +bspbrush_t *InitialBrushList (bspbrush_t *list); +bspbrush_t *OptimizedBrushList (bspbrush_t *list); + +void WriteBrushMap (char *name, bspbrush_t *list); + +//============================================================================= + +// brushbsp + +void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis); + +bspbrush_t *CopyBrush (bspbrush_t *brush); + +void SplitBrush (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back); + +tree_t *AllocTree (void); +node_t *AllocNode (void); +bspbrush_t *AllocBrush (int numsides); +int CountBrushList (bspbrush_t *brushes); +void FreeBrush (bspbrush_t *brushes); +vec_t BrushVolume (bspbrush_t *brush); + +void BoundBrush (bspbrush_t *brush); +void FreeBrushList (bspbrush_t *brushes); + +tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs); + +//============================================================================= + +// portals.c + +int VisibleContents (int contents); + +void MakeHeadnodePortals (tree_t *tree); +void MakeNodePortal (node_t *node); +void SplitNodePortals (node_t *node); + +qboolean Portal_VisFlood (portal_t *p); + +qboolean FloodEntities (tree_t *tree); +void FillOutside (node_t *headnode); +void FloodAreas (tree_t *tree); +void MarkVisibleSides (tree_t *tree, int start, int end); +void FreePortal (portal_t *p); +void EmitAreaPortals (node_t *headnode); + +void MakeTreePortals (tree_t *tree); + +//============================================================================= + +// glfile.c + +void OutputWinding (winding_t *w, FILE *glview); +void WriteGLView (tree_t *tree, char *source); + +//============================================================================= + +// leakfile.c + +//void LeakFile (tree_t *tree); +xmlNodePtr LeakFile (tree_t *tree); + +//============================================================================= + +// prtfile.c + +void WritePortalFile (tree_t *tree); + +//============================================================================= + +// writebsp.c + +void SetModelNumbers (void); +void SetLightStyles (void); + +void BeginBSPFile (void); +void WriteBSP (node_t *headnode); +void EndBSPFile (void); +void BeginModel (void); +void EndModel (void); + +//============================================================================= + +// faces.c + +void MakeFaces (node_t *headnode); +void FixTjuncs (node_t *headnode); +int GetEdge2 (int v1, int v2, face_t *f); + +face_t *AllocFace (void); +void FreeFace (face_t *f); + +void MergeNodeFaces (node_t *node); + +//============================================================================= + +// tree.c + +void FreeTree (tree_t *tree); +void FreeTree_r (node_t *node); +void PrintTree_r (node_t *node, int depth); +void FreeTreePortals_r (node_t *node); +void PruneNodes_r (node_t *node); +void PruneNodes (node_t *node); + +//============================================================================= + +// externs + +extern char *mapname; +extern char game[64]; diff --git a/tools/quake2/q2map/qrad.c b/tools/quake2/q2map/qrad.c new file mode 100644 index 00000000..e324c574 --- /dev/null +++ b/tools/quake2/q2map/qrad.c @@ -0,0 +1,647 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// qrad.c + +#include "qrad.h" + + + +/* + +NOTES +----- + +every surface must be divided into at least two patches each axis + +*/ + +patch_t *face_patches[MAX_MAP_FACES]; +entity_t *face_entity[MAX_MAP_FACES]; +patch_t patches[MAX_PATCHES]; +unsigned num_patches; + +vec3_t radiosity[MAX_PATCHES]; // light leaving a patch +vec3_t illumination[MAX_PATCHES]; // light arriving at a patch + +vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels +dplane_t backplanes[MAX_MAP_PLANES]; + +char inbase[32], outbase[32]; + +int fakeplanes; // created planes for origin offset + +int numbounce = 8; +qboolean extrasamples; + +float subdiv = 64; +qboolean dumppatches; + +void BuildLightmaps (void); +int TestLine (vec3_t start, vec3_t stop); + +int junk; + +float ambient = 0; +float maxlight = 196; + +float lightscale = 1.0; + +qboolean glview; + +qboolean nopvs; + +char source[1024]; + +float direct_scale = 0.4; +float entity_scale = 1.0; + +/* +=================================================================== + +MISC + +=================================================================== +*/ + + +/* +============= +MakeBackplanes +============= +*/ +void MakeBackplanes (void) +{ + int i; + + for (i=0 ; ichildren[i]; + if (j < 0) + leafparents[-j - 1] = nodenum; + else + MakeParents (j, nodenum); + } +} + + +/* +=================================================================== + +TRANSFER SCALES + +=================================================================== +*/ + +int PointInLeafnum (vec3_t point) +{ + int nodenum; + vec_t dist; + dnode_t *node; + dplane_t *plane; + + nodenum = 0; + while (nodenum >= 0) + { + node = &dnodes[nodenum]; + plane = &dplanes[node->planenum]; + dist = DotProduct (point, plane->normal) - plane->dist; + if (dist > 0) + nodenum = node->children[0]; + else + nodenum = node->children[1]; + } + + return -nodenum - 1; +} + + +dleaf_t *Rad_PointInLeaf (vec3_t point) +{ + int num; + + num = PointInLeafnum (point); + return &dleafs[num]; +} + + +qboolean PvsForOrigin (vec3_t org, byte *pvs) +{ + dleaf_t *leaf; + + if (!visdatasize) + { + memset (pvs, 255, (numleafs+7)/8 ); + return true; + } + + leaf = Rad_PointInLeaf (org); + if (leaf->cluster == -1) + return false; // in solid leaf + + DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs); + return true; +} + + +/* +============= +MakeTransfers + +============= +*/ +int total_transfer; + +void MakeTransfers (int i) +{ + int j; + vec3_t delta; + vec_t dist, scale; + float trans; + int itrans; + patch_t *patch, *patch2; + float total; + dplane_t plane; + vec3_t origin; + float transfers[MAX_PATCHES], *all_transfers; + int s; + int itotal; + byte pvs[(MAX_MAP_LEAFS+7)/8]; + int cluster; + + patch = patches + i; + total = 0; + + VectorCopy (patch->origin, origin); + plane = *patch->plane; + + if (!PvsForOrigin (patch->origin, pvs)) + return; + + // find out which patch2s will collect light + // from patch + + all_transfers = transfers; + patch->numtransfers = 0; + for (j=0, patch2 = patches ; jcluster; + if (cluster == -1) + continue; + if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) ) + continue; // not in pvs + } + + // calculate vector + VectorSubtract (patch2->origin, origin, delta); + dist = VectorNormalize (delta, delta); + if (!dist) + continue; // should never happen + + // reletive angles + scale = DotProduct (delta, plane.normal); + scale *= -DotProduct (delta, patch2->plane->normal); + if (scale <= 0) + continue; + + // check exact tramsfer + if (TestLine_r (0, patch->origin, patch2->origin) ) + continue; + + trans = scale * patch2->area / (dist*dist); + + if (trans < 0) + trans = 0; // rounding errors... + + transfers[j] = trans; + if (trans > 0) + { + total += trans; + patch->numtransfers++; + } + } + + // copy the transfers out and normalize + // total should be somewhere near PI if everything went right + // because partial occlusion isn't accounted for, and nearby + // patches have underestimated form factors, it will usually + // be higher than PI + if (patch->numtransfers) + { + transfer_t *t; + + if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES) + Error ("Weird numtransfers"); + s = patch->numtransfers * sizeof(transfer_t); + patch->transfers = malloc (s); + if (!patch->transfers) + Error ("Memory allocation failure"); + + // + // normalize all transfers so all of the light + // is transfered to the surroundings + // + t = patch->transfers; + itotal = 0; + for (j=0 ; jtransfer = itrans; + t->patch = j; + t++; + } + } + + // don't bother locking around this. not that important. + total_transfer += patch->numtransfers; +} + + +/* +============= +FreeTransfers +============= +*/ +void FreeTransfers (void) +{ + int i; + + for (i=0 ; iwinding; + fprintf (out, "%i\n", w->numpoints); + for (i=0 ; inumpoints ; i++) + { + fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + patch->totallight[0], + patch->totallight[1], + patch->totallight[2]); + } + fprintf (out, "\n"); + } + + fclose (out); +} + +/* +============= +WriteGlView +============= +*/ +void WriteGlView (void) +{ + char name[1024]; + FILE *f; + int i, j; + patch_t *p; + winding_t *w; + + strcpy (name, source); + StripExtension (name); + strcat (name, ".glr"); + + f = fopen (name, "w"); + if (!f) + Error ("Couldn't open %s", f); + + for (j=0 ; jwinding; + fprintf (f, "%i\n", w->numpoints); + for (i=0 ; inumpoints ; i++) + { + fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + p->totallight[0]/128, + p->totallight[1]/128, + p->totallight[2]/128); + } + fprintf (f, "\n"); + } + + fclose (f); +} + + +//============================================================== + +/* +============= +CollectLight +============= +*/ +float CollectLight (void) +{ + int i, j; + patch_t *patch; + vec_t total; + + total = 0; + + for (i=0, patch=patches ; isky) + { + VectorClear (radiosity[i]); + VectorClear (illumination[i]); + continue; + } + + for (j=0 ; j<3 ; j++) + { + patch->totallight[j] += illumination[i][j] / patch->area; + radiosity[i][j] = illumination[i][j] * patch->reflectivity[j]; + } + + total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2]; + VectorClear (illumination[i]); + } + + return total; +} + + +/* +============= +ShootLight + +Send light out to other patches + Run multi-threaded +============= +*/ +void ShootLight (int patchnum) +{ + int k, l; + transfer_t *trans; + int num; + patch_t *patch; + vec3_t send; + + // this is the amount of light we are distributing + // prescale it so that multiplying by the 16 bit + // transfer values gives a proper output value + for (k=0 ; k<3 ; k++) + send[k] = radiosity[patchnum][k] / 0x10000; + patch = &patches[patchnum]; + + trans = patch->transfers; + num = patch->numtransfers; + + for (k=0 ; kpatch][l] += send[l]*trans->transfer; + } +} + +/* +============= +BounceLight +============= +*/ +void BounceLight (void) +{ + int i, j; + float added; + char name[64]; + patch_t *p; + + for (i=0 ; itotallight[j] = p->samplelight[j]; + radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area; + } + } + + for (i=0 ; itotallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0) + Error ("negative patch totallight\n"); + } +} + +/* +============= +RadWorld +============= +*/ +void RadWorld (void) +{ + if (numnodes == 0 || numfaces == 0) + Error ("Empty map"); + MakeBackplanes (); + MakeParents (0, -1); + MakeTnodes (&dmodels[0]); + + // turn each face into a single patch + MakePatches (); + + // subdivide patches to a maximum dimension + SubdividePatches (); + + // create directlights out of patches and lights + CreateDirectLights (); + + // build initial facelights + RunThreadsOnIndividual (numfaces, true, BuildFacelights); + + if (numbounce > 0) + { + // build transfer lists + RunThreadsOnIndividual (num_patches, true, MakeTransfers); + Sys_FPrintf( SYS_VRB, "transfer lists: %5.1f megs\n" + , (float)total_transfer * sizeof(transfer_t) / (1024*1024)); + + // spread light around + BounceLight (); + + FreeTransfers (); + + CheckPatches (); + } + + if (glview) + WriteGlView (); + + // blend bounced light into direct light and save + PairEdges (); + LinkPlaneFaces (); + + lightdatasize = 0; + RunThreadsOnIndividual (numfaces, true, FinalLightFace); +} + + +/* +======== +main + +light modelfile +======== +*/ +int RAD_Main () +{ + double start, end; + char name[1024]; + int total_rad_time; + + Sys_Printf ("\n----- RAD ----\n\n"); + + if (maxlight > 255) + maxlight = 255; + + start = I_FloatTime (); + + if ( !strcmp( game, "heretic2" ) ) + CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2; + else + CalcTextureReflectivity = &CalcTextureReflectivity_Quake2; + + SetQdirFromPath (mapname); + strcpy (source, ExpandArg(mapname)); + StripExtension (source); + DefaultExtension (source, ".bsp"); + +// ReadLightFile (); + + sprintf (name, "%s%s", inbase, source); + Sys_Printf ("reading %s\n", name); + LoadBSPFile (name); + ParseEntities (); + (*CalcTextureReflectivity) (); + + if (!visdatasize) + { + Sys_Printf ("No vis information, direct lighting only.\n"); + numbounce = 0; + ambient = 0.1; + } + + RadWorld (); + + sprintf (name, "%s%s", outbase, source); + Sys_Printf ("writing %s\n", name); + WriteBSPFile (name); + + end = I_FloatTime (); + total_rad_time = (int) (end-start); + Sys_Printf("\nRAD Time: "); + if ( total_rad_time > 59 ) + Sys_Printf("%d Minutes ", total_rad_time/60 ); + Sys_Printf( "%d Seconds\n", total_rad_time%60 ); + + + return 0; +} + diff --git a/tools/quake2/q2map/qrad.h b/tools/quake2/q2map/qrad.h new file mode 100644 index 00000000..3bfc3854 --- /dev/null +++ b/tools/quake2/q2map/qrad.h @@ -0,0 +1,184 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* Files: + +lightmap.c +patches.c +qrad.c +trace.c + +*/ + + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" +#include "polylib.h" +#include "q2_threads.h" +#include "lbmlib.h" +#include "inout.h" + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 + #ifdef NDEBUG // Don't show in a Release build + #pragma warning(disable : 4305) // truncate from double to float + #pragma warning(disable : 4244) // conversion from double to float + #pragma warning(disable : 4018) // signed/unsigned mismatch + #endif +#endif + +typedef enum +{ + emit_surface, + emit_point, + emit_spotlight +} emittype_t; + + + +typedef struct directlight_s +{ + struct directlight_s *next; + emittype_t type; + + float intensity; + int style; + vec3_t origin; + vec3_t color; + vec3_t normal; // for surfaces and spotlights + float stopdot; // for spotlights +} directlight_t; + + +// the sum of all tranfer->transfer values for a given patch +// should equal exactly 0x10000, showing that all radiance +// reaches other patches +typedef struct +{ + unsigned short patch; + unsigned short transfer; +} transfer_t; + + +#define MAX_PATCHES 65000 // larger will cause 32 bit overflows + +typedef struct patch_s +{ + winding_t *winding; + struct patch_s *next; // next in face + int numtransfers; + transfer_t *transfers; + + int cluster; // for pvs checking + vec3_t origin; + dplane_t *plane; + + qboolean sky; + + vec3_t totallight; // accumulated by radiosity + // does NOT include light + // accounted for by direct lighting + float area; + + // illuminance * reflectivity = radiosity + vec3_t reflectivity; + vec3_t baselight; // emissivity only + + // each style 0 lightmap sample in the patch will be + // added up to get the average illuminance of the entire patch + vec3_t samplelight; + int samples; // for averaging direct light +} patch_t; + +extern patch_t *face_patches[MAX_MAP_FACES]; +extern entity_t *face_entity[MAX_MAP_FACES]; +extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels +extern patch_t patches[MAX_PATCHES]; +extern unsigned num_patches; + +extern int leafparents[MAX_MAP_LEAFS]; +extern int nodeparents[MAX_MAP_NODES]; + +extern float lightscale; + + +void MakeShadowSplits (void); + +//============================================== + + +void BuildVisMatrix (void); +qboolean CheckVisBit (unsigned p1, unsigned p2); + +//============================================== + +extern float ambient, maxlight; + +void LinkPlaneFaces (void); + +extern qboolean extrasamples; +extern int numbounce; + +extern directlight_t *directlights[MAX_MAP_LEAFS]; + +extern byte nodehit[MAX_MAP_NODES]; + +void BuildLightmaps (void); + +void BuildFacelights (int facenum); + +void FinalLightFace (int facenum); + +qboolean PvsForOrigin (vec3_t org, byte *pvs); + +int TestLine_r (int node, vec3_t start, vec3_t stop); + +void CreateDirectLights (void); + +dleaf_t *Rad_PointInLeaf (vec3_t point); + + +extern dplane_t backplanes[MAX_MAP_PLANES]; +extern int fakeplanes; // created planes for origin offset + +extern float subdiv; + +extern float direct_scale; +extern float entity_scale; + +int PointInLeafnum (vec3_t point); +void MakeTnodes (dmodel_t *bm); +void MakePatches (void); +void SubdividePatches (void); +void PairEdges (void); +void (*CalcTextureReflectivity) (void); +void CalcTextureReflectivity_Quake2(void); +void CalcTextureReflectivity_Heretic2(void); + +//============================================================================= + +// externs + +extern char *mapname; +extern char game[64]; diff --git a/tools/quake2/q2map/qvis.c b/tools/quake2/q2map/qvis.c new file mode 100644 index 00000000..30979914 --- /dev/null +++ b/tools/quake2/q2map/qvis.c @@ -0,0 +1,581 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// qvis.c + +#include "qvis.h" +#include "q2_threads.h" +#include "stdlib.h" + +int numportals; +int portalclusters; + +char inbase[32]; +char outbase[32]; + +portal_t *portals; +leaf_t *leafs; + +int c_portaltest, c_portalpass, c_portalcheck; + +byte *uncompressedvis; + +byte *vismap, *vismap_p, *vismap_end; // past visfile +int originalvismapsize; + +int leafbytes; // (portalclusters+63)>>3 +int leaflongs; + +int portalbytes, portallongs; + +qboolean fastvis; +qboolean nosort; + +int testlevel = 2; + +int totalvis; + +portal_t *sorted_portals[MAX_MAP_PORTALS*2]; + + +//============================================================================= + +void PlaneFromWinding (winding_t *w, plane_t *plane) +{ + vec3_t v1, v2; + +// calc plane + VectorSubtract (w->points[2], w->points[1], v1); + VectorSubtract (w->points[0], w->points[1], v2); + CrossProduct (v2, v1, plane->normal); + VectorNormalize (plane->normal, plane->normal); + plane->dist = DotProduct (w->points[0], plane->normal); +} + + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + size = (int)((winding_t *)0)->points[points]; + w = malloc (size); + memset (w, 0, size); + + return w; +} + + +/* +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + Sys_Printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]); +} +*/ +void prl(leaf_t *l) +{ + int i; + portal_t *p; + plane_t pl; + + for (i=0 ; inumportals ; i++) + { + p = l->portals[i]; + pl = p->plane; + Sys_Printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]); + } +} + + +//============================================================================= + +/* +============= +SortPortals + +Sorts the portals from the least complex, so the later ones can reuse +the earlier information. +============= +*/ +int PComp (const void *a, const void *b) +{ + if ( (*(portal_t **)a)->nummightsee == (*(portal_t **)b)->nummightsee) + return 0; + if ( (*(portal_t **)a)->nummightsee < (*(portal_t **)b)->nummightsee) + return -1; + return 1; +} +void SortPortals (void) +{ + int i; + + for (i=0 ; i>3] & (1<<(i&7)) ) + { + p = portals+i; + leafbits[p->leaf>>3] |= (1<<(p->leaf&7)); + } + } + + c_leafs = CountBits (leafbits, portalclusters); + + return c_leafs; +} + + +/* +=============== +ClusterMerge + +Merges the portal visibility for a leaf +=============== +*/ +void ClusterMerge (int leafnum) +{ + leaf_t *leaf; + byte portalvector[MAX_PORTALS/8]; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + int i, j; + int numvis; + byte *dest; + portal_t *p; + int pnum; + + // OR together all the portalvis bits + + memset (portalvector, 0, portalbytes); + leaf = &leafs[leafnum]; + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + if (p->status != stat_done) + Error ("portal not done"); + for (j=0 ; jportalvis)[j]; + pnum = p - portals; + portalvector[pnum>>3] |= 1<<(pnum&7); + } + + // convert portal bits to leaf bits + numvis = LeafVectorFromPortalVector (portalvector, uncompressed); + + if (uncompressed[leafnum>>3] & (1<<(leafnum&7))) + Sys_Printf ("WARNING: Leaf portals saw into leaf\n"); + + uncompressed[leafnum>>3] |= (1<<(leafnum&7)); + numvis++; // count the leaf itself + + // save uncompressed for PHS calculation + memcpy (uncompressedvis + leafnum*leafbytes, uncompressed, leafbytes); + +// +// compress the bit string +// + Sys_FPrintf( SYS_VRB, "cluster %4i : %4i visible\n", leafnum, numvis); + totalvis += numvis; + + i = CompressVis (uncompressed, compressed); + + dest = vismap_p; + vismap_p += i; + + if (vismap_p > vismap_end) + Error ("Vismap expansion overflow"); + + dvis->bitofs[leafnum][DVIS_PVS] = dest-vismap; + + memcpy (dest, compressed, i); +} + + +/* +================== +CalcPortalVis +================== +*/ +void CalcPortalVis (void) +{ + int i; + +// fastvis just uses mightsee for a very loose bound + if (fastvis) + { + for (i=0 ; iwinding; + VectorCopy (vec3_origin, total); + for (i=0 ; inumpoints ; i++) + { + VectorAdd (total, w->points[i], total); + } + + for (i=0 ; i<3 ; i++) + total[i] /= w->numpoints; + + bestr = 0; + for (i=0 ; inumpoints ; i++) + { + VectorSubtract (w->points[i], total, dist); + r = VectorLength (dist); + if (r > bestr) + bestr = r; + } + VectorCopy (total, p->origin); + p->radius = bestr; +} + +/* +============ +LoadPortals +============ +*/ +void LoadPortals (char *name) +{ + int i, j; + portal_t *p; + leaf_t *l; + char magic[80]; + FILE *f; + int numpoints; + winding_t *w; + int leafnums[2]; + plane_t plane; + + if (!strcmp(name,"-")) + f = stdin; + else + { + f = fopen(name, "r"); + if (!f) + Error ("LoadPortals: couldn't read %s\n",name); + } + + if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalclusters, &numportals) != 3) + Error ("LoadPortals: failed to read header"); + if (strcmp(magic,PORTALFILE)) + Error ("LoadPortals: not a portal file"); + + Sys_Printf ("%4i portalclusters\n", portalclusters); + Sys_Printf ("%4i numportals\n", numportals); + + // these counts should take advantage of 64 bit systems automatically + leafbytes = ((portalclusters+63)&~63)>>3; + leaflongs = leafbytes/sizeof(long); + + portalbytes = ((numportals*2+63)&~63)>>3; + portallongs = portalbytes/sizeof(long); + +// each file portal is split into two memory portals + portals = malloc(2*numportals*sizeof(portal_t)); + memset (portals, 0, 2*numportals*sizeof(portal_t)); + + leafs = malloc(portalclusters*sizeof(leaf_t)); + memset (leafs, 0, portalclusters*sizeof(leaf_t)); + + originalvismapsize = portalclusters*leafbytes; + uncompressedvis = malloc(originalvismapsize); + + vismap = vismap_p = dvisdata; + dvis->numclusters = portalclusters; + vismap_p = (byte *)&dvis->bitofs[portalclusters]; + + vismap_end = vismap + MAX_MAP_VISIBILITY; + + for (i=0, p=portals ; i MAX_POINTS_ON_WINDING) + Error ("LoadPortals: portal %i has too many points", i); + if ( (unsigned)leafnums[0] > portalclusters + || (unsigned)leafnums[1] > portalclusters) + Error ("LoadPortals: reading portal %i", i); + + w = p->winding = NewWinding (numpoints); + w->original = true; + w->numpoints = numpoints; + + for (j=0 ; jpoints[j][k] = v[k]; + } + fscanf (f, "\n"); + + // calc plane + PlaneFromWinding (w, &plane); + + // create forward portal + l = &leafs[leafnums[0]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = w; + VectorSubtract (vec3_origin, plane.normal, p->plane.normal); + p->plane.dist = -plane.dist; + p->leaf = leafnums[1]; + SetPortalSphere (p); + p++; + + // create backwards portal + l = &leafs[leafnums[1]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = NewWinding(w->numpoints); + p->winding->numpoints = w->numpoints; + for (j=0 ; jnumpoints ; j++) + { + VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); + } + + p->plane = plane; + p->leaf = leafnums[0]; + SetPortalSphere (p); + p++; + + } + + fclose (f); +} + + +/* +================ +CalcPHS + +Calculate the PHS (Potentially Hearable Set) +by ORing together all the PVS visible from a leaf +================ +*/ +void CalcPHS (void) +{ + int i, j, k, l, index; + int bitbyte; + long *dest, *src; + byte *scan; + int count; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + + Sys_Printf ("Building PHS...\n"); + + count = 0; + for (i=0 ; i= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + src = (long *)(uncompressedvis + index*leafbytes); + dest = (long *)uncompressed; + for (l=0 ; l>3] & (1<<(j&7)) ) + count++; + + // + // compress the bit string + // + j = CompressVis (uncompressed, compressed); + + dest = (long *)vismap_p; + vismap_p += j; + + if (vismap_p > vismap_end) + Error ("Vismap expansion overflow"); + + dvis->bitofs[i][DVIS_PHS] = (byte *)dest-vismap; + + memcpy (dest, compressed, j); + } + + Sys_Printf ("Average clusters hearable: %i\n", count/portalclusters); +} + +/* +=========== +main +=========== +*/ +int VIS_Main () +{ + char portalfile[1024]; + char source[1024]; + char name[1024]; + double start, end; + int total_vis_time; + + Sys_Printf ("\n----- VIS ----\n\n"); + + //if (i != argc - 1) + // Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile"); + + start = I_FloatTime (); + + ThreadSetDefault (); + + SetQdirFromPath (mapname); + strcpy (source, ExpandArg(mapname)); + StripExtension (source); + DefaultExtension (source, ".bsp"); + + sprintf (name, "%s%s", inbase, source); + Sys_Printf ("reading %s\n", name); + LoadBSPFile (name); + if (numnodes == 0 || numfaces == 0) + Error ("Empty map"); + + sprintf (portalfile, "%s%s", inbase, ExpandArg(mapname)); + StripExtension (portalfile); + strcat (portalfile, ".prt"); + + Sys_Printf ("reading %s\n", portalfile); + LoadPortals (portalfile); + + CalcVis (); + + CalcPHS (); + + visdatasize = vismap_p - dvisdata; + Sys_Printf ("visdatasize:%i compressed from %i\n", visdatasize, originalvismapsize*2); + + sprintf (name, "%s%s", outbase, source); + Sys_Printf ("writing %s\n", name); + WriteBSPFile (name); + + end = I_FloatTime (); + total_vis_time = (int) (end-start); + Sys_Printf("\nVIS Time: "); + if ( total_vis_time > 59 ) + Sys_Printf("%d Minutes ", total_vis_time/60 ); + Sys_Printf( "%d Seconds\n", total_vis_time%60 ); + + + return 0; +} + diff --git a/tools/quake2/q2map/qvis.h b/tools/quake2/q2map/qvis.h new file mode 100644 index 00000000..9128907c --- /dev/null +++ b/tools/quake2/q2map/qvis.h @@ -0,0 +1,169 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* Files: + +flow.c +qvis3.c + +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" +#include "inout.h" + +#ifdef _WIN32 + #ifdef NDEBUG // Don't show in a Release build + #pragma warning(disable : 4305) // truncate from double to float + #pragma warning(disable : 4244) // conversion from double to float + #pragma warning(disable : 4018) // signed/unsigned mismatch + #endif +#endif + +#define MAX_PORTALS 32768 + +#define PORTALFILE "PRT1" + +#define ON_EPSILON 0.1 + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +#define MAX_POINTS_ON_WINDING 64 +#define MAX_POINTS_ON_FIXED_WINDING 12 + +typedef struct +{ + qboolean original; // don't free, it's part of the portal + int numpoints; + vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized +} winding_t; + +winding_t *NewWinding (int points); +void FreeWinding (winding_t *w); +winding_t *CopyWinding (winding_t *w); + + +typedef enum {stat_none, stat_working, stat_done} vstatus_t; +typedef struct +{ + plane_t plane; // normal pointing into neighbor + int leaf; // neighbor + + vec3_t origin; // for fast clip testing + float radius; + + winding_t *winding; + vstatus_t status; + byte *portalfront; // [portals], preliminary + byte *portalflood; // [portals], intermediate + byte *portalvis; // [portals], final + + int nummightsee; // bit count on portalflood for sort +} portal_t; + +typedef struct seperating_plane_s +{ + struct seperating_plane_s *next; + plane_t plane; // from portal is on positive side +} sep_t; + + +typedef struct passage_s +{ + struct passage_s *next; + int from, to; // leaf numbers + sep_t *planes; +} passage_t; + +#define MAX_PORTALS_ON_LEAF 128 +typedef struct leaf_s +{ + int numportals; + passage_t *passages; + portal_t *portals[MAX_PORTALS_ON_LEAF]; +} leaf_t; + + +typedef struct pstack_s +{ + byte mightsee[MAX_PORTALS/8]; // bit string + struct pstack_s *next; + leaf_t *leaf; + portal_t *portal; // portal exiting + winding_t *source; + winding_t *pass; + + winding_t windings[3]; // source, pass, temp in any order + int freewindings[3]; + + plane_t portalplane; +} pstack_t; + +typedef struct +{ + portal_t *base; + int c_chains; + pstack_t pstack_head; +} threaddata_t; + + + +extern int numportals; +extern int portalclusters; + +extern portal_t *portals; +extern leaf_t *leafs; + +extern int c_portaltest, c_portalpass, c_portalcheck; +extern int c_portalskip, c_leafskip; +extern int c_vistest, c_mighttest; +extern int c_chains; + +extern byte *vismap, *vismap_p, *vismap_end; // past visfile + +extern int testlevel; + +extern byte *uncompressed; + +extern int leafbytes, leaflongs; +extern int portalbytes, portallongs; + + +void LeafFlow (int leafnum); + + +void BasePortalVis (int portalnum); +void BetterPortalVis (int portalnum); +void PortalFlow (int portalnum); + +extern portal_t *sorted_portals[MAX_MAP_PORTALS*2]; + +int CountBits (byte *bits, int numbits); + +//============================================================================= + +// externs + +extern char *mapname; diff --git a/tools/quake2/q2map/textures.c b/tools/quake2/q2map/textures.c new file mode 100644 index 00000000..bbf6b29a --- /dev/null +++ b/tools/quake2/q2map/textures.c @@ -0,0 +1,249 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + +int nummiptex; +textureref_t textureref[MAX_MAP_TEXTURES]; + +//========================================================================== + + +int FindMiptex (char *name) +{ + int i; + char path[1024]; + miptex_t *mt; + miptex_m8_t *mt_m8; + miptex_m32_t *mt_m32; + + for (i=0 ; ivalue); + textureref[i].flags = LittleLong (mt_m32->flags); + textureref[i].contents = LittleLong (mt_m32->contents); + strcpy (textureref[i].animname, mt_m32->animname); + free (mt_m32); + } + else + sprintf (path, "%stextures/%s.m8", gamedir, name); + + if (TryLoadFile (path, (void **)&mt_m8) != -1) + { + textureref[i].value = LittleLong (mt_m8->value); + textureref[i].flags = LittleLong (mt_m8->flags); + textureref[i].contents = LittleLong (mt_m8->contents); + strcpy (textureref[i].animname, mt_m8->animname); + free (mt_m8); + } + } + else + { + sprintf (path, "%stextures/%s.wal", gamedir, name); + if (TryLoadFile (path, (void **)&mt) != -1) + { + textureref[i].value = LittleLong (mt->value); + textureref[i].flags = LittleLong (mt->flags); + textureref[i].contents = LittleLong (mt->contents); + strcpy (textureref[i].animname, mt->animname); + free (mt); + } + } + + nummiptex++; + + if (textureref[i].animname[0]) + FindMiptex (textureref[i].animname); + + return i; +} + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + vec_t dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + + + +int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin) +{ + vec3_t vecs[2]; + int sv, tv; + vec_t ang, sinv, cosv; + vec_t ns, nt; + texinfo_t tx, *tc; + int i, j, k; + float shift[2]; + brush_texture_t anim; + int mt; + + if (!bt->name[0]) + return 0; + + memset (&tx, 0, sizeof(tx)); + strcpy (tx.texture, bt->name); + + TextureAxisFromPlane(plane, vecs[0], vecs[1]); + + shift[0] = DotProduct (origin, vecs[0]); + shift[1] = DotProduct (origin, vecs[1]); + + if (!bt->scale[0]) + bt->scale[0] = 1; + if (!bt->scale[1]) + bt->scale[1] = 1; + + +// rotate axis + if (bt->rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (bt->rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (bt->rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (bt->rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = bt->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (vecs[0][0]) + sv = 0; + else if (vecs[0][1]) + sv = 1; + else + sv = 2; + + if (vecs[1][0]) + tv = 0; + else if (vecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) + { + ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; + nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + tx.vecs[i][j] = vecs[i][j] / bt->scale[i]; + + tx.vecs[0][3] = bt->shift[0] + shift[0]; + tx.vecs[1][3] = bt->shift[1] + shift[1]; + tx.flags = bt->flags; + tx.value = bt->value; + + // + // find the texinfo + // + tc = texinfo; + for (i=0 ; iflags != tx.flags) + continue; + if (tc->value != tx.value) + continue; + for (j=0 ; j<2 ; j++) + { + if (strcmp (tc->texture, tx.texture)) + goto skip; + for (k=0 ; k<4 ; k++) + { + if (tc->vecs[j][k] != tx.vecs[j][k]) + goto skip; + } + } + return i; +skip:; + } + *tc = tx; + numtexinfo++; + + // load the next animation + mt = FindMiptex (bt->name); + if (textureref[mt].animname[0]) + { + anim = *bt; + strcpy (anim.name, textureref[mt].animname); + tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); + } + else + tc->nexttexinfo = -1; + + + return i; +} diff --git a/tools/quake2/q2map/trace.c b/tools/quake2/q2map/trace.c new file mode 100644 index 00000000..66d0e837 --- /dev/null +++ b/tools/quake2/q2map/trace.c @@ -0,0 +1,298 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +// trace.c +/* +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" +*/ + +#include "qrad.h" + +#define ON_EPSILON 0.1 + +typedef struct tnode_s +{ + int type; + vec3_t normal; + float dist; + int children[2]; + int pad; +} tnode_t; + +tnode_t *tnodes, *tnode_p; + +/* +============== +MakeTnode + +Converts the disk node structure into the efficient tracing structure +============== +*/ +void MakeTnode (int nodenum) +{ + tnode_t *t; + dplane_t *plane; + int i; + dnode_t *node; + + t = tnode_p++; + + node = dnodes + nodenum; + plane = dplanes + node->planenum; + + t->type = plane->type; + VectorCopy (plane->normal, t->normal); + t->dist = plane->dist; + + for (i=0 ; i<2 ; i++) + { + if (node->children[i] < 0) + t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31); + else + { + t->children[i] = tnode_p - tnodes; + MakeTnode (node->children[i]); + } + } + +} + + +/* +============= +MakeTnodes + +Loads the node structure out of a .bsp file to be used for light occlusion +============= +*/ +void MakeTnodes (dmodel_t *bm) +{ + // 32 byte align the structs + tnodes = malloc( (numnodes+1) * sizeof(tnode_t)); + tnodes = (tnode_t *)(((int)tnodes + 31)&~31); + tnode_p = tnodes; + + MakeTnode (0); +} + + +//========================================================== + + +int TestLine_r (int node, vec3_t start, vec3_t stop) +{ + tnode_t *tnode; + float front, back; + vec3_t mid; + float frac; + int side; + int r; + + if (node & (1<<31)) + return node & ~(1<<31); // leaf node + + tnode = &tnodes[node]; + switch (tnode->type) + { + case PLANE_X: + front = start[0] - tnode->dist; + back = stop[0] - tnode->dist; + break; + case PLANE_Y: + front = start[1] - tnode->dist; + back = stop[1] - tnode->dist; + break; + case PLANE_Z: + front = start[2] - tnode->dist; + back = stop[2] - tnode->dist; + break; + default: + front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist; + back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist; + break; + } + + if (front >= -ON_EPSILON && back >= -ON_EPSILON) + return TestLine_r (tnode->children[0], start, stop); + + if (front < ON_EPSILON && back < ON_EPSILON) + return TestLine_r (tnode->children[1], start, stop); + + side = front < 0; + + frac = front / (front-back); + + mid[0] = start[0] + (stop[0] - start[0])*frac; + mid[1] = start[1] + (stop[1] - start[1])*frac; + mid[2] = start[2] + (stop[2] - start[2])*frac; + + r = TestLine_r (tnode->children[side], start, mid); + if (r) + return r; + return TestLine_r (tnode->children[!side], mid, stop); +} + +int TestLine (vec3_t start, vec3_t stop) +{ + return TestLine_r (0, start, stop); +} + +/* +============================================================================== + +LINE TRACING + +The major lighting operation is a point to point visibility test, performed +by recursive subdivision of the line by the BSP tree. + +============================================================================== +*/ + +typedef struct +{ + vec3_t backpt; + int side; + int node; +} tracestack_t; + + +/* +============== +TestLine +============== +*/ +qboolean _TestLine (vec3_t start, vec3_t stop) +{ + int node; + float front, back; + tracestack_t *tstack_p; + int side; + float frontx,fronty, frontz, backx, backy, backz; + tracestack_t tracestack[64]; + tnode_t *tnode; + + frontx = start[0]; + fronty = start[1]; + frontz = start[2]; + backx = stop[0]; + backy = stop[1]; + backz = stop[2]; + + tstack_p = tracestack; + node = 0; + + while (1) + { + if (node == CONTENTS_SOLID) + { +#if 0 + float d1, d2, d3; + + d1 = backx - frontx; + d2 = backy - fronty; + d3 = backz - frontz; + + if (d1*d1 + d2*d2 + d3*d3 > 1) +#endif + return false; // DONE! + } + + while (node < 0) + { + // pop up the stack for a back side + tstack_p--; + if (tstack_p < tracestack) + return true; + node = tstack_p->node; + + // set the hit point for this plane + + frontx = backx; + fronty = backy; + frontz = backz; + + // go down the back side + + backx = tstack_p->backpt[0]; + backy = tstack_p->backpt[1]; + backz = tstack_p->backpt[2]; + + node = tnodes[tstack_p->node].children[!tstack_p->side]; + } + + tnode = &tnodes[node]; + + switch (tnode->type) + { + case PLANE_X: + front = frontx - tnode->dist; + back = backx - tnode->dist; + break; + case PLANE_Y: + front = fronty - tnode->dist; + back = backy - tnode->dist; + break; + case PLANE_Z: + front = frontz - tnode->dist; + back = backz - tnode->dist; + break; + default: + front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist; + back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist; + break; + } + + if (front > -ON_EPSILON && back > -ON_EPSILON) +// if (front > 0 && back > 0) + { + node = tnode->children[0]; + continue; + } + + if (front < ON_EPSILON && back < ON_EPSILON) +// if (front <= 0 && back <= 0) + { + node = tnode->children[1]; + continue; + } + + side = front < 0; + + front = front / (front-back); + + tstack_p->node = node; + tstack_p->side = side; + tstack_p->backpt[0] = backx; + tstack_p->backpt[1] = backy; + tstack_p->backpt[2] = backz; + + tstack_p++; + + backx = frontx + front*(backx-frontx); + backy = fronty + front*(backy-fronty); + backz = frontz + front*(backz-frontz); + + node = tnode->children[side]; + } +} + + diff --git a/tools/quake2/q2map/tree.c b/tools/quake2/q2map/tree.c new file mode 100644 index 00000000..ec5b5b7c --- /dev/null +++ b/tools/quake2/q2map/tree.c @@ -0,0 +1,218 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "qbsp.h" + +extern int c_nodes; + +void RemovePortalFromNode (portal_t *portal, node_t *l); + +node_t *NodeForPoint (node_t *node, vec3_t origin) +{ + plane_t *plane; + vec_t d; + + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if (d >= 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return node; +} + + + +/* +============= +FreeTreePortals_r +============= +*/ +void FreeTreePortals_r (node_t *node) +{ + portal_t *p, *nextp; + int s; + + // free children + if (node->planenum != PLANENUM_LEAF) + { + FreeTreePortals_r (node->children[0]); + FreeTreePortals_r (node->children[1]); + } + + // free portals + for (p=node->portals ; p ; p=nextp) + { + s = (p->nodes[1] == node); + nextp = p->next[s]; + + RemovePortalFromNode (p, p->nodes[!s]); + FreePortal (p); + } + node->portals = NULL; +} + +/* +============= +FreeTree_r +============= +*/ +void FreeTree_r (node_t *node) +{ + face_t *f, *nextf; + + // free children + if (node->planenum != PLANENUM_LEAF) + { + FreeTree_r (node->children[0]); + FreeTree_r (node->children[1]); + } + + // free bspbrushes + FreeBrushList (node->brushlist); + + // free faces + for (f=node->faces ; f ; f=nextf) + { + nextf = f->next; + FreeFace (f); + } + + // free the node + if (node->volume) + FreeBrush (node->volume); + + if (numthreads == 1) + c_nodes--; + free (node); +} + + +/* +============= +FreeTree +============= +*/ +void FreeTree (tree_t *tree) +{ + FreeTreePortals_r (tree->headnode); + FreeTree_r (tree->headnode); + free (tree); +} + +//=============================================================== + +void PrintTree_r (node_t *node, int depth) +{ + int i; + plane_t *plane; + bspbrush_t *bb; + + for (i=0 ; iplanenum == PLANENUM_LEAF) + { + if (!node->brushlist) + Sys_Printf ("NULL\n"); + else + { + for (bb=node->brushlist ; bb ; bb=bb->next) + Sys_Printf ("%i ", bb->original->brushnum); + Sys_Printf ("\n"); + } + return; + } + + plane = &mapplanes[node->planenum]; + Sys_Printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum, + plane->normal[0], plane->normal[1], plane->normal[2], + plane->dist); + PrintTree_r (node->children[0], depth+1); + PrintTree_r (node->children[1], depth+1); +} + +/* +========================================================= + +NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED + +========================================================= +*/ + +int c_pruned; + +/* +============ +PruneNodes_r +============ +*/ +void PruneNodes_r (node_t *node) +{ + bspbrush_t *b, *next; + + if (node->planenum == PLANENUM_LEAF) + return; + PruneNodes_r (node->children[0]); + PruneNodes_r (node->children[1]); + + if ( (node->children[0]->contents & CONTENTS_SOLID) + && (node->children[1]->contents & CONTENTS_SOLID) ) + { + if (node->faces) + Error ("node->faces seperating CONTENTS_SOLID"); + if (node->children[0]->faces || node->children[1]->faces) + Error ("!node->faces with children"); + + // FIXME: free stuff + node->planenum = PLANENUM_LEAF; + node->contents = CONTENTS_SOLID; + node->detail_seperator = false; + + if (node->brushlist) + Error ("PruneNodes: node->brushlist"); + + // combine brush lists + node->brushlist = node->children[1]->brushlist; + + for (b=node->children[0]->brushlist ; b ; b=next) + { + next = b->next; + b->next = node->brushlist; + node->brushlist = b; + } + + c_pruned++; + } +} + + +void PruneNodes (node_t *node) +{ + Sys_FPrintf( SYS_VRB, "--- PruneNodes ---\n"); + c_pruned = 0; + PruneNodes_r (node); + Sys_FPrintf( SYS_VRB, "%5i pruned nodes\n", c_pruned); +} + +//=========================================================== diff --git a/tools/quake2/q2map/writebsp.c b/tools/quake2/q2map/writebsp.c new file mode 100644 index 00000000..083f0ea7 --- /dev/null +++ b/tools/quake2/q2map/writebsp.c @@ -0,0 +1,591 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "qbsp.h" + +int c_nofaces; +int c_facenodes; + + +/* +========================================================= + +ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES + +========================================================= +*/ + +int planeused[MAX_MAP_PLANES]; + +/* +============ +EmitPlanes + +There is no oportunity to discard planes, because all of the original +brushes will be saved in the map. +============ +*/ +void EmitPlanes (void) +{ + int i; + dplane_t *dp; + plane_t *mp; + int planetranslate[MAX_MAP_PLANES]; + + mp = mapplanes; + for (i=0 ; inormal, dp->normal); + dp->dist = mp->dist; + dp->type = mp->type; + numplanes++; + } +} + + +//======================================================== + +void EmitMarkFace (dleaf_t *leaf_p, face_t *f) +{ + int i; + int facenum; + + while (f->merged) + f = f->merged; + + if (f->split[0]) + { + EmitMarkFace (leaf_p, f->split[0]); + EmitMarkFace (leaf_p, f->split[1]); + return; + } + + facenum = f->outputnumber; + if (facenum == -1) + return; // degenerate face + + if (facenum < 0 || facenum >= numfaces) + Error ("Bad leafface"); + for (i=leaf_p->firstleafface ; i= MAX_MAP_LEAFFACES) + Error ("MAX_MAP_LEAFFACES"); + + dleaffaces[numleaffaces] = facenum; + numleaffaces++; + } + +} + + +/* +================== +EmitLeaf +================== +*/ +void EmitLeaf (node_t *node) +{ + dleaf_t *leaf_p; + portal_t *p; + int s; + face_t *f; + bspbrush_t *b; + int i; + int brushnum; + + // emit a leaf + if (numleafs >= MAX_MAP_LEAFS) + Error ("MAX_MAP_LEAFS"); + + leaf_p = &dleafs[numleafs]; + numleafs++; + + leaf_p->contents = node->contents; + leaf_p->cluster = node->cluster; + leaf_p->area = node->area; + + // + // write bounding box info + // + VectorCopy ((short) node->mins, leaf_p->mins); + VectorCopy ((short) node->maxs, leaf_p->maxs); + + // + // write the leafbrushes + // + leaf_p->firstleafbrush = numleafbrushes; + for (b=node->brushlist ; b ; b=b->next) + { + if (numleafbrushes >= MAX_MAP_LEAFBRUSHES) + Error ("MAX_MAP_LEAFBRUSHES"); + + brushnum = b->original - mapbrushes; + for (i=leaf_p->firstleafbrush ; inumleafbrushes = numleafbrushes - leaf_p->firstleafbrush; + + // + // write the leaffaces + // + if (leaf_p->contents & CONTENTS_SOLID) + return; // no leaffaces in solids + + leaf_p->firstleafface = numleaffaces; + + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + f = p->face[s]; + if (!f) + continue; // not a visible portal + + EmitMarkFace (leaf_p, f); + } + + leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface; +} + + +/* +================== +EmitFace +================== +*/ +void EmitFace (face_t *f) +{ + dface_t *df; + int i; + int e; + + f->outputnumber = -1; + + if (f->numpoints < 3) + { + return; // degenerated + } + if (f->merged || f->split[0] || f->split[1]) + { + return; // not a final face + } + + // save output number so leaffaces can use + f->outputnumber = numfaces; + + if (numfaces >= MAX_MAP_FACES) + Error ("numfaces == MAX_MAP_FACES"); + df = &dfaces[numfaces]; + numfaces++; + + // planenum is used by qlight, but not quake + df->planenum = f->planenum & (~1); + df->side = f->planenum & 1; + + df->firstedge = numsurfedges; + df->numedges = f->numpoints; + df->texinfo = f->texinfo; + for (i=0 ; inumpoints ; i++) + { +// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f); + e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f); + if (numsurfedges >= MAX_MAP_SURFEDGES) + Error ("numsurfedges == MAX_MAP_SURFEDGES"); + dsurfedges[numsurfedges] = e; + numsurfedges++; + } +} + +/* +============ +EmitDrawingNode_r +============ +*/ +int EmitDrawNode_r (node_t *node) +{ + dnode_t *n; + face_t *f; + int i; + + if (node->planenum == PLANENUM_LEAF) + { + EmitLeaf (node); + return -numleafs; + } + + // emit a node + if (numnodes == MAX_MAP_NODES) + Error ("MAX_MAP_NODES"); + n = &dnodes[numnodes]; + numnodes++; + + VectorCopy ((short) node->mins, n->mins); + VectorCopy ((short) node->maxs, n->maxs); + + planeused[node->planenum]++; + planeused[node->planenum^1]++; + + if (node->planenum & 1) + Error ("WriteDrawNodes_r: odd planenum"); + n->planenum = node->planenum; + n->firstface = numfaces; + + if (!node->faces) + c_nofaces++; + else + c_facenodes++; + + for (f=node->faces ; f ; f=f->next) + EmitFace (f); + + n->numfaces = numfaces - n->firstface; + + + // + // recursively output the other nodes + // + for (i=0 ; i<2 ; i++) + { + if (node->children[i]->planenum == PLANENUM_LEAF) + { + n->children[i] = -(numleafs + 1); + EmitLeaf (node->children[i]); + } + else + { + n->children[i] = numnodes; + EmitDrawNode_r (node->children[i]); + } + } + + return n - dnodes; +} + +//========================================================= + + +/* +============ +WriteBSP +============ +*/ +void WriteBSP (node_t *headnode) +{ + int oldfaces; + + c_nofaces = 0; + c_facenodes = 0; + + Sys_FPrintf( SYS_VRB, "--- WriteBSP ---\n"); + + oldfaces = numfaces; + dmodels[nummodels].headnode = EmitDrawNode_r (headnode); + EmitAreaPortals (headnode); + + Sys_FPrintf( SYS_VRB, "%5i nodes with faces\n", c_facenodes); + Sys_FPrintf( SYS_VRB, "%5i nodes without faces\n", c_nofaces); + Sys_FPrintf( SYS_VRB, "%5i faces\n", numfaces-oldfaces); +} + +//=========================================================== + +/* +============ +SetModelNumbers +============ +*/ +void SetModelNumbers (void) +{ + int i; + int models; + char value[10]; + + models = 1; + for (i=1 ; icontents = b->contents; + db->firstside = numbrushsides; + db->numsides = b->numsides; + for (j=0 ; jnumsides ; j++) + { + if (numbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + cp = &dbrushsides[numbrushsides]; + numbrushsides++; + cp->planenum = b->original_sides[j].planenum; + cp->texinfo = b->original_sides[j].texinfo; + } + + // add any axis planes not contained in the brush to bevel off corners + for (x=0 ; x<3 ; x++) + for (s=-1 ; s<=1 ; s+=2) + { + // add the plane + VectorCopy (vec3_origin, normal); + normal[x] = (float) s; + if (s == -1) + dist = -b->mins[x]; + else + dist = b->maxs[x]; + planenum = FindFloatPlane (normal, dist); + for (i=0 ; inumsides ; i++) + if (b->original_sides[i].planenum == planenum) + break; + if (i == b->numsides) + { + if (numbrushsides >= MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + + dbrushsides[numbrushsides].planenum = planenum; + dbrushsides[numbrushsides].texinfo = + dbrushsides[numbrushsides-1].texinfo; + numbrushsides++; + db->numsides++; + } + } + + } + +} + +//=========================================================== + +/* +================== +BeginBSPFile +================== +*/ +void BeginBSPFile (void) +{ + // these values may actually be initialized + // if the file existed when loaded, so clear them explicitly + nummodels = 0; + numfaces = 0; + numnodes = 0; + numbrushsides = 0; + numvertexes = 0; + numleaffaces = 0; + numleafbrushes = 0; + numsurfedges = 0; + + // edge 0 is not used, because 0 can't be negated + numedges = 1; + + // leave vertex 0 as an error + numvertexes = 1; + + // leave leaf 0 as an error + numleafs = 1; + dleafs[0].contents = CONTENTS_SOLID; +} + + +/* +============ +EndBSPFile +============ +*/ +void EndBSPFile (void) +{ + char path[1024]; + +#if 0 + int len; + byte *buf; +#endif + + EmitBrushes (); + EmitPlanes (); + UnparseEntities (); + + // load the pop +#if 0 + sprintf (path, "%s/pics/pop.lmp", gamedir); + len = LoadFile (path, &buf); + memcpy (dpop, buf, sizeof(dpop)); + free (buf); +#endif + + // write the map + sprintf (path, "%s.bsp", source); + Sys_Printf ("Writing %s\n", path); + WriteBSPFile (path); +} + + +/* +================== +BeginModel +================== +*/ +int firstmodleaf; +extern int firstmodeledge; +extern int firstmodelface; +void BeginModel (void) +{ + dmodel_t *mod; + int start, end; + mapbrush_t *b; + int j; + entity_t *e; + vec3_t mins, maxs; + + if (nummodels == MAX_MAP_MODELS) + Error ("MAX_MAP_MODELS"); + mod = &dmodels[nummodels]; + + mod->firstface = numfaces; + + firstmodleaf = numleafs; + firstmodeledge = numedges; + firstmodelface = numfaces; + + // + // bound the brushes + // + e = &entities[entity_num]; + + start = e->firstbrush; + end = start + e->numbrushes; + ClearBounds (mins, maxs); + + for (j=start ; jnumsides) + continue; // not a real brush (origin brush) + AddPointToBounds (b->mins, mins, maxs); + AddPointToBounds (b->maxs, mins, maxs); + } + + VectorCopy (mins, mod->mins); + VectorCopy (maxs, mod->maxs); +} + + +/* +================== +EndModel +================== +*/ +void EndModel (void) +{ + dmodel_t *mod; + + mod = &dmodels[nummodels]; + + mod->numfaces = numfaces - mod->firstface; + + nummodels++; +} + diff --git a/tools/quake2/qdata/anorms.h b/tools/quake2/qdata/anorms.h new file mode 100644 index 00000000..caddaa0c --- /dev/null +++ b/tools/quake2/qdata/anorms.h @@ -0,0 +1,162 @@ + { -0.525731f, 0.000000f, 0.850651f }, + { -0.442863f, 0.238856f, 0.864188f }, + { -0.295242f, 0.000000f, 0.955423f }, + { -0.309017f, 0.500000f, 0.809017f }, + { -0.162460f, 0.262866f, 0.951056f }, + { 0.000000f, 0.000000f, 1.000000f }, + { 0.000000f, 0.850651f, 0.525731f }, + { -0.147621f, 0.716567f, 0.681718f }, + { 0.147621f, 0.716567f, 0.681718f }, + { 0.000000f, 0.525731f, 0.850651f }, + { 0.309017f, 0.500000f, 0.809017f }, + { 0.525731f, 0.000000f, 0.850651f }, + { 0.295242f, 0.000000f, 0.955423f }, + { 0.442863f, 0.238856f, 0.864188f }, + { 0.162460f, 0.262866f, 0.951056f }, + { -0.681718f, 0.147621f, 0.716567f }, + { -0.809017f, 0.309017f, 0.500000f }, + { -0.587785f, 0.425325f, 0.688191f }, + { -0.850651f, 0.525731f, 0.000000f }, + { -0.864188f, 0.442863f, 0.238856f }, + { -0.716567f, 0.681718f, 0.147621f }, + { -0.688191f, 0.587785f, 0.425325f }, + { -0.500000f, 0.809017f, 0.309017f }, + { -0.238856f, 0.864188f, 0.442863f }, + { -0.425325f, 0.688191f, 0.587785f }, + { -0.716567f, 0.681718f, -0.147621f }, + { -0.500000f, 0.809017f, -0.309017f }, + { -0.525731f, 0.850651f, 0.000000f }, + { 0.000000f, 0.850651f, -0.525731f }, + { -0.238856f, 0.864188f, -0.442863f }, + { 0.000000f, 0.955423f, -0.295242f }, + { -0.262866f, 0.951056f, -0.162460f }, + { 0.000000f, 1.000000f, 0.000000f }, + { 0.000000f, 0.955423f, 0.295242f }, + { -0.262866f, 0.951056f, 0.162460f }, + { 0.238856f, 0.864188f, 0.442863f }, + { 0.262866f, 0.951056f, 0.162460f }, + { 0.500000f, 0.809017f, 0.309017f }, + { 0.238856f, 0.864188f, -0.442863f }, + { 0.262866f, 0.951056f, -0.162460f }, + { 0.500000f, 0.809017f, -0.309017f }, + { 0.850651f, 0.525731f, 0.000000f }, + { 0.716567f, 0.681718f, 0.147621f }, + { 0.716567f, 0.681718f, -0.147621f }, + { 0.525731f, 0.850651f, 0.000000f }, + { 0.425325f, 0.688191f, 0.587785f }, + { 0.864188f, 0.442863f, 0.238856f }, + { 0.688191f, 0.587785f, 0.425325f }, + { 0.809017f, 0.309017f, 0.500000f }, + { 0.681718f, 0.147621f, 0.716567f }, + { 0.587785f, 0.425325f, 0.688191f }, + { 0.955423f, 0.295242f, 0.000000f }, + { 1.000000f, 0.000000f, 0.000000f }, + { 0.951056f, 0.162460f, 0.262866f }, + { 0.850651f, -0.525731f, 0.000000f }, + { 0.955423f, -0.295242f, 0.000000f }, + { 0.864188f, -0.442863f, 0.238856f }, + { 0.951056f, -0.162460f, 0.262866f }, + { 0.809017f, -0.309017f, 0.500000f }, + { 0.681718f, -0.147621f, 0.716567f }, + { 0.850651f, 0.000000f, 0.525731f }, + { 0.864188f, 0.442863f, -0.238856f }, + { 0.809017f, 0.309017f, -0.500000f }, + { 0.951056f, 0.162460f, -0.262866f }, + { 0.525731f, 0.000000f, -0.850651f }, + { 0.681718f, 0.147621f, -0.716567f }, + { 0.681718f, -0.147621f, -0.716567f }, + { 0.850651f, 0.000000f, -0.525731f }, + { 0.809017f, -0.309017f, -0.500000f }, + { 0.864188f, -0.442863f, -0.238856f }, + { 0.951056f, -0.162460f, -0.262866f }, + { 0.147621f, 0.716567f, -0.681718f }, + { 0.309017f, 0.500000f, -0.809017f }, + { 0.425325f, 0.688191f, -0.587785f }, + { 0.442863f, 0.238856f, -0.864188f }, + { 0.587785f, 0.425325f, -0.688191f }, + { 0.688191f, 0.587785f, -0.425325f }, + { -0.147621f, 0.716567f, -0.681718f }, + { -0.309017f, 0.500000f, -0.809017f }, + { 0.000000f, 0.525731f, -0.850651f }, + { -0.525731f, 0.000000f, -0.850651f }, + { -0.442863f, 0.238856f, -0.864188f }, + { -0.295242f, 0.000000f, -0.955423f }, + { -0.162460f, 0.262866f, -0.951056f }, + { 0.000000f, 0.000000f, -1.000000f }, + { 0.295242f, 0.000000f, -0.955423f }, + { 0.162460f, 0.262866f, -0.951056f }, + { -0.442863f, -0.238856f, -0.864188f }, + { -0.309017f, -0.500000f, -0.809017f }, + { -0.162460f, -0.262866f, -0.951056f }, + { 0.000000f, -0.850651f, -0.525731f }, + { -0.147621f, -0.716567f, -0.681718f }, + { 0.147621f, -0.716567f, -0.681718f }, + { 0.000000f, -0.525731f, -0.850651f }, + { 0.309017f, -0.500000f, -0.809017f }, + { 0.442863f, -0.238856f, -0.864188f }, + { 0.162460f, -0.262866f, -0.951056f }, + { 0.238856f, -0.864188f, -0.442863f }, + { 0.500000f, -0.809017f, -0.309017f }, + { 0.425325f, -0.688191f, -0.587785f }, + { 0.716567f, -0.681718f, -0.147621f }, + { 0.688191f, -0.587785f, -0.425325f }, + { 0.587785f, -0.425325f, -0.688191f }, + { 0.000000f, -0.955423f, -0.295242f }, + { 0.000000f, -1.000000f, 0.000000f }, + { 0.262866f, -0.951056f, -0.162460f }, + { 0.000000f, -0.850651f, 0.525731f }, + { 0.000000f, -0.955423f, 0.295242f }, + { 0.238856f, -0.864188f, 0.442863f }, + { 0.262866f, -0.951056f, 0.162460f }, + { 0.500000f, -0.809017f, 0.309017f }, + { 0.716567f, -0.681718f, 0.147621f }, + { 0.525731f, -0.850651f, 0.000000f }, + { -0.238856f, -0.864188f, -0.442863f }, + { -0.500000f, -0.809017f, -0.309017f }, + { -0.262866f, -0.951056f, -0.162460f }, + { -0.850651f, -0.525731f, 0.000000f }, + { -0.716567f, -0.681718f, -0.147621f }, + { -0.716567f, -0.681718f, 0.147621f }, + { -0.525731f, -0.850651f, 0.000000f }, + { -0.500000f, -0.809017f, 0.309017f }, + { -0.238856f, -0.864188f, 0.442863f }, + { -0.262866f, -0.951056f, 0.162460f }, + { -0.864188f, -0.442863f, 0.238856f }, + { -0.809017f, -0.309017f, 0.500000f }, + { -0.688191f, -0.587785f, 0.425325f }, + { -0.681718f, -0.147621f, 0.716567f }, + { -0.442863f, -0.238856f, 0.864188f }, + { -0.587785f, -0.425325f, 0.688191f }, + { -0.309017f, -0.500000f, 0.809017f }, + { -0.147621f, -0.716567f, 0.681718f }, + { -0.425325f, -0.688191f, 0.587785f }, + { -0.162460f, -0.262866f, 0.951056f }, + { 0.442863f, -0.238856f, 0.864188f }, + { 0.162460f, -0.262866f, 0.951056f }, + { 0.309017f, -0.500000f, 0.809017f }, + { 0.147621f, -0.716567f, 0.681718f }, + { 0.000000f, -0.525731f, 0.850651f }, + { 0.425325f, -0.688191f, 0.587785f }, + { 0.587785f, -0.425325f, 0.688191f }, + { 0.688191f, -0.587785f, 0.425325f }, + { -0.955423f, 0.295242f, 0.000000f }, + { -0.951056f, 0.162460f, 0.262866f }, + { -1.000000f, 0.000000f, 0.000000f }, + { -0.850651f, 0.000000f, 0.525731f }, + { -0.955423f, -0.295242f, 0.000000f }, + { -0.951056f, -0.162460f, 0.262866f }, + { -0.864188f, 0.442863f, -0.238856f }, + { -0.951056f, 0.162460f, -0.262866f }, + { -0.809017f, 0.309017f, -0.500000f }, + { -0.864188f, -0.442863f, -0.238856f }, + { -0.951056f, -0.162460f, -0.262866f }, + { -0.809017f, -0.309017f, -0.500000f }, + { -0.681718f, 0.147621f, -0.716567f }, + { -0.681718f, -0.147621f, -0.716567f }, + { -0.850651f, 0.000000f, -0.525731f }, + { -0.688191f, 0.587785f, -0.425325f }, + { -0.587785f, 0.425325f, -0.688191f }, + { -0.425325f, 0.688191f, -0.587785f }, + { -0.425325f, -0.688191f, -0.587785f }, + { -0.587785f, -0.425325f, -0.688191f }, + { -0.688191f, -0.587785f, -0.425325f }, diff --git a/tools/quake2/qdata/images.c b/tools/quake2/qdata/images.c new file mode 100644 index 00000000..e3b8fc1b --- /dev/null +++ b/tools/quake2/qdata/images.c @@ -0,0 +1,742 @@ +#include "qdata.h" +#include "inout.h" + +char mip_prefix[1024]; // directory to dump the textures in + +qboolean colormap_issued; +byte colormap_palette[768]; + +/* +============== +RemapZero + +Replaces all 0 bytes in an image with the closest palette entry. +This is because NT won't let us change index 0, so any palette +animation leaves those pixels untouched. +============== +*/ +void RemapZero (byte *pixels, byte *palette, int width, int height) +{ + int i, c; + int alt_zero; + int value, best; + + alt_zero = 0; + best = 9999999; + for (i=1 ; i<255 ; i++) + { + value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2]; + if (value < best) + { + best = value; + alt_zero = i; + } + } + + c = width*height; + for (i=0 ; ibyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; ybyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; y 255) + r = 255; + if (r < 0) + r = 0; + if (g > 255) + g = 255; + if (g < 0) + g = 0; + if (b > 255) + b = 255; + if (b < 0) + b = 0; +#ifndef TABLECOLORS + bestcolor = BestColor (r, g, b, 0, 254); +#else + bestcolor = palmap[r>>3][g>>3][b>>3]; +#endif + + return bestcolor; +} + + +void BuildPalmap (void) +{ +#ifdef TABLECOLORS + int r, g, b; + int bestcolor; + + if (palmap_built) + return; + palmap_built = true; + + for (r=4 ; r<256 ; r+=8) + { + for (g=4 ; g<256 ; g+=8) + { + for (b=4 ; b<256 ; b+=8) + { + bestcolor = BestColor (r, g, b, 1, 254); + palmap[r>>3][g>>3][b>>3] = bestcolor; + } + } + } +#endif + + if (!colormap_issued) + Error ("You must issue a $colormap command first"); + +} + +/* +============= +AveragePixels +============= +*/ +byte AveragePixels (int count) +{ + int r,g,b; + int i; + int vis; + int pix; + int bestcolor; + byte *pal; + int fullbright; + + vis = 0; + r = g = b = 0; + fullbright = 0; + for (i=0 ; i +must be multiples of sixteen +SURF_WINDOW +============== +*/ +void Cmd_Mip (void) +{ + int x,y,xl,yl,xh,yh,w,h; + byte *screen_p, *source; + int linedelta; + miptex_t *qtex; + int miplevel, mipstep; + int xx, yy, pix; + int count; + int flags, value, contents; + mipparm_t *mp; + char lumpname[64]; + byte *lump_p; + char filename[1024]; + char animname[64]; + + GetToken (false); + strcpy (lumpname, token); + + GetToken (false); + xl = atoi (token); + GetToken (false); + yl = atoi (token); + GetToken (false); + w = atoi (token); + GetToken (false); + h = atoi (token); + + if ( (w & 15) || (h & 15) ) + Error ("line %i: miptex sizes must be multiples of 16", scriptline); + + flags = 0; + contents = 0; + value = 0; + + animname[0] = 0; + + // get optional flags and values + while (TokenAvailable ()) + { + GetToken (false); + + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + switch (mp->type) + { + case pt_animvalue: + GetToken (false); // specify the next animation frame + strcpy (animname, token); + break; + case pt_flags: + flags |= mp->flags; + break; + case pt_contents: + contents |= mp->flags; + break; + case pt_flagvalue: + flags |= mp->flags; + GetToken (false); // specify the light value + value = atoi(token); + break; + } + break; + } + } + if (!mp->name) + Error ("line %i: unknown parm %s", scriptline, token); + } + + sprintf (filename, "%stextures/%s/%s.wal", gamedir, mip_prefix, lumpname); + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + qtex = malloc (sizeof(miptex_t) + w*h*2); + memset (qtex, 0, sizeof(miptex_t)); + + qtex->width = LittleLong(w); + qtex->height = LittleLong(h); + qtex->flags = LittleLong(flags); + qtex->contents = LittleLong(contents); + qtex->value = LittleLong(value); + sprintf (qtex->name, "%s/%s", mip_prefix, lumpname); + if (animname[0]) + sprintf (qtex->animname, "%s/%s", mip_prefix, animname); + + lump_p = (byte *)(&qtex->value+1); + + screen_p = byteimage + yl*byteimagewidth + xl; + linedelta = byteimagewidth - w; + + source = lump_p; + qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex); + + for (y=yl ; yoffsets[miplevel] = LittleLong(lump_p - (byte *)qtex); + + mipstep = 1< /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/models.o : models.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/sprites.o : sprites.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/images.o : images.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/tables.o : tables.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i + +$(ODIR)/cmdlib.o : ../common/cmdlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/scriplib.o : ../common/scriplib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/lbmlib.o : ../common/lbmlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/mathlib.o : ../common/mathlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/trilib.o : ../common/trilib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/l3dslib.o : ../common/l3dslib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/threads.o : ../common/threads.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i diff --git a/tools/quake2/qdata/models.c b/tools/quake2/qdata/models.c new file mode 100644 index 00000000..58fdc0ff --- /dev/null +++ b/tools/quake2/qdata/models.c @@ -0,0 +1,1132 @@ + +#include "qdata.h" +#include "inout.h" + +//================================================================= + +typedef struct +{ + int numnormals; + vec3_t normalsum; +} vertexnormals_t; + +typedef struct +{ + vec3_t v; + int lightnormalindex; +} trivert_t; + +typedef struct +{ + vec3_t mins, maxs; + char name[16]; + trivert_t v[MAX_VERTS]; +} frame_t; + +//================================================================ + +frame_t g_frames[MAX_FRAMES]; + +dmdl_t model; + + +float scale_up; // set by $scale +vec3_t adjust; // set by $origin +int g_fixedwidth, g_fixedheight; // set by $skinsize + + +// +// base frame info +// +vec3_t base_xyz[MAX_VERTS]; +dstvert_t base_st[MAX_VERTS]; +dtriangle_t triangles[MAX_TRIANGLES]; + +int triangle_st[MAX_TRIANGLES][3][2]; + +// the command list holds counts, s/t values, and xyz indexes +// that are valid for every frame +int commands[16384]; +int numcommands; +int numglverts; +int used[MAX_TRIANGLES]; + +char g_skins[MAX_MD2SKINS][64]; + +char cdarchive[1024]; +char cdpartial[1024]; +char cddir[1024]; + +char modelname[64]; // empty unless $modelname issued (players) + +#define NUMVERTEXNORMALS 162 + +float avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +FILE *headerouthandle = NULL; + +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +void ClearModel (void) +{ + memset (&model, 0, sizeof(model)); + + modelname[0] = 0; + scale_up = 1.0; + VectorCopy (vec3_origin, adjust); + g_fixedwidth = g_fixedheight = 0; + g_skipmodel = false; +} + + +void H_printf(char *fmt, ...) +{ + va_list argptr; + char name[1024]; + + if (!headerouthandle) + { + sprintf (name, "%s/tris.h", cddir); + headerouthandle = SafeOpenWrite (name); + fprintf(headerouthandle, "// %s\n\n", cddir); + fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n"); + } + + va_start (argptr, fmt); + vfprintf (headerouthandle, fmt, argptr); + va_end (argptr); +} + + +/* +============ +WriteModelFile +============ +*/ +void WriteModelFile (FILE *modelouthandle) +{ + int i; + dmdl_t modeltemp; + int j, k; + frame_t *in; + daliasframe_t *out; + byte buffer[MAX_VERTS*4+128]; + float v; + int c_on, c_off; + + model.ident = IDALIASHEADER; + model.version = ALIAS_VERSION; + model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; + model.num_glcmds = numcommands; + model.ofs_skins = sizeof(dmdl_t); + model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; + model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); + model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); + model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; + model.ofs_end = model.ofs_glcmds + model.num_glcmds*4; + + // + // write out the model header + // + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, model.framesize); + } + + // + // write out glcmds + // + SafeWrite (modelouthandle, commands, numcommands*4); +} + + +/* +=============== +FinishModel +=============== +*/ +void FinishModel (void) +{ + FILE *modelouthandle; + int i; + char name[1024]; + + if (!model.num_frames) + return; + +// +// copy to release directory tree if doing a release build +// + if (g_release) + { + if (modelname[0]) + sprintf (name, "%s", modelname); + else + sprintf (name, "%s/tris.md2", cdpartial); + ReleaseFile (name); + + for (i=0 ; iindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+2)%3]; + st1 = last->index_st[(startv+2)%3]; + m2 = last->index_xyz[(startv+1)%3]; + st2 = last->index_st[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + if (stripcount & 1) + { + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + } + else + { + m1 = check->index_xyz[ (k+2)%3 ]; + st1 = check->index_st[ (k+2)%3 ]; + } + + strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ]; + strip_st[stripcount+2] = check->index_st[ (k+2)%3 ]; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+0)%3]; + st1 = last->index_st[(startv+0)%3]; + m2 = last->index_xyz[(startv+2)%3]; + st2 = last->index_st[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + + strip_xyz[stripcount+2] = m2; + strip_st[stripcount+2] = st2; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; j bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + } + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + swidth = iwidth*2; + model.skinwidth = (swidth + 3) & ~3; + model.skinheight = iheight; +} + + +/* +================= +Cmd_Base +================= +*/ +void Cmd_Base (void) +{ + triangle_t *ptri; + int i, j, k; + int time1; + char file1[1024]; + + GetToken (false); + + if (g_skipmodel || g_release || g_archive) + return; + + printf ("---------------------\n"); + sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext); + printf ("%s\n", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s.%s", cddir, token, trifileext); + + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s doesn't exist", file1); + +// +// load the base triangles +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &model.num_tris); + else + LoadTriangleList (file1, &ptri, &model.num_tris); + +// +// get the ST values +// + BuildST (ptri, model.num_tris); + +// +// run through all the base triangles, storing each unique vertex in the +// base vertex list and setting the indirect triangles to point to the base +// vertices +// + for (i=0 ; i= '0' && *s <= '9') + s--; + + strcpy (suffix, s+1); + strcpy (base, frame); + base[s-frame+1] = 0; + + // check for 'run1.tri' + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, trifileext); + return retname; + } + + // check for 'run.1' + sprintf (file1, "%s/%s.%s",cddir, base, suffix); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s.%s", base, suffix); + return retname; + } + + Error ("frame %s could not be found",frame); + return NULL; +} + +/* +=============== +GrabFrame +=============== +*/ +void GrabFrame (char *frame) +{ + triangle_t *ptri; + int i, j; + trivert_t *ptrivert; + int num_tris; + char file1[1024]; + frame_t *fr; + vertexnormals_t vnorms[MAX_VERTS]; + int index_xyz; + char *framefile; + + // the frame 'run1' will be looked for as either + // run.1 or run1.tri, so the new alias sequence save + // feature an be used + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s\n", file1); + + if (model.num_frames >= MAX_FRAMES) + Error ("model.num_frames >= MAX_FRAMES"); + fr = &g_frames[model.num_frames]; + model.num_frames++; + + strcpy (fr->name, frame); + +// +// load the frame +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &num_tris); + else + LoadTriangleList (file1, &ptri, &num_tris); + + if (num_tris != model.num_tris) + Error ("%s: number of triangles doesn't match base frame\n", file1); + +// +// allocate storage for the frame's vertices +// + ptrivert = fr->v; + + for (i=0 ; imins, fr->maxs); + +// +// store the frame's vertices in the same order as the base. This assumes the +// triangles and vertices in this frame are in exactly the same order as in the +// base +// + for (i=0 ; imins, fr->maxs); + + VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum); + vnorms[index_xyz].numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + free (ptri); +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_Frame (void) +{ + while (TokenAvailable()) + { + GetToken (false); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + model.num_frames = 1; // don't skip the writeout + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames); + + GrabFrame (token); + } +} + + +/* +=============== +Cmd_Skin + +Skins aren't actually stored in the file, only a reference +is saved out to the header file. +=============== +*/ +void Cmd_Skin (void) +{ + byte *palette; + byte *pixels; + int width, height; + byte *cropped; + int y; + char name[1024], savename[1024]; + + GetToken (false); + + if (model.num_skins == MAX_MD2SKINS) + Error ("model.num_skins == MAX_MD2SKINS"); + + if (g_skipmodel) + return; + + sprintf (name, "%s/%s.lbm", cdarchive, token); + strcpy (name, ExpandPathAndArchive( name ) ); +// sprintf (name, "%s/%s.lbm", cddir, token); + + if (TokenAvailable()) + { + GetToken (false); + sprintf (g_skins[model.num_skins], "%s.pcx", token); + sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]); + } + else + { + sprintf (savename, "%s/%s.pcx", cddir, token); + sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token); + } + + model.num_skins++; + + if (g_skipmodel || g_release || g_archive) + return; + + // load the image + printf ("loading %s\n", name); + Load256Image (name, &pixels, &palette, &width, &height); + RemapZero (pixels, palette, width, height); + + // crop it to the proper size + cropped = malloc (model.skinwidth*model.skinheight); + for (y=0 ; y= sizeof(pf->name)) + Error ("Filename too long for pak: %s", filename); + + len = LoadFile (source, (void **)&buf); + + if (g_compress_pak && len < 4096*1024 ) + { + cblock_t in, out; + cblock_t Huffman (cblock_t in); + + in.count = len; + in.data = buf; + + out = Huffman (in); + + if (out.count < in.count) + { + printf (" compressed from %i to %i\n", in.count, out.count); + free (in.data); + buf = out.data; + len = out.count; + } + else + free (out.data); + } + + strcpy (pf->name, filename); + pf->filepos = LittleLong(ftell(pakfile)); + pf->filelen = LittleLong(len); + pf++; + + SafeWrite (pakfile, buf, len); + + free (buf); +} + + +/* +============== +FinishPak +============== +*/ +void FinishPak (void) +{ + int dirlen; + int d; + int i; + + if (!g_pak) + return; + + pakheader.id[0] = 'P'; + pakheader.id[1] = 'A'; + pakheader.id[2] = 'C'; + pakheader.id[3] = 'K'; + dirlen = (byte *)pf - (byte *)pfiles; + pakheader.dirofs = LittleLong(ftell(pakfile)); + pakheader.dirlen = LittleLong(dirlen); + + SafeWrite (pakfile, pfiles, dirlen); + + i = ftell (pakfile); + + fseek (pakfile, 0, SEEK_SET); + SafeWrite (pakfile, &pakheader, sizeof(pakheader)); + fclose (pakfile); + + d = pf - pfiles; + printf ("%i files packed in %i bytes\n",d, i); +} + + +/* +=============== +Cmd_File + +This is only used to cause a file to be copied during a release +build (default.cfg, maps, etc) +=============== +*/ +void Cmd_File (void) +{ + GetToken (false); + ReleaseFile (token); +} + +/* +=============== +PackDirectory_r + +=============== +*/ +#ifdef _WIN32 +#include "io.h" +void PackDirectory_r (char *dir) +{ + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char filename[1024]; + + sprintf (dirstring, "%s%s/*.*", gamedir, dir); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + do + { + sprintf (filename, "%s/%s", dir, fileinfo.name); + if (fileinfo.attrib & _A_SUBDIR) + { // directory + if (fileinfo.name[0] != '.') // don't pak . and .. + PackDirectory_r (filename); + continue; + } + // copy or pack the file + ReleaseFile (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); +} +#else + +#include +#include + +void PackDirectory_r (char *dir) +{ +#ifdef NeXT + struct direct **namelist, *ent; +#else + struct dirent **namelist, *ent; +#endif + int count; + struct stat st; + int i; + int len; + char fullname[1024]; + char dirstring[1024]; + char *name; + + sprintf (dirstring, "%s%s", gamedir, dir); + count = scandir(dirstring, &namelist, NULL, NULL); + + for (i=0 ; id_name; + + if (name[0] == '.') + continue; + + sprintf (fullname, "%s/%s", dir, name); + sprintf (dirstring, "%s%s/%s", gamedir, dir, name); + + if (stat (dirstring, &st) == -1) + Error ("fstating %s", pf->name); + if (st.st_mode & S_IFDIR) + { // directory + PackDirectory_r (fullname); + continue; + } + + // copy or pack the file + ReleaseFile (fullname); + } +} +#endif + + +/* +=============== +Cmd_Dir + +This is only used to cause a directory to be copied during a +release build (sounds, etc) +=============== +*/ +void Cmd_Dir (void) +{ + GetToken (false); + PackDirectory_r (token); +} + +//======================================================================== + +#define MAX_RTEX 16384 +int numrtex; +char rtex[MAX_RTEX][64]; + +void ReleaseTexture (char *name) +{ + int i; + char path[1024]; + + for (i=0 ; i= argc) + Error ("usage: %s [-archive ] [-release ] [-only ] [-3ds] file.qgr", argv[ 0 ] ); + + if (do3ds) + trifileext = ext_3ds; + else + trifileext = ext_tri; + + for ( ; i +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "mathlib.h" +#include "trilib.h" +#include "lbmlib.h" +#include "q2_threads.h" +#include "l3dslib.h" +#include "bspfile.h" + +#ifdef _WIN32 + #ifdef NDEBUG // Don't show in a Release build + #pragma warning(disable : 4305) // truncate from double to float + #pragma warning(disable : 4244) // conversion from double to float + #pragma warning(disable : 4018) // signed/unsigned mismatch + #endif +#endif + +void Cmd_Modelname (void); +void Cmd_Base (void); +void Cmd_Cd (void); +void Cmd_Origin (void); +void Cmd_ScaleUp (void); +void Cmd_Frame (void); +void Cmd_Modelname (void); +void Cmd_Skin (void); +void Cmd_Skinsize (void); +void FinishModel (void); + +void Cmd_Inverse16Table( void ); + +void Cmd_SpriteName (void); +void Cmd_Load (void); +void Cmd_SpriteFrame (void); +void FinishSprite (void); + +void Cmd_Grab (void); +void Cmd_Raw (void); +void Cmd_Mip (void); +void Cmd_Environment (void); +void Cmd_Colormap (void); + +void Cmd_File (void); +void Cmd_Dir (void); +void Cmd_StartWad (void); +void Cmd_EndWad (void); +void Cmd_Mippal (void); +void Cmd_Mipdir (void); +void Cmd_Alphalight (void); + +void Cmd_Video (void); + +void RemapZero (byte *pixels, byte *palette, int width, int height); + +void ReleaseFile (char *filename); + +extern byte *byteimage, *lbmpalette; +extern int byteimagewidth, byteimageheight; + +extern qboolean g_release; // don't grab, copy output data to new tree +extern char g_releasedir[1024]; // c:\quake2\baseq2, etc +extern qboolean g_archive; // don't grab, copy source data to new tree +extern qboolean do3ds; +extern char g_only[256]; // if set, only grab this cd +extern qboolean g_skipmodel; // set true when a cd is not g_only + +extern char *trifileext; diff --git a/tools/quake2/qdata/qdata3.vcproj b/tools/quake2/qdata/qdata3.vcproj new file mode 100644 index 00000000..f3be5b02 --- /dev/null +++ b/tools/quake2/qdata/qdata3.vcproj @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/quake2/qdata/sprites.c b/tools/quake2/qdata/sprites.c new file mode 100644 index 00000000..0f3f2f3e --- /dev/null +++ b/tools/quake2/qdata/sprites.c @@ -0,0 +1,208 @@ + +#include "qdata.h" +#include "inout.h" + +#define MAX_SPRFRAMES MAX_MD2SKINS + +dsprite_t sprite; +dsprframe_t frames[MAX_SPRFRAMES]; + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +char spritename[1024]; + + +void FinishSprite (void); +void Cmd_Spritename (void); + + + +/* +============== +FinishSprite +============== +*/ +void FinishSprite (void) +{ + FILE *spriteouthandle; + int i, curframe; + dsprite_t spritetemp; + char savename[1024]; + + if (sprite.numframes == 0) + return; + + if (!strlen(spritename)) + Error ("Didn't name sprite file"); + + sprintf (savename, "%s%s.sp2", gamedir, spritename); + + if (g_release) + { + char name[1024]; + + sprintf (name, "%s.sp2", spritename); + ReleaseFile (name); + spritename[0] = 0; // clear for a new sprite + sprite.numframes = 0; + return; + } + + + printf ("saving in %s\n", savename); + CreatePath (savename); + spriteouthandle = SafeOpenWrite (savename); + + +// +// write out the sprite header +// + spritetemp.ident = LittleLong (IDSPRITEHEADER); + spritetemp.version = LittleLong (SPRITE_VERSION); + spritetemp.numframes = LittleLong (sprite.numframes); + + SafeWrite (spriteouthandle, &spritetemp, 12); + +// +// write out the frames +// + curframe = 0; + + for (i=0 ; i 256) || (h > 256)) + Error ("Sprite has a dimension longer than 256"); + + xh = xl+w; + yh = yl+h; + + if (sprite.numframes >= MAX_SPRFRAMES) + Error ("Too many frames; increase MAX_SPRFRAMES\n"); + + pframe = &frames[sprite.numframes]; + pframe->width = w; + pframe->height = h; + pframe->origin_x = ox; + pframe->origin_y = oy; + sprintf (pframe->name, "%s_%i.pcx", spritename, sprite.numframes); + sprintf (savename, "%s%s_%i.pcx", gamedir, spritename, sprite.numframes); + sprite.numframes++; + + if (g_release) + { + ReleaseFile (pframe->name); + return; + } + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; y> 5 ) & 63 ) << 2; + b[0] = ( ( color >> 11 ) & 31 ) << 3; + + for ( i = 0; i < 256; i++ ) + { + r[1] = ( d_8to24table[i] >> 0 ) & 0xFF; + g[1] = ( d_8to24table[i] >> 8 ) & 0xFF; + b[1] = ( d_8to24table[i] >> 16 ) & 0xFF; + + d = ( r[1] - r[0] ) * ( r[1] - r[0] ) + + ( g[1] - g[0] ) * ( g[1] - g[0] ) + + ( b[1] - b[0] ) * ( b[1] - b[0] ); + + if ( d < closest_distance_so_far ) + { + closest_distance_so_far = d; + closest_so_far = i; + } + } + + return closest_so_far; +} +*/ + +extern byte BestColor( int, int, int, int, int ); + +void Inverse16_BuildTable( void ) +{ + int i; + + /* + ** create the 16-to-8 table + */ + for ( i = 0; i < 65536; i++ ) + { + int r = i & 31; + int g = ( i >> 5 ) & 63; + int b = ( i >> 11 ) & 31; + + r <<= 3; + g <<= 2; + b <<= 3; + + inverse16to8table[i] = BestColor( r, g, b, 0, 255 ); + } +} + +void Alphalight_Thread (int i) +{ + int j; + float r, g, b; + float mr, mg, mb, ma; + float distortion, bestdistortion; + float v; + + r = (i>>10) * (1.0/16); + g = ((i>>5)&31) * (1.0/16); + b = (i&31) * (1.0/16); + + bestdistortion = 999999; + for (j=0 ; j<16*16*16*16 ; j++) + { + mr = (j>>12) * (1.0/16); + mg = ((j>>8)&15) * (1.0/16); + mb = ((j>>4)&15) * (1.0/16); + ma = (j&15) * (1.0/16); + + v = r * 0.5 - (mr*ma + 0.5*(1.0-ma)); + distortion = v*v; + v = g * 0.5 - (mg*ma + 0.5*(1.0-ma)); + distortion += v*v; + v = b * 0.5 - (mb*ma + 0.5*(1.0-ma)); + distortion += v*v; + + distortion *= 1.0 + ma*4; + + if (distortion < bestdistortion) + { + bestdistortion = distortion; + alphamap[i] = j; + } + } +} + +void Cmd_Alphalight (void) +{ + char savename[1024]; + + GetToken (false); + + if (g_release) + { + ReleaseFile (token); + return; + } + + sprintf (savename, "%s%s", gamedir, token); + printf ("Building alphalight table...\n"); + + RunThreadsOnIndividual (32*32*32, true, Alphalight_Thread); + + SaveFile (savename, (byte *)alphamap, sizeof(alphamap)); +} + + +void Cmd_Inverse16Table( void ) +{ + char savename[1024]; + + if ( g_release ) + { + sprintf (savename, "pics/16to8.dat"); + ReleaseFile( savename ); + return; + } + + sprintf (savename, "%spics/16to8.dat", gamedir); + printf ("Building inverse 16-to-8 table...\n"); + + Inverse16_BuildTable(); + + SaveFile( savename, (byte *) inverse16to8table, sizeof( inverse16to8table ) ); +} diff --git a/tools/quake2/qdata/video.c b/tools/quake2/qdata/video.c new file mode 100644 index 00000000..1ed1b96c --- /dev/null +++ b/tools/quake2/qdata/video.c @@ -0,0 +1,1238 @@ +#include "qdata.h" +#include "inout.h" + +byte *soundtrack; +char base[32]; + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + + +int samplecounts[0x10000]; + +wavinfo_t wavinfo; + +short GetLittleShort(void) +{ + short val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + data_p += 2; + return val; +} + +int GetLittleLong(void) +{ + int val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + val = val + (*(data_p+2)<<16); + val = val + (*(data_p+3)<<24); + data_p += 4; + return val; +} + +void FindNextChunk(char *name) +{ + while (1) + { + data_p=last_chunk; + + if (data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = GetLittleLong(); + if (iff_chunk_len < 0) + { + data_p = NULL; + return; + } +// if (iff_chunk_len > 1024*1024) +// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); + data_p -= 8; + last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); + if (!strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p=iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = GetLittleLong(); + printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } while (data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset (&info, 0, sizeof(info)); + + if (!wav) + return info; + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !strncmp(data_p+8, "WAVE", 4))) + { + printf("Missing RIFF/WAVE chunks\n"); + return info; + } + +// get "fmt " chunk + iff_data = data_p + 12; +// DumpChunks (); + + FindChunk("fmt "); + if (!data_p) + { + printf("Missing fmt chunk\n"); + return info; + } + data_p += 8; + format = GetLittleShort(); + if (format != 1) + { + printf("Microsoft PCM format only\n"); + return info; + } + + info.channels = GetLittleShort(); + info.rate = GetLittleLong(); + data_p += 4+2; + info.width = GetLittleShort() / 8; + +// get cue chunk + FindChunk("cue "); + if (data_p) + { + data_p += 32; + info.loopstart = GetLittleLong(); +// Com_Printf("loopstart=%d\n", sfx->loopstart); + + // if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if (data_p) + { + if (!strncmp (data_p + 28, "mark", 4)) + { // this is not a proper parse, but it works with cooledit... + data_p += 24; + i = GetLittleLong (); // samples in loop + info.samples = info.loopstart + i; + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = GetLittleLong (); + + if (info.samples) + { + if (samples < info.samples) + Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + + return info; +} + +//===================================================================== + +/* +============== +LoadSoundtrack +============== +*/ +void LoadSoundtrack (void) +{ + char name[1024]; + FILE *f; + int len; + int i, val, j; + + soundtrack = NULL; + sprintf (name, "%svideo/%s/%s.wav", gamedir, base, base); + printf ("%s\n", name); + f = fopen (name, "rb"); + if (!f) + { + printf ("no soundtrack for %s\n", base); + return; + } + len = Q_filelength(f); + soundtrack = malloc(len); + fread (soundtrack, 1, len, f); + fclose (f); + + wavinfo = GetWavinfo (name, soundtrack, len); + + // count samples for compression + memset (samplecounts, 0, sizeof(samplecounts)); + + j = wavinfo.samples/2; + for (i=0 ; i wavinfo.samples || !soundtrack) + fwrite (&empty, 1, width, output); + else + fwrite (soundtrack + wavinfo.dataofs + sample*width, 1, width,output); + } +} + +//========================================================================== + +/* +================== +MTF +================== +*/ +cblock_t MTF (cblock_t in) +{ + int i, j, b, code; + byte *out_p; + int index[256]; + cblock_t out; + + out_p = out.data = malloc(in.count + 4); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i<256 ; i++) + index[i] = i; + + for (i=0 ; i b2) + return 1; + if (++i1 == bwt_size) + i1 = 0; + if (++i2 == bwt_size) + i2 = 0; + } + + return 0; +} + +/* +================== +BWT +================== +*/ +cblock_t BWT (cblock_t in) +{ + int *sorted; + int i; + byte *out_p; + cblock_t out; + + bwt_size = in.count; + bwt_data = in.data; + + sorted = malloc(in.count*sizeof(*sorted)); + for (i=0 ; i>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write head index + for (i=0 ; i>8)&255; + *out_p++ = (i>>16)&255; + *out_p++ = (i>>24)&255; + + // write the L column + for (i=0 ; i 32) + Error ("bitcount > 32"); + charbits[nodenum] = bits; + charbitscount[nodenum] = bitcount; + return; + } + + node = &hnodes[nodenum]; + bits <<= 1; + BuildChars (node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars (node->children[1], bits, bitcount+1); +} + + +/* +================== +Huffman +================== +*/ +cblock_t Huffman (cblock_t in) +{ + int i; + hnode_t *node; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int max, maxchar; + + // count + memset (hnodes, 0, sizeof(hnodes)); + for (i=0 ; i max) + { + max = hnodes[i].count; + maxchar = i; + } + } + if (max == 0) + Error ("Huffman: max == 0"); + + for (i=0 ; i<256 ; i++) + { + hnodes[i].count = (hnodes[i].count*255+max-1) / max; + } + + // build the nodes + numhnodes = 256; + while (numhnodes != 511) + { + node = &hnodes[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode (); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode (); + if (node->children[1] == -1) + { + if (node->children[0] != numhnodes-1) + Error ("Bad smallestnode"); + break; + } + node->count = hnodes[node->children[0]].count + + hnodes[node->children[1]].count; + numhnodes++; + } + + BuildChars (numhnodes-1, 0, 0); + + out_p = out.data = malloc(in.count*2 + 1024); + memset (out_p, 0, in.count*2+1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // save out the 256 normalized counts so the tree can be recreated + for (i=0 ; i<256 ; i++) + *out_p++ = hnodes[i].count; + + // write bits + outbits = 0; + for (i=0 ; i>3] |= 1<<(outbits&7); + outbits++; + } + } + + out_p += (outbits+7)>>3; + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + +/* +================== +RLE +================== +*/ +#define RLE_CODE 0xe8 +#define RLE_TRIPPLE 0xe9 + +int rle_counts[256]; +int rle_bytes[256]; + +cblock_t RLE (cblock_t in) +{ + int i; + byte *out_p; + int val; + int repeat; + cblock_t out; + + out_p = out.data = malloc (in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i 3 || val == RLE_CODE) + { + *out_p++ = RLE_CODE; + *out_p++ = val; + *out_p++ = repeat; + } + else + { + while (repeat--) + *out_p++ = val; + } + } + + out.count = out_p - out.data; + return out; +} + +//========================================================================== + +unsigned lzss_head[256]; +unsigned lzss_next[0x20000]; + +/* +================== +LZSS +================== +*/ +#define BACK_WINDOW 0x10000 +#define BACK_BITS 16 +#define FRONT_WINDOW 16 +#define FRONT_BITS 4 +cblock_t LZSS (cblock_t in) +{ + int i; + byte *out_p; + cblock_t out; + int val; + int j, start, max; + int bestlength, beststart; + int outbits; + +if (in.count >= sizeof(lzss_next)/4) +Error ("LZSS: too big"); + + memset (lzss_head, -1, sizeof(lzss_head)); + + out_p = out.data = malloc (in.count*2); + memset (out.data, 0, in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + outbits = 0; + for (i=0 ; i in.count) + max = in.count - i; + + start = lzss_head[val]; + while (start != -1 && start >= i-BACK_WINDOW) + { + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + start = lzss_next[start]; + } + +#else +// slow simple search + // search for a match + max = FRONT_WINDOW; + if (i + max > in.count) + max = in.count - i; + + start = i - BACK_WINDOW; + if (start < 0) + start = 0; + bestlength = 0; + beststart = 0; + for ( ; start < i ; start++) + { + if (in.data[start] != val) + continue; + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + } +#endif + beststart = BACK_WINDOW - (i-beststart); + + if (bestlength < 3) + { // output a single char + bestlength = 1; + + out_p[outbits>>3] |= 1<<(outbits&7); // set bit to mark char + outbits++; + for (j=0 ; j<8 ; j++, outbits++) + if (val & (1<>3] |= 1<<(outbits&7); + } + else + { // output a phrase + outbits++; // leave a 0 bit to mark phrase + for (j=0 ; j>3] |= 1<<(outbits&7); + for (j=0 ; j>3] |= 1<<(outbits&7); + } + + while (bestlength--) + { + val = in.data[i]; + lzss_next[i] = lzss_head[val]; + lzss_head[val] = i; + i++; + } + } + + out_p += (outbits+7)>>3; + out.count = out_p - out.data; + return out; +} + +//========================================================================== + +#define MIN_REPT 15 +#define MAX_REPT 0 +#define HUF_TOKENS (256+MAX_REPT) + +unsigned charbits1[256][HUF_TOKENS]; +int charbitscount1[256][HUF_TOKENS]; + +hnode_t hnodes1[256][HUF_TOKENS*2]; +int numhnodes1[256]; + +int order0counts[256]; + +/* +================== +SmallestNode1 +================== +*/ +int SmallestNode1 (hnode_t *hnodes, int numhnodes) +{ + int i; + int best, bestnode; + + best = 99999999; + bestnode = -1; + for (i=0 ; i 32) + Error ("bitcount > 32"); + charbits1[prev][nodenum] = bits; + charbitscount1[prev][nodenum] = bitcount; + return; + } + + node = &hnodes1[prev][nodenum]; + bits <<= 1; + BuildChars1 (prev, node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars1 (prev, node->children[1], bits, bitcount+1); +} + + +/* +================== +BuildTree1 +================== +*/ +void BuildTree1 (int prev) +{ + hnode_t *node, *nodebase; + int numhnodes; + + // build the nodes + numhnodes = HUF_TOKENS; + nodebase = hnodes1[prev]; + while (1) + { + node = &nodebase[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode1 (nodebase, numhnodes); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode1 (nodebase, numhnodes); + if (node->children[1] == -1) + break; + + node->count = nodebase[node->children[0]].count + + nodebase[node->children[1]].count; + numhnodes++; + } + numhnodes1[prev] = numhnodes-1; + BuildChars1 (prev, numhnodes-1, 0, 0); +} + + +/* +================== +Huffman1_Count +================== +*/ +void Huffman1_Count (cblock_t in) +{ + int i; + int prev; + int v; + int rept; + + prev = 0; + for (i=0 ; i MIN_REPT) + { + hnodes1[prev][255+rept].count++; + i += rept-1; + } +#endif + } +} + + +/* +================== +Huffman1_Build +================== +*/ +byte scaled[256][HUF_TOKENS]; +void Huffman1_Build (FILE *f) +{ + int i, j, v; + int max; + int total; + + for (i=0 ; i<256 ; i++) + { + // normalize and save the counts + max = 0; + for (j=0 ; j max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; + for (j=0 ; j 255) + Error ("v > 255"); + scaled[i][j] = hnodes1[i][j].count = v; + if (v) + total++; + } + if (total == 1) + { // must have two tokens + if (!scaled[i][0]) + scaled[i][0] = hnodes1[i][0].count = 1; + else + scaled[i][1] = hnodes1[i][1].count = 1; + } + + BuildTree1 (i); + } + +#if 0 + // count up the total bits + total = 0; + for (i=0 ; i<256 ; i++) + for (j=0 ; j<256 ; j++) + total += charbitscount1[i][j] * hnodes1[i][j].count; + + total = (total+7)/8; + printf ("%i bytes huffman1 compressed\n", total); +#endif + + fwrite (scaled, 1, sizeof(scaled), f); +} + +/* +================== +Huffman1 + +Order 1 compression with pre-built table +================== +*/ +cblock_t Huffman1 (cblock_t in) +{ + int i; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int prev; + int v; + int rept; + + out_p = out.data = malloc(in.count*2 + 1024); + memset (out_p, 0, in.count*2+1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write bits + outbits = 0; + prev = 0; + for (i=0 ; i>3] |= 1<<(outbits&7); + outbits++; + } + + prev = v; +#if 1 + // check for repeat encodes + for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++) + if (in.data[i+rept] != v) + break; + if (rept > MIN_REPT) + { + c = charbitscount1[prev][255+rept]; + bits = charbits1[prev][255+rept]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if (bits & (1<>3] |= 1<<(outbits&7); + outbits++; + } + i += rept-1; + } +#endif + } + + out_p += (outbits+7)>>3; + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + + +/* +=================== +LoadFrame +=================== +*/ +cblock_t LoadFrame (char *base, int frame, int digits, byte **palette) +{ + int ten3, ten2, ten1, ten0; + cblock_t in; + int width, height; + char name[1024]; + FILE *f; + + in.data = NULL; + in.count = -1; + + ten3 = frame/1000; + ten2 = (frame-ten3*1000)/100; + ten1 = (frame-ten3*1000-ten2*100)/10; + ten0 = frame%10; + + if (digits == 4) + sprintf (name, "%svideo/%s/%s%i%i%i%i.pcx", gamedir, base, base, ten3, ten2, ten1, ten0); + else + sprintf (name, "%svideo/%s/%s%i%i%i.pcx", gamedir, base, base, ten2, ten1, ten0); + + f = fopen(name, "rb"); + if (!f) + { + in.data = NULL; + return in; + } + fclose (f); + + printf ("%s\n", name); + Load256Image (name, &in.data, palette, &width, &height); + in.count = width*height; +// FIXME: map 0 and 255! + +#if 0 + // rle compress + rle = RLE(in); + free (in.data); + + return rle; +#endif + + return in; +} + +/* +=============== +Cmd_Video + +video +=============== +*/ +void Cmd_Video (void) +{ + char savename[1024]; + char name[1024]; + FILE *output; + int startframe, frame; + byte *palette; + int width, height; + byte current_palette[768]; + int command; + int i; + int digits; + cblock_t in, huffman; + int swap; + + + GetToken (false); + strcpy (base, token); + if (g_release) + { +// sprintf (savename, "video/%s.cin", token); +// ReleaseFile (savename); + return; + } + + GetToken (false); + digits = atoi(token); + + // optionally skip frames + if (TokenAvailable ()) + { + GetToken (false); + startframe = atoi(token); + } + else + startframe=0; + + sprintf (savename, "%svideo/%s.cin", gamedir, base); + + + // clear stuff + memset (charbits1, 0, sizeof(charbits1)); + memset (charbitscount1, 0, sizeof(charbitscount1)); + memset (hnodes1, 0, sizeof(hnodes1)); + memset (numhnodes1, 0, sizeof(numhnodes1)); + memset (order0counts, 0, sizeof(order0counts)); + + + // load the entire sound wav file if present + LoadSoundtrack (); + + if (digits == 4) + sprintf (name, "%svideo/%s/%s0000.pcx", gamedir, base, base); + else + sprintf (name, "%svideo/%s/%s000.pcx", gamedir, base, base); + + printf ("%s\n", name); + Load256Image (name, NULL, &palette, &width, &height); + + output = fopen (savename, "wb"); + if (!output) + Error ("Can't open %s", savename); + + // write header info + i = LittleLong (width); + fwrite (&i, 4, 1, output); + i = LittleLong (height); + fwrite (&i, 4, 1, output); + i = LittleLong (wavinfo.rate); + fwrite (&i, 4, 1, output); + i = LittleLong (wavinfo.width); + fwrite (&i, 4, 1, output); + i = LittleLong (wavinfo.channels); + fwrite (&i, 4, 1, output); + + // build the dictionary + for ( frame=startframe ; ; frame++) + { + printf ("counting ", frame); + in = LoadFrame (base, frame, digits, &palette); + if (!in.data) + break; + Huffman1_Count (in); + free (in.data); + } + printf ("\n"); + + // build nodes and write counts + Huffman1_Build (output); + + + memset (current_palette, 0, sizeof(current_palette)); + + // compress it with the dictionary + for (frame=startframe ; ; frame++) + { + printf ("packing ", frame); + in = LoadFrame (base, frame, digits, &palette); + if (!in.data) + break; + + // see if the palette has changed + for (i=0 ; i<768 ; i++) + if (palette[i] != current_palette[i]) + { + // write a palette change + memcpy (current_palette, palette, sizeof(current_palette)); + command = LittleLong(1); + fwrite (&command, 1, 4, output); + fwrite (current_palette, 1, sizeof(current_palette), output); + break; + } + if (i == 768) + { + command = 0; // no palette change + fwrite (&command, 1, 4, output); + } + + // save the image + huffman = Huffman1 (in); + printf ("%5i bytes after huffman1\n", huffman.count); + + swap = LittleLong (huffman.count); + fwrite (&swap, 1, sizeof(swap), output); + + fwrite (huffman.data, 1, huffman.count, output); + + // save some sound samples + WriteSound (output, frame); + + free (palette); + free (in.data); + free (huffman.data); + } + printf ("\n"); + + // write end-of-file command + command = 2; + fwrite (&command, 1, 4, output); + + printf ("Total size: %i\n", ftell (output)); + + fclose (output); + + if (soundtrack) + free (soundtrack); +} diff --git a/tools/quake2/qdata_heretic2/adpcm.h b/tools/quake2/qdata_heretic2/adpcm.h new file mode 100644 index 00000000..e4e8b5dc --- /dev/null +++ b/tools/quake2/qdata_heretic2/adpcm.h @@ -0,0 +1,49 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +** adpcm.h - include file for adpcm coder. +** +** Version 1.0, 7-Jul-92. +** +** Modded 10/3/98 +** John Scott +*/ + +typedef struct adpcm_state_s +{ + short in_valprev; // Previous output value + short in_index; // Index into stepsize table + short out_valprev; // Previous output value + short out_index; // Index into stepsize table + int count; // Number of sample counts +} adpcm_state_t; + +typedef struct adpcm_s +{ + adpcm_state_t state; + char adpcm[0x10000]; +} adpcm_t; + +void adpcm_coder(short [], adpcm_t *); +void adpcm_decoder(adpcm_t *, short []); + +// end diff --git a/tools/quake2/qdata_heretic2/animcomp.c b/tools/quake2/qdata_heretic2/animcomp.c new file mode 100644 index 00000000..7e0c96d1 --- /dev/null +++ b/tools/quake2/qdata_heretic2/animcomp.c @@ -0,0 +1,351 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include +#include +#include +#include +#include "animcomp.h" + + +void *SafeMalloc(size_t n, char *desc); + + + +float *matrix; +float *delta; +float *best; +float *comp; +float *tcomp; +float *bestcomp; +float *frames; +float *base; + +int MatWidth; +int MatHeight; +int CFrameSize; +int nFrames; + + +void AnimCompressInit(int nframes,int nVerts,int CompressedFrameSize) +{ + nFrames=nframes; + MatWidth=nVerts*3; + MatHeight=CompressedFrameSize; + CFrameSize=CompressedFrameSize; + matrix=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit"); + best=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit"); + delta=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit"); + comp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit"); + tcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit"); + bestcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit"); + base=(float *)SafeMalloc(MatWidth*sizeof(float), "AnimCompressInit"); + frames=(float *)SafeMalloc(MatWidth*nFrames*sizeof(float), "AnimCompressInit"); +} + +void AnimSetFrame(int frame,int index,float x,float y,float z) +{ + frames[frame*MatWidth+index*3]=x; + frames[frame*MatWidth+index*3+1]=y; + frames[frame*MatWidth+index*3+2]=z; +} + +typedef struct +{ + int index; + float val; +} SORTP; + + +#define F_RANDOM (((float)rand())/(float)RAND_MAX) + +extern void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize); + +void AnimCompressDoit() +{ + float compression; + float *rescale; + float *ans; + float maxdev; + float avedev; + float tmp; + int j,k,l,numave; + + for (k=0;kmaxdev) + maxdev=tmp; + avedev+=tmp; + numave++; + } + } + avedev/=(float)numave; +printf("%f Max Deviation (inches) %f Ave Dev. (inches)\n",maxdev,avedev); +printf("%d bytes original size\n",MatWidth*nFrames); +printf("%d bytes of overhead\n",MatWidth*MatHeight); +printf("%d bytes/frame * %d frames = %d bytes\n",CFrameSize,nFrames,CFrameSize*nFrames); + compression=(float)(MatWidth*MatHeight+CFrameSize*nFrames+MatWidth); + compression/=(float)(MatWidth*nFrames); +printf("Overall compression = %f %%\n",100.0f-100.0f*compression); + compression=(float)(CFrameSize); + compression/=(float)(MatWidth); +printf("frame size compression = %f %%\n",100.0f-100.0f*compression); + free(rescale); + free(ans); +} + +void AnimCompressToBytes(float *trans,float *scale,char *mat,char *ccomp,unsigned char *cbase,float *cscale,float *coffset,float *bmin,float *bmax) +{ + int k,l,nv,j; + float maxdev; + float avedev; + float tmp; + int numave; + float t,mx; + float *ans; + + + nv=MatWidth/3; + + trans[0]=1E30f; + scale[0]=-1E30f; + trans[1]=1E30f; + scale[1]=-1E30f; + trans[2]=1E30f; + scale[2]=-1E30f; + for (k=0;kscale[0]) + scale[0]=base[k]; + if (base[k]scale[1]) + scale[1]=base[k+1]; + if (base[k+1]scale[2]) + scale[2]=base[k+2]; + if (base[k+2]255.0f) + t=255.0f; + cbase[k]=(unsigned char)t; + + t=(base[k+1]-trans[1])/scale[1]; + if (t<0.0f) + t=0.0f; + if (t>255.0f) + t=255.0f; + cbase[k+1]=(unsigned char)t; + + t=(base[k+2]-trans[2])/scale[2]; + if (t<0.0f) + t=0.0f; + if (t>255.0f) + t=255.0f; + cbase[k+2]=(unsigned char)t; + } + for (l=0;lmx) + mx=(float)fabs(best[l*MatWidth+k]); + } + if (mx>1E-8) + { + mx/=127.0f; + coffset[l]=1E30f; + cscale[l]=-1E30f; + for (j=0;jcscale[l]) + cscale[l]=bestcomp[j*MatHeight+l]; + if (bestcomp[j*MatHeight+l]1E-10) + { + for (j=0;j127.0f) + tmp=127.0f; + if (tmp<-127.0f) + tmp=-127.0f; + ccomp[j*MatHeight+l]=(char)floor(tmp+0.5); + } + coffset[l]+=cscale[l]*127.0f/254.0f; + cscale[l]/=254.0f; + } + else + { + cscale[l]=1.0f; + coffset[l]=0.0f; + for (j=0;j127.0f) + tmp=127.0f; + if (tmp<-127.0f) + tmp=-127.0f; + mat[k*MatHeight+l]=(char)floor(tmp+0.5); + } + } + else + { + cscale[l]=1.0f; + coffset[l]=0.0f; + for (j=0;jmaxdev) + maxdev=tmp; + avedev+=tmp; + numave++; + + if (bmin[k%3]>ans[k]) + bmin[k%3]=ans[k]; + if (bmax[k%3]version = MIP_VERSION; + + for(i=j=0;i<256;i++,j+=3) + { + mp->palette[i].r = palette[j]; + mp->palette[i].g = palette[j+1]; + mp->palette[i].b = palette[j+2]; + } + pos = (byte *)(mp + 1); + + mp->width[0] = w; + mp->height[0] = h; + mp->offsets[0] = sizeof(*mp); + memcpy(pos, buffer, w * h); + + *FinalSize = size; + return(mp); +} + +miptex32_t *CreateBook32(long *buffer, int w, int h, int *FinalSize) +{ + miptex32_t *mp; + byte *pos; + int size; + + size = sizeof(*mp) + (w * h * 4); + mp = (miptex32_t *)SafeMalloc(size, "CreateBook32"); + memset(mp, 0, size); + + mp->version = MIP32_VERSION; + + pos = (byte *)(mp + 1); + + mp->width[0] = w; + mp->height[0] = h; + mp->offsets[0] = sizeof(*mp); + memcpy(pos, buffer, w * h * 4); + + *FinalSize = size; + return(mp); +} + + +// Routines to chop a random sized image into gl texture friendly chunks + +typedef struct rect_s +{ + int x, y; + int w, h; + char name[4]; +} rect_t; + +int GetCoords(int x, int store[MAX_MD2SKINS]) +{ + int index, start, delta; + + index = 0; + start = 0; + delta = 256; + + store[index++] = start; + while(x) + { + if(x >= delta) + { + start += delta; + store[index++] = start; + x -= delta; + } + else + { + delta >>= 1; + } + } + return(index); +} + +int ChopImage(int w, int h, rect_t coords[MAX_MD2SKINS]) +{ + int xs[MAX_MD2SKINS], ys[MAX_MD2SKINS]; + int xcount, ycount, x, y, index; + + index = 0; + xcount = GetCoords(w, xs) - 1; + ycount = GetCoords(h, ys) - 1; + + for(y = 0; y < ycount; y++) + { + for(x = 0; x < xcount; x++, index++) + { + coords[index].x = xs[x]; + coords[index].y = ys[y]; + coords[index].w = xs[x + 1] - xs[x]; + coords[index].h = ys[y + 1] - ys[y]; + coords[index].name[0] = x + '0'; + coords[index].name[1] = y + '0'; + coords[index].name[2] = 0; + } + } + return(index); +} + +/* +=============== +Cmd_Pic +=============== +*/ + +void Cmd_Book() +{ + int xl,yl,xh,yh,w,h; + byte *dest, *source; + int flags, value, contents; + char lumpname[64]; + char filename[1024]; + unsigned long *destl, *sourcel; + int linedelta, x, y; + int size; + miptex_t *qtex; + miptex32_t *qtex32; + float scale_x, scale_y; + int numrects, i; + rect_t coords[MAX_MD2SKINS]; + bookframe_t bframes[MAX_MD2SKINS]; + bookframe_t *bf; + book_t book; + + GetScriptToken (false); + strcpy (lumpname, token); + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + total_x += w; + total_y += h; + total_textures++; + + if ( (w & 7) || (h & 7) ) + Error ("line %i: miptex sizes must be multiples of 8", scriptline); + + flags = 0; + contents = 0; + value = 0; + + scale_x = scale_y = 0.5; + + if (g_release) + return; + + if(TrueColorImage) + { + xh = xl + w; + yh = yl + h; + + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = (unsigned long *) longimage + (yl * longimagewidth) + xl; + destl = (unsigned long *) longimage; + linedelta = (longimagewidth - w); + + for(y = yl; y < yh; y++) + { + for(x = xl; x < xh; x++) + { + *destl++ = *sourcel++; // RGBA + } + sourcel += linedelta; + } + + // Get rectangles to chop into + numrects = ChopImage(w, h, coords); + + bf = bframes; + for(i = 0; i < numrects; i++, bf++) + { + // Copy section of image to buffer + sourcel = (unsigned long *) longimage + (coords[i].y * w) + coords[i].x; + destl = bufferl; + linedelta = w - coords[i].w; + + for(y = 0; y < coords[i].h; y++) + { + for(x = 0; x < coords[i].w; x++) + { + *destl++ = *sourcel++; + } + sourcel += linedelta; + } + + qtex32 = CreateBook32(bufferl, coords[i].w, coords[i].h, &size); + + qtex32->flags = flags; + qtex32->contents = contents; + qtex32->value = value; + qtex32->scale_x = scale_x; + qtex32->scale_y = scale_y; + + sprintf (filename, "%sbook/%s/%s_%s.m32", gamedir, book_prefix, lumpname, coords[i].name); + sprintf (qtex32->name, "%s/%s_%s.m32", book_prefix, lumpname, coords[i].name); + + strcpy(bf->name, qtex32->name); + bf->x = coords[i].x; + bf->y = coords[i].y; + bf->w = coords[i].w; + bf->h = coords[i].h; + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + } + else + { + xh = xl + w; + yh = yl + h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + // Copy image to top left + source = byteimage + yl*byteimagewidth + xl; + dest = byteimage; + linedelta = byteimagewidth - w; + + for(y = yl; y < yh; y++) + { + for(x = xl; x < xh; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + // Get rectangles to chop into + numrects = ChopImage(w, h, coords); + + bf = bframes; + for(i = 0; i < numrects; i++, bf++) + { + // Copy section of image to buffer + source = byteimage + (coords[i].y * w) + coords[i].x; + dest = buffer; + linedelta = w - coords[i].w; + + for(y = 0; y < coords[i].h; y++) + { + for(x = 0; x < coords[i].w; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + qtex = CreateBook8(buffer, coords[i].w, coords[i].h, lbmpalette, &size); + + qtex->flags = flags; + qtex->contents = contents; + qtex->value = value; + + sprintf (filename, "%sbook/%s/%s_%s.m8", gamedir, book_prefix, lumpname, coords[i].name); + sprintf (qtex->name, "%s/%s_%s.m8", book_prefix, lumpname, coords[i].name); + + strcpy(bf->name, qtex->name); + bf->x = coords[i].x; + bf->y = coords[i].y; + bf->w = coords[i].w; + bf->h = coords[i].h; + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } + } + // Set up descriptor + size = sizeof(bookframe_t) * numrects; + + book.bheader.ident = IDBOOKHEADER; + book.bheader.version = BOOK_VERSION; + book.bheader.num_segments = numrects; + book.bheader.total_w = w; + book.bheader.total_h = h; + memcpy(book.bframes, bframes, size); + + // Save out segment descriptor + sprintf (filename, "%sBook/%s/%s.bk", gamedir, book_prefix, lumpname); + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)&book, size + sizeof(bookheader_t)); +} + +/* +=============== +Cmd_picdir +=============== +*/ +void Cmd_Bookdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (book_prefix, token); + // create the directory if needed + sprintf (filename, "%sBook", gamedir); + Q_mkdir (filename); + sprintf (filename, "%sBook/%s", gamedir, book_prefix); + Q_mkdir (filename); +} + +// end diff --git a/tools/quake2/qdata_heretic2/common/bspfile.c b/tools/quake2/qdata_heretic2/common/bspfile.c new file mode 100644 index 00000000..db7c0add --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/bspfile.c @@ -0,0 +1,793 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "bspfile.h" +#include "scriplib.h" + +void GetLeafNums (void); + +//============================================================================= + +int nummodels; +dmodel_t dmodels[MAX_MAP_MODELS]; + +int visdatasize; +byte dvisdata[MAX_MAP_VISIBILITY]; +dvis_t *dvis = (dvis_t *)dvisdata; + +int lightdatasize; +byte dlightdata[MAX_MAP_LIGHTING]; + +int entdatasize; +char dentdata[MAX_MAP_ENTSTRING]; + +int numleafs; +dleaf_t dleafs[MAX_MAP_LEAFS]; + +int numplanes; +dplane_t dplanes[MAX_MAP_PLANES]; + +int numvertexes; +dvertex_t dvertexes[MAX_MAP_VERTS]; + +int numnodes; +dnode_t dnodes[MAX_MAP_NODES]; + +int numtexinfo; +texinfo_t texinfo[MAX_MAP_TEXINFO]; + +int numfaces; +dface_t dfaces[MAX_MAP_FACES]; + +int numedges; +dedge_t dedges[MAX_MAP_EDGES]; + +int numleaffaces; +unsigned short dleaffaces[MAX_MAP_LEAFFACES]; + +int numleafbrushes; +unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +int numsurfedges; +int dsurfedges[MAX_MAP_SURFEDGES]; + +int numbrushes; +dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +int numbrushsides; +dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +int numareas; +darea_t dareas[MAX_MAP_AREAS]; + +int numareaportals; +dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; + +byte dpop[256]; + +/* +=============== +CompressVis + +=============== +*/ +int CompressVis (byte *vis, byte *dest) +{ + int j; + int rep; + int visrow; + byte *dest_p; + + dest_p = dest; +// visrow = (r_numvisleafs + 7)>>3; + visrow = (dvis->numclusters + 7)>>3; + + for (j=0 ; j>3; + row = (dvis->numclusters+7)>>3; + out = decompressed; + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + if (!c) + Error ("DecompressVis: 0 repeat"); + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +} + +//============================================================================= + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile (qboolean todisk) +{ + int i, j; + dmodel_t *d; + + +// models + for (i=0 ; ifirstface = LittleLong (d->firstface); + d->numfaces = LittleLong (d->numfaces); + d->headnode = LittleLong (d->headnode); + + for (j=0 ; j<3 ; j++) + { + d->mins[j] = LittleFloat(d->mins[j]); + d->maxs[j] = LittleFloat(d->maxs[j]); + d->origin[j] = LittleFloat(d->origin[j]); + } + } + +// +// vertexes +// + for (i=0 ; inumclusters; + else + j = LittleLong(dvis->numclusters); + dvis->numclusters = LittleLong (dvis->numclusters); + for (i=0 ; ibitofs[i][0] = LittleLong (dvis->bitofs[i][0]); + dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]); + } +} + + +dheader_t *header; + +int CopyLump (int lump, void *dest, int size) +{ + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if (length % size) + Error ("LoadBSPFile: odd lump size"); + + memcpy (dest, (byte *)header + ofs, length); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +void LoadBSPFile (char *filename) +{ + int i; + +// +// load the file header +// + LoadFile (filename, (void **)&header); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->ident != IDBSPHEADER) + Error ("%s is not a IBSP file", filename); + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, header->version, BSPVERSION); + + nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t)); + numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t)); + numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t)); + numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t)); + numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t)); + numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t)); + numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t)); + numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0])); + numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0])); + numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0])); + numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t)); + numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t)); + numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t)); + numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t)); + numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t)); + + visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1); + lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1); + entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1); + + CopyLump (LUMP_POP, dpop, 1); + + free (header); // everything has been copied out + +// +// swap everything +// + SwapBSPFile (false); +} + + +/* +============= +LoadBSPFileTexinfo + +Only loads the texinfo lump, so qdata can scan for textures +============= +*/ +void LoadBSPFileTexinfo (char *filename) +{ + int i; + FILE *f; + int length, ofs; + + header = malloc(sizeof(dheader_t)); + + f = fopen (filename, "rb"); + fread (header, sizeof(dheader_t), 1, f); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->ident != IDBSPHEADER) + Error ("%s is not a IBSP file", filename); + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, header->version, BSPVERSION); + + + length = header->lumps[LUMP_TEXINFO].filelen; + ofs = header->lumps[LUMP_TEXINFO].fileofs; + + fseek (f, ofs, SEEK_SET); + fread (texinfo, length, 1, f); + fclose (f); + + numtexinfo = length / sizeof(texinfo_t); + + free (header); // everything has been copied out + + SwapBSPFile (false); +} + + +//============================================================================ + +FILE *wadfile; +dheader_t outheader; + +void AddLump (int lumpnum, void *data, int len) +{ + lump_t *lump; + + lump = &header->lumps[lumpnum]; + + lump->fileofs = LittleLong( ftell(wadfile) ); + lump->filelen = LittleLong(len); + SafeWrite (wadfile, data, (len+3)&~3); +} + +/* +============= +WriteBSPFile + +Swaps the bsp file in place, so it should not be referenced again +============= +*/ +void WriteBSPFile (char *filename) +{ + header = &outheader; + memset (header, 0, sizeof(dheader_t)); + + SwapBSPFile (true); + + header->ident = LittleLong (IDBSPHEADER); + header->version = LittleLong (BSPVERSION); + + wadfile = SafeOpenWrite (filename); + SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later + + AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t)); + AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t)); + AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t)); + AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t)); + AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t)); + AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t)); + AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t)); + AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t)); + AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0])); + AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0])); + AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0])); + AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t)); + AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t)); + AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t)); + AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t)); + + AddLump (LUMP_LIGHTING, dlightdata, lightdatasize); + AddLump (LUMP_VISIBILITY, dvisdata, visdatasize); + AddLump (LUMP_ENTITIES, dentdata, entdatasize); + AddLump (LUMP_POP, dpop, sizeof(dpop)); + + fseek (wadfile, 0, SEEK_SET); + SafeWrite (wadfile, header, sizeof(dheader_t)); + fclose (wadfile); +} + +//============================================================================ + +/* +============= +PrintBSPFileSizes + +Dumps info about current file +============= +*/ +void PrintBSPFileSizes (void) +{ + if (!num_entities) + ParseEntities (); + + printf ("%5i models %7i\n" + ,nummodels, (int)(nummodels*sizeof(dmodel_t))); + printf ("%5i brushes %7i\n" + ,numbrushes, (int)(numbrushes*sizeof(dbrush_t))); + printf ("%5i brushsides %7i\n" + ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t))); + printf ("%5i planes %7i\n" + ,numplanes, (int)(numplanes*sizeof(dplane_t))); + printf ("%5i texinfo %7i\n" + ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t))); + printf ("%5i entdata %7i\n", num_entities, entdatasize); + + printf ("\n"); + + printf ("%5i vertexes %7i\n" + ,numvertexes, (int)(numvertexes*sizeof(dvertex_t))); + printf ("%5i nodes %7i\n" + ,numnodes, (int)(numnodes*sizeof(dnode_t))); + printf ("%5i faces %7i\n" + ,numfaces, (int)(numfaces*sizeof(dface_t))); + printf ("%5i leafs %7i\n" + ,numleafs, (int)(numleafs*sizeof(dleaf_t))); + printf ("%5i leaffaces %7i\n" + ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0]))); + printf ("%5i leafbrushes %7i\n" + ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0]))); + printf ("%5i surfedges %7i\n" + ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0]))); + printf ("%5i edges %7i\n" + ,numedges, (int)(numedges*sizeof(dedge_t))); + printf (" lightdata %7i\n", lightdatasize); + printf (" visdata %7i\n", visdatasize); +} + + +//============================================ + +int num_entities; +entity_t entities[MAX_MAP_ENTITIES]; + +void StripTrailing (char *e) +{ + char *s; + + s = e + strlen(e)-1; + while (s >= e && *s <= 32) + { + *s = 0; + s--; + } +} + +/* +================= +ParseEpair +================= +*/ +epair_t *ParseEpair (void) +{ + epair_t *e; + + e = malloc (sizeof(epair_t)); + memset (e, 0, sizeof(epair_t)); + + if (strlen(token) >= MAX_KEY-1) + Error ("ParseEpar: token too long"); + e->key = copystring(token); + GetScriptToken (false); + if (strlen(token) >= MAX_VALUE-1) + Error ("ParseEpar: token too long"); + e->value = copystring(token); + + // strip trailing spaces + StripTrailing (e->key); + StripTrailing (e->value); + + return e; +} + + +/* +================ +ParseEntity +================ +*/ +qboolean ParseEntity (void) +{ + epair_t *e; + entity_t *mapent; + + if (!GetScriptToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + mapent = &entities[num_entities]; + num_entities++; + + do + { + if (!GetScriptToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } while (1); + + return true; +} + +/* +================ +ParseEntities + +Parses the dentdata string into entities +================ +*/ +void ParseEntities (void) +{ + num_entities = 0; + ParseFromMemory (dentdata, entdatasize); + + while (ParseEntity ()) + { + } +} + + +/* +================ +UnparseEntities + +Generates the dentdata string from all the entities +================ +*/ +void UnparseEntities (void) +{ + char *buf, *end; + epair_t *ep; + char line[2048]; + int i; + char key[1024], value[1024]; + + buf = dentdata; + end = buf; + *end = 0; + + for (i=0 ; inext) + { + strcpy (key, ep->key); + StripTrailing (key); + strcpy (value, ep->value); + StripTrailing (value); + + sprintf (line, "\"%s\" \"%s\"\n", key, value); + strcat (end, line); + end += strlen(line); + } + strcat (end,"}\n"); + end += 2; + + if (end > buf + MAX_MAP_ENTSTRING) + Error ("Entity text too long"); + } + entdatasize = end - buf + 1; +} + +void PrintEntity (entity_t *ent) +{ + epair_t *ep; + + printf ("------- entity %p -------\n", ent); + for (ep=ent->epairs ; ep ; ep=ep->next) + { + printf ("%s = %s\n", ep->key, ep->value); + } + +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = copystring(value); + return; + } + ep = malloc (sizeof(*ep)); + if (!ep) + Error("SetKeyValue MALLOC failed! Could not allocate %s bytes.", sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = copystring(key); + ep->value = copystring(value); +} + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +vec_t FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + double v1, v2, v3; + + k = ValueForKey (ent, key); +// scanf into doubles, then assign, so it is vec_t size independent + v1 = v2 = v3 = 0; + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + vec[0] = v1; + vec[1] = v2; + vec[2] = v3; +} + + diff --git a/tools/quake2/qdata_heretic2/common/bspfile.h b/tools/quake2/qdata_heretic2/common/bspfile.h new file mode 100644 index 00000000..c08cf6c9 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/bspfile.h @@ -0,0 +1,133 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _QBSP3_H +#define _QBSP3_H + + +#include "qfiles.h" + + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; +extern dvis_t *dvis; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int numleaffaces; +extern unsigned short dleaffaces[MAX_MAP_LEAFFACES]; + +extern int numleafbrushes; +extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + +extern int numareas; +extern darea_t dareas[MAX_MAP_AREAS]; + +extern int numareaportals; +extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; + +extern int numbrushes; +extern dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +extern int numbrushsides; +extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +extern byte dpop[256]; + +void DecompressVis (byte *in, byte *decompressed); +int CompressVis (byte *vis, byte *dest); + +void LoadBSPFile (char *filename); +void LoadBSPFileTexinfo (char *filename); // just for qdata +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +//=============== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + int firstbrush; + int numbrushes; + epair_t *epairs; + +// only valid for func_areaportals + int areaportalnum; + int portalareas[2]; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities (void); +void UnparseEntities (void); + +void SetKeyValue (entity_t *ent, char *key, char *value); +char *ValueForKey (entity_t *ent, char *key); +// will return "" if not present + +vec_t FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +epair_t *ParseEpair (void); + +void PrintEntity (entity_t *ent); + +#endif //_QBSP3_H diff --git a/tools/quake2/qdata_heretic2/common/cmdlib.c b/tools/quake2/qdata_heretic2/common/cmdlib.c new file mode 100644 index 00000000..1eeb3c49 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/cmdlib.c @@ -0,0 +1,1238 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Nurail: Swiped from quake3/common + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#ifdef NeXT +#include +#endif + +#define BASEDIRNAME "h" +#define PATHSEPERATOR '/' + +extern qboolean verbose; + +qboolean g_dokeypress = false; + +qboolean g_nomkdir = false; + + +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ) +{ + void *p; + + p = malloc(size); + if(!p) + Error ("safe_malloc failed on allocation of %i bytes", size); + + return p; +} + +void *safe_malloc_info( size_t size, char* info ) +{ + void *p; + + p = malloc(size); + if(!p) + Error ("%s: safe_malloc failed on allocation of %i bytes", info, size); + + return p; +} +#endif + +void *SafeMalloc(size_t n, char *desc) +{ + void *p; + + if((p = malloc(n)) == NULL) + { + Error("Failed to allocate %d bytes for '%s'.\n", n, desc); + } + memset(p, 0, n); + return p; +} + +#if defined (__linux__) || defined (__APPLE__) +void strlwr(char *conv_str) +{ + int i; + + for(i=0; i32); + + com_token[len] = 0; + return data; +} + +int Q_strncasecmp (const char *s1, const char *s2, int n) +{ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + } while (c1); + + return 0; // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + +int Q_strcasecmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + +// NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config +// started getting warnings about that function, prolly a duplicate with the runtime function +// maybe we still need to have it in linux builds +/* +char *strupr (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; +} +*/ + +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (const char *check) +{ + int i; + + for (i = 1;i 0) { + nAllocSize += MEM_BLOCKSIZE - nBlock; + } + buffer = safe_malloc (nAllocSize+1); + memset(buffer, 0, nAllocSize+1); + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +TryLoadFile + +Allows failure +============== +*/ +int TryLoadFile (const char *filename, void **bufferptr) +{ + FILE *f; + int length; + void *buffer; + + *bufferptr = NULL; + + f = fopen (filename, "rb"); + if (!f) + return -1; + length = Q_filelength (f); + buffer = safe_malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +SaveFile +============== +*/ +void SaveFile (const char *filename, const void *buffer, int count) +{ + FILE *f; + + f = SafeOpenWrite (filename); + SafeWrite (f, buffer, count); + fclose (f); +} + + + +void DefaultExtension (char *path, const char *extension) +{ + char *src; +// +// if path doesnt have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && *src != '\\' && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + + +void DefaultPath (char *path, const char *basepath) +{ + char temp[128]; + + if( path[ 0 ] == '/' || path[ 0 ] == '\\' ) + return; // absolute path location + strcpy (temp,path); + strcpy (path,basepath); + strcat (path,temp); +} + + +void StripFilename (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '/' && path[ length ] != '\\' ) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/' || path[ length ] == '\\' ) + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '\\' && *(src-1) != '/') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (const char *hex) +{ + const char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (const char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} +/* +// all output ends up through here +void FPrintf (int flag, char *buf) +{ + printf(buf); + +} + +void Sys_FPrintf (int flag, const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + if ((flag == SYS_VRB) && (verbose == false)) + return; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (flag, out_buffer); +} + +void Sys_Printf (const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (SYS_STD, out_buffer); +} + +//================= +//Error +// +//For abnormal program terminations +//================= + +void Error( const char *error, ...) +{ + char out_buffer[4096]; + char tmp[4096]; + va_list argptr; + + va_start (argptr,error); + vsprintf (tmp, error, argptr); + va_end (argptr); + + sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); + + FPrintf( SYS_ERR, out_buffer ); + + exit (1); +} + +*/ + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* +============ +CreatePath +============ +*/ +void CreatePath (const char *path) +{ + const char *ofs; + char c; + char dir[1024]; + +#ifdef _WIN32 + int olddrive = -1; + + if ( path[1] == ':' ) + { + olddrive = _getdrive(); + _chdrive( toupper( path[0] ) - 'A' + 1 ); + } +#endif + + if (path[1] == ':') + path += 2; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + memcpy( dir, path, ofs - path ); + dir[ ofs - path ] = 0; + Q_mkdir( dir ); + } + } + +#ifdef _WIN32 + if ( olddrive != -1 ) + { + _chdrive( olddrive ); + } +#endif +} + + +/* +============ +QCopyFile + + Used to archive source files +============ +*/ +void QCopyFile (const char *from, const char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} + +void Sys_Sleep(int n) +{ +#ifdef _WIN32 + Sleep (n); +#endif +#if defined (__linux__) || defined (__APPLE__) + usleep (n * 1000); +#endif +} diff --git a/tools/quake2/qdata_heretic2/common/cmdlib.h b/tools/quake2/qdata_heretic2/common/cmdlib.h new file mode 100644 index 00000000..ba7bacde --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/cmdlib.h @@ -0,0 +1,177 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#ifdef _WIN32 +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4305) // truncate from double to float + +#pragma check_stack(off) + +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +#pragma intrinsic( memset, memcpy ) + +#endif + +#ifndef __BYTEBOOL__ + #define __BYTEBOOL__ + //typedef enum {false, true} qboolean; + //typedef unsigned char byte; + #include "q_typedef.h" +#endif + +#define MAX_OS_PATH 1024 +#define MEM_BLOCKSIZE 4096 +/* +extern qboolean verbose; +#define SYS_VRB 0 // verbose support (on/off) +#define SYS_STD 1 // standard print level +#define SYS_WRN 2 // warnings +#define SYS_ERR 3 // error +*/ +// the dec offsetof macro doesnt work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + +#define SAFE_MALLOC +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ); +void *safe_malloc_info( size_t size, char* info ); +#else +#define safe_malloc(a) malloc(a) +#endif /* SAFE_MALLOC */ + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +char *strlower (char *in); +int Q_strncasecmp( const char *s1, const char *s2, int n ); +int Q_stricmp( const char *s1, const char *s2 ); +int Q_strcasecmp( const char *s1, const char *s2 ); +void Q_getwd( char *out ); + +int Q_filelength (FILE *f); +int FileTime( const char *path ); + +void Q_mkdir( const char *path ); + +extern char qdir[1024]; +extern char gamedir[1024]; +extern char writedir[1024]; +extern char *moddirparam; +void SetQdirFromPath( const char *path); +char *ExpandArg( const char *path ); // from cmd line +char *ExpandPath( const char *path ); // from scripts +char *ExpandGamePath (const char *path); +char *ExpandPathAndArchive( const char *path ); +void ExpandWildcards( int *argc, char ***argv ); + + +double I_FloatTime( void ); + +int CheckParm( const char *check ); + +void *SafeMalloc(size_t n, char *desc); +FILE *SafeOpenWrite( const char *filename ); +FILE *SafeOpenRead( const char *filename ); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, const void *buffer, int count); + +int LoadFile( const char *filename, void **bufferptr ); +int LoadFileBlock( const char *filename, void **bufferptr ); +int TryLoadFile( const char *filename, void **bufferptr ); +void SaveFile( const char *filename, const void *buffer, int count ); +qboolean FileExists( const char *filename ); + +void DefaultExtension( char *path, const char *extension ); +void DefaultPath( char *path, const char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); + +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); + +int ParseNum (const char *str); +/* +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); +void Error( const char *error, ... ); +*/ +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +char *copystring(const char *s); + + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); + +void CreatePath( const char *path ); +void QCopyFile( const char *from, const char *to ); + +extern qboolean archive; +extern char archivedir[1024]; + +extern qboolean g_dokeypress; + +// sleep for the given amount of milliseconds +void Sys_Sleep(int n); + +// for compression routines +typedef struct +{ + byte *data; + int count; +} cblock_t; + + +#endif diff --git a/tools/quake2/qdata_heretic2/common/her2_threads.h b/tools/quake2/qdata_heretic2/common/her2_threads.h new file mode 100644 index 00000000..1ef28c0f --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/her2_threads.h @@ -0,0 +1,35 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _THREADS_H + +#define _THREADS_H + + +extern int numthreads; + +void ThreadSetDefault (void); +int GetThreadWork (void); +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)); +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)); +void ThreadLock (void); +void ThreadUnlock (void); + +#endif //_THREADS_H diff --git a/tools/quake2/qdata_heretic2/common/inout.c b/tools/quake2/qdata_heretic2/common/inout.c new file mode 100644 index 00000000..ef21edea --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/inout.c @@ -0,0 +1,367 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// deal with in/out tasks, for either stdin/stdout or network/XML stream +// + +#include "cmdlib.h" +#include "mathlib.h" +#include "polylib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +// network broadcasting +#include "l_net/l_net.h" +#include "libxml/tree.h" + +#ifdef _WIN32 +HWND hwndOut = NULL; +qboolean lookedForServer = false; +UINT wm_BroadcastCommand = -1; +#endif + +socket_t *brdcst_socket; +netmessage_t msg; + +qboolean verbose = false; + +// our main document +// is streamed through the network to Radiant +// possibly written to disk at the end of the run +//++timo FIXME: need to be global, required when creating nodes? +xmlDocPtr doc; +xmlNodePtr tree; + +// some useful stuff +xmlNodePtr xml_NodeForVec( vec3_t v ) +{ + xmlNodePtr ret; + char buf[1024]; + + sprintf (buf, "%f %f %f", v[0], v[1], v[2]); + ret = xmlNewNode (NULL, "point"); + xmlNodeSetContent (ret, buf); + return ret; +} + +// send a node down the stream, add it to the document +void xml_SendNode (xmlNodePtr node) +{ + xmlBufferPtr xml_buf; + char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks .. + // this index loops through the node buffer + int pos = 0; + int size; + + xmlAddChild( doc->children, node ); + + if (brdcst_socket) + { + xml_buf = xmlBufferCreate(); + xmlNodeDump( xml_buf, doc, node, 0, 0 ); + + // the XML node might be too big to fit in a single network message + // l_net library defines an upper limit of MAX_NETMESSAGE + // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe + // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages + while (pos < xml_buf->use) + { + // what size are we gonna send now? + (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10); + //++timo just a debug thing + if (size == MAX_NETMESSAGE - 10) + Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n"); + memcpy( xmlbuf, xml_buf->content+pos, size); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); + // now that the thing is sent prepare to loop again + pos += size; + } + +#if 0 + // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE + // we will need to split into chunks + // (we could also go lower level, in the end it's using send and receiv which are not size limited) + //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message + // there's some tweaking to do in l_net for that .. so let's give us a margin for now + + //++timo we need to handle the case of a buffer too big to fit in a single message + // try without checks for now + if (xml_buf->use > MAX_NETMESSAGE-10 ) + { + // if we send that we are probably gonna break the stream at the other end.. + // and Error will call right there + //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing + Sys_FPrintf (SYS_NOXML, xml_buf->content); + + } + + size = xml_buf->use; + memcpy( xmlbuf, xml_buf->content, size ); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); +#endif + + xmlBufferFree( xml_buf ); + } +} + +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError) +{ + xmlNodePtr node, select; + char buf[1024]; + char level[2]; + + // now build a proper "select" XML node + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + node = xmlNewNode (NULL, "select"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'select' information + sprintf (buf, "%i %i", entitynum, brushnum); + select = xmlNewNode (NULL, "brush"); + xmlNodeSetContent (select, buf); + xmlAddChild (node, select); + xml_SendNode (node); + + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + if (bError) + Error(buf); + else + Sys_FPrintf (SYS_NOXML, "%s\n", buf); + +} + +void xml_Point (char *msg, vec3_t pt) +{ + xmlNodePtr node, point; + char buf[1024]; + char level[2]; + + node = xmlNewNode (NULL, "pointmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'point' node + sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]); + point = xmlNewNode (NULL, "point"); + xmlNodeSetContent (point, buf); + xmlAddChild (node, point); + xml_SendNode (node); + + sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]); + Error (buf); +} + +#define WINDING_BUFSIZE 2048 +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die) +{ + xmlNodePtr node, winding; + char buf[WINDING_BUFSIZE]; + char smlbuf[128]; + char level[2]; + int i; + + node = xmlNewNode (NULL, "windingmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'winding' node + sprintf( buf, "%i ", numpoints); + for(i = 0; i < numpoints; i++) + { + sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]); + // don't overflow + if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE) + break; + strcat( buf, smlbuf); + } + + winding = xmlNewNode (NULL, "winding"); + xmlNodeSetContent (winding, buf); + xmlAddChild (node, winding); + xml_SendNode (node); + + if(die) + Error (msg); + else + { + Sys_Printf(msg); + Sys_Printf("\n"); + } +} + +// in include +#include "stream_version.h" + +void Broadcast_Setup( const char *dest ) +{ + address_t address; + char sMsg[1024]; + + Net_Setup(); + Net_StringToAddress((char *)dest, &address); + brdcst_socket = Net_Connect(&address, 0); + if (brdcst_socket) + { + // send in a header + sprintf (sMsg, ""); + NMSG_Clear( &msg ); + NMSG_WriteString(&msg, sMsg ); + Net_Send(brdcst_socket, &msg ); + } +} + +void Broadcast_Shutdown() +{ + if (brdcst_socket) + { + Sys_Printf("Disconnecting\n"); + Net_Disconnect(brdcst_socket); + brdcst_socket = NULL; + } +} + +// all output ends up through here +void FPrintf (int flag, char *buf) +{ + xmlNodePtr node; + static qboolean bGotXML = false; + char level[2]; + + printf(buf); + + // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe? + if (flag == SYS_NOXML) + return; + + // ouput an XML file of the run + // use the DOM interface to build a tree + /* + + message string + .. various nodes to describe corresponding geometry .. + + */ + if (!bGotXML) + { + // initialize + doc = xmlNewDoc("1.0"); + doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL); + bGotXML = true; + } + node = xmlNewNode (NULL, "message"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + flag; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level ); + + xml_SendNode (node); +} + +#ifdef DBG_XML +void DumpXML() +{ + xmlSaveFile( "XMLDump.xml", doc ); +} +#endif + +void Sys_FPrintf (int flag, const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + if ((flag == SYS_VRB) && (verbose == false)) + return; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (flag, out_buffer); +} + +void Sys_Printf (const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (SYS_STD, out_buffer); +} + +/* +================= +Error + +For abnormal program terminations +================= +*/ +void Error( const char *error, ...) +{ + char out_buffer[4096]; + char tmp[4096]; + va_list argptr; + + va_start (argptr,error); + vsprintf (tmp, error, argptr); + va_end (argptr); + + sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); + + FPrintf( SYS_ERR, out_buffer ); + +#ifdef DBG_XML + DumpXML(); +#endif + + //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener. + // a clean solution is to send a sync request node in the stream and wait for an answer before exiting + Sys_Sleep( 1000 ); + + Broadcast_Shutdown(); + + exit (1); +} + diff --git a/tools/quake2/qdata_heretic2/common/inout.h b/tools/quake2/qdata_heretic2/common/inout.h new file mode 100644 index 00000000..4843a7b6 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/inout.h @@ -0,0 +1,63 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __INOUT__ +#define __INOUT__ + +// inout is the only stuff relying on xml, include the headers there +#include "libxml/tree.h" +#include "mathlib.h" + +// some useful xml routines +xmlNodePtr xml_NodeForVec( vec3_t v ); +void xml_SendNode (xmlNodePtr node); +// print a message in q3map output and send the corresponding select information down the xml stream +// bError: do we end with an error on this one or do we go ahead? +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError); +// end q3map with an error message and send a point information in the xml stream +// note: we might want to add a boolean to use this as a warning or an error thing.. +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die); +void xml_Point (char *msg, vec3_t pt); + +extern qboolean bNetworkBroadcast; +void Broadcast_Setup( const char *dest ); +void Broadcast_Shutdown(); + +#define SYS_VRB 0 // verbose support (on/off) +#define SYS_STD 1 // standard print level +#define SYS_WRN 2 // warnings +#define SYS_ERR 3 // error +#define SYS_NOXML 4 // don't send that down the XML stream + +extern qboolean verbose; +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); +void Error( const char *error, ...); + +#ifdef _DEBUG +#define DBG_XML 1 +#endif + +#ifdef DBG_XML +void DumpXML(); +#endif + +#endif diff --git a/tools/quake2/qdata_heretic2/common/l3dslib.c b/tools/quake2/qdata_heretic2/common/l3dslib.c new file mode 100644 index 00000000..686c0191 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/l3dslib.c @@ -0,0 +1,476 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// l3dslib.c: library for loading triangles from an Alias triangle file +// + +#include +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "trilib.h" +#include "l3dslib.h" +#include "token.h" +#include "fmodel.h" +#include "bspfile.h" + +#define MAIN3DS 0x4D4D +#define EDIT3DS 0x3D3D // this is the start of the editor config +#define EDIT_OBJECT 0x4000 +#define OBJ_TRIMESH 0x4100 +#define TRI_VERTEXL 0x4110 +#define TRI_FACEL1 0x4120 + +#define MAXVERTS 2000 + +typedef struct { + int v[4]; +} tri; + +float fverts[MAXVERTS][3]; +tri tris[MAXTRIANGLES]; + +int bytesread, level, numtris, totaltris; +int vertsfound, trisfound; + +triangle_t *ptri; + + + +void DefaultNodesList(mesh_node_t **nodesList, int *num_mesh_nodes, int *numtriangles) +{ + int pos, bit, i; + + if (nodesList) + { + *num_mesh_nodes = 1; + memset(&(*nodesList)[0], 0, sizeof(mesh_node_t)); + strcpy((*nodesList)[0].name, "default"); + + // set all of the tris to be used for the top node + for(i = 0; i < (*numtriangles); i++) + { + pos = (i) >> 3; + bit = 1 << ((i) & 7 ); + + (*nodesList)[0].tris[pos] |= bit; + } + } +} + + +// Alias stores triangles as 3 explicit vertices in .tri files, so even though we +// start out with a vertex pool and vertex indices for triangles, we have to convert +// to raw, explicit triangles +void StoreAliasTriangles (void) +{ + int i, j, k; + + if ((totaltris + numtris) > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0; i MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i 0) + { + w -= ParseChunk (input); + } + + retval = length; + goto Done; + + default: + // skip other chunks + while (w > 0) + { + t = w; + + if (t > BLOCK_SIZE) + t = BLOCK_SIZE; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp, t, 1, input); + bytesread += t; + + w -= t; + } + + retval = length; + goto Done; + } + +Done: + level--; + return retval; +} + + +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **nodesList, int *num_mesh_nodes) +{ + FILE *input; + short int tshort; + + if (nodesList) + { + *num_mesh_nodes = 0; + *nodesList = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + } + + bytesread = 0; + level = 0; + numtris = 0; + totaltris = 0; + vertsfound = 0; + trisfound = 0; + + if ((input = fopen(filename, "rb")) == 0) { + fprintf(stderr,"reader: could not open file '%s'\n", filename); + exit(0); + } + + fread(&tshort, sizeof(tshort), 1, input); + +// should only be MAIN3DS, but some files seem to start with EDIT3DS, with +// no MAIN3DS + if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) { + fprintf(stderr,"File is not a 3DS file.\n"); + exit(0); + } + +// back to top of file so we can parse the first chunk descriptor + fseek(input, 0, SEEK_SET); + + ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); + + *pptri = ptri; + +// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT | +// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks + ParseChunk (input); + + if (vertsfound || trisfound) + Error ("Incomplete triangle set"); + + *numtriangles = totaltris; + + fclose (input); + + DefaultNodesList(nodesList,num_mesh_nodes,numtriangles); +} + +//========================================================================== +// +// LoadASC +// +//========================================================================== + +void LoadASC(char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes) +{ + int i, j; + int vertexCount; + struct + { + float v[3]; + } *vList; + int triCount; + triangle_t *tList; + float x, y, z; +// float x2, y2, z2; +// float rx, ry, rz; + qboolean goodObject; + + if (nodesList) + { + *num_mesh_nodes = 0; + *nodesList = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + } + + TK_OpenSource(fileName); + + goodObject = false; + while(goodObject == false) + { + TK_Beyond(TK_C_NAMED); + TK_Beyond(TK_OBJECT); + TK_Beyond(TK_C_TRI); + TK_Beyond(TK_MESH); + TK_BeyondRequire(TK_C_VERTICES, TK_COLON); + TK_FetchRequire(TK_INTNUMBER); + vertexCount = tk_IntNumber; + if(vertexCount > 0) + { + goodObject = true; + } + } + TK_BeyondRequire(TK_C_FACES, TK_COLON); + TK_FetchRequire(TK_INTNUMBER); + triCount = tk_IntNumber; + if(triCount >= MAXTRIANGLES) + { + Error("Too many triangles in file %s\n", fileName); + } + *triangleCount = triCount; + tList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list"); + *triList = tList; + + memset(*triList,0,MAXTRIANGLES*sizeof(triangle_t)); + TK_BeyondRequire(TK_C_VERTEX, TK_LIST); + +/* rx = ((rotation[0]+90.0)/360.0)*2.0*M_PI; + //rx = (rotation[0]/360.0)*2.0*M_PI; + ry = (rotation[1]/360.0)*2.0*M_PI; + rz = (rotation[2]/360.0)*2.0*M_PI; +*/ + vList = (void *) SafeMalloc(vertexCount*sizeof vList[0], "Vertex list"); + for(i = 0; i < vertexCount; i++) + { + TK_BeyondRequire(TK_C_VERTEX, TK_INTNUMBER); + if(tk_IntNumber != i) + { + Error("File '%s', line %d:\nVertex index mismatch.\n", + tk_SourceName, tk_Line); + } + TK_FetchRequireFetch(TK_COLON); + + TK_BeyondRequire(TK_COLON, TK_FLOATNUMBER); + x = tk_FloatNumber; + TK_BeyondRequire(TK_COLON, TK_FLOATNUMBER); + y = tk_FloatNumber; + TK_BeyondRequire(TK_COLON, TK_FLOATNUMBER); + z = tk_FloatNumber; + +/* x2 = x*cos(rz)+y*sin(rz); + y2 = -x*sin(rz)+y*cos(rz); + x = x2; + y = y2; + y2 = y*cos(rx)+z*sin(rx); + z2 = -y*sin(rx)+z*cos(rx); + y = y2; + z = z2; + x2 = x*cos(ry)-z*sin(ry); + z2 = x*sin(ry)+z*cos(ry); + x = x2; + z = z2; +*/ + vList[i].v[0] = x; + vList[i].v[1] = y; + vList[i].v[2] = z; + } + TK_BeyondRequire(TK_C_FACE, TK_LIST); + for(i = 0; i < triCount; i++) + { + TK_BeyondRequire(TK_C_FACE, TK_INTNUMBER); + if(tk_IntNumber != i) + { + Error("File '%s', line %d:\nTriangle index mismatch.\n", + tk_SourceName, tk_Line); + } + for(j = 0; j < 3; j++) + { + TK_BeyondRequire(TK_IDENTIFIER, TK_COLON); + TK_FetchRequire(TK_INTNUMBER); + if(tk_IntNumber >= vertexCount) + { + Error("File '%s', line %d:\nVertex number" + " > vertexCount: %d\n", tk_SourceName, tk_Line, + tk_IntNumber); + } + tList[i].verts[2-j][0] = vList[tk_IntNumber].v[0]; + tList[i].verts[2-j][1] = vList[tk_IntNumber].v[1]; + tList[i].verts[2-j][2] = vList[tk_IntNumber].v[2]; +#ifdef _QDATA + tList[i].indicies[2-j] = tk_IntNumber; +#endif + } + +/* printf("Face %i:\n v0: %f, %f, %f\n v1: %f, %f, %f\n" + " v2: %f, %f, %f\n", i, + tList[i].verts[0][0], + tList[i].verts[0][1], + tList[i].verts[0][2], + tList[i].verts[1][0], + tList[i].verts[1][1], + tList[i].verts[1][2], + tList[i].verts[2][0], + tList[i].verts[2][1], + tList[i].verts[2][2]); +*/ + } + + DefaultNodesList(nodesList,num_mesh_nodes,triangleCount); +} diff --git a/tools/quake2/qdata_heretic2/common/l3dslib.h b/tools/quake2/qdata_heretic2/common/l3dslib.h new file mode 100644 index 00000000..899b9fe6 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/l3dslib.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// l3dslib.h: header file for loading triangles from a 3DS triangle file +// +void DefaultNodesList(mesh_node_t **nodesList, int *num_mesh_nodes, int *numtriangles); + +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **ppmnodes, int *num_mesh_nodes); +void LoadASC(char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **ppmnodes, int *num_mesh_nodes); diff --git a/tools/quake2/qdata_heretic2/common/lbmlib.c b/tools/quake2/qdata_heretic2/common/lbmlib.c new file mode 100644 index 00000000..7e3611ac --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/lbmlib.c @@ -0,0 +1,1052 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// lbmlib.c + +#include "cmdlib.h" +#include "inout.h" +#include "lbmlib.h" + +// Ups the palette values so no pixels except 0 appear transparent +// Need a value of 8 to cater for 16bit renderers + +typedef struct +{ + byte r; + byte g; + byte b; +} paletteRGB_t; + + +void CorrectPalette(byte *pal) +{ + paletteRGB_t *p; + + p = (paletteRGB_t *)pal; + // Color 0 always transparent + p->r = 0; + p->g = 0; + p->b = 0; +} + +/* +============================================================================ + + LBM STUFF + +============================================================================ +*/ + + +typedef unsigned char UBYTE; +//conflicts with windows typedef short WORD; +typedef unsigned short UWORD; +typedef long LONG; + +typedef enum +{ + ms_none, + ms_mask, + ms_transcolor, + ms_lasso +} mask_t; + +typedef enum +{ + cm_none, + cm_rle1 +} compress_t; + +typedef struct +{ + UWORD w,h; + short x,y; + UBYTE nPlanes; + UBYTE masking; + UBYTE compression; + UBYTE pad1; + UWORD transparentColor; + UBYTE xAspect,yAspect; + short pageWidth,pageHeight; +} bmhd_t; + +extern bmhd_t bmhd; // will be in native byte order + + + +#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) +#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) +#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) +#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) +#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) +#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) + + +bmhd_t bmhd; + +int Align (int l) +{ + if (l&1) + return l+1; + return l; +} + + + +/* +================ +LBMRLEdecompress + +Source must be evenly aligned! +================ +*/ +byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) +{ + int count; + byte b,rept; + + count = 0; + + do + { + rept = *source++; + + if (rept > 0x80) + { + rept = (rept^0xff)+2; + b = *source++; + memset(unpacked,b,rept); + unpacked += rept; + } + else if (rept < 0x80) + { + rept++; + memcpy(unpacked,source,rept); + unpacked += rept; + source += rept; + } + else + rept = 0; // rept of 0x80 is NOP + + count += rept; + + } while (countbpwidth) + Error ("Decompression exceeded width!\n"); + + + return source; +} + + +/* +================= +LoadLBM +================= +*/ +void LoadLBM (char *filename, byte **picture, byte **palette) +{ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + + int formtype,formlength; + int chunktype,chunklength; + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + +// +// load the LBM +// + LoadFile (filename, (void **)&LBMbuffer); + +// +// parse the LBM header +// + LBM_P = LBMbuffer; + if ( *(int *)LBMbuffer != LittleLong(FORMID) ) + Error ("No FORM ID at start of file!\n"); + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align(formlength); + + formtype = LittleLong(*(int *)LBM_P); + + if (formtype != ILBMID && formtype != PBMID) + Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff + ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + + LBM_P += 4; + +// +// parse chunks +// + + while (LBM_P < LBMEND_P) + { + chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + LBM_P += 4; + chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + LBM_P += 4; + + switch ( chunktype ) + { + case BMHDID: + memcpy (&bmhd,LBM_P,sizeof(bmhd)); + bmhd.w = BigShort(bmhd.w); + bmhd.h = BigShort(bmhd.h); + bmhd.x = BigShort(bmhd.x); + bmhd.y = BigShort(bmhd.y); + bmhd.pageWidth = BigShort(bmhd.pageWidth); + bmhd.pageHeight = BigShort(bmhd.pageHeight); + break; + + case CMAPID: + cmapbuffer = malloc (768); + memset (cmapbuffer, 0, 768); + memcpy (cmapbuffer, LBM_P, chunklength); + CorrectPalette(cmapbuffer); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = malloc (bmhd.w*bmhd.h); + if (formtype == PBMID) + { + // + // unpack PBM + // + for (y=0 ; ydata; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + Error ("Bad pcx file %s", filename); + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + CorrectPalette(*palette); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + if (!out) + Error ("Skin_Cache: couldn't allocate"); + + *pic = out; + + pix = out; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + Error ("PCX file %s was malformed", filename); + + free (pcx); +} + +/* +============== +WritePCXfile +============== +*/ + +void StuffPackedByte(int curRepCount, byte curByte, byte** packPtr) +{ + byte* pack; + + pack = *packPtr; + + while(curRepCount > 0) + { + if (curRepCount == 1) + { + if ((curByte & 0xc0) != 0xc0) + { + *pack++ = curByte; + } + else + { + *pack++ = 0xc1; + *pack++ = curByte; + } + break; + } + if (curRepCount < 0x0040) + { + *pack++ = (0x00c0 | curRepCount); + curRepCount = 0; + } + else + { + *pack++ = 0xff; + curRepCount -= 0x003f; + } + *pack++ = curByte; + } + *packPtr = pack; +} + +void WritePCXfile (char *filename, byte *data, + int width, int height, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + byte curByte; + int curRepCount; + + pcx = malloc (width*height*2+1000); + memset (pcx, 0, sizeof(*pcx)); + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // RLE + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(1); // not a grey scale + + // pack the image + pack = &pcx->data; + +/* for (i=0 ; i= rows) + goto breakOut; + pixbuf += rowOffset; + rowBuf = pixbuf; + } + } + } + else + { // non run-length packet + for(j = 0; j < packetSize; j++) + { + switch (targa_header.pixel_size) + { + case 24: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + rowBuf[0] = red; + rowBuf[1] = green; + rowBuf[2] = blue; + rowBuf[3] = 255; + rowBuf += pixDirection; + break; + case 32: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = getc(fin); + rowBuf[0] = red; + rowBuf[1] = green; + rowBuf[2] = blue; + rowBuf[3] = alphabyte; + rowBuf += pixDirection; + break; + } + column++; + if (column == columns) + { // pixel packet run spans across rows + column = 0; + row++; + if (row >= rows) + goto breakOut; + pixbuf += rowOffset; + rowBuf = pixbuf; + } + } + } + } + breakOut:; + pixbuf += rowOffset; + } + } + fclose(fin); +} + +void MergeAlpha(byte *pix, byte *alpha, byte *pal, byte **out, int width, int height) +{ + int size, i; + byte *data, *src, *srca; + + size = width * height; + data = malloc(size * 4); + if(!data) + Error("Could not allocate memory for true color image"); + + *out = data; + src = pix; + srca = alpha; + + for(i = 0; i < size; i++, src++, srca++) + { + *data++ = pal[*src * 3 + 0]; // r + *data++ = pal[*src * 3 + 1]; // g + *data++ = pal[*src * 3 + 2]; // b + *data++ = *srca; // a + } + free(pix); + free(alpha); + free(pal); +} + +/* +============== +LoadAnyImage + +Return Value: + false: paletted texture + true: true color RGBA image (no palette) +============== +*/ +qboolean LoadAnyImage (char *name, byte **pixels, byte **palette, int *width, int *height) +{ + char ext[128]; + int len; + int alpha_width, alpha_height; + char alpha_name[128]; + byte *alpha_pixels; + + ExtractFileExtension (name, ext); + + if(palette) + { + *palette = NULL; + } + + if (!Q_strcasecmp (ext, "lbm")) + { + LoadLBM (name, pixels, palette); + if (width) + *width = bmhd.w; + if (height) + *height = bmhd.h; + return false; + } + else if (!Q_strcasecmp (ext, "pcx")) + { + len = strlen(name); + strcpy(alpha_name, name); + strcpy(&alpha_name[len - 4], "_a.pcx"); // Alpha map name (may not exist) + + if(FileExists(alpha_name)) + { + LoadPCX (name, pixels, palette, width, height); // Load in image + LoadPCX (alpha_name, &alpha_pixels, NULL, &alpha_width, &alpha_height); // Load in alpha map + if((*width != alpha_width) || (*height != alpha_height)) + { + Error("Alpha image dimensions not equal to graphic image dimensions"); + } + MergeAlpha(*pixels, alpha_pixels, *palette, pixels, *width, *height); + *palette = NULL;//Merge Frees pal + return true; + } + else + { + LoadPCX (name, pixels, palette, width, height); // Load in image + return false; + } + } + else if (!Q_strcasecmp (ext, "tga")) + { + LoadTGA(name, pixels, width, height); + if (palette) + { + *palette = NULL; + } + + return true; + } + else + Error ("%s doesn't have a known image extension", name); + + return false; +} + diff --git a/tools/quake2/qdata_heretic2/common/lbmlib.h b/tools/quake2/qdata_heretic2/common/lbmlib.h new file mode 100644 index 00000000..ec0e8e2a --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/lbmlib.h @@ -0,0 +1,41 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// piclib.h + + +void LoadLBM (char *filename, byte **picture, byte **palette); +void WriteLBMfile (char *filename, byte *data, int width, int height + , byte *palette); +void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height); +void WritePCXfile (char *filename, byte *data, int width, int height + , byte *palette); + +// loads / saves either lbm or pcx, depending on extension +void Load256Image (char *name, byte **pixels, byte **palette, + int *width, int *height); +void Save256Image (char *name, byte *pixels, byte *palette, + int width, int height); + + +void LoadTGA (char *filename, byte **pixels, int *width, int *height); + +qboolean LoadAnyImage (char *name, byte **pixels, byte **palette, int *width, int *height); diff --git a/tools/quake2/qdata_heretic2/common/mathlib.c b/tools/quake2/qdata_heretic2/common/mathlib.c new file mode 100644 index 00000000..0fd9ac23 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/mathlib.c @@ -0,0 +1,176 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// mathlib.c -- math primitives + +#include "cmdlib.h" +#include "mathlib.h" + +vec3_t vec3_origin = {0,0,0}; + + +double VectorLength(vec3_t v) +{ + int i; + double length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return false; + + return true; +} + +vec_t Q_rint (vec_t in) +{ + return floor (in + 0.5); +} + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void _VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} + +#pragma optimize("g", off) // went back to turning optimization off, + // the bug_fix thing stopped working + +vec_t VectorNormalize (vec3_t in, vec3_t out) +{ + vec_t length, ilength; + + length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +vec_t ColorNormalize (vec3_t in, vec3_t out) +{ + float max, scale; + + max = in[0]; + if (in[1] > max) + max = in[1]; + if (in[2] > max) + max = in[2]; + + if (max == 0) + return 0; + + scale = 1.0 / max; + + VectorScale (in, scale, out); + + return max; +} + +#pragma optimize("", on) + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void ClearBounds (vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} diff --git a/tools/quake2/qdata_heretic2/common/mathlib.h b/tools/quake2/qdata_heretic2/common/mathlib.h new file mode 100644 index 00000000..b4cbf05f --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/mathlib.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h + +#include +/* +#ifdef DOUBLEVEC_T +typedef double vec_t; +#else +typedef float vec_t; +#endif +typedef vec_t vec3_t[3]; +*/ +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +#define Q_PI 3.14159265358979323846 + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];} + +vec_t Q_rint (vec_t in); +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); +void _VectorScale (vec3_t v, vec_t scale, vec3_t out); + +double VectorLength(vec3_t v); + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc); + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (vec3_t in, vec3_t out); +vec_t ColorNormalize (vec3_t in, vec3_t out); +void VectorInverse (vec3_t v); + +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +#endif diff --git a/tools/quake2/qdata_heretic2/common/md4.c b/tools/quake2/qdata_heretic2/common/md4.c new file mode 100644 index 00000000..e69de29b diff --git a/tools/quake2/qdata_heretic2/common/path_init.c b/tools/quake2/qdata_heretic2/common/path_init.c new file mode 100644 index 00000000..0a630a10 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/path_init.c @@ -0,0 +1,404 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Nurail: Swiped from Q3Map2 +*/ + + + +/* marker */ +#define PATH_INIT_C + +#if defined( __linux__ ) || defined( __APPLE__ ) + #define Q_UNIX +#endif + +#ifdef Q_UNIX + #include + #include + #include +#endif + + +/* dependencies */ +#include "cmdlib.h" +#include "inout.h" + + + +/* path support */ +#define MAX_BASE_PATHS 10 +#define MAX_GAME_PATHS 10 + +char *homePath; +char installPath[ MAX_OS_PATH ]; + +int numBasePaths; +char *basePaths[ MAX_BASE_PATHS ]; +int numGamePaths; +char *gamePaths[ MAX_GAME_PATHS ]; + +/* +some of this code is based off the original q3map port from loki +and finds various paths. moved here from bsp.c for clarity. +*/ + +/* +PathLokiGetHomeDir() +gets the user's home dir (for ~/.q3a) +*/ + +char *LokiGetHomeDir( void ) +{ + #ifndef Q_UNIX + return NULL; + #else + char *home; + uid_t id; + struct passwd *pwd; + + + /* get the home environment variable */ + home = getenv( "HOME" ); + if( home == NULL ) + { + /* do some more digging */ + id = getuid(); + setpwent(); + while( (pwd = getpwent()) != NULL ) + { + if( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + } + endpwent(); + } + + /* return it */ + return home; + #endif +} + + + +/* +PathLokiInitPaths() +initializes some paths on linux/os x +*/ + +void LokiInitPaths( char *argv0 ) +{ + #ifndef Q_UNIX + /* this is kinda crap, but hey */ + strcpy( installPath, "../" ); + #else + char temp[ MAX_OS_PATH ]; + char *home; + char *path; + char *last; + qboolean found; + + + /* get home dir */ + home = LokiGetHomeDir(); + if( home == NULL ) + home = "."; + + /* do some path divining */ + strcpy( temp, argv0 ); + if( strrchr( temp, '/' ) ) + argv0 = strrchr( argv0, '/' ) + 1; + else + { + /* get path environment variable */ + path = getenv( "PATH" ); + + /* minor setup */ + last[ 0 ] = path[ 0 ]; + last[ 1 ] = '\0'; + found = false; + + /* go through each : segment of path */ + while( last[ 0 ] != '\0' && found == false ) + { + /* null out temp */ + temp[ 0 ] = '\0'; + + /* find next chunk */ + last = strchr( path, ':' ); + if( last == NULL ) + last = path + strlen( path ); + + /* found home dir candidate */ + if( *path == '~' ) + { + strcpy( temp, home ); + path++; + } + + /* concatenate */ + if( last > (path + 1) ) + { + strncat( temp, path, (last - path) ); + strcat( temp, "/" ); + } + strcat( temp, "./" ); + strcat( temp, argv0 ); + + /* verify the path */ + if( access( temp, X_OK ) == 0 ) + found++; + path = last + 1; + } + } + + /* flake */ + if( realpath( temp, installPath ) ) + { + /* q3map is in "tools/" */ + *(strrchr( installPath, '/' )) = '\0'; + *(strrchr( installPath, '/' ) + 1) = '\0'; + } + + /* set home path */ + homePath = home; + #endif +} + + + +/* +CleanPath() - ydnar +cleans a dos path \ -> / +*/ + +void CleanPath( char *path ) +{ + while( *path ) + { + if( *path == '\\' ) + *path = '/'; + path++; + } +} + +/* +AddBasePath() - ydnar +adds a base path to the list +*/ + +void AddBasePath( char *path ) +{ + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS ) + return; + + /* add it to the list */ + basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 ); + strcpy( basePaths[ numBasePaths ], path ); + CleanPath( basePaths[ numBasePaths ] ); + numBasePaths++; +} + + + +/* +AddHomeBasePath() - ydnar +adds a base path to the beginning of the list, prefixed by ~/ +*/ + +void AddHomeBasePath( char *path ) +{ + #ifdef Q_UNIX + int i; + char temp[ MAX_OS_PATH ]; + + + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' ) + return; + + /* make a hole */ + for( i = 0; i < (MAX_BASE_PATHS - 1); i++ ) + basePaths[ i + 1 ] = basePaths[ i ]; + + /* concatenate home dir and path */ + sprintf( temp, "%s/%s", homePath, path ); + + /* add it to the list */ + basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 ); + strcpy( basePaths[ 0 ], temp ); + CleanPath( basePaths[ 0 ] ); + numBasePaths++; + #endif +} + + + +/* +AddGamePath() - ydnar +adds a game path to the list +*/ + +void AddGamePath( char *path ) +{ + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS ) + return; + + /* add it to the list */ + gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 ); + strcpy( gamePaths[ numGamePaths ], path ); + CleanPath( gamePaths[ numGamePaths ] ); + numGamePaths++; +} + + + + +/* +InitPaths() - ydnar +cleaned up some of the path initialization code from bsp.c +will remove any arguments it uses +*/ + +void InitPaths( int *argc, char **argv ) +{ + int i, j, k, len, len2; + char temp[ MAX_OS_PATH ]; + char gamePath[MAX_OS_PATH], homeBasePath[MAX_OS_PATH], game_magic[10]; + + strcpy(gamePath, "base"); + strcpy(game_magic, "h"); + strcpy(homeBasePath, ".heretic2"); + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" ); + + /* get the install path for backup */ + LokiInitPaths( argv[ 0 ] ); + + /* set game to default (q3a) */ + numBasePaths = 0; + numGamePaths = 0; + + /* parse through the arguments and extract those relevant to paths */ + for( i = 0; i < *argc; i++ ) + { + /* check for null */ + if( argv[ i ] == NULL ) + continue; + + /* -fs_basepath */ + if( strcmp( argv[ i ], "-fs_basepath" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + AddBasePath( argv[ i ] ); + argv[ i ] = NULL; + } + + } + + /* remove processed arguments */ + for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ ) + { + for( j; j < *argc && argv[ j ] == NULL; j++ ); + argv[ i ] = argv[ j ]; + if( argv[ i ] != NULL ) + k++; + } + *argc = k; + + /* add standard game path */ + AddGamePath( gamePath ); + + /* if there is no base path set, figure it out */ + if( numBasePaths == 0 ) + { + /* this is another crappy replacement for SetQdirFromPath() */ + len2 = strlen( game_magic ); + for( i = 0; i < *argc && numBasePaths == 0; i++ ) + { + /* extract the arg */ + strcpy( temp, argv[ i ] ); + CleanPath( temp ); + len = strlen( temp ); + Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game_magic, temp, i ); + + /* this is slow, but only done once */ + for( j = 0; j < (len - len2); j++ ) + { + /* check for the game's magic word */ + if( Q_strncasecmp( &temp[ j ], game_magic, len2 ) == 0 ) + { + /* now find the next slash and nuke everything after it */ + while( temp[ ++j ] != '/' && temp[ j ] != '\0' ); + temp[ j ] = '\0'; + + /* add this as a base path */ + AddBasePath( temp ); + break; + } + } + } + + /* add install path */ + if( numBasePaths == 0 ) + AddBasePath( installPath ); + + /* check again */ + if( numBasePaths == 0 ) + Error( "Failed to find a valid base path." ); + } + + /* this only affects unix */ + AddHomeBasePath( homeBasePath ); + + /* initialize vfs paths */ + if( numBasePaths > MAX_BASE_PATHS ) + numBasePaths = MAX_BASE_PATHS; + if( numGamePaths > MAX_GAME_PATHS ) + numGamePaths = MAX_GAME_PATHS; + + /* walk the list of game paths */ + //for( j = 0; j < numGamePaths; j++ ) + //{ + /* walk the list of base paths */ + // for( i = 0; i < numBasePaths; i++ ) + // { + /* create a full path and initialize it */ + // sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] ); + // vfsInitDirectory( temp ); + // } + //} + + /* done */ + Sys_Printf( "\n" ); +} + + + + diff --git a/tools/quake2/qdata_heretic2/common/polylib.c b/tools/quake2/qdata_heretic2/common/polylib.c new file mode 100644 index 00000000..34dfc2ef --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/polylib.c @@ -0,0 +1,656 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "polylib.h" + + +extern int numthreads; + +// counters are only bumped when running single threaded, +// because they are an awefull coherence problem +int c_active_windings; +int c_peak_windings; +int c_winding_allocs; +int c_winding_points; + +#define BOGUS_RANGE 8192 + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]); +} + + +/* +============= +AllocWinding +============= +*/ +winding_t *AllocWinding (int points) +{ + winding_t *w; + int s; + + if (numthreads == 1) + { + c_winding_allocs++; + c_winding_points += points; + c_active_windings++; + if (c_active_windings > c_peak_windings) + c_peak_windings = c_active_windings; + } + s = sizeof(vec_t)*3*points + sizeof(int); + w = malloc (s); + if (!w) + Error("AllocWinding MALLOC failed! Could not allocate %s bytes.", s); + memset (w, 0, s); + return w; +} + +void FreeWinding (winding_t *w) +{ + if (*(unsigned *)w == 0xdeaddead) + Error ("FreeWinding: freed a freed winding"); + *(unsigned *)w = 0xdeaddead; + + if (numthreads == 1) + c_active_windings--; + free (w); +} + +/* +============ +RemoveColinearPoints +============ +*/ +int c_removed; + +void RemoveColinearPoints (winding_t *w) +{ + int i, j, k; + vec3_t v1, v2; + int nump; + vec3_t p[MAX_POINTS_ON_WINDING]; + + nump = 0; + for (i=0 ; inumpoints ; i++) + { + j = (i+1)%w->numpoints; + k = (i+w->numpoints-1)%w->numpoints; + VectorSubtract (w->p[j], w->p[i], v1); + VectorSubtract (w->p[i], w->p[k], v2); + VectorNormalize(v1,v1); + VectorNormalize(v2,v2); + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (w->p[i], p[nump]); + nump++; + } + } + + if (nump == w->numpoints) + return; + + if (numthreads == 1) + c_removed += w->numpoints - nump; + w->numpoints = nump; + memcpy (w->p, p, nump*sizeof(p[0])); +} + +/* +============ +WindingPlane +============ +*/ +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist) +{ + vec3_t v1, v2; + + VectorSubtract (w->p[1], w->p[0], v1); + VectorSubtract (w->p[2], w->p[0], v2); + CrossProduct (v2, v1, normal); + VectorNormalize (normal, normal); + *dist = DotProduct (w->p[0], normal); + +} + +/* +============= +WindingArea +============= +*/ +vec_t WindingArea (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->p[i-1], w->p[0], d1); + VectorSubtract (w->p[i], w->p[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs) +{ + vec_t v; + int i,j; + + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +/* +============= +WindingCenter +============= +*/ +void WindingCenter (winding_t *w, vec3_t center) +{ + int i; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; inumpoints ; i++) + VectorAdd (w->p[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + +/* +================= +BaseWindingForPlane +================= +*/ +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + c = AllocWinding (w->numpoints); + size = (int)((winding_t *)0)->p[w->numpoints]; + memcpy (c, w, size); + return c; +} + +/* +================== +ReverseWinding +================== +*/ +winding_t *ReverseWinding (winding_t *w) +{ + int i; + winding_t *c; + + c = AllocWinding (w->numpoints); + for (i=0 ; inumpoints ; i++) + { + VectorCopy (w->p[w->numpoints-1-i], c->p[i]); + } + c->numpoints = w->numpoints; + return c; +} + + +/* +============= +ClipWindingEpsilon +============= +*/ +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + if (in->numpoints >= MAX_POINTS_ON_WINDING-4) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding (in); + return; + } + if (!counts[1]) + { + *front = CopyWinding (in); + return; + } + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + *front = f = AllocWinding (maxpts); + *back = b = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon) +{ + winding_t *in; + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + + if (!in) + { + printf ("Warning: NULL passed to ChopWindingInPlace\n"); + return; + } + if (in->numpoints >= MAX_POINTS_ON_WINDING-4) + Error ("ChopWinding: MAX_POINTS_ON_WINDING"); + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding (in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding (in); + *inout = f; +} + + +/* +================= +ChopWinding + +Returns the fragment of in that is on the front side +of the cliping plane. The original is freed. +================= +*/ +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) +{ + winding_t *f, *b; + + ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b); + FreeWinding (in); + if (b) + FreeWinding (b); + return f; +} + + +/* +================= +CheckWinding + +================= +*/ +void CheckWinding (winding_t *w) +{ + int i, j; + vec_t *p1, *p2; + vec_t d, edgedist; + vec3_t dir, edgenormal, facenormal; + vec_t area; + vec_t facedist; + + if (w->numpoints < 3) + Error ("CheckWinding: %i points",w->numpoints); + + area = WindingArea(w); + if (area < 1) + Error ("CheckWinding: %f area", area); + + WindingPlane (w, facenormal, &facedist); + + for (i=0 ; inumpoints ; i++) + { + p1 = w->p[i]; + + for (j=0 ; j<3 ; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Error ("CheckFace: BUGUS_RANGE: %f",p1[j]); + + j = i+1 == w->numpoints ? 0 : i+1; + + // check the point is on the face plane + d = DotProduct (p1, facenormal) - facedist; + if (d < -ON_EPSILON || d > ON_EPSILON) + Error ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = w->p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Error ("CheckWinding: degenerate edge"); + + CrossProduct (facenormal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + edgedist += ON_EPSILON; + + // all other points must be on front side + for (j=0 ; jnumpoints ; j++) + { + if (j == i) + continue; + d = DotProduct (w->p[j], edgenormal); + if (d > edgedist) + Error ("CheckWinding: non-convex"); + } + } +} + + +/* +============ +WindingOnPlaneSide +============ +*/ +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist) +{ + qboolean front, back; + int i; + vec_t d; + + front = false; + back = false; + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = true; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = true; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + diff --git a/tools/quake2/qdata_heretic2/common/polylib.h b/tools/quake2/qdata_heretic2/common/polylib.h new file mode 100644 index 00000000..e19fb2bd --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/polylib.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +typedef struct +{ + int numpoints; + vec3_t p[4]; // variable sized +} winding_t; + +#define MAX_POINTS_ON_WINDING 64 + +// you can define on_epsilon in the makefile as tighter +#ifndef ON_EPSILON +#define ON_EPSILON 0.1 +#endif + +winding_t *AllocWinding (int points); +vec_t WindingArea (winding_t *w); +void WindingCenter (winding_t *w, vec3_t center); +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back); +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist); +winding_t *CopyWinding (winding_t *w); +winding_t *ReverseWinding (winding_t *w); +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist); +void CheckWinding (winding_t *w); +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist); +void RemoveColinearPoints (winding_t *w); +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist); +void FreeWinding (winding_t *w); +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs); + +void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon); +// frees the original if clipped + +void pw(winding_t *w); diff --git a/tools/quake2/qdata_heretic2/common/qfiles.c b/tools/quake2/qdata_heretic2/common/qfiles.c new file mode 100644 index 00000000..58fcda00 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/qfiles.c @@ -0,0 +1,82 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qfiles.h" +#include "scriplib.h" +//#include + +materialtype_t defaultmaterialtypes[] = +{ + {"gravel", MATERIAL_GRAVEL}, + {"metal", MATERIAL_METAL}, + {"stone", MATERIAL_STONE}, + {"wood", MATERIAL_WOOD}, + {NULL, 0} +}; + +materialtype_t *materialtypes; + +void QFile_ReadMaterialTypes(char* filename) +{ + int i; + FILE *f; + + f = fopen (filename, "rb"); + if (!f) + { + materialtypes = defaultmaterialtypes; + return; + } + fclose (f); + + free(materialtypes); + materialtypes = (materialtype_t*)malloc(256 * sizeof(materialtype_t)); + + LoadScriptFile(filename); + i = 0; + + while (i < 255) + { + GetScriptToken (true); + if (endofscript) + { + break; + } + if (strcmp(token, "material") != 0) + { + while (ScriptTokenAvailable()) + { + GetScriptToken(false); + } + } + else + { + GetScriptToken(false); + materialtypes[i].name = (char*)malloc(strlen(token) + 1); + strcpy(materialtypes[i].name, token); + GetScriptToken (false); + materialtypes[i].value = atoi(token); + } + i++; + } + materialtypes[i].name = NULL; + materialtypes[i].value = 0; +} diff --git a/tools/quake2/qdata_heretic2/common/qfiles.h b/tools/quake2/qdata_heretic2/common/qfiles.h new file mode 100644 index 00000000..1af6d078 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/qfiles.h @@ -0,0 +1,619 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _QFILES_H +#define _QFILES_H + +#include "q_typedef.h" + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +The .pak files are just a linear collapse of a directory tree + +======================================================================== +*/ + +#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 4096 + + +/* +======================================================================== + +PCX files are used for as many images as possible + +======================================================================== +*/ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* +======================================================================== + +.MD2 compressed triangle model file format + +======================================================================== +*/ +#define IDJOINTEDALIASHEADER (('2'<<24)+('J'<<16)+('D'<<8)+'I') + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 2048 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 64 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +/* +======================================================================== + +.BK file format + +======================================================================== +*/ + +#define IDBOOKHEADER (('K'<<24)+('O'<<16)+('O'<<8)+'B') +#define BOOK_VERSION 2 + +typedef struct bookframe_s +{ + int x; + int y; + int w; + int h; + char name[MAX_SKINNAME]; // name of gfx file +} bookframe_t; + +typedef struct bookheader_s +{ + unsigned int ident; + unsigned int version; + int num_segments; + int total_w; + int total_h; +} bookheader_t; + +typedef struct book_s +{ + bookheader_t bheader; + bookframe_t bframes[MAX_MD2SKINS]; +} book_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .M8 texture file format + +============================================================================== +*/ + +typedef struct palette_s +{ + union + { + struct + { + byte r,g,b; + }; + }; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define MIPLEVELS 16 + +typedef struct miptex_s +{ + int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + + +#define MIP32_VERSION 4 + +#define MIP32_NOMIP_FLAG2 0x00000001 +#define MIP32_DETAILER_FLAG2 0x00000002 + +typedef struct miptex32_s +{ + int version; + char name[128]; + char altname[128]; // texture substitution + char animname[128]; // next frame in animation chain + char damagename[128]; // image that should be shown when damaged + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; + int flags; + int contents; + int value; + float scale_x, scale_y; + int mip_scale; + + // detail texturing info + char dt_name[128]; // detailed texture name + float dt_scale_x, dt_scale_y; + float dt_u, dt_v; + float dt_alpha; + int dt_src_blend_mode, dt_dst_blend_mode; + + int flags2; + int unused[19]; // future expansion to maintain compatibility with h2 +} miptex32_t; + + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 38 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x180000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// these definitions also need to be in q_shared.h! + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 0x00000001 // an eye is never valid in a solid +#define CONTENTS_WINDOW 0x00000002 // translucent, but not watery +#define CONTENTS_PUSHPULL 0x00000004 +#define CONTENTS_LAVA 0x00000008 +#define CONTENTS_SLIME 0x00000010 +#define CONTENTS_WATER 0x00000020 +#define CONTENTS_MIST 0x00000040 // 64 +#define LAST_VISIBLE_CONTENTS 64 // this one worries me a bit JKH + +// remaining contents are non-visible, and don't eat brushes + +#define CONTENTS_AREAPORTAL 0x00008000 + +#define CONTENTS_PLAYERCLIP 0x00010000 +#define CONTENTS_MONSTERCLIP 0x00020000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x00040000 +#define CONTENTS_CURRENT_90 0x00080000 +#define CONTENTS_CURRENT_180 0x00100000 +#define CONTENTS_CURRENT_270 0x00200000 +#define CONTENTS_CURRENT_UP 0x00400000 +#define CONTENTS_CURRENT_DOWN 0x00800000 + +#define CONTENTS_ORIGIN 0x01000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x02000000 // should never be on a brush, only in game +#define CONTENTS_DEADMONSTER 0x04000000 +#define CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTS_LADDER 0x20000000 + + + +#define SURF_LIGHT 0x00000001 // value will hold the light strength + +#define SURF_SLICK 0x00000002 // effects game physics + +#define SURF_SKY 0x00000004 // don't draw, but add to skybox +#define SURF_WARP 0x00000008 // turbulent water warp +#define SURF_TRANS33 0x00000010 +#define SURF_TRANS66 0x00000020 +#define SURF_FLOWING 0x00000040 // scroll towards angle +#define SURF_NODRAW 0x00000080 // don't bother referencing the texture + +#define SURF_HINT 0x00000100 // make a primary bsp splitter +#define SURF_SKIP 0x00000200 // completely ignore, allowing non-closed brushes +#define SURF_TALL_WALL 0x00000400 // face doesn't get broken up as normal + +#define SURF_ALPHA_TEXTURE 0x00000800 // texture has alpha in it, and should show through in bsp process +#define SURF_ANIMSPEED 0x00001000 // value will hold the anim speed in fps + +#define SURF_UNDULATE 0x00002000 // rock surface up and down... +#define SURF_SKYREFLECT 0x00004000 // liquid will somewhat reflect the sky - not quite finished.... + +#define SURF_TYPE_GRAVEL 0x00000000 +#define SURF_TYPE_METAL 0x01000000 +#define SURF_TYPE_STONE 0x02000000 +#define SURF_TYPE_WOOD 0x03000000 +#define SURF_MATERIAL 0xFF000000 + + + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + union { + byte styles[MAXLIGHTMAPS]; + paletteRGBA_t lighting; + }; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; + +typedef struct +{ + char *name; + int value; +} materialtype_t; + +enum +{ + MATERIAL_GRAVEL, + MATERIAL_METAL, + MATERIAL_STONE, + MATERIAL_WOOD, +}; + +materialtype_t *materialtypes; + +void QFile_ReadMaterialTypes(char* filename); + + +#endif //_QFILES_H diff --git a/tools/quake2/qdata_heretic2/common/scriplib.c b/tools/quake2/qdata_heretic2/common/scriplib.c new file mode 100644 index 00000000..25fc66d1 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/scriplib.c @@ -0,0 +1,297 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// scriplib.c + +#include "cmdlib.h" +#include "inout.h" +#include "scriplib.h" + +/* +============================================================================= + + PARSING STUFF + +============================================================================= +*/ + +typedef struct +{ + char filename[1024]; + char *buffer,*script_p,*end_p; + int line; +} script_t; + +#define MAX_INCLUDES 8 +script_t scriptstack[MAX_INCLUDES]; +script_t *script; +int scriptline; + +char token[MAXTOKEN]; +qboolean endofscript; +qboolean tokenready; // only true if UnGetScriptToken was just called + +/* +============== +AddScriptToStack +============== +*/ +void AddScriptToStack (char *filename) +{ + int size; + + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, ExpandPath (filename) ); + + size = LoadFile (script->filename, (void **)&script->buffer); + + printf ("entering %s\n", script->filename); + + script->line = 1; + + script->script_p = script->buffer; + script->end_p = script->buffer + size; +} + + +/* +============== +LoadScriptFile +============== +*/ +void LoadScriptFile (char *filename) +{ + script = scriptstack; + AddScriptToStack (filename); + + endofscript = false; + tokenready = false; +} + + +/* +============== +ParseFromMemory +============== +*/ +void ParseFromMemory (char *buffer, int size) +{ + script = scriptstack; + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, "memory buffer" ); + + script->buffer = buffer; + script->line = 1; + script->script_p = script->buffer; + script->end_p = script->buffer + size; + + endofscript = false; + tokenready = false; +} + + +/* +============== +UnGetScriptToken + +Signals that the current token was not used, and should be reported +for the next GetScriptToken. Note that + +GetScriptToken (true); +UnGetScriptToken (); +GetScriptToken (false); + +could cross a line boundary. +============== +*/ +void UnGetScriptToken (void) +{ + tokenready = true; +} + + +qboolean EndOfScript (qboolean crossline) +{ + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + + if (!strcmp (script->filename, "memory buffer")) + { + endofscript = true; + return false; + } + + free (script->buffer); + if (script == scriptstack+1) + { + endofscript = true; + return false; + } + script--; + scriptline = script->line; + printf ("returning to %s\n", script->filename); + return GetScriptToken (crossline); +} + +/* +============== +GetScriptToken +============== +*/ +qboolean GetScriptToken (qboolean crossline) +{ + char *token_p; + + if (tokenready) // is a token allready waiting? + { + tokenready = false; + return true; + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + +// +// skip space +// +skipspace: + while (*script->script_p <= 32) + { + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + if (*script->script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + scriptline = script->line++; + } + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + + // ; # // comments + if (*script->script_p == ';' || *script->script_p == '#' + || ( script->script_p[0] == '/' && script->script_p[1] == '/') ) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script->script_p++ != '\n') + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + goto skipspace; + } + + // /* */ comments + if (script->script_p[0] == '/' && script->script_p[1] == '*') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + script->script_p+=2; + while (script->script_p[0] != '*' && script->script_p[1] != '/') + { + script->script_p++; + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + } + script->script_p += 2; + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script->script_p == '"') + { + // quoted token + script->script_p++; + while (*script->script_p != '"') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + script->script_p++; + } + else // regular token + while ( *script->script_p > 32 && *script->script_p != ';') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + + *token_p = 0; + + if (!strcmp (token, "$include")) + { + GetScriptToken (false); + AddScriptToStack (token); + return GetScriptToken (crossline); + } + + return true; +} + + +/* +============== +ScriptTokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean ScriptTokenAvailable (void) +{ + char *search_p; + + search_p = script->script_p; + + if (search_p >= script->end_p) + return false; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + search_p++; + if (search_p == script->end_p) + return false; + + } + + if (*search_p == ';') + return false; + + return true; +} + + diff --git a/tools/quake2/qdata_heretic2/common/scriplib.h b/tools/quake2/qdata_heretic2/common/scriplib.h new file mode 100644 index 00000000..bee8d0aa --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/scriplib.h @@ -0,0 +1,44 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// scriplib.h + +#ifndef __CMDLIB__ +#include "cmdlib.h" +#endif + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern char *scriptbuffer,*script_p,*scriptend_p; +extern int grabbed; +extern int scriptline; +extern qboolean endofscript; + + +void LoadScriptFile (char *filename); +void ParseFromMemory (char *buffer, int size); + +qboolean GetScriptToken (qboolean crossline); +void UnGetScriptToken (void); +qboolean ScriptTokenAvailable (void); + + diff --git a/tools/quake2/qdata_heretic2/common/threads.c b/tools/quake2/qdata_heretic2/common/threads.c new file mode 100644 index 00000000..2a2b9787 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/threads.c @@ -0,0 +1,620 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIN32 +// The below define is necessary to use +// pthreads extensions like pthread_mutexattr_settype +#define _GNU_SOURCE +#include +#endif + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include "her2_threads.h" + +#define MAX_THREADS 64 + +int dispatch; +int workcount; +int oldf; +qboolean pacifier; + +qboolean threaded; + +/* +============= +GetThreadWork + +============= +*/ +int GetThreadWork (void) +{ + int r; + int f; + + ThreadLock (); + + if (dispatch == workcount) + { + ThreadUnlock (); + return -1; + } + + f = 10*dispatch / workcount; + if (f != oldf) + { + oldf = f; + if (pacifier) + { + Sys_Printf ("%i...", f); + fflush( stdout ); /* ydnar */ + } + } + + r = dispatch; + dispatch++; + ThreadUnlock (); + + return r; +} + + +void (*workfunction) (int); + +void ThreadWorkerFunction (int threadnum) +{ + int work; + + while (1) + { + work = GetThreadWork (); + if (work == -1) + break; +//Sys_Printf ("thread %i, work %i\n", threadnum, work); + workfunction(work); + } +} + +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + if (numthreads == -1) + ThreadSetDefault (); + workfunction = func; + RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); +} + + +/* +=================================================================== + +WIN32 + +=================================================================== +*/ +#ifdef _WIN32 + +#define USED + +#include + +int numthreads = -1; +CRITICAL_SECTION crit; +static int enter; + +void ThreadSetDefault (void) +{ + SYSTEM_INFO info; + + if (numthreads == -1) // not set manually + { + GetSystemInfo (&info); + numthreads = info.dwNumberOfProcessors; + if (numthreads < 1 || numthreads > 32) + numthreads = 1; + } + + Sys_Printf ("%i threads\n", numthreads); +} + + +void ThreadLock (void) +{ + if (!threaded) + return; + EnterCriticalSection (&crit); + if (enter) + Error ("Recursive ThreadLock\n"); + enter = 1; +} + +void ThreadUnlock (void) +{ + if (!threaded) + return; + if (!enter) + Error ("ThreadUnlock without lock\n"); + enter = 0; + LeaveCriticalSection (&crit); +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int threadid[MAX_THREADS]; + HANDLE threadhandle[MAX_THREADS]; + int i; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + // + // run threads in parallel + // + InitializeCriticalSection (&crit); + + if (numthreads == 1) + { // use same thread + func (0); + } + else + { + for (i=0 ; i + +pthread_mutex_t *my_mutex; + +void ThreadLock (void) +{ + if (my_mutex) + pthread_mutex_lock (my_mutex); +} + +void ThreadUnlock (void) +{ + if (my_mutex) + pthread_mutex_unlock (my_mutex); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + pthread_t work_threads[MAX_THREADS]; + pthread_addr_t status; + pthread_attr_t attrib; + pthread_mutexattr_t mattrib; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + if (pacifier) + setbuf (stdout, NULL); + + if (!my_mutex) + { + my_mutex = safe_malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); + } + + if (pthread_attr_create (&attrib) == -1) + Error ("pthread_attr_create failed"); + if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) + Error ("pthread_attr_setstacksize failed"); + + for (i=0 ; i +#include +#include +#include + + +int numthreads = -1; +abilock_t lck; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) + numthreads = prctl(PR_MAXPPROCS); + Sys_Printf ("%i threads\n", numthreads); + usconfig (CONF_INITUSERS, numthreads); +} + + +void ThreadLock (void) +{ + spin_lock (&lck); +} + +void ThreadUnlock (void) +{ + release_lock (&lck); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int pid[MAX_THREADS]; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + if (pacifier) + setbuf (stdout, NULL); + + init_lock (&lck); + + for (i=0 ; i 1) + Sys_Printf("threads: %d\n", numthreads); +} + +#include + +typedef struct pt_mutex_s +{ + pthread_t *owner; + pthread_mutex_t a_mutex; + pthread_cond_t cond; + unsigned int lock; +} pt_mutex_t; + +pt_mutex_t global_lock; + +void ThreadLock(void) +{ + pt_mutex_t *pt_mutex = &global_lock; + + if(!threaded) + return; + + pthread_mutex_lock(&pt_mutex->a_mutex); + if(pthread_equal(pthread_self(), (pthread_t)&pt_mutex->owner)) + pt_mutex->lock++; + else + { + if((!pt_mutex->owner) && (pt_mutex->lock == 0)) + { + pt_mutex->owner = (pthread_t *)pthread_self(); + pt_mutex->lock = 1; + } + else + { + while(1) + { + pthread_cond_wait(&pt_mutex->cond, &pt_mutex->a_mutex); + if((!pt_mutex->owner) && (pt_mutex->lock == 0)) + { + pt_mutex->owner = (pthread_t *)pthread_self(); + pt_mutex->lock = 1; + break; + } + } + } + } + pthread_mutex_unlock(&pt_mutex->a_mutex); +} + +void ThreadUnlock(void) +{ + pt_mutex_t *pt_mutex = &global_lock; + + if(!threaded) + return; + + pthread_mutex_lock(&pt_mutex->a_mutex); + pt_mutex->lock--; + + if(pt_mutex->lock == 0) + { + pt_mutex->owner = NULL; + pthread_cond_signal(&pt_mutex->cond); + } + + pthread_mutex_unlock(&pt_mutex->a_mutex); +} + +void recursive_mutex_init(pthread_mutexattr_t attribs) +{ + pt_mutex_t *pt_mutex = &global_lock; + + pt_mutex->owner = NULL; + if(pthread_mutex_init(&pt_mutex->a_mutex, &attribs) != 0) + Error("pthread_mutex_init failed\n"); + if(pthread_cond_init(&pt_mutex->cond, NULL) != 0) + Error("pthread_cond_init failed\n"); + + pt_mutex->lock = 0; +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + pthread_mutexattr_t mattrib; + pthread_t work_threads[MAX_THREADS]; + + int start, end; + int i=0, status=0; + + start = I_FloatTime (); + pacifier = showpacifier; + + dispatch = 0; + oldf = -1; + workcount = workcnt; + + if(numthreads == 1) + func(0); + else + { + threaded = true; + + if(pacifier) + setbuf(stdout, NULL); + + if(pthread_mutexattr_init(&mattrib) != 0) + Error("pthread_mutexattr_init failed"); +#if __GLIBC_MINOR__ == 1 + if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_FAST_NP) != 0) +#else + if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_ADAPTIVE_NP) != 0) +#endif + Error ("pthread_mutexattr_settype failed"); + recursive_mutex_init(mattrib); + + for (i=0 ; i", + "", + "", + "", + "", + "", + "", + "(", + ")", + "{", + "}", + "[", + "]", + ":", + "mesh", + "model", + "nodes", + "rotation", + "scaling", + "translation", + "polygons", + "position", + "vertex", + "vertices", + "HRCH", + "Softimage" +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// TK_Init +// +//========================================================================== + +void TK_Init(void) +{ + int i; + + for(i = 0; i < 256; i++) + { + ASCIIToChrCode[i] = CHR_SPECIAL; + } + for(i = '0'; i <= '9'; i++) + { + ASCIIToChrCode[i] = CHR_NUMBER; + } + for(i = 'A'; i <= 'Z'; i++) + { + ASCIIToChrCode[i] = CHR_LETTER; + } + for(i = 'a'; i <= 'z'; i++) + { + ASCIIToChrCode[i] = CHR_LETTER; + } + ASCIIToChrCode[ASCII_QUOTE] = CHR_QUOTE; + ASCIIToChrCode[ASCII_UNDERSCORE] = CHR_LETTER; + ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF; + tk_String = TokenStringBuffer; + IncLineNumber = FALSE; + SourceOpen = FALSE; +} + +//========================================================================== +// +// TK_OpenSource +// +//========================================================================== + +void TK_OpenSource(char *fileName) +{ + int size; + + TK_CloseSource(); + size = LoadFile(fileName, (void **)&FileStart); + strcpy(tk_SourceName, fileName); + SourceOpen = TRUE; + FileEnd = FileStart+size; + FilePtr = FileStart; + tk_Line = 1; + tk_Token = TK_NONE; + NextChr(); +} + +//========================================================================== +// +// TK_CloseSource +// +//========================================================================== + +void TK_CloseSource(void) +{ + if(SourceOpen) + { + free(FileStart); + SourceOpen = FALSE; + } +} + +//========================================================================== +// +// TK_Fetch +// +//========================================================================== + +tokenType_t TK_Fetch(void) +{ + while(Chr == ASCII_SPACE) + { + NextChr(); + } + if(Chr == '-') + { + ProcessNumberToken(); + } + else switch(ASCIIToChrCode[(byte)Chr]) + { + case CHR_EOF: + tk_Token = TK_EOF; + break; + case CHR_LETTER: + ProcessLetterToken(); + break; + case CHR_NUMBER: + ProcessNumberToken(); + break; + case CHR_QUOTE: + ProcessQuoteToken(); + break; + default: + ProcessSpecialToken(); + break; + } + return tk_Token; +} + +//========================================================================== +// +// TK_Require +// +//========================================================================== + +void TK_Require(tokenType_t tokType) +{ + if(tokType == TK_FLOATNUMBER && tk_Token == TK_INTNUMBER) + { + tk_FloatNumber = (float)tk_IntNumber; + tk_Token = TK_FLOATNUMBER; + return; + } + if(tk_Token != tokType) + { + Error("File '%s', line %d:\nExpected '%s', found '%s'.\n", + tk_SourceName, tk_Line, TokenNames[tokType], + TokenNames[tk_Token]); + } +} + +void TK_FetchRequire(tokenType_t tokType) +{ + TK_Fetch(); + TK_Require(tokType); +} + +tokenType_t TK_RequireFetch(tokenType_t tokType) +{ + TK_Require(tokType); + return TK_Fetch(); +} + +tokenType_t TK_FetchRequireFetch(tokenType_t tokType) +{ + TK_Fetch(); + TK_Require(tokType); + return TK_Fetch(); +} + +tokenType_t TK_Beyond(tokenType_t tokType) +{ + while(tk_Token != tokType) + { + if(TK_Fetch() == TK_EOF) + { + Error("File '%s':\nCould not find token '%s'.\n", // FIXME: TokenNames table not big enuff + tk_SourceName, TokenNames[tokType]); + } + } + return TK_Fetch(); +} + +void TK_BeyondRequire(tokenType_t bTok, tokenType_t rTok) +{ + TK_Beyond(bTok); + TK_Require(rTok); +} + +tokenType_t TK_Search(tokenType_t tokType) +{ + while(tk_Token != tokType) + { + if(TK_Fetch() == TK_EOF) + { + return TK_EOF; + } + } + return TK_Fetch(); +} + +tokenType_t TK_Get(tokenType_t tokType) +{ + while(tk_Token != tokType) + { + if(TK_Fetch() == TK_EOF) + { + Error("File '%s':\nCould not find token '%s'.\n", + tk_SourceName, TokenNames[tokType]); + } + } + return tk_Token; +} + +//========================================================================== +// +// ProcessLetterToken +// +//========================================================================== + +static void ProcessLetterToken(void) +{ + int i; + char *text; + + i = 0; + text = TokenStringBuffer; + while(ASCIIToChrCode[(byte)Chr] == CHR_LETTER + || ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) + { + if(++i == MAX_IDENTIFIER_LENGTH) + { + Error("File '%s', line %d:\nIdentifier too long.\n", + tk_SourceName, tk_Line); + } + *text++ = Chr; + NextChr(); + } + *text = 0; + if(CheckForKeyword() == FALSE) + { + tk_Token = TK_IDENTIFIER; + } +} + +//========================================================================== +// +// CheckForKeyword +// +//========================================================================== + +static qboolean CheckForKeyword(void) +{ + int i; + + for(i = 0; Keywords[i].name != NULL; i++) + { + if(strcmp(tk_String, Keywords[i].name) == 0) + { + tk_Token = Keywords[i].token; + return TRUE; + } + } + return FALSE; +} + +//========================================================================== +// +// ProcessNumberToken +// +//========================================================================== + +static void ProcessNumberToken(void) +{ + char *buffer; + + buffer = TempBuffer; + *buffer++ = Chr; + NextChr(); + while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) + { + *buffer++ = Chr; + NextChr(); + } + if(Chr == '.') + { // Float + *buffer++ = Chr; + NextChr(); // Skip period + while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) + { + *buffer++ = Chr; + NextChr(); + } + *buffer = 0; + tk_FloatNumber = (float)atof(TempBuffer); + tk_Token = TK_FLOATNUMBER; + return; + } + + // Integer + *buffer = 0; + tk_IntNumber = atoi(TempBuffer); + tk_Token = TK_INTNUMBER; +} + +//========================================================================== +// +// ProcessQuoteToken +// +//========================================================================== + +static void ProcessQuoteToken(void) +{ + int i; + char *text; + + i = 0; + text = TokenStringBuffer; + NextChr(); + while(Chr != ASCII_QUOTE) + { + if(Chr == EOF_CHARACTER) + { + Error("File '%s', line %d:\n inside string.\n", + tk_SourceName, tk_Line); + } + if(++i > MAX_QUOTED_LENGTH-1) + { + Error("File '%s', line %d:\nString literal too long.\n", + tk_SourceName, tk_Line); + } + *text++ = Chr; + NextChr(); + } + *text = 0; + NextChr(); + tk_Token = TK_STRING; +} + +//========================================================================== +// +// ProcessSpecialToken +// +//========================================================================== + +static void ProcessSpecialToken(void) +{ + char c; + + c = Chr; + NextChr(); + switch(c) + { + case '(': + tk_Token = TK_LPAREN; + break; + case ')': + tk_Token = TK_RPAREN; + break; + case '{': + tk_Token = TK_LBRACE; + break; + case '}': + tk_Token = TK_RBRACE; + break; + case '[': + tk_Token = TK_LBRACKET; + break; + case ']': + tk_Token = TK_RBRACKET; + break; + case ':': + tk_Token = TK_COLON; + break; + default: + tk_Token = TK_UNKNOWNCHAR; + break; + } +} + +//========================================================================== +// +// NextChr +// +//========================================================================== + +static void NextChr(void) +{ + if(FilePtr >= FileEnd) + { + Chr = EOF_CHARACTER; + return; + } + if(IncLineNumber == TRUE) + { + tk_Line++; + IncLineNumber = FALSE; + } + Chr = *FilePtr++; + if(Chr < ASCII_SPACE) + { + if(Chr == '\n') + { + IncLineNumber = TRUE; + } + Chr = ASCII_SPACE; + } +} diff --git a/tools/quake2/qdata_heretic2/common/token.h b/tools/quake2/qdata_heretic2/common/token.h new file mode 100644 index 00000000..e6aab853 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/token.h @@ -0,0 +1,132 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +//************************************************************************** +//** +//** token.h +//** +//************************************************************************** + +#ifndef __TOKEN_H__ +#define __TOKEN_H__ + +#include "cmdlib.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef YES +#define YES 1 +#endif +#ifndef NO +#define NO 0 +#endif +#define ASCII_SPACE 32 +#define ASCII_QUOTE 34 +#define ASCII_UNDERSCORE 95 +#define EOF_CHARACTER 127 +#define MAX_IDENTIFIER_LENGTH 64 +#define MAX_QUOTED_LENGTH 1024 +#define MAX_FILE_NAME_LENGTH 1024 + +typedef enum +{ + TK_NONE, + TK_UNKNOWNCHAR, + TK_EOF, + TK_IDENTIFIER, // VALUE: (char *) tk_String + TK_STRING, // VALUE: (char *) tk_String + TK_INTNUMBER, // VALUE: (int) tk_IntNumber + TK_FLOATNUMBER, // VALUE: (float) tk_FloatNumber + TK_LPAREN, + TK_RPAREN, + TK_LBRACE, + TK_RBRACE, // 10 + TK_LBRACKET, + TK_RBRACKET, + TK_COLON, + TK_MESH, + TK_MODEL, // 15 + TK_NODES, + TK_ROTATION, + TK_SCALING, + TK_TRANSLATION, + TK_POLYGONS, // 20 + TK_POSITION, + TK_VERTEX, + TK_VERTICES, + TK_EDGES, + TK_HRCH, // 25 + TK_SOFTIMAGE, + TK_MATERIAL, + TK_SPLINE, // 28 + + TK_C_NAMED, + TK_OBJECT, // 30 + TK_C_TRI, + TK_C_VERTICES, + TK_C_FACES, + TK_C_VERTEX, + TK_LIST, // 35 + TK_C_FACE, + + TK_C_HEXEN, + TK_C_TRIANGLES, + TK_C_VERSION, + TK_FACES, // 40 + TK_FACE, + TK_ORIGIN, + + TK_CLUSTERS, + TK_NUM_CLUSTER_VERTICES, + TK_NAME, // 45 + TK_CLUSTER_NAME, + TK_CLUSTER_STATE, + + TK_ACTOR_DATA, + TK_UVTEXTURE, +} tokenType_t; + +void TK_Init(void); +void TK_OpenSource(char *fileName); +void TK_CloseSource(void); +tokenType_t TK_Fetch(void); +void TK_Require(tokenType_t tokType); +void TK_FetchRequire(tokenType_t tokType); +tokenType_t TK_RequireFetch(tokenType_t tokType); +tokenType_t TK_FetchRequireFetch(tokenType_t tokType); +tokenType_t TK_Beyond(tokenType_t tokType); +void TK_BeyondRequire(tokenType_t bTok, tokenType_t rTok); +tokenType_t TK_Search(tokenType_t tokType); +tokenType_t TK_Get(tokenType_t tokType); + +extern tokenType_t tk_Token; +extern int tk_Line; +extern int tk_IntNumber; +extern float tk_FloatNumber; +extern char *tk_String; +extern char tk_SourceName[MAX_FILE_NAME_LENGTH]; + +#endif diff --git a/tools/quake2/qdata_heretic2/common/trilib.c b/tools/quake2/qdata_heretic2/common/trilib.c new file mode 100644 index 00000000..4ed79051 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/trilib.c @@ -0,0 +1,1077 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// trilib.c: library for loading triangles from an Alias triangle file +// + +#include +#include "cmdlib.h" +#include "inout.h" +#include "mathlib.h" +#include "trilib.h" +#include "token.h" +#include "l3dslib.h" +#include "fmodel.h" +#if 1 +#include "qd_skeletons.h" +#endif + +// on disk representation of a face +#define FLOAT_START 99999.0 +#define FLOAT_END -FLOAT_START +#define MAGIC 123322 +#ifndef M_PI + #define M_PI 3.14159265 +#endif + +float FixHTRRotateX = 0.0; +float FixHTRRotateY = 0.0; +float FixHTRRotateZ = 0.0; +float FixHTRTranslateX = 0.0; +float FixHTRTranslateY = 0.0; +float FixHTRTranslateZ = 0.0; + +//#define NOISY 1 + +typedef struct { + float v[3]; +} vector; + +typedef struct +{ + vector n; /* normal */ + vector p; /* point */ + vector c; /* color */ + float u; /* u */ + float v; /* v */ +} aliaspoint_t; + +typedef struct { + aliaspoint_t pt[3]; +} tf_triangle; + + +void ByteSwapTri (tf_triangle *tri) +{ + int i; + + for (i=0 ; iverts[j][k] = tri.pt[j].p.v[k]; + } + } + + ptri++; + + if ((ptri - *pptri) >= MAXTRIANGLES) + Error ("Error: too many triangles; increase MAXTRIANGLES\n"); + } + } + + *numtriangles = ptri - *pptri; + + fclose (input); + + DefaultNodesList(nodesList,num_mesh_nodes,numtriangles); +} + + +//========================================================================== +// +// LoadHRC +// +//========================================================================== + +float scaling[3]; +float rotation[3]; +float translation[3]; +static char *hrc_name; + +struct +{ + float v[3]; +} vList[8192]; + +void HandleHRCModel(triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes, + int ActiveNode, int Depth, int numVerts) +{ + void ReadHRCClusterList(mesh_node_t *meshNode, int baseIndex); + + int i, j; + int vertexCount; + int triCount; + triangle_t *tList; + mesh_node_t *meshNode; + float x, y, z; + float x2, y2, z2; + float rx, ry, rz; + tokenType_t nextToken; + float orig_scaling[3]; + float orig_rotation[3]; + float orig_translation[3]; + int start_tri; + int pos,bit; + int vertIndexBase; + + // Update Node Info + if (nodesList) + { + TK_BeyondRequire(TK_NAME, TK_STRING); + + if (Depth == 0 || tk_String[0] == '_') + { // Root + ActiveNode = *num_mesh_nodes; + (*num_mesh_nodes)++; + if ((*num_mesh_nodes) > MAX_FM_MESH_NODES) + { + Error("Too many mesh nodes in file %s\n", hrc_name); + } + meshNode = &(*nodesList)[ActiveNode]; + +// memset(meshNode, 0, sizeof(mesh_node_t)); + strcpy(meshNode->name, tk_String); + + memset(meshNode->tris, 0, sizeof(meshNode->tris)); + memset(meshNode->verts, 0, sizeof(meshNode->verts)); + + meshNode->start_glcmds = 0; + meshNode->num_glcmds = 0; + vertIndexBase = 0; + } + else + { // Childs under the children + meshNode = &(*nodesList)[ActiveNode]; + vertIndexBase = numVerts; + } + } + else + { + meshNode = NULL; + } + + + // Get the scaling, rotation, and translation values + TK_Beyond(TK_SCALING); + for(i = 0; i < 3; i++) + { + orig_scaling[i] = scaling[i]; + + TK_Require(TK_FLOATNUMBER); + scaling[i] *= tk_FloatNumber; + + TK_Fetch(); + } + TK_Beyond(TK_ROTATION); + for(i = 0; i < 3; i++) + { + orig_rotation[i] = rotation[i]; + + TK_Require(TK_FLOATNUMBER); + rotation[i] = tk_FloatNumber; + + TK_Fetch(); + } + TK_Beyond(TK_TRANSLATION); + for(i = 0; i < 3; i++) + { + orig_translation[i] = translation[i]; + + TK_Require(TK_FLOATNUMBER); + translation[i] += tk_FloatNumber; + + TK_Fetch(); + } + + rx = ((rotation[0]-90.0)/360.0)*2.0*M_PI; + ry = (rotation[2]/360.0)*2.0*M_PI; + rz = (rotation[1]/360.0)*2.0*M_PI; + + // rjr - might not work if there an item doesn't have a mesh + nextToken = tk_Token; + if (nextToken == TK_ACTOR_DATA) + { + while (nextToken != TK_MODEL && nextToken != TK_RBRACE) + { + nextToken = TK_Fetch(); + } + } + + while (nextToken == TK_SPLINE) + { // spline node has two right braces + nextToken = TK_Beyond(TK_RBRACE); + nextToken = TK_Beyond(TK_RBRACE); + } + + while (nextToken == TK_MATERIAL) + { + nextToken = TK_Beyond(TK_RBRACE); + } + + while(nextToken == TK_MODEL) + { + HandleHRCModel(triList,triangleCount,nodesList,num_mesh_nodes,ActiveNode, Depth+1, 0); + + nextToken = TK_Fetch(); + } + + if (nextToken == TK_MESH) + { + // Get all the tri and vertex info + TK_BeyondRequire(TK_VERTICES, TK_INTNUMBER); + vertexCount = tk_IntNumber; + for(i = 0; i < vertexCount; i++) + { + TK_BeyondRequire(TK_LBRACKET, TK_INTNUMBER); + if(tk_IntNumber != i) + { + Error("File '%s', line %d:\nVertex index mismatch.\n", + tk_SourceName, tk_Line); + } + TK_Beyond(TK_POSITION); + // Apply the scaling, rotation, and translation in the order + // specified in the HRC file. This could be wrong. + TK_Require(TK_FLOATNUMBER); + x = tk_FloatNumber*scaling[0]; + TK_FetchRequire(TK_FLOATNUMBER); + y = tk_FloatNumber*scaling[1]; + TK_FetchRequire(TK_FLOATNUMBER); + z = tk_FloatNumber*scaling[2]; + + y2 = y*cos(rx)+z*sin(rx); + z2 = -y*sin(rx)+z*cos(rx); + y = y2; + z = z2; + + x2 = x*cos(ry)-z*sin(ry); + z2 = x*sin(ry)+z*cos(ry); + x = x2; + z = z2; + + x2 = x*cos(rz)+y*sin(rz); + y2 = -x*sin(rz)+y*cos(rz); + x = x2; + y = y2; + + vList[i].v[0] = x+translation[0]; + vList[i].v[1] = y-translation[2]; + vList[i].v[2] = z+translation[1]; + } + TK_BeyondRequire(TK_POLYGONS, TK_INTNUMBER); + triCount = tk_IntNumber; + if(triCount >= MAXTRIANGLES) + { + Error("Too many triangles in file %s\n", hrc_name); + } + + start_tri = *triangleCount; + *triangleCount += triCount; + + tList = *triList; + + for(i = 0; i < triCount; i++) + { + if (meshNode) + { // Update the node + pos = (i + start_tri) >> 3; + bit = 1 << ((i + start_tri) & 7 ); + meshNode->tris[pos] |= bit; + } + + TK_BeyondRequire(TK_LBRACKET, TK_INTNUMBER); + if(tk_IntNumber != i) + { + Error("File '%s', line %d:\nTriangle index mismatch.\n", + tk_SourceName, tk_Line); + } + TK_BeyondRequire(TK_NODES, TK_INTNUMBER); + if(tk_IntNumber != 3) + { + Error("File '%s', line %d:\nBad polygon vertex count: %d.", + tk_SourceName, tk_Line, tk_IntNumber); + } + tList[i+start_tri].HasUV = true; + for(j = 0; j < 3; j++) + { + TK_BeyondRequire(TK_LBRACKET, TK_INTNUMBER); + if(tk_IntNumber != j) + { + Error("File '%s', line %d:\nTriangle vertex index" + " mismatch. %d should be %d\n", tk_SourceName, tk_Line, + tk_IntNumber, j); + } + TK_BeyondRequire(TK_VERTEX, TK_INTNUMBER); + + tList[i+start_tri].verts[2-j][0] = vList[tk_IntNumber].v[0]; + tList[i+start_tri].verts[2-j][1] = vList[tk_IntNumber].v[1]; + tList[i+start_tri].verts[2-j][2] = vList[tk_IntNumber].v[2]; +#if 1 + tList[i+start_tri].indicies[2-j] = tk_IntNumber+vertIndexBase; +#endif + TK_BeyondRequire(TK_UVTEXTURE, TK_FLOATNUMBER); + tList[i+start_tri].uv[2-j][0] = tk_FloatNumber; + TK_Fetch(); + TK_Require(TK_FLOATNUMBER); + tList[i+start_tri].uv[2-j][1] = tk_FloatNumber; + } + + /* printf("Face %i:\n v0: %f, %f, %f\n v1: %f, %f, %f\n" + " v2: %f, %f, %f\n", i, + tList[i].verts[0][0], + tList[i].verts[0][1], + tList[i].verts[0][2], + tList[i].verts[1][0], + tList[i].verts[1][1], + tList[i].verts[1][2], + tList[i].verts[2][0], + tList[i].verts[2][1], + tList[i].verts[2][2]); + */ + } + + TK_Beyond(TK_RBRACE); + TK_Beyond(TK_RBRACE); + + if (tk_Token == TK_EDGES) + { + // TK_Beyond(TK_EDGES); + TK_Beyond(TK_RBRACE); + } + + scaling[0] = scaling[1] = scaling[2] = 1.0; + // rotation[0] = rotation[1] = rotation[2] = 0.0; + // translation[0] = translation[1] = translation[2] = 0.0; + + // See if there are any other models belonging to this node + +#if 1 + TK_Fetch(); + + nextToken = tk_Token; + if(nextToken == TK_CLUSTERS) + { + if(g_skelModel.clustered == -1) + { + ReadHRCClusterList(meshNode, vertIndexBase); + } + else + { + nextToken = TK_Get(TK_CLUSTER_NAME); + + while (nextToken == TK_CLUSTER_NAME) + { + TK_BeyondRequire(TK_CLUSTER_STATE, TK_INTNUMBER); + nextToken = TK_Fetch(); + } + } + + // one right brace follow the list of clusters + nextToken = TK_Beyond(TK_RBRACE); + } + else + { + if(g_skelModel.clustered == -1 && !vertIndexBase) + { + meshNode->clustered = false; + } + } +#endif + + nextToken = tk_Token; + if(nextToken == TK_SPLINE) + { + while (nextToken == TK_SPLINE) + { // spline node has two right braces + nextToken = TK_Beyond(TK_RBRACE); + nextToken = TK_Beyond(TK_RBRACE); + } + + nextToken = TK_Beyond(TK_RBRACE); + } + + while (nextToken == TK_MATERIAL) + { + nextToken = TK_Beyond(TK_RBRACE); + } + + while(nextToken == TK_MODEL) + { + HandleHRCModel(triList,triangleCount,nodesList, num_mesh_nodes, ActiveNode, Depth+1, vertexCount+vertIndexBase); + + nextToken = TK_Fetch(); + } + } + + for(i=0;i<3;i++) + { + scaling[i] = orig_scaling[i]; + rotation[i] = orig_rotation[i]; + translation[i] = orig_translation[i]; + } +} + +static void LoadHRC(char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes) +{ + if (nodesList) + { + *num_mesh_nodes = 0; + + if(!*nodesList) + { + *nodesList = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + } + } + + hrc_name = fileName; + + scaling[0] = scaling[1] = scaling[2] = 1.0; + rotation[0] = rotation[1] = rotation[2] = 0.0; + translation[0] = translation[1] = translation[2] = 0.0; + + *triangleCount = 0; + *triList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list"); + memset(*triList,0,MAXTRIANGLES*sizeof(triangle_t)); + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + // prime it + TK_Beyond(TK_MODEL); + + HandleHRCModel(triList, triangleCount, nodesList, num_mesh_nodes, 0, 0, 0); + TK_CloseSource(); +} + +//========================================================================== +// +// LoadHTR +// +//========================================================================== +/* +static int Version2; + +void HandleHTRModel(triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes, + int ActiveNode, int Depth, int numVerts) +{ + int i, j; + int vertexCount; + int vertexNum; + int triCount; + float origin[3]; + triangle_t *tList; + float x, y, z; + float x2, y2, z2; + float rx, ry, rz; + mesh_node_t *meshNode; + int pos,bit; + int vertIndexBase; + int start_tri; + + if (nodesList) + { + TK_BeyondRequire(TK_NAME, TK_STRING); + + if (Depth == 0 || tk_String[0] == '_') + { // Root + ActiveNode = *num_mesh_nodes; + (*num_mesh_nodes)++; + if ((*num_mesh_nodes) > MAX_FM_MESH_NODES) + { + Error("Too many mesh nodes in file %s\n", hrc_name); + } + meshNode = &(*nodesList)[ActiveNode]; + +// memset(meshNode, 0, sizeof(mesh_node_t)); + strcpy(meshNode->name, tk_String); + + memset(meshNode->tris, 0, sizeof(meshNode->tris)); + memset(meshNode->verts, 0, sizeof(meshNode->verts)); + + meshNode->start_glcmds = 0; + meshNode->num_glcmds = 0; + vertIndexBase = 0; + } + else + { // Childs under the children + meshNode = &(*nodesList)[ActiveNode]; + vertIndexBase = numVerts; + } + } + else + { + meshNode = NULL; + } + + // Get vertex count + TK_BeyondRequire(TK_VERTICES, TK_INTNUMBER); + vertexCount = tk_IntNumber; + + // Get triangle count + TK_BeyondRequire(TK_FACES, TK_INTNUMBER); + triCount = tk_IntNumber; + if(triCount >= MAXTRIANGLES) + { + Error("Too many triangles in file %s\n", hrc_name); + } + + // Get origin + TK_Beyond(TK_ORIGIN); + TK_Require(TK_FLOATNUMBER); + origin[0] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + origin[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + origin[2] = tk_FloatNumber; + + //rx = 90.0/360.0*2.0*M_PI; + rx = FixHTRRotateX/360.0*2.0*M_PI; + ry = FixHTRRotateY/360.0*2.0*M_PI; + rz = FixHTRRotateZ/360.0*2.0*M_PI; + + // Get vertex list + for(i = 0; i < vertexCount; i++) + { + TK_FetchRequire(TK_VERTEX); + TK_FetchRequire(TK_FLOATNUMBER); + x = tk_FloatNumber-origin[0]; + TK_FetchRequire(TK_FLOATNUMBER); + y = tk_FloatNumber-origin[1]; + TK_FetchRequire(TK_FLOATNUMBER); + z = tk_FloatNumber-origin[2]; + + x += FixHTRTranslateX; + y += FixHTRTranslateY; + z += FixHTRTranslateZ; + + y2 = y*cos(rx)-z*sin(rx); + z2 = y*sin(rx)+z*cos(rx); + y = y2; + z = z2; + x2 = x*cos(ry)+z*sin(ry); + z2 = -x*sin(ry)+z*cos(ry); + x = x2; + z = z2; + x2 = x*cos(rz)-y*sin(rz); + y2 = x*sin(rz)+y*cos(rz); + x = x2; + y = y2; + + vList[i].v[0] = x; + vList[i].v[1] = y; + vList[i].v[2] = z; + } + + start_tri = *triangleCount; + *triangleCount += triCount; + + tList = *triList; + + // Get face list + for(i = 0; i < triCount; i++) + { + if (meshNode) + { // Update the node + pos = (i + start_tri) >> 3; + bit = 1 << ((i + start_tri) & 7 ); + meshNode->tris[pos] |= bit; + } + + TK_FetchRequire(TK_FACE); + TK_FetchRequire(TK_LPAREN); + for(j = 0; j < 3; j++) + { + TK_FetchRequire(TK_INTNUMBER); + vertexNum = tk_IntNumber-1; + if(vertexNum >= vertexCount) + { + Error("File '%s', line %d:\nVertex number" + " >= vertexCount: %d\n", tk_SourceName, tk_Line, + tk_IntNumber); + } + tList[i+start_tri].verts[2-j][0] = vList[vertexNum].v[0]; + tList[i+start_tri].verts[2-j][1] = vList[vertexNum].v[1]; + tList[i+start_tri].verts[2-j][2] = vList[vertexNum].v[2]; + } + TK_FetchRequire(TK_RPAREN); +#ifdef _QDATA + if (Version2) + { + TK_FetchRequire(TK_FLOATNUMBER); + tList[i+start_tri].uv[0][0]=tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + tList[i+start_tri].uv[0][1]=tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + tList[i+start_tri].uv[1][0]=tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + tList[i+start_tri].uv[1][1]=tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + tList[i+start_tri].uv[2][0]=tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + tList[i+start_tri].uv[2][1]=tk_FloatNumber; + tList[i+start_tri].HasUV=1; + } + else + tList[i+start_tri].HasUV=0; +#endif +// printf("Face %i:\n v0: %f, %f, %f\n v1: %f, %f, %f\n" +// " v2: %f, %f, %f\n", i, +// tList[i].verts[0][0], +// tList[i].verts[0][1], +// tList[i].verts[0][2], +// tList[i].verts[1][0], +// tList[i].verts[1][1], +// tList[i].verts[1][2], +// tList[i].verts[2][0], +// tList[i].verts[2][1], +// tList[i].verts[2][2]); + + } + + TK_Fetch(); + + if (tk_Token == TK_VERTICES) + { + HandleHTRModel(triList,triangleCount,nodesList, num_mesh_nodes, ActiveNode, Depth+1, vertexCount+vertIndexBase); + } +} + +static void LoadHTR(char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes) +{ + if (nodesList) + { + *num_mesh_nodes = 0; + + if(!*nodesList) + { + *nodesList = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + } + } + + hrc_name = fileName; + + scaling[0] = scaling[1] = scaling[2] = 1.0; + rotation[0] = rotation[1] = rotation[2] = 0.0; + translation[0] = translation[1] = translation[2] = 0.0; + + *triangleCount = 0; + *triList = SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list"); + memset(*triList,0,MAXTRIANGLES*sizeof(triangle_t)); + + TK_OpenSource(fileName); + + TK_Beyond(TK_C_HEXEN); + TK_Beyond(TK_C_TRIANGLES); + TK_BeyondRequire(TK_C_VERSION, TK_INTNUMBER); + if(tk_IntNumber != 1&&tk_IntNumber != 2) + { + Error("Unsupported version (%d) in file %s\n", tk_IntNumber, + fileName); + } + Version2=(tk_IntNumber==2); + + + HandleHTRModel(triList, triangleCount, nodesList, num_mesh_nodes, 0, 0, 0); +} + +*/ + +static void LoadHTR(char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes) +{ + int Version2=0; + int i, j; + int vertexCount; + int vertexNum; + struct + { + float v[3]; + } *vList; + int triCount; + float origin[3]; + triangle_t *tList; + float x, y, z; + float x2, y2, z2; + float rx, ry, rz; + + if (nodesList) + { + *num_mesh_nodes = 0; + *nodesList = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + } + + TK_OpenSource(fileName); + + TK_Beyond(TK_C_HEXEN); + TK_Beyond(TK_C_TRIANGLES); + TK_BeyondRequire(TK_C_VERSION, TK_INTNUMBER); + if(tk_IntNumber != 1&&tk_IntNumber != 2) + { + Error("Unsupported version (%d) in file %s\n", tk_IntNumber, + fileName); + } + Version2=(tk_IntNumber==2); + + + // Get vertex count + TK_BeyondRequire(TK_VERTICES, TK_INTNUMBER); + vertexCount = tk_IntNumber; + vList = (void *) SafeMalloc(vertexCount*sizeof vList[0], "Vertex list"); + + // Get triangle count + TK_BeyondRequire(TK_FACES, TK_INTNUMBER); + triCount = tk_IntNumber; + if(triCount >= MAXTRIANGLES) + { + Error("Too many triangles in file %s\n", fileName); + } + *triangleCount = triCount; + tList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list"); + *triList = tList; + memset(*triList,0,MAXTRIANGLES*sizeof(triangle_t)); + + // Get origin + TK_Beyond(TK_ORIGIN); + TK_Require(TK_FLOATNUMBER); + origin[0] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + origin[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + origin[2] = tk_FloatNumber; + + //rx = 90.0/360.0*2.0*M_PI; + rx = FixHTRRotateX/360.0*2.0*M_PI; + ry = FixHTRRotateY/360.0*2.0*M_PI; + rz = FixHTRRotateZ/360.0*2.0*M_PI; + + // Get vertex list + for(i = 0; i < vertexCount; i++) + { + TK_FetchRequire(TK_VERTEX); + TK_FetchRequire(TK_FLOATNUMBER); + x = tk_FloatNumber-origin[0]; + TK_FetchRequire(TK_FLOATNUMBER); + y = tk_FloatNumber-origin[1]; + TK_FetchRequire(TK_FLOATNUMBER); + z = tk_FloatNumber-origin[2]; + + x += FixHTRTranslateX; + y += FixHTRTranslateY; + z += FixHTRTranslateZ; + + y2 = y*cos(rx)-z*sin(rx); + z2 = y*sin(rx)+z*cos(rx); + y = y2; + z = z2; + x2 = x*cos(ry)+z*sin(ry); + z2 = -x*sin(ry)+z*cos(ry); + x = x2; + z = z2; + x2 = x*cos(rz)-y*sin(rz); + y2 = x*sin(rz)+y*cos(rz); + x = x2; + y = y2; + + vList[i].v[0] = x; + vList[i].v[1] = y; + vList[i].v[2] = z; + } + + // Get face list + for(i = 0; i < triCount; i++) + { + TK_FetchRequire(TK_FACE); + TK_FetchRequire(TK_LPAREN); + for(j = 0; j < 3; j++) + { + TK_FetchRequire(TK_INTNUMBER); + vertexNum = tk_IntNumber-1; + if(vertexNum >= vertexCount) + { + Error("File '%s', line %d:\nVertex number" + " >= vertexCount: %d\n", tk_SourceName, tk_Line, + tk_IntNumber); + } + tList[i].verts[2-j][0] = vList[vertexNum].v[0]; + tList[i].verts[2-j][1] = vList[vertexNum].v[1]; + tList[i].verts[2-j][2] = vList[vertexNum].v[2]; + } + TK_FetchRequire(TK_RPAREN); +#if 1 + if (Version2) + { + TK_FetchRequire(TK_FLOATNUMBER); + tList[i].uv[2][0]= fmod(1000+tk_FloatNumber,1); + TK_FetchRequire(TK_FLOATNUMBER); + tList[i].uv[2][1]=fmod(1000+tk_FloatNumber,1); + TK_FetchRequire(TK_FLOATNUMBER); + tList[i].uv[1][0]=fmod(1000+tk_FloatNumber,1); + TK_FetchRequire(TK_FLOATNUMBER); + tList[i].uv[1][1]=fmod(1000+tk_FloatNumber,1); + TK_FetchRequire(TK_FLOATNUMBER); + tList[i].uv[0][0]=fmod(1000+tk_FloatNumber,1); + TK_FetchRequire(TK_FLOATNUMBER); + tList[i].uv[0][1]=fmod(1000+tk_FloatNumber,1); + tList[i].HasUV=1; + } + else + tList[i].HasUV=0; +#endif +/* printf("Face %i:\n v0: %f, %f, %f\n v1: %f, %f, %f\n" + " v2: %f, %f, %f\n", i, + tList[i].verts[0][0], + tList[i].verts[0][1], + tList[i].verts[0][2], + tList[i].verts[1][0], + tList[i].verts[1][1], + tList[i].verts[1][2], + tList[i].verts[2][0], + tList[i].verts[2][1], + tList[i].verts[2][2]); +*/ + } + + free(vList); + TK_CloseSource(); + DefaultNodesList(nodesList,num_mesh_nodes,triangleCount); +} + +//========================================================================== +// +// LoadTriangleList +// +//========================================================================== + +void LoadTriangleList(char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **ppmnodes, int *num_mesh_nodes) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + LoadHRC(InputFileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + printf(" - assuming .HRC\n"); + return; + } + + strcpy(InputFileName, fileName); + strcat(InputFileName, ".asc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + LoadASC(InputFileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + printf(" - assuming .ASC\n"); + return; + } + + strcpy(InputFileName, fileName); + strcat(InputFileName, ".tri"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + LoadTRI(InputFileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + printf(" - assuming .TRI\n"); + return; + } + + strcpy(InputFileName, fileName); + strcat(InputFileName, ".3ds"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + Load3DSTriangleList (InputFileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + printf(" - assuming .3DS\n"); + return; + } + + strcpy(InputFileName, fileName); + strcat(InputFileName, ".htr"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + LoadHTR (InputFileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + printf(" - assuming .HTR\n"); + return; + } + Error("\n Could not open file '%s':\n" + "No HRC, ASC, 3DS, HTR, or TRI match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRC(fileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + } + else if (strcmp(dotstart,".asc") == 0 || strcmp(dotstart,".ASC") == 0) + { + LoadASC(fileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + } + else if (strcmp(dotstart,".tri") == 0 || strcmp(dotstart,".TRI") == 0) + { + LoadTRI(fileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + } + else if (strcmp(dotstart,".3ds") == 0 || strcmp(dotstart,".3DS") == 0) + { + Load3DSTriangleList (fileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + } + else if (strcmp(dotstart,".htr") == 0 || strcmp(dotstart,".HTR") == 0) + { + LoadHTR (fileName, triList, triangleCount, ppmnodes, num_mesh_nodes); + } + else + { + Error("Could not open file '%s':\n",fileName); + return; + } + } + else //failed to load file + { + Error("Could not open file '%s':\n",fileName); + } + + } +} diff --git a/tools/quake2/qdata_heretic2/common/trilib.h b/tools/quake2/qdata_heretic2/common/trilib.h new file mode 100644 index 00000000..2afdf559 --- /dev/null +++ b/tools/quake2/qdata_heretic2/common/trilib.h @@ -0,0 +1,56 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// trilib.h: header file for loading triangles from an Alias triangle file +// + +#include "fmodel.h" + +#define MAXTRIANGLES MAX_FM_TRIANGLES + +typedef struct +{ + vec3_t verts[3]; +#if 1 + int indicies[3]; + float uv[3][2]; + qboolean HasUV; +#endif +} triangle_t; + +#define NUM_CLUSTERS 8 + +typedef struct +{ + char name[64]; + byte tris[MAXTRIANGLES>>3]; + byte verts[MAX_FM_VERTS>>3]; + int start_glcmds, num_glcmds; + + int *clusters[NUM_CLUSTERS]; + struct IntListNode_s *vertLists[NUM_CLUSTERS]; + int num_verts[NUM_CLUSTERS + 1]; + int new_num_verts[NUM_CLUSTERS + 1]; + qboolean clustered; +} mesh_node_t; + +void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **ppmnodes, int *num_mesh_nodes); diff --git a/tools/quake2/qdata_heretic2/fmodels.c b/tools/quake2/qdata_heretic2/fmodels.c new file mode 100644 index 00000000..6dd16355 --- /dev/null +++ b/tools/quake2/qdata_heretic2/fmodels.c @@ -0,0 +1,3404 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qd_fmodel.h" +#include "animcomp.h" +#include "qd_skeletons.h" +#include "skeletons.h" +#include "qdata.h" +#include "flex.h" +#include "reference.h" + +#include + +/* +======================================================================== + +.FM triangle flexible model file format + +======================================================================== +*/ + +//================================================================= + +#define NUMVERTEXNORMALS 162 + +extern float avertexnormals[NUMVERTEXNORMALS][3]; + +#define MAX_GROUPS 128 + +typedef struct +{ + triangle_t triangle; + int group; +} trigroup_t; + +#define TRIVERT_DIST .1 + +typedef struct +{ + int start_frame; + int num_frames; + int degrees; + char *mat; + char *ccomp; + char *cbase; + float *cscale; + float *coffset; + float trans[3]; + float scale[3]; + float bmin[3]; + float bmax[3]; +} fmgroup_t; + +//================================================================ + +// Initial +fmheader_t fmheader; + +// Skin +extern char g_skins[MAX_FM_SKINS][64]; + +// ST Coord +extern fmstvert_t base_st[MAX_FM_VERTS]; + +// Triangles +extern fmtriangle_t triangles[MAX_FM_TRIANGLES]; + +// Frames +fmframe_t g_frames[MAX_FM_FRAMES]; +//fmframe_t *g_FMframes; + +// GL Commands +extern int commands[16384]; +extern int numcommands; + + +// +// varibles set by commands +// +extern float scale_up; // set by $scale +extern vec3_t adjust; // set by $origin +extern int g_fixedwidth, g_fixedheight; // set by $skinsize +extern char modelname[64]; // set by $modelname + + +extern char *g_outputDir; + + +// Mesh Nodes +mesh_node_t *pmnodes = NULL; +fmmeshnode_t mesh_nodes[MAX_FM_MESH_NODES]; + +fmgroup_t groups[MAX_GROUPS]; +int num_groups; +int frame_to_group[MAX_FM_FRAMES]; + +// +// variables set by command line arguments +// +qboolean g_no_opimizations = false; + + +// +// base frame info +// +static int triangle_st[MAX_FM_TRIANGLES][3][2]; + + +// number of gl vertices +extern int numglverts; +// indicates if a triangle has already been used in a glcmd +extern int used[MAX_FM_TRIANGLES]; +// indicates if a triangle has translucency in it or not +static qboolean translucent[MAX_FM_TRIANGLES]; + +// main output file handle +extern FILE *headerouthandle; +// output sizes of buildst() +static int skin_width, skin_height; + + +// statistics +static int total_skin_pixels; +static int skin_pixels_used; + +int ShareVertex( trigroup_t trione, trigroup_t tritwo); +float DistBetween(vec3_t point1, vec3_t point2); +int GetNumTris( trigroup_t *tris, int group); +void GetOneGroup(trigroup_t *tris, int grp, triangle_t* triangles); +void ScaleTris( vec3_t min, vec3_t max, int Width, int Height, float* u, float* v, int verts); +void NewDrawLine(int x1, int y1, int x2, int y2, unsigned char* picture, int width, int height); + +#ifndef _WIN32 + +void strupr(char *string) +{ + int i; + + for (i=0 ; iverts[fmheader.num_xyz]; + + WriteHeader(modelouthandle, FM_HEADER_NAME, FM_HEADER_VER, sizeof(fmheader), &fmheader); + + // + // write out the skin names + // + + WriteHeader(modelouthandle, FM_SKIN_NAME, FM_SKIN_VER, fmheader.num_skins * MAX_FM_SKINNAME, g_skins); + + // + // write out the texture coordinates + // + c_on = c_off = 0; + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + + outFrames[i].scale[j] = out->scale[j]; + outFrames[i].translate[j] = out->translate[j]; + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, fmheader.framesize); + } + + // Go back and finish the header + // WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, -1, NULL); + } + else + { + WriteHeader(modelouthandle, FM_SHORT_FRAME_NAME, FM_SHORT_FRAME_VER,FRAME_NAME_LEN*fmheader.num_frames, NULL); + for (i=0 ; iname,FRAME_NAME_LEN); + } + WriteHeader(modelouthandle, FM_NORMAL_NAME, FM_NORMAL_VER,fmheader.num_xyz, NULL); + in = &g_frames[0]; + for (j=0 ; jv[j].lightnormalindex,1); + } + + // + // write out glcmds + // + WriteHeader(modelouthandle, FM_GLCMDS_NAME, FM_GLCMDS_VER, numcommands*4, commands); + + // + // write out mesh nodes + // + for(i=0;idegrees*sizeof(char) + char *ccomp; g->num_frames*g->degrees*sizeof(char) + char *cbase; fmheader.num_xyz*3*sizeof(unsigned char) + float *cscale; g->degrees*sizeof(float) + float *coffset; g->degrees*sizeof(float) + float trans[3]; 3*sizeof(float) + float scale[3]; 3*sizeof(float) +} fmgroup_t; +*/ + int tmp,k; + fmgroup_t *g; + size=sizeof(int)+fmheader.num_frames*sizeof(int); + for (k=0;kdegrees*sizeof(char); + size+=g->num_frames*g->degrees*sizeof(char); + size+=fmheader.num_xyz*3*sizeof(unsigned char); + size+=g->degrees*sizeof(float); + size+=g->degrees*sizeof(float); + size+=12*sizeof(float); + } + WriteHeader(modelouthandle, FM_COMP_NAME, FM_COMP_VER,size, NULL); + SafeWrite (modelouthandle,&num_groups,sizeof(int)); + SafeWrite (modelouthandle,frame_to_group,sizeof(int)*fmheader.num_frames); + + for (k=0;kstart_frame); + SafeWrite (modelouthandle,&tmp,sizeof(int)); + tmp=LittleLong(g->num_frames); + SafeWrite (modelouthandle,&tmp,sizeof(int)); + tmp=LittleLong(g->degrees); + SafeWrite (modelouthandle,&tmp,sizeof(int)); + + SafeWrite (modelouthandle,g->mat,fmheader.num_xyz*3*g->degrees*sizeof(char)); + SafeWrite (modelouthandle,g->ccomp,g->num_frames*g->degrees*sizeof(char)); + SafeWrite (modelouthandle,g->cbase,fmheader.num_xyz*3*sizeof(unsigned char)); + SafeWrite (modelouthandle,g->cscale,g->degrees*sizeof(float)); + SafeWrite (modelouthandle,g->coffset,g->degrees*sizeof(float)); + SafeWrite (modelouthandle,g->trans,3*sizeof(float)); + SafeWrite (modelouthandle,g->scale,3*sizeof(float)); + SafeWrite (modelouthandle,g->bmin,3*sizeof(float)); + SafeWrite (modelouthandle,g->bmax,3*sizeof(float)); + free(g->mat); + free(g->ccomp); + free(g->cbase); + free(g->cscale); + free(g->coffset); + } + } + + // write the skeletal info + if(g_skelModel.type != SKEL_NULL) + { + size = 0; + + temp = sizeof(int); // change this to a byte + memcpy(data + size, &g_skelModel.type, temp); + size += temp; + + // number of joints + temp = sizeof(int); // change this to a byte + memcpy(data + size, &numJointsInSkeleton[g_skelModel.type], temp); + size += temp; + + // number of verts in each joint cluster + temp = sizeof(int)*numJointsInSkeleton[g_skelModel.type]; // change this to shorts + memcpy(data + size, &g_skelModel.new_num_verts[1], temp); + size += temp; + + // cluster verts + for(i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i) + { + current = g_skelModel.vertLists[i]; + while(current) + { + temp = sizeof(int); // change this to a short + memcpy(data + size, ¤t->data, temp); + size += temp; + toFree = current; + current = current->next; + free(toFree); // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base + } + } + + if(!num_groups) // joints are stored with regular verts for compressed models + { + framesWritten = true; + + temp = sizeof(int); // change this to a byte + memcpy(data + size, &framesWritten, temp); + size += temp; + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + + for (j = 0 ; j < numJointsInSkeleton[g_skelModel.type]; ++j) + { + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->joints[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data + size, &v, temp); + size += temp; + } + } + } + + } + else + { + temp = sizeof(int); // change this to a byte + memcpy(data + size, &framesWritten, temp); + size += temp; + } + + WriteHeader(modelouthandle, FM_SKELETON_NAME, FM_SKELETON_VER, size, data); + } + + if(g_skelModel.references != REF_NULL) + { + int refnum; + + size = 0; + if (RefPointNum <= 0) + { // Hard-coded labels + refnum = numReferences[g_skelModel.references]; + } + else + { // Labels indicated in QDT + refnum = RefPointNum; + } + + temp = sizeof(int); // change this to a byte + memcpy(data2 + size, &g_skelModel.references, temp); + size += temp; + + if(!num_groups) + { + framesWritten = true; + + temp = sizeof(int); // change this to a byte + memcpy(data2 + size, &framesWritten, temp); + size += temp; + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + + for (j = 0 ; j < refnum; ++j) + { + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->references[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data2 + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->references[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data2 + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->references[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data2 + size, &v, temp); + size += temp; + } + } + } + } + else // FINISH ME: references need to be stored with regular verts for compressed models + { + framesWritten = false; + + temp = sizeof(int); // change this to a byte + memcpy(data2 + size, &framesWritten, temp); + size += temp; + } + + WriteHeader(modelouthandle, FM_REFERENCES_NAME, FM_REFERENCES_VER, size, data2); + } +} + +static void CompressFrames() +{ + fmgroup_t *g; + int i,j,k; + fmframe_t *in; + + j=0; + for (i=0;i=groups[j].start_frame+groups[j].num_frames&&jnum_frames,fmheader.num_xyz,g->degrees); + for (i=0;inum_frames;i++) + { + in = &g_frames[i+g->start_frame]; + for (j=0;jv[j].v[0],in->v[j].v[1],in->v[j].v[2]); + } + AnimCompressDoit(); + g->mat= (char *) SafeMalloc(fmheader.num_xyz*3*g->degrees*sizeof(char), "CompressFrames"); + g->ccomp=(char *) SafeMalloc(g->num_frames*g->degrees*sizeof(char), "CompressFrames"); + g->cbase=(char *) SafeMalloc(fmheader.num_xyz*3*sizeof(unsigned char), "CompressFrames"); + g->cscale=(float *) SafeMalloc(g->degrees*sizeof(float), "CompressFrames"); + g->coffset=(float *) SafeMalloc(g->degrees*sizeof(float), "CompressFrames"); + AnimCompressToBytes(g->trans,g->scale,g->mat,g->ccomp,g->cbase,g->cscale,g->coffset,g->bmin,g->bmax); + AnimCompressEnd(); + } +} + +static void OptimizeVertices(void) +{ + qboolean vert_used[MAX_FM_VERTS]; + short vert_replacement[MAX_FM_VERTS]; + int i,j,k,l,pos,bit,set_pos,set_bit; + fmframe_t *in; + qboolean Found; + int num_unique; + static IntListNode_t *newVertLists[NUM_CLUSTERS]; + static int newNum_verts[NUM_CLUSTERS]; + IntListNode_t *current, *next; + + printf("Optimizing vertices..."); + + memset(vert_used, 0, sizeof(vert_used)); + + if(g_skelModel.clustered == true) + { + memset(newNum_verts, 0, sizeof(newNum_verts)); + memset(newVertLists, 0, sizeof(newVertLists)); + } + + num_unique = 0; + + // search for common points among all the frames + for (i=0 ; iv[j].v[0] == in->v[k].v[0] && + in->v[j].v[1] == in->v[k].v[1] && + in->v[j].v[2] == in->v[k].v[2]) + { + Found = true; + vert_replacement[j] = k; + break; + } + + } + + if (!Found) + { + if (!vert_used[j]) + { + num_unique++; + } + vert_used[j] = true; + } + } + } + + // recompute the light normals + for (i=0 ; iv[j].vnorm.normalsum, in->v[k].vnorm.normalsum, in->v[k].vnorm.normalsum); + in->v[k].vnorm.numnormals += in->v[j].vnorm.numnormals++; + } + } + + for (j=0 ; jv[j].vnorm.numnormals; + if (!c) + Error ("Vertex with no triangles attached"); + + VectorScale (in->v[j].vnorm.normalsum, 1.0/c, v); + VectorNormalize (v, v); + + maxdot = -999999.0; + maxdotindex = -1; + + for (k=0 ; k maxdot) + { + maxdot = dot; + maxdotindex = k; + } + } + + in->v[j].lightnormalindex = maxdotindex; + } + } + + // create substitution list + num_unique = 0; + for(i=0;inext) + { + if(current->data == i) + { + IntListNode_t *current2; + int m; + qboolean added = false; + + for(m = 0, current2 = newVertLists[k]; m < newNum_verts[k+1]; + ++m, current2 = current2->next) + { + if(current2->data == vert_replacement[i]) + { + added = true; + break; + } + } + + if(!added) + { + ++newNum_verts[k+1]; + + next = newVertLists[k]; + + newVertLists[k] = (IntListNode_t *) SafeMalloc(sizeof(IntListNode_t), "OptimizeVertices"); + // freed after model write out + + newVertLists[k]->data = vert_replacement[i]; + newVertLists[k]->next = next; + } + break; + } + } + } + } + } + + // substitute + for (i=0 ; iv[vert_replacement[j]] = in->v[j]; + } + + } + + for(i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i) + { + IntListNode_t *toFree; + current = g_skelModel.vertLists[i]; + + while(current) + { + toFree = current; + current = current->next; + free(toFree); // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base + } + + g_skelModel.vertLists[i] = newVertLists[i]; + g_skelModel.new_num_verts[i+1] = newNum_verts[i+1]; + } + +#ifndef NDEBUG + for(k = 0; k < numJointsInSkeleton[g_skelModel.type]; ++k) + { + for(l = 0, current = g_skelModel.vertLists[k]; + l < g_skelModel.new_num_verts[k+1]; ++l, current = current->next) + { + IntListNode_t *current2; + int m; + + for(m = l+1, current2 = current->next; m < newNum_verts[k+1]; + ++m, current2 = current2->next) + { + if(current->data == current2->data) + { + printf("Warning duplicate vertex: %d\n", current->data); + break; + } + } + } + } +#endif + + for(i=0;i> 3; + bit = 1 << (i & 7 ); + + for (j=0 ; j<3 ; j++) + { + set_bit = set_pos = triangles[i].index_xyz[j] = vert_replacement[triangles[i].index_xyz[j]]; + + set_pos >>= 3; + set_bit = 1 << (set_bit & 7); + + for(k=0;kreferences[j].placement.origin, in->v[index].v); + index++; + + VectorCopy(in->references[j].placement.direction, in->v[index].v); + index++; + + VectorCopy(in->references[j].placement.up, in->v[index].v); + index++; + } + } + + fmheader.num_xyz += refnum*3; + } + + // tack on the skeletal joint verts to the regular verts + if(g_skelModel.type != SKEL_NULL) + { + fmframe_t *in; + int index; + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + index = fmheader.num_xyz; + + for (j = 0 ; j < numJointsInSkeleton[g_skelModel.type]; ++j) + { + VectorCopy(in->joints[j].placement.origin, in->v[index].v); + index++; + + VectorCopy(in->joints[j].placement.direction, in->v[index].v); + index++; + + VectorCopy(in->joints[j].placement.up, in->v[index].v); + index++; + } + } + + fmheader.num_xyz += numJointsInSkeleton[g_skelModel.type]*3; + } + + CompressFrames(); + } +} + + +/* +=============== +FinishModel +=============== +*/ +void FMFinishModel (void) +{ + FILE *modelouthandle; + int i,j,length,tris,verts,bit,pos,total_tris,total_verts; + char name[1024]; + int trans_count; + + if (!fmheader.num_frames) + return; + +// +// copy to release directory tree if doing a release build +// + if (g_release) + { + if (modelname[0]) + sprintf (name, "%s", modelname); + else + sprintf (name, "%s/tris.fm", cdpartial); + ReleaseFile (name); + + for (i=0 ; i> 3; + bit = 1 << ((j) & 7 ); + if (pmnodes[i].tris[pos] & bit) + { + tris++; + } + } + for(j=0;j> 3; + bit = 1 << ((j) & 7 ); + if (pmnodes[i].verts[pos] & bit) + { + verts++; + } + } + + printf("%-33s %4d %5d\n",pmnodes[i].name,tris,verts); + + total_tris += tris; + total_verts += verts; + } + printf("--------------------------------- ---- -----\n"); + printf("%-33s %4d %5d\n","TOTALS",total_tris,total_verts); + } + } + fclose (modelouthandle); + + // finish writing header file + H_printf("\n"); + + // scale_up is usefull to allow step distances to be adjusted + H_printf("#define MODEL_SCALE\t\t%f\n", scale_up); + + // mesh nodes + if (fmheader.num_mesh_nodes) + { + H_printf("\n"); + H_printf("#define NUM_MESH_NODES\t\t%d\n\n",fmheader.num_mesh_nodes); + for(i=0;iindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+2)%3]; + st1 = last->index_st[(startv+2)%3]; + m2 = last->index_xyz[(startv+1)%3]; + st2 = last->index_st[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; j> 3; + bit = 1 << (j & 7 ); + if (!(pmnodes[node].tris[pos] & bit)) + { + continue; + } + for (k=0 ; k<3 ; k++) + { + if (check->index_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j] || translucent[j] != translucent[starttri]) + goto done; + + // the new edge + if (stripcount & 1) + { + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + } + else + { + m1 = check->index_xyz[ (k+2)%3 ]; + st1 = check->index_st[ (k+2)%3 ]; + } + + strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ]; + strip_st[stripcount+2] = check->index_st[ (k+2)%3 ]; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+0)%3]; + st1 = last->index_st[(startv+0)%3]; + m2 = last->index_xyz[(startv+2)%3]; + st2 = last->index_st[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; j> 3; + bit = 1 << (j & 7 ); + if (!(pmnodes[node].tris[pos] & bit)) + { + continue; + } + for (k=0 ; k<3 ; k++) + { + if (check->index_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j] || translucent[j] != translucent[starttri]) + goto done; + + // the new edge + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + + strip_xyz[stripcount+2] = m2; + strip_st[stripcount+2] = st2; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; j> 3; + bit = 1 << (i & 7 ); + if (!(pmnodes[l].tris[pos] & bit)) + { + continue; + } + + // pick an unused triangle and start the trifan + if (used[i] || trans_check != translucent[i]) + { + continue; + } + + bestlen = 0; + for (type = 0 ; type < 2 ; type++) + // type = 1; + { + for (startv =0 ; startv < 3 ; startv++) + { + if (type == 1) + len = StripLength (i, startv, fmheader.num_tris, l); + else + len = FanLength (i, startv, fmheader.num_tris, l); + if (len > bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j + "-------------------------", // ? + "-------------------------", // @ + "-***-*---*******---**---*", // A + "****-*---*****-*---*****-", + "-*****----*----*-----****", + "****-*---**---**---*****-", + "******----****-*----*****", + "******----****-*----*----", + "-*****----*--***---*-****", + "*---**---*******---**---*", + "-***---*----*----*---***-", + "----*----*----**---*-***-", + "-*--*-*-*--**---*-*--*--*", + "-*----*----*----*----****", + "*---***-***-*-**---**---*", + "*---***--**-*-**--***---*", + "-***-*---**---**---*-***-", + "****-*---*****-*----*----", + "-***-*---**---*-***----**", + "****-*---*****-*-*--*--**", + "-*****-----***-----*****-", + "*****--*----*----*----*--", + "*---**---**---**---******", + "*---**---**---*-*-*---*--", + "*---**---**-*-***-***---*", + "*---*-*-*---*---*-*-*---*", + "*---**---*-*-*---*----*--", + "*****---*---*---*---*****" // Z +}; + +void DrawLine(int x1, int y1, int x2, int y2) +{ + int dx, dy; + int adx, ady; + int count; + float xfrac, yfrac, xstep, ystep; + unsigned sx, sy; + float u, v; + + dx = x2 - x1; + dy = y2 - y1; + adx = abs(dx); + ady = abs(dy); + + count = adx > ady ? adx : ady; + count++; + + if(count > 300) + { + printf("Bad count\n"); + return; // don't ever hang up on bad data + } + + xfrac = x1; + yfrac = y1; + + xstep = (float)dx/count; + ystep = (float)dy/count; + + switch(LineType) + { + case LINE_NORMAL: + do + { + if(xfrac < SKINPAGE_WIDTH && yfrac < SKINPAGE_HEIGHT) + { + pic[(int)yfrac*SKINPAGE_WIDTH+(int)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_FAT: + do + { + for (u=-0.1 ; u<=0.9 ; u+=0.999) + { + for (v=-0.1 ; v<=0.9 ; v+=0.999) + { + sx = xfrac+u; + sy = yfrac+v; + if(sx < SKINPAGE_WIDTH && sy < SKINPAGE_HEIGHT) + { + pic[sy*SKINPAGE_WIDTH+sx] = LineColor; + } + } + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_DOTTED: + do + { + if(count&1 && xfrac < SKINPAGE_WIDTH && + yfrac < SKINPAGE_HEIGHT) + { + pic[(int)yfrac*SKINPAGE_WIDTH+(int)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + default: + Error("Unknown %d.\n", LineType); + } +} + +//========================================================================== +// +// DrawCharacter +// +//========================================================================== + +static void DrawCharacter(int x, int y, int character) +{ + int r, c; + char *def; + + character = toupper(character); + if(character < ASCII_SPACE || character > 'Z') + { + character = ASCII_SPACE; + } + character -= ASCII_SPACE; + for(def = CharDefs[character], r = 0; r < 5; r++) + { + for(c = 0; c < 5; c++) + { + pic[(y+r)*SKINPAGE_WIDTH+x+c] = *def++ == '*' ? 255 : 0; + } + } +} + +//========================================================================== +// +// DrawTextChar +// +//========================================================================== + +void DrawTextChar(int x, int y, char *text) +{ + int c; + + while((c = *text++) != '\0') + { + DrawCharacter(x, y, c); + x += 6; + } +} + + +extern void DrawScreen(float s_scale, float t_scale, float iwidth, float iheight); + +//========================================================================== +// ExtractDigit + +static int ExtractDigit(byte *pic, int x, int y) +{ + int i; + int r, c; + char digString[32]; + char *buffer; + byte backColor; + char **DigitDefs; + + backColor = pic[(SKINPAGE_HEIGHT - 1) * SKINPAGE_WIDTH]; + DigitDefs = &CharDefs['0' - ASCII_SPACE]; + + buffer = digString; + for(r = 0; r < 5; r++) + { + for(c = 0; c < 5; c++) + { + *buffer++ = (pic[(y + r) * SKINPAGE_WIDTH + x + c] == backColor) ? ' ' : '*'; + } + } + *buffer = '\0'; + for(i = 0; i < 10; i++) + { + if(strcmp(DigitDefs[i], digString) == 0) + { + return i; + } + } + + Error("Unable to extract scaling info from skin PCX."); + return 0; +} + +//========================================================================== +// ExtractNumber + +int ExtractNumber(byte *pic, int x, int y) +{ + return ExtractDigit(pic, x, y) * 100 + ExtractDigit(pic, x + 6, y) * 10 + ExtractDigit(pic, x + 12, y); +} + + + + + +/* +============ +BuildST + +Builds the triangle_st array for the base frame and +fmheader.skinwidth / fmheader.skinheight + + FIXME: allow this to be loaded from a file for + arbitrary mappings +============ +*/ +static void BuildST (triangle_t *ptri, int numtri, qboolean DrawSkin) +{ + int backface_flag; + int i, j; + int width, height, iwidth, iheight, swidth; + float basex, basey; + float scale; + vec3_t mins, maxs; + float *pbasevert; + vec3_t vtemp1, vtemp2, normal; + float s_scale, t_scale; + float scWidth; + float scHeight; + int skinwidth; + int skinheight; + + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + backface_flag = false; + + if (ptri[0].HasUV) // if we have the uv already, we don't want to double up or scale + { + iwidth = ScaleWidth; + iheight = ScaleHeight; + + t_scale = s_scale = 1.0; + } + else + { + for (i=0 ; i 0) + { + backface_flag = true; + break; + } + } + scWidth = ScaleWidth*SCALE_ADJUST_FACTOR; + if (backface_flag) //we are doubling + scWidth /= 2; + + scHeight = ScaleHeight*SCALE_ADJUST_FACTOR; + + scale = scWidth/width; + + if(height*scale >= scHeight) + { + scale = scHeight/height; + } + + iwidth = ceil(width*scale)+4; + iheight = ceil(height*scale)+4; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + t_scale = s_scale; + } + if (DrawSkin) + { + if(backface_flag) + DrawScreen(s_scale, t_scale, iwidth*2, iheight); + else + DrawScreen(s_scale, t_scale, iwidth, iheight); + } + if (backface_flag) + skinwidth=iwidth*2; + else + skinwidth=iwidth; + skinheight=iheight; + + +/* if (!g_fixedwidth) + { // old style + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + }*/ + +// +// determine which side of each triangle to map the texture to +// + basey = 2; + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + + if (DrawSkin) + { + DrawLine(triangle_st[i][0][0], triangle_st[i][0][1], + triangle_st[i][1][0], triangle_st[i][1][1]); + DrawLine(triangle_st[i][1][0], triangle_st[i][1][1], + triangle_st[i][2][0], triangle_st[i][2][1]); + DrawLine(triangle_st[i][2][0], triangle_st[i][2][1], + triangle_st[i][0][0], triangle_st[i][0][1]); + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + + swidth = iwidth; + if(backface_flag) + swidth *= 2; + fmheader.skinwidth = (swidth + 3) & ~3; + fmheader.skinheight = iheight; + + skin_width = iwidth; + skin_height = iheight; +} + + +static void BuildNewST (triangle_t *ptri, int numtri, qboolean DrawSkin) +{ + int i, j; + + for (i=0 ; i 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return 0; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + if (SetPixel) + { + assert ((new[1]*BaseWidth) + new[0] < BaseWidth*BaseHeight); + + if (BaseTrueColor) + { + BasePixels[((new[1]*BaseWidth) + new[0]) * 4] = 1; + } + else + { + BasePixels[(new[1]*BaseWidth) + new[0]] = 1; + } + } + else + { + if (TransPixels) + { + if (TransPixels[(new[1]*TransWidth) + new[0]] != 255) + return 1; + } + else if (BaseTrueColor) + { + if (BasePixels[(((new[1]*BaseWidth) + new[0]) * 4) + 3] != 255) + return 1; + } + else + { +// pixel = BasePixels[(new[1]*BaseWidth) + new[0]]; + } + } + +nodraw: +// recursively continue + if (CheckTransRecursiveTri(lp3, lp1, new)) + return 1; + + return CheckTransRecursiveTri(lp3, new, lp2); +} + +static void ReplaceClusterIndex(int newIndex, int oldindex, int **clusters, + IntListNode_t **vertLists, int *num_verts, int *new_num_verts) +{ + int i, j; + IntListNode_t *next; + + for(j = 0; j < numJointsInSkeleton[g_skelModel.type]; ++j) + { + if(!clusters[j]) + { + continue; + } + + for(i = 0; i < num_verts[j+1]; ++i) + { + if(clusters[j][i] == oldindex) + { + ++new_num_verts[j+1]; + + next = vertLists[j]; + + vertLists[j] = (IntListNode_t *) SafeMalloc(sizeof(IntListNode_t), "ReplaceClusterIndex"); + // Currently freed in WriteJointedModelFile only + + vertLists[j]->data = newIndex; + vertLists[j]->next = next; + } + } + } +} + +#define FUDGE_EPSILON 0.002 + +qboolean VectorFudgeCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > FUDGE_EPSILON) + return false; + + return true; +} + +/* +================= +Cmd_Base +================= +*/ +void Cmd_FMBase (qboolean GetST) +{ + triangle_t *ptri, *st_tri; + int num_st_tris; + int i, j, k, l; + int x,y,z; +// int time1; + char file1[1024],file2[1024],trans_file[1024], stfile[1024], extension[256]; + vec3_t base_xyz[MAX_FM_VERTS]; + FILE *FH; + int pos,bit; + qboolean NewSkin; + + GetScriptToken (false); + + if (g_skipmodel || g_release || g_archive) + return; + + printf ("---------------------\n"); + sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext); + printf ("%s ", file1); + + ExpandPathAndArchive (file1); + + // Use the input filepath for this one. + sprintf (file1, "%s/%s", cddir, token); + +// time1 = FileTime (file1); +// if (time1 == -1) +// Error ("%s doesn't exist", file1); + +// +// load the base triangles +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); + else + LoadTriangleList (file1, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); + + if (g_ignoreTriUV) + { + for (i=0;i> 3; + bit = 1 << (i & 7 ); + if (!(pmnodes[l].tris[pos] & bit)) + { + continue; + } + + for (j=0 ; j<3 ; j++) + { + // get the xyz index + for (k=0 ; k> 3; + bit = 1 << (k & 7); + pmnodes[l].verts[pos] |= bit; + + triangles[i].index_xyz[j] = k; + + // get the st index + for (k=0 ; k= fmheader.num_mesh_nodes) + { + Error("Node '%s' not in base list!\n", token); + } + } + + free(pmnodes); + pmnodes = newnodes; +} + +//=============================================================== + +extern char *FindFrameFile (char *frame); + + +/* +=============== +GrabFrame +=============== +*/ +void GrabFrame (char *frame) +{ + triangle_t *ptri; + int i, j; + fmtrivert_t *ptrivert; + int num_tris; + char file1[1024]; + fmframe_t *fr; + int index_xyz; + char *framefile; + + // the frame 'run1' will be looked for as either + // run.1 or run1.tri, so the new alias sequence save + // feature an be used + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s ", file1); + + if (fmheader.num_frames >= MAX_FM_FRAMES) + Error ("fmheader.num_frames >= MAX_FM_FRAMES"); + fr = &g_frames[fmheader.num_frames]; + fmheader.num_frames++; + + strcpy (fr->name, frame); + +// +// load the frame +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &num_tris, NULL, NULL); + else + LoadTriangleList (file1, &ptri, &num_tris, NULL, NULL); + + if (num_tris != fmheader.num_tris) + Error ("%s: number of triangles (%d) doesn't match base frame (%d)\n", file1, num_tris, fmheader.num_tris); + +// +// allocate storage for the frame's vertices +// + ptrivert = fr->v; + + for (i=0 ; imins, fr->maxs); + +// +// store the frame's vertices in the same order as the base. This assumes the +// triangles and vertices in this frame are in exactly the same order as in the +// base +// + for (i=0 ; imins, fr->maxs); + + VectorAdd (ptrivert[index_xyz].vnorm.normalsum, normal, ptrivert[index_xyz].vnorm.normalsum); + ptrivert[index_xyz].vnorm.numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + free (ptri); +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_FMFrame (void) +{ + while (ScriptTokenAvailable()) + { + GetScriptToken (false); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + fmheader.num_frames = 1; // don't skip the writeout + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames); + + if((g_skelModel.type != SKEL_NULL) || (g_skelModel.references != REF_NULL)) + { + GrabModelTransform(token); + } + + GrabFrame (token); + + if(g_skelModel.type != SKEL_NULL) + { + GrabSkeletalFrame(token); + } + + if(g_skelModel.references != REF_NULL) + { + GrabReferencedFrame(token); + } + + // need to add the up and dir points to the frame bounds here + // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs); + // then remove fudge in determining scale on frame write out + } +} + +/* +=============== +Cmd_Skin + +Skins aren't actually stored in the file, only a reference +is saved out to the header file. +=============== +*/ +void Cmd_FMSkin (void) +{ + byte *palette; + byte *pixels; + int width, height; + byte *cropped; + int y; + char name[1024], savename[1024], transname[1024], extension[256]; + miptex32_t *qtex32; + int size; + FILE *FH; + qboolean TrueColor; + + GetScriptToken (false); + + if (fmheader.num_skins == MAX_FM_SKINS) + Error ("fmheader.num_skins == MAX_FM_SKINS"); + + if (g_skipmodel) + return; + + sprintf (name, "%s/%s", cdarchive, token); + strcpy (name, ExpandPathAndArchive( name ) ); +// sprintf (name, "%s/%s.lbm", cddir, token); + + if (ScriptTokenAvailable()) + { + GetScriptToken (false); + sprintf (g_skins[fmheader.num_skins], "!%s", token); + sprintf (savename, "%s!%s", g_outputDir, token); + sprintf (transname, "%s!%s_a.pcx", gamedir, token); + } + else + { + sprintf (g_skins[fmheader.num_skins], "%s/!%s", cdpartial, token); + sprintf (savename, "%s/!%s", g_outputDir, token); + sprintf (transname, "%s/!%s_a.pcx", cddir, token); + } + + fmheader.num_skins++; + + if (g_skipmodel || g_release || g_archive) + return; + + // load the image + printf ("loading %s\n", name); + ExtractFileExtension (name, extension); + if (extension[0] == 0) + { + strcat(name, ".pcx"); + } + + + TrueColor = LoadAnyImage (name, &pixels, &palette, &width, &height); +// RemapZero (pixels, palette, width, height); + + // crop it to the proper size + + if (!TrueColor) + { + cropped = (byte *) SafeMalloc (fmheader.skinwidth*fmheader.skinheight, "Cmd_FMSkin"); + for (y=0 ; y= 3); +// figure out the best plane projections + DOsvdPlane ((float*)vertices, num, (float *)&n, (float *)&base); + + if (DotProduct(aveNorm,n) < 0.0f) + { + VectorScale(n, -1.0f, n); + } + VectorNormalize(n,n); + if (fabs(n[2]) < .57) + { + CrossProduct( zaxis, n, crossvect); + VectorCopy(crossvect, u); + } + else + { + CrossProduct( yaxis, n, crossvect); + VectorCopy(crossvect, u); + } + VectorNormalize(u,u); + CrossProduct( n, u, crossvect); + VectorCopy(crossvect, v); + VectorNormalize(v,v); + + num = 0; + + for ( j = 0; j < 3; j++) + { + groupMin[j] = 1e30f; + groupMax[j] = -1e30f; + } + + for ( j = 0; j < numtris; j++) + { + for ( k = 0; k < 3; k++) + { + VectorCopy(grouptris[j].verts[k],v0); + VectorSubtract(v0, base, v0); + uvw[0] = DotProduct(v0, u); + uvw[1] = DotProduct(v0, v); + uvw[2] = DotProduct(v0, n); + VectorCopy(uvw,uvs[num]); + num++; + for ( l = 0; l < 3; l++) + { + if (uvw[l] < groupMin[l]) + { + groupMin[l] = uvw[l]; + } + if (uvw[l] > groupMax[l]) + { + groupMax[l] = uvw[l]; + } + } + } + } + + xwidth = ceil(0 - groupMin[0]) + 2; // move right of origin and avoid overlap + ywidth = ceil(0 - groupMin[1]) + 2; // move "above" origin + + for ( j=0; j < numverts; j++) + { + uFinal[finalcount] = uvs[j][0] + xwidth + xbase; + vFinal[finalcount] = uvs[j][1] + ywidth; + if (uFinal[finalcount] < uvwMin[0]) + { + uvwMin[0] = uFinal[finalcount]; + } + if (uFinal[finalcount] > uvwMax[0]) + { + uvwMax[0] = uFinal[finalcount]; + } + if (vFinal[finalcount] < uvwMin[1]) + { + uvwMin[1] = vFinal[finalcount]; + } + if (vFinal[finalcount] > uvwMax[1]) + { + uvwMax[1] = vFinal[finalcount]; + } + finalcount++; + } + + fprintf(grpfile,"svdPlaned Group min: ( %f , %f )\n",groupMin[0] + xwidth + xbase, groupMin[1] + ywidth); + fprintf(grpfile,"svdPlaned Group max: ( %f , %f )\n",groupMax[0] + xwidth + xbase, groupMax[1] + ywidth); + + finalcount = finalstart; + + for ( count = 0; count < numverts; count++) + { + fprintf(grpfile,"Vertex %d: ( %f , %f , %f )\n",count,vertices[count][0],vertices[count][1],vertices[count][2]); + fprintf(grpfile,"svdPlaned: ( %f , %f )\n",uFinal[finalcount],vFinal[finalcount++]); + } + + finalstart = finalcount; + + fprintf(grpfile,"\n"); + + free(vertices); + free(uvs); + free(grouptris); + + xbase += ceil(groupMax[0] - groupMin[0]) + 2; + + } + + fprintf(grpfile,"Global Min ( %f , %f )\n",uvwMin[0],uvwMin[1]); + fprintf(grpfile,"Global Max ( %f , %f )\n",uvwMax[0],uvwMax[1]); + + + ScaleTris(uvwMin, uvwMax, width, height, uFinal, vFinal, finalcount); + + for (k = 0; k < finalcount; k++) + { + fprintf(grpfile, "scaled vertex %d: ( %f , %f )\n",k,uFinal[k],vFinal[k]); + } + + // i've got the array of vertices in uFinal and vFinal. Now I need to write them and draw lines + + datasize = width * height*sizeof(unsigned char); + newpic = (unsigned char*)SafeMalloc(datasize, "NewGen"); + memset(newpic,0,datasize); + memset(pic_palette,0,sizeof(pic_palette)); + pic_palette[767] = pic_palette[766] = pic_palette[765] = 255; + + k = 0; + while (k < finalcount) + { + NewDrawLine(uFinal[k], vFinal[k], uFinal[k+1], vFinal[k+1], newpic, width, height); + k++; + NewDrawLine(uFinal[k], vFinal[k], uFinal[k+1], vFinal[k+1], newpic, width, height); + k++; + NewDrawLine(uFinal[k], vFinal[k], uFinal[k-2], vFinal[k-2], newpic, width, height); + k++; + fprintf(grpfile, "output tri with verts %d, %d, %d", k-2, k-1, k); + } + + WritePCXfile (OutputName, newpic, width, height, pic_palette); + + fclose(grpfile); + + free(todo); + free(done); + free(triangles); + free(newpic); + return; +} +void NewDrawLine(int x1, int y1, int x2, int y2, unsigned char* picture, int width, int height) +{ + long dx, dy; + long adx, ady; + long count; + float xfrac, yfrac, xstep, ystep; + unsigned long sx, sy; + float u, v; + + dx = x2 - x1; + dy = y2 - y1; + adx = abs(dx); + ady = abs(dy); + + count = adx > ady ? adx : ady; + count++; + + if(count > 300) + { + printf("Bad count\n"); + return; // don't ever hang up on bad data + } + + xfrac = x1; + yfrac = y1; + + xstep = (float)dx/count; + ystep = (float)dy/count; + + switch(LineType) + { + case LINE_NORMAL: + do + { + if(xfrac < width && yfrac < height) + { + picture[(long)yfrac*width+(long)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_FAT: + do + { + for (u=-0.1 ; u<=0.9 ; u+=0.999) + { + for (v=-0.1 ; v<=0.9 ; v+=0.999) + { + sx = xfrac+u; + sy = yfrac+v; + if(sx < width && sy < height) + { + picture[sy*width+sx] = LineColor; + } + } + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_DOTTED: + do + { + if(count&1 && xfrac < width && + yfrac < height) + { + picture[(long)yfrac*width+(long)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + default: + Error("Unknown %d.\n", LineType); + } +} +*/ +void ScaleTris( vec3_t min, vec3_t max, int Width, int Height, float* u, float* v, int verts) +{ + + int i; + float hscale, vscale; + float scale; + + hscale = max[0]; + vscale = max[1]; + + hscale = (Width-2) / max[0]; + vscale = (Height-2) / max[1]; + + scale = hscale; + if (scale > vscale) + { + scale = vscale; + } + for ( i = 0; i 32) + { + Error ("Degrees of freedom out of range: %d",groups[num_groups].degrees); + } +} + +void Cmd_FMEndGroup (void) +{ + groups[num_groups].num_frames = fmheader.num_frames - groups[num_groups].start_frame; + + if(num_groups < MAX_GROUPS - 1) + { + num_groups++; + } + else + { + Error("Number of compression groups exceded: %i\n", MAX_GROUPS); + } +} + diff --git a/tools/quake2/qdata_heretic2/icon1.ico b/tools/quake2/qdata_heretic2/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..8f44194128ade27ac79a97e16a0100032e36fc90 GIT binary patch literal 766 zcmeHFI|{-;6nqgu(pd?@f+;P%fgWvd5Zi#5t3)isDpyd_cmxB1aoz^9j}XKIIGcHI zCi6BwB9d@r*-{j*naGNLOJ?MOOk~a~;+ajuGi2g@-&iT7sw#F35Do!Ukz9I8%OBsr zKw1#TI73}TCn-&8V%1}BH-yYwVC=)J$<^yU2GH2Y(bUGn+>e6)z$7~7E-l|Y@KoH} k^ZKc}bGs|b7CqzE#{#(RfxKj-tRrjcItQ8!@aBxg2Lb$&{Qv*} literal 0 HcmV?d00001 diff --git a/tools/quake2/qdata_heretic2/images.c b/tools/quake2/qdata_heretic2/images.c new file mode 100644 index 00000000..bdc8ba50 --- /dev/null +++ b/tools/quake2/qdata_heretic2/images.c @@ -0,0 +1,1397 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qdata.h" + +#ifdef _WIN32 + #include +#endif + +#include + +#if 1 + extern char *g_outputDir; +#endif // _QDATA + +char mip_prefix[1024]; // directory to dump the textures in + +qboolean colormap_issued; +byte colormap_palette[768]; + +unsigned total_x = 0; +unsigned total_y = 0; +unsigned total_textures = 0; + +#define MAX_IMAGE_SIZE 512 + +#if 0 +/* +============== +RemapZero + +Replaces all 0 bytes in an image with the closest palette entry. +This is because NT won't let us change index 0, so any palette +animation leaves those pixels untouched. +============== +*/ +void RemapZero (byte *pixels, byte *palette, int width, int height) +{ + int i, c; + int alt_zero; + int value, best; + + alt_zero = 0; + best = 9999999; + for (i=1 ; i<255 ; i++) + { + value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2]; + if (value < best) + { + best = value; + alt_zero = i; + } + } + + c = width*height; + for (i=0 ; i> 16; + palette_g[i] = (palette[i] & 0x0000ff00) >> 8; + palette_b[i] = (palette[i] & 0x000000ff); + } + + for(i=0;i biggest_delta) + continue; + dg = abs(palette_g[i] - g); + if (dg > biggest_delta) + continue; + db = abs(palette_b[i] - b); + if (db > biggest_delta) + continue; + + dist = dr * dr + dg * dg + db * db; + if (dist < min_dist) + { + min_dist = dist; + min_index = i; + if (min_dist == 0) break; + + dist = dr; + if (dg > dist) dist = dg; + if (db > dist) dist = db; + if (dist < biggest_delta) + biggest_delta = dist; + } + } + + last_place++; + if (last_place >= MAX_LAST) + last_place = 0; + + last_r[last_place] = r; + last_g[last_place] = g; + last_b[last_place] = b; + last_i[last_place] = min_index; + + return min_index; +} + + +void GL_ResampleTexture8P (byte *in, int inwidth, int inheight, byte *out, + int outwidth, int outheight, palette_t *palette) +{ + int i, j; + byte *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[1024], p2[1024], *p1p, *p2p; + palette_t *c1,*c2,*c3,*c4; + unsigned r,g,b; + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for (i=0 ; i>16; + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i>16; + frac += fracstep; + } + + cached = 0; + + for (i=0 ; ir + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r)>>2; + g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g)>>2; + b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b)>>2; + + *out++ = ConvertTrueColorToPal(r,g,b); + } + } +} + +void GL_MipMap8P(byte *out, byte *in, int width, int height, palette_t *palette) +{ + int i, j; + palette_t *c1,*c2,*c3,*c4; + unsigned r,g,b; + + cached = 0; + memset(out, 0, 256 * 256); + width <<= 1; + height <<= 1; + + for (i = 0; i < height; i += 2, in += width) + { + for (j = 0; j < width; j += 2) + { + c1 = &palette[in[0]]; + c3 = &palette[in[width]]; + in++; + c2 = &palette[in[0]]; + c4 = &palette[in[width]]; + in++; + + r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r) >> 2; + g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g) >> 2; + b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b) >> 2; + + *out++ = ConvertTrueColorToPal(r, g, b); + } + } +} + + +miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip) +{ + int scaled_width, scaled_height; + int i,j,r,g,b; + byte intensitytable[256]; + byte scaled[256*256]; + byte out[256*256]; + int miplevel; + miptex_t *mp; + byte *pos; + int size; + + for (i=0 ; i<256 ; i++) + { + j = i * intensity_value; + if (j > 255) + j = 255; + intensitytable[i] = j; + } + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + if (1 && scaled_width > width && 1) + scaled_width >>= 1; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if (1 && scaled_height > height && 1) + scaled_height >>= 1; + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + size = sizeof(*mp) + (scaled_width*scaled_height*3); + mp = (miptex_t *)SafeMalloc(size, "CreateMip"); + memset(mp,0,size); + + mp->version = MIP_VERSION; + + for(i=j=0;i<256;i++,j+=3) + { + mp->palette[i].r = r = intensitytable[palette[j]]; + mp->palette[i].g = g = intensitytable[palette[j+1]]; + mp->palette[i].b = b = intensitytable[palette[j+2]]; + image_pal[i] = 0xff000000 | (r<<16) | (g<<8) | (b); + } + + PrepareConvert(image_pal); + + if (scaled_width == width && scaled_height == height) + { + memcpy (scaled, data, width*height); + } + else + GL_ResampleTexture8P (data, width, height, scaled, scaled_width, scaled_height, mp->palette); + + pos = (byte *)(mp + 1); + miplevel = 0; + + while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip)) + { + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + if(miplevel > 0) + GL_MipMap8P(out, (byte *)scaled, scaled_width, scaled_height, mp->palette); + else + memcpy(out, scaled, 256 * 256); + + mp->width[miplevel] = scaled_width; + mp->height[miplevel] = scaled_height; + mp->offsets[miplevel] = pos - ((byte *)(mp)); + memcpy(pos, out, scaled_width * scaled_height); + memcpy(scaled, out, 256 * 256); + pos += scaled_width * scaled_height; + + scaled_width >>= 1; + scaled_height >>= 1; + + miplevel++; + } + + *FinalSize = pos - ((byte *)(mp)); + + return mp; +} + + +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) +{ + int i, j; + unsigned *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[1024], p2[1024]; + byte *pix1, *pix2, *pix3, *pix4; + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for (i=0 ; i>16); + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i>16); + frac += fracstep; + } + + for (i=0 ; i> 1; + for (j=0 ; j>2; + ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; + ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; + ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; + } + } +} + +void GL_MipMap (byte *out, byte *in, int width, int height) +{ + int i, j; + + width <<=3; + height <<= 1; + for (i=0 ; i>2; + out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; + out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; + out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; + } + } +} + +miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip) +{ + int scaled_width, scaled_height; + unsigned scaled[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE]; + unsigned out[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE]; + int miplevel; + miptex32_t *mp; + byte *pos; + int size; + paletteRGBA_t *test; + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + if (1 && scaled_width > width && 1) + scaled_width >>= 1; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if (1 && scaled_height > height && 1) + scaled_height >>= 1; + + // don't ever bother with >256 textures + if (scaled_width > MAX_IMAGE_SIZE) + scaled_width = MAX_IMAGE_SIZE; + if (scaled_height > MAX_IMAGE_SIZE) + scaled_height = MAX_IMAGE_SIZE; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + size = sizeof(*mp) + (scaled_width*scaled_height*3*4); + mp = (miptex32_t *)SafeMalloc(size, "CreateMip"); + memset(mp,0,size); + + mp->version = MIP32_VERSION; + + size = width*height; + test = (paletteRGBA_t *)data; + while(size) + { + if (test->a != 255) + { + mp->flags |= LittleLong(SURF_ALPHA_TEXTURE); + break; + } + + size--; + test++; + } + + if (scaled_width == width && scaled_height == height) + { + memcpy (scaled, data, width*height*4); + } + else + GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); + + pos = (byte *)(mp + 1); + miplevel = 0; + + while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip)) + { + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + if (miplevel > 0) + { + GL_MipMap((byte *)out, (byte *)scaled, scaled_width, scaled_height); + } + else + { + memcpy(out, scaled, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4); + } + + mp->width[miplevel] = scaled_width; + mp->height[miplevel] = scaled_height; + mp->offsets[miplevel] = pos - ((byte *)(mp)); + memcpy(pos, out, scaled_width * scaled_height * 4); + memcpy(scaled, out, MAX_IMAGE_SIZE * MAX_IMAGE_SIZE * 4); + pos += scaled_width * scaled_height * 4; + + scaled_width >>= 1; + scaled_height >>= 1; + + miplevel++; + } + + *FinalSize = pos - ((byte *)(mp)); + + return mp; +} + +/* +============== +Cmd_Grab + +$grab filename x y width height +============== +*/ +void Cmd_Grab (void) +{ + int xl,yl,w,h,y; + byte *cropped; + char savename[1024]; + char dest[1024]; + + GetScriptToken (false); + + if (token[0] == '/' || token[0] == '\\') + sprintf (savename, "%s%s.pcx", gamedir, token+1); + else + sprintf (savename, "%spics/%s.pcx", gamedir, token); + + if (g_release) + { + if (token[0] == '/' || token[0] == '\\') + sprintf (dest, "%s.pcx", token+1); + else + sprintf (dest, "pics/%s.pcx", token); + + ReleaseFile (dest); + return; + } + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = (byte *) SafeMalloc (w*h, "Cmd_Grab"); + for (y=0 ; ybyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = (byte *) SafeMalloc (w*h, "Cmd_Raw"); + for (y=0 ; y 255) + r = 255; + if (r < 0) + r = 0; + if (g > 255) + g = 255; + if (g < 0) + g = 0; + if (b > 255) + b = 255; + if (b < 0) + b = 0; +#ifndef TABLECOLORS + bestcolor = BestColor (r, g, b, 0, 254); +#else + bestcolor = palmap[r>>3][g>>3][b>>3]; +#endif + + return bestcolor; +} + + +void BuildPalmap (void) +{ +#ifdef TABLECOLORS + int r, g, b; + int bestcolor; + + if (palmap_built) + return; + palmap_built = true; + + for (r=4 ; r<256 ; r+=8) + { + for (g=4 ; g<256 ; g+=8) + { + for (b=4 ; b<256 ; b+=8) + { + bestcolor = BestColor (r, g, b, 1, 254); + palmap[r>>3][g>>3][b>>3] = bestcolor; + } + } + } +#endif + + if (!colormap_issued) + Error ("You must issue a $colormap command first"); + +} + +/* +============= +AveragePixels +============= +*/ +byte AveragePixels (int count) +{ + int r,g,b; + int i; + int vis; + int pix; + int bestcolor; + byte *pal; + int fullbright; + + vis = 0; + r = g = b = 0; + fullbright = 0; + for (i=0 ; i +must be multiples of sixteen +SURF_WINDOW +============== +*/ + +void Cmd_Mip (void) +{ + int xl,yl,xh,yh,w,h; + byte *dest, *source; + int flags, value, contents; + mipparm_t *mp; + char lumpname[128]; + char altname[128]; + char animname[128]; + char damagename[128]; + byte buffer[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE]; + unsigned bufferl[MAX_IMAGE_SIZE*MAX_IMAGE_SIZE]; + materialtype_t *mat; + char filename[1024]; + unsigned *destl, *sourcel; + int linedelta, x, y; + int size; + miptex_t *qtex; + miptex32_t *qtex32; + float scale_x, scale_y; + int mip_scale; + // detail texturing + char dt_name[128]; + float dt_scale_x, dt_scale_y; + float dt_u, dt_v; + float dt_alpha; + int dt_src_blend_mode, dt_dst_blend_mode; + int flags2; + + + GetScriptToken (false); + strcpy (lumpname, token); + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + total_x += w; + total_y += h; + total_textures++; + + if ( (w & 15) || (h & 15) ) + Error ("line %i: miptex sizes must be multiples of 16", scriptline); + + flags = 0; + flags2 = 0; + contents = 0; + value = 0; + mip_scale = 0; + + altname[0] = animname[0] = damagename[0] = 0; + + scale_x = scale_y = 0.5; + + // detail texturing + dt_name[0] = 0; + dt_scale_x = dt_scale_y = 0.0; + dt_u = dt_v = 0.0; + dt_alpha = 0.0; + dt_src_blend_mode = dt_dst_blend_mode = 0; + + // get optional flags and values + while (ScriptTokenAvailable ()) + { + GetScriptToken (false); + + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + switch (mp->type) + { + case pt_animvalue: + GetScriptToken (false); // specify the next animation frame + strcpy (animname, token); + break; + case pt_altnamevalue: + GetScriptToken (false); // specify the alternate texture + strcpy (altname, token); + break; + case pt_damagenamevalue: + GetScriptToken (false); // specify the damage texture + strcpy (damagename, token); + break; + case pt_flags: + flags |= mp->flags; + break; + case pt_contents: + contents |= mp->flags; + break; + case pt_flagvalue: + flags |= mp->flags; + GetScriptToken (false); // specify the light value + value = atoi(token); + break; + case pt_materialvalue: + GetScriptToken(false); + for (mat=materialtypes ; mat->name ; mat++) + { + if (!strcmp(mat->name, token)) + { + // assumes SURF_MATERIAL is in top 8 bits + flags = (flags & 0x0FFFFFF) | (mat->value << 24); + break; + } + } + break; + case pt_scale: + GetScriptToken (false); // specify the x scale + scale_x = atof(token); + GetScriptToken (false); // specify the y scale + scale_y = atof(token); + break; + + case pt_mip: + mip_scale = 1; + break; + + case pt_detailer: + flags2 |= MIP32_DETAILER_FLAG2; + break; + + case pt_nomip: + flags2 |= MIP32_NOMIP_FLAG2; + break; + + case pt_detail: + GetScriptToken(false); + strcpy(dt_name, token); + GetScriptToken(false); + dt_scale_x = atof(token); + GetScriptToken(false); + dt_scale_y = atof(token); + GetScriptToken(false); + dt_u = atof(token); + GetScriptToken(false); + dt_v = atof(token); + GetScriptToken(false); + dt_alpha = atof(token); + GetScriptToken(false); + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + if (mp->type == pt_gl) + { + dt_src_blend_mode = mp->flags; + break; + } + } + } + if (!mp->name) + { + Error ("line %i: invalid gl blend mode %s", scriptline, token); + } + GetScriptToken (false); + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + if (mp->type == pt_gl) + { + dt_dst_blend_mode = mp->flags; + break; + } + } + } + if (!mp->name) + { + Error ("line %i: invalid gl blend mode %s", scriptline, token); + } + break; + } + break; + } + } + if (!mp->name) + Error ("line %i: unknown parm %s", scriptline, token); + } + + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + if (xh*yh > MAX_IMAGE_SIZE*MAX_IMAGE_SIZE) + { + Error("line %i image %s: image is too big!", scriptline, lumpname); + } + + if (TrueColorImage) + { + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i image %s: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, lumpname, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl*longimagewidth) + xl; + destl = bufferl; + linedelta = (longimagewidth - w); + + for (y=yl ; yflags |= LittleLong(flags); + qtex32->flags2 |= LittleLong(flags2); + qtex32->contents = LittleLong(contents); + qtex32->value = LittleLong(value); + qtex32->scale_x = scale_x; + qtex32->scale_y = scale_y; + qtex32->mip_scale = mip_scale; + sprintf (qtex32->name, "%s/%s", mip_prefix, lumpname); + if (animname[0]) + { + sprintf (qtex32->animname, "%s/%s", mip_prefix, animname); + } + if (altname[0]) + { + sprintf (qtex32->altname, "%s/%s", mip_prefix, altname); + } + if (damagename[0]) + { + sprintf (qtex32->damagename, "%s/%s", mip_prefix, damagename); + } + if (dt_name[0] & ((flags2 & MIP32_DETAILER_FLAG2) == 0)) + { + sprintf (qtex32->dt_name, "%s/%s", mip_prefix, dt_name); + qtex32->dt_scale_x = dt_scale_x; + qtex32->dt_scale_y = dt_scale_y; + qtex32->dt_u = dt_u; + qtex32->dt_v = dt_v; + qtex32->dt_alpha = dt_alpha; + qtex32->dt_src_blend_mode = dt_src_blend_mode; + qtex32->dt_dst_blend_mode = dt_dst_blend_mode; + } + + // + // write it out + // + sprintf (filename, "%stextures/%s/%s.m32", g_outputDir, mip_prefix, lumpname); + if(qtex32->flags & (SURF_ALPHA_TEXTURE)) + printf ("writing %s with ALPHA\n", filename); + else + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + else + { + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + source = byteimage + yl*byteimagewidth + xl; + dest = buffer; + linedelta = byteimagewidth - w; + + for (y=yl ; yflags = LittleLong(flags); + qtex->contents = LittleLong(contents); + qtex->value = LittleLong(value); + sprintf (qtex->name, "%s/%s", mip_prefix, lumpname); + if (animname[0]) + sprintf (qtex->animname, "%s/%s", mip_prefix, animname); + + // + // write it out + // + sprintf (filename, "%stextures/%s/%s.m8", g_outputDir, mip_prefix, lumpname); + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } +} + +/* +=============== +Cmd_Mippal +=============== +*/ +void Cmd_Mippal (void) +{ + colormap_issued = true; + if (g_release) + return; + + memcpy (colormap_palette, lbmpalette, 768); + + BuildPalmap(); +} + + +/* +=============== +Cmd_Mipdir +=============== +*/ +void Cmd_Mipdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (mip_prefix, token); + // create the directory if needed + sprintf (filename, "%stextures", g_outputDir); + Q_mkdir (filename); + sprintf (filename, "%stextures/%s", g_outputDir, mip_prefix); + Q_mkdir (filename); +} + + +/* +============================================================================= + +ENVIRONMENT MAP GRABBING + +Creates six pcx files from tga files without any palette edge seams +also copies the tga files for GL rendering. +============================================================================= +*/ + +// 3dstudio environment map suffixes +char *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"}; + +/* +================= +Cmd_Environment +================= +*/ +void Cmd_Environment (void) +{ + char name[1024]; + int i, x, y; + byte image[256*256]; + byte *tga; + + GetScriptToken (false); + + if (g_release) + { + for (i=0 ; i<6 ; i++) + { + sprintf (name, "env/%s%s.pcx", token, suf[i]); + ReleaseFile (name); + sprintf (name, "env/%s%s.tga", token, suf[i]); + ReleaseFile (name); + } + return; + } + // get the palette + BuildPalmap (); + + sprintf (name, "%senv/", gamedir); + CreatePath (name); + + // convert the images + for (i=0 ; i<6 ; i++) + { + sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]); + printf ("loading %s...\n", name); + LoadTGA (name, &tga, NULL, NULL); + + for (y=0 ; y<256 ; y++) + { + for (x=0 ; x<256 ; x++) + { + image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]); + } + } + free (tga); + sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]); + if (FileTime (name) != -1) + printf ("%s already exists, not overwriting.\n", name); + else + WritePCXfile (name, image, 256, 256, colormap_palette); + } +} + diff --git a/tools/quake2/qdata_heretic2/jointed.c b/tools/quake2/qdata_heretic2/jointed.c new file mode 100644 index 00000000..09b963f6 --- /dev/null +++ b/tools/quake2/qdata_heretic2/jointed.c @@ -0,0 +1,572 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "token.h" +#include "joints.h" +#include "angles.h" +#include "inout.h" + +char *SKEL_ROOT_NAMES[] = +{ + "RAVEN_SPINE" +}; + +char *SKEL_NAMES[] = +{ + "RAVEN_WAIST1", + "RAVEN_WAIST2", + "RAVEN_NECK" +}; + +int NAME_OFFSETS[] = +{ + 0 +}; + +int numJointsForSkeleton[] = +{ + NUM_JOINTS_RAVEN, + NUM_JOINTS_BOX +}; + +float g_scaling[3]; +float g_rotation[3]; +float g_translation[3]; + +//========================================================================== +// +// LoadHRCClustered +// +//========================================================================== + +static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + int i, j; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_CLUSTERS); + + while(TK_Search(TK_CLUSTER_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + for( i = 0; i < numJointsForSkeleton[skelType]; ++i) + { + if(stricmp(tk_String, SKEL_NAMES[NAME_OFFSETS[skelType]+i]) == 0) + { + i = -i + numJointsForSkeleton[skelType] - 1; + + TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER); + + num_verts[i+1] = tk_IntNumber; + + clusterList[i] = (int *) SafeMalloc(num_verts[i+1]*sizeof(int), "LoadHRCClustered"); + assert(clusterList[i]); + // currently this function is only called by LoadTriangleListClustered, which in turn is only + // called by Cmd_Base in qdata. This is where the only call to free for this memory is being made. + + TK_Beyond(TK_LBRACE); + + for(j = 0; j < num_verts[i+1]; ++j) + { + TK_Require(TK_INTNUMBER); + clusterList[i][j] = tk_IntNumber; + TK_Fetch(); + } + + break; + } + } + } + + num_verts[0] = numJointsForSkeleton[skelType]; +} + +static void LoadHRCGlobals(char *fileName) +{ + int i; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + TK_Beyond(TK_MODEL); + + TK_Beyond(TK_SCALING); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_scaling[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_ROTATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_rotation[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_TRANSLATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_translation[i] = tk_FloatNumber; + TK_Fetch(); + } +} + +static void ParseVec3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseRotation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = -tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseTranslation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void LoadHRCJointList(char *fileName, QDataJoint_t *jointList, int skelType) +{ +#define MAX_STACK 64 + int i, j; + vec3_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK]; + int curCorrespondingJoint[MAX_STACK]; + int currentStack = 0, stackSize; + int baseJoint; + float cx, sx, cy, sy, cz, sz; + float rx, ry, rz; + float x2, y2, z2; + + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_MODEL); + TK_Beyond(TK_MODEL); + +/* while(1) + { + TK_Beyond(TK_MODEL); + TK_BeyondRequire(TK_NAME, TK_STRING); + + if(_stricmp(tk_String, SKEL_ROOT_NAMES[skelType]) == 0) + break; + }*/ + + TK_Beyond(TK_SCALING); + + ParseVec3(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3(curTranslation[currentStack]); + + // account for global model translation + curTranslation[currentStack][1] += g_translation[0]; + curTranslation[currentStack][2] += g_translation[1]; + curTranslation[currentStack][0] += g_translation[2]; + + ++currentStack; + + for(i = 0; i < NUM_JOINTS_RAVEN; ++i) + { + while(1) + { + TK_Beyond(TK_MODEL); + +// TK_BeyondRequire(TK_NAME, TK_STRING); + +// if(_stricmp(tk_String, SKEL_NAMES[NAME_OFFSETS[skelType]+i]) == 0) + break; + + TK_Beyond(TK_SCALING); + + ParseVec3(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3(curTranslation[currentStack]); + + curCorrespondingJoint[currentStack] = -1; + + ++currentStack; + } + + TK_Beyond(TK_SCALING); + + ParseVec3(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3(curRotation[currentStack]); + + jointList[i].rotation[1] = curRotation[currentStack][1]; + jointList[i].rotation[2] = curRotation[currentStack][2]; + jointList[i].rotation[0] = curRotation[currentStack][0]; + + TK_Beyond(TK_TRANSLATION); + + ParseVec3(curTranslation[currentStack]); + + jointList[i].placement.origin[1] = curTranslation[currentStack][1]; + jointList[i].placement.origin[2] = curTranslation[currentStack][2]; + jointList[i].placement.origin[0] = curTranslation[currentStack][0]; + + jointList[i].placement.direction[1] = 7.5; + jointList[i].placement.direction[2] = 0.0; + jointList[i].placement.direction[0] = 0.0; + + jointList[i].placement.up[1] = 0.0; + jointList[i].placement.up[2] = 7.5; + jointList[i].placement.up[0] = 0.0; + + curCorrespondingJoint[currentStack] = i; + + ++currentStack; + } + + stackSize = currentStack; + + for(i = 0; i < NUM_JOINTS_RAVEN; ++i) + { + rx = jointList[i].rotation[0]*ANGLE_TO_RAD; + ry = jointList[i].rotation[1]*ANGLE_TO_RAD; + rz = jointList[i].rotation[2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + // y-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy; + z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy; + z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[2] = z2; + + // z-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz; + y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz; + y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[1] = y2; + + // x-axis rotation for direction vector + y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx; + z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx; + jointList[i].placement.direction[1] = y2; + jointList[i].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx; + z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx; + jointList[i].placement.up[1] = y2; + jointList[i].placement.up[2] = z2; + + // translate to position in model + jointList[i].placement.direction[0] += jointList[i].placement.origin[0]; + jointList[i].placement.direction[1] += jointList[i].placement.origin[1]; + jointList[i].placement.direction[2] += jointList[i].placement.origin[2]; + + // translate to position in model + jointList[i].placement.up[0] += jointList[i].placement.origin[0]; + jointList[i].placement.up[1] += jointList[i].placement.origin[1]; + jointList[i].placement.up[2] += jointList[i].placement.origin[2]; + } + + baseJoint = NUM_JOINTS_RAVEN; + + for(i = stackSize/*NUM_JOINTS_RAVEN*/ - 1; i > 0; --i) + { + + rx = curRotation[i-1][0]*ANGLE_TO_RAD; + ry = curRotation[i-1][1]*ANGLE_TO_RAD; + rz = curRotation[i-1][2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + for(j = i-1; j < stackSize-1; ++j) + { + // y-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy; + z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[2] = z2; + + // y-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy; + z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy; + z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[2] = z2; + + // z-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz; + y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[1] = y2; + + // z-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz; + y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz; + y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[1] = y2; + + // x-axis rotation for origin + y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx; + z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx; + jointList[j].placement.origin[1] = y2; + jointList[j].placement.origin[2] = z2; + + // x-axis rotation for direction vector + y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx; + z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx; + jointList[j].placement.direction[1] = y2; + jointList[j].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx; + z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx; + jointList[j].placement.up[1] = y2; + jointList[j].placement.up[2] = z2; + + if(curCorrespondingJoint[j+1] != -1) + { + // translate origin + jointList[j].placement.origin[0] += curTranslation[i-1][0]; + jointList[j].placement.origin[1] += curTranslation[i-1][1]; + jointList[j].placement.origin[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.direction[0] += curTranslation[i-1][0]; + jointList[j].placement.direction[1] += curTranslation[i-1][1]; + jointList[j].placement.direction[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.up[0] += curTranslation[i-1][0]; + jointList[j].placement.up[1] += curTranslation[i-1][1]; + jointList[j].placement.up[2] += curTranslation[i-1][2]; + } + } + } +} + +void LoadGlobals(char *fileName) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCGlobals(InputFileName); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCGlobals(fileName); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadClusters(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCClustered(InputFileName, clusterList, num_verts, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCClustered(fileName, clusterList, num_verts, skelType); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadJointList(char *fileName, QDataJoint_t *jointList, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCJointList(InputFileName, jointList, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCJointList(fileName, jointList, skelType); + + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + diff --git a/tools/quake2/qdata_heretic2/jointed.h b/tools/quake2/qdata_heretic2/jointed.h new file mode 100644 index 00000000..6907a2d8 --- /dev/null +++ b/tools/quake2/qdata_heretic2/jointed.h @@ -0,0 +1,35 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _JOINTED_H +#define _JOINTED_H + +#include "joints.h" + +void LoadGlobals(char *fileName); +void LoadClusters(char *fileName, int **clusterList, int *num_verts, int skel_type); +void LoadJointList(char *fileName, struct QDataJoint_s *jointList, int num_verts); + +#define NUM_CLUSTERS 8 + +#define NOT_JOINTED -1 + +#endif //_JOINTED_H diff --git a/tools/quake2/qdata_heretic2/joints.h b/tools/quake2/qdata_heretic2/joints.h new file mode 100644 index 00000000..e489114e --- /dev/null +++ b/tools/quake2/qdata_heretic2/joints.h @@ -0,0 +1,144 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef JOINTS_H +#define JOINTS_H + +#ifdef _HERETIC2_ +#include "angles.h" +#endif + +//typedef float vec3_t[3]; +//typedef unsigned char byte; + +#ifndef _WIN32 +#define stricmp strcasecmp +#define strcmpi strcasecmp +#endif + +typedef struct Placement_s +{ + vec3_t origin; + vec3_t direction; + vec3_t up; +} Placement_t; + +#if 1 +typedef struct QDataJoint_s +{ + Placement_t placement; + vec3_t rotation; +} QDataJoint_t; +#endif + +typedef struct ArrayedListNode_s +{ + int data; + int next; + int inUse; +} ArrayedListNode_t; + +#define ARRAYEDLISTNODE_NULL -1 + +typedef struct JointAngles_s +{ + float angles[3]; + int children; + int created; +} JointAngles_t; + +typedef struct JointAngles2_s +{ + float angles[3]; + int children; + int changed[3]; + int inUse; +} JointAngles2_t; + +#define MAX_MODELJOINTS 256 +#define MAX_MODELJOINTNODES 255 + +extern JointAngles_t jointAngles[MAX_MODELJOINTS]; +extern JointAngles2_t jointAngles2[MAX_MODELJOINTS]; + +extern ArrayedListNode_t jointAngleNodes[MAX_MODELJOINTNODES]; + +// Skeletal structures enums +enum { + SKEL_RAVEN = 0, + SKEL_BOX, + NUM_SKELETONS +}; + +// Raven Skeletal structures enums +enum { + RAVEN_WAIST1 = 0, + RAVEN_WAIST2 = 1, + RAVEN_HEAD = 2, + NUM_JOINTS_RAVEN +}; + +// Box Skeletal structures enums +enum { + BOX_CENTER = 0, + NUM_JOINTS_BOX +}; + +extern int numJointsForSkeleton[]; +extern char *RAVEN_SKEL_NAMES[]; + +#define J_NEW_SKELETON 0x00001000 +#define J_YAW_CHANGED 0x00002000 +#define J_PITCH_CHANGED 0x00004000 +#define J_ROLL_CHANGED 0x00008000 +#define MAX_JOINTS 0x00000fff +/* +inline int GetFreeNode(ArrayedListNode_t *nodeArray, int max) +{ // yeah, I know this is a sucky, inefficient way to do this, but I didn't feel like taking the time to write a real resource manager in C + int i; + + for(i = 0; i < max; ++i) + { + if(!nodeArray[i].inUse) + { + nodeArray[i].inUse = 1; + return i; + } + } + + assert(0); + return -1; +} + +inline void FreeNode(ArrayedListNode_t *nodeArray, int index) +{ + nodeArray[index].inUse = 0; +} +*/ +int CreateSkeleton(int structure); +void CreateSkeletonAtIndex(int structure, int index); +void FreeSkeleton(int structure, int index); +void SetJointAngle(int jointIndex, int angleIndex, float angle); +float ModifyJointAngle(int jointIndex, int angleIndex, float deltaAngle); +int ZeroJointAngle(int jointIndex, int angleIndex, float angVel); +int ApplyAngVelToJoint(int jointIndex, int angleIndex, float angVel, float destAng); + +#endif diff --git a/tools/quake2/qdata_heretic2/models.c b/tools/quake2/qdata_heretic2/models.c new file mode 100644 index 00000000..d594cafe --- /dev/null +++ b/tools/quake2/qdata_heretic2/models.c @@ -0,0 +1,2050 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "qdata.h" +#include +#include "jointed.h" +#include "fmodel.h" + +//================================================================= + +typedef struct +{ + int numnormals; + vec3_t normalsum; +} vertexnormals_t; + +typedef struct +{ + vec3_t v; + int lightnormalindex; +} trivert_t; + +typedef struct +{ + vec3_t mins, maxs; + char name[16]; + trivert_t v[MAX_VERTS]; + QDataJoint_t joints[NUM_CLUSTERS]; // ,this +} frame_t; + +// ,and all of this should get out of here, need to use new stuff in fmodels instead + +typedef struct IntListNode_s +{ + int data; + struct IntListNode_s *next; +} IntListNode_t; // gaak + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this +} PartialAliasFrame_t; + +int jointed; +int clustered; + +int *clusters[NUM_CLUSTERS]; +IntListNode_t *vertLists[NUM_CLUSTERS]; +int num_verts[NUM_CLUSTERS + 1]; +int new_num_verts[NUM_CLUSTERS + 1]; + +// end that + +//================================================================ + +frame_t g_frames[MAX_FRAMES]; +//frame_t *g_frames; + +static dmdl_t model; + + +float scale_up; // set by $scale +vec3_t adjust; // set by $origin +int g_fixedwidth, g_fixedheight; // set by $skinsize + + +// +// base frame info +// +dstvert_t base_st[MAX_VERTS]; +dtriangle_t triangles[MAX_TRIANGLES]; + +static int triangle_st[MAX_TRIANGLES][3][2]; + +// the command list holds counts, s/t values, and xyz indexes +// that are valid for every frame +int commands[16384]; +int numcommands; +int numglverts; +int used[MAX_TRIANGLES]; + +char g_skins[MAX_MD2SKINS][64]; + +char cdarchive[1024]; +char cdpartial[1024]; +char cddir[1024]; + +char modelname[64]; // empty unless $modelname issued (players) + +extern char *g_outputDir; + +#define NUMVERTEXNORMALS 162 + +float avertexnormals[NUMVERTEXNORMALS][3] = +{ + #include "anorms.h" +}; + +unsigned char pic[SKINPAGE_HEIGHT*SKINPAGE_WIDTH], pic_palette[768]; + +FILE *headerouthandle = NULL; + +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +static void ClearModel (void) +{ + memset (&model, 0, sizeof(model)); + + modelname[0] = 0; + jointed = NOT_JOINTED; + clustered = 0; + scale_up = 1.0; + VectorCopy (vec3_origin, adjust); + g_fixedwidth = g_fixedheight = 0; + g_skipmodel = false; +} + + +void H_printf(char *fmt, ...) +{ + va_list argptr; + char name[1024]; + + if (!headerouthandle) + { + sprintf (name, "%s/tris.h", cddir); + headerouthandle = SafeOpenWrite (name); + fprintf(headerouthandle, "// %s\n\n", cddir); + fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n"); + } + + va_start (argptr, fmt); + vfprintf (headerouthandle, fmt, argptr); + va_end (argptr); +} + +#if 1 +/* +============ +WriteModelFile +============ +*/ +void WriteCommonModelFile (FILE *modelouthandle, PartialAliasFrame_t *outFrames) +{ + int i; + dmdl_t modeltemp; + int j, k; + frame_t *in; + daliasframe_t *out; + byte buffer[MAX_VERTS*4+128]; + float v; + int c_on, c_off; + + model.version = ALIAS_VERSION; + model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; + model.num_glcmds = numcommands; + model.ofs_skins = sizeof(dmdl_t); + model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; + model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); + model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); + model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; + model.ofs_end = model.ofs_glcmds + model.num_glcmds*sizeof(int); + // + // write out the model header + // + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + + if(outFrames) + { + outFrames[i].scale[j] = out->scale[j]; + outFrames[i].translate[j] = out->translate[j]; + } + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, model.framesize); + } + + // + // write out glcmds + // + SafeWrite (modelouthandle, commands, numcommands*4); +} + +/* +============ +WriteModelFile +============ +*/ +void WriteModelFile (FILE *modelouthandle) +{ + model.ident = IDALIASHEADER; + + WriteCommonModelFile(modelouthandle, NULL); +} + +/* +============ +WriteJointedModelFile +============ +*/ +void WriteJointedModelFile (FILE *modelouthandle) +{ + int i; + int j, k; + frame_t *in; + float v; + IntListNode_t *current, *toFree; + PartialAliasFrame_t outFrames[MAX_FRAMES]; + + model.ident = IDJOINTEDALIASHEADER; + + WriteCommonModelFile(modelouthandle, outFrames); + + // Skeletal Type + SafeWrite(modelouthandle, &jointed, sizeof(int)); + + // number of joints + SafeWrite(modelouthandle, &numJointsForSkeleton[jointed], sizeof(int)); + + // number of verts in each cluster + SafeWrite(modelouthandle, &new_num_verts[1], sizeof(int)*numJointsForSkeleton[jointed]); + + // cluster verts + for(i = 0; i < new_num_verts[0]; ++i) + { + current = vertLists[i]; + while(current) + { + SafeWrite (modelouthandle, ¤t->data, sizeof(int)); + toFree = current; + current = current->next; + free(toFree); // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base + } + } + + for (i=0 ; ijoints[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + { + v = 255.0; + } + + if (v < 0) + { + v = 0; + } + + // write out origin as a float (there's only a few per model, so it's not really + // a size issue) + SafeWrite (modelouthandle, &v, sizeof(float)); + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + { + v = 255.0; + } + + if (v < 0) + { + v = 0; + } + + // write out origin as a float (there's only a few per model, so it's not really + // a size issue) + SafeWrite (modelouthandle, &v, sizeof(float)); + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + { + v = 255.0; + } + + if (v < 0) + { + v = 0; + } + + // write out origin as a float (there's only a few per model, so it's not really + // a size issue) + SafeWrite (modelouthandle, &v, sizeof(float)); + } + } + } +} +#else +/* +============ +WriteModelFile +============ +*/ +static void WriteModelFile (FILE *modelouthandle) +{ + int i; + dmdl_t modeltemp; + int j, k; + frame_t *in; + daliasframe_t *out; + byte buffer[MAX_VERTS*4+128]; + float v; + int c_on, c_off; + + model.ident = IDALIASHEADER; + model.version = ALIAS_VERSION; + model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; + model.num_glcmds = numcommands; + model.ofs_skins = sizeof(dmdl_t); + model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; + model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); + model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); + model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; + model.ofs_end = model.ofs_glcmds + model.num_glcmds*4; + + // + // write out the model header + // + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, model.framesize); + } + + // + // write out glcmds + // + SafeWrite (modelouthandle, commands, numcommands*4); +} +#endif + +/* +=============== +FinishModel +=============== +*/ +void FinishModel (void) +{ + FILE *modelouthandle; + int i; + char name[1024]; + + if (!model.num_frames) + return; + +// +// copy to release directory tree if doing a release build +// + if (g_release) + { + if (modelname[0]) + sprintf (name, "%s", modelname); + else + sprintf (name, "%s/tris.md2", cdpartial); + ReleaseFile (name); + + for (i=0 ; iindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+2)%3]; + st1 = last->index_st[(startv+2)%3]; + m2 = last->index_xyz[(startv+1)%3]; + st2 = last->index_st[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + if (stripcount & 1) + { + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + } + else + { + m1 = check->index_xyz[ (k+2)%3 ]; + st1 = check->index_st[ (k+2)%3 ]; + } + + strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ]; + strip_st[stripcount+2] = check->index_st[ (k+2)%3 ]; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+0)%3]; + st1 = last->index_st[(startv+0)%3]; + m2 = last->index_xyz[(startv+2)%3]; + st2 = last->index_st[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + + strip_xyz[stripcount+2] = m2; + strip_st[stripcount+2] = st2; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; j bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + } + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + swidth = iwidth*2; + model.skinwidth = (swidth + 3) & ~3; + model.skinheight = iheight; +} +#endif + +//========================================================================== +// +// DrawScreen +// +//========================================================================== + +void DrawScreen(float s_scale, float t_scale, float iwidth, float iheight) +{ + int i; + byte *scrpos; + char buffer[256]; + + // Divider + scrpos = &pic[(INFO_Y-2)*SKINPAGE_WIDTH]; + for(i = 0; i < SKINPAGE_WIDTH; i++) + { + *scrpos++ = 255; + } + + sprintf(buffer, "GENSKIN: "); + DrawTextChar(16, INFO_Y, buffer); + + sprintf(buffer, "( %03d * %03d ) SCALE %f %f, SKINWIDTH %d," + " SKINHEIGHT %d", (int)ScaleWidth, (int)ScaleHeight, s_scale, t_scale, (int)iwidth*2, (int)iheight); + DrawTextChar(80, INFO_Y, buffer); +} + +/* +============ +BuildST + +Builds the triangle_st array for the base frame and +model.skinwidth / model.skinheight + + FIXME: allow this to be loaded from a file for + arbitrary mappings +============ +*/ +void BuildST (triangle_t *ptri, int numtri, qboolean DrawSkin) +{ + int i, j; + int width, height, iwidth, iheight, swidth; + float basex, basey; + float scale; + vec3_t mins, maxs; + float *pbasevert; + vec3_t vtemp1, vtemp2, normal; + float s_scale, t_scale; + float scWidth; + float scHeight; + + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + + for (i=0 ; i= scHeight) + { + scale = scHeight/height; + } + + iwidth = ceil(width*scale)+4; + iheight = ceil(height*scale)+4; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + t_scale = s_scale; + + if (DrawSkin) + DrawScreen(s_scale, t_scale, iwidth, iheight); + + +/* if (!g_fixedwidth) + { // old style + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + }*/ + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + + DrawLine(triangle_st[i][0][0], triangle_st[i][0][1], + triangle_st[i][1][0], triangle_st[i][1][1]); + DrawLine(triangle_st[i][1][0], triangle_st[i][1][1], + triangle_st[i][2][0], triangle_st[i][2][1]); + DrawLine(triangle_st[i][2][0], triangle_st[i][2][1], + triangle_st[i][0][0], triangle_st[i][0][1]); + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + + swidth = iwidth*2; + model.skinwidth = (swidth + 3) & ~3; + model.skinheight = iheight; +} + + +static void ReplaceClusterIndex(int newIndex, int oldindex, int **clusters, + IntListNode_t **vertLists, int *num_verts, int *new_num_verts) +{ + int i, j; + IntListNode_t *next; + + for(j = 0; j < num_verts[0]; ++j) + { + for(i = 0; i < num_verts[j+1]; ++i) + { + if(clusters[j][i] == oldindex) + { + ++new_num_verts[j+1]; + + next = vertLists[j]; + + vertLists[j] = (IntListNode_t *) SafeMalloc(sizeof(IntListNode_t), "ReplaceClusterIndex"); + // Currently freed in WriteJointedModelFile only + + vertLists[j]->data = newIndex; + vertLists[j]->next = next; + } + } + } +} + +/* +================= +Cmd_Base +================= +*/ +void Cmd_Base (void) +{ + vec3_t base_xyz[MAX_VERTS]; + triangle_t *ptri; + int i, j, k; +#if 1 +#else + int time1; +#endif + char file1[1024]; + char file2[1024]; + + GetScriptToken (false); + + if (g_skipmodel || g_release || g_archive) + return; + + printf ("---------------------\n"); +#if 1 + sprintf (file1, "%s/%s", cdpartial, token); + printf ("%s ", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s", cddir, token); +#else + sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext); + printf ("%s\n", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s.%s", cddir, token, trifileext); + + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s doesn't exist", file1); +#endif +// +// load the base triangles +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &model.num_tris, NULL, NULL); + else + LoadTriangleList (file1, &ptri, &model.num_tris, NULL, NULL); + + + GetScriptToken (false); + sprintf (file2, "%s/%s.pcx", cddir, token); +// sprintf (trans_file, "%s/!%s_a.pcx", cddir, token); + + printf ("skin: %s\n", file2); + Load256Image (file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight); + + if (BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT) + { + if (g_allow_newskin) + { + ScaleWidth = BaseWidth; + ScaleHeight = BaseHeight; + } + else + { + Error("Invalid skin page size: (%d,%d) should be (%d,%d)", + BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT); + } + } + else + { + ScaleWidth = (float)ExtractNumber(BasePixels, ENCODED_WIDTH_X, + ENCODED_WIDTH_Y); + ScaleHeight = (float)ExtractNumber(BasePixels, ENCODED_HEIGHT_X, + ENCODED_HEIGHT_Y); + } + +// +// get the ST values +// + BuildST (ptri, model.num_tris,false); + +// +// run through all the base triangles, storing each unique vertex in the +// base vertex list and setting the indirect triangles to point to the base +// vertices +// + for (i=0 ; i= '0' && *s <= '9') + s--; + + strcpy (suffix, s+1); + strcpy (base, frame); + base[s-frame+1] = 0; + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "hrc"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "hrc"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "asc"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "asc"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "tri"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "tri"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "3ds"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "3ds"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "htr"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "htr"); + return retname; + } + + // check for 'run.1' + sprintf (file1, "%s/%s.%s",cddir, base, suffix); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s.%s", base, suffix); + return retname; + } + + Error ("frame %s could not be found",frame); + return NULL; +} + +/* +=============== +GrabFrame +=============== +*/ +static void GrabFrame (char *frame) +{ + triangle_t *ptri; + int i, j; + trivert_t *ptrivert; + int num_tris; + char file1[1024]; + frame_t *fr; + vertexnormals_t vnorms[MAX_VERTS]; + int index_xyz; + char *framefile; + + // the frame 'run1' will be looked for as either + // run.1 or run1.tri, so the new alias sequence save + // feature an be used + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s ", file1); + + if (model.num_frames >= MAX_FRAMES) + Error ("model.num_frames >= MAX_FRAMES"); + fr = &g_frames[model.num_frames]; + model.num_frames++; + + strcpy (fr->name, frame); + +// +// load the frame +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &num_tris, NULL, NULL); + else + LoadTriangleList (file1, &ptri, &num_tris, NULL, NULL); + + if (num_tris != model.num_tris) + Error ("%s: number of triangles doesn't match base frame\n", file1); + +// +// allocate storage for the frame's vertices +// + ptrivert = fr->v; + + for (i=0 ; imins, fr->maxs); + +// +// store the frame's vertices in the same order as the base. This assumes the +// triangles and vertices in this frame are in exactly the same order as in the +// base +// + for (i=0 ; imins, fr->maxs); + + VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum); + vnorms[index_xyz].numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + free (ptri); +} + +/* +=============== +GrabJointedFrame +=============== +*/ +void GrabJointedFrame(char *frame) +{ + char file1[1024]; + char *framefile; + frame_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s\n", file1); + + fr = &g_frames[model.num_frames - 1]; // last frame read in + + LoadJointList(file1, fr->joints, jointed); +} + +/* +=============== +GrabGlobals +=============== +*/ +void GrabGlobals(char *frame) +{ + char file1[1024]; + char *framefile; + frame_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s\n", file1); + + fr = &g_frames[model.num_frames - 1]; // last frame read in + + LoadGlobals(file1); +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_Frame (void) +{ + while (ScriptTokenAvailable()) + { + GetScriptToken (false); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + model.num_frames = 1; // don't skip the writeout + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames); + + GrabFrame (token); + } +} + +/* +=============== +Cmd_Skin + +Skins aren't actually stored in the file, only a reference +is saved out to the header file. +=============== +*/ +void Cmd_Skin (void) +{ + byte *palette; + byte *pixels; + int width, height; + byte *cropped; + int y; + char name[1024], savename[1024]; + + GetScriptToken (false); + + if (model.num_skins == MAX_MD2SKINS) + Error ("model.num_skins == MAX_MD2SKINS"); + + if (g_skipmodel) + return; + +#if 1 + sprintf (name, "%s/%s.pcx", cddir, token); + sprintf (savename, "%s/!%s.pcx", g_outputDir, token); + sprintf (g_skins[model.num_skins], "%s/!%s.pcx", cdpartial, token); +#else + sprintf (name, "%s/%s.lbm", cdarchive, token); + strcpy (name, ExpandPathAndArchive( name ) ); +// sprintf (name, "%s/%s.lbm", cddir, token); + + if (ScriptTokenAvailable()) + { + GetScriptToken (false); + sprintf (g_skins[model.num_skins], "%s.pcx", token); + sprintf (savename, "%s%s.pcx", g_outputDir, g_skins[model.num_skins]); + } + else + { + sprintf (savename, "%s/%s.pcx", g_outputDir, token); + sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token); + } +#endif + + model.num_skins++; + + if (g_skipmodel || g_release || g_archive) + return; + + // load the image + printf ("loading %s\n", name); + Load256Image (name, &pixels, &palette, &width, &height); +// RemapZero (pixels, palette, width, height); + + // crop it to the proper size + cropped = (byte *) SafeMalloc (model.skinwidth*model.skinheight, "Cmd_Skin"); + for (y=0 ; y= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl*longimagewidth) + xl; + destl = bufferl; + linedelta = (longimagewidth - w); + + for (y=yl ; yflags |= LittleLong(flags); + qtex32->contents = contents; + qtex32->value = value; + qtex32->scale_x = scale_x; + qtex32->scale_y = scale_y; + sprintf (qtex32->name, "%s/%s", pic_prefix, lumpname); + if (animname[0]) + sprintf (qtex32->animname, "%s/%s", pic_prefix, animname); + + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + else + { + sprintf (filename, "%spics/%s/%s.m8", g_outputDir, pic_prefix, lumpname); + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + source = byteimage + yl*byteimagewidth + xl; + dest = buffer; + linedelta = byteimagewidth - w; + + for (y=yl ; yflags = flags; + qtex->contents = contents; + qtex->value = value; + sprintf (qtex->name, "%s/%s", pic_prefix, lumpname); + if (animname[0]) + sprintf (qtex->animname, "%s/%s", pic_prefix, animname); + + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } +} + + +/* +=============== +Cmd_picdir +=============== +*/ +void Cmd_Picdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (pic_prefix, token); + // create the directory if needed + sprintf (filename, "%sPics", g_outputDir); + Q_mkdir (filename); + sprintf (filename, "%sPics/%s", g_outputDir, pic_prefix); + Q_mkdir (filename); +} + + diff --git a/tools/quake2/qdata_heretic2/qcommon/angles.h b/tools/quake2/qdata_heretic2/qcommon/angles.h new file mode 100644 index 00000000..b264f96a --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/angles.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Angles in radians + +#define ANGLE_0 0.0F +#define ANGLE_1 0.017453292F +#define ANGLE_5 0.087266462F +#define ANGLE_10 0.174532925F +#define ANGLE_15 0.261799387F +#define ANGLE_20 0.392699081F +#define ANGLE_30 0.523598775F +#define ANGLE_45 0.785398163F +#define ANGLE_60 1.047197551F +#define ANGLE_72 1.256637061F +#define ANGLE_90 1.570796327F +#define ANGLE_120 2.094395102F +#define ANGLE_135 2.35619449F +#define ANGLE_144 2.513274123F +#define ANGLE_180 3.141592653F +#define ANGLE_225 3.926990817F +#define ANGLE_270 4.71238898F +#define ANGLE_315 5.497787144F +#define ANGLE_360 6.283185307F + +// Angles in degrees + +#define DEGREE_0 0.0F +#define DEGREE_180 180.0F +#define DEGREE_45 (DEGREE_180 / 4.0F) +#define DEGREE_90 (DEGREE_180 / 2.0F) +#define DEGREE_135 (DEGREE_90 + DEGREE_45) +#define DEGREE_270 (DEGREE_180 + DEGREE_90) +#define DEGREE_360 (DEGREE_180 * 2.0F) + +#define DEGREE_225 (DEGREE_180 + DEGREE_45) +#define DEGREE_315 (DEGREE_270 + DEGREE_45) + +#define DEGREE_30 (DEGREE_180 / 6.0F) +#define DEGREE_60 (DEGREE_180 / 3.0F) +#define DEGREE_120 (DEGREE_360 / 3.0F) + +#define DEGREE_1 (DEGREE_180 / 180.0F) +#define DEGREE_5 (DEGREE_180 / 36.0F) +#define DEGREE_10 (DEGREE_180 / 18.0F) +#define DEGREE_15 (DEGREE_180 / 12.0F) +#define DEGREE_20 (DEGREE_180 / 8.0F) + +// Conversion routines + +#define ANGLE_TO_RAD ANGLE_1 +#define RAD_TO_ANGLE (180.0F / ANGLE_180) + +#define SHORT_TO_ANGLE (360.0/65536) + + +#pragma warning(disable : 4305) // 'initializing' : truncation from 'const double ' to 'float ' + diff --git a/tools/quake2/qdata_heretic2/qcommon/arrayedlist.h b/tools/quake2/qdata_heretic2/qcommon/arrayedlist.h new file mode 100644 index 00000000..d329d1a6 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/arrayedlist.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ARRAYEDLIST_H +#define _ARRAYEDLIST_H + +#include + +typedef struct ArrayedListNode_s +{ + int data; + int next; + int inUse; +} ArrayedListNode_t; + +#define ARRAYEDLISTNODE_NULL -1 + +static +#ifdef _WIN32 + _inline +#else + inline +#endif + int GetFreeNode(ArrayedListNode_t *nodeArray, int max) +{ + int i; + + for(i = 0; i < max; ++i) + { + if(!nodeArray[i].inUse) + { + nodeArray[i].inUse = 1; + return i; + } + } + + assert(0); + return -1; +} + +static +#ifdef _WIN32 + _inline +#else + inline +#endif +void FreeNode(ArrayedListNode_t *nodeArray, int index) +{ + nodeArray[index].inUse = 0; +} + +#endif //_ARRAYEDLIST_H + diff --git a/tools/quake2/qdata_heretic2/qcommon/flex.h b/tools/quake2/qdata_heretic2/qcommon/flex.h new file mode 100644 index 00000000..c3cf6076 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/flex.h @@ -0,0 +1,33 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Generic flexible format + +typedef struct +{ + char ident[32]; + int version; + int size; +} header_t; + +void WriteHeader(FILE *, char *, int, int, void *); + +// end diff --git a/tools/quake2/qdata_heretic2/qcommon/fmodel.h b/tools/quake2/qdata_heretic2/qcommon/fmodel.h new file mode 100644 index 00000000..f33efa47 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/fmodel.h @@ -0,0 +1,202 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +/* +======================================================================== + +.FM triangle flexible model file format + +======================================================================== +*/ + +#ifndef __FMODEL_HEADER +#define __FMODEL_HEADER + +#include "bspfile.h" + +//typedef unsigned char byte; +//typedef int qboolean; +//typedef float vec3_t[3]; + +#define MAX_FM_TRIANGLES 2048 +#define MAX_FM_VERTS 2048 +#define MAX_FM_FRAMES 2048 +#define MAX_FM_SKINS 64 +#define MAX_FM_SKINNAME 64 +#define MAX_FM_MESH_NODES 16 // also defined in game/qshared.h + + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +#define SKINPAGE_WIDTH 640 +#define SKINPAGE_HEIGHT 480 + +#define ENCODED_WIDTH_X 92 +#define ENCODED_WIDTH_Y 475 +#define ENCODED_HEIGHT_X 128 +#define ENCODED_HEIGHT_Y 475 + +#define SCALE_ADJUST_FACTOR 0.96 + +#define INFO_HEIGHT 5 +#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT) + +extern byte *BasePalette; +extern byte *BasePixels,*TransPixels; +extern int BaseWidth, BaseHeight, TransWidth, TransHeight; +extern int ScaleWidth, ScaleHeight; + +int ExtractNumber(byte *pic, int x, int y); +void DrawTextChar(int x, int y, char *text); +void DrawLine(int x1, int y1, int x2, int y2); + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +// Initial Header +#define FM_HEADER_NAME "header" +#define FM_HEADER_VER 2 + +typedef struct +{ + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + int num_mesh_nodes; +} fmheader_t; + + +// Skin Header +#define FM_SKIN_NAME "skin" +#define FM_SKIN_VER 1 + + +// ST Coord Header +#define FM_ST_NAME "st coord" +#define FM_ST_VER 1 + +typedef struct +{ + short s; + short t; +} fmstvert_t; + + +// Tri Header +#define FM_TRI_NAME "tris" +#define FM_TRI_VER 1 + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} fmtriangle_t; + + +// Frame Header +#define FM_FRAME_NAME "frames" +#define FM_FRAME_VER 1 + +// Frame for compression, just the names +#define FM_SHORT_FRAME_NAME "short frames" +#define FM_SHORT_FRAME_VER 1 + +// Normals for compressed frames +#define FM_NORMAL_NAME "normals" +#define FM_NORMAL_VER 1 + +// Compressed Frame Data +#define FM_COMP_NAME "comp data" +#define FM_COMP_VER 1 + +// GL Cmds Header +#define FM_GLCMDS_NAME "glcmds" +#define FM_GLCMDS_VER 1 + + +// Mesh Nodes Header +#define FM_MESH_NAME "mesh nodes" +#define FM_MESH_VER 3 + +// Skeleton Header +#define FM_SKELETON_NAME "skeleton" +#define FM_SKELETON_VER 1 + +// References Header +#define FM_REFERENCES_NAME "references" +#define FM_REFERENCES_VER 1 + +typedef struct +{ + + union + { + + byte tris[MAX_FM_TRIANGLES>>3]; + + struct { + short *triIndicies; + int num_tris; + }; + + }; + + byte verts[MAX_FM_VERTS>>3]; + short start_glcmds, num_glcmds; +} fmmeshnode_t; + +//================================================================= + +// Frame info +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} fmtrivertx_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + fmtrivertx_t verts[1]; // variable sized +} fmaliasframe_t; + + +#endif // #define __FMODEL_HEADER diff --git a/tools/quake2/qdata_heretic2/qcommon/h2common.h b/tools/quake2/qdata_heretic2/qcommon/h2common.h new file mode 100644 index 00000000..a2778f0b --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/h2common.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef H2COMMON_H +#define H2COMMON_H + #define H2COMMON_API +#endif + diff --git a/tools/quake2/qdata_heretic2/qcommon/placement.h b/tools/quake2/qdata_heretic2/qcommon/placement.h new file mode 100644 index 00000000..df98896f --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/placement.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef PLACEMENT_H +#define PLACEMENT_H + +#include "q_typedef.h" + +//typedef float vec3_t[3]; + +typedef struct Placement_s +{ + vec3_t origin; + vec3_t direction; + vec3_t up; +} Placement_t; + +#endif + + diff --git a/tools/quake2/qdata_heretic2/qcommon/q_typedef.h b/tools/quake2/qdata_heretic2/qcommon/q_typedef.h new file mode 100644 index 00000000..14206cb0 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/q_typedef.h @@ -0,0 +1,63 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Q_TYPEDEF_H +#define Q_TYPEDEF_H + +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef double vec3d_t[3]; +typedef vec_t vec5_t[5]; + +typedef float matrix3_t[3][3]; +typedef float matrix3d_t[3][3]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +typedef unsigned char byte; + +#ifndef __cplusplus +typedef enum {false, true} qboolean; +#else +typedef int qboolean; +#endif + +typedef struct edict_s edict_t; + +typedef struct paletteRGBA_s +{ + union + { + struct + { + byte r,g,b,a; + }; + unsigned c; + byte c_array[4]; + }; +} paletteRGBA_t; + +#endif + + diff --git a/tools/quake2/qdata_heretic2/qcommon/qfiles.h b/tools/quake2/qdata_heretic2/qcommon/qfiles.h new file mode 100644 index 00000000..cb0a4b53 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/qfiles.h @@ -0,0 +1,604 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +The .pak files are just a linear collapse of a directory tree + +======================================================================== +*/ + +#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 6144 + + +/* +======================================================================== + +PCX files are used for as many images as possible + +======================================================================== +*/ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + +/* +======================================================================== + +.MD2 compressed triangle model file format + +======================================================================== +*/ +#define IDCOMPRESSEDALIASHEADER (('2'<<24)+('C'<<16)+('D'<<8)+'I') + +/* +======================================================================== + +.MD2 compressed triangle model file format + +======================================================================== +*/ +#define IDJOINTEDALIASHEADER (('2'<<24)+('J'<<16)+('D'<<8)+'I') + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 64 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + union + { + struct + { + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; + }; + + int vert; + }; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +// compressed model +typedef struct dcompmdl_s +{ + dmdl_t header; + short CompressedFrameSize; + short UniqueVerts; + short *remap; + float *translate; // then add this + float *scale; // multiply byte verts by this + char *mat; + char *frames; + char *base; + float *ctranslate; + float *cscale; + char data[1]; +} dcompmdl_t; + +typedef struct +{ + dcompmdl_t compModInfo; + int rootCluster; + int skeletalType; + struct ModelSkeleton_s *skeletons; +} JointedModel_t; + +/* +======================================================================== + +.BK file format + +======================================================================== +*/ + +#define IDBOOKHEADER (('K'<<24)+('O'<<16)+('O'<<8)+'B') +#define BOOK_VERSION 2 + +typedef struct bookframe_s +{ + int x; + int y; + int w; + int h; + char name[MAX_SKINNAME]; // name of gfx file +} bookframe_t; + +typedef struct bookheader_s +{ + unsigned int ident; + unsigned int version; + int num_segments; + int total_w; + int total_h; +} bookheader_t; + +typedef struct book_s +{ + bookheader_t bheader; + bookframe_t bframes[MAX_MD2SKINS]; +} book_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .M8 texture file format + +============================================================================== +*/ + +typedef struct palette_s +{ + union + { + struct + { + byte r,g,b; + }; + }; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define MIPLEVELS 16 + +typedef struct miptex_s +{ + int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + + + +#define MIP32_VERSION 4 + +typedef struct miptex32_s +{ + int version; + char name[128]; + char altname[128]; // texture substitution + char animname[128]; // next frame in animation chain + char damagename[128]; // image that should be shown when damaged + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; + int flags; + int contents; + int value; + float scale_x, scale_y; + int mip_scale; + + // detail texturing info + char dt_name[128]; // detailed texture name + float dt_scale_x, dt_scale_y; + float dt_u, dt_v; + float dt_alpha; + int dt_src_blend_mode, dt_dst_blend_mode; + + int unused[20]; // future expansion to maintain compatibility with h2 +} miptex32_t; + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 38 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +//#define MAX_MAP_BRUSHES 8192 // Quake 2 original +#define MAX_MAP_BRUSHES 10240 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x180000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// These definitions also need to be in q_shared.h! + +// ************************************************************************************************ +// CONTENTS_XXX +// ------------ +// Contents flags. +// ************************************************************************************************ + +// Lower bits are stronger, and will eat weaker brushes completely. + +#define CONTENTS_SOLID 0x00000001 // An eye is never valid in a solid. +#define CONTENTS_WINDOW 0x00000002 // Translucent, but not watery. +#define CONTENTS_AUX 0x00000004 +#define CONTENTS_LAVA 0x00000008 +#define CONTENTS_SLIME 0x00000010 +#define CONTENTS_WATER 0x00000020 +#define CONTENTS_MIST 0x00000040 +#define LAST_VISIBLE_CONTENTS CONTENTS_MIST + +// Remaining contents are non-visible, and don't eat brushes. + +#define CONTENTS_AREAPORTAL 0x00008000 +#define CONTENTS_PLAYERCLIP 0x00010000 +#define CONTENTS_MONSTERCLIP 0x00020000 + +// Currents can be added to any other contents, and may be mixed. + +#define CONTENTS_CURRENT_0 0x00040000 +#define CONTENTS_CURRENT_90 0x00080000 +#define CONTENTS_CURRENT_180 0x00100000 +#define CONTENTS_CURRENT_270 0x00200000 +#define CONTENTS_CURRENT_UP 0x00400000 +#define CONTENTS_CURRENT_DOWN 0x00800000 +#define CONTENTS_ORIGIN 0x01000000 // Removed before bsping an entity. +#define CONTENTS_MONSTER 0x02000000 // Should never be on a brush, only in game. +#define CONTENTS_DEADMONSTER 0x04000000 +#define CONTENTS_DETAIL 0x08000000 // Brushes to be added after vis leaves. +#define CONTENTS_TRANSLUCENT 0x10000000 // Auto set if any surface has transparency. +#define CONTENTS_LADDER 0x20000000 +#define CONTENTS_CAMERANOBLOCK 0x40000000 // Camera LOS ignores any brushes with this flag. + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; + diff --git a/tools/quake2/qdata_heretic2/qcommon/reference.c b/tools/quake2/qdata_heretic2/qcommon/reference.c new file mode 100644 index 00000000..c26b1ae9 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/reference.c @@ -0,0 +1,124 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "reference.h" +#include "arrayedlist.h" +#include "resourcemanager.h" +#include "skeletons.h" + +char *referenceRootNames[] = +{ + "elf_Lhandroot",//0 + "elf_Rhandroot", + "elf_Rfootroot", + "elf_Lfootroot", + "elf_Bstaffroot", + "elf_bladeroot", + "elf_hellroot", + "StaffBone",//7 + "SwordBone", + "SpearBone", + "RFootBone", + "LFootBone", + "hp_backroot",//12 + "hp_staffroot", + "hp_lhandroot", + "hp_rhandroot", + "hp_rfootroot", + "hp_lfootroot", + "staffroot",//18 + "rfootroot", + "lfootroot", + "rhandroot", + "lhandroot", + "leyeroot", + "reyeroot" +}; + +int referenceRootNameOffsets[NUM_REFERENCED] = +{ + 0, // CORVUS + 7, // INSECT + 12, // HIGH PRIESTESS + 18, // MORCALAVIN +}; + +int numReferences[NUM_REFERENCED] = +{ + NUM_REFERENCES_CORVUS, + NUM_REFERENCES_INSECT, + NUM_REFERENCES_PRIESTESS, + NUM_REFERENCES_MORK, +}; + +int corvusJointIDs[NUM_REFERENCES_CORVUS] = +{ + CORVUS_UPPERBACK, + CORVUS_UPPERBACK, + -1, + -1, + CORVUS_UPPERBACK, + CORVUS_UPPERBACK, + CORVUS_UPPERBACK, +}; + +int *jointIDs[NUM_REFERENCED] = +{ + corvusJointIDs, +}; + +static ResourceManager_t ReferenceMngr; + +void InitReferenceMngr() +{ +#define REFERENCE_BLOCK_SIZE 8 + char *dummystr = NULL; + + ResMngr_Con(&ReferenceMngr, sizeof(LERPedReferences_t), REFERENCE_BLOCK_SIZE, dummystr); +} + +void ReleaseReferenceMngr() +{ + ResMngr_Des(&ReferenceMngr); +} + +LERPedReferences_t *LERPedReferences_new(int init_refType) +{ + LERPedReferences_t *newRefs; + + newRefs = ResMngr_AllocateResource(&ReferenceMngr, sizeof(*newRefs)); + newRefs->refType = init_refType; + newRefs->jointIDs = jointIDs[init_refType]; + newRefs->lastUpdate = -(REF_MINCULLTIME*2.0); + + memset(newRefs->references, 0, MAX_REFPOINTS*sizeof(Reference_t)); + memset(newRefs->oldReferences, 0, MAX_REFPOINTS*sizeof(Reference_t)); + + return newRefs; +} + +void LERPedReferences_delete(LERPedReferences_t *toDelete) +{ + ResMngr_DeallocateResource(&ReferenceMngr, toDelete, sizeof(*toDelete)); +} + +// end diff --git a/tools/quake2/qdata_heretic2/qcommon/reference.h b/tools/quake2/qdata_heretic2/qcommon/reference.h new file mode 100644 index 00000000..9acdc56b --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/reference.h @@ -0,0 +1,126 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef REFERENCE_H +#define REFERENCE_H + +#include "placement.h" + +#define MAX_REFPOINTS 16 +#define REF_MINCULLTIME 1.0 + +typedef struct Reference_s +{ + int activecount; + Placement_t placement; +} Reference_t; + +typedef struct LERPedReferences_s +{ + int refType; + int *jointIDs; + float lastUpdate; + Reference_t references[MAX_REFPOINTS]; + Reference_t oldReferences[MAX_REFPOINTS]; +} LERPedReferences_t; + +// Reference Types +enum { + REF_NULL = -1, + REF_CORVUS,//0 + REF_INSECT,//1 + REF_PRIESTESS,//2 + REF_MORK,//3 + NUM_REFERENCED//4 +}; + +// Corvus Reference Points +enum { + CORVUS_LEFTHAND,//0 + CORVUS_RIGHTHAND, + CORVUS_LEFTFOOT, + CORVUS_RIGHTFOOT, + CORVUS_STAFF, + CORVUS_BLADE, + CORVUS_HELL_HEAD, + NUM_REFERENCES_CORVUS//7 +}; + +// Tchekrik Reference Points +enum { + INSECT_STAFF,//0 + INSECT_SWORD, + INSECT_SPEAR, + INSECT_RIGHTFOOT, + INSECT_LEFTFOOT, + NUM_REFERENCES_INSECT//5 +}; + +// High Priestess Reference Points +enum { + PRIESTESS_BACK,//0 + PRIESTESS_STAFF, + PRIESTESS_LHAND, + PRIESTESS_RHAND, + PRIESTESS_RFOOT, + PRIESTESS_LFOOT, + NUM_REFERENCES_PRIESTESS//6 +}; + +// Morcalavin Reference Points +enum +{ + MORK_STAFFREF,//0 + MORK_RFOOTREF,//1 + MORK_LFOOTREF,//2 + MORK_RHANDREF,//3 + MORK_LHANDREF,//4 + MORK_LEYEREF,//5 + MORK_REYEREF,//6 + NUM_REFERENCES_MORK//7 +}; + +#define CORVUS_LIMBS_MASK ((1 << CORVUS_LEFTHAND) | (1 << CORVUS_RIGHTHAND) | (1 << CORVUS_LEFTFOOT) | (1 << CORVUS_RIGHTFOOT)) +#define CORVUS_WEAPON_MASK ((1 << CORVUS_STAFF) | (1 << CORVUS_BLADE) | (1 << CORVUS_HELL_HEAD)) +#define CORVUS_MASK (CORVUS_LIMBS_MASK | CORVUS_WEAPON_MASK) + +#define INSECT_MASK ((1 << INSECT_STAFF) | (1 << INSECT_SWORD) | (1 << INSECT_SPEAR) | (1 << INSECT_RIGHTFOOT) | (1 << INSECT_LEFTFOOT)) + +#define PRIESTESS_MASK ((1 << PRIESTESS_BACK) | (1 << PRIESTESS_STAFF) | (1 << PRIESTESS_LHAND) | (1 << PRIESTESS_RHAND) | (1 << PRIESTESS_RFOOT) | (1 << PRIESTESS_LFOOT)) + +#define MORK_MASK ((1 << MORK_STAFFREF) | (1 << MORK_RFOOTREF) | (1 << MORK_LFOOTREF) | (1 << MORK_RHANDREF) | (1 << MORK_LHANDREF) | (1 << MORK_LEYEREF) | (1 << MORK_REYEREF)) + +extern char *referenceRootNames[]; +extern int referenceRootNameOffsets[]; +extern int numReferences[]; + +void EnableRefPoints(LERPedReferences_t *refInfo, int mask); +void DisableRefPoints(LERPedReferences_t *refInfo, int mask); + +void InitReferenceMngr(); +void ReleaseReferenceMngr(); + +LERPedReferences_t *LERPedReferences_new(int init_refType); +void LERPedReferences_delete(LERPedReferences_t *toDelete); + +#endif + + diff --git a/tools/quake2/qdata_heretic2/qcommon/resourcemanager.c b/tools/quake2/qdata_heretic2/qcommon/resourcemanager.c new file mode 100644 index 00000000..cc5293c5 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/resourcemanager.c @@ -0,0 +1,159 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +// +// ResourceManager.c +// + +#include +#include "resourcemanager.h" +#include + +typedef struct ResMngr_Block_s +{ + char *start; + unsigned int size; + struct ResMngr_Block_s *next; +} ResMngr_Block_t; + +static void ResMngr_CreateBlock(ResourceManager_t *resource) +{ + unsigned int _blockSize; + char *block; + char **current; + ResMngr_Block_t *temp; + unsigned int i; + + _blockSize = resource->nodeSize * resource->resPerBlock; + + block = malloc(_blockSize); + + assert(block); + + temp = malloc(sizeof(*temp)); + + temp->start = block; + temp->size = _blockSize; + temp->next = resource->blockList; + + resource->blockList = temp; + + resource->free = (char **)(block); + + current = resource->free; + + for(i = 1; i < resource->resPerBlock; ++i) + { + // set current->next to point to next node + *current = (char *)(current) + resource->nodeSize; + + // set current node to current->next + current = (char **)(*current); + } + + *current = NULL; +} + +H2COMMON_API void ResMngr_Con(ResourceManager_t *resource, size_t init_resSize, unsigned int init_resPerBlock, char *resman_name) +{ + resource->resSize = init_resSize; + + resource->resPerBlock = init_resPerBlock; + + resource->nodeSize = resource->resSize + sizeof(*resource->free); + + resource->blockList = NULL; + + resource->numResourcesAllocated = 0; + + ResMngr_CreateBlock(resource); +} + +H2COMMON_API void ResMngr_Des(ResourceManager_t *resource) +{ + ResMngr_Block_t *toDelete; + +#if 0 + if (resource->numResourcesAllocated) + { + char mess[100]; + sprintf(mess,"Potential memory leak %d bytes unfreed\n",resource->resSize*resource->numResourcesAllocated); + OutputDebugString(mess); + } +#endif + + while(resource->blockList) + { + toDelete = resource->blockList; + resource->blockList = resource->blockList->next; + free(toDelete->start); + free(toDelete); + } +} + +H2COMMON_API void *ResMngr_AllocateResource(ResourceManager_t *resource, size_t size) +{ + char **toPop; + + assert(size == resource->resSize); + + ++resource->numResourcesAllocated; + + assert(resource->free); // constructor not called; possibly due to a static object + // containing a static ResourceManagerFastLarge member being + // constructed before its own static members + + toPop = resource->free; + + // set unallocated to the next node and check for NULL (end of list) + if(!(resource->free = (char **)(*resource->free))) + { // if at end create new block + ResMngr_CreateBlock(resource); + } + + // set next to NULL + *toPop = NULL; + + // return the resource for the node + return (void *)(toPop + 1); +} + +H2COMMON_API void ResMngr_DeallocateResource(ResourceManager_t *resource, void *toDeallocate, size_t size) +{ + char **toPush; + + assert(size == resource->resSize); + + --resource->numResourcesAllocated; + + toPush = (char **)(toDeallocate) - 1; + + assert(resource->free); // see same assert at top of AllocateResource + + // set toPop->next to current unallocated front + *toPush = (char *)(resource->free); + + // set unallocated to the node removed from allocated + resource->free = toPush; +} + +// end diff --git a/tools/quake2/qdata_heretic2/qcommon/resourcemanager.h b/tools/quake2/qdata_heretic2/qcommon/resourcemanager.h new file mode 100644 index 00000000..b8f1eb89 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/resourcemanager.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// ResourceManager.h +// + +#include "h2common.h" +#include // needed here for size_t + +typedef struct ResourceManager_s +{ + size_t resSize; + unsigned int resPerBlock; + unsigned int nodeSize; + struct ResMngr_Block_s *blockList; + char **free; + char *ResMan_Name; + + unsigned numResourcesAllocated; + +} ResourceManager_t; + +extern H2COMMON_API void ResMngr_Con(ResourceManager_t *resource, size_t init_resSize, unsigned int init_resPerBlock, char *resman_name); +extern H2COMMON_API void ResMngr_Des(ResourceManager_t *resource); +extern H2COMMON_API void *ResMngr_AllocateResource(ResourceManager_t *resource, size_t size); +extern H2COMMON_API void ResMngr_DeallocateResource(ResourceManager_t *resource, void *toDeallocate, size_t size); + + diff --git a/tools/quake2/qdata_heretic2/qcommon/skeletons.c b/tools/quake2/qdata_heretic2/qcommon/skeletons.c new file mode 100644 index 00000000..c1db9608 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/skeletons.c @@ -0,0 +1,232 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Skeletons.c +// + +#include "skeletons.h" + +char *skeletonRootNames[] = +{ + "RAVEN_ROOT", + "BOX_ROOT", + "BEETLE_ROOT", + "ELFLORD_ROOT", + "PLAGUELF_ROOT", + "ELF_BACKROOT", +}; + +int skeletonRNameOffsets[] = +{ + 0, // RAVEN + 1, // BOX + 2, // BEETLE + 3, // ELFLORD + 4, // PLAGUE ELF + 5, // CORVUS +}; + +char *skeletonJointNames[] = +{ + "RAVEN_LOWERBACK", // 0 + "RAVEN_UPPERBACK", + "RAVEN_NECK", + "BOX_CENTER", // 3 + "BEETLE_NECK", // 4 + "BEETLE_HEAD", + "PLAGUELF_BACKB", // 6 + "PLAGUELF_BACKC", + "PLAGUELF_NECK", + "ELF_BACKB", // 9 + "ELF_BACKC", + "ELF_NECKB", +}; + +int skeletonNameOffsets[] = +{ + 0, // RAVEN + 3, // BOX + 4, // BEETLE + -1, // ELFLORD + 6, // PLAGUE ELF + 9, // CORVUS +}; + +char *skeletonEffectorNames[] = +{ + "BEETLE_EYES", // 0 + "CORVUS_EYES", // 1 +}; + +int skeletonENameOffsets[] = +{ + -1, // RAVEN + -1, // BOX + 0, // BEETLE + -1, // ELFLORD + 1, // PLAGUE ELF +}; + +int numJointsInSkeleton[] = +{ + NUM_JOINTS_RAVEN, + NUM_JOINTS_BOX, + NUM_JOINTS_BEETLE, + NUM_JOINTS_ELFLORD, + NUM_JOINTS_PLAGUE_ELF, + NUM_JOINTS_CORVUS, +}; + +int numNodesInSkeleton[] = +{ + 2, // RAVEN + 0, // BOX + 1, // BEETLE + -1, // ELFLORD + 2, // PLAGUE ELF + 2, // CORVUS +}; + +void CreateRavenSkel(void *g_skeletalJoints, size_t jointSize, struct ArrayedListNode_s *g_jointNodes, int root); +void CreateBoxSkel(void *g_skeletalJoints, size_t jointSize, struct ArrayedListNode_s *g_jointNodes, int root); +void CreateBeetleSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex); +void CreateElfLordSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex); +void CreatePlagueElfSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex); + +CreateSkeleton_t SkeletonCreators[NUM_SKELETONS] = +{ + CreateRavenSkel, + CreateBoxSkel, + CreateBeetleSkel, + CreateElfLordSkel, + CreatePlagueElfSkel, + CreatePlagueElfSkel, // Corvus has the same structure as the Plague Elf +}; + +void CreateRavenSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)g_skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + RAVEN_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(g_jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + RAVEN_UPPERBACK * jointSize); + *children = nodeIndex; + + g_jointNodes[nodeIndex].data = rootIndex + RAVEN_HEAD; + g_jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(g_jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + RAVEN_LOWERBACK * jointSize); + *children = nodeIndex; + + g_jointNodes[nodeIndex].data = rootIndex + RAVEN_UPPERBACK; + g_jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + +void CreateBoxSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex) +{ + char *root; + int *children; + + root = (char *)g_skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + RAVEN_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; +} + +void CreateBeetleSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)g_skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + BEETLE_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(g_jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + BEETLE_NECK * jointSize); + *children = nodeIndex; + + g_jointNodes[nodeIndex].data = rootIndex + BEETLE_HEAD; + g_jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + +void CreateElfLordSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)g_skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + BEETLE_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(g_jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + BEETLE_NECK * jointSize); + *children = nodeIndex; + + g_jointNodes[nodeIndex].data = rootIndex + BEETLE_HEAD; + g_jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + +void CreatePlagueElfSkel(void *g_skeletalJoints, size_t jointSize, ArrayedListNode_t *g_jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)g_skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + PLAGUE_ELF_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(g_jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + PLAGUE_ELF_UPPERBACK * jointSize); + *children = nodeIndex; + + g_jointNodes[nodeIndex].data = rootIndex + PLAGUE_ELF_HEAD; + g_jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(g_jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + PLAGUE_ELF_LOWERBACK * jointSize); + *children = nodeIndex; + + g_jointNodes[nodeIndex].data = rootIndex + PLAGUE_ELF_UPPERBACK; + g_jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + + diff --git a/tools/quake2/qdata_heretic2/qcommon/skeletons.h b/tools/quake2/qdata_heretic2/qcommon/skeletons.h new file mode 100644 index 00000000..83793592 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qcommon/skeletons.h @@ -0,0 +1,107 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include // for size_t +#include "arrayedlist.h" + +#define JN_YAW_CHANGED 0x00000001 +#define JN_PITCH_CHANGED 0x00000002 +#define JN_ROLL_CHANGED 0x00000004 + +// Skeleton types +enum { + SKEL_NULL = -1, + SKEL_RAVEN = 0, + SKEL_BOX, + SKEL_BEETLE, + SKEL_ELFLORD, + SKEL_PLAGUE_ELF, + SKEL_CORVUS, + NUM_SKELETONS +}; + +// Raven Skeletal joints +enum { + RAVEN_LOWERBACK = 0, + RAVEN_UPPERBACK, + RAVEN_HEAD, + NUM_JOINTS_RAVEN +}; + +// Box Skeletal joints +enum { + BOX_CENTER = 0, + NUM_JOINTS_BOX +}; + +// Beetle Skeletal joints +enum { + BEETLE_NECK = 0, + BEETLE_HEAD, + NUM_JOINTS_BEETLE +}; + +// Elflord Skeletal joints +enum { + ELFLORD_, + ELFLORD__, + NUM_JOINTS_ELFLORD +}; + +// Plague Elf Skeletal joints +enum { + PLAGUE_ELF_LOWERBACK, + PLAGUE_ELF_UPPERBACK, + PLAGUE_ELF_HEAD, + NUM_JOINTS_PLAGUE_ELF +}; + +// Corvus Skeletal joints +enum { + CORVUS_LOWERBACK, + CORVUS_UPPERBACK, + CORVUS_HEAD, + NUM_JOINTS_CORVUS +}; + +#define NO_SWAP_FRAME -1 +#define NULL_ROOT_JOINT -1 + +#define MAX_ARRAYED_SKELETAL_JOINTS 255 // has max of 65,535 (if this remains at 255, net code can be changed to reflect) +#define MAX_ARRAYED_JOINT_NODES (MAX_ARRAYED_SKELETAL_JOINTS - 1) + +#define MAX_JOINTS_PER_SKELETON 8 // arbitrary small number +#define MAX_JOINT_NODES_PER_SKELETON (MAX_JOINTS_PER_SKELETON - 1) + +extern char *skeletonRootNames[]; +extern int skeletonRNameOffsets[]; +extern char *skeletonJointNames[]; +extern int skeletonNameOffsets[]; +extern int numJointsInSkeleton[]; +extern char *skeletonEffectorNames[]; +extern int skeletonENameOffsets[]; +extern int numNodesInSkeleton[]; + +typedef void (*CreateSkeleton_t)(void *skeletalJoints, size_t jointSize, struct ArrayedListNode_s *jointNodes, int rootIndex); + +extern CreateSkeleton_t SkeletonCreators[NUM_SKELETONS]; + + diff --git a/tools/quake2/qdata_heretic2/qd_fmodel.h b/tools/quake2/qdata_heretic2/qd_fmodel.h new file mode 100644 index 00000000..830325f1 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qd_fmodel.h @@ -0,0 +1,61 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef FMODEL_H +#define FMODEL_H +#include "fmodel.h" +#endif +#include "qd_skeletons.h" + +typedef struct +{ + int numnormals; + vec3_t normalsum; +} fmvertexnormals_t; + +typedef struct +{ + vec3_t v; + int lightnormalindex; + fmvertexnormals_t vnorm; +} fmtrivert_t; + +#define FRAME_NAME_LEN (16) + +typedef struct +{ + vec3_t mins, maxs; + char name[FRAME_NAME_LEN]; + fmtrivert_t v[MAX_FM_VERTS]; + struct QD_SkeletalJoint_s joints[NUM_CLUSTERS]; + struct QD_SkeletalJoint_s references[NUM_REFERENCES]; +} fmframe_t; + +extern fmframe_t g_frames[MAX_FM_FRAMES]; + +extern fmheader_t fmheader; +extern char cdarchive[1024]; // set by $fmcd +extern char cdpartial[1024]; // set by $fmcd +extern char cddir[1024]; // set by $fmcd + +void GrabFrame (char *frame); +void H_printf(char *fmt, ...); +char *FindFrameFile (char *frame); diff --git a/tools/quake2/qdata_heretic2/qd_skeletons.c b/tools/quake2/qdata_heretic2/qd_skeletons.c new file mode 100644 index 00000000..18868f1e --- /dev/null +++ b/tools/quake2/qdata_heretic2/qd_skeletons.c @@ -0,0 +1,1291 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qd_skeletons.h" +#include "skeletons.h" +#include "qd_fmodel.h" +#include "angles.h" +#include "token.h" +#include "qdata.h" +#include "reference.h" + +#include +#include +#include + + +// We're assuming no more than 16 reference points, with no more than 32 characters in the name +char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN]; +int RefPointNum = 0; + +Skeletalfmheader_t g_skelModel; + +void ClearSkeletalModel() +{ + g_skelModel.type = SKEL_NULL; + g_skelModel.clustered = false; + g_skelModel.references = REF_NULL; +} + +//========================================================================== +// +// LoadHRCClustered +// +//========================================================================== + +// Places the null terminated src string into the dest string less any trailing digits or underscores +void StripTrailingDigits(char *src, char *dest) +{ +#ifndef NDEBUG + int max = SKELETAL_NAME_MAX; // should be sufficient for inteded use on names from hrc files +#endif + int i = 0; + + while(src[i] != '\0') + { + ++i; +#ifndef NDEBUG + assert(i < max); +#endif + } + + while((src[--i] >= '0' && src[i] <= '9') || src[i] == '_') + { + + } + + memcpy(dest, src, ++i); + + dest[i] = '\0'; +} + +static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + extern void HandleHRCModel(triangle_t **triList, int *triangleCount, + mesh_node_t **nodesList, int *num_mesh_nodes, int ActiveNode, int Depth); + + extern mesh_node_t *pmnodes; + + triangle_t *triList; +// mesh_node_t *nodesList; + int num_mesh_nodes = 0, triangleCount = 0; + +#if 0 + int i; + int j, numVerts; + char stripped[SKELETAL_NAME_MAX]; + + for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i) + { + num_verts[i] = 0; + } + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_CLUSTERS); + + while(TK_Search(TK_CLUSTER_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + for( i = 0; i < numJointsInSkeleton[skelType]; ++i) + { + if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0) + { + i = -i + numJointsInSkeleton[skelType] - 1; + + TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER); + + numVerts = tk_IntNumber; + + if(!num_verts[i+1]) // first set of verts for cluster + { + clusterList[i] = SafeMalloc(numVerts*sizeof(int), "LoadHRCClustered"); + assert(clusterList[i]); + } + else // any later sets of verts need to copy current + { + int *temp; + + temp = SafeMalloc((num_verts[i+1]+numVerts)*sizeof(int), "LoadHRCClustered"); + assert(temp); + + memcpy(temp + numVerts, clusterList[i], num_verts[i+1]*sizeof(int)); + + free(clusterList[i]); + + clusterList[i] = temp; + } + + // currently this function is only called by LoadModelClusters. + // Apparently the matching free has disappeared, + // should probably be free at the end of FMCmd_Base + + TK_Beyond(TK_LBRACE); + + for(j = 0; j < numVerts; ++j) + { + TK_Require(TK_INTNUMBER); + clusterList[i][j] = tk_IntNumber; + TK_Fetch(); + } + + num_verts[i+1] += numVerts; + + break; + } + } + } + + num_verts[0] = numJointsInSkeleton[skelType]; +#endif + +#if 1 // get the index number localized to the root +// for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i) +// { +// g_skelModel.num_verts[i] = 0; +// } + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + // prime it + TK_Beyond(TK_MODEL); + + triList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list"); + memset(triList,0,MAXTRIANGLES*sizeof(triangle_t)); +// nodesList = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + pmnodes = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + + memset(pmnodes, 0, MAX_FM_MESH_NODES * sizeof(mesh_node_t)); + + // this should eventually use a stripped down version of this + HandleHRCModel(&triList, &triangleCount, &pmnodes, &num_mesh_nodes, 0, 0); + +// free(nodesList); + free(triList); + + num_verts[0] = numJointsInSkeleton[skelType]; +#endif +} + +void ReadHRCClusterList(mesh_node_t *meshNode, int baseIndex) +{ + int i, j, numVerts; + tokenType_t nextToken; + char stripped[SKELETAL_NAME_MAX]; + + meshNode->clustered = true; + + nextToken = TK_Get(TK_CLUSTER_NAME); + + while (nextToken == TK_CLUSTER_NAME) + { + TK_FetchRequire(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + for( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i) + { + if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[g_skelModel.type]+i]) == 0) + { + i = -i + numJointsInSkeleton[g_skelModel.type] - 1; + + TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER); + + numVerts = tk_IntNumber; + + if(!baseIndex) + { + meshNode->clusters[i] = (int *) SafeMalloc(numVerts*sizeof(int), "ReadHRCClusterList"); + assert(meshNode->clusters[i]); + } + else + { + int *temp; + + temp = meshNode->clusters[i]; + meshNode->clusters[i] = (int *) SafeMalloc((meshNode->num_verts[i+1]+numVerts)*sizeof(int), "ReadHRCClusterList"); + assert(meshNode->clusters[i]); + + memcpy(meshNode->clusters[i], temp, meshNode->num_verts[i+1]*sizeof(int)); + free(temp); + } + + // currently this function is only called by LoadModelClusters. + // Apparently the matching free has disappeared, + // should probably be free at the end of FMCmd_Base + + TK_Beyond(TK_LBRACE); + + for(j = 0; j < numVerts; ++j) + { + TK_Require(TK_INTNUMBER); + meshNode->clusters[i][baseIndex+j] = tk_IntNumber+baseIndex; + TK_Fetch(); + } + + if(baseIndex) + { + meshNode->num_verts[i+1] += numVerts; + } + else + { + meshNode->num_verts[i+1] = numVerts; + } + + break; + } + } + + TK_BeyondRequire(TK_CLUSTER_STATE, TK_INTNUMBER); + nextToken = TK_Fetch(); + } +} + +static void LoadHRCGlobals(char *fileName) +{ + int i; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + TK_Beyond(TK_MODEL); + + TK_Beyond(TK_SCALING); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_skelModel.scaling[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_ROTATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_skelModel.rotation[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_TRANSLATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_skelModel.translation[i] = tk_FloatNumber; + TK_Fetch(); + } +} + +static void ParseVec3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseVec3d(vec3d_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseRotation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseRotation3d(vec3d_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseTranslation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseTranslation3d(vec3d_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void LoadHRCJointList(char *fileName, QD_SkeletalJoint_t *jointList, int skelType) +{ +#define MAX_STACK 64 + int i, j; + vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK]; + int curCorrespondingJoint[MAX_STACK]; + int currentStack = 0, stackSize; + double cx, sx, cy, sy, cz, sz; + double rx, ry, rz; + double x2, y2, z2; + char stripped[SKELETAL_NAME_MAX]; + Placement_d_t *placement; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_MODEL); + + while(TK_Search(TK_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + if(stricmp(stripped, skeletonRootNames[skeletonRNameOffsets[skelType]]) == 0) + { + break; + } + } + + if(tk_Token == TK_EOF) + { + Error("Bone Chain Root: %s not found\n", skeletonRootNames[skeletonRNameOffsets[skelType]]); + return; + } + + TK_Beyond(TK_SCALING); + + ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + + // account for global model translation + curTranslation[currentStack][1] += g_skelModel.translation[0]; + curTranslation[currentStack][2] += g_skelModel.translation[1]; + curTranslation[currentStack][0] += g_skelModel.translation[2]; + + curCorrespondingJoint[currentStack] = -1; + + ++currentStack; + + for(i = 0; i < numJointsInSkeleton[skelType]; ++i) + { + while(1) + { + TK_Beyond(TK_MODEL); + + TK_BeyondRequire(TK_NAME, TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0) + break; + + TK_Beyond(TK_SCALING); + + ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + + curCorrespondingJoint[currentStack] = -1; + + ++currentStack; + } + + TK_Beyond(TK_SCALING); + + ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + jointList[i].rotation[1] = curRotation[currentStack][1]; + jointList[i].rotation[2] = curRotation[currentStack][2]; + jointList[i].rotation[0] = curRotation[currentStack][0]; + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + +// jointList[i].placement.origin[1] = curTranslation[currentStack][1]; +// jointList[i].placement.origin[2] = curTranslation[currentStack][2]; +// jointList[i].placement.origin[0] = curTranslation[currentStack][0]; + + jointList[i].placement.origin[1] = 0.0; + jointList[i].placement.origin[2] = 0.0; + jointList[i].placement.origin[0] = 0.0; + + jointList[i].placement.direction[1] = 20.0; + jointList[i].placement.direction[2] = 0.0; + jointList[i].placement.direction[0] = 0.0; + + jointList[i].placement.up[1] = 0.0; + jointList[i].placement.up[2] = 20.0; + jointList[i].placement.up[0] = 0.0; + + curCorrespondingJoint[currentStack] = i; + + ++currentStack; + } + + stackSize = currentStack; + +#if 0 + // rotate the direction and up vectors to correspond to the rotation + for(i = 0; i < numJointsInSkeleton[skelType]; ++i) + { + rx = jointList[i].rotation[0]*ANGLE_TO_RAD; + ry = jointList[i].rotation[1]*ANGLE_TO_RAD; + rz = jointList[i].rotation[2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + // y-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy; + z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy; + z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[2] = z2; + + // z-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz; + y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz; + y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[1] = y2; + + // x-axis rotation for direction vector + y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx; + z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx; + jointList[i].placement.direction[1] = y2; + jointList[i].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx; + z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx; + jointList[i].placement.up[1] = y2; + jointList[i].placement.up[2] = z2; + + // translate direction to a point in the model + jointList[i].placement.direction[0] += jointList[i].placement.origin[0]; + jointList[i].placement.direction[1] += jointList[i].placement.origin[1]; + jointList[i].placement.direction[2] += jointList[i].placement.origin[2]; + + // translate up to a point in the model + jointList[i].placement.up[0] += jointList[i].placement.origin[0]; + jointList[i].placement.up[1] += jointList[i].placement.origin[1]; + jointList[i].placement.up[2] += jointList[i].placement.origin[2]; + } +#endif + + for(i = stackSize - 1; i >= 0; --i) + { + rx = curRotation[i][0]*ANGLE_TO_RAD; + ry = curRotation[i][1]*ANGLE_TO_RAD; + rz = curRotation[i][2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + +#if 1 + for(j = i; j < stackSize; ++j) + { + if(curCorrespondingJoint[j] != -1) + { + placement = &jointList[curCorrespondingJoint[j]].placement; + + // y-axis rotation for origin + x2 = placement->origin[0]*cy+placement->origin[2]*sy; + z2 = -placement->origin[0]*sy+placement->origin[2]*cy; + placement->origin[0] = x2; + placement->origin[2] = z2; + + // y-axis rotation for direction + x2 = placement->direction[0]*cy+placement->direction[2]*sy; + z2 = -placement->direction[0]*sy+placement->direction[2]*cy; + placement->direction[0] = x2; + placement->direction[2] = z2; + + // y-axis rotation for up + x2 = placement->up[0]*cy+placement->up[2]*sy; + z2 = -placement->up[0]*sy+placement->up[2]*cy; + placement->up[0] = x2; + placement->up[2] = z2; + + // z-axis rotation for origin + x2 = placement->origin[0]*cz-placement->origin[1]*sz; + y2 = placement->origin[0]*sz+placement->origin[1]*cz; + placement->origin[0] = x2; + placement->origin[1] = y2; + + // z-axis rotation for direction + x2 = placement->direction[0]*cz-placement->direction[1]*sz; + y2 = placement->direction[0]*sz+placement->direction[1]*cz; + placement->direction[0] = x2; + placement->direction[1] = y2; + + // z-axis rotation for up + x2 = placement->up[0]*cz-placement->up[1]*sz; + y2 = placement->up[0]*sz+placement->up[1]*cz; + placement->up[0] = x2; + placement->up[1] = y2; + + // x-axis rotation for origin + y2 = placement->origin[1]*cx-placement->origin[2]*sx; + z2 = placement->origin[1]*sx+placement->origin[2]*cx; + placement->origin[1] = y2; + placement->origin[2] = z2; + + // x-axis rotation for direction vector + y2 = placement->direction[1]*cx-placement->direction[2]*sx; + z2 = placement->direction[1]*sx+placement->direction[2]*cx; + placement->direction[1] = y2; + placement->direction[2] = z2; + + // x-axis rotation for up vector + y2 = placement->up[1]*cx-placement->up[2]*sx; + z2 = placement->up[1]*sx+placement->up[2]*cx; + placement->up[1] = y2; + placement->up[2] = z2; + + // translate origin + placement->origin[0] += curTranslation[i][0]; + placement->origin[1] += curTranslation[i][1]; + placement->origin[2] += curTranslation[i][2]; + + // translate back to local coord + placement->direction[0] += curTranslation[i][0]; + placement->direction[1] += curTranslation[i][1]; + placement->direction[2] += curTranslation[i][2]; + + // translate back to local coord + placement->up[0] += curTranslation[i][0]; + placement->up[1] += curTranslation[i][1]; + placement->up[2] += curTranslation[i][2]; + } + } +#else + // This screwed up and needs to be sorted out!!! + // The stack info needs to be written too instead of the jointList for j > numJoints for Skeleton + for(j = i-1; j < stackSize-1; ++j) + { + // y-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy; + z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[2] = z2; + + // y-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy; + z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy; + z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[2] = z2; + + // z-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz; + y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[1] = y2; + + // z-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz; + y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz; + y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[1] = y2; + + // x-axis rotation for origin + y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx; + z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx; + jointList[j].placement.origin[1] = y2; + jointList[j].placement.origin[2] = z2; + + // x-axis rotation for direction vector + y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx; + z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx; + jointList[j].placement.direction[1] = y2; + jointList[j].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx; + z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx; + jointList[j].placement.up[1] = y2; + jointList[j].placement.up[2] = z2; + + if(curCorrespondingJoint[j+1] != -1) + { + // translate origin + jointList[j].placement.origin[0] += curTranslation[i-1][0]; + jointList[j].placement.origin[1] += curTranslation[i-1][1]; + jointList[j].placement.origin[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.direction[0] += curTranslation[i-1][0]; + jointList[j].placement.direction[1] += curTranslation[i-1][1]; + jointList[j].placement.direction[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.up[0] += curTranslation[i-1][0]; + jointList[j].placement.up[1] += curTranslation[i-1][1]; + jointList[j].placement.up[2] += curTranslation[i-1][2]; + } + } +#endif + } +} + +void LoadModelTransform(char *fileName) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCGlobals(InputFileName); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { +// printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCGlobals(fileName); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadModelClusters(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCClustered(InputFileName, clusterList, num_verts, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { +// printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCClustered(fileName, clusterList, num_verts, skelType); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadSkeleton(char *fileName, QD_SkeletalJoint_t *jointList, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCJointList(InputFileName, jointList, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { +// printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCJointList(fileName, jointList, skelType); + + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +/* +=============== +GrabSkeletalFrame +=============== +*/ +void GrabSkeletalFrame(char *frame) +{ + char file1[1024]; + char *framefile; + fmframe_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("Grabbing Skeletal Frame %s\n", file1); + + fr = &g_frames[fmheader.num_frames - 1]; // last frame read in + + LoadSkeleton(file1, fr->joints, g_skelModel.type); +} + +/* +=============== +GrabModelTransform +=============== +*/ +void GrabModelTransform(char *frame) +{ + char file1[1024]; + char *framefile; + fmframe_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + +// printf ("grabbing %s\n", file1); + + fr = &g_frames[fmheader.num_frames - 1]; // last frame read in + + LoadModelTransform(file1); +} + +void Cmd_FMCluster() +{ + char file1[1024]; + + GetScriptToken (false); + + printf ("---------------------\n"); + sprintf (file1, "%s/%s", cdpartial, token); + printf ("%s\n", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s", cddir, token); + + g_skelModel.clustered = -1; + + LoadModelClusters(file1, (int **)&g_skelModel.clusters, (int *)&g_skelModel.num_verts, g_skelModel.type); + + g_skelModel.new_num_verts[0] = g_skelModel.num_verts[0]; + + g_skelModel.clustered = true; +} + +void Cmd_FMSkeleton() +{ + GetScriptToken (false); + g_skelModel.type = atoi(token); +} + +void Cmd_FMSkeletalFrame() +{ + while (ScriptTokenAvailable()) + { + GetScriptToken (false); + if (g_skipmodel) + { + GetScriptToken (false); + continue; + } + if (g_release || g_archive) + { + fmheader.num_frames = 1; // don't skip the writeout + GetScriptToken (false); + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames); + + GrabModelTransform (token); + GrabFrame (token); + GrabSkeletalFrame (token); + + // need to add the up and dir points to the frame bounds here + // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs); + // then remove fudge in determining scale on frame write out + } +} + +static void LoadHRCReferences(char *fileName, fmframe_t *fr) +{ +#define MAX_STACK 64 + int i, j, k; + vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK]; + int curCorrespondingJoint[MAX_STACK]; + int currentStack, stackSize; + double cx, sx, cy, sy, cz, sz; + double rx, ry, rz; + double x2, y2, z2; + char stripped[SKELETAL_NAME_MAX]; + Placement_d_t *placement; + int refnum; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + if (RefPointNum <= 0) + { // There were no labels indicated in the QDT, so use the hard-coded stuff. + refnum = numReferences[g_skelModel.references]; + } + else + { + refnum = RefPointNum; + } + + for(k = 0; k < refnum; ++k) + { + currentStack = 0; + + // Load the root to get translation and initial rotation +// TK_Beyond(TK_MODEL); + + while(TK_Search(TK_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + if (RefPointNum == 0) + { // Hard coded refpoint labels + if(stricmp(stripped, + referenceRootNames[referenceRootNameOffsets[g_skelModel.references]+k]) == 0) + { + break; + } + } + else + { // labels indicated by the QDT + if(stricmp(stripped, RefPointNameList[k]) == 0) + { + break; + } + } + } + + if(tk_Token == TK_EOF) + { + if (RefPointNum == 0) + { // Hard coded refpoint labels + Error("Bone Chain Root: %s not found\n", referenceRootNames[referenceRootNameOffsets[g_skelModel.references]]); + } + else + { // labels indicated by the QDT + Error("Bone Chain Root: %s not found\n", RefPointNameList[k]); + } + return; + } + +// TK_Beyond(TK_SCALING); + +// ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + + // account for global model translation + curTranslation[currentStack][1] += g_skelModel.translation[0]; + curTranslation[currentStack][2] += g_skelModel.translation[1]; + curTranslation[currentStack][0] += g_skelModel.translation[2]; + + curCorrespondingJoint[currentStack] = -1; + +// rjr - this one not needed, as there is also a stack increment 20 lines below??? +// ++currentStack; + + // Load the joint to get orientation + TK_Beyond(TK_MODEL); + +// TK_Beyond(TK_SCALING); + +// ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + +// TK_Beyond(TK_TRANSLATION); + +// ParseVec3d(curTranslation[currentStack]); + + fr->references[k].placement.origin[1] = 0.0; + fr->references[k].placement.origin[2] = 0.0; + fr->references[k].placement.origin[0] = 0.0; + + fr->references[k].placement.direction[1] = 20.0; + fr->references[k].placement.direction[2] = 0.0; + fr->references[k].placement.direction[0] = 0.0; + + fr->references[k].placement.up[1] = 0.0; + fr->references[k].placement.up[2] = 20.0; + fr->references[k].placement.up[0] = 0.0; + + curCorrespondingJoint[currentStack] = k; + + ++currentStack; + + stackSize = currentStack; + + for(i = stackSize - 1; i >= 0; --i) + { + rx = curRotation[i][0]*ANGLE_TO_RAD; + ry = curRotation[i][1]*ANGLE_TO_RAD; + rz = curRotation[i][2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + for(j = i; j < stackSize; ++j) + { + if(curCorrespondingJoint[j] != -1) + { + placement = &fr->references[curCorrespondingJoint[j]].placement; + + // y-axis rotation for origin + x2 = placement->origin[0]*cy+placement->origin[2]*sy; + z2 = -placement->origin[0]*sy+placement->origin[2]*cy; + placement->origin[0] = x2; + placement->origin[2] = z2; + + // y-axis rotation for direction + x2 = placement->direction[0]*cy+placement->direction[2]*sy; + z2 = -placement->direction[0]*sy+placement->direction[2]*cy; + placement->direction[0] = x2; + placement->direction[2] = z2; + + // y-axis rotation for up + x2 = placement->up[0]*cy+placement->up[2]*sy; + z2 = -placement->up[0]*sy+placement->up[2]*cy; + placement->up[0] = x2; + placement->up[2] = z2; + + // z-axis rotation for origin + x2 = placement->origin[0]*cz-placement->origin[1]*sz; + y2 = placement->origin[0]*sz+placement->origin[1]*cz; + placement->origin[0] = x2; + placement->origin[1] = y2; + + // z-axis rotation for direction + x2 = placement->direction[0]*cz-placement->direction[1]*sz; + y2 = placement->direction[0]*sz+placement->direction[1]*cz; + placement->direction[0] = x2; + placement->direction[1] = y2; + + // z-axis rotation for up + x2 = placement->up[0]*cz-placement->up[1]*sz; + y2 = placement->up[0]*sz+placement->up[1]*cz; + placement->up[0] = x2; + placement->up[1] = y2; + + // x-axis rotation for origin + y2 = placement->origin[1]*cx-placement->origin[2]*sx; + z2 = placement->origin[1]*sx+placement->origin[2]*cx; + placement->origin[1] = y2; + placement->origin[2] = z2; + + // x-axis rotation for direction vector + y2 = placement->direction[1]*cx-placement->direction[2]*sx; + z2 = placement->direction[1]*sx+placement->direction[2]*cx; + placement->direction[1] = y2; + placement->direction[2] = z2; + + // x-axis rotation for up vector + y2 = placement->up[1]*cx-placement->up[2]*sx; + z2 = placement->up[1]*sx+placement->up[2]*cx; + placement->up[1] = y2; + placement->up[2] = z2; + + // translate origin + placement->origin[0] += curTranslation[i][0]; + placement->origin[1] += curTranslation[i][1]; + placement->origin[2] += curTranslation[i][2]; + + // translate back to local coord + placement->direction[0] += curTranslation[i][0]; + placement->direction[1] += curTranslation[i][1]; + placement->direction[2] += curTranslation[i][2]; + + // translate back to local coord + placement->up[0] += curTranslation[i][0]; + placement->up[1] += curTranslation[i][1]; + placement->up[2] += curTranslation[i][2]; + + } + } + } + printf("%f, %f, %f\n", placement->origin[0], placement->origin[1], placement->origin[2]); + } + printf("\n"); +} + +void Cmd_FMReferenced() +{ + int i; + + GetScriptToken (false); + g_skelModel.references = atoi(token); + + // Guess what? Now, we now want a list of strings to look for here instead of a hard-coded list + for (i=0; i 0) + { + printf("Searching for %d different reference points.\n", RefPointNum); + } + else + { + printf("Using built-in reference points.\n"); + } + +} + +void LoadReferences(char *fileName, fmframe_t *fr) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCReferences(InputFileName, fr); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCReferences(fileName, fr); + + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void GrabReferencedFrame(char *frame) +{ + char file1[1024]; + char *framefile; + fmframe_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("Grabbing Referenced %s\n", file1); + + fr = &g_frames[fmheader.num_frames - 1]; // last frame read in + + LoadReferences(file1, fr); +} + diff --git a/tools/quake2/qdata_heretic2/qd_skeletons.h b/tools/quake2/qdata_heretic2/qd_skeletons.h new file mode 100644 index 00000000..867e9602 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qd_skeletons.h @@ -0,0 +1,84 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef QD_SKELETONS_H +#define QD_SKELETONS_H + +#include "placement.h" + + +typedef struct Placement_d_s +{ + vec3d_t origin; + vec3d_t direction; + vec3d_t up; +} Placement_d_t; + +typedef struct QD_SkeletalJoint_s +{ + Placement_d_t placement; + vec3d_t rotation; +} QD_SkeletalJoint_t; + +#define NUM_CLUSTERS 8 + +typedef struct IntListNode_s +{ + int data; + struct IntListNode_s *next; +} IntListNode_t; // gaak + +typedef struct Skeletalfmheader_s +{ + int type; + int clustered; + int references; + + int *clusters[NUM_CLUSTERS]; + IntListNode_t *vertLists[NUM_CLUSTERS]; + int num_verts[NUM_CLUSTERS + 1]; + int new_num_verts[NUM_CLUSTERS + 1]; + + float scaling[3]; + float rotation[3]; + float translation[3]; +} Skeletalfmheader_t; + +#define SKELETAL_NAME_MAX 32 + +extern Skeletalfmheader_t g_skelModel; + +void ClearSkeletalModel(); +void GrabModelTransform(char *frame); +void GrabSkeletalFrame(char *frame); +void GrabReferencedFrame(char *frame); + +// Reference Stuff +#define NUM_REFERENCES 8 + +#define REF_MAX_POINTS 16 +#define REF_MAX_STRLEN 32 + +// We're assuming no more than 16 reference points, with no more than 32 characters in the name +extern char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN]; +extern int RefPointNum; + +#endif diff --git a/tools/quake2/qdata_heretic2/qdata.c b/tools/quake2/qdata_heretic2/qdata.c new file mode 100644 index 00000000..d8488f69 --- /dev/null +++ b/tools/quake2/qdata_heretic2/qdata.c @@ -0,0 +1,730 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qdata.h" + +void TK_Init(); + +qboolean g_compress_pak; +qboolean g_release; // don't grab, copy output data to new tree +qboolean g_pak; // if true, copy to pak instead of release +char g_releasedir[1024]; // c:\quake2\baseq2, etc +qboolean g_archive; // don't grab, copy source data to new tree +qboolean do3ds; +char g_only[256]; // if set, only grab this cd +qboolean g_skipmodel; // set true when a cd is not g_only +int g_forcemodel = MODEL_AUTO; +qboolean g_verbose = false; +qboolean g_allow_newskin = true; +qboolean g_ignoreTriUV = false; +qboolean g_publishOutput = false; + +char *ext_3ds = "3ds"; +char *ext_tri= "tri"; +char *trifileext; + +char g_materialFile[256] = "none"; // default for Heretic2 +char *g_outputDir; +extern char *g_publishDir; + +extern qboolean g_nomkdir; + +/* +======================================================= + + PAK FILES + +======================================================= +*/ + +typedef struct +{ + char name[56]; + int filepos, filelen; +} packfile_t; + +typedef struct +{ + char id[4]; + int dirofs; + int dirlen; +} packheader_t; + +packfile_t pfiles[16384]; +FILE *pakfile; +packfile_t *pf; +packheader_t pakheader; + + + +/* +============== +BeginPak +============== +*/ +void BeginPak (char *outname) +{ + if (!g_pak) + return; + + pakfile = SafeOpenWrite (outname); + + // leave space for header + SafeWrite (pakfile, &pakheader, sizeof(pakheader)); + + pf = pfiles; +} + + +/* +============== +ReleaseFile + +Filename should be gamedir reletive. +Either copies the file to the release dir, or adds it to +the pak file. +============== +*/ +void ReleaseFile (char *filename) +{ + int len; + byte *buf; + char source[1024]; + char dest[1024]; + + if (!g_release) + return; + + sprintf (source, "%s%s", gamedir, filename); + + if (!g_pak) + { // copy it + sprintf (dest, "%s/%s", g_releasedir, filename); + printf ("copying to %s\n", dest); + QCopyFile (source, dest); + return; + } + + // pak it + printf ("paking %s\n", filename); + if (strlen(filename) >= sizeof(pf->name)) + Error ("Filename too long for pak: %s", filename); + + len = LoadFile (source, (void **)&buf); + + // segment moved to old.c + + strcpy (pf->name, filename); + pf->filepos = LittleLong(ftell(pakfile)); + pf->filelen = LittleLong(len); + pf++; + + SafeWrite (pakfile, buf, len); + + free (buf); +} + + +/* +============== +FinishPak +============== +*/ +void FinishPak (void) +{ + int dirlen; + int d; + int i; + + if (!g_pak) + return; + + pakheader.id[0] = 'P'; + pakheader.id[1] = 'A'; + pakheader.id[2] = 'C'; + pakheader.id[3] = 'K'; + dirlen = (byte *)pf - (byte *)pfiles; + pakheader.dirofs = LittleLong(ftell(pakfile)); + pakheader.dirlen = LittleLong(dirlen); + + SafeWrite (pakfile, pfiles, dirlen); + + i = ftell (pakfile); + + fseek (pakfile, 0, SEEK_SET); + SafeWrite (pakfile, &pakheader, sizeof(pakheader)); + fclose (pakfile); + + d = pf - pfiles; + printf ("%i files packed in %i bytes\n",d, i); +} + + +/* +=============== +Cmd_File + +This is only used to cause a file to be copied during a release +build (default.cfg, maps, etc) +=============== +*/ +void Cmd_File (void) +{ + GetScriptToken (false); + ReleaseFile (token); +} + +/* +=============== +PackDirectory_r + +=============== +*/ +#ifdef _WIN32 +#include "io.h" +void PackDirectory_r (char *dir) +{ + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char filename[1024]; + + sprintf (dirstring, "%s%s/*.*", gamedir, dir); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + do + { + sprintf (filename, "%s/%s", dir, fileinfo.name); + if (fileinfo.attrib & _A_SUBDIR) + { // directory + if (fileinfo.name[0] != '.') // don't pak . and .. + PackDirectory_r (filename); + continue; + } + // copy or pack the file + ReleaseFile (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); +} +#else + +#include +#ifdef NeXT +#include +#else +#include +#endif + +void PackDirectory_r (char *dir) +{ +#ifdef NeXT + struct direct **namelist, *ent; +#else + struct dirent **namelist, *ent; +#endif + int count; + struct stat st; + int i; + int len; + char fullname[1024]; + char dirstring[1024]; + char *name; + + sprintf (dirstring, "%s%s", gamedir, dir); + count = scandir(dirstring, &namelist, NULL, NULL); + + for (i=0 ; id_name; + + if (name[0] == '.') + continue; + + sprintf (fullname, "%s/%s", dir, name); + sprintf (dirstring, "%s%s/%s", gamedir, dir, name); + + if (stat (dirstring, &st) == -1) + Error ("fstating %s", pf->name); + if (st.st_mode & S_IFDIR) + { // directory + PackDirectory_r (fullname); + continue; + } + + // copy or pack the file + ReleaseFile (fullname); + } +} +#endif + + +/* +=============== +Cmd_Dir + +This is only used to cause a directory to be copied during a +release build (sounds, etc) +=============== +*/ +void Cmd_Dir (void) +{ + GetScriptToken (false); + PackDirectory_r (token); +} + +//======================================================================== + +#define MAX_RTEX 16384 +int numrtex; +char rtex[MAX_RTEX][64]; + +void ReleaseTexture (char *name) +{ + int i; + char path[1024]; + + for (i=0 ; i width height\n"); + } + return 0; + } +*/ else if (!strcmpi(argv[i], "-genskin")) + { + i++; + if (i < argc-3) + { + GenSkin(argv[i],argv[i+1],atol(argv[i+2]),atol(argv[i+3])); + } + else + { + printf("qdata -genskin \n"); + } + return 0; + + } + else if (!strcmpi(argv[i], "-noopts")) + { + g_no_opimizations = true; + printf("not performing optimizations\n"); + } + else if (!strcmpi(argv[i], "-md2")) + { + g_forcemodel = MODEL_MD2; + } + else if (!strcmpi(argv[i], "-fm")) + { + g_forcemodel = MODEL_FM; + } + else if (!strcmpi(argv[i], "-verbose")) + { + g_verbose = true; + } + else if (!strcmpi(argv[i], "-oldskin")) + { + g_allow_newskin = false; + } + else if (!strcmpi(argv[i], "-ignoreUV")) + { + g_ignoreTriUV = true; + } + else if (!strcmpi(argv[i], "-publish")) + { + g_publishOutput = true; + } + else if (!strcmpi(argv[i], "-nomkdir")) + { + g_nomkdir = true; + } + else if (argv[i][0] == '-') + Error ("Unknown option \"%s\"", argv[i]); + else + break; + } + + if (i >= argc) + { + Error ("usage: qdata [-archive ]\n" + " [-release ]\n" + " [-base ]\n" + " [-compress]\n" + " [-pak ]\n" + " [-only ]\n" + " [-keypress]\n" + " [-3ds]\n" + " [-materialfile ]\n" + " [-noopts]\n" + " [-md2]\n" + " [-fm]\n" + " [-verbose]\n" + " [-ignoreUV]\n" + " [-oldskin]\n" + " [-publish]\n" + " [-nomkdir]\n" + " file.qdt\n" + "or\n" + " qdata -genskin "); + } + + if (do3ds) + trifileext = ext_3ds; + else + trifileext = ext_tri; + + for ( ; i +#include +#include +#include +#include + +#include "cmdlib.h" +#include "inout.h" +#include "scriplib.h" +#include "mathlib.h" +#include "trilib.h" +#include "lbmlib.h" +#include "her2_threads.h" +#include "l3dslib.h" +#include "bspfile.h" + +#ifndef _WIN32 +#define stricmp strcasecmp +#define strcmpi strcasecmp +#endif + + +#define MODEL_AUTO 0 +#define MODEL_MD2 1 +#define MODEL_FM 2 + +// Model cover functions (to allow the forcing of a model type) +void MODELCMD_Modelname (int modeltype); +void MODELCMD_Cd (int modeltype); +void MODELCMD_Origin (int modeltype); +void MODELCMD_Jointed (int modeltype); +void MODELCMD_Cluster (int modeltype); +void MODELCMD_Base (int modeltype); +void MODELCMD_BaseST (int modeltype); +void MODELCMD_ScaleUp (int modeltype); +void MODELCMD_Frame (int modeltype); +void MODELCMD_Skin (int modeltype); +void MODELCMD_Skinsize (int modeltype); +void MODELCMD_Skeleton (int modeltype); +void MODELCMD_SkeletalFrame (int modeltype); +void MODELCMD_BeginGroup(int modeltype); +void MODELCMD_EndGroup(int modeltype); +void MODELCMD_Referenced(int modeltype); +void MODELCMD_NodeOrder(int modeltype); + +void Cmd_Modelname (void); +void Cmd_Base (void); +void Cmd_Cd (void); +void Cmd_Origin (void); +void Cmd_ScaleUp (void); +void Cmd_Frame (void); +void Cmd_Skin (void); +void Cmd_Skinsize (void); +void FinishModel (void); +void Cmd_Cluster (void); + +// Flexible Models +//void Cmd_FMModelname (void); +void Cmd_FMBase (qboolean GetST); +void Cmd_FMCd (void); +//void Cmd_FMOrigin (void); +void Cmd_FMCluster(); +void Cmd_FMSkeleton(); +//void Cmd_FMScaleUp (void); +void Cmd_FMFrame (void); +void Cmd_FMSkeletalFrame(); +void Cmd_FMSkin (void); +//void Cmd_FMSkinsize (void); +void Cmd_FMBeginGroup(void); +void Cmd_FMEndGroup(void); +void Cmd_FMReferenced(); +void Cmd_FMNodeOrder(void); +void FMFinishModel (void); +void GenSkin(char *ModelFile, char *OutputName, int Width, int Height); +void NewGen (char *ModelFile, char *OutputName, int width, int height); + + +void Cmd_Inverse16Table( void ); + +void Cmd_SpriteName (void); +void Cmd_Load (void); +void Cmd_SpriteFrame (void); +void Cmd_Sprdir (void); +void FinishSprite (void); + +void Cmd_Grab (void); +void Cmd_Raw (void); +void Cmd_Mip (void); +void Cmd_Environment (void); +void Cmd_Colormap (void); + +void Cmd_File (void); +void Cmd_Dir (void); +void Cmd_StartWad (void); +void Cmd_EndWad (void); +void Cmd_Mippal (void); +void Cmd_Mipdir (void); +void Cmd_Alphalight (void); + +void Cmd_Picdir (void); +void Cmd_Pic (void); + +void Cmd_Bookdir (void); +void Cmd_Book (void); + +void Cmd_TextureMix (void); + +void Cmd_Video (void); + +//void RemapZero (byte *pixels, byte *palette, int width, int height); + +void ReleaseFile (char *filename); + +extern byte *byteimage, *lbmpalette; +extern int byteimagewidth, byteimageheight; +extern qboolean TrueColorImage; +extern unsigned *longimage; +extern int longimagewidth, longimageheight; + +extern qboolean g_release; // don't grab, copy output data to new tree +extern char g_releasedir[1024]; // c:\quake2\baseq2, etc +extern qboolean g_archive; // don't grab, copy source data to new tree +extern qboolean do3ds; +extern char g_only[256]; // if set, only grab this cd +extern qboolean g_skipmodel; // set true when a cd is not g_only +extern qboolean g_no_opimizations; +extern int g_forcemodel; +extern qboolean g_verbose; +extern qboolean g_allow_newskin; +extern qboolean g_ignoreTriUV; //from qdata.c +extern qboolean g_dokeypress; + +extern char *trifileext; + +extern char g_materialFile[256]; + +extern unsigned total_x; +extern unsigned total_y; +extern unsigned total_textures; + +miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip); +miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip); diff --git a/tools/quake2/qdata_heretic2/qdata3_heretic2.vcproj b/tools/quake2/qdata_heretic2/qdata3_heretic2.vcproj new file mode 100644 index 00000000..4e0ae31e --- /dev/null +++ b/tools/quake2/qdata_heretic2/qdata3_heretic2.vcproj @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/quake2/qdata_heretic2/resource.h b/tools/quake2/qdata_heretic2/resource.h new file mode 100644 index 00000000..b71bb50e --- /dev/null +++ b/tools/quake2/qdata_heretic2/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Script1.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/tools/quake2/qdata_heretic2/script1.aps b/tools/quake2/qdata_heretic2/script1.aps new file mode 100644 index 0000000000000000000000000000000000000000..6650b67c6de853163570a230cecb91f4c3d4d645 GIT binary patch literal 18732 zcmeHPdAKD-bw3X#!WczdvS|F`!{S`8ygEHzIjvmg)Ukm5)a(5wDX)@ z2X`!sROF#&@5tBJ_dROwp&jD`>w6CDJm;Lf`}fGSgFDVUYv-YzJF+tm>^=98b;^M= zxtv>$spL3zT1V?dUB}7bEaGz-J`1F(z8HDt|6ELj|LNk3)j#-+uXOd*SL0s>xUu}t zhWZD;Rr@*d|9_6Efz6lT=ee4K@0aMmXfyuUY{2}z`L~%tVnzYYza`he`ERac`h!1A zaTqn>Den*bvT=l;-`?|{*W8Ad%g;+Lx#6};?|u`1|Lr|nAKJL=whi^snZI$|#>RCI z-Pm}}Wq|l|qyF58?>9bYW8>y~ZEV~Mj`?#p$hnBm#>NTw?2=NO^MFVH0xd3{C}#oB zng#k(usZnUBxoCchZK`X5lzTP3YVqktXa;1T?f|>A2@T@DQ6S?`R~oICYqW5Z}#p# zbKl{!b}im}=k5zo*ePe<`;NCqImiCqvY0_+mc<#5NAe=lH#Sbx@{*qa#~;frT%n8# z{1%krTSy67TFCYW_|899ZTiXYSSLzPoWlAddMJOz&nEn*w4wgy-)BoLW^{-S&|cb4 zdnmxa`)C(R-cP$}9UNbBTF`TghWK>ok@!tO?~C$0aL&PhyTCt02a&#v?>p(yvYZRi zvU9*V3xDm#XBWOL;@bh4YZ1S>-aYv2N1lDaLiF4sN?ON%`%oIuL+DP^dd>xFKV68n z@04{ip32&|{zYhJ9i<bT^2Myq=A(4RJuLNNy>bc<|dB~DM?xoC8Ay(szhl)mWcXwa4Jg+!bF%fO3<=K zB}@y_M3_+u%9A9@!*K>F(QyDCR02V?=CbT9NDUm^n_ z4=Iu5&==^YapZVHf~`RW+pHwW!tJ8)*J5XcZsYn|orq2|!64iwRG}?9BBz9c2%?1X zlFDO6a8y-+OKCVBi&Um_hjDZL5=+uh#Cfrtq}%CaV^l!l7a4ylJ#N8#RYjKBFyiuB zHXcl7KG`{2XsMo!^{y&2s#n>Jg12DxP_;QxR0<#9C!*8K^f-}2ST(q8SW;qgSeq@< zqLsa0$~G=D@DMZkQw@~#N(E<>d^PUO95O{U!x++Auqdf!l!MXCqLONPQ12G3U6{KV zA%5sNd6E_|3uvY2!&Iy_AP@FSVHRy~VDW_KA+p)@um+TQDJvCNn|3s?WQ7L{pbkB} z0i}Y+B%m%mq5*AnVn<;;cq1%-CdN+6^209gqy;C~R)jw6&UjqpVIJ|&7w9&6zQ#g7 z5+jji&Qgh5^a718i)cJb{5r#?7iq?{>_UuO;rnVnpq4gV=BWfQ(PIq40&}darb92* zaN?e>1T^L-is;fyWwU}X5=AUlS$r5PdZkWH#v)e97QIR*dr^|fig>YjwNB5Rl`^?a zm)DaENA{|PK6s5r#?TAYnorm;qw+3YVSs6fscfJ<_zT<*Qs6P8Dp#Lg*GMn?5ItMM z1A2WE9;ad@tXe#zH)wn^_MNdvYItpvkJ7%%2!aDTMS*)k9F1>3O z>np5B@1Dg53hUE*W-)lz=wNF=@14caY6%YMeRIH4GY-9f4p^$jrK{$ErEWa>z#Ont zj!z$)1D4tmboCstR8K(H)WOK9dN`nKB_#YXFT6-N(*9U>i$2mwhtr})jBU|J4GiN< z>cqC`IwN_ahLGK+>vd`XyQ;_?xESyq^0e!Ltl&in6>>>TTMlum$D(Z$hbfX3*v7ab0T>6wwPDPdM(WhndDjJ!r zPR&%iMV~d(oiue~Wn-!? zvvCwERkXYGC5f=PcHE@wrcR4)nkI{FCAnkKH)SeYe_j*CHmQM*O*iXw?o{dH2&>bk zZ)sqXm1}_2>Cm@jI(zo)Xmf$8s4jhHnnR`Z=oXpci@MVG<^ouDb=LC;FxgOZq5B#!@ zp*5AtZ7eUpYM{&9&vMJd_1ahne_dycQ>dywWz#pfU{`1sI{?99y0@PPm)n6 z7vwgU%46r^<=|_#dbDYQS4&>#3f=~|$_!!WK*wo>_fwOsn1U7^ufbGI(>t_Tr#q88 zF{a!A(%fF7*$7sRH>KRr0hD|PjYUqnBs6Bx9Stm026SNAbb?OyMUHh<_U6E9)15Se zVI-96Ft9pwq6S>vZpc0wSY5jFR8dkFP+>TNCt2x6i+h&_(b-lbmZjcR)&u_n`#e3E zhEVHYm`Jr83^7Xn(gb*-v1W!CAa^%`YHSQKsPDl*eYbn>O1iAbJl<7tA=vEE-Ala#N>Zn@%x77FgL|Rbz)9V8Sf631jgz;puz|FeEJ#LF56> zv}y*r+%~b?$+kx2cnHwzZ4HjFi&zdLx#k5{KwS;_BHQYC9vto@l?!O#JJi=W`?Ksl zq8+?vrw3|?{W}d=^dJpkGy}<{IYu^{PSw~Xmaabw1E@_8)=*U#m7V~+fYG{qLnS;3@n+_J53J^YHq;UW0dlkqr7 zb5tO-~MjFXi6OGt3(ugdPF|}(%#x}(!EVlqmz^LI}AQ&A=Oa_c`xn8O% z3r3g5^BJmu9-YyEjgiyoQ`$hW+ns8@GoY*i=gD+Pc7~K|6k9rWszzvBmpa6$|a zQDY6dVLo!kCO&M@KWJRKPAXt)lrgmEQJN!T1+^k<+NWW;GvIQBpRbLT6&ZGDzh+G0 zt#Ps%YqU%28cp+{R(Oxj)u8l5P09Lno<_qMQD!W>-Xu*$>?ylA9MHj83h%@7P_E)Z zYdEAsN2X+OTcw_d4jry&>|3kKxHn3FAm9MU1)37TNWui>Nx@4);V04%aFqJOc_cZu zrX-slqe)n=xEN-zC>GX&$7)p9hV(?uC>vKU z1DMrS+Z=k5W=-N$ETP?UgMmt1dU6x2RpHT7H15MxARdg>P%1!a#;2#&87>GgX?$v+ z7=oUr83^8Gyf=|k(t=z1j3$Pz;Z1K~VNHEz6GX5Iui424U79t)mnxQD44o6jv zbhIo4K>qbeq}3FbS=H8|OJ-P5t#XibVO{#SBh!rHdh}w=Q|C~HT8L$JSbs0oc&RFw z1Z;$26^sn5fkl^T4xAzkS9EnI4WTu#>17%%N3&d@EiAz=uOQ{X!Gf5Tcjy%rj@4so zCgAFYL0Nj2UOA7VEQD%8k6xuIrAeEHL?M2kUafImi%A*K8hT9-Z(?Sf*wlqB`H|Xuhf)kE=dl|oT6Ct7ELKDl8g*-W<{~-tpy{IOKNegAEv~;MOVZ(bWx@t=`n=!K_`= zz(o=$xddISAt%LJKJ90>MIUZpW zx`Ym0-ylG#RZKIm+%DZPi+c!-NYB}Fd-SncJoA>th|k_oK%YKd5warj5E1d5NKE1| z&x$e5jb&UYu)G$1QuE4~RvDZOY($GcqtWt69OGTN0yYB1|Dj=&?cq$$fNlD$hBXzP--+8;c|nD zh@j9meYMUDLJ?s&OVt&l5J9cnlZ&oB=+M{d+%Ss75_}atdsH%Z>FafhyaF(WQAv|k z9B~E#RxmYZZEWJcQ70qlP)n3~x?x1Nvs2ruAbER~w7Q&2=K{8+GSN zuKYH8;Lx|~l*D(vrsrs5!T5Ha#`hEEE(-R*qwmzYS&Sp?Fe+9pj+y!a^Tci0e!E|LQ~{$oh=)br`V%l zS5#KtrJvME+^9fQ<9XPlpVsj(#-PKf$qR0e9DKt*{j5$Zwc_JA3i~g$rYh=yeqN`R zw^evhBak?+9Ygv>J&T%twPn=CZuFORmYXD7M^3u65rR`VN58JP zS)rO#B0k+#A!7^|c)Rfu!sOWZp!=}*-i}K(YF}Yv`Pis)eOzg9VZNn6SUzwDp>8>- zqROZfx3at$5ZG8m7V0eY7ECN=hzjM|SVeAEXJC!sTI9tpHj!?Jj;k}2y_>|fD5j0& z9M70r|P1OG~=%E$qSA!KBP&*A>M2}%lw2M~neqquv`5YWXX+NQ-Bw2Zyl zILkWe7(R-^@o0owDhXdT!SR?y_mRn~;da;Y*bPHsoBp;+EDuVM*rC6x5^*pZX1uT= zxl8xemFAAimX_~0Dzrr>SE$ctksQtPqa|v$`l$Lr8k6m;5JdM)L_238((GSDMe12Q^Soxn5NCr_gs)|DYZ*^B{hFqbn_ z9Td2{z6yyANoY)NF;N&ip+Ki9xs3x;X4tf>8L9>9f+&}Y6Y{V^J*jTYFM00VZVmf= z8fkFkEXBO_WMDwC2IP4gP7fie1c#Jpa9N(J^Qj~9VMjgI&`J%m=nM_TiH}oXFU?do zn^KMCDaKZ;v@(R>lrNh?X#ky7N46LnBtyh(tKd^@6xX41H3BC{q?ikQXBkIl=V>H!*iM$Futx_pf^`K8 zx{IqSTL~e+79DP4tIHfd0%p;pn;1JtKx{g{i7cf8<{wy_E@)z|yjIOO-!5!IYXZU2 zRnFI?$237qAXs{b(H=dviF#{@c?0UxMNMca#UKPUpvN^KT#;VRD||?gZ{j|j6V*z@ zN1recty+o@>BaN#vbBhhKCubQ%GpA(;5gHLQj@^7>sBK+`s8_xvgL@1KBWPx@yH?3 zr)nfyL)d8~J07FUvikHi4RQ{-f+2uu(K8Gn^m2}eBi*KF>h#jUBDqb^(#h(Q7g9U) z>?#!j6O_&ejJ$ortxqUHi0ne$y?iFfFwO&n|XY66dStnPNBkS<-?B(26iui#6{ za}*e_m(8J6zL>zEeOVLdvp#j%1XT>^<@0b|z>r?iB*;U}^1cd+aOjmyMi@6ZF1@PB zQ4C#?N3U*Ds$w+Br^}n9vL^W`fYPm?*EC60N$PsFq6KtClLqZ7Bg}n-dHLEV0hgbX zh#eHUC&M*MdR>#^=5bK{LAB0k8GL%D2GLYJ5CP*OPkgFilduH6>qsPJCS)%M^zI|EDr>+z z9J{8EqOq+o7miNsvst}`qyZioGSRGPJ^}^%5YL-wPf-6dw zJ}^ruFM**AJ^G-Al~o##`MD2Z1G;(+Rv7mt1g@K2qdBbTVw&BdYiFT)ZkIl!DWwK= z0UmvLE?O_cr;p6A)Jjo37!csLAbnJm)RdRrP{G%qfm?Lle4KAU1GnjVjq}Zof;R&a z!)=+5H!xlRrq>_?fm<`5s2F2JPUY(6IWbJX+P4b0#y8Go@VTq31uM*_W*EFR;yZnc z(WOt%FgS>(!z}_{^Jg>%fe96i3=jh1$OOW>@(e`a5aV+u4?c8?XM&W0!V$*jYakAe z0(Af_1;Gi%7fjp_S3*7(cGtFxR7Ug#4l%xHQs81Hftsy)v2!}~r8y+5bq1$P|7mg% zR;X?qBq=T*x$4kM;2h)2CQp)*d>YLYIKudfNhk}dqO<}>7+*DUF2IRcy=&86#4*O# zOpcEYtS7=`8d?xI$@sd-FiOF_mn>In2o5y9VX`2L3d`au#gaPB6^=(YnH=*-gHLL| zX@b)NOpOS-xxuM4r+P7*EjK!BWwgFcB8 zh+}=%BynR9a*^7V!XS)wi%HJCGoo1EHwoo|7s}(i7-|Hn z8hiAEIYiv0OM z^b3=Nv*Dx27tk+{LYDI3oat94r;@GK!Jb9GHc4d%dr>%cac$Z+`o**9H*=`w67RL? zR+Caj<@A8_I&_;!V5`p8ka!5-XaomHO7t%Mmr2X;ScI-@0+JD*|-)@CEo|B`rRTo$S0T0XPK*aBW&Iz=z(}% zZwb%S@sr&L@qJmo2SCU-9(ZIUCC3xp{KWjD@YM7n{H>nL-b4IEH9w!v&x!9bcwCBp zLVO2!T=F`e2|s|R!gt~McDx<|?;}t@l??S#7pKp1b7>>g!OzvN%W`%@ibXu}y%&ES zh79~{Kfh<-Fr9_8b?{g4v^zi3&N%~o-yz>-px@r`0OZ<@=hl^E{}<#rUuv-~&k4}c zEpF literal 0 HcmV?d00001 diff --git a/tools/quake2/qdata_heretic2/script1.rc b/tools/quake2/qdata_heretic2/script1.rc new file mode 100644 index 00000000..70e36910 --- /dev/null +++ b/tools/quake2/qdata_heretic2/script1.rc @@ -0,0 +1,115 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Heavily modified from original ID tool\0" + VALUE "CompanyName", "Raven Software\0" + VALUE "FileDescription", "qdata\0" + VALUE "FileVersion", "2.0\0" + VALUE "InternalName", "qdata\0" + VALUE "LegalCopyright", "Copyright © 1998\0" + VALUE "OriginalFilename", "qdata.exe\0" + VALUE "ProductName", "Raven Software qdata\0" + VALUE "ProductVersion", "2.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/quake2/qdata_heretic2/sprites.c b/tools/quake2/qdata_heretic2/sprites.c new file mode 100644 index 00000000..68514c20 --- /dev/null +++ b/tools/quake2/qdata_heretic2/sprites.c @@ -0,0 +1,349 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "qdata.h" + +#define MAX_SPRFRAMES MAX_MD2SKINS + +dsprite_t sprite; +dsprframe_t frames[MAX_SPRFRAMES]; + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +qboolean TrueColorImage; +unsigned *longimage; +int longimagewidth, longimageheight; + +char spritename[1024]; + + +void FinishSprite (void); +void Cmd_Spritename (void); + +char spr_prefix[1024]; +char pic_prefix[1024]; + +extern char *g_outputDir; + + +/* +============== +FinishSprite +============== +*/ +void FinishSprite (void) +{ + FILE *spriteouthandle; + int i, curframe; + dsprite_t spritetemp; + char savename[1024]; + + if (sprite.numframes == 0) + return; + + if (!strlen(spritename)) + Error ("Didn't name sprite file"); + + sprintf (savename, "%sSprites/%s/%s.sp2", g_outputDir, spr_prefix, spritename); + + if (g_release) + { + char name[1024]; + + sprintf (name, "%s.sp2", spritename); + ReleaseFile (name); + spritename[0] = 0; // clear for a new sprite + sprite.numframes = 0; + return; + } + + + printf ("saving in %s\n", savename); + CreatePath (savename); + spriteouthandle = SafeOpenWrite (savename); + + +// +// write out the sprite header +// + spritetemp.ident = LittleLong (IDSPRITEHEADER); + spritetemp.version = LittleLong (SPRITE_VERSION); + spritetemp.numframes = LittleLong (sprite.numframes); + + SafeWrite (spriteouthandle, &spritetemp, 12); + +// +// write out the frames +// + curframe = 0; + + for (i=0 ; i 256) || (h > 256)) + Error ("Sprite has a dimension longer than 256"); + + xh = xl+w; + yh = yl+h; + + if (sprite.numframes >= MAX_SPRFRAMES) + Error ("Too many frames; increase MAX_SPRFRAMES\n"); + + pframe = &frames[sprite.numframes]; + pframe->width = w; + pframe->height = h; + pframe->origin_x = ox; + pframe->origin_y = oy; + + if (g_release) + { + ReleaseFile (pframe->name); + return; + } + + if (TrueColorImage) + { + sprintf (filename, "%ssprites/%s/%s_%i.m32", g_outputDir, spr_prefix, spritename, sprite.numframes); + sprintf (pframe->name, "%s/%s_%i.m32", spr_prefix, spritename, sprite.numframes); + + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl*longimagewidth) + xl; + destl = bufferl; + linedelta = (longimagewidth - w); + + for (y=yl ; ycontents = 0; + qtex32->value = 0; + strcpy(qtex32->name, pframe->name); + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + else + { + sprintf (filename, "%ssprites/%s/%s_%i.m8", g_outputDir, spr_prefix, spritename, sprite.numframes); + sprintf (pframe->name, "%s/%s_%i.m8", spr_prefix, spritename, sprite.numframes); + + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + source = byteimage + yl*byteimagewidth + xl; + dest = buffer; + linedelta = byteimagewidth - w; + + for (y=yl ; yflags = 0; + qtex->contents = 0; + qtex->value = 0; + strcpy(qtex->name, pframe->name); + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } + + sprite.numframes++; +} + + +/* +============== +Cmd_SpriteName +============== +*/ +void Cmd_SpriteName (void) +{ + if (sprite.numframes) + FinishSprite (); + + GetScriptToken (false); + strcpy (spritename, token); + memset (&sprite, 0, sizeof(sprite)); + memset (&frames, 0, sizeof(frames)); +} + + +/* +=============== +Cmd_Sprdir +=============== +*/ +void Cmd_Sprdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (spr_prefix, token); + // create the directory if needed + sprintf (filename, "%sSprites", g_outputDir); + Q_mkdir (filename); + sprintf (filename, "%sSprites/%s", g_outputDir, spr_prefix); + Q_mkdir (filename); +} + + diff --git a/tools/quake2/qdata_heretic2/svdcmp.c b/tools/quake2/qdata_heretic2/svdcmp.c new file mode 100644 index 00000000..8e02f8e4 --- /dev/null +++ b/tools/quake2/qdata_heretic2/svdcmp.c @@ -0,0 +1,490 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include + +static double at,bt,ct; +#define PYTHAG(a,b) ((at=fabs(a)) > (bt=fabs(b)) ? \ + (ct=bt/at,at*sqrt(1.0+ct*ct)) : (bt ? (ct=at/bt,bt*sqrt(1.0+ct*ct)): 0.0)) + + static double maxarg1,maxarg2; +#define MAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ + (maxarg1) : (maxarg2)) +#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) + +void ntrerror(char *s) +{ + printf("%s\n",s); + exit(1); +} + +double *allocVect(int sz) +{ + double *ret; + + ret = calloc(sizeof(double), (size_t)sz); + return ret; +} + +void freeVect(double *ret) +{ + free(ret); +} + +double **allocMatrix(int r,int c) +{ + double **ret; + + ret = calloc(sizeof(double), (size_t)(r*c)); + return ret; +} + +void freeMatrix(double **ret,int r) +{ + free(ret); +} + +void svdcmp(double** a, int m, int n, double* w, double** v) +{ + int flag,i,its,j,jj,k,l,nm; + double c,f,h,s,x,y,z; + double anorm=0.0,g=0.0,scale=0.0; + double *rv1; + void nrerror(); + + if (m < n) ntrerror("SVDCMP: You must augment A with extra zero rows"); + rv1=allocVect(n); + for (i=1;i<=n;i++) { + l=i+1; + rv1[i]=scale*g; + g=s=scale=0.0; + if (i <= m) { + for (k=i;k<=m;k++) scale += fabs(a[k][i]); + if (scale) { + for (k=i;k<=m;k++) { + a[k][i] /= scale; + s += a[k][i]*a[k][i]; + } + f=a[i][i]; + g = -SIGN(sqrt(s),f); + h=f*g-s; + a[i][i]=f-g; + if (i != n) { + for (j=l;j<=n;j++) { + for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j]; + f=s/h; + for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; + } + } + for (k=i;k<=m;k++) a[k][i] *= scale; + } + } + w[i]=scale*g; + g=s=scale=0.0; + if (i <= m && i != n) { + for (k=l;k<=n;k++) scale += fabs(a[i][k]); + if (scale) { + for (k=l;k<=n;k++) { + a[i][k] /= scale; + s += a[i][k]*a[i][k]; + } + f=a[i][l]; + g = -SIGN(sqrt(s),f); + h=f*g-s; + a[i][l]=f-g; + for (k=l;k<=n;k++) rv1[k]=a[i][k]/h; + if (i != m) { + for (j=l;j<=m;j++) { + for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k]; + for (k=l;k<=n;k++) a[j][k] += s*rv1[k]; + } + } + for (k=l;k<=n;k++) a[i][k] *= scale; + } + } + anorm=MAX(anorm,(fabs(w[i])+fabs(rv1[i]))); + } + for (i=n;i>=1;i--) { + if (i < n) { + if (g) { + for (j=l;j<=n;j++) + v[j][i]=(a[i][j]/a[i][l])/g; + for (j=l;j<=n;j++) { + for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j]; + for (k=l;k<=n;k++) v[k][j] += s*v[k][i]; + } + } + for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0; + } + v[i][i]=1.0; + g=rv1[i]; + l=i; + } + for (i=n;i>=1;i--) { + l=i+1; + g=w[i]; + if (i < n) + for (j=l;j<=n;j++) a[i][j]=0.0; + if (g) { + g=1.0/g; + if (i != n) { + for (j=l;j<=n;j++) { + for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j]; + f=(s/a[i][i])*g; + for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; + } + } + for (j=i;j<=m;j++) a[j][i] *= g; + } else { + for (j=i;j<=m;j++) a[j][i]=0.0; + } + ++a[i][i]; + } + for (k=n;k>=1;k--) { + for (its=1;its<=30;its++) { + flag=1; + for (l=k;l>=1;l--) { + nm=l-1; + if (fabs(rv1[l])+anorm == anorm) { + flag=0; + break; + } + if (fabs(w[nm])+anorm == anorm) break; + } + if (flag) { + c=0.0; + s=1.0; + for (i=l;i<=k;i++) { + f=s*rv1[i]; + if (fabs(f)+anorm != anorm) { + g=w[i]; + h=PYTHAG(f,g); + w[i]=h; + h=1.0/h; + c=g*h; + s=(-f*h); + for (j=1;j<=m;j++) { + y=a[j][nm]; + z=a[j][i]; + a[j][nm]=y*c+z*s; + a[j][i]=z*c-y*s; + } + } + } + } + z=w[k]; + if (l == k) { + if (z < 0.0) { + w[k] = -z; + for (j=1;j<=n;j++) v[j][k]=(-v[j][k]); + } + break; + } + if (its == 30) ntrerror("No convergence in 30 SVDCMP iterations"); + x=w[l]; + nm=k-1; + y=w[nm]; + g=rv1[nm]; + h=rv1[k]; + f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); + g=PYTHAG(f,1.0); + f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; + c=s=1.0; + for (j=l;j<=nm;j++) { + i=j+1; + g=rv1[i]; + y=w[i]; + h=s*g; + g=c*g; + z=PYTHAG(f,h); + rv1[j]=z; + c=f/z; + s=h/z; + f=x*c+g*s; + g=g*c-x*s; + h=y*s; + y=y*c; + for (jj=1;jj<=n;jj++) { + x=v[jj][j]; + z=v[jj][i]; + v[jj][j]=x*c+z*s; + v[jj][i]=z*c-x*s; + } + z=PYTHAG(f,h); + w[j]=z; + if (z) { + z=1.0/z; + c=f*z; + s=h*z; + } + f=(c*g)+(s*y); + x=(c*y)-(s*g); + for (jj=1;jj<=m;jj++) { + y=a[jj][j]; + z=a[jj][i]; + a[jj][j]=y*c+z*s; + a[jj][i]=z*c-y*s; + } + } + rv1[l]=0.0; + rv1[k]=f; + w[k]=x; + } + } + freeVect(rv1); +} + + + +void svbksb(double** u, double* w, double** v,int m, int n, double* b, double* x) +{ + int jj,j,i; + double s,*tmp; + tmp=allocVect(n); + for (j=1;j<=n;j++) + { + s=0.0; + if (w[j]) + { + for (i=1;i<=m;i++) + s += u[i][j]*b[i]; + s /= w[j]; + } + tmp[j]=s; + } + for (j=1;j<=n;j++) + { + s=0.0; + for (jj=1;jj<=n;jj++) + s += v[j][jj]*tmp[jj]; + x[j]=s; + } + freeVect(tmp); +} + +#undef SIGN +#undef MAX +#undef PYTHAG + + +#if 1 +void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize) +{ + int usedfs; + int *remap; + int i,j; + double **da; + double **v; + double *w; + int DOFerr; + float mx; + int bestat; + + if (nframes>framesize) + usedfs=nframes; + else + usedfs=framesize; + + da=allocMatrix(usedfs,nframes); + v=allocMatrix(nframes,nframes); + w=allocVect(nframes); + + DOFerr = 0; //false + for (i=0;imx) + { + mx=(float) fabs(w[i+1]); + bestat=i; + } + } + + if(mx>0) + { + remap[bestat]=j; + } + else + { + DOFerr = 1; //true + } + } + + if(DOFerr) + { + printf("Warning: To many degrees of freedom! File size may increase\n"); + + for (i=0;imx) + { + mx=fabs(w[i+1]); + bestat=i; + } + } + assert(mx>-.5f); + remap[bestat]=j; + } + // josh **DO NOT** put your dof>nframes mod here + for (i=0;i=3); + base[0]=pnts[0]; + base[1]=pnts[1]; + base[2]=pnts[2]; + for (i=1;i> 5 ) & 63 ) << 2; + b[0] = ( ( color >> 11 ) & 31 ) << 3; + + for ( i = 0; i < 256; i++ ) + { + r[1] = ( d_8to24table[i] >> 0 ) & 0xFF; + g[1] = ( d_8to24table[i] >> 8 ) & 0xFF; + b[1] = ( d_8to24table[i] >> 16 ) & 0xFF; + + d = ( r[1] - r[0] ) * ( r[1] - r[0] ) + + ( g[1] - g[0] ) * ( g[1] - g[0] ) + + ( b[1] - b[0] ) * ( b[1] - b[0] ); + + if ( d < closest_distance_so_far ) + { + closest_distance_so_far = d; + closest_so_far = i; + } + } + + return closest_so_far; +} +*/ + +extern byte BestColor( int, int, int, int, int ); + +void Inverse16_BuildTable( void ) +{ + int i; + + /* + ** create the 16-to-8 table + */ + for ( i = 0; i < 65536; i++ ) + { + int r = i & 31; + int g = ( i >> 5 ) & 63; + int b = ( i >> 11 ) & 31; + + r <<= 3; + g <<= 2; + b <<= 3; + + inverse16to8table[i] = BestColor( r, g, b, 0, 255 ); + } +} + +void Alphalight_Thread (int i) +{ + int j; + float r, g, b; + float mr, mg, mb, ma; + float distortion, bestdistortion; + float v; + + r = (i>>10) * (1.0/16); + g = ((i>>5)&31) * (1.0/16); + b = (i&31) * (1.0/16); + + bestdistortion = 999999; + for (j=0 ; j<16*16*16*16 ; j++) + { + mr = (j>>12) * (1.0/16); + mg = ((j>>8)&15) * (1.0/16); + mb = ((j>>4)&15) * (1.0/16); + ma = (j&15) * (1.0/16); + + v = r * 0.5 - (mr*ma + 0.5*(1.0-ma)); + distortion = v*v; + v = g * 0.5 - (mg*ma + 0.5*(1.0-ma)); + distortion += v*v; + v = b * 0.5 - (mb*ma + 0.5*(1.0-ma)); + distortion += v*v; + + distortion *= 1.0 + ma*4; + + if (distortion < bestdistortion) + { + bestdistortion = distortion; + alphamap[i] = j; + } + } +} + +void Cmd_Alphalight (void) +{ + char savename[1024]; + + GetScriptToken (false); + + if (g_release) + { + ReleaseFile (token); + return; + } + + sprintf (savename, "%s%s", gamedir, token); + printf ("Building alphalight table...\n"); + + RunThreadsOnIndividual (32*32*32, true, Alphalight_Thread); + + SaveFile (savename, (byte *)alphamap, sizeof(alphamap)); +} + + +void Cmd_Inverse16Table( void ) +{ + char savename[1024]; + + if ( g_release ) + { + sprintf (savename, "pics/16to8.dat"); + ReleaseFile( savename ); + return; + } + + sprintf (savename, "%spics/16to8.dat", gamedir); + printf ("Building inverse 16-to-8 table...\n"); + + Inverse16_BuildTable(); + + SaveFile( savename, (byte *) inverse16to8table, sizeof( inverse16to8table ) ); +} diff --git a/tools/quake2/qdata_heretic2/tmix.c b/tools/quake2/qdata_heretic2/tmix.c new file mode 100644 index 00000000..ad1d1902 --- /dev/null +++ b/tools/quake2/qdata_heretic2/tmix.c @@ -0,0 +1,698 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qdata.h" +#include "flex.h" + +#define MAXFILES 2048 + +typedef struct +{ + int x; + int y; + int w; + int h; + int cw; + int ch; + int rw; + int index; + int depth; + int col; + int baseline; + char name[128]; +} Coords; + +int filenum; +int valid; +Coords in[MAXFILES]; +Coords out; +char outscript[256]; +char sourcedir[256]; +char outusage[256]; +char root[32]; + +int destsize = 0; +byte *pixels = NULL; // Buffer to load image +long *outpixels = NULL; // Buffer to store combined textures +long *usagemap = NULL; // Buffer of usage map +void *bmptemp = NULL; // Buffer of usage map +byte *map = NULL; + +int xcharsize; +int ycharsize; +int dosort = 0; +int missed = 0; +int overlap = 0; +int nobaseline = 0; +int percent; + +////////////////////////////////////////////////// +// Setting the char based usage map // +////////////////////////////////////////////////// + +byte TryPlace(Coords *coord) +{ + int x, y; + byte entry = 0; + byte *mapitem; + + mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw); + + for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw) + { + for (x = 0; x < coord->cw; x++) + { + if (entry |= *mapitem++ & 8) + { + return(entry); + } + } + } + return(entry); +} + +void SetMap(Coords *coord) +{ + int x, y; + byte *mapitem; + + mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw); + + for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw) + for (x = 0; x < coord->cw; x++) + *mapitem++ |= 8; +} + +////////////////////////////////////////////////// +// Setting the pixel based usage map // +////////////////////////////////////////////////// + +void CheckOverlap(Coords *coord) +{ + int x; + int y; + long *dest; + + x = coord->x; + y = coord->y; + + dest = (long *)(usagemap + x + (y * out.w)); + + for (y = 0; y < coord->h; y++, dest += out.w - coord->w) + { + for (x = 0; x < coord->w; x++) + { + if (*dest++) + { + overlap++; + return; + } + } + } +} + +void SetUsageMap(Coords *coord) +{ + int x; + int y; + long *dest; + + x = coord->x; + y = coord->y; + + dest = (long *)(usagemap + x + (y * out.w)); + + for (y = 0; y < coord->h; y++, dest += out.w - coord->w) + { + for (x = 0; x < coord->w; x++) + { + *dest++ = coord->col; + } + } +} + +////////////////////////////////////////////////// +// Flips the BMP image to the correct way up // +////////////////////////////////////////////////// + +void CopyLine(byte *dest, byte *src, int size) +{ + int x; + + for (x = 0; x < size; x++) + *dest++ = *src++; +} + +/****************************************************/ +/* Printing headers etc */ +/****************************************************/ + +void RemoveLeading(char *name) +{ + int i; + char temp[128]; + + for(i = strlen(name) - 1; i > 0; i--) + { + if((name[i] == '\\') || (name[i] == '/')) + { + strcpy(temp, name + i + 1); + strcpy(name, temp); + return; + } + } +} + +void RemoveExt(char *name) +{ + while ((*name != '.') && *name) + name++; + *name = 0; +} + +/****************************************************/ +/* Misc calcualtions */ +/****************************************************/ + +int TotalArea() +{ + int i; + int total = 0; + + for (i = 0; i < (filenum + 2); i++) + total += in[i].w * in[i].h; + + return(total); +} + +/****************************************************/ +/* Setup and checking of all info */ +/****************************************************/ + +void InitVars() +{ + filenum = 0; + valid = 0; + dosort = 0; + missed = 0; + overlap = 0; + nobaseline = 0; + + memset(outscript, 0, sizeof(outscript)); + memset(outscript, 0, sizeof(sourcedir)); + memset(outscript, 0, sizeof(outusage)); + memset(outscript, 0, sizeof(root)); + + memset(in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); +} +void Cleanup() +{ + if (pixels) + free(pixels); + if (usagemap) + free(usagemap); + if (outpixels) + free(outpixels); + if (bmptemp) + free(bmptemp); + if (map) + free(map); +} + +typedef struct glxy_s +{ + float xl, yt, xr, yb; + int w, h, baseline; +} glxy_t; + +int SaveScript(char *name) +{ + FILE *fp; + int i, j; + glxy_t buff; + + if(fp = fopen(name, "wb")) + { + for (j = 0; j < filenum; j++) + { + for (i = 0; i < filenum; i++) + { + if (in[i].index == j) + { + if (in[i].depth) + { + buff.xl = (float)in[i].x / (float)out.w; + buff.yt = (float)in[i].y / (float)out.h; + buff.xr = ((float)in[i].w + (float)in[i].x) / (float)out.w; + buff.yb = ((float)in[i].h + (float)in[i].y) / (float)out.h; + buff.w = in[i].w; + buff.h = in[i].h; + buff.baseline = in[i].baseline; + } + else + { + memset(&buff, 0, sizeof(glxy_t)); + } + fwrite(&buff, 1, sizeof(glxy_t), fp); + i = filenum; + } + } + } + fclose(fp); + return(true); + } + else + return(false); +} + +int GetScriptInfo(char *name) +{ + FILE *fp; + char buffer[256]; + char tempbuff[256]; + char delims[] = {" \t,\n"}; + + printf("Opening script file %s.\n", name); + + if (fp = fopen(name, "r")) + { + while(fgets(buffer, 256, fp)) + { + if (strncmp(buffer, "//", 2) && strncmp(buffer, "\n", 1)) + { + strupr(buffer); + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "OUTPUT") == 0) + { + strcpy(out.name, strtok(NULL, delims)); + strlwr(out.name); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "SOURCEDIR") == 0) + { + strcpy(tempbuff, strtok(NULL, delims)); + strcpy(sourcedir, ExpandPathAndArchive(tempbuff)); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "DOSORT") == 0) + dosort = 1; + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "XCHARSIZE") == 0) + xcharsize = strtol(strtok(NULL, delims), NULL, 0); + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "YCHARSIZE") == 0) + ycharsize = strtol(strtok(NULL, delims), NULL, 0); + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "OUTSCRIPT") == 0) + { + strcpy(outscript, strtok(NULL, delims)); + strlwr(outscript); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "OUTUSAGE") == 0) + strcpy(outusage, strtok(NULL, delims)); + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "POS") == 0) + { + out.w = strtol(strtok(NULL, delims), NULL, 0); + out.h = strtol(strtok(NULL, delims), NULL, 0); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "FILE") == 0) + { + strcpy(in[filenum].name, strtok(NULL, delims)); + in[filenum].x = strtol(strtok(NULL, delims), NULL, 0); + in[filenum].y = strtol(strtok(NULL, delims), NULL, 0); + in[filenum].col = strtol(strtok(NULL, delims), NULL, 0); + filenum++; + } + } + } + fclose(fp); + return(true); + } + else + { + printf("ERROR : Could not open script file.\n"); + return(false); + } +} + +int CheckVars() +{ + int i; + + if (out.name[0] == 0) + { + printf("ERROR : No output name specified.\n"); + return(false); + } + if ((out.w <= 0) || (out.h <= 0)) + { + printf("ERROR : Invalid VRAM coordinates.\n"); + return(false); + } + if (filenum == 0) + { + printf("ERROR : No input files specified.\n"); + return(false); + } + for (i = 0; i < filenum; i++) + if (in[i].name[0] == 0) + { + printf("ERROR : Input filename invalid.\n"); + return(false); + } + return(true); +} + +// Makes sure texture is totally within the output area + +int CheckCoords(Coords *coord) +{ + if ((coord->x + coord->w) > out.w) + return(false); + if ((coord->y + coord->h) > out.h) + return(false); + + return(true); +} +// Gets the width, height, palette width and palette height of each BMP file + +int GetFileDimensions() +{ + int i; + int width, height; + char name[128]; + + for (i = 0; i < filenum; i++) + { + in[i].index = i; + + strcpy(name, sourcedir); + strcat(name, in[i].name); + printf("Getting file dimensions, file : %s \r", in[i].name); + if(FileExists(name)) + { + LoadAnyImage(name, NULL, NULL, &width, &height); + in[i].depth = 32; + in[i].rw = width; + in[i].w = width; // makes it width in + in[i].h = height; + in[i].cw = (in[i].w + (xcharsize - 1)) / xcharsize; + in[i].ch = (in[i].h + (ycharsize - 1)) / ycharsize; + + if (!CheckCoords(&in[i]) && (in[i].x >= 0)) + { + printf("Error : texture %s out of bounds.\n", in[i].name); + return(false); + } + valid++; + } + else + { + in[i].depth = 0; + in[i].x = -1; + in[i].y = -1; + in[i].w = 0; + in[i].h = 0; + } + } + printf("\n\n"); + return(true); +} + +// Sorts files into order for optimal space finding +// Fixed position ones first, followed by the others in descending size +// The theory being that it is easier to find space for smaller textures. +// size = (width + height) +// For space finding it is easier to place a 32x32 than a 128x2 + +#define WEIGHT 0x8000 + +void Swap(Coords *a, Coords *b) +{ + Coords c; + + c = *a; + *a = *b; + *b = c; +} + +void SortInNames() +{ + int i, j; + int largest, largcount; + int size; + + printf("Sorting filenames by size.\n\n"); + + for (j = 0; j < filenum; j++) + { + largest = -1; + largcount = -1; + + for (i = j; i < filenum; i++) + { + if (in[i].depth) + { + size = in[i].w + in[i].h; + + if ((in[i].x < 0) && (size > largest)) + { + largcount = i; + largest = size; + } + } + } + if ((largcount >= 0) && (largcount != j)) + Swap(&in[j], &in[largcount]); + } +} + +int SetVars(char *name) +{ + if (!GetScriptInfo(name)) + return(false); + + if (!CheckVars()) + return(false); + + destsize = out.w * out.h; + + out.cw = out.w / xcharsize; + out.ch = out.h / ycharsize; + + if ((usagemap = (long *)SafeMalloc(destsize * 4, "")) == NULL) + return(false); + if ((outpixels = (long *)SafeMalloc(destsize * 4, "")) == NULL) + return(false); + if ((bmptemp = (void *)SafeMalloc(destsize * 4, "")) == NULL) + return(false); + if ((map = (byte *)SafeMalloc(destsize / (xcharsize * ycharsize), "")) == NULL) + return(false); + + if (GetFileDimensions() == false) + return(false); + + if (dosort) + SortInNames(); + + return(true); +} +/****************************************************/ +/* Actual copying routines */ +/****************************************************/ + +int FindCoords(Coords *coord) +{ + int tx, ty; + + if (coord->x >= 0) + { + SetMap(coord); + return(true); + } + else + { + for (ty = 0; ty < out.ch; ty++) + { + for (tx = 0; tx < out.cw; tx++) + { + coord->x = (tx * xcharsize); + coord->y = (ty * ycharsize); + + if (CheckCoords(coord) && !TryPlace(coord)) + { + SetMap(coord); + return(true); + } + } + } + } + coord->x = -1; + coord->y = -1; + + return(false); +} + +void CheckBaseline(int i) +{ + int y; + long *pix; + + in[i].baseline = -1; + pix = (long *)pixels; + + for(y = 0; y < in[i].h; y++, pix += in[i].w) + { + if((*pix & 0x00ffffff) == 0x00ff00ff) + { + in[i].baseline = y; + break; + } + } + pix = (long *)pixels; + for(y = 0; y < in[i].w * in[i].h; y++, pix++) + { + if((*pix & 0x00ffffff) == 0x00ff00ff) + { + *pix = 0; + } + } + + if(in[i].baseline == -1) + { + printf("\nERROR : %s has no baseline\n", in[i].name); + nobaseline++; + } +} + +void CopyToMain32(Coords *coord) +{ + int x; + int y; + long *source; + long *dest; + + x = coord->x; + y = coord->y; + + source = (long *)pixels; + dest = (long *)(outpixels + x + (y * out.w)); + + for (y = 0; y < coord->h; y++, dest += out.w - coord->w) + { + for (x = 0; x < coord->w; x++) + { + *dest++ = *source++; + } + } +} + +void CreateMain() +{ + int i, count; + int width, height; + char name[128]; + + for (i = 0, count = 0; i < filenum; i++) + { + if (in[i].depth) + { + printf("\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline); + count++; + if (!FindCoords(&in[i])) + missed++; + else + { + strcpy(name, sourcedir); + strcat(name, in[i].name); + LoadAnyImage(name, &pixels, NULL, &width, &height); + CheckBaseline(i); + CheckOverlap(&in[i]); + CopyToMain32(&in[i]); + SetUsageMap(&in[i]); + } + } + } +} + +void Cmd_TextureMix() +{ + miptex32_t *qtex32; + char filename[1024]; + int size; + + InitVars(); + + GetScriptToken (false); + + strcpy(root, token); + RemoveExt(root); + RemoveLeading(root); + + strcpy(filename, ExpandPathAndArchive(token)); + if (SetVars(filename)) + { + // Create combined texture + percent = ((TotalArea() * 100) / (out.w * out.h)); + printf("Total area consumed : %d%%\n", percent); + printf("Texture resolution : %dx%d pixels.\n", xcharsize, ycharsize); + CreateMain(); + + // Save image as m32 + sprintf (filename, "%spics/misc/%s.m32", gamedir, out.name); + qtex32 = CreateMip32((unsigned *)outpixels, out.w, out.h, &size, false); + + qtex32->contents = 0; + qtex32->value = 0; + qtex32->scale_x = 1.0; + qtex32->scale_y = 1.0; + sprintf (qtex32->name, "misc/%s", out.name); + + printf ("\n\nwriting %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + free (qtex32); + + // Save out script file + sprintf (filename, "%spics/misc/%s.fnt", gamedir, outscript); + printf("Writing %s as script file\n", filename); + if (!SaveScript(filename)) + { + printf("Unable to save output script.\n"); + } + } + printf("Everythings groovy.\n"); + Cleanup(); +} + +// end + diff --git a/tools/quake2/qdata_heretic2/video.c b/tools/quake2/qdata_heretic2/video.c new file mode 100644 index 00000000..b41c6598 --- /dev/null +++ b/tools/quake2/qdata_heretic2/video.c @@ -0,0 +1,1149 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// To do + +// Sound error handling (when sound too short) +// rle b4 huffing +// adpcm encoding of sound + +#if 0 +#include "qdata.h" +#include "flex.h" +#include "fc.h" +#include "adpcm.h" + +#define MIN_REPT 15 +#define MAX_REPT 0 +#define HUF_TOKENS (256 + MAX_REPT) + +#define BLOCKSIZE 8 + +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#define SQRT2 1.414213562 + +typedef struct hnode_s +{ + int count; + qboolean used; + int children[2]; +} hnode_t; + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + +// These weren`t picked out my ass.... +// They were defined at http://www.rahul.net/jfm/dct.html +// However, I think he plucked them out of his ass..... + +float Quantise[BLOCKSIZE * BLOCKSIZE]; + +float LUT_Quantise[BLOCKSIZE * BLOCKSIZE] = +{ + 16.0F/16.0F, 11.0F/16.0F, 10.0F/16.0F, 16.0F/16.0F, 24.0F/16.0F, 40.0F/16.0F, 51.0F/16.0F, 61.0F/16.0F, + 12.0F/16.0F, 13.0F/16.0F, 14.0F/16.0F, 19.0F/16.0F, 26.0F/16.0F, 58.0F/16.0F, 60.0F/16.0F, 55.0F/16.0F, + 14.0F/16.0F, 13.0F/16.0F, 16.0F/16.0F, 24.0F/16.0F, 40.0F/16.0F, 57.0F/16.0F, 69.0F/16.0F, 56.0F/16.0F, + 14.0F/16.0F, 17.0F/16.0F, 22.0F/16.0F, 29.0F/16.0F, 51.0F/16.0F, 87.0F/16.0F, 80.0F/16.0F, 62.0F/16.0F, + 18.0F/16.0F, 22.0F/16.0F, 37.0F/16.0F, 56.0F/16.0F, 68.0F/16.0F,109.0F/16.0F,103.0F/16.0F, 77.0F/16.0F, + 24.0F/16.0F, 35.0F/16.0F, 55.0F/16.0F, 64.0F/16.0F, 81.0F/16.0F,104.0F/16.0F,113.0F/16.0F, 92.0F/16.0F, + 49.0F/16.0F, 64.0F/16.0F, 78.0F/16.0F, 87.0F/16.0F,103.0F/16.0F,121.0F/16.0F,120.0F/16.0F,101.0F/16.0F, + 72.0F/16.0F, 92.0F/16.0F, 95.0F/16.0F, 98.0F/16.0F,112.0F/16.0F,100.0F/16.0F,103.0F/16.0F, 99.0F/16.0F +}; + +int LUT_ZZ[BLOCKSIZE * BLOCKSIZE] = +{ + 0, + 1, 8, + 16, 9, 2, + 3, 10, 17, 24, + 32, 25, 18, 11, 4, + 5, 12, 19, 26, 33, 40, + 48, 41, 34, 27, 20, 13, 6, + 7, 14, 21, 28, 35, 42, 49, 56, + 57, 50, 43, 36, 29, 22, 15, + 23, 30, 37, 44, 51, 58, + 59, 52, 45, 38, 31, + 39, 46, 53, 60, + 61, 54, 47, + 55, 62, + 63 +}; + +char base[32]; + +byte *soundtrack; + +byte scaled[256][HUF_TOKENS]; +unsigned int charbits1[256][HUF_TOKENS]; +int charbitscount1[256][HUF_TOKENS]; +hnode_t hnodes1[256][HUF_TOKENS * 2]; +int numhnodes1[256]; +int order0counts[256]; +int numhnodes; +hnode_t hnodes[512]; +unsigned charbits[256]; +int charbitscount[256]; + +CineHead_t cinehead; + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + +float dctbase[BLOCKSIZE][BLOCKSIZE]; +float red[BLOCKSIZE * BLOCKSIZE]; +float green[BLOCKSIZE * BLOCKSIZE]; +float blue[BLOCKSIZE * BLOCKSIZE]; +float temp[BLOCKSIZE * BLOCKSIZE]; + +wavinfo_t wavinfo; +adpcm_t adpcm; + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + +/* Intel ADPCM step variation table */ +static int indexTable[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8, +}; + +static int stepsizeTable[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +#if 0 +static void adpcm_decoder(char *indata, short *outdata, int len, adpcm_state_t *state) +{ + signed char *inp; /* Input buffer pointer */ + short *outp; /* output buffer pointer */ + int sign; /* Current adpcm sign bit */ + int delta; /* Current adpcm output value */ + int step; /* Stepsize */ + int valpred; /* Predicted value */ + int vpdiff; /* Current change to valpred */ + int index; /* Current step change index */ + int inputbuffer; /* place to keep next 4-bit value */ + int bufferstep; /* toggle between inputbuffer/input */ + + outp = outdata; + inp = (signed char *)indata; + + valpred = state->valprev; + index = state->index; + step = stepsizeTable[index]; + + bufferstep = 0; + + for(; len > 0; len--) + { + /* Step 1 - get the delta value */ + if (bufferstep) + delta = inputbuffer & 0xf; + else + { + inputbuffer = *inp++; + delta = (inputbuffer >> 4) & 0xf; + } + bufferstep = !bufferstep; + + /* Step 2 - Find new index value (for later) */ + index += indexTable[delta]; + if(index < 0) + index = 0; + if(index > 88) + index = 88; + + /* Step 3 - Separate sign and magnitude */ + sign = delta & 8; + delta = delta & 7; + + /* Step 4 - Compute difference and new predicted value */ + /* + ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment + ** in adpcm_coder. + */ + vpdiff = step >> 3; + if(delta & 4) + vpdiff += step; + if(delta & 2) + vpdiff += step>>1; + if(delta & 1) + vpdiff += step>>2; + + if (sign) + valpred -= vpdiff; + else + valpred += vpdiff; + + /* Step 5 - clamp output value */ + if (valpred > 32767) + valpred = 32767; + else if (valpred < -32768) + valpred = -32768; + + /* Step 6 - Update step value */ + step = stepsizeTable[index]; + + /* Step 7 - Output value */ + *outp++ = valpred; + } + + state->valprev = valpred; + state->index = index; +} +#endif + +void adpcm_coder(short *inp, adpcm_t *adpcm) +{ + int val; /* Current input sample value */ + int sign; /* Current adpcm sign bit */ + int delta; /* Current adpcm output value */ + int diff; /* Difference between val and valprev */ + int step; /* Stepsize */ + int valpred; /* Predicted output value */ + int vpdiff; /* Current change to valpred */ + int index; /* Current step change index */ + int outputbuffer; /* place to keep previous 4-bit value */ + int bufferstep; /* toggle between outputbuffer/output */ + adpcm_state_t *state; + char *outp; + int len; + + state = &adpcm->state; + len = state->count; + outp = adpcm->adpcm; + + valpred = state->in_valprev; + index = state->in_index; + step = stepsizeTable[index]; + + bufferstep = 1; + while(len--) + { + val = *inp++; + + /* Step 1 - compute difference with previous value */ + diff = val - valpred; + sign = (diff < 0) ? 8 : 0; + if (sign) + diff = -diff; + + /* Step 2 - Divide and clamp */ + /* Note: + ** This code *approximately* computes: + ** delta = diff*4/step; + ** vpdiff = (delta+0.5)*step/4; + ** but in shift step bits are dropped. The net result of this is + ** that even if you have fast mul/div hardware you cannot put it to + ** good use since the fixup would be too expensive. + */ + delta = 0; + vpdiff = (step >> 3); + + if (diff >= step) + { + delta = 4; + diff -= step; + vpdiff += step; + } + step >>= 1; + if (diff >= step) + { + delta |= 2; + diff -= step; + vpdiff += step; + } + step >>= 1; + if (diff >= step) + { + delta |= 1; + vpdiff += step; + } + + /* Step 3 - Update previous value */ + if (sign) + valpred -= vpdiff; + else + valpred += vpdiff; + + /* Step 4 - Clamp previous value to 16 bits */ + if (valpred > 32767) + valpred = 32767; + else if (valpred < -32768) + valpred = -32768; + + /* Step 5 - Assemble value, update index and step values */ + delta |= sign; + + index += indexTable[delta]; + if (index < 0) + index = 0; + if (index > 88) + index = 88; + step = stepsizeTable[index]; + + /* Step 6 - Output value */ + if (bufferstep) + outputbuffer = (delta << 4) & 0xf0; + else + *outp++ = (delta & 0x0f) | outputbuffer; + + bufferstep = !bufferstep; + } + + /* Output last step, if needed */ + if(!bufferstep) + *outp++ = outputbuffer; + + state->out_valprev = valpred; + state->out_index = index; +} + +void FindNextChunk(char *name) +{ + while(1) + { + data_p = last_chunk; + + if(data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = *(long *)data_p; + data_p += 4; + if(iff_chunk_len < 0) + { + data_p = NULL; + return; + } + + data_p -= 8; + last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1); + if (!strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p = iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = *(long *)data_p; + data_p += 4; + printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } + while(data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset(&info, 0, sizeof(info)); + + if (!wav) + return(info); + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !strncmp(data_p + 8, "WAVE", 4))) + { + printf("Missing RIFF/WAVE chunks\n"); + return(info); + } + +// get "fmt " chunk + iff_data = data_p + 12; + + FindChunk("fmt "); + if(!data_p) + { + printf("Missing fmt chunk\n"); + return(info); + } + data_p += 8; + format = *(short *)data_p; + data_p += 2; + if (format != 1) + { + printf("Microsoft PCM format only\n"); + return(info); + } + + info.channels = *(short *)data_p; + data_p += 2; + info.rate = *(long *)data_p; + data_p += 4; + data_p += 6; + info.width = *(short *)data_p / 8; + data_p += 2; + +// get cue chunk + FindChunk("cue "); + if(data_p) + { + data_p += 32; + info.loopstart = *(long *)data_p; + data_p += 4; + +// if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if(data_p) + { +// this is not a proper parse, but it works with cooledit... + if (!strncmp (data_p + 28, "mark", 4)) + { + data_p += 24; + i = *(long *)data_p; // samples in loop + data_p += 4; + info.samples = info.loopstart + i; + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + printf("Missing data chunk\n"); + return(info); + } + + data_p += 4; + samples = *(long *)data_p; + data_p += 4; + + if (info.samples) + { + if(samples < info.samples) + Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + return(info); +} + +// ============== +// LoadSoundtrack +// ============== + +void LoadSoundtrack() +{ + char name[1024]; + FILE *f; + int len; + + soundtrack = NULL; + sprintf (name, "%svideo/%s/%s.wav", gamedir, base, base); + printf ("\nLoading sound : %s\n", name); + f = fopen (name, "rb"); + if (!f) + { + printf ("\nNo soundtrack for %s\n", base); + return; + } + len = Q_filelength(f); + soundtrack = SafeMalloc(len, "LoadSoundtrack"); + fread(soundtrack, 1, len, f); + fclose(f); + + wavinfo = GetWavinfo(name, soundtrack, len); + adpcm.state.out_valprev = 0; + adpcm.state.out_index = 0; +} + +// ================== +// WriteSound +// ================== + +int WriteSound(FILE *output, int frame, int numframes) +{ + int start, end; + int count; + int empty = 0; + int width; + char *work; + + width = wavinfo.width * wavinfo.channels; + start = ((frame * wavinfo.rate / 14) + 31) & 0xffffffe0; // start sample + end = (((frame + numframes) * wavinfo.rate / 14) + 31) & 0xffffffe0; // end sample + count = end - start; + + work = soundtrack + wavinfo.dataofs + (start * width); + adpcm.state.count = count * wavinfo.channels; // Number of samples + adpcm.state.in_valprev = adpcm.state.out_valprev; + adpcm.state.in_index = adpcm.state.out_index; + adpcm_coder((short *)work, &adpcm); + WriteHeader(output, FC_SOUND_22KMADPCM, FC_ADPCM_VERSION, (adpcm.state.count / 2) + sizeof(adpcm_state_t), (char *)&adpcm); + return(count / 2); +} +// ============================== +// Basic run length encoder +// ============================== + +char *RLEZZ(char *in, char *out) +{ + int srun; + char count; + int idx = 0; + + while(idx < 64) + { + srun = idx; // Start of run + + while(idx < 63) + { + if(in[LUT_ZZ[idx]] != in[LUT_ZZ[idx + 1]]) + break; + idx++; + } + count = (char)(idx - srun); // count of repeated bytes + + if(!count) + { + while(idx < 63) + { + if(in[LUT_ZZ[idx]] == in[LUT_ZZ[idx + 1]]) + break; + idx++; + } + if(idx == 63) + idx++; + + count = (char)(idx - srun); // count of unique bytes + *out++ = count; + while(count--) + *out++ = in[LUT_ZZ[srun++]]; + } + else + { + *out++ = -(count + 1); + *out++ = in[LUT_ZZ[idx]]; + idx++; + } + } + return(out); +} + +// ============================== +// Discrete Cosine Transformation +// ============================== + +void init_base(float quant) +{ + int y, x; + + for(y = 0; y < BLOCKSIZE; y++) + for(x = 0; x < BLOCKSIZE; x++) + { + if(y == 0) + dctbase[y][x] = 1; + else + dctbase[y][x] = SQRT2 * cos(((x * 2 + 1) * y * M_PI) / (BLOCKSIZE * 2)); + } + + for(y = 0; y < BLOCKSIZE * BLOCKSIZE; y++) + Quantise[y] = LUT_Quantise[y] / quant; +} + +void SplitComponents(byte *src, int width, int height) +{ + int i, j; + float *tr = red; + float *tg = green; + float *tb = blue; + + for(i = 0; i < BLOCKSIZE; i++, src += (width - BLOCKSIZE) * 4) + for(j = 0; j < BLOCKSIZE; j++) + { + *tr++ = ((float)*src++) - 128.0F; + *tg++ = ((float)*src++) - 128.0F; + *tb++ = ((float)*src++) - 128.0F; + src++; + } +} + +void transferH(float *src, float *dst) +{ + int y, dx, dy; + float sum; + float *work; + + for(y = 0; y < BLOCKSIZE; y++, src += BLOCKSIZE) + { + for(dy = 0; dy < BLOCKSIZE; dy++) + { + sum = 0; + work = src; + for(dx = 0; dx < BLOCKSIZE; dx++, work++) + sum += dctbase[dy][dx] * *work; + + *dst++ = sum / BLOCKSIZE; + } + } +} + +void transferV(float *src, float *dst) +{ + int x, dy, fy; + float sum; + float *work; + + for(x = 0; x < BLOCKSIZE; x++, src++, dst++) + { + for(fy = 0; fy < BLOCKSIZE; fy++) + { + sum = 0; + work = src; + for(dy = 0; dy < BLOCKSIZE; dy++, work += BLOCKSIZE) + sum += dctbase[fy][dy] * *work; + + dst[fy * BLOCKSIZE] = sum / BLOCKSIZE; + } + } +} + +char *Combine(byte *dst, float *p, float *q) +{ + int i, j; + byte rlesrc[BLOCKSIZE * BLOCKSIZE]; + int c; + byte *work; + + work = rlesrc; + for(j = 0; j < BLOCKSIZE; j++) + for(i = 0; i < BLOCKSIZE; i++) + { + c = (int)((*p++ / *q++) + 128.5F); + c -= 128; + + if(c < -128) + c = -128; + if(c > 127) + c = 127; + + *work++ = (char)c; + } + + dst = RLEZZ(rlesrc, dst); + return(dst); +} + +char *CombineComponents(char *dst, int width, int height) +{ + dst = Combine(dst, red, Quantise); + dst = Combine(dst, green, Quantise); + dst = Combine(dst, blue, Quantise); + return(dst); +} + +void DCT(cblock_t *out, cblock_t in, int width, int height) +{ + int x, y; + char *cursrc; + char *curdst; + + curdst = out->data; + for(y = 0; y < height; y += BLOCKSIZE) + for(x = 0; x < width; x += BLOCKSIZE) + { + cursrc = in.data + ((y * width) + x) * 4; + SplitComponents(cursrc, width, height); + transferH(red, temp); + transferV(temp, red); + transferH(green, temp); + transferV(temp, green); + transferH(blue, temp); + transferV(temp, blue); + curdst = CombineComponents(curdst, width, height); + } + out->count = curdst - out->data; +} + +// ================== +// BuildChars1 +// ================== + +void BuildChars1(int prev, int nodenum, unsigned bits, int bitcount) +{ + hnode_t *node; + + if(nodenum < HUF_TOKENS) + { + if (bitcount > 32) + Error("bitcount > 32"); + charbits1[prev][nodenum] = bits; + charbitscount1[prev][nodenum] = bitcount; + return; + } + + node = &hnodes1[prev][nodenum]; + bits <<= 1; + BuildChars1(prev, node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars1(prev, node->children[1], bits, bitcount+1); +} + +// ================== +// SmallestNode1 +// ================== + +int SmallestNode1(hnode_t *hnodes, int numhnodes) +{ + int i; + int best, bestnode; + + best = 99999999; + bestnode = -1; + for(i = 0; i < numhnodes; i++) + { + if(hnodes[i].used) + continue; + if(!hnodes[i].count) + continue; + if(hnodes[i].count < best) + { + best = hnodes[i].count; + bestnode = i; + } + } + + if (bestnode == -1) + return(-1); + + hnodes[bestnode].used = true; + return(bestnode); +} + +// ================== +// BuildTree1 +// ================== + +void BuildTree1(int prev) +{ + hnode_t *node, *nodebase; + int numhnodes; + + // build the nodes + numhnodes = HUF_TOKENS; + nodebase = hnodes1[prev]; + while(1) + { + node = &nodebase[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode1 (nodebase, numhnodes); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode1 (nodebase, numhnodes); + if (node->children[1] == -1) + break; + + node->count = nodebase[node->children[0]].count + + nodebase[node->children[1]].count; + numhnodes++; + } + numhnodes1[prev] = numhnodes-1; + BuildChars1 (prev, numhnodes-1, 0, 0); +} + +// ================== +// Huffman1_Count +// ================== + +void Huffman1_Count(cblock_t in) +{ + int i; + int prev; + int v; + int rept; + + prev = 0; + for(i = 0; i < in.count; i++) + { + v = in.data[i]; + order0counts[v]++; + hnodes1[prev][v].count++; + prev = v; + + for(rept = 1; (i + rept < in.count) && (rept < MAX_REPT); rept++) + if(in.data[i+rept] != v) + break; + if(rept > MIN_REPT) + { + hnodes1[prev][255 + rept].count++; + i += rept - 1; + } + } +} + +// ================== +// Huffman1_Build +// ================== + +void Huffman1_Build() +{ + int i, j, v; + int max; + int total; + + for(i = 0; i < 256; i++) + { +// normalize and save the counts + max = 0; + for (j = 0; j < HUF_TOKENS; j++) + { + if (hnodes1[i][j].count > max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; +// easy to overflow 32 bits here! + for(j = 0; j < HUF_TOKENS; j++) + { + v = (hnodes1[i][j].count * (double) 255 + max - 1) / max; + if (v > 255) + Error ("v > 255"); + scaled[i][j] = hnodes1[i][j].count = v; + if (v) + total++; + } + if (total == 1) + { // must have two tokens + if (!scaled[i][0]) + scaled[i][0] = hnodes1[i][0].count = 1; + else + scaled[i][1] = hnodes1[i][1].count = 1; + } + BuildTree1 (i); + } +} + +// ================== +// Huffman1 +// Order 1 compression with pre-built table +// ================== + +cblock_t Huffman1(cblock_t in) +{ + int i; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int prev; + int v; + int rept; + + out_p = out.data = SafeMalloc((in.count * 2) + 1024 + 4, "Huffman"); + memset(out_p, 0, (in.count * 2) + 1024 + 4); + + // leave space for compressed count + out_p += 4; + // write count + *(long *)out_p = in.count; + out_p += 4; + + // write bits + outbits = 0; + prev = 0; + for(i = 0; i < in.count; i++) + { + v = in.data[i]; + + c = charbitscount1[prev][v]; + bits = charbits1[prev][v]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if (bits & (1 << c)) + out_p[outbits>>3] |= 1 << (outbits & 7); + outbits++; + } + + prev = v; + // check for repeat encodes + for(rept = 1; (i + rept < in.count) && (rept < MAX_REPT); rept++) + if(in.data[i + rept] != v) + break; + if (rept > MIN_REPT) + { + c = charbitscount1[prev][255 + rept]; + bits = charbits1[prev][255 + rept]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if(bits & (1 << c)) + out_p[outbits >> 3] |= 1 << (outbits & 7); + outbits++; + } + i += rept - 1; + } + } + out_p += (outbits + 7) >> 3; + out.count = out_p - out.data; + + out_p = out.data; + *(long *)out_p = out.count; + return(out); +} +// =================== +// LoadFrame +// =================== + +void LoadFrame(cblock_t *out, char *base, int frame) +{ + cblock_t in; + int width, height; + char name[1024]; + FILE *f; + + in.data = NULL; + in.count = -1; + sprintf (name, "%svideo/%s/%s%04i.tga", gamedir, base, base, frame); + + f = fopen(name, "rb"); + if (!f) + { + out->data = NULL; + return; + } + fclose (f); + + LoadTGA(name, &in.data, &width, &height); + if((width != cinehead.Width) || (height != cinehead.Height)) + { + free(in.data); + printf("Invalid picture size\n"); + out->data = NULL; + return; + } + out->data = SafeMalloc(width * height * 3, "LoadFrame"); // rle could possibly expand file so this not 100% safe (however DCT should force a lot of compression) + DCT(out, in, width, height); + free(in.data); +} + +// ================================== +// Cmd_Video +// +// video +// ================================== + +void Cmd_Video() +{ + char savename[256]; + char name[256]; + FILE *output; + int frame; + int width, height; + cblock_t in, huffman; + int size; + float dctconst; + int maxsize, ssize; + int min_rle_size, warnings; + int ave_image, ave_sound; + + GetScriptToken(false); + strcpy(base, token); + if (g_release) + return; + + GetScriptToken(false); + dctconst = atof(token); + GetScriptToken(false); + maxsize = atoi(token); + + sprintf (savename, "%svideo/%s.cin", gamedir, base); + + // clear stuff + memset(charbits1, 0, sizeof(charbits1)); + memset(charbitscount1, 0, sizeof(charbitscount1)); + memset(hnodes1, 0, sizeof(hnodes1)); + memset(numhnodes1, 0, sizeof(numhnodes1)); + memset(order0counts, 0, sizeof(order0counts)); + + // load the entire sound wav file if present + LoadSoundtrack(); + + cinehead.SndRate = wavinfo.rate; + cinehead.SndWidth = wavinfo.width; + cinehead.SndChannels = wavinfo.channels; + + sprintf(name, "%svideo/%s/%s0000.tga", gamedir, base, base); + printf("Loading sequence : %s\n", name); + printf("DCT constant : %f\n", dctconst); + + LoadTGA (name, NULL, &width, &height); + + output = fopen (savename, "wb"); + if (!output) + Error ("Can't open %s", savename); + + if((width % BLOCKSIZE) || (height % BLOCKSIZE)) + Error("Width and height must be a multiple of %d", BLOCKSIZE); + + cinehead.Width = width; + cinehead.Height = height; + init_base(dctconst); + + // build the dictionary + printf("Counting : "); + min_rle_size = 0; + for (frame = 0; ; frame++) + { + printf("."); + LoadFrame(&in, base, frame); + if(!in.data) + break; + Huffman1_Count(in); + if(in.count > min_rle_size) + min_rle_size = in.count; + free(in.data); + } + printf ("\n"); + cinehead.NumFrames = frame; + printf("Num Frames : %d\n", frame); + cinehead.MaxRleSize = (min_rle_size + 0x1f) & 0xfffffe0; + cinehead.MaxSndSize = ((4 * wavinfo.rate * wavinfo.channels / 14) + 0x1f) & 0xffffffe0; + + WriteHeader(output, FC_HEADER_NAME, FC_HEADER_VERSION, sizeof(CineHead_t), &cinehead); + + // build nodes and write counts + Huffman1_Build(); + WriteHeader(output, FC_HUFFBITS_NAME, FC_HUFFBITS_VERSION, sizeof(scaled), scaled); + WriteHeader(output, FC_QUANT_NAME, FC_QUANT_VERSION, sizeof(Quantise), Quantise); + + ave_image = 0; + ave_sound = 0; + warnings = 0; + // compress it with the dictionary + if(soundtrack) + { + ssize = WriteSound(output, frame, 4); + ave_sound += ssize; + } + + for (frame = 0; frame < cinehead.NumFrames; frame++) + { + // save some sound samples + printf ("Packing : ", frame); + LoadFrame(&in, base, frame); + + // save the image + huffman = Huffman1(in); + printf ("%d bytes rle, %d bytes huffman", in.count, huffman.count); + size = (huffman.count + 3) & 0xfffffffc; // round up to longwords + if(size > maxsize) + { + printf(" ** WARNING **"); + warnings++; + } + printf("\n"); + ave_image += huffman.count; + + WriteHeader(output, FC_IMAGE_NAME, FC_IMAGE_VERSION, size, huffman.data); + if(soundtrack) + { + ssize = WriteSound(output, frame + 4, 1); + ave_sound += ssize; + } + + free (in.data); + free (huffman.data); + } + printf("\nTotal size: %d (headers + %d image + %d sound)\n", ftell(output), ave_image, ave_sound); + printf("Data rate : %d bytes per sec (image and sound)\n", (ave_image + ave_sound) / cinehead.NumFrames); + printf("Cin created ok with %d warnings.\n", warnings); + fclose (output); + + if (soundtrack) + free (soundtrack); +} +#endif + +void Cmd_Video() +{ +} + +// end + diff --git a/tools/quake3/common/aselib.c b/tools/quake3/common/aselib.c new file mode 100644 index 00000000..58307f85 --- /dev/null +++ b/tools/quake3/common/aselib.c @@ -0,0 +1,965 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "aselib.h" +#include "inout.h" + +#include +#include +#include + +#define MAX_ASE_MATERIALS 32 +#define MAX_ASE_OBJECTS 64 +#define MAX_ASE_ANIMATIONS 32 +#define MAX_ASE_ANIMATION_FRAMES 512 + +#define VERBOSE( x ) { if ( ase.verbose ) { Sys_Printf x ; } } + +typedef struct +{ + float x, y, z; + float nx, ny, nz; + float s, t; +} aseVertex_t; + +typedef struct +{ + float s, t; +} aseTVertex_t; + +typedef int aseFace_t[3]; + +typedef struct +{ + int numFaces; + int numVertexes; + int numTVertexes; + + int timeValue; + + aseVertex_t *vertexes; + aseTVertex_t *tvertexes; + aseFace_t *faces, *tfaces; + + int currentFace, currentVertex; +} aseMesh_t; + +typedef struct +{ + int numFrames; + aseMesh_t frames[MAX_ASE_ANIMATION_FRAMES]; + + int currentFrame; +} aseMeshAnimation_t; + +typedef struct +{ + char name[128]; +} aseMaterial_t; + +/* +** contains the animate sequence of a single surface +** using a single material +*/ +typedef struct +{ + char name[128]; + + int materialRef; + int numAnimations; + + aseMeshAnimation_t anim; + +} aseGeomObject_t; + +typedef struct +{ + int numMaterials; + aseMaterial_t materials[MAX_ASE_MATERIALS]; + aseGeomObject_t objects[MAX_ASE_OBJECTS]; + + char *buffer; + char *curpos; + int len; + + int currentObject; + qboolean verbose; + qboolean grabAnims; + +} ase_t; + +static char s_token[1024]; +static ase_t ase; +static char gl_filename[1024]; + +static void ASE_Process( void ); +static void ASE_FreeGeomObject( int ndx ); + +#if defined (__linux__) || defined (__APPLE__) + +static char* strlwr (char* string) +{ + char *cp; + for (cp = string; *cp; ++cp) + { + if ('A' <= *cp && *cp <= 'Z') + *cp += 'a' - 'A'; + } + + return string; +} + +#endif + +/* +** ASE_Load +*/ +void ASE_Load( const char *filename, qboolean verbose, qboolean grabAnims ) +{ + FILE *fp = fopen( filename, "rb" ); + + if ( !fp ) + Error( "File not found '%s'", filename ); + + memset( &ase, 0, sizeof( ase ) ); + + ase.verbose = verbose; + ase.grabAnims = grabAnims; + ase.len = Q_filelength( fp ); + + ase.curpos = ase.buffer = safe_malloc( ase.len ); + + Sys_Printf( "Processing '%s'\n", filename ); + + if ( fread( ase.buffer, ase.len, 1, fp ) != 1 ) + { + fclose( fp ); + Error( "fread() != -1 for '%s'", filename ); + } + + fclose( fp ); + + strcpy(gl_filename, filename); + + ASE_Process(); +} + +/* +** ASE_Free +*/ +void ASE_Free( void ) +{ + int i; + + for ( i = 0; i < ase.currentObject; i++ ) + { + ASE_FreeGeomObject( i ); + } +} + +/* +** ASE_GetNumSurfaces +*/ +int ASE_GetNumSurfaces( void ) +{ + return ase.currentObject; +} + +/* +** ASE_GetSurfaceName +*/ +const char *ASE_GetSurfaceName( int which ) +{ + aseGeomObject_t *pObject = &ase.objects[which]; + + if ( !pObject->anim.numFrames ) + return 0; + + return pObject->name; +} + +/* +** ASE_GetSurfaceAnimation +** +** Returns an animation (sequence of polysets) +*/ +polyset_t *ASE_GetSurfaceAnimation( int which, int *pNumFrames, int skipFrameStart, int skipFrameEnd, int maxFrames ) +{ + aseGeomObject_t *pObject = &ase.objects[which]; + polyset_t *psets; + int numFramesInAnimation; + int numFramesToKeep; + int i, f; + + if ( !pObject->anim.numFrames ) + return 0; + + if ( pObject->anim.numFrames > maxFrames && maxFrames != -1 ) + { + numFramesInAnimation = maxFrames; + } + else + { + numFramesInAnimation = pObject->anim.numFrames; + if ( maxFrames != -1 ) + Sys_Printf( "WARNING: ASE_GetSurfaceAnimation maxFrames > numFramesInAnimation\n" ); + } + + if ( skipFrameEnd != -1 ) + numFramesToKeep = numFramesInAnimation - ( skipFrameEnd - skipFrameStart + 1 ); + else + numFramesToKeep = numFramesInAnimation; + + *pNumFrames = numFramesToKeep; + + psets = calloc( sizeof( polyset_t ) * numFramesToKeep, 1 ); + + for ( f = 0, i = 0; i < numFramesInAnimation; i++ ) + { + int t; + aseMesh_t *pMesh = &pObject->anim.frames[i]; + + if ( skipFrameStart != -1 ) + { + if ( i >= skipFrameStart && i <= skipFrameEnd ) + continue; + } + + strcpy( psets[f].name, pObject->name ); + strcpy( psets[f].materialname, ase.materials[pObject->materialRef].name ); + + psets[f].triangles = calloc( sizeof( triangle_t ) * pObject->anim.frames[i].numFaces, 1 ); + psets[f].numtriangles = pObject->anim.frames[i].numFaces; + + for ( t = 0; t < pObject->anim.frames[i].numFaces; t++ ) + { + int k; + + for ( k = 0; k < 3; k++ ) + { + psets[f].triangles[t].verts[k][0] = pMesh->vertexes[pMesh->faces[t][k]].x; + psets[f].triangles[t].verts[k][1] = pMesh->vertexes[pMesh->faces[t][k]].y; + psets[f].triangles[t].verts[k][2] = pMesh->vertexes[pMesh->faces[t][k]].z; + + if ( pMesh->tvertexes && pMesh->tfaces ) + { + psets[f].triangles[t].texcoords[k][0] = pMesh->tvertexes[pMesh->tfaces[t][k]].s; + psets[f].triangles[t].texcoords[k][1] = pMesh->tvertexes[pMesh->tfaces[t][k]].t; + } + + } + } + + f++; + } + + return psets; +} + +static void ASE_FreeGeomObject( int ndx ) +{ + aseGeomObject_t *pObject; + int i; + + pObject = &ase.objects[ndx]; + + for ( i = 0; i < pObject->anim.numFrames; i++ ) + { + if ( pObject->anim.frames[i].vertexes ) + { + free( pObject->anim.frames[i].vertexes ); + } + if ( pObject->anim.frames[i].tvertexes ) + { + free( pObject->anim.frames[i].tvertexes ); + } + if ( pObject->anim.frames[i].faces ) + { + free( pObject->anim.frames[i].faces ); + } + if ( pObject->anim.frames[i].tfaces ) + { + free( pObject->anim.frames[i].tfaces ); + } + } + + memset( pObject, 0, sizeof( *pObject ) ); +} + +static aseMesh_t *ASE_GetCurrentMesh( void ) +{ + aseGeomObject_t *pObject; + + if ( ase.currentObject >= MAX_ASE_OBJECTS ) + { + Error( "Too many GEOMOBJECTs" ); + return 0; // never called + } + + pObject = &ase.objects[ase.currentObject]; + + if ( pObject->anim.currentFrame >= MAX_ASE_ANIMATION_FRAMES ) + { + Error( "Too many MESHes" ); + return 0; + } + + return &pObject->anim.frames[pObject->anim.currentFrame]; +} + +static int CharIsTokenDelimiter( int ch ) +{ + if ( ch <= 32 ) + return 1; + return 0; +} + +static int ASE_GetToken( qboolean restOfLine ) +{ + int i = 0; + + if ( ase.buffer == 0 ) + return 0; + + if ( ( ase.curpos - ase.buffer ) == ase.len ) + return 0; + + // skip over crap + while ( ( ( ase.curpos - ase.buffer ) < ase.len ) && + ( *ase.curpos <= 32 ) ) + { + ase.curpos++; + } + + while ( ( ase.curpos - ase.buffer ) < ase.len ) + { + s_token[i] = *ase.curpos; + + ase.curpos++; + i++; + + if ( ( CharIsTokenDelimiter( s_token[i-1] ) && !restOfLine ) || + ( ( s_token[i-1] == '\n' ) || ( s_token[i-1] == '\r' ) ) ) + { + s_token[i-1] = 0; + break; + } + } + + s_token[i] = 0; + + return 1; +} + +static void ASE_ParseBracedBlock( void (*parser)( const char *token ) ) +{ + int indent = 0; + + while ( ASE_GetToken( qfalse ) ) + { + if ( !strcmp( s_token, "{" ) ) + { + indent++; + } + else if ( !strcmp( s_token, "}" ) ) + { + --indent; + if ( indent == 0 ) + break; + else if ( indent < 0 ) + Error( "Unexpected '}'" ); + } + else + { + if ( parser ) + parser( s_token ); + } + } +} + +static void ASE_SkipEnclosingBraces( void ) +{ + int indent = 0; + + while ( ASE_GetToken( qfalse ) ) + { + if ( !strcmp( s_token, "{" ) ) + { + indent++; + } + else if ( !strcmp( s_token, "}" ) ) + { + indent--; + if ( indent == 0 ) + break; + else if ( indent < 0 ) + Error( "Unexpected '}'" ); + } + } +} + +static void ASE_SkipRestOfLine( void ) +{ + ASE_GetToken( qtrue ); +} + +static void ASE_KeyMAP_DIFFUSE( const char *token ) +{ + char fullpath[1024], bitmap[1024], modeldir[1024]; + char filename[1024]; + int i = 0, count; + + strcpy(filename, gl_filename); + + if ( !strcmp( token, "*BITMAP" ) ) + { + ASE_GetToken( qfalse ); + + // the purpose of this whole chunk of code below is to extract the relative path + // from a full path in the ASE + + strcpy( bitmap, s_token + 1 ); + if ( strchr( bitmap, '"' ) ) + *strchr( bitmap, '"' ) = 0; + + /* convert backslash to slash */ + while ( bitmap[i] ) + { + if ( bitmap[i] == '\\' ) + bitmap[i] = '/'; + i++; + } + + /* remove filename from path */ + for( i=strlen(filename); i>0; i--) + { + if(filename[i] == '/') + { + filename[i] = '\0'; + break; + } + } + + /* replaces a relative path with a full path */ + if(bitmap[0] == '.' && bitmap[1] == '.' && bitmap[2] == '/') + { + while(bitmap[0] == '.' && bitmap[1] == '.' && bitmap[2] == '/') + { + /* remove last item from path */ + for( i=strlen(filename); i>0; i--) + { + if(filename[i] == '/') + { + filename[i] = '\0'; + break; + } + } + strcpy(bitmap, &bitmap[3]); + } + strcat(filename, "/"); + strcat(filename, bitmap); + strcpy(bitmap, filename); + } + + if ( strstr( bitmap, gamedir ) ) + { + strcpy( ase.materials[ase.numMaterials].name, strstr( bitmap, gamedir ) + strlen( gamedir ) ); + Sys_Printf("material name: \'%s\'\n", strstr( bitmap, gamedir ) + strlen( gamedir ) ); + } + else + { + sprintf( ase.materials[ase.numMaterials].name, "(not converted: '%s')", bitmap ); + Sys_Printf( "WARNING: illegal material name '%s'\n", bitmap ); + } + } + else + { + } +} + +static void ASE_KeyMATERIAL( const char *token ) +{ + if ( !strcmp( token, "*MAP_DIFFUSE" ) ) + { + ASE_ParseBracedBlock( ASE_KeyMAP_DIFFUSE ); + } + else + { + } +} + +static void ASE_KeyMATERIAL_LIST( const char *token ) +{ + if ( !strcmp( token, "*MATERIAL_COUNT" ) ) + { + ASE_GetToken( qfalse ); + VERBOSE( ( "..num materials: %s\n", s_token ) ); + if ( atoi( s_token ) > MAX_ASE_MATERIALS ) + { + Error( "Too many materials!" ); + } + ase.numMaterials = 0; + } + else if ( !strcmp( token, "*MATERIAL" ) ) + { + VERBOSE( ( "..material %d ", ase.numMaterials ) ); + ASE_ParseBracedBlock( ASE_KeyMATERIAL ); + ase.numMaterials++; + } +} + +static void ASE_KeyMESH_VERTEX_LIST( const char *token ) +{ + aseMesh_t *pMesh = ASE_GetCurrentMesh(); + + if ( !strcmp( token, "*MESH_VERTEX" ) ) + { + ASE_GetToken( qfalse ); // skip number + + ASE_GetToken( qfalse ); + pMesh->vertexes[pMesh->currentVertex].y = atof( s_token ); + + ASE_GetToken( qfalse ); + pMesh->vertexes[pMesh->currentVertex].x = -atof( s_token ); + + ASE_GetToken( qfalse ); + pMesh->vertexes[pMesh->currentVertex].z = atof( s_token ); + + pMesh->currentVertex++; + + if ( pMesh->currentVertex > pMesh->numVertexes ) + { + Error( "pMesh->currentVertex >= pMesh->numVertexes" ); + } + } + else + { + Error( "Unknown token '%s' while parsing MESH_VERTEX_LIST", token ); + } +} + +static void ASE_KeyMESH_FACE_LIST( const char *token ) +{ + aseMesh_t *pMesh = ASE_GetCurrentMesh(); + + if ( !strcmp( token, "*MESH_FACE" ) ) + { + ASE_GetToken( qfalse ); // skip face number + + ASE_GetToken( qfalse ); // skip label + ASE_GetToken( qfalse ); // first vertex + pMesh->faces[pMesh->currentFace][0] = atoi( s_token ); + + ASE_GetToken( qfalse ); // skip label + ASE_GetToken( qfalse ); // second vertex + pMesh->faces[pMesh->currentFace][2] = atoi( s_token ); + + ASE_GetToken( qfalse ); // skip label + ASE_GetToken( qfalse ); // third vertex + pMesh->faces[pMesh->currentFace][1] = atoi( s_token ); + + ASE_GetToken( qtrue ); + +/* + if ( ( p = strstr( s_token, "*MESH_MTLID" ) ) != 0 ) + { + p += strlen( "*MESH_MTLID" ) + 1; + mtlID = atoi( p ); + } + else + { + Error( "No *MESH_MTLID found for face!" ); + } +*/ + + pMesh->currentFace++; + } + else + { + Error( "Unknown token '%s' while parsing MESH_FACE_LIST", token ); + } +} + +static void ASE_KeyTFACE_LIST( const char *token ) +{ + aseMesh_t *pMesh = ASE_GetCurrentMesh(); + + if ( !strcmp( token, "*MESH_TFACE" ) ) + { + int a, b, c; + + ASE_GetToken( qfalse ); + + ASE_GetToken( qfalse ); + a = atoi( s_token ); + ASE_GetToken( qfalse ); + c = atoi( s_token ); + ASE_GetToken( qfalse ); + b = atoi( s_token ); + + pMesh->tfaces[pMesh->currentFace][0] = a; + pMesh->tfaces[pMesh->currentFace][1] = b; + pMesh->tfaces[pMesh->currentFace][2] = c; + + pMesh->currentFace++; + } + else + { + Error( "Unknown token '%s' in MESH_TFACE", token ); + } +} + +static void ASE_KeyMESH_TVERTLIST( const char *token ) +{ + aseMesh_t *pMesh = ASE_GetCurrentMesh(); + + if ( !strcmp( token, "*MESH_TVERT" ) ) + { + char u[80], v[80], w[80]; + + ASE_GetToken( qfalse ); + + ASE_GetToken( qfalse ); + strcpy( u, s_token ); + + ASE_GetToken( qfalse ); + strcpy( v, s_token ); + + ASE_GetToken( qfalse ); + strcpy( w, s_token ); + + pMesh->tvertexes[pMesh->currentVertex].s = atof( u ); + pMesh->tvertexes[pMesh->currentVertex].t = 1.0f - atof( v ); + + pMesh->currentVertex++; + + if ( pMesh->currentVertex > pMesh->numTVertexes ) + { + Error( "pMesh->currentVertex > pMesh->numTVertexes" ); + } + } + else + { + Error( "Unknown token '%s' while parsing MESH_TVERTLIST" ); + } +} + +static void ASE_KeyMESH( const char *token ) +{ + aseMesh_t *pMesh = ASE_GetCurrentMesh(); + + if ( !strcmp( token, "*TIMEVALUE" ) ) + { + ASE_GetToken( qfalse ); + + pMesh->timeValue = atoi( s_token ); + VERBOSE( ( ".....timevalue: %d\n", pMesh->timeValue ) ); + } + else if ( !strcmp( token, "*MESH_NUMVERTEX" ) ) + { + ASE_GetToken( qfalse ); + + pMesh->numVertexes = atoi( s_token ); + VERBOSE( ( ".....TIMEVALUE: %d\n", pMesh->timeValue ) ); + VERBOSE( ( ".....num vertexes: %d\n", pMesh->numVertexes ) ); + } + else if ( !strcmp( token, "*MESH_NUMFACES" ) ) + { + ASE_GetToken( qfalse ); + + pMesh->numFaces = atoi( s_token ); + VERBOSE( ( ".....num faces: %d\n", pMesh->numFaces ) ); + } + else if ( !strcmp( token, "*MESH_NUMTVFACES" ) ) + { + ASE_GetToken( qfalse ); + + if ( atoi( s_token ) != pMesh->numFaces ) + { + Error( "MESH_NUMTVFACES != MESH_NUMFACES" ); + } + } + else if ( !strcmp( token, "*MESH_NUMTVERTEX" ) ) + { + ASE_GetToken( qfalse ); + + pMesh->numTVertexes = atoi( s_token ); + VERBOSE( ( ".....num tvertexes: %d\n", pMesh->numTVertexes ) ); + } + else if ( !strcmp( token, "*MESH_VERTEX_LIST" ) ) + { + pMesh->vertexes = calloc( sizeof( aseVertex_t ) * pMesh->numVertexes, 1 ); + pMesh->currentVertex = 0; + VERBOSE( ( ".....parsing MESH_VERTEX_LIST\n" ) ); + ASE_ParseBracedBlock( ASE_KeyMESH_VERTEX_LIST ); + } + else if ( !strcmp( token, "*MESH_TVERTLIST" ) ) + { + pMesh->currentVertex = 0; + pMesh->tvertexes = calloc( sizeof( aseTVertex_t ) * pMesh->numTVertexes, 1 ); + VERBOSE( ( ".....parsing MESH_TVERTLIST\n" ) ); + ASE_ParseBracedBlock( ASE_KeyMESH_TVERTLIST ); + } + else if ( !strcmp( token, "*MESH_FACE_LIST" ) ) + { + pMesh->faces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 ); + pMesh->currentFace = 0; + VERBOSE( ( ".....parsing MESH_FACE_LIST\n" ) ); + ASE_ParseBracedBlock( ASE_KeyMESH_FACE_LIST ); + } + else if ( !strcmp( token, "*MESH_TFACELIST" ) ) + { + pMesh->tfaces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 ); + pMesh->currentFace = 0; + VERBOSE( ( ".....parsing MESH_TFACE_LIST\n" ) ); + ASE_ParseBracedBlock( ASE_KeyTFACE_LIST ); + } + else if ( !strcmp( token, "*MESH_NORMALS" ) ) + { + ASE_ParseBracedBlock( 0 ); + } +} + +static void ASE_KeyMESH_ANIMATION( const char *token ) +{ + aseMesh_t *pMesh = ASE_GetCurrentMesh(); + + // loads a single animation frame + if ( !strcmp( token, "*MESH" ) ) + { + VERBOSE( ( "...found MESH\n" ) ); + assert( pMesh->faces == 0 ); + assert( pMesh->vertexes == 0 ); + assert( pMesh->tvertexes == 0 ); + memset( pMesh, 0, sizeof( *pMesh ) ); + + ASE_ParseBracedBlock( ASE_KeyMESH ); + + if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES ) + { + Error( "Too many animation frames" ); + } + } + else + { + Error( "Unknown token '%s' while parsing MESH_ANIMATION", token ); + } +} + +static void ASE_KeyGEOMOBJECT( const char *token ) +{ + if ( !strcmp( token, "*NODE_NAME" ) ) + { + char *name = ase.objects[ase.currentObject].name; + + ASE_GetToken( qtrue ); + VERBOSE( ( " %s\n", s_token ) ); + strcpy( ase.objects[ase.currentObject].name, s_token + 1 ); + if ( strchr( ase.objects[ase.currentObject].name, '"' ) ) + *strchr( ase.objects[ase.currentObject].name, '"' ) = 0; + + if ( strstr( name, "tag" ) == name ) + { + while ( strchr( name, '_' ) != strrchr( name, '_' ) ) + { + *strrchr( name, '_' ) = 0; + } + while ( strrchr( name, ' ' ) ) + { + *strrchr( name, ' ' ) = 0; + } + } + } + else if ( !strcmp( token, "*NODE_PARENT" ) ) + { + ASE_SkipRestOfLine(); + } + // ignore unused data blocks + else if ( !strcmp( token, "*NODE_TM" ) || + !strcmp( token, "*TM_ANIMATION" ) ) + { + ASE_ParseBracedBlock( 0 ); + } + // ignore regular meshes that aren't part of animation + else if ( !strcmp( token, "*MESH" ) && !ase.grabAnims ) + { +/* + if ( strstr( ase.objects[ase.currentObject].name, "tag_" ) == ase.objects[ase.currentObject].name ) + { + s_forceStaticMesh = true; + ASE_ParseBracedBlock( ASE_KeyMESH ); + s_forceStaticMesh = false; + } +*/ + ASE_ParseBracedBlock( ASE_KeyMESH ); + if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES ) + { + Error( "Too many animation frames" ); + } + ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame; + ase.objects[ase.currentObject].numAnimations++; +/* + // ignore meshes that aren't part of animations if this object isn't a + // a tag + else + { + ASE_ParseBracedBlock( 0 ); + } +*/ + } + // according to spec these are obsolete + else if ( !strcmp( token, "*MATERIAL_REF" ) ) + { + ASE_GetToken( qfalse ); + + ase.objects[ase.currentObject].materialRef = atoi( s_token ); + } + // loads a sequence of animation frames + else if ( !strcmp( token, "*MESH_ANIMATION" ) ) + { + if ( ase.grabAnims ) + { + VERBOSE( ( "..found MESH_ANIMATION\n" ) ); + + if ( ase.objects[ase.currentObject].numAnimations ) + { + Error( "Multiple MESH_ANIMATIONS within a single GEOM_OBJECT" ); + } + ASE_ParseBracedBlock( ASE_KeyMESH_ANIMATION ); + ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame; + ase.objects[ase.currentObject].numAnimations++; + } + else + { + ASE_SkipEnclosingBraces(); + } + } + // skip unused info + else if ( !strcmp( token, "*PROP_MOTIONBLUR" ) || + !strcmp( token, "*PROP_CASTSHADOW" ) || + !strcmp( token, "*PROP_RECVSHADOW" ) ) + { + ASE_SkipRestOfLine(); + } +} + +static void ConcatenateObjects( aseGeomObject_t *pObjA, aseGeomObject_t *pObjB ) +{ +} + +static void CollapseObjects( void ) +{ + int i; + int numObjects = ase.currentObject; + + for ( i = 0; i < numObjects; i++ ) + { + int j; + + // skip tags + if ( strstr( ase.objects[i].name, "tag" ) == ase.objects[i].name ) + { + continue; + } + + if ( !ase.objects[i].numAnimations ) + { + continue; + } + + for ( j = i + 1; j < numObjects; j++ ) + { + if ( strstr( ase.objects[j].name, "tag" ) == ase.objects[j].name ) + { + continue; + } + if ( ase.objects[i].materialRef == ase.objects[j].materialRef ) + { + if ( ase.objects[j].numAnimations ) + { + ConcatenateObjects( &ase.objects[i], &ase.objects[j] ); + } + } + } + } +} + +/* +** ASE_Process +*/ +static void ASE_Process( void ) +{ + while ( ASE_GetToken( qfalse ) ) + { + if ( !strcmp( s_token, "*3DSMAX_ASCIIEXPORT" ) || + !strcmp( s_token, "*COMMENT" ) ) + { + ASE_SkipRestOfLine(); + } + else if ( !strcmp( s_token, "*SCENE" ) ) + ASE_SkipEnclosingBraces(); + else if ( !strcmp( s_token, "*MATERIAL_LIST" ) ) + { + VERBOSE( ("MATERIAL_LIST\n") ); + + ASE_ParseBracedBlock( ASE_KeyMATERIAL_LIST ); + } + else if ( !strcmp( s_token, "*GEOMOBJECT" ) ) + { + VERBOSE( ("GEOMOBJECT" ) ); + + ASE_ParseBracedBlock( ASE_KeyGEOMOBJECT ); + + if ( strstr( ase.objects[ase.currentObject].name, "Bip" ) || + strstr( ase.objects[ase.currentObject].name, "ignore_" ) ) + { + ASE_FreeGeomObject( ase.currentObject ); + VERBOSE( ( "(discarding BIP/ignore object)\n" ) ); + } + else if ( ( strstr( ase.objects[ase.currentObject].name, "h_" ) != ase.objects[ase.currentObject].name ) && + ( strstr( ase.objects[ase.currentObject].name, "l_" ) != ase.objects[ase.currentObject].name ) && + ( strstr( ase.objects[ase.currentObject].name, "u_" ) != ase.objects[ase.currentObject].name ) && + ( strstr( ase.objects[ase.currentObject].name, "tag" ) != ase.objects[ase.currentObject].name ) && + ase.grabAnims ) + { + VERBOSE( ( "(ignoring improperly labeled object '%s')\n", ase.objects[ase.currentObject].name ) ); + ASE_FreeGeomObject( ase.currentObject ); + } + else + { + if ( ++ase.currentObject == MAX_ASE_OBJECTS ) + { + Error( "Too many GEOMOBJECTs" ); + } + } + } + else if ( s_token[0] ) + { + Sys_Printf( "Unknown token '%s'\n", s_token ); + } + } + + if ( !ase.currentObject ) + Error( "No animation data!" ); + + CollapseObjects(); +} diff --git a/tools/quake3/common/aselib.h b/tools/quake3/common/aselib.h new file mode 100644 index 00000000..4ff9b234 --- /dev/null +++ b/tools/quake3/common/aselib.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "../common/cmdlib.h" +#include "mathlib.h" +#include "polyset.h" + +void ASE_Load( const char *filename, qboolean verbose, qboolean meshanims ); +int ASE_GetNumSurfaces( void ); +polyset_t *ASE_GetSurfaceAnimation( int ndx, int *numFrames, int skipFrameStart, int skipFrameEnd, int maxFrames ); +const char *ASE_GetSurfaceName( int ndx ); +void ASE_Free( void ); diff --git a/tools/quake3/common/bspfile.c b/tools/quake3/common/bspfile.c new file mode 100644 index 00000000..edc3cd65 --- /dev/null +++ b/tools/quake3/common/bspfile.c @@ -0,0 +1,706 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include "bspfile.h" +#include "scriplib.h" + +void GetLeafNums (void); + +//============================================================================= + +int bsp_version = Q3_BSP_VERSION; + +int nummodels; +dmodel_t dmodels[MAX_MAP_MODELS]; + +int numShaders; +dshader_t dshaders[MAX_MAP_SHADERS]; + +int entdatasize; +char dentdata[MAX_MAP_ENTSTRING]; + +int numleafs; +dleaf_t dleafs[MAX_MAP_LEAFS]; + +int numplanes; +dplane_t dplanes[MAX_MAP_PLANES]; + +int numnodes; +dnode_t dnodes[MAX_MAP_NODES]; + +int numleafsurfaces; +int dleafsurfaces[MAX_MAP_LEAFFACES]; + +int numleafbrushes; +int dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +int numbrushes; +dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +int numbrushsides; +dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +int numLightBytes; +byte *lightBytes; + +int numGridPoints; +byte *gridData; + +int numVisBytes; +byte visBytes[MAX_MAP_VISIBILITY]; + +int numDrawVerts = 0; +int numDrawVertsBuffer = 0; +drawVert_t *drawVerts = NULL; + +int numDrawIndexes; +int drawIndexes[MAX_MAP_DRAW_INDEXES]; + +int numDrawSurfaces; +int numDrawSurfacesBuffer = 0; +dsurface_t *drawSurfaces = NULL; + +int numFogs; +dfog_t dfogs[MAX_MAP_FOGS]; + +void SetLightBytes(int n) +{ + if(lightBytes != 0) + free(lightBytes); + + numLightBytes = n; + + if(n == 0) + return; + + lightBytes = safe_malloc_info(numLightBytes, "SetLightBytes"); + + memset(lightBytes, 0, numLightBytes); +} + +void SetGridPoints(int n) +{ + if(gridData != 0) + free(gridData); + + numGridPoints = n; + + if(n == 0) + return; + + gridData = safe_malloc_info(numGridPoints * 8, "SetGridPoints"); + + memset(gridData, 0, numGridPoints * 8); +} + +void IncDrawVerts() +{ + numDrawVerts++; + + if(drawVerts == 0) + { + numDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37; + + drawVerts = safe_malloc_info(sizeof(drawVert_t) * numDrawVertsBuffer, "IncDrawVerts"); + + } + else if(numDrawVerts > numDrawVertsBuffer) + { + numDrawVertsBuffer *= 3; // multiply by 1.5 + numDrawVertsBuffer /= 2; + + if(numDrawVertsBuffer > MAX_MAP_DRAW_VERTS) + numDrawVertsBuffer = MAX_MAP_DRAW_VERTS; + + drawVerts = realloc(drawVerts, sizeof(drawVert_t) * numDrawVertsBuffer); + + if(!drawVerts) + Error( "realloc() failed (IncDrawVerts)"); + } + + memset(drawVerts + (numDrawVerts - 1), 0, sizeof(drawVert_t)); +} + +void SetDrawVerts(int n) +{ + if(drawVerts != 0) + free(drawVerts); + + numDrawVerts = n; + numDrawVertsBuffer = numDrawVerts; + + drawVerts = safe_malloc_info(sizeof(drawVert_t) * numDrawVertsBuffer, "IncDrawVerts"); + + memset(drawVerts, 0, n * sizeof(drawVert_t)); +} + +void SetDrawSurfacesBuffer() +{ + if(drawSurfaces != 0) + free(drawSurfaces); + + numDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS; + + drawSurfaces = safe_malloc_info(sizeof(dsurface_t) * numDrawSurfacesBuffer, "IncDrawSurfaces"); + + memset(drawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(drawVert_t)); +} + +void SetDrawSurfaces(int n) +{ + if(drawSurfaces != 0) + free(drawSurfaces); + + numDrawSurfaces = n; + numDrawSurfacesBuffer = numDrawSurfaces; + + drawSurfaces = safe_malloc_info(sizeof(dsurface_t) * numDrawSurfacesBuffer, "IncDrawSurfaces"); + + memset(drawSurfaces, 0, n * sizeof(drawVert_t)); +} + +void BspFilesCleanup() +{ + if(drawVerts != 0) + free(drawVerts); + if(drawSurfaces != 0) + free(drawSurfaces); + if(lightBytes != 0) + free(lightBytes); + if(gridData != 0) + free(gridData); +} + +//============================================================================= + +/* +============= +SwapBlock + +If all values are 32 bits, this can be used to swap everything +============= +*/ +void SwapBlock( int *block, int sizeOfBlock ) { + int i; + + sizeOfBlock >>= 2; + for ( i = 0 ; i < sizeOfBlock ; i++ ) { + block[i] = LittleLong( block[i] ); + } +} + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile( void ) { + int i; + + // models + SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) ); + + // shaders (don't swap the name) + for ( i = 0 ; i < numShaders ; i++ ) { + dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags ); + dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags ); + } + + // planes + SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) ); + + // nodes + SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) ); + + // leafs + SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) ); + + // leaffaces + SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) ); + + // leafbrushes + SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) ); + + // brushes + SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) ); + + // brushsides + SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) ); + + // vis + ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] ); + ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] ); + + // drawverts (don't swap colors ) + for ( i = 0 ; i < numDrawVerts ; i++ ) { + drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] ); + drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] ); + drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] ); + drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] ); + drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] ); + drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] ); + drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] ); + drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] ); + drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] ); + drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] ); + } + + // drawindexes + SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) ); + + // drawsurfs + SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) ); + + // fogs + for ( i = 0 ; i < numFogs ; i++ ) { + dfogs[i].brushNum = LittleLong( dfogs[i].brushNum ); + dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide ); + } +} + + + +/* +============= +GetLumpElements +============= +*/ +int GetLumpElements( dheader_t *header, int lump, int size ) { + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if ( length % size ) { + Error ("LoadBSPFile: odd lump size"); + } + + return length / size; +} + +/* +============= +CopyLump +============= +*/ +int CopyLump( dheader_t *header, int lump, void *dest, int size ) { + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if(length == 0) + return 0; + + if ( length % size ) { + Error ("LoadBSPFile: odd lump size"); + } + + memcpy( dest, (byte *)header + ofs, length ); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +void LoadBSPFile( const char *filename ) { + dheader_t *header; + + // load the file header + LoadFile (filename, (void **)&header); + + // swap the header + SwapBlock( (int *)header, sizeof(*header) ); + + if ( header->ident != BSP_IDENT ) { + Error( "%s is not a IBSP file", filename ); + } + if ( header->version != bsp_version ) { + Error( "%s is version %i, not %i", filename, header->version, bsp_version ); + } + + numShaders = CopyLump( header, LUMP_SHADERS, dshaders, sizeof(dshader_t) ); + nummodels = CopyLump( header, LUMP_MODELS, dmodels, sizeof(dmodel_t) ); + numplanes = CopyLump( header, LUMP_PLANES, dplanes, sizeof(dplane_t) ); + numleafs = CopyLump( header, LUMP_LEAFS, dleafs, sizeof(dleaf_t) ); + numnodes = CopyLump( header, LUMP_NODES, dnodes, sizeof(dnode_t) ); + numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, dleafsurfaces, sizeof(dleafsurfaces[0]) ); + numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]) ); + numbrushes = CopyLump( header, LUMP_BRUSHES, dbrushes, sizeof(dbrush_t) ); + numbrushsides = CopyLump( header, LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t) ); + numDrawVerts = GetLumpElements( header, LUMP_DRAWVERTS, sizeof(drawVert_t) ); + SetDrawVerts(numDrawVerts); + CopyLump( header, LUMP_DRAWVERTS, drawVerts, sizeof(drawVert_t) ); + numDrawSurfaces = GetLumpElements( header, LUMP_SURFACES, sizeof(dsurface_t) ); + SetDrawSurfaces(numDrawSurfaces); + numDrawSurfaces = CopyLump( header, LUMP_SURFACES, drawSurfaces, sizeof(dsurface_t) ); + numFogs = CopyLump( header, LUMP_FOGS, dfogs, sizeof(dfog_t) ); + numDrawIndexes = CopyLump( header, LUMP_DRAWINDEXES, drawIndexes, sizeof(drawIndexes[0]) ); + + numVisBytes = CopyLump( header, LUMP_VISIBILITY, visBytes, 1 ); + numLightBytes = GetLumpElements( header, LUMP_LIGHTMAPS, 1 ); + SetLightBytes(numLightBytes); + CopyLump( header, LUMP_LIGHTMAPS, lightBytes, 1 ); + entdatasize = CopyLump( header, LUMP_ENTITIES, dentdata, 1); + + numGridPoints = GetLumpElements( header, LUMP_LIGHTGRID, 8 ); + SetGridPoints(numGridPoints); + CopyLump( header, LUMP_LIGHTGRID, gridData, 8 ); + + + free( header ); // everything has been copied out + + // swap everything + SwapBSPFile(); +} + + +//============================================================================ + +/* +============= +AddLump +============= +*/ +void AddLump( FILE *bspfile, dheader_t *header, int lumpnum, const void *data, int len ) { + lump_t *lump; + + lump = &header->lumps[lumpnum]; + + lump->fileofs = LittleLong( ftell(bspfile) ); + lump->filelen = LittleLong( len ); + SafeWrite( bspfile, data, (len+3)&~3 ); +} + +/* +============= +WriteBSPFile + +Swaps the bsp file in place, so it should not be referenced again +============= +*/ +void WriteBSPFile( const char *filename ) { + dheader_t outheader, *header; + FILE *bspfile; + + header = &outheader; + memset( header, 0, sizeof(dheader_t) ); + + SwapBSPFile(); + + header->ident = LittleLong( BSP_IDENT ); + header->version = LittleLong( bsp_version ); + + bspfile = SafeOpenWrite( filename ); + SafeWrite( bspfile, header, sizeof(dheader_t) ); // overwritten later + + AddLump( bspfile, header, LUMP_SHADERS, dshaders, numShaders*sizeof(dshader_t) ); + AddLump( bspfile, header, LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t) ); + AddLump( bspfile, header, LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t) ); + AddLump( bspfile, header, LUMP_NODES, dnodes, numnodes*sizeof(dnode_t) ); + AddLump( bspfile, header, LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t) ); + AddLump( bspfile, header, LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t) ); + AddLump( bspfile, header, LUMP_LEAFSURFACES, dleafsurfaces, numleafsurfaces*sizeof(dleafsurfaces[0]) ); + AddLump( bspfile, header, LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]) ); + AddLump( bspfile, header, LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t) ); + AddLump( bspfile, header, LUMP_DRAWVERTS, drawVerts, numDrawVerts*sizeof(drawVert_t) ); + AddLump( bspfile, header, LUMP_SURFACES, drawSurfaces, numDrawSurfaces*sizeof(dsurface_t) ); + AddLump( bspfile, header, LUMP_VISIBILITY, visBytes, numVisBytes ); + AddLump( bspfile, header, LUMP_LIGHTMAPS, lightBytes, numLightBytes ); + AddLump( bspfile, header, LUMP_LIGHTGRID, gridData, 8 * numGridPoints ); + AddLump( bspfile, header, LUMP_ENTITIES, dentdata, entdatasize ); + AddLump( bspfile, header, LUMP_FOGS, dfogs, numFogs * sizeof(dfog_t) ); + AddLump( bspfile, header, LUMP_DRAWINDEXES, drawIndexes, numDrawIndexes * sizeof(drawIndexes[0]) ); + + fseek (bspfile, 0, SEEK_SET); + SafeWrite (bspfile, header, sizeof(dheader_t)); + fclose (bspfile); +} + +//============================================================================ + +/* +============= +PrintBSPFileSizes + +Dumps info about current file +============= +*/ +void PrintBSPFileSizes( void ) { + if ( !num_entities ) { + ParseEntities(); + } + + Sys_Printf ("%6i models %7i\n" + ,nummodels, (int)(nummodels*sizeof(dmodel_t))); + Sys_Printf ("%6i shaders %7i\n" + ,numShaders, (int)(numShaders*sizeof(dshader_t))); + Sys_Printf ("%6i brushes %7i\n" + ,numbrushes, (int)(numbrushes*sizeof(dbrush_t))); + Sys_Printf ("%6i brushsides %7i\n" + ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t))); + Sys_Printf ("%6i fogs %7i\n" + ,numFogs, (int)(numFogs*sizeof(dfog_t))); + Sys_Printf ("%6i planes %7i\n" + ,numplanes, (int)(numplanes*sizeof(dplane_t))); + Sys_Printf ("%6i entdata %7i\n", num_entities, entdatasize); + + Sys_Printf ("\n"); + + Sys_Printf ("%6i nodes %7i\n" + ,numnodes, (int)(numnodes*sizeof(dnode_t))); + Sys_Printf ("%6i leafs %7i\n" + ,numleafs, (int)(numleafs*sizeof(dleaf_t))); + Sys_Printf ("%6i leafsurfaces %7i\n" + ,numleafsurfaces, (int)(numleafsurfaces*sizeof(dleafsurfaces[0]))); + Sys_Printf ("%6i leafbrushes %7i\n" + ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0]))); + Sys_Printf ("%6i drawverts %7i\n" + ,numDrawVerts, (int)(numDrawVerts*sizeof(drawVerts[0]))); + Sys_Printf ("%6i drawindexes %7i\n" + ,numDrawIndexes, (int)(numDrawIndexes*sizeof(drawIndexes[0]))); + Sys_Printf ("%6i drawsurfaces %7i\n" + ,numDrawSurfaces, (int)(numDrawSurfaces*sizeof(drawSurfaces[0]))); + + Sys_Printf ("%6i lightmaps %7i\n" + ,numLightBytes / (LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT*3), numLightBytes ); + Sys_Printf (" visibility %7i\n" + , numVisBytes ); +} + + +//============================================ + +int num_entities; +entity_t entities[MAX_MAP_ENTITIES]; + +void StripTrailing( char *e ) { + char *s; + + s = e + strlen(e)-1; + while (s >= e && *s <= 32) + { + *s = 0; + s--; + } +} + +/* +================= +ParseEpair +================= +*/ +epair_t *ParseEpair( void ) { + epair_t *e; + + e = safe_malloc( sizeof(epair_t) ); + memset( e, 0, sizeof(epair_t) ); + + if ( strlen(token) >= MAX_KEY-1 ) { + Error ("ParseEpar: token too long"); + } + e->key = copystring( token ); + GetToken( qfalse ); + if ( strlen(token) >= MAX_VALUE-1 ) { + Error ("ParseEpar: token too long"); + } + e->value = copystring( token ); + + // strip trailing spaces that sometimes get accidentally + // added in the editor + StripTrailing( e->key ); + StripTrailing( e->value ); + + return e; +} + + +/* +================ +ParseEntity +================ +*/ +qboolean ParseEntity( void ) { + epair_t *e; + entity_t *mapent; + + if ( !GetToken (qtrue) ) { + return qfalse; + } + + if ( strcmp (token, "{") ) { + Error ("ParseEntity: { not found"); + } + if ( num_entities == MAX_MAP_ENTITIES ) { + Error ("num_entities == MAX_MAP_ENTITIES"); + } + mapent = &entities[num_entities]; + num_entities++; + + do { + if ( !GetToken (qtrue) ) { + Error ("ParseEntity: EOF without closing brace"); + } + if ( !strcmp (token, "}") ) { + break; + } + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } while (1); + + return qtrue; +} + +/* +================ +ParseEntities + +Parses the dentdata string into entities +================ +*/ +void ParseEntities( void ) { + num_entities = 0; + ParseFromMemory( dentdata, entdatasize ); + + while ( ParseEntity () ) { + } +} + + +/* +================ +UnparseEntities + +Generates the dentdata string from all the entities +This allows the utilities to add or remove key/value pairs +to the data created by the map editor. +================ +*/ +void UnparseEntities( void ) { + char *buf, *end; + epair_t *ep; + char line[2048]; + int i; + char key[1024], value[1024]; + + buf = dentdata; + end = buf; + *end = 0; + + for (i=0 ; inext ) { + strcpy (key, ep->key); + StripTrailing (key); + strcpy (value, ep->value); + StripTrailing (value); + + sprintf (line, "\"%s\" \"%s\"\n", key, value); + strcat (end, line); + end += strlen(line); + } + strcat (end,"}\n"); + end += 2; + + if (end > buf + MAX_MAP_ENTSTRING) { + Error ("Entity text too long"); + } + } + entdatasize = end - buf + 1; +} + +void PrintEntity( const entity_t *ent ) { + epair_t *ep; + + Sys_Printf ("------- entity %p -------\n", ent); + for (ep=ent->epairs ; ep ; ep=ep->next) { + Sys_Printf( "%s = %s\n", ep->key, ep->value ); + } + +} + +void SetKeyValue( entity_t *ent, const char *key, const char *value ) { + epair_t *ep; + + for ( ep=ent->epairs ; ep ; ep=ep->next ) { + if ( !strcmp (ep->key, key) ) { + free (ep->value); + ep->value = copystring(value); + return; + } + } + ep = safe_malloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = copystring(key); + ep->value = copystring(value); +} + +const char *ValueForKey( const entity_t *ent, const char *key ) { + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) { + if (!strcmp (ep->key, key) ) { + return ep->value; + } + } + return ""; +} + +vec_t FloatForKey( const entity_t *ent, const char *key ) { + const char *k; + + k = ValueForKey( ent, key ); + return atof(k); +} + +void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ) { + const char *k; + double v1, v2, v3; + + k = ValueForKey (ent, key); + + // scanf into doubles, then assign, so it is vec_t size independent + v1 = v2 = v3 = 0; + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + vec[0] = v1; + vec[1] = v2; + vec[2] = v3; +} + + diff --git a/tools/quake3/common/bspfile.h b/tools/quake3/common/bspfile.h new file mode 100644 index 00000000..b44285f0 --- /dev/null +++ b/tools/quake3/common/bspfile.h @@ -0,0 +1,121 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qfiles.h" +#include "surfaceflags.h" + +extern int bsp_version; + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int numShaders; +extern dshader_t dshaders[MAX_MAP_MODELS]; + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numleafsurfaces; +extern int dleafsurfaces[MAX_MAP_LEAFFACES]; + +extern int numleafbrushes; +extern int dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +extern int numbrushes; +extern dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +extern int numbrushsides; +extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +void SetLightBytes(int n); +extern int numLightBytes; +extern byte *lightBytes; + +void SetGridPoints(int n); +extern int numGridPoints; +extern byte *gridData; + +extern int numVisBytes; +extern byte visBytes[MAX_MAP_VISIBILITY]; + +void SetDrawVerts(int n); +void IncDrawVerts(); +extern int numDrawVerts; +extern drawVert_t *drawVerts; + +extern int numDrawIndexes; +extern int drawIndexes[MAX_MAP_DRAW_INDEXES]; + +void SetDrawSurfaces(int n); +void SetDrawSurfacesBuffer(); +extern int numDrawSurfaces; +extern dsurface_t *drawSurfaces; + +extern int numFogs; +extern dfog_t dfogs[MAX_MAP_FOGS]; + +void LoadBSPFile( const char *filename ); +void WriteBSPFile( const char *filename ); +void PrintBSPFileSizes( void ); + +//=============== + + +typedef struct epair_s { + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct { + vec3_t origin; + struct bspbrush_s *brushes; + struct parseMesh_s *patches; + int firstDrawSurf; + epair_t *epairs; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities( void ); +void UnparseEntities( void ); + +void SetKeyValue( entity_t *ent, const char *key, const char *value ); +const char *ValueForKey( const entity_t *ent, const char *key ); +// will return "" if not present + +vec_t FloatForKey( const entity_t *ent, const char *key ); +void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ); + +epair_t *ParseEpair( void ); + +void PrintEntity( const entity_t *ent ); + diff --git a/tools/quake3/common/cmdlib.c b/tools/quake3/common/cmdlib.c new file mode 100644 index 00000000..17e41032 --- /dev/null +++ b/tools/quake3/common/cmdlib.c @@ -0,0 +1,1153 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// cmdlib.c +// TTimo 09/30/2000 +// from an intial copy of common/cmdlib.c +// stripped out the Sys_Printf Sys_Printf stuff + +// SPoG 05/27/2001 +// merging alpha branch into trunk +// replaced qprintf with Sys_Printf + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#ifdef NeXT +#include +#endif + +#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following +#define PATHSEPERATOR '/' + +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ) +{ + void *p; + + p = malloc(size); + if(!p) + Error ("safe_malloc failed on allocation of %i bytes", size); + + return p; +} + +void *safe_malloc_info( size_t size, char* info ) +{ + void *p; + + p = malloc(size); + if(!p) + Error ("%s: safe_malloc failed on allocation of %i bytes", info, size); + + return p; +} +#endif + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; +qboolean com_eof; + +qboolean archive; +char archivedir[1024]; + + +/* +=================== +ExpandWildcards + +Mimic unix command line expansion +=================== +*/ +#define MAX_EX_ARGC 1024 +int ex_argc; +char *ex_argv[MAX_EX_ARGC]; +#ifdef _WIN32 +#include "io.h" +void ExpandWildcards( int *argc, char ***argv ) +{ + struct _finddata_t fileinfo; + int handle; + int i; + char filename[1024]; + char filebase[1024]; + char *path; + + ex_argc = 0; + for (i=0 ; i<*argc ; i++) + { + path = (*argv)[i]; + if ( path[0] == '-' + || ( !strstr(path, "*") && !strstr(path, "?") ) ) + { + ex_argv[ex_argc++] = path; + continue; + } + + handle = _findfirst (path, &fileinfo); + if (handle == -1) + return; + + ExtractFilePath (path, filebase); + + do + { + sprintf (filename, "%s%s", filebase, fileinfo.name); + ex_argv[ex_argc++] = copystring (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + + *argc = ex_argc; + *argv = ex_argv; +} +#else +void ExpandWildcards (int *argc, char ***argv) +{ +} +#endif + +/* + +qdir will hold the path up to the quake directory, including the slash + + f:\quake\ + /raid/quake/ + +gamedir will hold qdir + the game directory (id1, id2, etc) + +*/ + +char qdir[1024]; +char gamedir[1024]; +char writedir[1024]; + +void SetQdirFromPath( const char *path ) +{ + char temp[1024]; + const char *c; + const char *sep; + int len, count; + + if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) + { // path is partial + Q_getwd (temp); + strcat (temp, path); + path = temp; + } + + // search for "quake2" in path + + len = strlen(BASEDIRNAME); + for (c=path+strlen(path)-1 ; c != path ; c--) + { + int i; + + if (!Q_strncasecmp (c, BASEDIRNAME, len)) + { + // + //strncpy (qdir, path, c+len+2-path); + // the +2 assumes a 2 or 3 following quake which is not the + // case with a retail install + // so we need to add up how much to the next separator + sep = c + len; + count = 1; + while (*sep && *sep != '/' && *sep != '\\') + { + sep++; + count++; + } + strncpy (qdir, path, c+len+count-path); + Sys_Printf ("qdir: %s\n", qdir); + for ( i = 0; i < strlen( qdir ); i++ ) + { + if ( qdir[i] == '\\' ) + qdir[i] = '/'; + } + + c += len+count; + while (*c) + { + if (*c == '/' || *c == '\\') + { + strncpy (gamedir, path, c+1-path); + + for ( i = 0; i < strlen( gamedir ); i++ ) + { + if ( gamedir[i] == '\\' ) + gamedir[i] = '/'; + } + + Sys_Printf ("gamedir: %s\n", gamedir); + + if ( !writedir[0] ) + strcpy( writedir, gamedir ); + else if ( writedir[strlen( writedir )-1] != '/' ) + { + writedir[strlen( writedir )] = '/'; + writedir[strlen( writedir )+1] = 0; + } + + return; + } + c++; + } + Error ("No gamedir in %s", path); + return; + } + } + Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path); +} + +char *ExpandArg (const char *path) +{ + static char full[1024]; + + if (path[0] != '/' && path[0] != '\\' && path[1] != ':') + { + Q_getwd (full); + strcat (full, path); + } + else + strcpy (full, path); + return full; +} + +char *ExpandPath (const char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandPath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { + strcpy( full, path ); + return full; + } + sprintf (full, "%s%s", qdir, path); + return full; +} + +char *ExpandGamePath (const char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandGamePath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { + strcpy( full, path ); + return full; + } + sprintf (full, "%s%s", gamedir, path); + return full; +} + +char *ExpandPathAndArchive (const char *path) +{ + char *expanded; + char archivename[1024]; + + expanded = ExpandPath (path); + + if (archive) + { + sprintf (archivename, "%s/%s", archivedir, path); + QCopyFile (expanded, archivename); + } + return expanded; +} + + +char *copystring(const char *s) +{ + char *b; + b = safe_malloc(strlen(s)+1); + strcpy (b, s); + return b; +} + + + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + +void Q_getwd (char *out) +{ + int i = 0; + +#ifdef _WIN32 + _getcwd (out, 256); + strcat (out, "\\"); +#else + // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow + getcwd (out, 256); + strcat (out, "/"); +#endif + while ( out[i] != 0 ) + { + if ( out[i] == '\\' ) + out[i] = '/'; + i++; + } +} + + +void Q_mkdir (const char *path) +{ +#ifdef _WIN32 + if (_mkdir (path) != -1) + return; +#else + if (mkdir (path, 0777) != -1) + return; +#endif + if (errno != EEXIST) + Error ("mkdir %s: %s",path, strerror(errno)); +} + +/* +============ +FileTime + +returns -1 if not present +============ +*/ +int FileTime (const char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = qtrue; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +int Q_strncasecmp (const char *s1, const char *s2, int n) +{ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + } while (c1); + + return 0; // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + +// NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config +// started getting warnings about that function, prolly a duplicate with the runtime function +// maybe we still need to have it in linux builds +/* +char *strupr (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; +} +*/ + +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (const char *check) +{ + int i; + + for (i = 1;i 0) { + nAllocSize += MEM_BLOCKSIZE - nBlock; + } + buffer = safe_malloc (nAllocSize+1); + memset(buffer, 0, nAllocSize+1); + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +TryLoadFile + +Allows failure +============== +*/ +int TryLoadFile (const char *filename, void **bufferptr) +{ + FILE *f; + int length; + void *buffer; + + *bufferptr = NULL; + + f = fopen (filename, "rb"); + if (!f) + return -1; + length = Q_filelength (f); + buffer = safe_malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +SaveFile +============== +*/ +void SaveFile (const char *filename, const void *buffer, int count) +{ + FILE *f; + + f = SafeOpenWrite (filename); + SafeWrite (f, buffer, count); + fclose (f); +} + + + +void DefaultExtension (char *path, const char *extension) +{ + char *src; +// +// if path doesnt have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && *src != '\\' && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + + +void DefaultPath (char *path, const char *basepath) +{ + char temp[128]; + + if( path[ 0 ] == '/' || path[ 0 ] == '\\' ) + return; // absolute path location + strcpy (temp,path); + strcpy (path,basepath); + strcat (path,temp); +} + + +void StripFilename (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '/' && path[ length ] != '\\' ) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/' || path[ length ] == '\\' ) + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '\\' && *(src-1) != '/') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (const char *hex) +{ + const char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (const char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* +============ +CreatePath +============ +*/ +void CreatePath (const char *path) +{ + const char *ofs; + char c; + char dir[1024]; + +#ifdef _WIN32 + int olddrive = -1; + + if ( path[1] == ':' ) + { + olddrive = _getdrive(); + _chdrive( toupper( path[0] ) - 'A' + 1 ); + } +#endif + + if (path[1] == ':') + path += 2; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + memcpy( dir, path, ofs - path ); + dir[ ofs - path ] = 0; + Q_mkdir( dir ); + } + } + +#ifdef _WIN32 + if ( olddrive != -1 ) + { + _chdrive( olddrive ); + } +#endif +} + + +/* +============ +QCopyFile + + Used to archive source files +============ +*/ +void QCopyFile (const char *from, const char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} + +void Sys_Sleep(int n) +{ +#ifdef _WIN32 + Sleep (n); +#endif +#if defined (__linux__) || defined (__APPLE__) + usleep (n * 1000); +#endif +} diff --git a/tools/quake3/common/cmdlib.h b/tools/quake3/common/cmdlib.h new file mode 100644 index 00000000..8c27ab85 --- /dev/null +++ b/tools/quake3/common/cmdlib.h @@ -0,0 +1,160 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include "bytebool.h" + +#ifdef _WIN32 +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4305) // truncate from double to float + +#pragma check_stack(off) + +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +#pragma intrinsic( memset, memcpy ) + +#endif + + +#define MAX_OS_PATH 1024 +#define MEM_BLOCKSIZE 4096 + +// the dec offsetof macro doesnt work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + +#define SAFE_MALLOC +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ); +void *safe_malloc_info( size_t size, char* info ); +#else +#define safe_malloc(a) malloc(a) +#endif /* SAFE_MALLOC */ + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +char *strlower (char *in); +int Q_strncasecmp( const char *s1, const char *s2, int n ); +int Q_stricmp( const char *s1, const char *s2 ); +void Q_getwd( char *out ); + +int Q_filelength (FILE *f); +int FileTime( const char *path ); + +void Q_mkdir( const char *path ); + +extern char qdir[1024]; +extern char gamedir[1024]; +extern char writedir[1024]; +extern char *moddirparam; +void SetQdirFromPath( const char *path); +char *ExpandArg( const char *path ); // from cmd line +char *ExpandPath( const char *path ); // from scripts +char *ExpandGamePath (const char *path); +char *ExpandPathAndArchive( const char *path ); +void ExpandWildcards( int *argc, char ***argv ); + + +double I_FloatTime( void ); + +void Error( const char *error, ... ); +int CheckParm( const char *check ); + +FILE *SafeOpenWrite( const char *filename ); +FILE *SafeOpenRead( const char *filename ); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, const void *buffer, int count); + +int LoadFile( const char *filename, void **bufferptr ); +int LoadFileBlock( const char *filename, void **bufferptr ); +int TryLoadFile( const char *filename, void **bufferptr ); +void SaveFile( const char *filename, const void *buffer, int count ); +qboolean FileExists( const char *filename ); + +void DefaultExtension( char *path, const char *extension ); +void DefaultPath( char *path, const char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); + +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); + +int ParseNum (const char *str); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +char *copystring(const char *s); + + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); + +void CreatePath( const char *path ); +void QCopyFile( const char *from, const char *to ); + +extern qboolean archive; +extern char archivedir[1024]; + +// sleep for the given amount of milliseconds +void Sys_Sleep(int n); + +// for compression routines +typedef struct +{ + void *data; + int count, width, height; +} cblock_t; + + +#endif diff --git a/tools/quake3/common/imagelib.c b/tools/quake3/common/imagelib.c new file mode 100644 index 00000000..8955d35a --- /dev/null +++ b/tools/quake3/common/imagelib.c @@ -0,0 +1,1220 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// imagelib.c + +#include "cmdlib.h" +#include "imagelib.h" +#include "vfs.h" + +int fgetLittleShort (FILE *f) +{ + byte b1, b2; + + b1 = fgetc(f); + b2 = fgetc(f); + + return (short)(b1 + b2*256); +} + +int fgetLittleLong (FILE *f) +{ + byte b1, b2, b3, b4; + + b1 = fgetc(f); + b2 = fgetc(f); + b3 = fgetc(f); + b4 = fgetc(f); + + return b1 + (b2<<8) + (b3<<16) + (b4<<24); +} + +int bufLittleShort (byte *buf, int len, int *pos) +{ + byte b1, b2; + + if ((len - *pos) < 2) + Error ("Unexpected buffer end"); + + b1 = buf[*pos]; *pos += 1; + b2 = buf[*pos]; *pos += 1; + + return (short)(b1 + b2*256); +} + +int bufLittleLong (byte *buf, int len, int *pos) +{ + byte b1, b2, b3, b4; + + if ((len - *pos) < 4) + Error ("Unexpected buffer end"); + + b1 = buf[*pos]; *pos += 1; + b2 = buf[*pos]; *pos += 1; + b3 = buf[*pos]; *pos += 1; + b4 = buf[*pos]; *pos += 1; + + return b1 + (b2<<8) + (b3<<16) + (b4<<24); +} + + +/* +============================================================================ + + LBM STUFF + +============================================================================ +*/ + + +typedef unsigned char UBYTE; +//conflicts with windows typedef short WORD; +typedef unsigned short UWORD; +typedef long LONG; + +typedef enum +{ + ms_none, + ms_mask, + ms_transcolor, + ms_lasso +} mask_t; + +typedef enum +{ + cm_none, + cm_rle1 +} compress_t; + +typedef struct +{ + UWORD w,h; + short x,y; + UBYTE nPlanes; + UBYTE masking; + UBYTE compression; + UBYTE pad1; + UWORD transparentColor; + UBYTE xAspect,yAspect; + short pageWidth,pageHeight; +} bmhd_t; + +extern bmhd_t bmhd; // will be in native byte order + + + +#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) +#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) +#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) +#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) +#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) +#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) + + +bmhd_t bmhd; + +int Align (int l) +{ + if (l&1) + return l+1; + return l; +} + + + +/* +================ +LBMRLEdecompress + +Source must be evenly aligned! +================ +*/ +byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) +{ + int count; + byte b,rept; + + count = 0; + + do + { + rept = *source++; + + if (rept > 0x80) + { + rept = (rept^0xff)+2; + b = *source++; + memset(unpacked,b,rept); + unpacked += rept; + } + else if (rept < 0x80) + { + rept++; + memcpy(unpacked,source,rept); + unpacked += rept; + source += rept; + } + else + rept = 0; // rept of 0x80 is NOP + + count += rept; + + } while (countbpwidth) + Error ("Decompression exceeded width!\n"); + + + return source; +} + + +/* +================= +LoadLBM +================= +*/ +void LoadLBM (const char *filename, byte **picture, byte **palette) +{ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + + int formtype,formlength; + int chunktype,chunklength; + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + +// +// load the LBM +// + LoadFile (filename, (void **)&LBMbuffer); + +// +// parse the LBM header +// + LBM_P = LBMbuffer; + if ( *(int *)LBMbuffer != LittleLong(FORMID) ) + Error ("No FORM ID at start of file!\n"); + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align(formlength); + + formtype = LittleLong(*(int *)LBM_P); + + if (formtype != ILBMID && formtype != PBMID) + Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff + ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + + LBM_P += 4; + +// +// parse chunks +// + + while (LBM_P < LBMEND_P) + { + chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + LBM_P += 4; + chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + LBM_P += 4; + + switch ( chunktype ) + { + case BMHDID: + memcpy (&bmhd,LBM_P,sizeof(bmhd)); + bmhd.w = BigShort(bmhd.w); + bmhd.h = BigShort(bmhd.h); + bmhd.x = BigShort(bmhd.x); + bmhd.y = BigShort(bmhd.y); + bmhd.pageWidth = BigShort(bmhd.pageWidth); + bmhd.pageHeight = BigShort(bmhd.pageHeight); + break; + + case CMAPID: + cmapbuffer = safe_malloc (768); + memset (cmapbuffer, 0, 768); + memcpy (cmapbuffer, LBM_P, chunklength); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = safe_malloc (bmhd.w*bmhd.h); + if (formtype == PBMID) + { + // + // unpack PBM + // + for (y=0 ; ydata; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + Error ("Bad pcx file %s", filename); + + if (palette) + { + *palette = safe_malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = safe_malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + if (!out) + Error( "LoadPCX: couldn't allocate"); + + *pic = out; + pix = out; + + /* RR2DO2: pcx fix */ + lsize = pcx->color_planes * pcx->bytes_per_line; + + /* go scanline by scanline */ + for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 ) + { + /* do a scanline */ + for( x=0; x <= pcx->xmax; ) + { + /* RR2DO2 */ + DECODEPCX( raw, dataByte, runLength ); + while( runLength-- > 0 ) + pix[ x++ ] = dataByte; + } + + /* RR2DO2: discard any other data */ + while( x < lsize ) + { + DECODEPCX( raw, dataByte, runLength ); + x++; + } + while( runLength-- > 0 ) + x++; + } + + /* validity check */ + if( raw - (byte *) pcx > len) + Error( "PCX file %s was malformed", filename ); + free( pcx ); +} + + + +/* +============== +WritePCXfile +============== +*/ +void WritePCXfile (const char *filename, byte *data, + int width, int height, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = safe_malloc (width*height*2+1000); + memset (pcx, 0, sizeof(*pcx)); + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(1); // not a grey scale + + // pack the image + pack = &pcx->data; + + for (i=0 ; i=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + // vertically flipped + if ( (targa_header.attributes & (1<<5)) ) { + int flip; + for (row = 0; row < .5f * rows; row++) + { + for (column = 0; column < columns; column++) + { + flip = *( (int*)targa_rgba + row * columns + column); + *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); + *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; + } + } + } + + //free(buffer); +} + + + +/* +============= +LoadTGA +============= +*/ +void LoadTGA (const char *name, byte **pixels, int *width, int *height) +{ + byte *buffer; + int nLen; + // + // load the file + // + nLen = vfsLoadFile ( ( char * ) name, (void **)&buffer, 0); + if (nLen == -1) + { + Error ("Couldn't read %s", name); + } + + LoadTGABuffer(buffer, pixels, width, height); + +} + + +/* +================ +WriteTGA +================ +*/ +void WriteTGA (const char *filename, byte *data, int width, int height) { + byte *buffer; + int i; + int c; + FILE *f; + + buffer = safe_malloc(width*height*4 + 18); + memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = width&255; + buffer[13] = width>>8; + buffer[14] = height&255; + buffer[15] = height>>8; + buffer[16] = 32; // pixel size + + // swap rgb to bgr + c = 18 + width * height * 4; + for (i=18 ; i +#include + +#ifdef _WIN32 +#include +#include +#endif + +// network broadcasting +#include "l_net/l_net.h" +#include "libxml/tree.h" + +#ifdef _WIN32 +HWND hwndOut = NULL; +qboolean lookedForServer = qfalse; +UINT wm_BroadcastCommand = -1; +#endif + +socket_t *brdcst_socket; +netmessage_t msg; + +qboolean verbose = qfalse; + +// our main document +// is streamed through the network to Radiant +// possibly written to disk at the end of the run +//++timo FIXME: need to be global, required when creating nodes? +xmlDocPtr doc; +xmlNodePtr tree; + +// some useful stuff +xmlNodePtr xml_NodeForVec( vec3_t v ) +{ + xmlNodePtr ret; + char buf[1024]; + + sprintf (buf, "%f %f %f", v[0], v[1], v[2]); + ret = xmlNewNode (NULL, "point"); + xmlNodeSetContent (ret, buf); + return ret; +} + +// send a node down the stream, add it to the document +void xml_SendNode (xmlNodePtr node) +{ + xmlBufferPtr xml_buf; + char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks .. + // this index loops through the node buffer + int pos = 0; + int size; + + xmlAddChild( doc->children, node ); + + if (brdcst_socket) + { + xml_buf = xmlBufferCreate(); + xmlNodeDump( xml_buf, doc, node, 0, 0 ); + + // the XML node might be too big to fit in a single network message + // l_net library defines an upper limit of MAX_NETMESSAGE + // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe + // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages + while (pos < xml_buf->use) + { + // what size are we gonna send now? + (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10); + //++timo just a debug thing + if (size == MAX_NETMESSAGE - 10) + Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n"); + memcpy( xmlbuf, xml_buf->content+pos, size); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); + // now that the thing is sent prepare to loop again + pos += size; + } + +#if 0 + // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE + // we will need to split into chunks + // (we could also go lower level, in the end it's using send and receiv which are not size limited) + //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message + // there's some tweaking to do in l_net for that .. so let's give us a margin for now + + //++timo we need to handle the case of a buffer too big to fit in a single message + // try without checks for now + if (xml_buf->use > MAX_NETMESSAGE-10 ) + { + // if we send that we are probably gonna break the stream at the other end.. + // and Error will call right there + //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing + Sys_FPrintf (SYS_NOXML, xml_buf->content); + + } + + size = xml_buf->use; + memcpy( xmlbuf, xml_buf->content, size ); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); +#endif + + xmlBufferFree( xml_buf ); + } +} + +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError) +{ + xmlNodePtr node, select; + char buf[1024]; + char level[2]; + + // now build a proper "select" XML node + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + node = xmlNewNode (NULL, "select"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'select' information + sprintf (buf, "%i %i", entitynum, brushnum); + select = xmlNewNode (NULL, "brush"); + xmlNodeSetContent (select, buf); + xmlAddChild (node, select); + xml_SendNode (node); + + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + if (bError) + Error(buf); + else + Sys_FPrintf (SYS_NOXML, "%s\n", buf); + +} + +void xml_Point (char *msg, vec3_t pt) +{ + xmlNodePtr node, point; + char buf[1024]; + char level[2]; + + node = xmlNewNode (NULL, "pointmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'point' node + sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]); + point = xmlNewNode (NULL, "point"); + xmlNodeSetContent (point, buf); + xmlAddChild (node, point); + xml_SendNode (node); + + sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]); + Error (buf); +} + +#define WINDING_BUFSIZE 2048 +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die) +{ + xmlNodePtr node, winding; + char buf[WINDING_BUFSIZE]; + char smlbuf[128]; + char level[2]; + int i; + + node = xmlNewNode (NULL, "windingmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'winding' node + sprintf( buf, "%i ", numpoints); + for(i = 0; i < numpoints; i++) + { + sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]); + // don't overflow + if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE) + break; + strcat( buf, smlbuf); + } + + winding = xmlNewNode (NULL, "winding"); + xmlNodeSetContent (winding, buf); + xmlAddChild (node, winding); + xml_SendNode (node); + + if(die) + Error (msg); + else + { + Sys_Printf(msg); + Sys_Printf("\n"); + } +} + +// in include +#include "stream_version.h" + +void Broadcast_Setup( const char *dest ) +{ + address_t address; + char sMsg[1024]; + + Net_Setup(); + Net_StringToAddress((char *)dest, &address); + brdcst_socket = Net_Connect(&address, 0); + if (brdcst_socket) + { + // send in a header + sprintf (sMsg, ""); + NMSG_Clear( &msg ); + NMSG_WriteString(&msg, sMsg ); + Net_Send(brdcst_socket, &msg ); + } +} + +void Broadcast_Shutdown() +{ + if (brdcst_socket) + { + Sys_Printf("Disconnecting\n"); + Net_Disconnect(brdcst_socket); + brdcst_socket = NULL; + } +} + +// all output ends up through here +void FPrintf (int flag, char *buf) +{ + xmlNodePtr node; + static qboolean bGotXML = qfalse; + char level[2]; + + printf(buf); + + // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe? + if (flag == SYS_NOXML) + return; + + // ouput an XML file of the run + // use the DOM interface to build a tree + /* + + message string + .. various nodes to describe corresponding geometry .. + + */ + if (!bGotXML) + { + // initialize + doc = xmlNewDoc("1.0"); + doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL); + bGotXML = qtrue; + } + node = xmlNewNode (NULL, "message"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + flag; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level ); + + xml_SendNode (node); +} + +#ifdef DBG_XML +void DumpXML() +{ + xmlSaveFile( "XMLDump.xml", doc ); +} +#endif + +void Sys_FPrintf (int flag, const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + if ((flag == SYS_VRB) && (verbose == qfalse)) + return; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (flag, out_buffer); +} + +void Sys_Printf (const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (SYS_STD, out_buffer); +} + +/* +================= +Error + +For abnormal program terminations +================= +*/ +void Error( const char *error, ...) +{ + char out_buffer[4096]; + char tmp[4096]; + va_list argptr; + + va_start (argptr,error); + vsprintf (tmp, error, argptr); + va_end (argptr); + + sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); + + FPrintf( SYS_ERR, out_buffer ); + +#ifdef DBG_XML + DumpXML(); +#endif + + //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener. + // a clean solution is to send a sync request node in the stream and wait for an answer before exiting + Sys_Sleep( 1000 ); + + Broadcast_Shutdown(); + + exit (1); +} + diff --git a/tools/quake3/common/inout.h b/tools/quake3/common/inout.h new file mode 100644 index 00000000..b7f13270 --- /dev/null +++ b/tools/quake3/common/inout.h @@ -0,0 +1,61 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __INOUT__ +#define __INOUT__ + +// inout is the only stuff relying on xml, include the headers there +#include "libxml/tree.h" + +// some useful xml routines +xmlNodePtr xml_NodeForVec( vec3_t v ); +void xml_SendNode (xmlNodePtr node); +// print a message in q3map output and send the corresponding select information down the xml stream +// bError: do we end with an error on this one or do we go ahead? +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError); +// end q3map with an error message and send a point information in the xml stream +// note: we might want to add a boolean to use this as a warning or an error thing.. +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die); +void xml_Point (char *msg, vec3_t pt); + +extern qboolean bNetworkBroadcast; +void Broadcast_Setup( const char *dest ); +void Broadcast_Shutdown(); + +#define SYS_VRB 0 // verbose support (on/off) +#define SYS_STD 1 // standard print level +#define SYS_WRN 2 // warnings +#define SYS_ERR 3 // error +#define SYS_NOXML 4 // don't send that down the XML stream + +extern qboolean verbose; +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); + +#ifdef _DEBUG +#define DBG_XML 1 +#endif + +#ifdef DBG_XML +void DumpXML(); +#endif + +#endif diff --git a/tools/quake3/common/l3dslib.c b/tools/quake3/common/l3dslib.c new file mode 100644 index 00000000..eb67e065 --- /dev/null +++ b/tools/quake3/common/l3dslib.c @@ -0,0 +1,301 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// l3dslib.c: library for loading triangles from an Alias triangle file +// + +#include +#include "cmdlib.h" +#include "mathlib.h" +#include "trilib.h" +#include "l3dslib.h" + +#define MAIN3DS 0x4D4D +#define EDIT3DS 0x3D3D // this is the start of the editor config +#define EDIT_OBJECT 0x4000 +#define OBJ_TRIMESH 0x4100 +#define TRI_VERTEXL 0x4110 +#define TRI_FACEL1 0x4120 + +#define MAXVERTS 2000 +#define MAXTRIANGLES 750 + +typedef struct { + int v[4]; +} tri; + +float fverts[MAXVERTS][3]; +tri tris[MAXTRIANGLES]; + +int bytesread, level, numtris, totaltris; +int vertsfound, trisfound; + +triangle_t *ptri; + + +// Alias stores triangles as 3 explicit vertices in .tri files, so even though we +// start out with a vertex pool and vertex indices for triangles, we have to convert +// to raw, explicit triangles +void StoreAliasTriangles (void) +{ + int i, j, k; + + if ((totaltris + numtris) > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0; i MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i 0) + { + w -= ParseChunk (input); + } + + retval = length; + goto Done; + + default: + // skip other chunks + while (w > 0) + { + t = w; + + if (t > BLOCK_SIZE) + t = BLOCK_SIZE; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp, t, 1, input); + bytesread += t; + + w -= t; + } + + retval = length; + goto Done; + } + +Done: + level--; + return retval; +} + + +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles) +{ + FILE *input; + short int tshort; + + bytesread = 0; + level = 0; + numtris = 0; + totaltris = 0; + vertsfound = 0; + trisfound = 0; + + if ((input = fopen(filename, "rb")) == 0) { + fprintf(stderr,"reader: could not open file '%s'\n", filename); + exit(0); + } + + fread(&tshort, sizeof(tshort), 1, input); + +// should only be MAIN3DS, but some files seem to start with EDIT3DS, with +// no MAIN3DS + if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) { + fprintf(stderr,"File is not a 3DS file.\n"); + exit(0); + } + +// back to top of file so we can parse the first chunk descriptor + fseek(input, 0, SEEK_SET); + + ptri = safe_malloc (MAXTRIANGLES * sizeof(triangle_t)); + + *pptri = ptri; + +// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT | +// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks + ParseChunk (input); + + if (vertsfound || trisfound) + Error ("Incomplete triangle set"); + + *numtriangles = totaltris; + + fclose (input); +} + diff --git a/tools/quake3/common/l3dslib.h b/tools/quake3/common/l3dslib.h new file mode 100644 index 00000000..a22d9c87 --- /dev/null +++ b/tools/quake3/common/l3dslib.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// l3dslib.h: header file for loading triangles from a 3DS triangle file +// +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles); + diff --git a/tools/quake3/common/md4.c b/tools/quake3/common/md4.c new file mode 100644 index 00000000..e69de29b diff --git a/tools/quake3/common/mutex.c b/tools/quake3/common/mutex.c new file mode 100644 index 00000000..bd699bf9 --- /dev/null +++ b/tools/quake3/common/mutex.c @@ -0,0 +1,197 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "cmdlib.h" +#include "qthreads.h" +#include "mutex.h" + +/* +=================================================================== + +WIN32 + +=================================================================== +*/ +#ifdef _WIN32 + +#define USED + +#include + +void MutexLock (mutex_t *m) +{ + CRITICAL_SECTION *crit; + + if (!m) + return; + crit = (CRITICAL_SECTION *) m; + EnterCriticalSection (crit); +} + +void MutexUnlock (mutex_t *m) +{ + CRITICAL_SECTION *crit; + + if (!m) + return; + crit = (CRITICAL_SECTION *) m; + LeaveCriticalSection (crit); +} + +mutex_t *MutexAlloc(void) +{ + CRITICAL_SECTION *crit; + + if (numthreads == 1) + return NULL; + crit = (CRITICAL_SECTION *) safe_malloc(sizeof(CRITICAL_SECTION)); + InitializeCriticalSection (crit); + return (void *) crit; +} + +#endif + +/* +=================================================================== + +OSF1 + +=================================================================== +*/ + +#ifdef __osf__ +#define USED + +#include + +void MutexLock (mutex_t *m) +{ + pthread_mutex_t *my_mutex; + + if (!m) + return; + my_mutex = (pthread_mutex_t *) m; + pthread_mutex_lock (my_mutex); +} + +void MutexUnlock (mutex_t *m) +{ + pthread_mutex_t *my_mutex; + + if (!m) + return; + my_mutex = (pthread_mutex_t *) m; + pthread_mutex_unlock (my_mutex); +} + +mutex_t *MutexAlloc(void) +{ + pthread_mutex_t *my_mutex; + pthread_mutexattr_t mattrib; + + if (numthreads == 1) + return NULL; + my_mutex = safe_malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); + return (void *) my_mutex; +} + +#endif + +/* +=================================================================== + +IRIX + +=================================================================== +*/ + +#ifdef _MIPS_ISA +#define USED + +#include +#include +#include +#include + +void MutexLock (mutex_t *m) +{ + abilock_t *lck; + + if (!m) + return; + lck = (abilock_t *) m; + spin_lock (lck); +} + +void MutexUnlock (mutex_t *m) +{ + abilock_t *lck; + + if (!m) + return; + lck = (abilock_t *) m; + release_lock (lck); +} + +mutex_t *MutexAlloc(void) +{ + abilock_t *lck; + + if (numthreads == 1) + return NULL; + lck = (abilock_t *) safe_malloc(sizeof(abilock_t)); + init_lock (lck); + return (void *) lck; +} + +#endif + +/* +======================================================================= + + SINGLE THREAD + +======================================================================= +*/ + +#ifndef USED + +void MutexLock (mutex_t *m) +{ +} + +void MutexUnlock (mutex_t *m) +{ +} + +mutex_t *MutexAlloc(void) +{ + return NULL; +} + +#endif diff --git a/tools/quake3/common/mutex.h b/tools/quake3/common/mutex.h new file mode 100644 index 00000000..ce6dab00 --- /dev/null +++ b/tools/quake3/common/mutex.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + + +typedef void *mutex_t; + +void MutexLock (mutex_t *m); +void MutexUnlock (mutex_t *m); +mutex_t *MutexAlloc(void); diff --git a/tools/quake3/common/polylib.c b/tools/quake3/common/polylib.c new file mode 100644 index 00000000..9f5a1d49 --- /dev/null +++ b/tools/quake3/common/polylib.c @@ -0,0 +1,745 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include "polylib.h" +#include "qfiles.h" + + +extern int numthreads; + +// counters are only bumped when running single threaded, +// because they are an awefull coherence problem +int c_active_windings; +int c_peak_windings; +int c_winding_allocs; +int c_winding_points; + +#define BOGUS_RANGE WORLD_SIZE + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + Sys_Printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]); +} + + +/* +============= +AllocWinding +============= +*/ +winding_t *AllocWinding (int points) +{ + winding_t *w; + int s; + + if (points >= MAX_POINTS_ON_WINDING) + Error ("AllocWinding failed: MAX_POINTS_ON_WINDING exceeded"); + + if (numthreads == 1) + { + c_winding_allocs++; + c_winding_points += points; + c_active_windings++; + if (c_active_windings > c_peak_windings) + c_peak_windings = c_active_windings; + } + s = sizeof(vec_t)*3*points + sizeof(int); + w = safe_malloc (s); + memset (w, 0, s); + return w; +} + +void FreeWinding (winding_t *w) +{ + if (*(unsigned *)w == 0xdeaddead) + Error ("FreeWinding: freed a freed winding"); + *(unsigned *)w = 0xdeaddead; + + if (numthreads == 1) + c_active_windings--; + free (w); +} + +/* +============ +RemoveColinearPoints +============ +*/ +int c_removed; + +void RemoveColinearPoints (winding_t *w) +{ + int i, j, k; + vec3_t v1, v2; + int nump; + vec3_t p[MAX_POINTS_ON_WINDING]; + + nump = 0; + for (i=0 ; inumpoints ; i++) + { + j = (i+1)%w->numpoints; + k = (i+w->numpoints-1)%w->numpoints; + VectorSubtract (w->p[j], w->p[i], v1); + VectorSubtract (w->p[i], w->p[k], v2); + VectorNormalize(v1,v1); + VectorNormalize(v2,v2); + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (w->p[i], p[nump]); + nump++; + } + } + + if (nump == w->numpoints) + return; + + if (numthreads == 1) + c_removed += w->numpoints - nump; + w->numpoints = nump; + memcpy (w->p, p, nump*sizeof(p[0])); +} + +/* +============ +WindingPlane +============ +*/ +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist) +{ + vec3_t v1, v2; + + VectorSubtract (w->p[1], w->p[0], v1); + VectorSubtract (w->p[2], w->p[0], v2); + CrossProduct (v2, v1, normal); + VectorNormalize (normal, normal); + *dist = DotProduct (w->p[0], normal); + +} + +/* +============= +WindingArea +============= +*/ +vec_t WindingArea (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->p[i-1], w->p[0], d1); + VectorSubtract (w->p[i], w->p[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs) +{ + vec_t v; + int i,j; + + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +/* +============= +WindingCenter +============= +*/ +void WindingCenter (winding_t *w, vec3_t center) +{ + int i; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; inumpoints ; i++) + VectorAdd (w->p[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + +/* +================= +BaseWindingForPlane +================= +*/ +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, MAX_WORLD_COORD, vup); + VectorScale (vright, MAX_WORLD_COORD, vright); + + // project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + c = AllocWinding (w->numpoints); + size = (int)((winding_t *)0)->p[w->numpoints]; + memcpy (c, w, size); + return c; +} + +/* +================== +ReverseWinding +================== +*/ +winding_t *ReverseWinding (winding_t *w) +{ + int i; + winding_t *c; + + c = AllocWinding (w->numpoints); + for (i=0 ; inumpoints ; i++) + { + VectorCopy (w->p[w->numpoints-1-i], c->p[i]); + } + c->numpoints = w->numpoints; + return c; +} + + +/* +============= +ClipWindingEpsilon +============= +*/ +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding (in); + return; + } + if (!counts[1]) + { + *front = CopyWinding (in); + return; + } + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + *front = f = AllocWinding (maxpts); + *back = b = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon) +{ + winding_t *in; + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding (in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding (in); + *inout = f; +} + + +/* +================= +ChopWinding + +Returns the fragment of in that is on the front side +of the cliping plane. The original is freed. +================= +*/ +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) +{ + winding_t *f, *b; + + ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b); + FreeWinding (in); + if (b) + FreeWinding (b); + return f; +} + + +/* +================= +CheckWinding + +================= +*/ +void CheckWinding (winding_t *w) +{ + int i, j; + vec_t *p1, *p2; + vec_t d, edgedist; + vec3_t dir, edgenormal, facenormal; + vec_t area; + vec_t facedist; + + if (w->numpoints < 3) + Error ("CheckWinding: %i points",w->numpoints); + + area = WindingArea(w); + if (area < 1) + Error ("CheckWinding: %f area", area); + + WindingPlane (w, facenormal, &facedist); + + for (i=0 ; inumpoints ; i++) + { + p1 = w->p[i]; + + for (j=0 ; j<3 ; j++) + if (p1[j] > MAX_WORLD_COORD || p1[j] < MIN_WORLD_COORD) + Error ("CheckFace: MAX_WORLD_COORD exceeded: %f",p1[j]); + + j = i+1 == w->numpoints ? 0 : i+1; + + // check the point is on the face plane + d = DotProduct (p1, facenormal) - facedist; + if (d < -ON_EPSILON || d > ON_EPSILON) + Error ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = w->p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Error ("CheckWinding: degenerate edge"); + + CrossProduct (facenormal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + edgedist += ON_EPSILON; + + // all other points must be on front side + for (j=0 ; jnumpoints ; j++) + { + if (j == i) + continue; + d = DotProduct (w->p[j], edgenormal); + if (d > edgedist) + Error ("CheckWinding: non-convex"); + } + } +} + + +/* +============ +WindingOnPlaneSide +============ +*/ +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist) +{ + qboolean front, back; + int i; + vec_t d; + + front = qfalse; + back = qfalse; + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = qtrue; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = qtrue; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + + +/* +================= +AddWindingToConvexHull + +Both w and *hull are on the same plane +================= +*/ +#define MAX_HULL_POINTS 128 +void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) { + int i, j, k; + float *p, *copy; + vec3_t dir; + float d; + int numHullPoints, numNew; + vec3_t hullPoints[MAX_HULL_POINTS]; + vec3_t newHullPoints[MAX_HULL_POINTS]; + vec3_t hullDirs[MAX_HULL_POINTS]; + qboolean hullSide[MAX_HULL_POINTS]; + qboolean outside; + + if ( !*hull ) { + *hull = CopyWinding( w ); + return; + } + + numHullPoints = (*hull)->numpoints; + memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) ); + + for ( i = 0 ; i < w->numpoints ; i++ ) { + p = w->p[i]; + + // calculate hull side vectors + for ( j = 0 ; j < numHullPoints ; j++ ) { + k = ( j + 1 ) % numHullPoints; + + VectorSubtract( hullPoints[k], hullPoints[j], dir ); + VectorNormalize( dir, dir ); + CrossProduct( normal, dir, hullDirs[j] ); + } + + outside = qfalse; + for ( j = 0 ; j < numHullPoints ; j++ ) { + VectorSubtract( p, hullPoints[j], dir ); + d = DotProduct( dir, hullDirs[j] ); + if ( d >= ON_EPSILON ) { + outside = qtrue; + } + if ( d >= -ON_EPSILON ) { + hullSide[j] = qtrue; + } else { + hullSide[j] = qfalse; + } + } + + // if the point is effectively inside, do nothing + if ( !outside ) { + continue; + } + + // find the back side to front side transition + for ( j = 0 ; j < numHullPoints ; j++ ) { + if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) { + break; + } + } + if ( j == numHullPoints ) { + continue; + } + + // insert the point here + VectorCopy( p, newHullPoints[0] ); + numNew = 1; + + // copy over all points that aren't double fronts + j = (j+1)%numHullPoints; + for ( k = 0 ; k < numHullPoints ; k++ ) { + if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) { + continue; + } + copy = hullPoints[ (j+k+1) % numHullPoints ]; + VectorCopy( copy, newHullPoints[numNew] ); + numNew++; + } + + numHullPoints = numNew; + memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) ); + } + + FreeWinding( *hull ); + w = AllocWinding( numHullPoints ); + w->numpoints = numHullPoints; + *hull = w; + memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) ); +} + + diff --git a/tools/quake3/common/polylib.h b/tools/quake3/common/polylib.h new file mode 100644 index 00000000..0bc4a8ad --- /dev/null +++ b/tools/quake3/common/polylib.h @@ -0,0 +1,57 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +typedef struct +{ + int numpoints; + vec3_t p[4]; // variable sized +} winding_t; + +#define MAX_POINTS_ON_WINDING 64 + +// you can define on_epsilon in the makefile as tighter +#ifndef ON_EPSILON +#define ON_EPSILON 0.1 +#endif + +winding_t *AllocWinding (int points); +vec_t WindingArea (winding_t *w); +void WindingCenter (winding_t *w, vec3_t center); +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back); +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist); +winding_t *CopyWinding (winding_t *w); +winding_t *ReverseWinding (winding_t *w); +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist); +void CheckWinding (winding_t *w); +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist); +void RemoveColinearPoints (winding_t *w); +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist); +void FreeWinding (winding_t *w); +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs); + +void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ); + +void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon); +// frees the original if clipped + +void pw(winding_t *w); diff --git a/tools/quake3/common/polyset.h b/tools/quake3/common/polyset.h new file mode 100644 index 00000000..459fde12 --- /dev/null +++ b/tools/quake3/common/polyset.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __POLYSET_H__ +#define __POLYSET_H__ + +#define POLYSET_MAXTRIANGLES 4096 +#define POLYSET_MAXPOLYSETS 64 + +typedef float st_t[2]; +typedef float rgb_t[3]; + +typedef struct { + vec3_t verts[3]; + vec3_t normals[3]; + st_t texcoords[3]; +} triangle_t; + +typedef struct +{ + char name[100]; + char materialname[100]; + triangle_t *triangles; + int numtriangles; +} polyset_t; + +polyset_t *Polyset_LoadSets( const char *file, int *numpolysets, int maxTrisPerSet ); +polyset_t *Polyset_CollapseSets( polyset_t *psets, int numpolysets ); +polyset_t *Polyset_SplitSets( polyset_t *psets, int numpolysets, int *pNumNewPolysets, int maxTris ); +void Polyset_SnapSets( polyset_t *psets, int numpolysets ); +void Polyset_ComputeNormals( polyset_t *psets, int numpolysets ); + +#endif diff --git a/tools/quake3/common/qfiles.h b/tools/quake3/common/qfiles.h new file mode 100644 index 00000000..584d8e96 --- /dev/null +++ b/tools/quake3/common/qfiles.h @@ -0,0 +1,489 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __QFILES_H__ +#define __QFILES_H__ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +// surface geometry should not exceed these limits +#define SHADER_MAX_VERTEXES 1000 +#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES) + + +// the maximum size of game reletive pathnames +#define MAX_QPATH 64 + +/* +======================================================================== + +QVM files + +======================================================================== +*/ + +#define VM_MAGIC 0x12721444 +typedef struct { + int vmMagic; + + int instructionCount; + + int codeOffset; + int codeLength; + + int dataOffset; + int dataLength; + int litLength; // ( dataLength - litLength ) should be byteswapped on load + int bssLength; // zero filled memory appended to datalength +} vmHeader_t; + + +/* +======================================================================== + +PCX files are used for 8 bit images + +======================================================================== +*/ + +typedef struct { + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* +======================================================================== + +TGA files are used for 24/32 bit images + +======================================================================== +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + + +/* +======================================================================== + +.MD3 triangle model file format + +======================================================================== +*/ + +#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I') +#define MD3_VERSION 15 + +// limits +#define MD3_MAX_LODS 4 +#define MD3_MAX_TRIANGLES 8192 // per surface +#define MD3_MAX_VERTS 4096 // per surface +#define MD3_MAX_SHADERS 256 // per surface +#define MD3_MAX_FRAMES 1024 // per model +#define MD3_MAX_SURFACES 32 // per model +#define MD3_MAX_TAGS 16 // per frame + +// vertex scales +#define MD3_XYZ_SCALE (1.0/64) + +typedef struct md3Frame_s { + vec3_t bounds[2]; + vec3_t localOrigin; + float radius; + char name[16]; +} md3Frame_t; + +typedef struct md3Tag_s { + char name[MAX_QPATH]; // tag name + vec3_t origin; + vec3_t axis[3]; +} md3Tag_t; + +/* +** md3Surface_t +** +** CHUNK SIZE +** header sizeof( md3Surface_t ) +** shaders sizeof( md3Shader_t ) * numShaders +** triangles[0] sizeof( md3Triangle_t ) * numTriangles +** st sizeof( md3St_t ) * numVerts +** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames +*/ +typedef struct { + int ident; // + + char name[MAX_QPATH]; // polyset name + + int flags; + int numFrames; // all surfaces in a model should have the same + + int numShaders; // all surfaces in a model should have the same + int numVerts; + + int numTriangles; + int ofsTriangles; + + int ofsShaders; // offset from start of md3Surface_t + int ofsSt; // texture coords are common for all frames + int ofsXyzNormals; // numVerts * numFrames + + int ofsEnd; // next surface follows +} md3Surface_t; + +typedef struct { + char name[MAX_QPATH]; + int shaderIndex; // for in-game use +} md3Shader_t; + +typedef struct { + int indexes[3]; +} md3Triangle_t; + +typedef struct { + float st[2]; +} md3St_t; + +typedef struct { + short xyz[3]; + short normal; +} md3XyzNormal_t; + +typedef struct { + int ident; + int version; + + char name[MAX_QPATH]; // model name + + int flags; + + int numFrames; + int numTags; + int numSurfaces; + + int numSkins; + + int ofsFrames; // offset for first frame + int ofsTags; // numFrames * numTags + int ofsSurfaces; // first surface, others follow + + int ofsEnd; // end of file +} md3Header_t; + +/* +============================================================================== + +MD4 file format + +============================================================================== +*/ + +#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I') +#define MD4_VERSION 1 +#define MD4_MAX_BONES 128 + +typedef struct { + int boneIndex; // these are indexes into the boneReferences, + float boneWeight; // not the global per-frame bone list +} md4Weight_t; + +typedef struct { + vec3_t vertex; + vec3_t normal; + float texCoords[2]; + int numWeights; + md4Weight_t weights[1]; // variable sized +} md4Vertex_t; + +typedef struct { + int indexes[3]; +} md4Triangle_t; + +typedef struct { + int ident; + + char name[MAX_QPATH]; // polyset name + char shader[MAX_QPATH]; + int shaderIndex; // for in-game use + + int ofsHeader; // this will be a negative number + + int numVerts; + int ofsVerts; + + int numTriangles; + int ofsTriangles; + + // Bone references are a set of ints representing all the bones + // present in any vertex weights for this surface. This is + // needed because a model may have surfaces that need to be + // drawn at different sort times, and we don't want to have + // to re-interpolate all the bones for each surface. + int numBoneReferences; + int ofsBoneReferences; + + int ofsEnd; // next surface follows +} md4Surface_t; + +typedef struct { + float matrix[3][4]; +} md4Bone_t; + +typedef struct { + vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame + vec3_t localOrigin; // midpoint of bounds, used for sphere cull + float radius; // dist from localOrigin to corner + char name[16]; + md4Bone_t bones[1]; // [numBones] +} md4Frame_t; + +typedef struct { + int numSurfaces; + int ofsSurfaces; // first surface, others follow + int ofsEnd; // next lod follows +} md4LOD_t; + +typedef struct { + int ident; + int version; + + char name[MAX_QPATH]; // model name + + // frames and bones are shared by all levels of detail + int numFrames; + int numBones; + int ofsFrames; // md4Frame_t[numFrames] + + // each level of detail has completely separate sets of surfaces + int numLODs; + int ofsLODs; + + int ofsEnd; // end of file +} md4Header_t; + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + + +#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +//#define BSP_VERSION 46 +#define Q3_BSP_VERSION 46 +#define WOLF_BSP_VERSION 47 + +// there shouldn't be any problem with increasing these values at the +// expense of more memory allocation in the utilities +#define MAX_MAP_MODELS 0x400 +#define MAX_MAP_BRUSHES 0x8000 +#define MAX_MAP_ENTITIES 0x800 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_SHADERS 0x400 + +#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match! +#define MAX_MAP_FOGS 0x100 +#define MAX_MAP_PLANES 0x20000 +#define MAX_MAP_NODES 0x20000 +#define MAX_MAP_BRUSHSIDES 0x40000 //% 0x20000 /* ydnar */ +#define MAX_MAP_LEAFS 0x20000 +#define MAX_MAP_LEAFFACES 0x20000 +#define MAX_MAP_LEAFBRUSHES 0x40000 +#define MAX_MAP_PORTALS 0x20000 +#define MAX_MAP_LIGHTING 0x800000 +#define MAX_MAP_LIGHTGRID 0x800000 +#define MAX_MAP_VISIBILITY 0x200000 + +#define MAX_MAP_DRAW_SURFS 0x20000 +#define MAX_MAP_DRAW_VERTS 0x80000 +#define MAX_MAP_DRAW_INDEXES 0x80000 + + +// key / value pair sizes in the entities lump +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +// the editor uses these predefined yaw angles to orient entities up or down +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +#define LIGHTMAP_WIDTH 128 +#define LIGHTMAP_HEIGHT 128 + +#define MIN_WORLD_COORD (-65536) +#define MAX_WORLD_COORD (65536) +#define WORLD_SIZE (MAX_WORLD_COORD - MIN_WORLD_COORD) + +//============================================================================= + + +typedef struct { + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define HEADER_LUMPS 17 + +typedef struct { + int ident; + int version; + + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct { + float mins[3], maxs[3]; + int firstSurface, numSurfaces; + int firstBrush, numBrushes; +} dmodel_t; + +typedef struct { + char shader[MAX_QPATH]; + int surfaceFlags; + int contentFlags; +} dshader_t; + +// planes x^1 is allways the opposite of plane x + +typedef struct { + float normal[3]; + float dist; +} dplane_t; + +typedef struct { + int planeNum; + int children[2]; // negative numbers are -(leafs+1), not nodes + int mins[3]; // for frustom culling + int maxs[3]; +} dnode_t; + +typedef struct { + int cluster; // -1 = opaque cluster (do I still store these?) + int area; + + int mins[3]; // for frustum culling + int maxs[3]; + + int firstLeafSurface; + int numLeafSurfaces; + + int firstLeafBrush; + int numLeafBrushes; +} dleaf_t; + +typedef struct { + int planeNum; // positive plane side faces out of the leaf + int shaderNum; +} dbrushside_t; + +typedef struct { + int firstSide; + int numSides; + int shaderNum; // the shader that determines the contents flags +} dbrush_t; + +typedef struct { + char shader[MAX_QPATH]; + int brushNum; + int visibleSide; // the brush side that ray tests need to clip against (-1 == none) +} dfog_t; + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; + byte color[4]; +} drawVert_t; + +typedef enum { + MST_BAD, + MST_PLANAR, + MST_PATCH, + MST_TRIANGLE_SOUP, + MST_FLARE +} mapSurfaceType_t; + +typedef struct { + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + int lightmapNum; + int lightmapX, lightmapY; + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds + + int patchWidth; + int patchHeight; +} dsurface_t; + + +#endif diff --git a/tools/quake3/common/qthreads.h b/tools/quake3/common/qthreads.h new file mode 100644 index 00000000..eeeac14f --- /dev/null +++ b/tools/quake3/common/qthreads.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +extern int numthreads; + +void ThreadSetDefault (void); +int GetThreadWork (void); +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)); +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)); +void ThreadLock (void); +void ThreadUnlock (void); + diff --git a/tools/quake3/common/scriplib.c b/tools/quake3/common/scriplib.c new file mode 100644 index 00000000..267078c6 --- /dev/null +++ b/tools/quake3/common/scriplib.c @@ -0,0 +1,409 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// scriplib.c + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include "scriplib.h" +#include "vfs.h" + +/* +============================================================================= + + PARSING STUFF + +============================================================================= +*/ + +typedef struct +{ + char filename[1024]; + char *buffer,*script_p,*end_p; + int line; +} script_t; + +#define MAX_INCLUDES 8 +script_t scriptstack[MAX_INCLUDES]; +script_t *script; +int scriptline; + +char token[MAXTOKEN]; +qboolean endofscript; +qboolean tokenready; // only qtrue if UnGetToken was just called + +/* +============== +AddScriptToStack +============== +*/ +void AddScriptToStack (const char *filename, int index) +{ + int size; + + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, ExpandPath (filename)); + + size = vfsLoadFile (script->filename, (void **)&script->buffer, index); + + if (size == -1) + Sys_Printf ("Script file %s was not found\n", script->filename); + else + { + if (index > 0) + Sys_Printf ("entering %s (%d)\n", script->filename, index+1); + else + Sys_Printf ("entering %s\n", script->filename); + } + + script->line = 1; + script->script_p = script->buffer; + script->end_p = script->buffer + size; +} + + +/* +============== +LoadScriptFile +============== +*/ +void LoadScriptFile (const char *filename, int index) +{ + script = scriptstack; + AddScriptToStack (filename, index); + + endofscript = qfalse; + tokenready = qfalse; +} + + +/* +============== +ParseFromMemory +============== +*/ +void ParseFromMemory (char *buffer, int size) +{ + script = scriptstack; + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, "memory buffer" ); + + script->buffer = buffer; + script->line = 1; + script->script_p = script->buffer; + script->end_p = script->buffer + size; + + endofscript = qfalse; + tokenready = qfalse; +} + + +/* +============== +UnGetToken + +Signals that the current token was not used, and should be reported +for the next GetToken. Note that + +GetToken (qtrue); +UnGetToken (); +GetToken (qfalse); + +could cross a line boundary. +============== +*/ +void UnGetToken (void) +{ + tokenready = qtrue; +} + + +qboolean EndOfScript (qboolean crossline) +{ + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + + if (!strcmp (script->filename, "memory buffer")) + { + endofscript = qtrue; + return qfalse; + } + + if( script->buffer == NULL ) + Sys_Printf( "WARNING: Attempt to free already freed script buffer\n" ); + else + free( script->buffer ); + script->buffer = NULL; + if (script == scriptstack+1) + { + endofscript = qtrue; + return qfalse; + } + script--; + scriptline = script->line; + Sys_Printf ("returning to %s\n", script->filename); + return GetToken (crossline); +} + +/* +============== +GetToken +============== +*/ +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + + /* ydnar: dummy testing */ + if( script == NULL || script->buffer == NULL ) + return qfalse; + + if (tokenready) // is a token already waiting? + { + tokenready = qfalse; + return qtrue; + } + + if ((script->script_p >= script->end_p) || (script->script_p == NULL)) + return EndOfScript (crossline); + +// +// skip space +// +skipspace: + while (*script->script_p <= 32) + { + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + if (*script->script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + script->line++; + scriptline = script->line; + } + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + + // ; # // comments + if (*script->script_p == ';' || *script->script_p == '#' + || ( script->script_p[0] == '/' && script->script_p[1] == '/') ) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script->script_p++ != '\n') + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + script->line++; + scriptline = script->line; + goto skipspace; + } + + // /* */ comments + if (script->script_p[0] == '/' && script->script_p[1] == '*') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + script->script_p+=2; + while (script->script_p[0] != '*' && script->script_p[1] != '/') + { + if ( *script->script_p == '\n' ) + { + script->line++; + scriptline = script->line; + } + script->script_p++; + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + } + script->script_p += 2; + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script->script_p == '"') + { + // quoted token + script->script_p++; + while (*script->script_p != '"') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + script->script_p++; + } + else // regular token + while ( *script->script_p > 32 && *script->script_p != ';') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + + *token_p = 0; + + if (!strcmp (token, "$include")) + { + GetToken (qfalse); + AddScriptToStack (token, 0); + return GetToken (crossline); + } + + return qtrue; +} + + +/* +============== +TokenAvailable + +Returns qtrue if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) { + int oldLine, oldScriptLine; + qboolean r; + + /* save */ + oldLine = scriptline; + oldScriptLine = script->line; + + /* test */ + r = GetToken( qtrue ); + if ( !r ) { + return qfalse; + } + UnGetToken(); + if ( oldLine == scriptline ) { + return qtrue; + } + + /* restore */ + //% scriptline = oldLine; + //% script->line = oldScriptLine; + + return qfalse; +} + + +//===================================================================== + + +void MatchToken( char *match ) { + GetToken( qtrue ); + + if ( strcmp( token, match ) ) { + Error( "MatchToken( \"%s\" ) failed at line %i in file %s", match, scriptline, script->filename); + } +} + + +void Parse1DMatrix (int x, vec_t *m) { + int i; + + MatchToken( "(" ); + + for (i = 0 ; i < x ; i++) { + GetToken( qfalse ); + m[i] = atof(token); + } + + MatchToken( ")" ); +} + +void Parse2DMatrix (int y, int x, vec_t *m) { + int i; + + MatchToken( "(" ); + + for (i = 0 ; i < y ; i++) { + Parse1DMatrix (x, m + i * x); + } + + MatchToken( ")" ); +} + +void Parse3DMatrix (int z, int y, int x, vec_t *m) { + int i; + + MatchToken( "(" ); + + for (i = 0 ; i < z ; i++) { + Parse2DMatrix (y, x, m + i * x*y); + } + + MatchToken( ")" ); +} + + +void Write1DMatrix (FILE *f, int x, vec_t *m) { + int i; + + fprintf (f, "( "); + for (i = 0 ; i < x ; i++) { + if (m[i] == (int)m[i] ) { + fprintf (f, "%i ", (int)m[i]); + } else { + fprintf (f, "%f ", m[i]); + } + } + fprintf (f, ")"); +} + +void Write2DMatrix (FILE *f, int y, int x, vec_t *m) { + int i; + + fprintf (f, "( "); + for (i = 0 ; i < y ; i++) { + Write1DMatrix (f, x, m + i*x); + fprintf (f, " "); + } + fprintf (f, ")\n"); +} + + +void Write3DMatrix (FILE *f, int z, int y, int x, vec_t *m) { + int i; + + fprintf (f, "(\n"); + for (i = 0 ; i < z ; i++) { + Write2DMatrix (f, y, x, m + i*(x*y) ); + } + fprintf (f, ")\n"); +} + diff --git a/tools/quake3/common/scriplib.h b/tools/quake3/common/scriplib.h new file mode 100644 index 00000000..accc5a1c --- /dev/null +++ b/tools/quake3/common/scriplib.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// scriplib.h + +#ifndef __CMDLIB__ +#include "../common/cmdlib.h" +#endif +#ifndef __MATHLIB__ +#include "mathlib.h" +#endif + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern char *scriptbuffer,*script_p,*scriptend_p; +extern int grabbed; +extern int scriptline; +extern qboolean endofscript; + + +void LoadScriptFile (const char *filename, int index); +void ParseFromMemory (char *buffer, int size); + +qboolean GetToken (qboolean crossline); +void UnGetToken (void); +qboolean TokenAvailable (void); + +void MatchToken( char *match ); + +void Parse1DMatrix (int x, vec_t *m); +void Parse2DMatrix (int y, int x, vec_t *m); +void Parse3DMatrix (int z, int y, int x, vec_t *m); + +void Write1DMatrix (FILE *f, int x, vec_t *m); +void Write2DMatrix (FILE *f, int y, int x, vec_t *m); +void Write3DMatrix (FILE *f, int z, int y, int x, vec_t *m); diff --git a/tools/quake3/common/surfaceflags.h b/tools/quake3/common/surfaceflags.h new file mode 100644 index 00000000..cb8f045c --- /dev/null +++ b/tools/quake3/common/surfaceflags.h @@ -0,0 +1,112 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// This file must be identical in the quake and utils directories + +// contents flags are seperate bits +// a given brush can contribute multiple content bits + +// these definitions also need to be in q_shared.h! + +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_FOG 64 + +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 +//bot specific contents types +#define CONTENTS_TELEPORTER 0x40000 +#define CONTENTS_JUMPPAD 0x80000 +#define CONTENTS_CLUSTERPORTAL 0x100000 +#define CONTENTS_DONOTENTER 0x200000 +#define CONTENTS_BOTCLIP 0x400000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_BODY 0x2000000 // should never be on a brush, only in game +#define CONTENTS_CORPSE 0x4000000 +#define CONTENTS_DETAIL 0x8000000 // brushes not used for the bsp +#define CONTENTS_STRUCTURAL 0x10000000 // brushes used for the bsp +#define CONTENTS_TRANSLUCENT 0x20000000 // don't consume surface fragments inside +#define CONTENTS_TRIGGER 0x40000000 +#define CONTENTS_NODROP 0x80000000 // don't leave bodies or items (death fog, lava) + +#define SURF_NODAMAGE 0x1 // never give falling damage +#define SURF_SLICK 0x2 // effects game physics +#define SURF_SKY 0x4 // lighting from environment map +#define SURF_LADDER 0x8 +#define SURF_NOIMPACT 0x10 // don't make missile explosions +#define SURF_NOMARKS 0x20 // don't leave missile marks +#define SURF_FLESH 0x40 // make flesh sounds and effects +#define SURF_NODRAW 0x80 // don't generate a drawsurface at all +#define SURF_HINT 0x100 // make a primary bsp splitter +#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes +#define SURF_NOLIGHTMAP 0x400 // surface doesn't need a lightmap +#define SURF_POINTLIGHT 0x800 // generate lighting info at vertexes +#define SURF_METALSTEPS 0x1000 // clanking footsteps +#define SURF_NOSTEPS 0x2000 // no footstep sounds +#define SURF_NONSOLID 0x4000 // don't collide against curves with this set +#define SURF_LIGHTFILTER 0x8000 // act as a light filter during q3map -light +#define SURF_ALPHASHADOW 0x10000 // do per-pixel light shadow casting in q3map +#define SURF_NODLIGHT 0x20000 // don't dlight even if solid (solid lava, skies) +#define SURF_DUST 0x40000 // leave a dust trail when walking on this surface + + + + +/* ydnar flags */ + +#define CONTENTS_OPAQUE 0x02 +#define CONTENTS_LIGHTGRID 0x04 + +#define SURF_VERTEXLIT (SURF_POINTLIGHT | SURF_NOLIGHTMAP) + + + +/* wolfenstein flags (collisions with valid q3a flags are noted) */ + +#define CONTENTS_MISSILECLIP 0x80 +#define CONTENTS_ITEM 0x100 +#define CONTENTS_AI_NOSIGHT 0x1000 +#define CONTENTS_CLIPSHOT 0x2000 +#define CONTENTS_DONOTENTER_LARGE 0x400000 /* CONTENTS_BOTCLIP */ + +#define SURF_CERAMIC 0x40 /* SURF_FLESH */ +#define SURF_METAL 0x1000 /* SURF_METALSTEPS */ +#define SURF_WOOD 0x40000 /* SURF_DUST */ +#define SURF_GRASS 0x80000 +#define SURF_GRAVEL 0x100000 +#define SURF_GLASS 0x200000 +#define SURF_SNOW 0x400000 +#define SURF_ROOF 0x800000 +#define SURF_RUBBLE 0x1000000 +#define SURF_CARPET 0x2000000 +#define SURF_MONSTERSLICK 0x4000000 +#define SURF_MONSLICK_W 0x8000000 +#define SURF_MONSLICK_N 0x10000000 +#define SURF_MONSLICK_E 0x20000000 +#define SURF_MONSLICK_S 0x40000000 + + diff --git a/tools/quake3/common/threads.c b/tools/quake3/common/threads.c new file mode 100644 index 00000000..49ded171 --- /dev/null +++ b/tools/quake3/common/threads.c @@ -0,0 +1,620 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _WIN32 +// The below define is necessary to use +// pthreads extensions like pthread_mutexattr_settype +#define _GNU_SOURCE +#include +#endif + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include "qthreads.h" + +#define MAX_THREADS 64 + +int dispatch; +int workcount; +int oldf; +qboolean pacifier; + +qboolean threaded; + +/* +============= +GetThreadWork + +============= +*/ +int GetThreadWork (void) +{ + int r; + int f; + + ThreadLock (); + + if (dispatch == workcount) + { + ThreadUnlock (); + return -1; + } + + f = 10*dispatch / workcount; + if (f != oldf) + { + oldf = f; + if (pacifier) + { + Sys_Printf ("%i...", f); + fflush( stdout ); /* ydnar */ + } + } + + r = dispatch; + dispatch++; + ThreadUnlock (); + + return r; +} + + +void (*workfunction) (int); + +void ThreadWorkerFunction (int threadnum) +{ + int work; + + while (1) + { + work = GetThreadWork (); + if (work == -1) + break; +//Sys_Printf ("thread %i, work %i\n", threadnum, work); + workfunction(work); + } +} + +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + if (numthreads == -1) + ThreadSetDefault (); + workfunction = func; + RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); +} + + +/* +=================================================================== + +WIN32 + +=================================================================== +*/ +#ifdef _WIN32 + +#define USED + +#include + +int numthreads = -1; +CRITICAL_SECTION crit; +static int enter; + +void ThreadSetDefault (void) +{ + SYSTEM_INFO info; + + if (numthreads == -1) // not set manually + { + GetSystemInfo (&info); + numthreads = info.dwNumberOfProcessors; + if (numthreads < 1 || numthreads > 32) + numthreads = 1; + } + + Sys_Printf ("%i threads\n", numthreads); +} + + +void ThreadLock (void) +{ + if (!threaded) + return; + EnterCriticalSection (&crit); + if (enter) + Error ("Recursive ThreadLock\n"); + enter = 1; +} + +void ThreadUnlock (void) +{ + if (!threaded) + return; + if (!enter) + Error ("ThreadUnlock without lock\n"); + enter = 0; + LeaveCriticalSection (&crit); +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int threadid[MAX_THREADS]; + HANDLE threadhandle[MAX_THREADS]; + int i; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = qtrue; + + // + // run threads in parallel + // + InitializeCriticalSection (&crit); + + if (numthreads == 1) + { // use same thread + func (0); + } + else + { + for (i=0 ; i + +pthread_mutex_t *my_mutex; + +void ThreadLock (void) +{ + if (my_mutex) + pthread_mutex_lock (my_mutex); +} + +void ThreadUnlock (void) +{ + if (my_mutex) + pthread_mutex_unlock (my_mutex); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + pthread_t work_threads[MAX_THREADS]; + pthread_addr_t status; + pthread_attr_t attrib; + pthread_mutexattr_t mattrib; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = qtrue; + + if (pacifier) + setbuf (stdout, NULL); + + if (!my_mutex) + { + my_mutex = safe_malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); + } + + if (pthread_attr_create (&attrib) == -1) + Error ("pthread_attr_create failed"); + if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) + Error ("pthread_attr_setstacksize failed"); + + for (i=0 ; i +#include +#include +#include + + +int numthreads = -1; +abilock_t lck; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) + numthreads = prctl(PR_MAXPPROCS); + Sys_Printf ("%i threads\n", numthreads); + usconfig (CONF_INITUSERS, numthreads); +} + + +void ThreadLock (void) +{ + spin_lock (&lck); +} + +void ThreadUnlock (void) +{ + release_lock (&lck); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int pid[MAX_THREADS]; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = qtrue; + + if (pacifier) + setbuf (stdout, NULL); + + init_lock (&lck); + + for (i=0 ; i 1) + Sys_Printf("threads: %d\n", numthreads); +} + +#include + +typedef struct pt_mutex_s +{ + pthread_t *owner; + pthread_mutex_t a_mutex; + pthread_cond_t cond; + unsigned int lock; +} pt_mutex_t; + +pt_mutex_t global_lock; + +void ThreadLock(void) +{ + pt_mutex_t *pt_mutex = &global_lock; + + if(!threaded) + return; + + pthread_mutex_lock(&pt_mutex->a_mutex); + if(pthread_equal(pthread_self(), (pthread_t)&pt_mutex->owner)) + pt_mutex->lock++; + else + { + if((!pt_mutex->owner) && (pt_mutex->lock == 0)) + { + pt_mutex->owner = (pthread_t *)pthread_self(); + pt_mutex->lock = 1; + } + else + { + while(1) + { + pthread_cond_wait(&pt_mutex->cond, &pt_mutex->a_mutex); + if((!pt_mutex->owner) && (pt_mutex->lock == 0)) + { + pt_mutex->owner = (pthread_t *)pthread_self(); + pt_mutex->lock = 1; + break; + } + } + } + } + pthread_mutex_unlock(&pt_mutex->a_mutex); +} + +void ThreadUnlock(void) +{ + pt_mutex_t *pt_mutex = &global_lock; + + if(!threaded) + return; + + pthread_mutex_lock(&pt_mutex->a_mutex); + pt_mutex->lock--; + + if(pt_mutex->lock == 0) + { + pt_mutex->owner = NULL; + pthread_cond_signal(&pt_mutex->cond); + } + + pthread_mutex_unlock(&pt_mutex->a_mutex); +} + +void recursive_mutex_init(pthread_mutexattr_t attribs) +{ + pt_mutex_t *pt_mutex = &global_lock; + + pt_mutex->owner = NULL; + if(pthread_mutex_init(&pt_mutex->a_mutex, &attribs) != 0) + Error("pthread_mutex_init failed\n"); + if(pthread_cond_init(&pt_mutex->cond, NULL) != 0) + Error("pthread_cond_init failed\n"); + + pt_mutex->lock = 0; +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + pthread_mutexattr_t mattrib; + pthread_t work_threads[MAX_THREADS]; + + int start, end; + int i=0, status=0; + + start = I_FloatTime (); + pacifier = showpacifier; + + dispatch = 0; + oldf = -1; + workcount = workcnt; + + if(numthreads == 1) + func(0); + else + { + threaded = qtrue; + + if(pacifier) + setbuf(stdout, NULL); + + if(pthread_mutexattr_init(&mattrib) != 0) + Error("pthread_mutexattr_init failed"); +#if __GLIBC_MINOR__ == 1 + if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_FAST_NP) != 0) +#else + if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_ADAPTIVE_NP) != 0) +#endif + Error ("pthread_mutexattr_settype failed"); + recursive_mutex_init(mattrib); + + for (i=0 ; i +#include "cmdlib.h" +#include "mathlib.h" +#include "polyset.h" +#include "trilib.h" + +// on disk representation of a face + + +#define FLOAT_START 99999.0 +#define FLOAT_END -FLOAT_START +#define MAGIC 123322 + +//#define NOISY 1 + +#if defined (__linux__) || defined (__APPLE__) +#define strlwr strlower +#endif + +typedef struct { + float v[3]; +} vector; + +typedef struct +{ + vector n; /* normal */ + vector p; /* point */ + vector c; /* color */ + float u; /* u */ + float v; /* v */ +} aliaspoint_t; + +typedef struct { + aliaspoint_t pt[3]; +} tf_triangle; + + +static void ByteSwapTri (tf_triangle *tri) +{ + int i; + + for (i=0 ; iverts[j][k] = tri.pt[j].p.v[k]; + ptri->normals[j][k] = tri.pt[j].n.v[k]; +// ptri->colors[j][k] = tri.pt[j].c.v[k]; + } + + ptri->texcoords[j][0] = tri.pt[j].u; + ptri->texcoords[j][1] = tri.pt[j].v; + } + + ptri++; + if ((ptri - tripool ) >= POLYSET_MAXTRIANGLES) + Error ("Error: too many triangles; increase POLYSET_MAXTRIANGLES\n"); + } +} + +void TRI_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets ) +{ + FILE *input; + float start; + char name[256], tex[256]; + int i, count, magic, pset = 0; + triangle_t *ptri; + polyset_t *pPSET; + int iLevel; + int exitpattern; + float t; + + t = -FLOAT_START; + *((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3); + *((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2); + *((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1); + *((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0); + + if ((input = fopen(filename, "rb")) == 0) + Error ("reader: could not open file '%s'", filename); + + iLevel = 0; + + fread(&magic, sizeof(int), 1, input); + if (BigLong(magic) != MAGIC) + Error ("%s is not a Alias object separated triangle file, magic number is wrong.", filename); + + pPSET = calloc( 1, POLYSET_MAXPOLYSETS * sizeof( polyset_t ) ); + ptri = calloc( 1, POLYSET_MAXTRIANGLES * sizeof( triangle_t ) ); + + *ppPSET = pPSET; + + while (feof(input) == 0) { + if (fread(&start, sizeof(float), 1, input) < 1) + break; + *(int *)&start = BigLong(*(int *)&start); + if (*(int *)&start != exitpattern) + { + if (start == FLOAT_START) { + /* Start of an object or group of objects. */ + i = -1; + do { + /* There are probably better ways to read a string from */ + /* a file, but this does allow you to do error checking */ + /* (which I'm not doing) on a per character basis. */ + ++i; + fread( &(name[i]), sizeof( char ), 1, input); + } while( name[i] != '\0' ); + + if ( i != 0 ) + strncpy( pPSET[pset].name, name, sizeof( pPSET[pset].name ) - 1 ); + else + strcpy( pPSET[pset].name , "(unnamed)" ); + strlwr( pPSET[pset].name ); + +// indent(); +// fprintf(stdout,"OBJECT START: %s\n",name); + fread( &count, sizeof(int), 1, input); + count = BigLong(count); + ++iLevel; + if (count != 0) { +// indent(); +// fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count); + + i = -1; + do { + ++i; + fread( &(tex[i]), sizeof( char ), 1, input); + } while( tex[i] != '\0' ); + +/* + if ( i != 0 ) + strncpy( pPSET[pset].texname, tex, sizeof( pPSET[pset].texname ) - 1 ); + else + strcpy( pPSET[pset].texname, "(unnamed)" ); + strlwr( pPSET[pset].texname ); +*/ + +// indent(); +// fprintf(stdout," Object texture name: '%s'\n",tex); + } + + /* Else (count == 0) this is the start of a group, and */ + /* no texture name is present. */ + } + else if (start == FLOAT_END) { + /* End of an object or group. Yes, the name should be */ + /* obvious from context, but it is in here just to be */ + /* safe and to provide a little extra information for */ + /* those who do not wish to write a recursive reader. */ + /* Mea culpa. */ + --iLevel; + i = -1; + do { + ++i; + fread( &(name[i]), sizeof( char ), 1, input); + } while( name[i] != '\0' ); + + if ( i != 0 ) + strncpy( pPSET[pset].name, name, sizeof( pPSET[pset].name ) - 1 ); + else + strcpy( pPSET[pset].name , "(unnamed)" ); + + strlwr( pPSET[pset].name ); + +// indent(); +// fprintf(stdout,"OBJECT END: %s\n",name); + continue; + } + } + +// +// read the triangles +// + if ( count > 0 ) + { + pPSET[pset].triangles = ptri; + ReadPolysetGeometry( pPSET[0].triangles, input, count, ptri ); + ptri += count; + pPSET[pset].numtriangles = count; + if ( ++pset >= POLYSET_MAXPOLYSETS ) + { + Error ("Error: too many polysets; increase POLYSET_MAXPOLYSETS\n"); + } + } + } + + *numpsets = pset; + + fclose (input); +} + diff --git a/tools/quake3/common/trilib.h b/tools/quake3/common/trilib.h new file mode 100644 index 00000000..0b41d3c0 --- /dev/null +++ b/tools/quake3/common/trilib.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// trilib.h: header file for loading triangles from an Alias triangle file +// +void TRI_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets ); + diff --git a/tools/quake3/common/unzip.c b/tools/quake3/common/unzip.c new file mode 100644 index 00000000..1732626a --- /dev/null +++ b/tools/quake3/common/unzip.c @@ -0,0 +1,4596 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * + *****************************************************************************/ + +#include +#include +#include +#include "unzip.h" + +// TTimo added for safe_malloc wrapping +#include "cmdlib.h" + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + 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. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + 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. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +int deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +int deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +int gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +// private stuff to not include cmdlib.h +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short __LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __BigShort (short l) +{ + return l; +} + + +int __LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __BigLong (int l) +{ + return l; +} + + +float __LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __BigFloat (float l) +{ + return l; +} + + +#else + + +short __BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __LittleShort (short l) +{ + return l; +} + + +int __BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __LittleLong (int l) +{ + return l; +} + +float __BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __LittleFloat (float l) +{ + return l; +} + + + +#endif + + + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +const char * zError OF((int err)); +int inflateSyncPoint OF((z_streamp z)); +const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#define zmemcpy memcpy +#define zmemcmp memcmp +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (safe_malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +static uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)safe_malloc(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)safe_malloc(sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + free(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + safe_malloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)safe_malloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + free(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + free(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + free(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifdef DYNAMIC_CRC_TABLE + +static int crc_table_empty = 1; +static uLong crc_table[256]; +static void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +#ifndef __APPLE__ +const uLong * get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLong *)crc_table; +} +#endif + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +#ifndef __APPLE__ +uLong crc32(uLong crc, const Byte *buf, uInt len) +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} +#endif + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single safe_malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +#ifndef __APPLE__ +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} +#endif + +#ifndef __APPLE__ +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} +#endif + +#ifndef __APPLE__ +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} +#endif + +#ifndef __APPLE__ +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} +#endif + +#ifndef __APPLE__ +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} +#endif + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +#ifndef __APPLE__ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} +#endif + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +#ifndef __APPLE__ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} +#endif + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef __APPLE__ +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +#endif + +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +#ifndef __APPLE__ +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} +#endif + +#ifndef __APPLE__ +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} +#endif + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +#ifndef __APPLE__ +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +#ifndef __APPLE__ +int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} +#endif + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + +#ifndef __APPLE__ +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} +#endif + +#ifndef __APPLE__ +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} +#endif + +#ifndef __APPLE__ +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} +#endif + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +#ifndef __APPLE__ +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} +#endif + + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +#ifndef __APPLE__ +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} +#endif + +#ifndef __APPLE__ +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} +#endif + +#ifndef __APPLE__ +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} +#endif + +#ifndef __APPLE__ +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} +#endif + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +#ifndef __APPLE__ +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} +#endif + +#ifndef __APPLE__ +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} +#endif + +#ifndef __APPLE__ +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} +#endif + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +#ifndef __APPLE__ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} +#endif + +#ifndef __APPLE__ +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidp)safe_malloc(items*size); +} + +void zcfree (voidp opaque, voidp ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} +#endif diff --git a/tools/quake3/common/unzip.h b/tools/quake3/common/unzip.h new file mode 100644 index 00000000..ddb7820a --- /dev/null +++ b/tools/quake3/common/unzip.h @@ -0,0 +1,321 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef void* unzFile; +#endif + + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + unsigned long number_entry; /* total number of entries in the central dir on this disk */ + unsigned long size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + unsigned long version; /* version made by 2 unsigned chars */ + unsigned long version_needed; /* version needed to extract 2 unsigned chars */ + unsigned long flag; /* general purpose bit flag 2 unsigned chars */ + unsigned long compression_method; /* compression method 2 unsigned chars */ + unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ + unsigned long crc; /* crc-32 4 unsigned chars */ + unsigned long compressed_size; /* compressed size 4 unsigned chars */ + unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ + unsigned long size_filename; /* filename length 2 unsigned chars */ + unsigned long size_file_extra; /* extra field length 2 unsigned chars */ + unsigned long size_file_comment; /* file comment length 2 unsigned chars */ + + unsigned long disk_num_start; /* disk number start 2 unsigned chars */ + unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ + unsigned long external_fa; /* external file attributes 4 unsigned chars */ + + tm_unz tmu_date; +} unz_file_info; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ +} unz_file_info_internal; + +typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void* opaque, void* address); + +struct internal_state; + +typedef struct z_stream_s { + unsigned char *next_in; /* next input unsigned char */ + unsigned int avail_in; /* number of unsigned chars available at next_in */ + unsigned long total_in; /* total nb of input unsigned chars read so */ + + unsigned char *next_out; /* next output unsigned char should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total nb of unsigned chars output so */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + unsigned char* opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ + unsigned long stream_initialised; /* flag set if stream structure is initialised*/ + + unsigned long offset_local_extrafield;/* offset of the static extra field */ + unsigned int size_local_extrafield;/* size of the static extra field */ + unsigned long pos_local_extrafield; /* position in the static extra field in read*/ + + unsigned long crc32; /* crc32 of all data uncompressed */ + unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ + unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ + unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + unsigned long compression_method; /* compression method (0==store) */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ + unsigned long num_file; /* number of the current file in the zipfile*/ + unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ + unsigned long current_file_ok; /* flag about the usability of the current file*/ + unsigned long central_pos; /* position of the beginning of the central dir*/ + + unsigned long size_central_dir; /* size of the central directory */ + unsigned long offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_CASESENSITIVE 1 +#define UNZ_NOTCASESENSITIVE 2 +#define UNZ_OSDEFAULTCASE 0 + +extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + +extern unzFile unzOpen (const char *path); +extern unzFile unzReOpen (const char* path, unzFile file); + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int unzClose (unzFile file); + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of unsigned char copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int unzGoToFirstFile (unzFile file); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int unzGoToNextFile (unzFile file); + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); + +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int unzOpenCurrentFile (unzFile file); + +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int unzCloseCurrentFile (unzFile file); + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); + +/* + Read unsigned chars from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of unsigned char copied if somes unsigned chars are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern long unztell(unzFile file); + +/* + Give the current position in uncompressed data +*/ + +extern int unzeof (unzFile file); + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of unsigned chars copied in buf, or (if <0) + the error code +*/ diff --git a/tools/quake3/common/vfs.c b/tools/quake3/common/vfs.c new file mode 100644 index 00000000..2d2ab138 --- /dev/null +++ b/tools/quake3/common/vfs.c @@ -0,0 +1,365 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. +*/ + +// +// Rules: +// +// - Directories should be searched in the following order: ~/.q3a/baseq3, +// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). +// +// - Pak files are searched first inside the directories. +// - Case insensitive. +// - Unix-style slashes (/) (windows is backwards .. everyone knows that) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include + +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#else +#include +#include +#define R_OK 04 +#define S_ISDIR(mode) (mode & _S_IFDIR) +#define PATH_MAX 260 +#endif + +#include +#include +#include + +#include "cmdlib.h" +#include "mathlib.h" +#include "glib.h" +#include "inout.h" +#include "vfs.h" +#include "unzip.h" + +typedef struct +{ + char* name; + unz_s zipinfo; + unzFile zipfile; + guint32 size; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_unzFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; +static gboolean g_bUsePak = TRUE; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +//!\todo Define globally or use heap-allocated string. +#define NAME_MAX 255 + +static void vfsInitPakFile (const char *filename) +{ + unz_global_info gi; + unzFile uf; + guint32 i; + int err; + + uf = unzOpen (filename); + if (uf == NULL) + return; + + g_unzFiles = g_slist_append (g_unzFiles, uf); + + err = unzGetGlobalInfo (uf,&gi); + if (err != UNZ_OK) + return; + unzGoToFirstFile(uf); + + for (i = 0; i < gi.number_entry; i++) + { + char filename_inzip[NAME_MAX]; + unz_file_info file_info; + VFS_PAKFILE* file; + + err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) + break; + + file = (VFS_PAKFILE*)safe_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + vfsFixDOSName (filename_inzip); + g_strdown (filename_inzip); + + file->name = strdup (filename_inzip); + file->size = file_info.uncompressed_size; + file->zipfile = uf; + memcpy (&file->zipinfo, uf, sizeof (unz_s)); + + if ((i+1) < gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err!=UNZ_OK) + break; + } + } +} + +// ============================================================================= +// Global functions + +// reads all pak files from a dir +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + char *dirlist; + GDir *dir; + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + Sys_Printf ("VFS Init: %s\n", path); + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + + if (g_bUsePak) + { + dir = g_dir_open (path, 0, NULL); + + if (dir != NULL) + { + while (1) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + dirlist = g_strdup(name); + + { + char *ext = strrchr (dirlist, '.'); + if ((ext == NULL) || (Q_stricmp (ext, ".pk3") != 0)) + continue; + } + + sprintf (filename, "%s/%s", path, dirlist); + vfsInitPakFile (filename); + + g_free(dirlist); + } + g_dir_close (dir); + } + } +} + +// frees all memory that we allocated +void vfsShutdown () +{ + while (g_unzFiles) + { + unzClose ((unzFile)g_unzFiles->data); + g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); + } + + while (g_pakFiles) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)g_pakFiles->data; + free (file->name); + free (file); + g_pakFiles = g_slist_remove (g_pakFiles, file); + } +} + +// return the number of files that match +int vfsGetFileCount (const char *filename) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) == 0) + count++; + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + + return count; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + // filename is a full path + if (index == -1) + { + long len; + FILE *f; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = safe_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; + } + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + long len; + FILE *f; + + f = fopen (tmp, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = safe_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; + } + + count++; + } + } + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) != 0) + continue; + + if (count == index) + { + memcpy (file->zipfile, &file->zipinfo, sizeof (unz_s)); + + if (unzOpenCurrentFile (file->zipfile) != UNZ_OK) + return -1; + + *bufferptr = safe_malloc (file->size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->size] = 0; + + i = unzReadCurrentFile (file->zipfile , *bufferptr, file->size); + unzCloseCurrentFile (file->zipfile); + if (i < 0) + return -1; + else + return file->size; + } + + count++; + } + + return -1; +} diff --git a/tools/quake3/common/vfs.h b/tools/quake3/common/vfs.h new file mode 100644 index 00000000..ed74161e --- /dev/null +++ b/tools/quake3/common/vfs.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 _VFS_H_ +#define _VFS_H_ + +#define VFS_MAXDIRS 8 + +void vfsInitDirectory (const char *path); +void vfsShutdown (); +int vfsGetFileCount (const char *filename); +int vfsLoadFile (const char *filename, void **buffer, int index); + +#endif // _VFS_H_ diff --git a/tools/quake3/q3data/.cvsignore b/tools/quake3/q3data/.cvsignore new file mode 100644 index 00000000..e70c49e1 --- /dev/null +++ b/tools/quake3/q3data/.cvsignore @@ -0,0 +1,12 @@ +q3map +*.d +*.o +*.bak +*.BAK +*~ +*.ncb +*.plg +*.opt +*.log +Debug +Release diff --git a/tools/quake3/q3data/.cvswrappers b/tools/quake3/q3data/.cvswrappers new file mode 100644 index 00000000..2ea7d171 --- /dev/null +++ b/tools/quake3/q3data/.cvswrappers @@ -0,0 +1,2 @@ +*.dsp -m 'COPY' -k 'b' +*.dsw -m 'COPY' -k 'b' diff --git a/tools/quake3/q3data/3dslib.c b/tools/quake3/q3data/3dslib.c new file mode 100644 index 00000000..d5e864fd --- /dev/null +++ b/tools/quake3/q3data/3dslib.c @@ -0,0 +1,630 @@ +#include +#include "q3data.h" + +static void Load3DS( const char *filename, _3DS_t *p3DS, qboolean verbose ); + +static qboolean s_verbose; + +#define MAX_MATERIALS 100 +#define MAX_NAMED_OBJECTS 100 +#define MAX_MESH_MATERIAL_GROUPS 100 +#define MAX_TRI_OBJECTS 512 + +static char s_buffer[1000000]; + +static int ReadString( FILE *fp, char *buffer ) +{ + int i = 0; + int bytesRead = 0; + + do + { + fread( &buffer[i], 1, sizeof( char ), fp ); + bytesRead++; + } while ( buffer[i++] != 0 ); + buffer[i] = 0; + + return bytesRead; +} + +static int ReadChunkAndLength( FILE *fp, short *chunk, long *len ) +{ + if ( fread( chunk, sizeof( short ), 1, fp ) != 1 ) + return 0; + if ( fread( len, sizeof( long ), 1, fp ) != 1 ) + Error( "Unexpected EOF found" ); + return 1; +} + +static void LoadMapName( FILE *fp, char *buffer, int thisChunkLen ) +{ + unsigned short chunkID; + long chunkLen; + long bytesRead = 0; + + while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + { + switch ( chunkID ) + { + case _3DS_CHUNK_MAT_MAPNAME: + fread( buffer, chunkLen - 6, 1, fp ); + break; + default: + fread( s_buffer, chunkLen - 6, 1, fp ); + break; + } + bytesRead += chunkLen; + if ( bytesRead >= thisChunkLen ) + return; + } +} + +static void LoadMaterialList( FILE *fp, long thisChunkLen, _3DSMaterial_t *pMat ) +{ + long chunkLen; + unsigned short chunkID; + long bytesRead = 0; + _3DSMaterial_t mat; + char curdir[1024]; + char buffer[2048]; + + memset( &mat, 0, sizeof( mat ) ); + + if ( s_verbose ) + printf( " >>> MATERIAL LIST\n" ); + + while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + { + switch ( chunkID ) + { + case _3DS_CHUNK_MAT_NAME: + fread( mat.name, chunkLen - 6, 1, fp ); + if ( s_verbose ) + printf( " found mat name '%s'\n", mat.name ); + break; + case _3DS_CHUNK_TEXMAP: + LoadMapName( fp, mat.texture, chunkLen - 6 ); + if ( s_verbose ) + printf( " found texture '%s'\n", mat.texture ); + break; + case _3DS_CHUNK_SPECMAP: + LoadMapName( fp, mat.specular, chunkLen - 6 ); + if ( s_verbose ) + printf( " found specular map '%s'\n", mat.specular ); + break; + case _3DS_CHUNK_OPACMAP: + LoadMapName( fp, mat.opacity, chunkLen - 6 ); + if ( s_verbose ) + printf( " found opacity map '%s'\n", mat.opacity ); + break; + case _3DS_CHUNK_REFLMAP: + LoadMapName( fp, mat.reflection, chunkLen - 6 ); + if ( s_verbose ) + printf( " found reflection map '%s'\n", mat.reflection ); + break; + case _3DS_CHUNK_BUMPMAP: + LoadMapName( fp, mat.bump, chunkLen - 6 ); + if ( s_verbose ) + printf( " found bump map '%s'\n", mat.bump ); + break; + default: + fread( s_buffer, chunkLen - 6, 1, fp ); + break; + } + + bytesRead += chunkLen; + + if ( bytesRead >= thisChunkLen ) + break; + } + + Q_getwd( curdir ); + + if ( mat.texture[0] ) + { + sprintf( buffer, "%s%s", curdir, mat.texture ); + if ( strstr( buffer, gamedir + 1 ) ) + strcpy( mat.texture, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 ); + else + strcpy( mat.texture, buffer ); + } + + if ( mat.specular[0] ) + { + sprintf( buffer, "%s%s", curdir, mat.specular ); + if ( strstr( buffer, gamedir + 1 ) ) + strcpy( mat.specular, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 ); + else + strcpy( mat.specular, buffer ); + } + + if ( mat.bump[0] ) + { + sprintf( buffer, "%s%s", curdir, mat.bump ); + if ( strstr( buffer, gamedir + 1 ) ) + strcpy( mat.bump, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 ); + else + strcpy( mat.bump, buffer ); + } + + if ( mat.reflection[0] ) + { + sprintf( buffer, "%s%s", curdir, mat.reflection ); + if ( strstr( buffer, gamedir + 1 ) ) + strcpy( mat.reflection, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 ); + else + strcpy( mat.reflection, buffer ); + } + + if ( mat.opacity[0] ) + { + sprintf( buffer, "%s%s", curdir, mat.opacity ); + if ( strstr( buffer, gamedir + 1 ) ) + strcpy( mat.opacity, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 ); + else + strcpy( mat.opacity, buffer ); + } + + *pMat = mat; +} + +static void LoadMeshMaterialGroup( FILE *fp, long thisChunkLen, _3DSMeshMaterialGroup_t *pMMG ) +{ + _3DSMeshMaterialGroup_t mmg; + + memset( &mmg, 0, sizeof( mmg ) ); + + ReadString( fp, mmg.name ); + + fread( &mmg.numFaces, sizeof( mmg.numFaces ), 1, fp ); + mmg.pFaces = malloc( sizeof( mmg.pFaces[0] ) * mmg.numFaces ); + fread( mmg.pFaces, sizeof( mmg.pFaces[0] ), mmg.numFaces, fp ); + + if ( s_verbose ) + { + printf( " >>> MESH MATERIAL GROUP '%s' (%d faces)\n", mmg.name, mmg.numFaces ); + + { + int i; + + for ( i = 0; i < mmg.numFaces; i++ ) + { + printf( " %d\n", mmg.pFaces[i] ); + } + } + } + + *pMMG = mmg; +} + +static void LoadNamedTriObject( FILE *fp, long thisChunkLen, _3DSTriObject_t *pTO ) +{ + long chunkLen; + unsigned short chunkID; + int i = 0; + long bytesRead = 0; + _3DSTriObject_t triObj; + _3DSMeshMaterialGroup_t meshMaterialGroups[MAX_MESH_MATERIAL_GROUPS]; + int numMeshMaterialGroups = 0; + + memset( &triObj, 0, sizeof( triObj ) ); + + if ( s_verbose ) + printf( " >>> NAMED TRI OBJECT\n" ); + + while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + { + switch ( chunkID ) + { + case _3DS_CHUNK_MSH_MAT_GROUP: + LoadMeshMaterialGroup( fp, chunkLen - 6, &meshMaterialGroups[numMeshMaterialGroups] ); + bytesRead += chunkLen; + numMeshMaterialGroups++; + break; + case _3DS_CHUNK_FACE_ARRAY: + fread( &triObj.numFaces, sizeof( triObj.numFaces ), 1, fp ); + assert( triObj.pFaces == 0 ); + + triObj.pFaces = malloc( sizeof( triObj.pFaces[0] ) * triObj.numFaces ); + fread( triObj.pFaces, sizeof( triObj.pFaces[0] ), triObj.numFaces, fp ); + bytesRead += sizeof( triObj.numFaces ) + triObj.numFaces * sizeof( triObj.pFaces[0] ) + 6; + + if ( s_verbose ) + { + printf( " found face array with %d faces\n", triObj.numFaces ); + for ( i = 0; i < triObj.numFaces; i++ ) + { + printf( " %d: %d,%d,%d\n", i, triObj.pFaces[i].a, triObj.pFaces[i].b, triObj.pFaces[i].c ); + } + } + + break; + case _3DS_CHUNK_POINT_ARRAY: + fread( &triObj.numPoints, sizeof( triObj.numPoints ), 1, fp ); + triObj.pPoints = malloc( sizeof( triObj.pPoints[0] ) * triObj.numPoints ); + fread( triObj.pPoints, sizeof( triObj.pPoints[0] ), triObj.numPoints, fp ); + bytesRead += sizeof( triObj.numPoints ) + triObj.numPoints * sizeof( triObj.pPoints[0] ) + 6; + + // flip points around into our coordinate system + for ( i = 0; i < triObj.numPoints; i++ ) + { + float x, y, z; + + x = triObj.pPoints[i].x; + y = triObj.pPoints[i].y; + z = triObj.pPoints[i].z; + + triObj.pPoints[i].x = -y; + triObj.pPoints[i].y = x; + triObj.pPoints[i].z = z; + } + + if ( s_verbose ) + { + printf( " found point array with %d points\n", triObj.numPoints ); + for ( i = 0; i < triObj.numPoints; i++ ) + { + printf( " %d: %f,%f,%f\n", i, triObj.pPoints[i].x, triObj.pPoints[i].y, triObj.pPoints[i].z ); + } + } + break; + case _3DS_CHUNK_TEX_VERTS: + fread( &triObj.numTexVerts, sizeof( triObj.numTexVerts ), 1, fp ); + triObj.pTexVerts = malloc( sizeof( triObj.pTexVerts[0] ) * triObj.numTexVerts ); + fread( triObj.pTexVerts, sizeof( triObj.pTexVerts[0] ), triObj.numTexVerts, fp ); + bytesRead += sizeof( triObj.numTexVerts ) + sizeof( triObj.pTexVerts[0] ) * triObj.numTexVerts + 6; + + if ( s_verbose ) + { + printf( " found tex vert array with %d tex verts\n", triObj.numTexVerts ); + for ( i = 0; i < triObj.numTexVerts; i++ ) + { + printf( " %d: %f,%f\n", i, triObj.pTexVerts[i].s, triObj.pTexVerts[i].t ); + } + } + break; + default: + fread( s_buffer, chunkLen - 6, 1, fp ); + bytesRead += chunkLen; + break; + } + + if ( bytesRead >= thisChunkLen ) + break; + } + *pTO = triObj; + + if ( numMeshMaterialGroups == 0 ) + { + numMeshMaterialGroups = 1; + strcpy( meshMaterialGroups[0].name, "(null)" ); + if ( pTO->numTexVerts ) { + printf( "Warning: assigning (null) skin to tri object\n" ); + } + } + else + { + assert( pTO->numFaces == meshMaterialGroups[0].numFaces ); + } + + pTO->pMeshMaterialGroups = malloc( sizeof( _3DSMeshMaterialGroup_t ) * numMeshMaterialGroups ); + memcpy( pTO->pMeshMaterialGroups, meshMaterialGroups, numMeshMaterialGroups * sizeof( meshMaterialGroups[0] ) ); + pTO->numMeshMaterialGroups = numMeshMaterialGroups; + + // + // sanity checks + // + assert( numMeshMaterialGroups <= 1 ); +} + +static void LoadNamedObject( FILE *fp, long thisChunkLen, _3DSNamedObject_t *pNO ) +{ + long chunkLen; + unsigned short chunkID; + int i = 0; + long bytesRead = 0; + char name[100]; + _3DSTriObject_t triObj[MAX_TRI_OBJECTS]; + int numTriObjects = 0; + + memset( triObj, 0, sizeof( triObj ) ); + + bytesRead += ReadString( fp, name ); + + if ( s_verbose ) + printf( " >>> NAMED OBJECT '%s'\n", name ); + + while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + { + switch ( chunkID ) + { + case _3DS_CHUNK_NAMED_TRI_OBJECT: + LoadNamedTriObject( fp, chunkLen - 6, &triObj[numTriObjects] ); + numTriObjects++; + break; + default: + fread( s_buffer, chunkLen - 6, 1, fp ); + break; + } + + bytesRead += chunkLen; + + if ( bytesRead >= thisChunkLen ) + break; + } + + strcpy( pNO->name, name ); + pNO->pTriObjects = malloc( sizeof( _3DSTriObject_t ) * numTriObjects ); + memcpy( pNO->pTriObjects, triObj, sizeof( triObj[0] ) * numTriObjects ); + pNO->numTriObjects = numTriObjects; + + assert( numTriObjects <= 1 ); +} + +static void LoadEditChunk( FILE *fp, long thisChunkLen, _3DSEditChunk_t *pEC ) +{ + unsigned short chunkID; + long chunkLen; + long bytesRead = 0; + _3DSEditChunk_t editChunk; + + _3DSMaterial_t mat[MAX_MATERIALS]; + _3DSNamedObject_t namedObjects[MAX_NAMED_OBJECTS]; + + int numMaterials = 0, numNamedObjects = 0; + + memset( &editChunk, 0, sizeof( editChunk ) ); + + if ( s_verbose ) + printf( ">>> EDIT CHUNK\n" ); + + while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + { + switch ( chunkID ) + { + case _3DS_CHUNK_MAT_LIST: + LoadMaterialList( fp, chunkLen - 6, &mat[numMaterials] ); + numMaterials++; + break; + case _3DS_CHUNK_NAMED_OBJECT: + LoadNamedObject( fp, chunkLen - 6, &namedObjects[numNamedObjects] ); + if ( namedObjects[numNamedObjects].numTriObjects != 0 ) + ++numNamedObjects; + break; + case _3DS_CHUNK_MESH_VERSION: + default: + fread( s_buffer, chunkLen - 6, 1, fp ); + break; + } + + bytesRead += chunkLen; + + if ( bytesRead >= thisChunkLen ) + break; + } + + if ( numMaterials == 0 ) + { + numMaterials = 1; + strcpy( mat[0].name, "(null)" ); + printf( "Warning: no material definitions found\n" ); + } + + pEC->numNamedObjects = numNamedObjects; + + pEC->pMaterials = malloc( sizeof( _3DSMaterial_t ) * numMaterials ); + pEC->pNamedObjects = malloc( sizeof( _3DSNamedObject_t ) * numNamedObjects ); + + memcpy( pEC->pMaterials, mat, numMaterials * sizeof( mat[0] ) ); + memcpy( pEC->pNamedObjects, namedObjects, numNamedObjects * sizeof( namedObjects[0] ) ); +} + +static void Load3DS( const char *filename, _3DS_t *p3DS, qboolean verbose ) +{ + FILE *fp; + unsigned short chunkID; + long chunkLen; + _3DSEditChunk_t editChunk; + + s_verbose = verbose; + + if ( ( fp = fopen( filename, "rb" ) ) == 0 ) + Error( "Unable to open '%s'", filename ); + + // read magic number + if ( ( fread( &chunkID, sizeof( short ), 1, fp ) != 1 ) || + ( LittleShort( chunkID ) != _3DS_CHUNK_MAGIC ) ) + { + Error( "Missing or incorrect magic number in '%s'", filename ); + } + if ( fread( &chunkLen, sizeof( chunkLen ), 1, fp ) != 1 ) + Error( "Unexpected EOF encountered in '%s'", filename ); + // version number + if ( !ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + Error( "Missing version number in '%s'", filename ); + if ( fread( s_buffer, chunkLen - 6, 1, fp ) != 1 ) + Error( "Unexpected EOF encountered in '%s'", filename ); + + while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) ) + { + switch ( chunkID ) + { + case _3DS_CHUNK_EDIT: + LoadEditChunk( fp, chunkLen - 6, &editChunk ); + break; + case _3DS_CHUNK_KEYFRAME_DATA: + fread( s_buffer, chunkLen - 6, 1, fp ); + break; + default: + fread( s_buffer, chunkLen - 6, 1, fp ); + break; + } + } + + fclose( fp ); + + p3DS->editChunk = editChunk; +} + +static void ComputeNormals( _3DSTriObject_t *pTO, triangle_t *pTris ) +{ + vec3_t faceNormals[POLYSET_MAXTRIANGLES]; + vec3_t vertexNormals[POLYSET_MAXTRIANGLES*3]; + vec3_t side0, side1, facenormal; + int f, v; + + memset( faceNormals, 0, sizeof( faceNormals ) ); + memset( vertexNormals, 0, sizeof( vertexNormals ) ); + + // + // compute face normals + // + for ( f = 0; f < pTO->numFaces; f++ ) + { + VectorSubtract( pTris[f].verts[0], pTris[f].verts[1], side0 ); + VectorSubtract( pTris[f].verts[2], pTris[f].verts[1], side1 ); + + CrossProduct( side0, side1, facenormal ); + VectorNormalize( facenormal, faceNormals[f] ); + } + + // + // sum vertex normals + // + for ( v = 0; v < pTO->numPoints; v++ ) + { + for ( f = 0; f < pTO->numFaces; f++ ) + { + if ( ( pTO->pFaces[f].a == v ) || + ( pTO->pFaces[f].b == v ) || + ( pTO->pFaces[f].c == v ) ) + { + vertexNormals[v][0] += faceNormals[f][0]; + vertexNormals[v][1] += faceNormals[f][1]; + vertexNormals[v][2] += faceNormals[f][2]; + } + } + + VectorNormalize( vertexNormals[v], vertexNormals[v] ); + } + + // + // copy vertex normals into triangles + // + for ( f = 0; f < pTO->numFaces; f++ ) + { + int i0 = pTO->pFaces[f].c; + int i1 = pTO->pFaces[f].b; + int i2 = pTO->pFaces[f].a; + + VectorCopy( vertexNormals[i0], pTris[f].normals[0] ); + VectorCopy( vertexNormals[i1], pTris[f].normals[1] ); + VectorCopy( vertexNormals[i2], pTris[f].normals[2] ); + } +} + +/* +** void _3DS_LoadPolysets +*/ +void _3DS_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets, qboolean verbose ) +{ + _3DS_t _3ds; + int numPolysets; + polyset_t *pPSET; + triangle_t *ptri, *triangles; + int i; + + // load the 3DS + memset( &_3ds, 0, sizeof( _3ds ) ); + Load3DS( filename, &_3ds, verbose ); + + // compute information + numPolysets = _3ds.editChunk.numNamedObjects; + + // allocate memory + pPSET = calloc( 1, numPolysets * sizeof( polyset_t ) ); + triangles = ptri = calloc( 1, POLYSET_MAXTRIANGLES * sizeof( triangle_t ) ); + + // copy the data over + for ( i = 0; i < numPolysets; i++ ) + { + char matnamebuf[1024]; + int j; + triangle_t *tri; + _3DSTriObject_t *pTO = &_3ds.editChunk.pNamedObjects[i].pTriObjects[0]; + + pPSET[i].triangles = ptri; + pPSET[i].numtriangles = pTO->numFaces; + strcpy( pPSET[i].name, _3ds.editChunk.pNamedObjects[i].name ); + + strcpy( matnamebuf, filename ); + if ( strrchr( matnamebuf, '/' ) ) + *( strrchr( matnamebuf, '/' ) + 1 )= 0; + strcat( matnamebuf, pTO->pMeshMaterialGroups[0].name ); + + if ( strstr( matnamebuf, gamedir ) ) + strcpy( pPSET[i].materialname, strstr( matnamebuf, gamedir ) + strlen( gamedir ) ); + else + strcpy( pPSET[i].materialname, pTO->pMeshMaterialGroups[0].name ); + + assert( pPSET[i].numtriangles < POLYSET_MAXTRIANGLES ); + + for ( tri = ptri, j = 0; j < pPSET[i].numtriangles; j++ ) + { + int i0 = pTO->pFaces[j].c; + int i1 = pTO->pFaces[j].b; + int i2 = pTO->pFaces[j].a; + + tri->verts[0][0] = pTO->pPoints[i0].x; + tri->verts[0][1] = pTO->pPoints[i0].y; + tri->verts[0][2] = pTO->pPoints[i0].z; + + tri->verts[1][0] = pTO->pPoints[i1].x; + tri->verts[1][1] = pTO->pPoints[i1].y; + tri->verts[1][2] = pTO->pPoints[i1].z; + + tri->verts[2][0] = pTO->pPoints[i2].x; + tri->verts[2][1] = pTO->pPoints[i2].y; + tri->verts[2][2] = pTO->pPoints[i2].z; +/* + for ( k = 0; k < 3; k++ ) + { + tri->colors[0][k] = 1; + tri->colors[1][k] = 1; + tri->colors[2][k] = 1; + } +*/ + + if ( pTO->pTexVerts ) + { + tri->texcoords[0][0] = pTO->pTexVerts[i0].s; + tri->texcoords[0][1] = 1.0f - pTO->pTexVerts[i0].t; + tri->texcoords[1][0] = pTO->pTexVerts[i1].s; + tri->texcoords[1][1] = 1.0f - pTO->pTexVerts[i1].t; + tri->texcoords[2][0] = pTO->pTexVerts[i2].s; + tri->texcoords[2][1] = 1.0f - pTO->pTexVerts[i2].t; + } + + tri++; + } + + ptri += pPSET[i].numtriangles; + assert( ptri - triangles < POLYSET_MAXTRIANGLES ); + } + + // compute normal data +#if 0 + for ( i = 0; i < numPolysets; i++ ) + { + // unique vertices based solely on vertex position + ComputeNormals( &_3ds.editChunk.pNamedObjects[i].pTriObjects[0], + pPSET[i].triangles ); + } +#endif + + free( _3ds.editChunk.pMaterials ); + free( _3ds.editChunk.pNamedObjects ); + + *ppPSET = pPSET; + *numpsets = numPolysets; +} diff --git a/tools/quake3/q3data/3dslib.h b/tools/quake3/q3data/3dslib.h new file mode 100644 index 00000000..96757234 --- /dev/null +++ b/tools/quake3/q3data/3dslib.h @@ -0,0 +1,118 @@ +typedef struct +{ + float x, y, z; +} _3DSPoint_t; + +typedef struct +{ + short a, b, c; + short flags; +} _3DSFace_t; + +typedef struct +{ + float s, t; +} _3DSTexVert_t; + +typedef struct +{ + char name[100]; + short numFaces; + short *pFaces; +} _3DSMeshMaterialGroup_t; + +typedef struct +{ + char name[80]; + + char texture[100]; + char specular[100]; + char reflection[100]; + char bump[100]; + char opacity[100]; +} _3DSMaterial_t; + +typedef struct +{ + short numFaces, numPoints, numTexVerts; + int numMeshMaterialGroups; + + _3DSPoint_t *pPoints; + _3DSFace_t *pFaces; + _3DSTexVert_t *pTexVerts; + + _3DSMeshMaterialGroup_t *pMeshMaterialGroups; +} _3DSTriObject_t; + +typedef struct +{ + char name[100]; + + int numTriObjects; + _3DSTriObject_t *pTriObjects; +} _3DSNamedObject_t; + +typedef struct +{ + int numNamedObjects; + int numMaterials; + + _3DSNamedObject_t *pNamedObjects; + _3DSMaterial_t *pMaterials; + +} _3DSEditChunk_t; + +typedef struct +{ + _3DSEditChunk_t editChunk; +} _3DS_t; + +#define _3DS_CHUNK_NULL 0x0000 +#define _3DS_CHUNK_UNKNOWN0 0x0001 +#define _3DS_CHUNK_M3D_VERSION 0x0002 +#define _3DS_CHUNK_M3D_KFVERSION 0x0005 +#define _3DS_CHUNK_COLOR_F 0x0010 +#define _3DS_CHUNK_COLOR_24 0x0011 +#define _3DS_CHUNK_LIN_COLOR_24 0x0012 +#define _3DS_CHUNK_LIN_COLOR_F 0x0013 +#define _3DS_CHUNK_INT_PERCENTAGE 0x0030 +#define _3DS_CHUNK_FLOAT_PERCENT 0x0031 +#define _3DS_CHUNK_MASTER_SCALE 0x0100 +#define _3DS_CHUNK_CHUNK_TYPE 0x0995 +#define _3DS_CHUNK_CHUNK_UNIQUE 0x0996 +#define _3DS_CHUNK_NOT_CHUNK 0x0997 +#define _3DS_CHUNK_CONTAINER 0x0998 +#define _3DS_CHUNK_IS_CHUNK 0x0999 +#define _3DS_CHUNK_C_SXP_SELFI_MASKDATA 0x0c3c + +#define _3DS_CHUNK_BITMAP 0x1100 +#define _3DS_CHUNK_USE_BITMAP 0x1101 +#define _3DS_CHUNK_SOLID_BGND 0x1200 +#define _3DS_CHUNK_USE_SOLID_BGND 0x1201 + +#define _3DS_CHUNK_EDIT 0x3d3d +#define _3DS_CHUNK_MESH_VERSION 0x3d3e + +#define _3DS_CHUNK_NAMED_OBJECT 0x4000 +#define _3DS_CHUNK_NAMED_TRI_OBJECT 0x4100 +#define _3DS_CHUNK_POINT_ARRAY 0x4110 +#define _3DS_CHUNK_POINT_FLAG_ARRAY 0x4111 +#define _3DS_CHUNK_FACE_ARRAY 0x4120 +#define _3DS_CHUNK_MSH_MAT_GROUP 0x4130 +#define _3DS_CHUNK_TEX_VERTS 0x4140 +#define _3DS_CHUNK_SMOOTH_GROUP 0x4150 +#define _3DS_CHUNK_MESH_MATRIX 0x4160 +#define _3DS_CHUNK_MAGIC 0x4d4d + +#define _3DS_CHUNK_MAT_NAME 0xa000 +#define _3DS_CHUNK_TEXMAP 0xa200 +#define _3DS_CHUNK_SPECMAP 0xa204 +#define _3DS_CHUNK_OPACMAP 0xa210 +#define _3DS_CHUNK_REFLMAP 0xa220 +#define _3DS_CHUNK_BUMPMAP 0xa230 +#define _3DS_CHUNK_MAT_MAPNAME 0xa300 +#define _3DS_CHUNK_MAT_LIST 0xafff + +#define _3DS_CHUNK_KEYFRAME_DATA 0xb000 + +void _3DS_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets, qboolean verbose ); diff --git a/tools/quake3/q3data/compress.c b/tools/quake3/q3data/compress.c new file mode 100644 index 00000000..ede2a95e --- /dev/null +++ b/tools/quake3/q3data/compress.c @@ -0,0 +1,750 @@ +#include "q3data.h" + +#if 0 +/* +================== +MTF +================== +*/ +cblock_t MTF (cblock_t in) +{ + int i, j, b, code; + byte *out_p; + int index[256]; + cblock_t out; + + out_p = out.data = malloc(in.count + 4); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i<256 ; i++) + index[i] = i; + + for (i=0 ; i b2) + return 1; + if (++i1 == bwt_size) + i1 = 0; + if (++i2 == bwt_size) + i2 = 0; + } + + return 0; +} + +/* +================== +BWT +================== +*/ +cblock_t BWT (cblock_t in) +{ + int *sorted; + int i; + byte *out_p; + cblock_t out; + + bwt_size = in.count; + bwt_data = in.data; + + sorted = malloc(in.count*sizeof(*sorted)); + for (i=0 ; i>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write head index + for (i=0 ; i>8)&255; + *out_p++ = (i>>16)&255; + *out_p++ = (i>>24)&255; + + // write the L column + for (i=0 ; i 32) + Error ("bitcount > 32"); + charbits[nodenum] = bits; + charbitscount[nodenum] = bitcount; + return; + } + + node = &hnodes[nodenum]; + bits <<= 1; + BuildChars (node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars (node->children[1], bits, bitcount+1); +} + +/* +================== +Huffman +================== +*/ +cblock_t Huffman (cblock_t in) +{ + int i; + hnode_t *node; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int max, maxchar; + + // count + memset (hnodes, 0, sizeof(hnodes)); + for (i=0 ; i max) + { + max = hnodes[i].count; + maxchar = i; + } + } + if (max == 0) + Error ("Huffman: max == 0"); + + for (i=0 ; i<256 ; i++) + { + hnodes[i].count = (hnodes[i].count*255+max-1) / max; + } + + // build the nodes + numhnodes = 256; + while (numhnodes != 511) + { + node = &hnodes[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode (); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode (); + if (node->children[1] == -1) + { + if (node->children[0] != numhnodes-1) + Error ("Bad smallestnode"); + break; + } + node->count = hnodes[node->children[0]].count + + hnodes[node->children[1]].count; + numhnodes++; + } + + BuildChars (numhnodes-1, 0, 0); + + out_p = out.data = malloc(in.count*2 + 1024); + memset (out_p, 0, in.count*2+1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // save out the 256 normalized counts so the tree can be recreated + for (i=0 ; i<256 ; i++) + *out_p++ = hnodes[i].count; + + // write bits + outbits = 0; + for (i=0 ; i>3] |= 1<<(outbits&7); + outbits++; + } + } + + out_p += (outbits+7)>>3; + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + +/* +================== +RLE +================== +*/ +#define RLE_CODE 0xe8 +#define RLE_TRIPPLE 0xe9 + +int rle_counts[256]; +int rle_bytes[256]; + +cblock_t RLE (cblock_t in) +{ + int i; + byte *out_p; + int val; + int repeat; + cblock_t out; + + out_p = out.data = malloc (in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i 3 || val == RLE_CODE) + { + *out_p++ = RLE_CODE; + *out_p++ = val; + *out_p++ = repeat; + } + else + { + while (repeat--) + *out_p++ = val; + } + } + + out.count = out_p - out.data; + return out; +} + +//========================================================================== + +unsigned lzss_head[256]; +unsigned lzss_next[0x20000]; + +/* +================== +LZSS +================== +*/ +#define BACK_WINDOW 0x10000 +#define BACK_BITS 16 +#define FRONT_WINDOW 16 +#define FRONT_BITS 4 +cblock_t LZSS (cblock_t in) +{ + int i; + byte *out_p; + cblock_t out; + int val; + int j, start, max; + int bestlength, beststart; + int outbits; + +if (in.count >= sizeof(lzss_next)/4) +Error ("LZSS: too big"); + + memset (lzss_head, -1, sizeof(lzss_head)); + + out_p = out.data = malloc (in.count*2); + memset (out.data, 0, in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + outbits = 0; + for (i=0 ; i in.count) + max = in.count - i; + + start = lzss_head[val]; + while (start != -1 && start >= i-BACK_WINDOW) + { + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + start = lzss_next[start]; + } + +#else +// slow simple search + // search for a match + max = FRONT_WINDOW; + if (i + max > in.count) + max = in.count - i; + + start = i - BACK_WINDOW; + if (start < 0) + start = 0; + bestlength = 0; + beststart = 0; + for ( ; start < i ; start++) + { + if (in.data[start] != val) + continue; + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + } +#endif + beststart = BACK_WINDOW - (i-beststart); + + if (bestlength < 3) + { // output a single char + bestlength = 1; + + out_p[outbits>>3] |= 1<<(outbits&7); // set bit to mark char + outbits++; + for (j=0 ; j<8 ; j++, outbits++) + if (val & (1<>3] |= 1<<(outbits&7); + } + else + { // output a phrase + outbits++; // leave a 0 bit to mark phrase + for (j=0 ; j>3] |= 1<<(outbits&7); + for (j=0 ; j>3] |= 1<<(outbits&7); + } + + while (bestlength--) + { + val = in.data[i]; + lzss_next[i] = lzss_head[val]; + lzss_head[val] = i; + i++; + } + } + + out_p += (outbits+7)>>3; + out.count = out_p - out.data; + return out; +} + +//========================================================================== + +#define MIN_REPT 15 +#define MAX_REPT 0 +#define HUF_TOKENS (256+MAX_REPT) + +unsigned charbits1[256][HUF_TOKENS]; +int charbitscount1[256][HUF_TOKENS]; + +hnode_t hnodes1[256][HUF_TOKENS*2]; +int numhnodes1[256]; + +int order0counts[256]; + +/* +================== +SmallestNode1 +================== +*/ +int SmallestNode1 (hnode_t *hnodes, int numhnodes) +{ + int i; + int best, bestnode; + + best = 99999999; + bestnode = -1; + for (i=0 ; i 32) + Error ("bitcount > 32"); + charbits1[prev][nodenum] = bits; + charbitscount1[prev][nodenum] = bitcount; + return; + } + + node = &hnodes1[prev][nodenum]; + bits <<= 1; + BuildChars1 (prev, node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars1 (prev, node->children[1], bits, bitcount+1); +} + + +/* +================== +BuildTree1 +================== +*/ +void BuildTree1 (int prev) +{ + hnode_t *node, *nodebase; + int numhnodes; + + // build the nodes + numhnodes = HUF_TOKENS; + nodebase = hnodes1[prev]; + while (1) + { + node = &nodebase[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode1 (nodebase, numhnodes); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode1 (nodebase, numhnodes); + if (node->children[1] == -1) + break; + + node->count = nodebase[node->children[0]].count + + nodebase[node->children[1]].count; + numhnodes++; + } + numhnodes1[prev] = numhnodes-1; + BuildChars1 (prev, numhnodes-1, 0, 0); +} + + +/* +================== +Huffman1_Count +================== +*/ +void Huffman1_Count (cblock_t in) +{ + int i; + int prev; + int v; + int rept; + + prev = 0; + for (i=0 ; i MIN_REPT) + { + hnodes1[prev][255+rept].count++; + i += rept-1; + } +#endif + } +} + + +/* +================== +Huffman1_Build +================== +*/ +byte scaled[256][HUF_TOKENS]; +void Huffman1_Build (FILE *f) +{ + int i, j, v; + int max; + int total; + + for (i=0 ; i<256 ; i++) + { + // normalize and save the counts + max = 0; + for (j=0 ; j max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; + for (j=0 ; j 255) + Error ("v > 255"); + scaled[i][j] = hnodes1[i][j].count = v; + if (v) + total++; + } + if (total == 1) + { // must have two tokens + if (!scaled[i][0]) + scaled[i][0] = hnodes1[i][0].count = 1; + else + scaled[i][1] = hnodes1[i][1].count = 1; + } + + BuildTree1 (i); + } + +#if 0 + // count up the total bits + total = 0; + for (i=0 ; i<256 ; i++) + for (j=0 ; j<256 ; j++) + total += charbitscount1[i][j] * hnodes1[i][j].count; + + total = (total+7)/8; + printf ("%i bytes huffman1 compressed\n", total); +#endif + + fwrite (scaled, 1, sizeof(scaled), f); +} + +/* +================== +Huffman1 + +Order 1 compression with pre-built table +================== +*/ +cblock_t Huffman1 (cblock_t in) +{ + int i; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int prev; + int v; + int rept; + + out_p = out.data = malloc(in.count*2 + 1024); + memset (out_p, 0, in.count*2+1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write bits + outbits = 0; + prev = 0; + for (i=0 ; i>3] |= 1<<(outbits&7); + outbits++; + } + + prev = v; +#if 1 + // check for repeat encodes + for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++) + if (in.data[i+rept] != v) + break; + if (rept > MIN_REPT) + { + c = charbitscount1[prev][255+rept]; + bits = charbits1[prev][255+rept]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if (bits & (1<>3] |= 1<<(outbits&7); + outbits++; + } + i += rept-1; + } +#endif + } + + out_p += (outbits+7)>>3; + + out.count = out_p - out.data; + + return out; +} + +#endif diff --git a/tools/quake3/q3data/images.c b/tools/quake3/q3data/images.c new file mode 100644 index 00000000..ea661754 --- /dev/null +++ b/tools/quake3/q3data/images.c @@ -0,0 +1,465 @@ +#include "q3data.h" + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + + +char mip_prefix[1024]; // directory to dump the textures in + +qboolean colormap_issued; +byte colormap_palette[768]; + +/* +============== +Cmd_Grab + +$grab filename x y width height +============== +*/ +void Cmd_Grab (void) +{ + int xl,yl,w,h,y; + byte *cropped; + char savename[1024]; + char dest[1024]; + + GetToken (qfalse); + + if (token[0] == '/' || token[0] == '\\') + sprintf (savename, "%s%s.pcx", writedir, token+1); + else + sprintf (savename, "%spics/%s.pcx", writedir, token); + + if (g_release) + { + if (token[0] == '/' || token[0] == '\\') + sprintf (dest, "%s.pcx", token+1); + else + sprintf (dest, "pics/%s.pcx", token); + + ReleaseFile (dest); + return; + } + + GetToken (qfalse); + xl = atoi (token); + GetToken (qfalse); + yl = atoi (token); + GetToken (qfalse); + w = atoi (token); + GetToken (qfalse); + h = atoi (token); + + if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; ybyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; y 255) + r = 255; + if (r < 0) + r = 0; + if (g > 255) + g = 255; + if (g < 0) + g = 0; + if (b > 255) + b = 255; + if (b < 0) + b = 0; +#ifndef TABLECOLORS + bestcolor = BestColor (r, g, b, 0, 254); +#else + bestcolor = palmap[r>>3][g>>3][b>>3]; +#endif + + return bestcolor; +} + + +void BuildPalmap (void) +{ +#ifdef TABLECOLORS + int r, g, b; + int bestcolor; + + if (palmap_built) + return; + palmap_built = qtrue; + + for (r=4 ; r<256 ; r+=8) + { + for (g=4 ; g<256 ; g+=8) + { + for (b=4 ; b<256 ; b+=8) + { + bestcolor = BestColor (r, g, b, 1, 254); + palmap[r>>3][g>>3][b>>3] = bestcolor; + } + } + } +#endif + + if (!colormap_issued) + Error ("You must issue a $colormap command first"); + +} + +/* +============= +AveragePixels +============= +*/ +byte AveragePixels (int count) +{ + int r,g,b; + int i; + int vis; + int pix; + int bestcolor; + byte *pal; + int fullbright; + + vis = 0; + r = g = b = 0; + fullbright = 0; + for (i=0 ; i +#ifdef _WIN32 +#include +#endif +#include "md3lib.h" + +#if defined (__linux__) || defined (__APPLE__) +#define filelength Q_filelength +#endif + +/* +** MD3_ComputeTagFromTri +*/ +void MD3_ComputeTagFromTri( md3Tag_t *pTag, const float pTri[3][3] ) +{ + float len[3]; + vec3_t axes[3], sides[3]; + int longestSide, shortestSide, hypotSide; + int origin; + int j; + float d; + + memset( axes, 0, sizeof( axes ) ); + memset( sides, 0, sizeof( sides ) ); + + // + // compute sides + // + for ( j = 0; j < 3; j++ ) + { + sides[j][0] = pTri[(j+1)%3][0] - pTri[j][0]; + sides[j][1] = pTri[(j+1)%3][1] - pTri[j][1]; + sides[j][2] = pTri[(j+1)%3][2] - pTri[j][2]; + + len[j] = ( float ) sqrt( DotProduct( sides[j], sides[j] ) ); + } + +#if 0 + if ( len[0] > len[1] && len[0] > len[2] ) + { + longestSide = 0; shortestSide = 1; origin = 2; + } + else if ( len[1] > len[0] && len[1] > len[2] ) + { + longestSide = 1; shortestSide = 2; origin = 0; + } + else if ( len[2] > len[0] && len[2] > len[1] ) + { + longestSide = 2; shortestSide = 0; origin = 1; + } + else + { + Error( "invalid tag triangle, must be a right triangle with unequal length sides" ); + } +#endif + if ( len[0] > len[1] && len[0] > len[2] ) { + hypotSide = 0; + origin = 2; + } else if ( len[1] > len[0] && len[1] > len[2] ) { + hypotSide = 1; + origin = 0; + } else if ( len[2] > len[0] && len[2] > len[1] ) { + hypotSide = 2; + origin = 1; + } + len[hypotSide] = -1; + + if ( len[0] > len[1] && len[0] > len[2] ) { + longestSide = 0; + } else if ( len[1] > len[0] && len[1] > len[2] ) { + longestSide = 1; + } else if ( len[2] > len[0] && len[2] > len[1] ) { + longestSide = 2; + } + len[longestSide] = -1; + + if ( len[0] > len[1] && len[0] > len[2] ) { + shortestSide = 0; + } else if ( len[1] > len[0] && len[1] > len[2] ) { + shortestSide = 1; + } else if ( len[2] > len[0] && len[2] > len[1] ) { + shortestSide = 2; + } + len[shortestSide] = -1; + + + +// VectorNormalize( sides[shortestSide], axes[0] ); +// VectorNormalize( sides[longestSide], axes[1] ); + VectorNormalize( sides[longestSide], axes[0] ); + VectorNormalize( sides[shortestSide], axes[1] ); + + // project shortest side so that it is exactly 90 degrees to the longer side + d = DotProduct( axes[0], axes[1] ); + VectorMA( axes[0], -d, axes[1], axes[0] ); + VectorNormalize( axes[0], axes[0] ); + + CrossProduct( sides[longestSide], sides[shortestSide], axes[2] ); + VectorNormalize( axes[2], axes[2] ); + + pTag->origin[0] = pTri[origin][0]; + pTag->origin[1] = pTri[origin][1]; + pTag->origin[2] = pTri[origin][2]; + + VectorCopy( axes[0], pTag->axis[0] ); + VectorCopy( axes[1], pTag->axis[1] ); + VectorCopy( axes[2], pTag->axis[2] ); +} + +/* +============== +MD3_Dump +============== +*/ +void MD3_Dump( const char *filename ) +{ + md3Header_t header; + md3Tag_t *pTag; + md3Surface_t *pSurface; + FILE *fp; + void *_buffer; + void *buffer; + long fileSize; + int i; + + if ( ( fp = fopen( filename, "rb" ) ) == 0 ) + { + Error( "Unable to open '%s'\n", filename ); + } + + fileSize = filelength( fileno( fp ) ); + _buffer = malloc( filelength( fileno( fp ) ) ); + fread( _buffer, fileSize, 1, fp ); + fclose( fp ); + + buffer = ( char * ) _buffer; + header = *( md3Header_t * ) _buffer; + + if ( header.ident != MD3_IDENT ) + { + Error( "Incorrect ident for '%s'\n", filename ); + } + + printf( "Contents of '%s'\n", filename ); + printf( " version: %d\n", header.version ); + printf( " name: %s\n", header.name ); + printf( " num frames: %d\n", header.numFrames ); + printf( " num tags: %d\n", header.numTags ); + printf( " num surfaces: %d\n", header.numSurfaces ); + printf( " num skins: %d\n", header.numSkins ); + printf( " file size: %d\n", fileSize ); + + printf( "--- TAGS ---\n" ); + pTag = ( md3Tag_t * ) ( ( ( char * ) buffer ) + header.ofsTags ); + for ( i = 0; i < header.numTags; i++, pTag++ ) + { + printf( " tag %d ('%s')\n", i, pTag->name ); + printf( " origin: %f,%f,%f\n", pTag->origin[0], pTag->origin[1], pTag->origin[2] ); + printf( " vf: %f,%f,%f\n", pTag->axis[0][0], pTag->axis[0][1], pTag->axis[0][2] ); + printf( " vr: %f,%f,%f\n", pTag->axis[1][0], pTag->axis[1][1], pTag->axis[1][2] ); + printf( " vu: %f,%f,%f\n", pTag->axis[2][0], pTag->axis[2][1], pTag->axis[2][2] ); + } + + printf( "--- SURFACES ---\n" ); + pSurface = ( md3Surface_t * ) ( ( ( char * ) buffer ) + header.ofsSurfaces ); + + for ( i = 0; i < header.numSurfaces; i++ ) + { + int j; + + md3Shader_t *pShader = ( md3Shader_t * ) ( ( ( char * ) pSurface ) + pSurface->ofsShaders ); + + printf( "\n surface %d ('%s')\n", i, pSurface->name ); + printf( " num frames: %d\n", pSurface->numFrames ); + printf( " num shaders: %d\n", pSurface->numShaders ); + printf( " num tris: %d\n", pSurface->numTriangles ); + printf( " num verts: %d\n", pSurface->numVerts ); + + if ( pSurface->numShaders > 0 ) + { + printf( " --- SHADERS ---\n" ); + + for ( j = 0; j < pSurface->numShaders; j++, pShader++ ) + { + printf( " shader %d ('%s')\n", j, pShader->name ); + } + } + pSurface = ( md3Surface_t * ) ( ( ( char * ) pSurface ) + pSurface->ofsEnd ); + } + + free( _buffer ); +} + diff --git a/tools/quake3/q3data/md3lib.h b/tools/quake3/q3data/md3lib.h new file mode 100644 index 00000000..7132906f --- /dev/null +++ b/tools/quake3/q3data/md3lib.h @@ -0,0 +1,7 @@ +#include +#include "../common/cmdlib.h" +#include "mathlib.h" +#include "../common/qfiles.h" + +void MD3_Dump( const char *filename ); +void MD3_ComputeTagFromTri( md3Tag_t *pTag, const float tri[3][3] ); diff --git a/tools/quake3/q3data/models.c b/tools/quake3/q3data/models.c new file mode 100644 index 00000000..05d65df7 --- /dev/null +++ b/tools/quake3/q3data/models.c @@ -0,0 +1,2134 @@ +#include +#include "q3data.h" + +//================================================================= + +static void OrderSurfaces( void ); +static void LoadBase( const char *filename ); +static int LoadModelFile( const char *filename, polyset_t **ppsets, int *pnumpolysets ); + +#define MAX_SURFACE_TRIS (SHADER_MAX_INDEXES / 3) +#define MAX_SURFACE_VERTS SHADER_MAX_VERTEXES + +#define MD3_TYPE_UNKNOWN 0 +#define MD3_TYPE_BASE3DS 1 +#define MD3_TYPE_SPRITE 2 +#define MD3_TYPE_ASE 3 + +#define MAX_ANIM_FRAMES 512 +#define MAX_ANIM_SURFACES 32 + +typedef struct +{ + polyset_t *frames; + int numFrames; +} SurfaceAnimation_t; + +typedef struct +{ + polyset_t *surfaces[MAX_ANIM_SURFACES]; + int numSurfaces; +} ObjectAnimationFrame_t; + +typedef struct { + vec3_t xyz; + vec3_t normal; + vec3_t color; + float st[2]; + int index; +} baseVertex_t; + +typedef struct { + baseVertex_t v[3]; +} baseTriangle_t; + +//================================================================ + +typedef struct +{ + md3Surface_t header; + md3Shader_t shaders[MD3_MAX_SHADERS]; + // all verts (xyz_normal) + float *verts[MD3_MAX_FRAMES]; + + baseTriangle_t baseTriangles[MD3_MAX_TRIANGLES]; + + // the triangles will be sorted so that they form long generalized tristrips + int orderedTriangles[MD3_MAX_TRIANGLES][3]; + int lodTriangles[MD3_MAX_TRIANGLES][3]; + baseVertex_t baseVertexes[MD3_MAX_VERTS]; + +} md3SurfaceData_t; + +typedef struct +{ + int skinwidth, skinheight; + + md3SurfaceData_t surfData[MD3_MAX_SURFACES]; + + md3Tag_t tags[MD3_MAX_FRAMES][MD3_MAX_TAGS]; + md3Frame_t frames[MD3_MAX_FRAMES]; + + md3Header_t model; + float scale_up; // set by $scale + vec3_t adjust; // set by $origin + vec3_t aseAdjust; + int fixedwidth, fixedheight; // set by $skinsize + + int maxSurfaceTris; + + int lowerSkipFrameStart, lowerSkipFrameEnd; + int maxUpperFrames; + int maxHeadFrames; + int currentLod; + float lodBias; + + int type; // MD3_TYPE_BASE, MD3_TYPE_OLDBASE, MD3_TYPE_ASE, or MD3_TYPE_SPRITE + +} q3data; + +q3data g_data; + +// the command list holds counts, the count * 3 xyz, st, normal indexes +// that are valid for every frame +char g_cddir[1024]; +char g_modelname[1024]; + +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +void ClearModel (void) +{ + int i; + + g_data.type = MD3_TYPE_UNKNOWN; + + for ( i = 0; i < MD3_MAX_SURFACES; i++ ) + { + memset( &g_data.surfData[i].header, 0, sizeof( g_data.surfData[i].header ) ); + memset( &g_data.surfData[i].shaders, 0, sizeof( g_data.surfData[i].shaders ) ); + memset( &g_data.surfData[i].verts, 0, sizeof( g_data.surfData[i].verts ) ); + } + + memset( g_data.tags, 0, sizeof( g_data.tags ) ); + + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + int j; + + for ( j = 0; j < g_data.surfData[i].header.numShaders; j++ ) + { + memset( &g_data.surfData[i].shaders[j], 0, sizeof( g_data.surfData[i].shaders[j] ) ); + } + } + memset (&g_data.model, 0, sizeof(g_data.model)); + memset (g_cddir, 0, sizeof(g_cddir)); + + g_modelname[0] = 0; + g_data.scale_up = 1.0; + memset( &g_data.model, 0, sizeof( g_data.model ) ); + VectorCopy (vec3_origin, g_data.adjust); + g_data.fixedwidth = g_data.fixedheight = 0; + g_skipmodel = qfalse; +} + +/* +** void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData ) +** +** This routine assumes that the file position has been adjusted +** properly prior to entry to point at the beginning of the surface. +** +** Since surface header information is completely relative, we can't +** just randomly seek to an arbitrary surface location right now. Is +** this something we should add? +*/ +void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData ) +{ + md3Surface_t *pSurf = &pSurfData->header; + md3Shader_t *pShader = pSurfData->shaders; + baseVertex_t *pBaseVertex = pSurfData->baseVertexes; + float **verts = pSurfData->verts; + + short xyznormals[MD3_MAX_VERTS][4]; + + float base_st[MD3_MAX_VERTS][2]; + md3Surface_t surftemp; + + int f, i, j, k; + + if ( strstr( pSurf->name, "tag_" ) == pSurf->name ) + return; + + // + // write out the header + // + surftemp = *pSurf; + surftemp.ident = LittleLong( MD3_IDENT ); + surftemp.flags = LittleLong( pSurf->flags ); + surftemp.numFrames = LittleLong( pSurf->numFrames ); + surftemp.numShaders = LittleLong( pSurf->numShaders ); + + surftemp.ofsShaders = LittleLong( pSurf->ofsShaders ); + + surftemp.ofsTriangles = LittleLong( pSurf->ofsTriangles ); + surftemp.numTriangles = LittleLong( pSurf->numTriangles ); + + surftemp.ofsSt = LittleLong( pSurf->ofsSt ); + surftemp.ofsXyzNormals = LittleLong( pSurf->ofsXyzNormals ); + surftemp.ofsEnd = LittleLong( pSurf->ofsEnd ); + + SafeWrite( modelouthandle, &surftemp, sizeof( surftemp ) ); + + if ( g_verbose ) + { + printf( "surface '%s'\n", pSurf->name ); + printf( "...num shaders: %d\n", pSurf->numShaders ); + } + + // + // write out shaders + // + for ( i = 0; i < pSurf->numShaders; i++ ) + { + md3Shader_t shadertemp; + + if ( g_verbose ) + printf( "......'%s'\n", pShader[i].name ); + + shadertemp = pShader[i]; + shadertemp.shaderIndex = LittleLong( shadertemp.shaderIndex ); + SafeWrite( modelouthandle, &shadertemp, sizeof( shadertemp ) ); + } + + // + // write out the triangles + // + for ( i = 0 ; i < pSurf->numTriangles ; i++ ) + { + for (j = 0 ; j < 3 ; j++) + { + int ivalue = LittleLong( pSurfData->orderedTriangles[i][j] ); + pSurfData->orderedTriangles[i][j] = ivalue; + } + } + + SafeWrite( modelouthandle, pSurfData->orderedTriangles, pSurf->numTriangles * sizeof( g_data.surfData[0].orderedTriangles[0] ) ); + + if ( g_verbose ) + { + printf( "\n...num verts: %d\n", pSurf->numVerts ); + printf( "...TEX COORDINATES\n" ); + } + + // + // write out the texture coordinates + // + for ( i = 0; i < pSurf->numVerts ; i++) { + base_st[i][0] = LittleFloat( pBaseVertex[i].st[0] ); + base_st[i][1] = LittleFloat( pBaseVertex[i].st[1] ); + if ( g_verbose ) + printf( "......%d: %f,%f\n", i, base_st[i][0], base_st[i][1] ); + } + SafeWrite( modelouthandle, base_st, pSurf->numVerts * sizeof(base_st[0])); + + // + // write the xyz_normal + // + if ( g_verbose ) + printf( "...XYZNORMALS\n" ); + for ( f = 0; f < g_data.model.numFrames; f++ ) + { + for (j=0 ; j< pSurf->numVerts; j++) + { + short value; + + for (k=0 ; k < 3 ; k++) + { + value = ( short ) ( verts[f][j*6+k] / MD3_XYZ_SCALE ); + xyznormals[j][k] = LittleShort( value ); + } + NormalToLatLong( &verts[f][j*6+3], (byte *)&xyznormals[j][3] ); + } + SafeWrite( modelouthandle, xyznormals, pSurf->numVerts * sizeof( short ) * 4 ); + } +} + +/* +** void WriteModelFile( FILE *modelouthandle ) +** +** CHUNK SIZE +** header sizeof( md3Header_t ) +** frames sizeof( md3Frame_t ) * numFrames +** tags sizeof( md3Tag_t ) * numFrames * numTags +** surfaces surfaceSum +*/ +void WriteModelFile( FILE *modelouthandle ) +{ + int f; + int i, j; + md3Header_t modeltemp; + long surfaceSum = 0; + int numRealSurfaces = 0; + int numFrames = g_data.model.numFrames; + + // compute offsets for all surfaces, sum their total size + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + if ( strstr( g_data.surfData[i].header.name, "tag_" ) != g_data.surfData[i].header.name ) + { + md3Surface_t *psurf = &g_data.surfData[i].header; + + if ( psurf->numTriangles == 0 || psurf->numVerts == 0 ) + continue; + + // + // the triangle and vertex split threshold is controlled by a parameter + // to $base, a la $base blah.3ds 1900, where "1900" determines the number + // of triangles to split on + // + else if ( psurf->numVerts > MAX_SURFACE_VERTS ) + { + Error( "too many vertices\n" ); + } + + psurf->numFrames = numFrames; + + psurf->ofsShaders = sizeof( md3Surface_t ); + + if ( psurf->numTriangles > MAX_SURFACE_TRIS ) + { + Error( "too many faces\n" ); + } + + psurf->ofsTriangles = psurf->ofsShaders + psurf->numShaders * sizeof( md3Shader_t ); + + psurf->ofsSt = psurf->ofsTriangles + psurf->numTriangles * sizeof( md3Triangle_t ); + psurf->ofsXyzNormals = psurf->ofsSt + psurf->numVerts * sizeof( md3St_t ); + psurf->ofsEnd = psurf->ofsXyzNormals + psurf->numFrames * psurf->numVerts * ( sizeof( short ) * 4 ); + + surfaceSum += psurf->ofsEnd; + + numRealSurfaces++; + } + } + + g_data.model.ident = MD3_IDENT; + g_data.model.version = MD3_VERSION; + + g_data.model.ofsFrames = sizeof(md3Header_t); + g_data.model.ofsTags = g_data.model.ofsFrames + numFrames*sizeof(md3Frame_t); + g_data.model.ofsSurfaces = g_data.model.ofsTags + numFrames*g_data.model.numTags*sizeof(md3Tag_t); + g_data.model.ofsEnd = g_data.model.ofsSurfaces + surfaceSum; + + // + // write out the model header + // + modeltemp = g_data.model; + modeltemp.ident = LittleLong( modeltemp.ident ); + modeltemp.version = LittleLong( modeltemp.version ); + modeltemp.numFrames = LittleLong( modeltemp.numFrames ); + modeltemp.numTags = LittleLong( modeltemp.numTags ); + modeltemp.numSurfaces = LittleLong( numRealSurfaces ); + modeltemp.ofsFrames = LittleLong( modeltemp.ofsFrames ); + modeltemp.ofsTags = LittleLong( modeltemp.ofsTags ); + modeltemp.ofsSurfaces = LittleLong( modeltemp.ofsSurfaces ); + modeltemp.ofsEnd = LittleLong( modeltemp.ofsEnd ); + + SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); + + // + // write out the frames + // + for (i=0 ; i < numFrames ; i++) + { + vec3_t tmpVec; + float maxRadius = 0; + + // + // compute localOrigin and radius + // + g_data.frames[i].localOrigin[0] = + g_data.frames[i].localOrigin[1] = + g_data.frames[i].localOrigin[2] = 0; + + for ( j = 0; j < 8; j++ ) + { + tmpVec[0] = g_data.frames[i].bounds[(j&1)!=0][0]; + tmpVec[1] = g_data.frames[i].bounds[(j&2)!=0][1]; + tmpVec[2] = g_data.frames[i].bounds[(j&4)!=0][2]; + + if ( VectorLength( tmpVec ) > maxRadius ) + maxRadius = VectorLength( tmpVec ); + } + + g_data.frames[i].radius = LittleFloat( maxRadius ); + + // swap + for (j=0 ; j<3 ; j++) { + g_data.frames[i].bounds[0][j] = LittleFloat( g_data.frames[i].bounds[0][j] ); + g_data.frames[i].bounds[1][j] = LittleFloat( g_data.frames[i].bounds[1][j] ); + g_data.frames[i].localOrigin[j] = LittleFloat( g_data.frames[i].localOrigin[j] ); + } + } + fseek (modelouthandle, g_data.model.ofsFrames, SEEK_SET); + SafeWrite( modelouthandle, g_data.frames, numFrames * sizeof(g_data.frames[0]) ); + + // + // write out the tags + // + fseek( modelouthandle, g_data.model.ofsTags, SEEK_SET ); + for (f=0 ; fshaders[j].name ); + } + } + return; + } + + // + // write the model output file + // + printf ("saving to %s\n", name); + CreatePath (name); + modelouthandle = SafeOpenWrite (name); + + WriteModelFile (modelouthandle); + + printf ("%4d surfaces\n", g_data.model.numSurfaces); + printf ("%4d frames\n", g_data.model.numFrames); + printf ("%4d tags\n", g_data.model.numTags); + printf ("file size: %d\n", (int)ftell (modelouthandle) ); + printf ("---------------------\n"); + + fclose (modelouthandle); +} + +/* +** OrderSurfaces +** +** Reorders triangles in all the surfaces. +*/ +static void OrderSurfaces( void ) +{ + int s; + extern qboolean g_stripify; + + // go through each surface and find best strip/fans possible + for ( s = 0; s < g_data.model.numSurfaces; s++ ) + { + int mesh[MD3_MAX_TRIANGLES][3]; + int i; + + printf( "stripifying surface %d/%d with %d tris\n", s, g_data.model.numSurfaces, g_data.surfData[s].header.numTriangles ); + + for ( i = 0; i < g_data.surfData[s].header.numTriangles; i++ ) + { + mesh[i][0] = g_data.surfData[s].lodTriangles[i][0]; + mesh[i][1] = g_data.surfData[s].lodTriangles[i][1]; + mesh[i][2] = g_data.surfData[s].lodTriangles[i][2]; + } + + if ( g_stripify ) + { + OrderMesh( mesh, // input + g_data.surfData[s].orderedTriangles, // output + g_data.surfData[s].header.numTriangles ); + } + else + { + memcpy( g_data.surfData[s].orderedTriangles, mesh, sizeof( int ) * 3 * g_data.surfData[s].header.numTriangles ); + } + } +} + + +/* +=============================================================== + +BASE FRAME SETUP + +=============================================================== +*/ +/* +============ +CopyTrianglesToBaseTriangles + +============ +*/ +static void CopyTrianglesToBaseTriangles(triangle_t *ptri, int numtri, baseTriangle_t *bTri ) +{ + int i; +// int width, height, iwidth, iheight, swidth; +// float s_scale, t_scale; +// float scale; +// vec3_t mins, maxs; + float *pbasevert; + +/* + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + + for (i=0 ; i= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_data.fixedwidth / 2; + iheight = g_data.fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + } + + // make the width a multiple of 4; some hardware requires this, and it ensures + // dword alignment for each scan + swidth = iwidth*2; + g_data.skinwidth = (swidth + 3) & ~3; + g_data.skinheight = iheight; +*/ + + for (i=0; iverts[j]; + + VectorCopy( ptri->verts[j], bTri->v[j].xyz); + VectorCopy( ptri->normals[j], bTri->v[j].normal ); + + bTri->v[j].st[0] = ptri->texcoords[j][0]; + bTri->v[j].st[1] = ptri->texcoords[j][1]; + } + } +} + +static void BuildBaseFrame( const char *filename, ObjectAnimationFrame_t *pOAF ) +{ + baseTriangle_t *bTri; + baseVertex_t *bVert; + int i, j; + + // calculate the base triangles + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + CopyTrianglesToBaseTriangles( pOAF->surfaces[i]->triangles, + pOAF->surfaces[i]->numtriangles, + g_data.surfData[i].baseTriangles ); + + strcpy( g_data.surfData[i].header.name, pOAF->surfaces[i]->name ); + + g_data.surfData[i].header.numTriangles = pOAF->surfaces[i]->numtriangles; + g_data.surfData[i].header.numVerts = 0; + +/* + if ( strstr( filename, gamedir + 1 ) ) + { + strcpy( shaderName, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 ); + } + else + { + strcpy( shaderName, filename ); + } + + if ( strrchr( shaderName, '/' ) ) + *( strrchr( shaderName, '/' ) + 1 ) = 0; + + + strcpy( shaderName, pOAF->surfaces[i]->materialname ); +*/ + strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, pOAF->surfaces[i]->materialname ); + + g_data.surfData[i].header.numShaders++; + } + + // + // compute unique vertices for each polyset + // + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + int t; + + for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ ) + { + bTri = &g_data.surfData[i].baseTriangles[t]; + + for (j=0 ; j<3 ; j++) + { + int k; + + bVert = &bTri->v[j]; + + // get the xyz index + for ( k = 0; k < g_data.surfData[i].header.numVerts; k++ ) + { + if ( ( g_data.surfData[i].baseVertexes[k].st[0] == bVert->st[0] ) && + ( g_data.surfData[i].baseVertexes[k].st[1] == bVert->st[1] ) && + ( VectorCompare (bVert->xyz, g_data.surfData[i].baseVertexes[k].xyz) ) && + ( VectorCompare (bVert->normal, g_data.surfData[i].baseVertexes[k].normal) ) ) + { + break; // this vertex is already in the base vertex list + } + } + + if (k == g_data.surfData[i].header.numVerts) { // new index + g_data.surfData[i].baseVertexes[g_data.surfData[i].header.numVerts] = *bVert; + g_data.surfData[i].header.numVerts++; + } + + bVert->index = k; + + g_data.surfData[i].lodTriangles[t][j] = k; + } + } + } + + // + // find tags + // + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name ) + { + if ( pOAF->surfaces[i]->numtriangles != 1 ) + { + Error( "tag polysets must consist of only one triangle" ); + } + if ( strstr( filename, "_flash.md3" ) && !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) ) + continue; + printf( "found tag '%s'\n", pOAF->surfaces[i]->name ); + g_data.model.numTags++; + } + } + +} + +static int LoadModelFile( const char *filename, polyset_t **psets, int *numpolysets ) +{ + int time1; + char file1[1024]; + const char *frameFile; + + printf ("---------------------\n"); + if ( filename[1] != ':' ) + { + frameFile = filename; + sprintf( file1, "%s/%s", g_cddir, frameFile ); + } + else + { + strcpy( file1, filename ); + } + + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s doesn't exist", file1); + + // + // load the base triangles + // + *psets = Polyset_LoadSets( file1, numpolysets, g_data.maxSurfaceTris ); + + // + // snap polysets + // + Polyset_SnapSets( *psets, *numpolysets ); + + if ( strstr( file1, ".3ds" ) || strstr( file1, ".3DS" ) ) + return MD3_TYPE_BASE3DS; + + Error( "Unknown model file type" ); + + return MD3_TYPE_UNKNOWN; +} + +/* +================= +Cmd_Base +================= +*/ +void Cmd_Base( void ) +{ + char filename[1024]; + + GetToken( qfalse ); + sprintf( filename, "%s/%s", g_cddir, token ); + LoadBase( filename ); +} + +static void LoadBase( const char *filename ) +{ + int numpolysets; + polyset_t *psets; + int i; + ObjectAnimationFrame_t oaf; + + // determine polyset splitting threshold + if ( TokenAvailable() ) + { + GetToken( qfalse ); + g_data.maxSurfaceTris = atoi( token ); + } + else + { + g_data.maxSurfaceTris = MAX_SURFACE_TRIS - 1; + } + + g_data.type = LoadModelFile( filename, &psets, &numpolysets ); + + Polyset_ComputeNormals( psets, numpolysets ); + + g_data.model.numSurfaces = numpolysets; + + memset( &oaf, 0, sizeof( oaf ) ); + + for ( i = 0; i < numpolysets; i++ ) + { + oaf.surfaces[i] = &psets[i]; + oaf.numSurfaces = numpolysets; + } + + BuildBaseFrame( filename, &oaf ); + + free( psets[0].triangles ); + free( psets ); +} + +/* +================= +Cmd_SpriteBase + +$spritebase xorg yorg width height + +Generate a single square for the model +================= +*/ +void Cmd_SpriteBase (void) +{ + float xl, yl, width, height; + + g_data.type = MD3_TYPE_SPRITE; + + GetToken (qfalse); + xl = atof(token); + GetToken (qfalse); + yl = atof(token); + GetToken (qfalse); + width = atof(token); + GetToken (qfalse); + height = atof(token); + +// if (g_skipmodel || g_release || g_archive) +// return; + + printf ("---------------------\n"); + + g_data.surfData[0].verts[0] = ( float * ) calloc( 1, sizeof( float ) * 6 * 4 ); + + g_data.surfData[0].header.numVerts = 4; + + g_data.surfData[0].verts[0][0+0] = 0; + g_data.surfData[0].verts[0][0+1] = -xl; + g_data.surfData[0].verts[0][0+2] = yl + height; + + g_data.surfData[0].verts[0][0+3] = -1; + g_data.surfData[0].verts[0][0+4] = 0; + g_data.surfData[0].verts[0][0+5] = 0; + g_data.surfData[0].baseVertexes[0].st[0] = 0; + g_data.surfData[0].baseVertexes[0].st[1] = 0; + + + g_data.surfData[0].verts[0][6+0] = 0; + g_data.surfData[0].verts[0][6+1] = -xl - width; + g_data.surfData[0].verts[0][6+2] = yl + height; + + g_data.surfData[0].verts[0][6+3] = -1; + g_data.surfData[0].verts[0][6+4] = 0; + g_data.surfData[0].verts[0][6+5] = 0; + g_data.surfData[0].baseVertexes[1].st[0] = 1; + g_data.surfData[0].baseVertexes[1].st[1] = 0; + + + g_data.surfData[0].verts[0][12+0] = 0; + g_data.surfData[0].verts[0][12+1] = -xl - width; + g_data.surfData[0].verts[0][12+2] = yl; + + g_data.surfData[0].verts[0][12+3] = -1; + g_data.surfData[0].verts[0][12+4] = 0; + g_data.surfData[0].verts[0][12+5] = 0; + g_data.surfData[0].baseVertexes[2].st[0] = 1; + g_data.surfData[0].baseVertexes[2].st[1] = 1; + + + g_data.surfData[0].verts[0][18+0] = 0; + g_data.surfData[0].verts[0][18+1] = -xl; + g_data.surfData[0].verts[0][18+2] = yl; + + g_data.surfData[0].verts[0][18+3] = -1; + g_data.surfData[0].verts[0][18+4] = 0; + g_data.surfData[0].verts[0][18+5] = 0; + g_data.surfData[0].baseVertexes[3].st[0] = 0; + g_data.surfData[0].baseVertexes[3].st[1] = 1; + + g_data.surfData[0].lodTriangles[0][0] = 0; + g_data.surfData[0].lodTriangles[0][1] = 1; + g_data.surfData[0].lodTriangles[0][2] = 2; + + g_data.surfData[0].lodTriangles[1][0] = 2; + g_data.surfData[0].lodTriangles[1][1] = 3; + g_data.surfData[0].lodTriangles[1][2] = 0; + + g_data.model.numSurfaces = 1; + + g_data.surfData[0].header.numTriangles = 2; + g_data.surfData[0].header.numVerts = 4; + + g_data.model.numFrames = 1; +} + +/* +=========================================================================== + + FRAME GRABBING + +=========================================================================== +*/ + +/* +=============== +GrabFrame +=============== +*/ +void GrabFrame (const char *frame) +{ + int i, j, k; + char file1[1024]; + md3Frame_t *fr; + md3Tag_t tagParent; + float *frameXyz; + float *frameNormals; + const char *framefile; + polyset_t *psets; + qboolean parentTagExists = qfalse; + int numpolysets; + int numtags = 0; + int tagcount; + + // the frame 'run1' will be looked for as either + // run.1 or run1.tri, so the new alias sequence save + // feature an be used + if ( frame[1] != ':' ) + { +// framefile = FindFrameFile (frame); + framefile = frame; + sprintf (file1, "%s/%s",g_cddir, framefile); + } + else + { + strcpy( file1, frame ); + } + printf ("grabbing %s\n", file1); + + if (g_data.model.numFrames >= MD3_MAX_FRAMES) + Error ("model.numFrames >= MD3_MAX_FRAMES"); + fr = &g_data.frames[g_data.model.numFrames]; + + strcpy (fr->name, frame); + + psets = Polyset_LoadSets( file1, &numpolysets, g_data.maxSurfaceTris ); + + // + // snap polysets + // + Polyset_SnapSets( psets, numpolysets ); + + // + // compute vertex normals + // + Polyset_ComputeNormals( psets, numpolysets ); + + // + // flip everything to compensate for the alias coordinate system + // and perform global scale and adjust + // + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + triangle_t *ptri = psets[i].triangles; + int t; + + for ( t = 0; t < psets[i].numtriangles; t++ ) + { + + for ( j = 0; j < 3; j++ ) + { + + // scale and adjust + for ( k = 0 ; k < 3 ; k++ ) { + ptri[t].verts[j][k] = ptri[t].verts[j][k] * g_data.scale_up + + g_data.adjust[k]; + + if ( ptri[t].verts[j][k] > 1023 || + ptri[t].verts[j][k] < -1023 ) + { + Error( "Model extents too large" ); + } + } + } + } + } + + // + // find and count tags, locate parent tag + // + for ( i = 0; i < numpolysets; i++ ) + { + if ( strstr( psets[i].name, "tag_" ) == psets[i].name ) + { + if ( strstr( psets[i].name, "tag_parent" ) == psets[i].name ) + { + if ( strstr( psets[i].name, "tag_parent" ) ) + { + float tri[3][3]; + + if ( parentTagExists ) + Error( "Multiple parent tags not allowed" ); + + memcpy( tri[0], psets[i].triangles[0].verts[0], sizeof( float ) * 3 ); + memcpy( tri[1], psets[i].triangles[0].verts[1], sizeof( float ) * 3 ); + memcpy( tri[2], psets[i].triangles[0].verts[2], sizeof( float ) * 3 ); + + MD3_ComputeTagFromTri( &tagParent, tri ); + strcpy( tagParent.name, psets[i].name ); + g_data.tags[g_data.model.numFrames][numtags] = tagParent; + parentTagExists = qtrue; + + } + } + numtags++; + } + + if ( strcmp( psets[i].name, g_data.surfData[i].header.name ) ) + { + Error( "Mismatched surfaces from base('%s') to frame('%s') in model '%s'\n", g_data.surfData[i].header.name, psets[i].name, g_modelname ); + } + } + + if ( numtags != g_data.model.numTags ) + { + Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags ); + } + + if ( numpolysets != g_data.model.numSurfaces ) + { + Error( "mismatched number of surfaces in frame(%d) vs. base(%d)", numpolysets-numtags, g_data.model.numSurfaces ); + } + + // + // prepare to accumulate bounds and normals + // + ClearBounds( fr->bounds[0], fr->bounds[1] ); + + // + // store the frame's vertices in the same order as the base. This assumes the + // triangles and vertices in this frame are in exactly the same order as in the + // base + // + for ( i = 0, tagcount = 0; i < numpolysets; i++ ) + { + int t; + triangle_t *pTris = psets[i].triangles; + + strcpy( g_data.surfData[i].header.name, psets[i].name ); + + // + // parent tag adjust + // + if ( parentTagExists ) { + for ( t = 0; t < psets[i].numtriangles; t++ ) + { + for ( j = 0; j < 3 ; j++ ) + { + vec3_t tmp; + + VectorSubtract( pTris[t].verts[j], tagParent.origin, tmp ); + + pTris[t].verts[j][0] = DotProduct( tmp, tagParent.axis[0] ); + pTris[t].verts[j][1] = DotProduct( tmp, tagParent.axis[1] ); + pTris[t].verts[j][2] = DotProduct( tmp, tagParent.axis[2] ); + + VectorCopy( pTris[t].normals[j], tmp ); + pTris[t].normals[j][0] = DotProduct( tmp, tagParent.axis[0] ); + pTris[t].normals[j][1] = DotProduct( tmp, tagParent.axis[1] ); + pTris[t].normals[j][2] = DotProduct( tmp, tagParent.axis[2] ); + } + } + } + + // + // compute tag data + // + if ( strstr( psets[i].name, "tag_" ) == psets[i].name ) + { + md3Tag_t *pTag = &g_data.tags[g_data.model.numFrames][tagcount]; + float tri[3][3]; + + strcpy( pTag->name, psets[i].name ); + + memcpy( tri[0], pTris[0].verts[0], sizeof( float ) * 3 ); + memcpy( tri[1], pTris[0].verts[1], sizeof( float ) * 3 ); + memcpy( tri[2], pTris[0].verts[2], sizeof( float ) * 3 ); + + MD3_ComputeTagFromTri( pTag, tri ); + tagcount++; + } + else + { + if ( g_data.surfData[i].verts[g_data.model.numFrames] ) + free( g_data.surfData[i].verts[g_data.model.numFrames] ); + frameXyz = g_data.surfData[i].verts[g_data.model.numFrames] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts ); + frameNormals = frameXyz + 3; + + for ( t = 0; t < psets[i].numtriangles; t++ ) + { + for ( j = 0; j < 3 ; j++ ) + { + int index; + + index = g_data.surfData[i].baseTriangles[t].v[j].index; + frameXyz[index*6+0] = pTris[t].verts[j][0]; + frameXyz[index*6+1] = pTris[t].verts[j][1]; + frameXyz[index*6+2] = pTris[t].verts[j][2]; + frameNormals[index*6+0] = pTris[t].normals[j][0]; + frameNormals[index*6+1] = pTris[t].normals[j][1]; + frameNormals[index*6+2] = pTris[t].normals[j][2]; + AddPointToBounds (&frameXyz[index*6], fr->bounds[0], fr->bounds[1] ); + } + } + } + } + + g_data.model.numFrames++; + + // only free the first triangle array, all of the psets in this array share the + // same triangle pool!!! +// free( psets[0].triangles ); +// free( psets ); +} + +//=========================================================================== + + + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_Frame (void) +{ + while (TokenAvailable()) + { + GetToken (qfalse); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + g_data.model.numFrames = 1; // don't skip the writeout + continue; + } + + GrabFrame( token ); + } +} + + +/* +=============== +Cmd_Skin + +=============== +*/ +void SkinFrom3DS( const char *filename ) +{ + polyset_t *psets; + char name[1024]; + int numPolysets; + int i; + + _3DS_LoadPolysets( filename, &psets, &numPolysets, g_verbose ); + + for ( i = 0; i < numPolysets; i++ ) + { +/* + if ( strstr( filename, gamedir + 1 ) ) + { + strcpy( name, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 ); + } + else + { + strcpy( name, filename ); + } + + if ( strrchr( name, '/' ) ) + *( strrchr( name, '/' ) + 1 ) = 0; +*/ + strcpy( name, psets[i].materialname ); + strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, name ); + + g_data.surfData[i].header.numShaders++; + } + + free( psets[0].triangles ); + free( psets ); +} + +void Cmd_Skin (void) +{ + char skinfile[1024]; + + if ( g_data.type == MD3_TYPE_BASE3DS ) + { + GetToken( qfalse ); + + sprintf( skinfile, "%s/%s", g_cddir, token ); + + if ( strstr( token, ".3ds" ) || strstr( token, ".3DS" ) ) + { + SkinFrom3DS( skinfile ); + } + else + { + Error( "Unknown file format for $skin '%s'\n", skinfile ); + } + } + else + { + Error( "invalid model type while processing $skin" ); + } + + g_data.model.numSkins++; +} + +/* +================= +Cmd_SpriteShader +================= + +This routine is also called for $oldskin + +*/ +void Cmd_SpriteShader() +{ + GetToken( qfalse ); + strcpy( g_data.surfData[0].shaders[g_data.surfData[0].header.numShaders].name, token ); + g_data.surfData[0].header.numShaders++; + g_data.model.numSkins++; +} + +/* +================= +Cmd_Origin +================= +*/ +void Cmd_Origin (void) +{ + // rotate points into frame of reference so model points down the + // positive x axis + // FIXME: use alias native coordinate system + GetToken (qfalse); + g_data.adjust[1] = -atof (token); + + GetToken (qfalse); + g_data.adjust[0] = atof (token); + + GetToken (qfalse); + g_data.adjust[2] = -atof (token); +} + + +/* +================= +Cmd_ScaleUp +================= +*/ +void Cmd_ScaleUp (void) +{ + GetToken (qfalse); + g_data.scale_up = atof (token); + if (g_skipmodel || g_release || g_archive) + return; + + printf ("Scale up: %f\n", g_data.scale_up); +} + + +/* +================= +Cmd_Skinsize + +Set a skin size other than the default +QUAKE3: not needed +================= +*/ +void Cmd_Skinsize (void) +{ + GetToken (qfalse); + g_data.fixedwidth = atoi(token); + GetToken (qfalse); + g_data.fixedheight = atoi(token); +} + +/* +================= +Cmd_Modelname + +Begin creating a model of the given name +================= +*/ +void Cmd_Modelname (void) +{ + FinishModel ( TYPE_UNKNOWN ); + ClearModel (); + + GetToken (qfalse); + strcpy (g_modelname, token); + StripExtension (g_modelname); + strcat (g_modelname, ".md3"); + strcpy (g_data.model.name, g_modelname); +} + +/* +=============== +fCmd_Cd +=============== +*/ +void Cmd_Cd (void) +{ + if ( g_cddir[0]) { + Error ("$cd command without a $modelname"); + } + + GetToken (qfalse); + + sprintf ( g_cddir, "%s%s", gamedir, token); + + // if -only was specified and this cd doesn't match, + // skip the model (you only need to match leading chars, + // so you could regrab all monsters with -only models/monsters) + if (!g_only[0]) + return; + if (strncmp(token, g_only, strlen(g_only))) + { + g_skipmodel = qtrue; + printf ("skipping %s\n", token); + } +} + +void Convert3DStoMD3( const char *file ) +{ + LoadBase( file ); + GrabFrame( file ); + SkinFrom3DS( file ); + + strcpy( g_data.model.name, g_modelname ); + + FinishModel( TYPE_UNKNOWN ); + ClearModel(); +} + +/* +** Cmd_3DSConvert +*/ +void Cmd_3DSConvert() +{ + char file[1024]; + + FinishModel( TYPE_UNKNOWN ); + ClearModel(); + + GetToken( qfalse ); + + sprintf( file, "%s%s", gamedir, token ); + strcpy( g_modelname, token ); + if ( strrchr( g_modelname, '.' ) ) + *strrchr( g_modelname, '.' ) = 0; + strcat( g_modelname, ".md3" ); + + if ( FileTime( file ) == -1 ) + Error( "%s doesn't exist", file ); + + if ( TokenAvailable() ) + { + GetToken( qfalse ); + g_data.scale_up = atof( token ); + } + + Convert3DStoMD3( file ); +} + +static void ConvertASE( const char *filename, int type, qboolean grabAnims ); + +/* +** Cmd_ASEConvert +*/ +void Cmd_ASEConvert( qboolean grabAnims ) +{ + char filename[1024]; + int type = TYPE_ITEM; + + FinishModel( TYPE_UNKNOWN ); + ClearModel(); + + GetToken( qfalse ); + sprintf( filename, "%s%s", gamedir, token ); + + strcpy (g_modelname, token); + StripExtension (g_modelname); + strcat (g_modelname, ".md3"); + strcpy (g_data.model.name, g_modelname); + + if ( !strstr( filename, ".ase" ) && !strstr( filename, ".ASE" ) ) + strcat( filename, ".ASE" ); + + g_data.maxSurfaceTris = MAX_SURFACE_TRIS - 1; + + while ( TokenAvailable() ) + { + GetToken( qfalse ); + if ( !strcmp( token, "-origin" ) ) + { + if ( !TokenAvailable() ) + Error( "missing parameter for -origin" ); + GetToken( qfalse ); + g_data.aseAdjust[1] = -atof( token ); + + if ( !TokenAvailable() ) + Error( "missing parameter for -origin" ); + GetToken( qfalse ); + g_data.aseAdjust[0] = atof (token); + + if ( !TokenAvailable() ) + Error( "missing parameter for -origin" ); + GetToken( qfalse ); + g_data.aseAdjust[2] = -atof (token); + } + else if ( !strcmp( token, "-lod" ) ) + { + if ( !TokenAvailable() ) + Error( "No parameter for -lod" ); + GetToken( qfalse ); + g_data.currentLod = atoi( token ); + if ( g_data.currentLod > MD3_MAX_LODS - 1 ) + { + Error( "-lod parameter too large! (%d)\n", g_data.currentLod ); + } + + if ( !TokenAvailable() ) + Error( "No second parameter for -lod" ); + GetToken( qfalse ); + g_data.lodBias = atof( token ); + } + else if ( !strcmp( token, "-maxtris" ) ) + { + if ( !TokenAvailable() ) + Error( "No parameter for -maxtris" ); + GetToken( qfalse ); + g_data.maxSurfaceTris = atoi( token ); + } + else if ( !strcmp( token, "-playerparms" ) ) + { + if ( !TokenAvailable() ) + Error( "missing skip start parameter for -playerparms" ); + GetToken( qfalse ); + g_data.lowerSkipFrameStart = atoi( token ); + +#if 0 + if ( !TokenAvailable() ) + Error( "missing skip end parameter for -playerparms" ); + GetToken( qfalse ); + g_data.lowerSkipFrameEnd = atoi( token ); +#endif + + if ( !TokenAvailable() ) + Error( "missing upper parameter for -playerparms" ); + GetToken( qfalse ); + g_data.maxUpperFrames = atoi( token ); + + g_data.lowerSkipFrameEnd = g_data.maxUpperFrames - 1; + +#if 0 + if ( !TokenAvailable() ) + Error( "missing head parameter for -playerparms" ); + GetToken( qfalse ); + g_data.maxHeadFrames = atoi( token ); +#endif + g_data.maxHeadFrames = 1; + + if ( type != TYPE_ITEM ) + Error( "invalid argument" ); + + type = TYPE_PLAYER; + } + else if ( !strcmp( token, "-weapon" ) ) + { + if ( type != TYPE_ITEM ) + Error( "invalid argument" ); + + type = TYPE_WEAPON; + } + } + + g_data.type = MD3_TYPE_ASE; + + if ( type == TYPE_WEAPON && grabAnims ) + { + Error( "can't grab anims with weapon models" ); + } + if ( type == TYPE_PLAYER && !grabAnims ) + { + Error( "player models must be converted with $aseanimconvert" ); + } + + if ( type == TYPE_WEAPON ) + { + ConvertASE( filename, type, qfalse ); + ConvertASE( filename, TYPE_HAND, qtrue ); + } + else + { + ConvertASE( filename, type, grabAnims ); + } +} + +static int GetSurfaceAnimations( SurfaceAnimation_t sanims[MAX_ANIM_SURFACES], + const char *part, + int skipFrameStart, + int skipFrameEnd, + int maxFrames ) + +{ + int numSurfaces; + int numValidSurfaces; + int i; + int numFrames = -1; + + if ( ( numSurfaces = ASE_GetNumSurfaces() ) > MAX_ANIM_SURFACES ) + { + Error( "Too many surfaces in ASE" ); + } + + for ( numValidSurfaces = 0, i = 0; i < numSurfaces; i++ ) + { + polyset_t *splitSets; + int numNewFrames; + const char *surfaceName = ASE_GetSurfaceName( i ); + + if ( !surfaceName ) + { + continue; +// Error( "Missing animation frames in model" ); + } + + if ( strstr( surfaceName, "tag_" ) || + !strcmp( part, "any" ) || + ( strstr( surfaceName, part ) == surfaceName ) ) + { + + // skip this if it's an inappropriate tag + if ( strcmp( part, "any" ) ) + { + // ignore non-"tag_head" tags if this is the head + if ( !strcmp( part, "h_" ) && strstr( surfaceName, "tag_" ) && strcmp( surfaceName, "tag_head" ) ) + continue; + // ignore "tag_head" if this is the legs + if ( !strcmp( part, "l_" ) && !strcmp( surfaceName, "tag_head" ) ) + continue; + // ignore "tag_weapon" if this is the legs + if ( !strcmp( part, "l_" ) && !strcmp( surfaceName, "tag_weapon" ) ) + continue; + } + + if ( ( sanims[numValidSurfaces].frames = ASE_GetSurfaceAnimation( i, &sanims[numValidSurfaces].numFrames, skipFrameStart, skipFrameEnd, maxFrames ) ) != 0 ) + { + splitSets = Polyset_SplitSets( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames, &numNewFrames, g_data.maxSurfaceTris ); + + if ( numFrames == -1 ) + numFrames = sanims[numValidSurfaces].numFrames; + else if ( numFrames != sanims[numValidSurfaces].numFrames ) + Error( "Different number of animation frames on surfaces" ); + + if ( sanims[numValidSurfaces].frames != splitSets ) + { + int j; + + // free old data if we split the surfaces + for ( j = 0; j < sanims[numValidSurfaces].numFrames; j++ ) + { + free( sanims[numValidSurfaces].frames[j].triangles ); + free( sanims[numValidSurfaces].frames ); + } + + sanims[numValidSurfaces].frames = splitSets; + sanims[numValidSurfaces].numFrames = numNewFrames; + } + Polyset_SnapSets( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames ); + Polyset_ComputeNormals( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames ); + + numValidSurfaces++; + } + } + } + + return numValidSurfaces; +} + +static int SurfaceOrderToFrameOrder( SurfaceAnimation_t sanims[], ObjectAnimationFrame_t oanims[], int numSurfaces ) +{ + int i, s; + int numFrames = -1; + + /* + ** we have the data here arranged in surface order, now we need to convert it to + ** frame order + */ + for ( i = 0, s = 0; i < numSurfaces; i++ ) + { + int j; + + if ( sanims[i].frames ) + { + if ( numFrames == -1 ) + numFrames = sanims[i].numFrames; + else if ( numFrames != sanims[i].numFrames ) + Error( "numFrames != sanims[i].numFrames (%d != %d)\n", numFrames, sanims[i].numFrames ); + + for ( j = 0; j < sanims[i].numFrames; j++ ) + { + oanims[j].surfaces[s] = &sanims[i].frames[j]; + oanims[j].numSurfaces = numSurfaces; + } + s++; + } + } + + return numFrames; +} + +static void WriteMD3( const char *_filename, ObjectAnimationFrame_t oanims[], int numFrames ) +{ + char filename[1024]; + + strcpy( filename, _filename ); + if ( strchr( filename, '.' ) ) + *strchr( filename, '.' ) = 0; + strcat( filename, ".md3" ); +} + +static void BuildAnimationFromOAFs( const char *filename, ObjectAnimationFrame_t oanims[], int numFrames, int type ) +{ + int f, i, j, tagcount; + float *frameXyz; + float *frameNormals; + + g_data.model.numSurfaces = oanims[0].numSurfaces; + g_data.model.numFrames = numFrames; + if ( g_data.model.numFrames < 0) + Error ("model.numFrames < 0"); + if ( g_data.model.numFrames >= MD3_MAX_FRAMES) + Error ("model.numFrames >= MD3_MAX_FRAMES"); + + // build base frame + BuildBaseFrame( filename, &oanims[0] ); + + // build animation frames + for ( f = 0; f < numFrames; f++ ) + { + ObjectAnimationFrame_t *pOAF = &oanims[f]; + qboolean parentTagExists = qfalse; + md3Tag_t tagParent; + int numtags = 0; + md3Frame_t *fr; + + fr = &g_data.frames[f]; + + strcpy( fr->name, "(from ASE)" ); + + // scale and adjust frame + for ( i = 0; i < pOAF->numSurfaces; i++ ) + { + triangle_t *pTris = pOAF->surfaces[i]->triangles; + int t; + + for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ ) + { + for ( j = 0; j < 3; j++ ) + { + int k; + + // scale and adjust + for ( k = 0 ; k < 3 ; k++ ) { + pTris[t].verts[j][k] = pTris[t].verts[j][k] * g_data.scale_up + + g_data.aseAdjust[k]; + + if ( pTris[t].verts[j][k] > 1023 || + pTris[t].verts[j][k] < -1023 ) + { + Error( "Model extents too large" ); + } + } + } + } + } + + // + // find and count tags, locate parent tag + // + for ( i = 0; i < pOAF->numSurfaces; i++ ) + { + if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name ) + { + // ignore parent tags when grabbing a weapon model and this is the flash portion + if ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) && strstr( filename, "_flash.md3" ) ) + { + continue; + } + else if ( !strstr( filename, "_hand.md3" ) && ( + ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) && !strstr( filename, "_flash.md3" ) ) || + ( !strcmp( pOAF->surfaces[i]->name, "tag_torso" ) && ( strstr( filename, "upper_" ) || strstr( filename, "upper.md3" ) ) ) || + ( !strcmp( pOAF->surfaces[i]->name, "tag_head" ) && ( strstr( filename, "head.md3" ) || strstr( filename, "head_" ) ) ) || + ( !strcmp( pOAF->surfaces[i]->name, "tag_flash" ) && strstr( filename, "_flash.md3" ) )|| + ( !strcmp( pOAF->surfaces[i]->name, "tag_weapon" ) && type == TYPE_WEAPON ) ) ) + { + float tri[3][3]; + + if ( parentTagExists ) + Error( "Multiple parent tags not allowed" ); + + memcpy( tri[0], pOAF->surfaces[i]->triangles[0].verts[0], sizeof( float ) * 3 ); + memcpy( tri[1], pOAF->surfaces[i]->triangles[0].verts[1], sizeof( float ) * 3 ); + memcpy( tri[2], pOAF->surfaces[i]->triangles[0].verts[2], sizeof( float ) * 3 ); + + MD3_ComputeTagFromTri( &tagParent, tri ); + strcpy( tagParent.name, "tag_parent" ); + g_data.tags[f][numtags] = tagParent; + parentTagExists = qtrue; + } + else + { + float tri[3][3]; + + memcpy( tri[0], pOAF->surfaces[i]->triangles[0].verts[0], sizeof( float ) * 3 ); + memcpy( tri[1], pOAF->surfaces[i]->triangles[0].verts[1], sizeof( float ) * 3 ); + memcpy( tri[2], pOAF->surfaces[i]->triangles[0].verts[2], sizeof( float ) * 3 ); + + MD3_ComputeTagFromTri( &g_data.tags[f][numtags], tri ); + strcpy( g_data.tags[f][numtags].name, pOAF->surfaces[i]->name ); + if ( strstr( g_data.tags[f][numtags].name, "tag_flash" ) ) + * ( strstr( g_data.tags[f][numtags].name, "tag_flash" ) + strlen( "tag_flash" ) ) = 0; + } + + numtags++; + } + + if ( strcmp( pOAF->surfaces[i]->name, g_data.surfData[i].header.name ) ) + { + Error( "Mismatched surfaces from base('%s') to frame('%s') in model '%s'\n", g_data.surfData[i].header.name, pOAF->surfaces[i]->name, filename ); + } + } + + if ( numtags != g_data.model.numTags ) + { + Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags ); + } + + // + // prepare to accumulate bounds and normals + // + ClearBounds( fr->bounds[0], fr->bounds[1] ); + + // + // store the frame's vertices in the same order as the base. This assumes the + // triangles and vertices in this frame are in exactly the same order as in the + // base + // + for ( i = 0, tagcount = 0; i < pOAF->numSurfaces; i++ ) + { + int t; + triangle_t *pTris = pOAF->surfaces[i]->triangles; + + // + // parent tag adjust + // + if ( parentTagExists ) + { + for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ ) + { + for ( j = 0; j < 3 ; j++ ) + { + vec3_t tmp; + + VectorSubtract( pTris[t].verts[j], tagParent.origin, tmp ); + + pTris[t].verts[j][0] = DotProduct( tmp, tagParent.axis[0] ); + pTris[t].verts[j][1] = DotProduct( tmp, tagParent.axis[1] ); + pTris[t].verts[j][2] = DotProduct( tmp, tagParent.axis[2] ); + + VectorCopy( pTris[t].normals[j], tmp ); + pTris[t].normals[j][0] = DotProduct( tmp, tagParent.axis[0] ); + pTris[t].normals[j][1] = DotProduct( tmp, tagParent.axis[1] ); + pTris[t].normals[j][2] = DotProduct( tmp, tagParent.axis[2] ); + } + } + } + + // + // compute tag data + // + if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name ) + { + md3Tag_t *pTag = &g_data.tags[f][tagcount]; + float tri[3][3]; + + strcpy( pTag->name, pOAF->surfaces[i]->name ); + + memcpy( tri[0], pTris[0].verts[0], sizeof( float ) * 3 ); + memcpy( tri[1], pTris[0].verts[1], sizeof( float ) * 3 ); + memcpy( tri[2], pTris[0].verts[2], sizeof( float ) * 3 ); + + MD3_ComputeTagFromTri( pTag, tri ); + tagcount++; + } + else + { + if ( g_data.surfData[i].verts[f] ) + free( g_data.surfData[i].verts[f] ); + frameXyz = g_data.surfData[i].verts[f] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts ); + frameNormals = frameXyz + 3; + + for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ ) + { + for ( j = 0; j < 3 ; j++ ) + { + int index; + + index = g_data.surfData[i].baseTriangles[t].v[j].index; + frameXyz[index*6+0] = pTris[t].verts[j][0]; + frameXyz[index*6+1] = pTris[t].verts[j][1]; + frameXyz[index*6+2] = pTris[t].verts[j][2]; + frameNormals[index*6+0] = pTris[t].normals[j][0]; + frameNormals[index*6+1] = pTris[t].normals[j][1]; + frameNormals[index*6+2] = pTris[t].normals[j][2]; + AddPointToBounds (&frameXyz[index*6], fr->bounds[0], fr->bounds[1] ); + } + } + } + } + } + + if ( strstr( filename, gamedir + 1 ) ) + { + strcpy( g_modelname, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 ); + } + else + { + strcpy( g_modelname, filename ); + } + + FinishModel( type ); + ClearModel(); +} + +static void ConvertASE( const char *filename, int type, qboolean grabAnims ) +{ + int i, j; + int numSurfaces; + int numFrames = -1; + SurfaceAnimation_t surfaceAnimations[MAX_ANIM_SURFACES]; + ObjectAnimationFrame_t objectAnimationFrames[MAX_ANIM_FRAMES]; + char outfilename[1024]; + + /* + ** load ASE into memory + */ + ASE_Load( filename, g_verbose, grabAnims ); + + /* + ** process parts + */ + if ( type == TYPE_ITEM ) + { + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "any", -1, -1, -1 ); + + if ( numSurfaces <= 0 ) + Error( "numSurfaces <= 0" ); + + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + + if ( numFrames <= 0 ) + Error( "numFrames <= 0" ); + + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '.' ) ) + *( strrchr( outfilename, '.' ) + 1 ) = 0; + strcat( outfilename, "md3" ); + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + } + else if ( type == TYPE_PLAYER ) + { + qboolean tagTorso = qfalse; + qboolean tagHead = qfalse; + qboolean tagWeapon = qfalse; + + // + // verify that all necessary tags exist + // + numSurfaces = ASE_GetNumSurfaces(); + for ( i = 0; i < numSurfaces; i++ ) + { + if ( !strcmp( ASE_GetSurfaceName( i ), "tag_head" ) ) + { + tagHead = qtrue; + } + if ( !strcmp( ASE_GetSurfaceName( i ), "tag_torso" ) ) + { + tagTorso = qtrue; + } + if ( !strcmp( ASE_GetSurfaceName( i ), "tag_weapon" ) ) + { + tagWeapon = qtrue; + } + } + + if ( !tagWeapon ) + { + Error( "Missing tag_weapon!" ); + } + if ( !tagTorso ) + { + Error( "Missing tag_torso!" ); + } + if ( !tagWeapon ) + { + Error( "Missing tag_weapon!" ); + } + + // get all upper body surfaces + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "u_", -1, -1, g_data.maxUpperFrames ); + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '/' ) ) + *( strrchr( outfilename, '/' ) + 1 ) = 0; + + if ( g_data.currentLod == 0 ) + { + strcat( outfilename, "upper.md3" ); + } + else + { + char temp[128]; + + sprintf( temp, "upper_%d.md3", g_data.currentLod ); + strcat( outfilename, temp ); + } + + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + + // get lower body surfaces + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "l_", g_data.lowerSkipFrameStart, g_data.lowerSkipFrameEnd, -1 ); + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '/' ) ) + *( strrchr( outfilename, '/' ) + 1 ) = 0; + + if ( g_data.currentLod == 0 ) + { + strcat( outfilename, "lower.md3" ); + } + else + { + char temp[128]; + + sprintf( temp, "lower_%d.md3", g_data.currentLod ); + strcat( outfilename, temp ); + } + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + + // get head surfaces + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "h_", -1, -1, g_data.maxHeadFrames ); + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '/' ) ) + *( strrchr( outfilename, '/' ) + 1 ) = 0; + + if ( g_data.currentLod == 0 ) + { + strcat( outfilename, "head.md3" ); + } + else + { + char temp[128]; + + sprintf( temp, "head_%d.md3", g_data.currentLod ); + strcat( outfilename, temp ); + } + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + } + else if ( type == TYPE_WEAPON ) + { + // get the weapon surfaces + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "w_", -1, -1, -1 ); + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '.' ) ) + *( strrchr( outfilename, '.' ) + 1 ) = 0; + strcat( outfilename, "md3" ); + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + + // get the flash surfaces + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "f_", -1, -1, -1 ); + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '.' ) ) + *strrchr( outfilename, '.' ) = 0; + strcat( outfilename, "_flash.md3" ); + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_ITEM ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + } + else if ( type == TYPE_HAND ) + { + // get the hand tags + numSurfaces = GetSurfaceAnimations( surfaceAnimations, "tag_", -1, -1, -1 ); + numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces ); + + strcpy( outfilename, filename ); + if ( strrchr( outfilename, '.' ) ) + *strrchr( outfilename, '.' ) = 0; + strcat( outfilename, "_hand.md3" ); + BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_HAND ); + + // free memory + for ( i = 0; i < numSurfaces; i++ ) + { + if ( surfaceAnimations[i].frames ) + { + for ( j = 0; j < surfaceAnimations[i].numFrames; j++ ) + { + free( surfaceAnimations[i].frames[j].triangles ); + } + free( surfaceAnimations[i].frames ); + surfaceAnimations[i].frames = 0; + } + } + } + else + { + Error( "Unknown type passed to ConvertASE()" ); + } + + g_data.currentLod = 0; + g_data.lodBias = 0; + g_data.maxHeadFrames = 0; + g_data.maxUpperFrames = 0; + g_data.lowerSkipFrameStart = 0; + g_data.lowerSkipFrameEnd = 0; + VectorCopy( vec3_origin, g_data.aseAdjust ); + + // unload ASE from memory + ASE_Free(); +} diff --git a/tools/quake3/q3data/oldstuff.c b/tools/quake3/q3data/oldstuff.c new file mode 100644 index 00000000..2444f95e --- /dev/null +++ b/tools/quake3/q3data/oldstuff.c @@ -0,0 +1,130 @@ +#if 0 + +/* +** ReindexTriangle +** +** Given a triangle_t, find which indices match into the associated +** surface's base triangles. +*/ +static void ReindexTriangle( int surfno, triangle_t *pTri, int indices[3] ) +{ + int t, i; + md3SurfaceData_t *pSurfData = &g_data.surfData[surfno]; + int matches[3][3]; + int numMatches = 0; + + + indices[0] = -1; + indices[1] = -1; + indices[2] = -1; + + for ( i = 0; i < 3; i++ ) + { + numMatches = 0; + + matches[i][0] = -1; + matches[i][1] = -1; + matches[i][2] = -1; + + for ( t = 0; t < pSurfData->header.numVerts; t++ ) + { + if ( !VectorCompare( pTri->verts[i], pSurfData->baseVertexes[t].xyz ) ) + continue; + +/* + if ( !VectorCompare( pTri->normals[i], pSurfData->baseVertexes[t].normal ) ) + continue; + if ( pTri->texcoords[i][0] != pSurfData->baseVertexes[t].st[0] ) + continue; + if ( pTri->texcoords[i][1] != pSurfData->baseVertexes[t].st[1] ) + continue; +*/ + + matches[i][numMatches++] = t; + } + + if ( indices[i] == -1 ) + { +// Error( "Could not ReindexTriangle, vertex not found" ); + } + } + +#if 0 + for ( t = 0; t < psets[i].numtriangles; t++ ) + { + int b; + + bTri = &g_data.surfData[i].baseTriangles[t]; + + for (j=0 ; j<3 ; j++) + { + bVert = &bTri->v[j]; + + // get the xyz index + for ( k = 0; k < g_data.surfData[i].header.numVerts; k++ ) + { + if ( ( g_data.surfData[i].baseVertexes[k].st[0] == bVert->st[0] ) && + ( g_data.surfData[i].baseVertexes[k].st[1] == bVert->st[1] ) && + ( VectorCompare (bVert->xyz, g_data.surfData[i].baseVertexes[k].xyz) ) && + ( VectorCompare (bVert->normal, g_data.surfData[i].baseVertexes[k].normal) ) ) + { + break; // this vertex is already in the base vertex list + } + } + + if (k == g_data.surfData[i].header.numVerts) { // new index + g_data.surfData[i].baseVertexes[g_data.surfData[i].header.numVerts] = *bVert; + g_data.surfData[i].header.numVerts++; + } + + bVert->index = k; + } + } +#endif +} + +const char *FindFrameFile (const char *frame) +{ + int time1; + char file1[1024]; + static char retname[1024]; + char base[32]; + char suffix[32]; + const char *s; + + if (strstr (frame, ".")) + return frame; // allready in dot format + + // split 'run1' into 'run' and '1' + s = frame + strlen(frame)-1; + + while (s != frame && *s >= '0' && *s <= '9') + s--; + + strcpy (suffix, s+1); + strcpy (base, frame); + base[s-frame+1] = 0; + + // check for 'run1.tri' + sprintf (file1, "%s/%s%s.tri", g_cddir, base, suffix); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.tri", base, suffix); + return retname; + } + + // check for 'run.1' + sprintf (file1, "%s/%s.%s",g_cddir, base, suffix); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s.%s", base, suffix); + return retname; + } + + Error ("frame %s could not be found",frame); + return NULL; +} + +#endif diff --git a/tools/quake3/q3data/p3dlib.c b/tools/quake3/q3data/p3dlib.c new file mode 100644 index 00000000..6afc3491 --- /dev/null +++ b/tools/quake3/q3data/p3dlib.c @@ -0,0 +1,324 @@ +#include "p3dlib.h" + +#ifdef _WIN32 +#include +#endif +#include +#include +#include + +#define MAX_POLYSETS 64 + +#if defined (__linux__) || defined (__APPLE__) +#define _strcmpi Q_stricmp +#define filelength Q_filelength +#define strlwr strlower +#endif +typedef struct +{ + long len; + + int numPairs; + char polysetNames[MAX_POLYSETS][256]; + char shaders[MAX_POLYSETS][256]; + + char *buffer, *curpos; +} p3d_t; + +static p3d_t p3d; + +static int P3DProcess(); +static int P3DGetToken( int restOfLine ); + +static char s_token[1024]; +static int s_curpair; + +/* +** P3DLoad +** +*/ +int P3DLoad( const char *filename ) +{ + FILE *fp = fopen( filename, "rb" ); + + if ( !fp ) + return 0; + + memset( &p3d, 0, sizeof( p3d ) ); + + p3d.len = filelength( fileno( fp ) ); + + p3d.curpos = p3d.buffer = malloc( p3d.len ); + + if ( fread( p3d.buffer, p3d.len, 1, fp ) != 1 ) + { + fclose( fp ); + return 0; + } + + fclose( fp ); + + return P3DProcess(); +} + +/* +** P3DClose +** +*/ +void P3DClose() +{ + if ( p3d.buffer ) + { + free( p3d.buffer ); + p3d.buffer = 0; + } +} + +int CharIsTokenDelimiter( int ch ) +{ + if ( ch <= 32 ) + return 1; + return 0; +} + +int P3DSkipToToken( const char *name ) +{ + while ( P3DGetToken( 0 ) ) + { + if ( !_strcmpi( s_token, name ) ) + return 1; + } + + return 0; +} + +/* +** P3DGetToken +** +*/ +int P3DGetToken( int restOfLine ) +{ + int i = 0; + + if ( p3d.buffer == 0 ) + return 0; + + if ( ( p3d.curpos - p3d.buffer ) == p3d.len ) + return 0; + + // skip over crap + while ( ( ( p3d.curpos - p3d.buffer ) < p3d.len ) && + ( *p3d.curpos <= 32 ) ) + { + p3d.curpos++; + } + + while ( ( p3d.curpos - p3d.buffer ) < p3d.len ) + { + s_token[i] = *p3d.curpos; + + p3d.curpos++; + i++; + + if ( ( CharIsTokenDelimiter( s_token[i-1] ) && !restOfLine ) || + ( ( s_token[i-1] == '\n' ) ) ) + { + s_token[i-1] = 0; + break; + } + } + + s_token[i] = 0; + + return 1; +} + +int P3DGetNextPair( char **psetName, char **associatedShader ) +{ + if ( s_curpair < p3d.numPairs ) + { + *psetName = p3d.polysetNames[s_curpair]; + *associatedShader = p3d.shaders[s_curpair]; + s_curpair++; + return 1; + } + + return 0; +} + +int P3DSkipToTokenInBlock( const char *name ) +{ + int iLevel = 0; + + while ( P3DGetToken( 0 ) ) + { + if ( !_strcmpi( s_token, "}" ) ) + iLevel--; + else if ( !_strcmpi( s_token, "{" ) ) + iLevel++; + + if ( !_strcmpi( s_token, name ) ) + return 1; + + if ( iLevel == 0 ) + { + return 0; + } + } + + return 0; +} + +/* +** P3DProcess +** +** Nothing fancy here. +*/ +int P3DProcess() +{ + + s_curpair = 0; + + // first token should be a string + P3DGetToken( 1 ); // Voodoo Ascii File + + // skip to the first Obj declaration + while ( P3DGetToken( 0 ) ) + { + if ( !_strcmpi( s_token, "Obj" ) ) + { + int j = 0, k = 0; + + if ( P3DSkipToToken( "Text" ) ) + { + if ( P3DSkipToTokenInBlock( "TMap" ) ) + { + char *p; + + if ( !P3DSkipToToken( "Path" ) ) + return 0; + + if ( !P3DGetToken( 1 ) ) + return 0; + + while ( s_token[j] != 0 ) + { + if ( s_token[j] == '\\' ) + { + j++; + p3d.shaders[p3d.numPairs][k] = '/'; + } + else + { + p3d.shaders[p3d.numPairs][k] = s_token[j]; + } + j++; + k++; + } + p3d.shaders[p3d.numPairs][k] = 0; + + // + // strip off any explicit extensions + // + if ( ( p = strrchr( p3d.shaders[p3d.numPairs], '/' ) ) != 0 ) + { + while ( *p ) + { + if ( *p == '.' ) + { + *p = 0; + break; + } + p++; + } + } + + // + // skip to the end of the Object and grab its name + // + if ( !P3DSkipToToken( "Name" ) ) + return 0; + + if ( P3DGetToken( 0 ) ) + { + // strip off leading 'Obj_' if it exists + if ( strstr( s_token, "Obj_" ) == s_token ) + strcpy( p3d.polysetNames[p3d.numPairs], s_token + strlen( "Obj_" ) ); + else + strcpy( p3d.polysetNames[p3d.numPairs], s_token ); + + // strip off trailing unused color information +// if ( strrchr( p3d.polysetNames[p3d.numPairs], '_' ) != 0 ) +// *strrchr( p3d.polysetNames[p3d.numPairs], '_' ) = 0; + + p3d.numPairs++; + } + else + { + return 0; + } + } + } + } + } + + s_curpair = 0; + + return 1; +} + +#if 0 +void SkinFromP3D( const char *file ) +{ + char filename[1024]; + char *psetName, *associatedShader; + + /* + ** a P3D file contains a list of polysets, each with a list of associated + ** texture names that constitute it's + ** + ** Thus: + ** + ** P3D file -> skin + ** polyset -> polyset + ** texture -> texture.SHADER becomes polyset's shader + */ + sprintf( filename, "%s/%s", g_cddir, file ); + + if ( !P3DLoad( filename ) ) + Error( "unable to load '%s'", filename ); + + while ( P3DGetNextPair( &psetName, &associatedShader ) ) + { + int i; + + // find the polyset in the object that this particular pset/shader pair + // corresponds to and append the shader to it + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + if ( !_strcmpi( g_data.surfData[i].header.name, psetName) ) + { + char *p; + + if ( strstr( associatedShader, gamedir + 1 ) ) + { + p = strstr( associatedShader, gamedir + 1 ) + strlen( gamedir ) - 1; + } + else + { + p = associatedShader; + } + + strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, p ); + + g_data.surfData[i].header.numShaders++; + } + } + + } + + P3DClose(); +} +#endif + + diff --git a/tools/quake3/q3data/p3dlib.h b/tools/quake3/q3data/p3dlib.h new file mode 100644 index 00000000..a6c0320d --- /dev/null +++ b/tools/quake3/q3data/p3dlib.h @@ -0,0 +1,8 @@ + +#define P3D_GET_CROSSLINE 1 +#define P3D_GET_RESTOFLINE 2 + +int P3DLoad( const char *filename ); +void P3DClose(); + +int P3DGetNextPair( char **name, char **associatedShader ); diff --git a/tools/quake3/q3data/polyset.c b/tools/quake3/q3data/polyset.c new file mode 100644 index 00000000..794fc026 --- /dev/null +++ b/tools/quake3/q3data/polyset.c @@ -0,0 +1,252 @@ +#include +#include "q3data.h" + +polyset_t *Polyset_SplitSets( polyset_t *psets, int numpolysets, int *pNumNewPolysets, int maxTris ) +{ + int p, np, op; + int numNewPolysets = 0; + int numSplitPolysets = 0; + polyset_t *newpsets; + int sumTriangles = 0; + + for ( p = 0; p < numpolysets; p++ ) + { + numNewPolysets += psets[p].numtriangles / maxTris + 1; + } + + if ( numNewPolysets == numpolysets ) + return psets; + + printf( "Warning: creating %d polysets from input of %d polysets\n", numNewPolysets, numpolysets ); + + newpsets = calloc( sizeof( polyset_t ) * numNewPolysets, 1 ); + + for ( np = 0, op = 0; op < numpolysets; op++ ) + { + numSplitPolysets = ( psets[op].numtriangles / ( maxTris + 1 ) ) + 1; + if ( numSplitPolysets == 1 ) + { + memcpy( &newpsets[np], &psets[op], sizeof( polyset_t ) ); + np++; + } + else + { + sumTriangles = 0; + + // split this pset into multiple smaller psets + for ( p = 0; p < numSplitPolysets; p++, np++ ) + { + memcpy( &newpsets[np], &psets[op], sizeof( polyset_t ) ); + + newpsets[np].triangles = psets[op].triangles + sumTriangles; + + if ( sumTriangles + maxTris > psets[op].numtriangles ) + newpsets[np].numtriangles = psets[op].numtriangles - sumTriangles; + else + newpsets[np].numtriangles = maxTris; + + sumTriangles += newpsets[np].numtriangles; + } + } + } + + *pNumNewPolysets = numNewPolysets; + + return newpsets; +} + +polyset_t *Polyset_LoadSets( const char *file, int *numpolysets, int maxTrisPerSet ) +{ + polyset_t *psets; + polyset_t *finalpsets; + + // + // load the frame + // + if ( strstr( file, ".3DS" ) || strstr( file, ".3ds" ) ) + _3DS_LoadPolysets( file, &psets, numpolysets, g_verbose ); + else + Error( "TRI files no longer supported" ); +// TRI_LoadPolysets( file, &psets, numpolysets ); + +/* + // + // scale polysets + // + for ( i = 0; i < psets; i++ ) + { + int j; + + for ( j = 0; j < psets[i].numtriangles; j++ ) + { + } + } +*/ + + // + // split polysets if necessary + // + finalpsets = Polyset_SplitSets( psets, *numpolysets, numpolysets, maxTrisPerSet ); + + return finalpsets; +} + +polyset_t *Polyset_CollapseSets( polyset_t *psets, int numpolysets ) +{ + int p; + int sumtriangles = 0; + + polyset_t *oldpsets = psets; + + // + // no tag checking because this is an $oldbase and thus shouldn't have any + // tags + // + for ( p = 0; p < numpolysets; p++ ) + { + sumtriangles += oldpsets[p].numtriangles; + } + + psets = calloc( 1, sizeof( polyset_t ) ); + psets[0].numtriangles = sumtriangles; + psets[0].triangles = malloc( MD3_MAX_TRIANGLES * sizeof( triangle_t ) ); + + // each call to "LoadPolysets" only allocates a single large chunk of + // triangle memory that is utilized by all the polysets loaded by + // that one call + memcpy( psets[0].triangles, oldpsets[0].triangles, sizeof( triangle_t ) * sumtriangles ); + + free( oldpsets[0].triangles ); + free( oldpsets ); + + return psets; +} + +static float SnapFloat( float x ) +{ + int ix; + + x *= 1.0f / MD3_XYZ_SCALE; + ix = ( int ) x; + x = ( float ) ix; + x *= MD3_XYZ_SCALE; + + return x; +} + +void Polyset_SnapSets( polyset_t *psets, int numpolysets ) +{ + int p; + + for ( p = 0; p < numpolysets; p++ ) + { + int t; + + for ( t = 0; t < psets[p].numtriangles; t++ ) + { + int v; + + for ( v = 0; v < 3; v++ ) + { + psets[p].triangles[t].verts[v][0] = SnapFloat( psets[p].triangles[t].verts[v][0] ); + psets[p].triangles[t].verts[v][1] = SnapFloat( psets[p].triangles[t].verts[v][1] ); + psets[p].triangles[t].verts[v][2] = SnapFloat( psets[p].triangles[t].verts[v][2] ); + } + } + } +} + +void Polyset_ComputeNormals( polyset_t *psets, int numpolysets ) +{ + int p; + int i, t; + int vertexIndex[MD3_MAX_TRIANGLES][3]; + vec3_t verts[MD3_MAX_VERTS]; + vec3_t normals[MD3_MAX_VERTS]; + vec3_t faceNormals[MD3_MAX_TRIANGLES]; + + // + // iterate through polysets + // + for ( p = 0; p < numpolysets; p++ ) + { + int numUniqueVertices = 0; + + assert( psets[p].numtriangles < MD3_MAX_TRIANGLES ); + + memset( vertexIndex, 0xff, sizeof( vertexIndex ) ); + memset( verts, 0, sizeof( verts ) ); + memset( normals, 0, sizeof( normals ) ); + + // + // unique vertices + // + for ( t = 0; t < psets[p].numtriangles; t++ ) + { + int j; + + for ( j = 0; j < 3; j++ ) + { + for ( i = 0; i < numUniqueVertices; i++ ) + { + if ( VectorCompare( psets[p].triangles[t].verts[j], verts[i] ) ) + { + break; + } + } + if ( i == numUniqueVertices ) + { + vertexIndex[t][j] = numUniqueVertices; + VectorCopy( (psets[p].triangles[t].verts[j]), (verts[numUniqueVertices]) ); + numUniqueVertices++; + } + else + { + vertexIndex[t][j] = i; + } + } + } + + // + // compute face normals + // + for ( t = 0; t < psets[p].numtriangles; t++ ) + { + vec3_t side0, side1, facenormal; + + VectorSubtract( psets[p].triangles[t].verts[0], psets[p].triangles[t].verts[1], side0 ); + VectorSubtract( psets[p].triangles[t].verts[2], psets[p].triangles[t].verts[1], side1); + + CrossProduct( side0, side1, facenormal ); + VectorNormalize( facenormal, faceNormals[t] ); + } + + // + // sum normals and copy them back + // + for ( i = 0; i < numUniqueVertices; i++ ) + { + for ( t = 0; t < psets[p].numtriangles; t++ ) + { + if ( vertexIndex[t][0] == i || + vertexIndex[t][1] == i || + vertexIndex[t][2] == i ) + { + normals[i][0] += faceNormals[t][0]; + normals[i][1] += faceNormals[t][1]; + normals[i][2] += faceNormals[t][2]; + } + } + VectorNormalize( normals[i], normals[i] ); + } + + + for ( t = 0; t < psets[p].numtriangles; t++ ) + { + VectorCopy( normals[vertexIndex[t][0]], psets[p].triangles[t].normals[0] ); + VectorCopy( normals[vertexIndex[t][1]], psets[p].triangles[t].normals[1] ); + VectorCopy( normals[vertexIndex[t][2]], psets[p].triangles[t].normals[2] ); + } + } +} + diff --git a/tools/quake3/q3data/q3data.c b/tools/quake3/q3data/q3data.c new file mode 100644 index 00000000..05ff9220 --- /dev/null +++ b/tools/quake3/q3data/q3data.c @@ -0,0 +1,643 @@ +#ifdef _WIN32 +#include +#endif +#include "q3data.h" +#include "md3lib.h" + +#include "vfs.h" + +qboolean g_verbose; +qboolean g_stripify = qtrue; +qboolean g_release; // don't grab, copy output data to new tree +char g_releasedir[1024]; // c:\quake2\baseq2, etc +qboolean g_archive; // don't grab, copy source data to new tree +char g_only[256]; // if set, only grab this cd +qboolean g_skipmodel; // set true when a cd is not g_only + +// bogus externs for some TA hacks (common/ using them against q3map) +char *moddir = NULL; +// some old defined that was in cmdlib lost during merge +char writedir[1024]; + +#if defined (__linux__) || defined (__APPLE__) +#define strlwr strlower +#endif + +/* +======================================================= + + PAK FILES + +======================================================= +*/ + +typedef struct +{ + char name[56]; + int filepos, filelen; +} packfile_t; + +typedef struct +{ + char id[4]; + int dirofs; + int dirlen; +} packheader_t; + +packfile_t pfiles[16384]; +FILE *pakfile; +packfile_t *pf; +packheader_t pakheader; + +/* +============== +ReleaseFile + +Filename should be gamedir reletive. +Either copies the file to the release dir, or adds it to +the pak file. +============== +*/ +void ReleaseFile (char *filename) +{ + char source[1024]; + char dest[1024]; + + if (!g_release) + return; + + sprintf (source, "%s%s", gamedir, filename); + sprintf (dest, "%s/%s", g_releasedir, filename); + printf ("copying to %s\n", dest); + QCopyFile (source, dest); + return; +} + +typedef struct +{ + // shader + // opaque + // opaque 2 + // blend + // blend 2 + char names[5][1024]; + int num; +} ShaderFiles_t; + +ShaderFiles_t s_shaderFiles; + +void FindShaderFiles( char *filename ) +{ + char buffer[1024]; + char stripped[1024]; + char linebuffer[1024]; + int len, i; + char *buf; + char *diffuseExtensions[] = + { + ".TGA", + ".WAL", + ".PCX", + 0 + }; + char *otherExtensions[] = + { + ".specular.TGA", + ".blend.TGA", + ".alpha.TGA", + 0 + }; + + s_shaderFiles.num = 0; + + strcpy( stripped, filename ); + if ( strrchr( stripped, '.' ) ) + *strrchr( stripped, '.' ) = 0; + strcat( stripped, ".shader" ); + + if ( FileExists( stripped ) ) + { + char *p; + char mapa[512], mapb[512]; + + strcpy( s_shaderFiles.names[s_shaderFiles.num], stripped ); + s_shaderFiles.num++; + + // load and parse + len = LoadFile( stripped, (void **)&buf); + + p = buf; + + while ( p - buf < len ) + { + i = 0; + + // skip spaces + while ( *p == ' ' || *p == '\n' || *p == '\t' ) + p++; + + // grab rest of the line + while ( *p != 0 && *p != '\n' ) + { + linebuffer[i] = *p; + i++; + p++; + } + if ( *p == '\n' ) + p++; + linebuffer[i] = 0; + + strlwr( linebuffer ); + + // see if the line specifies an opaque map or blendmap + if ( strstr( linebuffer, "opaquemap" ) == linebuffer || + strstr( linebuffer, "blendmap" ) == linebuffer ) + { + int j; + + i = 0; + + mapa[0] = mapb[0] = 0; + + // skip past the keyword + while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] ) + i++; + // skip past spaces + while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] ) + i++; + + // grab first map name + j = 0; + while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] ) + { + mapa[j] = linebuffer[i]; + j++; + i++; + } + mapa[j] = 0; + + // skip past spaces + while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] ) + i++; + + // grab second map name + j = 0; + while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] ) + { + mapb[j] = linebuffer[i]; + j++; + i++; + } + mapb[j] = 0; + + // store map names + if ( mapa[0] != 0 && mapa[0] != '-' ) + { + sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapa ); + s_shaderFiles.num++; + } + if ( mapb[0] != 0 && mapb[0] != '-' && mapb[0] != '^' && mapb[0] != '*' ) + { + sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapb ); + s_shaderFiles.num++; + } + } + } + } + else + { + if ( strrchr( stripped, '.' ) ) + *strrchr( stripped, '.' ) = 0; + + // look for diffuse maps + for ( i = 0; i < 3; i++ ) + { + strcpy( buffer, stripped ); + strcat( buffer, diffuseExtensions[i] ); + if ( FileExists( buffer ) ) + { + strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer ); + s_shaderFiles.num++; + break; + } + } + for ( i = 0; i < 3; i++ ) + { + strcpy( buffer, stripped ); + strcat( buffer, otherExtensions[i] ); + if ( FileExists( buffer ) ) + { + strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer ); + s_shaderFiles.num++; + } + } + } +} + +/* +============== +ReleaseShader + +Copies all needed files for a shader to the release directory +============== +*/ +void ReleaseShader( char *filename ) +{ + char fullpath[1024]; + char dest[1024]; + char stripped[1024]; + int i; + + sprintf( fullpath, "%s%s", gamedir, filename ); + + FindShaderFiles( fullpath ); + + for ( i = 0; i < s_shaderFiles.num; i++ ) + { + strcpy( stripped, s_shaderFiles.names[i] ); + if ( strstr( stripped, gamedir ) ) + { + memmove( stripped, stripped+ strlen( gamedir ), strlen( stripped ) ); + } + sprintf( dest, "%s/%s", g_releasedir, stripped ); + printf ("copying to %s\n", dest ); + QCopyFile( s_shaderFiles.names[i], dest ); + } +} + +/* +=============== +Cmd_File + +This is only used to cause a file to be copied during a release +build (default.cfg, maps, etc) +=============== +*/ +void Cmd_File (void) +{ + GetToken (qfalse); + ReleaseFile (token); +} + +/* +=============== +PackDirectory_r + +=============== +*/ +#ifdef _WIN32 +#include "io.h" +void PackDirectory_r (char *dir) +{ + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char filename[1024]; + + sprintf (dirstring, "%s%s/*.*", gamedir, dir); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + do + { + sprintf (filename, "%s/%s", dir, fileinfo.name); + if (fileinfo.attrib & _A_SUBDIR) + { // directory + if (fileinfo.name[0] != '.') // don't pak . and .. + PackDirectory_r (filename); + continue; + } + // copy or pack the file + ReleaseFile (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); +} +#else + +#include +#ifndef WIN32 +#include +#else +#include +#endif + +void PackDirectory_r (char *dir) +{ +#ifdef NeXT + struct direct **namelist, *ent; +#else + struct dirent **namelist, *ent; +#endif + int count; + struct stat st; + int i; + int len; + char fullname[1024]; + char dirstring[1024]; + char *name; + + sprintf (dirstring, "%s%s", gamedir, dir); + count = scandir(dirstring, &namelist, NULL, NULL); + + for (i=0 ; id_name; + + if (name[0] == '.') + continue; + + sprintf (fullname, "%s/%s", dir, name); + sprintf (dirstring, "%s%s/%s", gamedir, dir, name); + + if (stat (dirstring, &st) == -1) + Error ("fstating %s", pf->name); + if (st.st_mode & S_IFDIR) + { // directory + PackDirectory_r (fullname); + continue; + } + + // copy or pack the file + ReleaseFile (fullname); + } +} +#endif + + +/* +=============== +Cmd_Dir + +This is only used to cause a directory to be copied during a +release build (sounds, etc) +=============== +*/ +void Cmd_Dir (void) +{ + GetToken (qfalse); + PackDirectory_r (token); +} + +//======================================================================== + +#define MAX_RTEX 16384 +int numrtex; +char rtex[MAX_RTEX][64]; + +void ReleaseTexture (char *name) +{ + int i; + char path[1024]; + + for (i=0 ; i] [-dump ] [-release ] [-only ] [-3dsconvert ] [-verbose] [file.qdt]"); + + for ( ; i +#include +#include +#include +#include + +#include "../common/cmdlib.h" +#include "scriplib.h" +#include "mathlib.h" +#include "polyset.h" +#include "trilib.h" +#include "imagelib.h" +#include "qthreads.h" +#include "l3dslib.h" +#include "bspfile.h" +#include "p3dlib.h" +#include "3dslib.h" +#include "aselib.h" +#include "md3lib.h" + +void Cmd_ASEConvert( qboolean grabAnims ); +void Cmd_3DSConvert( void ); +void Cmd_Modelname (void); +void Cmd_SpriteBase (void); +void Cmd_Base (void); +void Cmd_Cd (void); +void Cmd_Origin (void); +void Cmd_ScaleUp (void); +void Cmd_Frame (void); +void Cmd_Modelname (void); +void Cmd_SpriteShader(void); +void Cmd_Skin(void); +void Cmd_Skinsize (void); +void FinishModel (int type); + +void Cmd_Grab (void); +void Cmd_Raw (void); +void Cmd_Mip (void); +void Cmd_Environment (void); +void Cmd_Colormap (void); + +void Cmd_File (void); +void Cmd_Dir (void); +void Cmd_StartWad (void); +void Cmd_EndWad (void); +void Cmd_Mippal (void); +void Cmd_Mipdir (void); + +void Cmd_Video (void); + +void ReleaseFile (char *filename); +void ReleaseShader( char *filename ); + +void Convert3DStoMD3( const char *filename ); + +void OrderMesh( int input[][3], int output[][3], int numTris ); + +extern byte *byteimage, *lbmpalette; +extern int byteimagewidth, byteimageheight; + +extern qboolean g_release; // don't grab, copy output data to new tree +extern char g_releasedir[1024]; // c:\quake2\baseq2, etc +extern qboolean g_archive; // don't grab, copy source data to new tree +extern qboolean do3ds; +extern char g_only[256]; // if set, only grab this cd +extern qboolean g_skipmodel; // set true when a cd is not g_only +extern qboolean g_verbose; + +extern char *trifileext; + +#define TYPE_ITEM 0 +#define TYPE_PLAYER 1 +#define TYPE_WEAPON 2 +#define TYPE_HAND 3 +#define TYPE_UNKNOWN 4 diff --git a/tools/quake3/q3data/q3data.vcproj b/tools/quake3/q3data/q3data.vcproj new file mode 100644 index 00000000..70e5a465 --- /dev/null +++ b/tools/quake3/q3data/q3data.vcproj @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/quake3/q3data/stripper.c b/tools/quake3/q3data/stripper.c new file mode 100644 index 00000000..8229aba3 --- /dev/null +++ b/tools/quake3/q3data/stripper.c @@ -0,0 +1,282 @@ +#include +#include +#include + +static int s_used[8192]; // same as MD3_MAX_TRIANGLES + +/* +** FindNextTriangleInStrip +** +** Given a surface and triangle this tries to find the next triangle +** in the strip that would continue the strip. The next triangle in +** the strip should have the same winding as this triangle. +*/ +static int FindNextTriangleInStripOrFan( int mesh[][3], int tri, int orientation, int numTris, int odd ) +{ + int t; + int sum = 0; + int currentTri[3]; + int side; + int a, b, c; + int refa, refb; + + currentTri[0] = mesh[tri][(0+orientation)%3]; + currentTri[1] = mesh[tri][(1+orientation)%3]; + currentTri[2] = mesh[tri][(2+orientation)%3]; + + if ( odd ) + { + refa = currentTri[1]; + refb = currentTri[2]; + } + else + { + refa = currentTri[2]; + refb = currentTri[0]; + } + + // go through all triangles and look for sides that match + // this triangle's + for ( t = 0; t < numTris; t++ ) + { + // don't check against self or against previously used triangles + if ( t == tri ) + continue; + if ( s_used[t] ) + continue; + + // check all three sides of the candidate triangle + for ( side = 0; side < 3; side++ ) + { + // check only the second (abutting) side + if ( ( refa == mesh[t][(side+1)%3] ) && + ( refb == mesh[t][side] ) ) + { + + a = mesh[t][0]; + b = mesh[t][1]; + c = mesh[t][2]; + + // rotate the candidate triangle to align it properly in the strip + if ( side == 1 ) + { + mesh[t][0] = b; + mesh[t][1] = c; + mesh[t][2] = a; + } + else if ( side == 2 ) + { + mesh[t][0] = c; + mesh[t][1] = a; + mesh[t][2] = b; + } + + return t; + } +/* + else + { + Error( "fans not implemented yet" ); + + // check only the third (abutting) side + if ( ( currentTri[2] == pSurf->baseTriangles[t].v[side].index ) && + ( currentTri[0] == pSurf->baseTriangles[t].v[(side+1)%3].index ) ) + { + return t; + } + } +*/ + } + } + + return -1; +} + +/* +** StripLength +*/ +static int StripLength( int mesh[][3], int strip[][3], int tri, int orientation, int numInputTris, int fillNo ) +{ + int stripIndex = 0; + int next; + + int odd = 1; + + strip[stripIndex][0] = mesh[tri][(0+orientation)%3]; + strip[stripIndex][1] = mesh[tri][(1+orientation)%3]; + strip[stripIndex][2] = mesh[tri][(2+orientation)%3]; + s_used[tri] = fillNo; + stripIndex++; + + next = tri; + + while ( ( next = FindNextTriangleInStripOrFan( mesh, next, orientation, numInputTris, odd ) ) != -1 ) + { + s_used[next] = fillNo; + odd = !odd; + strip[stripIndex][0] = mesh[next][0]; + strip[stripIndex][1] = mesh[next][1]; + strip[stripIndex][2] = mesh[next][2]; + stripIndex++; + + // all iterations after first need to be with an unrotated reference triangle + orientation = 0; + } + + return stripIndex; +} + +/* +** BuildOptimizedList +** +** Attempts to build the longest strip/fan possible. Does not adhere +** to pure strip or fan, will intermix between the two so long as some +** type of connectivity can be maintained. +*/ +#define MAX_ORIENTATIONS 3 +#define MAX_MATCHED_SIDES 4 +#define MAX_SEED_TRIANGLES 16 + +static int BuildOptimizedList( int mesh[][3], int strip[][3], int numInputTris ) +{ + int t; + int stripLen = 0; + int startTri = -1; + int bestTri = -1, bestLength = 0, bestOrientation = -1; + int matchedSides = 0; + int orientation = 0; + int seedTriangles[MAX_MATCHED_SIDES][MAX_SEED_TRIANGLES]; + int seedLengths[MAX_ORIENTATIONS][MAX_MATCHED_SIDES][MAX_SEED_TRIANGLES]; + int numSeeds[MAX_MATCHED_SIDES] = { 0, 0, 0 }; + int i; + + // build a ranked list of candidate seed triangles based on + // number of offshoot strips. Precedence goes to orphans, + // then corners, then edges, and interiors. + memset( seedTriangles, 0xff, sizeof( seedTriangles ) ); + memset( seedLengths, 0xff, sizeof( seedLengths ) ); + + for ( i = 0; i < MAX_MATCHED_SIDES; i++ ) + { + // find the triangle with lowest number of child strips + for ( t = 0; t < numInputTris; t++ ) + { + int orientation; + int n; + + if ( s_used[t] ) + continue; + + // try the candidate triangle in three different orientations + matchedSides = 0; + for ( orientation = 0; orientation < 3; orientation++ ) + { + if ( ( n = FindNextTriangleInStripOrFan( mesh, t, orientation, numInputTris, 1 ) ) != -1 ) + { + matchedSides++; + } + } + + if ( matchedSides == i ) + { + seedTriangles[i][numSeeds[i]] = t; + numSeeds[i]++; + if ( numSeeds[i] == MAX_SEED_TRIANGLES ) + break; + } + } + } + + // we have a list of potential seed triangles, so we now go through each + // potential candidate and look to see which produces the longest strip + // and select our startTri based on this + for ( i = 0; i < MAX_MATCHED_SIDES; i++ ) + { + int j; + + for ( j = 0; j < numSeeds[i]; j++ ) + { + for ( orientation = 0; orientation < 3; orientation++ ) + { + int k; + + seedLengths[orientation][i][j] = StripLength( mesh, strip, seedTriangles[i][j], orientation, numInputTris, 2 ); + + if ( seedLengths[orientation][i][j] > bestLength ) + { + bestTri = seedTriangles[i][j]; + bestLength = seedLengths[orientation][i][j]; + bestOrientation = orientation; + } + + for ( k = 0; k < numInputTris; k++ ) + { + if ( s_used[k] == 2 ) + s_used[k] = 0; + } + } + } + + if ( bestTri != -1 ) + { + break; + } + } + + // build the strip for real + if ( bestTri != -1 ) + { + stripLen = StripLength( mesh, strip, bestTri, bestOrientation, numInputTris, 1 ); + } + + return stripLen; +} + +/* +** OrderMesh +** +** Given an input mesh and an output mesh, this routine will reorder +** the triangles within the mesh into strips/fans. +*/ +void OrderMesh( int input[][3], int output[][3], int numTris ) +{ + int i; + int sumStrippedTriangles = 0; + int strippedTriangles; + int totalStrips = 0; + int strip[8192][3]; // could dump directly into 'output', but + // this helps with debugging + + memset( s_used, 0, sizeof( s_used ) ); + +#if 0 + FILE *fp = fopen( "strip.txt", "wt" ); + + for ( i = 0; i < numTris; i++ ) + { + fprintf( fp, "%4d: %3d %3d %3d\n", i, input[i][0], input[i][1], input[i][2] ); + } + fclose( fp ); +#endif + + // while there are still triangles that are not part of a strip + while ( sumStrippedTriangles < numTris ) + { + // build a strip + strippedTriangles = BuildOptimizedList( input, strip, numTris ); + + for ( i = 0; i < strippedTriangles; i++ ) + { + output[sumStrippedTriangles+i][0] = strip[i][0]; + output[sumStrippedTriangles+i][1] = strip[i][1]; + output[sumStrippedTriangles+i][2] = strip[i][2]; + } + + sumStrippedTriangles += strippedTriangles; + totalStrips++; + } + + printf( "Triangles on surface: %d\n", sumStrippedTriangles ); + printf( "Total strips from surface: %d\n", totalStrips ); + printf( "Average strip length: %f\n", ( float ) sumStrippedTriangles / totalStrips ); +} diff --git a/tools/quake3/q3data/video.c b/tools/quake3/q3data/video.c new file mode 100644 index 00000000..35e097bf --- /dev/null +++ b/tools/quake3/q3data/video.c @@ -0,0 +1,1132 @@ +#include +#include "q3data.h" + +static int s_resample_width = 256; +static int s_resample_height = 256; + +#define OUTPUT_TGAS 1 + +#define UNCOMPRESSED 0 +#define BTC_COMPRESSION 1 + +static int s_compression_method = BTC_COMPRESSION; + +static const char *CIN_EXTENSION = "cn2"; +static const int CIN_SIGNATURE = ( 'C' << 24 ) | ( 'I' << 16 ) | ( 'N' << 8 ) | ( '2' ); + +static byte *s_soundtrack; +static char s_base[32]; +static char s_output_base[32]; + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + + +static int s_samplecounts[0x10000]; +static wavinfo_t s_wavinfo; + +short GetLittleShort(void) +{ + short val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + data_p += 2; + return val; +} + +int GetLittleLong(void) +{ + int val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + val = val + (*(data_p+2)<<16); + val = val + (*(data_p+3)<<24); + data_p += 4; + return val; +} + +void FindNextChunk(char *name) +{ + while (1) + { + data_p=last_chunk; + + if (data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = GetLittleLong(); + if (iff_chunk_len < 0) + { + data_p = NULL; + return; + } +// if (iff_chunk_len > 1024*1024) +// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); + data_p -= 8; + last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); + if (!strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p=iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = GetLittleLong(); + printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } while (data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset (&info, 0, sizeof(info)); + + if (!wav) + return info; + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !strncmp(data_p+8, "WAVE", 4))) + { + printf("Missing RIFF/WAVE chunks\n"); + return info; + } + +// get "fmt " chunk + iff_data = data_p + 12; +// DumpChunks (); + + FindChunk("fmt "); + if (!data_p) + { + printf("Missing fmt chunk\n"); + return info; + } + data_p += 8; + format = GetLittleShort(); + if (format != 1) + { + printf("Microsoft PCM format only\n"); + return info; + } + + info.channels = GetLittleShort(); + info.rate = GetLittleLong(); + data_p += 4+2; + info.width = GetLittleShort() / 8; + +// get cue chunk + FindChunk("cue "); + if (data_p) + { + data_p += 32; + info.loopstart = GetLittleLong(); +// Com_Printf("loopstart=%d\n", sfx->loopstart); + + // if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if (data_p) + { + if (!strncmp (data_p + 28, "mark", 4)) + { // this is not a proper parse, but it works with cooledit... + data_p += 24; + i = GetLittleLong (); // samples in loop + info.samples = info.loopstart + i; + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = GetLittleLong (); + + if (info.samples) + { + if (samples < info.samples) + Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + + return info; +} + +//===================================================================== + +/* +============== +LoadSoundtrack +============== +*/ +void LoadSoundtrack (void) +{ + char name[1024]; + FILE *f; + int len; + int i, val, j; + + s_soundtrack = NULL; + sprintf (name, "%svideo/%s/%s.wav", gamedir, s_base, s_base); + printf ("WAV: %s\n", name); + f = fopen (name, "rb"); + if (!f) + { + printf ("no soundtrack for %s\n", s_base); + return; + } + len = Q_filelength(f); + s_soundtrack = malloc(len); + fread (s_soundtrack, 1, len, f); + fclose (f); + + s_wavinfo = GetWavinfo (name, s_soundtrack, len); + + // count samples for compression + memset (s_samplecounts, 0, sizeof(s_samplecounts)); + + j = s_wavinfo.samples/2; + for (i=0 ; i s_wavinfo.samples || !s_soundtrack) + fwrite (&empty, 1, width, output); + else + fwrite (s_soundtrack + s_wavinfo.dataofs + sample*width, 1, width,output); + } +} + +//========================================================================== + +static float s_resampleXRatio; +static float s_resampleYRatio; + +static void BoxFilterHorizontalElements( unsigned char *dst, unsigned char *src, float s0, float s1 ) +{ + float w; + float rSum = 0, gSum = 0, bSum = 0; + float x = s0; + float sumWeight = 0; + + for ( x = s0; x < s1; x++, src += 4 ) + { + if ( x == s0 ) + { + w = ( int ) ( s0 + 1 ) - x; + } + else if ( x + 1 >= s1 ) + { + w = s1 - ( int ) x; + } + else + { + w = 1.0f; + } + + rSum += src[0] * w; + gSum += src[1] * w; + bSum += src[2] * w; + sumWeight += w; + } + + rSum /= sumWeight; + gSum /= sumWeight; + bSum /= sumWeight; + + dst[0] = ( unsigned char ) ( rSum + 0.5 ); + dst[1] = ( unsigned char ) ( gSum + 0.5 ); + dst[2] = ( unsigned char ) ( bSum + 0.5 ); +} + +static void BoxFilterVerticalElements( unsigned char *dst, // destination of the filter process + unsigned char *src, // source pixels + int srcStep, // stride of the source pixels + float s0, float s1 ) +{ + float w; + float rSum = 0, gSum = 0, bSum = 0; + float y = s0; + float sumWeight = 0; + + for ( y = s0; y < ( int ) ( s1 + 1 ) ; y++, src += srcStep ) + { + if ( y == s0 ) + { + w = ( int ) ( s0 + 1 ) - y; + } + else if ( y + 1 >= s1 ) + { + w = s1 - ( int ) y; + } + else + { + w = 1.0f; + } + + rSum += src[0] * w; + gSum += src[1] * w; + bSum += src[2] * w; + sumWeight += w; + } + + rSum /= sumWeight; + gSum /= sumWeight; + bSum /= sumWeight; + + dst[0] = ( unsigned char ) ( rSum + 0.5 ); + dst[1] = ( unsigned char ) ( gSum + 0.5 ); + dst[2] = ( unsigned char ) ( bSum + 0.5 ); + dst[3] = 0xff; + +} + +static void BoxFilterRow( unsigned char *dstStart, cblock_t *in, int dstRow, int rowWidth ) +{ + int i; + unsigned char *indata = ( unsigned char * ) in->data; + + indata += 4 * dstRow * in->width; + + for ( i = 0; i < rowWidth; i++ ) + { + float c0 = i * s_resampleXRatio; + float c1 = ( i + 1 ) * s_resampleXRatio; + + BoxFilterHorizontalElements( &dstStart[i*4], &indata[( ( int ) c0 ) * 4], c0, c1 ); + } +} + +static void BoxFilterColumn( unsigned char *dstStart, unsigned char *srcStart, int dstCol, int dstRowWidth, int dstColHeight, int srcRowWidthInPels ) +{ + float c0, c1; + int i; + + for ( i = 0; i < dstColHeight; i++ ) + { + c0 = i * s_resampleYRatio; + c1 = ( i + 1 ) * s_resampleYRatio; + + BoxFilterVerticalElements( &dstStart[i*4*dstRowWidth], &srcStart[(int)c0*srcRowWidthInPels*4], srcRowWidthInPels*4, c0, c1 ); + } +} + +#define DROP_SAMPLE 0 +#define BOX_FILTER 1 + +static void ResampleFrame( cblock_t *in, unsigned char *out, int method, int outWidth, int outHeight ) +{ + int row, column; + unsigned char *indata = ( unsigned char * ) in->data; + + s_resampleXRatio = in->width / ( float ) outWidth; + s_resampleYRatio = in->height / ( float ) outHeight; + + if ( method == DROP_SAMPLE ) + { + for ( row = 0; row < outHeight; row++ ) + { + int r = ( int ) ( row * s_resampleYRatio ); + + for ( column = 0; column < outWidth; column++ ) + { + int c = ( int ) ( column * s_resampleXRatio ); + + out[(row*outWidth+column)*4+0] = indata[(r*in->width+c)*4+0]; + out[(row*outWidth+column)*4+1] = indata[(r*in->width+c)*4+1]; + out[(row*outWidth+column)*4+2] = indata[(r*in->width+c)*4+2]; + out[(row*outWidth+column)*4+3] = 0xff; + } + } + } + else if ( method == BOX_FILTER ) + { + unsigned char intermediate[1024*1024*4]; + + assert( in->height <= 1024 ); + assert( in->width <= 1024 ); + + // + // filter our M x N source image into a RESAMPLE_WIDTH x N horizontally filtered image + // + for ( row = 0; row < in->height; row++ ) + { + BoxFilterRow( &intermediate[row*4*outWidth], in, row, outWidth ); + } + + // + // filter our RESAMPLE_WIDTH x N horizontally filtered image into a RESAMPLE_WIDTH x RESAMPLE_HEIGHT filtered image + // + for ( column = 0; column < outWidth; column++ ) + { + BoxFilterColumn( &out[column*4], &intermediate[column*4], column, outWidth, outHeight, s_resample_width ); + } + } +} + +static float BTCDistanceSquared( float a[3], float b[3] ) +{ + return ( b[0] - a[0] ) * ( b[0] - a[0] ) + + ( b[1] - a[1] ) * ( b[1] - a[1] ) + + ( b[2] - a[2] ) * ( b[2] - a[2] ); +} + +static void BTCFindEndpoints( float inBlock[4][4][3], unsigned int endPoints[2][2] ) +{ + float longestDistance = -1; + + int bX, bY; + + // + // find the two points farthest from each other + // + for ( bY = 0; bY < 4; bY++ ) + { + for ( bX = 0; bX < 4; bX++ ) + { + int cX, cY; + float d; + + // + // check the rest of the current row + // + for ( cX = bX + 1; cX < 4; cX++ ) + { + if ( ( d = BTCDistanceSquared( inBlock[bY][bX], inBlock[bY][cX] ) ) > longestDistance ) + { + longestDistance = d; + endPoints[0][0] = bX; + endPoints[0][1] = bY; + endPoints[1][0] = cX; + endPoints[1][1] = bY; + } + } + + // + // check remaining rows and columns + // + for ( cY = bY+1; cY < 4; cY++ ) + { + for ( cX = 0; cX < 4; cX++ ) + { + if ( ( d = BTCDistanceSquared( inBlock[bY][bX], inBlock[cY][cX] ) ) > longestDistance ) + { + longestDistance = d; + endPoints[0][0] = bX; + endPoints[0][1] = bY; + endPoints[1][0] = cX; + endPoints[1][1] = cY; + } + } + } + } + } +} + +static float BTCQuantizeBlock( float inBlock[4][4][3], unsigned long endPoints[2][2], int btcQuantizedBlock[4][4], float bestError ) +{ + int i; + int blockY, blockX; + float dR, dG, dB; + float R, G, B; + float error = 0; + float colorLine[4][3]; + + // + // build the color line + // + dR = inBlock[endPoints[1][1]][endPoints[1][0]][0] - + inBlock[endPoints[0][1]][endPoints[0][0]][0]; + dG = inBlock[endPoints[1][1]][endPoints[1][0]][1] - + inBlock[endPoints[0][1]][endPoints[0][0]][1]; + dB = inBlock[endPoints[1][1]][endPoints[1][0]][2] - + inBlock[endPoints[0][1]][endPoints[0][0]][2]; + + dR *= 0.33f; + dG *= 0.33f; + dB *= 0.33f; + + R = inBlock[endPoints[0][1]][endPoints[0][0]][0]; + G = inBlock[endPoints[0][1]][endPoints[0][0]][1]; + B = inBlock[endPoints[0][1]][endPoints[0][0]][2]; + + for ( i = 0; i < 4; i++ ) + { + colorLine[i][0] = R; + colorLine[i][1] = G; + colorLine[i][2] = B; + + R += dR; + G += dG; + B += dB; + } + + // + // quantize each pixel into the appropriate range + // + for ( blockY = 0; blockY < 4; blockY++ ) + { + for ( blockX = 0; blockX < 4; blockX++ ) + { + float distance = 10000000000; + int shortest = -1; + + for ( i = 0; i < 4; i++ ) + { + float d; + + if ( ( d = BTCDistanceSquared( inBlock[blockY][blockX], colorLine[i] ) ) < distance ) + { + distance = d; + shortest = i; + } + } + + error += distance; + + // + // if bestError is not -1 then that means this is a speculative quantization + // + if ( bestError != -1 ) + { + if ( error > bestError ) + return error; + } + + btcQuantizedBlock[blockY][blockX] = shortest; + } + } + + return error; +} + +/* +** float BTCCompressBlock +*/ +static float BTCCompressBlock( float inBlock[4][4][3], unsigned long out[2] ) +{ + int i; + int btcQuantizedBlock[4][4]; // values should be [0..3] + unsigned long encodedEndPoints, encodedBitmap; + unsigned int endPoints[2][2]; // endPoints[0] = color start, endPoints[1] = color end + int blockY, blockX; + float error = 0; + float bestError = 10000000000; + unsigned int bestEndPoints[2][2]; + +#if 0 + // + // find the "ideal" end points for the color vector + // + BTCFindEndpoints( inBlock, endPoints ); + error = BTCQuantizeBlock( inBlock, endPoints, btcQuantizedBlock ); + memcpy( bestEndPoints, endPoints, sizeof( bestEndPoints ) ); +#else + for ( blockY = 0; blockY < 4; blockY++ ) + { + for ( blockX = 0; blockX < 4; blockX++ ) + { + int x2, y2; + + for ( y2 = 0; y2 < 4; y2++ ) + { + for ( x2 = 0; x2 < 4; x2++ ) + { + if ( ( x2 == blockX ) && ( y2 == blockY ) ) + continue; + + endPoints[0][0] = blockX; + endPoints[0][1] = blockY; + endPoints[1][0] = x2; + endPoints[1][1] = y2; + + error = BTCQuantizeBlock( inBlock, endPoints, btcQuantizedBlock, -1 ); //bestError ); + + if ( error < bestError ) + { + bestError = error; + memcpy( bestEndPoints, endPoints, sizeof( bestEndPoints ) ); + } + } + } + } + } + + error = BTCQuantizeBlock( inBlock, bestEndPoints, btcQuantizedBlock, -1.0f ); +#endif + + // + // encode the results + // + encodedBitmap = 0; + for ( blockY = 0; blockY < 4; blockY++ ) + { + for ( blockX = 0; blockX < 4; blockX++ ) + { + int shift = ( blockX + blockY * 4 ) * 2; + encodedBitmap |= btcQuantizedBlock[blockY][blockX] << shift; + } + } + + // + // encode endpoints + // + encodedEndPoints = 0; + for ( i = 0; i < 2; i++ ) + { + int iR, iG, iB; + + iR = ( ( int ) inBlock[bestEndPoints[i][1]][bestEndPoints[i][0]][0] ); + if ( iR > 255 ) + iR = 255; + else if ( iR < 0 ) + iR = 0; + iR >>= 3; + + iG = ( ( int ) inBlock[bestEndPoints[i][1]][bestEndPoints[i][0]][1] ); + if ( iG > 255 ) + iG = 255; + else if ( iG < 0 ) + iG = 0; + iG >>= 2; + + iB = ( ( int ) inBlock[bestEndPoints[i][1]][bestEndPoints[i][0]][2] ); + if ( iB > 255 ) + iB = 255; + else if ( iB < 0 ) + iB = 0; + iB >>= 3; + + + encodedEndPoints |= ( ( ( iR << 11 ) | ( iG << 5 ) | ( iB ) ) << ( i * 16 ) ); + } + + // + // store + // + out[0] = encodedBitmap; + out[1] = encodedEndPoints; + + return error; +} + +/* +** void BTCDecompressFrame +*/ +static void BTCDecompressFrame( unsigned long *src, unsigned char *dst ) +{ + int x, y; + int iR, iG, iB; + int dstX, dstY; + float colorStart[3], colorEnd[3]; + unsigned char colorRampABGR[4][4]; + unsigned encoded; + + memset( colorRampABGR, 0xff, sizeof( colorRampABGR ) ); + + for ( y = 0; y < s_resample_height / 4; y++ ) + { + for ( x = 0; x < s_resample_width / 4; x++ ) + { + unsigned colorStartPacked = src[(y*s_resample_width/4 + x)*2 + 1] & 0xffff; + unsigned colorEndPacked = src[(y*s_resample_width/4 + x)*2 + 1] >> 16; + + // + // grab the end points + // 0 = color start + // 1 = color end + // + iR = ( ( colorStartPacked >> 11 ) & ( ( 1 << 5 ) - 1 ) ); + iR = ( iR << 3 ) | ( iR >> 2 ); + iG = ( ( colorStartPacked >> 5 ) & ( ( 1 << 6 ) - 1 ) ); + iG = ( iG << 2 ) | ( iG >> 4 ); + iB = ( ( colorStartPacked ) & ( ( 1 << 5 ) - 1 ) ); + iB = ( iB << 3 ) | ( iB >> 2 ); + + colorStart[0] = iR; + colorStart[1] = iG; + colorStart[2] = iB; + colorRampABGR[0][0] = iR; + colorRampABGR[0][1] = iG; + colorRampABGR[0][2] = iB; + + iR = ( ( colorEndPacked >> 11 ) & ( ( 1 << 5 ) - 1 ) ); + iR = ( iR << 3 ) | ( iR >> 2 ); + iG = ( ( colorEndPacked >> 5 ) & ( ( 1 << 6 ) - 1 ) ); + iG = ( iG << 2 ) | ( iG >> 4 ); + iB = ( colorEndPacked & ( ( 1 << 5 ) - 1 ) ); + iB = ( iB << 3 ) | ( iB >> 2 ); + + colorEnd[0] = iR; + colorEnd[1] = iG; + colorEnd[2] = iB; + colorRampABGR[3][0] = iR; + colorRampABGR[3][1] = iG; + colorRampABGR[3][2] = iB; + + // + // compute this block's color ramp + // FIXME: This needs to be reversed on big-endian machines + // + + colorRampABGR[1][0] = colorStart[0] * 0.66f + colorEnd[0] * 0.33f; + colorRampABGR[1][1] = colorStart[1] * 0.66f + colorEnd[1] * 0.33f; + colorRampABGR[1][2] = colorStart[2] * 0.66f + colorEnd[2] * 0.33f; + + colorRampABGR[2][0] = colorStart[0] * 0.33f + colorEnd[0] * 0.66f; + colorRampABGR[2][1] = colorStart[1] * 0.33f + colorEnd[1] * 0.66f; + colorRampABGR[2][2] = colorStart[2] * 0.33f + colorEnd[2] * 0.66f; + + // + // decode the color data + // information is encoded in 2-bit pixels, with low order bits corresponding + // to upper left pixels. These 2-bit values are indexed into the block's + // computer color ramp. + // + encoded = src[(y*s_resample_width/4 + x)*2 + 0]; + + for ( dstY = 0; dstY < 4; dstY++ ) + { + for ( dstX = 0; dstX < 4; dstX++ ) + { + memcpy( &dst[(y*4+dstY)*s_resample_width*4+x*4*4+dstX*4], colorRampABGR[encoded&3], sizeof( colorRampABGR[0] ) ); + encoded >>= 2; + } + } + } + } +} + +/* +** BTCCompressFrame +** +** Perform a BTC compression using a 2-bit encoding at each pixel. This +** compression method is performed by decomposing the incoming image into +** a sequence of 4x4 blocks. At each block two color values are computed +** that define the endpoints of a vector in color space that represent +** the two colors "farthest apart". +*/ +static float BTCCompressFrame( unsigned char *src, unsigned long *dst ) +{ + int x, y; + int bX, bY; + float btcBlock[4][4][3]; + + float error = 0; + + for ( y = 0; y < s_resample_height / 4; y++ ) + { + for ( x = 0; x < s_resample_width / 4; x++ ) + { + // + // fill in the BTC block with raw values + // + for ( bY = 0; bY < 4; bY++ ) + { + for ( bX = 0; bX < 4; bX++ ) + { + btcBlock[bY][bX][0] = src[(y*4+bY)*s_resample_width*4 + (x*4+bX)*4 + 0]; + btcBlock[bY][bX][1] = src[(y*4+bY)*s_resample_width*4 + (x*4+bX)*4 + 1]; + btcBlock[bY][bX][2] = src[(y*4+bY)*s_resample_width*4 + (x*4+bX)*4 + 2]; + } + } + + error += BTCCompressBlock( btcBlock, &dst[(y*s_resample_width/4+x)*2] ); + } + } + + return error / ( ( s_resample_width / 4 ) * ( s_resample_height / 4 ) ); +} + +/* +=================== +LoadFrame +=================== +*/ +cblock_t LoadFrame (char *base, int frame, int digits, byte **palette) +{ + int ten3, ten2, ten1, ten0; + cblock_t in; + int width, height; + char name[1024]; + FILE *f; + + in.data = NULL; + in.count = -1; + + ten3 = frame/1000; + ten2 = (frame-ten3*1000)/100; + ten1 = (frame-ten3*1000-ten2*100)/10; + ten0 = frame%10; + + if (digits == 4) + sprintf (name, "%svideo/%s/%s%i%i%i%i.tga", gamedir, base, base, ten3, ten2, ten1, ten0); + else + sprintf (name, "%svideo/%s/%s%i%i%i.tga", gamedir, base, base, ten2, ten1, ten0); + + f = fopen(name, "rb"); + if (!f) + { + in.data = NULL; + return in; + } + fclose (f); + + printf ("%s", name); + LoadTGA( name, ( unsigned char ** ) &in.data, &width, &height ); + if ( palette ) + *palette = 0; +// Load256Image (name, &in.data, palette, &width, &height); + in.count = width*height; + in.width = width; + in.height = height; +// FIXME: map 0 and 255! + +#if 0 + // rle compress + rle = RLE(in); + free (in.data); + + return rle; +#endif + + return in; +} + +/* +=============== +Cmd_Video + +video +=============== +*/ +void Cmd_Video (void) +{ + float sumError = 0, error = 0, maxError = 0; + char savename[1024]; + char name[1024]; + FILE *output; + int startframe, frame; + int width, height; + int i; + int digits; + int minutes; + float fseconds; + int remSeconds; + cblock_t in; + unsigned char *resampled; + unsigned long *compressed; + clock_t start, stop; + + GetToken (qfalse); + strcpy (s_base, token); + if (g_release) + { +// sprintf (savename, "video/%s.cin", token); +// ReleaseFile (savename); + return; + } + + GetToken( qfalse ); + strcpy( s_output_base, token ); + + GetToken (qfalse); + digits = atoi(token); + + GetToken( qfalse ); + + if ( !strcmp( token, "btc" ) ) + { + s_compression_method = BTC_COMPRESSION; + printf( "Compression: BTC\n" ); + } + else if ( !strcmp( token, "uc" ) ) + { + s_compression_method = UNCOMPRESSED; + printf( "Compression: none\n" ); + } + else + { + Error( "Uknown compression method '%s'\n", token ); + } + + GetToken( qfalse ); + s_resample_width = atoi( token ); + + GetToken( qfalse ); + s_resample_height = atoi( token ); + + resampled = malloc( sizeof( unsigned char ) * 4 * s_resample_width * s_resample_height ); + compressed = malloc( sizeof( long ) * 2 * ( s_resample_width / 4 ) * ( s_resample_height / 4 ) ); + + printf( "Resample width: %d\n", s_resample_width ); + printf( "Resample height: %d\n", s_resample_height ); + + // optionally skip frames + if (TokenAvailable ()) + { + GetToken (qfalse); + startframe = atoi(token); + } + else + startframe=0; + + sprintf (savename, "%svideo/%s.%s", writedir, s_output_base, CIN_EXTENSION ); + + // load the entire sound wav file if present + LoadSoundtrack (); + + if (digits == 4) + sprintf (name, "%svideo/%s/%s0000.tga", gamedir, s_base, s_base); + else + sprintf (name, "%svideo/%s/%s000.tga", gamedir, s_base, s_base); + + printf ("%s\n", name); + LoadTGA( name, NULL, &width, &height); + + output = fopen (savename, "wb"); + if (!output) + Error ("Can't open %s", savename); + + // write header info + i = LittleLong( CIN_SIGNATURE ); + fwrite (&i, 4, 1, output ); + i = LittleLong (s_resample_width); + fwrite (&i, 4, 1, output); + i = LittleLong (s_resample_height); + fwrite (&i, 4, 1, output); + i = LittleLong (s_wavinfo.rate); + fwrite (&i, 4, 1, output); + i = LittleLong (s_wavinfo.width); + fwrite (&i, 4, 1, output); + i = LittleLong (s_wavinfo.channels); + fwrite (&i, 4, 1, output); + i = LittleLong ( s_compression_method ); + fwrite (&i, 4, 1, output ); + + start = clock(); + + // perform compression on a per frame basis + for ( frame=startframe ; ; frame++) + { + printf ("%02d: ", frame); + in = LoadFrame (s_base, frame, digits, 0 ); + if (!in.data) + break; + + ResampleFrame( &in, ( unsigned char * ) resampled, BOX_FILTER, s_resample_width, s_resample_height ); + + if ( s_compression_method == UNCOMPRESSED ) + { + printf( "\n" ); + fwrite( resampled, 1, sizeof( unsigned char ) * s_resample_width * s_resample_height * 4, output ); + +#if OUTPUT_TGAS + { + int x, y; + char buffer[1000]; + + for ( y = 0; y < s_resample_height/2; y++ ) + { + for ( x = 0; x < s_resample_width; x++ ) + { + unsigned char tmp[4]; + + tmp[0] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0]; + tmp[1] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1]; + tmp[2] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2]; + tmp[3] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3]; + + resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0] = resampled[y*s_resample_width*4 + x*4 + 0]; + resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1] = resampled[y*s_resample_width*4 + x*4 + 1]; + resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2] = resampled[y*s_resample_width*4 + x*4 + 2]; + resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3] = resampled[y*s_resample_width*4 + x*4 + 3]; + + resampled[y*s_resample_width*4 + x*4 + 0] = tmp[0]; + resampled[y*s_resample_width*4 + x*4 + 1] = tmp[1]; + resampled[y*s_resample_width*4 + x*4 + 2] = tmp[2]; + resampled[y*s_resample_width*4 + x*4 + 3] = tmp[3]; + } + } + + sprintf( buffer, "%svideo/%s/uc%04d.tga", gamedir, s_base, frame ); + WriteTGA( buffer, resampled, s_resample_width, s_resample_height ); + } +#endif + } + else if ( s_compression_method == BTC_COMPRESSION ) + { + error = BTCCompressFrame( resampled, compressed ); + + sumError += error; + + if ( error > maxError ) + maxError = error; + + printf( " (error = %f)\n", error ); + fwrite( compressed, 1, 2 * sizeof( long ) * ( s_resample_width / 4 ) * ( s_resample_height / 4 ), output ); + +#if OUTPUT_TGAS + { + int x, y; + unsigned char *uncompressed; + char buffer[1000]; + + uncompressed = malloc( sizeof( unsigned char ) * 4 * s_resample_width * s_resample_height ); + BTCDecompressFrame( compressed, uncompressed ); + + for ( y = 0; y < s_resample_height/2; y++ ) + { + for ( x = 0; x < s_resample_width; x++ ) + { + unsigned char tmp[4]; + + tmp[0] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0]; + tmp[1] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1]; + tmp[2] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2]; + tmp[3] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3]; + + uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0] = uncompressed[y*s_resample_width*4 + x*4 + 0]; + uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1] = uncompressed[y*s_resample_width*4 + x*4 + 1]; + uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2] = uncompressed[y*s_resample_width*4 + x*4 + 2]; + uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3] = uncompressed[y*s_resample_width*4 + x*4 + 3]; + + uncompressed[y*s_resample_width*4 + x*4 + 0] = tmp[0]; + uncompressed[y*s_resample_width*4 + x*4 + 1] = tmp[1]; + uncompressed[y*s_resample_width*4 + x*4 + 2] = tmp[2]; + uncompressed[y*s_resample_width*4 + x*4 + 3] = tmp[3]; + } + } + + + sprintf( buffer, "%svideo/%s/btc%04d.tga", gamedir, s_base, frame ); + WriteTGA( buffer, uncompressed, s_resample_width, s_resample_height ); + + free( uncompressed ); + } +#endif + } + + WriteSound( output, frame ); + + free (in.data); + } + stop = clock(); + + printf ("\n"); + + printf ("Total size: %i\n", ftell( output ) ); + printf ("Average error: %f\n", sumError / ( frame - startframe ) ); + printf ("Max error: %f\n", maxError ); + + fseconds = ( stop - start ) / 1000.0f; + minutes = fseconds / 60; + remSeconds = fseconds - minutes * 60; + + printf ("Total time: %d s (%d m %d s)\n", ( int ) fseconds, minutes, remSeconds ); + printf ("Time/frame: %.2f seconds\n", fseconds / ( frame - startframe ) ); + + fclose (output); + + if ( s_soundtrack ) + { + free( s_soundtrack ); + s_soundtrack = 0; + } +} diff --git a/tools/quake3/q3map2/.cvsignore b/tools/quake3/q3map2/.cvsignore new file mode 100644 index 00000000..e70c49e1 --- /dev/null +++ b/tools/quake3/q3map2/.cvsignore @@ -0,0 +1,12 @@ +q3map +*.d +*.o +*.bak +*.BAK +*~ +*.ncb +*.plg +*.opt +*.log +Debug +Release diff --git a/tools/quake3/q3map2/brush.c b/tools/quake3/q3map2/brush.c new file mode 100644 index 00000000..eebc097f --- /dev/null +++ b/tools/quake3/q3map2/brush.c @@ -0,0 +1,982 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define BRUSH_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* ------------------------------------------------------------------------------- + +functions + +------------------------------------------------------------------------------- */ + +/* +AllocSideRef() - ydnar +allocates and assigns a brush side reference +*/ + +sideRef_t *AllocSideRef( side_t *side, sideRef_t *next ) +{ + sideRef_t *sideRef; + + + /* dummy check */ + if( side == NULL ) + return next; + + /* allocate and return */ + sideRef = safe_malloc( sizeof( *sideRef ) ); + sideRef->side = side; + sideRef->next = next; + return sideRef; +} + + + +/* +CountBrushList() +counts the number of brushes in a brush linked list +*/ + +int CountBrushList( brush_t *brushes ) +{ + int c = 0; + + + /* count brushes */ + for( brushes; brushes != NULL; brushes = brushes->next ) + c++; + return c; +} + + + +/* +AllocBrush() +allocates a new brush +*/ + +brush_t *AllocBrush( int numSides ) +{ + brush_t *bb; + int c; + + + /* allocate and clear */ + if( numSides <= 0 ) + Error( "AllocBrush called with numsides = %d", numSides ); + c = (int) &(((brush_t*) 0)->sides[ numSides ]); + bb = safe_malloc( c ); + memset( bb, 0, c ); + if( numthreads == 1 ) + numActiveBrushes++; + + /* return it */ + return bb; +} + + + +/* +FreeBrush() +frees a single brush and all sides/windings +*/ + +void FreeBrush( brush_t *b ) +{ + int i; + + + /* error check */ + if( *((int*) b) == 0xFEFEFEFE ) + { + Sys_FPrintf( SYS_VRB, "WARNING: Attempt to free an already freed brush!\n" ); + return; + } + + /* free brush sides */ + for( i = 0; i < b->numsides; i++ ) + if( b->sides[i].winding != NULL ) + FreeWinding( b->sides[ i ].winding ); + + /* ydnar: overwrite it */ + memset( b, 0xFE, (int) &(((brush_t*) 0)->sides[ b->numsides ]) ); + *((int*) b) = 0xFEFEFEFE; + + /* free it */ + free( b ); + if( numthreads == 1 ) + numActiveBrushes--; +} + + + +/* +FreeBrushList() +frees a linked list of brushes +*/ + +void FreeBrushList( brush_t *brushes ) +{ + brush_t *next; + + + /* walk brush list */ + for( brushes; brushes != NULL; brushes = next ) + { + next = brushes->next; + FreeBrush( brushes ); + } +} + + + +/* +CopyBrush() +duplicates the brush, sides, and windings +*/ + +brush_t *CopyBrush( brush_t *brush ) +{ + brush_t *newBrush; + int size; + int i; + + + /* copy brush */ + size = (int) &(((brush_t*) 0)->sides[ brush->numsides ]); + newBrush = AllocBrush( brush->numsides ); + memcpy( newBrush, brush, size ); + + /* ydnar: nuke linked list */ + newBrush->next = NULL; + + /* copy sides */ + for( i = 0; i < brush->numsides; i++ ) + { + if( brush->sides[ i ].winding != NULL ) + newBrush->sides[ i ].winding = CopyWinding( brush->sides[ i ].winding ); + } + + /* return it */ + return newBrush; +} + + + + +/* +BoundBrush() +sets the mins/maxs based on the windings +returns false if the brush doesn't enclose a valid volume +*/ + +qboolean BoundBrush( brush_t *brush ) +{ + int i, j; + winding_t *w; + + + ClearBounds( brush->mins, brush->maxs ); + for( i = 0; i < brush->numsides; i++ ) + { + w = brush->sides[ i ].winding; + if( w == NULL ) + continue; + for( j = 0; j < w->numpoints; j++ ) + AddPointToBounds( w->p[ j ], brush->mins, brush->maxs ); + } + + for( i = 0; i < 3; i++ ) + { + if( brush->mins[ i ] < MIN_WORLD_COORD || brush->maxs[ i ] > MAX_WORLD_COORD || brush->mins[i] >= brush->maxs[ i ] ) + return qfalse; + } + + return qtrue; +} + + + + +/* +SnapWeldVector() - ydnar +welds two vec3_t's into a third, taking into account nearest-to-integer +instead of averaging +*/ + +#define SNAP_EPSILON 0.01 + +void SnapWeldVector( vec3_t a, vec3_t b, vec3_t out ) +{ + int i; + vec_t ai, bi, outi; + + + /* dummy check */ + if( a == NULL || b == NULL || out == NULL ) + return; + + /* do each element */ + for( i = 0; i < 3; i++ ) + { + /* round to integer */ + ai = Q_rint( a[ i ] ); + bi = Q_rint( a[ i ] ); + + /* prefer exact integer */ + if( ai == a[ i ] ) + out[ i ] = a[ i ]; + else if( bi == b[ i ] ) + out[ i ] = b[ i ]; + + /* use nearest */ + else if( fabs( ai - a[ i ] ) < fabs( bi < b[ i ] ) ) + out[ i ] = a[ i ]; + else + out[ i ] = b[ i ]; + + /* snap */ + outi = Q_rint( out[ i ] ); + if( fabs( outi - out[ i ] ) <= SNAP_EPSILON ) + out[ i ] = outi; + } +} + + + +/* +FixWinding() - ydnar +removes degenerate edges from a winding +returns qtrue if the winding is valid +*/ + +#define DEGENERATE_EPSILON 0.1 + +qboolean FixWinding( winding_t *w ) +{ + qboolean valid = qtrue; + int i, j, k; + vec3_t vec; + float dist; + + + /* dummy check */ + if( !w ) + return qfalse; + + /* check all verts */ + for( i = 0; i < w->numpoints; i++ ) + { + /* don't remove points if winding is a triangle */ + if( w->numpoints == 3 ) + return valid; + + /* get second point index */ + j = (i + 1) % w->numpoints; + + /* degenerate edge? */ + VectorSubtract( w->p[ i ], w->p[ j ], vec ); + dist = VectorLength( vec ); + if( dist < DEGENERATE_EPSILON ) + { + valid = qfalse; + //Sys_FPrintf( SYS_VRB, "WARNING: Degenerate winding edge found, fixing...\n" ); + + /* create an average point (ydnar 2002-01-26: using nearest-integer weld preference) */ + SnapWeldVector( w->p[ i ], w->p[ j ], vec ); + VectorCopy( vec, w->p[ i ] ); + //VectorAdd( w->p[ i ], w->p[ j ], vec ); + //VectorScale( vec, 0.5, w->p[ i ] ); + + /* move the remaining verts */ + for( k = i + 2; k < w->numpoints; k++ ) + { + VectorCopy( w->p[ k ], w->p[ k - 1 ] ); + } + w->numpoints--; + } + } + + /* one last check and return */ + if( w->numpoints < 3 ) + valid = qfalse; + return valid; +} + + + + + + + +/* +CreateBrushWindings() +makes basewindigs for sides and mins/maxs for the brush +returns false if the brush doesn't enclose a valid volume +*/ + +qboolean CreateBrushWindings( brush_t *brush ) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + + /* walk the list of brush sides */ + for( i = 0; i < brush->numsides; i++ ) + { + /* get side and plane */ + side = &brush->sides[ i ]; + plane = &mapplanes[ side->planenum ]; + + /* make huge winding */ + w = BaseWindingForPlane( plane->normal, plane->dist ); + + /* walk the list of brush sides */ + for( j = 0; j < brush->numsides && w != NULL; j++ ) + { + if( i == j ) + continue; + if( brush->sides[ j ].planenum == (brush->sides[ i ].planenum ^ 1) ) + continue; /* back side clipaway */ + if( brush->sides[ j ].bevel ) + continue; + if( brush->sides[ j ].backSide ) + continue; + plane = &mapplanes[ brush->sides[ j ].planenum ^ 1 ]; + ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); // CLIP_EPSILON ); + + /* ydnar: fix broken windings that would generate trifans */ + FixWinding( w ); + } + + /* set side winding */ + side->winding = w; + } + + /* find brush bounds */ + return BoundBrush( brush ); +} + + + + +/* +================== +BrushFromBounds + +Creates a new axial brush +================== +*/ +brush_t *BrushFromBounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + vec3_t normal; + vec_t dist; + + b = AllocBrush (6); + b->numsides = 6; + for (i=0 ; i<3 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = maxs[i]; + b->sides[i].planenum = FindFloatPlane (normal, dist, 1, (vec3_t*) &maxs ); + + normal[i] = -1; + dist = -mins[i]; + b->sides[3+i].planenum = FindFloatPlane (normal, dist, 1, (vec3_t*) &mins ); + } + + CreateBrushWindings (b); + + return b; +} + +/* +================== +BrushVolume + +================== +*/ +vec_t BrushVolume (brush_t *brush) +{ + int i; + winding_t *w; + vec3_t corner; + vec_t d, area, volume; + plane_t *plane; + + if (!brush) + return 0; + + // grab the first valid point as the corner + + w = NULL; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (w) + break; + } + if (!w) + return 0; + VectorCopy (w->p[0], corner); + + // make tetrahedrons to all other faces + + volume = 0; + for ( ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + plane = &mapplanes[brush->sides[i].planenum]; + d = -(DotProduct (corner, plane->normal) - plane->dist); + area = WindingArea (w); + volume += d*area; + } + + volume /= 3; + return volume; +} + + + +/* +WriteBSPBrushMap() +writes a map with the split bsp brushes +*/ + +void WriteBSPBrushMap( char *name, brush_t *list ) +{ + FILE *f; + side_t *s; + int i; + winding_t *w; + + + /* note it */ + Sys_Printf( "Writing %s\n", name ); + + /* open the map file */ + f = fopen( name, "wb" ); + if( f == NULL ) + Error( "Can't write %s\b", name ); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for ( ; list ; list=list->next ) + { + fprintf (f, "{\n"); + for (i=0,s=list->sides ; inumsides ; i++,s++) + { + w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "notexture 0 0 0 1 1\n" ); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + +} + + + +/* +FilterBrushIntoTree_r() +adds brush reference to any intersecting bsp leafnode +*/ + +int FilterBrushIntoTree_r( brush_t *b, node_t *node ) +{ + brush_t *front, *back; + int c; + + + /* dummy check */ + if( b == NULL ) + return 0; + + /* add it to the leaf list */ + if( node->planenum == PLANENUM_LEAF ) + { + /* something somewhere is hammering brushlist */ + b->next = node->brushlist; + node->brushlist = b; + + /* classify the leaf by the structural brush */ + if( !b->detail ) + { + if( b->opaque ) + { + node->opaque = qtrue; + node->areaportal = qfalse; + } + else if( b->compileFlags & C_AREAPORTAL ) + { + if( !node->opaque ) + node->areaportal = qtrue; + } + } + + return 1; + } + + /* split it by the node plane */ + c = b->numsides; + SplitBrush( b, node->planenum, &front, &back ); + FreeBrush( b ); + + c = 0; + c += FilterBrushIntoTree_r( front, node->children[ 0 ] ); + c += FilterBrushIntoTree_r( back, node->children[ 1 ] ); + + return c; +} + + + +/* +FilterDetailBrushesIntoTree +fragment all the detail brushes into the structural leafs +*/ + +void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree ) +{ + brush_t *b, *newb; + int r; + int c_unique, c_clusters; + int i; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- FilterDetailBrushesIntoTree ---\n" ); + + /* walk the list of brushes */ + c_unique = 0; + c_clusters = 0; + for( b = e->brushes; b; b = b->next ) + { + if( !b->detail ) + continue; + c_unique++; + newb = CopyBrush( b ); + r = FilterBrushIntoTree_r( newb, tree->headnode ); + c_clusters += r; + + /* mark all sides as visible so drawsurfs are created */ + if( r ) + { + for( i = 0; i < b->numsides; i++ ) + { + if( b->sides[ i ].winding ) + b->sides[ i ].visible = qtrue; + } + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_unique ); + Sys_FPrintf( SYS_VRB, "%9d cluster references\n", c_clusters ); +} + +/* +===================== +FilterStructuralBrushesIntoTree + +Mark the leafs as opaque and areaportals +===================== +*/ +void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree ) { + brush_t *b, *newb; + int r; + int c_unique, c_clusters; + int i; + + Sys_FPrintf (SYS_VRB, "--- FilterStructuralBrushesIntoTree ---\n"); + + c_unique = 0; + c_clusters = 0; + for ( b = e->brushes ; b ; b = b->next ) { + if ( b->detail ) { + continue; + } + c_unique++; + newb = CopyBrush( b ); + r = FilterBrushIntoTree_r( newb, tree->headnode ); + c_clusters += r; + + // mark all sides as visible so drawsurfs are created + if ( r ) { + for ( i = 0 ; i < b->numsides ; i++ ) { + if ( b->sides[i].winding ) { + b->sides[i].visible = qtrue; + } + } + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d structural brushes\n", c_unique ); + Sys_FPrintf( SYS_VRB, "%9d cluster references\n", c_clusters ); +} + + + +/* +================ +AllocTree +================ +*/ +tree_t *AllocTree (void) +{ + tree_t *tree; + + tree = safe_malloc(sizeof(*tree)); + memset (tree, 0, sizeof(*tree)); + ClearBounds (tree->mins, tree->maxs); + + return tree; +} + +/* +================ +AllocNode +================ +*/ +node_t *AllocNode (void) +{ + node_t *node; + + node = safe_malloc(sizeof(*node)); + memset (node, 0, sizeof(*node)); + + return node; +} + + +/* +================ +WindingIsTiny + +Returns true if the winding would be crunched out of +existance by the vertex snapping. +================ +*/ +#define EDGE_LENGTH 0.2 +qboolean WindingIsTiny (winding_t *w) +{ +/* + if (WindingArea (w) < 1) + return qtrue; + return qfalse; +*/ + int i, j; + vec_t len; + vec3_t delta; + int edges; + + edges = 0; + for (i=0 ; inumpoints ; i++) + { + j = i == w->numpoints - 1 ? 0 : i+1; + VectorSubtract (w->p[j], w->p[i], delta); + len = VectorLength (delta); + if (len > EDGE_LENGTH) + { + if (++edges == 3) + return qfalse; + } + } + return qtrue; +} + +/* +================ +WindingIsHuge + +Returns true if the winding still has one of the points +from basewinding for plane +================ +*/ +qboolean WindingIsHuge (winding_t *w) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->p[i][j] <= MIN_WORLD_COORD || w->p[i][j] >= MAX_WORLD_COORD) + return qtrue; + } + return qfalse; +} + +//============================================================ + +/* +================== +BrushMostlyOnSide + +================== +*/ +int BrushMostlyOnSide (brush_t *brush, plane_t *plane) +{ + int i, j; + winding_t *w; + vec_t d, max; + int side; + + max = 0; + side = PSIDE_FRONT; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > max) + { + max = d; + side = PSIDE_FRONT; + } + if (-d > max) + { + max = -d; + side = PSIDE_BACK; + } + } + } + return side; +} + + + +/* +SplitBrush() +generates two new brushes, leaving the original unchanged +*/ + +void SplitBrush( brush_t *brush, int planenum, brush_t **front, brush_t **back ) +{ + brush_t *b[2]; + int i, j; + winding_t *w, *cw[2], *midwinding; + plane_t *plane, *plane2; + side_t *s, *cs; + float d, d_front, d_back; + + + *front = NULL; + *back = NULL; + plane = &mapplanes[planenum]; + + // check all points + d_front = d_back = 0; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > 0 && d > d_front) + d_front = d; + if (d < 0 && d < d_back) + d_back = d; + } + } + + if (d_front < 0.1) // PLANESIDE_EPSILON) + { // only on back + *back = CopyBrush( brush ); + return; + } + + if (d_back > -0.1) // PLANESIDE_EPSILON) + { // only on front + *front = CopyBrush( brush ); + return; + } + + // create a new winding from the split plane + w = BaseWindingForPlane (plane->normal, plane->dist); + for (i=0 ; inumsides && w ; i++) + { + if ( brush->sides[i].backSide ) { + continue; // fake back-sided polygons never split + } + plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; + ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); + } + + if (!w || WindingIsTiny (w) ) + { // the brush isn't really split + int side; + + side = BrushMostlyOnSide (brush, plane); + if (side == PSIDE_FRONT) + *front = CopyBrush (brush); + if (side == PSIDE_BACK) + *back = CopyBrush (brush); + return; + } + + if( WindingIsHuge( w ) ) + Sys_FPrintf( SYS_VRB,"WARNING: huge winding\n" ); + + midwinding = w; + + // split it for real + + for (i=0 ; i<2 ; i++) + { + b[i] = AllocBrush (brush->numsides+1); + memcpy( b[i], brush, sizeof( brush_t ) - sizeof( brush->sides ) ); + b[i]->numsides = 0; + b[i]->next = NULL; + b[i]->original = brush->original; + } + + // split all the current windings + + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + w = s->winding; + if (!w) + continue; + ClipWindingEpsilon (w, plane->normal, plane->dist, + 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); + for (j=0 ; j<2 ; j++) + { + if (!cw[j]) + continue; + cs = &b[j]->sides[b[j]->numsides]; + b[j]->numsides++; + *cs = *s; + cs->winding = cw[j]; + } + } + + + // see if we have valid polygons on both sides + for (i=0 ; i<2 ; i++) + { + BoundBrush (b[i]); + for (j=0 ; j<3 ; j++) + { + if (b[i]->mins[j] < MIN_WORLD_COORD || b[i]->maxs[j] > MAX_WORLD_COORD) + { + Sys_FPrintf (SYS_VRB,"bogus brush after clip\n"); + break; + } + } + + if (b[i]->numsides < 3 || j < 3) + { + FreeBrush (b[i]); + b[i] = NULL; + } + } + + if ( !(b[0] && b[1]) ) + { + if (!b[0] && !b[1]) + Sys_FPrintf (SYS_VRB,"split removed brush\n"); + else + Sys_FPrintf (SYS_VRB,"split not on both sides\n"); + if (b[0]) + { + FreeBrush (b[0]); + *front = CopyBrush (brush); + } + if (b[1]) + { + FreeBrush (b[1]); + *back = CopyBrush (brush); + } + return; + } + + // add the midwinding to both sides + for (i=0 ; i<2 ; i++) + { + cs = &b[i]->sides[b[i]->numsides]; + b[i]->numsides++; + + cs->planenum = planenum^i^1; + cs->shaderInfo = NULL; + if (i==0) + cs->winding = CopyWinding (midwinding); + else + cs->winding = midwinding; + } + + { + vec_t v1; + int i; + + + for (i=0 ; i<2 ; i++) + { + v1 = BrushVolume (b[i]); + if (v1 < 1.0) + { + FreeBrush (b[i]); + b[i] = NULL; + // Sys_FPrintf (SYS_VRB,"tiny volume after clip\n"); + } + } + } + + *front = b[0]; + *back = b[1]; +} diff --git a/tools/quake3/q3map2/brush_primit.c b/tools/quake3/q3map2/brush_primit.c new file mode 100644 index 00000000..ae0110d6 --- /dev/null +++ b/tools/quake3/q3map2/brush_primit.c @@ -0,0 +1,80 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define BRUSH_PRIMIT_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* ------------------------------------------------------------------------------- + +functions + +------------------------------------------------------------------------------- */ + +/* +ComputeAxisBase() +computes the base texture axis for brush primitive texturing +note: ComputeAxisBase here and in editor code must always BE THE SAME! +warning: special case behaviour of atan2( y, x ) <-> atan( y / x ) might not be the same everywhere when x == 0 +rotation by (0,RotY,RotZ) assigns X to normal +*/ + +void ComputeAxisBase( vec3_t normal, vec3_t texX, vec3_t texY ) +{ + vec_t RotY, RotZ; + + + /* do some cleaning */ + if( fabs( normal[ 0 ] ) < 1e-6 ) + normal[ 0 ]= 0.0f; + if( fabs( normal[ 1 ] ) < 1e-6 ) + normal[ 1 ]=0.0f; + if( fabs( normal[ 2 ] ) < 1e-6 ) + normal[ 2 ] = 0.0f; + + /* compute the two rotations around y and z to rotate x to normal */ + RotY = -atan2( normal[ 2 ], sqrt( normal[ 1 ] * normal[ 1 ] + normal[ 0 ] * normal[ 0 ]) ); + RotZ = atan2( normal[ 1 ], normal[ 0 ] ); + + /* rotate (0,1,0) and (0,0,1) to compute texX and texY */ + texX[ 0 ] = -sin( RotZ ); + texX[ 1 ] = cos( RotZ ); + texX[ 2 ] = 0; + + /* the texY vector is along -z (t texture coorinates axis) */ + texY[ 0 ] = -sin( RotY ) * cos( RotZ ); + texY[ 1 ] = -sin( RotY ) * sin( RotZ ); + texY[ 2 ] = -cos( RotY ); +} diff --git a/tools/quake3/q3map2/bsp.c b/tools/quake3/q3map2/bsp.c new file mode 100644 index 00000000..c73242da --- /dev/null +++ b/tools/quake3/q3map2/bsp.c @@ -0,0 +1,853 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define BSP_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* ------------------------------------------------------------------------------- + +functions + +------------------------------------------------------------------------------- */ + + + +/* +SetCloneModelNumbers() - ydnar +sets the model numbers for brush entities +*/ + +static void SetCloneModelNumbers( void ) +{ + int i, j; + int models; + char modelValue[ 10 ]; + const char *value, *value2, *value3; + + + /* start with 1 (worldspawn is model 0) */ + models = 1; + for( i = 1; i < numEntities; i++ ) + { + /* only entities with brushes or patches get a model number */ + if( entities[ i ].brushes == NULL && entities[ i ].patches == NULL ) + continue; + + /* is this a clone? */ + value = ValueForKey( &entities[ i ], "_clone" ); + if( value[ 0 ] != '\0' ) + continue; + + /* add the model key */ + sprintf( modelValue, "*%d", models ); + SetKeyValue( &entities[ i ], "model", modelValue ); + + /* increment model count */ + models++; + } + + /* fix up clones */ + for( i = 1; i < numEntities; i++ ) + { + /* only entities with brushes or patches get a model number */ + if( entities[ i ].brushes == NULL && entities[ i ].patches == NULL ) + continue; + + /* is this a clone? */ + value = ValueForKey( &entities[ i ], "_ins" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ i ], "_instance" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ i ], "_clone" ); + if( value[ 0 ] == '\0' ) + continue; + + /* find an entity with matching clone name */ + for( j = 0; j < numEntities; j++ ) + { + /* is this a clone parent? */ + value2 = ValueForKey( &entities[ j ], "_clonename" ); + if( value2[ 0 ] == '\0' ) + continue; + + /* do they match? */ + if( strcmp( value, value2 ) == 0 ) + { + /* get the model num */ + value3 = ValueForKey( &entities[ j ], "model" ); + if( value3[ 0 ] == '\0' ) + { + Sys_Printf( "WARNING: Cloned entity %s referenced entity without model\n", value2 ); + continue; + } + models = atoi( &value2[ 1 ] ); + + /* add the model key */ + sprintf( modelValue, "*%d", models ); + SetKeyValue( &entities[ i ], "model", modelValue ); + + /* nuke the brushes/patches for this entity (fixme: leak!) */ + entities[ i ].brushes = NULL; + entities[ i ].patches = NULL; + } + } + } +} + + + +/* +FixBrushSides() - ydnar +matches brushsides back to their appropriate drawsurface and shader +*/ + +static void FixBrushSides( entity_t *e ) +{ + int i; + mapDrawSurface_t *ds; + sideRef_t *sideRef; + bspBrushSide_t *side; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- FixBrushSides ---\n" ); + + /* walk list of drawsurfaces */ + for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ ) + { + /* get surface and try to early out */ + ds = &mapDrawSurfs[ i ]; + if( ds->outputNum < 0 ) + continue; + + /* walk sideref list */ + for( sideRef = ds->sideRef; sideRef != NULL; sideRef = sideRef->next ) + { + /* get bsp brush side */ + if( sideRef->side == NULL || sideRef->side->outputNum < 0 ) + continue; + side = &bspBrushSides[ sideRef->side->outputNum ]; + + /* set drawsurface */ + side->surfaceNum = ds->outputNum; + //% Sys_FPrintf( SYS_VRB, "DS: %7d Side: %7d ", ds->outputNum, sideRef->side->outputNum ); + + /* set shader */ + if( strcmp( bspShaders[ side->shaderNum ].shader, ds->shaderInfo->shader ) ) + { + //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", bspShaders[ side->shaderNum ].shader, ds->shaderInfo->shader ); + side->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags ); + } + } + } +} + + + +/* +ProcessWorldModel() +creates a full bsp + surfaces for the worldspawn entity +*/ + +void ProcessWorldModel( void ) +{ + int i, s; + entity_t *e; + tree_t *tree; + face_t *faces; + qboolean ignoreLeaks, leaked; + xmlNodePtr polyline, leaknode; + char level[ 2 ], shader[ 1024 ]; + const char *value; + + + /* sets integer blockSize from worldspawn "_blocksize" key if it exists */ + value = ValueForKey( &entities[ 0 ], "_blocksize" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ 0 ], "blocksize" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ 0 ], "chopsize" ); /* sof2 */ + if( value[ 0 ] != '\0' ) + { + /* scan 3 numbers */ + s = sscanf( value, "%d %d %d", &blockSize[ 0 ], &blockSize[ 1 ], &blockSize[ 2 ] ); + + /* handle legacy case */ + if( s == 1 ) + { + blockSize[ 1 ] = blockSize[ 0 ]; + blockSize[ 2 ] = blockSize[ 0 ]; + } + } + Sys_Printf( "block size = { %d %d %d }\n", blockSize[ 0 ], blockSize[ 1 ], blockSize[ 2 ] ); + + /* sof2: ignore leaks? */ + value = ValueForKey( &entities[ 0 ], "_ignoreleaks" ); /* ydnar */ + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ 0 ], "ignoreleaks" ); + if( value[ 0 ] == '1' ) + ignoreLeaks = qtrue; + else + ignoreLeaks = qfalse; + + /* begin worldspawn model */ + BeginModel(); + e = &entities[ 0 ]; + e->firstDrawSurf = 0; + + /* ydnar: gs mods */ + ClearMetaTriangles(); + + /* check for patches with adjacent edges that need to lod together */ + PatchMapDrawSurfs( e ); + + /* build an initial bsp tree using all of the sides of all of the structural brushes */ + faces = MakeStructuralBSPFaceList( entities[ 0 ].brushes ); + tree = FaceBSP( faces ); + MakeTreePortals( tree ); + FilterStructuralBrushesIntoTree( e, tree ); + + /* see if the bsp is completely enclosed */ + if( FloodEntities( tree ) || ignoreLeaks ) + { + /* rebuild a better bsp tree using only the sides that are visible from the inside */ + FillOutside( tree->headnode ); + + /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */ + ClipSidesIntoTree( e, tree ); + + /* build a visible face tree */ + faces = MakeVisibleBSPFaceList( entities[ 0 ].brushes ); + FreeTree( tree ); + tree = FaceBSP( faces ); + MakeTreePortals( tree ); + FilterStructuralBrushesIntoTree( e, tree ); + leaked = qfalse; + + /* ydnar: flood again for skybox */ + if( skyboxPresent ) + FloodEntities( tree ); + } + else + { + Sys_FPrintf( SYS_NOXML, "**********************\n" ); + Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" ); + Sys_FPrintf( SYS_NOXML, "**********************\n" ); + polyline = LeakFile( tree ); + leaknode = xmlNewNode( NULL, "message" ); + xmlNodeSetContent( leaknode, "MAP LEAKED\n" ); + xmlAddChild( leaknode, polyline ); + level[0] = (int) '0' + SYS_ERR; + level[1] = 0; + xmlSetProp( leaknode, "level", (char*) &level ); + xml_SendNode( leaknode ); + if( leaktest ) + { + Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n"); + exit( 0 ); + } + leaked = qtrue; + + /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */ + ClipSidesIntoTree( e, tree ); + } + + /* save out information for visibility processing */ + NumberClusters( tree ); + if( !leaked ) + WritePortalFile( tree ); + + /* flood from entities */ + FloodAreas( tree ); + + /* create drawsurfs for triangle models */ + AddTriangleModels( e ); + + /* create drawsurfs for surface models */ + AddEntitySurfaceModels( e ); + + /* generate bsp brushes from map brushes */ + EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes ); + + /* add references to the detail brushes */ + FilterDetailBrushesIntoTree( e, tree ); + + /* drawsurfs that cross fog boundaries will need to be split along the fog boundary */ + if( !nofog ) + FogDrawSurfaces( e ); + + /* subdivide each drawsurf as required by shader tesselation */ + if( !nosubdivide ) + SubdivideFaceSurfaces( e, tree ); + + /* add in any vertexes required to fix t-junctions */ + if( !notjunc ) + FixTJunctions( e ); + + /* ydnar: classify the surfaces */ + ClassifyEntitySurfaces( e ); + + /* ydnar: project decals */ + MakeEntityDecals( e ); + + /* ydnar: meta surfaces */ + MakeEntityMetaTriangles( e ); + SmoothMetaTriangles(); + FixMetaTJunctions(); + MergeMetaTriangles(); + + /* ydnar: debug portals */ + if( debugPortals ) + MakeDebugPortalSurfs( tree ); + + /* ydnar: fog hull */ + value = ValueForKey( &entities[ 0 ], "_foghull" ); + if( value[ 0 ] != '\0' ) + { + sprintf( shader, "textures/%s", value ); + MakeFogHullSurfs( e, tree, shader ); + } + + /* ydnar: bug 645: do flares for lights */ + for( i = 0; i < numEntities && emitFlares; i++ ) + { + entity_t *light, *target; + const char *value, *flareShader; + vec3_t origin, targetOrigin, normal, color; + int lightStyle; + + + /* get light */ + light = &entities[ i ]; + value = ValueForKey( light, "classname" ); + if( !strcmp( value, "light" ) ) + { + /* get flare shader */ + flareShader = ValueForKey( light, "_flareshader" ); + value = ValueForKey( light, "_flare" ); + if( flareShader[ 0 ] != '\0' || value[ 0 ] != '\0' ) + { + /* get specifics */ + GetVectorForKey( light, "origin", origin ); + GetVectorForKey( light, "_color", color ); + lightStyle = IntForKey( light, "_style" ); + if( lightStyle == 0 ) + lightStyle = IntForKey( light, "style" ); + + /* handle directional spotlights */ + value = ValueForKey( light, "target" ); + if( value[ 0 ] != '\0' ) + { + /* get target light */ + target = FindTargetEntity( value ); + if( target != NULL ) + { + GetVectorForKey( target, "origin", targetOrigin ); + VectorSubtract( targetOrigin, origin, normal ); + VectorNormalize( normal, normal ); + } + } + else + //% VectorClear( normal ); + VectorSet( normal, 0, 0, -1 ); + + /* create the flare surface (note shader defaults automatically) */ + DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle ); + } + } + } + + /* add references to the final drawsurfs in the apropriate clusters */ + FilterDrawsurfsIntoTree( e, tree ); + + /* match drawsurfaces back to original brushsides (sof2) */ + FixBrushSides( e ); + + /* finish */ + EndModel( e, tree->headnode ); + FreeTree( tree ); +} + + + +/* +ProcessSubModel() +creates bsp + surfaces for other brush models +*/ + +void ProcessSubModel( void ) +{ + entity_t *e; + tree_t *tree; + brush_t *b, *bc; + node_t *node; + + + /* start a brush model */ + BeginModel(); + e = &entities[ mapEntityNum ]; + e->firstDrawSurf = numMapDrawSurfs; + + /* ydnar: gs mods */ + ClearMetaTriangles(); + + /* check for patches with adjacent edges that need to lod together */ + PatchMapDrawSurfs( e ); + + /* allocate a tree */ + node = AllocNode(); + node->planenum = PLANENUM_LEAF; + tree = AllocTree(); + tree->headnode = node; + + /* add the sides to the tree */ + ClipSidesIntoTree( e, tree ); + + /* ydnar: create drawsurfs for triangle models */ + AddTriangleModels( e ); + + /* create drawsurfs for surface models */ + AddEntitySurfaceModels( e ); + + /* generate bsp brushes from map brushes */ + EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes ); + + /* just put all the brushes in headnode */ + for( b = e->brushes; b; b = b->next ) + { + bc = CopyBrush( b ); + bc->next = node->brushlist; + node->brushlist = bc; + } + + /* subdivide each drawsurf as required by shader tesselation */ + if( !nosubdivide ) + SubdivideFaceSurfaces( e, tree ); + + /* add in any vertexes required to fix t-junctions */ + if( !notjunc ) + FixTJunctions( e ); + + /* ydnar: classify the surfaces and project lightmaps */ + ClassifyEntitySurfaces( e ); + + /* ydnar: project decals */ + MakeEntityDecals( e ); + + /* ydnar: meta surfaces */ + MakeEntityMetaTriangles( e ); + SmoothMetaTriangles(); + FixMetaTJunctions(); + MergeMetaTriangles(); + + /* add references to the final drawsurfs in the apropriate clusters */ + FilterDrawsurfsIntoTree( e, tree ); + + /* match drawsurfaces back to original brushsides (sof2) */ + FixBrushSides( e ); + + /* finish */ + EndModel( e, node ); + FreeTree( tree ); +} + + + +/* +ProcessModels() +process world + other models into the bsp +*/ + +void ProcessModels( void ) +{ + qboolean oldVerbose; + entity_t *entity; + + + /* preserve -v setting */ + oldVerbose = verbose; + + /* start a new bsp */ + BeginBSPFile(); + + /* create map fogs */ + CreateMapFogs(); + + /* walk entity list */ + for( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ ) + { + /* get entity */ + entity = &entities[ mapEntityNum ]; + if( entity->brushes == NULL && entity->patches == NULL ) + continue; + + /* process the model */ + Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels ); + if( mapEntityNum == 0 ) + ProcessWorldModel(); + else + ProcessSubModel(); + + /* potentially turn off the deluge of text */ + verbose = verboseEntities; + } + + /* restore -v setting */ + verbose = oldVerbose; + + /* write fogs */ + EmitFogs(); +} + + + +/* +OnlyEnts() +this is probably broken unless teamed with a radiant version that preserves entity order +*/ + +void OnlyEnts( void ) +{ + char out[ 1024 ]; + + + /* note it */ + Sys_Printf( "--- OnlyEnts ---\n" ); + + sprintf( out, "%s.bsp", source ); + LoadBSPFile( out ); + numEntities = 0; + + LoadShaderInfo(); + LoadMapFile( name, qfalse ); + SetModelNumbers(); + SetLightStyles(); + + numBSPEntities = numEntities; + UnparseEntities(); + + WriteBSPFile( out ); +} + + + +/* +BSPMain() - ydnar +handles creation of a bsp from a map file +*/ + +int BSPMain( int argc, char **argv ) +{ + int i; + char path[ 1024 ], tempSource[ 1024 ]; + qboolean onlyents = qfalse; + + + /* note it */ + Sys_Printf( "--- BSP ---\n" ); + + SetDrawSurfacesBuffer(); + mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS ); + memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS ); + numMapDrawSurfs = 0; + + tempSource[ 0 ] = '\0'; + + /* set flares flag */ + emitFlares = game->emitFlares; + + /* process arguments */ + for( i = 1; i < (argc - 1); i++ ) + { + if( !strcmp( argv[ i ], "-onlyents" ) ) + { + Sys_Printf( "Running entity-only compile\n" ); + onlyents = qtrue; + } + else if( !strcmp( argv[ i ], "-tempname" ) ) + strcpy( tempSource, argv[ ++i ] ); + else if( !strcmp( argv[ i ], "-tmpout" ) ) + strcpy( outbase, "/tmp" ); + else if( !strcmp( argv[ i ], "-nowater" ) ) + { + Sys_Printf( "Disabling water\n" ); + nowater = qtrue; + } + else if( !strcmp( argv[ i ], "-nodetail" ) ) + { + Sys_Printf( "Ignoring detail brushes\n") ; + nodetail = qtrue; + } + else if( !strcmp( argv[ i ], "-fulldetail" ) ) + { + Sys_Printf( "Turning detail brushes into structural brushes\n" ); + fulldetail = qtrue; + } + else if( !strcmp( argv[ i ], "-nofog" ) ) + { + Sys_Printf( "Fog volumes disabled\n" ); + nofog = qtrue; + } + else if( !strcmp( argv[ i ], "-nosubdivide" ) ) + { + Sys_Printf( "Disabling brush face subdivision\n" ); + nosubdivide = qtrue; + } + else if( !strcmp( argv[ i ], "-leaktest" ) ) + { + Sys_Printf( "Leaktest enabled\n" ); + leaktest = qtrue; + } + else if( !strcmp( argv[ i ], "-verboseentities" ) ) + { + Sys_Printf( "Verbose entities enabled\n" ); + verboseEntities = qtrue; + } + else if( !strcmp( argv[ i ], "-nocurves" ) ) + { + Sys_Printf( "Ignoring curved surfaces (patches)\n" ); + noCurveBrushes = qtrue; + } + else if( !strcmp( argv[ i ], "-notjunc" ) ) + { + Sys_Printf( "T-junction fixing disabled\n" ); + notjunc = qtrue; + } + else if( !strcmp( argv[ i ], "-fakemap" ) ) + { + Sys_Printf( "Generating fakemap.map\n" ); + fakemap = qtrue; + } + else if( !strcmp( argv[ i ], "-samplesize" ) ) + { + sampleSize = atoi( argv[ i + 1 ] ); + if( sampleSize < 1 ) + sampleSize = 1; + i++; + Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize ); + } + else if( !strcmp( argv[ i ], "-custinfoparms") ) + { + Sys_Printf( "Custom info parms enabled\n" ); + useCustomInfoParms = qtrue; + } + + /* sof2 args */ + else if( !strcmp( argv[ i ], "-rename" ) ) + { + Sys_Printf( "Appending _bsp suffix to misc_model shaders (SOF2)\n" ); + renameModelShaders = qtrue; + } + + /* ydnar args */ + else if( !strcmp( argv[ i ], "-ne" ) ) + { + normalEpsilon = atof( argv[ i + 1 ] ); + i++; + Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon ); + } + else if( !strcmp( argv[ i ], "-de" ) ) + { + distanceEpsilon = atof( argv[ i + 1 ] ); + i++; + Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon ); + } + else if( !strcmp( argv[ i ], "-mv" ) ) + { + maxSurfaceVerts = atoi( argv[ i + 1 ] ); + if( maxSurfaceVerts < 3 ) + maxSurfaceVerts = 3; + i++; + Sys_Printf( "Maximum per-surface vertex count set to %d\n", maxSurfaceVerts ); + } + else if( !strcmp( argv[ i ], "-mi" ) ) + { + maxSurfaceIndexes = atoi( argv[ i + 1 ] ); + if( maxSurfaceIndexes < 3 ) + maxSurfaceIndexes = 3; + i++; + Sys_Printf( "Maximum per-surface index count set to %d\n", maxSurfaceIndexes ); + } + else if( !strcmp( argv[ i ], "-np" ) ) + { + npDegrees = atof( argv[ i + 1 ] ); + if( npDegrees < 0.0f ) + shadeAngleDegrees = 0.0f; + else if( npDegrees > 0.0f ) + Sys_Printf( "Forcing nonplanar surfaces with a breaking angle of %f degrees\n", npDegrees ); + i++; + } + else if( !strcmp( argv[ i ], "-snap" ) ) + { + bevelSnap = atoi( argv[ i + 1 ]); + if( bevelSnap < 0 ) + bevelSnap = 0; + i++; + if( bevelSnap > 0 ) + Sys_Printf( "Snapping brush bevel planes to %d units\n", bevelSnap ); + } + else if( !strcmp( argv[ i ], "-texrange" ) ) + { + texRange = atoi( argv[ i + 1 ]); + if( texRange < 0 ) + texRange = 0; + i++; + Sys_Printf( "Limiting per-surface texture range to %d texels\n", texRange ); + } + else if( !strcmp( argv[ i ], "-nohint" ) ) + { + Sys_Printf( "Hint brushes disabled\n" ); + noHint = qtrue; + } + else if( !strcmp( argv[ i ], "-flat" ) ) + { + Sys_Printf( "Flatshading enabled\n" ); + flat = qtrue; + } + else if( !strcmp( argv[ i ], "-meta" ) ) + { + Sys_Printf( "Creating meta surfaces from brush faces\n" ); + meta = qtrue; + } + else if( !strcmp( argv[ i ], "-patchmeta" ) ) + { + Sys_Printf( "Creating meta surfaces from patches\n" ); + patchMeta = qtrue; + } + else if( !strcmp( argv[ i ], "-flares" ) ) + { + Sys_Printf( "Flare surfaces enabled\n" ); + emitFlares = qtrue; + } + else if( !strcmp( argv[ i ], "-noflares" ) ) + { + Sys_Printf( "Flare surfaces disabled\n" ); + emitFlares = qfalse; + } + else if( !strcmp( argv[ i ], "-skyfix" ) ) + { + Sys_Printf( "GL_CLAMP sky fix/hack/workaround enabled\n" ); + skyFixHack = qtrue; + } + else if( !strcmp( argv[ i ], "-debugsurfaces" ) ) + { + Sys_Printf( "emitting debug surfaces\n" ); + debugSurfaces = qtrue; + } + else if( !strcmp( argv[ i ], "-debuginset" ) ) + { + Sys_Printf( "Debug surface triangle insetting enabled\n" ); + debugInset = qtrue; + } + else if( !strcmp( argv[ i ], "-debugportals" ) ) + { + Sys_Printf( "Debug portal surfaces enabled\n" ); + debugPortals = qtrue; + } + else if( !strcmp( argv[ i ], "-bsp" ) ) + Sys_Printf( "-bsp argument unnecessary\n" ); + else + Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); + } + + /* fixme: print more useful usage here */ + if( i != (argc - 1) ) + Error( "usage: q3map [options] mapfile" ); + + /* copy source name */ + strcpy( source, ExpandArg( argv[ i ] ) ); + StripExtension( source ); + + /* ydnar: set default sample size */ + SetDefaultSampleSize( sampleSize ); + + /* delete portal, line and surface files */ + sprintf( path, "%s.prt", source ); + remove( path ); + sprintf( path, "%s.lin", source ); + remove( path ); + //% sprintf( path, "%s.srf", source ); /* ydnar */ + //% remove( path ); + + /* expand mapname */ + strcpy( name, ExpandArg( argv[ i ] ) ); + if( strcmp( name + strlen( name ) - 4, ".reg" ) ) + { + /* if we are doing a full map, delete the last saved region map */ + sprintf( path, "%s.reg", source ); + remove( path ); + DefaultExtension( name, ".map" ); /* might be .reg */ + } + + /* if onlyents, just grab the entites and resave */ + if( onlyents ) + { + OnlyEnts(); + return 0; + } + + /* load shaders */ + LoadShaderInfo(); + + /* load original file from temp spot in case it was renamed by the editor on the way in */ + if( strlen( tempSource ) > 0 ) + LoadMapFile( tempSource, qfalse ); + else + LoadMapFile( name, qfalse ); + + /* ydnar: decal setup */ + ProcessDecals(); + + /* ydnar: cloned brush model entities */ + SetCloneModelNumbers(); + + /* process world and submodels */ + ProcessModels(); + + /* set light styles from targetted light entities */ + SetLightStyles(); + + /* finish and write bsp */ + EndBSPFile(); + + /* remove temp map source file if appropriate */ + if( strlen( tempSource ) > 0) + remove( tempSource ); + + /* return to sender */ + return 0; +} + diff --git a/tools/quake3/q3map2/bspfile_abstract.c b/tools/quake3/q3map2/bspfile_abstract.c new file mode 100644 index 00000000..db34dd61 --- /dev/null +++ b/tools/quake3/q3map2/bspfile_abstract.c @@ -0,0 +1,834 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define BSPFILE_ABSTRACT_C + + + +/* dependencies */ +#include "q3map2.h" + + + + +/* ------------------------------------------------------------------------------- + +this file was copied out of the common directory in order to not break +compatibility with the q3map 1.x tree. it was moved out in order to support +the raven bsp format (RBSP) used in soldier of fortune 2 and jedi knight 2. + +since each game has its own set of particular features, the data structures +below no longer directly correspond to the binary format of a particular game. + +the translation will be done at bsp load/save time to keep any sort of +special-case code messiness out of the rest of the program. + +------------------------------------------------------------------------------- */ + + + +/* FIXME: remove the functions below that handle memory management of bsp file chunks */ + +int numBSPDrawVertsBuffer = 0; +void IncDrawVerts() +{ + numBSPDrawVerts++; + + if(bspDrawVerts == 0) + { + numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37; + + bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts"); + + } + else if(numBSPDrawVerts > numBSPDrawVertsBuffer) + { + numBSPDrawVertsBuffer *= 3; // multiply by 1.5 + numBSPDrawVertsBuffer /= 2; + + if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS) + numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS; + + bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer); + + if(!bspDrawVerts) + Error( "realloc() failed (IncDrawVerts)"); + } + + memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t)); +} + +void SetDrawVerts(int n) +{ + if(bspDrawVerts != 0) + free(bspDrawVerts); + + numBSPDrawVerts = n; + numBSPDrawVertsBuffer = numBSPDrawVerts; + + bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts"); + + memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t)); +} + +int numBSPDrawSurfacesBuffer = 0; +void SetDrawSurfacesBuffer() +{ + if(bspDrawSurfaces != 0) + free(bspDrawSurfaces); + + numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS; + + bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces"); + + memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t)); +} + +void SetDrawSurfaces(int n) +{ + if(bspDrawSurfaces != 0) + free(bspDrawSurfaces); + + numBSPDrawSurfaces = n; + numBSPDrawSurfacesBuffer = numBSPDrawSurfaces; + + bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces"); + + memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t)); +} + +void BSPFilesCleanup() +{ + if(bspDrawVerts != 0) + free(bspDrawVerts); + if(bspDrawSurfaces != 0) + free(bspDrawSurfaces); + if(bspLightBytes != 0) + free(bspLightBytes); + if(bspGridPoints != 0) + free(bspGridPoints); +} + + + + + + +/* +SwapBlock() +if all values are 32 bits, this can be used to swap everything +*/ + +void SwapBlock( int *block, int size ) +{ + int i; + + + /* dummy check */ + if( block == NULL ) + return; + + /* swap */ + size >>= 2; + for( i = 0; i < size; i++ ) + block[ i ] = LittleLong( block[ i ] ); +} + + + +/* +SwapBSPFile() +byte swaps all data in the abstract bsp +*/ + +void SwapBSPFile( void ) +{ + int i, j; + + + /* models */ + SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) ); + + /* shaders (don't swap the name) */ + for( i = 0; i < numBSPShaders ; i++ ) + { + bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags ); + bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags ); + } + + /* planes */ + SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) ); + + /* nodes */ + SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) ); + + /* leafs */ + SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) ); + + /* leaffaces */ + SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) ); + + /* leafbrushes */ + SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) ); + + // brushes + SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) ); + + // brushsides + SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) ); + + // vis + ((int*) &bspVisBytes)[ 0 ] = LittleLong( ((int*) &bspVisBytes)[ 0 ] ); + ((int*) &bspVisBytes)[ 1 ] = LittleLong( ((int*) &bspVisBytes)[ 1 ] ); + + /* drawverts (don't swap colors) */ + for( i = 0; i < numBSPDrawVerts; i++ ) + { + bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] ); + bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] ); + bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] ); + bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] ); + bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] ); + bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] ); + bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] ); + bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] ); + for( j = 0; j < MAX_LIGHTMAPS; j++ ) + { + bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] ); + bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] ); + } + } + + /* drawindexes */ + SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) ); + + /* drawsurfs */ + /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */ + SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) ); + + /* fogs */ + for( i = 0; i < numBSPFogs; i++ ) + { + bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum ); + bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide ); + } +} + + + +/* +GetLumpElements() +gets the number of elements in a bsp lump +*/ + +int GetLumpElements( bspHeader_t *header, int lump, int size ) +{ + /* check for odd size */ + if( header->lumps[ lump ].length % size ) + { + if( force ) + { + Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump ); + return 0; + } + else + Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump ); + } + + /* return element count */ + return header->lumps[ lump ].length / size; +} + + + +/* +GetLump() +returns a pointer to the specified lump +*/ + +void *GetLump( bspHeader_t *header, int lump ) +{ + return (void*)( (byte*) header + header->lumps[ lump ].offset); +} + + + +/* +CopyLump() +copies a bsp file lump into a destination buffer +*/ + +int CopyLump( bspHeader_t *header, int lump, void *dest, int size ) +{ + int length, offset; + + + /* get lump length and offset */ + length = header->lumps[ lump ].length; + offset = header->lumps[ lump ].offset; + + /* handle erroneous cases */ + if( length == 0 ) + return 0; + if( length % size ) + { + if( force ) + { + Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump ); + return 0; + } + else + Error( "CopyLump: odd lump size (%d) in lump %d", length, lump ); + } + + /* copy block of memory and return */ + memcpy( dest, (byte*) header + offset, length ); + return length / size; +} + + + +/* +AddLump() +adds a lump to an outgoing bsp file +*/ + +void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ) +{ + bspLump_t *lump; + + + /* add lump to bsp file header */ + lump = &header->lumps[ lumpNum ]; + lump->offset = LittleLong( ftell( file ) ); + lump->length = LittleLong( length ); + + /* write lump to file */ + SafeWrite( file, data, (length + 3) & ~3 ); +} + + + +/* +LoadBSPFile() +loads a bsp file into memory +*/ + +void LoadBSPFile( const char *filename ) +{ + /* dummy check */ + if( game == NULL || game->load == NULL ) + Error( "LoadBSPFile: unsupported BSP file format" ); + + /* load it, then byte swap the in-memory version */ + game->load( filename ); + SwapBSPFile(); +} + + + +/* +WriteBSPFile() +writes a bsp file +*/ + +void WriteBSPFile( const char *filename ) +{ + char tempname[ 1024 ]; + time_t tm; + + + /* dummy check */ + if( game == NULL || game->write == NULL ) + Error( "WriteBSPFile: unsupported BSP file format" ); + + /* make fake temp name so existing bsp file isn't damaged in case write process fails */ + time( &tm ); + sprintf( tempname, "%s.%08X", filename, (int) tm ); + + /* byteswap, write the bsp, then swap back so it can be manipulated further */ + SwapBSPFile(); + game->write( tempname ); + SwapBSPFile(); + + /* replace existing bsp file */ + remove( filename ); + rename( tempname, filename ); +} + + + +/* +PrintBSPFileSizes() +dumps info about current file +*/ + +void PrintBSPFileSizes( void ) +{ + /* parse entities first */ + if( numEntities <= 0 ) + ParseEntities(); + + /* note that this is abstracted */ + Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" ); + + /* print various and sundry bits */ + Sys_Printf( "%9d models %9d\n", + numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) ); + Sys_Printf( "%9d shaders %9d\n", + numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) ); + Sys_Printf( "%9d brushes %9d\n", + numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) ); + Sys_Printf( "%9d brushsides %9d *\n", + numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) ); + Sys_Printf( "%9d fogs %9d\n", + numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) ); + Sys_Printf( "%9d planes %9d\n", + numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) ); + Sys_Printf( "%9d entdata %9d\n", + numEntities, bspEntDataSize ); + Sys_Printf( "\n"); + + Sys_Printf( "%9d nodes %9d\n", + numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) ); + Sys_Printf( "%9d leafs %9d\n", + numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) ); + Sys_Printf( "%9d leafsurfaces %9d\n", + numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) ); + Sys_Printf( "%9d leafbrushes %9d\n", + numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) ); + Sys_Printf( "\n"); + + Sys_Printf( "%9d drawsurfaces %9d *\n", + numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) ); + Sys_Printf( "%9d drawverts %9d *\n", + numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) ); + Sys_Printf( "%9d drawindexes %9d\n", + numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) ); + Sys_Printf( "\n"); + + Sys_Printf( "%9d lightmaps %9d\n", + numBSPLightBytes / (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3), numBSPLightBytes ); + Sys_Printf( "%9d lightgrid %9d *\n", + numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) ); + Sys_Printf( " visibility %9d\n", + numBSPVisBytes ); +} + + + +/* ------------------------------------------------------------------------------- + +entity data handling + +------------------------------------------------------------------------------- */ + + +/* +StripTrailing() +strips low byte chars off the end of a string +*/ + +void StripTrailing( char *e ) +{ + char *s; + + + s = e + strlen( e ) - 1; + while( s >= e && *s <= 32 ) + { + *s = 0; + s--; + } +} + + + +/* +ParseEpair() +parses a single quoted "key" "value" pair into an epair struct +*/ + +epair_t *ParseEPair( void ) +{ + epair_t *e; + + + /* allocate and clear new epair */ + e = safe_malloc( sizeof( epair_t ) ); + memset( e, 0, sizeof( epair_t ) ); + + /* handle key */ + if( strlen( token ) >= (MAX_KEY - 1) ) + Error( "ParseEPair: token too long" ); + + e->key = copystring( token ); + GetToken( qfalse ); + + /* handle value */ + if( strlen( token ) >= MAX_VALUE - 1 ) + Error( "ParseEpar: token too long" ); + e->value = copystring( token ); + + /* strip trailing spaces that sometimes get accidentally added in the editor */ + StripTrailing( e->key ); + StripTrailing( e->value ); + + /* return it */ + return e; +} + + + +/* +ParseEntity() +parses an entity's epairs +*/ + +qboolean ParseEntity( void ) +{ + epair_t *e; + + + /* dummy check */ + if( !GetToken( qtrue ) ) + return qfalse; + if( strcmp( token, "{" ) ) + Error( "ParseEntity: { not found" ); + if( numEntities == MAX_MAP_ENTITIES ) + Error( "numEntities == MAX_MAP_ENTITIES" ); + + /* create new entity */ + mapEnt = &entities[ numEntities ]; + numEntities++; + + /* parse */ + while( 1 ) + { + if( !GetToken( qtrue ) ) + Error( "ParseEntity: EOF without closing brace" ); + if( !EPAIR_STRCMP( token, "}" ) ) + break; + e = ParseEPair(); + e->next = mapEnt->epairs; + mapEnt->epairs = e; + } + + /* return to sender */ + return qtrue; +} + + + +/* +ParseEntities() +parses the bsp entity data string into entities +*/ + +void ParseEntities( void ) +{ + numEntities = 0; + ParseFromMemory( bspEntData, bspEntDataSize ); + while( ParseEntity() ); + + /* ydnar: set number of bsp entities in case a map is loaded on top */ + numBSPEntities = numEntities; +} + + + +/* +UnparseEntities() +generates the dentdata string from all the entities. +this allows the utilities to add or remove key/value +pairs to the data created by the map editor +*/ + +void UnparseEntities( void ) +{ + int i; + char *buf, *end; + epair_t *ep; + char line[ 2048 ]; + char key[ 1024 ], value[ 1024 ]; + const char *value2; + + + /* setup */ + buf = bspEntData; + end = buf; + *end = 0; + + /* run through entity list */ + for( i = 0; i < numBSPEntities && i < numEntities; i++ ) + { + /* get epair */ + ep = entities[ i ].epairs; + if( ep == NULL ) + continue; /* ent got removed */ + + /* ydnar: certain entities get stripped from bsp file */ + value2 = ValueForKey( &entities[ i ], "classname" ); + if( !Q_stricmp( value2, "misc_model" ) || + !Q_stricmp( value2, "_decal" ) || + !Q_stricmp( value2, "_skybox" ) ) + continue; + + /* add beginning brace */ + strcat( end, "{\n" ); + end += 2; + + /* walk epair list */ + for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next ) + { + /* copy and clean */ + strcpy( key, ep->key ); + StripTrailing( key ); + strcpy( value, ep->value ); + StripTrailing( value ); + + /* add to buffer */ + sprintf( line, "\"%s\" \"%s\"\n", key, value ); + strcat( end, line ); + end += strlen( line ); + } + + /* add trailing brace */ + strcat( end,"}\n" ); + end += 2; + + /* check for overflow */ + if( end > buf + MAX_MAP_ENTSTRING ) + Error( "Entity text too long" ); + } + + /* set size */ + bspEntDataSize = end - buf + 1; +} + + + +/* +PrintEntity() +prints an entity's epairs to the console +*/ + +void PrintEntity( const entity_t *ent ) +{ + epair_t *ep; + + + Sys_Printf( "------- entity %p -------\n", ent ); + for( ep = ent->epairs; ep != NULL; ep = ep->next ) + Sys_Printf( "%s = %s\n", ep->key, ep->value ); + +} + + + +/* +SetKeyValue() +sets an epair in an entity +*/ + +void SetKeyValue( entity_t *ent, const char *key, const char *value ) +{ + epair_t *ep; + + + /* check for existing epair */ + for( ep = ent->epairs; ep != NULL; ep = ep->next ) + { + if( !EPAIR_STRCMP( ep->key, key ) ) + { + free( ep->value ); + ep->value = copystring( value ); + return; + } + } + + /* create new epair */ + ep = safe_malloc( sizeof( *ep ) ); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = copystring( key ); + ep->value = copystring( value ); +} + + + +/* +ValueForKey() +gets the value for an entity key +*/ + +const char *ValueForKey( const entity_t *ent, const char *key ) +{ + epair_t *ep; + + + /* dummy check */ + if( ent == NULL ) + return ""; + + /* walk epair list */ + for( ep = ent->epairs; ep != NULL; ep = ep->next ) + { + if( !EPAIR_STRCMP( ep->key, key ) ) + return ep->value; + } + + /* if no match, return empty string */ + return ""; +} + + + +/* +IntForKey() +gets the integer point value for an entity key +*/ + +int IntForKey( const entity_t *ent, const char *key ) +{ + const char *k; + + + k = ValueForKey( ent, key ); + return atoi( k ); +} + + + +/* +FloatForKey() +gets the floating point value for an entity key +*/ + +vec_t FloatForKey( const entity_t *ent, const char *key ) +{ + const char *k; + + + k = ValueForKey( ent, key ); + return atof( k ); +} + + + +/* +GetVectorForKey() +gets a 3-element vector value for an entity key +*/ + +void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ) +{ + const char *k; + double v1, v2, v3; + + + /* get value */ + k = ValueForKey( ent, key ); + + /* scanf into doubles, then assign, so it is vec_t size independent */ + v1 = v2 = v3 = 0.0; + sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 ); + vec[ 0 ] = v1; + vec[ 1 ] = v2; + vec[ 2 ] = v3; +} + + + +/* +FindTargetEntity() +finds an entity target +*/ + +entity_t *FindTargetEntity( const char *target ) +{ + int i; + const char *n; + + + /* walk entity list */ + for( i = 0; i < numEntities; i++ ) + { + n = ValueForKey( &entities[ i ], "targetname" ); + if ( !strcmp( n, target ) ) + return &entities[ i ]; + } + + /* nada */ + return NULL; +} + + + +/* +GetEntityShadowFlags() - ydnar +gets an entity's shadow flags +note: does not set them to defaults if the keys are not found! +*/ + +void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ) +{ + const char *value; + + + /* get cast shadows */ + if( castShadows != NULL ) + { + value = ValueForKey( ent, "_castShadows" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( ent, "_cs" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( ent2, "_castShadows" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( ent2, "_cs" ); + if( value[ 0 ] != '\0' ) + *castShadows = atoi( value ); + } + + /* receive */ + if( recvShadows != NULL ) + { + value = ValueForKey( ent, "_receiveShadows" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( ent, "_rs" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( ent2, "_receiveShadows" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( ent2, "_rs" ); + if( value[ 0 ] != '\0' ) + *recvShadows = atoi( value ); + } +} + diff --git a/tools/quake3/q3map2/bspfile_ibsp.c b/tools/quake3/q3map2/bspfile_ibsp.c new file mode 100644 index 00000000..dddf63ca --- /dev/null +++ b/tools/quake3/q3map2/bspfile_ibsp.c @@ -0,0 +1,584 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define BSPFILE_IBSP_C + + + +/* dependencies */ +#include "q3map2.h" + + + + +/* ------------------------------------------------------------------------------- + +this file handles translating the bsp file format used by quake 3, rtcw, and ef +into the abstracted bsp file used by q3map2. + +------------------------------------------------------------------------------- */ + +/* constants */ +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define HEADER_LUMPS 17 + + +/* types */ +typedef struct +{ + char ident[ 4 ]; + int version; + + bspLump_t lumps[ HEADER_LUMPS ]; +} +ibspHeader_t; + + + +/* brush sides */ +typedef struct +{ + int planeNum; + int shaderNum; +} +ibspBrushSide_t; + + +static void CopyBrushSidesLump( ibspHeader_t *header ) +{ + int i; + ibspBrushSide_t *in; + bspBrushSide_t *out; + + + /* get count */ + numBSPBrushSides = GetLumpElements( (bspHeader_t*) header, LUMP_BRUSHSIDES, sizeof( *in ) ); + + /* copy */ + in = GetLump( (bspHeader_t*) header, LUMP_BRUSHSIDES ); + out = bspBrushSides; + for( i = 0; i < numBSPBrushSides; i++ ) + { + out->planeNum = in->planeNum; + out->shaderNum = in->shaderNum; + out->surfaceNum = -1; + in++; + out++; + } +} + + +static void AddBrushSidesLump( FILE *file, ibspHeader_t *header ) +{ + int i, size; + bspBrushSide_t *in; + ibspBrushSide_t *buffer, *out; + + + /* allocate output buffer */ + size = numBSPBrushSides * sizeof( *buffer ); + buffer = safe_malloc( size ); + memset( buffer, 0, size ); + + /* convert */ + in = bspBrushSides; + out = buffer; + for( i = 0; i < numBSPBrushSides; i++ ) + { + out->planeNum = in->planeNum; + out->shaderNum = in->shaderNum; + in++; + out++; + } + + /* write lump */ + AddLump( file, (bspHeader_t*) header, LUMP_BRUSHSIDES, buffer, size ); + + /* free buffer */ + free( buffer ); +} + + + +/* drawsurfaces */ +typedef struct ibspDrawSurface_s +{ + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + int lightmapNum; + int lightmapX, lightmapY; + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[ 3 ]; + + int patchWidth; + int patchHeight; +} +ibspDrawSurface_t; + + +static void CopyDrawSurfacesLump( ibspHeader_t *header ) +{ + int i, j; + ibspDrawSurface_t *in; + bspDrawSurface_t *out; + + + /* get count */ + numBSPDrawSurfaces = GetLumpElements( (bspHeader_t*) header, LUMP_SURFACES, sizeof( *in ) ); + SetDrawSurfaces( numBSPDrawSurfaces ); + + /* copy */ + in = GetLump( (bspHeader_t*) header, LUMP_SURFACES ); + out = bspDrawSurfaces; + for( i = 0; i < numBSPDrawSurfaces; i++ ) + { + out->shaderNum = in->shaderNum; + out->fogNum = in->fogNum; + out->surfaceType = in->surfaceType; + out->firstVert = in->firstVert; + out->numVerts = in->numVerts; + out->firstIndex = in->firstIndex; + out->numIndexes = in->numIndexes; + + out->lightmapStyles[ 0 ] = LS_NORMAL; + out->vertexStyles[ 0 ] = LS_NORMAL; + out->lightmapNum[ 0 ] = in->lightmapNum; + out->lightmapX[ 0 ] = in->lightmapX; + out->lightmapY[ 0 ] = in->lightmapY; + + for( j = 1; j < MAX_LIGHTMAPS; j++ ) + { + out->lightmapStyles[ j ] = LS_NONE; + out->vertexStyles[ j ] = LS_NONE; + out->lightmapNum[ j ] = -3; + out->lightmapX[ j ] = 0; + out->lightmapY[ j ] = 0; + } + + out->lightmapWidth = in->lightmapWidth; + out->lightmapHeight = in->lightmapHeight; + + VectorCopy( in->lightmapOrigin, out->lightmapOrigin ); + VectorCopy( in->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] ); + VectorCopy( in->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] ); + VectorCopy( in->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] ); + + out->patchWidth = in->patchWidth; + out->patchHeight = in->patchHeight; + + in++; + out++; + } +} + + +static void AddDrawSurfacesLump( FILE *file, ibspHeader_t *header ) +{ + int i, size; + bspDrawSurface_t *in; + ibspDrawSurface_t *buffer, *out; + + + /* allocate output buffer */ + size = numBSPDrawSurfaces * sizeof( *buffer ); + buffer = safe_malloc( size ); + memset( buffer, 0, size ); + + /* convert */ + in = bspDrawSurfaces; + out = buffer; + for( i = 0; i < numBSPDrawSurfaces; i++ ) + { + out->shaderNum = in->shaderNum; + out->fogNum = in->fogNum; + out->surfaceType = in->surfaceType; + out->firstVert = in->firstVert; + out->numVerts = in->numVerts; + out->firstIndex = in->firstIndex; + out->numIndexes = in->numIndexes; + + out->lightmapNum = in->lightmapNum[ 0 ]; + out->lightmapX = in->lightmapX[ 0 ]; + out->lightmapY = in->lightmapY[ 0 ]; + out->lightmapWidth = in->lightmapWidth; + out->lightmapHeight = in->lightmapHeight; + + VectorCopy( in->lightmapOrigin, out->lightmapOrigin ); + VectorCopy( in->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] ); + VectorCopy( in->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] ); + VectorCopy( in->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] ); + + out->patchWidth = in->patchWidth; + out->patchHeight = in->patchHeight; + + in++; + out++; + } + + /* write lump */ + AddLump( file, (bspHeader_t*) header, LUMP_SURFACES, buffer, size ); + + /* free buffer */ + free( buffer ); +} + + + +/* drawverts */ +typedef struct +{ + vec3_t xyz; + float st[ 2 ]; + float lightmap[ 2 ]; + vec3_t normal; + byte color[ 4 ]; +} +ibspDrawVert_t; + + +static void CopyDrawVertsLump( ibspHeader_t *header ) +{ + int i; + ibspDrawVert_t *in; + bspDrawVert_t *out; + + + /* get count */ + numBSPDrawVerts = GetLumpElements( (bspHeader_t*) header, LUMP_DRAWVERTS, sizeof( *in ) ); + SetDrawVerts( numBSPDrawVerts ); + + /* copy */ + in = GetLump( (bspHeader_t*) header, LUMP_DRAWVERTS ); + out = bspDrawVerts; + for( i = 0; i < numBSPDrawVerts; i++ ) + { + VectorCopy( in->xyz, out->xyz ); + out->st[ 0 ] = in->st[ 0 ]; + out->st[ 1 ] = in->st[ 1 ]; + + out->lightmap[ 0 ][ 0 ] = in->lightmap[ 0 ]; + out->lightmap[ 0 ][ 1 ] = in->lightmap[ 1 ]; + + VectorCopy( in->normal, out->normal ); + + out->color[ 0 ][ 0 ] = in->color[ 0 ]; + out->color[ 0 ][ 1 ] = in->color[ 1 ]; + out->color[ 0 ][ 2 ] = in->color[ 2 ]; + out->color[ 0 ][ 3 ] = in->color[ 3 ]; + + in++; + out++; + } +} + + +static void AddDrawVertsLump( FILE *file, ibspHeader_t *header ) +{ + int i, size; + bspDrawVert_t *in; + ibspDrawVert_t *buffer, *out; + + + /* allocate output buffer */ + size = numBSPDrawVerts * sizeof( *buffer ); + buffer = safe_malloc( size ); + memset( buffer, 0, size ); + + /* convert */ + in = bspDrawVerts; + out = buffer; + for( i = 0; i < numBSPDrawVerts; i++ ) + { + VectorCopy( in->xyz, out->xyz ); + out->st[ 0 ] = in->st[ 0 ]; + out->st[ 1 ] = in->st[ 1 ]; + + out->lightmap[ 0 ] = in->lightmap[ 0 ][ 0 ]; + out->lightmap[ 1 ] = in->lightmap[ 0 ][ 1 ]; + + VectorCopy( in->normal, out->normal ); + + out->color[ 0 ] = in->color[ 0 ][ 0 ]; + out->color[ 1 ] = in->color[ 0 ][ 1 ]; + out->color[ 2 ] = in->color[ 0 ][ 2 ]; + out->color[ 3 ] = in->color[ 0 ][ 3 ]; + + in++; + out++; + } + + /* write lump */ + AddLump( file, (bspHeader_t*) header, LUMP_DRAWVERTS, buffer, size ); + + /* free buffer */ + free( buffer ); +} + + + +/* light grid */ +typedef struct +{ + byte ambient[ 3 ]; + byte directed[ 3 ]; + byte latLong[ 2 ]; +} +ibspGridPoint_t; + + +static void CopyLightGridLumps( ibspHeader_t *header ) +{ + int i, j; + ibspGridPoint_t *in; + bspGridPoint_t *out; + + + /* get count */ + numBSPGridPoints = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTGRID, sizeof( *in ) ); + + /* allocate buffer */ + bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) ); + memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) ); + + /* copy */ + in = GetLump( (bspHeader_t*) header, LUMP_LIGHTGRID ); + out = bspGridPoints; + for( i = 0; i < numBSPGridPoints; i++ ) + { + for( j = 0; j < MAX_LIGHTMAPS; j++ ) + { + VectorCopy( in->ambient, out->ambient[ j ] ); + VectorCopy( in->directed, out->directed[ j ] ); + out->styles[ j ] = LS_NONE; + } + + out->styles[ 0 ] = LS_NORMAL; + + out->latLong[ 0 ] = in->latLong[ 0 ]; + out->latLong[ 1 ] = in->latLong[ 1 ]; + + in++; + out++; + } +} + + +static void AddLightGridLumps( FILE *file, ibspHeader_t *header ) +{ + int i; + bspGridPoint_t *in; + ibspGridPoint_t *buffer, *out; + + + /* dummy check */ + if( bspGridPoints == NULL ) + return; + + /* allocate temporary buffer */ + buffer = safe_malloc( numBSPGridPoints * sizeof( *out ) ); + + /* convert */ + in = bspGridPoints; + out = buffer; + for( i = 0; i < numBSPGridPoints; i++ ) + { + VectorCopy( in->ambient[ 0 ], out->ambient ); + VectorCopy( in->directed[ 0 ], out->directed ); + + out->latLong[ 0 ] = in->latLong[ 0 ]; + out->latLong[ 1 ] = in->latLong[ 1 ]; + + in++; + out++; + } + + /* write lumps */ + AddLump( file, (bspHeader_t*) header, LUMP_LIGHTGRID, buffer, (numBSPGridPoints * sizeof( *out )) ); + + /* free buffer (ydnar 2002-10-22: [bug 641] thanks Rap70r! */ + free( buffer ); +} + + + +/* +LoadIBSPFile() +loads a quake 3 bsp file into memory +*/ + +void LoadIBSPFile( const char *filename ) +{ + ibspHeader_t *header; + + + /* load the file header */ + LoadFile( filename, (void**) &header ); + + /* swap the header (except the first 4 bytes) */ + SwapBlock( (int*) ((byte*) header + sizeof( int )), sizeof( *header ) - sizeof( int ) ); + + /* make sure it matches the format we're trying to load */ + if( force == qfalse && *((int*) header->ident) != *((int*) game->bspIdent) ) + Error( "%s is not a %s file", filename, game->bspIdent ); + if( force == qfalse && header->version != game->bspVersion ) + Error( "%s is version %d, not %d", filename, header->version, game->bspVersion ); + + /* load/convert lumps */ + numBSPShaders = CopyLump( (bspHeader_t*) header, LUMP_SHADERS, bspShaders, sizeof( bspShader_t ) ); + + numBSPModels = CopyLump( (bspHeader_t*) header, LUMP_MODELS, bspModels, sizeof( bspModel_t ) ); + + numBSPPlanes = CopyLump( (bspHeader_t*) header, LUMP_PLANES, bspPlanes, sizeof( bspPlane_t ) ); + + numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) ); + + numBSPNodes = CopyLump( (bspHeader_t*) header, LUMP_NODES, bspNodes, sizeof( bspNode_t ) ); + + numBSPLeafSurfaces = CopyLump( (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ) ); + + numBSPLeafBrushes = CopyLump( (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ) ); + + numBSPBrushes = CopyLump( (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, sizeof( bspBrush_t ) ); + + CopyBrushSidesLump( header ); + + CopyDrawVertsLump( header ); + + CopyDrawSurfacesLump( header ); + + numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFog_t ) ); + + numBSPDrawIndexes = CopyLump( (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, sizeof( bspDrawIndexes[ 0 ] ) ); + + numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 ); + + numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 ); + bspLightBytes = safe_malloc( numBSPLightBytes ); + CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 ); + + bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1); + + CopyLightGridLumps( header ); + + /* free the file buffer */ + free( header ); +} + + + +/* +WriteIBSPFile() +writes an id bsp file +*/ + +void WriteIBSPFile( const char *filename ) +{ + ibspHeader_t outheader, *header; + FILE *file; + time_t t; + char marker[ 1024 ]; + int size; + + + /* set header */ + header = &outheader; + memset( header, 0, sizeof( *header ) ); + + //% Swapfile(); + + /* set up header */ + *((int*) (bspHeader_t*) header->ident) = *((int*) game->bspIdent); + header->version = LittleLong( game->bspVersion ); + + /* write initial header */ + file = SafeOpenWrite( filename ); + SafeWrite( file, (bspHeader_t*) header, sizeof( *header ) ); /* overwritten later */ + + /* add marker lump */ + time( &t ); + sprintf( marker, "I LOVE MY Q3MAP2 %s on %s)", Q3MAP_VERSION, asctime( localtime( &t ) ) ); + AddLump( file, (bspHeader_t*) header, 0, marker, strlen( marker ) + 1 ); + + /* add lumps */ + AddLump( file, (bspHeader_t*) header, LUMP_SHADERS, bspShaders, numBSPShaders * sizeof( bspShader_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_PLANES, bspPlanes, numBSPPlanes * sizeof( bspPlane_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, numBSPLeafs * sizeof( bspLeaf_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_NODES, bspNodes, numBSPNodes * sizeof( bspNode_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, numBSPBrushes*sizeof( bspBrush_t ) ); + AddBrushSidesLump( file, header ); + AddLump( file, (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_MODELS, bspModels, numBSPModels * sizeof( bspModel_t ) ); + AddDrawVertsLump( file, header ); + AddDrawSurfacesLump( file, header ); + AddLump( file, (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, numBSPVisBytes ); + AddLump( file, (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, numBSPLightBytes ); + AddLightGridLumps( file, header ); + AddLump( file, (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, bspEntDataSize ); + AddLump( file, (bspHeader_t*) header, LUMP_FOGS, bspFogs, numBSPFogs * sizeof( bspFog_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[ 0 ] ) ); + + /* emit bsp size */ + size = ftell( file ); + Sys_Printf( "Wrote %.1f MB (%d bytes)\n", (float) size / (1024 * 1024), size ); + + /* write the completed header */ + fseek( file, 0, SEEK_SET ); + SafeWrite( file, header, sizeof( *header ) ); + + /* close the file */ + fclose( file ); +} diff --git a/tools/quake3/q3map2/bspfile_rbsp.c b/tools/quake3/q3map2/bspfile_rbsp.c new file mode 100644 index 00000000..2e09510c --- /dev/null +++ b/tools/quake3/q3map2/bspfile_rbsp.c @@ -0,0 +1,339 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define BSPFILE_RBSP_C + + + +/* dependencies */ +#include "q3map2.h" + + + + +/* ------------------------------------------------------------------------------- + +this file handles translating the bsp file format used by quake 3, rtcw, and ef +into the abstracted bsp file used by q3map2. + +------------------------------------------------------------------------------- */ + +/* constants */ +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define LUMP_LIGHTARRAY 17 +#define HEADER_LUMPS 18 + + +/* types */ +typedef struct +{ + char ident[ 4 ]; + int version; + + bspLump_t lumps[ HEADER_LUMPS ]; +} +rbspHeader_t; + + + +/* light grid */ +#define MAX_MAP_GRID 0xffff +#define MAX_MAP_GRIDARRAY 0x100000 +#define LG_EPSILON 4 + + +static void CopyLightGridLumps( rbspHeader_t *header ) +{ + int i; + unsigned short *inArray; + bspGridPoint_t *in, *out; + + + /* get count */ + numBSPGridPoints = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTARRAY, sizeof( *inArray ) ); + + /* allocate buffer */ + bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) ); + memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) ); + + /* copy */ + inArray = GetLump( (bspHeader_t*) header, LUMP_LIGHTARRAY ); + in = GetLump( (bspHeader_t*) header, LUMP_LIGHTGRID ); + out = bspGridPoints; + for( i = 0; i < numBSPGridPoints; i++ ) + { + memcpy( out, &in[ *inArray ], sizeof( *in ) ); + inArray++; + out++; + } +} + + +static void AddLightGridLumps( FILE *file, rbspHeader_t *header ) +{ + int i, j, k, c, d; + int numGridPoints, maxGridPoints; + bspGridPoint_t *gridPoints, *in, *out; + int numGridArray; + unsigned short *gridArray; + qboolean bad; + + + /* allocate temporary buffers */ + maxGridPoints = (numBSPGridPoints < MAX_MAP_GRID) ? numBSPGridPoints : MAX_MAP_GRID; + gridPoints = safe_malloc( maxGridPoints * sizeof( *gridPoints ) ); + gridArray = safe_malloc( numBSPGridPoints * sizeof( *gridArray ) ); + + /* zero out */ + numGridPoints = 0; + numGridArray = numBSPGridPoints; + + /* for each bsp grid point, find an approximate twin */ + Sys_Printf( "Storing lightgrid: %d points\n", numBSPGridPoints ); + for( i = 0; i < numGridArray; i++ ) + { + /* get points */ + in = &bspGridPoints[ i ]; + + /* walk existing list */ + for( j = 0; j < numGridPoints; j++ ) + { + /* get point */ + out = &gridPoints[ j ]; + + /* compare styles */ + if( *((unsigned int*) in->styles) != *((unsigned int*) out->styles) ) + continue; + + /* compare direction */ + d = abs( in->latLong[ 0 ] - out->latLong[ 0 ] ); + if( d < (255 - LG_EPSILON) && d > LG_EPSILON ) + continue; + d = abs( in->latLong[ 1 ] - out->latLong[ 1 ] ); + if( d < 255 - LG_EPSILON && d > LG_EPSILON ) + continue; + + /* compare light */ + bad = qfalse; + for( k = 0; (k < MAX_LIGHTMAPS && bad == qfalse); k++ ) + { + for( c = 0; c < 3; c++ ) + { + if( abs( (int) in->ambient[ k ][ c ] - (int) out->ambient[ k ][ c ]) > LG_EPSILON || + abs( (int) in->directed[ k ][ c ] - (int) out->directed[ k ][ c ]) > LG_EPSILON ) + { + bad = qtrue; + break; + } + } + } + + /* failure */ + if( bad ) + continue; + + /* this sample is ok */ + break; + } + + /* set sample index */ + gridArray[ i ] = (unsigned short) j; + + /* if no sample found, add a new one */ + if( j >= numGridPoints && numGridPoints < maxGridPoints ) + { + out = &gridPoints[ numGridPoints++ ]; + memcpy( out, in, sizeof( *in ) ); + } + } + + /* swap array */ + for( i = 0; i < numGridArray; i++ ) + gridArray[ i ] = LittleShort( gridArray[ i ] ); + + /* write lumps */ + AddLump( file, (bspHeader_t*) header, LUMP_LIGHTGRID, gridPoints, (numGridPoints * sizeof( *gridPoints )) ); + AddLump( file, (bspHeader_t*) header, LUMP_LIGHTARRAY, gridArray, (numGridArray * sizeof( *gridArray )) ); + + /* free buffers */ + free( gridPoints ); + free( gridArray ); +} + + + +/* +LoadRBSPFile() +loads a raven bsp file into memory +*/ + +void LoadRBSPFile( const char *filename ) +{ + rbspHeader_t *header; + + + /* load the file header */ + LoadFile( filename, (void**) &header ); + + /* swap the header (except the first 4 bytes) */ + SwapBlock( (int*) ((byte*) header + sizeof( int )), sizeof( *header ) - sizeof( int ) ); + + /* make sure it matches the format we're trying to load */ + if( force == qfalse && *((int*) header->ident) != *((int*) game->bspIdent) ) + Error( "%s is not a %s file", filename, game->bspIdent ); + if( force == qfalse && header->version != game->bspVersion ) + Error( "%s is version %d, not %d", filename, header->version, game->bspVersion ); + + /* load/convert lumps */ + numBSPShaders = CopyLump( (bspHeader_t*) header, LUMP_SHADERS, bspShaders, sizeof( bspShader_t ) ); + + numBSPModels = CopyLump( (bspHeader_t*) header, LUMP_MODELS, bspModels, sizeof( bspModel_t ) ); + + numBSPPlanes = CopyLump( (bspHeader_t*) header, LUMP_PLANES, bspPlanes, sizeof( bspPlane_t ) ); + + numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) ); + + numBSPNodes = CopyLump( (bspHeader_t*) header, LUMP_NODES, bspNodes, sizeof( bspNode_t ) ); + + numBSPLeafSurfaces = CopyLump( (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ) ); + + numBSPLeafBrushes = CopyLump( (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ) ); + + numBSPBrushes = CopyLump( (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, sizeof( bspBrush_t ) ); + + numBSPBrushSides = CopyLump( (bspHeader_t*) header, LUMP_BRUSHSIDES, bspBrushSides, sizeof( bspBrushSide_t ) ); + + numBSPDrawVerts = GetLumpElements( (bspHeader_t*) header, LUMP_DRAWVERTS, sizeof( bspDrawVerts[ 0 ] ) ); + SetDrawVerts( numBSPDrawVerts ); + CopyLump( (bspHeader_t*) header, LUMP_DRAWVERTS, bspDrawVerts, sizeof( bspDrawVerts[ 0 ] ) ); + + numBSPDrawSurfaces = GetLumpElements( (bspHeader_t*) header, LUMP_SURFACES, sizeof( bspDrawSurfaces[ 0 ] ) ); + SetDrawSurfaces( numBSPDrawSurfaces ); + CopyLump( (bspHeader_t*) header, LUMP_SURFACES, bspDrawSurfaces, sizeof( bspDrawSurfaces[ 0 ] ) ); + + numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFogs[ 0 ] ) ); + + numBSPDrawIndexes = CopyLump( (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, sizeof( bspDrawIndexes[ 0 ] ) ); + + numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 ); + + numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 ); + bspLightBytes = safe_malloc( numBSPLightBytes ); + CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 ); + + bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1); + + CopyLightGridLumps( header ); + + /* free the file buffer */ + free( header ); +} + + + +/* +WriteRBSPFile() +writes a raven bsp file +*/ + +void WriteRBSPFile( const char *filename ) +{ + rbspHeader_t outheader, *header; + FILE *file; + time_t t; + char marker[ 1024 ]; + int size; + + + /* set header */ + header = &outheader; + memset( header, 0, sizeof( *header ) ); + + //% Swapfile(); + + /* set up header */ + *((int*) (bspHeader_t*) header->ident) = *((int*) game->bspIdent); + header->version = LittleLong( game->bspVersion ); + + /* write initial header */ + file = SafeOpenWrite( filename ); + SafeWrite( file, (bspHeader_t*) header, sizeof( *header ) ); /* overwritten later */ + + /* add marker lump */ + time( &t ); + sprintf( marker, "I LOVE MY Q3MAP2 %s on %s)", Q3MAP_VERSION, asctime( localtime( &t ) ) ); + AddLump( file, (bspHeader_t*) header, 0, marker, strlen( marker ) + 1 ); + + /* add lumps */ + AddLump( file, (bspHeader_t*) header, LUMP_SHADERS, bspShaders, numBSPShaders * sizeof( bspShader_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_PLANES, bspPlanes, numBSPPlanes * sizeof( bspPlane_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, numBSPLeafs * sizeof( bspLeaf_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_NODES, bspNodes, numBSPNodes * sizeof( bspNode_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, numBSPBrushes*sizeof( bspBrush_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_BRUSHSIDES, bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_MODELS, bspModels, numBSPModels * sizeof( bspModel_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_DRAWVERTS, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVerts[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_SURFACES, bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) ); + AddLump( file, (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, numBSPVisBytes ); + AddLump( file, (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, numBSPLightBytes ); + AddLightGridLumps( file, header ); + AddLump( file, (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, bspEntDataSize ); + AddLump( file, (bspHeader_t*) header, LUMP_FOGS, bspFogs, numBSPFogs * sizeof( bspFog_t ) ); + AddLump( file, (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[ 0 ] ) ); + + /* emit bsp size */ + size = ftell( file ); + Sys_Printf( "Wrote %.1f MB (%d bytes)\n", (float) size / (1024 * 1024), size ); + + /* write the completed header */ + fseek( file, 0, SEEK_SET ); + SafeWrite( file, header, sizeof( *header ) ); + + /* close the file */ + fclose( file ); +} diff --git a/tools/quake3/q3map2/changelog.q3map1 b/tools/quake3/q3map2/changelog.q3map1 new file mode 100644 index 00000000..e9be59b6 --- /dev/null +++ b/tools/quake3/q3map2/changelog.q3map1 @@ -0,0 +1,371 @@ +Old Q3Map 1.x and Early Q3Map2 Changelog (Chronological Order) + +- FILE IS STATIC. IF YOU MAKE CHANGES, UPDATE CHANGELOG.Q3MAP2 - + + +Date Version Notes +---------------------------------------------------------------- +2001-12-03 1.2 (ydnar) Alpha Initial version (win32) + +2001-12-03 1.2 (ydnar 2) Alpha Tolerance expanded + (more brush faces caught) + +2001-12-04 1.2 (ydnar 3) Alpha Detail faces inside other + detail brushes now culled, + Small against large detail + faces also culled. + +2001-12-04 1.2 (ydnar 4) Alpha djbob found a bug where + coincident caulk faces + were causing textured + faces to be caulked. Fixed. + +2001-12-04 1.2 (ydnar 7) Alpha 5 and 6 were internal test + versions. This version + takes into account extra + surface info, so coplanar + clip brushes no longer + cull away textured sides. + +2001-12-22 1.2 (ydnar 8) Alpha Optimized light. Lighting + for most maps should now + be measurable in minutes + as opposed to hours. + +2001-12-24 1.2 (ydnar 9) Alpha Fixed light. It is still + faster, but to enable + "blinding fast" mode, + you must supply the -fast + switch on the commandline + after -light. Fast mode + should be approximately + 2x as fast as build 8. + +2001-12-24 1.2 (ydnar 10) Alpha Grid lighting is now + optimized. Not as much + as I would like, but + a distance^2 cull before + traces on EVERY SINGLE + SURFACE LIGHT IN THE MAP + certainly speeds things + the fuck up. -fast not + necessary to see this + optimization. Also added + the -cheap switch to + limit light contributions + to a point when it exceeds + 255 in R, G, and B. This + *may* cause artifacts. + Test away... + +2001-12-24 1.2 (ydnar 11) Alpha Now using PVS data (vis). + Well constructed and + hinted maps should now + see a bit of a speedup. + Lights in the void are + also now removed as a + byproduct. + +2001-12-24 1.2 (ydnar 12) Alpha Fixed bug that caused + vlight to crash. + +2001-12-27 1.2 (ydnar 13) Alpha - Fixed broken PVS check. + - Cheap now supresses sun + Sun trace skipped if + sample is "cheapened." + - Experimental -smooth + option for subsampling + shadow edges. + - Experimental radiosity + code. Will probably crash. + - Other minor optimizations. + +2001-12-27 1.2 (ydnar 14) Alpha Build 13 always subsampled, + making it slower. Fixed. + +2001-12-28 1.2 (ydnar 15) Alpha Bad windings from edge- or + vertex- manipulated brushes + no longer created. Vertex + lighting on func_* with + an origin now works. + Radiosity should be more + stable (but not fully + correct yet). Light + envelopes now properly + calculated for entities + with origins. + +2001-12-28 1.2 (ydnar 16) Alpha Un-vised maps will now light. + +2001-12-30 1.2 (ydnar 17) Alpha Radiosity. Use q3map_bounce + in shaders to specify + amount of light to reflect. + Use -bounce N after -light + to enable radiosity. Use + -dump to emit radiosity + lights as a prefab. + +2001-12-31 1.2 (ydnar 18) Alpha Normalization release. New + features include -fastgrid, + -cheapgrid, and -fastbounce. + Running with -fastgrid and + -cheapgrid will produce + results identical to normal + q3map (with the lightgrid + being a little darker). + Also added q3map_nofast to + shaders to override -fast + switch for a surface light. + +2002-01-01 1.2 (ydnar 19) Alpha Fixed an odd vertex lighting + bug (thanks Quakin) that was + causing sun to leak to brush + faces when using r_vertexlight + ingame. Changed a little bit + of the default behavior, so + test with vertex lighting + and with terrain. Minor + shader changes might be + necessary to get some maps to + look as before. + +2002-01-01 1.2 (ydnar 20) Alpha Colored alpha shadows. Some + minor optimizations in + shadow tracing. Should be + slightly faster than 19. + +2002-01-02 1.2 (ydnar 21) Alpha Set up colored shadows + properly to use + surfaceparm lightfilter. + Shaders must use this parm + to have colored shadows. + Can be used with alphashadow + as well. + +2002-01-04 1.2.1-y1 (nightly) This version is all new, + based off the official + GtkRadiant tree, which has + all the previous enhancements. + New features include colored + lightgrid tracing through + lightfilter shaders, and + surfaceparm lightgrid, for + large/space maps with large + volumes. Also fixed are + potential broken brush + winding radiosity crashes. + Maybe. + +2002-01-05 1.2.1-y2 (nightly) Merged latest CVS. Removed + bug where ambient was getting + calculated into the radiosity + solution for every pass, + leading to overbright maps + in a hurry. Also removed + the bad PTPFF reporting, + as it only caused problems + with radiosity in a big way. + Sue me. + +2002-01-05 1.2.1-y3 (nightly) I really suck. Sample color + now properly cleared to 0 + when bouncing. + +2002-01-07 1.2.1-y4 (nightly) Particle Studio generated + brush faces should no longer + be culled. I no longer cull + faces that are autosprite. + Added -bouncegrid to have + radiosity add to lightgrid. + +2002-01-08 1.2.1-y5 (nightly) Same as y4, but compiled with + full optimizations. Should + be 10-25% faster in all, + including BSP and vis + stages. + +2002-01-09 1.2.1-y6 (nightly) Brushfaces with polygonoffset + in their shader will no longer + be faceculled. + +2002-01-11 1.2.1-y7 (nightly) Increased stack size for threads + to 4MB on Win32 to (hopefully) + elminate stack overflow + crash with radiosity. Also + made subdivision use the heap + to lessen the stack load. Fixed + bug where q3map_bounce was not + being used in shader parsing. + Redid some of the divide math + to work in 0-255 instead of + 0-256. + +2002-01-11 1.2.1-y8 (nightly) More Win32 threading + crutches. Eat me, Bill. + +2002-01-15 1.2.1-y9 RR2DO2 noticed a stupid bug + in my PVS code. Fixed it, + so the PVS light opts work as + they should. Lighting is + faster. Also got rid of some + redundant square roots from + the raytracing, speeding up + lighting another ~25%. + +2002-01-20 1.2.1-y10 Fixed a potential crash bug + with maps with 0 lights. Also + changed how lightmaps are + projected onto patches that + lie in a single plane (bevel + endcaps, floors, etc). Shadows + now work properly on them. + +2002-01-22 1.2.1-y11 Fixed a divide-by-zero crash + with maps with no lights or + no tracing. Also added + code to make brush/patch + vertex lighting more closely + resemble lightmap, even on + less-than-perfect maps. And + -light is faster, too...about + 25% on q3dm17. 34->25 seconds. + +2002-01-24 1.2.1-y12 Completely rewrote the path + argument handling. Should find + the Quake 3 dir and other + dirs properly now. Needs to + be tested on Linux though. + Also made lights linear by + default when run with -game + wolf. This is to match the + Gray Matter q3map and + entity definition. + +2002-01-28 1.2.4-y1 Merged from 1.2.4-nightly CVS + sources. Fog sparklies gone. + -nopatchfix so vlight works + properly again. Cleaned up + paths processing some more, + including Linux stuff. Added + _lightmapscale entity key. + Brought -game wolf lighting + to parity with GM tools. + RR2DO2's PCX loading fix. A + bunch of other useful fun shit. + +2002-01-29 1.2.4-y2 Fixed a bug in RR2DO2's PCX fix. + Fixed a stupid bug in lightmap + dimension bounds checking (thanks + Laerth). + +2002-01-29 1.2.4-y3 Now will detect (and report to + GtkRadiant) all degenerate patches + like those created by capping a + cone. + +2002-02-23 2.0.0-a1 thru a3 Rewrote about 30% of the code. + Lots of cool new shit. + +2002-02-24 2.0.0-a4 thru a8 Terrain fix (thx Pointy), patches + are no longer circus colored, more + terrain texturing fixes. + +2002-02-26 2.0.0-a10 thru a11 Adjacent coplanar surfaces now + will share lightmaps. This prevents + most wierd edge cases with filter + and speeds things up a bit. Patches + too. + +2002-02-27 2.0.0-a12 More lightmap fixes for non-planar + surfaces. Bugfixes in allocation/ + compression of lightmaps as well. + +2002-03-02 2.0.0-a13 Fixed some surface light bugs, + adjusted the occluded-luxel finding + code, and amped the radiosity. Other + fixes to RTCW lighting code (better + angle attenuation on linear lights). + +2002-03-04 2.0.0-a14 Vertex light should now be near- + perfect on clean (and mostly on not- + so-clean) maps. Unlit maps will no + longer have tri-fanned brush faces + with random vertex colors. VLight is + now totally gone (reverts to -light). + +2002-03-06 2.0.0-a15 Relaxed the planar check, should now + classify all slightly-off plane brush + face metasurfaces as planar. Triangle + checking much more stringent as well. + +2002-03-11 2.0.0-a16 Vis crash gone. Lightmap allocation + now sorted by shader to minimize + shader count (and lessen chance for + RTCW shader substitution bug). Hit + big quarter-century also. + +2002-03-12 2.0.0-a17 Dammit. + +2002-03-12 2.0.0-a18 Hunting phantom lights... + +2002-03-16 2.0.0-a19 Fogclip and _celshader. Check the + extras folder... + +2002-03-18 2.0.0-b1-rc1 Beta release candidate. Fixed the + stupid phantom light bug finally. + Tricked out the sun tracing a wee + bit as well, should be a little + faster + more accurate. Other little + bits fixed up as well. Thanks to K, + {wf}ShadowSpawn and RR2DO2 for their + help tracking these last bugs down. + +2002-03-19 2.0.0-b1-rc2 Increased some maximums, and got + rid of some cruft. + +2002-03-22 2.0.0-b1-rc3 Some minor optimizations. + +2002-03-30 2.0.0-b1-rc5 Now with fur (see extras/fur.shader). + +2002-04-01 2.0.0-b1-rc6 Enhanced with baby seal technology. + +2002-05-01 2.0.1 OK, better late than never. Fixed the + alphashadow = 255 = transparent bug. + +2002-06-24 2.1.0-b1 Added _foghull functionality. Works + like terrain "_shader" where + you don't need "textures/" prefix. + Also added q3map_normalmap. See + NVIDIA's website for Photoshop filter + to generate normalmaps from grayscale + heightmaps. This makes lightmaps + look bumpmapped. Currently 50% broken. + +2002-07-06 2.2.0-b1 Empty epairs now stripped from map, + fixing Wolfenstein crash bug. Func_* + entities are now fogged properly. + Sort of. This will be enhanced later. + Added the .srf file to store all the + extra crap I was hiding in the BSP. + It's an editable text file that + -light uses, so you can change the + samplesize w/o recompiling the map + (just -light'ing it). Changed color + normalization to clamping, because + it looks better. Other stuff got + fixed as well. + +2002-07-08 2.2.0-b2 thru b11 Test versions. Thanks jer and jet! + +2002-07-09 2.2.0-b12 Larger-than-life lightmaps are now + supported, up to 1024x1024. Add + q3map_lightmapSize H W to a shader + to use. Lightmaps are stored in + maps/{mapname}/_lm_NNN.tga and a + shader script q3map_{mapname}.shader + is generated. Also added + q3map_lightmapGamma N.N. Use a + value of 2.0 to simulate + r_overBrightBits 1 and + r_mapOverBrightBits 2 on external + lightmap images. diff --git a/tools/quake3/q3map2/changelog.q3map2.txt b/tools/quake3/q3map2/changelog.q3map2.txt new file mode 100644 index 00000000..29446abd --- /dev/null +++ b/tools/quake3/q3map2/changelog.q3map2.txt @@ -0,0 +1,607 @@ +Q3Map2 Version History + Changelog (Reverse Chronological Order) + +2.5.11 (2003-12-01) + +- New: added support for _skybox entities to generate "portal sky" + surfaces in games w/o native support (Quake 3). _skybox entities have + 3 keys: _scale (default 64), and angle/angles (for rotation of the + skybox relative to the map) +- New: added -skyfix switch to BSP phase as a workaround hack for + the black GL_CLAMP border on skybox edges on ATI (and newer nvidia) + video cards. Note: unnecessary in ET or JA +- New: Added _anglescale to light entities for scaling angle attenuation. + Use a small value (< 1.0) to lessen the angle attenuation, and a high + value (> 1.0) for sharper, more faceted lighting +- New: Added _lightmapscale support to misc_model entities +- Custom shaders (external lightmaps, styles) will not be generated + if the find/replace text cannot be found +- Tightened up light culling epsilon from 1.0 to 0.125 to stop certain + surface lights from being incorrectly culled (thanks RasputiN!) +- Fixed bug where small 3 and 4 sided brush faces were getting fanned, + adding triangle/vertex counts +- Moved to Visual Studio .NET, with aggressive optimizations enabled +- Cleaned up missing image warnings +- Parsing images out of shader stages if not found explicit/implicitly +- Loads Enemy Territory implicitMap images if editor/light image not found + + +2.5.10 (2003-10-22) + +- New: Lightwave model support (beta) courtesy of RR2DO2 +- New: Heretic 2 FM model support courtesy of Nurail +- Re-enabled vertex cache friendly triangle reordering with fix +- Disabled triangle reordering on certain surfaces, including autosprite + shaders due to visual errors +- Fixed bug in radiosity where sorting of lights by style took forever. + Thanks ReBoOT! +- Fixed bug in sun lighting code where maps too far off the origin would + not be properly it by sun or sky light. Thanks MindLink! +- Entity causing a leak will be printed and selected in Radiant if BSP + monitoring is enabled. Requested by heeen +- Fixed odd bug causing 10x slowdown in lighting in some maps. Should + be back to 2.5.7 performance. Also fixed a couple old bugs related to + autosprite shader (point) lights and backsplash lights not being styled + or setup correctly + + +2.5.9 (2003-10-12) + +- Disabled triangle reordering for now (crashing on some maps) + + +2.5.8 (2003-10-02) + +- New: Added two new sun parameters: angular deviation (width of the sun in + degrees) and sampling count (jitters). This allows for decent approximation + of penumbra "half-shadow" effects from sunlight with 16+ samples. These + parameters are accessible for entity lights (including spots and suns) via + these entity keys: _deviance and _samples. To use in shaders, use the new + q3map_sunExt +- New: q3map_lightmapFilterRadius for light-emitting shaders. + Put *after* any q3map_sun directives or else your sun will be filtered. This + is good for eliminating the "stadium lighting" effect from q3map_skyLight. + Also usable as an entity key: _filterradius or _filter +- New: Quake 2 MD2 model support in PicoModel for misc_model entities + (thanks to Nurail!) +- Re-enabled vertex-cache-aware triangle reordering. Will probably have a + negligible effect on rendering performance, but can't hurt +- Added short-circuit to raytracer: any empty nodes (including children) are + ignored on sun traces +- Added BSP file size printout +- Filtering of any kind now disables adaptive supersampling on a per-light, + per-ightmap basis +- Fixed another _minlight <-> styled light interaction bug (thanks pjw!) + + +2.5.7 (2003-08-31) + +- New: Jedi Academy support via -game ja +- New: DDS (DXT1/3/5) texture support for future games +- Re-enabled q3map_surfaceModel support, and the 'oriented' flag works as well +- Re-enabled (fixed, really) large external lightmap support +- Fixed a bug in the model code that would cause a crash if an uninvertable + matrix was created +- Fixed a bug in Mathlib m4x4_t code where the tolerance for a singular matrix + was too low and crapping out on small (scaled down) matrices +- Fixed bug in divide-by-zero on lightmap efficiency calculation +- Added -force switch, allows unsupported BSP formats to (try) to be loaded + + +2.5.6 (2003-08-15) + +- New: can convert BSP files to MAP files via -convert -format map. Note: not + perfect by any means, as certain pieces of data are irretrievably lost, such + as func_group entities (including terrain specifics), brush face texturing + info, and light/misc_model entities with Q3Map2-generated BSPs + + +2.5.5 + +- New: -scale N.N mode to scale the BSP +- New: -light -lomem switch to supress trace BSP optimization. This + feature trades lighting performance for decreased memory usage +- New: Added negative light support (note: will not darken below _minlight value) + might screw up radiosity, haven't tested much. Should work with entity + lights, shader lights, sun/sky lights and radiosity. Lightfilter shadows + tint negative lights too, so the end effect is subtraction of the color +- New: Lightstyle support for non-Raven (JK2/SOF2) games, including Quake 3, + RTCW, ET, EF. Only works with lightmapped surfaces, use with care +- Fixed long standing terrain texturing bug, should produce exact desired + results all of the time now. May require fixing alphamaps that were + kludged together to accomodate this bug on existing maps +- Fixed bug (huh, wtf) causing misc_model surfaces to not be fogged +- Fixed bug where fog brushes wouldn't fog surfaces if a global map fog + shader was present +- Fixed bug where -patchmeta surfaces were being ignored for raytracing +- Fixed long-standing bug where twosided surfaces were not correctly + bouncing light. You can now have a foggy glass window that re-emits + bright light with q3map_bounce 3.0 or so +- Fixed really stupid bug in radiosity with bouncing styled lights +- Stripping .map and appending .bsp in -info mode +- Fixed bug where tesselated brush face surfaces were not being fogged +- Twosided surfaces (using cull disable/twosided/none) are now lit twosided +- Added tighter tolerance for alphashadow/lightfilter shadowing to raytracer + which fixed problem with double shadows from tracing near triangle seams +- Brush entities should now be properly fogged. Really. +- Styled lightmaps are no longer affected by _minlight (doh) + + +2.5.4 (2003-04-01) + +- New: q3map_tessSize support for JK2/SOF2 +- New: -lightmapsize N argument +- Fixed bug where switched styled lights weren't working correctly in SOF2/JK2 +- Fixed bug where external lightmaps with generated shaders were referencing + the wrong lightmap +- Fixed bug causing lightgrid brushes to be ignored +- Added variable sphere around trace sample points to inhibit occluder geometry + + +2.5.3 (2003-03-06) + +- New: SOF2/JK2 light styles now supported +- New: q3map_lightStyle N to set shader lightstyles +- New: Tenebrae 2 support via -game tenebrae +- New: -light -deluxe and -debugdeluxe for Tenebrae "deluxemap" static + lighting algorithm +- Light envelopes now properly clipped to the PVS +- q3map_vertexScale re-enabled (scales vertex lighting per-shader) +- Minor bug in brush bevel code corrected +- Brushes from func_group entities are correctly sorted on insertion +- Fixed a couple misc warnings to print "percent" instead of "%" +- Added -custinfoparms support to -light mode to suppress warnings +- _minlight, _minvertexlight and _mingridlight order independent, and now + allow for values of 0 + + +2.5.2 (2003-02-17) + +- Fixed crash bugs with global map fog +- Model loading really only warns once now + + +2.5.1 (2003-02-17) (Splash Damage internal release) + +- Added more Hella-Fast juice to light code. Overall should be 35% faster +- Refactored surface portion of raytracer code for less memory usage +- Changed UVW epsilon in raytracer to catch more edge cases +- Removed bounds check on occluded luxel finding, was causing more problems + than it was solving +- Adaptive antialiasing code now ignores unmapped luxels for better shadow + edges and higher performance +- Brushes in the BSP are now sorted opaque first +- Fixed Really Stupid bug causing MapRawLightmap to take about 4x as long +- Added optimization to make MapRawLightmap 2x as fast +- New non-sucky quadrilateral subdivision of patches for MapRawLightmap +- Patches with < 90 degrees of curvature are now box-lightmapped +- Patch vertex normals now correctly stored, fixing bug in 2.5.0 +- Prints warning if map with < 10% detail brushes is detected + + +2.5.0 (2003-02-14) (Splash Damage internal release) + +RAYTRACING AND SHADOW CALCULATION +- New raytracing code. Rewrote the raytracer to maximize efficiency on modern + "caulk-hull" maps. Uses triangle intercept code written by SPoG, based on code + by Tomas Moller and Ben Trumbore (Journal of Graphics Tools, 2(1):21-28, 1997) + and a biased octree leaf subdivision scheme by Y.T. +- Shadows (casting and receiving) are now controllable per-entity + New entity keys: "_castShadows" or "_cs" and "_receiveShadows" or "_rc" + Values: 0 = no shadows, 1 = worldspawn shadows, > 1 explicit shadow group, + negative values imply no worldspawn shadow interation. + *Entities, including model2 and RTCW misc_gamemodels can now cast shadows* + +RADIOSITY +- Bumped up default and smallest radiosity patch size. Performance should be + approximately 4x with a small quality tradeoff +- Radiosity patches now trace to centroid of triangle, and not bounds center +- Radiosity and surface lights are now nudged around a bit if in solid +- Radiosity light generation code is now thread-safe +- Radiosity -dump files now .map instead of .pfb +- Poorly worded "q3map_bounce" renamed to "q3map_bounceScale" (old still works) +- New -bounceonly switch to store only bounced light in the BSP (for Tenebrae) + +MISC LIGHTING +- Optimized case where light and sample are coplanar +- Forcing nudged luxels to stay within lightmap surfaces' bounds + +CURVED SURFACES +- New -subdivisions N argument, works with -patchmeta and -light for setting + patch level-of-detail. Default value is 8, use 4 to simulate default Q3 +- All patch tesselation code changed to create x-patterned tesselation for + better lighting +- Storing patch LOD info in the .srf file for better patch light/shadows + +FOG +- Reworked fog code to fix bad interation with fog and clipped models + +MODELS +- Entities with attached MD3/ASE misc_models now have their bounds correctly set +- Attached misc_models now support q3map_clipModel for solidity +- Missing models will only warn once, rather than spew errors + +MISC +- Metasurface merging no longer folds nonplanar triangles into planar surfaces + and vice-versa * +- Fixed Really Stupid Bug where entity numbering was not loaded by lighting code + resulting in lightmaps merging across entity boundaries * + +* Might result in slightly larger BSP. For maximum efficiency, ungroup + func_group entities before doing a final compile + +TODO ++ Document new shadow stuff ++ Merge adjacent light-casting triangles into convex windings + + +2.3.38 (2003-02-07) + +- New lighting code, return of Smoove-B. Intelligently antialises shadow edges + when you use the new -samples N switch. Get -extra quality in 1/3 the time +- New lightmap filtering code. Now using a proper 0.25/0.5/1.0 filter kernel. + Also operates on individual lightsources, so per-lightsource filter/kernel + settings are now possible +- New -patchmeta fixes, now does stitching and adaptive subdivision. + Thanks Sock! +- Nonsolid patches will no longer be in the BSP when run with -patchmeta +- Misc fog fixes, including q3map_noFog support in maps with global _fog + support (SOF2/JK2) +- Now stripping misc_model entities from the BSP +- Fixed disappearing face bug that's been present since 2.3.36. + Thanks Shadowspawn! + + +2.3.37 (2003-01-24) + +- Building from GtkRadiant CVS trunk +- Added new brush bevel code by MrElusive to fix lingering aas problems (sweet!) +- Added -snap N arg to BSP phase for axial bevel plane snapping to reduce + clipped model plane count (note: will muck with above, use with care) +- Patches in terrain entities should now have proper vertex alpha set +- Fixed bug in fur code where fur was being limited to 2 layers (thanks pazur) +- Reduced vertexlight search area to a reasonable size to keep vertex lighting + times down + + +2.3.36 (2003-01-15) + +- Plane hashing re-enabled (I suck) +- Plane hashing optimized (faster parsing of larger maps) +- Plane finding accuracy code enabled +- New ASE clipping code + + With above should be 10-50% faster + + Should generate 33% fewer planes + + Generates mostly-axial 5-sided polyhedra instead of pyramids, + for tighter 2-sided clipping +- New -light args: + + -scale N -- scales all lightsources (area, radiosity, point, sky) + + -sky[scale] N -- scales sky lights (q3map_skylight, q3map_sunlight) +- Changed fur code to scale fur offset based on original vertex alpha + + +2.3.35 (2003-01-14) + +- PicoModel now inverts ASE T coordinate +- BSP to ASE converter now inverts T coordinate +- Disabling 2.3.34 triangle optimization code until I find out why it crashes +- Fixed Conscript-q3map2 to use stack_size ld flags directly on Darwin/OS X +- Added Conscript-q3map2 to q3map2.dsp for easier Win32 edit, *nix target + + +2.3.34 (2003-01-08) + +- Building from merged GtkRadiant 1.2 -> 1.3 merged codebase +- IMPORTANT NEW CHANGE: Light entities are now STRIPPED from the BSP file. + They are re-read in by -light from the MAP file. This has two consequences: + + It is no longer necessary to re-BSP & re-vis a map in order to change + lighting. You can just change lights in the map file and run -light. + + Slightly smaller BSP file, due to fewer entities + + Faster loading time, as the game code doesn't have to deal with them +- Added new -ne (normal epsilon) and -de (distance epsilon) for tuning precision + of plane snapping to correct potential AAS/BSP issues +- Using latest PicoModel, with support for RTCW MDC models +- Surfaces per raw lightmap are now sorted by shader name, which should give + slightly better lightmap efficiency and lower in-game shader counts +- Adjusted model code to use correct m4x4_t code & angles key +- Minor bugfix in patch color gradient calculation code +- Silenced erroneous areaportal warning spew +- q3map_tcGen now works on model surfaces +- Using default radiosity subdivide of 256 again (should make radiosity faster) +- Enabled byte-swapping code so Q3Map2 can be compiled/run on little-endian + architectures (Mac OS X) + + +2.3.33 (2002-12-08) + +- Added new -bouncescale argument for radiosity scaling +- Added -pointscale and -areascale for consistent naming +- Radiosity patch subdivision code enhanced +- Hint portals split the BSP first (higher priority) +- Antiportal and areaportal faces split the BSP last, to minimize errors +- Areaportals work internally like hint and antiportals, so they no longer need + to be full brushes (the other sides can be skip) +- External lightmaps are now named "lm_NNNN.tga" in the maps/mapname dir +- Cleaned up some of -light argument processing +- Planar surfaces w/o lightmaps will no longer be tagged as MST_TRIANGLE_SOUP + (this fixes problems with Particle Studio particles dropping out of view) + + +2.3.32 (2002-11-30) + +- GtkRadiant (1.2.11) integration +- Added epsilon to texture plane choose code to eliminate numerical + inconsistencies on brush faces slanted at 45 degree angles (bug 637) +- Fixed bug in lightmap export after lighting when map contains 0 BSP lightmaps +- Adjusted some light tracing constants to fix certain brush/patch seam shadows +- Tinkered with skylight code again +- Fixed bug where lightgrid would be black if level was compiled with -nogrid +- Fixed -approx code to work in floating-point space, using _minlight +- Fixed bug where vertex light code was using invalid pvs data to create + light list for surface, leading to incorrect vertex lighting +- Fixed related bug in anti-light-leak code that was causing brush faces to go + black (bug 694) +- New: _minlight sets _minvertexlight and (new) _mingridlight automatically +- New: _mingridlight key to set minimum grid lighting + + +2.3.31 (2002-11-21) + +- Stitching the edges of lightmaps on patches that wrap around (cyls and cones) + so the seam is no longer visible +- The -patchmeta switch works better now, the patches are still stored in the + BSP for collision, but are pre-tesselated into nonplanar meta surfaces for + more efficient rendering +- Better, more uniform lightmap sample position finding on patch meshes +- Moved q3map_tcMod and q3map_alphaMod processing to the final phase +- New: q3map_skylight AMOUNT ITERATIONS to replace surfacelight on sky surfaces + for much faster and more uniform sky illumination + + +2.3.30 (Splash Damage internal release) + +- Fixed bug in PicoModel ASE material parsing code +- Fixed a few seam/lightmap precision/projection errors +- Increased MAX_SHADER FILES to 1024 and fixed overrun error when more than that + number of shaders was listed in shaderlist.txt +- Increased a few compiler maximums for larger maps +- New: -np N switch on BSP phase, works like -shadeangle, in that it forces all + planar shaders to be nonplanar with the shading angle specified +- New: -nohint switch on BSP phase, omits hint brushes from compile for testing +- New: -debugaxis switch on light mode. Colors lightmaps based on their lightmap + axis (which direction the lightmap was projected on) +- New: -debugorigin switch on light mode. Colors lightmaps based on the luxel + origin relative to the raw lightmap's bounding box +- New: -debugcluster switch on light mode. Colors lightmaps based on the pvs + cluster the luxel falls into +- New: -convert switch to convert BSP to ASE file (experimental) +- New: q3map_lightmapmergable directive to allow terrain to be mapped onto a + single lightmap page for seamless terrain shadows + + +2.3.29 (2002-11-03) + +- Merged with latest CVS, fixed minor issues with matrix order +- Fixed minor Sys_FPrintf/Sys_Printf substitution typo in Q3Map2 +- Expanded debug colors to 12 for debugging surface meshes +- PicoModel: fixed ASE loader to support > 1 texture coordinate per-vertex, + so more models supported correctly, also loading vertex normals +- PicoModel: md3 shader names are now cleaned. Suffixes (such as .tga or .jpg) + are stripped, and \ path separators are changed to / +- New: Add :q3map to the end of any shader name, and it will be interpreted as + the named shader minus :q3map. Example: + textures/shaderlab/concrete:q3map -> textures/shaderlab/concrete + One potential use is the -approx feature to collapse lightmapped surfaces + into vertexlit surfaces, saving lightmap space/memory +- New: q3map_clipModel -- does what you think it does, sort of. This code ix + really experimental, and should *only* be used on large models such as terrain + (not small decorative models). This code will be evolving. Note: the shader's + surfaceparms are inherited by the magic clip brush, so if you have nonsolid + in your model's shader that uses q3map_clipModel, then the brush will also + be nonsolid + + +2.3.28 (2002-11-01) + +- Bug 654 (http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=654): + Fixed problem where brush faces, drawsurfaces, and surfaceparms weren't living + together in perfect harmony (terrain surfaceparms now inherited by brushes) +- Nodraw fog works now, albeit when you're underneath, surfaces above don't get + fogged properly. Could be good for foggy water where you want the above-water + portions to only be occluded by the water surface +- Bug 656 (http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=656): + Number of lightgrid points displayed (byte size is currently out of proportion + due to internal storage format) when Q3Map is called with the -info switch +- Fixed wack surface merging bug where code would attempt to merge triangles not + adjacent to the current set, causing bad lightmap projections on nonplanar + surfaces +- Fixed tiny 1-character bug in 2d lightmap texture allocator where adjacent + luxels were being checked for occlusion rather than the actual source luxel + + +2.3.27 (2002-10-31) Happy Halloween! + +- Fixed minor bug in scriplib bugfix where the last character in a file wasn't + being read. +- Fixed bug where 0-area or bogus triangles were causing crash in MapRawLightmap + if they used a shader with a normalmap (thanks ShadowSpawn) +- Fixed bug where lightmaps were getting hosed levelwide on a prerelease version + of 2.3.27 +- Fixed bug where lightmaps were getting knackered on models and certain patches +- Merged latest PicoModel version from seaw0lf, adding support for ASE and WF OBJ + models (preliminary) +- Increased MAX_MAP_PLANES to 0x40000 (~256k) + +Known issues: +- Lightmap projection and surface merging on large ASE models sometimes flakes +- Surface to brush surfaceparm propogation doesn't work properly with large + metasurfaces: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=654 + + +2.3.26 (2002-10-27) + +- Now using GtkRadiant's libpng and zlib config (linked as DLLs) +- Fixed bug in script parser where repeat calls to GetToken() were causing + memory corruption +- Fixed SOF2 -rename bug +- When using -game sof2 or -game jk2, the -flares argument is implied +- Added -noflares argument to disable the above behavior +- Added support for flares on entities. Use one of the following keys: + "_flare" "1" -- use default flare (different for each game) + "_flareshader" "path/to/flareshader" -- use a specific flare shader + Note: This only matters in SOF2/JK2 now. Make a light targetted (a spotlight) + to get it to aim the correct direction, otherwise it defaults to pointing + downward. You cannot have omnidirectional flares +- Lightgrid size is automatically increased to accomodate large maps. The + MAX_MAP_LIGHTGRID error will never happen again + + +2.3.25 (2002-10-22) + +- Go Giants! +- Fixed bug where Q3Map would crash on writing the BSP after the light stage. + Thanks to Rap7or (#q3map) and loon8 (Q3W forums) [bug 641] +- Fixed bug where surface lights were not affecting the light grid properly. + Thanks to Shadowspawn and djbob [bug 642] +- NEW: Added -faster support to lightgrid calculations while fixing previous bug +- NEW: Changed it so the BSP file is written to a temp file first, then renamed. + This should prevent BSP file corruption on crashes during writes + + +2.3.24 (2002-10-20) + +- Fixed numerous outstanding bugs and issues. +- Normal interpolation is now improved. It's slightly slower, but more 'correct' + in cases where you have 10 triangles in one plane and 1 triangle in another + meeting up and the 10 triangles were over-affecting the average. Only new + identical normals are averaged now. This change affects phong shading, meta + surfaces, and PicoModel +- PicoModel up to version 0.7.6, BSD license, better 3DS model support +- PicoModel library now fixes broken normals on MD3 and 3DS models +- Bumpmapping code is improved. The correct tangent vectors per-triangle are + now calculated so the bumpmaps are consistent with regards to light direction +- Metasurface merging code optimized. Should be about 100x as fast on complex + maps or maps using models with high triangle counts +- Vertexlight code tweaked a bit +- Triangle/winding orders now more consistent. Tesselated surfaces will have + a uniform triangle ordering (thanks RR2DO2) +- NEW: "vertexDeform move" now parsed and surfaces are merged into the + appropriate BSP leaves they may enter into (thanks to Bart Vrijkorte) +- NEW: shader command: q3map_alphaMod. Currently takes a single form: + q3map_alphaMod dotproduct ( NX NY NZ ) + where NX NY NZ are a unit normal (length of 1.0) specifying direction. + An example use would be snow in a shader's 2nd pass, using alphaFunc or + blendFunc: + q3map_alphaMod dotproduct ( 0 0 1 ) // surfaces facing upwards have snow + (idea contributed by RR2DO2) + + +2.3.23 (2002-10-18) + +- In my haste to release the previous version, I neglected to give credit where + it was due. Seaw0lf had as much (probably more) to do with the new model + loading library (PicoModel). Because of his efforts, you can load 3DS models + and use them in misc_model entities. +- PicoModel model library up to version 0.7. Improved 3DS support, more stable. +- Surface models still not reenabled. Soon. :) +- You can now remap a misc_model's shaders like this: + Key "_remapNN" "the/model/shader;the/real/shader" + This works just like TA terrain vertexRemapShader key. You can also supply a + * glob for the source shader if you want all your model's shaders to use the + specified shader: + "_remap" "*;models/mapobjects/tree/bark" + + +2.3.22 (2002-10-16) + +- Moving to sensible Linux-style versioning. +- The misc_model code has been completely rewritten, breaking surface models. + Surface models will reappear in the next release, once the new model API has + stablized. +- New: MD3 and 3D Studio 3DS models now natively supported. +- The misc_model "angles" key now supported. Values: "pitch yaw roll" in keeping + with standard Quake 3 angles order. +- Models scaled with "modelscale_vec" now have proper normal scaling/rotation + (thanks SPOG). +- Models can now be lightmapped. +- Models can now have > 1000 vertexes per surface. +- For best results for above, add the following to models' shaders: + q3map_splotchfix + q3map_nonplanar +- 3DS models' MATERIAL NAMES ARE THE FINAL Q3 SHADER NAMES. YOU HAVE BEEN WARNED. +- Models are generally 13373R. :) + + +2.3.0-a21 (2002-10-02) + +- Fixed a stack of really stupid bugs in the lightgrid code. Should be faster + and more predictable now. +- SOF2/JK2 lightgrid now compiled. This is the first version of Q3Map2 that can + compile full, release-worthy SOF2 and JK2 maps. +- SOF2/JK2 damageshader and damagable brush faces should work correctly now. + + +2.3.0-a20 (2002-09-26) + +- SOF2/JK2 worldspawn "fog" (and "_fog") shader key support for levelwide fog +- SOF2/JK2 light "scale" key to scale light brightness +- SOF2/JK2 -rename function for _bsp and _rmg_bsp shader renaming + + +2.3.0-a19 (2002-09-24) + +- Shaders can now be subclassed (Q3Map relavant portions only, such as + surfaceparms, lighting, texture projection, etc). To subclass an existing + shader, add "q3map_baseshader X" where X is the name of the base shader. +- Preliminary auto-model distribution over surfaces. You can now have things + like grass and tree models automatically distributed across your terrain + or other surfaces. To wit: + + q3map_surfacemodel models/mapobjects/tree2/tree2.md3 64 0.001 0.5 4.0 0 360 1 + + q3map_surfacemodel + + + The last flag is 1 or 0, and sets whether the model gets fitted to the + orientation of the surface. Not functional yet. See screenshots page for + shots of this in action. + + +2.3.0-a18 (2002-09-21) + +- misc_models can now be attached to any brush model entity. Just target the + brush entity with the misc_model (select model, then entity, hit Ctrl+K) +- q3map_tcMod translate (or shift or offset) +- q3map_tcMod rotate (rotates around origin, not center) +- q3map_tcMod scale +- Metasurface merging now much, much better. Merges into roughly rectangular or + square areas wherever possible +- q3map_terrain no longer sets Z-axis lightmap projection. It must be set in + the terrain layer shaders if you want previous behavior +- Worlspawn _blocksize key now supports 3 elements for setting X Y and Z splits + independently of each other (use a value of 0 for no splits on that axis) +- Misc bugfixes + + +2.3.0-a1 through 2.3.0-a17 (2002-07 through 2002-09-20) + +- Elite Force support (via -game ef) +- SOF2 and JK2 support (via -game sof2 or -game jk2) +- All new image handling with PNG support +- q3map_lightimage specifies image for radiosity and lighting +- External lightmaps, set using q3map_lightmapsize . Up to + 1024 x 1024 supported. +- q3map_lightmapGamma sets the brightness scale of a lightmap +- q3map_lightmapsampleoffset to fix glitches in lightmapped terrain +- Tons more features and bugfixes. See the forum threads for details/screenshots +- Two new surfaceparms, "antiportal" and "skip," and associated shaders, for + allowing the mapper to more cleanly set up visibility data +- Lightmaps will always have square texels now (no more stretching) +- Vertex light improvements +- Light grid improvements +- q3map_lightrgb support for RTCW + + + + + + diff --git a/tools/quake3/q3map2/convert_ase.c b/tools/quake3/q3map2/convert_ase.c new file mode 100644 index 00000000..1d937c76 --- /dev/null +++ b/tools/quake3/q3map2/convert_ase.c @@ -0,0 +1,374 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define CONVERT_ASE_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +ConvertSurface() +converts a bsp drawsurface to an ase chunk +*/ + +static void ConvertSurface( FILE *f, bspModel_t *model, int modelNum, bspDrawSurface_t *ds, int surfaceNum, vec3_t origin ) +{ + int i, v, face, a, b, c; + bspDrawVert_t *dv; + vec3_t normal; + char name[ 1024 ]; + + + /* ignore patches for now */ + if( ds->surfaceType != MST_PLANAR && ds->surfaceType != MST_TRIANGLE_SOUP ) + return; + + /* print object header for each dsurf */ + sprintf( name, "mat%dmodel%dsurf%d", ds->shaderNum, modelNum, surfaceNum ); + fprintf( f, "*GEOMOBJECT\t{\r\n" ); + fprintf( f, "\t*NODE_NAME\t\"%s\"\r\n", name ); + fprintf( f, "\t*NODE_TM\t{\r\n" ); + fprintf( f, "\t\t*NODE_NAME\t\"%s\"\r\n", name ); + fprintf( f, "\t\t*INHERIT_POS\t0\t0\t0\r\n" ); + fprintf( f, "\t\t*INHERIT_ROT\t0\t0\t0\r\n" ); + fprintf( f, "\t\t*INHERIT_SCL\t0\t0\t0\r\n" ); + fprintf( f, "\t\t*TM_ROW0\t1.0\t0\t0\r\n" ); + fprintf( f, "\t\t*TM_ROW1\t0\t1.0\t0\r\n" ); + fprintf( f, "\t\t*TM_ROW2\t0\t0\t1.0\r\n" ); + fprintf( f, "\t\t*TM_ROW3\t0\t0\t0\r\n" ); + fprintf( f, "\t\t*TM_POS\t%f\t%f\t%f\r\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] ); + fprintf( f, "\t}\r\n" ); + + /* print mesh header */ + fprintf( f, "\t*MESH\t{\r\n" ); + fprintf( f, "\t\t*TIMEVALUE\t0\r\n" ); + fprintf( f, "\t\t*MESH_NUMVERTEX\t%d\r\n", ds->numVerts ); + fprintf( f, "\t\t*MESH_NUMFACES\t%d\r\n", ds->numIndexes / 3 ); + switch( ds->surfaceType ) + { + case MST_PLANAR: + fprintf( f, "\t\t*COMMENT\t\"SURFACETYPE\tMST_PLANAR\"\r\n" ); + break; + case MST_TRIANGLE_SOUP: + fprintf( f, "\t\t*COMMENT\t\"SURFACETYPE\tMST_TRIANGLE_SOUP\"\r\n" ); + break; + } + + /* export vertex xyz */ + fprintf( f, "\t\t*MESH_VERTEX_LIST\t{\r\n" ); + for( i = 0; i < ds->numVerts; i++ ) + { + v = i + ds->firstVert; + dv = &bspDrawVerts[ v ]; + fprintf( f, "\t\t\t*MESH_VERTEX\t%d\t%f\t%f\t%f\r\n", i, dv->xyz[ 0 ], dv->xyz[ 1 ], dv->xyz[ 2 ] ); + } + fprintf( f, "\t\t}\r\n" ); + + /* export vertex normals */ + fprintf( f, "\t\t*MESH_NORMALS\t{\r\n" ); + for( i = 0; i < ds->numIndexes; i += 3 ) + { + face = (i / 3); + a = bspDrawIndexes[ i + ds->firstIndex ]; + b = bspDrawIndexes[ i + ds->firstIndex + 1 ]; + c = bspDrawIndexes[ i + ds->firstIndex + 2 ]; + VectorCopy( bspDrawVerts[ a ].normal, normal ); + VectorAdd( normal, bspDrawVerts[ b ].normal, normal ); + VectorAdd( normal, bspDrawVerts[ c ].normal, normal ); + if( VectorNormalize( normal, normal ) ) + fprintf( f, "\t\t\t*MESH_FACENORMAL\t%d\t%f\t%f\t%f\r\n", face, normal[ 0 ], normal[ 1 ], normal[ 2 ] ); + } + for( i = 0; i < ds->numVerts; i++ ) + { + v = i + ds->firstVert; + dv = &bspDrawVerts[ v ]; + fprintf( f, "\t\t\t*MESH_VERTEXNORMAL\t%d\t%f\t%f\t%f\r\n", i, dv->normal[ 0 ], dv->normal[ 1 ], dv->normal[ 2 ] ); + } + fprintf( f, "\t\t}\r\n" ); + + /* export faces */ + fprintf( f, "\t\t*MESH_FACE_LIST\t{\r\n" ); + for( i = 0; i < ds->numIndexes; i += 3 ) + { + face = (i / 3); + a = bspDrawIndexes[ i + ds->firstIndex ]; + c = bspDrawIndexes[ i + ds->firstIndex + 1 ]; + b = bspDrawIndexes[ i + ds->firstIndex + 2 ]; + fprintf( f, "\t\t\t*MESH_FACE\t%d\tA:\t%d\tB:\t%d\tC:\t%d\tAB:\t1\tBC:\t1\tCA:\t1\t*MESH_SMOOTHING\t0\t*MESH_MTLID\t0\r\n", + face, a, b, c ); + } + fprintf( f, "\t\t}\r\n" ); + + /* export vertex st */ + fprintf( f, "\t\t*MESH_NUMTVERTEX\t%d\r\n", ds->numVerts ); + fprintf( f, "\t\t*MESH_TVERTLIST\t{\r\n" ); + for( i = 0; i < ds->numVerts; i++ ) + { + v = i + ds->firstVert; + dv = &bspDrawVerts[ v ]; + fprintf( f, "\t\t\t*MESH_TVERT\t%d\t%f\t%f\t%f\r\n", i, dv->st[ 0 ], (1.0 - dv->st[ 1 ]), 1.0f ); + } + fprintf( f, "\t\t}\r\n" ); + + /* export texture faces */ + fprintf( f, "\t\t*MESH_NUMTVFACES\t%d\r\n", ds->numIndexes / 3 ); + fprintf( f, "\t\t*MESH_TFACELIST\t{\r\n" ); + for( i = 0; i < ds->numIndexes; i += 3 ) + { + face = (i / 3); + a = bspDrawIndexes[ i + ds->firstIndex ]; + c = bspDrawIndexes[ i + ds->firstIndex + 1 ]; + b = bspDrawIndexes[ i + ds->firstIndex + 2 ]; + fprintf( f, "\t\t\t*MESH_TFACE\t%d\t%d\t%d\t%d\r\n", face, a, b, c ); + } + fprintf( f, "\t\t}\r\n" ); + + /* print mesh footer */ + fprintf( f, "\t}\r\n" ); + + /* print object footer */ + fprintf( f, "\t*PROP_MOTIONBLUR\t0\r\n" ); + fprintf( f, "\t*PROP_CASTSHADOW\t1\r\n" ); + fprintf( f, "\t*PROP_RECVSHADOW\t1\r\n" ); + fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->shaderNum ); + fprintf( f, "}\r\n" ); +} + + + +/* +ConvertModel() +exports a bsp model to an ase chunk +*/ + +static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin ) +{ + int i, s; + bspDrawSurface_t *ds; + + + /* go through each drawsurf in the model */ + for( i = 0; i < model->numBSPSurfaces; i++ ) + { + s = i + model->firstBSPSurface; + ds = &bspDrawSurfaces[ s ]; + ConvertSurface( f, model, modelNum, ds, s, origin ); + } +} + + + +/* +ConvertShader() +exports a bsp shader to an ase chunk +*/ + +/* + *MATERIAL 0 { + *MATERIAL_NAME "models/test/rock16l" + *MATERIAL_CLASS "Standard" + *MATERIAL_AMBIENT 0.5882 0.5882 0.5882 + *MATERIAL_DIFFUSE 0.5882 0.5882 0.5882 + *MATERIAL_SPECULAR 0.5882 0.5882 0.5882 + *MATERIAL_SHINE 0.0000 + *MATERIAL_SHINESTRENGTH 0.0000 + *MATERIAL_TRANSPARENCY 0.0000 + *MATERIAL_WIRESIZE 1.0000 + *MATERIAL_SHADING Phong + *MATERIAL_XP_FALLOFF 0.0000 + *MATERIAL_SELFILLUM 0.0000 + *MATERIAL_FALLOFF In + *MATERIAL_XP_TYPE Filter + *MAP_DIFFUSE { + *MAP_NAME "Map #2" + *MAP_CLASS "Bitmap" + *MAP_SUBNO 1 + *MAP_AMOUNT 1.0000 + *BITMAP "models/test/rock16l" + *MAP_TYPE Screen + *UVW_U_OFFSET 0.0000 + *UVW_V_OFFSET 0.0000 + *UVW_U_TILING 1.0000 + *UVW_V_TILING 1.0000 + *UVW_ANGLE 0.0000 + *UVW_BLUR 1.0000 + *UVW_BLUR_OFFSET 0.0000 + *UVW_NOUSE_AMT 1.0000 + *UVW_NOISE_SIZE 1.0000 + *UVW_NOISE_LEVEL 1 + *UVW_NOISE_PHASE 0.0000 + *BITMAP_FILTER Pyramidal + } + } +*/ + +static void ConvertShader( FILE *f, bspShader_t *shader, int shaderNum ) +{ + shaderInfo_t *si; + char *c, filename[ 1024 ]; + + + /* get shader */ + si = ShaderInfoForShader( shader->shader ); + if( si == NULL ) + { + Sys_Printf( "WARNING: NULL shader in BSP\n" ); + return; + } + + /* set bitmap filename */ + if( si->shaderImage->filename[ 0 ] != '*' ) + strcpy( filename, si->shaderImage->filename ); + else + sprintf( filename, "%s.tga", si->shader ); + for( c = filename; *c != '\0'; c++ ) + if( *c == '/' ) + *c = '\\'; + + /* print shader info */ + fprintf( f, "\t*MATERIAL\t%d\t{\r\n", shaderNum ); + fprintf( f, "\t\t*MATERIAL_NAME\t\"%s\"\r\n", shader->shader ); + fprintf( f, "\t\t*MATERIAL_CLASS\t\"Standard\"\r\n" ); + fprintf( f, "\t\t*MATERIAL_DIFFUSE\t%f\t%f\t%f\r\n", si->color[ 0 ], si->color[ 1 ], si->color[ 2 ] ); + fprintf( f, "\t\t*MATERIAL_SHADING Phong\r\n" ); + + /* print map info */ + fprintf( f, "\t\t*MAP_DIFFUSE\t{\r\n" ); + fprintf( f, "\t\t\t*MAP_NAME\t\"%s\"\r\n", shader->shader ); + fprintf( f, "\t\t\t*MAP_CLASS\t\"Bitmap\"\r\n"); + fprintf( f, "\t\t\t*MAP_SUBNO\t1\r\n" ); + fprintf( f, "\t\t\t*MAP_AMOUNT\t1.0\r\n" ); + fprintf( f, "\t\t\t*MAP_TYPE\tScreen\r\n" ); + fprintf( f, "\t\t\t*BITMAP\t\"..\\%s\"\r\n", filename ); + fprintf( f, "\t\t\t*BITMAP_FILTER\tPyramidal\r\n" ); + fprintf( f, "\t\t}\r\n" ); + + fprintf( f, "\t}\r\n" ); +} + + + +/* +ConvertBSPToASE() +exports an 3d studio ase file from the bsp +*/ + +int ConvertBSPToASE( char *bspName ) +{ + int i, modelNum; + FILE *f; + bspShader_t *shader; + bspModel_t *model; + entity_t *e; + vec3_t origin; + const char *key; + char name[ 1024 ], base[ 1024 ]; + + + /* note it */ + Sys_Printf( "--- Convert BSP to ASE ---\n" ); + + /* create the ase filename from the bsp name */ + strcpy( name, bspName ); + StripExtension( name ); + strcat( name, ".ase" ); + Sys_Printf( "writing %s\n", name ); + + ExtractFileBase( bspName, base ); + strcat( base, ".bsp" ); + + /* open it */ + f = fopen( name, "wb" ); + if( f == NULL ) + Error( "Open failed on %s\n", name ); + + /* print header */ + fprintf( f, "*3DSMAX_ASCIIEXPORT\t200\r\n" ); + fprintf( f, "*COMMENT\t\"Generated by Q3Map2 (ydnar) -convert -format ase\"\r\n" ); + fprintf( f, "*SCENE\t{\r\n" ); + fprintf( f, "\t*SCENE_FILENAME\t\"%s\"\r\n", base ); + fprintf( f, "\t*SCENE_FIRSTFRAME\t0\r\n" ); + fprintf( f, "\t*SCENE_LASTFRAME\t100\r\n" ); + fprintf( f, "\t*SCENE_FRAMESPEED\t30\r\n" ); + fprintf( f, "\t*SCENE_TICKSPERFRAME\t160\r\n" ); + fprintf( f, "\t*SCENE_BACKGROUND_STATIC\t0.0000\t0.0000\t0.0000\r\n" ); + fprintf( f, "\t*SCENE_AMBIENT_STATIC\t0.0000\t0.0000\t0.0000\r\n" ); + fprintf( f, "}\r\n" ); + + /* print materials */ + fprintf( f, "*MATERIAL_LIST\t{\r\n" ); + fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", numBSPShaders ); + for( i = 0; i < numBSPShaders; i++ ) + { + shader = &bspShaders[ i ]; + ConvertShader( f, shader, i ); + } + fprintf( f, "}\r\n" ); + + /* walk entity list */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity and model */ + e = &entities[ i ]; + if( i == 0 ) + modelNum = 0; + else + { + key = ValueForKey( e, "model" ); + if( key[ 0 ] != '*' ) + continue; + modelNum = atoi( key + 1 ); + } + model = &bspModels[ modelNum ]; + + /* get entity origin */ + key = ValueForKey( e, "origin" ); + if( key[ 0 ] == '\0' ) + VectorClear( origin ); + else + GetVectorForKey( e, "origin", origin ); + + /* convert model */ + ConvertModel( f, model, modelNum, origin ); + } + + /* close the file and return */ + fclose( f ); + + /* return to sender */ + return 0; +} + + + diff --git a/tools/quake3/q3map2/convert_map.c b/tools/quake3/q3map2/convert_map.c new file mode 100644 index 00000000..ff69c8a5 --- /dev/null +++ b/tools/quake3/q3map2/convert_map.c @@ -0,0 +1,443 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define CONVERT_MAP_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +ConvertBrush() +exports a map brush +*/ + +#define SNAP_FLOAT_TO_INT 4 +#define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT) + +static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) +{ + int i, j; + bspBrushSide_t *side; + side_t *buildSide; + bspShader_t *shader; + char *texture; + bspPlane_t *plane; + vec3_t pts[ 3 ]; + + + /* start brush */ + fprintf( f, "\t// brush %d\n", num ); + fprintf( f, "\t{\n" ); + + /* clear out build brush */ + for( i = 0; i < buildBrush->numsides; i++ ) + { + buildSide = &buildBrush->sides[ i ]; + if( buildSide->winding != NULL ) + { + FreeWinding( buildSide->winding ); + buildSide->winding = NULL; + } + } + buildBrush->numsides = 0; + + /* iterate through bsp brush sides */ + for( i = 0; i < brush->numSides; i++ ) + { + /* get side */ + side = &bspBrushSides[ brush->firstSide + i ]; + + /* get shader */ + if( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) + continue; + shader = &bspShaders[ side->shaderNum ]; + if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) + continue; + + /* get plane */ + plane = &bspPlanes[ side->planeNum ]; + + /* add build side */ + buildSide = &buildBrush->sides[ buildBrush->numsides ]; + buildBrush->numsides++; + + /* tag it */ + buildSide->shaderInfo = ShaderInfoForShader( shader->shader ); + buildSide->planenum = side->planeNum; + buildSide->winding = NULL; + } + + /* make brush windings */ + if( !CreateBrushWindings( buildBrush ) ) + return; + + /* iterate through build brush sides */ + for( i = 0; i < buildBrush->numsides; i++ ) + { + /* get build side */ + buildSide = &buildBrush->sides[ i ]; + + /* dummy check */ + if( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) + continue; + + /* get texture name */ + if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) + texture = buildSide->shaderInfo->shader + 9; + else + texture = buildSide->shaderInfo->shader; + + /* get plane points and offset by origin */ + for( j = 0; j < 3; j++ ) + { + VectorAdd( buildSide->winding->p[ j ], origin, pts[ j ] ); + //% pts[ j ][ 0 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 0 ] * SNAP_FLOAT_TO_INT + 0.5f ); + //% pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f ); + //% pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f ); + } + + /* print brush side */ + /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], + texture ); + } + + /* end brush */ + fprintf( f, "\t}\n\n" ); +} + +#if 0 + /* iterate through the brush sides (ignore the first 6 bevel planes) */ + for( i = 0; i < brush->numSides; i++ ) + { + /* get side */ + side = &bspBrushSides[ brush->firstSide + i ]; + + /* get shader */ + if( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) + continue; + shader = &bspShaders[ side->shaderNum ]; + if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) + continue; + + /* get texture name */ + if( !Q_strncasecmp( shader->shader, "textures/", 9 ) ) + texture = shader->shader + 9; + else + texture = shader->shader; + + /* get plane */ + plane = &bspPlanes[ side->planeNum ]; + + /* make plane points */ + { + vec3_t vecs[ 2 ]; + + + MakeNormalVectors( plane->normal, vecs[ 0 ], vecs[ 1 ] ); + VectorMA( vec3_origin, plane->dist, plane->normal, pts[ 0 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] ); + } + + /* offset by origin */ + for( j = 0; j < 3; j++ ) + VectorAdd( pts[ j ], origin, pts[ j ] ); + + /* print brush side */ + /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], + texture ); + } +#endif + + + +/* +ConvertPatch() +converts a bsp patch to a map patch + + { + patchDef2 + { + base_wall/concrete + ( 9 3 0 0 0 ) + ( + ( ( 168 168 -192 0 2 ) ( 168 168 -64 0 1 ) ( 168 168 64 0 0 ) ... ) + ... + ) + } + } + +*/ + +static void ConvertPatch( FILE *f, int num, bspDrawSurface_t *ds, vec3_t origin ) +{ + int x, y; + bspShader_t *shader; + char *texture; + bspDrawVert_t *dv; + vec3_t xyz; + + + /* only patches */ + if( ds->surfaceType != MST_PATCH ) + return; + + /* get shader */ + if( ds->shaderNum < 0 || ds->shaderNum >= numBSPShaders ) + return; + shader = &bspShaders[ ds->shaderNum ]; + + /* get texture name */ + if( !Q_strncasecmp( shader->shader, "textures/", 9 ) ) + texture = shader->shader + 9; + else + texture = shader->shader; + + /* start patch */ + fprintf( f, "\t// patch %d\n", num ); + fprintf( f, "\t{\n" ); + fprintf( f, "\t\tpatchDef2\n" ); + fprintf( f, "\t\t{\n" ); + fprintf( f, "\t\t\t%s\n", texture ); + fprintf( f, "\t\t\t( %d %d 0 0 0 )\n", ds->patchWidth, ds->patchHeight ); + fprintf( f, "\t\t\t(\n" ); + + /* iterate through the verts */ + for( x = 0; x < ds->patchWidth; x++ ) + { + /* start row */ + fprintf( f, "\t\t\t\t(" ); + + /* iterate through the row */ + for( y = 0; y < ds->patchHeight; y++ ) + { + /* get vert */ + dv = &bspDrawVerts[ ds->firstVert + (y * ds->patchWidth) + x ]; + + /* offset it */ + VectorAdd( origin, dv->xyz, xyz ); + + /* print vertex */ + fprintf( f, " ( %f %f %f %f %f )", xyz[ 0 ], xyz[ 1 ], xyz[ 2 ], dv->st[ 0 ], dv->st[ 1 ] ); + } + + /* end row */ + fprintf( f, " )\n" ); + } + + /* end patch */ + fprintf( f, "\t\t\t)\n" ); + fprintf( f, "\t\t}\n" ); + fprintf( f, "\t}\n\n" ); +} + + + +/* +ConvertModel() +exports a bsp model to a map file +*/ + +static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin ) +{ + int i, num; + bspBrush_t *brush; + bspDrawSurface_t *ds; + + + /* convert bsp planes to map planes */ + nummapplanes = numBSPPlanes; + for( i = 0; i < numBSPPlanes; i++ ) + { + VectorCopy( bspPlanes[ i ].normal, mapplanes[ i ].normal ); + mapplanes[ i ].dist = bspPlanes[ i ].dist; + mapplanes[ i ].type = PlaneTypeForNormal( mapplanes[ i ].normal ); + mapplanes[ i ].hash_chain = NULL; + } + + /* allocate a build brush */ + buildBrush = AllocBrush( 512 ); + buildBrush->entityNum = 0; + buildBrush->original = buildBrush; + + /* go through each brush in the model */ + for( i = 0; i < model->numBSPBrushes; i++ ) + { + num = i + model->firstBSPBrush; + brush = &bspBrushes[ num ]; + ConvertBrush( f, num, brush, origin ); + } + + /* free the build brush */ + free( buildBrush ); + + /* go through each drawsurf in the model */ + for( i = 0; i < model->numBSPSurfaces; i++ ) + { + num = i + model->firstBSPSurface; + ds = &bspDrawSurfaces[ num ]; + + /* we only love patches */ + if( ds->surfaceType == MST_PATCH ) + ConvertPatch( f, num, ds, origin ); + } +} + + + +/* +ConvertEPairs() +exports entity key/value pairs to a map file +*/ + +static void ConvertEPairs( FILE *f, entity_t *e ) +{ + epair_t *ep; + + + /* walk epairs */ + for( ep = e->epairs; ep != NULL; ep = ep->next ) + { + /* ignore empty keys/values */ + if( ep->key[ 0 ] == '\0' || ep->value[ 0 ] == '\0' ) + continue; + + /* ignore model keys with * prefixed values */ + if( !Q_stricmp( ep->key, "model" ) && ep->value[ 0 ] == '*' ) + continue; + + /* emit the epair */ + fprintf( f, "\t\"%s\" \"%s\"\n", ep->key, ep->value ); + } +} + + + +/* +ConvertBSPToMap() +exports an quake map file from the bsp +*/ + +int ConvertBSPToMap( char *bspName ) +{ + int i, modelNum; + FILE *f; + bspModel_t *model; + entity_t *e; + vec3_t origin; + const char *value; + char name[ 1024 ], base[ 1024 ]; + + + /* note it */ + Sys_Printf( "--- Convert BSP to MAP ---\n" ); + + /* create the bsp filename from the bsp name */ + strcpy( name, bspName ); + StripExtension( name ); + strcat( name, "_converted.map" ); + Sys_Printf( "writing %s\n", name ); + + ExtractFileBase( bspName, base ); + strcat( base, ".bsp" ); + + /* open it */ + f = fopen( name, "wb" ); + if( f == NULL ) + Error( "Open failed on %s\n", name ); + + /* print header */ + fprintf( f, "// Generated by Q3Map2 (ydnar) -convert -format map\n" ); + + /* walk entity list */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity */ + e = &entities[ i ]; + + /* start entity */ + fprintf( f, "// entity %d\n", i ); + fprintf( f, "{\n" ); + + /* export keys */ + ConvertEPairs( f, e ); + fprintf( f, "\n" ); + + /* get model num */ + if( i == 0 ) + modelNum = 0; + else + { + value = ValueForKey( e, "model" ); + if( value[ 0 ] == '*' ) + modelNum = atoi( value + 1 ); + else + modelNum = -1; + } + + /* only handle bsp models */ + if( modelNum >= 0 ) + { + /* get model */ + model = &bspModels[ modelNum ]; + + /* get entity origin */ + value = ValueForKey( e, "origin" ); + if( value[ 0 ] == '\0' ) + VectorClear( origin ); + else + GetVectorForKey( e, "origin", origin ); + + /* convert model */ + ConvertModel( f, model, modelNum, origin ); + } + + /* end entity */ + fprintf( f, "}\n\n" ); + } + + /* close the file and return */ + fclose( f ); + + /* return to sender */ + return 0; +} diff --git a/tools/quake3/q3map2/decals.c b/tools/quake3/q3map2/decals.c new file mode 100644 index 00000000..d7b01d64 --- /dev/null +++ b/tools/quake3/q3map2/decals.c @@ -0,0 +1,908 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define DECALS_C + + + +/* dependencies */ +#include "q3map2.h" + + + +#define MAX_PROJECTORS 1024 + +typedef struct decalProjector_s +{ + shaderInfo_t *si; + vec3_t mins, maxs; + vec3_t center; + float radius, radius2; + int numPlanes; /* either 5 or 6, for quad or triangle projectors */ + vec4_t planes[ 6 ]; + vec4_t texMat[ 2 ]; +} +decalProjector_t; + +static int numProjectors = 0; +static decalProjector_t projectors[ MAX_PROJECTORS ]; + +static int numDecalSurfaces = 0; + +static vec3_t entityOrigin; + + + +/* +DVectorNormalize() +normalizes a vector, returns the length, operates using doubles +*/ + +typedef double dvec_t; +typedef dvec_t dvec3_t[ 3 ]; + +dvec_t DVectorNormalize( dvec3_t in, dvec3_t out ) +{ + dvec_t len, ilen; + + + len = (dvec_t) sqrt( in[ 0 ] * in[ 0 ] + in[ 1 ] * in[ 1 ] + in[ 2 ] * in[ 2 ] ); + if( len == 0.0 ) + { + VectorClear( out ); + return 0.0; + } + + ilen = 1.0 / len; + out[ 0 ] = in[ 0 ] * ilen; + out[ 1 ] = in[ 1 ] * ilen; + out[ 2 ] = in[ 2 ] * ilen; + + return len; +} + + + +/* +MakeTextureMatrix() +generates a texture projection matrix for a triangle +returns qfalse if a texture matrix cannot be created +*/ + +#define Vector2Subtract(a,b,c) ((c)[ 0 ] = (a)[ 0 ] - (b)[ 0 ], (c)[ 1 ] = (a)[ 1 ] - (b)[ 1 ]) + +static qboolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c ) +{ + int i, j; + double bb, s, t, d; + dvec3_t pa, pb, pc; + dvec3_t bary, xyz; + dvec3_t vecs[ 3 ], axis[ 3 ], lengths; + + + /* project triangle onto plane of projection */ + d = DotProduct( a->xyz, projection ) - projection[ 3 ]; + VectorMA( a->xyz, -d, projection, pa ); + d = DotProduct( b->xyz, projection ) - projection[ 3 ]; + VectorMA( b->xyz, -d, projection, pb ); + d = DotProduct( c->xyz, projection ) - projection[ 3 ]; + VectorMA( c->xyz, -d, projection, pc ); + + /* two methods */ + #if 1 + { + /* old code */ + + /* calculate barycentric basis for the triangle */ + bb = (b->st[ 0 ] - a->st[ 0 ]) * (c->st[ 1 ] - a->st[ 1 ]) - (c->st[ 0 ] - a->st[ 0 ]) * (b->st[ 1 ] - a->st[ 1 ]); + if( fabs( bb ) < 0.00000001 ) + return qfalse; + + /* calculate texture origin */ + #if 0 + s = 0.0; + t = 0.0; + bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb; + bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb; + bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb; + + origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ]; + origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ]; + origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ]; + #endif + + /* calculate s vector */ + s = a->st[ 0 ] + 1.0; + t = a->st[ 1 ] + 0.0; + bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb; + bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb; + bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb; + + xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ]; + xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ]; + xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ]; + + //% VectorSubtract( xyz, origin, vecs[ 0 ] ); + VectorSubtract( xyz, pa, vecs[ 0 ] ); + + /* calculate t vector */ + s = a->st[ 0 ] + 0.0; + t = a->st[ 1 ] + 1.0; + bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb; + bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb; + bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb; + + xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ]; + xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ]; + xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ]; + + //% VectorSubtract( xyz, origin, vecs[ 1 ] ); + VectorSubtract( xyz, pa, vecs[ 1 ] ); + + /* calcuate r vector */ + VectorScale( projection, -1.0, vecs[ 2 ] ); + + /* calculate transform axis */ + for( i = 0; i < 3; i++ ) + lengths[ i ] = DVectorNormalize( vecs[ i ], axis[ i ] ); + for( i = 0; i < 2; i++ ) + for( j = 0; j < 3; j++ ) + dp->texMat[ i ][ j ] = lengths[ i ] > 0.0 ? (axis[ i ][ j ] / lengths[ i ]) : 0.0; + //% dp->texMat[ i ][ j ] = fabs( vecs[ i ][ j ] ) > 0.0 ? (1.0 / vecs[ i ][ j ]) : 0.0; + //% dp->texMat[ i ][ j ] = axis[ i ][ j ] > 0.0 ? (1.0 / axis[ i ][ j ]) : 0.0; + + /* calculalate translation component */ + dp->texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( a->xyz, dp->texMat[ 0 ] ); + dp->texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( a->xyz, dp->texMat[ 1 ] ); + } + #else + { + int k; + dvec3_t origin, deltas[ 3 ]; + double texDeltas[ 3 ][ 2 ]; + double delta, texDelta; + + + /* new code */ + + /* calculate deltas */ + VectorSubtract( pa, pb, deltas[ 0 ] ); + VectorSubtract( pa, pc, deltas[ 1 ] ); + VectorSubtract( pb, pc, deltas[ 2 ] ); + Vector2Subtract( a->st, b->st, texDeltas[ 0 ] ); + Vector2Subtract( a->st, c->st, texDeltas[ 1 ] ); + Vector2Subtract( b->st, c->st, texDeltas[ 2 ] ); + + /* walk st */ + for( i = 0; i < 2; i++ ) + { + /* walk xyz */ + for( j = 0; j < 3; j++ ) + { + /* clear deltas */ + delta = 0.0; + texDelta = 0.0; + + /* walk deltas */ + for( k = 0; k < 3; k++ ) + { + if( fabs( deltas[ k ][ j ] ) > delta && + fabs( texDeltas[ k ][ i ] ) > texDelta ) + { + delta = deltas[ k ][ j ]; + texDelta = texDeltas[ k ][ i ]; + } + } + + /* set texture matrix component */ + if( fabs( delta ) > 0.0 ) + dp->texMat[ i ][ j ] = texDelta / delta; + else + dp->texMat[ i ][ j ] = 0.0; + } + + /* set translation component */ + dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] ); + } + } + #endif + + /* debug code */ + #if 1 + Sys_Printf( "Mat: [ %f %f %f %f ] [ %f %f %f %f ] Theta: %f (%f)\n", + dp->texMat[ 0 ][ 0 ], dp->texMat[ 0 ][ 1 ], dp->texMat[ 0 ][ 2 ], dp->texMat[ 0 ][ 3 ], + dp->texMat[ 1 ][ 0 ], dp->texMat[ 1 ][ 1 ], dp->texMat[ 1 ][ 2 ], dp->texMat[ 1 ][ 3 ], + RAD2DEG( acos( DotProduct( dp->texMat[ 0 ], dp->texMat[ 1 ] ) ) ), + RAD2DEG( acos( DotProduct( axis[ 0 ], axis[ 1 ] ) ) ) ); + + Sys_Printf( "XYZ: %f %f %f ST: %f %f ST(t): %f %f\n", + a->xyz[ 0 ], a->xyz[ 1 ], a->xyz[ 2 ], + a->st[ 0 ], a->st[ 1 ], + DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ], DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ] ); + #endif + + /* test texture matrix */ + s = DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; + t = DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; + if( fabs( s - a->st[ 0 ] ) > 0.01 || fabs( t - a->st[ 1 ] ) > 0.01 ) + { + Sys_Printf( "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n", + s, t, a->st[ 0 ], a->st[ 1 ] ); + //% return qfalse; + } + s = DotProduct( b->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; + t = DotProduct( b->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; + if( fabs( s - b->st[ 0 ] ) > 0.01 || fabs( t - b->st[ 1 ] ) > 0.01 ) + { + Sys_Printf( "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n", + s, t, b->st[ 0 ], b->st[ 1 ] ); + //% return qfalse; + } + s = DotProduct( c->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; + t = DotProduct( c->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; + if( fabs( s - c->st[ 0 ] ) > 0.01 || fabs( t - c->st[ 1 ] ) > 0.01 ) + { + Sys_Printf( "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n", + s, t, c->st[ 0 ], c->st[ 1 ] ); + //% return qfalse; + } + + /* disco */ + return qtrue; +} + + + +/* +TransformDecalProjector() +transforms a decal projector +note: non-normalized axes will screw up the plane transform +*/ + +static void TransformDecalProjector( decalProjector_t *in, vec3_t axis[ 3 ], vec3_t origin, decalProjector_t *out ) +{ + int i; + + + /* copy misc stuff */ + out->si = in->si; + out->numPlanes = in->numPlanes; + + /* translate bounding box and sphere (note: rotated projector bounding box will be invalid!) */ + VectorSubtract( in->mins, origin, out->mins ); + VectorSubtract( in->maxs, origin, out->maxs ); + VectorSubtract( in->center, origin, out->center ); + out->radius = in->radius; + out->radius2 = in->radius2; + + /* translate planes */ + for( i = 0; i < in->numPlanes; i++ ) + { + out->planes[ i ][ 0 ] = DotProduct( in->planes[ i ], axis[ 0 ] ); + out->planes[ i ][ 1 ] = DotProduct( in->planes[ i ], axis[ 1 ] ); + out->planes[ i ][ 2 ] = DotProduct( in->planes[ i ], axis[ 2 ] ); + out->planes[ i ][ 3 ] = in->planes[ i ][ 3 ] - DotProduct( out->planes[ i ], origin ); + } + + /* translate texture matrix */ + for( i = 0; i < 2; i++ ) + { + out->texMat[ i ][ 0 ] = DotProduct( in->texMat[ i ], axis[ 0 ] ); + out->texMat[ i ][ 1 ] = DotProduct( in->texMat[ i ], axis[ 1 ] ); + out->texMat[ i ][ 2 ] = DotProduct( in->texMat[ i ], axis[ 2 ] ); + out->texMat[ i ][ 3 ] = in->texMat[ i ][ 3 ] + DotProduct( out->texMat[ i ], origin ); + } +} + + + +/* +MakeDecalProjector() +creates a new decal projector from a triangle +*/ + +static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv ) +{ + int i, j; + decalProjector_t *dp; + vec3_t xyz; + + + /* dummy check */ + if( numVerts != 3 && numVerts != 4 ) + return -1; + + /* limit check */ + if( numProjectors >= MAX_PROJECTORS ) + { + Sys_Printf( "WARNING: MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS ); + return -2; + } + + /* create a new projector */ + dp = &projectors[ numProjectors ]; + memset( dp, 0, sizeof( *dp ) ); + + /* basic setup */ + dp->si = si; + dp->numPlanes = numVerts + 2; + + /* make texture matrix */ + if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) ) + return -1; + + /* bound the projector */ + ClearBounds( dp->mins, dp->maxs ); + for( i = 0; i < numVerts; i++ ) + { + AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs ); + VectorMA( dv[ i ]->xyz, distance, projection, xyz ); + AddPointToBounds( xyz, dp->mins, dp->maxs ); + } + + /* make bouding sphere */ + VectorAdd( dp->mins, dp->maxs, dp->center ); + VectorScale( dp->center, 0.5f, dp->center ); + VectorSubtract( dp->maxs, dp->center, xyz ); + dp->radius = VectorLength( xyz ); + dp->radius2 = dp->radius * dp->radius; + + /* make the front plane */ + if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) ) + return -1; + + /* make the back plane */ + VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] ); + VectorMA( dv[ 0 ]->xyz, distance, projection, xyz ); + dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] ); + + /* make the side planes */ + for( i = 0; i < numVerts; i++ ) + { + j = (i + 1) % numVerts; + VectorMA( dv[ i ]->xyz, distance, projection, xyz ); + if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) ) + return -1; + } + + /* return ok */ + numProjectors++; + return numProjectors - 1; +} + + + +/* +ProcessDecals() +finds all decal entities and creates decal projectors +*/ + +#define PLANAR_EPSILON 0.5f + +void ProcessDecals( void ) +{ + int i, j, x, y, pw[ 5 ], r, iterations; + float distance; + vec4_t projection, plane; + vec3_t origin, target, delta; + entity_t *e, *e2; + parseMesh_t *p; + mesh_t *mesh, *subdivided; + bspDrawVert_t *dv[ 4 ]; + const char *value; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" ); + + /* walk entity list */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity */ + e = &entities[ i ]; + value = ValueForKey( e, "classname" ); + if( Q_stricmp( value, "_decal" ) ) + continue; + + /* any patches? */ + if( e->patches == NULL ) + { + Sys_Printf( "WARNING: Decal entity without any patch meshes, ignoring.\n" ); + e->epairs = NULL; /* fixme: leak! */ + continue; + } + + /* find target */ + value = ValueForKey( e, "target" ); + e2 = FindTargetEntity( value ); + + /* no target? */ + if( e2 == NULL ) + { + Sys_Printf( "WARNING: Decal entity without a valid target, ignoring.\n" ); + continue; + } + + /* walk entity patches */ + for( p = e->patches; p != NULL; p = e->patches ) + { + /* setup projector */ + if( VectorCompare( e->origin, vec3_origin ) ) + { + VectorAdd( p->eMins, p->eMaxs, origin ); + VectorScale( origin, 0.5f, origin ); + } + else + VectorCopy( e->origin, origin ); + + VectorCopy( e2->origin, target ); + VectorSubtract( target, origin, delta ); + + /* setup projection plane */ + distance = VectorNormalize( delta, projection ); + projection[ 3 ] = DotProduct( origin, projection ); + + /* create projectors */ + if( distance > 0.125f ) + { + /* tesselate the patch */ + iterations = IterationsForCurve( p->longestCurve, patchSubdivisions ); + subdivided = SubdivideMesh2( p->mesh, iterations ); + + /* fit it to the curve and remove colinear verts on rows/columns */ + PutMeshOnCurve( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + + /* offset by projector origin */ + for( j = 0; j < (mesh->width * mesh->height); j++ ) + VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz ); + + /* iterate through the mesh quads */ + for( y = 0; y < (mesh->height - 1); y++ ) + { + for( x = 0; x < (mesh->width - 1); x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ + + /* set radix */ + r = (x + y) & 1; + + /* get drawverts */ + dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ]; + dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ]; + + /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */ + plane[ 0 ] = 0.0f; /* stupid msvc */ + if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) && + fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON ) + { + /* make a quad projector */ + MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv ); + } + else + { + /* make first triangle */ + MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv ); + + /* make second triangle */ + dv[ 1 ] = dv[ 2 ]; + dv[ 2 ] = dv[ 3 ]; + MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv ); + } + } + } + + /* clean up */ + free( mesh ); + } + + /* remove patch from entity (fixme: leak!) */ + e->patches = p->next; + + /* push patch to worldspawn (enable this to debug projectors) */ + #if 0 + p->next = entities[ 0 ].patches; + entities[ 0 ].patches = p; + #endif + } + } + + /* emit some stats */ + Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors ); +} + + + +/* +ProjectDecalOntoWinding() +projects a decal onto a winding +*/ + +static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w ) +{ + int i, j; + float d, d2, alpha; + winding_t *front, *back; + mapDrawSurface_t *ds2; + bspDrawVert_t *dv; + vec4_t plane; + + + /* dummy check */ + if( w->numpoints < 3 ) + { + FreeWinding( w ); + return; + } + + /* offset by entity origin */ + for( i = 0; i < w->numpoints; i++ ) + VectorAdd( w->p[ i ], entityOrigin, w->p[ i ] ); + + /* make a plane from the winding */ + if( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) ) + { + FreeWinding( w ); + return; + } + + /* backface check */ + d = DotProduct( dp->planes[ 0 ], plane ); + if( d < -0.0001f ) + { + FreeWinding( w ); + return; + } + + /* walk list of planes */ + for( i = 0; i < dp->numPlanes; i++ ) + { + /* chop winding by the plane */ + ClipWindingEpsilon( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back ); + FreeWinding( w ); + + /* lose the front fragment */ + if( front != NULL ) + FreeWinding( front ); + + /* if nothing left in back, then bail */ + if( back == NULL ) + return; + + /* reset winding */ + w = back; + } + + /* nothing left? */ + if( w == NULL || w->numpoints < 3 ) + return; + + /* add to counts */ + numDecalSurfaces++; + + /* make a new surface */ + ds2 = AllocDrawSurface( SURFACE_DECAL ); + + /* set it up */ + ds2->entityNum = ds->entityNum; + ds2->castShadows = ds->castShadows; + ds2->recvShadows = ds->recvShadows; + ds2->shaderInfo = dp->si; + ds2->fogNum = ds->fogNum; /* why was this -1? */ + ds2->lightmapScale = ds->lightmapScale; + ds2->numVerts = w->numpoints; + ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) ); + memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) ); + + /* set vertexes */ + for( i = 0; i < ds2->numVerts; i++ ) + { + /* get vertex */ + dv = &ds2->verts[ i ]; + + /* set alpha */ + d = DotProduct( w->p[ i ], dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ]; + d2 = DotProduct( w->p[ i ], dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ]; + alpha = 255.0f * d2 / (d + d2); + if( alpha > 255 ) + alpha = 255; + else if( alpha < 0 ) + alpha = 0; + + /* set misc */ + VectorSubtract( w->p[ i ], entityOrigin, dv->xyz ); + VectorCopy( plane, dv->normal ); + dv->st[ 0 ] = DotProduct( dv->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; + dv->st[ 1 ] = DotProduct( dv->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; + + /* set color */ + for( j = 0; j < MAX_LIGHTMAPS; j++ ) + { + dv->color[ j ][ 0 ] = 255; + dv->color[ j ][ 1 ] = 255; + dv->color[ j ][ 2 ] = 255; + dv->color[ j ][ 3 ] = alpha; + } + } + + /* ydnar: finish the surface */ + FinishSurface( ds2 ); +} + + + +/* +ProjectDecalOntoFace() +projects a decal onto a brushface surface +*/ + +static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds ) +{ + vec4_t plane; + float d; + winding_t *w; + + + /* dummy check */ + if( ds->sideRef == NULL || ds->sideRef->side == NULL ) + return; + + /* backface check */ + if( ds->planar ) + { + VectorCopy( mapplanes[ ds->planeNum ].normal, plane ); + plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin ); + d = DotProduct( dp->planes[ 0 ], plane ); + if( d < -0.0001f ) + return; + } + + /* generate decal */ + w = WindingFromDrawSurf( ds ); + ProjectDecalOntoWinding( dp, ds, w ); +} + + + +/* +ProjectDecalOntoPatch() +projects a decal onto a patch surface +*/ + +static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds ) +{ + int x, y, pw[ 5 ], r, iterations; + vec4_t plane; + float d; + mesh_t src, *mesh, *subdivided; + winding_t *w; + + + /* backface check */ + if( ds->planar ) + { + VectorCopy( mapplanes[ ds->planeNum ].normal, plane ); + plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin ); + d = DotProduct( dp->planes[ 0 ], plane ); + if( d < -0.0001f ) + return; + } + + /* tesselate the patch */ + src.width = ds->patchWidth; + src.height = ds->patchHeight; + src.verts = ds->verts; + iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions ); + subdivided = SubdivideMesh2( src, iterations ); + + /* fit it to the curve and remove colinear verts on rows/columns */ + PutMeshOnCurve( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + + /* iterate through the mesh quads */ + for( y = 0; y < (mesh->height - 1); y++ ) + { + for( x = 0; x < (mesh->width - 1); x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ + + /* set radix */ + r = (x + y) & 1; + + /* generate decal for first triangle */ + w = AllocWinding( 3 ); + w->numpoints = 3; + VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] ); + VectorCopy( mesh->verts[ pw[ r + 1 ] ].xyz, w->p[ 1 ] ); + VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 2 ] ); + ProjectDecalOntoWinding( dp, ds, w ); + + /* generate decal for second triangle */ + w = AllocWinding( 3 ); + w->numpoints = 3; + VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] ); + VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 1 ] ); + VectorCopy( mesh->verts[ pw[ r + 3 ] ].xyz, w->p[ 2 ] ); + ProjectDecalOntoWinding( dp, ds, w ); + } + } + + /* clean up */ + free( mesh ); +} + + + +/* +ProjectDecalOntoTriangles() +projects a decal onto a triangle surface +*/ + +static void ProjectDecalOntoTriangles( decalProjector_t *dp, mapDrawSurface_t *ds ) +{ + int i; + vec4_t plane; + float d; + winding_t *w; + + + /* triangle surfaces without shaders don't get marks by default */ + if( (ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FORCED_META) && + ds->shaderInfo->shaderText == NULL ) + return; + + /* backface check */ + if( ds->planar ) + { + VectorCopy( mapplanes[ ds->planeNum ].normal, plane ); + plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin ); + d = DotProduct( dp->planes[ 0 ], plane ); + if( d < -0.0001f ) + return; + } + + /* iterate through triangles */ + for( i = 0; i < ds->numIndexes; i += 3 ) + { + /* generate decal */ + w = AllocWinding( 3 ); + w->numpoints = 3; + VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] ); + VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] ); + VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] ); + ProjectDecalOntoWinding( dp, ds, w ); + } +} + + + +/* +MakeEntityDecals() +projects decals onto world surfaces +*/ + +void MakeEntityDecals( entity_t *e ) +{ + int i, j, k, f, fOld, start; + decalProjector_t dp; + mapDrawSurface_t *ds; + vec3_t identityAxis[ 3 ] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- MakeEntityDecals ---\n" ); + + /* set entity origin */ + VectorCopy( e->origin, entityOrigin ); + + /* transform projector instead of geometry */ + VectorClear( entityOrigin ); + + /* init pacifier */ + fOld = -1; + start = I_FloatTime(); + + /* walk the list of decal projectors */ + for( i = 0; i < numProjectors; i++ ) + { + /* print pacifier */ + f = 10 * i / numProjectors; + if( f != fOld ) + { + fOld = f; + Sys_FPrintf( SYS_VRB, "%d...", f ); + } + + /* get projector */ + TransformDecalProjector( &projectors[ i ], identityAxis, e->origin, &dp ); + + /* walk the list of surfaces in the entity */ + for( j = e->firstDrawSurf; j < numMapDrawSurfs; j++ ) + { + /* get surface */ + ds = &mapDrawSurfs[ j ]; + if( ds->numVerts <= 0 ) + continue; + + /* ignore autosprite or nomarks */ + if( ds->shaderInfo->autosprite || (ds->shaderInfo->compileFlags & C_NOMARKS) ) + continue; + + /* bounds check */ + for( k = 0; k < 3; k++ ) + if( ds->mins[ k ] >= (dp.center[ k ] + dp.radius) || + ds->maxs[ k ] <= (dp.center[ k ] - dp.radius) ) + break; + if( k < 3 ) + continue; + + /* switch on type */ + switch( ds->type ) + { + case SURFACE_FACE: + ProjectDecalOntoFace( &dp, ds ); + break; + + case SURFACE_PATCH: + ProjectDecalOntoPatch( &dp, ds ); + break; + + case SURFACE_TRIANGLES: + case SURFACE_FORCED_META: + case SURFACE_META: + ProjectDecalOntoTriangles( &dp, ds ); + break; + + default: + break; + } + } + } + + /* print time */ + Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) ); + + /* emit some stats */ + Sys_FPrintf( SYS_VRB, "%9d decal surfaces\n", numDecalSurfaces ); +} diff --git a/tools/quake3/q3map2/facebsp.c b/tools/quake3/q3map2/facebsp.c new file mode 100644 index 00000000..b92facc4 --- /dev/null +++ b/tools/quake3/q3map2/facebsp.c @@ -0,0 +1,453 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define FACEBSP_C + + + +/* dependencies */ +#include "q3map2.h" + + + +int c_faceLeafs; + + +/* +================ +AllocBspFace +================ +*/ +face_t *AllocBspFace( void ) { + face_t *f; + + f = safe_malloc(sizeof(*f)); + memset( f, 0, sizeof(*f) ); + + return f; +} + + + +/* +================ +FreeBspFace +================ +*/ +void FreeBspFace( face_t *f ) { + if ( f->w ) { + FreeWinding( f->w ); + } + free( f ); +} + + + +/* +SelectSplitPlaneNum() +finds the best split plane for this node +*/ + +static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, int *compileFlags ) +{ + face_t *split; + face_t *check; + face_t *bestSplit; + int splits, facing, front, back; + int side; + plane_t *plane; + int value, bestValue; + int i; + vec3_t normal; + float dist; + int planenum; + + + /* ydnar: set some defaults */ + *splitPlaneNum = -1; /* leaf */ + *compileFlags = 0; + + /* ydnar 2002-06-24: changed this to split on z-axis as well */ + /* ydnar 2002-09-21: changed blocksize to be a vector, so mappers can specify a 3 element value */ + + /* if it is crossing a block boundary, force a split */ + for( i = 0; i < 3; i++ ) + { + if( blockSize[ i ] <= 0 ) + continue; + dist = blockSize[ i ] * (floor( node->mins[ i ] / blockSize[ i ] ) + 1); + if( node->maxs[ i ] > dist ) + { + VectorClear( normal ); + normal[ i ] = 1; + planenum = FindFloatPlane( normal, dist, 0, NULL ); + *splitPlaneNum = planenum; + return; + } + } + + /* pick one of the face planes */ + bestValue = -99999; + bestSplit = list; + + for( split = list; split; split = split->next ) + split->checked = qfalse; + + for( split = list; split; split = split->next ) + { + if ( split->checked ) + continue; + + plane = &mapplanes[ split->planenum ]; + splits = 0; + facing = 0; + front = 0; + back = 0; + for ( check = list ; check ; check = check->next ) { + if ( check->planenum == split->planenum ) { + facing++; + check->checked = qtrue; // won't need to test this plane again + continue; + } + side = WindingOnPlaneSide( check->w, plane->normal, plane->dist ); + if ( side == SIDE_CROSS ) { + splits++; + } else if ( side == SIDE_FRONT ) { + front++; + } else if ( side == SIDE_BACK ) { + back++; + } + } + value = 5*facing - 5*splits; // - abs(front-back); + if ( plane->type < 3 ) { + value+=5; // axial is better + } + value += split->priority; // prioritize hints higher + + if ( value > bestValue ) { + bestValue = value; + bestSplit = split; + } + } + + /* nothing, we have a leaf */ + if( bestValue == -99999 ) + return; + + /* set best split data */ + *splitPlaneNum = bestSplit->planenum; + *compileFlags = bestSplit->compileFlags; +} + + + +/* +CountFaceList() +counts bsp faces in the linked list +*/ + +int CountFaceList( face_t *list ) +{ + int c; + + + c = 0; + for( list; list != NULL; list = list->next ) + c++; + return c; +} + + + +/* +BuildFaceTree_r() +recursively builds the bsp, splitting on face planes +*/ + +void BuildFaceTree_r( node_t *node, face_t *list ) +{ + face_t *split; + face_t *next; + int side; + plane_t *plane; + face_t *newFace; + face_t *childLists[2]; + winding_t *frontWinding, *backWinding; + int i; + int splitPlaneNum, compileFlags; + + + /* count faces left */ + i = CountFaceList( list ); + + /* select the best split plane */ + SelectSplitPlaneNum( node, list, &splitPlaneNum, &compileFlags ); + + /* if we don't have any more faces, this is a node */ + if ( splitPlaneNum == -1 ) + { + node->planenum = PLANENUM_LEAF; + c_faceLeafs++; + return; + } + + /* partition the list */ + node->planenum = splitPlaneNum; + node->compileFlags = compileFlags; + plane = &mapplanes[ splitPlaneNum ]; + childLists[0] = NULL; + childLists[1] = NULL; + for( split = list; split; split = next ) + { + /* set next */ + next = split->next; + + /* don't split by identical plane */ + if( split->planenum == node->planenum ) + { + FreeBspFace( split ); + continue; + } + + /* determine which side the face falls on */ + side = WindingOnPlaneSide( split->w, plane->normal, plane->dist ); + + /* switch on side */ + if( side == SIDE_CROSS ) + { + ClipWindingEpsilon( split->w, plane->normal, plane->dist, CLIP_EPSILON * 2, + &frontWinding, &backWinding ); + if( frontWinding ) { + newFace = AllocBspFace(); + newFace->w = frontWinding; + newFace->next = childLists[0]; + newFace->planenum = split->planenum; + newFace->priority = split->priority; + newFace->compileFlags = split->compileFlags; + childLists[0] = newFace; + } + if( backWinding ) { + newFace = AllocBspFace(); + newFace->w = backWinding; + newFace->next = childLists[1]; + newFace->planenum = split->planenum; + newFace->priority = split->priority; + newFace->compileFlags = split->compileFlags; + childLists[1] = newFace; + } + FreeBspFace( split ); + } else if ( side == SIDE_FRONT ) { + split->next = childLists[0]; + childLists[0] = split; + } else if ( side == SIDE_BACK ) { + split->next = childLists[1]; + childLists[1] = split; + } + } + + + // recursively process children + for ( i = 0 ; i < 2 ; i++ ) { + node->children[i] = AllocNode(); + node->children[i]->parent = node; + VectorCopy( node->mins, node->children[i]->mins ); + VectorCopy( node->maxs, node->children[i]->maxs ); + } + + for ( i = 0 ; i < 3 ; i++ ) { + if ( plane->normal[i] == 1 ) { + node->children[0]->mins[i] = plane->dist; + node->children[1]->maxs[i] = plane->dist; + break; + } + } + + for ( i = 0 ; i < 2 ; i++ ) { + BuildFaceTree_r ( node->children[i], childLists[i]); + } +} + + +/* +================ +FaceBSP + +List will be freed before returning +================ +*/ +tree_t *FaceBSP( face_t *list ) { + tree_t *tree; + face_t *face; + int i; + int count; + + Sys_FPrintf (SYS_VRB, "--- FaceBSP ---\n" ); + + tree = AllocTree (); + + count = 0; + for( face = list; face != NULL; face = face->next ) + { + count++; + for( i = 0; i < face->w->numpoints; i++ ) + { + AddPointToBounds( face->w->p[ i ], tree->mins, tree->maxs ); + } + } + Sys_FPrintf( SYS_VRB, "%9d faces\n", count ); + + tree->headnode = AllocNode(); + VectorCopy( tree->mins, tree->headnode->mins ); + VectorCopy( tree->maxs, tree->headnode->maxs ); + c_faceLeafs = 0; + + BuildFaceTree_r ( tree->headnode, list ); + + Sys_FPrintf( SYS_VRB, "%9d leafs\n", c_faceLeafs ); + + return tree; +} + + + +/* +MakeStructuralBSPFaceList() +get structural brush faces +*/ + +face_t *MakeStructuralBSPFaceList( brush_t *list ) +{ + brush_t *b; + int i; + side_t *s; + winding_t *w; + face_t *f, *flist; + + + flist = NULL; + for( b = list; b != NULL; b = b->next ) + { + if( b->detail ) + continue; + + for( i = 0; i < b->numsides; i++ ) + { + /* get side and winding */ + s = &b->sides[ i ]; + w = s->winding; + if( w == NULL ) + continue; + + /* ydnar: skip certain faces */ + if( s->compileFlags & C_SKIP ) + continue; + + /* allocate a face */ + f = AllocBspFace(); + f->w = CopyWinding( w ); + f->planenum = s->planenum & ~1; + f->compileFlags = s->compileFlags; /* ydnar */ + + /* ydnar: set priority */ + f->priority = 0; + if( f->compileFlags & C_HINT ) + f->priority += HINT_PRIORITY; + if( f->compileFlags & C_ANTIPORTAL ) + f->priority += ANTIPORTAL_PRIORITY; + if( f->compileFlags & C_AREAPORTAL ) + f->priority += AREAPORTAL_PRIORITY; + + /* get next face */ + f->next = flist; + flist = f; + } + } + + return flist; +} + + + +/* +MakeVisibleBSPFaceList() +get visible brush faces +*/ + +face_t *MakeVisibleBSPFaceList( brush_t *list ) +{ + brush_t *b; + int i; + side_t *s; + winding_t *w; + face_t *f, *flist; + + + flist = NULL; + for( b = list; b != NULL; b = b->next ) + { + if( b->detail ) + continue; + + for( i = 0; i < b->numsides; i++ ) + { + /* get side and winding */ + s = &b->sides[ i ]; + w = s->visibleHull; + if( w == NULL ) + continue; + + /* ydnar: skip certain faces */ + if( s->compileFlags & C_SKIP ) + continue; + + /* allocate a face */ + f = AllocBspFace(); + f->w = CopyWinding( w ); + f->planenum = s->planenum & ~1; + f->compileFlags = s->compileFlags; /* ydnar */ + + /* ydnar: set priority */ + f->priority = 0; + if( f->compileFlags & C_HINT ) + f->priority += HINT_PRIORITY; + if( f->compileFlags & C_ANTIPORTAL ) + f->priority += ANTIPORTAL_PRIORITY; + if( f->compileFlags & C_AREAPORTAL ) + f->priority += AREAPORTAL_PRIORITY; + + /* get next face */ + f->next = flist; + flist = f; + } + } + + return flist; +} + diff --git a/tools/quake3/q3map2/fog.c b/tools/quake3/q3map2/fog.c new file mode 100644 index 00000000..70348099 --- /dev/null +++ b/tools/quake3/q3map2/fog.c @@ -0,0 +1,804 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define FOG_C + + + +/* dependencies */ +#include "q3map2.h" + + + +int numFogFragments; +int numFogPatchFragments; + + + +/* +DrawSurfToMesh() +converts a patch drawsurface to a mesh_t +*/ + +mesh_t *DrawSurfToMesh( mapDrawSurface_t *ds ) +{ + mesh_t *m; + + + m = safe_malloc( sizeof( *m ) ); + m->width = ds->patchWidth; + m->height = ds->patchHeight; + m->verts = safe_malloc( sizeof(m->verts[ 0 ]) * m->width * m->height ); + memcpy( m->verts, ds->verts, sizeof(m->verts[ 0 ]) * m->width * m->height ); + + return m; +} + + + +/* +SplitMeshByPlane() +chops a mesh by a plane +*/ + +void SplitMeshByPlane( mesh_t *in, vec3_t normal, float dist, mesh_t **front, mesh_t **back ) +{ + int w, h, split; + float d[MAX_PATCH_SIZE][MAX_PATCH_SIZE]; + bspDrawVert_t *dv, *v1, *v2; + int c_front, c_back, c_on; + mesh_t *f, *b; + int i; + float frac; + int frontAprox, backAprox; + + for ( i = 0 ; i < 2 ; i++ ) { + dv = in->verts; + c_front = 0; + c_back = 0; + c_on = 0; + for ( h = 0 ; h < in->height ; h++ ) { + for ( w = 0 ; w < in->width ; w++, dv++ ) { + d[h][w] = DotProduct( dv->xyz, normal ) - dist; + if ( d[h][w] > ON_EPSILON ) { + c_front++; + } else if ( d[h][w] < -ON_EPSILON ) { + c_back++; + } else { + c_on++; + } + } + } + + *front = NULL; + *back = NULL; + + if ( !c_front ) { + *back = in; + return; + } + if ( !c_back ) { + *front = in; + return; + } + + // find a split point + split = -1; + for ( w = 0 ; w < in->width -1 ; w++ ) { + if ( ( d[0][w] < 0 ) != ( d[0][w+1] < 0 ) ) { + if ( split == -1 ) { + split = w; + break; + } + } + } + + if ( split == -1 ) { + if ( i == 1 ) { + Sys_FPrintf (SYS_VRB, "No crossing points in patch\n"); + *front = in; + return; + } + + in = TransposeMesh( in ); + InvertMesh( in ); + continue; + } + + // make sure the split point stays the same for all other rows + for ( h = 1 ; h < in->height ; h++ ) { + for ( w = 0 ; w < in->width -1 ; w++ ) { + if ( ( d[h][w] < 0 ) != ( d[h][w+1] < 0 ) ) { + if ( w != split ) { + Sys_Printf( "multiple crossing points for patch -- can't clip\n"); + *front = in; + return; + } + } + } + if ( ( d[h][split] < 0 ) == ( d[h][split+1] < 0 ) ) { + Sys_Printf( "differing crossing points for patch -- can't clip\n"); + *front = in; + return; + } + } + + break; + } + + + // create two new meshes + f = safe_malloc( sizeof( *f ) ); + f->width = split + 2; + if ( ! (f->width & 1) ) { + f->width++; + frontAprox = 1; + } else { + frontAprox = 0; + } + if ( f->width > MAX_PATCH_SIZE ) { + Error( "MAX_PATCH_SIZE after split"); + } + f->height = in->height; + f->verts = safe_malloc( sizeof(f->verts[0]) * f->width * f->height ); + + b = safe_malloc( sizeof( *b ) ); + b->width = in->width - split; + if ( ! (b->width & 1) ) { + b->width++; + backAprox = 1; + } else { + backAprox = 0; + } + if ( b->width > MAX_PATCH_SIZE ) { + Error( "MAX_PATCH_SIZE after split"); + } + b->height = in->height; + b->verts = safe_malloc( sizeof(b->verts[0]) * b->width * b->height ); + + if ( d[0][0] > 0 ) { + *front = f; + *back = b; + } else { + *front = b; + *back = f; + } + + // distribute the points + for ( w = 0 ; w < in->width ; w++ ) { + for ( h = 0 ; h < in->height ; h++ ) { + if ( w <= split ) { + f->verts[ h * f->width + w ] = in->verts[ h * in->width + w ]; + } else { + b->verts[ h * b->width + w - split + backAprox ] = in->verts[ h * in->width + w ]; + } + } + } + + // clip the crossing line + for ( h = 0; h < in->height; h++ ) + { + dv = &f->verts[ h * f->width + split + 1 ]; + v1 = &in->verts[ h * in->width + split ]; + v2 = &in->verts[ h * in->width + split + 1 ]; + + frac = d[h][split] / ( d[h][split] - d[h][split+1] ); + + /* interpolate */ + //% for( i = 0; i < 10; i++ ) + //% dv->xyz[ i ] = v1->xyz[ i ] + frac * (v2->xyz[ i ] - v1->xyz[ i ]); + //% dv->xyz[10] = 0; // set all 4 colors to 0 + LerpDrawVertAmount( v1, v2, frac, dv ); + + if ( frontAprox ) { + f->verts[ h * f->width + split + 2 ] = *dv; + } + b->verts[ h * b->width ] = *dv; + if ( backAprox ) { + b->verts[ h * b->width + 1 ] = *dv; + } + } + + /* +PrintMesh( in ); +Sys_Printf("\n"); +PrintMesh( f ); +Sys_Printf("\n"); +PrintMesh( b ); +Sys_Printf("\n"); + */ + + FreeMesh( in ); +} + + +/* +ChopPatchSurfaceByBrush() +chops a patch up by a fog brush +*/ + +qboolean ChopPatchSurfaceByBrush( entity_t *e, mapDrawSurface_t *ds, brush_t *b ) +{ + int i, j; + side_t *s; + plane_t *plane; + mesh_t *outside[MAX_BRUSH_SIDES]; + int numOutside; + mesh_t *m, *front, *back; + mapDrawSurface_t *newds; + + m = DrawSurfToMesh( ds ); + numOutside = 0; + + // only split by the top and bottom planes to avoid + // some messy patch clipping issues + + for ( i = 4 ; i <= 5 ; i++ ) { + s = &b->sides[ i ]; + plane = &mapplanes[ s->planenum ]; + + SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back ); + + if ( !back ) { + // nothing actually contained inside + for ( j = 0 ; j < numOutside ; j++ ) { + FreeMesh( outside[j] ); + } + return qfalse; + } + m = back; + + if ( front ) { + if ( numOutside == MAX_BRUSH_SIDES ) { + Error( "MAX_BRUSH_SIDES" ); + } + outside[ numOutside ] = front; + numOutside++; + } + } + + /* all of outside fragments become seperate drawsurfs */ + numFogPatchFragments += numOutside; + for( i = 0; i < numOutside; i++ ) + { + /* transpose and invert the chopped patch (fixes potential crash. fixme: why?) */ + outside[ i ] = TransposeMesh( outside[ i ] ); + InvertMesh( outside[ i ] ); + + /* ydnar: do this the hacky right way */ + newds = AllocDrawSurface( SURFACE_PATCH ); + memcpy( newds, ds, sizeof( *ds ) ); + newds->patchWidth = outside[ i ]->width; + newds->patchHeight = outside[ i ]->height; + newds->numVerts = outside[ i ]->width * outside[ i ]->height; + newds->verts = safe_malloc( newds->numVerts * sizeof( *newds->verts ) ); + memcpy( newds->verts, outside[ i ]->verts, newds->numVerts * sizeof( *newds->verts ) ); + + /* free the source mesh */ + FreeMesh( outside[ i ] ); + } + + /* only rejigger this patch if it was chopped */ + //% Sys_Printf( "Inside: %d x %d\n", m->width, m->height ); + if( numOutside > 0 ) + { + /* transpose and invert the chopped patch (fixes potential crash. fixme: why?) */ + m = TransposeMesh( m ); + InvertMesh( m ); + + /* replace ds with m */ + ds->patchWidth = m->width; + ds->patchHeight = m->height; + ds->numVerts = m->width * m->height; + free( ds->verts ); + ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) ); + memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) ); + } + + /* free the source mesh and return */ + FreeMesh( m ); + return qtrue; +} + + + +/* +WindingFromDrawSurf() +creates a winding from a surface's verts +*/ + +winding_t *WindingFromDrawSurf( mapDrawSurface_t *ds ) +{ + winding_t *w; + int i; + + // we use the first point of the surface, maybe something more clever would be useful + // (actually send the whole draw surface would be cool?) + if( ds->numVerts >= MAX_POINTS_ON_WINDING ) + { + int max = ds->numVerts; + vec3_t p[256]; + + if(max > 256) + max = 256; + + for ( i = 0 ; i < max ; i++ ) { + VectorCopy( ds->verts[i].xyz, p[i] ); + } + + xml_Winding( "WindingFromDrawSurf failed: MAX_POINTS_ON_WINDING exceeded", p, max, qtrue ); + } + + w = AllocWinding( ds->numVerts ); + w->numpoints = ds->numVerts; + for ( i = 0 ; i < ds->numVerts ; i++ ) { + VectorCopy( ds->verts[i].xyz, w->p[i] ); + } + return w; +} + + + +/* +ChopFaceSurfaceByBrush() +chops up a face drawsurface by a fog brush, with a potential fragment left inside +*/ + +qboolean ChopFaceSurfaceByBrush( entity_t *e, mapDrawSurface_t *ds, brush_t *b ) +{ + int i, j; + side_t *s; + plane_t *plane; + winding_t *w; + winding_t *front, *back; + winding_t *outside[ MAX_BRUSH_SIDES ]; + int numOutside; + mapDrawSurface_t *newds; + + + /* dummy check */ + if( ds->sideRef == NULL || ds->sideRef->side == NULL ) + return qfalse; + + /* initial setup */ + w = WindingFromDrawSurf( ds ); + numOutside = 0; + + /* chop by each brush side */ + for( i = 0; i < b->numsides; i++ ) + { + /* get brush side and plane */ + s = &b->sides[ i ]; + if( s->backSide ) + continue; + plane = &mapplanes[ s->planenum ]; + + /* handle coplanar outfacing (don't fog) */ + if( ds->sideRef->side->planenum == s->planenum ) + return qfalse; + + /* handle coplanar infacing (keep inside) */ + if( (ds->sideRef->side->planenum ^ 1) == s->planenum ) + continue; + + /* general case */ + ClipWindingEpsilon( w, plane->normal, plane->dist, ON_EPSILON, &front, &back ); + FreeWinding( w ); + + if( back == NULL ) + { + /* nothing actually contained inside */ + for( j = 0; j < numOutside; j++ ) + FreeWinding( outside[ j ] ); + return qfalse; + } + + if( front != NULL ) + { + if( numOutside == MAX_BRUSH_SIDES ) + Error( "MAX_BRUSH_SIDES" ); + outside[ numOutside ] = front; + numOutside++; + } + + w = back; + } + + /* fixme: celshaded surface fragment errata */ + + /* all of outside fragments become seperate drawsurfs */ + numFogFragments += numOutside; + s = ds->sideRef->side; + for( i = 0; i < numOutside; i++ ) + { + newds = DrawSurfaceForSide( e, ds->mapBrush, s, outside[ i ] ); + newds->fogNum = ds->fogNum; + FreeWinding( outside[ i ] ); + } + + /* ydnar: the old code neglected to snap to 0.125 for the fragment + inside the fog brush, leading to sparklies. this new code does + the right thing and uses the original surface's brush side */ + + /* build a drawsurf for it */ + newds = DrawSurfaceForSide( e, ds->mapBrush, s, w ); + if( newds == NULL ) + return qfalse; + + /* copy new to original */ + ClearSurface( ds ); + memcpy( ds, newds, sizeof( mapDrawSurface_t ) ); + + /* didn't really add a new drawsurface... :) */ + numMapDrawSurfs--; + + /* return ok */ + return qtrue; +} + + + +/* +FogDrawSurfaces() +call after the surface list has been pruned, before tjunction fixing +*/ + +void FogDrawSurfaces( entity_t *e ) +{ + int i, j, k, fogNum; + fog_t *fog; + mapDrawSurface_t *ds; + vec3_t mins, maxs; + int fogged, numFogged; + int numBaseDrawSurfs; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "----- FogDrawSurfs -----\n" ); + + /* reset counters */ + numFogged = 0; + numFogFragments = 0; + + /* walk fog list */ + for( fogNum = 0; fogNum < numMapFogs; fogNum++ ) + { + /* get fog */ + fog = &mapFogs[ fogNum ]; + + /* clip each surface into this, but don't clip any of the resulting fragments to the same brush */ + numBaseDrawSurfs = numMapDrawSurfs; + for( i = 0; i < numBaseDrawSurfs; i++ ) + { + /* get the drawsurface */ + ds = &mapDrawSurfs[ i ]; + + /* no fog? */ + if( ds->shaderInfo->noFog ) + continue; + + /* global fog doesn't have a brush */ + if( fog->brush == NULL ) + { + /* don't re-fog already fogged surfaces */ + if( ds->fogNum >= 0 ) + continue; + fogged = 1; + } + else + { + /* find drawsurface bounds */ + ClearBounds( mins, maxs ); + for( j = 0; j < ds->numVerts; j++ ) + AddPointToBounds( ds->verts[ j ].xyz, mins, maxs ); + + /* check against the fog brush */ + for( k = 0; k < 3; k++ ) + { + if( mins[ k ] > fog->brush->maxs[ k ] ) + break; + if( maxs[ k ] < fog->brush->mins[ k ] ) + break; + } + + /* no intersection? */ + if( k < 3 ) + continue; + + /* ydnar: gs mods: handle the various types of surfaces */ + switch( ds->type ) + { + /* handle brush faces */ + case SURFACE_FACE: + fogged = ChopFaceSurfaceByBrush( e, ds, fog->brush ); + break; + + /* handle patches */ + case SURFACE_PATCH: + fogged = ChopPatchSurfaceByBrush( e, ds, fog->brush ); + break; + + /* handle triangle surfaces (fixme: split triangle surfaces) */ + case SURFACE_TRIANGLES: + case SURFACE_FORCED_META: + case SURFACE_META: + fogged = 1; + break; + + /* no fogging */ + default: + fogged = 0; + break; + } + } + + /* is this surface fogged? */ + if( fogged ) + { + numFogged += fogged; + ds->fogNum = fogNum; + } + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d fog polygon fragments\n", numFogFragments ); + Sys_FPrintf( SYS_VRB, "%9d fog patch fragments\n", numFogPatchFragments ); + Sys_FPrintf( SYS_VRB, "%9d fogged drawsurfs\n", numFogged ); +} + + + +/* +FogForPoint() - ydnar +gets the fog number for a point in space +*/ + +int FogForPoint( vec3_t point, float epsilon ) +{ + int fogNum, i, j; + float dot; + qboolean inside; + brush_t *brush; + plane_t *plane; + + + /* start with bogus fog num */ + fogNum = defaultFogNum; + + /* walk the list of fog volumes */ + for( i = 0; i < numMapFogs; i++ ) + { + /* sof2: global fog doesn't reference a brush */ + if( mapFogs[ i ].brush == NULL ) + { + fogNum = i; + continue; + } + + /* get fog brush */ + brush = mapFogs[ i ].brush; + + /* check point against all planes */ + inside = qtrue; + for( j = 0; j < brush->numsides && inside; j++ ) + { + plane = &mapplanes[ brush->sides[ j ].planenum ]; /* note usage of map planes here */ + dot = DotProduct( point, plane->normal ); + dot -= plane->dist; + if( dot > epsilon ) + inside = qfalse; + } + + /* if inside, return the fog num */ + if( inside ) + { + //% Sys_Printf( "FogForPoint: %f, %f, %f in fog %d\n", point[ 0 ], point[ 1 ], point[ 2 ], i ); + return i; + } + } + + /* if the point made it this far, it's not inside any fog volumes (or inside global fog) */ + return fogNum; +} + + + +/* +FogForBounds() - ydnar +gets the fog number for a bounding box +*/ + +int FogForBounds( vec3_t mins, vec3_t maxs, float epsilon ) +{ + int fogNum, i, j; + float highMin, lowMax, volume, bestVolume; + vec3_t fogMins, fogMaxs, overlap; + brush_t *brush; + + + /* start with bogus fog num */ + fogNum = defaultFogNum; + + /* init */ + bestVolume = 0.0f; + + /* walk the list of fog volumes */ + for( i = 0; i < numMapFogs; i++ ) + { + /* sof2: global fog doesn't reference a brush */ + if( mapFogs[ i ].brush == NULL ) + { + fogNum = i; + continue; + } + + /* get fog brush */ + brush = mapFogs[ i ].brush; + + /* get bounds */ + fogMins[ 0 ] = brush->mins[ 0 ] - epsilon; + fogMins[ 1 ] = brush->mins[ 1 ] - epsilon; + fogMins[ 2 ] = brush->mins[ 2 ] - epsilon; + fogMaxs[ 0 ] = brush->maxs[ 0 ] + epsilon; + fogMaxs[ 1 ] = brush->maxs[ 1 ] + epsilon; + fogMaxs[ 2 ] = brush->maxs[ 2 ] + epsilon; + + /* check against bounds */ + for( j = 0; j < 3; j++ ) + { + if( mins[ j ] > fogMaxs[ j ] || maxs[ j ] < fogMins[ j ] ) + break; + highMin = mins[ j ] > fogMins[ j ] ? mins[ j ] : fogMins[ j ]; + lowMax = maxs[ j ] < fogMaxs[ j ] ? maxs[ j ] : fogMaxs[ j ]; + overlap[ j ] = lowMax - highMin; + if( overlap[ j ] < 1.0f ) + overlap[ j ] = 1.0f; + } + + /* no overlap */ + if( j < 3 ) + continue; + + /* get volume */ + volume = overlap[ 0 ] * overlap[ 1 ] * overlap[ 2 ]; + + /* test against best volume */ + if( volume > bestVolume ) + { + bestVolume = volume; + fogNum = i; + } + } + + /* if the point made it this far, it's not inside any fog volumes (or inside global fog) */ + return fogNum; +} + + + +/* +CreateMapFogs() - ydnar +generates a list of map fogs +*/ + +void CreateMapFogs( void ) +{ + int i; + entity_t *entity; + brush_t *brush; + fog_t *fog; + vec3_t invFogDir; + const char *globalFog; + + + /* skip? */ + if( nofog ) + return; + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- CreateMapFogs ---\n" ); + + /* walk entities */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity */ + entity = &entities[ i ]; + + /* walk entity brushes */ + for( brush = entity->brushes; brush != NULL; brush = brush->next ) + { + /* ignore non-fog brushes */ + if( brush->contentShader->fogParms == qfalse ) + continue; + + /* test limit */ + if( numMapFogs >= MAX_MAP_FOGS ) + Error( "Exceeded MAX_MAP_FOGS (%d)", MAX_MAP_FOGS ); + + /* set up fog */ + fog = &mapFogs[ numMapFogs++ ]; + fog->si = brush->contentShader; + fog->brush = brush; + fog->visibleSide = -1; + + /* if shader specifies an explicit direction, then find a matching brush side with an opposed normal */ + if( VectorLength( fog->si->fogDir ) ) + { + /* flip it */ + VectorScale( fog->si->fogDir, -1.0f, invFogDir ); + + /* find the brush side */ + for( i = 0; i < brush->numsides; i++ ) + { + if( VectorCompare( invFogDir, mapplanes[ brush->sides[ i ].planenum ].normal ) ) + { + fog->visibleSide = i; + //% Sys_Printf( "Brush num: %d Side num: %d\n", fog->brushNum, fog->visibleSide ); + break; + } + } + } + } + } + + /* ydnar: global fog */ + globalFog = ValueForKey( &entities[ 0 ], "_fog" ); + if( globalFog[ 0 ] == '\0' ) + globalFog = ValueForKey( &entities[ 0 ], "fog" ); + if( globalFog[ 0 ] != '\0' ) + { + /* test limit */ + if( numMapFogs >= MAX_MAP_FOGS ) + Error( "Exceeded MAX_MAP_FOGS (%d) trying to add global fog", MAX_MAP_FOGS ); + + /* note it */ + Sys_FPrintf( SYS_VRB, "Map has global fog shader %s\n", globalFog ); + + /* set up fog */ + fog = &mapFogs[ numMapFogs++ ]; + fog->si = ShaderInfoForShader( globalFog ); + if( fog->si == NULL ) + Error( "Invalid shader \"%s\" referenced trying to add global fog", globalFog ); + fog->brush = NULL; + fog->visibleSide = -1; + + /* set as default fog */ + defaultFogNum = numMapFogs - 1; + + /* mark all worldspawn brushes as fogged */ + for( brush = entities[ 0 ].brushes; brush != NULL; brush = brush->next ) + ApplySurfaceParm( "fog", &brush->contentFlags, NULL, &brush->compileFlags ); + } + + /* emit some stats */ + Sys_FPrintf( SYS_VRB, "%9d fogs\n", numMapFogs ); +} + diff --git a/tools/quake3/q3map2/game_ef.h b/tools/quake3/q3map2/game_ef.h new file mode 100644 index 00000000..6b1c7bfa --- /dev/null +++ b/tools/quake3/q3map2/game_ef.h @@ -0,0 +1,186 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_EF_H +#define GAME_EF_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* game flags */ +#define E_CONT_SOLID 1 /* an eye is never valid in a solid */ +#define E_CONT_LAVA 8 +#define E_CONT_SLIME 16 +#define E_CONT_WATER 32 +#define E_CONT_FOG 64 +#define E_CONT_LADDER 128 /* elite force ladder contents */ + +#define E_CONT_AREAPORTAL 0x8000 + +#define E_CONT_PLAYERCLIP 0x10000 +#define E_CONT_MONSTERCLIP 0x20000 +#define E_CONT_SHOTCLIP 0x40000 /* elite force shot clip */ +#define E_CONT_ITEM 0x80000 +#define E_CONT_CLUSTERPORTAL 0x100000 +#define E_CONT_DONOTENTER 0x200000 +#define E_CONT_BOTCLIP 0x400000 + +#define E_CONT_ORIGIN 0x1000000 /* removed before bsping an entity */ + +#define E_CONT_BODY 0x2000000 /* should never be on a brush, only in game */ +#define E_CONT_CORPSE 0x4000000 +#define E_CONT_DETAIL 0x8000000 /* brushes not used for the bsp */ +#define E_CONT_STRUCTURAL 0x10000000 /* brushes used for the bsp */ +#define E_CONT_TRANSLUCENT 0x20000000 /* don't consume surface fragments inside */ +#define E_CONT_TRIGGER 0x40000000 +#define E_CONT_NODROP 0x80000000 /* don't leave bodies or items (death fog, lava) */ + +#define E_SURF_NODAMAGE 0x1 /* never give falling damage */ +#define E_SURF_SLICK 0x2 /* effects game physics */ +#define E_SURF_SKY 0x4 /* lighting from environment map */ +#define E_SURF_LADDER 0x8 +#define E_SURF_NOIMPACT 0x10 /* don't make missile explosions */ +#define E_SURF_NOMARKS 0x20 /* don't leave missile marks */ +#define E_SURF_FLESH 0x40 /* make flesh sounds and effects */ +#define E_SURF_NODRAW 0x80 /* don't generate a drawsurface at all */ +#define E_SURF_HINT 0x100 /* make a primary bsp splitter */ +#define E_SURF_SKIP 0x200 /* completely ignore, allowing non-closed brushes */ +#define E_SURF_NOLIGHTMAP 0x400 /* surface doesn't need a lightmap */ +#define E_SURF_POINTLIGHT 0x800 /* generate lighting info at vertexes */ +#define E_SURF_METALSTEPS 0x1000 /* clanking footsteps */ +#define E_SURF_NOSTEPS 0x2000 /* no footstep sounds */ +#define E_SURF_NONSOLID 0x4000 /* don't collide against curves with this set */ +#define E_SURF_LIGHTFILTER 0x8000 /* act as a light filter during q3map -light */ +#define E_SURF_ALPHASHADOW 0x10000 /* do per-pixel light shadow casting in q3map */ +#define E_SURF_NODLIGHT 0x20000 /* don't dlight even if solid (solid lava, skies) */ +#define E_SURF_FORCEFIELD 0x40000 /* elite force forcefield brushes */ + +/* ydnar flags */ +#define E_SURF_VERTEXLIT (E_SURF_POINTLIGHT | E_SURF_NOLIGHTMAP) + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "ef", /* -game x */ + "baseef", /* default base game data dir */ + ".ef", /* unix home sub-dir */ + "elite", /* magic path word */ + "scripts", /* shader directory */ + qfalse, /* wolf lighting model? */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", E_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", E_CONT_ORIGIN, E_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", E_CONT_AREAPORTAL, E_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", E_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", E_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", E_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, E_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, E_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, E_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, E_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, E_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, E_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, E_CONT_SOLID, E_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", E_CONT_TRIGGER, E_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", E_CONT_WATER, E_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", E_CONT_SLIME, E_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", E_CONT_LAVA, E_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", E_CONT_PLAYERCLIP, E_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", E_CONT_MONSTERCLIP, E_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "shotclip", E_CONT_SHOTCLIP, E_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", E_CONT_NODROP, E_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", E_CONT_CLUSTERPORTAL, E_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", E_CONT_DONOTENTER, E_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", E_CONT_BOTCLIP, E_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", E_CONT_FOG, E_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, E_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, E_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, E_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, E_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", E_CONT_LADDER, E_CONT_SOLID, E_SURF_LADDER, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodamage", 0, 0, E_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, E_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, E_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, E_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, E_SURF_NODLIGHT, 0, 0, 0 }, + { "forcefield", 0, 0, E_SURF_FORCEFIELD, 0, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_ja.h b/tools/quake3/q3map2/game_ja.h new file mode 100644 index 00000000..f0f8b276 --- /dev/null +++ b/tools/quake3/q3map2/game_ja.h @@ -0,0 +1,180 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_JA_H +#define GAME_JA_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* this file must be included *after* game_sof2.h and game_jk2.h because they share defines! */ + +#define JA_CONT_INSIDE 0x10000000 /* jedi academy 'inside' */ +#define JA_SURF_FORCESIGHT 0x02000000 /* jedi academy 'forcesight' */ + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "ja", /* -game x */ + "base", /* default base game data dir */ + ".ja", /* unix home sub-dir */ + "GameData", /* magic path word */ + "shaders", /* shader directory */ + qfalse, /* wolf lighting model? */ + qtrue, /* flares */ + "gfx/misc/flare", /* default flare shader */ + "RBSP", /* bsp file prefix */ + 1, /* bsp file version */ + LoadRBSPFile, /* bsp load function */ + WriteRBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", S_CONT_SOLID | S_CONT_OPAQUE, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", 0, S_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", S_CONT_TRANSLUCENT, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", S_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", S_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", 0, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, 0, 0, C_HINT, 0 }, + { "nodraw", 0, 0, S_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, 0, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, 0, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, 0, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, 0, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, S_CONT_SOLID, 0, 0, 0, C_SOLID }, + { "nonopaque", 0, S_CONT_OPAQUE, 0, 0, C_TRANSLUCENT, 0 }, /* setting trans ok? */ + + { "trigger", S_CONT_TRIGGER, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", S_CONT_WATER, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", S_CONT_SLIME, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", S_CONT_LAVA, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "shotclip", S_CONT_SHOTCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, /* setting trans/detail ok? */ + { "playerclip", S_CONT_PLAYERCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", S_CONT_MONSTERCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", S_CONT_NODROP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "terrain", S_CONT_TERRAIN, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "ladder", S_CONT_LADDER, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "abseil", S_CONT_ABSEIL, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "outside", S_CONT_OUTSIDE, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "botclip", S_CONT_BOTCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "fog", S_CONT_FOG, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_FOG | C_DETAIL | C_TRANSLUCENT, C_SOLID }, /* nonopaque? */ + { "sky", 0, 0, S_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, S_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, S_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, S_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "nodamage", 0, 0, S_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, S_SURF_METALSTEPS, 0, 0, 0 }, + { "nosteps", 0, 0, S_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, S_SURF_NODLIGHT, 0, 0, 0 }, + { "nomiscents", 0, 0, S_SURF_NOMISCENTS, 0, 0, 0 }, + { "forcefield", 0, 0, S_SURF_FORCEFIELD, 0, 0, 0 }, + + /* jedi academy */ + { "inside", JA_CONT_INSIDE, 0, 0, 0, 0, 0 }, + { "forcesight", 0, 0, JA_SURF_FORCESIGHT, 0, 0, 0 }, + + /* materials */ + { "*mat_none", 0, 0, S_MAT_NONE, S_MAT_MASK, 0, 0 }, + { "*mat_solidwood", 0, 0, S_MAT_SOLIDWOOD, S_MAT_MASK, 0, 0 }, + { "*mat_hollowwood", 0, 0, S_MAT_HOLLOWWOOD, S_MAT_MASK, 0, 0 }, + { "*mat_solidmetal", 0, 0, S_MAT_SOLIDMETAL, S_MAT_MASK, 0, 0 }, + { "*mat_hollowmetal", 0, 0, S_MAT_HOLLOWMETAL, S_MAT_MASK, 0, 0 }, + { "*mat_shortgrass", 0, 0, S_MAT_SHORTGRASS, S_MAT_MASK, 0, 0 }, + { "*mat_longgrass", 0, 0, S_MAT_LONGGRASS, S_MAT_MASK, 0, 0 }, + { "*mat_dirt", 0, 0, S_MAT_DIRT, S_MAT_MASK, 0, 0 }, + { "*mat_sand", 0, 0, S_MAT_SAND, S_MAT_MASK, 0, 0 }, + { "*mat_gravel", 0, 0, S_MAT_GRAVEL, S_MAT_MASK, 0, 0 }, + { "*mat_glass", 0, 0, S_MAT_GLASS, S_MAT_MASK, 0, 0 }, + { "*mat_concrete", 0, 0, S_MAT_CONCRETE, S_MAT_MASK, 0, 0 }, + { "*mat_marble", 0, 0, S_MAT_MARBLE, S_MAT_MASK, 0, 0 }, + { "*mat_water", 0, 0, S_MAT_WATER, S_MAT_MASK, 0, 0 }, + { "*mat_snow", 0, 0, S_MAT_SNOW, S_MAT_MASK, 0, 0 }, + { "*mat_ice", 0, 0, S_MAT_ICE, S_MAT_MASK, 0, 0 }, + { "*mat_flesh", 0, 0, S_MAT_FLESH, S_MAT_MASK, 0, 0 }, + { "*mat_mud", 0, 0, S_MAT_MUD, S_MAT_MASK, 0, 0 }, + { "*mat_bpglass", 0, 0, S_MAT_BPGLASS, S_MAT_MASK, 0, 0 }, + { "*mat_dryleaves", 0, 0, S_MAT_DRYLEAVES, S_MAT_MASK, 0, 0 }, + { "*mat_greenleaves", 0, 0, S_MAT_GREENLEAVES, S_MAT_MASK, 0, 0 }, + { "*mat_fabric", 0, 0, S_MAT_FABRIC, S_MAT_MASK, 0, 0 }, + { "*mat_canvas", 0, 0, S_MAT_CANVAS, S_MAT_MASK, 0, 0 }, + { "*mat_rock", 0, 0, S_MAT_ROCK, S_MAT_MASK, 0, 0 }, + { "*mat_rubber", 0, 0, S_MAT_RUBBER, S_MAT_MASK, 0, 0 }, + { "*mat_plastic", 0, 0, S_MAT_PLASTIC, S_MAT_MASK, 0, 0 }, + { "*mat_tiles", 0, 0, S_MAT_TILES, S_MAT_MASK, 0, 0 }, + { "*mat_carpet", 0, 0, S_MAT_CARPET, S_MAT_MASK, 0, 0 }, + { "*mat_plaster", 0, 0, S_MAT_PLASTER, S_MAT_MASK, 0, 0 }, + { "*mat_shatterglass", 0, 0, S_MAT_SHATTERGLASS, S_MAT_MASK, 0, 0 }, + { "*mat_armor", 0, 0, S_MAT_ARMOR, S_MAT_MASK, 0, 0 }, + { "*mat_computer", 0, 0, S_MAT_COMPUTER, S_MAT_MASK, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif diff --git a/tools/quake3/q3map2/game_jk2.h b/tools/quake3/q3map2/game_jk2.h new file mode 100644 index 00000000..8fbf7202 --- /dev/null +++ b/tools/quake3/q3map2/game_jk2.h @@ -0,0 +1,174 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_JK2_H +#define GAME_JK2_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* this file must be included *after* game_sof2.h because it shares defines! */ + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "jk2", /* -game x */ + "base", /* default base game data dir */ + ".jk2", /* unix home sub-dir */ + "GameData", /* magic path word */ + "shaders", /* shader directory */ + qfalse, /* wolf lighting model? */ + qtrue, /* flares */ + "gfx/misc/flare", /* default flare shader */ + "RBSP", /* bsp file prefix */ + 1, /* bsp file version */ + LoadRBSPFile, /* bsp load function */ + WriteRBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", S_CONT_SOLID | S_CONT_OPAQUE, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", 0, S_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", S_CONT_TRANSLUCENT, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", S_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", S_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", 0, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, 0, 0, C_HINT, 0 }, + { "nodraw", 0, 0, S_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, 0, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, 0, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, 0, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, 0, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, S_CONT_SOLID, 0, 0, 0, C_SOLID }, + { "nonopaque", 0, S_CONT_OPAQUE, 0, 0, C_TRANSLUCENT, 0 }, /* setting trans ok? */ + + { "trigger", S_CONT_TRIGGER, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", S_CONT_WATER, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", S_CONT_SLIME, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", S_CONT_LAVA, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "shotclip", S_CONT_SHOTCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, /* setting trans/detail ok? */ + { "playerclip", S_CONT_PLAYERCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", S_CONT_MONSTERCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", S_CONT_NODROP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "terrain", S_CONT_TERRAIN, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "ladder", S_CONT_LADDER, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "abseil", S_CONT_ABSEIL, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "outside", S_CONT_OUTSIDE, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "botclip", S_CONT_BOTCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "fog", S_CONT_FOG, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_FOG | C_DETAIL | C_TRANSLUCENT, C_SOLID }, /* nonopaque? */ + { "sky", 0, 0, S_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, S_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, S_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, S_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "nodamage", 0, 0, S_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, S_SURF_METALSTEPS, 0, 0, 0 }, + { "nosteps", 0, 0, S_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, S_SURF_NODLIGHT, 0, 0, 0 }, + { "nomiscents", 0, 0, S_SURF_NOMISCENTS, 0, 0, 0 }, + { "forcefield", 0, 0, S_SURF_FORCEFIELD, 0, 0, 0 }, + + + /* materials */ + { "*mat_none", 0, 0, S_MAT_NONE, S_MAT_MASK, 0, 0 }, + { "*mat_solidwood", 0, 0, S_MAT_SOLIDWOOD, S_MAT_MASK, 0, 0 }, + { "*mat_hollowwood", 0, 0, S_MAT_HOLLOWWOOD, S_MAT_MASK, 0, 0 }, + { "*mat_solidmetal", 0, 0, S_MAT_SOLIDMETAL, S_MAT_MASK, 0, 0 }, + { "*mat_hollowmetal", 0, 0, S_MAT_HOLLOWMETAL, S_MAT_MASK, 0, 0 }, + { "*mat_shortgrass", 0, 0, S_MAT_SHORTGRASS, S_MAT_MASK, 0, 0 }, + { "*mat_longgrass", 0, 0, S_MAT_LONGGRASS, S_MAT_MASK, 0, 0 }, + { "*mat_dirt", 0, 0, S_MAT_DIRT, S_MAT_MASK, 0, 0 }, + { "*mat_sand", 0, 0, S_MAT_SAND, S_MAT_MASK, 0, 0 }, + { "*mat_gravel", 0, 0, S_MAT_GRAVEL, S_MAT_MASK, 0, 0 }, + { "*mat_glass", 0, 0, S_MAT_GLASS, S_MAT_MASK, 0, 0 }, + { "*mat_concrete", 0, 0, S_MAT_CONCRETE, S_MAT_MASK, 0, 0 }, + { "*mat_marble", 0, 0, S_MAT_MARBLE, S_MAT_MASK, 0, 0 }, + { "*mat_water", 0, 0, S_MAT_WATER, S_MAT_MASK, 0, 0 }, + { "*mat_snow", 0, 0, S_MAT_SNOW, S_MAT_MASK, 0, 0 }, + { "*mat_ice", 0, 0, S_MAT_ICE, S_MAT_MASK, 0, 0 }, + { "*mat_flesh", 0, 0, S_MAT_FLESH, S_MAT_MASK, 0, 0 }, + { "*mat_mud", 0, 0, S_MAT_MUD, S_MAT_MASK, 0, 0 }, + { "*mat_bpglass", 0, 0, S_MAT_BPGLASS, S_MAT_MASK, 0, 0 }, + { "*mat_dryleaves", 0, 0, S_MAT_DRYLEAVES, S_MAT_MASK, 0, 0 }, + { "*mat_greenleaves", 0, 0, S_MAT_GREENLEAVES, S_MAT_MASK, 0, 0 }, + { "*mat_fabric", 0, 0, S_MAT_FABRIC, S_MAT_MASK, 0, 0 }, + { "*mat_canvas", 0, 0, S_MAT_CANVAS, S_MAT_MASK, 0, 0 }, + { "*mat_rock", 0, 0, S_MAT_ROCK, S_MAT_MASK, 0, 0 }, + { "*mat_rubber", 0, 0, S_MAT_RUBBER, S_MAT_MASK, 0, 0 }, + { "*mat_plastic", 0, 0, S_MAT_PLASTIC, S_MAT_MASK, 0, 0 }, + { "*mat_tiles", 0, 0, S_MAT_TILES, S_MAT_MASK, 0, 0 }, + { "*mat_carpet", 0, 0, S_MAT_CARPET, S_MAT_MASK, 0, 0 }, + { "*mat_plaster", 0, 0, S_MAT_PLASTER, S_MAT_MASK, 0, 0 }, + { "*mat_shatterglass", 0, 0, S_MAT_SHATTERGLASS, S_MAT_MASK, 0, 0 }, + { "*mat_armor", 0, 0, S_MAT_ARMOR, S_MAT_MASK, 0, 0 }, + { "*mat_computer", 0, 0, S_MAT_COMPUTER, S_MAT_MASK, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif diff --git a/tools/quake3/q3map2/game_quake3.h b/tools/quake3/q3map2/game_quake3.h new file mode 100644 index 00000000..27910473 --- /dev/null +++ b/tools/quake3/q3map2/game_quake3.h @@ -0,0 +1,184 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_QUAKE3_H +#define GAME_QUAKE3_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* game flags */ +#define Q_CONT_SOLID 1 /* an eye is never valid in a solid */ +#define Q_CONT_LAVA 8 +#define Q_CONT_SLIME 16 +#define Q_CONT_WATER 32 +#define Q_CONT_FOG 64 + +#define Q_CONT_AREAPORTAL 0x8000 + +#define Q_CONT_PLAYERCLIP 0x10000 +#define Q_CONT_MONSTERCLIP 0x20000 +#define Q_CONT_TELEPORTER 0x40000 +#define Q_CONT_JUMPPAD 0x80000 +#define Q_CONT_CLUSTERPORTAL 0x100000 +#define Q_CONT_DONOTENTER 0x200000 +#define Q_CONT_BOTCLIP 0x400000 + +#define Q_CONT_ORIGIN 0x1000000 /* removed before bsping an entity */ + +#define Q_CONT_BODY 0x2000000 /* should never be on a brush, only in game */ +#define Q_CONT_CORPSE 0x4000000 +#define Q_CONT_DETAIL 0x8000000 /* brushes not used for the bsp */ +#define Q_CONT_STRUCTURAL 0x10000000 /* brushes used for the bsp */ +#define Q_CONT_TRANSLUCENT 0x20000000 /* don't consume surface fragments inside */ +#define Q_CONT_TRIGGER 0x40000000 +#define Q_CONT_NODROP 0x80000000 /* don't leave bodies or items (death fog, lava) */ + +#define Q_SURF_NODAMAGE 0x1 /* never give falling damage */ +#define Q_SURF_SLICK 0x2 /* effects game physics */ +#define Q_SURF_SKY 0x4 /* lighting from environment map */ +#define Q_SURF_LADDER 0x8 +#define Q_SURF_NOIMPACT 0x10 /* don't make missile explosions */ +#define Q_SURF_NOMARKS 0x20 /* don't leave missile marks */ +#define Q_SURF_FLESH 0x40 /* make flesh sounds and effects */ +#define Q_SURF_NODRAW 0x80 /* don't generate a drawsurface at all */ +#define Q_SURF_HINT 0x100 /* make a primary bsp splitter */ +#define Q_SURF_SKIP 0x200 /* completely ignore, allowing non-closed brushes */ +#define Q_SURF_NOLIGHTMAP 0x400 /* surface doesn't need a lightmap */ +#define Q_SURF_POINTLIGHT 0x800 /* generate lighting info at vertexes */ +#define Q_SURF_METALSTEPS 0x1000 /* clanking footsteps */ +#define Q_SURF_NOSTEPS 0x2000 /* no footstep sounds */ +#define Q_SURF_NONSOLID 0x4000 /* don't collide against curves with this set */ +#define Q_SURF_LIGHTFILTER 0x8000 /* act as a light filter during q3map -light */ +#define Q_SURF_ALPHASHADOW 0x10000 /* do per-pixel light shadow casting in q3map */ +#define Q_SURF_NODLIGHT 0x20000 /* don't dlight even if solid (solid lava, skies) */ +#define Q_SURF_DUST 0x40000 /* leave a dust trail when walking on this surface */ + +/* ydnar flags */ +#define Q_SURF_VERTEXLIT (Q_SURF_POINTLIGHT | Q_SURF_NOLIGHTMAP) + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "quake3", /* -game x */ + "baseq3", /* default base game data dir */ + ".q3a", /* unix home sub-dir */ + "quake", /* magic path word */ + "scripts", /* shader directory */ + qfalse, /* wolf lighting model? */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 }, + { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_sof2.h b/tools/quake3/q3map2/game_sof2.h new file mode 100644 index 00000000..cd3c7a38 --- /dev/null +++ b/tools/quake3/q3map2/game_sof2.h @@ -0,0 +1,249 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_SOF2_H +#define GAME_SOF2_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* thanks to the gracious fellows at raven */ +#define S_CONT_SOLID 0x00000001 /* Default setting. An eye is never valid in a solid */ +#define S_CONT_LAVA 0x00000002 +#define S_CONT_WATER 0x00000004 +#define S_CONT_FOG 0x00000008 +#define S_CONT_PLAYERCLIP 0x00000010 +#define S_CONT_MONSTERCLIP 0x00000020 +#define S_CONT_BOTCLIP 0x00000040 +#define S_CONT_SHOTCLIP 0x00000080 +#define S_CONT_BODY 0x00000100 /* should never be on a brush, only in game */ +#define S_CONT_CORPSE 0x00000200 /* should never be on a brush, only in game */ +#define S_CONT_TRIGGER 0x00000400 +#define S_CONT_NODROP 0x00000800 /* don't leave bodies or items (death fog, lava) */ +#define S_CONT_TERRAIN 0x00001000 /* volume contains terrain data */ +#define S_CONT_LADDER 0x00002000 +#define S_CONT_ABSEIL 0x00004000 /* used like ladder to define where an NPC can abseil */ +#define S_CONT_OPAQUE 0x00008000 /* defaults to on, when off, solid can be seen through */ +#define S_CONT_OUTSIDE 0x00010000 /* volume is considered to be in the outside (i.e. not indoors) */ +#define S_CONT_SLIME 0x00020000 /* don't be fooled. it may SAY "slime" but it really means "projectileclip" */ +#define S_CONT_LIGHTSABER 0x00040000 +#define S_CONT_TELEPORTER 0x00080000 +#define S_CONT_ITEM 0x00100000 +#define S_CONT_DETAIL 0x08000000 /* brushes not used for the bsp */ +#define S_CONT_TRANSLUCENT 0x80000000 /* don't consume surface fragments inside */ + +#define S_SURF_SKY 0x00002000 /* lighting from environment map */ +#define S_SURF_SLICK 0x00004000 /* affects game physics */ +#define S_SURF_METALSTEPS 0x00008000 /* chc needs this since we use same tools */ +#define S_SURF_FORCEFIELD 0x00010000 /* chc */ +#define S_SURF_NODAMAGE 0x00040000 /* never give falling damage */ +#define S_SURF_NOIMPACT 0x00080000 /* don't make missile explosions */ +#define S_SURF_NOMARKS 0x00100000 /* don't leave missile marks */ +#define S_SURF_NODRAW 0x00200000 /* don't generate a drawsurface at all */ +#define S_SURF_NOSTEPS 0x00400000 /* no footstep sounds */ +#define S_SURF_NODLIGHT 0x00800000 /* don't dlight even if solid (solid lava, skies) */ +#define S_SURF_NOMISCENTS 0x01000000 /* no client models allowed on this surface */ + +#define S_SURF_PATCH 0x80000000 /* mark this face as a patch(editor only) */ + +/* materials */ +#define S_MAT_BITS 5 +#define S_MAT_MASK 0x1f /* mask to get the material type */ + +#define S_MAT_NONE 0 /* for when the artist hasn't set anything up =) */ +#define S_MAT_SOLIDWOOD 1 /* freshly cut timber */ +#define S_MAT_HOLLOWWOOD 2 /* termite infested creaky wood */ +#define S_MAT_SOLIDMETAL 3 /* solid girders */ +#define S_MAT_HOLLOWMETAL 4 /* hollow metal machines */ +#define S_MAT_SHORTGRASS 5 /* manicured lawn */ +#define S_MAT_LONGGRASS 6 /* long jungle grass */ +#define S_MAT_DIRT 7 /* hard mud */ +#define S_MAT_SAND 8 /* sandy beach */ +#define S_MAT_GRAVEL 9 /* lots of small stones */ +#define S_MAT_GLASS 10 +#define S_MAT_CONCRETE 11 /* hardened concrete pavement */ +#define S_MAT_MARBLE 12 /* marble floors */ +#define S_MAT_WATER 13 /* light covering of water on a surface */ +#define S_MAT_SNOW 14 /* freshly laid snow */ +#define S_MAT_ICE 15 /* packed snow/solid ice */ +#define S_MAT_FLESH 16 /* hung meat, corpses in the world */ +#define S_MAT_MUD 17 /* wet soil */ +#define S_MAT_BPGLASS 18 /* bulletproof glass */ +#define S_MAT_DRYLEAVES 19 /* dried up leaves on the floor */ +#define S_MAT_GREENLEAVES 20 /* fresh leaves still on a tree */ +#define S_MAT_FABRIC 21 /* Cotton sheets */ +#define S_MAT_CANVAS 22 /* tent material */ +#define S_MAT_ROCK 23 +#define S_MAT_RUBBER 24 /* hard tire like rubber */ +#define S_MAT_PLASTIC 25 +#define S_MAT_TILES 26 /* tiled floor */ +#define S_MAT_CARPET 27 /* lush carpet */ +#define S_MAT_PLASTER 28 /* drywall style plaster */ +#define S_MAT_SHATTERGLASS 29 /* glass with the Crisis Zone style shattering */ +#define S_MAT_ARMOR 30 /* body armor */ +#define S_MAT_COMPUTER 31 /* computers/electronic equipment */ +#define S_MAT_LAST 32 /* number of materials */ + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "sof2", /* -game x */ + "base", /* default base game data dir */ + ".sof2", /* unix home sub-dir */ + "soldier", /* magic path word */ + "shaders", /* shader directory */ + qfalse, /* wolf lighting model? */ + qtrue, /* flares */ + "gfx/misc/lens_flare", /* default flare shader */ + "RBSP", /* bsp file prefix */ + 1, /* bsp file version */ + LoadRBSPFile, /* bsp load function */ + WriteRBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", S_CONT_SOLID | S_CONT_OPAQUE, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", 0, S_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", S_CONT_TRANSLUCENT, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", S_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", S_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", 0, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, 0, 0, C_HINT, 0 }, + { "nodraw", 0, 0, S_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, 0, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, 0, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, 0, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, 0, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, S_CONT_SOLID, 0, 0, 0, C_SOLID }, + { "nonopaque", 0, S_CONT_OPAQUE, 0, 0, C_TRANSLUCENT, 0 }, /* setting trans ok? */ + + { "trigger", S_CONT_TRIGGER, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", S_CONT_WATER, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", S_CONT_SLIME, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", S_CONT_LAVA, S_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "shotclip", S_CONT_SHOTCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, /* setting trans/detail ok? */ + { "playerclip", S_CONT_PLAYERCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", S_CONT_MONSTERCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", S_CONT_NODROP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "terrain", S_CONT_TERRAIN, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "ladder", S_CONT_LADDER, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "abseil", S_CONT_ABSEIL, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "outside", S_CONT_OUTSIDE, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "botclip", S_CONT_BOTCLIP, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + + { "fog", S_CONT_FOG, S_CONT_SOLID | S_CONT_OPAQUE, 0, 0, C_FOG | C_DETAIL | C_TRANSLUCENT, C_SOLID }, /* nonopaque? */ + { "sky", 0, 0, S_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, S_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, S_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, S_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "nodamage", 0, 0, S_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, S_SURF_METALSTEPS, 0, 0, 0 }, + { "nosteps", 0, 0, S_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, S_SURF_NODLIGHT, 0, 0, 0 }, + { "nomiscents", 0, 0, S_SURF_NOMISCENTS, 0, 0, 0 }, + { "forcefield", 0, 0, S_SURF_FORCEFIELD, 0, 0, 0 }, + + + /* materials */ + { "*mat_none", 0, 0, S_MAT_NONE, S_MAT_MASK, 0, 0 }, + { "*mat_solidwood", 0, 0, S_MAT_SOLIDWOOD, S_MAT_MASK, 0, 0 }, + { "*mat_hollowwood", 0, 0, S_MAT_HOLLOWWOOD, S_MAT_MASK, 0, 0 }, + { "*mat_solidmetal", 0, 0, S_MAT_SOLIDMETAL, S_MAT_MASK, 0, 0 }, + { "*mat_hollowmetal", 0, 0, S_MAT_HOLLOWMETAL, S_MAT_MASK, 0, 0 }, + { "*mat_shortgrass", 0, 0, S_MAT_SHORTGRASS, S_MAT_MASK, 0, 0 }, + { "*mat_longgrass", 0, 0, S_MAT_LONGGRASS, S_MAT_MASK, 0, 0 }, + { "*mat_dirt", 0, 0, S_MAT_DIRT, S_MAT_MASK, 0, 0 }, + { "*mat_sand", 0, 0, S_MAT_SAND, S_MAT_MASK, 0, 0 }, + { "*mat_gravel", 0, 0, S_MAT_GRAVEL, S_MAT_MASK, 0, 0 }, + { "*mat_glass", 0, 0, S_MAT_GLASS, S_MAT_MASK, 0, 0 }, + { "*mat_concrete", 0, 0, S_MAT_CONCRETE, S_MAT_MASK, 0, 0 }, + { "*mat_marble", 0, 0, S_MAT_MARBLE, S_MAT_MASK, 0, 0 }, + { "*mat_water", 0, 0, S_MAT_WATER, S_MAT_MASK, 0, 0 }, + { "*mat_snow", 0, 0, S_MAT_SNOW, S_MAT_MASK, 0, 0 }, + { "*mat_ice", 0, 0, S_MAT_ICE, S_MAT_MASK, 0, 0 }, + { "*mat_flesh", 0, 0, S_MAT_FLESH, S_MAT_MASK, 0, 0 }, + { "*mat_mud", 0, 0, S_MAT_MUD, S_MAT_MASK, 0, 0 }, + { "*mat_bpglass", 0, 0, S_MAT_BPGLASS, S_MAT_MASK, 0, 0 }, + { "*mat_dryleaves", 0, 0, S_MAT_DRYLEAVES, S_MAT_MASK, 0, 0 }, + { "*mat_greenleaves", 0, 0, S_MAT_GREENLEAVES, S_MAT_MASK, 0, 0 }, + { "*mat_fabric", 0, 0, S_MAT_FABRIC, S_MAT_MASK, 0, 0 }, + { "*mat_canvas", 0, 0, S_MAT_CANVAS, S_MAT_MASK, 0, 0 }, + { "*mat_rock", 0, 0, S_MAT_ROCK, S_MAT_MASK, 0, 0 }, + { "*mat_rubber", 0, 0, S_MAT_RUBBER, S_MAT_MASK, 0, 0 }, + { "*mat_plastic", 0, 0, S_MAT_PLASTIC, S_MAT_MASK, 0, 0 }, + { "*mat_tiles", 0, 0, S_MAT_TILES, S_MAT_MASK, 0, 0 }, + { "*mat_carpet", 0, 0, S_MAT_CARPET, S_MAT_MASK, 0, 0 }, + { "*mat_plaster", 0, 0, S_MAT_PLASTER, S_MAT_MASK, 0, 0 }, + { "*mat_shatterglass", 0, 0, S_MAT_SHATTERGLASS, S_MAT_MASK, 0, 0 }, + { "*mat_armor", 0, 0, S_MAT_ARMOR, S_MAT_MASK, 0, 0 }, + { "*mat_computer", 0, 0, S_MAT_COMPUTER, S_MAT_MASK, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif diff --git a/tools/quake3/q3map2/game_t.h b/tools/quake3/q3map2/game_t.h new file mode 100644 index 00000000..319b1f78 --- /dev/null +++ b/tools/quake3/q3map2/game_t.h @@ -0,0 +1,34 @@ + +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* ydnar: for -game support */ +typedef struct game_s +{ + char *arg; /* -game matches this */ + char *gamePath; /* main game data dir */ + char *homeBasePath; /* home sub-dir on unix */ + char *magic; /* magic word for figuring out base path */ + qboolean wolfLight; /* when true, lights work like wolf q3map */ + int bspVersion; /* BSP version to use */ +} +game_t; + diff --git a/tools/quake3/q3map2/game_tenebrae.h b/tools/quake3/q3map2/game_tenebrae.h new file mode 100644 index 00000000..bfa2f031 --- /dev/null +++ b/tools/quake3/q3map2/game_tenebrae.h @@ -0,0 +1,184 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_TENEBRAE_H +#define GAME_TENEBRAE_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* game flags */ +#define T_CONT_SOLID 1 /* an eye is never valid in a solid */ +#define T_CONT_LAVA 8 +#define T_CONT_SLIME 16 +#define T_CONT_WATER 32 +#define T_CONT_FOG 64 + +#define T_CONT_AREAPORTAL 0x8000 + +#define T_CONT_PLAYERCLIP 0x10000 +#define T_CONT_MONSTERCLIP 0x20000 +#define T_CONT_TELEPORTER 0x40000 +#define T_CONT_JUMPPAD 0x80000 +#define T_CONT_CLUSTERPORTAL 0x100000 +#define T_CONT_DONOTENTER 0x200000 +#define T_CONT_BOTCLIP 0x400000 + +#define T_CONT_ORIGIN 0x1000000 /* removed before bsping an entity */ + +#define T_CONT_BODY 0x2000000 /* should never be on a brush, only in game */ +#define T_CONT_CORPSE 0x4000000 +#define T_CONT_DETAIL 0x8000000 /* brushes not used for the bsp */ +#define T_CONT_STRUCTURAL 0x10000000 /* brushes used for the bsp */ +#define T_CONT_TRANSLUCENT 0x20000000 /* don't consume surface fragments inside */ +#define T_CONT_TRIGGER 0x40000000 +#define T_CONT_NODROP 0x80000000 /* don't leave bodies or items (death fog, lava) */ + +#define T_SURF_NODAMAGE 0x1 /* never give falling damage */ +#define T_SURF_SLICK 0x2 /* effects game physics */ +#define T_SURF_SKY 0x4 /* lighting from environment map */ +#define T_SURF_LADDER 0x8 +#define T_SURF_NOIMPACT 0x10 /* don't make missile explosions */ +#define T_SURF_NOMARKS 0x20 /* don't leave missile marks */ +#define T_SURF_FLESH 0x40 /* make flesh sounds and effects */ +#define T_SURF_NODRAW 0x80 /* don't generate a drawsurface at all */ +#define T_SURF_HINT 0x100 /* make a primary bsp splitter */ +#define T_SURF_SKIP 0x200 /* completely ignore, allowing non-closed brushes */ +#define T_SURF_NOLIGHTMAP 0x400 /* surface doesn't need a lightmap */ +#define T_SURF_POINTLIGHT 0x800 /* generate lighting info at vertexes */ +#define T_SURF_METALSTEPS 0x1000 /* clanking footsteps */ +#define T_SURF_NOSTEPS 0x2000 /* no footstep sounds */ +#define T_SURF_NONSOLID 0x4000 /* don't collide against curves with this set */ +#define T_SURF_LIGHTFILTER 0x8000 /* act as a light filter during q3map -light */ +#define T_SURF_ALPHASHADOW 0x10000 /* do per-pixel light shadow casting in q3map */ +#define T_SURF_NODLIGHT 0x20000 /* don't dlight even if solid (solid lava, skies) */ +#define T_SURF_DUST 0x40000 /* leave a dust trail when walking on this surface */ + +/* ydnar flags */ +#define T_SURF_VERTEXLIT (T_SURF_POINTLIGHT | T_SURF_NOLIGHTMAP) + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "tenebrae", /* -game x */ + "base", /* default base game data dir */ + ".tenebrae", /* unix home sub-dir */ + "tenebrae", /* magic path word */ + "scripts", /* shader directory */ + qfalse, /* wolf lighting model? */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", T_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", T_CONT_ORIGIN, T_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", T_CONT_AREAPORTAL, T_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", T_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", T_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", T_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, T_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, T_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, T_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, T_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, T_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, T_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, T_CONT_SOLID, T_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", T_CONT_TRIGGER, T_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", T_CONT_WATER, T_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", T_CONT_SLIME, T_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", T_CONT_LAVA, T_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", T_CONT_PLAYERCLIP, T_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", T_CONT_MONSTERCLIP, T_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", T_CONT_NODROP, T_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", T_CONT_CLUSTERPORTAL, T_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", T_CONT_DONOTENTER, T_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", T_CONT_BOTCLIP, T_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", T_CONT_FOG, T_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, T_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, T_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, T_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, T_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, T_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, T_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, T_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, T_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, T_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, T_SURF_NODLIGHT, 0, 0, 0 }, + { "dust", 0, 0, T_SURF_DUST, 0, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_wolf.h b/tools/quake3/q3map2/game_wolf.h new file mode 100644 index 00000000..b1184a3e --- /dev/null +++ b/tools/quake3/q3map2/game_wolf.h @@ -0,0 +1,230 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_WOLF_H +#define GAME_WOLF_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* game flags */ +#define W_CONT_SOLID 1 /* an eye is never valid in a solid */ +#define W_CONT_LAVA 8 +#define W_CONT_SLIME 16 +#define W_CONT_WATER 32 +#define W_CONT_FOG 64 + +#define W_CONT_MISSILECLIP 0x80 /* wolf ranged missile blocking */ +#define W_CONT_ITEM 0x100 /* wolf item contents */ +#define W_CONT_AI_NOSIGHT 0x1000 /* wolf ai sight blocking */ +#define W_CONT_CLIPSHOT 0x2000 /* wolf shot clip */ +#define W_CONT_AREAPORTAL 0x8000 + +#define W_CONT_PLAYERCLIP 0x10000 +#define W_CONT_MONSTERCLIP 0x20000 +#define W_CONT_TELEPORTER 0x40000 +#define W_CONT_JUMPPAD 0x80000 +#define W_CONT_CLUSTERPORTAL 0x100000 +#define W_CONT_DONOTENTER 0x200000 +#define W_CONT_DONOTENTER_LARGE 0x400000 /* wolf dne */ + +#define W_CONT_ORIGIN 0x1000000 /* removed before bsping an entity */ + +#define W_CONT_BODY 0x2000000 /* should never be on a brush, only in game */ +#define W_CONT_CORPSE 0x4000000 +#define W_CONT_DETAIL 0x8000000 /* brushes not used for the bsp */ +#define W_CONT_STRUCTURAL 0x10000000 /* brushes used for the bsp */ +#define W_CONT_TRANSLUCENT 0x20000000 /* don't consume surface fragments inside */ +#define W_CONT_TRIGGER 0x40000000 +#define W_CONT_NODROP 0x80000000 /* don't leave bodies or items (death fog, lava) */ + +#define W_SURF_NODAMAGE 0x1 /* never give falling damage */ +#define W_SURF_SLICK 0x2 /* effects game physics */ +#define W_SURF_SKY 0x4 /* lighting from environment map */ +#define W_SURF_LADDER 0x8 +#define W_SURF_NOIMPACT 0x10 /* don't make missile explosions */ +#define W_SURF_NOMARKS 0x20 /* don't leave missile marks */ +#define W_SURF_CERAMIC 0x40 /* wolf ceramic material */ +#define W_SURF_NODRAW 0x80 /* don't generate a drawsurface at all */ +#define W_SURF_HINT 0x100 /* make a primary bsp splitter */ +#define W_SURF_SKIP 0x200 /* completely ignore, allowing non-closed brushes */ +#define W_SURF_NOLIGHTMAP 0x400 /* surface doesn't need a lightmap */ +#define W_SURF_POINTLIGHT 0x800 /* generate lighting info at vertexes */ +#define W_SURF_METAL 0x1000 /* wolf metal material */ +#define W_SURF_NOSTEPS 0x2000 /* no footstep sounds */ +#define W_SURF_NONSOLID 0x4000 /* don't collide against curves with this set */ +#define W_SURF_LIGHTFILTER 0x8000 /* act as a light filter during q3map -light */ +#define W_SURF_ALPHASHADOW 0x10000 /* do per-pixel light shadow casting in q3map */ +#define W_SURF_NODLIGHT 0x20000 /* don't dlight even if solid (solid lava, skies) */ +#define W_SURF_WOOD 0x40000 /* wolf wood material */ +#define W_SURF_GRASS 0x80000 /* wolf grass material */ +#define W_SURF_GRAVEL 0x100000 /* wolf gravel material */ +#define W_SURF_GLASS 0x200000 /* wolf glass material */ +#define W_SURF_SNOW 0x400000 /* wolf snow material */ +#define W_SURF_ROOF 0x800000 /* wolf roof material */ +#define W_SURF_RUBBLE 0x1000000 /* wolf rubble material */ +#define W_SURF_CARPET 0x2000000 /* wolf carpet material */ + +#define W_SURF_MONSTERSLICK 0x4000000 /* wolf npc slick surface */ +#define W_SURF_MONSLICK_W 0x8000000 /* wolf slide bodies west */ +#define W_SURF_MONSLICK_N 0x10000000 /* wolf slide bodies north */ +#define W_SURF_MONSLICK_E 0x20000000 /* wolf slide bodies east */ +#define W_SURF_MONSLICK_S 0x40000000 /* wolf slide bodies south */ + +/* ydnar flags */ +#define W_SURF_VERTEXLIT (W_SURF_POINTLIGHT | W_SURF_NOLIGHTMAP) + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "wolf", /* -game x */ + "main", /* default base game data dir */ + ".wolf", /* unix home sub-dir */ + "wolf", /* magic path word */ + "scripts", /* shader directory */ + qtrue, /* wolf lighting model? */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + "IBSP", /* bsp file prefix */ + 47, /* bsp file version */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", W_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", W_CONT_ORIGIN, W_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", W_CONT_AREAPORTAL, W_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", W_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", W_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", W_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, W_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, W_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, W_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, W_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, W_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, W_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, W_CONT_SOLID, W_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", W_CONT_TRIGGER, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", W_CONT_WATER, W_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slag", W_CONT_SLIME, W_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", W_CONT_LAVA, W_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", W_CONT_PLAYERCLIP, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", W_CONT_MONSTERCLIP, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "clipmissile", W_CONT_MISSILECLIP, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "clipshot", W_CONT_CLIPSHOT, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", W_CONT_NODROP, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", W_CONT_CLUSTERPORTAL, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", W_CONT_DONOTENTER, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "nonotenterlarge",W_CONT_DONOTENTER_LARGE, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", W_CONT_FOG, W_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, W_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, W_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, W_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, W_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, W_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, W_SURF_NODAMAGE, 0, 0, 0 }, + { "nosteps", 0, 0, W_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, W_SURF_NODLIGHT, 0, 0, 0 }, + + + /* materials */ + { "metal", 0, 0, W_SURF_METAL, 0, 0, 0 }, + { "metalsteps", 0, 0, W_SURF_METAL, 0, 0, 0 }, + { "glass", 0, 0, W_SURF_GLASS, 0, 0, 0 }, + { "ceramic", 0, 0, W_SURF_CERAMIC, 0, 0, 0 }, + { "woodsteps", 0, 0, W_SURF_WOOD, 0, 0, 0 }, + { "grasssteps", 0, 0, W_SURF_GRASS, 0, 0, 0 }, + { "gravelsteps", 0, 0, W_SURF_GRAVEL, 0, 0, 0 }, + { "rubble", 0, 0, W_SURF_RUBBLE, 0, 0, 0 }, + { "carpetsteps", 0, 0, W_SURF_CARPET, 0, 0, 0 }, + { "snowsteps", 0, 0, W_SURF_SNOW, 0, 0, 0 }, + { "roofsteps", 0, 0, W_SURF_ROOF, 0, 0, 0 }, + + + /* ai */ + { "ai_nosight", W_CONT_AI_NOSIGHT, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + /* ydnar: experimental until bits are confirmed! */ + { "ai_nopass", W_CONT_DONOTENTER, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "ai_nopasslarge", W_CONT_DONOTENTER_LARGE, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + + /* sliding bodies */ + { "monsterslick", 0, 0, W_SURF_MONSTERSLICK, 0, C_TRANSLUCENT, 0 }, + { "monsterslicknorth", 0, 0, W_SURF_MONSLICK_N, 0, C_TRANSLUCENT, 0 }, + { "monsterslickeast", 0, 0, W_SURF_MONSLICK_E, 0, C_TRANSLUCENT, 0 }, + { "monsterslicksouth", 0, 0, W_SURF_MONSLICK_S, 0, C_TRANSLUCENT, 0 }, + { "monsterslickwest", 0, 0, W_SURF_MONSLICK_W, 0, C_TRANSLUCENT, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_wolfet.h b/tools/quake3/q3map2/game_wolfet.h new file mode 100644 index 00000000..080e7fc9 --- /dev/null +++ b/tools/quake3/q3map2/game_wolfet.h @@ -0,0 +1,169 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +Support for Wolfenstein: Enemy Territory by ydnar@splashdamage.com + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_WOLFET_H +#define GAME_WOLFET_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags + +------------------------------------------------------------------------------- */ + +/* this file must be included *after* game_wolf.h because it shares defines! */ + +#define W_SURF_SPLASH 0x00000040 /* enemy territory water splash surface */ +#define W_SURF_LANDMINE 0x80000000 /* enemy territory 'landminable' surface */ + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "et", /* -game x */ + "etmain", /* default base game data dir */ + ".etwolf", /* unix home sub-dir */ + "et", /* magic path word */ + "scripts", /* shader directory */ + qtrue, /* wolf lighting model? */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + "IBSP", /* bsp file prefix */ + 47, /* bsp file version */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", W_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", W_CONT_ORIGIN, W_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", W_CONT_AREAPORTAL, W_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", W_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", W_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", W_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, W_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, W_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, W_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, W_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, W_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, W_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, W_CONT_SOLID, W_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", W_CONT_TRIGGER, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", W_CONT_WATER, W_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slag", W_CONT_SLIME, W_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", W_CONT_LAVA, W_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", W_CONT_PLAYERCLIP, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", W_CONT_MONSTERCLIP, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "clipmissile", W_CONT_MISSILECLIP, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "clipshot", W_CONT_CLIPSHOT, W_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", W_CONT_NODROP, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", W_CONT_CLUSTERPORTAL, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", W_CONT_DONOTENTER, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "nonotenterlarge",W_CONT_DONOTENTER_LARGE, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", W_CONT_FOG, W_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, W_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, W_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, W_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, W_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, W_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, W_SURF_NODAMAGE, 0, 0, 0 }, + { "nosteps", 0, 0, W_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, W_SURF_NODLIGHT, 0, 0, 0 }, + + /* wolf et landmine-able surface */ + { "landmine", 0, 0, W_SURF_LANDMINE, 0, 0, 0 }, + + /* materials */ + { "metal", 0, 0, W_SURF_METAL, 0, 0, 0 }, + { "metalsteps", 0, 0, W_SURF_METAL, 0, 0, 0 }, + { "glass", 0, 0, W_SURF_GLASS, 0, 0, 0 }, + { "splash", 0, 0, W_SURF_SPLASH, 0, 0, 0 }, + { "woodsteps", 0, 0, W_SURF_WOOD, 0, 0, 0 }, + { "grasssteps", 0, 0, W_SURF_GRASS, 0, 0, 0 }, + { "gravelsteps", 0, 0, W_SURF_GRAVEL, 0, 0, 0 }, + { "rubble", 0, 0, W_SURF_RUBBLE, 0, 0, 0 }, + { "carpetsteps", 0, 0, W_SURF_CARPET, 0, 0, 0 }, + { "snowsteps", 0, 0, W_SURF_SNOW, 0, 0, 0 }, + { "roofsteps", 0, 0, W_SURF_ROOF, 0, 0, 0 }, + + + /* ai */ + { "ai_nosight", W_CONT_AI_NOSIGHT, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + /* ydnar: experimental until bits are confirmed! */ + { "ai_nopass", W_CONT_DONOTENTER, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "ai_nopasslarge", W_CONT_DONOTENTER_LARGE, W_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + + /* sliding bodies */ + { "monsterslick", 0, 0, W_SURF_MONSTERSLICK, 0, C_TRANSLUCENT, 0 }, + { "monsterslicknorth", 0, 0, W_SURF_MONSLICK_N, 0, C_TRANSLUCENT, 0 }, + { "monsterslickeast", 0, 0, W_SURF_MONSLICK_E, 0, C_TRANSLUCENT, 0 }, + { "monsterslicksouth", 0, 0, W_SURF_MONSLICK_S, 0, C_TRANSLUCENT, 0 }, + { "monsterslickwest", 0, 0, W_SURF_MONSLICK_W, 0, C_TRANSLUCENT, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/image.c b/tools/quake3/q3map2/image.c new file mode 100644 index 00000000..26e0e24f --- /dev/null +++ b/tools/quake3/q3map2/image.c @@ -0,0 +1,467 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define IMAGE_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* ------------------------------------------------------------------------------- + +this file contains image pool management with reference counting. note: it isn't +reentrant, so only call it from init/shutdown code or wrap calls in a mutex + +------------------------------------------------------------------------------- */ + +/* +LoadDDSBuffer() +loads a dxtc (1, 3, 5) dds buffer into a valid rgba image +*/ + +static void LoadDDSBuffer( byte *buffer, int size, byte **pixels, int *width, int *height ) +{ + int w, h; + ddsPF_t pf; + + + /* dummy check */ + if( buffer == NULL || size <= 0 || pixels == NULL || width == NULL || height == NULL ) + return; + + /* null out */ + *pixels = 0; + *width = 0; + *height = 0; + + /* get dds info */ + if( DDSGetInfo( (ddsBuffer_t*) buffer, &w, &h, &pf ) ) + { + Sys_Printf( "WARNING: Invalid DDS texture\n" ); + return; + } + + /* only certain types of dds textures are supported */ + if( pf != DDS_PF_ARGB8888 && pf != DDS_PF_DXT1 && pf != DDS_PF_DXT3 && pf != DDS_PF_DXT5 ) + { + Sys_Printf( "WARNING: Only DDS texture formats ARGB8888, DXT1, DXT3, and DXT5 are supported (%d)\n", pf ); + return; + } + + /* create image pixel buffer */ + *width = w; + *height = h; + *pixels = safe_malloc( w * h * 4 ); + + /* decompress the dds texture */ + DDSDecompress( (ddsBuffer_t*) buffer, *pixels ); +} + + + +/* +PNGReadData() +callback function for libpng to read from a memory buffer +note: this function is a total hack, as it reads/writes the png struct directly! +*/ + +typedef struct pngBuffer_s +{ + byte *buffer; + int size, offset; +} +pngBuffer_t; + +void PNGReadData( png_struct *png, png_byte *buffer, png_size_t size ) +{ + pngBuffer_t *pb = (pngBuffer_t*) png_get_io_ptr( png ); + + + if( (pb->offset + size) > pb->size ) + size = (pb->size - pb->offset); + memcpy( buffer, &pb->buffer[ pb->offset ], size ); + pb->offset += size; + //% Sys_Printf( "Copying %d bytes from 0x%08X to 0x%08X (offset: %d of %d)\n", size, &pb->buffer[ pb->offset ], buffer, pb->offset, pb->size ); +} + + + +/* +LoadPNGBuffer() +loads a png file buffer into a valid rgba image +*/ + +static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, int *height ) +{ + png_struct *png; + png_info *info, *end; + pngBuffer_t pb; + int i, bitDepth, colorType, channels; + png_uint_32 w, h; + byte **rowPointers; + + + /* dummy check */ + if( buffer == NULL || size <= 0 || pixels == NULL || width == NULL || height == NULL ) + return; + + /* null out */ + *pixels = 0; + *width = 0; + *height = 0; + + /* determine if this is a png file */ + if( png_sig_cmp( buffer, 0, 8 ) != 0 ) + { + Sys_Printf( "WARNING: Invalid PNG file\n" ); + return; + } + + /* create png structs */ + png = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); + if( png == NULL ) + { + Sys_Printf( "WARNING: Unable to create PNG read struct\n" ); + return; + } + + info = png_create_info_struct( png ); + if( info == NULL ) + { + Sys_Printf( "WARNING: Unable to create PNG info struct\n" ); + png_destroy_read_struct( &png, NULL, NULL ); + return; + } + + end = png_create_info_struct( png ); + if( end == NULL ) + { + Sys_Printf( "WARNING: Unable to create PNG end info struct\n" ); + png_destroy_read_struct( &png, &info, NULL ); + return; + } + + /* set read callback */ + pb.buffer = buffer; + pb.size = size; + pb.offset = 0; + png_set_read_fn( png, &pb, PNGReadData ); + png->io_ptr = &pb; /* hack! */ + + /* set error longjmp */ + if( setjmp( png->jmpbuf ) ) + { + Sys_Printf( "WARNING: An error occurred reading PNG image\n" ); + png_destroy_read_struct( &png, &info, &end ); + return; + } + + /* fixme: add proper i/o stuff here */ + + /* read png info */ + png_read_info( png, info ); + + /* read image header chunk */ + png_get_IHDR( png, info, + &w, &h, &bitDepth, &colorType, NULL, NULL, NULL ); + + /* read number of channels */ + channels = png_get_channels( png, info ); + + /* the following will probably bork on certain types of png images, but hey... */ + + /* force indexed/gray/trans chunk to rgb */ + if( (colorType == PNG_COLOR_TYPE_PALETTE && bitDepth <= 8) || + (colorType == PNG_COLOR_TYPE_GRAY && bitDepth <= 8) || + png_get_valid( png, info, PNG_INFO_tRNS ) ) + png_set_expand( png ); + + /* strip 16bpc -> 8bpc */ + if( bitDepth == 16 ) + png_set_strip_16( png ); + + /* pad rgb to rgba */ + if( bitDepth == 8 && colorType == PNG_COLOR_TYPE_RGB) + png_set_filler( png, 255, PNG_FILLER_AFTER ); + + /* create image pixel buffer */ + *width = w; + *height = h; + *pixels = safe_malloc( w * h * 4 ); + + /* create row pointers */ + rowPointers = safe_malloc( h * sizeof( byte* ) ); + for( i = 0; i < h; i++ ) + rowPointers[ i ] = *pixels + (i * w * 4); + + /* read the png */ + png_read_image( png, rowPointers ); + + /* clean up */ + free( rowPointers ); + png_destroy_read_struct( &png, &info, &end ); + +} + + + +/* +ImageInit() +implicitly called by every function to set up image list +*/ + +static void ImageInit( void ) +{ + int i; + + + if( numImages <= 0 ) + { + /* clear images (fixme: this could theoretically leak) */ + memset( images, 0, sizeof( images ) ); + + /* generate *bogus image */ + images[ 0 ].name = safe_malloc( strlen( DEFAULT_IMAGE ) + 1 ); + strcpy( images[ 0 ].name, DEFAULT_IMAGE ); + images[ 0 ].filename = safe_malloc( strlen( DEFAULT_IMAGE ) + 1 ); + strcpy( images[ 0 ].filename, DEFAULT_IMAGE ); + images[ 0 ].width = 64; + images[ 0 ].height = 64; + images[ 0 ].refCount = 1; + images[ 0 ].pixels = safe_malloc( 64 * 64 * 4 ); + for( i = 0; i < (64 * 64 * 4); i++ ) + images[ 0 ].pixels[ i ] = 255; + } +} + + + +/* +ImageFree() +frees an rgba image +*/ + +void ImageFree( image_t *image ) +{ + /* dummy check */ + if( image == NULL ) + return; + + /* decrement refcount */ + image->refCount--; + + /* free? */ + if( image->refCount <= 0 ) + { + if( image->name != NULL ) + free( image->name ); + image->name = NULL; + if( image->filename != NULL ) + free( image->filename ); + image->filename = NULL; + free( image->pixels ); + image->width = 0; + image->height = 0; + numImages--; + } +} + + + +/* +ImageFind() +finds an existing rgba image and returns a pointer to the image_t struct or NULL if not found +*/ + +image_t *ImageFind( const char *filename ) +{ + int i; + char name[ 1024 ]; + + + /* init */ + ImageInit(); + + /* dummy check */ + if( filename == NULL || filename[ 0 ] == '\0' ) + return NULL; + + /* strip file extension off name */ + strcpy( name, filename ); + StripExtension( name ); + + /* search list */ + for( i = 0; i < MAX_IMAGES; i++ ) + { + if( images[ i ].name != NULL && !strcmp( name, images[ i ].name ) ) + return &images[ i ]; + } + + /* no matching image found */ + return NULL; +} + + + +/* +ImageLoad() +loads an rgba image and returns a pointer to the image_t struct or NULL if not found +*/ + +image_t *ImageLoad( const char *filename ) +{ + int i; + image_t *image; + char name[ 1024 ]; + int size; + byte *buffer = NULL; + + + /* init */ + ImageInit(); + + /* dummy check */ + if( filename == NULL || filename[ 0 ] == '\0' ) + return NULL; + + /* strip file extension off name */ + strcpy( name, filename ); + StripExtension( name ); + + /* try to find existing image */ + image = ImageFind( name ); + if( image != NULL ) + { + image->refCount++; + return image; + } + + /* none found, so find first non-null image */ + image = NULL; + for( i = 0; i < MAX_IMAGES; i++ ) + { + if( images[ i ].name == NULL ) + { + image = &images[ i ]; + break; + } + } + + /* too many images? */ + if( image == NULL ) + Error( "MAX_IMAGES (%d) exceeded, there are too many image files referenced by the map.", MAX_IMAGES ); + + /* set it up */ + image->name = safe_malloc( strlen( name ) + 1 ); + strcpy( image->name, name ); + + /* attempt to load tga */ + StripExtension( name ); + strcat( name, ".tga" ); + size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); + if( size > 0 ) + LoadTGABuffer( buffer, &image->pixels, &image->width, &image->height ); + else + { + /* attempt to load png */ + StripExtension( name ); + strcat( name, ".png" ); + size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); + if( size > 0 ) + LoadPNGBuffer( buffer, size, &image->pixels, &image->width, &image->height ); + else + { + /* attempt to load jpg */ + StripExtension( name ); + strcat( name, ".jpg" ); + size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); + if( size > 0 ) + { + if( LoadJPGBuff( buffer, size, &image->pixels, &image->width, &image->height ) == -1 && image->pixels != NULL ) + Sys_Printf( "WARNING: LoadJPGBuff: %s\n", (unsigned char*) image->pixels ); + } + else + { + /* attempt to load dds */ + StripExtension( name ); + strcat( name, ".dds" ); + size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); + if( size > 0 ) + { + LoadDDSBuffer( buffer, size, &image->pixels, &image->width, &image->height ); + + /* debug code */ + #if 1 + { + ddsPF_t pf; + DDSGetInfo( (ddsBuffer_t*) buffer, NULL, NULL, &pf ); + Sys_Printf( "pf = %d\n", pf ); + if( image->width > 0 ) + { + StripExtension( name ); + strcat( name, "_converted.tga" ); + WriteTGA( "C:\\games\\quake3\\baseq3\\textures\\rad\\dds_converted.tga", image->pixels, image->width, image->height ); + } + } + #endif + } + } + } + } + + /* free file buffer */ + free( buffer ); + + /* make sure everything's kosher */ + if( size <= 0 || image->width <= 0 || image->height <= 0 || image->pixels == NULL ) + { + //% Sys_Printf( "size = %d width = %d height = %d pixels = 0x%08x (%s)\n", + //% size, image->width, image->height, image->pixels, name ); + free( image->name ); + image->name = NULL; + return NULL; + } + + /* set filename */ + image->filename = safe_malloc( strlen( name ) + 1 ); + strcpy( image->filename, name ); + + /* set count */ + image->refCount = 1; + numImages++; + + /* return the image */ + return image; +} + + diff --git a/tools/quake3/q3map2/leakfile.c b/tools/quake3/q3map2/leakfile.c new file mode 100644 index 00000000..e8108c6f --- /dev/null +++ b/tools/quake3/q3map2/leakfile.c @@ -0,0 +1,126 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define LEAKFILE_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +============================================================================== + +LEAK FILE GENERATION + +Save out name.line for qe3 to read +============================================================================== +*/ + + +/* +============= +LeakFile + +Finds the shortest possible chain of portals +that leads from the outside leaf to a specifically +occupied leaf + +TTimo: builds a polyline xml node +============= +*/ +xmlNodePtr LeakFile (tree_t *tree) +{ + vec3_t mid; + FILE *linefile; + char filename[1024]; + node_t *node; + int count; + xmlNodePtr xml_node, point; + + if (!tree->outside_node.occupied) + return NULL; + + Sys_FPrintf (SYS_VRB,"--- LeakFile ---\n"); + + // + // write the points to the file + // + sprintf (filename, "%s.lin", source); + linefile = fopen (filename, "w"); + if (!linefile) + Error ("Couldn't open %s\n", filename); + + xml_node = xmlNewNode (NULL, "polyline"); + + count = 0; + node = &tree->outside_node; + while (node->occupied > 1) + { + int next; + portal_t *p, *nextportal; + node_t *nextnode; + int s; + + // find the best portal exit + next = node->occupied; + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (p->nodes[s]->occupied + && p->nodes[s]->occupied < next) + { + nextportal = p; + nextnode = p->nodes[s]; + next = nextnode->occupied; + } + } + node = nextnode; + WindingCenter (nextportal->winding, mid); + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + point = xml_NodeForVec(mid); + xmlAddChild(xml_node, point); + count++; + } + // add the occupant center + GetVectorForKey (node->occupant, "origin", mid); + + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + point = xml_NodeForVec(mid); + xmlAddChild(xml_node, point); + Sys_FPrintf( SYS_VRB, "%9d point linefile\n", count+1); + + fclose (linefile); + + return xml_node; +} + diff --git a/tools/quake3/q3map2/light.c b/tools/quake3/q3map2/light.c new file mode 100644 index 00000000..9ee61bea --- /dev/null +++ b/tools/quake3/q3map2/light.c @@ -0,0 +1,2182 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define LIGHT_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +CreateSunLight() - ydnar +this creates a sun light +*/ + +static void CreateSunLight( sun_t *sun ) +{ + int i; + float photons, d, angle, elevation, da, de; + vec3_t direction; + light_t *light; + + + /* dummy check */ + if( sun == NULL ) + return; + + /* fixup */ + if( sun->numSamples < 1 ) + sun->numSamples = 1; + + /* set photons */ + photons = sun->photons / sun->numSamples; + + /* create the right number of suns */ + for( i = 0; i < sun->numSamples; i++ ) + { + /* calculate sun direction */ + if( i == 0 ) + VectorCopy( sun->direction, direction ); + else + { + /* + sun->direction[ 0 ] = cos( angle ) * cos( elevation ); + sun->direction[ 1 ] = sin( angle ) * cos( elevation ); + sun->direction[ 2 ] = sin( elevation ); + + xz_dist = sqrt( x*x + z*z ) + latitude = atan2( xz_dist, y ) * RADIANS + longitude = atan2( x, z ) * RADIANS + */ + + d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] ); + angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] ); + elevation = atan2( sun->direction[ 2 ], d ); + + /* jitter the angles (loop to keep random sample within sun->deviance steridians) */ + do + { + da = (Random() * 2.0f - 1.0f) * sun->deviance; + de = (Random() * 2.0f - 1.0f) * sun->deviance; + } + while( (da * da + de * de) > (sun->deviance * sun->deviance) ); + angle += da; + elevation += de; + + /* debug code */ + //% Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) ); + + /* create new vector */ + direction[ 0 ] = cos( angle ) * cos( elevation ); + direction[ 1 ] = sin( angle ) * cos( elevation ); + direction[ 2 ] = sin( elevation ); + } + + /* create a light */ + numSunLights++; + light = safe_malloc( sizeof( *light ) ); + memset( light, 0, sizeof( *light ) ); + light->next = lights; + lights = light; + + /* initialize the light */ + light->flags = LIGHT_SUN_DEFAULT; + light->type = EMIT_SUN; + light->fade = 1.0f; + light->falloffTolerance = falloffTolerance; + light->filterRadius = sun->filterRadius / sun->numSamples; + + /* set the light's position out to infinity */ + VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin ); /* MAX_WORLD_COORD * 2.0f */ + + /* set the facing to be the inverse of the sun direction */ + VectorScale( direction, -1.0, light->normal ); + light->dist = DotProduct( light->origin, light->normal ); + + /* set color and photons */ + VectorCopy( sun->color, light->color ); + light->photons = photons * skyScale; + } + + /* another sun? */ + if( sun->next != NULL ) + CreateSunLight( sun->next ); +} + + + +/* +CreateSkyLights() - ydnar +simulates sky light with multiple suns +*/ + +static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius ) +{ + int c, i, j, k, numSuns; + float step, start; + vec3_t in; + sun_t sun; + + + /* dummy check */ + if( value <= 0.0f || iterations < 2 ) + return; + + /* calculate some stuff */ + step = 2.0f / (iterations - 1); + start = -1.0f; + + /* basic sun setup */ + VectorCopy( color, sun.color ); + sun.deviance = 0.0f; + sun.filterRadius = filterRadius; + sun.numSamples = 1; + sun.next = NULL; + + /* iterate */ + numSuns = 0; + for( c = 0; c < 2; c++ ) + { + for( k = 0, in[ 2 ] = start; k < iterations; k++, in[ 2 ] += step ) + { + /* don't create sky light below the horizon */ + if( in[ 2 ] <= 0.0f ) + continue; + + for( j = 0, in[ 1 ] = start; j < iterations; j++, in[ 1 ] += step ) + { + for( i = 0, in[ 0 ] = start; i < iterations; i++, in[ 0 ] += step ) + { + if( VectorNormalize( in, sun.direction ) ) + { + if( c > 0 && numSuns > 0 ) + { + sun.photons = value / numSuns; + CreateSunLight( &sun ); + } + else + numSuns++; + } + } + } + } + } +} + + + +/* +CreateEntityLights() +creates lights from light entities +*/ + +void CreateEntityLights( void ) +{ + int i, j; + light_t *light, *light2; + entity_t *e, *e2; + const char *name; + const char *target; + vec3_t dest; + const char *_color; + float intensity, scale, deviance, filterRadius; + int spawnflags, flags, numSamples; + qboolean junior; + + + /* go throught entity list and find lights */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity */ + e = &entities[ i ]; + name = ValueForKey( e, "classname" ); + + /* ydnar: check for lightJunior */ + if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 ) + junior = qtrue; + else if( Q_strncasecmp( name, "light", 5 ) == 0 ) + junior = qfalse; + else + continue; + + /* lights with target names (and therefore styles) are only parsed from BSP */ + target = ValueForKey( e, "targetname" ); + if( target[ 0 ] != '\0' && i >= numBSPEntities ) + continue; + + /* create a light */ + numPointLights++; + light = safe_malloc( sizeof( *light ) ); + memset( light, 0, sizeof( *light ) ); + light->next = lights; + lights = light; + + /* handle spawnflags */ + spawnflags = IntForKey( e, "spawnflags" ); + + /* ydnar: quake 3+ light behavior */ + if( game->wolfLight == qfalse ) + { + /* set default flags */ + flags = LIGHT_Q3A_DEFAULT; + + /* linear attenuation? */ + if( spawnflags & 1 ) + { + flags |= LIGHT_ATTEN_LINEAR; + flags &= ~LIGHT_ATTEN_ANGLE; + } + + /* no angle attenuate? */ + if( spawnflags & 2 ) + flags &= ~LIGHT_ATTEN_ANGLE; + } + + /* ydnar: wolf light behavior */ + else + { + /* set default flags */ + flags = LIGHT_WOLF_DEFAULT; + + /* inverse distance squared attenuation? */ + if( spawnflags & 1 ) + { + flags &= ~LIGHT_ATTEN_LINEAR; + flags |= LIGHT_ATTEN_ANGLE; + } + + /* angle attenuate? */ + if( spawnflags & 2 ) + flags |= LIGHT_ATTEN_ANGLE; + } + + /* other flags (borrowed from wolf) */ + + /* wolf dark light? */ + if( (spawnflags & 4) || (spawnflags & 8) ) + flags |= LIGHT_DARK; + + /* nogrid? */ + if( spawnflags & 16 ) + flags &= ~LIGHT_GRID; + + /* junior? */ + if( junior ) + { + flags |= LIGHT_GRID; + flags &= ~LIGHT_SURFACES; + } + + /* store the flags */ + light->flags = flags; + + /* ydnar: set fade key (from wolf) */ + light->fade = 1.0f; + if( light->flags & LIGHT_ATTEN_LINEAR ) + { + light->fade = FloatForKey( e, "fade" ); + if( light->fade == 0.0f ) + light->fade = 1.0f; + } + + /* ydnar: set angle scaling (from vlight) */ + light->angleScale = FloatForKey( e, "_anglescale" ); + if( light->angleScale != 0.0f ) + light->flags |= LIGHT_ATTEN_ANGLE; + + /* set origin */ + GetVectorForKey( e, "origin", light->origin); + light->style = IntForKey( e, "_style" ); + if( light->style == 0 ) + light->style = IntForKey( e, "style" ); + if( light->style < LS_NORMAL || light->style >= LS_NONE ) + Error( "Invalid lightstyle (%d) on entity %d", light->style, i ); + + /* set light intensity */ + intensity = FloatForKey( e, "_light" ); + if( intensity == 0.0f ) + intensity = FloatForKey( e, "light" ); + if( intensity == 0.0f) + intensity = 300.0f; + + /* ydnar: set light scale (sof2) */ + scale = FloatForKey( e, "scale" ); + if( scale == 0.0f ) + scale = 1.0f; + intensity *= scale; + + /* ydnar: get deviance and samples */ + deviance = FloatForKey( e, "_deviance" ); + if( deviance == 0.0f ) + deviance = FloatForKey( e, "_deviation" ); + if( deviance == 0.0f ) + deviance = FloatForKey( e, "_jitter" ); + numSamples = IntForKey( e, "_samples" ); + if( deviance < 0.0f || numSamples < 1 ) + { + deviance = 0.0f; + numSamples = 1; + } + intensity /= numSamples; + + /* ydnar: get filter radius */ + filterRadius = FloatForKey( e, "_filterradius" ); + if( filterRadius == 0.0f ) + filterRadius = FloatForKey( e, "_filteradius" ); + if( filterRadius == 0.0f ) + filterRadius = FloatForKey( e, "_filter" ); + if( filterRadius < 0.0f ) + filterRadius = 0.0f; + light->filterRadius = filterRadius; + + /* set light color */ + _color = ValueForKey( e, "_color" ); + if( _color && _color[ 0 ] ) + { + sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] ); + ColorNormalize( light->color, light->color ); + } + else + light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f; + + intensity = intensity * pointScale; + light->photons = intensity; + + light->type = EMIT_POINT; + + /* set falloff threshold */ + light->falloffTolerance = falloffTolerance / numSamples; + + /* lights with a target will be spotlights */ + target = ValueForKey( e, "target" ); + if( target[ 0 ] ) + { + float radius; + float dist; + sun_t sun; + const char *_sun; + + + /* get target */ + e2 = FindTargetEntity( target ); + if( e2 == NULL ) + { + Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n", + (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] ); + } + else + { + /* not a point light */ + numPointLights--; + numSpotLights++; + + /* make a spotlight */ + GetVectorForKey( e2, "origin", dest ); + VectorSubtract( dest, light->origin, light->normal ); + dist = VectorNormalize( light->normal, light->normal ); + radius = FloatForKey( e, "radius" ); + if( !radius ) + radius = 64; + if( !dist ) + dist = 64; + light->radiusByDist = (radius + 16) / dist; + light->type = EMIT_SPOT; + + /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */ + light->flags &= ~LIGHT_ATTEN_LINEAR; + light->flags |= LIGHT_ATTEN_ANGLE; + light->fade = 1.0f; + + /* ydnar: is this a sun? */ + _sun = ValueForKey( e, "_sun" ); + if( _sun[ 0 ] == '1' ) + { + /* not a spot light */ + numSpotLights--; + + /* unlink this light */ + lights = light->next; + + /* make a sun */ + VectorScale( light->normal, -1.0f, sun.direction ); + VectorCopy( light->color, sun.color ); + sun.photons = (intensity / pointScale); + sun.deviance = deviance / 180.0f * Q_PI; + sun.numSamples = numSamples; + sun.next = NULL; + + /* make a sun light */ + CreateSunLight( &sun ); + + /* free original light */ + free( light ); + light = NULL; + + /* skip the rest of this love story */ + continue; + } + } + } + + /* jitter the light */ + for( j = 1; j < numSamples; j++ ) + { + /* create a light */ + light2 = safe_malloc( sizeof( *light ) ); + memcpy( light2, light, sizeof( *light ) ); + light2->next = lights; + lights = light2; + + /* add to counts */ + if( light->type == EMIT_SPOT ) + numSpotLights++; + else + numPointLights++; + + /* jitter it */ + light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance; + light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance; + light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance; + } + } +} + + + +/* +CreateSurfaceLights() - ydnar +this hijacks the radiosity code to generate surface lights for first pass +*/ + +#define APPROX_BOUNCE 1.0f + +void CreateSurfaceLights( void ) +{ + int i; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + shaderInfo_t *si; + light_t *light; + float subdivide; + vec3_t origin; + clipWork_t cw; + const char *nss; + + + /* get sun shader supressor */ + nss = ValueForKey( &entities[ 0 ], "_noshadersun" ); + + /* walk the list of surfaces */ + for( i = 0; i < numBSPDrawSurfaces; i++ ) + { + /* get surface and other bits */ + ds = &bspDrawSurfaces[ i ]; + info = &surfaceInfos[ i ]; + si = info->si; + + /* sunlight? */ + if( si->sun != NULL && nss[ 0 ] != '1' ) + { + Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader ); + CreateSunLight( si->sun ); + si->sun = NULL; /* FIXME: leak! */ + } + + /* sky light? */ + if( si->skyLightValue > 0.0f ) + { + Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader ); + CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius ); + si->skyLightValue = 0.0f; /* FIXME: hack! */ + } + + /* try to early out */ + if( si->value <= 0 ) + continue; + + /* autosprite shaders become point lights */ + if( si->autosprite ) + { + /* create an average xyz */ + VectorAdd( info->mins, info->maxs, origin ); + VectorScale( origin, 0.5f, origin ); + + /* create a light */ + light = safe_malloc( sizeof( *light ) ); + memset( light, 0, sizeof( *light ) ); + light->next = lights; + lights = light; + + /* set it up */ + light->flags = LIGHT_Q3A_DEFAULT; + light->type = EMIT_POINT; + light->photons = si->value * pointScale; + light->fade = 1.0f; + light->si = si; + VectorCopy( origin, light->origin ); + VectorCopy( si->color, light->color ); + light->falloffTolerance = falloffTolerance; + light->style = light->style; + + /* add to point light count and continue */ + numPointLights++; + continue; + } + + /* get subdivision amount */ + if( si->lightSubdivide > 0 ) + subdivide = si->lightSubdivide; + else + subdivide = defaultLightSubdivide; + + /* switch on type */ + switch( ds->surfaceType ) + { + case MST_PLANAR: + case MST_TRIANGLE_SOUP: + RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw ); + break; + + case MST_PATCH: + RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw ); + break; + + default: + break; + } + } +} + + + +/* +SetEntityOrigins() +find the offset values for inline models +*/ + +void SetEntityOrigins( void ) +{ + int i, j, k, f; + entity_t *e; + vec3_t origin; + const char *key; + int modelnum; + bspModel_t *dm; + bspDrawSurface_t *ds; + + + /* ydnar: copy drawverts into private storage for nefarious purposes */ + yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) ); + memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) ); + + /* set the entity origins */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity and model */ + e = &entities[ i ]; + key = ValueForKey( e, "model" ); + if( key[ 0 ] != '*' ) + continue; + modelnum = atoi( key + 1 ); + dm = &bspModels[ modelnum ]; + + /* get entity origin */ + key = ValueForKey( e, "origin" ); + if( key[ 0 ] == '\0' ) + continue; + GetVectorForKey( e, "origin", origin ); + + /* set origin for all surfaces for this model */ + for( j = 0; j < dm->numBSPSurfaces; j++ ) + { + /* get drawsurf */ + ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ]; + + /* set its verts */ + for( k = 0; k < ds->numVerts; k++ ) + { + f = ds->firstVert + k; + VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz ); + } + } + } +} + + + +/* +PointToPolygonFormFactor() +calculates the area over a point/normal hemisphere a winding covers +ydnar: fixme: there has to be a faster way to calculate this +without the expensive per-vert sqrts and transcendental functions +ydnar 2002-09-30: added -faster switch because only 19% deviance > 10% +between this and the approximation +*/ + +#define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f)) + +float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) +{ + vec3_t triVector, triNormal; + int i, j; + vec3_t dirs[ MAX_POINTS_ON_WINDING ]; + float total; + float dot, angle, facing; + + + /* this is expensive */ + for( i = 0; i < w->numpoints; i++ ) + { + VectorSubtract( w->p[ i ], point, dirs[ i ] ); + VectorNormalize( dirs[ i ], dirs[ i ] ); + } + + /* duplicate first vertex to avoid mod operation */ + VectorCopy( dirs[ 0 ], dirs[ i ] ); + + /* calculcate relative area */ + total = 0.0f; + for( i = 0; i < w->numpoints; i++ ) + { + /* get a triangle */ + j = i + 1; + dot = DotProduct( dirs[ i ], dirs[ j ] ); + + /* roundoff can cause slight creep, which gives an IND from acos */ + if( dot > 1.0f ) + dot = 1.0f; + else if( dot < -1.0f ) + dot = -1.0f; + + /* get the angle */ + angle = acos( dot ); + + CrossProduct( dirs[ i ], dirs[ j ], triVector ); + if( VectorNormalize( triVector, triNormal ) < 0.0001f ) + continue; + + facing = DotProduct( normal, triNormal ); + total += facing * angle; + + /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */ + if( total > 6.3f || total < -6.3f ) + return 0.0f; + } + + /* now in the range of 0 to 1 over the entire incoming hemisphere */ + //% total /= (2.0f * 3.141592657f); + total *= ONE_OVER_2PI; + return total; +} + + + +/* +LightContributionTosample() +determines the amount of light reaching a sample (luxel or vertex) from a given light +*/ + +int LightContributionToSample( trace_t *trace ) +{ + light_t *light; + float angle; + float add; + float dist; + + + /* get light */ + light = trace->light; + + /* clear color */ + VectorClear( trace->color ); + + /* ydnar: early out */ + if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f ) + return 0; + + /* do some culling checks */ + if( light->type != EMIT_SUN ) + { + /* MrE: if the light is behind the surface */ + if( trace->twoSided == qfalse ) + if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f ) + return 0; + + /* ydnar: test pvs */ + if( !ClusterVisible( trace->cluster, light->cluster ) ) + return 0; + } + + /* ptpff approximation */ + if( light->type == EMIT_AREA && faster ) + { + /* get direction and distance */ + VectorCopy( light->origin, trace->end ); + dist = SetupTrace( trace ); + if( dist >= light->envelope ) + return 0; + + /* clamp the distance to prevent super hot spots */ + if( dist < 16.0f ) + dist = 16.0f; + + /* angle attenuation */ + angle = DotProduct( trace->normal, trace->direction ); + + /* twosided lighting */ + if( trace->twoSided ) + angle = fabs( angle ); + + /* attenuate */ + angle *= -DotProduct( light->normal, trace->direction ); + if( angle <= 0.0f ) + return 0; + add = light->photons / (dist * dist) * angle; + } + + /* exact point to polygon form factor */ + else if( light->type == EMIT_AREA ) + { + float factor; + float d; + vec3_t pushedOrigin; + + + /* project sample point into light plane */ + d = DotProduct( trace->origin, light->normal ) - light->dist; + //% if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f ) + //% return 0; + if( d < 3.0f ) + { + /* sample point behind plane? */ + if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f ) + return 0; + + /* sample plane coincident? */ + if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f ) + return 0; + } + + /* nudge the point so that it is clearly forward of the light */ + /* so that surfaces meeting a light emiter don't get black edges */ + if( d > -8.0f && d < 8.0f ) + VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin ); + else + VectorCopy( trace->origin, pushedOrigin ); + + /* get direction and distance */ + VectorCopy( light->origin, trace->end ); + dist = SetupTrace( trace ); + if( dist >= light->envelope ) + return 0; + + /* calculate the contribution */ + factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w ); + if( factor == 0.0f ) + return 0; + else if( factor < 0.0f ) + { + /* twosided lighting */ + if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) ) + { + factor = -factor; + + /* push light origin to other side of the plane */ + VectorMA( light->origin, -2.0f, light->normal, trace->end ); + dist = SetupTrace( trace ); + if( dist >= light->envelope ) + return 0; + } + else + return 0; + } + + /* ydnar: moved to here */ + add = factor * light->add; + } + + /* point/spot lights */ + else if( light->type == EMIT_POINT || light->type == EMIT_SPOT ) + { + /* get direction and distance */ + VectorCopy( light->origin, trace->end ); + dist = SetupTrace( trace ); + if( dist >= light->envelope ) + return 0; + + /* clamp the distance to prevent super hot spots */ + if( dist < 16.0f ) + dist = 16.0f; + + /* angle attenuation */ + angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f; + if( light->angleScale != 0.0f ) + { + angle /= light->angleScale; + if( angle > 1.0f ) + angle = 1.0f; + } + + /* twosided lighting */ + if( trace->twoSided ) + angle = fabs( angle ); + + /* attenuate */ + if( light->flags & LIGHT_ATTEN_LINEAR ) + { + add = angle * light->photons * linearScale - (dist * light->fade); + if( add < 0.0f ) + add = 0.0f; + } + else + add = light->photons / (dist * dist) * angle; + + /* handle spotlights */ + if( light->type == EMIT_SPOT ) + { + float distByNormal, radiusAtDist, sampleRadius; + vec3_t pointAtDist, distToSample; + + + /* do cone calculation */ + distByNormal = -DotProduct( trace->displacement, light->normal ); + if( distByNormal < 0.0f ) + return 0; + VectorMA( light->origin, distByNormal, light->normal, pointAtDist ); + radiusAtDist = light->radiusByDist * distByNormal; + VectorSubtract( trace->origin, pointAtDist, distToSample ); + sampleRadius = VectorLength( distToSample ); + + /* outside the cone */ + if( sampleRadius >= radiusAtDist ) + return 0; + + /* attenuate */ + if( sampleRadius > (radiusAtDist - 32.0f) ) + add *= ((radiusAtDist - sampleRadius) / 32.0f); + } + } + + /* ydnar: sunlight */ + else if( light->type == EMIT_SUN ) + { + /* get origin and direction */ + VectorAdd( trace->origin, light->origin, trace->end ); + dist = SetupTrace( trace ); + + /* angle attenuation */ + angle = (light->flags & LIGHT_ATTEN_ANGLE) + ? DotProduct( trace->normal, trace->direction ) + : 1.0f; + + /* twosided lighting */ + if( trace->twoSided ) + angle = fabs( angle ); + + /* attenuate */ + add = light->photons * angle; + if( add <= 0.0f ) + return 0; + + /* setup trace */ + trace->testAll = qtrue; + VectorScale( light->color, add, trace->color ); + + /* trace to point */ + if( trace->testOcclusion && !trace->forceSunlight ) + { + /* trace */ + TraceLine( trace ); + if( !(trace->compileFlags & C_SKY) || trace->opaque ) + { + VectorClear( trace->color ); + return -1; + } + } + + /* return to sender */ + return 1; + } + + /* ydnar: changed to a variable number */ + if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) ) + return 0; + + /* setup trace */ + trace->testAll = qfalse; + VectorScale( light->color, add, trace->color ); + + /* raytrace */ + TraceLine( trace ); + if( trace->passSolid || trace->opaque ) + { + VectorClear( trace->color ); + return -1; + } + + /* return to sender */ + return 1; +} + + + +/* +LightingAtSample() +determines the amount of light reaching a sample (luxel or vertex) +*/ + +void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] ) +{ + int i, lightmapNum; + + + /* clear colors */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + VectorClear( colors[ lightmapNum ] ); + + /* ydnar: normalmap */ + if( normalmap ) + { + colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f; + colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f; + colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f; + return; + } + + /* ydnar: don't bounce ambient all the time */ + if( !bouncing ) + VectorCopy( ambientColor, colors[ 0 ] ); + + /* ydnar: trace to all the list of lights pre-stored in tw */ + for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ ) + { + /* set light */ + trace->light = trace->lights[ i ]; + + /* style check */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + if( styles[ lightmapNum ] == trace->light->style || + styles[ lightmapNum ] == LS_NONE ) + break; + } + + /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */ + if( lightmapNum >= MAX_LIGHTMAPS ) + continue; + + /* sample light */ + LightContributionToSample( trace ); + if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f ) + continue; + + /* handle negative light */ + if( trace->light->flags & LIGHT_NEGATIVE ) + VectorScale( trace->color, -1.0f, trace->color ); + + /* set style */ + styles[ lightmapNum ] = trace->light->style; + + /* add it */ + VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] ); + + /* cheap mode */ + if( cheap && + colors[ 0 ][ 0 ] >= 255.0f && + colors[ 0 ][ 1 ] >= 255.0f && + colors[ 0 ][ 2 ] >= 255.0f ) + break; + } +} + + + +/* +LightContributionToPoint() +for a given light, how much light/color reaches a given point in space (with no facing) +note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling +*/ + +int LightContributionToPoint( trace_t *trace ) +{ + light_t *light; + float add, dist; + + + /* get light */ + light = trace->light; + + /* clear color */ + VectorClear( trace->color ); + + /* ydnar: early out */ + if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f ) + return qfalse; + + /* is this a sun? */ + if( light->type != EMIT_SUN ) + { + /* sun only? */ + if( sunOnly ) + return qfalse; + + /* test pvs */ + if( !ClusterVisible( trace->cluster, light->cluster ) ) + return qfalse; + } + + /* ydnar: check origin against light's pvs envelope */ + if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] || + trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] || + trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] ) + { + gridBoundsCulled++; + return qfalse; + } + + /* set light origin */ + if( light->type == EMIT_SUN ) + VectorAdd( trace->origin, light->origin, trace->end ); + else + VectorCopy( light->origin, trace->end ); + + /* set direction */ + dist = SetupTrace( trace ); + + /* test envelope */ + if( dist > light->envelope ) + { + gridEnvelopeCulled++; + return qfalse; + } + + /* ptpff approximation */ + if( light->type == EMIT_AREA && faster ) + { + /* clamp the distance to prevent super hot spots */ + if( dist < 16.0f ) + dist = 16.0f; + + /* attenuate */ + add = light->photons / (dist * dist); + } + + /* exact point to polygon form factor */ + else if( light->type == EMIT_AREA ) + { + float factor, d; + vec3_t pushedOrigin; + + + /* see if the point is behind the light */ + d = DotProduct( trace->origin, light->normal ) - light->dist; + if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f ) + return qfalse; + + /* nudge the point so that it is clearly forward of the light */ + /* so that surfaces meeting a light emiter don't get black edges */ + if( d > -8.0f && d < 8.0f ) + VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin ); + else + VectorCopy( trace->origin, pushedOrigin ); + + /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */ + factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w ); + if( factor == 0.0f ) + return qfalse; + else if( factor < 0.0f ) + { + if( light->flags & LIGHT_TWOSIDED ) + factor = -factor; + else + return qfalse; + } + + /* ydnar: moved to here */ + add = factor * light->add; + } + + /* point/spot lights */ + else if( light->type == EMIT_POINT || light->type == EMIT_SPOT ) + { + /* clamp the distance to prevent super hot spots */ + if( dist < 16.0f ) + dist = 16.0f; + + /* attenuate */ + if( light->flags & LIGHT_ATTEN_LINEAR ) + { + add = light->photons * linearScale - (dist * light->fade); + if( add < 0.0f ) + add = 0.0f; + } + else + add = light->photons / (dist * dist); + + /* handle spotlights */ + if( light->type == EMIT_SPOT ) + { + float distByNormal, radiusAtDist, sampleRadius; + vec3_t pointAtDist, distToSample; + + + /* do cone calculation */ + distByNormal = -DotProduct( trace->displacement, light->normal ); + if( distByNormal < 0.0f ) + return qfalse; + VectorMA( light->origin, distByNormal, light->normal, pointAtDist ); + radiusAtDist = light->radiusByDist * distByNormal; + VectorSubtract( trace->origin, pointAtDist, distToSample ); + sampleRadius = VectorLength( distToSample ); + + /* outside the cone */ + if( sampleRadius >= radiusAtDist ) + return qfalse; + + /* attenuate */ + if( sampleRadius > (radiusAtDist - 32.0f) ) + add *= ((radiusAtDist - sampleRadius) / 32.0f); + } + } + + /* ydnar: sunlight */ + else if( light->type == EMIT_SUN ) + { + /* attenuate */ + add = light->photons; + if( add <= 0.0f ) + return qfalse; + + /* setup trace */ + trace->testAll = qtrue; + VectorScale( light->color, add, trace->color ); + + /* trace to point */ + if( trace->testOcclusion && !trace->forceSunlight ) + { + /* trace */ + TraceLine( trace ); + if( !(trace->compileFlags & C_SKY) || trace->opaque ) + { + VectorClear( trace->color ); + return -1; + } + } + + /* return to sender */ + return qtrue; + } + + /* unknown light type */ + else + return qfalse; + + /* ydnar: changed to a variable number */ + if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) ) + return qfalse; + + /* setup trace */ + trace->testAll = qfalse; + VectorScale( light->color, add, trace->color ); + + /* trace */ + TraceLine( trace ); + if( trace->passSolid ) + { + VectorClear( trace->color ); + return qfalse; + } + + /* we have a valid sample */ + return qtrue; +} + + + +/* +TraceGrid() +grid samples are for quickly determining the lighting +of dynamically placed entities in the world +*/ + +#define MAX_CONTRIBUTIONS 1024 + +typedef struct +{ + vec3_t dir; + vec3_t color; + int style; +} +contribution_t; + +void TraceGrid( int num ) +{ + int i, j, x, y, z, mod, step, numCon, numStyles; + float d; + vec3_t baseOrigin, cheapColor, color; + rawGridPoint_t *gp; + bspGridPoint_t *bgp; + contribution_t contributions[ MAX_CONTRIBUTIONS ]; + trace_t trace; + + + /* get grid points */ + gp = &rawGridPoints[ num ]; + bgp = &bspGridPoints[ num ]; + + /* get grid origin */ + mod = num; + z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]); + mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]); + y = mod / gridBounds[ 0 ]; + mod -= y * gridBounds[ 0 ]; + x = mod; + + trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ]; + trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ]; + trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ]; + + /* set inhibit sphere */ + if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] ) + trace.inhibitRadius = gridSize[ 0 ] * 0.5f; + else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] ) + trace.inhibitRadius = gridSize[ 1 ] * 0.5f; + else + trace.inhibitRadius = gridSize[ 2 ] * 0.5f; + + /* find point cluster */ + trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON ); + if( trace.cluster < 0 ) + { + /* try to nudge the origin around to find a valid point */ + VectorCopy( trace.origin, baseOrigin ); + for( step = 9; step <= 18; step += 9 ) + { + for( i = 0; i < 8; i++ ) + { + VectorCopy( baseOrigin, trace.origin ); + if( i & 1 ) + trace.origin[ 0 ] += step; + else + trace.origin[ 0 ] -= step; + + if( i & 2 ) + trace.origin[ 1 ] += step; + else + trace.origin[ 1 ] -= step; + + if( i & 4 ) + trace.origin[ 2 ] += step; + else + trace.origin[ 2 ] -= step; + + /* ydnar: changed to find cluster num */ + trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON ); + if( trace.cluster >= 0 ) + break; + } + + if( i != 8 ) + break; + } + + /* can't find a valid point at all */ + if( step > 18 ) + return; + } + + /* setup trace */ + trace.testOcclusion = !noTrace; + trace.forceSunlight = qfalse; + trace.recvShadows = WORLDSPAWN_RECV_SHADOWS; + trace.numSurfaces = 0; + trace.surfaces = NULL; + trace.numLights = 0; + trace.lights = NULL; + + /* clear */ + numCon = 0; + VectorClear( cheapColor ); + + /* trace to all the lights, find the major light direction, and divide the + total light between that along the direction and the remaining in the ambient */ + for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next ) + { + float addSize; + + + /* sample light */ + if( !LightContributionToPoint( &trace ) ) + continue; + + /* handle negative light */ + if( trace.light->flags & LIGHT_NEGATIVE ) + VectorScale( trace.color, -1.0f, trace.color ); + + /* add a contribution */ + VectorCopy( trace.color, contributions[ numCon ].color ); + VectorCopy( trace.direction, contributions[ numCon ].dir ); + contributions[ numCon ].style = trace.light->style; + numCon++; + + /* push average direction around */ + addSize = VectorLength( trace.color ); + VectorMA( gp->dir, addSize, trace.direction, gp->dir ); + + /* stop after a while */ + if( numCon >= (MAX_CONTRIBUTIONS - 1) ) + break; + + /* ydnar: cheap mode */ + VectorAdd( cheapColor, trace.color, cheapColor ); + if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f ) + break; + } + + /* normalize to get primary light direction */ + VectorNormalize( gp->dir, gp->dir ); + + /* now that we have identified the primary light direction, + go back and separate all the light into directed and ambient */ + numStyles = 1; + for( i = 0; i < numCon; i++ ) + { + /* get relative directed strength */ + d = DotProduct( contributions[ i ].dir, gp->dir ); + if( d < 0.0f ) + d = 0.0f; + + /* find appropriate style */ + for( j = 0; j < numStyles; j++ ) + { + if( gp->styles[ j ] == contributions[ i ].style ) + break; + } + + /* style not found? */ + if( j >= numStyles ) + { + /* add a new style */ + if( numStyles < MAX_LIGHTMAPS ) + { + gp->styles[ numStyles ] = contributions[ i ].style; + bgp->styles[ numStyles ] = contributions[ i ].style; + numStyles++; + //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style ); + } + + /* fallback */ + else + j = 0; + } + + /* add the directed color */ + VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] ); + + /* ambient light will be at 1/4 the value of directed light */ + /* (ydnar: nuke this in favor of more dramatic lighting?) */ + d = 0.25f * (1.0f - d); + VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] ); + } + + + /* store off sample */ + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */ + if( !bouncing ) + VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] ); + + /* set minimum light and copy off to bytes */ + VectorCopy( gp->ambient[ i ], color ); + for( j = 0; j < 3; j++ ) + if( color[ j ] < minGridLight[ j ] ) + color[ j ] = minGridLight[ j ]; + ColorToBytes( color, bgp->ambient[ i ], 1.0f ); + ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f ); + } + + /* debug code */ + #if 0 + //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] ); + Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n", + num, + gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ], + gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] ); + #endif + + /* store direction */ + NormalToLatLong( gp->dir, bgp->latLong ); +} + + + +/* +SetupGrid() +calculates the size of the lightgrid and allocates memory +*/ + +void SetupGrid( void ) +{ + int i, j; + vec3_t maxs, oldGridSize; + const char *value; + char temp[ 64 ]; + + + /* don't do this if not grid lighting */ + if( noGridLighting ) + return; + + /* ydnar: set grid size */ + value = ValueForKey( &entities[ 0 ], "gridsize" ); + if( value[ 0 ] != '\0' ) + sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] ); + + /* quantize it */ + VectorCopy( gridSize, oldGridSize ); + for( i = 0; i < 3; i++ ) + gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f; + + /* ydnar: increase gridSize until grid count is smaller than max allowed */ + numRawGridPoints = MAX_MAP_LIGHTGRID + 1; + j = 0; + while( numRawGridPoints > MAX_MAP_LIGHTGRID ) + { + /* get world bounds */ + for( i = 0; i < 3; i++ ) + { + gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] ); + maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] ); + gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1; + } + + /* set grid size */ + numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ]; + + /* increase grid size a bit */ + if( numRawGridPoints > MAX_MAP_LIGHTGRID ) + gridSize[ j++ % 3 ] += 16.0f; + } + + /* print it */ + Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] ); + + /* different? */ + if( !VectorCompare( gridSize, oldGridSize ) ) + { + sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] ); + SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp ); + Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" ); + } + + /* 2nd variable. fixme: is this silly? */ + numBSPGridPoints = numRawGridPoints; + + /* allocate lightgrid */ + rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) ); + memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) ); + + if( bspGridPoints != NULL ) + free( bspGridPoints ); + bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) ); + memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) ); + + /* clear lightgrid */ + for( i = 0; i < numRawGridPoints; i++ ) + { + VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] ); + rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL; + bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL; + for( j = 1; j < MAX_LIGHTMAPS; j++ ) + { + rawGridPoints[ i ].styles[ j ] = LS_NONE; + bspGridPoints[ i ].styles[ j ] = LS_NONE; + } + } + + /* note it */ + Sys_Printf( "%9d grid points\n", numRawGridPoints ); +} + + + +/* +LightWorld() +does what it says... +*/ + +void LightWorld( void ) +{ + vec3_t color; + float f; + int b, bt; + qboolean minVertex, minGrid; + const char *value; + + + /* ydnar: smooth normals */ + if( shade ) + { + Sys_Printf( "--- SmoothNormals ---\n" ); + SmoothNormals(); + } + + /* determine the number of grid points */ + Sys_Printf( "--- SetupGrid ---\n" ); + SetupGrid(); + + /* find the optional minimum lighting values */ + GetVectorForKey( &entities[ 0 ], "_color", color ); + if( VectorLength( color ) == 0.0f ) + VectorSet( color, 1.0, 1.0, 1.0 ); + + /* ambient */ + f = FloatForKey( &entities[ 0 ], "_ambient" ); + if( f == 0.0f ) + f = FloatForKey( &entities[ 0 ], "ambient" ); + VectorScale( color, f, ambientColor ); + + /* minvertexlight */ + minVertex = qfalse; + value = ValueForKey( &entities[ 0 ], "_minvertexlight" ); + if( value[ 0 ] != '\0' ) + { + minVertex = qtrue; + f = atof( value ); + VectorScale( color, f, minVertexLight ); + } + + /* mingridlight */ + minGrid = qfalse; + value = ValueForKey( &entities[ 0 ], "_mingridlight" ); + if( value[ 0 ] != '\0' ) + { + minGrid = qtrue; + f = atof( value ); + VectorScale( color, f, minGridLight ); + } + + /* minlight */ + value = ValueForKey( &entities[ 0 ], "_minlight" ); + if( value[ 0 ] != '\0' ) + { + f = atof( value ); + VectorScale( color, f, minLight ); + if( minVertex == qfalse ) + VectorScale( color, f, minVertexLight ); + if( minGrid == qfalse ) + VectorScale( color, f, minGridLight ); + } + + /* create world lights */ + Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" ); + CreateEntityLights(); + CreateSurfaceLights(); + Sys_Printf( "%9d point lights\n", numPointLights ); + Sys_Printf( "%9d spotlights\n", numSpotLights ); + Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights ); + Sys_Printf( "%9d sun/sky lights\n", numSunLights ); + + /* calculate lightgrid */ + if( !noGridLighting ) + { + /* ydnar: set up light envelopes */ + SetupEnvelopes( qtrue, fastgrid ); + + Sys_Printf( "--- TraceGrid ---\n" ); + RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid ); + Sys_Printf( "%d x %d x %d = %d grid\n", + gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints ); + + /* ydnar: emit statistics on light culling */ + Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled ); + Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled ); + } + + /* slight optimization to remove a sqrt */ + subdivideThreshold *= subdivideThreshold; + + /* map the world luxels */ + Sys_Printf( "--- MapRawLightmap ---\n" ); + RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap ); + Sys_Printf( "%9d luxels\n", numLuxels ); + Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped ); + Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded ); + + /* ydnar: set up light envelopes */ + SetupEnvelopes( qfalse, fast ); + + /* light up my world */ + lightsPlaneCulled = 0; + lightsEnvelopeCulled = 0; + lightsBoundsCulled = 0; + lightsClusterCulled = 0; + + Sys_Printf( "--- IlluminateRawLightmap ---\n" ); + RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap ); + Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated ); + + StitchSurfaceLightmaps(); + + Sys_Printf( "--- IlluminateVertexes ---\n" ); + RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes ); + Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated ); + + /* ydnar: emit statistics on light culling */ + Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled ); + Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled ); + Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled ); + Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled ); + + /* radiosity */ + b = 1; + bt = bounce; + while( bounce > 0 ) + { + /* store off the bsp between bounces */ + StoreSurfaceLightmaps(); + Sys_Printf( "Writing %s\n", source ); + WriteBSPFile( source ); + + /* note it */ + Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt ); + + /* flag bouncing */ + bouncing = qtrue; + VectorClear( ambientColor ); + + /* generate diffuse lights */ + RadFreeLights(); + RadCreateDiffuseLights(); + + /* setup light envelopes */ + SetupEnvelopes( qfalse, fastbounce ); + if( numLights == 0 ) + { + Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" ); + break; + } + + /* add to lightgrid */ + if( bouncegrid ) + { + gridEnvelopeCulled = 0; + gridBoundsCulled = 0; + + Sys_Printf( "--- BounceGrid ---\n" ); + RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid ); + Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled ); + Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled ); + } + + /* light up my world */ + lightsPlaneCulled = 0; + lightsEnvelopeCulled = 0; + lightsBoundsCulled = 0; + lightsClusterCulled = 0; + + Sys_Printf( "--- IlluminateRawLightmap ---\n" ); + RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap ); + Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated ); + Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated ); + + StitchSurfaceLightmaps(); + + Sys_Printf( "--- IlluminateVertexes ---\n" ); + RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes ); + Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated ); + + /* ydnar: emit statistics on light culling */ + Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled ); + Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled ); + Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled ); + Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled ); + + /* interate */ + bounce--; + b++; + } +} + + + +/* +LightMain() +main routine for light processing +*/ + +int LightMain( int argc, char **argv ) +{ + int i; + float f; + char mapSource[ 1024 ]; + const char *value; + + + /* note it */ + Sys_Printf( "--- Light ---\n" ); + + /* process commandline arguments */ + for( i = 1; i < (argc - 1); i++ ) + { + /* lightsource scaling */ + if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) ) + { + f = atof( argv[ i + 1 ] ); + pointScale *= f; + Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale ); + i++; + } + + else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) ) + { + f = atof( argv[ i + 1 ] ); + areaScale *= f; + Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale ); + i++; + } + + else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) ) + { + f = atof( argv[ i + 1 ] ); + skyScale *= f; + Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale ); + i++; + } + + else if( !strcmp( argv[ i ], "-bouncescale" ) ) + { + f = atof( argv[ i + 1 ] ); + bounceScale *= f; + Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale ); + i++; + } + + else if( !strcmp( argv[ i ], "-scale" ) ) + { + f = atof( argv[ i + 1 ] ); + pointScale *= f; + areaScale *= f; + skyScale *= f; + bounceScale *= f; + Sys_Printf( "All light scaled by %f\n", f ); + i++; + } + + /* ydnar switches */ + else if( !strcmp( argv[ i ], "-bounce" ) ) + { + bounce = atoi( argv[ i + 1 ] ); + if( bounce < 0 ) + bounce = 0; + else if( bounce > 0 ) + Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce ); + i++; + } + + else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) ) + { + superSample = atoi( argv[ i + 1 ] ); + if( superSample < 1 ) + superSample = 1; + else if( superSample > 1 ) + Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) ); + i++; + } + + else if( !strcmp( argv[ i ], "-samples" ) ) + { + lightSamples = atoi( argv[ i + 1 ] ); + if( lightSamples < 1 ) + lightSamples = 1; + else if( lightSamples > 1 ) + Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples ); + i++; + } + + else if( !strcmp( argv[ i ], "-filter" ) ) + { + filter = qtrue; + Sys_Printf( "Lightmap filtering enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-shadeangle" ) ) + { + shadeAngleDegrees = atof( argv[ i + 1 ] ); + if( shadeAngleDegrees < 0.0f ) + shadeAngleDegrees = 0.0f; + else if( shadeAngleDegrees > 0.0f ) + { + shade = qtrue; + Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees ); + } + i++; + } + + else if( !strcmp( argv[ i ], "-thresh" ) ) + { + subdivideThreshold = atof( argv[ i + 1 ] ); + if( subdivideThreshold < 0 ) + subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD; + else + Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold ); + i++; + } + + else if( !strcmp( argv[ i ], "-approx" ) ) + { + approximateTolerance = atoi( argv[ i + 1 ] ); + if( approximateTolerance < 0 ) + approximateTolerance = 0; + else if( approximateTolerance > 0 ) + Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance ); + i++; + } + + else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) ) + { + deluxemap = qtrue; + Sys_Printf( "Generating deluxemaps for average light direction\n" ); + } + + else if( !strcmp( argv[ i ], "-external" ) ) + { + externalLightmaps = qtrue; + Sys_Printf( "Storing all lightmaps externally\n" ); + } + + else if( !strcmp( argv[ i ], "-lightmapsize" ) ) + { + lmCustomSize = atoi( argv[ i + 1 ] ); + + /* must be a power of 2 and greater than 2 */ + if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 ) + { + Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" ); + lmCustomSize = LIGHTMAP_WIDTH; + } + i++; + Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize ); + + /* enable external lightmaps */ + if( lmCustomSize != LIGHTMAP_WIDTH ) + { + externalLightmaps = qtrue; + Sys_Printf( "Storing all lightmaps externally\n" ); + } + } + + /* ydnar: add this to suppress warnings */ + else if( !strcmp( argv[ i ], "-custinfoparms") ) + { + Sys_Printf( "Custom info parms enabled\n" ); + useCustomInfoParms = qtrue; + } + + else if( !strcmp( argv[ i ], "-wolf" ) ) + { + /* -game should already be set */ + game->wolfLight = qtrue; + Sys_Printf( "Enabling Wolf lighting model\n" ); + } + + else if( !strcmp( argv[ i ], "-sunonly" ) ) + { + sunOnly = qtrue; + Sys_Printf( "Only computing sunlight\n" ); + } + + else if( !strcmp( argv[ i ], "-bounceonly" ) ) + { + bounceOnly = qtrue; + Sys_Printf( "Storing bounced light (radiosity) only\n" ); + } + + else if( !strcmp( argv[ i ], "-nocollapse" ) ) + { + noCollapse = qtrue; + Sys_Printf( "Identical lightmap collapsing disabled\n" ); + } + + else if( !strcmp( argv[ i ], "-shade" ) ) + { + shade = qtrue; + Sys_Printf( "Phong shading enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-bouncegrid") ) + { + bouncegrid = qtrue; + if( bounce > 0 ) + Sys_Printf( "Grid lighting with radiosity enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-smooth" ) ) + { + smooth = qtrue; + lightSamples = EXTRA_SCALE; + Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" ); + } + + else if( !strcmp( argv[ i ], "-fast" ) ) + { + fast = qtrue; + fastgrid = qtrue; + fastbounce = qtrue; + Sys_Printf( "Fast mode enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-faster" ) ) + { + faster = qtrue; + fast = qtrue; + fastgrid = qtrue; + fastbounce = qtrue; + Sys_Printf( "Faster mode enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-fastgrid" ) ) + { + fastgrid = qtrue; + Sys_Printf( "Fast grid lighting enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-fastbounce" ) ) + { + fastbounce = qtrue; + Sys_Printf( "Fast bounce mode enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-cheap" ) ) + { + cheap = qtrue; + cheapgrid = qtrue; + Sys_Printf( "Cheap mode enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-cheapgrid" ) ) + { + cheapgrid = qtrue; + Sys_Printf( "Cheap grid mode enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-normalmap" ) ) + { + normalmap = qtrue; + Sys_Printf( "Storing normal map instead of lightmap\n" ); + } + + else if( !strcmp( argv[ i ], "-trisoup" ) ) + { + trisoup = qtrue; + Sys_Printf( "Converting brush faces to triangle soup\n" ); + } + + else if( !strcmp( argv[ i ], "-debug" ) ) + { + debug = qtrue; + Sys_Printf( "Lightmap debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) ) + { + debugSurfaces = qtrue; + Sys_Printf( "Lightmap surface debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-debugunused" ) ) + { + debugUnused = qtrue; + Sys_Printf( "Unused luxel debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-debugaxis" ) ) + { + debugAxis = qtrue; + Sys_Printf( "Lightmap axis debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-debugcluster" ) ) + { + debugCluster = qtrue; + Sys_Printf( "Luxel cluster debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-debugorigin" ) ) + { + debugOrigin = qtrue; + Sys_Printf( "Luxel origin debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-debugdeluxe" ) ) + { + deluxemap = qtrue; + debugDeluxemap = qtrue; + Sys_Printf( "Deluxemap debugging enabled\n" ); + } + + else if( !strcmp( argv[ i ], "-export" ) ) + { + exportLightmaps = qtrue; + Sys_Printf( "Exporting lightmaps\n" ); + } + + else if( !strcmp(argv[ i ], "-notrace" )) + { + noTrace = qtrue; + Sys_Printf( "Shadow occlusion disabled\n" ); + } + else if( !strcmp(argv[ i ], "-patchshadows" ) ) + { + patchShadows = qtrue; + Sys_Printf( "Patch shadow casting enabled\n" ); + } + else if( !strcmp( argv[ i ], "-extra" ) ) + { + extra = qtrue; + superSample = EXTRA_SCALE; /* ydnar */ + Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" ); + } + else if( !strcmp( argv[ i ], "-extrawide" ) ) + { + extra = qtrue; + extraWide = qtrue; + superSample = EXTRAWIDE_SCALE; /* ydnar */ + filter = qtrue; /* ydnar */ + Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n"); + } + else if( !strcmp( argv[ i ], "-samplesize" ) ) + { + sampleSize = atoi( argv[ i + 1 ] ); + if( sampleSize < 1 ) + sampleSize = 1; + i++; + Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize ); + } + else if( !strcmp( argv[ i ], "-novertex" ) ) + { + noVertexLighting = qtrue; + Sys_Printf( "Disabling vertex lighting\n" ); + } + else if( !strcmp( argv[ i ], "-nogrid" ) ) + { + noGridLighting = qtrue; + Sys_Printf( "Disabling grid lighting\n" ); + } + else if( !strcmp( argv[ i ], "-border" ) ) + { + lightmapBorder = qtrue; + Sys_Printf( "Adding debug border to lightmaps\n" ); + } + else if( !strcmp( argv[ i ], "-nosurf" ) ) + { + noSurfaces = qtrue; + Sys_Printf( "Not tracing against surfaces\n" ); + } + else if( !strcmp( argv[ i ], "-dump" ) ) + { + dump = qtrue; + Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" ); + } + else if( !strcmp( argv[ i ], "-lomem" ) ) + { + loMem = qtrue; + Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" ); + } + + else + Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); + } + + /* clean up map name */ + strcpy( source, ExpandArg( argv[ i ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + strcpy( mapSource, ExpandArg( argv[ i ] ) ); + StripExtension( mapSource ); + DefaultExtension( mapSource, ".map" ); + + /* ydnar: set default sample size */ + SetDefaultSampleSize( sampleSize ); + + /* ydnar: handle shaders */ + BeginMapShaderFile( source ); + LoadShaderInfo(); + + /* note loading */ + Sys_Printf( "Loading %s\n", source ); + + /* ydnar: load surface file */ + LoadSurfaceExtraFile( source ); + + /* load bsp file */ + LoadBSPFile( source ); + + /* parse bsp entities */ + ParseEntities(); + + /* load map file */ + value = ValueForKey( &entities[ 0 ], "_keepLights" ); + if( value[ 0 ] != '1' ) + LoadMapFile( mapSource, qtrue ); + + /* set the entity/model origins and init yDrawVerts */ + SetEntityOrigins(); + + /* ydnar: set up optimization */ + SetupBrushes(); + SetupSurfaceLightmaps(); + + /* initialize the surface facet tracing */ + SetupTraceNodes(); + + /* light the world */ + LightWorld(); + + /* ydnar: store off lightmaps */ + StoreSurfaceLightmaps(); + + /* write out the bsp */ + UnparseEntities(); + Sys_Printf( "Writing %s\n", source ); + WriteBSPFile( source ); + + /* ydnar: export lightmaps */ + if( exportLightmaps && !externalLightmaps ) + ExportLightmaps(); + + /* return to sender */ + return 0; +} + diff --git a/tools/quake3/q3map2/light_bounce.c b/tools/quake3/q3map2/light_bounce.c new file mode 100644 index 00000000..e4d23da3 --- /dev/null +++ b/tools/quake3/q3map2/light_bounce.c @@ -0,0 +1,954 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define LIGHT_BOUNCE_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* functions */ + +/* +RadFreeLights() +deletes any existing lights, freeing up memory for the next bounce +*/ + +void RadFreeLights( void ) +{ + light_t *light, *next; + + + /* delete lights */ + for( light = lights; light; light = next ) + { + next = light->next; + if( light->w != NULL ) + FreeWinding( light->w ); + free( light ); + } + numLights = 0; + lights = NULL; +} + + + +/* +RadClipWindingEpsilon() +clips a rad winding by a plane +based off the regular clip winding code +*/ + +static void RadClipWindingEpsilon( radWinding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, radWinding_t *front, radWinding_t *back, clipWork_t *cw ) +{ + vec_t *dists; + int *sides; + int counts[ 3 ]; + vec_t dot; /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */ + int i, j, k; + radVert_t *v1, *v2, mid; + int maxPoints; + + + /* crutch */ + dists = cw->dists; + sides = cw->sides; + + /* clear counts */ + counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0; + + /* determine sides for each point */ + for( i = 0; i < in->numVerts; i++ ) + { + dot = DotProduct( in->verts[ i ].xyz, normal ); + dot -= dist; + dists[ i ] = dot; + if( dot > epsilon ) + sides[ i ] = SIDE_FRONT; + else if( dot < -epsilon ) + sides[ i ] = SIDE_BACK; + else + sides[ i ] = SIDE_ON; + counts[ sides[ i ] ]++; + } + sides[ i ] = sides[ 0 ]; + dists[ i ] = dists[ 0 ]; + + /* clear front and back */ + front->numVerts = back->numVerts = 0; + + /* handle all on one side cases */ + if( counts[ 0 ] == 0 ) + { + memcpy( back, in, sizeof( radWinding_t ) ); + return; + } + if( counts[ 1 ] == 0 ) + { + memcpy( front, in, sizeof( radWinding_t ) ); + return; + } + + /* setup windings */ + maxPoints = in->numVerts + 4; + + /* do individual verts */ + for( i = 0; i < in->numVerts; i++ ) + { + /* do simple vertex copies first */ + v1 = &in->verts[ i ]; + + if( sides[ i ] == SIDE_ON ) + { + memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) ); + memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) ); + continue; + } + + if( sides[ i ] == SIDE_FRONT ) + memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) ); + + if( sides[ i ] == SIDE_BACK ) + memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) ); + + if( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] ) + continue; + + /* generate a split vertex */ + v2 = &in->verts[ (i + 1) % in->numVerts ]; + + dot = dists[ i ] / (dists[ i ] - dists[ i + 1 ]); + + /* average vertex values */ + for( j = 0; j < 4; j++ ) + { + /* color */ + if( j < 4 ) + { + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + mid.color[ k ][ j ] = v1->color[ k ][ j ] + dot * (v2->color[ k ][ j ] - v1->color[ k ][ j ]); + } + + /* xyz, normal */ + if( j < 3 ) + { + mid.xyz[ j ] = v1->xyz[ j ] + dot * (v2->xyz[ j ] - v1->xyz[ j ]); + mid.normal[ j ] = v1->normal[ j ] + dot * (v2->normal[ j ] - v1->normal[ j ]); + } + + /* st, lightmap */ + if( j < 2 ) + { + mid.st[ j ] = v1->st[ j ] + dot * (v2->st[ j ] - v1->st[ j ]); + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + mid.lightmap[ k ][ j ] = v1->lightmap[ k ][ j ] + dot * (v2->lightmap[ k ][ j ] - v1->lightmap[ k ][ j ]); + } + } + + /* normalize the averaged normal */ + VectorNormalize( mid.normal, mid.normal ); + + /* copy the midpoint to both windings */ + memcpy( &front->verts[ front->numVerts++ ], &mid, sizeof( radVert_t ) ); + memcpy( &back->verts[ back->numVerts++ ], &mid, sizeof( radVert_t ) ); + } + + /* error check */ + if( front->numVerts > maxPoints || front->numVerts > maxPoints ) + Error( "RadClipWindingEpsilon: points exceeded estimate" ); + if( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING ) + Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" ); +} + + + + + +/* +RadSampleImage() +samples a texture image for a given color +returns qfalse if pixels are bad +*/ + +qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ) +{ + float sto[ 2 ]; + int x, y; + + + /* clear color first */ + color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255; + + /* dummy check */ + if( pixels == NULL || width < 1 || height < 1 ) + return qfalse; + + /* bias st */ + sto[ 0 ] = st[ 0 ]; + while( sto[ 0 ] < 0.0f ) + sto[ 0 ] += 1.0f; + sto[ 1 ] = st[ 1 ]; + while( sto[ 1 ] < 0.0f ) + sto[ 1 ] += 1.0f; + + /* get offsets */ + x = ((float) width * sto[ 0 ]) + 0.5f; + x %= width; + y = ((float) height * sto[ 1 ]) + 0.5f; + y %= height; + + /* get pixel */ + pixels += (y * width * 4) + (x * 4); + VectorCopy( pixels, color ); + color[ 3 ] = pixels[ 3 ]; + return qtrue; +} + + + +/* +RadSample() +samples a fragment's lightmap or vertex color and returns an +average color and a color gradient for the sample +*/ + +#define MAX_SAMPLES 150 +#define SAMPLE_GRANULARITY 6 + +static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, radWinding_t *rw, vec3_t average, vec3_t gradient, int *style ) +{ + int i, j, k, l, v, x, y, samples; + vec3_t color, mins, maxs; + vec4_t textureColor; + float alpha, alphaI, bf; + vec3_t blend; + float st[ 2 ], lightmap[ 2 ], *radLuxel; + radVert_t *rv[ 3 ]; + + + /* initial setup */ + ClearBounds( mins, maxs ); + VectorClear( average ); + VectorClear( gradient ); + alpha = 0; + + /* dummy check */ + if( rw == NULL || rw->numVerts < 3 ) + return; + + /* start sampling */ + samples = 0; + + /* sample vertex colors if no lightmap or this is the initial pass */ + if( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse ) + { + for( samples = 0; samples < rw->numVerts; samples++ ) + { + /* multiply by texture color */ + if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) + { + VectorCopy( si->averageColor, textureColor ); + textureColor[ 4 ] = 255.0f; + } + for( i = 0; i < 3; i++ ) + color[ i ] = (textureColor[ i ] / 255) * (rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f); + + AddPointToBounds( color, mins, maxs ); + VectorAdd( average, color, average ); + + /* get alpha */ + alpha += (textureColor[ 3 ] / 255.0f) * (rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f); + } + + /* set style */ + *style = ds->vertexStyles[ lightmapNum ]; + } + + /* sample lightmap */ + else + { + /* fracture the winding into a fan (including degenerate tris) */ + for( v = 1; v < (rw->numVerts - 1) && samples < MAX_SAMPLES; v++ ) + { + /* get a triangle */ + rv[ 0 ] = &rw->verts[ 0 ]; + rv[ 1 ] = &rw->verts[ v ]; + rv[ 2 ] = &rw->verts[ v + 1 ]; + + /* this code is embarassing (really should just rasterize the triangle) */ + for( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ ) + { + for( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ ) + { + for( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ ) + { + /* create a blend vector (barycentric coordinates) */ + blend[ 0 ] = i; + blend[ 1 ] = j; + blend[ 2 ] = k; + bf = (1.0 / (blend[ 0 ] + blend[ 1 ] + blend[ 2 ])); + VectorScale( blend, bf, blend ); + + /* create a blended sample */ + st[ 0 ] = st[ 1 ] = 0.0f; + lightmap[ 0 ] = lightmap[ 1 ] = 0.0f; + alphaI = 0.0f; + for( l = 0; l < 3; l++ ) + { + st[ 0 ] += (rv[ l ]->st[ 0 ] * blend[ l ]); + st[ 1 ] += (rv[ l ]->st[ 1 ] * blend[ l ]); + lightmap[ 0 ] += (rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ]); + lightmap[ 1 ] += (rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ]); + alphaI += (rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ]); + } + + /* get lightmap xy coords */ + x = lightmap[ 0 ] / (float) superSample; + y = lightmap[ 1 ] / (float) superSample; + if( x < 0 ) + x = 0; + else if ( x >= lm->w ) + x = lm->w - 1; + if( y < 0 ) + y = 0; + else if ( y >= lm->h ) + y = lm->h - 1; + + /* get radiosity luxel */ + radLuxel = RAD_LUXEL( lightmapNum, x, y ); + + /* ignore unlit/unused luxels */ + if( radLuxel[ 0 ] < 0.0f ) + continue; + + /* inc samples */ + samples++; + + /* multiply by texture color */ + if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) + { + VectorCopy( si->averageColor, textureColor ); + textureColor[ 4 ] = 255; + } + for( i = 0; i < 3; i++ ) + color[ i ] = (textureColor[ i ] / 255) * (radLuxel[ i ] / 255); + + AddPointToBounds( color, mins, maxs ); + VectorAdd( average, color, average ); + + /* get alpha */ + alpha += (textureColor[ 3 ] / 255) * (alphaI / 255); + } + } + } + } + + /* set style */ + *style = ds->lightmapStyles[ lightmapNum ]; + } + + /* any samples? */ + if( samples <= 0 ) + return; + + /* average the color */ + VectorScale( average, (1.0 / samples), average ); + + /* create the color gradient */ + //% VectorSubtract( maxs, mins, delta ); + + /* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */ + //% gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f; + //% gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f; + //% gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f; + + /* newer: another contrast function */ + for( i = 0; i < 3; i++ ) + gradient[ i ] = (maxs[ i ] - mins[ i ]) * maxs[ i ]; +} + + + +/* +RadSubdivideDiffuseLight() +subdivides a radiosity winding until it is smaller than subdivide, then generates an area light +*/ + +#define RADIOSITY_MAX_GRADIENT 0.75f //% 0.25f +#define RADIOSITY_VALUE 500.0f +#define RADIOSITY_MIN 0.0001f +#define RADIOSITY_CLIP_EPSILON 0.125f + +static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, + float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ) +{ + int i, style; + float dist, area, value; + vec3_t mins, maxs, normal, d1, d2, cross, color, gradient; + light_t *light, *splash; + winding_t *w; + + + /* dummy check */ + if( rw == NULL || rw->numVerts < 3 ) + return; + + /* get bounds for winding */ + ClearBounds( mins, maxs ); + for( i = 0; i < rw->numVerts; i++ ) + AddPointToBounds( rw->verts[ i ].xyz, mins, maxs ); + + /* subdivide if necessary */ + for( i = 0; i < 3; i++ ) + { + if( maxs[ i ] - mins[ i ] > subdivide ) + { + radWinding_t front, back; + + + /* make axial plane */ + VectorClear( normal ); + normal[ i ] = 1; + dist = (maxs[ i ] + mins[ i ]) * 0.5f; + + /* clip the winding */ + RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw ); + + /* recurse */ + RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw ); + RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw ); + return; + } + } + + /* check area */ + area = 0.0f; + for( i = 2; i < rw->numVerts; i++ ) + { + VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 ); + VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 ); + CrossProduct( d1, d2, cross ); + area += 0.5f * VectorLength( cross ); + } + if( area < 1.0f || area > 20000000.0f ) + return; + + /* more subdivision may be necessary */ + if( bouncing ) + { + /* get color sample for the surface fragment */ + RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style ); + + /* if color gradient is too high, subdivide again */ + if( subdivide > minDiffuseSubdivide && + (gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT) ) + { + RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, (subdivide / 2.0f), qfalse, rw, cw ); + return; + } + } + + /* create a regular winding and an average normal */ + w = AllocWinding( rw->numVerts ); + w->numpoints = rw->numVerts; + VectorClear( normal ); + for( i = 0; i < rw->numVerts; i++ ) + { + VectorCopy( rw->verts[ i ].xyz, w->p[ i ] ); + VectorAdd( normal, rw->verts[ i ].normal, normal ); + } + VectorScale( normal, (1.0f / rw->numVerts), normal ); + if( VectorNormalize( normal, normal ) == 0.0f ) + return; + + /* early out? */ + if( bouncing && VectorLength( color ) < RADIOSITY_MIN ) + return; + + /* debug code */ + //% Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) ); + //% Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] ); + + /* increment counts */ + numDiffuseLights++; + switch( ds->surfaceType ) + { + case MST_PLANAR: + numBrushDiffuseLights++; + break; + + case MST_TRIANGLE_SOUP: + numTriangleDiffuseLights; + break; + + case MST_PATCH: + numPatchDiffuseLights++; + break; + } + + /* create a light */ + light = safe_malloc( sizeof( *light ) ); + memset( light, 0, sizeof( *light ) ); + + /* attach it */ + ThreadLock(); + light->next = lights; + lights = light; + ThreadUnlock(); + + /* initialize the light */ + light->flags = LIGHT_AREA_DEFAULT; + light->type = EMIT_AREA; + light->si = si; + light->fade = 1.0f; + light->w = w; + + /* set falloff threshold */ + light->falloffTolerance = falloffTolerance; + + /* bouncing light? */ + if( bouncing == qfalse ) + { + /* handle first-pass lights in normal q3a style */ + value = si->value; + light->photons = value * area * areaScale; + light->add = value * formFactorValueScale * areaScale; + VectorCopy( si->color, light->color ); + VectorScale( light->color, light->add, light->emitColor ); + light->style = si->lightStyle; + if( light->style < 0 || light->style >= LS_NONE ) + light->style = 0; + + /* set origin */ + VectorAdd( mins, maxs, light->origin ); + VectorScale( light->origin, 0.5f, light->origin ); + + /* nudge it off the plane a bit */ + VectorCopy( normal, light->normal ); + VectorMA( light->origin, 1.0f, light->normal, light->origin ); + light->dist = DotProduct( light->origin, normal ); + + /* optionally create a point splashsplash light for first pass */ + if( original && si->backsplashFraction > 0 ) + { + /* allocate a new point light */ + splash = safe_malloc( sizeof( *splash ) ); + memset( splash, 0, sizeof( *splash ) ); + splash->next = lights; + lights = splash; + + /* set it up */ + splash->flags = LIGHT_Q3A_DEFAULT; + splash->type = EMIT_POINT; + splash->photons = light->photons * si->backsplashFraction; + splash->fade = 1.0f; + splash->si = si; + VectorMA( light->origin, si->backsplashDistance, normal, splash->origin ); + VectorCopy( si->color, splash->color ); + splash->falloffTolerance = falloffTolerance; + splash->style = light->style; + + /* add to counts */ + numPointLights++; + } + } + else + { + /* handle bounced light (radiosity) a little differently */ + value = RADIOSITY_VALUE * si->bounceScale * 0.375f; + light->photons = value * area * bounceScale; + light->add = value * formFactorValueScale * bounceScale; + VectorCopy( color, light->color ); + VectorScale( light->color, light->add, light->emitColor ); + light->style = style; + if( light->style < 0 || light->style >= LS_NONE ) + light->style = 0; + + /* set origin */ + WindingCenter( w, light->origin ); + + /* nudge it off the plane a bit */ + VectorCopy( normal, light->normal ); + VectorMA( light->origin, 1.0f, light->normal, light->origin ); + light->dist = DotProduct( light->origin, normal ); + } + + /* emit light from both sides? */ + if( si->compileFlags & C_FOG || si->twoSided ) + light->flags |= LIGHT_TWOSIDED; + + //% Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n", + //% light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add, + //% light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ], + //% light->si->shader ); +} + + + +/* +RadLightForTriangles() +creates unbounced diffuse lights for triangle soup (misc_models, etc) +*/ + +void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ) +{ + int i, j, k, v; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + float *radVertexLuxel; + radWinding_t rw; + + + /* get surface */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* each triangle is a potential emitter */ + rw.numVerts = 3; + for( i = 0; i < ds->numIndexes; i += 3 ) + { + /* copy each vert */ + for( j = 0; j < 3; j++ ) + { + /* get vertex index and rad vertex luxel */ + v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ]; + + /* get most everything */ + memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) ); + + /* fix colors */ + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + { + radVertexLuxel = RAD_VERTEX_LUXEL( k, ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ] ); + VectorCopy( radVertexLuxel, rw.verts[ j ].color[ k ] ); + rw.verts[ j ].color[ k ][ 3 ] = yDrawVerts[ v ].color[ k ][ 3 ]; + } + } + + /* subdivide into area lights */ + RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw ); + } +} + + + +/* +RadLightForPatch() +creates unbounced diffuse lights for patches +*/ + +#define PLANAR_EPSILON 0.1f + +void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ) +{ + int i, x, y, v, t, pw[ 5 ], r; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + bspDrawVert_t *bogus; + bspDrawVert_t *dv[ 4 ]; + mesh_t src, *subdivided, *mesh; + float *radVertexLuxel; + float dist; + vec4_t plane; + qboolean planar; + radWinding_t rw; + + + /* get surface */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* construct a bogus vert list with color index stuffed into color[ 0 ] */ + bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) ); + memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) ); + for( i = 0; i < ds->numVerts; i++ ) + bogus[ i ].color[ 0 ][ 0 ] = i; + + /* build a subdivided mesh identical to shadow facets for this patch */ + /* this MUST MATCH FacetsForPatch() identically! */ + src.width = ds->patchWidth; + src.height = ds->patchHeight; + src.verts = bogus; + //% subdivided = SubdivideMesh( src, 8, 512 ); + subdivided = SubdivideMesh2( src, info->patchIterations ); + PutMeshOnCurve( *subdivided ); + //% MakeMeshNormals( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + free( bogus ); + + /* FIXME: build interpolation table into color[ 1 ] */ + + /* fix up color indexes */ + for( i = 0; i < (mesh->width * mesh->height); i++ ) + { + dv[ 0 ] = &mesh->verts[ i ]; + if( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts ) + dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1; + } + + /* iterate through the mesh quads */ + for( y = 0; y < (mesh->height - 1); y++ ) + { + for( x = 0; x < (mesh->width - 1); x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ + + /* set radix */ + r = (x + y) & 1; + + /* get drawverts */ + dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ]; + dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ]; + + /* planar? */ + planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ); + if( planar ) + { + dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ]; + if( fabs( dist ) > PLANAR_EPSILON ) + planar = qfalse; + } + + /* generate a quad */ + if( planar ) + { + rw.numVerts = 4; + for( v = 0; v < 4; v++ ) + { + /* get most everything */ + memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) ); + + /* fix colors */ + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] ); + VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] ); + rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ]; + } + } + + /* subdivide into area lights */ + RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw ); + } + + /* generate 2 tris */ + else + { + rw.numVerts = 3; + for( t = 0; t < 2; t++ ) + { + for( v = 0; v < 3 + t; v++ ) + { + /* get "other" triangle (stupid hacky logic, but whatevah) */ + if( v == 1 && t == 1 ) + v++; + + /* get most everything */ + memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) ); + + /* fix colors */ + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] ); + VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] ); + rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ]; + } + } + + /* subdivide into area lights */ + RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw ); + } + } + } + } + + /* free the mesh */ + FreeMesh( mesh ); +} + + + + +/* +RadLight() +creates unbounced diffuse lights for a given surface +*/ + +void RadLight( int num ) +{ + int lightmapNum; + float scale, subdivide; + int contentFlags, surfaceFlags, compileFlags; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + rawLightmap_t *lm; + shaderInfo_t *si; + clipWork_t cw; + + + /* get drawsurface, lightmap, and shader info */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + lm = info->lm; + si = info->si; + scale = si->bounceScale; + + /* find nodraw bit */ + contentFlags = surfaceFlags = compileFlags = 0; + ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags ); + + /* early outs? */ + if( scale <= 0.0f || (si->compileFlags & C_SKY) || si->autosprite || + (bspShaders[ ds->shaderNum ].contentFlags & contentFlags) || (bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags) || + (si->compileFlags & compileFlags) ) + return; + + /* determine how much we need to chop up the surface */ + if( si->lightSubdivide ) + subdivide = si->lightSubdivide; + else + subdivide = diffuseSubdivide; + + /* inc counts */ + numDiffuseSurfaces++; + + /* iterate through styles (this could be more efficient, yes) */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* switch on type */ + if( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED ) + { + switch( ds->surfaceType ) + { + case MST_PLANAR: + case MST_TRIANGLE_SOUP: + RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw ); + break; + + case MST_PATCH: + RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw ); + break; + + default: + break; + } + } + } +} + + + +/* +RadCreateDiffuseLights() +creates lights for unbounced light on surfaces in the bsp +*/ + +int iterations = 0; + +void RadCreateDiffuseLights( void ) +{ + /* startup */ + Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" ); + numDiffuseSurfaces = 0; + numDiffuseLights = 0; + numBrushDiffuseLights = 0; + numTriangleDiffuseLights = 0; + numPatchDiffuseLights = 0; + numAreaLights = 0; + + /* hit every surface (threaded) */ + RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight ); + + /* dump the lights generated to a file */ + if( dump ) + { + char dumpName[ 1024 ], ext[ 64 ]; + FILE *file; + light_t *light; + + strcpy( dumpName, source ); + StripExtension( dumpName ); + sprintf( ext, "_bounce_%03d.map", iterations ); + strcat( dumpName, ext ); + file = fopen( dumpName, "wb" ); + Sys_Printf( "Writing %s...\n", dumpName ); + if( file ) + { + for( light = lights; light; light = light->next ) + { + fprintf( file, + "{\n" + "\"classname\" \"light\"\n" + "\"light\" \"%d\"\n" + "\"origin\" \"%.0f %.0f %.0f\"\n" + "\"_color\" \"%.3f %.3f %.3f\"\n" + "}\n", + + (int) light->add, + + light->origin[ 0 ], + light->origin[ 1 ], + light->origin[ 2 ], + + light->color[ 0 ], + light->color[ 1 ], + light->color[ 2 ] ); + } + fclose( file ); + } + } + + /* increment */ + iterations++; + + /* print counts */ + Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces ); + Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights ); + Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights ); + Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights ); + Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights ); +} + + + + + diff --git a/tools/quake3/q3map2/light_shadows.c b/tools/quake3/q3map2/light_shadows.c new file mode 100644 index 00000000..14a18d95 --- /dev/null +++ b/tools/quake3/q3map2/light_shadows.c @@ -0,0 +1,124 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#define LIGHT_SHADOWS_C + +#include "light.h" +#include "inout.h" + + + +/* ------------------------------------------------------------------------------- + +ydnar: this code deals with shadow volume bsps + +------------------------------------------------------------------------------- */ + +typedef struct shadowNode_s +{ + vec4_t plane; + int children[ 2 ]; +} +shadowNode_t; + +int numShadowNodes; +shadowNode_t *shadowNodes; + + + +/* +AddShadow() +adds a shadow, returning the index into the shadow list +*/ + + + +/* +MakeShadowFromPoints() +creates a shadow volume from 4 points (the first being the light origin) +*/ + + + +/* +SetupShadows() +sets up the shadow volumes for all lights in the world +*/ + +void SetupShadows( void ) +{ + int i, j, s; + light_t *light; + dleaf_t *leaf; + dsurface_t *ds; + surfaceInfo_t *info; + shaderInfo_t *si; + byte *tested; + + + /* early out for weird cases where there are no lights */ + if( lights == NULL ) + return; + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- SetupShadows ---\n" ); + + /* allocate a surface test list */ + tested = safe_malloc( numDrawSurfaces / 8 + 1 ); + + /* walk the list of lights */ + for( light = lights; light != NULL; light = light->next ) + { + /* do some early out testing */ + if( light->cluster < 0 ) + continue; + + /* clear surfacetest list */ + memset( tested, 0, numDrawSurfaces / 8 + 1 ); + + /* walk the bsp leaves */ + for( i = 0, leaf = dleafs; i < numleafs; i++, leaf++ ) + { + /* in pvs? */ + if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) + continue; + + /* walk the surface list for this leaf */ + for( j = 0; j < leaf->numLeafSurfaces; j++ ) + { + /* don't filter a surface more than once */ + s = dleafsurfaces[ leaf->firstLeafSurface + j ]; + if( tested[ s >> 3 ] & (1 << (s & 7)) ) + continue; + tested[ s >> 3 ] |= (1 << (s & 7)); + + /* get surface and info */ + ds = &drawSurfaces[ s ]; + info = &surfaceInfos[ s ]; + si = info->si; + + /* don't create shadow volumes from translucent surfaces */ + if( si->contents & CONTENTS_TRANSLUCENT ) + continue; + } + } + } +} \ No newline at end of file diff --git a/tools/quake3/q3map2/light_trace.c b/tools/quake3/q3map2/light_trace.c new file mode 100644 index 00000000..91fc25ec --- /dev/null +++ b/tools/quake3/q3map2/light_trace.c @@ -0,0 +1,1754 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define LIGHT_TRACE_C + + + +/* dependencies */ +#include "q3map2.h" + + +/* dependencies */ +#include "q3map2.h" + + + +#define Vector2Copy( a, b ) ((b)[ 0 ] = (a)[ 0 ], (b)[ 1 ] = (a)[ 1 ]) +#define Vector4Copy( a, b ) ((b)[ 0 ] = (a)[ 0 ], (b)[ 1 ] = (a)[ 1 ], (b)[ 2 ] = (a)[ 2 ], (b)[ 3 ] = (a)[ 3 ]) + +#define MAX_NODE_ITEMS 5 +#define MAX_NODE_TRIANGLES 5 +#define MAX_TRACE_DEPTH 32 +#define MIN_NODE_SIZE 32.0f + +#define GROW_TRACE_INFOS 32768 //% 4096 +#define GROW_TRACE_WINDINGS 65536 //% 32768 +#define GROW_TRACE_TRIANGLES 131072 //% 32768 +#define GROW_TRACE_NODES 16384 //% 16384 +#define GROW_NODE_ITEMS 16 //% 256 + +#define MAX_TW_VERTS 12 + +#define TRACE_ON_EPSILON 0.1f + +#define TRACE_LEAF -1 +#define TRACE_LEAF_SOLID -2 + +typedef struct traceVert_s +{ + vec3_t xyz; + float st[ 2 ]; +} +traceVert_t; + +typedef struct traceInfo_s +{ + shaderInfo_t *si; + int surfaceNum, castShadows, padding; +} +traceInfo_t; + +typedef struct traceWinding_s +{ + vec4_t plane; + int infoNum, numVerts; + traceVert_t v[ MAX_TW_VERTS ]; +} +traceWinding_t; + +typedef struct traceTriangle_s +{ + vec3_t edge1, edge2; + int infoNum, padding; + traceVert_t v[ 3 ]; +} +traceTriangle_t; + +typedef struct traceNode_s +{ + int type; + vec4_t plane; + vec3_t mins, maxs; + int children[ 2 ]; + int numItems, maxItems; + int *items; +} +traceNode_t; + + +int noDrawContentFlags, noDrawSurfaceFlags, noDrawCompileFlags; + +int numTraceInfos = 0, maxTraceInfos = 0, firstTraceInfo = 0; +traceInfo_t *traceInfos = NULL; + +int numTraceWindings = 0, maxTraceWindings = 0, deadWinding = -1; +traceWinding_t *traceWindings = NULL; + +int numTraceTriangles = 0, maxTraceTriangles = 0, deadTriangle = -1; +traceTriangle_t *traceTriangles = NULL; + +int headNodeNum = 0, skyboxNodeNum = 0, maxTraceDepth = 0, numTraceLeafNodes = 0; +int numTraceNodes = 0, maxTraceNodes = 0; +traceNode_t *traceNodes = NULL; + + + +/* ------------------------------------------------------------------------------- + +allocation and list management + +------------------------------------------------------------------------------- */ + +/* +AddTraceInfo() - ydnar +adds a trace info structure to the pool +*/ + +static int AddTraceInfo( traceInfo_t *ti ) +{ + int num; + void *temp; + + + /* find an existing info */ + for( num = firstTraceInfo; num < numTraceInfos; num++ ) + { + if( traceInfos[ num ].si == ti->si && + traceInfos[ num ].surfaceNum == ti->surfaceNum && + traceInfos[ num ].castShadows == ti->castShadows ) + return num; + } + + /* enough space? */ + if( numTraceInfos >= maxTraceInfos ) + { + /* allocate more room */ + maxTraceInfos += GROW_TRACE_INFOS; + temp = safe_malloc( maxTraceInfos * sizeof( *traceInfos ) ); + if( traceInfos != NULL ) + { + memcpy( temp, traceInfos, numTraceInfos * sizeof( *traceInfos ) ); + free( traceInfos ); + } + traceInfos = (traceInfo_t*) temp; + } + + /* add the info */ + memcpy( &traceInfos[ num ], ti, sizeof( *traceInfos ) ); + if( num == numTraceInfos ) + numTraceInfos++; + + /* return the ti number */ + return num; +} + + + +/* +AllocTraceNode() - ydnar +allocates a new trace node +*/ + +static int AllocTraceNode( void ) +{ + traceNode_t *temp; + + + /* enough space? */ + if( numTraceNodes >= maxTraceNodes ) + { + /* reallocate more room */ + maxTraceNodes += GROW_TRACE_NODES; + temp = safe_malloc( maxTraceNodes * sizeof( traceNode_t ) ); + if( traceNodes != NULL ) + { + memcpy( temp, traceNodes, numTraceNodes * sizeof( traceNode_t ) ); + free( traceNodes ); + } + traceNodes = temp; + } + + /* add the node */ + memset( &traceNodes[ numTraceNodes ], 0, sizeof( traceNode_t ) ); + traceNodes[ numTraceNodes ].type = TRACE_LEAF; + ClearBounds( traceNodes[ numTraceNodes ].mins, traceNodes[ numTraceNodes ].maxs ); + numTraceNodes++; + + /* return the count */ + return (numTraceNodes - 1); +} + + + +/* +AddTraceWinding() - ydnar +adds a winding to the raytracing pool +*/ + +static int AddTraceWinding( traceWinding_t *tw ) +{ + int num; + void *temp; + + + /* check for a dead winding */ + if( deadWinding >= 0 && deadWinding < numTraceWindings ) + num = deadWinding; + else + { + /* put winding at the end of the list */ + num = numTraceWindings; + + /* enough space? */ + if( numTraceWindings >= maxTraceWindings ) + { + /* allocate more room */ + maxTraceWindings += GROW_TRACE_WINDINGS; + temp = safe_malloc( maxTraceWindings * sizeof( *traceWindings ) ); + if( traceWindings != NULL ) + { + memcpy( temp, traceWindings, numTraceWindings * sizeof( *traceWindings ) ); + free( traceWindings ); + } + traceWindings = (traceWinding_t*) temp; + } + } + + /* add the winding */ + memcpy( &traceWindings[ num ], tw, sizeof( *traceWindings ) ); + if( num == numTraceWindings ) + numTraceWindings++; + deadWinding = -1; + + /* return the winding number */ + return num; +} + + + +/* +AddTraceTriangle() - ydnar +adds a triangle to the raytracing pool +*/ + +static int AddTraceTriangle( traceTriangle_t *tt ) +{ + int num; + void *temp; + + + /* check for a dead triangle */ + if( deadTriangle >= 0 && deadTriangle < numTraceTriangles ) + num = deadTriangle; + else + { + /* put triangle at the end of the list */ + num = numTraceTriangles; + + /* enough space? */ + if( numTraceTriangles >= maxTraceTriangles ) + { + /* allocate more room */ + maxTraceTriangles += GROW_TRACE_TRIANGLES; + temp = safe_malloc( maxTraceTriangles * sizeof( *traceTriangles ) ); + if( traceTriangles != NULL ) + { + memcpy( temp, traceTriangles, numTraceTriangles * sizeof( *traceTriangles ) ); + free( traceTriangles ); + } + traceTriangles = (traceTriangle_t*) temp; + } + } + + /* find vectors for two edges sharing the first vert */ + VectorSubtract( tt->v[ 1 ].xyz, tt->v[ 0 ].xyz, tt->edge1 ); + VectorSubtract( tt->v[ 2 ].xyz, tt->v[ 0 ].xyz, tt->edge2 ); + + /* add the triangle */ + memcpy( &traceTriangles[ num ], tt, sizeof( *traceTriangles ) ); + if( num == numTraceTriangles ) + numTraceTriangles++; + deadTriangle = -1; + + /* return the triangle number */ + return num; +} + + + +/* +AddItemToTraceNode() - ydnar +adds an item reference (winding or triangle) to a trace node +*/ + +static int AddItemToTraceNode( traceNode_t *node, int num ) +{ + void *temp; + + + /* dummy check */ + if( num < 0 ) + return -1; + + /* enough space? */ + if( node->numItems >= node->maxItems ) + { + /* allocate more room */ + if( node == traceNodes ) + node->maxItems *= 2; + else + node->maxItems += GROW_NODE_ITEMS; + temp = safe_malloc( node->maxItems * sizeof( *node->items ) ); + if( node->items != NULL ) + { + memcpy( temp, node->items, node->numItems * sizeof( *node->items ) ); + free( node->items ); + } + node->items = (int*) temp; + } + + /* add the poly */ + node->items[ node->numItems ] = num; + node->numItems++; + + /* return the count */ + return (node->numItems - 1); +} + + + + +/* ------------------------------------------------------------------------------- + +trace node setup + +------------------------------------------------------------------------------- */ + +/* +SetupTraceNodes_r() - ydnar +recursively create the initial trace node structure from the bsp tree +*/ + +static int SetupTraceNodes_r( int bspNodeNum ) +{ + int i, nodeNum, bspLeafNum; + bspPlane_t *plane; + bspNode_t *bspNode; + + + /* get bsp node and plane */ + bspNode = &bspNodes[ bspNodeNum ]; + plane = &bspPlanes[ bspNode->planeNum ]; + + /* allocate a new trace node */ + nodeNum = AllocTraceNode(); + + /* setup trace node */ + traceNodes[ nodeNum ].type = PlaneTypeForNormal( plane->normal ); + VectorCopy( plane->normal, traceNodes[ nodeNum ].plane ); + traceNodes[ nodeNum ].plane[ 3 ] = plane->dist; + + /* setup children */ + for( i = 0; i < 2; i++ ) + { + /* leafnode */ + if( bspNode->children[ i ] < 0 ) + { + bspLeafNum = -bspNode->children[ i ] - 1; + + #if 0 + /* solid leaf */ + if( bspLeafs[ bspLeafNum ].cluster == -1 ) + traceNodes[ nodeNum ].children[ i ] = -1; + + /* passable leaf */ + else + traceNodes[ nodeNum ].children[ i ] = AllocTraceNode(); + #endif + + /* new code */ + traceNodes[ nodeNum ].children[ i ] = AllocTraceNode(); + if( bspLeafs[ bspLeafNum ].cluster == -1 ) + traceNodes[ traceNodes[ nodeNum ].children[ i ] ].type = TRACE_LEAF_SOLID; + } + + /* normal node */ + else + traceNodes[ nodeNum ].children[ i ] = SetupTraceNodes_r( bspNode->children[ i ] ); + } + + /* return node number */ + return nodeNum; +} + + + +/* +ClipTraceWinding() - ydnar +clips a trace winding against a plane into one or two parts +*/ + +#define TW_ON_EPSILON 0.25f + +void ClipTraceWinding( traceWinding_t *tw, vec4_t plane, traceWinding_t *front, traceWinding_t *back ) +{ + int i, j, k; + int sides[ MAX_TW_VERTS ], counts[ 3 ] = { 0, 0, 0 }; + float dists[ MAX_TW_VERTS ]; + float frac; + traceVert_t *a, *b, mid; + + + /* clear front and back */ + front->numVerts = 0; + back->numVerts = 0; + + /* classify points */ + for( i = 0; i < tw->numVerts; i++ ) + { + dists[ i ] = DotProduct( tw->v[ i ].xyz, plane ) - plane[ 3 ]; + if( dists[ i ] < -TW_ON_EPSILON ) + sides[ i ] = SIDE_BACK; + else if( dists[ i ] > TW_ON_EPSILON ) + sides[ i ] = SIDE_FRONT; + else + sides[ i ] = SIDE_ON; + counts[ sides[ i ] ]++; + } + + /* entirely on front? */ + if( counts[ SIDE_BACK ] == 0 ) + memcpy( front, tw, sizeof( *front ) ); + + /* entirely on back? */ + else if( counts[ SIDE_FRONT ] == 0 ) + memcpy( back, tw, sizeof( *back ) ); + + /* straddles the plane */ + else + { + /* setup front and back */ + memcpy( front, tw, sizeof( *front ) ); + front->numVerts = 0; + memcpy( back, tw, sizeof( *back ) ); + back->numVerts = 0; + + /* split the winding */ + for( i = 0; i < tw->numVerts; i++ ) + { + /* radix */ + j = (i + 1) % tw->numVerts; + + /* get verts */ + a = &tw->v[ i ]; + b = &tw->v[ j ]; + + /* handle points on the splitting plane */ + switch( sides[ i ] ) + { + case SIDE_FRONT: + if( front->numVerts >= MAX_TW_VERTS ) + Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS ); + front->v[ front->numVerts++ ] = *a; + break; + + case SIDE_BACK: + if( back->numVerts >= MAX_TW_VERTS ) + Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS ); + back->v[ back->numVerts++ ] = *a; + break; + + case SIDE_ON: + if( front->numVerts >= MAX_TW_VERTS || back->numVerts >= MAX_TW_VERTS ) + Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS ); + front->v[ front->numVerts++ ] = *a; + back->v[ back->numVerts++ ] = *a; + continue; + } + + /* check next point to see if we need to split the edge */ + if( sides[ j ] == SIDE_ON || sides[ j ] == sides[ i ] ) + continue; + + /* check limit */ + if( front->numVerts >= MAX_TW_VERTS || back->numVerts >= MAX_TW_VERTS ) + Error( "MAX_TW_VERTS (%d) exceeded", MAX_TW_VERTS ); + + /* generate a split point */ + frac = dists[ i ] / (dists[ i ] - dists[ j ]); + for( k = 0; k < 3; k++ ) + { + /* minimize fp precision errors */ + if( plane[ k ] == 1.0f ) + mid.xyz[ k ] = plane[ 3 ]; + else if( plane[ k ] == -1.0f ) + mid.xyz[ k ] = -plane[ 3 ]; + else + mid.xyz[ k ] = a->xyz[ k ] + frac * (b->xyz[ k ] - a->xyz[ k ]); + + /* set texture coordinates */ + if( k > 1 ) + continue; + mid.st[ 0 ] = a->st[ 0 ] + frac * (b->st[ 0 ] - a->st[ 0 ]); + mid.st[ 1 ] = a->st[ 1 ] + frac * (b->st[ 1 ] - a->st[ 1 ]); + } + + /* copy midpoint to front and back polygons */ + front->v[ front->numVerts++ ] = mid; + back->v[ back->numVerts++ ] = mid; + } + } +} + + + +/* +FilterPointToTraceNodes_r() - ydnar +debugging tool +*/ + +static int FilterPointToTraceNodes_r( vec3_t pt, int nodeNum ) +{ + float dot; + traceNode_t *node; + + + if( nodeNum < 0 || nodeNum >= numTraceNodes ) + return -1; + + node = &traceNodes[ nodeNum ]; + + if( node->type >= 0 ) + { + dot = DotProduct( pt, node->plane ) - node->plane[ 3 ]; + if( dot > -0.001f ) + FilterPointToTraceNodes_r( pt, node->children[ 0 ] ); + if( dot < 0.001f ) + FilterPointToTraceNodes_r( pt, node->children[ 1 ] ); + return -1; + } + + Sys_Printf( "%d ", nodeNum ); + + return nodeNum; +} + + + +/* +FilterTraceWindingIntoNodes_r() - ydnar +filters a trace winding into the raytracing tree +*/ + +static void FilterTraceWindingIntoNodes_r( traceWinding_t *tw, int nodeNum ) +{ + int num; + vec4_t plane1, plane2, reverse; + traceNode_t *node; + traceWinding_t front, back; + + + /* don't filter if passed a bogus node (solid, etc) */ + if( nodeNum < 0 || nodeNum >= numTraceNodes ) + return; + + /* get node */ + node = &traceNodes[ nodeNum ]; + + /* is this a decision node? */ + if( node->type >= 0 ) + { + /* create winding plane if necessary, filtering out bogus windings as well */ + if( nodeNum == headNodeNum ) + { + if( !PlaneFromPoints( tw->plane, tw->v[ 0 ].xyz, tw->v[ 1 ].xyz, tw->v[ 2 ].xyz ) ) + return; + } + + /* validate the node */ + if( node->children[ 0 ] == 0 || node->children[ 1 ] == 0 ) + Error( "Invalid tracenode: %d", nodeNum ); + + /* get node plane */ + Vector4Copy( node->plane, plane1 ); + + /* get winding plane */ + Vector4Copy( tw->plane, plane2 ); + + /* invert surface plane */ + VectorSubtract( vec3_origin, plane2, reverse ); + reverse[ 3 ] = -plane2[ 3 ]; + + /* front only */ + if( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f ) + { + FilterTraceWindingIntoNodes_r( tw, node->children[ 0 ] ); + return; + } + + /* back only */ + if( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f ) + { + FilterTraceWindingIntoNodes_r( tw, node->children[ 1 ] ); + return; + } + + /* clip the winding by node plane */ + ClipTraceWinding( tw, plane1, &front, &back ); + + /* filter by node plane */ + if( front.numVerts >= 3 ) + FilterTraceWindingIntoNodes_r( &front, node->children[ 0 ] ); + if( back.numVerts >= 3 ) + FilterTraceWindingIntoNodes_r( &back, node->children[ 1 ] ); + + /* return to caller */ + return; + } + + /* add winding to leaf node */ + num = AddTraceWinding( tw ); + AddItemToTraceNode( node, num ); +} + + + +/* +SubdivideTraceNode_r() - ydnar +recursively subdivides a tracing node until it meets certain size and complexity criteria +*/ + +static void SubdivideTraceNode_r( int nodeNum, int depth ) +{ + int i, j, count, num, frontNum, backNum, type; + vec3_t size; + float dist; + double average[ 3 ]; + traceNode_t *node, *frontNode, *backNode; + traceWinding_t *tw, front, back; + + + /* dummy check */ + if( nodeNum < 0 || nodeNum >= numTraceNodes ) + return; + + /* get node */ + node = &traceNodes[ nodeNum ]; + + /* runaway recursion check */ + if( depth >= MAX_TRACE_DEPTH ) + { + //% Sys_Printf( "Depth: (%d items)\n", node->numItems ); + numTraceLeafNodes++; + return; + } + depth++; + + /* is this a decision node? */ + if( node->type >= 0 ) + { + /* subdivide children */ + frontNum = node->children[ 0 ]; + backNum = node->children[ 1 ]; + SubdivideTraceNode_r( frontNum, depth ); + SubdivideTraceNode_r( backNum, depth ); + return; + } + + /* bound the node */ + ClearBounds( node->mins, node->maxs ); + VectorClear( average ); + count = 0; + for( i = 0; i < node->numItems; i++ ) + { + /* get winding */ + tw = &traceWindings[ node->items[ i ] ]; + + /* walk its verts */ + for( j = 0; j < tw->numVerts; j++ ) + { + AddPointToBounds( tw->v[ j ].xyz, node->mins, node->maxs ); + average[ 0 ] += tw->v[ j ].xyz[ 0 ]; + average[ 1 ] += tw->v[ j ].xyz[ 1 ]; + average[ 2 ] += tw->v[ j ].xyz[ 2 ]; + count++; + } + } + + /* check triangle limit */ + //% if( node->numItems <= MAX_NODE_ITEMS ) + if( (count - (node->numItems * 2)) < MAX_NODE_TRIANGLES ) + { + //% Sys_Printf( "Limit: (%d triangles)\n", (count - (node->numItems * 2)) ); + numTraceLeafNodes++; + return; + } + + /* the largest dimension of the bounding box will be the split axis */ + VectorSubtract( node->maxs, node->mins, size ); + if( size[ 0 ] >= size[ 1 ] && size[ 0 ] >= size[ 2 ] ) + type = PLANE_X; + else if( size[ 1 ] >= size[ 0 ] && size[ 1 ] >= size[ 2 ] ) + type = PLANE_Y; + else + type = PLANE_Z; + + /* don't split small nodes */ + if( size[ type ] <= MIN_NODE_SIZE ) + { + //% Sys_Printf( "Limit: %f %f %f (%d items)\n", size[ 0 ], size[ 1 ], size[ 2 ], node->numItems ); + numTraceLeafNodes++; + return; + } + + /* set max trace depth */ + if( depth > maxTraceDepth ) + maxTraceDepth = depth; + + /* snap the average */ + dist = floor( average[ type ] / count ); + + /* dummy check it */ + if( dist <= node->mins[ type ] || dist >= node->maxs[ type ] ) + dist = floor( 0.5f * (node->mins[ type ] + node->maxs[ type ]) ); + + /* allocate child nodes */ + frontNum = AllocTraceNode(); + backNum = AllocTraceNode(); + + /* reset pointers */ + node = &traceNodes[ nodeNum ]; + frontNode = &traceNodes[ frontNum ]; + backNode = &traceNodes[ backNum ]; + + /* attach children */ + node->type = type; + node->plane[ type ] = 1.0f; + node->plane[ 3 ] = dist; + node->children[ 0 ] = frontNum; + node->children[ 1 ] = backNum; + + /* setup front node */ + frontNode->maxItems = (node->maxItems >> 1); + frontNode->items = safe_malloc( frontNode->maxItems * sizeof( *frontNode->items ) ); + + /* setup back node */ + backNode->maxItems = (node->maxItems >> 1); + backNode->items = safe_malloc( backNode->maxItems * sizeof( *backNode->items ) ); + + /* filter windings into child nodes */ + for( i = 0; i < node->numItems; i++ ) + { + /* get winding */ + tw = &traceWindings[ node->items[ i ] ]; + + /* clip the winding by the new split plane */ + ClipTraceWinding( tw, node->plane, &front, &back ); + + /* kill the existing winding */ + if( front.numVerts >= 3 || back.numVerts >= 3 ) + deadWinding = node->items[ i ]; + + /* add front winding */ + if( front.numVerts >= 3 ) + { + num = AddTraceWinding( &front ); + AddItemToTraceNode( frontNode, num ); + } + + /* add back winding */ + if( back.numVerts >= 3 ) + { + num = AddTraceWinding( &back ); + AddItemToTraceNode( backNode, num ); + } + } + + /* free original node winding list */ + node->numItems = 0; + node->maxItems = 0; + free( node->items ); + node->items = NULL; + + /* check children */ + if( frontNode->numItems <= 0 ) + { + frontNode->maxItems = 0; + free( frontNode->items ); + frontNode->items = NULL; + } + + if( backNode->numItems <= 0 ) + { + backNode->maxItems = 0; + free( backNode->items ); + backNode->items = NULL; + } + + /* subdivide children */ + SubdivideTraceNode_r( frontNum, depth ); + SubdivideTraceNode_r( backNum, depth ); +} + + + +/* +TriangulateTraceNode_r() +optimizes the tracing data by changing trace windings into triangles +*/ + +static int TriangulateTraceNode_r( int nodeNum ) +{ + int i, j, num, frontNum, backNum, numWindings, *windings; + traceNode_t *node; + traceWinding_t *tw; + traceTriangle_t tt; + + + /* dummy check */ + if( nodeNum < 0 || nodeNum >= numTraceNodes ) + return 0; + + /* get node */ + node = &traceNodes[ nodeNum ]; + + /* is this a decision node? */ + if( node->type >= 0 ) + { + /* triangulate children */ + frontNum = node->children[ 0 ]; + backNum = node->children[ 1 ]; + node->numItems = TriangulateTraceNode_r( frontNum ); + node->numItems += TriangulateTraceNode_r( backNum ); + return node->numItems; + } + + /* empty node? */ + if( node->numItems == 0 ) + { + node->maxItems = 0; + if( node->items != NULL ) + free( node->items ); + return node->numItems; + } + + /* store off winding data */ + numWindings = node->numItems; + windings = node->items; + + /* clear it */ + node->numItems = 0; + node->maxItems = numWindings * 2; + node->items = safe_malloc( node->maxItems * sizeof( tt ) ); + + /* walk winding list */ + for( i = 0; i < numWindings; i++ ) + { + /* get winding */ + tw = &traceWindings[ windings[ i ] ]; + + /* initial setup */ + tt.infoNum = tw->infoNum; + tt.v[ 0 ] = tw->v[ 0 ]; + + /* walk vertex list */ + for( j = 1; j + 1 < tw->numVerts; j++ ) + { + /* set verts */ + tt.v[ 1 ] = tw->v[ j ]; + tt.v[ 2 ] = tw->v[ j + 1 ]; + + /* find vectors for two edges sharing the first vert */ + VectorSubtract( tt.v[ 1 ].xyz, tt.v[ 0 ].xyz, tt.edge1 ); + VectorSubtract( tt.v[ 2 ].xyz, tt.v[ 0 ].xyz, tt.edge2 ); + + /* add it to the node */ + num = AddTraceTriangle( &tt ); + AddItemToTraceNode( node, num ); + } + } + + /* free windings */ + if( windings != NULL ) + free( windings ); + + /* return item count */ + return node->numItems; +} + + + +/* ------------------------------------------------------------------------------- + +shadow casting item setup (triangles, patches, entities) + +------------------------------------------------------------------------------- */ + +/* +PopulateWithBSPModel() - ydnar +filters a bsp model's surfaces into the raytracing tree +*/ + +static void PopulateWithBSPModel( bspModel_t *model, m4x4_t transform ) +{ + int i, j, x, y, pw[ 5 ], r, nodeNum; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + bspDrawVert_t *verts; + int *indexes; + mesh_t srcMesh, *mesh, *subdivided; + traceInfo_t ti; + traceWinding_t tw; + + + /* dummy check */ + if( model == NULL || transform == NULL ) + return; + + /* walk the list of surfaces in this model and fill out the info structs */ + for( i = 0; i < model->numBSPSurfaces; i++ ) + { + /* get surface and info */ + ds = &bspDrawSurfaces[ model->firstBSPSurface + i ]; + info = &surfaceInfos[ model->firstBSPSurface + i ]; + if( info->si == NULL ) + continue; + + /* no shadows */ + if( !info->castShadows ) + continue; + + /* patchshadows? */ + if( ds->surfaceType == MST_PATCH && patchShadows == qfalse ) + continue; + + /* some surfaces in the bsp might have been tagged as nodraw, with a bogus shader */ + if( (bspShaders[ ds->shaderNum ].contentFlags & noDrawContentFlags) || + (bspShaders[ ds->shaderNum ].surfaceFlags & noDrawSurfaceFlags) ) + continue; + + /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */ + if( (info->si->compileFlags & C_NODRAW) ) + continue; + if( (info->si->compileFlags & C_TRANSLUCENT) && + !(info->si->compileFlags & C_ALPHASHADOW) && + !(info->si->compileFlags & C_LIGHTFILTER) ) + continue; + + /* setup trace info */ + ti.si = info->si; + ti.castShadows = info->castShadows; + ti.surfaceNum = model->firstBSPBrush + i; + + /* setup trace winding */ + memset( &tw, 0, sizeof( tw ) ); + tw.infoNum = AddTraceInfo( &ti ); + tw.numVerts = 3; + + /* choose which node (normal or skybox) */ + if( info->parentSurfaceNum >= 0 ) + nodeNum = skyboxNodeNum; + else + nodeNum = headNodeNum; + + /* switch on type */ + switch( ds->surfaceType ) + { + /* handle patches */ + case MST_PATCH: + /* subdivide the surface */ + srcMesh.width = ds->patchWidth; + srcMesh.height = ds->patchHeight; + srcMesh.verts = &bspDrawVerts[ ds->firstVert ]; + //% subdivided = SubdivideMesh( srcMesh, 8, 512 ); + subdivided = SubdivideMesh2( srcMesh, info->patchIterations ); + + /* fit it to the curve and remove colinear verts on rows/columns */ + PutMeshOnCurve( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + + /* set verts */ + verts = mesh->verts; + + /* subdivide each quad to place the models */ + for( y = 0; y < (mesh->height - 1); y++ ) + { + for( x = 0; x < (mesh->width - 1); x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ + + /* set radix */ + r = (x + y) & 1; + + /* make first triangle */ + VectorCopy( verts[ pw[ r + 0 ] ].xyz, tw.v[ 0 ].xyz ); + Vector2Copy( verts[ pw[ r + 0 ] ].st, tw.v[ 0 ].st ); + VectorCopy( verts[ pw[ r + 1 ] ].xyz, tw.v[ 1 ].xyz ); + Vector2Copy( verts[ pw[ r + 1 ] ].st, tw.v[ 1 ].st ); + VectorCopy( verts[ pw[ r + 2 ] ].xyz, tw.v[ 2 ].xyz ); + Vector2Copy( verts[ pw[ r + 2 ] ].st, tw.v[ 2 ].st ); + m4x4_transform_point( transform, tw.v[ 0 ].xyz ); + m4x4_transform_point( transform, tw.v[ 1 ].xyz ); + m4x4_transform_point( transform, tw.v[ 2 ].xyz ); + FilterTraceWindingIntoNodes_r( &tw, nodeNum ); + + /* make second triangle */ + VectorCopy( verts[ pw[ r + 0 ] ].xyz, tw.v[ 0 ].xyz ); + Vector2Copy( verts[ pw[ r + 0 ] ].st, tw.v[ 0 ].st ); + VectorCopy( verts[ pw[ r + 2 ] ].xyz, tw.v[ 1 ].xyz ); + Vector2Copy( verts[ pw[ r + 2 ] ].st, tw.v[ 1 ].st ); + VectorCopy( verts[ pw[ r + 3 ] ].xyz, tw.v[ 2 ].xyz ); + Vector2Copy( verts[ pw[ r + 3 ] ].st, tw.v[ 2 ].st ); + m4x4_transform_point( transform, tw.v[ 0 ].xyz ); + m4x4_transform_point( transform, tw.v[ 1 ].xyz ); + m4x4_transform_point( transform, tw.v[ 2 ].xyz ); + FilterTraceWindingIntoNodes_r( &tw, nodeNum ); + } + } + + /* free the subdivided mesh */ + FreeMesh( mesh ); + break; + + /* handle triangle surfaces */ + case MST_TRIANGLE_SOUP: + case MST_PLANAR: + /* set verts and indexes */ + verts = &bspDrawVerts[ ds->firstVert ]; + indexes = &bspDrawIndexes[ ds->firstIndex ]; + + /* walk the triangle list */ + for( j = 0; j < ds->numIndexes; j += 3 ) + { + VectorCopy( verts[ indexes[ j ] ].xyz, tw.v[ 0 ].xyz ); + Vector2Copy( verts[ indexes[ j ] ].st, tw.v[ 0 ].st ); + VectorCopy( verts[ indexes[ j + 1 ] ].xyz, tw.v[ 1 ].xyz ); + Vector2Copy( verts[ indexes[ j + 1 ] ].st, tw.v[ 1 ].st ); + VectorCopy( verts[ indexes[ j + 2 ] ].xyz, tw.v[ 2 ].xyz ); + Vector2Copy( verts[ indexes[ j + 2 ] ].st, tw.v[ 2 ].st ); + m4x4_transform_point( transform, tw.v[ 0 ].xyz ); + m4x4_transform_point( transform, tw.v[ 1 ].xyz ); + m4x4_transform_point( transform, tw.v[ 2 ].xyz ); + FilterTraceWindingIntoNodes_r( &tw, nodeNum ); + } + break; + + /* other surface types do not cast shadows */ + default: + break; + } + } +} + + + +/* +PopulateWithPicoModel() - ydnar +filters a picomodel's surfaces into the raytracing tree +*/ + +static void PopulateWithPicoModel( int castShadows, picoModel_t *model, m4x4_t transform ) +{ + int i, j, k, numSurfaces, numIndexes; + picoSurface_t *surface; + picoShader_t *shader; + picoVec_t *xyz, *st; + picoIndex_t *indexes; + traceInfo_t ti; + traceWinding_t tw; + + + /* dummy check */ + if( model == NULL || transform == NULL ) + return; + + /* get info */ + numSurfaces = PicoGetModelNumSurfaces( model ); + + /* walk the list of surfaces in this model and fill out the info structs */ + for( i = 0; i < numSurfaces; i++ ) + { + /* get surface */ + surface = PicoGetModelSurface( model, i ); + if( surface == NULL ) + continue; + + /* only handle triangle surfaces initially (fixme: support patches) */ + if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) + continue; + + /* get shader (fixme: support shader remapping) */ + shader = PicoGetSurfaceShader( surface ); + if( shader == NULL ) + continue; + ti.si = ShaderInfoForShader( PicoGetShaderName( shader ) ); + if( ti.si == NULL ) + continue; + + /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */ + if( (ti.si->compileFlags & C_NODRAW) ) + continue; + if( (ti.si->compileFlags & C_TRANSLUCENT) && + !(ti.si->compileFlags & C_ALPHASHADOW) && + !(ti.si->compileFlags & C_LIGHTFILTER) ) + continue; + + /* setup trace info */ + ti.castShadows = castShadows; + ti.surfaceNum = -1; + + /* setup trace winding */ + memset( &tw, 0, sizeof( tw ) ); + tw.infoNum = AddTraceInfo( &ti ); + tw.numVerts = 3; + + /* get info */ + numIndexes = PicoGetSurfaceNumIndexes( surface ); + indexes = PicoGetSurfaceIndexes( surface, 0 ); + + /* walk the triangle list */ + for( j = 0; j < numIndexes; j += 3, indexes += 3 ) + { + for( k = 0; k < 3; k++ ) + { + xyz = PicoGetSurfaceXYZ( surface, indexes[ k ] ); + st = PicoGetSurfaceST( surface, 0, indexes[ k ] ); + VectorCopy( xyz, tw.v[ k ].xyz ); + Vector2Copy( st, tw.v[ k ].st ); + m4x4_transform_point( transform, tw.v[ k ].xyz ); + } + FilterTraceWindingIntoNodes_r( &tw, headNodeNum ); + } + } +} + + + +/* +PopulateTraceNodes() - ydnar +fills the raytracing tree with world and entity occluders +*/ + +static void PopulateTraceNodes( void ) +{ + int i, m, frame, castShadows; + float temp; + entity_t *e; + const char *value; + picoModel_t *model; + vec3_t origin, scale, angles; + m4x4_t transform; + + + /* add worldspawn triangles */ + m4x4_identity( transform ); + PopulateWithBSPModel( &bspModels[ 0 ], transform ); + + /* walk each entity list */ + for( i = 1; i < numEntities; i++ ) + { + /* get entity */ + e = &entities[ i ]; + + /* get shadow flags */ + castShadows = ENTITY_CAST_SHADOWS; + GetEntityShadowFlags( e, NULL, &castShadows, NULL ); + + /* early out? */ + if( !castShadows ) + continue; + + /* get entity origin */ + GetVectorForKey( e, "origin", origin ); + + /* get scale */ + scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = 1.0f; + temp = FloatForKey( e, "modelscale" ); + if( temp != 0.0f ) + scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = temp; + value = ValueForKey( e, "modelscale_vec" ); + if( value[ 0 ] != '\0' ) + sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] ); + + /* get "angle" (yaw) or "angles" (pitch yaw roll) */ + angles[ 0 ] = angles[ 1 ] = angles[ 2 ] = 0.0f; + angles[ 2 ] = FloatForKey( e, "angle" ); + value = ValueForKey( e, "angles" ); + if( value[ 0 ] != '\0' ) + sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] ); + + /* set transform matrix (thanks spog) */ + m4x4_identity( transform ); + m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin ); + + /* hack: Stable-1_2 and trunk have differing row/column major matrix order + this transpose is necessary with Stable-1_2 + uncomment the following line with old m4x4_t (non 1.3/spog_branch) code */ + //% m4x4_transpose( transform ); + + /* get model */ + value = ValueForKey( e, "model" ); + + /* switch on model type */ + switch( value[ 0 ] ) + { + /* no model */ + case '\0': + break; + + /* bsp model */ + case '*': + m = atoi( &value[ 1 ] ); + if( m <= 0 || m >= numBSPModels ) + continue; + PopulateWithBSPModel( &bspModels[ m ], transform ); + break; + + /* external model */ + default: + frame = IntForKey( e, "_frame" ); + model = LoadModel( (char*) value, frame ); + if( model == NULL ) + continue; + PopulateWithPicoModel( castShadows, model, transform ); + continue; + } + + /* get model2 */ + value = ValueForKey( e, "model2" ); + + /* switch on model type */ + switch( value[ 0 ] ) + { + /* no model */ + case '\0': + break; + + /* bsp model */ + case '*': + m = atoi( &value[ 1 ] ); + if( m <= 0 || m >= numBSPModels ) + continue; + PopulateWithBSPModel( &bspModels[ m ], transform ); + break; + + /* external model */ + default: + frame = IntForKey( e, "_frame2" ); + model = LoadModel( (char*) value, frame ); + if( model == NULL ) + continue; + PopulateWithPicoModel( castShadows, model, transform ); + continue; + } + } +} + + + + +/* ------------------------------------------------------------------------------- + +trace initialization + +------------------------------------------------------------------------------- */ + +/* +SetupTraceNodes() - ydnar +creates a balanced bsp with axis-aligned splits for efficient raytracing +*/ + +void SetupTraceNodes( void ) +{ + /* note it */ + Sys_FPrintf( SYS_VRB, "--- SetupTraceNodes ---\n" ); + + /* find nodraw bit */ + noDrawContentFlags = noDrawSurfaceFlags = noDrawCompileFlags = 0; + ApplySurfaceParm( "nodraw", &noDrawContentFlags, &noDrawSurfaceFlags, &noDrawCompileFlags ); + + /* create the baseline raytracing tree from the bsp tree */ + headNodeNum = SetupTraceNodes_r( 0 ); + + /* create outside node for skybox surfaces */ + skyboxNodeNum = AllocTraceNode(); + + /* populate the tree with triangles from the world and shadow casting entities */ + PopulateTraceNodes(); + + /* create the raytracing bsp */ + if( loMem == qfalse ) + { + SubdivideTraceNode_r( headNodeNum, 0 ); + SubdivideTraceNode_r( skyboxNodeNum, 0 ); + } + + /* create triangles from the trace windings */ + TriangulateTraceNode_r( headNodeNum ); + TriangulateTraceNode_r( skyboxNodeNum ); + + /* emit some stats */ + //% Sys_FPrintf( SYS_VRB, "%9d original triangles\n", numOriginalTriangles ); + Sys_FPrintf( SYS_VRB, "%9d trace windings (%.2fMB)\n", numTraceWindings, (float) (numTraceWindings * sizeof( *traceWindings )) / (1024.0f * 1024.0f) ); + Sys_FPrintf( SYS_VRB, "%9d trace triangles (%.2fMB)\n", numTraceTriangles, (float) (numTraceTriangles * sizeof( *traceTriangles )) / (1024.0f * 1024.0f) ); + Sys_FPrintf( SYS_VRB, "%9d trace nodes (%.2fMB)\n", numTraceNodes, (float) (numTraceNodes * sizeof( *traceNodes )) / (1024.0f * 1024.0f) ); + Sys_FPrintf( SYS_VRB, "%9d leaf nodes (%.2fMB)\n", numTraceLeafNodes, (float) (numTraceLeafNodes * sizeof( *traceNodes )) / (1024.0f * 1024.0f) ); + //% Sys_FPrintf( SYS_VRB, "%9d average triangles per leaf node\n", numTraceTriangles / numTraceLeafNodes ); + Sys_FPrintf( SYS_VRB, "%9d average windings per leaf node\n", numTraceWindings / (numTraceLeafNodes + 1) ); + Sys_FPrintf( SYS_VRB, "%9d max trace depth\n", maxTraceDepth ); + + /* free trace windings */ + free( traceWindings ); + numTraceWindings = 0; + maxTraceWindings = 0; + deadWinding = -1; + + /* debug code: write out trace triangles to an alias obj file */ + #if 0 + { + int i, j; + FILE *file; + char filename[ 1024 ]; + traceWinding_t *tw; + + + /* open the file */ + strcpy( filename, source ); + StripExtension( filename ); + strcat( filename, ".lin" ); + Sys_Printf( "Opening light trace file %s...\n", filename ); + file = fopen( filename, "w" ); + if( file == NULL ) + Error( "Error opening %s for writing", filename ); + + /* walk node list */ + for( i = 0; i < numTraceWindings; i++ ) + { + tw = &traceWindings[ i ]; + for( j = 0; j < tw->numVerts + 1; j++ ) + fprintf( file, "%f %f %f\n", + tw->v[ j % tw->numVerts ].xyz[ 0 ], tw->v[ j % tw->numVerts ].xyz[ 1 ], tw->v[ j % tw->numVerts ].xyz[ 2 ] ); + } + + /* close it */ + fclose( file ); + } + #endif +} + + + +/* ------------------------------------------------------------------------------- + +raytracer + +------------------------------------------------------------------------------- */ + +/* +TraceTriangle() +based on code written by william 'spog' joseph +based on code originally written by tomas moller and ben trumbore, journal of graphics tools, 2(1):21-28, 1997 +*/ + +#define BARY_EPSILON 0.01f +#define ASLF_EPSILON 0.0001f /* so to not get double shadows */ +#define COPLANAR_EPSILON 0.25f //% 0.000001f +#define NEAR_SHADOW_EPSILON 1.5f //% 1.25f +#define SELF_SHADOW_EPSILON 0.5f + +qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace ) +{ + int i; + float tvec[ 3 ], pvec[ 3 ], qvec[ 3 ]; + float det, invDet, depth; + float u, v, w, s, t; + int is, it; + byte *pixel; + float shadow; + shaderInfo_t *si; + + + /* don't double-trace against sky */ + si = ti->si; + if( trace->compileFlags & si->compileFlags & C_SKY ) + return qfalse; + + /* receive shadows from worldspawn group only */ + if( trace->recvShadows == 1 ) + { + if( ti->castShadows != 1 ) + return qfalse; + } + + /* receive shadows from same group and worldspawn group */ + else if( trace->recvShadows > 1 ) + { + if( ti->castShadows != 1 && abs( ti->castShadows ) != abs( trace->recvShadows ) ) + return qfalse; + //% Sys_Printf( "%d:%d ", tt->castShadows, trace->recvShadows ); + } + + /* receive shadows from the same group only (< 0) */ + else + { + if( abs( ti->castShadows ) != abs( trace->recvShadows ) ) + return qfalse; + } + + /* begin calculating determinant - also used to calculate u parameter */ + CrossProduct( trace->direction, tt->edge2, pvec ); + + /* if determinant is near zero, trace lies in plane of triangle */ + det = DotProduct( tt->edge1, pvec ); + + /* the non-culling branch */ + if( det > -COPLANAR_EPSILON && det < COPLANAR_EPSILON ) + return qfalse; + invDet = 1.0f / det; + + /* calculate distance from first vertex to ray origin */ + VectorSubtract( trace->origin, tt->v[ 0 ].xyz, tvec ); + + /* calculate u parameter and test bounds */ + u = DotProduct( tvec, pvec ) * invDet; + if( u < -BARY_EPSILON || u > (1.0f + BARY_EPSILON) ) + return qfalse; + + /* prepare to test v parameter */ + CrossProduct( tvec, tt->edge1, qvec ); + + /* calculate v parameter and test bounds */ + v = DotProduct( trace->direction, qvec ) * invDet; + if( v < -BARY_EPSILON || (u + v) > (1.0f + BARY_EPSILON) ) + return qfalse; + + /* calculate t (depth) */ + depth = DotProduct( tt->edge2, qvec ) * invDet; + //% if( depth <= SELF_SHADOW_EPSILON || depth >= (trace->dist - SELF_SHADOW_EPSILON) ) + //% return qfalse; + if( depth <= trace->inhibitRadius || depth >= trace->distance ) + return qfalse; + + /* if hitpoint is really close to trace origin (sample point), then check for self-shadowing */ + if( depth <= SELF_SHADOW_EPSILON ) + { + /* don't self-shadow */ + for( i = 0; i < trace->numSurfaces; i++ ) + { + if( ti->surfaceNum == trace->surfaces[ i ] ) + return qfalse; + } + } + + /* stack compile flags */ + trace->compileFlags |= si->compileFlags; + + /* don't trace against sky */ + if( si->compileFlags & C_SKY ) + return qfalse; + + /* most surfaces are completely opaque */ + if( !(si->compileFlags & (C_ALPHASHADOW | C_LIGHTFILTER)) || + si->lightImage == NULL || si->lightImage->pixels == NULL ) + { + VectorClear( trace->color ); + trace->opaque = qtrue; + return qtrue; + } + + /* try to avoid double shadows near triangle seams */ + if( u < -ASLF_EPSILON || u > (1.0f + ASLF_EPSILON) || + v < -ASLF_EPSILON || (u + v) > (1.0f + ASLF_EPSILON) ) + return qfalse; + + /* calculate w parameter */ + w = 1.0f - (u + v); + + /* calculate st from uvw (barycentric) coordinates */ + s = w * tt->v[ 0 ].st[ 0 ] + u * tt->v[ 1 ].st[ 0 ] + v * tt->v[ 2 ].st[ 0 ]; + t = w * tt->v[ 0 ].st[ 1 ] + u * tt->v[ 1 ].st[ 1 ] + v * tt->v[ 2 ].st[ 1 ]; + s = s - floor( s ); + t = t - floor( t ); + is = s * si->lightImage->width; + it = t * si->lightImage->height; + + /* get pixel */ + pixel = si->lightImage->pixels + 4 * (it * si->lightImage->width + is); + + /* ydnar: color filter */ + if( si->compileFlags & C_LIGHTFILTER ) + { + /* filter by texture color */ + trace->color[ 0 ] *= ((1.0f / 255.0f) * pixel[ 0 ]); + trace->color[ 1 ] *= ((1.0f / 255.0f) * pixel[ 1 ]); + trace->color[ 2 ] *= ((1.0f / 255.0f) * pixel[ 2 ]); + } + + /* ydnar: alpha filter */ + if( si->compileFlags & C_ALPHASHADOW ) + { + /* filter by inverse texture alpha */ + shadow = (1.0f / 255.0f) * (255 - pixel[ 3 ]); + trace->color[ 0 ] *= shadow; + trace->color[ 1 ] *= shadow; + trace->color[ 2 ] *= shadow; + } + + /* check filter for opaque */ + if( trace->color[ 0 ] <= 0.001f && trace->color[ 1 ] <= 0.001f && trace->color[ 2 ] <= 0.001f ) + { + trace->opaque = qtrue; + return qtrue; + } + + /* continue tracing */ + return qfalse; +} + + + +/* +TraceWinding() - ydnar +temporary hack +*/ + +qboolean TraceWinding( traceWinding_t *tw, trace_t *trace ) +{ + int i; + traceTriangle_t tt; + + + /* initial setup */ + tt.infoNum = tw->infoNum; + tt.v[ 0 ] = tw->v[ 0 ]; + + /* walk vertex list */ + for( i = 1; i + 1 < tw->numVerts; i++ ) + { + /* set verts */ + tt.v[ 1 ] = tw->v[ i ]; + tt.v[ 2 ] = tw->v[ i + 1 ]; + + /* find vectors for two edges sharing the first vert */ + VectorSubtract( tt.v[ 1 ].xyz, tt.v[ 0 ].xyz, tt.edge1 ); + VectorSubtract( tt.v[ 2 ].xyz, tt.v[ 0 ].xyz, tt.edge2 ); + + /* trace it */ + if( TraceTriangle( &traceInfos[ tt.infoNum ], &tt, trace ) ) + return qtrue; + } + + /* done */ + return qfalse; +} + + + + +/* +TraceLine_r() +returns qtrue if something is hit and tracing can stop +*/ + +static qboolean TraceLine_r( int nodeNum, vec3_t origin, vec3_t end, trace_t *trace ) +{ + traceNode_t *node; + int side; + float front, back, frac; + vec3_t mid; + qboolean r; + + + /* bogus node number means solid, end tracing unless testing all */ + if( nodeNum < 0 ) + { + trace->passSolid = qtrue; + return qtrue; + } + + /* get node */ + node = &traceNodes[ nodeNum ]; + + /* solid? */ + if( node->type == TRACE_LEAF_SOLID ) + { + trace->passSolid = qtrue; + return qtrue; + } + + /* leafnode? */ + if( node->type < 0 ) + { + /* note leaf and return */ + if( node->numItems > 0 && trace->numTestNodes < MAX_TRACE_TEST_NODES ) + trace->testNodes[ trace->numTestNodes++ ] = nodeNum; + return qfalse; + } + + /* ydnar 2003-09-07: don't test branches of the bsp with nothing in them when testall is enabled */ + if( trace->testAll && node->numItems == 0 ) + return qfalse; + + /* classify beginning and end points */ + switch( node->type ) + { + case PLANE_X: + front = origin[ 0 ] - node->plane[ 3 ]; + back = end[ 0 ] - node->plane[ 3 ]; + break; + + case PLANE_Y: + front = origin[ 1 ] - node->plane[ 3 ]; + back = end[ 1 ] - node->plane[ 3 ]; + break; + + case PLANE_Z: + front = origin[ 2 ] - node->plane[ 3 ]; + back = end[ 2 ] - node->plane[ 3 ]; + break; + + default: + front = DotProduct( origin, node->plane ) - node->plane[ 3 ]; + back = DotProduct( end, node->plane ) - node->plane[ 3 ]; + break; + } + + /* entirely in front side? */ + if( front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON ) + return TraceLine_r( node->children[ 0 ], origin, end, trace ); + + /* entirely on back side? */ + if( front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON ) + return TraceLine_r( node->children[ 1 ], origin, end, trace ); + + /* select side */ + side = front < 0; + + /* calculate intercept point */ + frac = front / (front - back); + mid[ 0 ] = origin[ 0 ] + (end[ 0 ] - origin[ 0 ]) * frac; + mid[ 1 ] = origin[ 1 ] + (end[ 1 ] - origin[ 1 ]) * frac; + mid[ 2 ] = origin[ 2 ] + (end[ 2 ] - origin[ 2 ]) * frac; + + /* fixme: check inhibit radius, then solid nodes and ignore */ + + /* trace first side */ + r = TraceLine_r( node->children[ side ], origin, mid, trace ); + if( r ) + return r; + + /* trace other side */ + return TraceLine_r( node->children[ !side ], mid, end, trace ); +} + + + +/* +TraceLine() - ydnar +rewrote this function a bit :) +*/ + +void TraceLine( trace_t *trace ) +{ + int i, j; + traceNode_t *node; + traceTriangle_t *tt; + traceInfo_t *ti; + + + /* setup output (note: this code assumes the input data is completely filled out) */ + trace->passSolid = qfalse; + trace->opaque = qfalse; + trace->compileFlags = 0; + trace->numTestNodes = 0; + + /* early outs */ + if( !trace->recvShadows || !trace->testOcclusion || trace->distance <= 0.00001f ) + return; + + /* trace through nodes */ + TraceLine_r( headNodeNum, trace->origin, trace->end, trace ); + if( (trace->passSolid && !trace->testAll) ) + { + trace->opaque = qtrue; + return; + } + + /* skip surfaces? */ + if( noSurfaces ) + return; + + /* testall means trace through sky */ + if( trace->testAll && trace->numTestNodes < MAX_TRACE_TEST_NODES && + (trace->numSurfaces == 0 || surfaceInfos[ trace->surfaces[ 0 ] ].childSurfaceNum < 0) ) + { + //% trace->testNodes[ trace->numTestNodes++ ] = skyboxNodeNum; + TraceLine_r( skyboxNodeNum, trace->origin, trace->end, trace ); + } + + /* walk node list */ + for( i = 0; i < trace->numTestNodes; i++ ) + { + /* get node */ + node = &traceNodes[ trace->testNodes[ i ] ]; + + /* walk node item list */ + for( j = 0; j < node->numItems; j++ ) + { + tt = &traceTriangles[ node->items[ j ] ]; + ti = &traceInfos[ tt->infoNum ]; + if( TraceTriangle( ti, tt, trace ) ) + return; + //% if( TraceWinding( &traceWindings[ node->items[ j ] ], trace ) ) + //% return; + } + } +} + + + +/* +SetupTrace() - ydnar +sets up certain trace values +*/ + +float SetupTrace( trace_t *trace ) +{ + VectorSubtract( trace->end, trace->origin, trace->displacement ); + trace->distance = VectorNormalize( trace->displacement, trace->direction ); + return trace->distance; +} diff --git a/tools/quake3/q3map2/light_ydnar.c b/tools/quake3/q3map2/light_ydnar.c new file mode 100644 index 00000000..33be2071 --- /dev/null +++ b/tools/quake3/q3map2/light_ydnar.c @@ -0,0 +1,3129 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define LIGHT_YDNAR_C + + + +/* dependencies */ +#include "q3map2.h" + + + + +/* +ColorToBytes() +ydnar: moved to here 2001-02-04 +*/ + +void ColorToBytes( const float *color, byte *colorBytes, float scale ) +{ + float max; + vec3_t sample; + + + /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */ + if( scale <= 0.0f ) + scale = 1.0f; + + /* make a local copy */ + VectorScale( color, scale, sample ); + + /* handle negative light */ + if( sample[ 0 ] < 0.0f ) + sample[ 0 ] = 0.0f; + if( sample[ 1 ] < 0.0f ) + sample[ 1 ] = 0.0f; + if( sample[ 2 ] < 0.0f ) + sample[ 2 ] = 0.0f; + + /* clamp with color normalization */ + max = sample[ 0 ]; + if( sample[ 1 ] > max ) + max = sample[ 1 ]; + if( sample[ 2 ] > max ) + max = sample[ 2 ]; + if( max > 255.0f ) + VectorScale( sample, (255.0f / max), sample ); + + /* store it off */ + colorBytes[ 0 ] = sample[ 0 ]; + colorBytes[ 1 ] = sample[ 1 ]; + colorBytes[ 2 ] = sample[ 2 ]; +} + + + +/* ------------------------------------------------------------------------------- + +this section deals with phong shading (normal interpolation across brush faces) + +------------------------------------------------------------------------------- */ + +/* +SmoothNormals() +smooths together coincident vertex normals across the bsp +*/ + +#define MAX_SAMPLES 256 +#define THETA_EPSILON 0.000001 +#define EQUAL_NORMAL_EPSILON 0.01 + +void SmoothNormals( void ) +{ + int i, j, k, f, cs, numVerts, numVotes, fOld, start; + float shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle; + bspDrawSurface_t *ds; + shaderInfo_t *si; + float *shadeAngles; + byte *smoothed; + vec3_t average, diff; + int indexes[ MAX_SAMPLES ]; + vec3_t votes[ MAX_SAMPLES ]; + + + /* allocate shade angle table */ + shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) ); + memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) ); + + /* allocate smoothed table */ + cs = (numBSPDrawVerts / 8) + 1; + smoothed = safe_malloc( cs ); + memset( smoothed, 0, cs ); + + /* set default shade angle */ + defaultShadeAngle = DEG2RAD( shadeAngleDegrees ); + maxShadeAngle = 0; + + /* run through every surface and flag verts belonging to non-lightmapped surfaces + and set per-vertex smoothing angle */ + for( i = 0; i < numBSPDrawSurfaces; i++ ) + { + /* get drawsurf */ + ds = &bspDrawSurfaces[ i ]; + + /* get shader for shade angle */ + si = surfaceInfos[ i ].si; + if( si->shadeAngleDegrees ) + shadeAngle = DEG2RAD( si->shadeAngleDegrees ); + else + shadeAngle = defaultShadeAngle; + if( shadeAngle > maxShadeAngle ) + maxShadeAngle = shadeAngle; + + /* flag its verts */ + for( j = 0; j < ds->numVerts; j++ ) + { + f = ds->firstVert + j; + shadeAngles[ f ] = shadeAngle; + if( ds->surfaceType == MST_TRIANGLE_SOUP ) + smoothed[ f >> 3 ] |= (1 << (f & 7)); + } + + /* ydnar: optional force-to-trisoup */ + if( trisoup && ds->surfaceType == MST_PLANAR ) + { + ds->surfaceType = MST_TRIANGLE_SOUP; + ds->lightmapNum[ 0 ] = -3; + } + } + + /* bail if no surfaces have a shade angle */ + if( maxShadeAngle == 0 ) + { + free( shadeAngles ); + free( smoothed ); + return; + } + + /* init pacifier */ + fOld = -1; + start = I_FloatTime(); + + /* go through the list of vertexes */ + for( i = 0; i < numBSPDrawVerts; i++ ) + { + /* print pacifier */ + f = 10 * i / numBSPDrawVerts; + if( f != fOld ) + { + fOld = f; + Sys_Printf( "%i...", f ); + } + + /* already smoothed? */ + if( smoothed[ i >> 3 ] & (1 << (i & 7)) ) + continue; + + /* clear */ + VectorClear( average ); + numVerts = 0; + numVotes = 0; + + /* build a table of coincident vertexes */ + for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ ) + { + /* already smoothed? */ + if( smoothed[ j >> 3 ] & (1 << (j & 7)) ) + continue; + + /* test vertexes */ + if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse ) + continue; + + /* use smallest shade angle */ + shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]); + + /* check shade angle */ + dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal ); + if( dot > 1.0 ) + dot = 1.0; + else if( dot < -1.0 ) + dot = -1.0; + testAngle = acos( dot ) + THETA_EPSILON; + if( testAngle >= shadeAngle ) + { + //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) ); + continue; + } + //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) ); + + /* add to the list */ + indexes[ numVerts++ ] = j; + + /* flag vertex */ + smoothed[ j >> 3 ] |= (1 << (j & 7)); + + /* see if this normal has already been voted */ + for( k = 0; k < numVotes; k++ ) + { + VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff ); + if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) + break; + } + + /* add a new vote? */ + if( k == numVotes && numVotes < MAX_SAMPLES ) + { + VectorAdd( average, bspDrawVerts[ j ].normal, average ); + VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] ); + numVotes++; + } + } + + /* don't average for less than 2 verts */ + if( numVerts < 2 ) + continue; + + /* average normal */ + if( VectorNormalize( average, average ) > 0 ) + { + /* smooth */ + for( j = 0; j < numVerts; j++ ) + VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal ); + } + } + + /* free the tables */ + free( shadeAngles ); + free( smoothed ); + + /* print time */ + Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) ); +} + + + +/* ------------------------------------------------------------------------------- + +this section deals with phong shaded lightmap tracing + +------------------------------------------------------------------------------- */ + +/* 9th rewrite (recursive subdivision of a lightmap triangle) */ + +/* +CalcTangentVectors() +calculates the st tangent vectors for normalmapping +*/ + +static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv ) +{ + int i; + float bb, s, t; + vec3_t bary; + + + /* calculate barycentric basis for the triangle */ + bb = (dv[ 1 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 2 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]) - (dv[ 2 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 1 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]); + if( fabs( bb ) < 0.00000001f ) + return qfalse; + + /* do each vertex */ + for( i = 0; i < numVerts; i++ ) + { + /* calculate s tangent vector */ + s = dv[ i ]->st[ 0 ] + 10.0f; + t = dv[ i ]->st[ 1 ]; + bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb; + bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb; + bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb; + + stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ]; + stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ]; + stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ]; + + VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] ); + VectorNormalize( stv[ i ], stv[ i ] ); + + /* calculate t tangent vector */ + s = dv[ i ]->st[ 0 ]; + t = dv[ i ]->st[ 1 ] + 10.0f; + bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb; + bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb; + bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb; + + ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ]; + ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ]; + ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ]; + + VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] ); + VectorNormalize( ttv[ i ], ttv[ i ] ); + + /* debug code */ + //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, + //% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] ); + } + + /* return to caller */ + return qtrue; +} + + + + +/* +PerturbNormal() +perterbs the normal by the shader's normalmap in tangent space +*/ + +static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] ) +{ + int i; + vec4_t bump; + + + /* passthrough */ + VectorCopy( dv->normal, pNormal ); + + /* sample normalmap */ + if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse ) + return; + + /* remap sampled normal from [0,255] to [-1,-1] */ + for( i = 0; i < 3; i++ ) + bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f); + + /* scale tangent vectors and add to original normal */ + VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal ); + VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal ); + VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal ); + + /* renormalize and return */ + VectorNormalize( pNormal, pNormal ); +} + + + +/* +MapSingleLuxel() +maps a luxel for triangle bv at +*/ + +#define NUDGE 0.5f +#define BOGUS_NUDGE -99999.0f + +static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] ) +{ + int i, x, y, numClusters, *clusters, pointCluster, *cluster; + float *luxel, *origin, *normal, d, lightmapSampleOffset; + shaderInfo_t *si; + vec3_t pNormal; + vec3_t vecs[ 3 ]; + vec3_t nudged; + float *nudge; + static float nudges[][ 2 ] = + { + //%{ 0, 0 }, /* try center first */ + { -NUDGE, 0 }, /* left */ + { NUDGE, 0 }, /* right */ + { 0, NUDGE }, /* up */ + { 0, -NUDGE }, /* down */ + { -NUDGE, NUDGE }, /* left/up */ + { NUDGE, -NUDGE }, /* right/down */ + { NUDGE, NUDGE }, /* right/up */ + { -NUDGE, -NUDGE }, /* left/down */ + { BOGUS_NUDGE, BOGUS_NUDGE } + }; + + + /* find luxel xy coords (fixme: subtract 0.5?) */ + x = dv->lightmap[ 0 ][ 0 ]; + y = dv->lightmap[ 0 ][ 1 ]; + if( x < 0 ) + x = 0; + else if( x >= lm->sw ) + x = lm->sw - 1; + if( y < 0 ) + y = 0; + else if( y >= lm->sh ) + y = lm->sh - 1; + + /* set shader and cluster list */ + if( info != NULL ) + { + si = info->si; + numClusters = info->numSurfaceClusters; + clusters = &surfaceClusters[ info->firstSurfaceCluster ]; + } + else + { + si = NULL; + numClusters = 0; + clusters = NULL; + } + + /* get luxel, origin, cluster, and normal */ + luxel = SUPER_LUXEL( 0, x, y ); + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); + cluster = SUPER_CLUSTER( x, y ); + + /* don't attempt to remap occluded luxels for planar surfaces */ + if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL ) + return (*cluster); + + /* only average the normal for premapped luxels */ + else if( (*cluster) >= 0 ) + { + /* do bumpmap calculations */ + if( stv != NULL ) + PerturbNormal( dv, si, pNormal, stv, ttv ); + else + VectorCopy( dv->normal, pNormal ); + + /* add the additional normal data */ + VectorAdd( normal, pNormal, normal ); + luxel[ 3 ] += 1.0f; + return (*cluster); + } + + /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */ + + /* get origin */ + + /* axial lightmap projection */ + if( lm->vecs != NULL ) + { + /* calculate an origin for the sample from the lightmap vectors */ + VectorCopy( lm->origin, origin ); + for( i = 0; i < 3; i++ ) + { + /* add unless it's the axis, which is taken care of later */ + if( i == lm->axisNum ) + continue; + origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]); + } + + /* project the origin onto the plane */ + d = DotProduct( origin, plane ) - plane[ 3 ]; + d /= plane[ lm->axisNum ]; + origin[ lm->axisNum ] -= d; + } + + /* non axial lightmap projection (explicit xyz) */ + else + VectorCopy( dv->xyz, origin ); + + /* planar surfaces have precalculated lightmap vectors for nudging */ + if( lm->plane != NULL ) + { + VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] ); + VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] ); + VectorCopy( lm->plane, vecs[ 2 ] ); + } + + /* non-planar surfaces must calculate them */ + else + { + if( plane != NULL ) + VectorCopy( plane, vecs[ 2 ] ); + else + VectorCopy( dv->normal, vecs[ 2 ] ); + MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] ); + } + + /* push the origin off the surface a bit */ + if( si != NULL ) + lightmapSampleOffset = si->lightmapSampleOffset; + else + lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET; + if( lm->axisNum < 0 ) + VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin ); + else if( vecs[ 2 ][ lm->axisNum ] < 0.0f ) + origin[ lm->axisNum ] -= lightmapSampleOffset; + else + origin[ lm->axisNum ] += lightmapSampleOffset; + + /* get cluster */ + pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters ); + + /* another retarded hack, storing nudge count in luxel[ 1 ] */ + luxel[ 1 ] = 0.0f; + + /* point in solid? */ + if( pointCluster < 0 ) + { + /* nudge the the location around */ + nudge = nudges[ 0 ]; + while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 ) + { + /* nudge the vector around a bit */ + for( i = 0; i < 3; i++ ) + { + /* set nudged point*/ + nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]); + } + nudge += 2; + + /* get pvs cluster */ + pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 ); + if( pointCluster >= 0 ) + VectorCopy( nudged, origin ); + luxel[ 1 ] += 1.0f; + } + } + + /* as a last resort, if still in solid, try drawvert origin offset by normal */ + if( pointCluster < 0 && si != NULL ) + { + VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged ); + pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); + if( pointCluster >= 0 ) + VectorCopy( nudged, origin ); + luxel[ 1 ] += 1.0f; + } + + /* valid? */ + if( pointCluster < 0 ) + { + (*cluster) = CLUSTER_OCCLUDED; + VectorClear( origin ); + VectorClear( normal ); + numLuxelsOccluded++; + return (*cluster); + } + + /* debug code */ + //% Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] ); + + /* do bumpmap calculations */ + if( stv ) + PerturbNormal( dv, si, pNormal, stv, ttv ); + else + VectorCopy( dv->normal, pNormal ); + + /* store the cluster and normal */ + (*cluster) = pointCluster; + VectorCopy( pNormal, normal ); + + /* store explicit mapping pass and implicit mapping pass */ + luxel[ 0 ] = pass; + luxel[ 3 ] = 1.0f; + + /* add to count */ + numLuxelsMapped++; + + /* return ok */ + return (*cluster); +} + + + +/* +MapTriangle_r() +recursively subdivides a triangle until its edges are shorter +than the distance between two luxels (thanks jc :) +*/ + +static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] ) +{ + bspDrawVert_t mid, *dv2[ 3 ]; + int max; + + + /* map the vertexes */ + #if 0 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); + #endif + + /* subdivide calc */ + { + int i; + float *a, *b, dx, dy, dist, maxDist; + + + /* find the longest edge and split it */ + max = -1; + maxDist = 0; + for( i = 0; i < 3; i++ ) + { + /* get verts */ + a = dv[ i ]->lightmap[ 0 ]; + b = dv[ (i + 1) % 3 ]->lightmap[ 0 ]; + + /* get dists */ + dx = a[ 0 ] - b[ 0 ]; + dy = a[ 1 ] - b[ 1 ]; + dist = (dx * dx) + (dy * dy); //% sqrt( (dx * dx) + (dy * dy) ); + + /* longer? */ + if( dist > maxDist ) + { + maxDist = dist; + max = i; + } + } + + /* try to early out */ + if( max < 0 || maxDist <= subdivideThreshold ) /* ydnar: was i < 0 instead of max < 0 (?) */ + return; + } + + /* split the longest edge and map it */ + LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid ); + MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv ); + + /* push the point up a little bit to account for fp creep (fixme: revisit this) */ + //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz ); + + /* recurse to first triangle */ + VectorCopy( dv, dv2 ); + dv2[ max ] = ∣ + MapTriangle_r( lm, info, dv2, plane, stv, ttv ); + + /* recurse to second triangle */ + VectorCopy( dv, dv2 ); + dv2[ (max + 1) % 3 ] = ∣ + MapTriangle_r( lm, info, dv2, plane, stv, ttv ); +} + + + +/* +MapTriangle() +seed function for MapTriangle_r() +requires a cw ordered triangle +*/ + +static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial ) +{ + int i; + vec4_t plane; + vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ]; + + + /* get plane if possible */ + if( lm->plane != NULL ) + { + VectorCopy( lm->plane, plane ); + plane[ 3 ] = lm->plane[ 3 ]; + } + + /* otherwise make one from the points */ + else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse ) + return qfalse; + + /* check to see if we need to calculate texture->world tangent vectors */ + if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) ) + { + stv = stvStatic; + ttv = ttvStatic; + } + else + { + stv = NULL; + ttv = NULL; + } + + /* map the vertexes */ + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); + + /* 2002-11-20: prefer axial triangle edges */ + if( mapNonAxial ) + { + /* subdivide the triangle */ + MapTriangle_r( lm, info, dv, plane, stv, ttv ); + return qtrue; + } + + for( i = 0; i < 3; i++ ) + { + float *a, *b; + bspDrawVert_t *dv2[ 3 ]; + + + /* get verts */ + a = dv[ i ]->lightmap[ 0 ]; + b = dv[ (i + 1) % 3 ]->lightmap[ 0 ]; + + /* make degenerate triangles for mapping edges */ + if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f ) + { + dv2[ 0 ] = dv[ i ]; + dv2[ 1 ] = dv[ (i + 1) % 3 ]; + dv2[ 2 ] = dv[ (i + 1) % 3 ]; + + /* map the degenerate triangle */ + MapTriangle_r( lm, info, dv2, plane, stv, ttv ); + } + } + + return qtrue; +} + + + +/* +MapQuad_r() +recursively subdivides a quad until its edges are shorter +than the distance between two luxels +*/ + +static void MapQuad_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ], vec4_t plane, vec3_t stv[ 4 ], vec3_t ttv[ 4 ] ) +{ + bspDrawVert_t mid[ 2 ], *dv2[ 4 ]; + int max; + + + /* subdivide calc */ + { + int i; + float *a, *b, dx, dy, dist, maxDist; + + + /* find the longest edge and split it */ + max = -1; + maxDist = 0; + for( i = 0; i < 4; i++ ) + { + /* get verts */ + a = dv[ i ]->lightmap[ 0 ]; + b = dv[ (i + 1) % 4 ]->lightmap[ 0 ]; + + /* get dists */ + dx = a[ 0 ] - b[ 0 ]; + dy = a[ 1 ] - b[ 1 ]; + dist = (dx * dx) + (dy * dy); //% sqrt( (dx * dx) + (dy * dy) ); + + /* longer? */ + if( dist > maxDist ) + { + maxDist = dist; + max = i; + } + } + + /* try to early out */ + if( max < 0 || maxDist <= subdivideThreshold ) + return; + } + + /* we only care about even/odd edges */ + max &= 1; + + /* split the longest edges */ + LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] ); + LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] ); + + /* map the vertexes */ + MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv ); + + /* 0 and 2 */ + if( max == 0 ) + { + /* recurse to first quad */ + dv2[ 0 ] = dv[ 0 ]; + dv2[ 1 ] = &mid[ 0 ]; + dv2[ 2 ] = &mid[ 1 ]; + dv2[ 3 ] = dv[ 3 ]; + MapQuad_r( lm, info, dv2, plane, stv, ttv ); + + /* recurse to second quad */ + dv2[ 0 ] = &mid[ 0 ]; + dv2[ 1 ] = dv[ 1 ]; + dv2[ 2 ] = dv[ 2 ]; + dv2[ 3 ] = &mid[ 1 ]; + MapQuad_r( lm, info, dv2, plane, stv, ttv ); + } + + /* 1 and 3 */ + else + { + /* recurse to first quad */ + dv2[ 0 ] = dv[ 0 ]; + dv2[ 1 ] = dv[ 1 ]; + dv2[ 2 ] = &mid[ 0 ]; + dv2[ 3 ] = &mid[ 1 ]; + MapQuad_r( lm, info, dv2, plane, stv, ttv ); + + /* recurse to second quad */ + dv2[ 0 ] = &mid[ 1 ]; + dv2[ 1 ] = &mid[ 0 ]; + dv2[ 2 ] = dv[ 2 ]; + dv2[ 3 ] = dv[ 3 ]; + MapQuad_r( lm, info, dv2, plane, stv, ttv ); + } +} + + + +/* +MapQuad() +seed function for MapQuad_r() +requires a cw ordered triangle quad +*/ + +#define QUAD_PLANAR_EPSILON 0.5f + +static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] ) +{ + float dist; + vec4_t plane; + vec3_t *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ]; + + + /* get plane if possible */ + if( lm->plane != NULL ) + { + VectorCopy( lm->plane, plane ); + plane[ 3 ] = lm->plane[ 3 ]; + } + + /* otherwise make one from the points */ + else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse ) + return qfalse; + + /* 4th point must fall on the plane */ + dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ]; + if( fabs( dist ) > QUAD_PLANAR_EPSILON ) + return qfalse; + + /* check to see if we need to calculate texture->world tangent vectors */ + if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) ) + { + stv = stvStatic; + ttv = ttvStatic; + } + else + { + stv = NULL; + ttv = NULL; + } + + /* map the vertexes */ + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv ); + + /* subdivide the quad */ + MapQuad_r( lm, info, dv, plane, stv, ttv ); + return qtrue; +} + + + +/* +MapRawLightmap() +maps the locations, normals, and pvs clusters for a raw lightmap +*/ + +#define VectorDivide( in, d, out ) VectorScale( in, (1.0f / (d)), out ) //% (out)[ 0 ] = (in)[ 0 ] / (d), (out)[ 1 ] = (in)[ 1 ] / (d), (out)[ 2 ] = (in)[ 2 ] / (d) + +void MapRawLightmap( int rawLightmapNum ) +{ + int n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial; + float *luxel, *origin, *normal, samples, radius, pass; + rawLightmap_t *lm; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + mesh_t src, *subdivided, *mesh; + bspDrawVert_t *verts, *dv[ 4 ], fake; + + + /* bail if this number exceeds the number of raw lightmaps */ + if( rawLightmapNum >= numRawLightmaps ) + return; + + /* get lightmap */ + lm = &rawLightmaps[ rawLightmapNum ]; + + /* ----------------------------------------------------------------- + map referenced surfaces onto the raw lightmap + ----------------------------------------------------------------- */ + + /* walk the list of surfaces on this raw lightmap */ + for( n = 0; n < lm->numLightSurfaces; n++ ) + { + /* with > 1 surface per raw lightmap, clear occluded */ + if( n > 0 ) + { + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + if( *cluster < 0 ) + *cluster = CLUSTER_UNMAPPED; + } + } + } + + /* get surface */ + num = lightSurfaces[ lm->firstLightSurface + n ]; + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* bail if no lightmap to calculate */ + if( info->lm != lm ) + { + Sys_Printf( "!" ); + continue; + } + + /* map the surface onto the lightmap origin/cluster/normal buffers */ + switch( ds->surfaceType ) + { + case MST_PLANAR: + /* get verts */ + verts = yDrawVerts + ds->firstVert; + + /* map the triangles */ + for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ ) + { + for( i = 0; i < ds->numIndexes; i += 3 ) + { + dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ]; + dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ]; + dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + } + } + break; + + case MST_PATCH: + /* make a mesh from the drawsurf */ + src.width = ds->patchWidth; + src.height = ds->patchHeight; + src.verts = &yDrawVerts[ ds->firstVert ]; + //% subdivided = SubdivideMesh( src, 8, 512 ); + subdivided = SubdivideMesh2( src, info->patchIterations ); + + /* fit it to the curve and remove colinear verts on rows/columns */ + PutMeshOnCurve( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + + /* get verts */ + verts = mesh->verts; + + /* debug code */ + #if 0 + if( lm->plane ) + { + Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n", + lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ], + lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ], + lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] ); + } + #endif + + /* map the mesh quads */ + #if 0 + + for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ ) + { + for( y = 0; y < (mesh->height - 1); y++ ) + { + for( x = 0; x < (mesh->width - 1); x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ + + /* set radix */ + r = (x + y) & 1; + + /* get drawverts and map first triangle */ + dv[ 0 ] = &verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &verts[ pw[ r + 2 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + + /* get drawverts and map second triangle */ + dv[ 0 ] = &verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &verts[ pw[ r + 2 ] ]; + dv[ 2 ] = &verts[ pw[ r + 3 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + } + } + } + + #else + + for( y = 0; y < (mesh->height - 1); y++ ) + { + for( x = 0; x < (mesh->width - 1); x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = pw[ 0 ]; + + /* set radix */ + r = (x + y) & 1; + + /* attempt to map quad first */ + dv[ 0 ] = &verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &verts[ pw[ r + 2 ] ]; + dv[ 3 ] = &verts[ pw[ r + 3 ] ]; + if( MapQuad( lm, info, dv ) ) + continue; + + /* get drawverts and map first triangle */ + MapTriangle( lm, info, dv, mapNonAxial ); + + /* get drawverts and map second triangle */ + dv[ 1 ] = &verts[ pw[ r + 2 ] ]; + dv[ 2 ] = &verts[ pw[ r + 3 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + } + } + + #endif + + /* free the mesh */ + FreeMesh( mesh ); + break; + + default: + break; + } + } + + /* ----------------------------------------------------------------- + average and clean up luxel normals + ----------------------------------------------------------------- */ + + /* walk the luxels */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get luxel */ + luxel = SUPER_LUXEL( 0, x, y ); + normal = SUPER_NORMAL( x, y ); + cluster = SUPER_CLUSTER( x, y ); + + /* only look at mapped luxels */ + if( *cluster < 0 ) + continue; + + /* the normal data could be the sum of multiple samples */ + if( luxel[ 3 ] > 1.0f ) + VectorNormalize( normal, normal ); + + /* mark this luxel as having only one normal */ + luxel[ 3 ] = 1.0f; + } + } + + /* non-planar surfaces stop here */ + if( lm->plane == NULL ) + return; + + /* ----------------------------------------------------------------- + map occluded or unuxed luxels + ----------------------------------------------------------------- */ + + /* walk the luxels */ + radius = floor( superSample / 2 ); + radius = radius > 0 ? radius : 1.0f; + radius += 1.0f; + for( pass = 2.0f; pass <= radius; pass += 1.0f ) + { + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get luxel */ + luxel = SUPER_LUXEL( 0, x, y ); + normal = SUPER_NORMAL( x, y ); + cluster = SUPER_CLUSTER( x, y ); + + /* only look at unmapped luxels */ + if( *cluster != CLUSTER_UNMAPPED ) + continue; + + /* divine a normal and origin from neighboring luxels */ + VectorClear( fake.xyz ); + VectorClear( fake.normal ); + fake.lightmap[ 0 ][ 0 ] = x; //% 0.0001 + x; + fake.lightmap[ 0 ][ 1 ] = y; //% 0.0001 + y; + samples = 0.0f; + for( sy = (y - 1); sy <= (y + 1); sy++ ) + { + if( sy < 0 || sy >= lm->sh ) + continue; + + for( sx = (x - 1); sx <= (x + 1); sx++ ) + { + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) ) + continue; + + /* get neighboring luxel */ + luxel = SUPER_LUXEL( 0, sx, sy ); + origin = SUPER_ORIGIN( sx, sy ); + normal = SUPER_NORMAL( sx, sy ); + cluster = SUPER_CLUSTER( sx, sy ); + + /* only consider luxels mapped in previous passes */ + if( *cluster < 0 || luxel[ 0 ] >= pass ) + continue; + + /* add its distinctiveness to our own */ + VectorAdd( fake.xyz, origin, fake.xyz ); + VectorAdd( fake.normal, normal, fake.normal ); + samples += luxel[ 3 ]; + } + } + + /* any samples? */ + if( samples == 0.0f ) + continue; + + /* average */ + VectorDivide( fake.xyz, samples, fake.xyz ); + //% VectorDivide( fake.normal, samples, fake.normal ); + if( VectorNormalize( fake.normal, fake.normal ) == 0.0f ) + continue; + + /* map the fake vert */ + MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL ); + } + } + } + + /* ----------------------------------------------------------------- + average and clean up luxel normals + ----------------------------------------------------------------- */ + + /* walk the luxels */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get luxel */ + luxel = SUPER_LUXEL( 0, x, y ); + normal = SUPER_NORMAL( x, y ); + cluster = SUPER_CLUSTER( x, y ); + + /* only look at mapped luxels */ + if( *cluster < 0 ) + continue; + + /* the normal data could be the sum of multiple samples */ + if( luxel[ 3 ] > 1.0f ) + VectorNormalize( normal, normal ); + + /* mark this luxel as having only one normal */ + luxel[ 3 ] = 1.0f; + } + } + + /* debug code */ + #if 0 + Sys_Printf( "\n" ); + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + vec3_t mins, maxs; + + + cluster = SUPER_CLUSTER( x, y ); + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); + luxel = SUPER_LUXEL( x, y ); + + if( *cluster < 0 ) + continue; + + /* check if within the bounding boxes of all surfaces referenced */ + ClearBounds( mins, maxs ); + for( n = 0; n < lm->numLightSurfaces; n++ ) + { + int TOL; + info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ]; + TOL = info->sampleSize + 2; + AddPointToBounds( info->mins, mins, maxs ); + AddPointToBounds( info->maxs, mins, maxs ); + if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) && + origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) && + origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) ) + break; + } + + /* inside? */ + if( n < lm->numLightSurfaces ) + continue; + + /* report bogus origin */ + Sys_Printf( "%6d [%2d,%2d] (%4d): XYZ(%+4.1f %+4.1f %+4.1f) LO(%+4.1f %+4.1f %+4.1f) HI(%+4.1f %+4.1f %+4.1f) <%3.0f>\n", + rawLightmapNum, x, y, *cluster, + origin[ 0 ], origin[ 1 ], origin[ 2 ], + mins[ 0 ], mins[ 1 ], mins[ 2 ], + maxs[ 0 ], maxs[ 1 ], maxs[ 2 ], + luxel[ 3 ] ); + } + } + #endif +} + + + +/* +SubmapRawLuxel() +calculates the pvs cluster, origin, normal of a sub-luxel +*/ + +static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal ) +{ + int i, *cluster, *cluster2; + float *origin, *origin2, *normal; //% , *normal2; + vec3_t originVecs[ 2 ]; //% , normalVecs[ 2 ]; + + + /* calulate x vector */ + if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) ) + { + cluster = SUPER_CLUSTER( x, y ); + origin = SUPER_ORIGIN( x, y ); + //% normal = SUPER_NORMAL( x, y ); + cluster2 = SUPER_CLUSTER( x + 1, y ); + origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y ); + //% normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y ); + } + else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) ) + { + cluster = SUPER_CLUSTER( x - 1, y ); + origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y ); + //% normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y ); + cluster2 = SUPER_CLUSTER( x, y ); + origin2 = SUPER_ORIGIN( x, y ); + //% normal2 = SUPER_NORMAL( x, y ); + } + else + Sys_Printf( "WARNING: Spurious lightmap S vector\n" ); + + VectorSubtract( origin2, origin, originVecs[ 0 ] ); + //% VectorSubtract( normal2, normal, normalVecs[ 0 ] ); + + /* calulate y vector */ + if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) ) + { + cluster = SUPER_CLUSTER( x, y ); + origin = SUPER_ORIGIN( x, y ); + //% normal = SUPER_NORMAL( x, y ); + cluster2 = SUPER_CLUSTER( x, y + 1 ); + origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 ); + //% normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 ); + } + else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) ) + { + cluster = SUPER_CLUSTER( x, y - 1 ); + origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 ); + //% normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 ); + cluster2 = SUPER_CLUSTER( x, y ); + origin2 = SUPER_ORIGIN( x, y ); + //% normal2 = SUPER_NORMAL( x, y ); + } + else + Sys_Printf( "WARNING: Spurious lightmap T vector\n" ); + + VectorSubtract( origin2, origin, originVecs[ 1 ] ); + //% VectorSubtract( normal2, normal, normalVecs[ 1 ] ); + + /* calculate new origin */ + //% VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin ); + //% VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin ); + for( i = 0; i < 3; i++ ) + sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]); + + /* get cluster */ + *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters ); + if( *sampleCluster < 0 ) + return qfalse; + + /* calculate new normal */ + //% VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal ); + //% VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal ); + //% if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f ) + //% return qfalse; + normal = SUPER_NORMAL( x, y ); + VectorCopy( normal, sampleNormal ); + + /* return ok */ + return qtrue; +} + + +/* +SubsampleRawLuxel_r() +recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached +*/ + +void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel ) +{ + int b, samples, mapped, lighted; + int cluster[ 4 ]; + vec4_t luxel[ 4 ]; + vec3_t origin[ 4 ], normal[ 4 ]; + float biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } }; + vec3_t color, total; + + + /* limit check */ + if( lightLuxel[ 3 ] >= lightSamples ) + return; + + /* setup */ + VectorClear( total ); + mapped = 0; + lighted = 0; + + /* make 2x2 subsample stamp */ + for( b = 0; b < 4; b++ ) + { + /* set origin */ + VectorCopy( sampleOrigin, origin[ b ] ); + + /* calculate position */ + if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) ) + { + cluster[ b ] = -1; + continue; + } + mapped++; + + /* increment sample count */ + luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f; + + /* setup trace */ + trace->cluster = *cluster; + VectorCopy( origin[ b ], trace->origin ); + VectorCopy( normal[ b ], trace->normal ); + + /* sample light */ + //% LightContributionToSample( light, cluster[ b ], origin[ b ], normal[ b ], luxel[ b ], qtrue, qfalse, lm->numLightSurfaces, &lightSurfaces[ lm->firstLightSurface ] ); + LightContributionToSample( trace ); + + /* add to totals (fixme: make contrast function) */ + VectorCopy( trace->color, luxel[ b ] ); + VectorAdd( total, trace->color, total ); + if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f ) + lighted++; + } + + /* subsample further? */ + if( (lightLuxel[ 3 ] + 1.0f) < lightSamples && + (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) && + lighted != 0 && lighted != mapped ) + { + for( b = 0; b < 4; b++ ) + { + if( cluster[ b ] < 0 ) + continue; + SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] ); + } + } + + /* average */ + //% VectorClear( color ); + //% samples = 0; + VectorCopy( lightLuxel, color ); + samples = 1; + for( b = 0; b < 4; b++ ) + { + if( cluster[ b ] < 0 ) + continue; + VectorAdd( color, luxel[ b ], color ); + samples++; + } + + /* add to luxel */ + if( samples > 0 ) + { + /* average */ + color[ 0 ] /= samples; + color[ 1 ] /= samples; + color[ 2 ] /= samples; + + /* add to color */ + VectorCopy( color, lightLuxel ); + lightLuxel[ 3 ] += 1.0f; + } +} + + + +/* +IlluminateRawLightmap() +illuminates the luxels +*/ + +#define LIGHT_LUXEL( x, y ) (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) + +void IlluminateRawLightmap( int rawLightmapNum ) +{ + int i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum; + int *cluster, *cluster2, mapped, lighted, totalLighted; + rawLightmap_t *lm; + surfaceInfo_t *info; + qboolean filterColor, filterDir; + float brightness; + float *origin, *normal, *luxel, *luxel2, *deluxel, *deluxel2; + float *lightLuxels, *lightLuxel, samples, filterRadius, weight; + vec3_t color, averageColor, averageDir, total, temp, temp2; + float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; + trace_t trace; + + + /* bail if this number exceeds the number of raw lightmaps */ + if( rawLightmapNum >= numRawLightmaps ) + return; + + /* get lightmap */ + lm = &rawLightmaps[ rawLightmapNum ]; + + /* setup trace */ + trace.testOcclusion = !noTrace; + trace.forceSunlight = qfalse; + trace.recvShadows = lm->recvShadows; + trace.numSurfaces = lm->numLightSurfaces; + trace.surfaces = &lightSurfaces[ lm->firstLightSurface ]; + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; + + /* twosided lighting (may or may not be a good idea for lightmapped stuff) */ + trace.twoSided = qfalse; + for( i = 0; i < trace.numSurfaces; i++ ) + { + /* get surface */ + info = &surfaceInfos[ trace.surfaces[ i ] ]; + + /* check twosidedness */ + if( info->si->twoSided ) + { + trace.twoSided = qtrue; + break; + } + } + + /* create a culled light list for this raw lightmap */ + CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace ); + + /* ----------------------------------------------------------------- + fill pass + ----------------------------------------------------------------- */ + + /* test debugging state */ + if( debugSurfaces || debugAxis || debugCluster || debugOrigin || normalmap ) + { + /* debug fill the luxels */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + + /* only fill mapped luxels */ + if( *cluster < 0 ) + continue; + + /* get particulars */ + luxel = SUPER_LUXEL( 0, x, y ); + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); + + /* color the luxel with raw lightmap num? */ + if( debugSurfaces ) + VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel ); + + /* color the luxel with lightmap axis? */ + else if( debugAxis ) + { + luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f; + luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f; + luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f; + } + + /* color the luxel with luxel cluster? */ + else if( debugCluster ) + VectorCopy( debugColors[ *cluster % 12 ], luxel ); + + /* color the luxel with luxel origin? */ + else if( debugOrigin ) + { + VectorSubtract( lm->maxs, lm->mins, temp ); + VectorScale( temp, (1.0f / 255.0f), temp ); + VectorSubtract( origin, lm->mins, temp2 ); + luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]); + luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]); + luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]); + } + + /* color the luxel with the normal */ + else if( normalmap ) + { + luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f; + luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f; + luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f; + } + + /* add to counts */ + numLuxelsIlluminated++; + luxel[ 3 ] = 1.0f; + } + } + } + else + { + /* allocate temporary per-light luxel storage */ + llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float ); + lightLuxels = safe_malloc( llSize ); + + /* clear luxels */ + //% memset( lm->superLuxels[ 0 ], 0, llSize ); + + /* set ambient color */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + luxel = SUPER_LUXEL( 0, x, y ); + normal = SUPER_NORMAL( x, y ); + deluxel = SUPER_DELUXEL( x, y ); + + /* blacken unmapped clusters */ + if( *cluster < 0 ) + VectorClear( luxel ); + + /* set ambient */ + else + { + VectorCopy( ambientColor, luxel ); + if( deluxemap ) + VectorScale( normal, 0.00390625f, deluxel ); + luxel[ 3 ] = 1.0f; + } + } + } + + /* clear styled lightmaps */ + size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float ); + for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + if( lm->superLuxels[ lightmapNum ] != NULL ) + memset( lm->superLuxels[ lightmapNum ], 0, size ); + } + + /* debugging code */ + //% if( trace.numLights <= 0 ) + //% Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] ); + + /* walk light list */ + for( i = 0; i < trace.numLights; i++ ) + { + /* setup trace */ + trace.light = trace.lights[ i ]; + + /* style check */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + if( lm->styles[ lightmapNum ] == trace.light->style || + lm->styles[ lightmapNum ] == LS_NONE ) + break; + } + + /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */ + if( lightmapNum >= MAX_LIGHTMAPS ) + { + Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS ); + continue; + } + + /* setup */ + memset( lightLuxels, 0, llSize ); + totalLighted = 0; + + /* initial pass, one sample per luxel */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + if( *cluster < 0 ) + continue; + + /* get particulars */ + lightLuxel = LIGHT_LUXEL( x, y ); + deluxel = SUPER_DELUXEL( x, y ); + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); + + /* set contribution count */ + lightLuxel[ 3 ] = 1.0f; + + /* setup trace */ + trace.cluster = *cluster; + VectorCopy( origin, trace.origin ); + VectorCopy( normal, trace.normal ); + + /* get light for this sample */ + LightContributionToSample( &trace ); + VectorCopy( trace.color, lightLuxel ); + + /* add to count */ + if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) + totalLighted++; + + /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */ + if( deluxemap ) + { + /* color to grayscale (photoshop rgb weighting) */ + brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f; + brightness *= (1.0 / 255.0); + VectorScale( trace.direction, brightness, trace.direction ); + VectorAdd( deluxel, trace.direction, deluxel ); + } + } + } + + /* don't even bother with everything else if nothing was lit */ + if( totalLighted == 0 ) + continue; + + /* determine filter radius */ + filterRadius = lm->filterRadius > trace.light->filterRadius + ? lm->filterRadius + : trace.light->filterRadius; + if( filterRadius < 0.0f ) + filterRadius = 0.0f; + + /* set luxel filter radius */ + luxelFilterRadius = superSample * filterRadius / lm->sampleSize; + if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) ) + luxelFilterRadius = 1; + + /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */ + /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */ + if( lightSamples > 1 && luxelFilterRadius == 0 ) + { + /* walk luxels */ + for( y = 0; y < (lm->sh - 1); y++ ) + { + for( x = 0; x < (lm->sw - 1); x++ ) + { + /* setup */ + mapped = 0; + lighted = 0; + VectorClear( total ); + + /* test 2x2 stamp */ + for( t = 0; t < 4; t++ ) + { + /* set sample coords */ + sx = x + tests[ t ][ 0 ]; + sy = y + tests[ t ][ 1 ]; + + /* get cluster */ + cluster = SUPER_CLUSTER( sx, sy ); + if( *cluster < 0 ) + continue; + mapped++; + + /* get luxel */ + lightLuxel = LIGHT_LUXEL( sx, sy ); + VectorAdd( total, lightLuxel, total ); + if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f ) + lighted++; + } + + /* if total color is under a certain amount, then don't bother subsampling */ + if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f ) + continue; + + /* if all 4 pixels are either in shadow or light, then don't subsample */ + if( lighted != 0 && lighted != mapped ) + { + for( t = 0; t < 4; t++ ) + { + /* set sample coords */ + sx = x + tests[ t ][ 0 ]; + sy = y + tests[ t ][ 1 ]; + + /* get luxel */ + cluster = SUPER_CLUSTER( sx, sy ); + if( *cluster < 0 ) + continue; + lightLuxel = LIGHT_LUXEL( sx, sy ); + origin = SUPER_ORIGIN( sx, sy ); + + /* only subsample shadowed luxels */ + //% if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f ) + //% continue; + + /* subsample it */ + SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel ); + + /* debug code to colorize subsampled areas to yellow */ + //% luxel = SUPER_LUXEL( lightmapNum, sx, sy ); + //% VectorSet( luxel, 255, 204, 0 ); + } + } + } + } + } + + /* allocate sampling lightmap storage */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + { + /* allocate sampling lightmap storage */ + size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float ); + lm->superLuxels[ lightmapNum ] = safe_malloc( size ); + memset( lm->superLuxels[ lightmapNum ], 0, size ); + } + + /* set style */ + if( lightmapNum > 0 ) + { + lm->styles[ lightmapNum ] = trace.light->style; + //% Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style ); + } + + /* copy to permanent luxels */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster and origin */ + cluster = SUPER_CLUSTER( x, y ); + if( *cluster < 0 ) + continue; + origin = SUPER_ORIGIN( x, y ); + + /* filter? */ + if( luxelFilterRadius ) + { + /* setup */ + VectorClear( averageColor ); + samples = 0.0f; + + /* cheaper distance-based filtering */ + for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ ) + { + if( sy < 0 || sy >= lm->sh ) + continue; + + for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ ) + { + if( sx < 0 || sx >= lm->sw ) + continue; + + /* get particulars */ + cluster = SUPER_CLUSTER( sx, sy ); + if( *cluster < 0 ) + continue; + lightLuxel = LIGHT_LUXEL( sx, sy ); + + /* create weight */ + weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f); + weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f); + + /* scale luxel by filter weight */ + VectorScale( lightLuxel, weight, color ); + VectorAdd( averageColor, color, averageColor ); + samples += weight; + } + } + + /* any samples? */ + if( samples <= 0.0f ) + continue; + + /* scale into luxel */ + luxel = SUPER_LUXEL( lightmapNum, x, y ); + luxel[ 3 ] = 1.0f; + + /* handle negative light */ + if( trace.light->flags & LIGHT_NEGATIVE ) + { + luxel[ 0 ] -= averageColor[ 0 ] / samples; + luxel[ 1 ] -= averageColor[ 1 ] / samples; + luxel[ 2 ] -= averageColor[ 2 ] / samples; + } + + /* handle normal light */ + else + { + luxel[ 0 ] += averageColor[ 0 ] / samples; + luxel[ 1 ] += averageColor[ 1 ] / samples; + luxel[ 2 ] += averageColor[ 2 ] / samples; + } + } + + /* single sample */ + else + { + /* get particulars */ + lightLuxel = LIGHT_LUXEL( x, y ); + luxel = SUPER_LUXEL( lightmapNum, x, y ); + + /* handle negative light */ + if( trace.light->flags & LIGHT_NEGATIVE ) + VectorScale( averageColor, -1.0f, averageColor ); + + /* add color */ + luxel[ 3 ] = 1.0f; + + /* handle negative light */ + if( trace.light->flags & LIGHT_NEGATIVE ) + VectorSubtract( luxel, lightLuxel, luxel ); + + /* handle normal light */ + else + VectorAdd( luxel, lightLuxel, luxel ); + } + } + } + } + + /* free temporary luxels */ + free( lightLuxels ); + } + + /* free light list */ + FreeTraceLights( &trace ); + + /* ----------------------------------------------------------------- + filter pass + ----------------------------------------------------------------- */ + + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + + /* average occluded luxels from neighbors */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get particulars */ + cluster = SUPER_CLUSTER( x, y ); + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); + normal = SUPER_NORMAL( x, y ); + + /* determine if filtering is necessary */ + filterColor = qfalse; + filterDir = qfalse; + if( *cluster < 0 || + (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) ) + filterColor = qtrue; + if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) ) + filterDir = qtrue; + + if( !filterColor && !filterDir ) + continue; + + /* choose seed amount */ + VectorClear( averageColor ); + VectorClear( averageDir ); + samples = 0; + + /* walk 3x3 matrix */ + for( sy = (y - 1); sy <= (y + 1); sy++ ) + { + if( sy < 0 || sy >= lm->sh ) + continue; + + for( sx = (x - 1); sx <= (x + 1); sx++ ) + { + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) ) + continue; + + /* get neighbor's particulars */ + cluster2 = SUPER_CLUSTER( sx, sy ); + luxel2 = SUPER_LUXEL( lightmapNum, sx, sy ); + deluxel2 = SUPER_DELUXEL( sx, sy ); + + /* ignore unmapped/unlit luxels */ + if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f || + (lm->splotchFix && VectorCompare( luxel2, ambientColor )) ) + continue; + + /* add its distinctiveness to our own */ + VectorAdd( averageColor, luxel2, averageColor ); + samples += luxel2[ 3 ]; + if( filterDir ) + VectorAdd( averageDir, deluxel2, averageDir ); + } + } + + /* fall through */ + if( samples == 0.0f ) + continue; + + /* average it */ + if( filterColor ) + { + VectorDivide( averageColor, samples, luxel ); + luxel[ 3 ] = 1.0f; + } + if( filterDir ) + VectorDivide( averageDir, samples, deluxel ); + + /* set cluster to -3 */ + if( *cluster < 0 ) + *cluster = CLUSTER_FLOODED; + } + } + } +} + + + +/* +IlluminateVertexes() +light the surface vertexes +*/ + +#define VERTEX_NUDGE 2.0f + +void IlluminateVertexes( int num ) +{ + int i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster; + int lightmapNum; + float samples, *vertLuxel, *radVertLuxel, *luxel; + vec3_t origin, temp, temp2, colors[ MAX_LIGHTMAPS ]; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + rawLightmap_t *lm; + bspDrawVert_t *verts; + trace_t trace; + + + /* der... */ + if( noVertexLighting ) + return; + + /* get surface, info, and raw lightmap */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + lm = info->lm; + + /* ----------------------------------------------------------------- + illuminate the vertexes + ----------------------------------------------------------------- */ + + /* calculate vertex lighting for surfaces without lightmaps */ + if( lm == NULL ) + { + /* setup trace */ + trace.testOcclusion = !noTrace; + trace.forceSunlight = info->si->forceSunlight; + trace.recvShadows = info->recvShadows; + trace.numSurfaces = 1; + trace.surfaces = # + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; + + /* twosided lighting */ + trace.twoSided = info->si->twoSided; + + /* make light list for this surface */ + CreateTraceLightsForSurface( num, &trace ); + + /* walk the surface verts */ + verts = yDrawVerts + ds->firstVert; + for( i = 0; i < ds->numVerts; i++ ) + { + /* get vertex luxel */ + radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i ); + + /* color the luxel with raw lightmap num? */ + if( debugSurfaces ) + VectorCopy( debugColors[ num % 12 ], radVertLuxel ); + + /* color the luxel with luxel origin? */ + else if( debugOrigin ) + { + VectorSubtract( info->maxs, info->mins, temp ); + VectorScale( temp, (1.0f / 255.0f), temp ); + VectorSubtract( origin, lm->mins, temp2 ); + radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]); + radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]); + radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]); + } + + /* color the luxel with the normal */ + else if( normalmap ) + { + radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f; + radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f; + radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f; + } + + /* illuminate the vertex */ + else + { + /* clear vertex luxel */ + VectorCopy( ambientColor, radVertLuxel ); + + /* try at initial origin */ + trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] ); + if( trace.cluster >= 0 ) + { + /* setup trace */ + VectorCopy( verts[ i ].xyz, trace.origin ); + VectorCopy( verts[ i ].normal, trace.normal ); + + /* trace */ + LightingAtSample( &trace, ds->vertexStyles, colors ); + + /* store */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); + VectorCopy( colors[ lightmapNum ], radVertLuxel ); + } + } + + /* is this sample bright enough? */ + if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] && + radVertLuxel[ 1 ] <= ambientColor[ 1 ] && + radVertLuxel[ 2 ] <= ambientColor[ 2 ] ) + { + /* nudge the sample point around a bit */ + for( x = 0; x < 4; x++ ) + { + /* two's complement 0, 1, -1, 2, -2, etc */ + x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1); + + for( y = 0; y < 4; y++ ) + { + y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1); + + for( z = 0; z < 4; z++ ) + { + z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1); + + /* nudge origin */ + trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1); + trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1); + trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1); + + /* try at nudged origin */ + trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] ); + if( trace.cluster < 0 ) + continue; + + /* trace */ + LightingAtSample( &trace, ds->vertexStyles, colors ); + + /* store */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); + VectorCopy( colors[ lightmapNum ], radVertLuxel ); + } + + /* bright enough? */ + radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i ); + if( radVertLuxel[ 0 ] > ambientColor[ 0 ] || + radVertLuxel[ 1 ] > ambientColor[ 1 ] || + radVertLuxel[ 2 ] > ambientColor[ 2 ] ) + x = y = z = 1000; + } + } + } + } + } + + /* another happy customer */ + numVertsIlluminated++; + + /* store it */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* get luxels */ + vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); + radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); + + /* store */ + if( bouncing || bounce == 0 || !bounceOnly ) + VectorAdd( vertLuxel, radVertLuxel, vertLuxel ); + ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale ); + } + } + + /* free light list */ + FreeTraceLights( &trace ); + + /* return to sender */ + return; + } + + /* ----------------------------------------------------------------- + reconstitute vertex lighting from the luxels + ----------------------------------------------------------------- */ + + /* set styles from lightmap */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ]; + + /* get max search radius */ + maxRadius = lm->sw; + maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh; + + /* walk the surface verts */ + verts = yDrawVerts + ds->firstVert; + for( i = 0; i < ds->numVerts; i++ ) + { + /* do each lightmap */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + + /* get luxel coords */ + x = verts[ i ].lightmap[ lightmapNum ][ 0 ]; + y = verts[ i ].lightmap[ lightmapNum ][ 1 ]; + if( x < 0 ) + x = 0; + else if( x >= lm->sw ) + x = lm->sw - 1; + if( y < 0 ) + y = 0; + else if( y >= lm->sh ) + y = lm->sh - 1; + + /* get vertex luxels */ + vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); + radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); + + /* color the luxel with the normal? */ + if( normalmap ) + { + radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f; + radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f; + radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f; + } + + /* color the luxel with surface num? */ + else if( debugSurfaces ) + VectorCopy( debugColors[ num % 12 ], radVertLuxel ); + + /* divine color from the superluxels */ + else + { + /* increasing radius */ + VectorClear( radVertLuxel ); + samples = 0.0f; + for( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ ) + { + /* sample within radius */ + for( sy = (y - radius); sy <= (y + radius); sy++ ) + { + if( sy < 0 || sy >= lm->sh ) + continue; + + for( sx = (x - radius); sx <= (x + radius); sx++ ) + { + if( sx < 0 || sx >= lm->sw ) + continue; + + /* get luxel particulars */ + luxel = SUPER_LUXEL( lightmapNum, sx, sy ); + cluster = SUPER_CLUSTER( sx, sy ); + if( *cluster < 0 ) + continue; + + /* testing: must be brigher than ambient color */ + //% if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] ) + //% continue; + + /* add its distinctiveness to our own */ + VectorAdd( radVertLuxel, luxel, radVertLuxel ); + samples += luxel[ 3 ]; + } + } + } + + /* any color? */ + if( samples > 0.0f ) + VectorDivide( radVertLuxel, samples, radVertLuxel ); + else + VectorCopy( ambientColor, radVertLuxel ); + } + + /* store into floating point storage */ + VectorAdd( vertLuxel, radVertLuxel, vertLuxel ); + numVertsIlluminated++; + + /* store into bytes (for vertex approximation) */ + ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f ); + } + } +} + + + +/* ------------------------------------------------------------------------------- + +light optimization (-fast) + +creates a list of lights that will affect a surface and stores it in tw +this is to optimize surface lighting by culling out as many of the +lights in the world as possible from further calculation + +------------------------------------------------------------------------------- */ + +/* +SetupBrushes() +determines opaque brushes in the world and find sky shaders for sunlight calculations +*/ + +void SetupBrushes( void ) +{ + int i, j, b, compileFlags; + qboolean inside; + bspBrush_t *brush; + bspBrushSide_t *side; + bspShader_t *shader; + shaderInfo_t *si; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" ); + + /* allocate */ + if( opaqueBrushes == NULL ) + opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 ); + + /* clear */ + memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 ); + numOpaqueBrushes = 0; + + /* walk the list of worldspawn brushes */ + for( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ ) + { + /* get brush */ + b = bspModels[ 0 ].firstBSPBrush + i; + brush = &bspBrushes[ b ]; + + /* check all sides */ + inside = qtrue; + compileFlags = 0; + for( j = 0; j < brush->numSides && inside; j++ ) + { + /* do bsp shader calculations */ + side = &bspBrushSides[ brush->firstSide + j ]; + shader = &bspShaders[ side->shaderNum ]; + + /* get shader info */ + si = ShaderInfoForShader( shader->shader ); + if( si == NULL ) + continue; + + /* or together compile flags */ + compileFlags |= si->compileFlags; + } + + /* determine if this brush is opaque to light */ + if( !(compileFlags & C_TRANSLUCENT) ) + { + opaqueBrushes[ b >> 3 ] |= (1 << (b & 7)); + numOpaqueBrushes++; + maxOpaqueBrush = i; + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes ); +} + + + +/* +ClusterVisible() +determines if two clusters are visible to each other using the PVS +*/ + +qboolean ClusterVisible( int a, int b ) +{ + int portalClusters, leafBytes; + byte *pvs; + + + /* dummy check */ + if( a < 0 || b < 0 ) + return qfalse; + + /* early out */ + if( a == b ) + return qtrue; + + /* not vised? */ + if( numBSPVisBytes <=8 ) + return qtrue; + + /* get pvs data */ + portalClusters = ((int *) bspVisBytes)[ 0 ]; + leafBytes = ((int*) bspVisBytes)[ 1 ]; + pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes); + + /* check */ + if( (pvs[ b >> 3 ] & (1 << (b & 7))) ) + return qtrue; + return qfalse; +} + + + +/* +PointInLeafNum_r() +borrowed from vlight.c +*/ + +int PointInLeafNum_r( vec3_t point, int nodenum ) +{ + int leafnum; + vec_t dist; + bspNode_t *node; + bspPlane_t *plane; + + + while( nodenum >= 0 ) + { + node = &bspNodes[ nodenum ]; + plane = &bspPlanes[ node->planeNum ]; + dist = DotProduct( point, plane->normal ) - plane->dist; + if( dist > 0.1 ) + nodenum = node->children[ 0 ]; + else if( dist < -0.1 ) + nodenum = node->children[ 1 ]; + else + { + leafnum = PointInLeafNum_r( point, node->children[ 0 ] ); + if( bspLeafs[ leafnum ].cluster != -1 ) + return leafnum; + nodenum = node->children[ 1 ]; + } + } + + leafnum = -nodenum - 1; + return leafnum; +} + + + +/* +PointInLeafnum() +borrowed from vlight.c +*/ + +int PointInLeafNum( vec3_t point ) +{ + return PointInLeafNum_r( point, 0 ); +} + + + +/* +ClusterVisibleToPoint() - ydnar +returns qtrue if point can "see" cluster +*/ + +qboolean ClusterVisibleToPoint( vec3_t point, int cluster ) +{ + int pointCluster; + + + /* get leafNum for point */ + pointCluster = ClusterForPoint( point ); + if( pointCluster < 0 ) + return qfalse; + + /* check pvs */ + return ClusterVisible( pointCluster, cluster ); +} + + + +/* +ClusterForPoint() - ydnar +returns the pvs cluster for point +*/ + +int ClusterForPoint( vec3_t point ) +{ + int leafNum; + + + /* get leafNum for point */ + leafNum = PointInLeafNum( point ); + if( leafNum < 0 ) + return -1; + + /* return the cluster */ + return bspLeafs[ leafNum ].cluster; +} + + + +/* +ClusterForPointExt() - ydnar +also takes brushes into account for occlusion testing +*/ + +int ClusterForPointExt( vec3_t point, float epsilon ) +{ + int i, j, b, leafNum, cluster; + float dot; + qboolean inside; + int *brushes, numBSPBrushes; + bspLeaf_t *leaf; + bspBrush_t *brush; + bspPlane_t *plane; + + + /* get leaf for point */ + leafNum = PointInLeafNum( point ); + if( leafNum < 0 ) + return -1; + leaf = &bspLeafs[ leafNum ]; + + /* get the cluster */ + cluster = leaf->cluster; + if( cluster < 0 ) + return -1; + + /* transparent leaf, so check point against all brushes in the leaf */ + brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ]; + numBSPBrushes = leaf->numBSPLeafBrushes; + for( i = 0; i < numBSPBrushes; i++ ) + { + /* get parts */ + b = brushes[ i ]; + if( b > maxOpaqueBrush ) + continue; + brush = &bspBrushes[ b ]; + if( !(opaqueBrushes[ b >> 3 ] & (1 << (b & 7))) ) + continue; + + /* check point against all planes */ + inside = qtrue; + for( j = 0; j < brush->numSides && inside; j++ ) + { + plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ]; + dot = DotProduct( point, plane->normal ); + dot -= plane->dist; + if( dot > epsilon ) + inside = qfalse; + } + + /* if inside, return bogus cluster */ + if( inside ) + return -1 - b; + } + + /* if the point made it this far, it's not inside any opaque brushes */ + return cluster; +} + + + +/* +ClusterForPointExtFilter() - ydnar +adds cluster checking against a list of known valid clusters +*/ + +int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters ) +{ + int i, cluster; + + + /* get cluster for point */ + cluster = ClusterForPointExt( point, epsilon ); + + /* check if filtering is necessary */ + if( cluster < 0 || numClusters <= 0 || clusters == NULL ) + return cluster; + + /* filter */ + for( i = 0; i < numClusters; i++ ) + { + if( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) ) + return cluster; + } + + /* failed */ + return -1; +} + + + +/* +ShaderForPointInLeaf() - ydnar +checks a point against all brushes in a leaf, returning the shader of the brush +also sets the cumulative surface and content flags for the brush hit +*/ + +int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags ) +{ + int i, j; + float dot; + qboolean inside; + int *brushes, numBSPBrushes; + bspLeaf_t *leaf; + bspBrush_t *brush; + bspBrushSide_t *side; + bspPlane_t *plane; + bspShader_t *shader; + int allSurfaceFlags, allContentFlags; + + + /* clear things out first */ + *surfaceFlags = 0; + *contentFlags = 0; + + /* get leaf */ + if( leafNum < 0 ) + return -1; + leaf = &bspLeafs[ leafNum ]; + + /* transparent leaf, so check point against all brushes in the leaf */ + brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ]; + numBSPBrushes = leaf->numBSPLeafBrushes; + for( i = 0; i < numBSPBrushes; i++ ) + { + /* get parts */ + brush = &bspBrushes[ brushes[ i ] ]; + + /* check point against all planes */ + inside = qtrue; + allSurfaceFlags = 0; + allContentFlags = 0; + for( j = 0; j < brush->numSides && inside; j++ ) + { + side = &bspBrushSides[ brush->firstSide + j ]; + plane = &bspPlanes[ side->planeNum ]; + dot = DotProduct( point, plane->normal ); + dot -= plane->dist; + if( dot > epsilon ) + inside = qfalse; + else + { + shader = &bspShaders[ side->shaderNum ]; + allSurfaceFlags |= shader->surfaceFlags; + allContentFlags |= shader->contentFlags; + } + } + + /* handle if inside */ + if( inside ) + { + /* if there are desired flags, check for same and continue if they aren't matched */ + if( wantContentFlags && !(wantContentFlags & allContentFlags) ) + continue; + if( wantSurfaceFlags && !(wantSurfaceFlags & allSurfaceFlags) ) + continue; + + /* store the cumulative flags and return the brush shader (which is mostly useless) */ + *surfaceFlags = allSurfaceFlags; + *contentFlags = allContentFlags; + return brush->shaderNum; + } + } + + /* if the point made it this far, it's not inside any brushes */ + return -1; +} + + + +/* +ChopBounds() +chops a bounding box by the plane defined by origin and normal +returns qfalse if the bounds is entirely clipped away + +this is not exactly the fastest way to do this... +*/ + +qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal ) +{ + /* FIXME: rewrite this so it doesn't use bloody brushes */ + return qtrue; +} + + + +/* +SetupEnvelopes() +calculates each light's effective envelope, +taking into account brightness, type, and pvs. +*/ + +#define LIGHT_EPSILON 0.125f +#define LIGHT_NUDGE 2.0f + +void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ) +{ + int i, x, y, z, x1, y1, z1; + light_t *light, *light2, **owner; + bspLeaf_t *leaf; + vec3_t origin, dir, mins, maxs, nullVector = { 0, 0, 0 }; + float radius, intensity; + light_t *buckets[ 256 ]; + + + /* early out for weird cases where there are no lights */ + if( lights == NULL ) + return; + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" ); + + /* count lights */ + numLights = 0; + numCulledLights = 0; + owner = &lights; + while( *owner != NULL ) + { + /* get light */ + light = *owner; + + /* handle negative lights */ + if( light->photons < 0.0f || light->add < 0.0f ) + { + light->photons *= -1.0f; + light->add *= -1.0f; + light->flags |= LIGHT_NEGATIVE; + } + + /* sunlight? */ + if( light->type == EMIT_SUN ) + { + /* special cased */ + light->cluster = 0; + light->envelope = MAX_WORLD_COORD * 8.0f; + VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f ); + VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f ); + } + + /* everything else */ + else + { + /* get pvs cluster for light */ + light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON ); + + /* invalid cluster? */ + if( light->cluster < 0 ) + { + /* nudge the sample point around a bit */ + for( x = 0; x < 4; x++ ) + { + /* two's complement 0, 1, -1, 2, -2, etc */ + x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1); + + for( y = 0; y < 4; y++ ) + { + y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1); + + for( z = 0; z < 4; z++ ) + { + z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1); + + /* nudge origin */ + origin[ 0 ] = light->origin[ 0 ] + (LIGHT_NUDGE * x1); + origin[ 1 ] = light->origin[ 1 ] + (LIGHT_NUDGE * y1); + origin[ 2 ] = light->origin[ 2 ] + (LIGHT_NUDGE * z1); + + /* try at nudged origin */ + light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON ); + if( light->cluster < 0 ) + continue; + + /* set origin */ + VectorCopy( origin, light->origin ); + } + } + } + } + + /* only calculate for lights in pvs and outside of opaque brushes */ + if( light->cluster >= 0 ) + { + /* set light fast flag */ + if( fastFlag ) + light->flags |= LIGHT_FAST_TEMP; + else + light->flags &= ~LIGHT_FAST_TEMP; + if( light->si && light->si->noFast ) + light->flags &= ~(LIGHT_FAST | LIGHT_FAST_TEMP); + + /* clear light envelope */ + light->envelope = 0; + + /* handle area lights */ + if( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL ) + { + /* ugly hack to calculate extent for area lights, but only done once */ + VectorScale( light->normal, -1.0f, dir ); + for( radius = 100.0f; radius < 130000.0f && light->envelope == 0; radius += 10.0f ) + { + float factor; + + VectorMA( light->origin, radius, light->normal, origin ); + factor = PointToPolygonFormFactor( origin, dir, light->w ); + if( factor < 0.0f ) + factor *= -1.0f; + if( (factor * light->add) <= light->falloffTolerance ) + light->envelope = radius; + } + + /* check for fast mode */ + if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) ) + light->envelope = MAX_WORLD_COORD * 8.0f; + } + else + { + radius = 0.0f; + intensity = light->photons; + } + + /* other calcs */ + if( light->envelope <= 0.0f ) + { + /* solve distance for non-distance lights */ + if( !(light->flags & LIGHT_ATTEN_DISTANCE) ) + light->envelope = MAX_WORLD_COORD * 8.0f; + + /* solve distance for linear lights */ + else if( (light->flags & LIGHT_ATTEN_LINEAR ) ) + //% light->envelope = ((intensity / light->falloffTolerance) * linearScale - 1 + radius) / light->fade; + light->envelope = ((intensity * linearScale) - light->falloffTolerance) / light->fade; + + /* + add = angle * light->photons * linearScale - (dist * light->fade); + T = (light->photons * linearScale) - (dist * light->fade); + T + (dist * light->fade) = (light->photons * linearScale); + dist * light->fade = (light->photons * linearScale) - T; + dist = ((light->photons * linearScale) - T) / light->fade; + */ + + /* solve for inverse square falloff */ + else + light->envelope = sqrt( intensity / light->falloffTolerance ) + radius; + + /* + add = light->photons / (dist * dist); + T = light->photons / (dist * dist); + T * (dist * dist) = light->photons; + dist = sqrt( light->photons / T ); + */ + } + + /* chop radius against pvs */ + { + /* clear bounds */ + ClearBounds( mins, maxs ); + + /* check all leaves */ + for( i = 0; i < numBSPLeafs; i++ ) + { + /* get test leaf */ + leaf = &bspLeafs[ i ]; + + /* in pvs? */ + if( leaf->cluster < 0 ) + continue; + if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */ + continue; + + /* add this leafs bbox to the bounds */ + VectorCopy( leaf->mins, origin ); + AddPointToBounds( origin, mins, maxs ); + VectorCopy( leaf->maxs, origin ); + AddPointToBounds( origin, mins, maxs ); + } + + /* test to see if bounds encompass light */ + for( i = 0; i < 3; i++ ) + { + if( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] ) + { + //% Sys_Printf( "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n", + //% mins[ 0 ], mins[ 1 ], mins[ 2 ], + //% maxs[ 0 ], maxs[ 1 ], maxs[ 2 ], + //% numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] ); + AddPointToBounds( light->origin, mins, maxs ); + } + } + + /* chop the bounds by a plane for area lights and spotlights */ + if( light->type == EMIT_AREA || light->type == EMIT_SPOT ) + ChopBounds( mins, maxs, light->origin, light->normal ); + + /* copy bounds */ + VectorCopy( mins, light->mins ); + VectorCopy( maxs, light->maxs ); + + /* reflect bounds around light origin */ + //% VectorMA( light->origin, -1.0f, origin, origin ); + VectorScale( light->origin, 2, origin ); + VectorSubtract( origin, maxs, origin ); + AddPointToBounds( origin, mins, maxs ); + //% VectorMA( light->origin, -1.0f, mins, origin ); + VectorScale( light->origin, 2, origin ); + VectorSubtract( origin, mins, origin ); + AddPointToBounds( origin, mins, maxs ); + + /* calculate spherical bounds */ + VectorSubtract( maxs, light->origin, dir ); + radius = (float) VectorLength( dir ); + + /* if this radius is smaller than the envelope, then set the envelope to it */ + if( radius < light->envelope ) + { + light->envelope = radius; + //% Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights ); + } + //% else + //% Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope ); + } + + /* add grid/surface only check */ + if( forGrid ) + { + if( !(light->flags & LIGHT_GRID) ) + light->envelope = 0.0f; + } + else + { + if( !(light->flags & LIGHT_SURFACES) ) + light->envelope = 0.0f; + } + } + + /* culled? */ + if( light->cluster < 0 || light->envelope <= 0.0f ) + { + /* debug code */ + //% Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope ); + + /* delete the light */ + numCulledLights++; + *owner = light->next; + if( light->w != NULL ) + free( light->w ); + free( light ); + continue; + } + } + + /* square envelope */ + light->envelope2 = (light->envelope * light->envelope); + + /* increment light count */ + numLights++; + + /* set next light */ + owner = &((**owner).next); + } + + /* bucket sort lights by style */ + memset( buckets, 0, sizeof( buckets ) ); + light2 = NULL; + for( light = lights; light != NULL; light = light2 ) + { + /* get next light */ + light2 = light->next; + + /* filter into correct bucket */ + light->next = buckets[ light->style ]; + buckets[ light->style ] = light; + } + + /* filter back into light list */ + lights = NULL; + for( i = 255; i >= 0; i-- ) + { + light2 = NULL; + for( light = buckets[ i ]; light != NULL; light = light2 ) + { + light2 = light->next; + light->next = lights; + lights = light; + } + } + + /* emit some statistics */ + Sys_Printf( "%9d total lights\n", numLights ); + Sys_Printf( "%9d culled lights\n", numCulledLights ); +} + + + +/* +CreateTraceLightsForBounds() +creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves) +*/ + +void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace ) +{ + int i; + light_t *light; + vec3_t origin, dir, nullVector = { 0.0f, 0.0f, 0.0f }; + float radius, dist, length; + + + /* potential pre-setup */ + if( numLights == 0 ) + SetupEnvelopes( qfalse, fast ); + + /* debug code */ + //% Sys_Printf( "CTWLFB: (%4.1f %4.1f %4.1f) (%4.1f %4.1f %4.1f)\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] ); + + /* allocate the light list */ + trace->lights = safe_malloc( sizeof( light_t* ) * (numLights + 1) ); + trace->numLights = 0; + + /* calculate spherical bounds */ + VectorAdd( mins, maxs, origin ); + VectorScale( origin, 0.5f, origin ); + VectorSubtract( maxs, origin, dir ); + radius = (float) VectorLength( dir ); + + /* get length of normal vector */ + if( normal != NULL ) + length = VectorLength( normal ); + else + { + normal = nullVector; + length = 0; + } + + /* test each light and see if it reaches the sphere */ + /* note: the attenuation code MUST match LightingAtSample() */ + for( light = lights; light; light = light->next ) + { + /* check zero sized envelope */ + if( light->envelope <= 0 ) + { + lightsEnvelopeCulled++; + continue; + } + + /* check flags */ + if( !(light->flags & flags) ) + continue; + + /* sunlight skips all this nonsense */ + if( light->type != EMIT_SUN ) + { + /* sun only? */ + if( sunOnly ) + continue; + + /* check against pvs cluster */ + if( numClusters > 0 && clusters != NULL ) + { + for( i = 0; i < numClusters; i++ ) + { + if( ClusterVisible( light->cluster, clusters[ i ] ) ) + break; + } + + /* fixme! */ + if( i == numClusters ) + { + lightsClusterCulled++; + continue; + } + } + + /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */ + VectorSubtract( light->origin, origin, dir ); + dist = VectorLength( dir ); + dist -= light->envelope; + dist -= radius; + if( dist > 0 ) + { + lightsEnvelopeCulled++; + continue; + } + + /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */ + #if 0 + skip = qfalse; + for( i = 0; i < 3; i++ ) + { + if( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] ) + skip = qtrue; + } + if( skip ) + { + lightsBoundsCulled++; + continue; + } + #endif + } + + /* planar surfaces (except twosided surfaces) have a couple more checks */ + if( length > 0.0f && trace->twoSided == qfalse ) + { + /* lights coplanar with a surface won't light it */ + if( !(light->flags & LIGHT_TWOSIDED) && DotProduct( light->normal, normal ) > 0.999f ) + { + lightsPlaneCulled++; + continue; + } + + /* check to see if light is behind the plane */ + if( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f ) + { + lightsPlaneCulled++; + continue; + } + } + + /* add this light */ + trace->lights[ trace->numLights++ ] = light; + } + + /* make last night null */ + trace->lights[ trace->numLights ] = NULL; +} + + + +void FreeTraceLights( trace_t *trace ) +{ + if( trace->lights != NULL ) + free( trace->lights ); +} + + + +/* +CreateTraceLightsForSurface() +creates a list of lights that can potentially affect a drawsurface +*/ + +void CreateTraceLightsForSurface( int num, trace_t *trace ) +{ + int i; + vec3_t mins, maxs, normal; + bspDrawVert_t *dv; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + + + /* dummy check */ + if( num < 0 ) + return; + + /* get drawsurface and info */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* get the mins/maxs for the dsurf */ + ClearBounds( mins, maxs ); + VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal ); + for( i = 0; i < ds->numVerts; i++ ) + { + dv = &yDrawVerts[ ds->firstVert + i ]; + AddPointToBounds( dv->xyz, mins, maxs ); + if( !VectorCompare( dv->normal, normal ) ) + VectorClear( normal ); + } + + /* create the lights for the bounding box */ + CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace ); +} + + + + + diff --git a/tools/quake3/q3map2/lightmaps.c b/tools/quake3/q3map2/lightmaps.c new file mode 100644 index 00000000..c79dfb40 --- /dev/null +++ b/tools/quake3/q3map2/lightmaps.c @@ -0,0 +1,496 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "qbsp.h" + + +/* + + Lightmap allocation has to be done after all flood filling and + visible surface determination. + +*/ + +int numSortShaders; +mapDrawSurface_t *surfsOnShader[ MAX_MAP_SHADERS ]; + + +int allocated[ LIGHTMAP_WIDTH ]; + +int numLightmaps = 1; +int c_exactLightmap = 0; +int c_planarPatch = 0; +int c_nonplanarLightmap = 0; + + +void PrepareNewLightmap( void ) { + memset( allocated, 0, sizeof( allocated ) ); + numLightmaps++; +} + +/* +=============== +AllocLMBlock + +returns a texture number and the position inside it +=============== +*/ +qboolean AllocLMBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + + best = LIGHTMAP_HEIGHT; + + for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) { + best2 = 0; + + for (j=0 ; j= best) { + break; + } + if (allocated[i+j] > best2) { + best2 = allocated[i+j]; + } + } + if (j == w) { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > LIGHTMAP_HEIGHT) { + return qfalse; + } + + for (i=0 ; iverts; + + mesh.width = ds->patchWidth; + mesh.height = ds->patchHeight; + mesh.verts = verts; + newmesh = SubdivideMesh( mesh, 8, 999 ); + + PutMeshOnCurve( *newmesh ); + tempMesh = RemoveLinearMeshColumnsRows( newmesh ); + FreeMesh(newmesh); + + /* get sample size */ + ssize = ds->sampleSize; + + +#ifdef LIGHTMAP_PATCHSHIFT + subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable ); +#else + subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable ); +#endif + + w = subdividedMesh->width; + h = subdividedMesh->height; + +#ifdef LIGHTMAP_PATCHSHIFT + w++; + h++; +#endif + + FreeMesh(subdividedMesh); + + // allocate the lightmap + c_exactLightmap += w * h; + + if ( !AllocLMBlock( w, h, &x, &y ) ) { + PrepareNewLightmap(); + if ( !AllocLMBlock( w, h, &x, &y ) ) + { + Error("Entity %i, brush %i: Lightmap allocation failed", + ds->mapBrush->entitynum, ds->mapBrush->brushnum ); + } + } + +#ifdef LIGHTMAP_PATCHSHIFT + w--; + h--; +#endif + + // set the lightmap texture coordinates in the drawVerts + ds->lightmapNum = numLightmaps - 1; + ds->lightmapWidth = w; + ds->lightmapHeight = h; + ds->lightmapX = x; + ds->lightmapY = y; + + for ( i = 0 ; i < ds->patchWidth ; i++ ) { + for ( k = 0 ; k < w ; k++ ) { + if ( originalWidths[k] >= i ) { + break; + } + } + if (k >= w) + k = w-1; + s = x + k; + for ( j = 0 ; j < ds->patchHeight ; j++ ) { + for ( k = 0 ; k < h ; k++ ) { + if ( originalHeights[k] >= j ) { + break; + } + } + if (k >= h) + k = h-1; + t = y + k; + verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH; + verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT; + } + } +} + + +/* +=================== +AllocateLightmapForSurface +=================== +*/ + +//#define LIGHTMAP_BLOCK 16 + +void AllocateLightmapForSurface( mapDrawSurface_t *ds ) +{ + vec3_t mins, maxs, size, exactSize, delta; + int i; + drawVert_t *verts; + int w, h; + int x, y, ssize; + int axis; + vec3_t vecs[ 2 ]; + float s, t; + vec3_t origin; + vec4_t plane; + float d; + + + /* debug code */ + #if 0 + if( ds->type == SURF_META && ds->planar == qfalse ) + Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader ); + else if( ds->type == SURF_META && ds->planar == qtrue ) + Sys_Printf( "PMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader ); + #endif + + /* ydnar: handle planar patches */ + if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) ) + { + AllocateLightmapForPatch( ds ); + return; + } + + /* get sample size */ + ssize = ds->sampleSize; + + /* bound the surface */ + ClearBounds( mins, maxs ); + verts = ds->verts; + for ( i = 0 ; i < ds->numVerts ; i++ ) + AddPointToBounds( verts[i].xyz, mins, maxs ); + + /* round to the lightmap resolution */ + for( i = 0; i < 3; i++ ) + { + exactSize[i] = maxs[i] - mins[i]; + mins[i] = ssize * floor( mins[i] / ssize ); + maxs[i] = ssize * ceil( maxs[i] / ssize ); + size[i] = (maxs[i] - mins[i]) / ssize + 1; + } + + /* ydnar: lightmap projection axis is already stored */ + memset( vecs, 0, sizeof( vecs ) ); + + /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */ + if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] ) + { + w = size[ 0 ]; + h = size[ 1 ]; + axis = 2; + vecs[ 0 ][ 0 ] = 1.0 / ssize; + vecs[ 1 ][ 1 ] = 1.0 / ssize; + } + else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] ) + { + w = size[ 1 ]; + h = size[ 2 ]; + axis = 0; + vecs[ 0 ][ 1 ] = 1.0 / ssize; + vecs[ 1 ][ 2 ] = 1.0 / ssize; + } + else + { + w = size[ 0 ]; + h = size[ 2 ]; + axis = 1; + vecs[ 0 ][ 0 ] = 1.0 / ssize; + vecs[ 1 ][ 2 ] = 1.0 / ssize; + } + + /* odd check, given projection is now precalculated */ + if( ds->lightmapAxis[ axis ] == 0 ) + Error( "Chose a 0 valued axis" ); + + /* clamp to lightmap texture resolution */ + if( w > LIGHTMAP_WIDTH ) + { + VectorScale ( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] ); + w = LIGHTMAP_WIDTH; + } + if( h > LIGHTMAP_HEIGHT ) + { + VectorScale ( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] ); + h = LIGHTMAP_HEIGHT; + } + + + /* ydnar */ + if( ds->planar == qfalse ) + c_nonplanarLightmap += w * h; + c_exactLightmap += w * h; + + + if( !AllocLMBlock( w, h, &x, &y ) ) + { + PrepareNewLightmap(); + if ( !AllocLMBlock( w, h, &x, &y ) ) + { + Error( "Entity %i, brush %i: Lightmap allocation failed", + ds->mapBrush->entitynum, ds->mapBrush->brushnum ); + } + } + + /* set the lightmap texture coordinates in the drawVerts */ + ds->lightmapNum = numLightmaps - 1; + ds->lightmapWidth = w; + ds->lightmapHeight = h; + ds->lightmapX = x; + ds->lightmapY = y; + for ( i = 0 ; i < ds->numVerts ; i++ ) + { + VectorSubtract( verts[i].xyz, mins, delta ); + s = DotProduct( delta, vecs[0] ) + x + 0.5; + t = DotProduct( delta, vecs[1] ) + y + 0.5; + verts[i].lightmap[0] = s / LIGHTMAP_WIDTH; + verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT; + } + + /* calculate the world coordinates of the lightmap samples */ + + /* construct a plane from the first vert and clear bounding box */ + + /* project mins onto plane to get origin */ + VectorCopy( ds->lightmapVecs[ 2 ], plane ); + plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane ); + d = DotProduct( mins, plane ) - plane[ 3 ]; + d /= plane[ axis ]; + + //% d = DotProduct( mins, plane->normal ) - plane->dist; + //% d /= plane->normal[ axis ]; + VectorCopy( mins, origin ); + origin[ axis ] -= d; + + /* project stepped lightmap blocks and subtract to get planevecs */ + for( i = 0; i < 2; i++ ) + { + vec3_t normalized; + float len; + + len = VectorNormalize( vecs[i], normalized ); + VectorScale( normalized, (1.0/len), vecs[i] ); + d = DotProduct( vecs[i], plane ); + d /= plane[ axis ]; + //%d = DotProduct( vecs[i], plane->normal ); + //%d /= plane->normal[ axis ]; + vecs[i][axis] -= d; + } + + /* store lightmap origin and vectors (fixme: make this work right) */ + VectorCopy( origin, ds->lightmapOrigin ); + //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] ); + + /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */ + if( ds->type == SURF_PATCH ) + c_planarPatch++; + + /* store lightmap vectors */ + VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] ); + VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] ); + + /* ydnar: print some stats */ + //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h ); +} + + +/* +=================== +AllocateLightmaps +=================== +*/ +void AllocateLightmaps( entity_t *e ) +{ + int i, j; + mapDrawSurface_t *ds; + shaderInfo_t *si; + + + /* note it */ + Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" ); + + + /* sort all surfaces by shader so common shaders will usually be in the same lightmap */ + /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */ + numSortShaders = 0; + for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ ) + { + /* get surface and early out if possible */ + ds = &mapDrawSurfs[ i ]; + si = ds->shaderInfo; + if( si->surfaceFlags & SURF_VERTEXLIT ) + continue; + if( ds->numVerts <= 0 ) + continue; + + /* ydnar: handle brush faces and patches first */ + if( ds->type != SURF_FACE && ds->type != SURF_PATCH ) + continue; + + /* ydnar: this is unecessary because it should already be set */ + //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] ); + + /* search for this shader */ + for( j = 0 ; j < numSortShaders; j++ ) + { + if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo ) + { + ds->nextOnShader = surfsOnShader[ j ]; + surfsOnShader[ j ] = ds; + break; + } + } + + /* new shader */ + if( j == numSortShaders ) + { + if( numSortShaders >= MAX_MAP_SHADERS ) + Error( "MAX_MAP_SHADERS" ); + surfsOnShader[ j ] = ds; + ds->nextOnShader = NULL; + numSortShaders++; + } + } + + /* second pass, to allocate lightmapped terrain last */ + for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ ) + { + /* get surface and early out if possible */ + ds = &mapDrawSurfs[ i ]; + si = ds->shaderInfo; + if( si->surfaceFlags & SURF_VERTEXLIT ) + continue; + if( ds->numVerts <= 0 ) + continue; + + /* ydnar: this only handles metasurfaces and terrain */ + if( ds->type != SURF_TERRAIN && ds->type != SURF_META ) + continue; + + /* ydnar: a lightmap projection should be pre-stored for anything but excessively curved patches */ + if( VectorLength( ds->lightmapAxis ) <= 0 ) + continue; + + /* search for this shader */ + for( j = 0; j < numSortShaders; j++ ) + { + if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo ) + { + ds->nextOnShader = surfsOnShader[ j ]; + surfsOnShader[ j ] = ds; + break; + } + } + + /* new shader */ + if( j == numSortShaders ) + { + if( numSortShaders >= MAX_MAP_SHADERS ) + Error( "MAX_MAP_SHADERS" ); + surfsOnShader[ j ] = ds; + ds->nextOnShader = NULL; + numSortShaders++; + } + } + + /* tot up shader count */ + Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders ); + + /* for each shader, allocate lightmaps for each surface */ + for( i = 0; i < numSortShaders; i++ ) + { + si = surfsOnShader[ i ]->shaderInfo; + for( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader ) + { + /* ydnar: promoting pointlight above nolightmap */ + if( si->surfaceFlags & SURF_POINTLIGHT ) + ds->lightmapNum = -3; + else if( si->surfaceFlags & SURF_NOLIGHTMAP ) + ds->lightmapNum = -1; + else + AllocateLightmapForSurface( ds ); + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap ); + Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT ); + Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap ); + Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch ); + Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, (numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) / 1024 ); +} + + + diff --git a/tools/quake3/q3map2/lightmaps_ydnar.c b/tools/quake3/q3map2/lightmaps_ydnar.c new file mode 100644 index 00000000..22b6e376 --- /dev/null +++ b/tools/quake3/q3map2/lightmaps_ydnar.c @@ -0,0 +1,2997 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define LIGHTMAPS_YDNAR_C + + + +/* dependencies */ +#include "q3map2.h" + + + + +/* ------------------------------------------------------------------------------- + +this file contains code that doe lightmap allocation and projection that +runs in the -light phase. + +this is handled here rather than in the bsp phase for a few reasons-- +surfaces are no longer necessarily convex polygons, patches may or may not be +planar or have lightmaps projected directly onto control points. + +also, this allows lightmaps to be calculated before being allocated and stored +in the bsp. lightmaps that have little high-frequency information are candidates +for having their resolutions scaled down. + +------------------------------------------------------------------------------- */ + +/* +WriteTGA24() +based on WriteTGA() from imagelib.c +*/ + +void WriteTGA24( char *filename, byte *data, int width, int height, qboolean flip ) +{ + int i, c; + byte *buffer, *in; + FILE *file; + + + /* allocate a buffer and set it up */ + buffer = safe_malloc( width * height * 3 + 18 ); + memset( buffer, 0, 18 ); + buffer[ 2 ] = 2; + buffer[ 12 ] = width & 255; + buffer[ 13 ] = width >> 8; + buffer[ 14 ] = height & 255; + buffer[ 15 ] = height >> 8; + buffer[ 16 ] = 24; + + /* swap rgb to bgr */ + c = (width * height * 3) + 18; + for( i = 18; i < c; i += 3 ) + { + buffer[ i ] = data[ i - 18 + 2 ]; /* blue */ + buffer[ i + 1 ] = data[ i - 18 + 1 ]; /* green */ + buffer[ i + 2 ] = data[ i - 18 + 0 ]; /* red */ + } + + /* write it and free the buffer */ + file = fopen( filename, "wb" ); + if( file == NULL ) + Error( "Unable to open %s for writing", filename ); + + /* flip vertically? */ + if( flip ) + { + fwrite( buffer, 1, 18, file ); + for( in = buffer + ((height - 1) * width * 3) + 18; in >= buffer; in -= (width * 3) ) + fwrite( in, 1, (width * 3), file ); + } + else + fwrite( buffer, 1, c, file ); + + /* close the file */ + fclose( file ); + free( buffer ); +} + + + +/* +ExportLightmaps() +exports the lightmaps as a list of numbered tga images +*/ + +void ExportLightmaps( void ) +{ + int i; + char dirname[ 1024 ], filename[ 1024 ]; + byte *lightmap; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- ExportLightmaps ---\n"); + + /* do some path mangling */ + strcpy( dirname, source ); + StripExtension( dirname ); + + /* sanity check */ + if( bspLightBytes == NULL ) + { + Sys_Printf( "WARNING: No BSP lightmap data\n" ); + return; + } + + /* make a directory for the lightmaps */ + Q_mkdir( dirname ); + + /* iterate through the lightmaps */ + for( i = 0, lightmap = bspLightBytes; lightmap < (bspLightBytes + numBSPLightBytes); i++, lightmap += (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) ) + { + /* write a tga image out */ + sprintf( filename, "%s/lightmap_%04d.tga", dirname, i ); + Sys_Printf( "Writing %s\n", filename ); + WriteTGA24( filename, lightmap, LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT, qfalse ); + } +} + + + +/* +ExportLightmapsMain() +exports the lightmaps as a list of numbered tga images +*/ + +int ExportLightmapsMain( int argc, char **argv ) +{ + /* arg checking */ + if( argc < 1 ) + { + Sys_Printf( "Usage: q3map -export [-v] \n" ); + return 0; + } + + /* do some path mangling */ + strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + + /* load the bsp */ + Sys_Printf( "Loading %s\n", source ); + LoadBSPFile( source ); + + /* export the lightmaps */ + ExportLightmaps(); + + /* return to sender */ + return 0; +} + + + +/* +ImportLightmapsMain() +imports the lightmaps from a list of numbered tga images +*/ + +int ImportLightmapsMain( int argc, char **argv ) +{ + int i, x, y, len, width, height; + char dirname[ 1024 ], filename[ 1024 ]; + byte *lightmap, *buffer, *pixels, *in, *out; + + + /* arg checking */ + if( argc < 1 ) + { + Sys_Printf( "Usage: q3map -import [-v] \n" ); + return 0; + } + + /* do some path mangling */ + strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + + /* load the bsp */ + Sys_Printf( "Loading %s\n", source ); + LoadBSPFile( source ); + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- ImportLightmaps ---\n"); + + /* do some path mangling */ + strcpy( dirname, source ); + StripExtension( dirname ); + + /* sanity check */ + if( bspLightBytes == NULL ) + Error( "No lightmap data" ); + + /* make a directory for the lightmaps */ + Q_mkdir( dirname ); + + /* iterate through the lightmaps */ + for( i = 0, lightmap = bspLightBytes; lightmap < (bspLightBytes + numBSPLightBytes); i++, lightmap += (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) ) + { + /* read a tga image */ + sprintf( filename, "%s/lightmap_%04d.tga", dirname, i ); + Sys_Printf( "Loading %s\n", filename ); + buffer = NULL; + len = vfsLoadFile( filename, (void*) &buffer, -1 ); + if( len < 0 ) + { + Sys_Printf( "WARNING: Unable to load image %s\n", filename ); + continue; + } + + /* parse file into an image */ + pixels = NULL; + LoadTGABuffer( buffer, &pixels, &width, &height ); + free( buffer ); + + /* sanity check it */ + if( pixels == NULL ) + { + Sys_Printf( "WARNING: Unable to load image %s\n", filename ); + continue; + } + if( width != LIGHTMAP_WIDTH || height != LIGHTMAP_HEIGHT ) + Sys_Printf( "WARNING: Image %s is not the right size (%d, %d) != (%d, %d)\n", + filename, width, height, LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT ); + + /* copy the pixels */ + in = pixels; + for( y = 1; y <= LIGHTMAP_HEIGHT; y++ ) + { + out = lightmap + ((LIGHTMAP_HEIGHT - y) * LIGHTMAP_WIDTH * 3); + for( x = 0; x < LIGHTMAP_WIDTH; x++, in += 4, out += 3 ) + VectorCopy( in, out ); + } + + /* free the image */ + free( pixels ); + } + + /* write the bsp */ + Sys_Printf( "writing %s\n", source ); + WriteBSPFile( source ); + + /* return to sender */ + return 0; +} + + + +/* ------------------------------------------------------------------------------- + +this section deals with projecting a lightmap onto a raw drawsurface + +------------------------------------------------------------------------------- */ + +/* +CompareLightSurface() +compare function for qsort() +*/ + +static int CompareLightSurface( const void *a, const void *b ) +{ + shaderInfo_t *asi, *bsi; + + + /* get shaders */ + asi = surfaceInfos[ *((int*) a) ].si; + bsi = surfaceInfos[ *((int*) b) ].si; + + /* dummy check */ + if( asi == NULL ) + return -1; + if( bsi == NULL ) + return 1; + + /* compare shader names */ + return strcmp( asi->shader, bsi->shader ); +} + + + +/* +FinishRawLightmap() +allocates a raw lightmap's necessary buffers +*/ + +void FinishRawLightmap( rawLightmap_t *lm ) +{ + int i, j, c, size, *sc; + float is; + surfaceInfo_t *info; + + + /* sort light surfaces by shader name */ + qsort( &lightSurfaces[ lm->firstLightSurface ], lm->numLightSurfaces, sizeof( int ), CompareLightSurface ); + + /* count clusters */ + lm->numLightClusters = 0; + for( i = 0; i < lm->numLightSurfaces; i++ ) + { + /* get surface info */ + info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ]; + + /* add surface clusters */ + lm->numLightClusters += info->numSurfaceClusters; + } + + /* allocate buffer for clusters and copy */ + lm->lightClusters = safe_malloc( lm->numLightClusters * sizeof( *lm->lightClusters ) ); + c = 0; + for( i = 0; i < lm->numLightSurfaces; i++ ) + { + /* get surface info */ + info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ]; + + /* add surface clusters */ + for( j = 0; j < info->numSurfaceClusters; j++ ) + lm->lightClusters[ c++ ] = surfaceClusters[ info->firstSurfaceCluster + j ]; + } + + /* set styles */ + lm->styles[ 0 ] = LS_NORMAL; + for( i = 1; i < MAX_LIGHTMAPS; i++ ) + lm->styles[ i ] = LS_NONE; + + /* set supersampling size */ + lm->sw = lm->w * superSample; + lm->sh = lm->h * superSample; + + /* add to super luxel count */ + numRawSuperLuxels += (lm->sw * lm->sh); + + /* manipulate origin/vecs for supersampling */ + if( superSample > 1 && lm->vecs != NULL ) + { + /* calc inverse supersample */ + is = 1.0f / superSample; + + /* scale the vectors and shift the origin */ + #if 1 + /* new code that works for arbitrary supersampling values */ + VectorMA( lm->origin, -0.5, lm->vecs[ 0 ], lm->origin ); + VectorMA( lm->origin, -0.5, lm->vecs[ 1 ], lm->origin ); + VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] ); + VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] ); + VectorMA( lm->origin, is, lm->vecs[ 0 ], lm->origin ); + VectorMA( lm->origin, is, lm->vecs[ 1 ], lm->origin ); + #else + /* old code that only worked with a value of 2 */ + VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] ); + VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] ); + VectorMA( lm->origin, -is, lm->vecs[ 0 ], lm->origin ); + VectorMA( lm->origin, -is, lm->vecs[ 1 ], lm->origin ); + #endif + } + + /* allocate bsp lightmap storage */ + size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float ); + if( lm->bspLuxels[ 0 ] == NULL ) + lm->bspLuxels[ 0 ] = safe_malloc( size ); + memset( lm->bspLuxels[ 0 ], 0, size ); + + /* allocate radiosity lightmap storage */ + if( bounce ) + { + size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float ); + if( lm->radLuxels[ 0 ] == NULL ) + lm->radLuxels[ 0 ] = safe_malloc( size ); + memset( lm->radLuxels[ 0 ], 0, size ); + } + + /* allocate sampling lightmap storage */ + size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float ); + if( lm->superLuxels[ 0 ] == NULL ) + lm->superLuxels[ 0 ] = safe_malloc( size ); + memset( lm->superLuxels[ 0 ], 0, size ); + + /* allocate origin map storage */ + size = lm->sw * lm->sh * SUPER_ORIGIN_SIZE * sizeof( float ); + if( lm->superOrigins == NULL ) + lm->superOrigins = safe_malloc( size ); + memset( lm->superOrigins, 0, size ); + + /* allocate normal map storage */ + size = lm->sw * lm->sh * SUPER_NORMAL_SIZE * sizeof( float ); + if( lm->superNormals == NULL ) + lm->superNormals = safe_malloc( size ); + memset( lm->superNormals, 0, size ); + + /* allocate cluster map storage */ + size = lm->sw * lm->sh * sizeof( int ); + if( lm->superClusters == NULL ) + lm->superClusters = safe_malloc( size ); + size = lm->sw * lm->sh; + sc = lm->superClusters; + for( i = 0; i < size; i++ ) + (*sc++) = CLUSTER_UNMAPPED; + + /* deluxemap allocation */ + if( deluxemap ) + { + /* allocate sampling deluxel storage */ + size = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float ); + if( lm->superDeluxels == NULL ) + lm->superDeluxels = safe_malloc( size ); + memset( lm->superDeluxels, 0, size ); + + /* allocate bsp deluxel storage */ + size = lm->w * lm->h * BSP_DELUXEL_SIZE * sizeof( float ); + if( lm->bspDeluxels == NULL ) + lm->bspDeluxels = safe_malloc( size ); + memset( lm->bspDeluxels, 0, size ); + } + + /* add to count */ + numLuxels += (lm->sw * lm->sh); +} + + + +/* +AddPatchToRawLightmap() +projects a lightmap for a patch surface +since lightmap calculation for surfaces is now handled in a general way (light_ydnar.c), +it is no longer necessary for patch verts to fall exactly on a lightmap sample +based on AllocateLightmapForPatch() +*/ + +qboolean AddPatchToRawLightmap( int num, rawLightmap_t *lm ) +{ + bspDrawSurface_t *ds; + surfaceInfo_t *info; + int x, y; + bspDrawVert_t *verts, *a, *b; + vec3_t delta; + mesh_t src, *subdivided, *mesh; + float sBasis, tBasis, s, t; + float length, widthTable[ MAX_EXPANDED_AXIS ], heightTable[ MAX_EXPANDED_AXIS ]; + + + /* patches finish a raw lightmap */ + lm->finished = qtrue; + + /* get surface and info */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* make a temporary mesh from the drawsurf */ + src.width = ds->patchWidth; + src.height = ds->patchHeight; + src.verts = &yDrawVerts[ ds->firstVert ]; + //% subdivided = SubdivideMesh( src, 8, 512 ); + subdivided = SubdivideMesh2( src, info->patchIterations ); + + /* fit it to the curve and remove colinear verts on rows/columns */ + PutMeshOnCurve( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + + /* find the longest distance on each row/column */ + verts = mesh->verts; + memset( widthTable, 0, sizeof( widthTable ) ); + memset( heightTable, 0, sizeof( heightTable ) ); + for( y = 0; y < mesh->height; y++ ) + { + for( x = 0; x < mesh->width; x++ ) + { + /* get width */ + if( x + 1 < mesh->width ) + { + a = &verts[ (y * mesh->width) + x ]; + b = &verts[ (y * mesh->width) + x + 1 ]; + VectorSubtract( a->xyz, b->xyz, delta ); + length = VectorLength( delta ); + if( length > widthTable[ x ] ) + widthTable[ x ] = length; + } + + /* get height */ + if( y + 1 < mesh->height ) + { + a = &verts[ (y * mesh->width) + x ]; + b = &verts[ ((y + 1) * mesh->width) + x ]; + VectorSubtract( a->xyz, b->xyz, delta ); + length = VectorLength( delta ); + if( length > heightTable[ y ] ) + heightTable[ y ] = length; + } + } + } + + /* determine lightmap width */ + length = 0; + for( x = 0; x < (mesh->width - 1); x++ ) + length += widthTable[ x ]; + lm->w = ceil( length / lm->sampleSize ) + 1; + if( lm->w < ds->patchWidth ) + lm->w = ds->patchWidth; + if( lm->w > lm->customWidth ) + lm->w = lm->customWidth; + sBasis = (float) (lm->w - 1) / (float) (ds->patchWidth - 1); + + /* determine lightmap height */ + length = 0; + for( y = 0; y < (mesh->height - 1); y++ ) + length += heightTable[ y ]; + lm->h = ceil( length / lm->sampleSize ) + 1; + if( lm->h < ds->patchHeight ) + lm->h = ds->patchHeight; + if( lm->h > lm->customHeight ) + lm->h = lm->customHeight; + tBasis = (float) (lm->h - 1) / (float) (ds->patchHeight - 1); + + /* free the temporary mesh */ + FreeMesh( mesh ); + + /* set the lightmap texture coordinates in yDrawVerts */ + lm->wrap[ 0 ] = qtrue; + lm->wrap[ 1 ] = qtrue; + verts = &yDrawVerts[ ds->firstVert ]; + for( y = 0; y < ds->patchHeight; y++ ) + { + t = (tBasis * y) + 0.5f; + for( x = 0; x < ds->patchWidth; x++ ) + { + s = (sBasis * x) + 0.5f; + verts[ (y * ds->patchWidth) + x ].lightmap[ 0 ][ 0 ] = s * superSample; + verts[ (y * ds->patchWidth) + x ].lightmap[ 0 ][ 1 ] = t * superSample; + + if( y == 0 && !VectorCompare( verts[ x ].xyz, verts[ ((ds->patchHeight - 1) * ds->patchWidth) + x ].xyz ) ) + lm->wrap[ 1 ] = qfalse; + } + + if( !VectorCompare( verts[ (y * ds->patchWidth) ].xyz, verts[ (y * ds->patchWidth) + (ds->patchWidth - 1) ].xyz ) ) + lm->wrap[ 0 ] = qfalse; + } + + /* debug code: */ + //% Sys_Printf( "wrap S: %d wrap T: %d\n", lm->wrap[ 0 ], lm->wrap[ 1 ] ); + //% if( lm->w > (ds->lightmapWidth & 0xFF) || lm->h > (ds->lightmapHeight & 0xFF) ) + //% Sys_Printf( "Patch lightmap: (%3d %3d) > (%3d, %3d)\n", lm->w, lm->h, ds->lightmapWidth & 0xFF, ds->lightmapHeight & 0xFF ); + //% ds->lightmapWidth = lm->w | (ds->lightmapWidth & 0xFFFF0000); + //% ds->lightmapHeight = lm->h | (ds->lightmapHeight & 0xFFFF0000); + + /* add to counts */ + numPatchesLightmapped++; + + /* return */ + return qtrue; +} + + + +/* +AddSurfaceToRawLightmap() +projects a lightmap for a surface +based on AllocateLightmapForSurface() +*/ + +qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm ) +{ + bspDrawSurface_t *ds, *ds2; + surfaceInfo_t *info, *info2; + int num2, n, i, axisNum; + float s, t, d, len, sampleSize; + vec3_t mins, maxs, origin, faxis, size, exactSize, delta, normalized, vecs[ 2 ]; + vec4_t plane; + bspDrawVert_t *verts; + + + /* get surface and info */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* add the surface to the raw lightmap */ + lightSurfaces[ numLightSurfaces++ ] = num; + lm->numLightSurfaces++; + + /* does this raw lightmap already have any surfaces? */ + if( lm->numLightSurfaces > 1 ) + { + /* surface and raw lightmap must have the same lightmap projection axis */ + if( VectorCompare( info->axis, lm->axis ) == qfalse ) + return qfalse; + + /* match identical attributes */ + if( info->sampleSize != lm->sampleSize || + info->entityNum != lm->entityNum || + info->recvShadows != lm->recvShadows || + info->si->lmCustomWidth != lm->customWidth || + info->si->lmCustomHeight != lm->customHeight || + info->si->lmGamma != lm->gamma || + info->si->lmFilterRadius != lm->filterRadius || + info->si->splotchFix != lm->splotchFix ) + return qfalse; + + /* surface bounds must intersect with raw lightmap bounds */ + for( i = 0; i < 3; i++ ) + { + if( info->mins[ i ] > lm->maxs[ i ] ) + return qfalse; + if( info->maxs[ i ] < lm->mins[ i ] ) + return qfalse; + } + + /* plane check (fixme: allow merging of nonplanars) */ + if( info->si->lmMergable == qfalse ) + { + if( info->plane == NULL || lm->plane == NULL ) + return qfalse; + + /* compare planes */ + for( i = 0; i < 4; i++ ) + if( fabs( info->plane[ i ] - lm->plane[ i ] ) > EQUAL_EPSILON ) + return qfalse; + } + + /* debug code hacking */ + //% if( lm->numLightSurfaces > 1 ) + //% return qfalse; + } + + /* set plane */ + if( info->plane == NULL ) + lm->plane = NULL; + + /* add surface to lightmap bounds */ + AddPointToBounds( info->mins, lm->mins, lm->maxs ); + AddPointToBounds( info->maxs, lm->mins, lm->maxs ); + + /* check to see if this is a non-planar patch */ + if( ds->surfaceType == MST_PATCH && + lm->axis[ 0 ] == 0.0f && lm->axis[ 1 ] == 0.0f && lm->axis[ 2 ] == 0.0f ) + return AddPatchToRawLightmap( num, lm ); + + /* start with initially requested sample size */ + sampleSize = lm->sampleSize; + + /* round to the lightmap resolution */ + for( i = 0; i < 3; i++ ) + { + exactSize[ i ] = lm->maxs[ i ] - lm->mins[ i ]; + mins[ i ] = sampleSize * floor( lm->mins[ i ] / sampleSize ); + maxs[ i ] = sampleSize * ceil( lm->maxs[ i ] / sampleSize ); + size[ i ] = (maxs[ i ] - mins[ i ]) / sampleSize + 1.0f; + + /* hack (god this sucks) */ + if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight ) + { + i = -1; + sampleSize += 1.0f; + } + } + + /* set actual sample size */ + lm->actualSampleSize = sampleSize; + + /* fixme: copy rounded mins/maxes to lightmap record? */ + if( lm->plane == NULL ) + { + VectorCopy( mins, lm->mins ); + VectorCopy( maxs, lm->maxs ); + VectorCopy( mins, origin ); + } + + /* set lightmap origin */ + VectorCopy( lm->mins, origin ); + + /* make absolute axis */ + faxis[ 0 ] = fabs( lm->axis[ 0 ] ); + faxis[ 1 ] = fabs( lm->axis[ 1 ] ); + faxis[ 2 ] = fabs( lm->axis[ 2 ] ); + + /* clear out lightmap vectors */ + memset( vecs, 0, sizeof( vecs ) ); + + /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */ + if( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] ) + { + axisNum = 2; + lm->w = size[ 0 ]; + lm->h = size[ 1 ]; + vecs[ 0 ][ 0 ] = 1.0f / sampleSize; + vecs[ 1 ][ 1 ] = 1.0f / sampleSize; + } + else if( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] ) + { + axisNum = 0; + lm->w = size[ 1 ]; + lm->h = size[ 2 ]; + vecs[ 0 ][ 1 ] = 1.0f / sampleSize; + vecs[ 1 ][ 2 ] = 1.0f / sampleSize; + } + else + { + axisNum = 1; + lm->w = size[ 0 ]; + lm->h = size[ 2 ]; + vecs[ 0 ][ 0 ] = 1.0f / sampleSize; + vecs[ 1 ][ 2 ] = 1.0f / sampleSize; + } + + /* check for bogus axis */ + if( faxis[ axisNum ] == 0.0f ) + { + Sys_Printf( "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" ); + lm->w = lm->h = 0; + return qfalse; + } + + /* store the axis number in the lightmap */ + lm->axisNum = axisNum; + + /* walk the list of surfaces on this raw lightmap */ + for( n = 0; n < lm->numLightSurfaces; n++ ) + { + /* get surface */ + num2 = lightSurfaces[ lm->firstLightSurface + n ]; + ds2 = &bspDrawSurfaces[ num2 ]; + info2 = &surfaceInfos[ num2 ]; + verts = &yDrawVerts[ ds2->firstVert ]; + + /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */ + for( i = 0; i < ds2->numVerts; i++ ) + { + VectorSubtract( verts[ i ].xyz, origin, delta ); + s = DotProduct( delta, vecs[ 0 ] ) + 0.5f; + t = DotProduct( delta, vecs[ 1 ] ) + 0.5f; + verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample; + verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample; + + if( s > (float) lm->w || t > (float) lm->h ) + { + Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n", + s, lm->w, t, lm->h ); + } + } + } + + /* get first drawsurface */ + num2 = lightSurfaces[ lm->firstLightSurface ]; + ds2 = &bspDrawSurfaces[ num2 ]; + info2 = &surfaceInfos[ num2 ]; + verts = &yDrawVerts[ ds2->firstVert ]; + + /* calculate lightmap origin */ + if( VectorLength( ds2->lightmapVecs[ 2 ] ) ) + VectorCopy( ds2->lightmapVecs[ 2 ], plane ); + else + VectorCopy( lm->axis, plane ); + plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane ); + + VectorCopy( origin, lm->origin ); + d = DotProduct( lm->origin, plane ) - plane[ 3 ]; + d /= plane[ axisNum ]; + lm->origin[ axisNum ] -= d; + + /* legacy support */ + VectorCopy( lm->origin, ds->lightmapOrigin ); + + /* for planar surfaces, create lightmap vectors for st->xyz conversion */ + if( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) /* ydnar: can't remember what exactly i was thinking here... */ + { + /* allocate space for the vectors */ + lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) ); + memset( lm->vecs, 0, 3 * sizeof( vec3_t ) ); + VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] ); + + /* project stepped lightmap blocks and subtract to get planevecs */ + for( i = 0; i < 2; i++ ) + { + len = VectorNormalize( vecs[ i ], normalized ); + VectorScale( normalized, (1.0 / len), lm->vecs[ i ] ); + d = DotProduct( lm->vecs[ i ], plane ); + d /= plane[ axisNum ]; + lm->vecs[ i ][ axisNum ] -= d; + } + } + else + { + /* lightmap vectors are useless on a non-planar surface */ + lm->vecs = NULL; + } + + /* add to counts */ + if( ds->surfaceType == MST_PATCH ) + { + numPatchesLightmapped++; + if( lm->plane != NULL ) + numPlanarPatchesLightmapped++; + } + else + { + if( lm->plane != NULL ) + numPlanarsLightmapped++; + else + numNonPlanarsLightmapped++; + } + + /* return */ + return qtrue; +} + + + +/* +CompareSurfaceInfo() +compare function for qsort() +*/ + +static int CompareSurfaceInfo( const void *a, const void *b ) +{ + surfaceInfo_t *aInfo, *bInfo; + int i; + + + /* get surface info */ + aInfo = &surfaceInfos[ *((int*) a) ]; + bInfo = &surfaceInfos[ *((int*) b) ]; + + /* model first */ + if( aInfo->model < bInfo->model ) + return 1; + else if( aInfo->model > bInfo->model ) + return -1; + + /* then lightmap status */ + if( aInfo->hasLightmap < bInfo->hasLightmap ) + return 1; + else if( aInfo->hasLightmap > bInfo->hasLightmap ) + return -1; + + /* then lightmap sample size */ + if( aInfo->sampleSize < bInfo->sampleSize ) + return 1; + else if( aInfo->sampleSize > bInfo->sampleSize ) + return -1; + + /* then lightmap axis */ + for( i = 0; i < 3; i++ ) + { + if( aInfo->axis[ i ] < bInfo->axis[ i ] ) + return 1; + else if( aInfo->axis[ i ] > bInfo->axis[ i ] ) + return -1; + } + + /* then plane */ + if( aInfo->plane == NULL && bInfo->plane != NULL ) + return 1; + else if( aInfo->plane != NULL && bInfo->plane == NULL ) + return -1; + else if( aInfo->plane != NULL && bInfo->plane != NULL ) + { + for( i = 0; i < 4; i++ ) + { + if( aInfo->plane[ i ] < bInfo->plane[ i ] ) + return 1; + else if( aInfo->plane[ i ] > bInfo->plane[ i ] ) + return -1; + } + } + + /* then position in world */ + for( i = 0; i < 3; i++ ) + { + if( aInfo->mins[ i ] < bInfo->mins[ i ] ) + return 1; + else if( aInfo->mins[ i ] > bInfo->mins[ i ] ) + return -1; + } + + /* these are functionally identical (this should almost never happen) */ + return 0; +} + + + +/* +SetupSurfaceLightmaps() +allocates lightmaps for every surface in the bsp that needs one +this depends on yDrawVerts being allocated +*/ + +void SetupSurfaceLightmaps( void ) +{ + int i, j, k, s,num, num2; + bspModel_t *model; + bspLeaf_t *leaf; + bspDrawSurface_t *ds, *ds2; + surfaceInfo_t *info, *info2; + rawLightmap_t *lm; + qboolean added; + vec3_t mapSize, entityOrigin; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n"); + + /* determine supersample amount */ + if( superSample < 1 ) + superSample = 1; + else if( superSample > 8 ) + { + Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample ); + superSample = 8; + } + + /* clear map bounds */ + ClearBounds( mapMins, mapMaxs ); + + /* allocate a list of surface clusters */ + numSurfaceClusters = 0; + maxSurfaceClusters = numBSPLeafSurfaces; + surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) ); + memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) ); + + /* allocate a list for per-surface info */ + surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) ); + memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) ); + for( i = 0; i < numBSPDrawSurfaces; i++ ) + surfaceInfos[ i ].childSurfaceNum = -1; + + /* allocate a list of surface indexes to be sorted */ + sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) ); + memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) ); + + /* walk each model in the bsp */ + for( i = 0; i < numBSPModels; i++ ) + { + /* get model */ + model = &bspModels[ i ]; + + /* walk the list of surfaces in this model and fill out the info structs */ + for( j = 0; j < model->numBSPSurfaces; j++ ) + { + /* make surface index */ + num = model->firstBSPSurface + j; + + /* copy index to sort list */ + sortSurfaces[ num ] = num; + + /* get surface and info */ + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* set entity origin */ + if( ds->numVerts > 0 ) + VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin ); + else + VectorClear( entityOrigin ); + + /* basic setup */ + info->model = model; + info->lm = NULL; + info->plane = NULL; + info->firstSurfaceCluster = numSurfaceClusters; + + /* get extra data */ + info->si = GetSurfaceExtraShaderInfo( num ); + if( info->si == NULL ) + info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader ); + info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num ); + info->entityNum = GetSurfaceExtraEntityNum( num ); + info->castShadows = GetSurfaceExtraCastShadows( num ); + info->recvShadows = GetSurfaceExtraRecvShadows( num ); + info->sampleSize = GetSurfaceExtraSampleSize( num ); + info->longestCurve = GetSurfaceExtraLongestCurve( num ); + info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions ); + GetSurfaceExtraLightmapAxis( num, info->axis ); + + /* mark parent */ + if( info->parentSurfaceNum >= 0 ) + surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j; + + /* determine surface bounds */ + ClearBounds( info->mins, info->maxs ); + for( k = 0; k < ds->numVerts; k++ ) + { + AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs ); + AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs ); + } + + /* find all the bsp clusters the surface falls into */ + for( k = 0; k < numBSPLeafs; k++ ) + { + /* get leaf */ + leaf = &bspLeafs[ k ]; + + /* test bbox */ + if( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] || + leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] || + leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] ) + continue; + + /* test leaf surfaces */ + for( s = 0; s < leaf->numBSPLeafSurfaces; s++ ) + { + if( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num ) + { + if( numSurfaceClusters >= maxSurfaceClusters ) + Error( "maxSurfaceClusters exceeded" ); + surfaceClusters[ numSurfaceClusters ] = leaf->cluster; + numSurfaceClusters++; + info->numSurfaceClusters++; + } + } + } + + /* determine if surface is planar */ + if( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f ) + { + /* make a plane */ + info->plane = safe_malloc( 4 * sizeof( float ) ); + VectorCopy( ds->lightmapVecs[ 2 ], info->plane ); + info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane ); + } + + /* determine if surface requires a lightmap */ + if( ds->surfaceType == MST_TRIANGLE_SOUP || + ds->surfaceType == MST_FOLIAGE || + (info->si->compileFlags & C_VERTEXLIT) ) + numSurfsVertexLit++; + else + { + numSurfsLightmapped++; + info->hasLightmap = qtrue; + } + } + } + + /* find longest map distance */ + VectorSubtract( mapMaxs, mapMins, mapSize ); + maxMapDistance = VectorLength( mapSize ); + + /* sort the surfaces info list */ + qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo ); + + /* allocate a list of surfaces that would go into raw lightmaps */ + numLightSurfaces = 0; + lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) ); + memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) ); + + /* allocate a list of raw lightmaps */ + numRawSuperLuxels = 0; + numRawLightmaps = 0; + rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) ); + memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) ); + + /* walk the list of sorted surfaces */ + for( i = 0; i < numBSPDrawSurfaces; i++ ) + { + /* get info and attempt early out */ + num = sortSurfaces[ i ]; + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + if( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 ) + continue; + + /* allocate a new raw lightmap */ + lm = &rawLightmaps[ numRawLightmaps ]; + numRawLightmaps++; + + /* set it up */ + lm->splotchFix = info->si->splotchFix; + lm->firstLightSurface = numLightSurfaces; + lm->numLightSurfaces = 0; + lm->sampleSize = info->sampleSize; + lm->actualSampleSize = info->sampleSize; + lm->entityNum = info->entityNum; + lm->recvShadows = info->recvShadows; + lm->gamma = info->si->lmGamma; + lm->filterRadius = info->si->lmFilterRadius; + VectorCopy( info->axis, lm->axis ); + lm->plane = info->plane; + VectorCopy( info->mins, lm->mins ); + VectorCopy( info->maxs, lm->maxs ); + + lm->customWidth = info->si->lmCustomWidth; + lm->customHeight = info->si->lmCustomHeight; + + /* add the surface to the raw lightmap */ + AddSurfaceToRawLightmap( num, lm ); + info->lm = lm; + + /* do an exhaustive merge */ + added = qtrue; + while( added ) + { + /* walk the list of surfaces again */ + added = qfalse; + for( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ ) + { + /* get info and attempt early out */ + num2 = sortSurfaces[ j ]; + ds2 = &bspDrawSurfaces[ num2 ]; + info2 = &surfaceInfos[ num2 ]; + if( info2->hasLightmap == qfalse || info2->lm != NULL ) + continue; + + /* add the surface to the raw lightmap */ + if( AddSurfaceToRawLightmap( num2, lm ) ) + { + info2->lm = lm; + added = qtrue; + } + else + { + /* back up one */ + lm->numLightSurfaces--; + numLightSurfaces--; + } + } + } + + /* finish the lightmap and allocate the various buffers */ + FinishRawLightmap( lm ); + } + + /* allocate vertex luxel storage */ + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + { + vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) ); + memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) ); + radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) ); + memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) ); + } + + /* emit some stats */ + Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces ); + Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps ); + Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit ); + Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped ); + Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped ); + Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped ); + Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped ); + Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped ); +} + + + +/* +StitchSurfaceLightmaps() +stitches lightmap edges +2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams +*/ + +#define MAX_STITCH_CANDIDATES 32 +#define MAX_STITCH_LUXELS 64 + +void StitchSurfaceLightmaps( void ) +{ + int i, j, x, y, x2, y2, *cluster, *cluster2, + numStitched, numCandidates, numLuxels, f, fOld, start; + rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ]; + float *luxel, *luxel2, *origin, *origin2, *normal, *normal2, + sampleSize, average[ 3 ], totalColor, ootc, *luxels[ MAX_STITCH_LUXELS ]; + + + /* disabled for now */ + return; + + /* note it */ + Sys_Printf( "--- StitchSurfaceLightmaps ---\n"); + + /* init pacifier */ + fOld = -1; + start = I_FloatTime(); + + /* walk the list of raw lightmaps */ + numStitched = 0; + for( i = 0; i < numRawLightmaps; i++ ) + { + /* print pacifier */ + f = 10 * i / numRawLightmaps; + if( f != fOld ) + { + fOld = f; + Sys_Printf( "%i...", f ); + } + + /* get lightmap a */ + a = &rawLightmaps[ i ]; + + /* walk rest of lightmaps */ + numCandidates = 0; + for( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ ) + { + /* get lightmap b */ + b = &rawLightmaps[ j ]; + + /* test bounding box */ + if( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] || + a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] || + a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] ) + continue; + + /* add candidate */ + c[ numCandidates++ ] = b; + } + + /* walk luxels */ + for( y = 0; y < a->sh; y++ ) + { + for( x = 0; x < a->sw; x++ ) + { + /* ignore unmapped/unlit luxels */ + lm = a; + cluster = SUPER_CLUSTER( x, y ); + if( *cluster == CLUSTER_UNMAPPED ) + continue; + luxel = SUPER_LUXEL( 0, x, y ); + if( luxel[ 3 ] <= 0.0f ) + continue; + + /* get particulars */ + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); + + /* walk candidate list */ + for( j = 0; j < numCandidates; j++ ) + { + /* get candidate */ + b = c[ j ]; + lm = b; + + /* set samplesize to the smaller of the pair */ + sampleSize = 0.5f * (a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize); + + /* test bounding box */ + if( origin[ 0 ] < (b->mins[ 0 ] - sampleSize) || (origin[ 0 ] > b->maxs[ 0 ] + sampleSize) || + origin[ 1 ] < (b->mins[ 1 ] - sampleSize) || (origin[ 1 ] > b->maxs[ 1 ] + sampleSize) || + origin[ 2 ] < (b->mins[ 2 ] - sampleSize) || (origin[ 2 ] > b->maxs[ 2 ] + sampleSize) ) + continue; + + /* walk candidate luxels */ + VectorClear( average ); + numLuxels = 0; + totalColor = 0.0f; + for( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ ) + { + for( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ ) + { + /* ignore same luxels */ + if( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 ) + continue; + + /* ignore unmapped/unlit luxels */ + cluster2 = SUPER_CLUSTER( x2, y2 ); + if( *cluster2 == CLUSTER_UNMAPPED ) + continue; + luxel2 = SUPER_LUXEL( 0, x2, y2 ); + if( luxel2[ 3 ] <= 0.0f ) + continue; + + /* get particulars */ + origin2 = SUPER_ORIGIN( x2, y2 ); + normal2 = SUPER_NORMAL( x2, y2 ); + + /* test normal */ + if( DotProduct( normal, normal2 ) < 0.5f ) + continue; + + /* test bounds */ + if( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize || + fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize || + fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize ) + continue; + + /* add luxel */ + //% VectorSet( luxel2, 255, 0, 255 ); + luxels[ numLuxels++ ] = luxel2; + VectorAdd( average, luxel2, average ); + totalColor += luxel2[ 3 ]; + } + } + + /* early out */ + if( numLuxels == 0 ) + continue; + + /* scale average */ + ootc = 1.0f / totalColor; + VectorScale( average, ootc, luxel ); + luxel[ 3 ] = 1.0f; + numStitched++; + } + } + } + } + + /* emit statistics */ + Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) ); + Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched ); +} + + + +/* +CompareBSPLuxels() +compares two surface lightmaps' bsp luxels, ignoring occluded luxels +*/ + +#define LUXEL_TOLERANCE 0.0025 +#define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */ + +static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ) +{ + rawLightmap_t *lm; + int x, y; + double delta, total, rd, gd, bd; + float *aLuxel, *bLuxel; + + + /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */ + if( (minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ]) && + ((aNum == 0 && bNum != 0) || (aNum != 0 && bNum == 0)) ) + return qfalse; + + /* compare */ + if( a->w != b->w || a->h != b->h || + a->customWidth != b->customWidth || a->customHeight != b->customHeight || + a->gamma != b->gamma || + a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) + return qfalse; + + /* compare luxels */ + delta = 0.0; + total = 0.0; + for( y = 0; y < a->h; y++ ) + { + for( x = 0; x < a->w; x++ ) + { + /* increment total */ + total += 1.0; + + /* get luxels */ + lm = a; aLuxel = BSP_LUXEL( aNum, x, y ); + lm = b; bLuxel = BSP_LUXEL( bNum, x, y ); + + /* ignore unused luxels */ + if( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 ) + continue; + + /* get deltas */ + rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] ); + gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] ); + bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] ); + + /* 2003-09-27: compare individual luxels */ + if( rd > 3.0 || gd > 3.0 || bd > 3.0 ) + return qfalse; + + /* compare (fixme: take into account perceptual differences) */ + delta += rd * LUXEL_COLOR_FRAC; + delta += gd * LUXEL_COLOR_FRAC; + delta += bd * LUXEL_COLOR_FRAC; + + /* is the change too high? */ + if( total > 0.0 && ((delta / total) > LUXEL_TOLERANCE) ) + return qfalse; + } + } + + /* made it this far, they must be identical (or close enough) */ + return qtrue; +} + + + +/* +MergeBSPLuxels() +merges two surface lightmaps' bsp luxels, overwriting occluded luxels +*/ + +static void MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ) +{ + rawLightmap_t *lm; + int x, y; + float luxel[ 3 ], *aLuxel, *bLuxel; + + + /* compare */ + if( a->w != b->w || a->h != b->h || + a->customWidth != b->customWidth || a->customHeight != b->customHeight || + a->gamma != b->gamma || + a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) + return; + + /* merge luxels */ + for( y = 0; y < a->h; y++ ) + { + for( x = 0; x < a->w; x++ ) + { + /* get luxels */ + lm = a; aLuxel = BSP_LUXEL( aNum, x, y ); + lm = b; bLuxel = BSP_LUXEL( bNum, x, y ); + + /* handle occlusion mismatch */ + if( aLuxel[ 0 ] < 0.0f ) + VectorCopy( bLuxel, aLuxel ); + else if( bLuxel[ 0 ] < 0.0f ) + VectorCopy( aLuxel, bLuxel ); + else + { + /* average */ + VectorAdd( aLuxel, bLuxel, luxel ); + VectorScale( luxel, 0.5f, luxel ); + + /* debugging code */ + //% luxel[ 2 ] += 64.0f; + + /* copy to both */ + VectorCopy( luxel, aLuxel ); + VectorCopy( luxel, bLuxel ); + } + } + } +} + + + +/* +ApproximateLuxel() +determines if a single luxel is can be approximated with the interpolated vertex rgba +*/ + +static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv ) +{ + int i, x, y, d, lightmapNum; + float *luxel; + vec3_t color, vertexColor; + byte cb[ 4 ], vcb[ 4 ]; + + + /* find luxel xy coords */ + x = dv->lightmap[ 0 ][ 0 ] / superSample; + y = dv->lightmap[ 0 ][ 1 ] / superSample; + if( x < 0 ) + x = 0; + else if( x >= lm->w ) + x = lm->w - 1; + if( y < 0 ) + y = 0; + else if( y >= lm->h ) + y = lm->h - 1; + + /* walk list */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->styles[ lightmapNum ] == LS_NONE ) + continue; + + /* get luxel */ + luxel = BSP_LUXEL( lightmapNum, x, y ); + + /* ignore occluded luxels */ + if( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f ) + return qtrue; + + /* copy, set min color and compare */ + VectorCopy( luxel, color ); + VectorCopy( dv->color[ 0 ], vertexColor ); + + /* styles are not affected by minlight */ + if( lightmapNum == 0 ) + { + for( i = 0; i < 3; i++ ) + { + /* set min color */ + if( color[ i ] < minLight[ i ] ) + color[ i ] = minLight[ i ]; + if( vertexColor[ i ] < minLight[ i ] ) /* note NOT minVertexLight */ + vertexColor[ i ] = minLight[ i ]; + } + } + + /* set to bytes */ + ColorToBytes( color, cb, 1.0f ); + ColorToBytes( vertexColor, vcb, 1.0f ); + + /* compare */ + for( i = 0; i < 3; i++ ) + { + d = cb[ i ] - vcb[ i ]; + if( d < 0 ) + d *= -1; + if( d > approximateTolerance ) + return qfalse; + } + } + + /* close enough for the girls i date */ + return qtrue; +} + + + +/* +ApproximateTriangle() +determines if a single triangle can be approximated with vertex rgba +*/ + +static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] ) +{ + bspDrawVert_t mid, *dv2[ 3 ]; + int max; + + + /* approximate the vertexes */ + if( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse ) + return qfalse; + if( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse ) + return qfalse; + if( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse ) + return qfalse; + + /* subdivide calc */ + { + int i; + float dx, dy, dist, maxDist; + + + /* find the longest edge and split it */ + max = -1; + maxDist = 0; + for( i = 0; i < 3; i++ ) + { + dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 0 ]; + dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 1 ]; + dist = sqrt( (dx * dx) + (dy * dy) ); + if( dist > maxDist ) + { + maxDist = dist; + max = i; + } + } + + /* try to early out */ + if( i < 0 || maxDist < subdivideThreshold ) + return qtrue; + } + + /* split the longest edge and map it */ + LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid ); + if( ApproximateLuxel( lm, &mid ) == qfalse ) + return qfalse; + + /* recurse to first triangle */ + VectorCopy( dv, dv2 ); + dv2[ max ] = ∣ + if( ApproximateTriangle_r( lm, dv2 ) == qfalse ) + return qfalse; + + /* recurse to second triangle */ + VectorCopy( dv, dv2 ); + dv2[ (max + 1) % 3 ] = ∣ + return ApproximateTriangle_r( lm, dv2 ); +} + + + +/* +ApproximateLightmap() +determines if a raw lightmap can be approximated sufficiently with vertex colors +*/ + +static qboolean ApproximateLightmap( rawLightmap_t *lm ) +{ + int n, num, i, x, y, pw[ 5 ], r; + bspDrawSurface_t *ds; + surfaceInfo_t *info; + mesh_t src, *subdivided, *mesh; + bspDrawVert_t *verts, *dv[ 3 ]; + qboolean approximated; + + + /* approximating? */ + if( approximateTolerance <= 0 ) + return qfalse; + + /* test for jmonroe */ + #if 0 + /* don't approx lightmaps with styled twins */ + if( lm->numStyledTwins > 0 ) + return qfalse; + + /* don't approx lightmaps with styles */ + for( i = 1; i < MAX_LIGHTMAPS; i++ ) + { + if( lm->styles[ i ] != LS_NONE ) + return qfalse; + } + #endif + + /* assume reduced until shadow detail is found */ + approximated = qtrue; + + /* walk the list of surfaces on this raw lightmap */ + for( n = 0; n < lm->numLightSurfaces; n++ ) + { + /* get surface */ + num = lightSurfaces[ lm->firstLightSurface + n ]; + ds = &bspDrawSurfaces[ num ]; + info = &surfaceInfos[ num ]; + + /* bail if lightmap doesn't match up */ + if( info->lm != lm ) + continue; + + /* assume reduced initially */ + info->approximated = qtrue; + + /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */ + if( (info->maxs[ 0 ] - info->mins[ 0 ]) <= (2.0f * info->sampleSize) && + (info->maxs[ 1 ] - info->mins[ 1 ]) <= (2.0f * info->sampleSize) && + (info->maxs[ 2 ] - info->mins[ 2 ]) <= (2.0f * info->sampleSize) ) + { + numSurfsVertexForced++; + continue; + } + + /* handle the triangles */ + switch( ds->surfaceType ) + { + case MST_PLANAR: + /* get verts */ + verts = yDrawVerts + ds->firstVert; + + /* map the triangles */ + for( i = 0; i < ds->numIndexes && info->approximated; i += 3 ) + { + dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ]; + dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ]; + dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ]; + info->approximated = ApproximateTriangle_r( lm, dv ); + } + break; + + case MST_PATCH: + /* make a mesh from the drawsurf */ + src.width = ds->patchWidth; + src.height = ds->patchHeight; + src.verts = &yDrawVerts[ ds->firstVert ]; + //% subdivided = SubdivideMesh( src, 8, 512 ); + subdivided = SubdivideMesh2( src, info->patchIterations ); + + /* fit it to the curve and remove colinear verts on rows/columns */ + PutMeshOnCurve( *subdivided ); + mesh = RemoveLinearMeshColumnsRows( subdivided ); + FreeMesh( subdivided ); + + /* get verts */ + verts = mesh->verts; + + /* map the mesh quads */ + for( y = 0; y < (mesh->height - 1) && info->approximated; y++ ) + { + for( x = 0; x < (mesh->width - 1) && info->approximated; x++ ) + { + /* set indexes */ + pw[ 0 ] = x + (y * mesh->width); + pw[ 1 ] = x + ((y + 1) * mesh->width); + pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); + pw[ 3 ] = x + 1 + (y * mesh->width); + pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ + + /* set radix */ + r = (x + y) & 1; + + /* get drawverts and map first triangle */ + dv[ 0 ] = &verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &verts[ pw[ r + 2 ] ]; + info->approximated = ApproximateTriangle_r( lm, dv ); + + /* get drawverts and map second triangle */ + dv[ 0 ] = &verts[ pw[ r + 0 ] ]; + dv[ 1 ] = &verts[ pw[ r + 2 ] ]; + dv[ 2 ] = &verts[ pw[ r + 3 ] ]; + if( info->approximated ) + info->approximated = ApproximateTriangle_r( lm, dv ); + } + } + + /* free the mesh */ + FreeMesh( mesh ); + break; + + default: + break; + } + + /* reduced? */ + if( info->approximated == qfalse ) + approximated = qfalse; + else + numSurfsVertexApproximated++; + } + + /* return */ + return approximated; +} + + + +/* +TestOutLightmapStamp() +tests a stamp on a given lightmap for validity +*/ + +static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y ) +{ + int sx, sy, ox, oy, offset; + float *luxel; + + + /* bounds check */ + if( x < 0 || y < 0 || (x + lm->w) > olm->customWidth || (y + lm->h) > olm->customHeight ) + return qfalse; + + /* test the stamp */ + for( sy = 0; sy < lm->h; sy++ ) + { + for( sx = 0; sx < lm->w; sx++ ) + { + /* get luxel */ + luxel = BSP_LUXEL( lightmapNum, sx, sy ); + if( luxel[ 0 ] < 0.0f ) + continue; + + /* get bsp lightmap coords and test */ + ox = x + sx; + oy = y + sy; + offset = (oy * olm->customWidth) + ox; + if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) ) + return qfalse; + } + } + + /* stamp is empty */ + return qtrue; +} + + + +/* +SetupOutLightmap() +sets up an output lightmap +*/ + +static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm ) +{ + /* dummy check */ + if( lm == NULL || olm == NULL ) + return; + + /* is this a "normal" bsp-stored lightmap? */ + if( (lm->customWidth == LIGHTMAP_WIDTH && lm->customHeight == LIGHTMAP_HEIGHT) || externalLightmaps ) + { + olm->lightmapNum = numBSPLightmaps; + numBSPLightmaps++; + + /* lightmaps are interleaved with light direction maps */ + if( deluxemap ) + numBSPLightmaps++; + } + else + olm->lightmapNum = -3; + + /* set external lightmap number */ + olm->extLightmapNum = -1; + + /* set it up */ + olm->numLightmaps = 0; + olm->customWidth = lm->customWidth; + olm->customHeight = lm->customHeight; + olm->freeLuxels = olm->customWidth * olm->customHeight; + olm->numShaders = 0; + + /* allocate buffers */ + olm->lightBits = safe_malloc( (olm->customWidth * olm->customHeight / 8) + 8 ); + memset( olm->lightBits, 0, (olm->customWidth * olm->customHeight / 8) + 8 ); + olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 ); + memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 ); + if( deluxemap ) + { + olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 ); + memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 ); + } +} + + + +/* +FindOutLightmaps() +for a given surface lightmap, find output lightmap pages and positions for it +*/ + +static void FindOutLightmaps( rawLightmap_t *lm ) +{ + int i, j, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset, temp; + outLightmap_t *olm; + surfaceInfo_t *info; + float *luxel, *deluxel; + vec3_t color, direction; + byte *pixel; + qboolean ok; + + + /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + lm->outLightmapNums[ lightmapNum ] = -3; + + /* can this lightmap be approximated with vertex color? */ + if( ApproximateLightmap( lm ) ) + return; + + /* walk list */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->styles[ lightmapNum ] == LS_NONE ) + continue; + + /* don't store twinned lightmaps */ + if( lm->twins[ lightmapNum ] != NULL ) + continue; + + /* if this is a styled lightmap, try some normalized locations first */ + ok = qfalse; + if( lightmapNum > 0 && outLightmaps != NULL ) + { + /* loop twice */ + for( j = 0; j < 2; j++ ) + { + /* try identical position */ + for( i = 0; i < numOutLightmaps; i++ ) + { + /* get the output lightmap */ + olm = &outLightmaps[ i ]; + + /* simple early out test */ + if( olm->freeLuxels < lm->used ) + continue; + + /* don't store non-custom raw lightmaps on custom bsp lightmaps */ + if( olm->customWidth != lm->customWidth || + olm->customHeight != lm->customHeight ) + continue; + + /* try identical */ + if( j == 0 ) + { + x = lm->lightmapX[ 0 ]; + y = lm->lightmapY[ 0 ]; + ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y ); + } + + /* try shifting */ + else + { + for( sy = -1; sy <= 1; sy++ ) + { + for( sx = -1; sx <= 1; sx++ ) + { + x = lm->lightmapX[ 0 ] + sx * (olm->customWidth >> 1); //% lm->w; + y = lm->lightmapY[ 0 ] + sy * (olm->customHeight >> 1); //% lm->h; + ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y ); + + if( ok ) + break; + } + + if( ok ) + break; + } + } + + if( ok ) + break; + } + + if( ok ) + break; + } + } + + /* try normal placement algorithm */ + if( ok == qfalse ) + { + /* reset origin */ + x = 0; + y = 0; + + /* walk the list of lightmap pages */ + for( i = 0; i < numOutLightmaps; i++ ) + { + /* get the output lightmap */ + olm = &outLightmaps[ i ]; + + /* simple early out test */ + if( olm->freeLuxels < lm->used ) + continue; + + /* don't store non-custom raw lightmaps on custom bsp lightmaps */ + if( olm->customWidth != lm->customWidth || + olm->customHeight != lm->customHeight ) + continue; + + /* set maxs */ + xMax = (olm->customWidth - lm->w) + 1; + yMax = (olm->customHeight - lm->h) + 1; + + /* walk the origin around the lightmap */ + for( y = 0; y < yMax; y++ ) + { + for( x = 0; x < xMax; x++ ) + { + /* find a fine tract of lauhnd */ + ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y ); + + if( ok ) + break; + } + + if( ok ) + break; + } + + if( ok ) + break; + + /* reset x and y */ + x = 0; + y = 0; + } + } + + /* no match? */ + if( ok == qfalse ) + { + /* allocate two new output lightmaps */ + numOutLightmaps += 2; + olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) ); + if( outLightmaps != NULL && numOutLightmaps > 2 ) + { + memcpy( olm, outLightmaps, (numOutLightmaps - 2) * sizeof( outLightmap_t ) ); + free( outLightmaps ); + } + outLightmaps = olm; + + /* initialize both out lightmaps */ + SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 2 ] ); + SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 1 ] ); + + /* set out lightmap */ + i = numOutLightmaps - 2; + olm = &outLightmaps[ i ]; + + /* set stamp xy origin to the first surface lightmap */ + if( lightmapNum > 0 ) + { + x = lm->lightmapX[ 0 ]; + y = lm->lightmapY[ 0 ]; + } + } + + /* if this is a style-using lightmap, it must be exported */ + if( lightmapNum > 0 ) + olm->extLightmapNum = 0; + + /* add the surface lightmap to the bsp lightmap */ + lm->outLightmapNums[ lightmapNum ] = i; + lm->lightmapX[ lightmapNum ] = x; + lm->lightmapY[ lightmapNum ] = y; + olm->numLightmaps++; + + /* add shaders */ + for( i = 0; i < lm->numLightSurfaces; i++ ) + { + /* get surface info */ + info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ]; + + /* test for shader */ + for( j = 0; j < olm->numShaders; j++ ) + { + if( olm->shaders[ j ] == info->si ) + break; + } + + /* if it doesn't exist, add it */ + if( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) + { + olm->shaders[ olm->numShaders ] = info->si; + olm->numShaders++; + numLightmapShaders++; + } + } + + /* mark the bits used */ + for( y = 0; y < lm->h; y++ ) + { + for( x = 0; x < lm->w; x++ ) + { + /* get luxel */ + luxel = BSP_LUXEL( lightmapNum, x, y ); + deluxel = BSP_DELUXEL( x, y ); + if( luxel[ 0 ] < 0.0f ) + continue; + + /* set minimum light */ + VectorCopy( luxel, color ); + + /* styles are not affected by minlight */ + if( lightmapNum == 0 ) + { + for( i = 0; i < 3; i++ ) + { + if( color[ i ] < minLight[ i ] ) + color[ i ] = minLight[ i ]; + } + } + + /* get bsp lightmap coords */ + ox = x + lm->lightmapX[ lightmapNum ]; + oy = y + lm->lightmapY[ lightmapNum ]; + offset = (oy * olm->customWidth) + ox; + + /* flag pixel as used */ + olm->lightBits[ offset >> 3 ] |= (1 << (offset & 7)); + olm->freeLuxels--; + + /* store color */ + pixel = olm->bspLightBytes + (((oy * olm->customWidth) + ox) * 3); + ColorToBytes( color, pixel, lm->gamma ); + + /* store direction */ + if( deluxemap ) + { + /* normalize average light direction */ + if( VectorNormalize( deluxel, direction ) ) + { + /* encode [-1,1] in [0,255] */ + pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3); + for( i = 0; i < 3; i++ ) + { + temp = (direction[ i ] + 1.0f) * 127.5f; + if( temp < 0 ) + pixel[ i ] = 0; + else if( temp > 255 ) + pixel[ i ] = 255; + else + pixel[ i ] = temp; + } + } + } + } + } + } +} + + + +/* +CompareRawLightmap() +compare function for qsort() +*/ + +static int CompareRawLightmap( const void *a, const void *b ) +{ + rawLightmap_t *alm, *blm; + surfaceInfo_t *aInfo, *bInfo; + int i, min, diff; + + + /* get lightmaps */ + alm = &rawLightmaps[ *((int*) a) ]; + blm = &rawLightmaps[ *((int*) b) ]; + + /* get min number of surfaces */ + min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces); + + /* iterate */ + for( i = 0; i < min; i++ ) + { + /* get surface info */ + aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ]; + bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ]; + + /* compare shader names */ + diff = strcmp( aInfo->si->shader, bInfo->si->shader ); + if( diff != 0 ) + return diff; + } + + /* test style count */ + diff = 0; + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + diff += blm->styles[ i ] - alm->styles[ i ]; + if( diff ) + return diff; + + /* compare size */ + diff = (blm->w * blm->h) - (alm->w * alm->h); + if( diff != 0 ) + return diff; + + /* must be equivalent */ + return 0; +} + + + +/* +StoreSurfaceLightmaps() +stores the surface lightmaps into the bsp as byte rgb triplets +*/ + +void StoreSurfaceLightmaps( void ) +{ + int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples; + int style, size, lightmapNum, lightmapNum2; + float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples; + vec3_t sample, occludedSample, dirSample; + float *deluxel, *bspDeluxel, *bspDeluxel2; + byte *lb; + int numUsed, numTwins, numTwinLuxels, numStored; + float lmx, lmy, efficiency; + vec3_t color; + bspDrawSurface_t *ds, *parent, dsTemp; + surfaceInfo_t *info; + rawLightmap_t *lm, *lm2; + outLightmap_t *olm; + bspDrawVert_t *dv, *ydv, *dvParent; + char dirname[ 1024 ], filename[ 1024 ]; + shaderInfo_t *csi; + char lightmapName[ 128 ]; + char *rgbGenValues[ 256 ]; + char *alphaGenValues[ 256 ]; + + + /* note it */ + Sys_Printf( "--- StoreSurfaceLightmaps ---\n"); + + /* setup */ + strcpy( dirname, source ); + StripExtension( dirname ); + memset( rgbGenValues, 0, sizeof( rgbGenValues ) ); + memset( alphaGenValues, 0, sizeof( alphaGenValues ) ); + + /* ----------------------------------------------------------------- + average the sampled luxels into the bsp luxels + ----------------------------------------------------------------- */ + + /* note it */ + Sys_FPrintf( SYS_VRB, "Subsampling..." ); + + /* walk the list of raw lightmaps */ + numUsed = 0; + numTwins = 0; + numTwinLuxels = 0; + for( i = 0; i < numRawLightmaps; i++ ) + { + /* get lightmap */ + lm = &rawLightmaps[ i ]; + + /* walk individual lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early outs */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + + /* allocate bsp luxel storage */ + if( lm->bspLuxels[ lightmapNum ] == NULL ) + { + size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float ); + lm->bspLuxels[ lightmapNum ] = safe_malloc( size ); + memset( lm->bspLuxels[ lightmapNum ], 0, size ); + } + + /* allocate radiosity lightmap storage */ + if( bounce ) + { + size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float ); + if( lm->radLuxels[ lightmapNum ] == NULL ) + lm->radLuxels[ lightmapNum ] = safe_malloc( size ); + memset( lm->radLuxels[ lightmapNum ], 0, size ); + } + + /* average supersampled luxels */ + for( y = 0; y < lm->h; y++ ) + { + for( x = 0; x < lm->w; x++ ) + { + /* subsample */ + samples = 0.0f; + occludedSamples = 0.0f; + mappedSamples = 0; + VectorClear( sample ); + VectorClear( occludedSample ); + VectorClear( dirSample ); + for( ly = 0; ly < superSample; ly++ ) + { + for( lx = 0; lx < superSample; lx++ ) + { + /* sample luxel */ + sx = x * superSample + lx; + sy = y * superSample + ly; + luxel = SUPER_LUXEL( lightmapNum, sx, sy ); + deluxel = SUPER_DELUXEL( sx, sy ); + normal = SUPER_NORMAL( sx, sy ); + cluster = SUPER_CLUSTER( sx, sy ); + + /* sample deluxemap */ + if( deluxemap && lightmapNum == 0 ) + VectorAdd( dirSample, deluxel, dirSample ); + + /* keep track of used/occluded samples */ + if( *cluster != CLUSTER_UNMAPPED ) + mappedSamples++; + + /* handle lightmap border? */ + if( lightmapBorder && (sx == 0 || sx == (lm->sw - 1) || sy == 0 || sy == (lm->sh - 1) ) && luxel[ 3 ] > 0.0f ) + { + VectorSet( sample, 255.0f, 0.0f, 0.0f ); + samples += 1.0f; + } + + /* handle debug */ + else if( debug && *cluster < 0 ) + { + if( *cluster == CLUSTER_UNMAPPED ) + VectorSet( luxel, 255, 204, 0 ); + else if( *cluster == CLUSTER_OCCLUDED ) + VectorSet( luxel, 255, 0, 255 ); + else if( *cluster == CLUSTER_FLOODED ) + VectorSet( luxel, 0, 32, 255 ); + VectorAdd( occludedSample, luxel, occludedSample ); + occludedSamples += 1.0f; + } + + /* normal luxel handling */ + else if( luxel[ 3 ] > 0.0f ) + { + /* handle lit or flooded luxels */ + if( *cluster > 0 || *cluster == CLUSTER_FLOODED ) + { + VectorAdd( sample, luxel, sample ); + samples += luxel[ 3 ]; + } + + /* handle occluded or unmapped luxels */ + else + { + VectorAdd( occludedSample, luxel, occludedSample ); + occludedSamples += luxel[ 3 ]; + } + + /* handle style debugging */ + if( debug && lightmapNum > 0 && x < 2 && y < 2 ) + { + VectorCopy( debugColors[ 0 ], sample ); + samples = 1; + } + } + } + } + + /* only use occluded samples if necessary */ + if( samples <= 0.0f ) + { + VectorCopy( occludedSample, sample ); + samples = occludedSamples; + } + + /* get luxels */ + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); + + /* store light direction */ + if( deluxemap && lightmapNum == 0 ) + VectorCopy( dirSample, deluxel ); + + /* store the sample back in super luxels */ + if( samples > 0.01f ) + { + VectorScale( sample, (1.0f / samples), luxel ); + luxel[ 3 ] = 1.0f; + } + + /* if any samples were mapped in any way, store ambient color */ + else if( mappedSamples > 0 ) + { + if( lightmapNum == 0 ) + VectorCopy( ambientColor, luxel ); + else + VectorClear( luxel ); + luxel[ 3 ] = 1.0f; + } + + /* store a bogus value to be fixed later */ + else + { + VectorClear( luxel ); + luxel[ 3 ] = -1.0f; + } + } + } + + /* clean up and store into bsp luxels */ + lm->used = 0; + for( y = 0; y < lm->h; y++ ) + { + for( x = 0; x < lm->w; x++ ) + { + /* get luxels */ + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); + + /* copy light direction */ + if( deluxemap && lightmapNum == 0 ) + VectorCopy( deluxel, dirSample ); + + /* is this a valid sample? */ + if( luxel[ 3 ] > 0.0f ) + { + VectorCopy( luxel, sample ); + samples = luxel[ 3 ]; + numUsed++; + lm->used++; + + /* fix negative samples */ + for( j = 0; j < 3; j++ ) + { + if( sample[ j ] < 0.0f ) + sample[ j ] = 0.0f; + } + } + else + { + /* nick an average value from the neighbors */ + VectorClear( sample ); + VectorClear( dirSample ); + samples = 0.0f; + + /* fixme: why is this disabled?? */ + for( sy = (y - 1); sy <= (y + 1); sy++ ) + { + if( sy < 0 || sy >= lm->h ) + continue; + + for( sx = (x - 1); sx <= (x + 1); sx++ ) + { + if( sx < 0 || sx >= lm->w || (sx == x && sy == y) ) + continue; + + /* get neighbor's particulars */ + luxel = SUPER_LUXEL( lightmapNum, sx, sy ); + if( luxel[ 3 ] < 0.0f ) + continue; + VectorAdd( sample, luxel, sample ); + samples += luxel[ 3 ]; + } + } + + /* no samples? */ + if( samples == 0.0f ) + { + VectorSet( sample, -1.0f, -1.0f, -1.0f ); + samples = 1.0f; + } + else + { + numUsed++; + lm->used++; + + /* fix negative samples */ + for( j = 0; j < 3; j++ ) + { + if( sample[ j ] < 0.0f ) + sample[ j ] = 0.0f; + } + } + } + + /* scale the sample */ + VectorScale( sample, (1.0f / samples), sample ); + + /* store the sample in the radiosity luxels */ + if( bounce > 0 ) + { + radLuxel = RAD_LUXEL( lightmapNum, x, y ); + VectorCopy( sample, radLuxel ); + + /* if only storing bounced light, early out here */ + if( bounceOnly && !bouncing ) + continue; + } + + /* store the sample in the bsp luxels */ + bspLuxel = BSP_LUXEL( lightmapNum, x, y ); + bspDeluxel = BSP_DELUXEL( x, y ); + + VectorAdd( bspLuxel, sample, bspLuxel ); + if( deluxemap && lightmapNum == 0 ) + VectorAdd( bspDeluxel, dirSample, bspDeluxel ); + } + } + + /* wrap bsp luxels if necessary */ + if( lm->wrap[ 0 ] ) + { + for( y = 0; y < lm->h; y++ ) + { + bspLuxel = BSP_LUXEL( lightmapNum, 0, y ); + bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y ); + VectorAdd( bspLuxel, bspLuxel2, bspLuxel ); + VectorScale( bspLuxel, 0.5f, bspLuxel ); + VectorCopy( bspLuxel, bspLuxel2 ); + if( deluxemap && lightmapNum == 0 ) + { + bspDeluxel = BSP_DELUXEL( 0, y ); + bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y ); + VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel ); + VectorScale( bspDeluxel, 0.5f, bspDeluxel ); + VectorCopy( bspDeluxel, bspDeluxel2 ); + } + } + } + if( lm->wrap[ 1 ] ) + { + for( x = 0; x < lm->w; x++ ) + { + bspLuxel = BSP_LUXEL( lightmapNum, x, 0 ); + bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 ); + VectorAdd( bspLuxel, bspLuxel2, bspLuxel ); + VectorScale( bspLuxel, 0.5f, bspLuxel ); + VectorCopy( bspLuxel, bspLuxel2 ); + if( deluxemap && lightmapNum == 0 ) + { + bspDeluxel = BSP_DELUXEL( x, 0 ); + bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 ); + VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel ); + VectorScale( bspDeluxel, 0.5f, bspDeluxel ); + VectorCopy( bspDeluxel, bspDeluxel2 ); + } + } + } + } + } + + /* ----------------------------------------------------------------- + collapse non-unique lightmaps + ----------------------------------------------------------------- */ + + if( noCollapse == qfalse && deluxemap == qfalse ) + { + /* note it */ + Sys_FPrintf( SYS_VRB, "collapsing..." ); + + /* set all twin refs to null */ + for( i = 0; i < numRawLightmaps; i++ ) + { + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + rawLightmaps[ i ].twins[ lightmapNum ] = NULL; + rawLightmaps[ i ].twinNums[ lightmapNum ] = -1; + rawLightmaps[ i ].numStyledTwins = 0; + } + } + + /* walk the list of raw lightmaps */ + for( i = 0; i < numRawLightmaps; i++ ) + { + /* get lightmap */ + lm = &rawLightmaps[ i ]; + + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early outs */ + if( lm->bspLuxels[ lightmapNum ] == NULL || + lm->twins[ lightmapNum ] != NULL ) + continue; + + /* find all lightmaps that are virtually identical to this one */ + for( j = i + 1; j < numRawLightmaps; j++ ) + { + /* get lightmap */ + lm2 = &rawLightmaps[ j ]; + + /* walk lightmaps */ + for( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ ) + { + /* early outs */ + if( lm2->bspLuxels[ lightmapNum2 ] == NULL || + lm2->twins[ lightmapNum2 ] != NULL ) + continue; + + /* compare them */ + if( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) + { + /* merge and set twin */ + MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ); + lm2->twins[ lightmapNum2 ] = lm; + lm2->twinNums[ lightmapNum2 ] = lightmapNum; + numTwins++; + numTwinLuxels += (lm->w * lm->h); + + /* count styled twins */ + if( lightmapNum > 0 ) + lm->numStyledTwins++; + } + } + } + } + } + } + + /* ----------------------------------------------------------------- + sort raw lightmaps by shader + ----------------------------------------------------------------- */ + + /* note it */ + Sys_FPrintf( SYS_VRB, "sorting..." ); + + /* allocate a new sorted list */ + if( sortLightmaps == NULL ) + sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) ); + + /* fill it out and sort it */ + for( i = 0; i < numRawLightmaps; i++ ) + sortLightmaps[ i ] = i; + qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap ); + + /* ----------------------------------------------------------------- + allocate output lightmaps + ----------------------------------------------------------------- */ + + /* note it */ + Sys_FPrintf( SYS_VRB, "allocating..." ); + + /* kill all existing output lightmaps */ + if( outLightmaps != NULL ) + { + for( i = 0; i < numOutLightmaps; i++ ) + { + free( outLightmaps[ i ].lightBits ); + free( outLightmaps[ i ].bspLightBytes ); + } + free( outLightmaps ); + outLightmaps = NULL; + } + + numLightmapShaders = 0; + numOutLightmaps = 0; + numBSPLightmaps = 0; + numExtLightmaps = 0; + + /* find output lightmap */ + for( i = 0; i < numRawLightmaps; i++ ) + { + lm = &rawLightmaps[ sortLightmaps[ i ] ]; + FindOutLightmaps( lm ); + } + + /* set output numbers in twinned lightmaps */ + for( i = 0; i < numRawLightmaps; i++ ) + { + /* get lightmap */ + lm = &rawLightmaps[ sortLightmaps[ i ] ]; + + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* get twin */ + lm2 = lm->twins[ lightmapNum ]; + if( lm2 == NULL ) + continue; + lightmapNum2 = lm->twinNums[ lightmapNum ]; + + /* find output lightmap from twin */ + lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ]; + lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ]; + lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ]; + } + } + + /* ----------------------------------------------------------------- + store output lightmaps + ----------------------------------------------------------------- */ + + /* note it */ + Sys_FPrintf( SYS_VRB, "storing..." ); + + /* count the bsp lightmaps and allocate space */ + if( bspLightBytes != NULL ) + free( bspLightBytes ); + if( numBSPLightmaps == 0 || externalLightmaps ) + { + numBSPLightBytes = 0; + bspLightBytes = NULL; + } + else + { + numBSPLightBytes = (numBSPLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3); + bspLightBytes = safe_malloc( numBSPLightBytes ); + memset( bspLightBytes, 0, numBSPLightBytes ); + } + + /* walk the list of output lightmaps */ + for( i = 0; i < numOutLightmaps; i++ ) + { + /* get output lightmap */ + olm = &outLightmaps[ i ]; + + /* is this a valid bsp lightmap? */ + if( olm->lightmapNum >= 0 && !externalLightmaps ) + { + /* copy lighting data */ + lb = bspLightBytes + (olm->lightmapNum * LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3); + memcpy( lb, olm->bspLightBytes, LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3 ); + + /* copy direction data */ + if( deluxemap ) + { + lb = bspLightBytes + ((olm->lightmapNum + 1) * LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3); + memcpy( lb, olm->bspDirBytes, LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3 ); + } + } + + /* external lightmap? */ + if( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) + { + /* make a directory for the lightmaps */ + Q_mkdir( dirname ); + + /* set external lightmap number */ + olm->extLightmapNum = numExtLightmaps; + + /* write lightmap */ + sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps ); + Sys_FPrintf( SYS_VRB, "\nwriting %s", filename ); + WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue ); + numExtLightmaps++; + + /* write deluxemap */ + if( deluxemap ) + { + sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps ); + Sys_FPrintf( SYS_VRB, "\nwriting %s", filename ); + WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue ); + numExtLightmaps++; + + if( debugDeluxemap ) + olm->extLightmapNum++; + } + } + } + + if( numExtLightmaps > 0 ) + Sys_FPrintf( SYS_VRB, "\n" ); + + /* delete unused external lightmaps */ + for( i = numExtLightmaps; i; i++ ) + { + /* determine if file exists */ + sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i ); + if( !FileExists( filename ) ) + break; + + /* delete it */ + remove( filename ); + } + + /* ----------------------------------------------------------------- + project the lightmaps onto the bsp surfaces + ----------------------------------------------------------------- */ + + /* note it */ + Sys_FPrintf( SYS_VRB, "projecting..." ); + + /* walk the list of surfaces */ + for( i = 0; i < numBSPDrawSurfaces; i++ ) + { + /* get the surface and info */ + ds = &bspDrawSurfaces[ i ]; + info = &surfaceInfos[ i ]; + lm = info->lm; + olm = NULL; + + /* handle surfaces with identical parent */ + if( info->parentSurfaceNum >= 0 ) + { + /* preserve original data and get parent */ + parent = &bspDrawSurfaces[ info->parentSurfaceNum ]; + memcpy( &dsTemp, ds, sizeof( *ds ) ); + + /* overwrite child with parent data */ + memcpy( ds, parent, sizeof( *ds ) ); + + /* restore key parts */ + ds->fogNum = dsTemp.fogNum; + ds->firstVert = dsTemp.firstVert; + ds->firstIndex = dsTemp.firstIndex; + memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) ); + + /* set vertex data */ + dv = &bspDrawVerts[ ds->firstVert ]; + dvParent = &bspDrawVerts[ parent->firstVert ]; + for( j = 0; j < ds->numVerts; j++ ) + { + memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) ); + memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) ); + } + + /* skip the rest */ + continue; + } + + /* handle vertex lit or approximated surfaces */ + else if( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) + { + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + ds->lightmapNum[ lightmapNum ] = -3; + ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ]; + } + } + + /* handle lightmapped surfaces */ + else + { + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* set style */ + ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ]; + + /* handle unused style */ + if( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) + { + ds->lightmapNum[ lightmapNum ] = -3; + continue; + } + + /* get output lightmap */ + olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ]; + + /* set bsp lightmap number */ + ds->lightmapNum[ lightmapNum ] = olm->lightmapNum; + + /* deluxemap debugging makes the deluxemap visible */ + if( deluxemap && debugDeluxemap && lightmapNum == 0 ) + ds->lightmapNum[ lightmapNum ]++; + + /* calc lightmap origin in texture space */ + lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth; + lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight; + + /* calc lightmap st coords and store lighting values */ + dv = &bspDrawVerts[ ds->firstVert ]; + ydv = &yDrawVerts[ ds->firstVert ]; + for( j = 0; j < ds->numVerts; j++ ) + { + dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (ydv[ j ].lightmap[ 0 ][ 0 ] / (superSample * olm->customWidth)); + dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (ydv[ j ].lightmap[ 0 ][ 1 ] / (superSample * olm->customHeight)); + } + } + } + + /* store vertex colors */ + dv = &bspDrawVerts[ ds->firstVert ]; + for( j = 0; j < ds->numVerts; j++ ) + { + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* handle unused style */ + if( ds->vertexStyles[ lightmapNum ] == LS_NONE ) + VectorClear( color ); + else + { + /* get vertex color */ + luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j ); + VectorCopy( luxel, color ); + + /* set minimum light */ + if( lightmapNum == 0 ) + { + for( k = 0; k < 3; k++ ) + if( color[ k ] < minVertexLight[ k ] ) + color[ k ] = minVertexLight[ k ]; + } + } + + /* store to bytes */ + ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale ); + } + } + + /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */ + if( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) //% info->si->styleMarker > 0 ) + { + qboolean dfEqual; + char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ]; + + + /* setup */ + sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" ); + dv = &bspDrawVerts[ ds->firstVert ]; + + /* depthFunc equal? */ + if( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) + dfEqual = qtrue; + else + dfEqual = qfalse; + + /* generate stages for styled lightmaps */ + for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + style = lm->styles[ lightmapNum ]; + if( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) + continue; + + /* get output lightmap */ + olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ]; + + /* lightmap name */ + if( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) + strcpy( lightmapName, "$lightmap" ); + else + sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum ); + + /* get rgbgen string */ + if( rgbGenValues[ style ] == NULL ) + { + sprintf( key, "_style%drgbgen", style ); + rgbGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key ); + if( rgbGenValues[ style ][ 0 ] == '\0' ) + rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37"; + } + rgbGen[ 0 ] = '\0'; + if( rgbGenValues[ style ][ 0 ] != '\0' ) + sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style ); + else + rgbGen[ 0 ] = '\0'; + + /* get alphagen string */ + if( alphaGenValues[ style ] == NULL ) + { + sprintf( key, "_style%dalphagen", style ); + alphaGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key ); + } + if( alphaGenValues[ style ][ 0 ] != '\0' ) + sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style ); + else + alphaGen[ 0 ] = '\0'; + + /* calculate st offset */ + lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ]; + lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ]; + + /* create additional stage */ + if( lmx == 0.0f && lmy == 0.0f ) + { + sprintf( styleStage, "\t{\n" + "\t\tmap %s\n" /* lightmap */ + "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n" + "%s" /* depthFunc equal */ + "%s" /* rgbGen */ + "%s" /* alphaGen */ + "\t\ttcGen lightmap\n" + "\t}\n", + lightmapName, + (dfEqual ? "\t\tdepthFunc equal\n" : ""), + rgbGen, + alphaGen ); + } + else + { + sprintf( styleStage, "\t{\n" + "\t\tmap %s\n" /* lightmap */ + "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n" + "%s" /* depthFunc equal */ + "%s" /* rgbGen */ + "%s" /* alphaGen */ + "\t\ttcGen lightmap\n" + "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */ + "\t}\n", + lightmapName, + (dfEqual ? "\t\tdepthFunc equal\n" : ""), + rgbGen, + alphaGen, + lmx, lmy ); + + } + + /* concatenate */ + strcat( styleStages, styleStage ); + } + + /* create custom shader */ + if( info->si->styleMarker == 2 ) + csi = CustomShader( info->si, "q3map_styleMarker2", styleStages ); + else + csi = CustomShader( info->si, "q3map_styleMarker", styleStages ); + + /* emit remap command */ + //% EmitVertexRemapShader( csi->shader, info->si->shader ); + + /* store it */ + //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) ); + ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags ); + //% Sys_Printf( ")\n" ); + } + + /* devise a custom shader for this surface (fixme: make this work with light styles) */ + else if( olm != NULL && lm != NULL && !externalLightmaps && + (olm->customWidth != LIGHTMAP_WIDTH || olm->customHeight != LIGHTMAP_HEIGHT) ) + { + /* get output lightmap */ + olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ]; + + /* do some name mangling */ + sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum ); + + /* create custom shader */ + csi = CustomShader( info->si, "$lightmap", lightmapName ); + + /* store it */ + //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) ); + ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags ); + //% Sys_Printf( ")\n" ); + } + + /* use the normal plain-jane shader */ + else + ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags ); + } + + /* finish */ + Sys_FPrintf( SYS_VRB, "done.\n" ); + + /* calc num stored */ + numStored = numBSPLightBytes / 3; + efficiency = (numStored <= 0) + ? 0 + : (float) numUsed / (float) numStored; + + /* print stats */ + Sys_Printf( "%9d luxels used\n", numUsed ); + Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f ); + Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels ); + Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced ); + Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated ); + Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps ); + Sys_Printf( "%9d total lightmaps\n", numOutLightmaps ); + Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders ); + + /* write map shader file */ + WriteMapShaderFile(); +} + + + + diff --git a/tools/quake3/q3map2/listen.pl b/tools/quake3/q3map2/listen.pl new file mode 100644 index 00000000..20001360 --- /dev/null +++ b/tools/quake3/q3map2/listen.pl @@ -0,0 +1,46 @@ +#!/usr/bin/perl -w + +use IO::Socket; +use Net::hostent; + +my $port = shift || 13131; + +my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalPort => $port, + Listen => SOMAXCONN, + Reuse => 1 ) + || die "can't setup server"; +print "[Q3Map2 listener $0 is now active on port $port]\n"; + +while( $client = $server->accept() ) +{ + + $client->autoflush( 1 ); + + $hostinfo = gethostbyaddr( $client->peeraddr ); + printf "[Connect from %s]\n\n", $hostinfo ? $hostinfo->name : $client->peerhost; + + #ask the client for a command + print $client "[server]\$"; + my $text = ""; + while( <$client> ) + { + $text .= $_; + while( $text =~ s|]*>([^<]+)|| ) + { + my $msg = $1; + + # fix xml ents + $msg =~ s|<|<|g; + $msg =~ s|>|>|g; + $msg =~ s|"|"|g;#" + $msg =~ s|'|'|g;#' + + print $msg; + } + } + + printf "\n[Disconnected: %s]\n\n", $hostinfo ? $hostinfo->name : $client->peerhost; + close $client; +} diff --git a/tools/quake3/q3map2/main.c b/tools/quake3/q3map2/main.c new file mode 100644 index 00000000..40fd5c8c --- /dev/null +++ b/tools/quake3/q3map2/main.c @@ -0,0 +1,456 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define MAIN_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +Random() +returns a pseudorandom number between 0 and 1 +*/ + +vec_t Random( void ) +{ + return (vec_t) rand() / RAND_MAX; +} + + + +/* +ExitQ3Map() +cleanup routine +*/ + +static void ExitQ3Map( void ) +{ + BSPFilesCleanup(); + if( mapDrawSurfs != NULL ) + free( mapDrawSurfs ); +} + + + +/* +BSPInfo() +emits statistics about the bsp file +*/ + +int BSPInfo( int count, char **fileNames ) +{ + int i; + char source[ 1024 ], ext[ 64 ]; + int size; + FILE *f; + + + /* dummy check */ + if( count < 1 ) + { + Sys_Printf( "No files to dump info for.\n"); + return -1; + } + + /* enable info mode */ + infoMode = qtrue; + + /* walk file list */ + for( i = 0; i < count; i++ ) + { + Sys_Printf( "---------------------------------\n" ); + + /* mangle filename and get size */ + strcpy( source, fileNames[ i ] ); + ExtractFileExtension( source, ext ); + if( !Q_stricmp( ext, "map" ) ) + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + f = fopen( source, "rb" ); + if( f ) + { + size = Q_filelength (f); + fclose( f ); + } + else + size = 0; + + /* load the bsp file and print lump sizes */ + Sys_Printf( "%s\n", source ); + LoadBSPFile( source ); + PrintBSPFileSizes(); + + /* print sizes */ + Sys_Printf( "\n" ); + Sys_Printf( " total %9d\n", size ); + Sys_Printf( " %9d KB\n", size / 1024 ); + Sys_Printf( " %9d MB\n", size / (1024 * 1024) ); + + Sys_Printf( "---------------------------------\n" ); + } + + /* return count */ + return i; +} + + + +/* +ScaleBSPMain() +amaze and confuse your enemies with wierd scaled maps! +*/ + +int ScaleBSPMain( int argc, char **argv ) +{ + int i; + float f, scale; + vec3_t vec; + char str[ 1024 ]; + + + /* arg checking */ + if( argc < 2 ) + { + Sys_Printf( "Usage: q3map -scale [-v] \n" ); + return 0; + } + + /* get scale */ + scale = atof( argv[ argc - 2 ] ); + if( scale == 0.0f ) + { + Sys_Printf( "Usage: q3map -scale [-v] \n" ); + Sys_Printf( "Non-zero scale value required.\n" ); + return 0; + } + + /* do some path mangling */ + strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + + /* load the bsp */ + Sys_Printf( "Loading %s\n", source ); + LoadBSPFile( source ); + ParseEntities(); + + /* note it */ + Sys_Printf( "--- ScaleBSP ---\n" ); + Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities ); + + /* scale entity keys */ + for( i = 0; i < numBSPEntities && i < numEntities; i++ ) + { + /* scale origin */ + GetVectorForKey( &entities[ i ], "origin", vec ); + if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) ) + { + VectorScale( vec, scale, vec ); + sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); + SetKeyValue( &entities[ i ], "origin", str ); + } + + /* scale door lip */ + f = FloatForKey( &entities[ i ], "lip" ); + if( f ) + { + f *= scale; + sprintf( str, "%f", f ); + SetKeyValue( &entities[ i ], "lip", str ); + } + } + + /* scale models */ + for( i = 0; i < numBSPModels; i++ ) + { + VectorScale( bspModels[ i ].mins, scale, bspModels[ i ].mins ); + VectorScale( bspModels[ i ].maxs, scale, bspModels[ i ].maxs ); + } + + /* scale nodes */ + for( i = 0; i < numBSPNodes; i++ ) + { + VectorScale( bspNodes[ i ].mins, scale, bspNodes[ i ].mins ); + VectorScale( bspNodes[ i ].maxs, scale, bspNodes[ i ].maxs ); + } + + /* scale leafs */ + for( i = 0; i < numBSPLeafs; i++ ) + { + VectorScale( bspLeafs[ i ].mins, scale, bspLeafs[ i ].mins ); + VectorScale( bspLeafs[ i ].maxs, scale, bspLeafs[ i ].maxs ); + } + + /* scale drawverts */ + for( i = 0; i < numBSPDrawVerts; i++ ) + VectorScale( bspDrawVerts[ i ].xyz, scale, bspDrawVerts[ i ].xyz ); + + /* scale planes */ + for( i = 0; i < numBSPPlanes; i++ ) + bspPlanes[ i ].dist *= scale; + + /* scale gridsize */ + GetVectorForKey( &entities[ 0 ], "gridsize", vec ); + if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f ) + VectorCopy( gridSize, vec ); + VectorScale( vec, scale, vec ); + sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); + SetKeyValue( &entities[ 0 ], "gridsize", str ); + + /* write the bsp */ + UnparseEntities(); + StripExtension( source ); + DefaultExtension( source, "_s.bsp" ); + Sys_Printf( "Writing %s\n", source ); + WriteBSPFile( source ); + + /* return to sender */ + return 0; +} + + + +/* +ConvertBSPMain() +main argument processing function for bsp conversion +*/ + +int ConvertBSPMain( int argc, char **argv ) +{ + int i; + int (*convertFunc)( char * ); + + + /* set default */ + convertFunc = ConvertBSPToASE; + + /* arg checking */ + if( argc < 1 ) + { + Sys_Printf( "Usage: q3map -scale [-v] \n" ); + return 0; + } + + /* process arguments */ + for( i = 1; i < (argc - 1); i++ ) + { + /* -format map|ase|... */ + if( !strcmp( argv[ i ], "-format" ) ) + { + i++; + if( !Q_stricmp( argv[ i ], "ase" ) ) + convertFunc = ConvertBSPToASE; + else if( !Q_stricmp( argv[ i ], "map" ) ) + convertFunc = ConvertBSPToMap; + else + Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); + } + } + + /* clean up map name */ + strcpy( source, ExpandArg( argv[ i ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + + LoadShaderInfo(); + + Sys_Printf( "Loading %s\n", source ); + + /* ydnar: load surface file */ + //% LoadSurfaceExtraFile( source ); + + LoadBSPFile( source ); + + /* parse bsp entities */ + ParseEntities(); + + /* convert */ + return convertFunc( source ); +} + + + +/* +main() +q3map mojo... +*/ + +int main( int argc, char **argv ) +{ + int i, r; + double start, end; + + + /* we want consistent 'randomness' */ + srand( 0 ); + + /* start timer */ + start = I_FloatTime(); + + /* this was changed to emit version number over the network */ + printf( Q3MAP_VERSION "\n" ); + + /* set exit call */ + atexit( ExitQ3Map ); + + /* read general options first */ + for( i = 1; i < argc; i++ ) + { + /* -connect */ + if( !strcmp( argv[ i ], "-connect" ) ) + { + argv[ i ] = NULL; + i++; + Broadcast_Setup( argv[ i ] ); + argv[ i ] = NULL; + } + + /* verbose */ + else if( !strcmp( argv[ i ], "-v" ) ) + { + verbose = qtrue; + argv[ i ] = NULL; + } + + /* force */ + else if( !strcmp( argv[ i ], "-force" ) ) + { + force = qtrue; + argv[ i ] = NULL; + } + + /* patch subdivisions */ + else if( !strcmp( argv[ i ], "-subdivisions" ) ) + { + argv[ i ] = NULL; + i++; + patchSubdivisions = atoi( argv[ i ] ); + argv[ i ] = NULL; + if( patchSubdivisions <= 0 ) + patchSubdivisions = 1; + } + + /* threads */ + else if( !strcmp( argv[ i ], "-threads" ) ) + { + argv[ i ] = NULL; + i++; + numthreads = atoi( argv[ i ] ); + argv[ i ] = NULL; + } + } + + /* init model library */ + PicoInit(); + PicoSetMallocFunc( safe_malloc ); + PicoSetFreeFunc( free ); + PicoSetPrintFunc( PicoPrintFunc ); + PicoSetLoadFileFunc( PicoLoadFileFunc ); + PicoSetFreeFileFunc( free ); + + /* set number of threads */ + ThreadSetDefault(); + + /* generate sinusoid jitter table */ + for( i = 0; i < MAX_JITTERS; i++ ) + { + jitters[ i ] = sin( i * 139.54152147 ); + //% Sys_Printf( "Jitter %4d: %f\n", i, jitters[ i ] ); + } + + /* we print out two versions, q3map's main version (since it evolves a bit out of GtkRadiant) + and we put the GtkRadiant version to make it easy to track with what version of Radiant it was built with */ + + Sys_Printf( "Q3Map - v1.0r (c) 1999 Id Software Inc.\n" ); + Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" ); + Sys_Printf( "GtkRadiant - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" ); + Sys_Printf( "%s\n", Q3MAP_MOTD ); + + /* ydnar: new path initialization */ + InitPaths( &argc, argv ); + + /* check if we have enough options left to attempt something */ + if( argc < 2 ) + Error( "Usage: %s [general options] [options] mapfile", argv[ 0 ] ); + + /* info */ + if( !strcmp( argv[ 1 ], "-info" ) ) + r = BSPInfo( argc - 2, argv + 2 ); + + /* vis */ + else if( !strcmp( argv[ 1 ], "-vis" ) ) + r = VisMain( argc - 1, argv + 1 ); + + /* light */ + else if( !strcmp( argv[ 1 ], "-light" ) ) + r = LightMain( argc - 1, argv + 1 ); + + /* vlight */ + else if( !strcmp( argv[ 1 ], "-vlight" ) ) + { + Sys_Printf( "WARNING: VLight is no longer supported, defaulting to -light -fast instead\n\n" ); + argv[ 1 ] = "-fast"; /* eek a hack */ + r = LightMain( argc, argv ); + } + + /* ydnar: lightmap export */ + else if( !strcmp( argv[ 1 ], "-export" ) ) + r = ExportLightmapsMain( argc - 1, argv + 1 ); + + /* ydnar: lightmap import */ + else if( !strcmp( argv[ 1 ], "-import" ) ) + r = ImportLightmapsMain( argc - 1, argv + 1 ); + + /* ydnar: bsp scaling */ + else if( !strcmp( argv[ 1 ], "-scale" ) ) + r = ScaleBSPMain( argc - 1, argv + 1 ); + + /* ydnar: bsp conversion */ + else if( !strcmp( argv[ 1 ], "-convert" ) ) + r = ConvertBSPMain( argc - 1, argv + 1 ); + + /* ydnar: otherwise create a bsp */ + else + r = BSPMain( argc, argv ); + + /* emit time */ + end = I_FloatTime(); + Sys_Printf( "%9.0f seconds elapsed\n", end - start ); + + /* shut down connection */ + Broadcast_Shutdown(); + + /* return any error code */ + return r; +} diff --git a/tools/quake3/q3map2/map.c b/tools/quake3/q3map2/map.c new file mode 100644 index 00000000..dbc71f14 --- /dev/null +++ b/tools/quake3/q3map2/map.c @@ -0,0 +1,1649 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define MAP_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* FIXME: remove these vars */ + +/* undefine to make plane finding use linear sort (note: really slow) */ +#define USE_HASHING +#define PLANE_HASHES 8192 + +plane_t *planehash[ PLANE_HASHES ]; + +int c_boxbevels; +int c_edgebevels; +int c_areaportals; +int c_detail; +int c_structural; + + + +/* +PlaneEqual() +ydnar: replaced with variable epsilon for djbob +*/ + +#define NORMAL_EPSILON 0.00001 +#define DIST_EPSILON 0.01 + +qboolean PlaneEqual( plane_t *p, vec3_t normal, vec_t dist ) +{ + float ne, de; + + + /* get local copies */ + ne = normalEpsilon; + de = distanceEpsilon; + + /* compare */ + if( fabs( p->dist - dist ) <= de && + fabs( p->normal[ 0 ] - normal[ 0 ] ) <= ne && + fabs( p->normal[ 1 ] - normal[ 1 ] ) <= ne && + fabs( p->normal[ 2 ] - normal[ 2 ] ) <= ne ) + return qtrue; + + /* different */ + return qfalse; +} + + + +/* +AddPlaneToHash() +*/ + +void AddPlaneToHash( plane_t *p ) +{ + int hash; + + + hash = (PLANE_HASHES - 1) & (int) fabs( p->dist ); + + p->hash_chain = planehash[hash]; + planehash[hash] = p; +} + +/* +================ +CreateNewFloatPlane +================ +*/ +int CreateNewFloatPlane (vec3_t normal, vec_t dist) +{ + plane_t *p, temp; + + if (VectorLength(normal) < 0.5) + { + Sys_Printf( "FloatPlane: bad normal\n"); + return -1; + } + + // create a new plane + if (nummapplanes+2 > MAX_MAP_PLANES) + Error ("MAX_MAP_PLANES"); + + p = &mapplanes[nummapplanes]; + VectorCopy (normal, p->normal); + p->dist = dist; + p->type = (p+1)->type = PlaneTypeForNormal (p->normal); + + VectorSubtract (vec3_origin, normal, (p+1)->normal); + (p+1)->dist = -dist; + + nummapplanes += 2; + + // allways put axial planes facing positive first + if (p->type < 3) + { + if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) + { + // flip order + temp = *p; + *p = *(p+1); + *(p+1) = temp; + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 1; + } + } + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 2; +} + + + +/* +SnapNormal() +snaps a near-axial normal vector +*/ + +void SnapNormal( vec3_t normal ) +{ + int i; + + for( i = 0; i < 3; i++ ) + { + if( fabs( normal[ i ] - 1 ) < normalEpsilon ) + { + VectorClear( normal ); + normal[ i ] = 1; + break; + } + if( fabs( normal[ i ] - -1 ) < normalEpsilon ) + { + VectorClear( normal ); + normal[ i ] = -1; + break; + } + } +} + + + +/* +SnapPlane() +snaps a plane to normal/distance epsilons +*/ + +void SnapPlane( vec3_t normal, vec_t *dist ) +{ + SnapNormal( normal ); + + if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) + *dist = Q_rint( *dist ); +} + + + +/* +FindFloatPlane() +ydnar: changed to allow a number of test points to be supplied that +must be within an epsilon distance of the plane +*/ + +int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) + +#ifdef USE_HASHING + +{ + int i, j, hash, h; + plane_t *p; + vec_t d; + + + /* hash the plane */ + SnapPlane( normal, &dist ); + hash = (PLANE_HASHES - 1) & (int) fabs( dist ); + + /* search the border bins as well */ + for( i = -1; i <= 1; i++ ) + { + h = (hash + i) & (PLANE_HASHES - 1); + for( p = planehash[ h ]; p != NULL; p = p->hash_chain ) + { + /* do standard plane compare */ + if( !PlaneEqual( p, normal, dist ) ) + continue; + + /* ydnar: uncomment the following line for old-style plane finding */ + //% return p - mapplanes; + + /* ydnar: test supplied points against this plane */ + for( j = 0; j < numPoints; j++ ) + { + d = DotProduct( points[ j ], normal ) - dist; + if( fabs( d ) > distanceEpsilon ) + break; + } + + /* found a matching plane */ + if( j >= numPoints ) + return p - mapplanes; + } + } + + /* none found, so create a new one */ + return CreateNewFloatPlane( normal, dist ); +} + +#else + +{ + int i; + plane_t *p; + + + SnapPlane( normal, &dist ); + for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ ) + { + if( PlaneEqual( p, normal, dist ) ) + return i; + } + + return CreateNewFloatPlane( normal, dist ); +} + +#endif + + + +/* +MapPlaneFromPoints() +takes 3 points and finds the plane they lie in +*/ + +int MapPlaneFromPoints( vec3_t *p ) +{ + vec3_t t1, t2, normal; + vec_t dist; + + + /* calc plane normal */ + VectorSubtract( p[ 0 ], p[ 1 ], t1 ); + VectorSubtract( p[ 2 ], p[ 1 ], t2 ); + CrossProduct( t1, t2, normal ); + VectorNormalize( normal, normal ); + + /* calc plane distance */ + dist = DotProduct( p[ 0 ], normal ); + + /* store the plane */ + return FindFloatPlane( normal, dist, 3, p ); +} + + + +/* +SetBrushContents() +the content flags and compile flags on all sides of a brush should be the same +*/ + +void SetBrushContents( brush_t *b ) +{ + int contentFlags, compileFlags; + side_t *s; + int i; + qboolean mixed; + + + /* get initial compile flags from first side */ + s = &b->sides[ 0 ]; + contentFlags = s->contentFlags; + compileFlags = s->compileFlags; + b->contentShader = s->shaderInfo; + mixed = qfalse; + + /* get the content/compile flags for every side in the brush */ + for( i = 1; i < b->numsides; i++, s++ ) + { + s = &b->sides[ i ]; + if( s->shaderInfo == NULL ) + continue; + if( s->contentFlags != contentFlags || s->compileFlags != compileFlags ) + mixed = qtrue; + } + + /* ydnar: getting rid of this stupid warning */ + //% if( mixed ) + //% Sys_FPrintf( SYS_VRB,"Entity %i, Brush %i: mixed face contentFlags\n", b->entitynum, b->brushnum ); + + /* check for detail & structural */ + if( (compileFlags & C_DETAIL) && (compileFlags & C_STRUCTURAL) ) + { + xml_Select( "Mixed detail and structural (defaulting to structural)", mapEnt->mapEntityNum, entitySourceBrushes, qfalse ); + compileFlags &= ~C_DETAIL; + } + + /* the fulldetail flag will cause detail brushes to be treated like normal brushes */ + if( fulldetail ) + compileFlags &= ~C_DETAIL; + + /* all translucent brushes that aren't specifically made structural will be detail */ + if( (compileFlags & C_TRANSLUCENT) && !(compileFlags & C_STRUCTURAL) ) + compileFlags |= C_DETAIL; + + /* detail? */ + if( compileFlags & C_DETAIL ) + { + c_detail++; + b->detail = qtrue; + } + else + { + c_structural++; + b->detail = qfalse; + } + + /* opaque? */ + if( compileFlags & C_TRANSLUCENT ) + b->opaque = qfalse; + else + b->opaque = qtrue; + + /* areaportal? */ + if( compileFlags & C_AREAPORTAL ) + c_areaportals++; + + /* set brush flags */ + b->contentFlags = contentFlags; + b->compileFlags = compileFlags; +} + + + +/* +AddBrushBevels() +adds any additional planes necessary to allow the brush being +built to be expanded against axial bounding boxes +ydnar 2003-01-20: added mrelusive fixes +*/ + +void AddBrushBevels( void ) +{ + int axis, dir; + int i, j, k, l, order; + side_t sidetemp; + side_t *s, *s2; + winding_t *w, *w2; + vec3_t normal; + float dist; + vec3_t vec, vec2; + float d, minBack; + + // + // add the axial planes + // + order = 0; + for ( axis = 0; axis < 3; axis++ ) { + for ( dir = -1; dir <= 1; dir += 2, order++ ) { + // see if the plane is allready present + for ( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ ) + { + /* ydnar: testing disabling of mre code */ + #if 0 + if ( dir > 0 ) { + if ( mapplanes[s->planenum].normal[axis] >= 0.9999f ) { + break; + } + } + else { + if ( mapplanes[s->planenum].normal[axis] <= -0.9999f ) { + break; + } + } + #else + if( (dir > 0 && mapplanes[ s->planenum ].normal[ axis ] == 1.0f ) || + (dir < 0 && mapplanes[ s->planenum ].normal[ axis ] == -1.0f) ) + break; + #endif + } + + if ( i == buildBrush->numsides ) { + // add a new side + if ( buildBrush->numsides == MAX_BUILD_SIDES ) { + xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue); + } + memset( s, 0, sizeof( *s ) ); + buildBrush->numsides++; + VectorClear (normal); + normal[axis] = dir; + + if( dir == 1 ) + { + /* ydnar: adding bevel plane snapping for fewer bsp planes */ + if( bevelSnap > 0 ) + dist = floor( buildBrush->maxs[ axis ] / bevelSnap ) * bevelSnap; + else + dist = buildBrush->maxs[ axis ]; + } + else + { + /* ydnar: adding bevel plane snapping for fewer bsp planes */ + if( bevelSnap > 0 ) + dist = -ceil( buildBrush->mins[ axis ] / bevelSnap ) * bevelSnap; + else + dist = -buildBrush->mins[ axis ]; + } + + s->planenum = FindFloatPlane( normal, dist, 0, NULL ); + s->contentFlags = buildBrush->sides[ 0 ].contentFlags; + s->bevel = qtrue; + c_boxbevels++; + } + + // if the plane is not in it canonical order, swap it + if ( i != order ) { + sidetemp = buildBrush->sides[order]; + buildBrush->sides[order] = buildBrush->sides[i]; + buildBrush->sides[i] = sidetemp; + } + } + } + + // + // add the edge bevels + // + if ( buildBrush->numsides == 6 ) { + return; // pure axial + } + + // test the non-axial plane edges + for ( i = 6; i < buildBrush->numsides; i++ ) { + s = buildBrush->sides + i; + w = s->winding; + if ( !w ) { + continue; + } + for ( j = 0; j < w->numpoints; j++) { + k = (j+1)%w->numpoints; + VectorSubtract( w->p[j], w->p[k], vec ); + if ( VectorNormalize( vec, vec ) < 0.5f ) { + continue; + } + SnapNormal( vec ); + for ( k = 0; k < 3; k++ ) { + if ( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) { + break; // axial + } + } + if ( k != 3 ) { + continue; // only test non-axial edges + } + + /* debug code */ + //% Sys_Printf( "-------------\n" ); + + // try the six possible slanted axials from this edge + for ( axis = 0; axis < 3; axis++ ) { + for ( dir = -1; dir <= 1; dir += 2 ) { + // construct a plane + VectorClear( vec2 ); + vec2[axis] = dir; + CrossProduct( vec, vec2, normal ); + if ( VectorNormalize( normal, normal ) < 0.5f ) { + continue; + } + dist = DotProduct( w->p[j], normal ); + + // if all the points on all the sides are + // behind this plane, it is a proper edge bevel + for ( k = 0; k < buildBrush->numsides; k++ ) { + + // if this plane has allready been used, skip it + if ( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ) ) { + break; + } + + w2 = buildBrush->sides[k].winding; + if ( !w2 ) { + continue; + } + minBack = 0.0f; + for ( l = 0; l < w2->numpoints; l++ ) { + d = DotProduct( w2->p[l], normal ) - dist; + if ( d > 0.1f ) { + break; // point in front + } + if ( d < minBack ) { + minBack = d; + } + } + // if some point was at the front + if ( l != w2->numpoints ) { + break; + } + + // if no points at the back then the winding is on the bevel plane + if ( minBack > -0.1f ) { + //% Sys_Printf( "On bevel plane\n" ); + break; + } + } + + if ( k != buildBrush->numsides ) { + continue; // wasn't part of the outer hull + } + + /* debug code */ + //% Sys_Printf( "n = %f %f %f\n", normal[ 0 ], normal[ 1 ], normal[ 2 ] ); + + // add this plane + if( buildBrush->numsides == MAX_BUILD_SIDES ) { + xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue); + } + s2 = &buildBrush->sides[buildBrush->numsides]; + buildBrush->numsides++; + memset( s2, 0, sizeof( *s2 ) ); + + s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[ j ] ); + s2->contentFlags = buildBrush->sides[0].contentFlags; + s2->bevel = qtrue; + c_edgebevels++; + } + } + } + } +} + + + +/* +FinishBrush() +produces a final brush based on the buildBrush->sides array +and links it to the current entity +*/ + +brush_t *FinishBrush( void ) +{ + brush_t *b; + + + /* create windings for sides and bounds for brush */ + if ( !CreateBrushWindings( buildBrush ) ) + return NULL; + + /* origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity. + after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */ + if( buildBrush->compileFlags & C_ORIGIN ) + { + char string[ 32 ]; + vec3_t origin; + + if( numEntities == 1 ) + { + Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n", + mapEnt->mapEntityNum, entitySourceBrushes ); + return NULL; + } + + VectorAdd (buildBrush->mins, buildBrush->maxs, origin); + VectorScale (origin, 0.5, origin); + + sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] ); + SetKeyValue( &entities[ numEntities - 1 ], "origin", string); + + VectorCopy( origin, entities[ numEntities - 1 ].origin); + + /* don't keep this brush */ + return NULL; + } + + /* determine if the brush is an area portal */ + if( buildBrush->compileFlags & C_AREAPORTAL ) + { + if( numEntities != 1 ) + { + Sys_Printf ("Entity %i, Brush %i: areaportals only allowed in world\n", numEntities - 1, entitySourceBrushes ); + return NULL; + } + } + + /* add bevel planes */ + AddBrushBevels(); + + /* keep it */ + b = CopyBrush( buildBrush ); + + /* set map entity and brush numbering */ + b->entityNum = mapEnt->mapEntityNum; + b->brushNum = entitySourceBrushes; + + /* set original */ + b->original = b; + + /* link opaque brushes to head of list, translucent brushes to end */ + if( b->opaque || mapEnt->lastBrush == NULL ) + { + b->next = mapEnt->brushes; + mapEnt->brushes = b; + if( mapEnt->lastBrush == NULL ) + mapEnt->lastBrush = b; + } + else + { + b->next = NULL; + mapEnt->lastBrush->next = b; + mapEnt->lastBrush = b; + } + + /* return to sender */ + return b; +} + + + +/* +TextureAxisFromPlane() +determines best orthagonal axis to project a texture onto a wall +(must be identical in radiant!) +*/ + +vec3_t baseaxis[18] = +{ + {0,0,1}, {1,0,0}, {0,-1,0}, // floor + {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling + {1,0,0}, {0,1,0}, {0,0,-1}, // west wall + {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall + {0,1,0}, {1,0,0}, {0,0,-1}, // south wall + {0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv ) +{ + int bestaxis; + vec_t dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if( dot > best + 0.0001f ) /* ydnar: bug 637 fix, suggested by jmonroe */ + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + + +/* +QuakeTextureVecs() +creates world-to-texture mapping vecs for crappy quake plane arrangements +*/ + +void QuakeTextureVecs( plane_t *plane, vec_t shift[ 2 ], vec_t rotate, vec_t scale[ 2 ], vec_t mappingVecs[ 2 ][ 4 ] ) +{ + vec3_t vecs[2]; + int sv, tv; + vec_t ang, sinv, cosv; + vec_t ns, nt; + int i, j; + + + TextureAxisFromPlane(plane, vecs[0], vecs[1]); + + if (!scale[0]) + scale[0] = 1; + if (!scale[1]) + scale[1] = 1; + + // rotate axis + if (rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (vecs[0][0]) + sv = 0; + else if (vecs[0][1]) + sv = 1; + else + sv = 2; + + if (vecs[1][0]) + tv = 0; + else if (vecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) { + ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; + nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + mappingVecs[i][j] = vecs[i][j] / scale[i]; + + mappingVecs[0][3] = shift[0]; + mappingVecs[1][3] = shift[1]; +} + + + +/* +ParseRawBrush() +parses the sides into buildBrush->sides[], nothing else. +no validation, back plane removal, etc. + +Timo - 08/26/99 +added brush epairs parsing ( ignoring actually ) +Timo - 08/04/99 +added exclusive brush primitive parsing +Timo - 08/08/99 +support for old brush format back in +NOTE: it would be "cleaner" to have seperate functions to parse between old and new brushes +*/ + +static void ParseRawBrush( qboolean onlyLights ) +{ + side_t *side; + vec3_t planePoints[ 3 ]; + int planenum; + shaderInfo_t *si; + vec_t shift[ 2 ]; + vec_t rotate; + vec_t scale[ 2 ]; + char name[ MAX_QPATH ]; + char shader[ MAX_QPATH ]; + int flags; + + + /* initial setup */ + buildBrush->numsides = 0; + buildBrush->detail = qfalse; + + /* bp */ + if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) + MatchToken( "{" ); + + /* parse sides */ + while( 1 ) + { + if( !GetToken( qtrue ) ) + break; + if( !strcmp( token, "}" ) ) + break; + + /* ttimo : bp: here we may have to jump over brush epairs (only used in editor) */ + if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) + { + while( 1 ) + { + if( strcmp( token, "(" ) ) + GetToken( qfalse ); + else + break; + GetToken( qtrue ); + } + } + UnGetToken(); + + /* test side count */ + if( buildBrush->numsides >= MAX_BUILD_SIDES ) + xml_Select( "MAX_BUILD_SIDES", buildBrush->entityNum, buildBrush->brushNum, qtrue ); + + /* add side */ + side = &buildBrush->sides[ buildBrush->numsides ]; + memset( side, 0, sizeof( *side ) ); + buildBrush->numsides++; + + /* read the three point plane definition */ + Parse1DMatrix( 3, planePoints[ 0 ] ); + Parse1DMatrix( 3, planePoints[ 1 ] ); + Parse1DMatrix( 3, planePoints[ 2 ] ); + + /* bp: read the texture matrix */ + if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) + Parse2DMatrix( 2, 3, (float*) side->texMat ); + + /* read shader name */ + GetToken( qfalse ); + strcpy( name, token ); + + /* bp */ + if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) + { + GetToken( qfalse ); + shift[ 0 ] = atof( token ); + GetToken( qfalse ); + shift[ 1 ] = atof( token ); + GetToken( qfalse ); + rotate = atof( token ); + GetToken( qfalse ); + scale[ 0 ] = atof( token ); + GetToken( qfalse ); + scale[ 1 ] = atof( token ); + } + + /* set default flags and values */ + sprintf( shader, "textures/%s", name ); + if( onlyLights ) + si = &shaderInfo[ 0 ]; + else + si = ShaderInfoForShader( shader ); + side->shaderInfo = si; + side->surfaceFlags = si->surfaceFlags; + side->contentFlags = si->contentFlags; + side->compileFlags = si->compileFlags; + side->value = si->value; + + /* ydnar: gs mods: bias texture shift */ + if( si->globalTexture == qfalse ) + { + shift[ 0 ] -= (floor( shift[ 0 ] / si->shaderWidth ) * si->shaderWidth); + shift[ 1 ] -= (floor( shift[ 1 ] / si->shaderHeight ) * si->shaderHeight); + } + + /* + historically, there are 3 integer values at the end of a brushside line in a .map file. + in quake 3, the only thing that mattered was the first of these three values, which + was previously the content flags. and only then did a single bit matter, the detail + bit. because every game has its own special flags for specifying detail, the + traditionally game-specified CONTENTS_DETAIL flag was overridden for Q3Map 2.3.0 + by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but + is stored in compileFlags, as opposed to contentFlags, for multiple-game + portability. :sigh: + */ + + if( TokenAvailable() ) + { + /* get detail bit from map content flags */ + GetToken( qfalse ); + flags = atoi( token ); + if( flags & C_DETAIL ) + side->compileFlags |= C_DETAIL; + + /* historical */ + GetToken( qfalse ); + //% td.flags = atoi( token ); + GetToken( qfalse ); + //% td.value = atoi( token ); + } + + /* find the plane number */ + planenum = MapPlaneFromPoints( planePoints ); + side->planenum = planenum; + + /* bp: get the texture mapping for this texturedef / plane combination */ + if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) + QuakeTextureVecs( &mapplanes[ planenum ], shift, rotate, scale, side->vecs ); + } + + /* bp */ + if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) + { + UnGetToken(); + MatchToken( "}" ); + MatchToken( "}" ); + } +} + + + +/* +RemoveDuplicateBrushPlanes +returns false if the brush has a mirrored set of planes, +meaning it encloses no volume. +also removes planes without any normal +*/ + +qboolean RemoveDuplicateBrushPlanes( brush_t *b ) +{ + int i, j, k; + side_t *sides; + + sides = b->sides; + + for ( i = 1 ; i < b->numsides ; i++ ) { + + // check for a degenerate plane + if ( sides[i].planenum == -1) { + xml_Select( "degenerate plane", b->entityNum, b->brushNum, qfalse ); + // remove it + for ( k = i + 1 ; k < b->numsides ; k++ ) { + sides[k-1] = sides[k]; + } + b->numsides--; + i--; + continue; + } + + // check for duplication and mirroring + for ( j = 0 ; j < i ; j++ ) { + if ( sides[i].planenum == sides[j].planenum ) { + xml_Select( "duplicate plane", b->entityNum, b->brushNum, qfalse ); + // remove the second duplicate + for ( k = i + 1 ; k < b->numsides ; k++ ) { + sides[k-1] = sides[k]; + } + b->numsides--; + i--; + break; + } + + if ( sides[i].planenum == (sides[j].planenum ^ 1) ) { + // mirror plane, brush is invalid + xml_Select( "mirrored plane", b->entityNum, b->brushNum, qfalse ); + return qfalse; + } + } + } + return qtrue; +} + + + +/* +ParseBrush() +parses a brush out of a map file and sets it up +*/ + +static void ParseBrush( qboolean onlyLights ) +{ + brush_t *b; + + + /* parse the brush out of the map */ + ParseRawBrush( onlyLights ); + + /* only go this far? */ + if( onlyLights ) + return; + + /* set some defaults */ + buildBrush->portalareas[ 0 ] = -1; + buildBrush->portalareas[ 1 ] = -1; + buildBrush->entityNum = numMapEntities - 1; + buildBrush->brushNum = entitySourceBrushes; + + /* if there are mirrored planes, the entire brush is invalid */ + if( !RemoveDuplicateBrushPlanes( buildBrush ) ) + return; + + /* get the content for the entire brush */ + SetBrushContents( buildBrush ); + + /* allow detail brushes to be removed */ + if( nodetail && (buildBrush->compileFlags & C_DETAIL) ) + { + //% FreeBrush( buildBrush ); + return; + } + + /* allow liquid brushes to be removed */ + if( nowater && (buildBrush->compileFlags & C_LIQUID ) ) + { + //% FreeBrush( buildBrush ); + return; + } + + /* ydnar: allow hint brushes to be removed */ + if( noHint && (buildBrush->compileFlags & C_HINT) ) + { + //% FreeBrush( buildBrush ); + return; + } + + /* finish the brush */ + b = FinishBrush(); +} + + + +/* +MoveBrushesToWorld() +takes all of the brushes from the current entity and +adds them to the world's brush list +(used by func_group) +*/ + +void MoveBrushesToWorld( entity_t *ent ) +{ + brush_t *b, *next; + parseMesh_t *pm; + + + /* move brushes */ + for( b = ent->brushes; b != NULL; b = next ) + { + /* get next brush */ + next = b->next; + + /* link opaque brushes to head of list, translucent brushes to end */ + if( b->opaque || entities[ 0 ].lastBrush == NULL ) + { + b->next = entities[ 0 ].brushes; + entities[ 0 ].brushes = b; + if( entities[ 0 ].lastBrush == NULL ) + entities[ 0 ].lastBrush = b; + } + else + { + b->next = NULL; + entities[ 0 ].lastBrush->next = b; + entities[ 0 ].lastBrush = b; + } + + //% b->next = entities[ 0 ].brushes; + //% entities[ 0 ].brushes = b; + } + ent->brushes = NULL; + + /* move patches */ + if( ent->patches != NULL ) + { + for( pm = ent->patches; pm->next; pm = pm->next ); + + pm->next = entities[ 0 ].patches; + entities[ 0 ].patches = ent->patches; + + ent->patches = NULL; + } +} + + + +/* +AdjustBrushesForOrigin() +*/ + +void AdjustBrushesForOrigin( entity_t *ent ) +{ + + int i; + side_t *s; + vec_t newdist; + brush_t *b; + parseMesh_t *p; + + + /* walk brush list */ + for( b = ent->brushes; b != NULL; b = b->next ) + { + /* offset brush planes */ + for( i = 0; i < b->numsides; i++) + { + /* get brush side */ + s = &b->sides[ i ]; + + /* offset side plane */ + newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin ); + + /* find a new plane */ + s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL ); + } + + /* rebuild brush windings (ydnar: just offsetting the winding above should be fine) */ + CreateBrushWindings( b ); + } + + /* walk patch list */ + for( p = ent->patches; p != NULL; p = p->next ) + { + for( i = 0; i < (p->mesh.width * p->mesh.height); i++ ) + VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz ); + } +} + + + +/* +SetEntityBounds() - ydnar +finds the bounds of an entity's brushes (necessary for terrain-style generic metashaders) +*/ + +void SetEntityBounds( entity_t *e ) +{ + int i; + brush_t *b; + parseMesh_t *p; + vec3_t mins, maxs; + const char *value; + + + + + /* walk the entity's brushes/patches and determine bounds */ + ClearBounds( mins, maxs ); + for( b = e->brushes; b; b = b->next ) + { + AddPointToBounds( b->mins, mins, maxs ); + AddPointToBounds( b->maxs, mins, maxs ); + } + for( p = e->patches; p; p = p->next ) + { + for( i = 0; i < (p->mesh.width * p->mesh.height); i++ ) + AddPointToBounds( p->mesh.verts[ i ].xyz, mins, maxs ); + } + + /* try to find explicit min/max key */ + value = ValueForKey( e, "min" ); + if( value[ 0 ] != '\0' ) + GetVectorForKey( e, "min", mins ); + value = ValueForKey( e, "max" ); + if( value[ 0 ] != '\0' ) + GetVectorForKey( e, "max", maxs ); + + /* store the bounds */ + for( b = e->brushes; b; b = b->next ) + { + VectorCopy( mins, b->eMins ); + VectorCopy( maxs, b->eMaxs ); + } + for( p = e->patches; p; p = p->next ) + { + VectorCopy( mins, p->eMins ); + VectorCopy( maxs, p->eMaxs ); + } +} + + + +/* +LoadEntityIndexMap() - ydnar +based on LoadAlphaMap() from terrain.c, a little more generic +*/ + +void LoadEntityIndexMap( entity_t *e ) +{ + int i, size, numLayers, w, h; + const char *value, *indexMapFilename, *shader; + char ext[ MAX_QPATH ], offset[ 4096 ], *search, *space; + byte *pixels; + unsigned int *pixels32; + indexMap_t *im; + brush_t *b; + parseMesh_t *p; + + + /* this only works with bmodel ents */ + if( e->brushes == NULL && e->patches == NULL ) + return; + + /* determine if there is an index map (support legacy "alphamap" key as well) */ + value = ValueForKey( e, "_indexmap" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( e, "alphamap" ); + if( value[ 0 ] == '\0' ) + return; + indexMapFilename = value; + + /* get number of layers (support legacy "layers" key as well) */ + value = ValueForKey( e, "_layers" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( e, "layers" ); + if( value[ 0 ] == '\0' ) + { + Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_layers\" or \"layers\" key\n", indexMapFilename ); + Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" ); + return; + } + numLayers = atoi( value ); + if( numLayers < 1 ) + { + Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has < 1 layer (%d)\n", indexMapFilename, numLayers ); + Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" ); + return; + } + + /* get base shader name (support legacy "shader" key as well) */ + value = ValueForKey( mapEnt, "_shader" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( e, "shader" ); + if( value[ 0 ] == '\0' ) + { + Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" has missing \"_shader\" or \"shader\" key\n", indexMapFilename ); + Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" ); + return; + } + shader = value; + + /* note it */ + Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, ValueForKey( e, "classname" ), indexMapFilename ); + + /* get index map file extension */ + ExtractFileExtension( indexMapFilename, ext ); + + /* handle tga image */ + if( !Q_stricmp( ext, "tga" ) ) + { + /* load it */ + Load32BitImage( indexMapFilename, &pixels32, &w, &h ); + + /* convert to bytes */ + size = w * h; + pixels = safe_malloc( size ); + for( i = 0; i < size; i++ ) + { + pixels[ i ] = ((pixels32[ i ] & 0xFF) * numLayers) / 256; + if( pixels[ i ] >= numLayers ) + pixels[ i ] = numLayers - 1; + } + + /* free the 32 bit image */ + free( pixels32 ); + } + else + { + /* load it */ + Load256Image( indexMapFilename, &pixels, NULL, &w, &h ); + + /* debug code */ + //% Sys_Printf( "-------------------------------" ); + + /* fix up out-of-range values */ + size = w * h; + for( i = 0; i < size; i++ ) + { + if( pixels[ i ] >= numLayers ) + pixels[ i ] = numLayers - 1; + + /* debug code */ + //% if( (i % w) == 0 ) + //% Sys_Printf( "\n" ); + //% Sys_Printf( "%c", pixels[ i ] + '0' ); + } + + /* debug code */ + //% Sys_Printf( "\n-------------------------------\n" ); + } + + /* the index map must be at least 2x2 pixels */ + if( w < 2 || h < 2 ) + { + Sys_Printf( "WARNING: Entity with index/alpha map \"%s\" is smaller than 2x2 pixels\n", indexMapFilename ); + Sys_Printf( "Entity will not be textured properly. Check your keys/values.\n" ); + free( pixels ); + return; + } + + /* create a new index map */ + im = safe_malloc( sizeof( *im ) ); + memset( im, 0, sizeof( *im ) ); + + /* set it up */ + im->w = w; + im->h = h; + im->numLayers = numLayers; + strcpy( im->name, indexMapFilename ); + strcpy( im->shader, shader ); + im->pixels = pixels; + + /* get height offsets */ + value = ValueForKey( mapEnt, "_offsets" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( e, "offsets" ); + if( value[ 0 ] != '\0' ) + { + /* value is a space-seperated set of numbers */ + strcpy( offset, value ); + search = offset; + + /* get each value */ + for( i = 0; i < 256 && *search != '\0'; i++ ) + { + space = strstr( search, " " ); + if( space != NULL ) + *space = '\0'; + im->offsets[ i ] = atof( search ); + if( space == NULL ) + break; + search = space + 1; + } + } + + /* store the index map in every brush/patch in the entity */ + for( b = e->brushes; b != NULL; b = b->next ) + b->im = im; + for( p = e->patches; p != NULL; p = p->next ) + p->im = im; +} + + + + + + + +/* +ParseMapEntity() +parses a single entity out of a map file +*/ + +static qboolean ParseMapEntity( qboolean onlyLights ) +{ + epair_t *ep; + const char *classname, *value; + float lightmapScale; + char shader[ MAX_QPATH ]; + shaderInfo_t *celShader = NULL; + brush_t *brush; + parseMesh_t *patch; + qboolean funcGroup; + int castShadows, recvShadows; + + + /* eof check */ + if( !GetToken( qtrue ) ) + return qfalse; + + /* conformance check */ + if( strcmp( token, "{" ) ) + { + Sys_Printf( "WARNING: ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...\n" + "Continuing to process map, but resulting BSP may be invalid.\n", + token, scriptline, entities[ numEntities ].origin[ 0 ], entities[ numEntities ].origin[ 1 ], entities[ numEntities ].origin[ 2 ] ); + return qfalse; + } + + /* range check */ + if( numEntities >= MAX_MAP_ENTITIES ) + Error( "numEntities == MAX_MAP_ENTITIES" ); + + /* setup */ + entitySourceBrushes = 0; + mapEnt = &entities[ numEntities ]; + numEntities++; + memset( mapEnt, 0, sizeof( *mapEnt ) ); + + /* ydnar: true entity numbering */ + mapEnt->mapEntityNum = numMapEntities; + numMapEntities++; + + /* loop */ + while( 1 ) + { + /* get initial token */ + if( !GetToken( qtrue ) ) + { + Sys_Printf( "WARNING: ParseEntity: EOF without closing brace\n" + "Continuing to process map, but resulting BSP may be invalid.\n" ); + return qfalse; + } + + if( !strcmp( token, "}" ) ) + break; + + if( !strcmp( token, "{" ) ) + { + /* parse a brush or patch */ + if( !GetToken( qtrue ) ) + break; + + /* check */ + if( !strcmp( token, "patchDef2" ) ) + { + numMapPatches++; + ParsePatch( onlyLights ); + } + else if( !strcmp( token, "terrainDef" ) ) + { + //% ParseTerrain(); + Sys_Printf( "WARNING: Terrain entity parsing not supported in this build.\n" ); /* ydnar */ + } + else if( !strcmp( token, "brushDef" ) ) + { + if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) + Error( "Old brush format not allowed in new brush format map" ); + g_bBrushPrimit = BPRIMIT_NEWBRUSHES; + + /* parse brush primitive */ + ParseBrush( onlyLights ); + } + else + { + if( g_bBrushPrimit == BPRIMIT_NEWBRUSHES ) + Error( "New brush format not allowed in old brush format map" ); + g_bBrushPrimit = BPRIMIT_OLDBRUSHES; + + /* parse old brush format */ + UnGetToken(); + ParseBrush( onlyLights ); + } + entitySourceBrushes++; + } + else + { + /* parse a key / value pair */ + ep = ParseEPair(); + + /* ydnar: 2002-07-06 fixed wolf bug with empty epairs */ + if( ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' ) + { + ep->next = mapEnt->epairs; + mapEnt->epairs = ep; + } + } + } + + /* ydnar: get classname */ + classname = ValueForKey( mapEnt, "classname" ); + + /* ydnar: only lights? */ + if( onlyLights && Q_strncasecmp( classname, "light", 5 ) ) + { + numEntities--; + return qtrue; + } + + /* ydnar: determine if this is a func_group */ + if( !Q_stricmp( "func_group", classname ) ) + funcGroup = qtrue; + else + funcGroup = qfalse; + + /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */ + if( funcGroup || mapEnt->mapEntityNum == 0 ) + { + //% Sys_Printf( "World: %d\n", mapEnt->mapEntityNum ); + castShadows = WORLDSPAWN_CAST_SHADOWS; + recvShadows = WORLDSPAWN_RECV_SHADOWS; + } + + /* other entities don't cast any shadows, but recv worldspawn shadows */ + else + { + //% Sys_Printf( "Entity: %d\n", mapEnt->mapEntityNum ); + castShadows = ENTITY_CAST_SHADOWS; + recvShadows = ENTITY_RECV_SHADOWS; + } + + /* get explicit shadow flags */ + GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows ); + + /* ydnar: get lightmap scaling value for this entity */ + if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) || + strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ) + { + /* get lightmap scale from entity */ + lightmapScale = FloatForKey( mapEnt, "lightmapscale" ); + if( lightmapScale <= 0.0f ) + lightmapScale = FloatForKey( mapEnt, "_lightmapscale" ); + if( lightmapScale > 0.0f ) + Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale ); + } + else + lightmapScale = 0.0f; + + /* ydnar: get cel shader :) for this entity */ + value = ValueForKey( mapEnt, "_celshader" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ 0 ], "_celshader" ); + if( value[ 0 ] != '\0' ) + { + sprintf( shader, "textures/%s", value ); + celShader = ShaderInfoForShader( shader ); + Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader ); + } + else + celShader = NULL; + + /* attach stuff to everything in the entity */ + for( brush = mapEnt->brushes; brush != NULL; brush = brush->next ) + { + brush->entityNum = mapEnt->mapEntityNum; + brush->castShadows = castShadows; + brush->recvShadows = recvShadows; + brush->lightmapScale = lightmapScale; + brush->celShader = celShader; + } + + for( patch = mapEnt->patches; patch != NULL; patch = patch->next ) + { + patch->entityNum = mapEnt->mapEntityNum; + patch->castShadows = castShadows; + patch->recvShadows = recvShadows; + patch->lightmapScale = lightmapScale; + patch->celShader = celShader; + } + + /* ydnar: gs mods: set entity bounds */ + SetEntityBounds( mapEnt ); + + /* ydnar: gs mods: load shader index map (equivalent to old terrain alphamap) */ + LoadEntityIndexMap( mapEnt ); + + /* get entity origin and adjust brushes */ + GetVectorForKey( mapEnt, "origin", mapEnt->origin ); + if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] ) + AdjustBrushesForOrigin( mapEnt ); + + /* group_info entities are just for editor grouping (fixme: leak!) */ + if( !Q_stricmp( "group_info", classname ) ) + { + numEntities--; + return qtrue; + } + + /* group entities are just for editor convenience, toss all brushes into worldspawn */ + if( funcGroup ) + { + MoveBrushesToWorld( mapEnt ); + numEntities--; + return qtrue; + } + + /* done */ + return qtrue; +} + + + +/* +LoadMapFile() +loads a map file into a list of entities +*/ + +void LoadMapFile( char *filename, qboolean onlyLights ) +{ + FILE *file; + brush_t *b; + int oldNumEntities, numMapBrushes; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- LoadMapFile ---\n" ); + Sys_Printf( "Loading %s\n", filename ); + + /* hack */ + file = SafeOpenRead( filename ); + fclose( file ); + + /* load the map file */ + LoadScriptFile( filename, -1 ); + + /* setup */ + if( onlyLights ) + oldNumEntities = numEntities; + else + numEntities = 0; + + /* initial setup */ + numMapDrawSurfs = 0; + c_detail = 0; + g_bBrushPrimit = BPRIMIT_UNDEFINED; + + /* allocate a very large temporary brush for building the brushes as they are loaded */ + buildBrush = AllocBrush( MAX_BUILD_SIDES ); + + /* parse the map file */ + while( ParseMapEntity( onlyLights ) ); + + /* light loading */ + if( onlyLights ) + { + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d light entities\n", numEntities - oldNumEntities ); + } + else + { + /* set map bounds */ + ClearBounds( mapMins, mapMaxs ); + for( b = entities[ 0 ].brushes; b; b = b->next ) + { + AddPointToBounds( b->mins, mapMins, mapMaxs ); + AddPointToBounds( b->maxs, mapMins, mapMaxs ); + } + + /* get brush counts */ + numMapBrushes = CountBrushList( entities[ 0 ].brushes ); + if( (float) c_detail / (float) numMapBrushes < 0.10f && numMapBrushes > 500 ) + Sys_Printf( "WARNING: Over 90 percent structural map detected. Compile time may be adversely affected.\n" ); + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d total world brushes\n", numMapBrushes ); + Sys_FPrintf( SYS_VRB, "%9d detail brushes\n", c_detail ); + Sys_FPrintf( SYS_VRB, "%9d patches\n", numMapPatches); + Sys_FPrintf( SYS_VRB, "%9d boxbevels\n", c_boxbevels); + Sys_FPrintf( SYS_VRB, "%9d edgebevels\n", c_edgebevels); + Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities ); + Sys_FPrintf( SYS_VRB, "%9d planes\n", nummapplanes); + Sys_Printf( "%9d areaportals\n", c_areaportals); + Sys_Printf( "Size: %5.0f, %5.0f, %5.0f to %5.0f, %5.0f, %5.0f\n", + mapMins[ 0 ], mapMins[ 1 ], mapMins[ 2 ], + mapMaxs[ 0 ], mapMaxs[ 1 ], mapMaxs[ 2 ]); + + /* write bogus map */ + if( fakemap ) + WriteBSPBrushMap( "fakemap.map", entities[ 0 ].brushes ); + } +} diff --git a/tools/quake3/q3map2/mesh.c b/tools/quake3/q3map2/mesh.c new file mode 100644 index 00000000..f1cccf04 --- /dev/null +++ b/tools/quake3/q3map2/mesh.c @@ -0,0 +1,825 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define MESH_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +LerpDrawVert() +returns an 50/50 interpolated vert +*/ + +void LerpDrawVert( bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *out ) +{ + int k; + + + out->xyz[ 0 ] = 0.5 * (a->xyz[ 0 ] + b->xyz[ 0 ]); + out->xyz[ 1 ] = 0.5 * (a->xyz[ 1 ] + b->xyz[ 1 ]); + out->xyz[ 2 ] = 0.5 * (a->xyz[ 2 ] + b->xyz[ 2 ]); + + out->st[ 0 ] = 0.5 * (a->st[ 0 ] + b->st[ 0 ]); + out->st[ 1 ] = 0.5 * (a->st[ 1 ] + b->st[ 1 ]); + + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + { + out->lightmap[ k ][ 0 ] = 0.5f * (a->lightmap[ k ][ 0 ] + b->lightmap[ k ][ 0 ]); + out->lightmap[ k ][ 1 ] = 0.5f * (a->lightmap[ k ][ 1 ] + b->lightmap[ k ][ 1 ]); + out->color[ k ][ 0 ] = (a->color[ k ][ 0 ] + b->color[ k ][ 0 ]) >> 1; + out->color[ k ][ 1 ] = (a->color[ k ][ 1 ] + b->color[ k ][ 1 ]) >> 1; + out->color[ k ][ 2 ] = (a->color[ k ][ 2 ] + b->color[ k ][ 2 ]) >> 1; + out->color[ k ][ 3 ] = (a->color[ k ][ 3 ] + b->color[ k ][ 3 ]) >> 1; + } + + /* ydnar: added normal interpolation */ + out->normal[ 0 ] = 0.5f * (a->normal[ 0 ] + b->normal[ 0 ]); + out->normal[ 1 ] = 0.5f * (a->normal[ 1 ] + b->normal[ 1 ]); + out->normal[ 2 ] = 0.5f * (a->normal[ 2 ] + b->normal[ 2 ]); + + /* if the interpolant created a bogus normal, just copy the normal from a */ + if( VectorNormalize( out->normal, out->normal ) == 0 ) + VectorCopy( a->normal, out->normal ); +} + + + +/* +LerpDrawVertAmount() +returns a biased interpolated vert +*/ + +void LerpDrawVertAmount( bspDrawVert_t *a, bspDrawVert_t *b, float amount, bspDrawVert_t *out ) +{ + int k; + + + out->xyz[ 0 ] = a->xyz[ 0 ] + amount * (b->xyz[ 0 ] - a->xyz[ 0 ]); + out->xyz[ 1 ] = a->xyz[ 1 ] + amount * (b->xyz[ 1 ] - a->xyz[ 1 ]); + out->xyz[ 2 ] = a->xyz[ 2 ] + amount * (b->xyz[ 2 ] - a->xyz[ 2 ]); + + out->st[ 0 ] = a->st[ 0 ] + amount * (b->st[ 0 ] - a->st[ 0 ]); + out->st[ 1 ] = a->st[ 1 ] + amount * (b->st[ 1 ] - a->st[ 1 ]); + + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + { + out->lightmap[ k ][ 0 ] = a->lightmap[ k ][ 0 ] + amount * (b->lightmap[ k ][ 0 ] - a->lightmap[ k ][ 0 ]); + out->lightmap[ k ][ 1 ] = a->lightmap[ k ][ 1 ] + amount * (b->lightmap[ k ][ 1 ] - a->lightmap[ k ][ 1 ]); + out->color[ k ][ 0 ] = a->color[ k ][ 0 ] + amount * (b->color[ k ][ 0 ] - a->color[ k ][ 0 ]); + out->color[ k ][ 1 ] = a->color[ k ][ 1 ] + amount * (b->color[ k ][ 1 ] - a->color[ k ][ 1 ]); + out->color[ k ][ 2 ] = a->color[ k ][ 2 ] + amount * (b->color[ k ][ 2 ] - a->color[ k ][ 2 ]); + out->color[ k ][ 3 ] = a->color[ k ][ 3 ] + amount * (b->color[ k ][ 3 ] - a->color[ k ][ 3 ]); + } + + out->normal[ 0 ] = a->normal[ 0 ] + amount * (b->normal[ 0 ] - a->normal[ 0 ]); + out->normal[ 1 ] = a->normal[ 1 ] + amount * (b->normal[ 1 ] - a->normal[ 1 ]); + out->normal[ 2 ] = a->normal[ 2 ] + amount * (b->normal[ 2 ] - a->normal[ 2 ]); + + /* if the interpolant created a bogus normal, just copy the normal from a */ + if( VectorNormalize( out->normal, out->normal ) == 0 ) + VectorCopy( a->normal, out->normal ); +} + + +void FreeMesh( mesh_t *m ) { + free( m->verts ); + free( m ); +} + +void PrintMesh( mesh_t *m ) { + int i, j; + + for ( i = 0 ; i < m->height ; i++ ) { + for ( j = 0 ; j < m->width ; j++ ) { + Sys_Printf("(%5.2f %5.2f %5.2f) " + , m->verts[i*m->width+j].xyz[0] + , m->verts[i*m->width+j].xyz[1] + , m->verts[i*m->width+j].xyz[2] ); + } + Sys_Printf("\n"); + } +} + + +mesh_t *CopyMesh( mesh_t *mesh ) { + mesh_t *out; + int size; + + out = safe_malloc( sizeof( *out ) ); + out->width = mesh->width; + out->height = mesh->height; + + size = out->width * out->height * sizeof( *out->verts ); + out->verts = safe_malloc( size ); + memcpy( out->verts, mesh->verts, size ); + + return out; +} + + +/* +TransposeMesh() +returns a transposed copy of the mesh, freeing the original +*/ + +mesh_t *TransposeMesh( mesh_t *in ) { + int w, h; + mesh_t *out; + + out = safe_malloc( sizeof( *out ) ); + out->width = in->height; + out->height = in->width; + out->verts = safe_malloc( out->width * out->height * sizeof( bspDrawVert_t ) ); + + for ( h = 0 ; h < in->height ; h++ ) { + for ( w = 0 ; w < in->width ; w++ ) { + out->verts[ w * in->height + h ] = in->verts[ h * in->width + w ]; + } + } + + FreeMesh( in ); + + return out; +} + +void InvertMesh( mesh_t *in ) { + int w, h; + bspDrawVert_t temp; + + for ( h = 0 ; h < in->height ; h++ ) { + for ( w = 0 ; w < in->width / 2 ; w++ ) { + temp = in->verts[ h * in->width + w ]; + in->verts[ h * in->width + w ] = in->verts[ h * in->width + in->width - 1 - w ]; + in->verts[ h * in->width + in->width - 1 - w ] = temp; + } + } +} + +/* +================= +MakeMeshNormals + +================= +*/ +void MakeMeshNormals( mesh_t in ) +{ + int i, j, k, dist; + vec3_t normal; + vec3_t sum; + int count; + vec3_t base; + vec3_t delta; + int x, y; + bspDrawVert_t *dv; + vec3_t around[8], temp; + qboolean good[8]; + qboolean wrapWidth, wrapHeight; + float len; + int neighbors[8][2] = + { + {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} + }; + + + wrapWidth = qfalse; + for ( i = 0 ; i < in.height ; i++ ) { + VectorSubtract( in.verts[i*in.width].xyz, + in.verts[i*in.width+in.width-1].xyz, delta ); + len = VectorLength( delta ); + if ( len > 1.0 ) { + break; + } + } + if ( i == in.height ) { + wrapWidth = qtrue; + } + + wrapHeight = qfalse; + for ( i = 0 ; i < in.width ; i++ ) { + VectorSubtract( in.verts[i].xyz, + in.verts[i + (in.height-1)*in.width].xyz, delta ); + len = VectorLength( delta ); + if ( len > 1.0 ) { + break; + } + } + if ( i == in.width) { + wrapHeight = qtrue; + } + + + for ( i = 0 ; i < in.width ; i++ ) { + for ( j = 0 ; j < in.height ; j++ ) { + count = 0; + dv = &in.verts[j*in.width+i]; + VectorCopy( dv->xyz, base ); + for ( k = 0 ; k < 8 ; k++ ) { + VectorClear( around[k] ); + good[k] = qfalse; + + for ( dist = 1 ; dist <= 3 ; dist++ ) { + x = i + neighbors[k][0] * dist; + y = j + neighbors[k][1] * dist; + if ( wrapWidth ) { + if ( x < 0 ) { + x = in.width - 1 + x; + } else if ( x >= in.width ) { + x = 1 + x - in.width; + } + } + if ( wrapHeight ) { + if ( y < 0 ) { + y = in.height - 1 + y; + } else if ( y >= in.height ) { + y = 1 + y - in.height; + } + } + + if ( x < 0 || x >= in.width || y < 0 || y >= in.height ) { + break; // edge of patch + } + VectorSubtract( in.verts[y*in.width+x].xyz, base, temp ); + if ( VectorNormalize( temp, temp ) == 0 ) { + continue; // degenerate edge, get more dist + } else { + good[k] = qtrue; + VectorCopy( temp, around[k] ); + break; // good edge + } + } + } + + VectorClear( sum ); + for ( k = 0 ; k < 8 ; k++ ) { + if ( !good[k] || !good[(k+1)&7] ) { + continue; // didn't get two points + } + CrossProduct( around[(k+1)&7], around[k], normal ); + if ( VectorNormalize( normal, normal ) == 0 ) { + continue; + } + VectorAdd( normal, sum, sum ); + count++; + } + if ( count == 0 ) { +//Sys_Printf("bad normal\n"); + count = 1; + } + VectorNormalize( sum, dv->normal ); + } + } +} + +/* +PutMeshOnCurve() +drops the aproximating points onto the curve +ydnar: fixme: make this use LerpDrawVert() rather than this complicated mess +*/ + +void PutMeshOnCurve( mesh_t in ) { + int i, j, l, m; + float prev, next; + + + // put all the aproximating points on the curve + for ( i = 0 ; i < in.width ; i++ ) { + for ( j = 1 ; j < in.height ; j += 2 ) { + for ( l = 0 ; l < 3 ; l++ ) { + prev = ( in.verts[j*in.width+i].xyz[l] + in.verts[(j+1)*in.width+i].xyz[l] ) * 0.5; + next = ( in.verts[j*in.width+i].xyz[l] + in.verts[(j-1)*in.width+i].xyz[l] ) * 0.5; + in.verts[j*in.width+i].xyz[l] = ( prev + next ) * 0.5; + + /* ydnar: interpolating st coords */ + if( l < 2 ) + { + prev = ( in.verts[j*in.width+i].st[l] + in.verts[(j+1)*in.width+i].st[l] ) * 0.5; + next = ( in.verts[j*in.width+i].st[l] + in.verts[(j-1)*in.width+i].st[l] ) * 0.5; + in.verts[j*in.width+i].st[l] = ( prev + next ) * 0.5; + + for( m = 0; m < MAX_LIGHTMAPS; m++ ) + { + prev = ( in.verts[j*in.width+i].lightmap[ m ][l] + in.verts[(j+1)*in.width+i].lightmap[ m ][l] ) * 0.5; + next = ( in.verts[j*in.width+i].lightmap[ m ][l] + in.verts[(j-1)*in.width+i].lightmap[ m ][l] ) * 0.5; + in.verts[j*in.width+i].lightmap[ m ][l] = ( prev + next ) * 0.5; + } + } + } + } + } + + for ( j = 0 ; j < in.height ; j++ ) { + for ( i = 1 ; i < in.width ; i += 2 ) { + for ( l = 0 ; l < 3 ; l++ ) { + prev = ( in.verts[j*in.width+i].xyz[l] + in.verts[j*in.width+i+1].xyz[l] ) * 0.5; + next = ( in.verts[j*in.width+i].xyz[l] + in.verts[j*in.width+i-1].xyz[l] ) * 0.5; + in.verts[j*in.width+i].xyz[l] = ( prev + next ) * 0.5; + + /* ydnar: interpolating st coords */ + if( l < 2 ) + { + prev = ( in.verts[j*in.width+i].st[l] + in.verts[j*in.width+i+1].st[l] ) * 0.5; + next = ( in.verts[j*in.width+i].st[l] + in.verts[j*in.width+i-1].st[l] ) * 0.5; + in.verts[j*in.width+i].st[l] = ( prev + next ) * 0.5; + + for( m = 0; m < MAX_LIGHTMAPS; m++ ) + { + prev = ( in.verts[j*in.width+i].lightmap[ m ][l] + in.verts[j*in.width+i+1].lightmap[ m ][l] ) * 0.5; + next = ( in.verts[j*in.width+i].lightmap[ m ][l] + in.verts[j*in.width+i-1].lightmap[ m ][l] ) * 0.5; + in.verts[j*in.width+i].lightmap[ m ][l] = ( prev + next ) * 0.5; + } + } + } + } + } +} + + +/* +================= +SubdivideMesh + +================= +*/ +mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ) +{ + int i, j, k, l; + bspDrawVert_t prev, next, mid; + vec3_t prevxyz, nextxyz, midxyz; + vec3_t delta; + float len; + mesh_t out; + + /* ydnar: static for os x */ + MAC_STATIC bspDrawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS]; + + + out.width = in.width; + out.height = in.height; + + for ( i = 0 ; i < in.width ; i++ ) { + for ( j = 0 ; j < in.height ; j++ ) { + expand[j][i] = in.verts[j*in.width+i]; + } + } + + // horizontal subdivisions + for ( j = 0 ; j + 2 < out.width ; j += 2 ) { + // check subdivided midpoints against control points + for ( i = 0 ; i < out.height ; i++ ) { + for ( l = 0 ; l < 3 ; l++ ) { + prevxyz[l] = expand[i][j+1].xyz[l] - expand[i][j].xyz[l]; + nextxyz[l] = expand[i][j+2].xyz[l] - expand[i][j+1].xyz[l]; + midxyz[l] = (expand[i][j].xyz[l] + expand[i][j+1].xyz[l] * 2 + + expand[i][j+2].xyz[l] ) * 0.25; + } + + // if the span length is too long, force a subdivision + if ( VectorLength( prevxyz ) > minLength + || VectorLength( nextxyz ) > minLength ) { + break; + } + + // see if this midpoint is off far enough to subdivide + VectorSubtract( expand[i][j+1].xyz, midxyz, delta ); + len = VectorLength( delta ); + if ( len > maxError ) { + break; + } + } + + if ( out.width + 2 >= MAX_EXPANDED_AXIS ) { + break; // can't subdivide any more + } + + if ( i == out.height ) { + continue; // didn't need subdivision + } + + // insert two columns and replace the peak + out.width += 2; + + for ( i = 0 ; i < out.height ; i++ ) { + LerpDrawVert( &expand[i][j], &expand[i][j+1], &prev ); + LerpDrawVert( &expand[i][j+1], &expand[i][j+2], &next ); + LerpDrawVert( &prev, &next, &mid ); + + for ( k = out.width - 1 ; k > j + 3 ; k-- ) { + expand[i][k] = expand[i][k-2]; + } + expand[i][j + 1] = prev; + expand[i][j + 2] = mid; + expand[i][j + 3] = next; + } + + // back up and recheck this set again, it may need more subdivision + j -= 2; + + } + + // vertical subdivisions + for ( j = 0 ; j + 2 < out.height ; j += 2 ) { + // check subdivided midpoints against control points + for ( i = 0 ; i < out.width ; i++ ) { + for ( l = 0 ; l < 3 ; l++ ) { + prevxyz[l] = expand[j+1][i].xyz[l] - expand[j][i].xyz[l]; + nextxyz[l] = expand[j+2][i].xyz[l] - expand[j+1][i].xyz[l]; + midxyz[l] = (expand[j][i].xyz[l] + expand[j+1][i].xyz[l] * 2 + + expand[j+2][i].xyz[l] ) * 0.25; + } + + // if the span length is too long, force a subdivision + if ( VectorLength( prevxyz ) > minLength + || VectorLength( nextxyz ) > minLength ) { + break; + } + // see if this midpoint is off far enough to subdivide + VectorSubtract( expand[j+1][i].xyz, midxyz, delta ); + len = VectorLength( delta ); + if ( len > maxError ) { + break; + } + } + + if ( out.height + 2 >= MAX_EXPANDED_AXIS ) { + break; // can't subdivide any more + } + + if ( i == out.width ) { + continue; // didn't need subdivision + } + + // insert two columns and replace the peak + out.height += 2; + + for ( i = 0 ; i < out.width ; i++ ) { + LerpDrawVert( &expand[j][i], &expand[j+1][i], &prev ); + LerpDrawVert( &expand[j+1][i], &expand[j+2][i], &next ); + LerpDrawVert( &prev, &next, &mid ); + + for ( k = out.height - 1 ; k > j + 3 ; k-- ) { + expand[k][i] = expand[k-2][i]; + } + expand[j+1][i] = prev; + expand[j+2][i] = mid; + expand[j+3][i] = next; + } + + // back up and recheck this set again, it may need more subdivision + j -= 2; + + } + + // collapse the verts + + out.verts = &expand[0][0]; + for ( i = 1 ; i < out.height ; i++ ) { + memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(bspDrawVert_t) ); + } + + return CopyMesh(&out); +} + + + +/* +IterationsForCurve() - ydnar +given a curve of a certain length, return the number of subdivision iterations +note: this is affected by subdivision amount +*/ + +int IterationsForCurve( float len, int subdivisions ) +{ + int iterations, facets; + + + /* calculate the number of subdivisions */ + for( iterations = 0; iterations < 3; iterations++ ) + { + facets = subdivisions * 16 * pow( 2, iterations ); + if( facets >= len ) + break; + } + + /* return to caller */ + return iterations; +} + + +/* +SubdivideMesh2() - ydnar +subdivides each mesh quad a specified number of times +*/ + +mesh_t *SubdivideMesh2( mesh_t in, int iterations ) +{ + int i, j, k; + bspDrawVert_t prev, next, mid; + mesh_t out; + + /* ydnar: static for os x */ + MAC_STATIC bspDrawVert_t expand[ MAX_EXPANDED_AXIS ][ MAX_EXPANDED_AXIS ]; + + + /* initial setup */ + out.width = in.width; + out.height = in.height; + for( i = 0; i < in.width; i++ ) + { + for( j = 0; j < in.height; j++ ) + expand[ j ][ i ] = in.verts[ j * in.width + i ]; + } + + /* keep chopping */ + for( iterations; iterations > 0; iterations-- ) + { + /* horizontal subdivisions */ + for( j = 0; j + 2 < out.width; j += 4 ) + { + /* check size limit */ + if( out.width + 2 >= MAX_EXPANDED_AXIS ) + break; + + /* insert two columns and replace the peak */ + out.width += 2; + for( i = 0; i < out.height; i++ ) + { + LerpDrawVert( &expand[ i ][ j ], &expand[ i ][ j + 1 ], &prev ); + LerpDrawVert( &expand[ i ][ j + 1 ], &expand[ i ][ j + 2 ], &next ); + LerpDrawVert( &prev, &next, &mid ); + + for ( k = out.width - 1 ; k > j + 3; k-- ) + expand [ i ][ k ] = expand[ i ][ k - 2 ]; + expand[ i ][ j + 1 ] = prev; + expand[ i ][ j + 2 ] = mid; + expand[ i ][ j + 3 ] = next; + } + + } + + /* vertical subdivisions */ + for ( j = 0; j + 2 < out.height; j += 4 ) + { + /* check size limit */ + if( out.height + 2 >= MAX_EXPANDED_AXIS ) + break; + + /* insert two columns and replace the peak */ + out.height += 2; + for( i = 0; i < out.width; i++ ) + { + LerpDrawVert( &expand[ j ][ i ], &expand[ j + 1 ][ i ], &prev ); + LerpDrawVert( &expand[ j + 1 ][ i ], &expand[ j + 2 ][ i ], &next ); + LerpDrawVert( &prev, &next, &mid ); + + for( k = out.height - 1; k > j + 3; k-- ) + expand[ k ][ i ] = expand[ k - 2 ][ i ]; + expand[ j + 1 ][ i ] = prev; + expand[ j + 2 ][ i ] = mid; + expand[ j + 3 ][ i ] = next; + } + } + } + + /* collapse the verts */ + out.verts = &expand[ 0 ][ 0 ]; + for( i = 1; i < out.height; i++ ) + memmove( &out.verts[ i * out.width ], expand[ i ], out.width * sizeof( bspDrawVert_t ) ); + + /* return to sender */ + return CopyMesh( &out ); +} + + + + + + + +/* +================ +ProjectPointOntoVector +================ +*/ +void ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ) +{ + vec3_t pVec, vec; + + VectorSubtract( point, vStart, pVec ); + VectorSubtract( vEnd, vStart, vec ); + VectorNormalize( vec, vec ); + // project onto the directional vector for this segment + VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj ); +} + +/* +================ +RemoveLinearMeshColumsRows +================ +*/ +mesh_t *RemoveLinearMeshColumnsRows( mesh_t *in ) { + int i, j, k; + float len, maxLength; + vec3_t proj, dir; + mesh_t out; + + /* ydnar: static for os x */ + MAC_STATIC bspDrawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS]; + + + out.width = in->width; + out.height = in->height; + + for ( i = 0 ; i < in->width ; i++ ) { + for ( j = 0 ; j < in->height ; j++ ) { + expand[j][i] = in->verts[j*in->width+i]; + } + } + + for ( j = 1 ; j < out.width - 1; j++ ) { + maxLength = 0; + for ( i = 0 ; i < out.height ; i++ ) { + ProjectPointOntoVector(expand[i][j].xyz, expand[i][j-1].xyz, expand[i][j+1].xyz, proj); + VectorSubtract(expand[i][j].xyz, proj, dir); + len = VectorLength(dir); + if (len > maxLength) { + maxLength = len; + } + } + if (maxLength < 0.1) + { + out.width--; + for ( i = 0 ; i < out.height ; i++ ) { + for (k = j; k < out.width; k++) { + expand[i][k] = expand[i][k+1]; + } + } + j--; + } + } + for ( j = 1 ; j < out.height - 1; j++ ) { + maxLength = 0; + for ( i = 0 ; i < out.width ; i++ ) { + ProjectPointOntoVector(expand[j][i].xyz, expand[j-1][i].xyz, expand[j+1][i].xyz, proj); + VectorSubtract(expand[j][i].xyz, proj, dir); + len = VectorLength(dir); + if (len > maxLength) { + maxLength = len; + } + } + if (maxLength < 0.1) + { + out.height--; + for ( i = 0 ; i < out.width ; i++ ) { + for (k = j; k < out.height; k++) { + expand[k][i] = expand[k+1][i]; + } + } + j--; + } + } + // collapse the verts + out.verts = &expand[0][0]; + for ( i = 1 ; i < out.height ; i++ ) { + memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(bspDrawVert_t) ); + } + + return CopyMesh(&out); +} + + + +/* +================= +SubdivideMeshQuads +================= +*/ +mesh_t *SubdivideMeshQuads( mesh_t *in, float minLength, int maxsize, int *widthtable, int *heighttable ) +{ + int i, j, k, w, h, maxsubdivisions, subdivisions; + vec3_t dir; + float length, maxLength, amount; + mesh_t out; + bspDrawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS]; + + out.width = in->width; + out.height = in->height; + + for ( i = 0 ; i < in->width ; i++ ) { + for ( j = 0 ; j < in->height ; j++ ) { + expand[j][i] = in->verts[j*in->width+i]; + } + } + + if (maxsize > MAX_EXPANDED_AXIS) + Error("SubdivideMeshQuads: maxsize > MAX_EXPANDED_AXIS"); + + // horizontal subdivisions + + maxsubdivisions = (maxsize - in->width) / (in->width - 1); + + for ( w = 0, j = 0 ; w < in->width - 1; w++, j += subdivisions + 1) { + maxLength = 0; + for ( i = 0 ; i < out.height ; i++ ) { + VectorSubtract(expand[i][j+1].xyz, expand[i][j].xyz, dir); + length = VectorLength( dir ); + if (length > maxLength) { + maxLength = length; + } + } + + subdivisions = (int) (maxLength / minLength); + if (subdivisions > maxsubdivisions) + subdivisions = maxsubdivisions; + + widthtable[w] = subdivisions + 1; + if (subdivisions <= 0) + continue; + + out.width += subdivisions; + + for ( i = 0 ; i < out.height ; i++ ) { + for ( k = out.width - 1 ; k > j + subdivisions; k-- ) { + expand[i][k] = expand[i][k-subdivisions]; + } + for (k = 1; k <= subdivisions; k++) + { + amount = (float) k / (subdivisions + 1); + LerpDrawVertAmount(&expand[i][j], &expand[i][j+subdivisions+1], amount, &expand[i][j+k]); + } + } + } + + maxsubdivisions = (maxsize - in->height) / (in->height - 1); + + for ( h = 0, j = 0 ; h < in->height - 1; h++, j += subdivisions + 1) { + maxLength = 0; + for ( i = 0 ; i < out.width ; i++ ) { + VectorSubtract(expand[j+1][i].xyz, expand[j][i].xyz, dir); + length = VectorLength( dir ); + if (length > maxLength) { + maxLength = length; + } + } + + subdivisions = (int) (maxLength / minLength); + if (subdivisions > maxsubdivisions) + subdivisions = maxsubdivisions; + + heighttable[h] = subdivisions + 1; + if (subdivisions <= 0) + continue; + + out.height += subdivisions; + + for ( i = 0 ; i < out.width ; i++ ) { + for ( k = out.height - 1 ; k > j + subdivisions; k-- ) { + expand[k][i] = expand[k-subdivisions][i]; + } + for (k = 1; k <= subdivisions; k++) + { + amount = (float) k / (subdivisions + 1); + LerpDrawVertAmount(&expand[j][i], &expand[j+subdivisions+1][i], amount, &expand[j+k][i]); + } + } + } + + // collapse the verts + out.verts = &expand[0][0]; + for ( i = 1 ; i < out.height ; i++ ) { + memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(bspDrawVert_t) ); + } + + return CopyMesh(&out); +} diff --git a/tools/quake3/q3map2/model.c b/tools/quake3/q3map2/model.c new file mode 100644 index 00000000..15192e2a --- /dev/null +++ b/tools/quake3/q3map2/model.c @@ -0,0 +1,706 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define MODEL_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +PicoPrintFunc() +callback for picomodel.lib +*/ + +void PicoPrintFunc( int level, const char *str ) +{ + if( str == NULL ) + return; + switch( level ) + { + case PICO_NORMAL: + Sys_Printf( "%s\n", str ); + break; + + case PICO_VERBOSE: + Sys_FPrintf( SYS_VRB, "%s\n", str ); + break; + + case PICO_WARNING: + Sys_Printf( "WARNING: %s\n", str ); + break; + + case PICO_ERROR: + Sys_Printf( "ERROR: %s\n", str ); + break; + + case PICO_FATAL: + Error( "ERROR: %s\n", str ); + break; + } +} + + + +/* +PicoLoadFileFunc() +callback for picomodel.lib +*/ + +void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ) +{ + *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 ); +} + + + +/* +FindModel() - ydnar +finds an existing picoModel and returns a pointer to the picoModel_t struct or NULL if not found +*/ + +picoModel_t *FindModel( char *name, int frame ) +{ + int i; + + + /* init */ + if( numPicoModels <= 0 ) + memset( picoModels, 0, sizeof( picoModels ) ); + + /* dummy check */ + if( name == NULL || name[ 0 ] == '\0' ) + return NULL; + + /* search list */ + for( i = 0; i < MAX_MODELS; i++ ) + { + if( picoModels[ i ] != NULL && + !strcmp( PicoGetModelName( picoModels[ i ] ), name ) && + PicoGetModelFrameNum( picoModels[ i ] ) == frame ) + return picoModels[ i ]; + } + + /* no matching picoModel found */ + return NULL; +} + + + +/* +LoadModel() - ydnar +loads a picoModel and returns a pointer to the picoModel_t struct or NULL if not found +*/ + +picoModel_t *LoadModel( char *name, int frame ) +{ + int i; + picoModel_t *model, **pm; + + + /* init */ + if( numPicoModels <= 0 ) + memset( picoModels, 0, sizeof( picoModels ) ); + + /* dummy check */ + if( name == NULL || name[ 0 ] == '\0' ) + return NULL; + + /* try to find existing picoModel */ + model = FindModel( name, frame ); + if( model != NULL ) + return model; + + /* none found, so find first non-null picoModel */ + pm = NULL; + for( i = 0; i < MAX_MODELS; i++ ) + { + if( picoModels[ i ] == NULL ) + { + pm = &picoModels[ i ]; + break; + } + } + + /* too many picoModels? */ + if( pm == NULL ) + Error( "MAX_MODELS (%d) exceeded, there are too many model files referenced by the map.", MAX_MODELS ); + + /* attempt to parse model */ + *pm = PicoLoadModel( (char*) name, frame ); + + /* if loading failed, make a bogus model to silence the rest of the warnings */ + if( *pm == NULL ) + { + /* allocate a new model */ + *pm = PicoNewModel(); + if( *pm == NULL ) + return NULL; + + /* set data */ + PicoSetModelName( *pm, name ); + PicoSetModelFrameNum( *pm, frame ); + } + + /* debug code */ + #if 0 + { + int numSurfaces, numVertexes; + picoSurface_t *ps; + + + Sys_Printf( "Model %s\n", name ); + numSurfaces = PicoGetModelNumSurfaces( *pm ); + for( i = 0; i < numSurfaces; i++ ) + { + ps = PicoGetModelSurface( *pm, i ); + numVertexes = PicoGetSurfaceNumVertexes( ps ); + Sys_Printf( "Surface %d has %d vertexes\n", i, numVertexes ); + } + } + #endif + + /* set count */ + if( *pm != NULL ) + numPicoModels++; + + /* return the picoModel */ + return *pm; +} + + + +/* +InsertModel() - ydnar +adds a picomodel into the bsp +*/ + +void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale ) +{ + int i, j, k, s, numSurfaces; + m4x4_t identity, nTransform; + picoModel_t *model; + picoShader_t *shader; + picoSurface_t *surface; + shaderInfo_t *si; + mapDrawSurface_t *ds; + bspDrawVert_t *dv; + char *picoShaderName; + char shaderName[ MAX_QPATH ]; + picoVec_t *xyz, *normal, *st; + byte *color; + picoIndex_t *indexes; + remap_t *rm, *glob; + + + /* get model */ + model = LoadModel( name, frame ); + if( model == NULL ) + return; + + /* handle null matrix */ + if( transform == NULL ) + { + m4x4_identity( identity ); + transform = identity; + } + + /* hack: Stable-1_2 and trunk have differing row/column major matrix order + this transpose is necessary with Stable-1_2 + uncomment the following line with old m4x4_t (non 1.3/spog_branch) code */ + //% m4x4_transpose( transform ); + + /* create transform matrix for normals */ + memcpy( nTransform, transform, sizeof( m4x4_t ) ); + if( m4x4_invert( nTransform ) ) + Sys_FPrintf( SYS_VRB, "WARNING: Can't invert model transform matrix, using transpose instead\n" ); + m4x4_transpose( nTransform ); + + /* fix bogus lightmap scale */ + if( lightmapScale <= 0.0f ) + lightmapScale = 1.0f; + + /* each surface on the model will become a new map drawsurface */ + numSurfaces = PicoGetModelNumSurfaces( model ); + //% Sys_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces ); + for( s = 0; s < numSurfaces; s++ ) + { + /* get surface */ + surface = PicoGetModelSurface( model, s ); + if( surface == NULL ) + continue; + + /* only handle triangle surfaces initially (fixme: support patches) */ + if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) + continue; + + /* fix the surface's normals */ + PicoFixSurfaceNormals( surface ); + + /* allocate a surface (ydnar: gs mods) */ + ds = AllocDrawSurface( SURFACE_TRIANGLES ); + ds->entityNum = eNum; + ds->castShadows = castShadows; + ds->recvShadows = recvShadows; + + /* get shader name */ + shader = PicoGetSurfaceShader( surface ); + if( shader == NULL ) + picoShaderName = ""; + else + picoShaderName = PicoGetShaderName( shader ); + + /* handle shader remapping */ + glob = NULL; + for( rm = remap; rm != NULL; rm = rm->next ) + { + if( rm->from[ 0 ] == '*' && rm->from[ 1 ] == '\0' ) + glob = rm; + else if( !Q_stricmp( picoShaderName, rm->from ) ) + { + Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", picoShaderName, rm->to ); + picoShaderName = rm->to; + glob = NULL; + break; + } + } + + if( glob != NULL ) + { + Sys_FPrintf( SYS_VRB, "Globbing %s to %s\n", picoShaderName, glob->to ); + picoShaderName = glob->to; + } + + /* shader renaming for sof2 */ + if( renameModelShaders ) + { + strcpy( shaderName, picoShaderName ); + StripExtension( shaderName ); + if( spawnFlags & 1 ) + strcat( shaderName, "_RMG_BSP" ); + else + strcat( shaderName, "_BSP" ); + si = ShaderInfoForShader( shaderName ); + } + else + si = ShaderInfoForShader( picoShaderName ); + + /* set shader */ + ds->shaderInfo = si; + + /* set lightmap scale */ + ds->lightmapScale = lightmapScale; + + /* force to meta? */ + if( si != NULL && si->forceMeta ) + ds->type = SURFACE_FORCED_META; + + /* set particulars */ + ds->numVerts = PicoGetSurfaceNumVertexes( surface ); + ds->verts = safe_malloc( ds->numVerts * sizeof( ds->verts[ 0 ] ) ); + memset( ds->verts, 0, ds->numVerts * sizeof( ds->verts[ 0 ] ) ); + + ds->numIndexes = PicoGetSurfaceNumIndexes( surface ); + ds->indexes = safe_malloc( ds->numIndexes * sizeof( ds->indexes[ 0 ] ) ); + memset( ds->indexes, 0, ds->numIndexes * sizeof( ds->indexes[ 0 ] ) ); + + /* copy vertexes */ + for( i = 0; i < ds->numVerts; i++ ) + { + /* get vertex */ + dv = &ds->verts[ i ]; + + /* xyz and normal */ + xyz = PicoGetSurfaceXYZ( surface, i ); + VectorCopy( xyz, dv->xyz ); + m4x4_transform_point( transform, dv->xyz ); + + normal = PicoGetSurfaceNormal( surface, i ); + VectorCopy( normal, dv->normal ); + m4x4_transform_normal( nTransform, dv->normal ); + VectorNormalize( dv->normal, dv->normal ); + + /* ydnar: tek-fu celshading support for flat shaded shit */ + if( flat ) + { + dv->st[ 0 ] = si->stFlat[ 0 ]; + dv->st[ 1 ] = si->stFlat[ 1 ]; + } + + /* ydnar: gs mods: added support for explicit shader texcoord generation */ + else if( si->tcGen ) + { + /* project the texture */ + dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], dv->xyz ); + dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], dv->xyz ); + } + + /* normal texture coordinates */ + { + st = PicoGetSurfaceST( surface, 0, i ); + dv->st[ 0 ] = st[ 0 ]; + dv->st[ 1 ] = st[ 1 ]; + } + + /* set lightmap/color bits */ + color = PicoGetSurfaceColor( surface, 0, i ); + for( j = 0; j < MAX_LIGHTMAPS; j++ ) + { + dv->lightmap[ j ][ 0 ] = 0.0f; + dv->lightmap[ j ][ 1 ] = 0.0f; + dv->color[ j ][ 0 ] = color[ 0 ]; + dv->color[ j ][ 1 ] = color[ 1 ]; + dv->color[ j ][ 2 ] = color[ 2 ]; + dv->color[ j ][ 3 ] = color[ 3 ]; + } + } + + /* copy indexes */ + indexes = PicoGetSurfaceIndexes( surface, 0 ); + for( i = 0; i < ds->numIndexes; i++ ) + ds->indexes[ i ] = indexes[ i ]; + + /* set cel shader */ + ds->celShader = celShader; + + /* finish surface */ + FinishSurface( ds ); + + /* ydnar: giant hack land: generate clipping brushes for model triangles */ + if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */ + { + vec3_t points[ 3 ], backs[ 3 ]; + vec4_t plane, reverse, pa, pb, pc; + vec3_t nadir; + + + /* temp hack */ + if( (si->compileFlags & C_TRANSLUCENT) || !(si->compileFlags & C_SOLID) ) + continue; + + /* overflow check */ + if( (nummapplanes + 64) >= (MAX_MAP_PLANES >> 1) ) + continue; + + /* walk triangle list */ + for( i = 0; i < ds->numIndexes; i += 3 ) + { + /* overflow hack */ + if( (nummapplanes + 64) >= (MAX_MAP_PLANES >> 1) ) + { + Sys_Printf( "WARNING: MAX_MAP_PLANES (%d) hit generating clip brushes for model %s.\n", + MAX_MAP_PLANES, name ); + break; + } + + /* make points and back points */ + for( j = 0; j < 3; j++ ) + { + /* get vertex */ + dv = &ds->verts[ ds->indexes[ i + j ] ]; + + /* copy xyz */ + VectorCopy( dv->xyz, points[ j ] ); + VectorCopy( dv->xyz, backs[ j ] ); + + /* find nearest axial to normal and push back points opposite */ + /* note: this doesn't work as well as simply using the plane of the triangle, below */ + for( k = 0; k < 3; k++ ) + { + if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) && + fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) ) + { + backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f; + break; + } + } + } + + /* make plane for triangle */ + if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) ) + { + /* regenerate back points */ + for( j = 0; j < 3; j++ ) + { + /* get vertex */ + dv = &ds->verts[ ds->indexes[ i + j ] ]; + + /* copy xyz */ + VectorCopy( dv->xyz, backs[ j ] ); + + /* find nearest axial to plane normal and push back points opposite */ + for( k = 0; k < 3; k++ ) + { + if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) && + fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) ) + { + backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f; + break; + } + } + } + + /* make back plane */ + VectorScale( plane, -1.0f, reverse ); + reverse[ 3 ] = -(plane[ 3 ] - 1); + + /* make back pyramid point */ + VectorCopy( points[ 0 ], nadir ); + VectorAdd( nadir, points[ 1 ], nadir ); + VectorAdd( nadir, points[ 2 ], nadir ); + VectorScale( nadir, 0.3333333333333f, nadir ); + VectorMA( nadir, -2.0f, plane, nadir ); + + /* make 3 more planes */ + //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) && + //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) && + //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) ) + if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) && + PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) && + PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) ) + { + /* build a brush */ + buildBrush = AllocBrush( 48 ); + + buildBrush->entityNum = mapEntityNum; + buildBrush->original = buildBrush; + buildBrush->contentShader = si; + buildBrush->compileFlags = si->compileFlags; + buildBrush->contentFlags = si->contentFlags; + buildBrush->detail = qtrue; + + /* set up brush sides */ + buildBrush->numsides = 5; + for( j = 0; j < buildBrush->numsides; j++ ) + buildBrush->sides[ j ].shaderInfo = si; + buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points ); + buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] ); + buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] ); + buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] ); + buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points ); + + /* add to entity */ + if( CreateBrushWindings( buildBrush ) ) + { + AddBrushBevels(); + //% EmitBrushes( buildBrush, NULL, NULL ); + buildBrush->next = entities[ mapEntityNum ].brushes; + entities[ mapEntityNum ].brushes = buildBrush; + entities[ mapEntityNum ].numBrushes++; + } + else + free( buildBrush ); + } + } + } + } + } +} + + + +/* +AddTriangleModels() +adds misc_model surfaces to the bsp +*/ + +void AddTriangleModels( entity_t *e ) +{ + int num, frame, castShadows, recvShadows, spawnFlags; + entity_t *e2; + const char *targetName; + const char *target, *model, *value; + char shader[ MAX_QPATH ]; + shaderInfo_t *celShader; + float temp, baseLightmapScale, lightmapScale; + vec3_t origin, scale, angles; + m4x4_t transform; + epair_t *ep; + remap_t *remap, *remap2; + char *split; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- AddTriangleModels ---\n" ); + + /* get current brush entity targetname */ + if( e == entities ) + targetName = ""; + else + { + targetName = ValueForKey( e, "targetname" ); + + /* misc_model entities target non-worldspawn brush model entities */ + if( targetName[ 0 ] == '\0' ) + return; + } + + /* get lightmap scale */ + baseLightmapScale = FloatForKey( e, "_lightmapscale" ); + if( baseLightmapScale <= 0.0f ) + baseLightmapScale = 0.0f; + + /* walk the entity list */ + for( num = 1; num < numEntities; num++ ) + { + /* get e2 */ + e2 = &entities[ num ]; + + /* convert misc_models into raw geometry */ + if( Q_stricmp( "misc_model", ValueForKey( e2, "classname" ) ) ) + continue; + + /* ydnar: added support for md3 models on non-worldspawn models */ + target = ValueForKey( e2, "target" ); + if( strcmp( target, targetName ) ) + continue; + + /* get model name */ + model = ValueForKey( e2, "model" ); + if( model[ 0 ] == '\0' ) + { + Sys_Printf( "WARNING: misc_model at %i %i %i without a model key\n", + (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] ); + continue; + } + + /* get model frame */ + frame = IntForKey( e2, "_frame" ); + + /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */ + if( e == entities ) + { + castShadows = WORLDSPAWN_CAST_SHADOWS; + recvShadows = WORLDSPAWN_RECV_SHADOWS; + } + + /* other entities don't cast any shadows, but recv worldspawn shadows */ + else + { + castShadows = ENTITY_CAST_SHADOWS; + recvShadows = ENTITY_RECV_SHADOWS; + } + + /* get explicit shadow flags */ + GetEntityShadowFlags( e2, e, &castShadows, &recvShadows ); + + /* get spawnflags */ + spawnFlags = IntForKey( e2, "spawnflags" ); + + /* get origin */ + GetVectorForKey( e2, "origin", origin ); + VectorSubtract( origin, e->origin, origin ); /* offset by parent */ + + /* get scale */ + scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = 1.0f; + temp = FloatForKey( e2, "modelscale" ); + if( temp != 0.0f ) + scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = temp; + value = ValueForKey( e2, "modelscale_vec" ); + if( value[ 0 ] != '\0' ) + sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] ); + + /* get "angle" (yaw) or "angles" (pitch yaw roll) */ + angles[ 0 ] = angles[ 1 ] = angles[ 2 ] = 0.0f; + angles[ 2 ] = FloatForKey( e2, "angle" ); + value = ValueForKey( e2, "angles" ); + if( value[ 0 ] != '\0' ) + sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] ); + + /* set transform matrix (thanks spog) */ + m4x4_identity( transform ); + m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin ); + + /* get shader remappings */ + remap = NULL; + for( ep = e2->epairs; ep != NULL; ep = ep->next ) + { + /* look for keys prefixed with "_remap" */ + if( ep->key != NULL && ep->value != NULL && + ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' && + !Q_strncasecmp( ep->key, "_remap", 6 ) ) + { + /* create new remapping */ + remap2 = remap; + remap = safe_malloc( sizeof( *remap ) ); + remap->next = remap2; + strcpy( remap->from, ep->value ); + + /* split the string */ + split = strchr( remap->from, ';' ); + if( split == NULL ) + { + Sys_Printf( "WARNING: Shader _remap key found in misc_model without a ; character\n" ); + free( remap ); + remap = remap2; + continue; + } + + /* store the split */ + *split = '\0'; + strcpy( remap->to, (split + 1) ); + + /* note it */ + //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to ); + } + } + + /* ydnar: cel shader support */ + value = ValueForKey( e2, "_celshader" ); + if( value[ 0 ] == '\0' ) + value = ValueForKey( &entities[ 0 ], "_celshader" ); + if( value[ 0 ] != '\0' ) + { + sprintf( shader, "textures/%s", value ); + celShader = ShaderInfoForShader( shader ); + } + else + celShader = NULL; + + /* get lightmap scale */ + lightmapScale = FloatForKey( e2, "_lightmapscale" ); + if( lightmapScale <= 0.0f ) + lightmapScale = baseLightmapScale; + + /* insert the model */ + InsertModel( (char*) model, frame, transform, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale ); + + /* free shader remappings */ + while( remap != NULL ) + { + remap2 = remap->next; + free( remap ); + remap = remap2; + } + } +} diff --git a/tools/quake3/q3map2/patch.c b/tools/quake3/q3map2/patch.c new file mode 100644 index 00000000..a9542004 --- /dev/null +++ b/tools/quake3/q3map2/patch.c @@ -0,0 +1,524 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define PATCH_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +ExpandLongestCurve() - ydnar +finds length of quadratic curve specified and determines if length is longer than the supplied max +*/ + +#define APPROX_SUBDIVISION 8 + +static void ExpandLongestCurve( float *longestCurve, vec3_t a, vec3_t b, vec3_t c ) +{ + int i; + float t, len; + vec3_t ab, bc, ac, pt, last, delta; + + + /* calc vectors */ + VectorSubtract( b, a, ab ); + if( VectorNormalize( ab, ab ) < 0.125f ) + return; + VectorSubtract( c, b, bc ); + if( VectorNormalize( bc, bc ) < 0.125f ) + return; + VectorSubtract( c, a, ac ); + if( VectorNormalize( ac, ac ) < 0.125f ) + return; + + /* if all 3 vectors are the same direction, then this edge is linear, so we ignore it */ + if( DotProduct( ab, bc ) > 0.99f && DotProduct( ab, ac ) > 0.99f ) + return; + + /* recalculate vectors */ + VectorSubtract( b, a, ab ); + VectorSubtract( c, b, bc ); + + /* determine length */ + VectorCopy( a, last ); + for( i = 0, len = 0.0f, t = 0.0f; i < APPROX_SUBDIVISION; i++, t += (1.0f / APPROX_SUBDIVISION) ) + { + /* calculate delta */ + delta[ 0 ] = ((1.0f - t) * ab[ 0 ]) + (t * bc[ 0 ]); + delta[ 1 ] = ((1.0f - t) * ab[ 1 ]) + (t * bc[ 1 ]); + delta[ 2 ] = ((1.0f - t) * ab[ 2 ]) + (t * bc[ 2 ]); + + /* add to first point and calculate pt-pt delta */ + VectorAdd( a, delta, pt ); + VectorSubtract( pt, last, delta ); + + /* add it to length and store last point */ + len += VectorLength( delta ); + VectorCopy( pt, last ); + } + + /* longer? */ + if( len > *longestCurve ) + *longestCurve = len; +} + + + +/* +ExpandMaxIterations() - ydnar +determines how many iterations a quadratic curve needs to be subdivided with to fit the specified error +*/ + +static void ExpandMaxIterations( int *maxIterations, int maxError, vec3_t a, vec3_t b, vec3_t c ) +{ + int i, j; + vec3_t prev, next, mid, delta, delta2; + float len, len2; + int numPoints, iterations; + vec3_t points[ MAX_EXPANDED_AXIS ]; + + + /* initial setup */ + numPoints = 3; + VectorCopy( a, points[ 0 ] ); + VectorCopy( b, points[ 1 ] ); + VectorCopy( c, points[ 2 ] ); + + /* subdivide */ + for( i = 0; i + 2 < numPoints; i += 2 ) + { + /* check subdivision limit */ + if( numPoints + 2 >= MAX_EXPANDED_AXIS ) + break; + + /* calculate new curve deltas */ + for( j = 0; j < 3; j++ ) + { + prev[ j ] = points[ i + 1 ][ j ] - points[ i ][ j ]; + next[ j ] = points[ i + 2 ][ j ] - points[ i + 1 ][ j ]; + mid[ j ] = (points[ i ][ j ] + points[ i + 1 ][ j ] * 2.0f + points[ i + 2 ][ j ]) * 0.25f; + } + + /* see if this midpoint is off far enough to subdivide */ + VectorSubtract( points[ i + 1 ], mid, delta ); + len = VectorLength( delta ); + if( len < maxError ) + continue; + + /* subdivide */ + numPoints += 2; + + /* create new points */ + for( j = 0; j < 3; j++ ) + { + prev[ j ] = 0.5f * (points[ i ][ j ] + points[ i + 1 ][ j ]); + next[ j ] = 0.5f * (points[ i + 1 ][ j ] + points[ i + 2 ][ j ]); + mid[ j ] = 0.5f * (prev[ j ] + next[ j ]); + } + + /* push points out */ + for( j = numPoints - 1; j > i + 3; j-- ) + VectorCopy( points[ j - 2 ], points[ j ] ); + + /* insert new points */ + VectorCopy( prev, points[ i + 1 ] ); + VectorCopy( mid, points[ i + 2 ] ); + VectorCopy( next, points[ i + 3 ] ); + + /* back up and recheck this set again, it may need more subdivision */ + i -= 2; + } + + /* put the line on the curve */ + for( i = 1; i < numPoints; i += 2 ) + { + for( j = 0; j < 3; j++ ) + { + prev[ j ] = 0.5f * (points[ i ][ j ] + points[ i + 1 ][ j ] ); + next[ j ] = 0.5f * (points[ i ][ j ] + points[ i - 1 ][ j ] ); + points[ i ][ j ] = 0.5f * (prev[ j ] + next[ j ]); + } + } + + /* eliminate linear sections */ + for( i = 0; i + 2 < numPoints; i++ ) + { + /* create vectors */ + VectorSubtract( points[ i + 1 ], points[ i ], delta ); + len = VectorNormalize( delta, delta ); + VectorSubtract( points[ i + 2 ], points[ i + 1 ], delta2 ); + len2 = VectorNormalize( delta2, delta2 ); + + /* if either edge is degenerate, then eliminate it */ + if( len < 0.0625f || len2 < 0.0625f || DotProduct( delta, delta2 ) >= 1.0f ) + { + for( j = i + 1; j + 1 < numPoints; j++ ) + VectorCopy( points[ j + 1 ], points[ j ] ); + numPoints--; + continue; + } + } + + /* the number of iterations is 2^(points - 1) - 1 */ + numPoints >>= 1; + iterations = 0; + while( numPoints > 1 ) + { + numPoints >>= 1; + iterations++; + } + + /* more? */ + if( iterations > *maxIterations ) + *maxIterations = iterations; +} + + + +/* +ParsePatch() +creates a mapDrawSurface_t from the patch text +*/ + +void ParsePatch( qboolean onlyLights ) +{ + vec_t info[ 5 ]; + int i, j, k; + parseMesh_t *pm; + char texture[ MAX_QPATH ]; + char shader[ MAX_QPATH ]; + mesh_t m; + bspDrawVert_t *verts; + epair_t *ep; + vec4_t delta, delta2, delta3; + qboolean degenerate; + float longestCurve; + int maxIterations; + + + MatchToken( "{" ); + + /* get texture */ + GetToken( qtrue ); + strcpy( texture, token ); + + Parse1DMatrix( 5, info ); + m.width = info[0]; + m.height = info[1]; + m.verts = verts = safe_malloc( m.width * m.height * sizeof( m.verts[0] ) ); + + if( m.width < 0 || m.width > MAX_PATCH_SIZE || m.height < 0 || m.height > MAX_PATCH_SIZE ) + Error( "ParsePatch: bad size" ); + + MatchToken( "(" ); + for( j = 0; j < m.width ; j++ ) + { + MatchToken( "(" ); + for( i = 0; i < m.height ; i++ ) + { + Parse1DMatrix( 5, verts[ i * m.width + j ].xyz ); + + /* ydnar: fix colors */ + for( k = 0; k < MAX_LIGHTMAPS; k++ ) + { + verts[ i * m.width + j ].color[ k ][ 0 ] = 255; + verts[ i * m.width + j ].color[ k ][ 1 ] = 255; + verts[ i * m.width + j ].color[ k ][ 2 ] = 255; + verts[ i * m.width + j ].color[ k ][ 3 ] = 255; + } + } + MatchToken( ")" ); + } + MatchToken( ")" ); + + // if brush primitives format, we may have some epairs to ignore here + GetToken(qtrue); + if (g_bBrushPrimit!=BPRIMIT_OLDBRUSHES && strcmp(token,"}")) + { + // NOTE: we leak that! + ep = ParseEPair(); + } + else + UnGetToken(); + + MatchToken( "}" ); + MatchToken( "}" ); + + /* short circuit */ + if( noCurveBrushes || onlyLights ) + return; + + + /* ydnar: delete and warn about degenerate patches */ + j = (m.width * m.height); + VectorClear( delta ); + delta[ 3 ] = 0; + degenerate = qtrue; + + /* find first valid vector */ + for( i = 1; i < j && delta[ 3 ] == 0; i++ ) + { + VectorSubtract( m.verts[ 0 ].xyz, m.verts[ i ].xyz, delta ); + delta[ 3 ] = VectorNormalize( delta, delta ); + } + + /* secondary degenerate test */ + if( delta[ 3 ] == 0 ) + degenerate = qtrue; + else + { + /* if all vectors match this or are zero, then this is a degenerate patch */ + for( i = 1; i < j && degenerate == qtrue; i++ ) + { + VectorSubtract( m.verts[ 0 ].xyz, m.verts[ i ].xyz, delta2 ); + delta2[ 3 ] = VectorNormalize( delta2, delta2 ); + if( delta2[ 3 ] != 0 ) + { + /* create inverse vector */ + VectorCopy( delta2, delta3 ); + delta3[ 3 ] = delta2[ 3 ]; + VectorInverse( delta3 ); + + /* compare */ + if( VectorCompare( delta, delta2 ) == qfalse && VectorCompare( delta, delta3 ) == qfalse ) + degenerate = qfalse; + } + } + } + + /* warn and select degenerate patch */ + if( degenerate ) + { + xml_Select( "degenerate patch", mapEnt->mapEntityNum, entitySourceBrushes, qfalse ); + free( m.verts ); + return; + } + + /* find longest curve on the mesh */ + longestCurve = 0.0f; + maxIterations = 0; + for( j = 0; j + 2 < m.width; j += 2 ) + { + for( i = 0; i + 2 < m.height; i += 2 ) + { + ExpandLongestCurve( &longestCurve, verts[ i * m.width + j ].xyz, verts[ i * m.width + (j + 1) ].xyz, verts[ i * m.width + (j + 2) ].xyz ); /* row */ + ExpandLongestCurve( &longestCurve, verts[ i * m.width + j ].xyz, verts[ (i + 1) * m.width + j ].xyz, verts[ (i + 2) * m.width + j ].xyz ); /* col */ + ExpandMaxIterations( &maxIterations, patchSubdivisions, verts[ i * m.width + j ].xyz, verts[ i * m.width + (j + 1) ].xyz, verts[ i * m.width + (j + 2) ].xyz ); /* row */ + ExpandMaxIterations( &maxIterations, patchSubdivisions, verts[ i * m.width + j ].xyz, verts[ (i + 1) * m.width + j ].xyz, verts[ (i + 2) * m.width + j ].xyz ); /* col */ + } + } + + /* allocate patch mesh */ + pm = safe_malloc( sizeof( *pm ) ); + memset( pm, 0, sizeof( *pm ) ); + + /* ydnar: add entity/brush numbering */ + pm->entityNum = mapEnt->mapEntityNum; + pm->brushNum = entitySourceBrushes; + + /* set shader */ + sprintf( shader, "textures/%s", texture ); + pm->shaderInfo = ShaderInfoForShader( shader ); + + /* set mesh */ + pm->mesh = m; + + /* set longest curve */ + pm->longestCurve = longestCurve; + pm->maxIterations = maxIterations; + + /* link to the entity */ + pm->next = mapEnt->patches; + mapEnt->patches = pm; +} + + + +/* +GrowGroup_r() +recursively adds patches to a lod group +*/ + +static void GrowGroup_r( parseMesh_t *pm, int patchNum, int patchCount, parseMesh_t **meshes, byte *bordering, byte *group ) +{ + int i; + const byte *row; + + + /* early out check */ + if( group[ patchNum ] ) + return; + + + /* set it */ + group[ patchNum ] = 1; + row = bordering + patchNum * patchCount; + + /* check maximums */ + if( meshes[ patchNum ]->longestCurve > pm->longestCurve ) + pm->longestCurve = meshes[ patchNum ]->longestCurve; + if( meshes[ patchNum ]->maxIterations > pm->maxIterations ) + pm->maxIterations = meshes[ patchNum ]->maxIterations; + + /* walk other patches */ + for( i = 0; i < patchCount; i++ ) + { + if( row[ i ] ) + GrowGroup_r( pm, i, patchCount, meshes, bordering, group ); + } +} + + +/* +PatchMapDrawSurfs() +any patches that share an edge need to choose their +level of detail as a unit, otherwise the edges would +pull apart. +*/ + +void PatchMapDrawSurfs( entity_t *e ) +{ + int i, j, k, l, c1, c2; + parseMesh_t *pm; + parseMesh_t *check, *scan; + mapDrawSurface_t *ds; + int patchCount, groupCount; + bspDrawVert_t *v1, *v2; + vec3_t bounds[ 2 ]; + byte *bordering; + + /* ydnar: mac os x fails with these if not static */ + MAC_STATIC parseMesh_t *meshes[ MAX_MAP_DRAW_SURFS ]; + MAC_STATIC qb_t grouped[ MAX_MAP_DRAW_SURFS ]; + MAC_STATIC byte group[ MAX_MAP_DRAW_SURFS ]; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- PatchMapDrawSurfs ---\n" ); + + patchCount = 0; + for ( pm = e->patches ; pm ; pm = pm->next ) { + meshes[patchCount] = pm; + patchCount++; + } + + if ( !patchCount ) { + return; + } + bordering = safe_malloc( patchCount * patchCount ); + memset( bordering, 0, patchCount * patchCount ); + + // build the bordering matrix + for ( k = 0 ; k < patchCount ; k++ ) { + bordering[k*patchCount+k] = 1; + + for ( l = k+1 ; l < patchCount ; l++ ) { + check = meshes[k]; + scan = meshes[l]; + c1 = scan->mesh.width * scan->mesh.height; + v1 = scan->mesh.verts; + + for ( i = 0 ; i < c1 ; i++, v1++ ) { + c2 = check->mesh.width * check->mesh.height; + v2 = check->mesh.verts; + for ( j = 0 ; j < c2 ; j++, v2++ ) { + if ( fabs( v1->xyz[0] - v2->xyz[0] ) < 1.0 + && fabs( v1->xyz[1] - v2->xyz[1] ) < 1.0 + && fabs( v1->xyz[2] - v2->xyz[2] ) < 1.0 ) { + break; + } + } + if ( j != c2 ) { + break; + } + } + if ( i != c1 ) { + // we have a connection + bordering[k*patchCount+l] = + bordering[l*patchCount+k] = 1; + } else { + // no connection + bordering[k*patchCount+l] = + bordering[l*patchCount+k] = 0; + } + + } + } + + /* build groups */ + memset( grouped, 0, patchCount ); + groupCount = 0; + for ( i = 0; i < patchCount; i++ ) + { + /* get patch */ + scan = meshes[ i ]; + + /* start a new group */ + if( !grouped[ i ] ) + groupCount++; + + /* recursively find all patches that belong in the same group */ + memset( group, 0, patchCount ); + GrowGroup_r( scan, i, patchCount, meshes, bordering, group ); + + /* bound them */ + ClearBounds( bounds[ 0 ], bounds[ 1 ] ); + for( j = 0; j < patchCount; j++ ) + { + if ( group[ j ] ) + { + grouped[ j ] = qtrue; + check = meshes[ j ]; + c1 = check->mesh.width * check->mesh.height; + v1 = check->mesh.verts; + for( k = 0; k < c1; k++, v1++ ) + AddPointToBounds( v1->xyz, bounds[ 0 ], bounds[ 1 ] ); + } + } + + /* debug code */ + //% Sys_Printf( "Longest curve: %f Iterations: %d\n", scan->longestCurve, scan->maxIterations ); + + /* create drawsurf */ + scan->grouped = qtrue; + ds = DrawSurfaceForMesh( e, scan, NULL ); /* ydnar */ + VectorCopy( bounds[ 0 ], ds->bounds[ 0 ] ); + VectorCopy( bounds[ 1 ], ds->bounds[ 1 ] ); + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d patches\n", patchCount ); + Sys_FPrintf( SYS_VRB, "%9d patch LOD groups\n", groupCount ); +} + diff --git a/tools/quake3/q3map2/path_init.c b/tools/quake3/q3map2/path_init.c new file mode 100644 index 00000000..e90b382d --- /dev/null +++ b/tools/quake3/q3map2/path_init.c @@ -0,0 +1,456 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define PATH_INIT_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* path support */ +#define MAX_BASE_PATHS 10 +#define MAX_GAME_PATHS 10 + +char *homePath; +char installPath[ MAX_OS_PATH ]; + +int numBasePaths; +char *basePaths[ MAX_BASE_PATHS ]; +int numGamePaths; +char *gamePaths[ MAX_GAME_PATHS ]; + + + +/* +some of this code is based off the original q3map port from loki +and finds various paths. moved here from bsp.c for clarity. +*/ + +/* +PathLokiGetHomeDir() +gets the user's home dir (for ~/.q3a) +*/ + +char *LokiGetHomeDir( void ) +{ + #ifndef Q_UNIX + return NULL; + #else + char *home; + uid_t id; + struct passwd *pwd; + + + /* get the home environment variable */ + home = getenv( "HOME" ); + if( home == NULL ) + { + /* do some more digging */ + id = getuid(); + setpwent(); + while( (pwd = getpwent()) != NULL ) + { + if( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + } + endpwent(); + } + + /* return it */ + return home; + #endif +} + + + +/* +PathLokiInitPaths() +initializes some paths on linux/os x +*/ + +void LokiInitPaths( char *argv0 ) +{ + #ifndef Q_UNIX + /* this is kinda crap, but hey */ + strcpy( installPath, "../" ); + #else + char temp[ MAX_OS_PATH ]; + char *home; + char *path; + char *last; + qboolean found; + + + /* get home dir */ + home = LokiGetHomeDir(); + if( home == NULL ) + home = "."; + + /* do some path divining */ + strcpy( temp, argv0 ); + if( strrchr( temp, '/' ) ) + argv0 = strrchr( argv0, '/' ) + 1; + else + { + /* get path environment variable */ + path = getenv( "PATH" ); + + /* minor setup */ + last[ 0 ] = path[ 0 ]; + last[ 1 ] = '\0'; + found = qfalse; + + /* go through each : segment of path */ + while( last[ 0 ] != '\0' && found == qfalse ) + { + /* null out temp */ + temp[ 0 ] = '\0'; + + /* find next chunk */ + last = strchr( path, ':' ); + if( last == NULL ) + last = path + strlen( path ); + + /* found home dir candidate */ + if( *path == '~' ) + { + strcpy( temp, home ); + path++; + } + + /* concatenate */ + if( last > (path + 1) ) + { + strncat( temp, path, (last - path) ); + strcat( temp, "/" ); + } + strcat( temp, "./" ); + strcat( temp, argv0 ); + + /* verify the path */ + if( access( temp, X_OK ) == 0 ) + found++; + path = last + 1; + } + } + + /* flake */ + if( realpath( temp, installPath ) ) + { + /* q3map is in "tools/" */ + *(strrchr( installPath, '/' )) = '\0'; + *(strrchr( installPath, '/' ) + 1) = '\0'; + } + + /* set home path */ + homePath = home; + #endif +} + + + +/* +CleanPath() - ydnar +cleans a dos path \ -> / +*/ + +void CleanPath( char *path ) +{ + while( *path ) + { + if( *path == '\\' ) + *path = '/'; + path++; + } +} + + + +/* +SetGame() - ydnar +sets the game based on a -game argument +doesn't set it if the game doesn't match any known games +*/ + +void SetGame( char *arg ) +{ + int i; + + + /* dummy check */ + if( arg == NULL || arg[ 0 ] == '\0' ) + return; + + /* joke */ + if( !Q_stricmp( arg, "quake1" ) || + !Q_stricmp( arg, "quake2" ) || + !Q_stricmp( arg, "unreal" ) || + !Q_stricmp( arg, "ut2k3" ) || + !Q_stricmp( arg, "dn3d" ) || + !Q_stricmp( arg, "dnf" ) || + !Q_stricmp( arg, "hl" ) ) + { + Sys_Printf( "April fools, silly rabbit!\n" ); + exit( 0 ); + } + + /* test it */ + i = 0; + while( games[ i ].arg != NULL ) + { + if( Q_stricmp( arg, games[ i ].arg ) == 0 ) + game = &games[ i ]; + i++; + } +} + + + +/* +AddBasePath() - ydnar +adds a base path to the list +*/ + +void AddBasePath( char *path ) +{ + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS ) + return; + + /* add it to the list */ + basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 ); + strcpy( basePaths[ numBasePaths ], path ); + CleanPath( basePaths[ numBasePaths ] ); + numBasePaths++; +} + + + +/* +AddHomeBasePath() - ydnar +adds a base path to the beginning of the list, prefixed by ~/ +*/ + +void AddHomeBasePath( char *path ) +{ + #ifdef Q_UNIX + int i; + char temp[ MAX_OS_PATH ]; + + + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' ) + return; + + /* make a hole */ + for( i = 0; i < (MAX_BASE_PATHS - 1); i++ ) + basePaths[ i + 1 ] = basePaths[ i ]; + + /* concatenate home dir and path */ + sprintf( temp, "%s/%s", homePath, path ); + + /* add it to the list */ + basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 ); + strcpy( basePaths[ 0 ], temp ); + CleanPath( basePaths[ 0 ] ); + numBasePaths++; + #endif +} + + + +/* +AddGamePath() - ydnar +adds a game path to the list +*/ + +void AddGamePath( char *path ) +{ + /* dummy check */ + if( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS ) + return; + + /* add it to the list */ + gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 ); + strcpy( gamePaths[ numGamePaths ], path ); + CleanPath( gamePaths[ numGamePaths ] ); + numGamePaths++; +} + + + + +/* +InitPaths() - ydnar +cleaned up some of the path initialization code from bsp.c +will remove any arguments it uses +*/ + +void InitPaths( int *argc, char **argv ) +{ + int i, j, k, len, len2; + char temp[ MAX_OS_PATH ]; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" ); + + /* get the install path for backup */ + LokiInitPaths( argv[ 0 ] ); + + /* set game to default (q3a) */ + game = &games[ 0 ]; + numBasePaths = 0; + numGamePaths = 0; + + /* parse through the arguments and extract those relevant to paths */ + for( i = 0; i < *argc; i++ ) + { + /* check for null */ + if( argv[ i ] == NULL ) + continue; + + /* -game */ + if( strcmp( argv[ i ], "-game" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No game specified after %s", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + SetGame( argv[ i ] ); + argv[ i ] = NULL; + } + + /* -fs_basepath */ + else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + AddBasePath( argv[ i ] ); + argv[ i ] = NULL; + } + + /* -fs_game */ + else if( strcmp( argv[ i ], "-fs_game" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + AddGamePath( argv[ i ] ); + argv[ i ] = NULL; + } + } + + /* remove processed arguments */ + for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ ) + { + for( j; j < *argc && argv[ j ] == NULL; j++ ); + argv[ i ] = argv[ j ]; + if( argv[ i ] != NULL ) + k++; + } + *argc = k; + + /* add standard game path */ + AddGamePath( game->gamePath ); + + /* if there is no base path set, figure it out */ + if( numBasePaths == 0 ) + { + /* this is another crappy replacement for SetQdirFromPath() */ + len2 = strlen( game->magic ); + for( i = 0; i < *argc && numBasePaths == 0; i++ ) + { + /* extract the arg */ + strcpy( temp, argv[ i ] ); + CleanPath( temp ); + len = strlen( temp ); + Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game->magic, temp, i ); + + /* this is slow, but only done once */ + for( j = 0; j < (len - len2); j++ ) + { + /* check for the game's magic word */ + if( Q_strncasecmp( &temp[ j ], game->magic, len2 ) == 0 ) + { + /* now find the next slash and nuke everything after it */ + while( temp[ ++j ] != '/' && temp[ j ] != '\0' ); + temp[ j ] = '\0'; + + /* add this as a base path */ + AddBasePath( temp ); + break; + } + } + } + + /* add install path */ + if( numBasePaths == 0 ) + AddBasePath( installPath ); + + /* check again */ + if( numBasePaths == 0 ) + Error( "Failed to find a valid base path." ); + } + + /* this only affects unix */ + AddHomeBasePath( game->homeBasePath ); + + /* initialize vfs paths */ + if( numBasePaths > MAX_BASE_PATHS ) + numBasePaths = MAX_BASE_PATHS; + if( numGamePaths > MAX_GAME_PATHS ) + numGamePaths = MAX_GAME_PATHS; + + /* walk the list of game paths */ + for( j = 0; j < numGamePaths; j++ ) + { + /* walk the list of base paths */ + for( i = 0; i < numBasePaths; i++ ) + { + /* create a full path and initialize it */ + sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] ); + vfsInitDirectory( temp ); + } + } + + /* done */ + Sys_Printf( "\n" ); +} + + + + diff --git a/tools/quake3/q3map2/portals.c b/tools/quake3/q3map2/portals.c new file mode 100644 index 00000000..0b3cdfd3 --- /dev/null +++ b/tools/quake3/q3map2/portals.c @@ -0,0 +1,970 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define PORTALS_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* ydnar: to fix broken portal windings */ +extern qboolean FixWinding( winding_t *w ); + + +int c_active_portals; +int c_peak_portals; +int c_boundary; +int c_boundary_sides; + +/* +=========== +AllocPortal +=========== +*/ +portal_t *AllocPortal (void) +{ + portal_t *p; + + if (numthreads == 1) + c_active_portals++; + if (c_active_portals > c_peak_portals) + c_peak_portals = c_active_portals; + + p = safe_malloc (sizeof(portal_t)); + memset (p, 0, sizeof(portal_t)); + + return p; +} + +void FreePortal (portal_t *p) +{ + if (p->winding) + FreeWinding (p->winding); + if (numthreads == 1) + c_active_portals--; + free (p); +} + + + +/* +PortalPassable +returns true if the portal has non-opaque leafs on both sides +*/ + +qboolean PortalPassable( portal_t *p ) +{ + /* is this to global outside leaf? */ + if( !p->onnode ) + return qfalse; + + /* this should never happen */ + if( p->nodes[ 0 ]->planenum != PLANENUM_LEAF || + p->nodes[ 1 ]->planenum != PLANENUM_LEAF ) + Error( "Portal_EntityFlood: not a leaf" ); + + /* ydnar: added antiportal to supress portal generation for visibility blocking */ + if( p->compileFlags & C_ANTIPORTAL ) + return qfalse; + + /* both leaves on either side of the portal must be passable */ + if( p->nodes[ 0 ]->opaque == qfalse && p->nodes[ 1 ]->opaque == qfalse ) + return qtrue; + + /* otherwise this isn't a passable portal */ + return qfalse; +} + + + + +int c_tinyportals; +int c_badportals; /* ydnar */ + +/* +============= +AddPortalToNodes +============= +*/ +void AddPortalToNodes (portal_t *p, node_t *front, node_t *back) +{ + if (p->nodes[0] || p->nodes[1]) + Error ("AddPortalToNode: allready included"); + + p->nodes[0] = front; + p->next[0] = front->portals; + front->portals = p; + + p->nodes[1] = back; + p->next[1] = back->portals; + back->portals = p; +} + + +/* +============= +RemovePortalFromNode +============= +*/ +void RemovePortalFromNode (portal_t *portal, node_t *l) +{ + portal_t **pp, *t; + +// remove reference to the current portal + pp = &l->portals; + while (1) + { + t = *pp; + if (!t) + Error ("RemovePortalFromNode: portal not in leaf"); + + if ( t == portal ) + break; + + if (t->nodes[0] == l) + pp = &t->next[0]; + else if (t->nodes[1] == l) + pp = &t->next[1]; + else + Error ("RemovePortalFromNode: portal not bounding leaf"); + } + + if (portal->nodes[0] == l) + { + *pp = portal->next[0]; + portal->nodes[0] = NULL; + } + else if (portal->nodes[1] == l) + { + *pp = portal->next[1]; + portal->nodes[1] = NULL; + } +} + +//============================================================================ + +void PrintPortal (portal_t *p) +{ + int i; + winding_t *w; + + w = p->winding; + for (i=0 ; inumpoints ; i++) + Sys_Printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0] + , w->p[i][1], w->p[i][2]); +} + +/* +================ +MakeHeadnodePortals + +The created portals will face the global outside_node +================ +*/ +#define SIDESPACE 8 +void MakeHeadnodePortals (tree_t *tree) +{ + vec3_t bounds[2]; + int i, j, n; + portal_t *p, *portals[6]; + plane_t bplanes[6], *pl; + node_t *node; + + node = tree->headnode; + +// pad with some space so there will never be null volume leafs + for (i=0 ; i<3 ; i++) + { + bounds[0][i] = tree->mins[i] - SIDESPACE; + bounds[1][i] = tree->maxs[i] + SIDESPACE; + if ( bounds[0][i] >= bounds[1][i] ) { + Error( "Backwards tree volume" ); + } + } + + tree->outside_node.planenum = PLANENUM_LEAF; + tree->outside_node.brushlist = NULL; + tree->outside_node.portals = NULL; + tree->outside_node.opaque = qfalse; + + for (i=0 ; i<3 ; i++) + for (j=0 ; j<2 ; j++) + { + n = j*3 + i; + + p = AllocPortal (); + portals[n] = p; + + pl = &bplanes[n]; + memset (pl, 0, sizeof(*pl)); + if (j) + { + pl->normal[i] = -1; + pl->dist = -bounds[j][i]; + } + else + { + pl->normal[i] = 1; + pl->dist = bounds[j][i]; + } + p->plane = *pl; + p->winding = BaseWindingForPlane (pl->normal, pl->dist); + AddPortalToNodes (p, node, &tree->outside_node); + } + +// clip the basewindings by all the other planes + for (i=0 ; i<6 ; i++) + { + for (j=0 ; j<6 ; j++) + { + if (j == i) + continue; + ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON); + } + } +} + +//=================================================== + + +/* +================ +BaseWindingForNode +================ +*/ +#define BASE_WINDING_EPSILON 0.001 +#define SPLIT_WINDING_EPSILON 0.001 + +winding_t *BaseWindingForNode (node_t *node) +{ + winding_t *w; + node_t *n; + plane_t *plane; + vec3_t normal; + vec_t dist; + + w = BaseWindingForPlane (mapplanes[node->planenum].normal + , mapplanes[node->planenum].dist); + + // clip by all the parents + for (n=node->parent ; n && w ; ) + { + plane = &mapplanes[n->planenum]; + + if (n->children[0] == node) + { // take front + ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); + } + else + { // take back + VectorSubtract (vec3_origin, plane->normal, normal); + dist = -plane->dist; + ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON); + } + node = n; + n = n->parent; + } + + return w; +} + +//============================================================ + +/* +================== +MakeNodePortal + +create the new portal by taking the full plane winding for the cutting plane +and clipping it by all of parents of this node +================== +*/ +void MakeNodePortal (node_t *node) +{ + portal_t *new_portal, *p; + winding_t *w; + vec3_t normal; + float dist; + int side; + + w = BaseWindingForNode (node); + + // clip the portal by all the other portals in the node + for (p = node->portals ; p && w; p = p->next[side]) + { + if (p->nodes[0] == node) + { + side = 0; + VectorCopy (p->plane.normal, normal); + dist = p->plane.dist; + } + else if (p->nodes[1] == node) + { + side = 1; + VectorSubtract (vec3_origin, p->plane.normal, normal); + dist = -p->plane.dist; + } + else + Error ("CutNodePortals_r: mislinked portal"); + + ChopWindingInPlace (&w, normal, dist, CLIP_EPSILON); + } + + if (!w) + { + return; + } + + + /* ydnar: adding this here to fix degenerate windings */ + #if 0 + if( FixWinding( w ) == qfalse ) + { + c_badportals++; + FreeWinding( w ); + return; + } + #endif + + if (WindingIsTiny (w)) + { + c_tinyportals++; + FreeWinding (w); + return; + } + + new_portal = AllocPortal (); + new_portal->plane = mapplanes[node->planenum]; + new_portal->onnode = node; + new_portal->winding = w; + new_portal->compileFlags = node->compileFlags; + AddPortalToNodes (new_portal, node->children[0], node->children[1]); +} + + +/* +============== +SplitNodePortals + +Move or split the portals that bound node so that the node's +children have portals instead of node. +============== +*/ +void SplitNodePortals (node_t *node) +{ + portal_t *p, *next_portal, *new_portal; + node_t *f, *b, *other_node; + int side; + plane_t *plane; + winding_t *frontwinding, *backwinding; + + plane = &mapplanes[node->planenum]; + f = node->children[0]; + b = node->children[1]; + + for (p = node->portals ; p ; p = next_portal) + { + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + side = 1; + else + Error ("SplitNodePortals: mislinked portal"); + next_portal = p->next[side]; + + other_node = p->nodes[!side]; + RemovePortalFromNode (p, p->nodes[0]); + RemovePortalFromNode (p, p->nodes[1]); + +// +// cut the portal into two portals, one on each side of the cut plane +// + ClipWindingEpsilon (p->winding, plane->normal, plane->dist, + SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); + + if (frontwinding && WindingIsTiny(frontwinding)) + { + if (!f->tinyportals) + VectorCopy(frontwinding->p[0], f->referencepoint); + f->tinyportals++; + if (!other_node->tinyportals) + VectorCopy(frontwinding->p[0], other_node->referencepoint); + other_node->tinyportals++; + + FreeWinding (frontwinding); + frontwinding = NULL; + c_tinyportals++; + } + + if (backwinding && WindingIsTiny(backwinding)) + { + if (!b->tinyportals) + VectorCopy(backwinding->p[0], b->referencepoint); + b->tinyportals++; + if (!other_node->tinyportals) + VectorCopy(backwinding->p[0], other_node->referencepoint); + other_node->tinyportals++; + + FreeWinding (backwinding); + backwinding = NULL; + c_tinyportals++; + } + + if (!frontwinding && !backwinding) + { // tiny windings on both sides + continue; + } + + if (!frontwinding) + { + FreeWinding (backwinding); + if (side == 0) + AddPortalToNodes (p, b, other_node); + else + AddPortalToNodes (p, other_node, b); + continue; + } + if (!backwinding) + { + FreeWinding (frontwinding); + if (side == 0) + AddPortalToNodes (p, f, other_node); + else + AddPortalToNodes (p, other_node, f); + continue; + } + + // the winding is split + new_portal = AllocPortal (); + *new_portal = *p; + new_portal->winding = backwinding; + FreeWinding (p->winding); + p->winding = frontwinding; + + if (side == 0) + { + AddPortalToNodes (p, f, other_node); + AddPortalToNodes (new_portal, b, other_node); + } + else + { + AddPortalToNodes (p, other_node, f); + AddPortalToNodes (new_portal, other_node, b); + } + } + + node->portals = NULL; +} + + +/* +================ +CalcNodeBounds +================ +*/ +void CalcNodeBounds (node_t *node) +{ + portal_t *p; + int s; + int i; + + // calc mins/maxs for both leafs and nodes + ClearBounds (node->mins, node->maxs); + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + for (i=0 ; iwinding->numpoints ; i++) + AddPointToBounds (p->winding->p[i], node->mins, node->maxs); + } +} + +/* +================== +MakeTreePortals_r +================== +*/ +void MakeTreePortals_r (node_t *node) +{ + int i; + + CalcNodeBounds (node); + if (node->mins[0] >= node->maxs[0]) + { + Sys_Printf ("WARNING: node without a volume\n"); + Sys_Printf("node has %d tiny portals\n", node->tinyportals); + Sys_Printf("node reference point %1.2f %1.2f %1.2f\n", node->referencepoint[0], + node->referencepoint[1], + node->referencepoint[2]); + } + + for (i=0 ; i<3 ; i++) + { + if (node->mins[i] < MIN_WORLD_COORD || node->maxs[i] > MAX_WORLD_COORD) + { + if(node->portals && node->portals->winding) + xml_Winding("WARNING: Node With Unbounded Volume", node->portals->winding->p, node->portals->winding->numpoints, qfalse); + + break; + } + } + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + MakeTreePortals_r (node->children[0]); + MakeTreePortals_r (node->children[1]); +} + +/* +================== +MakeTreePortals +================== +*/ +void MakeTreePortals (tree_t *tree) +{ + Sys_FPrintf (SYS_VRB, "--- MakeTreePortals ---\n"); + MakeHeadnodePortals (tree); + MakeTreePortals_r (tree->headnode); + Sys_FPrintf( SYS_VRB, "%9d tiny portals\n", c_tinyportals ); + Sys_FPrintf( SYS_VRB, "%9d bad portals\n", c_badportals ); /* ydnar */ +} + +/* +========================================================= + +FLOOD ENTITIES + +========================================================= +*/ + +int c_floodedleafs; + +/* +============= +FloodPortals_r +============= +*/ + +void FloodPortals_r( node_t *node, int dist, qboolean skybox ) +{ + int s; + portal_t *p; + + + if( skybox ) + node->skybox = skybox; + + if( node->occupied || node->opaque ) + return; + + c_floodedleafs++; + node->occupied = dist; + + for( p = node->portals; p; p = p->next[ s ] ) + { + s = (p->nodes[ 1 ] == node); + FloodPortals_r( p->nodes[ !s ], dist + 1, skybox ); + } +} + + + +/* +============= +PlaceOccupant +============= +*/ + +qboolean PlaceOccupant( node_t *headnode, vec3_t origin, entity_t *occupant, qboolean skybox ) +{ + vec_t d; + node_t *node; + plane_t *plane; + + + // find the leaf to start in + node = headnode; + while( node->planenum != PLANENUM_LEAF ) + { + plane = &mapplanes[ node->planenum ]; + d = DotProduct( origin, plane->normal ) - plane->dist; + if( d >= 0 ) + node = node->children[ 0 ]; + else + node = node->children[ 1 ]; + } + + if( node->opaque ) + return qfalse; + node->occupant = occupant; + node->skybox = skybox; + + FloodPortals_r( node, 1, skybox ); + + return qtrue; +} + +/* +============= +FloodEntities + +Marks all nodes that can be reached by entites +============= +*/ + +qboolean FloodEntities( tree_t *tree ) +{ + int i, s; + vec3_t origin, offset, scale, angles; + qboolean r, inside, tripped, skybox; + node_t *headnode; + entity_t *e; + const char *value; + + + headnode = tree->headnode; + Sys_FPrintf( SYS_VRB,"--- FloodEntities ---\n" ); + inside = qfalse; + tree->outside_node.occupied = 0; + + tripped = qfalse; + c_floodedleafs = 0; + for( i = 1; i < numEntities; i++ ) + { + /* get entity */ + e = &entities[ i ]; + + /* get origin */ + GetVectorForKey( e, "origin", origin ); + if( VectorCompare( origin, vec3_origin ) ) + continue; + + /* handle skybox entities */ + value = ValueForKey( e, "classname" ); + if( !Q_stricmp( value, "_skybox" ) ) + { + skybox = qtrue; + skyboxPresent = qtrue; + + /* invert origin */ + VectorScale( origin, -1.0f, offset ); + + /* get scale */ + VectorSet( scale, 64.0f, 64.0f, 64.0f ); + value = ValueForKey( e, "_scale" ); + if( value[ 0 ] != '\0' ) + { + s = sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] ); + if( s == 1 ) + { + scale[ 1 ] = scale[ 0 ]; + scale[ 2 ] = scale[ 0 ]; + } + } + + /* get "angle" (yaw) or "angles" (pitch yaw roll) */ + VectorClear( angles ); + angles[ 2 ] = FloatForKey( e, "angle" ); + value = ValueForKey( e, "angles" ); + if( value[ 0 ] != '\0' ) + sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] ); + + /* set transform matrix (thanks spog) */ + m4x4_identity( skyboxTransform ); + m4x4_pivoted_transform_by_vec3( skyboxTransform, offset, angles, eXYZ, scale, origin ); + } + else + skybox = qfalse; + + /* nudge off floor */ + origin[ 2 ] += 1; + + /* debugging code */ + //% if( i == 1 ) + //% origin[ 2 ] += 4096; + + /* find leaf */ + r = PlaceOccupant( headnode, origin, e, skybox ); + if( r ) + inside = qtrue; + if( (!r || tree->outside_node.occupied) && !tripped ) + { + xml_Select( "Entity leaked", e->mapEntityNum, 0, qfalse ); + tripped = qtrue; + } + } + + Sys_FPrintf( SYS_VRB, "%9d flooded leafs\n", c_floodedleafs ); + + if( !inside ) + Sys_FPrintf( SYS_VRB, "no entities in open -- no filling\n" ); + else if( tree->outside_node.occupied ) + Sys_FPrintf( SYS_VRB, "entity reached from outside -- no filling\n" ); + + return (qboolean) (inside && !tree->outside_node.occupied); +} + +/* +========================================================= + +FLOOD AREAS + +========================================================= +*/ + +int c_areas; + + + +/* +FloodAreas_r() +floods through leaf portals to tag leafs with an area +*/ + +void FloodAreas_r( node_t *node ) +{ + int s; + portal_t *p; + brush_t *b; + + + if( node->areaportal ) + { + if( node->area == -1 ) + node->area = c_areas; + + /* this node is part of an area portal brush */ + b = node->brushlist->original; + + /* if the current area has already touched this portal, we are done */ + if( b->portalareas[ 0 ] == c_areas || b->portalareas[ 1 ] == c_areas ) + return; + + // note the current area as bounding the portal + if( b->portalareas[ 1 ] != -1 ) + { + Sys_Printf( "WARNING: areaportal brush %i touches > 2 areas\n", b->brushNum ); + return; + } + if( b->portalareas[ 0 ] != -1 ) + b->portalareas[ 1 ] = c_areas; + else + b->portalareas[ 0 ] = c_areas; + + return; + } + + if( node->area != -1 ) + return; + if( node->cluster == -1 ) + return; + + node->area = c_areas; + + /* ydnar: skybox nodes set the skybox area */ + if( node->skybox ) + skyboxArea = c_areas; + + for( p = node->portals; p; p = p->next[ s ] ) + { + s = (p->nodes[1] == node); + + /* ydnar: allow areaportal portals to block area flow */ + if( p->compileFlags & C_AREAPORTAL ) + continue; + + if( !PortalPassable( p ) ) + continue; + + FloodAreas_r( p->nodes[ !s ] ); + } +} + +/* +============= +FindAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void FindAreas_r( node_t *node ) +{ + if( node->planenum != PLANENUM_LEAF ) + { + FindAreas_r( node->children[ 0 ] ); + FindAreas_r( node->children[ 1 ] ); + return; + } + + if( node->opaque || node->areaportal || node->area != -1 ) + return; + + FloodAreas_r( node ); + c_areas++; +} + +/* +============= +CheckAreas_r +============= +*/ +void CheckAreas_r (node_t *node) +{ + brush_t *b; + + if (node->planenum != PLANENUM_LEAF) + { + CheckAreas_r (node->children[0]); + CheckAreas_r (node->children[1]); + return; + } + + if (node->opaque) + return; + + if (node->cluster != -1) + if (node->area == -1) + Sys_Printf("WARNING: cluster %d has area set to -1\n", node->cluster); + if (node->areaportal) + { + b = node->brushlist->original; + + // check if the areaportal touches two areas + if (b->portalareas[0] == -1 || b->portalareas[1] == -1) + Sys_Printf ("WARNING: areaportal brush %i doesn't touch two areas\n", b->brushNum); + } +} + + + +/* +FloodSkyboxArea_r() - ydnar +sets all nodes with the skybox area to skybox +*/ + +void FloodSkyboxArea_r( node_t *node ) +{ + if( skyboxArea < 0 ) + return; + + if( node->planenum != PLANENUM_LEAF ) + { + FloodSkyboxArea_r( node->children[ 0 ] ); + FloodSkyboxArea_r( node->children[ 1 ] ); + return; + } + + if( node->opaque || node->area != skyboxArea ) + return; + + node->skybox = qtrue; +} + + + +/* +FloodAreas() +mark each leaf with an area, bounded by C_AREAPORTAL +*/ + +void FloodAreas( tree_t *tree ) +{ + Sys_FPrintf( SYS_VRB,"--- FloodAreas ---\n" ); + FindAreas_r( tree->headnode ); + + /* ydnar: flood all skybox nodes */ + FloodSkyboxArea_r( tree->headnode ); + + /* check for areaportal brushes that don't touch two areas */ + /* ydnar: fix this rather than just silence the warnings */ + //% CheckAreas_r( tree->headnode ); + + Sys_FPrintf( SYS_VRB, "%9d areas\n", c_areas ); +} + + + +//====================================================== + +int c_outside; +int c_inside; +int c_solid; + +void FillOutside_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FillOutside_r (node->children[0]); + FillOutside_r (node->children[1]); + return; + } + + // anything not reachable by an entity + // can be filled away + if (!node->occupied) { + if ( !node->opaque ) { + c_outside++; + node->opaque = qtrue; + } else { + c_solid++; + } + } else { + c_inside++; + } + +} + +/* +============= +FillOutside + +Fill all nodes that can't be reached by entities +============= +*/ +void FillOutside (node_t *headnode) +{ + c_outside = 0; + c_inside = 0; + c_solid = 0; + Sys_FPrintf( SYS_VRB,"--- FillOutside ---\n" ); + FillOutside_r( headnode ); + Sys_FPrintf( SYS_VRB,"%9d solid leafs\n", c_solid ); + Sys_Printf( "%9d leafs filled\n", c_outside ); + Sys_FPrintf( SYS_VRB, "%9d inside leafs\n", c_inside ); +} + + +//============================================================== + diff --git a/tools/quake3/q3map2/prtfile.c b/tools/quake3/q3map2/prtfile.c new file mode 100644 index 00000000..ab7c5304 --- /dev/null +++ b/tools/quake3/q3map2/prtfile.c @@ -0,0 +1,291 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define PRTFILE_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +============================================================================== + +PORTAL FILE GENERATION + +Save out name.prt for qvis to read +============================================================================== +*/ + + +#define PORTALFILE "PRT1" + +FILE *pf; +int num_visclusters; // clusters the player can be in +int num_visportals; +int num_solidfaces; + +void WriteFloat (FILE *f, vec_t v) +{ + if ( fabs(v - Q_rint(v)) < 0.001 ) + fprintf (f,"%i ",(int)Q_rint(v)); + else + fprintf (f,"%f ",v); +} + +/* +================= +WritePortalFile_r +================= +*/ +void WritePortalFile_r (node_t *node) +{ + int i, s; + portal_t *p; + winding_t *w; + vec3_t normal; + vec_t dist; + + // decision node + if (node->planenum != PLANENUM_LEAF) { + WritePortalFile_r (node->children[0]); + WritePortalFile_r (node->children[1]); + return; + } + + if (node->opaque) { + return; + } + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w && p->nodes[0] == node) + { + if (!PortalPassable(p)) + continue; + // write out to the file + + // sometimes planes get turned around when they are very near + // the changeover point between different axis. interpret the + // plane the same way vis will, and flip the side orders if needed + // FIXME: is this still relevent? + WindingPlane (w, normal, &dist); + if ( DotProduct (p->plane.normal, normal) < 0.99 ) + { // backwards... + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster); + } + else + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster); + + /* ydnar: added this change to make antiportals work */ + if( p->compileFlags & C_HINT ) + fprintf( pf, "1 " ); + else + fprintf( pf, "0 " ); + + /* write the winding */ + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->p[i][0]); + WriteFloat (pf, w->p[i][1]); + WriteFloat (pf, w->p[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + } + +} + +/* +================= +WriteFaceFile_r +================= +*/ +void WriteFaceFile_r (node_t *node) +{ + int i, s; + portal_t *p; + winding_t *w; + + // decision node + if (node->planenum != PLANENUM_LEAF) { + WriteFaceFile_r (node->children[0]); + WriteFaceFile_r (node->children[1]); + return; + } + + if (node->opaque) { + return; + } + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w) + { + if (PortalPassable(p)) + continue; + // write out to the file + + if (p->nodes[0] == node) + { + fprintf (pf,"%i %i ",w->numpoints, p->nodes[0]->cluster); + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->p[i][0]); + WriteFloat (pf, w->p[i][1]); + WriteFloat (pf, w->p[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + else + { + fprintf (pf,"%i %i ",w->numpoints, p->nodes[1]->cluster); + for (i = w->numpoints-1; i >= 0; i--) + { + fprintf (pf,"("); + WriteFloat (pf, w->p[i][0]); + WriteFloat (pf, w->p[i][1]); + WriteFloat (pf, w->p[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + } + } +} + +/* +================ +NumberLeafs_r +================ +*/ +void NumberLeafs_r (node_t *node) +{ + portal_t *p; + + if ( node->planenum != PLANENUM_LEAF ) { + // decision node + node->cluster = -99; + NumberLeafs_r (node->children[0]); + NumberLeafs_r (node->children[1]); + return; + } + + node->area = -1; + + if ( node->opaque ) { + // solid block, viewpoint never inside + node->cluster = -1; + return; + } + + node->cluster = num_visclusters; + num_visclusters++; + + // count the portals + for (p = node->portals ; p ; ) + { + if (p->nodes[0] == node) // only write out from first leaf + { + if (PortalPassable(p)) + num_visportals++; + else + num_solidfaces++; + p = p->next[0]; + } + else + { + if (!PortalPassable(p)) + num_solidfaces++; + p = p->next[1]; + } + } +} + + +/* +================ +NumberClusters +================ +*/ +void NumberClusters(tree_t *tree) { + num_visclusters = 0; + num_visportals = 0; + num_solidfaces = 0; + + Sys_FPrintf (SYS_VRB,"--- NumberClusters ---\n"); + + // set the cluster field in every leaf and count the total number of portals + NumberLeafs_r (tree->headnode); + + Sys_FPrintf( SYS_VRB, "%9d visclusters\n", num_visclusters ); + Sys_FPrintf( SYS_VRB, "%9d visportals\n", num_visportals ); + Sys_FPrintf( SYS_VRB, "%9d solidfaces\n", num_solidfaces ); +} + +/* +================ +WritePortalFile +================ +*/ +void WritePortalFile (tree_t *tree) +{ + char filename[1024]; + + Sys_FPrintf (SYS_VRB,"--- WritePortalFile ---\n"); + + // write the file + sprintf (filename, "%s.prt", source); + Sys_Printf ("writing %s\n", filename); + pf = fopen (filename, "w"); + if (!pf) + Error ("Error opening %s", filename); + + fprintf (pf, "%s\n", PORTALFILE); + fprintf (pf, "%i\n", num_visclusters); + fprintf (pf, "%i\n", num_visportals); + fprintf (pf, "%i\n", num_solidfaces); + + WritePortalFile_r(tree->headnode); + WriteFaceFile_r(tree->headnode); + + fclose (pf); +} + diff --git a/tools/quake3/q3map2/q3map2.h b/tools/quake3/q3map2/q3map2.h new file mode 100644 index 00000000..68ea5f6d --- /dev/null +++ b/tools/quake3/q3map2/q3map2.h @@ -0,0 +1,2276 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef Q3MAP2_H +#define Q3MAP2_H + + + +/* version */ +#define Q3MAP_VERSION "2.5.11" +#define Q3MAP_MOTD "A well-oiled toaster oven" + + + +/* ------------------------------------------------------------------------------- + +dependencies + +------------------------------------------------------------------------------- */ + +/* platform-specific */ +#if defined( __linux__ ) || defined( __APPLE__ ) + #define Q_UNIX +#endif + +#ifdef Q_UNIX + #include + #include + #include +#endif + +#ifdef _WIN32 + #include +#endif + + +/* general */ +#include "version.h" /* ttimo: might want to guard that if built outside of the GtkRadiant tree */ + +#include "cmdlib.h" +#include "mathlib.h" +#include "md5lib.h" +#include "ddslib.h" + +#include "picomodel.h" + +#include "scriplib.h" +#include "polylib.h" +#include "imagelib.h" +#include "qthreads.h" +#include "inout.h" +#include "vfs.h" +#include "png.h" +#include "radiant_jpeglib.h" + +#include + + + +/* ------------------------------------------------------------------------------- + +port-related hacks + +------------------------------------------------------------------------------- */ + +#define MAC_STATIC_HACK 0 +#if defined( __APPLE__ ) && MAC_STATIC_HACK + #define MAC_STATIC static +#else + #define MAC_STATIC +#endif + +#if 1 + #ifdef _WIN32 + #define Q_stricmp stricmp + #define Q_strncasecmp strnicmp + #else + #define Q_stricmp strcasecmp + #define Q_strncasecmp strncasecmp + #endif +#endif + +/* macro version */ +#define VectorMA( a, s, b, c ) ((c)[ 0 ] = (a)[ 0 ] + (s) * (b)[ 0 ], (c)[ 1 ] = (a)[ 1 ] + (s) * (b)[ 1 ], (c)[ 2 ] = (a)[ 2 ] + (s) * (b)[ 2 ]) + + + +/* ------------------------------------------------------------------------------- + +constants + +------------------------------------------------------------------------------- */ + +/* general */ +#define MAX_QPATH 64 + +#define MAX_IMAGES 512 +#define DEFAULT_IMAGE "*default" + +#define MAX_MODELS 512 + +#define DEF_BACKSPLASH_FRACTION 0.05f /* 5% backsplash by default */ +#define DEF_BACKSPLASH_DISTANCE 23 + +#define DEF_RADIOSITY_BOUNCE 1.0f /* ydnar: default to 100% re-emitted light */ + +#define MAX_SHADER_INFO 8192 +#define MAX_CUST_SURFACEPARMS 64 + +#define SHADER_MAX_VERTEXES 1000 +#define SHADER_MAX_INDEXES (6 * SHADER_MAX_VERTEXES) + +#define MAX_JITTERS 256 + + +/* epair parsing (note case-sensitivity directive) */ +#define CASE_INSENSITIVE_EPAIRS 1 + +#if CASE_INSENSITIVE_EPAIRS + #define EPAIR_STRCMP Q_stricmp +#else + #define EPAIR_STRCMP strcmp +#endif + + +/* ydnar: compiler flags, because games have widely varying content/surface flags */ +#define C_SOLID 0x00000001 +#define C_TRANSLUCENT 0x00000002 +#define C_STRUCTURAL 0x00000004 +#define C_HINT 0x00000008 +#define C_NODRAW 0x00000010 +#define C_LIGHTGRID 0x00000020 +#define C_ALPHASHADOW 0x00000040 +#define C_LIGHTFILTER 0x00000080 +#define C_VERTEXLIT 0x00000100 +#define C_LIQUID 0x00000200 +#define C_FOG 0x00000400 +#define C_SKY 0x00000800 +#define C_ORIGIN 0x00001000 +#define C_AREAPORTAL 0x00002000 +#define C_ANTIPORTAL 0x00004000 /* like hint, but doesn't generate portals */ +#define C_SKIP 0x00008000 /* like hint, but skips this face (doesn't split bsp) */ +#define C_NOMARKS 0x00010000 /* no decals */ + +#define C_DETAIL 0x08000000 /* THIS MUST BE THE SAME AS IN RADIANT! */ + + +/* shadow flags */ +#define WORLDSPAWN_CAST_SHADOWS 1 +#define WORLDSPAWN_RECV_SHADOWS 1 +#define ENTITY_CAST_SHADOWS 0 +#define ENTITY_RECV_SHADOWS 1 + + +/* bsp */ +#define MAX_PATCH_SIZE 32 +#define MAX_BRUSH_SIDES 1024 +#define MAX_BUILD_SIDES 300 + +#define MAX_EXPANDED_AXIS 128 + +#define CLIP_EPSILON 0.1f +#define PLANESIDE_EPSILON 0.001f +#define PLANENUM_LEAF -1 + +#define HINT_PRIORITY 1000 /* ydnar: force hint splits first and antiportal/areaportal splits last */ +#define ANTIPORTAL_PRIORITY -1000 +#define AREAPORTAL_PRIORITY -1000 + +#define PSIDE_FRONT 1 +#define PSIDE_BACK 2 +#define PSIDE_BOTH (PSIDE_FRONT | PSIDE_BACK) +#define PSIDE_FACING 4 + +#define BPRIMIT_UNDEFINED 0 +#define BPRIMIT_OLDBRUSHES 1 +#define BPRIMIT_NEWBRUSHES 2 + + +/* vis */ +#define VIS_HEADER_SIZE 8 + +#define SEPERATORCACHE /* seperator caching helps a bit */ + +#define PORTALFILE "PRT1" + +#define MAX_PORTALS 32768 +#define MAX_SEPERATORS MAX_POINTS_ON_WINDING +#define MAX_POINTS_ON_FIXED_WINDING 24 /* ydnar: increased this from 12 at the expense of more memory */ +#define MAX_PORTALS_ON_LEAF 128 + + +/* light */ +#define EMIT_POINT 0 +#define EMIT_AREA 1 +#define EMIT_SPOT 2 +#define EMIT_SUN 3 + +#define LIGHT_ATTEN_LINEAR 1 +#define LIGHT_ATTEN_ANGLE 2 +#define LIGHT_ATTEN_DISTANCE 4 +#define LIGHT_TWOSIDED 8 +#define LIGHT_GRID 16 +#define LIGHT_SURFACES 32 +#define LIGHT_DARK 64 /* probably never use this */ +#define LIGHT_FAST 256 +#define LIGHT_FAST_TEMP 512 +#define LIGHT_FAST_ACTUAL (LIGHT_FAST | LIGHT_FAST_TEMP) +#define LIGHT_NEGATIVE 1024 + +#define LIGHT_SUN_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_GRID | LIGHT_SURFACES) +#define LIGHT_AREA_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE | LIGHT_GRID | LIGHT_SURFACES) /* q3a and wolf are the same */ +#define LIGHT_Q3A_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE | LIGHT_GRID | LIGHT_SURFACES | LIGHT_FAST) +#define LIGHT_WOLF_DEFAULT (LIGHT_ATTEN_LINEAR | LIGHT_ATTEN_DISTANCE | LIGHT_GRID | LIGHT_SURFACES | LIGHT_FAST) + +#define MAX_TRACE_TEST_NODES 256 +#define DEFAULT_INHIBIT_RADIUS 1.5f + +#define LUXEL_EPSILON 0.125f +#define VERTEX_EPSILON -0.125f +#define GRID_EPSILON 0.0f + +#define DEFAULT_LIGHTMAP_SAMPLE_SIZE 16 +#define DEFAULT_LIGHTMAP_SAMPLE_OFFSET 1.0f +#define DEFAULT_SUBDIVIDE_THRESHOLD 1.0f + +#define EXTRA_SCALE 2 /* -extrawide = -super 2 */ +#define EXTRAWIDE_SCALE 2 /* -extrawide = -super 2 -filter */ + +#define CLUSTER_UNMAPPED -1 +#define CLUSTER_OCCLUDED -2 +#define CLUSTER_FLOODED -3 + +#define VERTEX_LUXEL_SIZE 3 +#define BSP_LUXEL_SIZE 3 +#define RAD_LUXEL_SIZE 3 +#define SUPER_LUXEL_SIZE 4 +#define SUPER_ORIGIN_SIZE 3 +#define SUPER_NORMAL_SIZE 3 +#define SUPER_DELUXEL_SIZE 3 +#define BSP_DELUXEL_SIZE 3 + +#define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) +#define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) +#define BSP_LUXEL( s, x, y ) (lm->bspLuxels[ s ] + ((((y) * lm->w) + (x)) * BSP_LUXEL_SIZE)) +#define RAD_LUXEL( s, x, y ) (lm->radLuxels[ s ] + ((((y) * lm->w) + (x)) * RAD_LUXEL_SIZE)) +#define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) +#define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE)) +#define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE)) +#define SUPER_CLUSTER( x, y ) (lm->superClusters + (((y) * lm->sw) + (x))) +#define SUPER_DELUXEL( x, y ) (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE)) +#define BSP_DELUXEL( x, y ) (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE)) + + + +/* ------------------------------------------------------------------------------- + +abstracted bsp file + +------------------------------------------------------------------------------- */ + +#define EXTERNAL_LIGHTMAP "lm_%04d.tga" + +#define MAX_LIGHTMAPS 4 /* RBSP */ +#define MAX_LIGHT_STYLES 64 +#define MAX_SWITCHED_LIGHTS 32 +#define LS_NORMAL 0x00 +#define LS_UNUSED 0xFE +#define LS_NONE 0xFF + +#define MAX_LIGHTMAP_SHADERS 256 + +/* ok to increase these at the expense of more memory */ +#define MAX_MAP_MODELS 0x400 +#define MAX_MAP_BRUSHES 0x8000 +#define MAX_MAP_ENTITIES 0x1000 //% 0x800 /* ydnar */ +#define MAX_MAP_ENTSTRING 0x80000 //% 0x40000 /* ydnar */ +#define MAX_MAP_SHADERS 0x400 + +#define MAX_MAP_AREAS 0x100 /* MAX_MAP_AREA_BYTES in q_shared must match! */ +#define MAX_MAP_FOGS 30 //& 0x100 /* RBSP (32 - world fog - goggles) */ +#define MAX_MAP_PLANES 0x100000 //% 0x20000 /* ydnar for md */ +#define MAX_MAP_NODES 0x20000 +#define MAX_MAP_BRUSHSIDES 0x100000 //% 0x20000 /* ydnar */ +#define MAX_MAP_LEAFS 0x20000 +#define MAX_MAP_LEAFFACES 0x20000 +#define MAX_MAP_LEAFBRUSHES 0x40000 +#define MAX_MAP_PORTALS 0x20000 +#define MAX_MAP_LIGHTING 0x800000 +#define MAX_MAP_LIGHTGRID 0x100000 //% 0x800000 /* ydnar: set to points, not bytes */ +#define MAX_MAP_VISIBILITY 0x200000 + +#define MAX_MAP_DRAW_SURFS 0x20000 +#define MAX_MAP_DRAW_VERTS 0x80000 +#define MAX_MAP_DRAW_INDEXES 0x80000 + + +/* key / value pair sizes in the entities lump */ +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +/* the editor uses these predefined yaw angles to orient entities up or down */ +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +#define LIGHTMAP_WIDTH 128 +#define LIGHTMAP_HEIGHT 128 + +#define MIN_WORLD_COORD (-65536) +#define MAX_WORLD_COORD (65536) +#define WORLD_SIZE (MAX_WORLD_COORD - MIN_WORLD_COORD) + + +typedef void (*bspFunc)( const char * ); + + +typedef struct +{ + int offset, length; +} +bspLump_t; + + +typedef struct +{ + char ident[ 4 ]; + int version; + + bspLump_t lumps[ 100 ]; /* theoretical maximum # of bsp lumps */ +} +bspHeader_t; + + +typedef struct +{ + float mins[ 3 ], maxs[ 3 ]; + int firstBSPSurface, numBSPSurfaces; + int firstBSPBrush, numBSPBrushes; +} +bspModel_t; + + +typedef struct +{ + char shader[ MAX_QPATH ]; + int surfaceFlags; + int contentFlags; +} +bspShader_t; + + +/* planes x^1 is allways the opposite of plane x */ + +typedef struct +{ + float normal[ 3 ]; + float dist; +} +bspPlane_t; + + +typedef struct +{ + int planeNum; + int children[ 2 ]; /* negative numbers are -(leafs+1), not nodes */ + int mins[ 3 ]; /* for frustom culling */ + int maxs[ 3 ]; +} +bspNode_t; + + +typedef struct +{ + int cluster; /* -1 = opaque cluster (do I still store these?) */ + int area; + + int mins[ 3 ]; /* for frustum culling */ + int maxs[ 3 ]; + + int firstBSPLeafSurface; + int numBSPLeafSurfaces; + + int firstBSPLeafBrush; + int numBSPLeafBrushes; +} +bspLeaf_t; + + +typedef struct +{ + int planeNum; /* positive plane side faces out of the leaf */ + int shaderNum; + int surfaceNum; /* RBSP */ +} +bspBrushSide_t; + + +typedef struct +{ + int firstSide; + int numSides; + int shaderNum; /* the shader that determines the content flags */ +} +bspBrush_t; + + +typedef struct +{ + char shader[ MAX_QPATH ]; + int brushNum; + int visibleSide; /* the brush side that ray tests need to clip against (-1 == none) */ +} +bspFog_t; + + +typedef struct +{ + vec3_t xyz; + float st[ 2 ]; + float lightmap[ MAX_LIGHTMAPS ][ 2 ]; /* RBSP */ + vec3_t normal; + byte color[ MAX_LIGHTMAPS ][ 4 ]; /* RBSP */ +} +bspDrawVert_t; + + +typedef enum +{ + MST_BAD, + MST_PLANAR, + MST_PATCH, + MST_TRIANGLE_SOUP, + MST_FLARE, + MST_FOLIAGE +} +bspSurfaceType_t; + + +typedef struct bspGridPoint_s +{ + byte ambient[ MAX_LIGHTMAPS ][ 3 ]; + byte directed[ MAX_LIGHTMAPS ][ 3 ]; + byte styles[ MAX_LIGHTMAPS ]; + byte latLong[ 2 ]; +} +bspGridPoint_t; + + +typedef struct +{ + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + byte lightmapStyles[ MAX_LIGHTMAPS ]; /* RBSP */ + byte vertexStyles[ MAX_LIGHTMAPS ]; /* RBSP */ + int lightmapNum[ MAX_LIGHTMAPS ]; /* RBSP */ + int lightmapX[ MAX_LIGHTMAPS ], lightmapY[ MAX_LIGHTMAPS ]; /* RBSP */ + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[ 3 ]; /* on patches, [ 0 ] and [ 1 ] are lodbounds */ + + int patchWidth; + int patchHeight; +} +bspDrawSurface_t; + + + +/* ------------------------------------------------------------------------------- + +general types + +------------------------------------------------------------------------------- */ + +/* ydnar: for smaller structs */ +typedef char qb_t; + + +/* ydnar: for q3map_tcMod */ +typedef float tcMod_t[ 3 ][ 3 ]; + + +/* ydnar: for multiple game support */ +typedef struct surfaceParm_s +{ + char *name; + int contentFlags, contentFlagsClear; + int surfaceFlags, surfaceFlagsClear; + int compileFlags, compileFlagsClear; +} +surfaceParm_t; + + +typedef struct game_s +{ + char *arg; /* -game matches this */ + char *gamePath; /* main game data dir */ + char *homeBasePath; /* home sub-dir on unix */ + char *magic; /* magic word for figuring out base path */ + char *shaderPath; /* shader directory */ + qboolean wolfLight; /* when true, lights work like wolf q3map */ + qboolean emitFlares; /* when true, emit flare surfaces */ + char *flareShader; /* default flare shader (MUST BE SET) */ + char *bspIdent; /* 4-letter bsp file prefix */ + int bspVersion; /* BSP version to use */ + bspFunc load, write; /* load/write function pointers */ + surfaceParm_t surfaceParms[ 128 ]; /* surfaceparm array */ +} +game_t; + + +typedef struct image_s +{ + char *name, *filename; + int refCount; + int width, height; + byte *pixels; +} +image_t; + + +typedef struct sun_s +{ + struct sun_s *next; + vec3_t direction, color; + float photons, deviance, filterRadius; + int numSamples; +} +sun_t; + + +typedef struct surfaceModel_s +{ + struct surfaceModel_s *next; + char model[ MAX_QPATH ]; + float density, odds; + float minScale, maxScale; + float minAngle, maxAngle; + qboolean oriented; +} +surfaceModel_t; + + +/* ydnar/sd: foliage stuff for wolf et (engine-supported optimization of the above) */ +typedef struct foliage_s +{ + struct foliage_s *next; + char model[ MAX_QPATH ]; + float scale, density, odds; + qboolean inverseAlpha; +} +foliage_t; + +typedef struct foliageInstance_s +{ + vec3_t xyz, normal; +} +foliageInstance_t; + + +typedef struct remap_s +{ + struct remap_s *next; + char from[ 1024 ]; + char to[ MAX_QPATH ]; +} +remap_t; + + +typedef enum +{ + AM_NONE, + AM_DOT_PRODUCT +} +alphaModType_t; + + +typedef struct alphaMod_s +{ + struct alphaMod_s *next; + alphaModType_t type; + vec_t data[ 16 ]; +} +alphaMod_t; + + +typedef enum +{ + IM_NONE, + IM_OPAQUE, + IM_MASKED, + IM_BLEND +} +implicitMap_t; + + +typedef struct shaderInfo_s +{ + char shader[ MAX_QPATH ]; + int surfaceFlags; + int contentFlags; + int compileFlags; + float value; /* light value */ + + char backShader[ MAX_QPATH ]; /* for surfaces that generate different front and back passes */ + char flareShader[ MAX_QPATH ]; /* for light flares */ + char cloneShader[ MAX_QPATH ]; /* ydnar: for cloning of a surface */ + char damageShader[ MAX_QPATH ]; /* ydnar: sof2 damage shader name */ + + surfaceModel_t *surfaceModel; /* ydnar: for distribution of models */ + foliage_t *foliage; /* ydnar/splash damage: wolf et foliage */ + + float subdivisions; /* from a "tesssize xxx" */ + float backsplashFraction; /* floating point value, usually 0.05 */ + float backsplashDistance; /* default 16 */ + float lightSubdivide; /* default 999 */ + float lightFilterRadius; /* ydnar: lightmap filtering/blurring radius for lights created by this shader (default: 0) */ + + int lightmapSampleSize; /* lightmap sample size */ + float lightmapSampleOffset; /* ydnar: lightmap sample offset (default: 1.0) */ + + float bounceScale; /* ydnar: radiosity re-emission [0,1.0+] */ + float offset; /* ydnar: offset in units */ + float shadeAngleDegrees; /* ydnar: breaking angle for smooth shading (degrees) */ + + vec3_t mins, maxs; /* ydnar: for particle studio vertexDeform move support */ + + qb_t legacyTerrain; /* ydnar: enable legacy terrain crutches */ + qb_t indexed; /* ydnar: attempt to use indexmap (terrain alphamap style) */ + qb_t forceMeta; /* ydnar: force metasurface path */ + qb_t noClip; /* ydnar: don't clip into bsp, preserve original face winding */ + qb_t noFast; /* ydnar: supress fast lighting for surfaces with this shader */ + qb_t invert; /* ydnar: reverse facing */ + qb_t nonplanar; /* ydnar: for nonplanar meta surface merging */ + qb_t tcGen; /* ydnar: has explicit texcoord generation */ + vec3_t vecs[ 2 ]; /* ydnar: explicit texture vectors for [0,1] texture space */ + tcMod_t mod; /* ydnar: q3map_tcMod matrix for djbob :) */ + vec3_t lightmapAxis; /* ydnar: explicit lightmap axis projection */ + alphaMod_t *alphaMod; /* ydnar: q3map_alphaMod support */ + + int furNumLayers; /* ydnar: number of fur layers */ + float furOffset; /* ydnar: offset of each layer */ + float furFade; /* ydnar: alpha fade amount per layer */ + + qb_t splotchFix; /* ydnar: filter splotches on lightmaps */ + + qb_t hasPasses; /* false if the shader doesn't define any rendering passes */ + qb_t globalTexture; /* don't normalize texture repeats */ + qb_t twoSided; /* cull none */ + qb_t autosprite; /* autosprite shaders will become point lights instead of area lights */ + qb_t polygonOffset; /* ydnar: don't face cull this or against this */ + qb_t patchShadows; /* have patches casting shadows when using -light for this surface */ + qb_t vertexShadows; /* shadows will be casted at this surface even when vertex lit */ + qb_t forceSunlight; /* force sun light at this surface even tho we might not calculate shadows in vertex lighting */ + qb_t notjunc; /* don't use this surface for tjunction fixing */ + qb_t fogParms; /* ydnar: has fogparms */ + qb_t noFog; /* ydnar: supress fogging */ + + qb_t clipModel; /* ydnar: solid model hack */ + + byte styleMarker; /* ydnar: light styles hack */ + + float vertexScale; /* vertex light scale */ + + char skyParmsImageBase[ MAX_QPATH ]; /* ydnar: for skies */ + + char editorImagePath[ MAX_QPATH ]; /* use this image to generate texture coordinates */ + char lightImagePath[ MAX_QPATH ]; /* use this image to generate color / averageColor */ + char normalImagePath[ MAX_QPATH ]; /* ydnar: normalmap image for bumpmapping */ + + implicitMap_t implicitMap; /* ydnar: enemy territory implicit shaders */ + char implicitImagePath[ MAX_QPATH ]; + + image_t *shaderImage; + image_t *lightImage; + image_t *normalImage; + + float skyLightValue; /* ydnar */ + int skyLightIterations; /* ydnar */ + sun_t *sun; /* ydnar */ + + vec3_t color; /* normalized color */ + vec3_t averageColor; + byte lightStyle; + + qb_t lmMergable; /* ydnar */ + int lmCustomWidth, lmCustomHeight; /* ydnar */ + float lmGamma; /* ydnar */ + float lmFilterRadius; /* ydnar: lightmap filtering/blurring radius for this shader (default: 0) */ + + int shaderWidth, shaderHeight; /* ydnar */ + float stFlat[ 2 ]; + + vec3_t fogDir; /* ydnar */ + + char *shaderText; /* ydnar */ + qb_t custom; + qb_t finished; +} +shaderInfo_t; + + + +/* ------------------------------------------------------------------------------- + +bsp structures + +------------------------------------------------------------------------------- */ + +typedef struct face_s +{ + struct face_s *next; + int planenum; + int priority; + qboolean checked; + int compileFlags; + winding_t *w; +} +face_t; + + +typedef struct plane_s +{ + vec3_t normal; + vec_t dist; + int type; + struct plane_s *hash_chain; +} +plane_t; + + +typedef struct side_s +{ + int planenum; + + int outputNum; /* set when the side is written to the file list */ + + float texMat[ 2 ][ 3 ]; /* brush primitive texture matrix */ + float vecs[ 2 ][ 4 ]; /* old-style texture coordinate mapping */ + + winding_t *winding; + winding_t *visibleHull; /* convex hull of all visible fragments */ + + shaderInfo_t *shaderInfo; + + int contentFlags; /* from shaderInfo */ + int surfaceFlags; /* from shaderInfo */ + int compileFlags; /* from shaderInfo */ + int value; /* from shaderInfo */ + + qboolean visible; /* choose visble planes first */ + qboolean bevel; /* don't ever use for bsp splitting, and don't bother making windings for it */ + qboolean backSide; /* generated side for a q3map_backShader */ + + qboolean culled; /* ydnar: face culling */ +} +side_t; + + +typedef struct sideRef_s +{ + struct sideRef_s *next; + side_t *side; +} +sideRef_t; + + +/* ydnar: generic index mapping for entities (natural extension of terrain texturing) */ +typedef struct indexMap_s +{ + int w, h, numLayers; + char name[ MAX_QPATH ], shader[ MAX_QPATH ]; + float offsets[ 256 ]; + byte *pixels; +} +indexMap_t; + + +typedef struct brush_s +{ + struct brush_s *next; + struct brush_s *original; /* chopped up brushes will reference the originals */ + + int entityNum, brushNum;/* editor numbering */ + int outputNum; /* set when the brush is written to the file list */ + + /* ydnar: for shadowcasting entities */ + int castShadows; + int recvShadows; + + shaderInfo_t *contentShader; + shaderInfo_t *celShader; /* :) */ + + /* ydnar: gs mods */ + float lightmapScale; + vec3_t eMins, eMaxs; + indexMap_t *im; + + int contentFlags; + int compileFlags; /* ydnar */ + qboolean detail; + qboolean opaque; + + int portalareas[ 2 ]; + + vec3_t mins, maxs; + int numsides; + + side_t sides[ 6 ]; /* variably sized */ +} +brush_t; + + +typedef struct fog_s +{ + shaderInfo_t *si; + brush_t *brush; + int visibleSide; /* the brush side that ray tests need to clip against (-1 == none) */ +} +fog_t; + + +typedef struct +{ + int width, height; + bspDrawVert_t *verts; +} +mesh_t; + + +typedef struct parseMesh_s +{ + struct parseMesh_s *next; + + int entityNum, brushNum; /* ydnar: editor numbering */ + + /* ydnar: for shadowcasting entities */ + int castShadows; + int recvShadows; + + mesh_t mesh; + shaderInfo_t *shaderInfo; + shaderInfo_t *celShader; /* :) */ + + /* ydnar: gs mods */ + float lightmapScale; + vec3_t eMins, eMaxs; + indexMap_t *im; + + /* grouping */ + qboolean grouped; + float longestCurve; + int maxIterations; +} +parseMesh_t; + + +/* + ydnar: the drawsurf struct was extended to allow for: + - non-convex planar surfaces + - non-planar brushface surfaces + - lightmapped terrain + - planar patches +*/ + +typedef enum +{ + /* ydnar: these match up exactly with bspSurfaceType_t */ + SURFACE_BAD, + SURFACE_FACE, + SURFACE_PATCH, + SURFACE_TRIANGLES, + SURFACE_FLARE, + SURFACE_FOLIAGE, /* wolf et */ + + /* ydnar: compiler-relevant surface types */ + SURFACE_FORCED_META, + SURFACE_META, + SURFACE_FOGHULL, + SURFACE_DECAL, + SURFACE_SHADER, + + NUM_SURFACE_TYPES +} +surfaceType_t; + +char *surfaceTypes[ NUM_SURFACE_TYPES ] +#ifndef MAIN_C + ; +#else + = + { + "SURFACE_BAD", + "SURFACE_FACE", + "SURFACE_PATCH", + "SURFACE_TRIANGLES", + "SURFACE_FLARE", + "SURFACE_FOLIAGE", + "SURFACE_FORCED_META", + "SURFACE_META", + "SURFACE_FOGHULL", + "SURFACE_DECAL", + "SURFACE_SHADER" + }; +#endif + + +/* ydnar: this struct needs an overhaul (again, heh) */ +typedef struct mapDrawSurface_s +{ + surfaceType_t type; + qboolean planar; + int outputNum; /* ydnar: to match this sort of thing up */ + + qboolean fur; /* ydnar: this is kind of a hack, but hey... */ + qboolean skybox; /* ydnar: yet another fun hack */ + + struct mapDrawSurface_s *parent; /* ydnar: for cloned (skybox) surfaces to share lighting data */ + + shaderInfo_t *shaderInfo; + shaderInfo_t *celShader; + brush_t *mapBrush; + parseMesh_t *mapMesh; + sideRef_t *sideRef; + + int fogNum; + + int numVerts; /* vertexes and triangles */ + bspDrawVert_t *verts; + int numIndexes; + int *indexes; + + int planeNum; + vec3_t lightmapOrigin; /* also used for flares */ + vec3_t lightmapVecs[ 3 ]; /* also used for flares */ + int lightStyle; /* used for flares */ + + /* ydnar: per-surface (per-entity, actually) lightmap sample size scaling */ + float lightmapScale; + + /* ydnar: surface classification */ + vec3_t mins, maxs; + vec3_t lightmapAxis; + int sampleSize; + + /* ydnar: shadow group support */ + int castShadows, recvShadows; + + /* ydnar: texture coordinate range monitoring for hardware with limited texcoord precision (in texel space) */ + float bias[ 2 ]; + int texMins[ 2 ], texMaxs[ 2 ], texRange[ 2 ]; + + /* ydnar: for patches */ + float longestCurve; + int maxIterations; + int patchWidth, patchHeight; + vec3_t bounds[ 2 ]; + + /* ydnar/sd: for foliage */ + int numFoliageInstances; + + /* ydnar: editor/useful numbering */ + int entityNum; + int surfaceNum; +} +mapDrawSurface_t; + + +typedef struct drawSurfRef_s +{ + struct drawSurfRef_s *nextRef; + int outputNum; +} +drawSurfRef_t; + + +/* ydnar: metasurfaces are constructed from lists of metatriangles so they can be merged in the best way */ +typedef struct metaTriangle_s +{ + shaderInfo_t *si; + side_t *side; + int entityNum, surfaceNum, planeNum, fogNum, sampleSize, castShadows, recvShadows; + vec4_t plane; + vec3_t lightmapAxis; + int indexes[ 3 ]; +} +metaTriangle_t; + + +typedef struct epair_s +{ + struct epair_s *next; + char *key, *value; +} +epair_t; + + +typedef struct +{ + vec3_t origin; + brush_t *brushes, *lastBrush; + parseMesh_t *patches; + int mapEntityNum, firstDrawSurf; + int firstBrush, numBrushes; /* only valid during BSP compile */ + epair_t *epairs; +} +entity_t; + + +typedef struct node_s +{ + /* both leafs and nodes */ + int planenum; /* -1 = leaf node */ + struct node_s *parent; + vec3_t mins, maxs; /* valid after portalization */ + brush_t *volume; /* one for each leaf/node */ + + /* nodes only */ + side_t *side; /* the side that created the node */ + struct node_s *children[ 2 ]; + int compileFlags; /* ydnar: hint, antiportal */ + int tinyportals; + vec3_t referencepoint; + + /* leafs only */ + qboolean opaque; /* view can never be inside */ + qboolean areaportal; + qboolean skybox; /* ydnar: a skybox leaf */ + qboolean sky; /* ydnar: a sky leaf */ + int cluster; /* for portalfile writing */ + int area; /* for areaportals */ + brush_t *brushlist; /* fragments of all brushes in this leaf */ + drawSurfRef_t *drawSurfReferences; + + int occupied; /* 1 or greater can reach entity */ + entity_t *occupant; /* for leak file testing */ + + struct portal_s *portals; /* also on nodes during construction */ +} +node_t; + + +typedef struct portal_s +{ + plane_t plane; + node_t *onnode; /* NULL = outside box */ + node_t *nodes[ 2 ]; /* [ 0 ] = front side of plane */ + struct portal_s *next[ 2 ]; + winding_t *winding; + + qboolean sidefound; /* false if ->side hasn't been checked */ + int compileFlags; /* from original face that caused the split */ + side_t *side; /* NULL = non-visible */ +} +portal_t; + + +typedef struct +{ + node_t *headnode; + node_t outside_node; + vec3_t mins, maxs; +} +tree_t; + + + +/* ------------------------------------------------------------------------------- + +vis structures + +------------------------------------------------------------------------------- */ + +typedef struct +{ + vec3_t normal; + float dist; +} +visPlane_t; + + +typedef struct +{ + int numpoints; + vec3_t points[ MAX_POINTS_ON_FIXED_WINDING ]; /* variable sized */ +} +fixedWinding_t; + + +typedef struct passage_s +{ + struct passage_s *next; + byte cansee[ 1 ]; /* all portals that can be seen through this passage */ +} passage_t; + + +typedef enum +{ + stat_none, + stat_working, + stat_done +} +vstatus_t; + + +typedef struct +{ + int num; + qboolean hint; /* true if this portal was created from a hint splitter */ + qboolean removed; + visPlane_t plane; /* normal pointing into neighbor */ + int leaf; /* neighbor */ + + vec3_t origin; /* for fast clip testing */ + float radius; + + fixedWinding_t *winding; + vstatus_t status; + byte *portalfront; /* [portals], preliminary */ + byte *portalflood; /* [portals], intermediate */ + byte *portalvis; /* [portals], final */ + + int nummightsee; /* bit count on portalflood for sort */ + passage_t *passages; /* there are just as many passages as there */ + /* are portals in the leaf this portal leads */ +} +vportal_t; + + +typedef struct leaf_s +{ + int numportals; + int merged; + vportal_t *portals[MAX_PORTALS_ON_LEAF]; +} +leaf_t; + + +typedef struct pstack_s +{ + byte mightsee[ MAX_PORTALS / 8 ]; + struct pstack_s *next; + leaf_t *leaf; + vportal_t *portal; /* portal exiting */ + fixedWinding_t *source; + fixedWinding_t *pass; + + fixedWinding_t windings[ 3 ]; /* source, pass, temp in any order */ + int freewindings[ 3 ]; + + visPlane_t portalplane; + int depth; +#ifdef SEPERATORCACHE + visPlane_t seperators[ 2 ][ MAX_SEPERATORS ]; + int numseperators[ 2 ]; +#endif +} +pstack_t; + + +typedef struct +{ + vportal_t *base; + int c_chains; + pstack_t pstack_head; +} +threaddata_t; + + + +/* ------------------------------------------------------------------------------- + +light structures + +------------------------------------------------------------------------------- */ + +/* ydnar: new light struct with flags */ +typedef struct light_s +{ + struct light_s *next; + + int type; + int flags; /* ydnar: condensed all the booleans into one flags int */ + shaderInfo_t *si; + + vec3_t origin; + vec3_t normal; /* for surfaces, spotlights, and suns */ + float dist; /* plane location along normal */ + + float photons; + int style; + vec3_t color; + float radiusByDist; /* for spotlights */ + float fade; /* ydnar: from wolf, for linear lights */ + float angleScale; /* ydnar: stolen from vlight for K */ + + float add; /* ydnar: used for area lights */ + float envelope; /* ydnar: units until falloff < tolerance */ + float envelope2; /* ydnar: envelope squared (tiny optimization) */ + vec3_t mins, maxs; /* ydnar: pvs envelope */ + int cluster; /* ydnar: cluster light falls into */ + + winding_t *w; + vec3_t emitColor; /* full out-of-gamut value */ + + float falloffTolerance; /* ydnar: minimum attenuation threshold */ + float filterRadius; /* ydnar: lightmap filter radius in world units, 0 == default */ +} +light_t; + + +typedef struct +{ + /* constant input */ + qboolean testOcclusion, forceSunlight, testAll; + int recvShadows; + + int numSurfaces; + int *surfaces; + + int numLights; + light_t **lights; + + qboolean twoSided; + + /* per-sample input */ + int cluster; + vec3_t origin, normal; + vec_t inhibitRadius; /* sphere in which occluding geometry is ignored */ + + /* per-light input */ + light_t *light; + vec3_t end; + + /* calculated input */ + vec3_t displacement, direction; + vec_t distance; + + /* input and output */ + vec3_t color; /* starts out at full color, may be reduced if transparent surfaces are crossed */ + + /* output */ + int compileFlags; /* for determining surface compile flags traced through */ + qboolean passSolid; + qboolean opaque; + + /* working data */ + int numTestNodes; + int testNodes[ MAX_TRACE_TEST_NODES ]; +} +trace_t; + + + +/* must be identical to bspDrawVert_t except for float color! */ +typedef struct +{ + vec3_t xyz; + float st[ 2 ]; + float lightmap[ MAX_LIGHTMAPS ][ 2 ]; + vec3_t normal; + float color[ MAX_LIGHTMAPS ][ 4 ]; +} +radVert_t; + + +typedef struct +{ + int numVerts; + radVert_t verts[ MAX_POINTS_ON_WINDING ]; +} +radWinding_t; + + +/* crutch for poor local allocations in win32 smp */ +typedef struct +{ + vec_t dists[ MAX_POINTS_ON_WINDING + 4 ]; + int sides[ MAX_POINTS_ON_WINDING + 4 ]; +} +clipWork_t; + + +/* ydnar: new lightmap handling code */ +typedef struct outLightmap_s +{ + int lightmapNum, extLightmapNum; + int customWidth, customHeight; + int numLightmaps; + int freeLuxels; + int numShaders; + shaderInfo_t *shaders[ MAX_LIGHTMAP_SHADERS ]; + byte *lightBits; + byte *bspLightBytes; + byte *bspDirBytes; +} +outLightmap_t; + + +typedef struct rawLightmap_s +{ + qboolean finished, splotchFix, wrap[ 2 ]; + int customWidth, customHeight; + float gamma; + float filterRadius; + + int firstLightSurface, numLightSurfaces; /* index into lightSurfaces */ + int numLightClusters, *lightClusters; + + int sampleSize, actualSampleSize, axisNum; + int entityNum; + int recvShadows; + vec3_t mins, maxs, axis, origin, *vecs; + float *plane; + int w, h, sw, sh, used; + + int numStyledTwins; + struct rawLightmap_s *twins[ MAX_LIGHTMAPS ]; + + int outLightmapNums[ MAX_LIGHTMAPS ]; + int twinNums[ MAX_LIGHTMAPS ]; + int lightmapX[ MAX_LIGHTMAPS ], lightmapY[ MAX_LIGHTMAPS ]; + byte styles[ MAX_LIGHTMAPS ]; + float *bspLuxels[ MAX_LIGHTMAPS ]; + float *radLuxels[ MAX_LIGHTMAPS ]; + float *superLuxels[ MAX_LIGHTMAPS ]; + float *superOrigins; + float *superNormals; + int *superClusters; + + float *superDeluxels; /* average light direction */ + float *bspDeluxels; +} +rawLightmap_t; + + +typedef struct rawGridPoint_s +{ + vec3_t ambient[ MAX_LIGHTMAPS ]; + vec3_t directed[ MAX_LIGHTMAPS ]; + vec3_t dir; + byte styles[ MAX_LIGHTMAPS ]; +} +rawGridPoint_t; + + +typedef struct surfaceInfo_s +{ + bspModel_t *model; + shaderInfo_t *si; + rawLightmap_t *lm; + int parentSurfaceNum, childSurfaceNum; + int entityNum, castShadows, recvShadows, sampleSize, patchIterations; + float longestCurve; + float *plane; + vec3_t axis, mins, maxs; + qboolean hasLightmap, approximated; + int firstSurfaceCluster, numSurfaceClusters; +} +surfaceInfo_t; + + + +/* ------------------------------------------------------------------------------- + +prototypes + +------------------------------------------------------------------------------- */ + +/* main.c */ +vec_t Random( void ); +int BSPInfo( int count, char **fileNames ); +int ScaleBSPMain( int argc, char **argv ); +int ConvertMain( int argc, char **argv ); + + +/* path_init.c */ +void InitPaths( int *argc, char **argv ); + + +/* bsp.c */ +int BSPMain( int argc, char **argv ); + + +/* convert_map.c */ +int ConvertBSPToMap( char *bspName ); + + +/* convert_ase.c */ +int ConvertBSPToASE( char *bspName ); + + +/* brush.c */ +sideRef_t *AllocSideRef( side_t *side, sideRef_t *next ); +int CountBrushList( brush_t *brushes ); +brush_t *AllocBrush( int numsides ); +void FreeBrush( brush_t *brushes ); +void FreeBrushList( brush_t *brushes ); +brush_t *CopyBrush( brush_t *brush ); +qboolean BoundBrush( brush_t *brush ); +qboolean CreateBrushWindings( brush_t *brush ); +brush_t *BrushFromBounds( vec3_t mins, vec3_t maxs ); +vec_t BrushVolume( brush_t *brush ); +void WriteBSPBrushMap( char *name, brush_t *list ); + +void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree ); +void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree ); + +int BoxOnPlaneSide( vec3_t mins, vec3_t maxs, plane_t *plane ); +qboolean WindingIsTiny( winding_t *w ); + +void SplitBrush( brush_t *brush, int planenum, brush_t **front, brush_t **back); + +tree_t *AllocTree( void ); +node_t *AllocNode( void ); + + +/* mesh.c */ +void LerpDrawVert( bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *out ); +void LerpDrawVertAmount( bspDrawVert_t *a, bspDrawVert_t *b, float amount, bspDrawVert_t *out ); +void FreeMesh( mesh_t *m ); +mesh_t *CopyMesh( mesh_t *mesh ); +void PrintMesh( mesh_t *m ); +mesh_t *TransposeMesh( mesh_t *in ); +void InvertMesh( mesh_t *m ); +mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ); +int IterationsForCurve( float len, int subdivisions ); +mesh_t *SubdivideMesh2( mesh_t in, int iterations ); +mesh_t *SubdivideMeshQuads( mesh_t *in, float minLength, int maxsize, int *widthtable, int *heighttable ); +mesh_t *RemoveLinearMeshColumnsRows( mesh_t *in ); +void MakeMeshNormals( mesh_t in ); +void PutMeshOnCurve( mesh_t in ); + +void MakeNormalVectors( vec3_t forward, vec3_t right, vec3_t up ); + + +/* map.c */ +void LoadMapFile( char *filename, qboolean onlyLights ); +int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ); +int PlaneTypeForNormal( vec3_t normal ); +void AddBrushBevels( void ); +brush_t *FinishBrush( void ); + + +/* portals.c */ +void MakeHeadnodePortals( tree_t *tree ); +void MakeNodePortal( node_t *node ); +void SplitNodePortals( node_t *node ); + +qboolean PortalPassable( portal_t *p ); + +qboolean FloodEntities( tree_t *tree ); +void FillOutside( node_t *headnode); +void FloodAreas( tree_t *tree); +face_t *VisibleFaces( entity_t *e, tree_t *tree ); +void FreePortal( portal_t *p ); + +void MakeTreePortals( tree_t *tree ); + + +/* leakfile.c */ +xmlNodePtr LeakFile( tree_t *tree ); + + +/* prtfile.c */ +void NumberClusters( tree_t *tree ); +void WritePortalFile( tree_t *tree ); + + +/* writebsp.c */ +void SetModelNumbers( void ); +void SetLightStyles( void ); + +int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags ); + +void BeginBSPFile( void ); +void EndBSPFile( void ); +void EmitBrushes( brush_t *brushes, int *firstBrush, int *numBrushes ); +void EmitFogs( void ); + +void BeginModel( void ); +void EndModel( entity_t *e, node_t *headnode ); + + +/* tree.c */ +void FreeTree( tree_t *tree ); +void FreeTree_r( node_t *node ); +void PrintTree_r( node_t *node, int depth ); +void FreeTreePortals_r( node_t *node ); + + +/* patch.c */ +void ParsePatch( qboolean onlyLights ); +mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ); +void PatchMapDrawSurfs( entity_t *e ); + + +/* tjunction.c */ +void FixTJunctions( entity_t *e ); + + +/* fog.c */ +winding_t *WindingFromDrawSurf( mapDrawSurface_t *ds ); +void FogDrawSurfaces( entity_t *e ); +int FogForPoint( vec3_t point, float epsilon ); +int FogForBounds( vec3_t mins, vec3_t maxs, float epsilon ); +void CreateMapFogs( void ); + + +/* facebsp.c */ +face_t *MakeStructuralBSPFaceList( brush_t *list ); +face_t *MakeVisibleBSPFaceList( brush_t *list ); +tree_t *FaceBSP( face_t *list ); + + +/* model.c */ +void PicoPrintFunc( int level, const char *str ); +void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ); +picoModel_t *FindModel( char *name, int frame ); +picoModel_t *LoadModel( char *name, int frame ); +void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale ); +void AddTriangleModels( entity_t *e ); + + +/* surface.c */ +mapDrawSurface_t *AllocDrawSurface( surfaceType_t type ); +void FinishSurface( mapDrawSurface_t *ds ); +void StripFaceSurface( mapDrawSurface_t *ds ); +qboolean CalcSurfaceTextureRange( mapDrawSurface_t *ds ); +qboolean CalcLightmapAxis( vec3_t normal, vec3_t axis ); +void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ); +void ClassifyEntitySurfaces( entity_t *e ); +void TidyEntitySurfaces( entity_t *e ); +mapDrawSurface_t *CloneSurface( mapDrawSurface_t *src, shaderInfo_t *si ); +mapDrawSurface_t *MakeCelSurface( mapDrawSurface_t *src, shaderInfo_t *si ); +qboolean IsTriangleDegenerate( bspDrawVert_t *points, int a, int b, int c ); +void ClearSurface( mapDrawSurface_t *ds ); +void AddEntitySurfaceModels( entity_t *e ); +mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, winding_t *w ); +mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh ); +mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, char *flareShader, int lightStyle ); +mapDrawSurface_t *DrawSurfaceForShader( char *shader ); +void ClipSidesIntoTree( entity_t *e, tree_t *tree ); +void MakeDebugPortalSurfs( tree_t *tree ); +void MakeFogHullSurfs( entity_t *e, tree_t *tree, char *shader ); +void SubdivideFaceSurfaces( entity_t *e, tree_t *tree ); +void AddEntitySurfaceModels( entity_t *e ); +int AddSurfaceModels( mapDrawSurface_t *ds ); +void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ); + + +/* surface_fur.c */ +void Fur( mapDrawSurface_t *src ); + + +/* surface_foliage.c */ +void Foliage( mapDrawSurface_t *src ); + + +/* ydnar: surface_meta.c */ +void ClearMetaTriangles( void ); +int FindMetaTriangle( metaTriangle_t *src, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c, int planeNum ); +void MakeEntityMetaTriangles( entity_t *e ); +void FixMetaTJunctions( void ); +void SmoothMetaTriangles( void ); +void MergeMetaTriangles( void ); + + +/* surface_extra.c */ +void SetDefaultSampleSize( int sampleSize ); + +void SetSurfaceExtra( mapDrawSurface_t *ds, int num ); + +shaderInfo_t *GetSurfaceExtraShaderInfo( int num ); +int GetSurfaceExtraParentSurfaceNum( int num ); +int GetSurfaceExtraEntityNum( int num ); +int GetSurfaceExtraCastShadows( int num ); +int GetSurfaceExtraRecvShadows( int num ); +int GetSurfaceExtraSampleSize( int num ); +float GetSurfaceExtraLongestCurve( int num ); +void GetSurfaceExtraLightmapAxis( int num, vec3_t lightmapAxis ); + +void WriteSurfaceExtraFile( const char *path ); +void LoadSurfaceExtraFile( const char *path ); + + +/* decals.c */ +void ProcessDecals( void ); +void MakeEntityDecals( entity_t *e ); + + +/* brush_primit.c */ +void ComputeAxisBase( vec3_t normal, vec3_t texX, vec3_t texY); + + +/* vis.c */ +fixedWinding_t *NewFixedWinding( int points ); +int VisMain( int argc, char **argv ); + +/* visflow.c */ +int CountBits( byte *bits, int numbits ); +void PassageFlow( int portalnum ); +void CreatePassages( int portalnum ); +void PassageMemory( void ); +void BasePortalVis( int portalnum ); +void BetterPortalVis( int portalnum ); +void PortalFlow( int portalnum ); +void PassagePortalFlow( int portalnum ); + + + +/* light.c */ +float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ); +int LightContributionToSample( trace_t *trace ); +void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] ); +int LightContributionToPoint( trace_t *trace ); +int LightMain( int argc, char **argv ); + + +/* light_trace.c */ +void SetupTraceNodes( void ); +void TraceLine( trace_t *trace ); +float SetupTrace( trace_t *trace ); + + +/* light_bounce.c */ +qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ); +void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ); +void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ); +void RadCreateDiffuseLights( void ); +void RadFreeLights(); + + +/* light_ydnar.c */ +void ColorToBytes( const float *color, byte *colorBytes, float scale ); +void SmoothNormals( void ); + +void MapRawLightmap( int num ); +void IlluminateRawLightmap( int num ); +void IlluminateVertexes( int num ); + +void SetupBrushes( void ); +void SetupClusters( void ); +qboolean ClusterVisible( int a, int b ); +qboolean ClusterVisibleToPoint( vec3_t point, int cluster ); +int ClusterForPoint( vec3_t point ); +int ClusterForPointExt( vec3_t point, float epsilon ); +int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters ); +int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags ); +void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ); +void FreeTraceLights( trace_t *trace ); +void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace ); +void CreateTraceLightsForSurface( int num, trace_t *trace ); + + +/* lightmaps_ydnar.c */ +void ExportLightmaps( void ); + +int ExportLightmapsMain( int argc, char **argv ); +int ImportLightmapsMain( int argc, char **argv ); + +void SetupSurfaceLightmaps( void ); +void StitchSurfaceLightmaps( void ); +void StoreSurfaceLightmaps( void ); + + +/* image.c */ +void ImageFree( image_t *image ); +image_t *ImageFind( const char *filename ); +image_t *ImageLoad( const char *filename ); + + +/* shaders.c */ +void AlphaMod( alphaMod_t *am, int numVerts, bspDrawVert_t *drawVerts ); + +void TcMod( tcMod_t mod, float st[ 2 ] ); +void TcModIdentity( tcMod_t mod ); +void TcModMultiply( tcMod_t a, tcMod_t b, tcMod_t out ); +void TcModTranslate( tcMod_t mod, float s, float t ); +void TcModScale( tcMod_t mod, float s, float t ); +void TcModRotate( tcMod_t mod, float euler ); + +qboolean ApplySurfaceParm( char *name, int *contentFlags, int *surfaceFlags, int *compileFlags ); + +void BeginMapShaderFile( const char *mapFile ); +void WriteMapShaderFile( void ); +shaderInfo_t *CustomShader( shaderInfo_t *si, char *find, char *replace ); +void EmitVertexRemapShader( char *from, char *to ); + +void LoadShaderInfo( void ); +shaderInfo_t *ShaderInfoForShader( const char *shader ); + + +/* bspfile_abstract.c */ +void SetGridPoints( int n ); +void SetDrawVerts( int n ); +void IncDrawVerts(); +void SetDrawSurfaces(int n); +void SetDrawSurfacesBuffer(); +void BSPFilesCleanup(); + +void SwapBlock( int *block, int size ); + +int GetLumpElements( bspHeader_t *header, int lump, int size ); +void *GetLump( bspHeader_t *header, int lump ); +int CopyLump( bspHeader_t *header, int lump, void *dest, int size ); +void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ); + +void LoadBSPFile( const char *filename ); +void WriteBSPFile( const char *filename ); +void PrintBSPFileSizes( void ); + +epair_t *ParseEPair( void ); +void ParseEntities( void ); +void UnparseEntities( void ); +void PrintEntity( const entity_t *ent ); +void SetKeyValue( entity_t *ent, const char *key, const char *value ); +const char *ValueForKey( const entity_t *ent, const char *key ); +int IntForKey( const entity_t *ent, const char *key ); +vec_t FloatForKey( const entity_t *ent, const char *key ); +void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ); +entity_t *FindTargetEntity( const char *target ); +void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ); + + +/* bspfile_ibsp.c */ +void LoadIBSPFile( const char *filename ); +void WriteIBSPFile( const char *filename ); + + +/* bspfile_rbsp.c */ +void LoadRBSPFile( const char *filename ); +void WriteRBSPFile( const char *filename ); + + + +/* ------------------------------------------------------------------------------- + +bsp/general global variables + +------------------------------------------------------------------------------- */ + +#ifdef MAIN_C + #define Q_EXTERN + #define Q_ASSIGN( a ) = a +#else + #define Q_EXTERN extern + #define Q_ASSIGN( a ) +#endif + +/* game support */ +Q_EXTERN game_t games[] +#ifndef MAIN_C + ; +#else + = + { + #include "game_quake3.h" + , + #include "game_tenebrae.h" + , + #include "game_wolf.h" + , + #include "game_wolfet.h"/* most be after game_wolf.h as they share defines! */ + , + #include "game_ef.h" + , + #include "game_sof2.h" + , + #include "game_jk2.h" /* most be after game_sof2.h as they share defines! */ + , + #include "game_ja.h" /* most be after game_jk2.h as they share defines! */ + , + { NULL, NULL, NULL, NULL, NULL, qfalse, 0, 0, NULL } /* null game */ + }; +#endif +Q_EXTERN game_t *game Q_ASSIGN( &games[ 0 ] ); + + +/* general */ +Q_EXTERN int numImages Q_ASSIGN( 0 ); +Q_EXTERN image_t images[ MAX_IMAGES ]; + +Q_EXTERN int numPicoModels Q_ASSIGN( 0 ); +Q_EXTERN picoModel_t *picoModels[ MAX_MODELS ]; + +Q_EXTERN shaderInfo_t *shaderInfo Q_ASSIGN( NULL ); +Q_EXTERN int numShaderInfo Q_ASSIGN( 0 ); +Q_EXTERN int numVertexRemaps Q_ASSIGN( 0 ); + +Q_EXTERN surfaceParm_t custSurfaceParms[ MAX_CUST_SURFACEPARMS ]; +Q_EXTERN int numCustSurfaceParms Q_ASSIGN( 0 ); + +Q_EXTERN char mapName[ MAX_QPATH ]; /* ydnar: per-map custom shaders for larger lightmaps */ +Q_EXTERN char mapShaderFile[ 1024 ]; +Q_EXTERN qboolean warnImage Q_ASSIGN( qtrue ); + +/* ydnar: sinusoid samples */ +Q_EXTERN float jitters[ MAX_JITTERS ]; + + +/* commandline arguments */ +Q_EXTERN qboolean verbose; +Q_EXTERN qboolean verboseEntities Q_ASSIGN( qfalse ); +Q_EXTERN qboolean force Q_ASSIGN( qfalse ); +Q_EXTERN qboolean infoMode Q_ASSIGN( qfalse ); +Q_EXTERN qboolean useCustomInfoParms Q_ASSIGN( qfalse ); +Q_EXTERN qboolean noprune Q_ASSIGN( qfalse ); +Q_EXTERN qboolean leaktest Q_ASSIGN( qfalse ); +Q_EXTERN qboolean nodetail Q_ASSIGN( qfalse ); +Q_EXTERN qboolean nosubdivide Q_ASSIGN( qfalse ); +Q_EXTERN qboolean notjunc Q_ASSIGN( qfalse ); +Q_EXTERN qboolean fulldetail Q_ASSIGN( qfalse ); +Q_EXTERN qboolean nowater Q_ASSIGN( qfalse ); +Q_EXTERN qboolean noCurveBrushes Q_ASSIGN( qfalse ); +Q_EXTERN qboolean fakemap Q_ASSIGN( qfalse ); +Q_EXTERN qboolean coplanar Q_ASSIGN( qfalse ); +Q_EXTERN qboolean nofog Q_ASSIGN( qfalse ); +Q_EXTERN qboolean noHint Q_ASSIGN( qfalse ); /* ydnar */ +Q_EXTERN qboolean renameModelShaders Q_ASSIGN( qfalse ); /* ydnar */ +Q_EXTERN qboolean skyFixHack Q_ASSIGN( qfalse ); /* ydnar */ + +Q_EXTERN int patchSubdivisions Q_ASSIGN( 8 ); /* ydnar: -patchmeta subdivisions */ + +Q_EXTERN int maxSurfaceVerts Q_ASSIGN( 64 ); /* ydnar */ +Q_EXTERN int maxSurfaceIndexes Q_ASSIGN( 1000 ); /* ydnar */ +Q_EXTERN float npDegrees Q_ASSIGN( 0.0f ); /* ydnar: nonplanar degrees */ +Q_EXTERN int bevelSnap Q_ASSIGN( 0 ); /* ydnar: bevel plane snap */ +Q_EXTERN int texRange Q_ASSIGN( 0 ); +Q_EXTERN qboolean flat Q_ASSIGN( qfalse ); +Q_EXTERN qboolean meta Q_ASSIGN( qfalse ); +Q_EXTERN qboolean patchMeta Q_ASSIGN( qfalse ); +Q_EXTERN qboolean emitFlares Q_ASSIGN( qfalse ); +Q_EXTERN qboolean debugSurfaces Q_ASSIGN( qfalse ); +Q_EXTERN qboolean debugInset Q_ASSIGN( qfalse ); +Q_EXTERN qboolean debugPortals Q_ASSIGN( qfalse ); + +Q_EXTERN double normalEpsilon Q_ASSIGN( 0.00001 ); +Q_EXTERN double distanceEpsilon Q_ASSIGN( 0.01 ); + + +/* bsp */ +Q_EXTERN int numMapEntities Q_ASSIGN( 0 ); + +Q_EXTERN int blockSize[ 3 ] /* should be the same as in radiant */ +#ifndef MAIN_C + ; +#else + = { 1024, 1024, 1024 }; +#endif + +Q_EXTERN char name[ 1024 ]; +Q_EXTERN char source[ 1024 ]; +Q_EXTERN char outbase[ 32 ]; + +Q_EXTERN int sampleSize; /* lightmap sample size in units */ + +Q_EXTERN int mapEntityNum Q_ASSIGN( 0 ); + +Q_EXTERN int entitySourceBrushes; + +Q_EXTERN plane_t mapplanes[ MAX_MAP_PLANES ]; /* mapplanes[ num ^ 1 ] will always be the mirror or mapplanes[ num ] */ +Q_EXTERN int nummapplanes; /* nummapplanes will always be even */ +Q_EXTERN int numMapPatches; +Q_EXTERN vec3_t mapMins, mapMaxs; + +Q_EXTERN int defaultFogNum Q_ASSIGN( -1 ); /* ydnar: cleaner fog handling */ +Q_EXTERN int numMapFogs Q_ASSIGN( 0 ); +Q_EXTERN fog_t mapFogs[ MAX_MAP_FOGS ]; + +Q_EXTERN entity_t *mapEnt; +Q_EXTERN brush_t *buildBrush; +Q_EXTERN int numActiveBrushes; +Q_EXTERN int g_bBrushPrimit; + +Q_EXTERN int numStrippedLights Q_ASSIGN( 0 ); + + +/* surface stuff */ +Q_EXTERN mapDrawSurface_t *mapDrawSurfs Q_ASSIGN( NULL ); +Q_EXTERN int numMapDrawSurfs; + +Q_EXTERN int numSurfacesByType[ NUM_SURFACE_TYPES ]; +Q_EXTERN int numClearedSurfaces; +Q_EXTERN int numStripSurfaces; +Q_EXTERN int numFanSurfaces; +Q_EXTERN int numMergedSurfaces; +Q_EXTERN int numMergedVerts; + +Q_EXTERN int numRedundantIndexes; + +Q_EXTERN int numSurfaceModels Q_ASSIGN( 0 ); + +Q_EXTERN byte debugColors[ 12 ][ 3 ] +#ifndef MAIN_C + ; +#else + = + { + { 255, 0, 0 }, + { 192, 128, 128 }, + { 255, 255, 0 }, + { 192, 192, 128 }, + { 0, 255, 255 }, + { 128, 192, 192 }, + { 0, 0, 255 }, + { 128, 128, 192 }, + { 255, 0, 255 }, + { 192, 128, 192 }, + { 0, 255, 0 }, + { 128, 192, 128 } + }; +#endif + +Q_EXTERN qboolean skyboxPresent Q_ASSIGN( qfalse ); +Q_EXTERN int skyboxArea Q_ASSIGN( -1 ); +Q_EXTERN m4x4_t skyboxTransform; + + + +/* ------------------------------------------------------------------------------- + +vis global variables + +------------------------------------------------------------------------------- */ + +/* commandline arguments */ +Q_EXTERN qboolean fastvis; +Q_EXTERN qboolean noPassageVis; +Q_EXTERN qboolean passageVisOnly; +Q_EXTERN qboolean mergevis; +Q_EXTERN qboolean nosort; +Q_EXTERN qboolean saveprt; +Q_EXTERN qboolean hint; /* ydnar */ +Q_EXTERN char inbase[ MAX_QPATH ]; + +/* other bits */ +Q_EXTERN int totalvis; + +Q_EXTERN float farPlaneDist; /* rr2do2, rf, mre, ydnar all contributed to this one... */ + +Q_EXTERN int numportals; +Q_EXTERN int portalclusters; + +Q_EXTERN vportal_t *portals; +Q_EXTERN leaf_t *leafs; + +Q_EXTERN vportal_t *faces; +Q_EXTERN leaf_t *faceleafs; + +Q_EXTERN int numfaces; + +Q_EXTERN int c_portaltest, c_portalpass, c_portalcheck; +Q_EXTERN int c_portalskip, c_leafskip; +Q_EXTERN int c_vistest, c_mighttest; +Q_EXTERN int c_chains; + +Q_EXTERN byte *vismap, *vismap_p, *vismap_end; + +Q_EXTERN int testlevel; + +Q_EXTERN byte *uncompressed; + +Q_EXTERN int leafbytes, leaflongs; +Q_EXTERN int portalbytes, portallongs; + +Q_EXTERN vportal_t *sorted_portals[ MAX_MAP_PORTALS * 2 ]; + + + +/* ------------------------------------------------------------------------------- + +light global variables + +------------------------------------------------------------------------------- */ + +/* commandline arguments */ +Q_EXTERN qboolean noSurfaces; + +Q_EXTERN qboolean deluxemap; +Q_EXTERN qboolean debugDeluxemap; + +Q_EXTERN qboolean loMem Q_ASSIGN( qfalse ); + +Q_EXTERN qboolean fast; +Q_EXTERN qboolean faster; +Q_EXTERN qboolean fastgrid; +Q_EXTERN qboolean fastbounce; +Q_EXTERN qboolean cheap; +Q_EXTERN qboolean cheapgrid; +Q_EXTERN qboolean smooth; +Q_EXTERN int bounce; +Q_EXTERN qboolean bounceOnly; +Q_EXTERN qboolean bouncing; +Q_EXTERN qboolean bouncegrid; +Q_EXTERN qboolean normalmap; +Q_EXTERN qboolean trisoup; +Q_EXTERN qboolean shade; +Q_EXTERN float shadeAngleDegrees Q_ASSIGN( 0.0f ); +Q_EXTERN int superSample Q_ASSIGN( 0 ); +Q_EXTERN int lightSamples Q_ASSIGN( 1 ); +Q_EXTERN qboolean filter; +Q_EXTERN qboolean sunOnly; +Q_EXTERN int approximateTolerance Q_ASSIGN( 0 ); +Q_EXTERN qboolean noCollapse; +Q_EXTERN qboolean debug; +Q_EXTERN qboolean debugSurfaces; +Q_EXTERN qboolean debugUnused; +Q_EXTERN qboolean debugAxis; +Q_EXTERN qboolean debugCluster; +Q_EXTERN qboolean debugOrigin; +Q_EXTERN qboolean exportLightmaps; +Q_EXTERN qboolean externalLightmaps; +Q_EXTERN int lmCustomSize Q_ASSIGN( LIGHTMAP_WIDTH ); + +/* standard flags */ +Q_EXTERN qboolean noTrace; +Q_EXTERN qboolean patchShadows; +Q_EXTERN qboolean dump; +Q_EXTERN qboolean extra; +Q_EXTERN qboolean extraWide; +Q_EXTERN qboolean lightmapBorder; + +Q_EXTERN qboolean noSurfaces; + +Q_EXTERN int sampleSize Q_ASSIGN( DEFAULT_LIGHTMAP_SAMPLE_SIZE ); +Q_EXTERN qboolean noVertexLighting Q_ASSIGN( qfalse ); +Q_EXTERN qboolean noGridLighting Q_ASSIGN( qfalse ); + +/* longest distance across the map */ +Q_EXTERN float maxMapDistance Q_ASSIGN( 0 ); + +/* for run time tweaking of light sources */ +Q_EXTERN float pointScale Q_ASSIGN( 7500.0f ); +Q_EXTERN float areaScale Q_ASSIGN( 0.25f ); +Q_EXTERN float skyScale Q_ASSIGN( 1.0f ); +Q_EXTERN float bounceScale Q_ASSIGN( 0.25f ); + +/* ydnar: for runtime tweaking of falloff tolerance */ +Q_EXTERN float falloffTolerance Q_ASSIGN( 1.0f ); + +Q_EXTERN qboolean exactPointToPolygon Q_ASSIGN( qtrue ); + +Q_EXTERN float formFactorValueScale Q_ASSIGN( 3.0f ); + +Q_EXTERN float linearScale Q_ASSIGN( 1.0f / 8000.0f ); + +Q_EXTERN light_t *lights; +Q_EXTERN int numPointLights; +Q_EXTERN int numSpotLights; +Q_EXTERN int numSunLights; +Q_EXTERN int numAreaLights; + +/* ydnar: for luxel placement */ +Q_EXTERN int numSurfaceClusters, maxSurfaceClusters; +Q_EXTERN int *surfaceClusters; + +/* ydnar: for radiosity */ +Q_EXTERN int numDiffuseLights; +Q_EXTERN int numBrushDiffuseLights; +Q_EXTERN int numTriangleDiffuseLights; +Q_EXTERN int numPatchDiffuseLights; + +/* ydnar: general purpose extra copy of drawvert list */ +Q_EXTERN bspDrawVert_t *yDrawVerts; + +/* ydnar: for tracing statistics */ +Q_EXTERN int minSurfacesTested; +Q_EXTERN int maxSurfacesTested; +Q_EXTERN int totalSurfacesTested; +Q_EXTERN int totalTraces; + +Q_EXTERN FILE *dumpFile; + +Q_EXTERN int c_visible, c_occluded; +Q_EXTERN int c_subsampled; /* ydnar */ + +Q_EXTERN int defaultLightSubdivide Q_ASSIGN( 999 ); + +Q_EXTERN vec3_t ambientColor; +Q_EXTERN vec3_t minLight, minVertexLight, minGridLight; + +Q_EXTERN int *entitySurface; +Q_EXTERN vec3_t *surfaceOrigin; + +Q_EXTERN vec3_t sunDirection; +Q_EXTERN vec3_t sunLight; + +/* tracing */ +Q_EXTERN int c_totalTrace; +Q_EXTERN int c_cullTrace, c_testTrace; +Q_EXTERN int c_testFacets; + +/* ydnar: light optimization */ +Q_EXTERN float subdivideThreshold Q_ASSIGN( DEFAULT_SUBDIVIDE_THRESHOLD ); + +Q_EXTERN int numOpaqueBrushes, maxOpaqueBrush; +Q_EXTERN byte *opaqueBrushes; + +Q_EXTERN int numLights; +Q_EXTERN int numCulledLights; + +Q_EXTERN int gridBoundsCulled; +Q_EXTERN int gridEnvelopeCulled; + +Q_EXTERN int lightsBoundsCulled; +Q_EXTERN int lightsEnvelopeCulled; +Q_EXTERN int lightsPlaneCulled; +Q_EXTERN int lightsClusterCulled; + +/* ydnar: radiosity */ +Q_EXTERN float diffuseSubdivide Q_ASSIGN( 256.0f ); +Q_EXTERN float minDiffuseSubdivide Q_ASSIGN( 64.0f ); +Q_EXTERN int numDiffuseSurfaces Q_ASSIGN( 0 ); + +/* ydnar: list of surface information necessary for lightmap calculation */ +Q_EXTERN surfaceInfo_t *surfaceInfos Q_ASSIGN( NULL ); + +/* ydnar: sorted list of surfaces */ +Q_EXTERN int *sortSurfaces Q_ASSIGN( NULL ); + +/* clumps of surfaces that share a raw lightmap */ +Q_EXTERN int numLightSurfaces Q_ASSIGN( 0 ); +Q_EXTERN int *lightSurfaces Q_ASSIGN( NULL ); + +/* raw lightmaps */ +Q_EXTERN int numRawSuperLuxels Q_ASSIGN( 0 ); +Q_EXTERN int numRawLightmaps Q_ASSIGN( 0 ); +Q_EXTERN rawLightmap_t *rawLightmaps Q_ASSIGN( NULL ); +Q_EXTERN int *sortLightmaps Q_ASSIGN( NULL ); + +/* vertex luxels */ +Q_EXTERN float *vertexLuxels[ MAX_LIGHTMAPS ]; +Q_EXTERN float *radVertexLuxels[ MAX_LIGHTMAPS ]; + +/* bsp lightmaps */ +Q_EXTERN int numLightmapShaders Q_ASSIGN( 0 ); +Q_EXTERN int numOutLightmaps Q_ASSIGN( 0 ); +Q_EXTERN int numBSPLightmaps Q_ASSIGN( 0 ); +Q_EXTERN int numExtLightmaps Q_ASSIGN( 0 ); +Q_EXTERN outLightmap_t *outLightmaps Q_ASSIGN( NULL ); + +/* grid points */ +Q_EXTERN int numRawGridPoints Q_ASSIGN( 0 ); +Q_EXTERN rawGridPoint_t *rawGridPoints Q_ASSIGN( NULL ); + +Q_EXTERN int numSurfsVertexLit Q_ASSIGN( 0 ); +Q_EXTERN int numSurfsVertexForced Q_ASSIGN( 0 ); +Q_EXTERN int numSurfsVertexApproximated Q_ASSIGN( 0 ); +Q_EXTERN int numSurfsLightmapped Q_ASSIGN( 0 ); +Q_EXTERN int numPlanarsLightmapped Q_ASSIGN( 0 ); +Q_EXTERN int numNonPlanarsLightmapped Q_ASSIGN( 0 ); +Q_EXTERN int numPatchesLightmapped Q_ASSIGN( 0 ); +Q_EXTERN int numPlanarPatchesLightmapped Q_ASSIGN( 0 ); + +Q_EXTERN int numLuxels Q_ASSIGN( 0 ); +Q_EXTERN int numLuxelsMapped Q_ASSIGN( 0 ); +Q_EXTERN int numLuxelsOccluded Q_ASSIGN( 0 ); +Q_EXTERN int numLuxelsIlluminated Q_ASSIGN( 0 ); +Q_EXTERN int numVertsIlluminated Q_ASSIGN( 0 ); + +/* lightgrid */ +Q_EXTERN vec3_t gridMins; +Q_EXTERN int gridBounds[ 3 ]; +Q_EXTERN vec3_t gridSize +#ifndef MAIN_C + ; +#else + = { 64, 64, 128 }; +#endif + + + +/* ------------------------------------------------------------------------------- + +abstracted bsp globals + +------------------------------------------------------------------------------- */ + +Q_EXTERN int numEntities Q_ASSIGN( 0 ); +Q_EXTERN int numBSPEntities Q_ASSIGN( 0 ); +Q_EXTERN entity_t entities[ MAX_MAP_ENTITIES ]; + +Q_EXTERN int numBSPModels Q_ASSIGN( 0 ); +Q_EXTERN bspModel_t bspModels[ MAX_MAP_MODELS ]; + +Q_EXTERN int numBSPShaders Q_ASSIGN( 0 ); +Q_EXTERN bspShader_t bspShaders[ MAX_MAP_MODELS ]; + +Q_EXTERN int bspEntDataSize Q_ASSIGN( 0 ); +Q_EXTERN char bspEntData[ MAX_MAP_ENTSTRING ]; + +Q_EXTERN int numBSPLeafs Q_ASSIGN( 0 ); +Q_EXTERN bspLeaf_t bspLeafs[ MAX_MAP_LEAFS ]; + +Q_EXTERN int numBSPPlanes Q_ASSIGN( 0 ); +Q_EXTERN bspPlane_t bspPlanes[ MAX_MAP_PLANES ]; + +Q_EXTERN int numBSPNodes Q_ASSIGN( 0 ); +Q_EXTERN bspNode_t bspNodes[ MAX_MAP_NODES ]; + +Q_EXTERN int numBSPLeafSurfaces Q_ASSIGN( 0 ); +Q_EXTERN int bspLeafSurfaces[ MAX_MAP_LEAFFACES ]; + +Q_EXTERN int numBSPLeafBrushes Q_ASSIGN( 0 ); +Q_EXTERN int bspLeafBrushes[ MAX_MAP_LEAFBRUSHES ]; + +Q_EXTERN int numBSPBrushes Q_ASSIGN( 0 ); +Q_EXTERN bspBrush_t bspBrushes[ MAX_MAP_BRUSHES ]; + +Q_EXTERN int numBSPBrushSides Q_ASSIGN( 0 ); +Q_EXTERN bspBrushSide_t bspBrushSides[ MAX_MAP_BRUSHSIDES ]; + +Q_EXTERN int numBSPLightBytes Q_ASSIGN( 0 ); +Q_EXTERN byte *bspLightBytes Q_ASSIGN( NULL ); + +//% Q_EXTERN int numBSPGridPoints Q_ASSIGN( 0 ); +//% Q_EXTERN byte *bspGridPoints Q_ASSIGN( NULL ); + +Q_EXTERN int numBSPGridPoints Q_ASSIGN( 0 ); +Q_EXTERN bspGridPoint_t *bspGridPoints Q_ASSIGN( NULL ); + +Q_EXTERN int numBSPVisBytes Q_ASSIGN( 0 ); +Q_EXTERN byte bspVisBytes[ MAX_MAP_VISIBILITY ]; + +Q_EXTERN int numBSPDrawVerts Q_ASSIGN( 0 ); +Q_EXTERN bspDrawVert_t *bspDrawVerts Q_ASSIGN( NULL ); + +Q_EXTERN int numBSPDrawIndexes Q_ASSIGN( 0 ); +Q_EXTERN int bspDrawIndexes[ MAX_MAP_DRAW_INDEXES ]; + +Q_EXTERN int numBSPDrawSurfaces Q_ASSIGN( 0 ); +Q_EXTERN bspDrawSurface_t *bspDrawSurfaces Q_ASSIGN( NULL ); + +Q_EXTERN int numBSPFogs Q_ASSIGN( 0 ); +Q_EXTERN bspFog_t bspFogs[ MAX_MAP_FOGS ]; + + + +/* end marker */ +#endif diff --git a/tools/quake3/q3map2/q3map2.ico b/tools/quake3/q3map2/q3map2.ico new file mode 100644 index 0000000000000000000000000000000000000000..4fe56fa66b6c64f555216795121402f9f324afbc GIT binary patch literal 1078 zcmc(eJCcJi42DIr^_nA4?c^AHB)XLLHC%BOj+2sZ$CdL*1_Fdhm^3S_$8Sj^%N8P) zoTO=LQM#Q(e$aJY@TC&@K8sw~Yv5nFk}sr4Aa}NJ`7WneG!JdqG{G?` OHfpDO`oGcO$9xA8=ia6O literal 0 HcmV?d00001 diff --git a/tools/quake3/q3map2/q3map2.rc b/tools/quake3/q3map2/q3map2.rc new file mode 100644 index 00000000..78cf7b3a --- /dev/null +++ b/tools/quake3/q3map2/q3map2.rc @@ -0,0 +1 @@ +101 ICON DISCARDABLE "q3map2.ico" diff --git a/tools/quake3/q3map2/q3map2.vcproj b/tools/quake3/q3map2/q3map2.vcproj new file mode 100644 index 00000000..d2a775d6 --- /dev/null +++ b/tools/quake3/q3map2/q3map2.vcproj @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/quake3/q3map2/shaders.c b/tools/quake3/q3map2/shaders.c new file mode 100644 index 00000000..abeada6d --- /dev/null +++ b/tools/quake3/q3map2/shaders.c @@ -0,0 +1,1926 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define SHADERS_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +AlphaMod() +routines for dealing with vertex alpha modification +*/ + +void AlphaMod( alphaMod_t *am, int numVerts, bspDrawVert_t *drawVerts ) +{ + int i, j; + float mult, add, a; + bspDrawVert_t *dv; + alphaMod_t *am2; + + + /* dummy check */ + if( am == NULL || numVerts < 1 || drawVerts == NULL ) + return; + + + /* walk vertex list */ + for( i = 0; i < numVerts; i++ ) + { + /* get vertex */ + dv = &drawVerts[ i ]; + + /* walk alphamod list */ + for( am2 = am; am2 != NULL; am2 = am2->next ) + { + /* switch on type */ + switch( am->type ) + { + case AM_DOT_PRODUCT: + mult = DotProduct( dv->normal, am2->data ); + add = 0.0f; + break; + + default: + mult = 1.0f; + add = 0.0f; + break; + } + + /* apply mod */ + for( j = 0; j < MAX_LIGHTMAPS; j++ ) + { + a = (mult * dv->color[ j ][ 3 ]) + add; + if( a < 0 ) + a = 0; + else if( a > 255 ) + a = 255; + dv->color[ j ][ 3 ] = a; + } + } + } +} + + + +/* +TcMod*() +routines for dealing with a 3x3 texture mod matrix +*/ + +void TcMod( tcMod_t mod, float st[ 2 ] ) +{ + float old[ 2 ]; + + + old[ 0 ] = st[ 0 ]; + old[ 1 ] = st[ 1 ]; + st[ 0 ] = (mod[ 0 ][ 0 ] * old[ 0 ]) + (mod[ 0 ][ 1 ] * old[ 1 ]) + mod[ 0 ][ 2 ]; + st[ 1 ] = (mod[ 1 ][ 0 ] * old[ 0 ]) + (mod[ 1 ][ 1 ] * old[ 1 ]) + mod[ 1 ][ 2 ]; +} + + +void TcModIdentity( tcMod_t mod ) +{ + mod[ 0 ][ 0 ] = 1.0f; mod[ 0 ][ 1 ] = 0.0f; mod[ 0 ][ 2 ] = 0.0f; + mod[ 1 ][ 0 ] = 0.0f; mod[ 1 ][ 1 ] = 1.0f; mod[ 1 ][ 2 ] = 0.0f; + mod[ 2 ][ 0 ] = 0.0f; mod[ 2 ][ 1 ] = 0.0f; mod[ 2 ][ 2 ] = 1.0f; /* this row is only used for multiples, not transformation */ +} + + +void TcModMultiply( tcMod_t a, tcMod_t b, tcMod_t out ) +{ + int i; + + + for( i = 0; i < 3; i++ ) + { + out[ i ][ 0 ] = (a[ i ][ 0 ] * b[ 0 ][ 0 ]) + (a[ i ][ 1 ] * b[ 1 ][ 0 ]) + (a[ i ][ 2 ] * b[ 2 ][ 0 ]); + out[ i ][ 1 ] = (a[ i ][ 0 ] * b[ 0 ][ 1 ]) + (a[ i ][ 1 ] * b[ 1 ][ 1 ]) + (a[ i ][ 2 ] * b[ 2 ][ 1 ]); + out[ i ][ 2 ] = (a[ i ][ 0 ] * b[ 0 ][ 2 ]) + (a[ i ][ 1 ] * b[ 1 ][ 2 ]) + (a[ i ][ 2 ] * b[ 2 ][ 2 ]); + } +} + + +void TcModTranslate( tcMod_t mod, float s, float t ) +{ + mod[ 0 ][ 2 ] += s; + mod[ 1 ][ 2 ] += t; +} + + +void TcModScale( tcMod_t mod, float s, float t ) +{ + mod[ 0 ][ 0 ] *= s; + mod[ 1 ][ 1 ] *= t; +} + + +void TcModRotate( tcMod_t mod, float euler ) +{ + tcMod_t old, temp; + float radians, sinv, cosv; + + + memcpy( old, mod, sizeof( tcMod_t ) ); + TcModIdentity( temp ); + + radians = euler / 180 * Q_PI; + sinv = sin( radians ); + cosv = cos( radians ); + + temp[ 0 ][ 0 ] = cosv; temp[ 0 ][ 1 ] = -sinv; + temp[ 1 ][ 0 ] = sinv; temp[ 1 ][ 1 ] = cosv; + + TcModMultiply( old, temp, mod ); +} + + + +/* +ApplySurfaceParm() - ydnar +applies a named surfaceparm to the supplied flags +*/ + +qboolean ApplySurfaceParm( char *name, int *contentFlags, int *surfaceFlags, int *compileFlags ) +{ + int i, fake; + surfaceParm_t *sp; + + + /* dummy check */ + if( name == NULL ) + name = ""; + if( contentFlags == NULL ) + contentFlags = &fake; + if( surfaceFlags == NULL ) + surfaceFlags = &fake; + if( compileFlags == NULL ) + compileFlags = &fake; + + /* walk the current game's surfaceparms */ + sp = game->surfaceParms; + while( sp->name != NULL ) + { + /* match? */ + if( !Q_stricmp( name, sp->name ) ) + { + /* clear and set flags */ + *contentFlags &= ~(sp->contentFlagsClear); + *contentFlags |= sp->contentFlags; + *surfaceFlags &= ~(sp->surfaceFlagsClear); + *surfaceFlags |= sp->surfaceFlags; + *compileFlags &= ~(sp->compileFlagsClear); + *compileFlags |= sp->compileFlags; + + /* return ok */ + return qtrue; + } + + /* next */ + sp++; + } + + /* check custom info parms */ + for( i = 0; i < numCustSurfaceParms; i++ ) + { + /* get surfaceparm */ + sp = &custSurfaceParms[ i ]; + + /* match? */ + if( !Q_stricmp( name, sp->name ) ) + { + /* clear and set flags */ + *contentFlags &= ~(sp->contentFlagsClear); + *contentFlags |= sp->contentFlags; + *surfaceFlags &= ~(sp->surfaceFlagsClear); + *surfaceFlags |= sp->surfaceFlags; + *compileFlags &= ~(sp->compileFlagsClear); + *compileFlags |= sp->compileFlags; + + /* return ok */ + return qtrue; + } + } + + /* no matching surfaceparm found */ + return qfalse; +} + + + +/* +BeginMapShaderFile() - ydnar +erases and starts a new map shader script +*/ + +void BeginMapShaderFile( const char *mapFile ) +{ + char base[ 1024 ]; + int len; + + + /* dummy check */ + mapName[ 0 ] = '\0'; + mapShaderFile[ 0 ] = '\0'; + if( mapFile == NULL || mapFile[ 0 ] == '\0' ) + return; + + /* copy map name */ + strcpy( base, mapFile ); + StripExtension( base ); + + /* extract map name */ + len = strlen( base ) - 1; + while( len > 0 && base[ len ] != '/' && base[ len ] != '\\' ) + len--; + strcpy( mapName, &base[ len + 1 ] ); + base[ len ] = '\0'; + if( len <= 0 ) + return; + + /* append ../scripts/q3map2_.shader */ + sprintf( mapShaderFile, "%s/../%s/q3map2_%s.shader", base, game->shaderPath, mapName ); + Sys_FPrintf( SYS_VRB, "Map has shader script %s\n", mapShaderFile ); + + /* remove it */ + remove( mapShaderFile ); + + /* stop making warnings about missing images */ + warnImage = qfalse; +} + + + +/* +WriteMapShaderFile() - ydnar +writes a shader to the map shader script +*/ + +void WriteMapShaderFile( void ) +{ + FILE *file; + shaderInfo_t *si; + int i, num; + + + /* dummy check */ + if( mapShaderFile[ 0 ] == '\0' ) + return; + + /* are there any custom shaders? */ + for( i = 0, num = 0; i < numShaderInfo; i++ ) + { + if( shaderInfo[ i ].custom ) + break; + } + if( i == numShaderInfo ) + return; + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- WriteMapShaderFile ---\n"); + Sys_FPrintf( SYS_VRB, "Writing %s", mapShaderFile ); + + /* open shader file */ + file = fopen( mapShaderFile, "w" ); + if( file == NULL ) + { + Sys_Printf( "WARNING: Unable to open map shader file %s for writing\n", mapShaderFile ); + return; + } + + /* print header */ + fprintf( file, + "// Custom shader file for %s.bsp\n" + "// Generated by Q3Map2 (ydnar)\n" + "// Do not edit! This file is overwritten on recompiles.\n\n", + mapName ); + + /* walk the shader list */ + for( i = 0, num = 0; i < numShaderInfo; i++ ) + { + /* get the shader and print it */ + si = &shaderInfo[ i ]; + if( si->custom == qfalse || si->shaderText == NULL || si->shaderText[ 0 ] == '\0' ) + continue; + num++; + + /* print it to the file */ + fprintf( file, "%s%s\n", si->shader, si->shaderText ); + //% Sys_Printf( "%s%s\n", si->shader, si->shaderText ); /* FIXME: remove debugging code */ + + Sys_FPrintf( SYS_VRB, "." ); + } + + /* close the shader */ + fclose( file ); + + Sys_FPrintf( SYS_VRB, "\n" ); + + /* print some stats */ + Sys_Printf( "%9d custom shaders emitted\n", num ); +} + + + +/* +CustomShader() - ydnar +sets up a custom map shader +*/ + +shaderInfo_t *CustomShader( shaderInfo_t *si, char *find, char *replace ) +{ + shaderInfo_t *csi; + char shader[ MAX_QPATH ]; + char *s; + int loc; + md5_state_t md5; + byte digest[ 16 ]; + char *srcShaderText, temp[ 8192 ], shaderText[ 8192 ]; /* ydnar: fixme (make this bigger?) */ + + + /* dummy check */ + if( si == NULL ) + return ShaderInfoForShader( "default" ); + + /* default shader text source */ + srcShaderText = si->shaderText; + + /* et: implicitMap */ + if( si->implicitMap == IM_OPAQUE ) + { + srcShaderText = temp; + sprintf( temp, "\n" + "{ // Q3Map2 defaulted (implicitMap)\n" + "\t{\n" + "\t\tmap $lightmap\n" + "\t\trgbGen identity\n" + "\t}\n" + "\tq3map_styleMarker\n" + "\t{\n" + "\t\tmap %s\n" + "\t\tblendFunc GL_DST_COLOR GL_ZERO\n" + "\t\trgbGen identity\n" + "\t}\n" + "}\n", + si->implicitImagePath ); + } + + /* et: implicitMask */ + else if( si->implicitMap == IM_MASKED ) + { + srcShaderText = temp; + sprintf( temp, "\n" + "{ // Q3Map2 defaulted (implicitMask)\n" + "\tcull none\n" + "\t{\n" + "\t\tmap %s\n" + "\t\talphaFunc GE128\n" + "\t\tdepthWrite\n" + "\t}\n" + "\t{\n" + "\t\tmap $lightmap\n" + "\t\trgbGen identity\n" + "\t\tdepthFunc equal\n" + "\t}\n" + "\tq3map_styleMarker\n" + "\t{\n" + "\t\tmap %s\n" + "\t\tblendFunc GL_DST_COLOR GL_ZERO\n" + "\t\tdepthFunc equal\n" + "\t\trgbGen identity\n" + "\t}\n" + "}\n", + si->implicitImagePath, + si->implicitImagePath ); + } + + /* et: implicitBlend */ + else if( si->implicitMap == IM_BLEND ) + { + srcShaderText = temp; + sprintf( temp, "\n" + "{ // Q3Map2 defaulted (implicitBlend)\n" + "\tcull none\n" + "\t{\n" + "\t\tmap %s\n" + "\t\tblendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA\n" + "\t}\n" + "\t{\n" + "\t\tmap $lightmap\n" + "\t\trgbGen identity\n" + "\t\tblendFunc GL_DST_COLOR GL_ZERO\n" + "\t}\n" + "\tq3map_styleMarker\n" + "}\n", + si->implicitImagePath ); + } + + /* default shader text */ + else if( srcShaderText == NULL ) + { + srcShaderText = temp; + sprintf( temp, "\n" + "{ // Q3Map2 defaulted\n" + "\t{\n" + "\t\tmap $lightmap\n" + "\t\trgbGen identity\n" + "\t}\n" + "\tq3map_styleMarker\n" + "\t{\n" + "\t\tmap %s.tga\n" + "\t\tblendFunc GL_DST_COLOR GL_ZERO\n" + "\t\trgbGen identity\n" + "\t}\n" + "}\n", + si->shader ); + } + + /* error check */ + if( (strlen( mapName ) + 1 + 32) > MAX_QPATH ) + Error( "Custom shader name length (%d) exceeded. Shorten your map name.\n", MAX_QPATH ); + + /* do some bad find-replace */ + s = strstr( srcShaderText, find ); + if( s == NULL ) + //% strcpy( shaderText, srcShaderText ); + return si; /* testing just using the existing shader if this fails */ + else + { + /* substitute 'find' with 'replace' */ + loc = s - srcShaderText; + strcpy( shaderText, srcShaderText ); + shaderText[ loc ] = '\0'; + strcat( shaderText, replace ); + strcat( shaderText, &srcShaderText[ loc + strlen( find ) ] ); + } + + /* make md5 hash of the shader text */ + md5_init( &md5 ); + md5_append( &md5, shaderText, strlen( shaderText ) ); + md5_finish( &md5, digest ); + + /* mangle hash into a shader name */ + sprintf( shader, "%s/%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", mapName, + digest[ 0 ], digest[ 1 ], digest[ 2 ], digest[ 3 ], digest[ 4 ], digest[ 5 ], digest[ 6 ], digest[ 7 ], + digest[ 8 ], digest[ 9 ], digest[ 10 ], digest[ 11 ], digest[ 12 ], digest[ 13 ], digest[ 14 ], digest[ 15 ] ); + + /* get shader */ + csi = ShaderInfoForShader( shader ); + + /* might be a preexisting shader */ + if( csi->custom ) + return csi; + + /* clone the existing shader and rename */ + memcpy( csi, si, sizeof( shaderInfo_t ) ); + strcpy( csi->shader, shader ); + csi->custom = qtrue; + + /* store new shader text */ + csi->shaderText = safe_malloc( strlen( shaderText ) + 1 ); + strcpy( csi->shaderText, shaderText ); /* LEAK! */ + + /* return it */ + return csi; +} + + + +/* +EmitVertexRemapShader() +adds a vertexremapshader key/value pair to worldspawn +*/ + +void EmitVertexRemapShader( char *from, char *to ) +{ + md5_state_t md5; + byte digest[ 16 ]; + char key[ 64 ], value[ 256 ]; + + + /* dummy check */ + if( from == NULL || from[ 0 ] == '\0' || + to == NULL || to[ 0 ] == '\0' ) + return; + + /* build value */ + sprintf( value, "%s;%s", from, to ); + + /* make md5 hash */ + md5_init( &md5 ); + md5_append( &md5, value, strlen( value ) ); + md5_finish( &md5, digest ); + + /* make key (this is annoying, as vertexremapshader is precisely 17 characters, + which is one too long, so we leave off the last byte of the md5 digest) */ + sprintf( key, "vertexremapshader%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + digest[ 0 ], digest[ 1 ], digest[ 2 ], digest[ 3 ], digest[ 4 ], digest[ 5 ], digest[ 6 ], digest[ 7 ], + digest[ 8 ], digest[ 9 ], digest[ 10 ], digest[ 11 ], digest[ 12 ], digest[ 13 ], digest[ 14 ] ); /* no: digest[ 15 ] */ + + /* add key/value pair to worldspawn */ + SetKeyValue( &entities[ 0 ], key, value ); +} + + + +/* +AllocShaderInfo() +allocates and initializes a new shader +*/ + +static shaderInfo_t *AllocShaderInfo( void ) +{ + shaderInfo_t *si; + + + /* allocate? */ + if( shaderInfo == NULL ) + { + shaderInfo = safe_malloc( sizeof( shaderInfo_t ) * MAX_SHADER_INFO ); + numShaderInfo = 0; + } + + /* bounds check */ + if( numShaderInfo == MAX_SHADER_INFO ) + Error( "MAX_SHADER_INFO exceeded. Remove some PK3 files or shader scripts from shaderlist.txt and try again." ); + si = &shaderInfo[ numShaderInfo ]; + numShaderInfo++; + + /* ydnar: clear to 0 first */ + memset( si, 0, sizeof( shaderInfo_t ) ); + + /* set defaults */ + ApplySurfaceParm( "default", &si->contentFlags, &si->surfaceFlags, &si->compileFlags ); + + si->backsplashFraction = DEF_BACKSPLASH_FRACTION; + si->backsplashDistance = DEF_BACKSPLASH_DISTANCE; + + si->bounceScale = DEF_RADIOSITY_BOUNCE; + + si->lightStyle = LS_NORMAL; + + si->polygonOffset = qfalse; + + si->shadeAngleDegrees = 0.0f; + si->lightmapSampleSize = 0; + si->lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET; + si->patchShadows = qfalse; + si->vertexShadows = qtrue; /* ydnar: changed default behavior */ + si->forceSunlight = qfalse; + si->vertexScale = 1.0; + si->notjunc = qfalse; + + /* ydnar: set texture coordinate transform matrix to identity */ + TcModIdentity( si->mod ); + + /* ydnar: lightmaps can now be > 128x128 in an externally generated tga */ + si->lmCustomWidth = lmCustomSize; //% LIGHTMAP_WIDTH; + si->lmCustomHeight = lmCustomSize; //% LIGHTMAP_HEIGHT; + + /* return to sender */ + return si; +} + + + +/* +FinishShader() - ydnar +sets a shader's width and height among other things +*/ + +void FinishShader( shaderInfo_t *si ) +{ + int x, y; + float st[ 2 ], o[ 2 ], dist, bestDist; + vec4_t color, bestColor, delta; + + + /* don't double-dip */ + if( si->finished ) + return; + + /* if they're explicitly set, copy from image size */ + if( si->shaderWidth == 0 && si->shaderHeight == 0 ) + { + si->shaderWidth = si->shaderImage->width; + si->shaderHeight = si->shaderImage->height; + } + + /* legacy terrain has explicit image-sized texture projection */ + if( si->legacyTerrain && si->tcGen == qfalse ) + { + /* set xy texture projection */ + si->tcGen = qtrue; + VectorSet( si->vecs[ 0 ], (1.0f / (si->shaderWidth * 0.5f)), 0, 0 ); + VectorSet( si->vecs[ 1 ], 0, (1.0f / (si->shaderHeight * 0.5f)), 0 ); + } + + /* find pixel coordinates best matching the average color of the image */ + bestDist = 99999999; + o[ 0 ] = 1.0f / si->shaderImage->width; + o[ 1 ] = 1.0f / si->shaderImage->height; + for( y = 0, st[ 1 ] = 0.0f; y < si->shaderImage->height; y++, st[ 1 ] += o[ 1 ] ) + { + for( x = 0, st[ 0 ] = 0.0f; x < si->shaderImage->width; x++, st[ 0 ] += o[ 0 ] ) + { + /* sample the shader image */ + RadSampleImage( si->shaderImage->pixels, si->shaderImage->width, si->shaderImage->height, st, color ); + + /* determine error squared */ + VectorSubtract( color, si->averageColor, delta ); + delta[ 3 ] = color[ 3 ] - si->averageColor[ 3 ]; + dist = delta[ 0 ] * delta[ 0 ] + delta[ 1 ] * delta[ 1 ] + delta[ 2 ] * delta[ 2 ] + delta[ 3 ] * delta[ 3 ]; + if( dist < bestDist ) + { + VectorCopy( color, bestColor ); + bestColor[ 3 ] = color[ 3 ]; + si->stFlat[ 0 ] = st[ 0 ]; + si->stFlat[ 1 ] = st[ 1 ]; + } + } + } + + /* set to finished */ + si->finished = qtrue; +} + + + +/* +LoadShaderImages() +loads a shader's images +ydnar: image.c made this a bit simpler +*/ + +static void LoadShaderImages( shaderInfo_t *si ) +{ + int i, count; + float color[ 4 ]; + + + /* nodraw shaders don't need images */ + if( si->compileFlags & C_NODRAW ) + si->shaderImage = ImageLoad( DEFAULT_IMAGE ); + else + { + /* try to load editor image first */ + si->shaderImage = ImageLoad( si->editorImagePath ); + + /* then try shadername */ + if( si->shaderImage == NULL ) + si->shaderImage = ImageLoad( si->shader ); + + /* then try implicit image path (note: new behavior!) */ + if( si->shaderImage == NULL ) + si->shaderImage = ImageLoad( si->implicitImagePath ); + + /* then try lightimage (note: new behavior!) */ + if( si->shaderImage == NULL ) + si->shaderImage = ImageLoad( si->lightImagePath ); + + /* otherwise, use default image */ + if( si->shaderImage == NULL ) + { + si->shaderImage = ImageLoad( DEFAULT_IMAGE ); + if( warnImage && strcmp( si->shader, "noshader" ) ) + Sys_Printf( "WARNING: Couldn't find image for shader %s\n", si->shader ); + } + + /* load light image */ + si->lightImage = ImageLoad( si->lightImagePath ); + + /* load normalmap image (ok if this is NULL) */ + si->normalImage = ImageLoad( si->normalImagePath ); + if( si->normalImage != NULL ) + { + Sys_FPrintf( SYS_VRB, "Shader %s has\n" + " NM %s\n", si->shader, si->normalImagePath ); + } + } + + /* if no light image, use shader image */ + if( si->lightImage == NULL ) + si->lightImage = ImageLoad( si->shaderImage->name ); + + /* create default and average colors */ + count = si->lightImage->width * si->lightImage->height; + VectorClear( color ); + color[ 3 ] = 0.0f; + for( i = 0; i < count; i++ ) + { + color[ 0 ] += si->lightImage->pixels[ i * 4 + 0 ]; + color[ 1 ] += si->lightImage->pixels[ i * 4 + 1 ]; + color[ 2 ] += si->lightImage->pixels[ i * 4 + 2 ]; + color[ 3 ] += si->lightImage->pixels[ i * 4 + 3 ]; + } + + if( VectorLength( si->color ) <= 0.0f ) + ColorNormalize( color, si->color ); + VectorScale( color, (1.0f / count), si->averageColor ); +} + + + +/* +ShaderInfoForShader() +finds a shaderinfo for a named shader +*/ + +shaderInfo_t *ShaderInfoForShader( const char *shaderName ) +{ + int i; + shaderInfo_t *si; + char shader[ MAX_QPATH ]; + + + /* dummy check */ + if( shaderName == NULL || shaderName[ 0 ] == '\0' ) + { + Sys_Printf( "WARNING: Null or empty shader name\n" ); + shaderName = "missing"; + } + + /* strip off extension */ + strcpy( shader, shaderName ); + StripExtension( shader ); + + /* search for it */ + for( i = 0; i < numShaderInfo; i++ ) + { + si = &shaderInfo[ i ]; + if( !Q_stricmp( shader, si->shader ) ) + { + /* load image if necessary */ + if( si->shaderImage == NULL ) + { + LoadShaderImages( si ); + FinishShader( si ); + } + + /* return it */ + return si; + } + } + + /* allocate a default shader */ + si = AllocShaderInfo(); + strcpy( si->shader, shader ); + LoadShaderImages( si ); + FinishShader( si ); + + /* return it */ + return si; +} + + + +/* +GetTokenAppend() - ydnar +gets a token and appends its text to the specified buffer +*/ + +static int oldScriptLine = 0; +static int tabDepth = 0; + +qboolean GetTokenAppend( char *buffer, qboolean crossline ) +{ + qboolean r; + int i; + + + /* get the token */ + r = GetToken( crossline ); + if( r == qfalse || buffer == NULL || token[ 0 ] == '\0' ) + return r; + + /* pre-tabstops */ + if( token[ 0 ] == '}' ) + tabDepth--; + + /* append? */ + if( oldScriptLine != scriptline ) + { + strcat( buffer, "\n" ); + for( i = 0; i < tabDepth; i++ ) + strcat( buffer, "\t" ); + } + else + strcat( buffer, " " ); + oldScriptLine = scriptline; + strcat( buffer, token ); + + /* post-tabstops */ + if( token[ 0 ] == '{' ) + tabDepth++; + + /* return */ + return r; +} + + +void Parse1DMatrixAppend( char *buffer, int x, vec_t *m ) +{ + int i; + + + if( !GetTokenAppend( buffer, qtrue ) || strcmp( token, "(" ) ) + Error( "Parse1DMatrixAppend(): line %d: ( not found!", scriptline ); + for( i = 0; i < x; i++ ) + { + if( !GetTokenAppend( buffer, qfalse ) ) + Error( "Parse1DMatrixAppend(): line %d: Number not found!", scriptline ); + m[ i ] = atof( token ); + } + if( !GetTokenAppend( buffer, qtrue ) || strcmp( token, ")" ) ) + Error( "Parse1DMatrixAppend(): line %d: ) not found!", scriptline ); +} + + + + +/* +ParseShaderFile() +parses a shader file into discrete shaderInfo_t +*/ + +static void ParseShaderFile( const char *filename ) +{ + int i, val; + shaderInfo_t *si; + char *suffix, temp[ 1024 ]; + char shaderText[ 8192 ]; /* ydnar: fixme (make this bigger?) */ + + + /* init */ + si = NULL; + shaderText[ 0 ] = '\0'; + + /* load the shader */ + LoadScriptFile( filename, 0 ); + + /* tokenize it */ + while( 1 ) + { + /* copy shader text to the shaderinfo */ + if( si != NULL && shaderText[ 0 ] != '\0' ) + { + strcat( shaderText, "\n" ); + si->shaderText = safe_malloc( strlen( shaderText ) + 1 ); + strcpy( si->shaderText, shaderText ); + //% if( VectorLength( si->vecs[ 0 ] ) ) + //% Sys_Printf( "%s\n", shaderText ); + } + + /* ydnar: clear shader text buffer */ + shaderText[ 0 ] = '\0'; + + /* test for end of file */ + if( !GetToken( qtrue ) ) + break; + + /* shader name is initial token */ + si = AllocShaderInfo(); + strcpy( si->shader, token ); + + /* ignore ":q3map" suffix */ + suffix = strstr( si->shader, ":q3map" ); + if( suffix != NULL ) + *suffix = '\0'; + + /* handle { } section */ + if( !GetTokenAppend( shaderText, qtrue ) ) + break; + if( strcmp( token, "{" ) ) + { + if( si != NULL ) + Error( "ParseShaderFile(): %s, line %d: { not found!\nFound instead: %s\nLast known shader: %s", + filename, scriptline, token, si->shader ); + else + Error( "ParseShaderFile(): %s, line %d: { not found!\nFound instead: %s", + filename, scriptline, token ); + } + + while( 1 ) + { + /* get the next token */ + if( !GetTokenAppend( shaderText, qtrue ) ) + break; + if( !strcmp( token, "}" ) ) + break; + + + /* ----------------------------------------------------------------- + shader stages (passes) + ----------------------------------------------------------------- */ + + /* parse stage directives */ + if( !strcmp( token, "{" ) ) + { + si->hasPasses = qtrue; + while( 1 ) + { + if( !GetTokenAppend( shaderText, qtrue ) ) + break; + if( !strcmp( token, "}" ) ) + break; + + /* only care about images if we don't have a editor/light image */ + if( si->editorImagePath[ 0 ] == '\0' && si->lightImagePath[ 0 ] == '\0' && si->implicitImagePath[ 0 ] == '\0' ) + { + /* digest any images */ + if( !Q_stricmp( token, "map" ) || + !Q_stricmp( token, "clampMap" ) || + !Q_stricmp( token, "animMap" ) || + !Q_stricmp( token, "clampAnimMap" ) || + !Q_stricmp( token, "clampMap" ) || + !Q_stricmp( token, "mapComp" ) || + !Q_stricmp( token, "mapNoComp" ) ) + { + /* skip one token for animated stages */ + if( !Q_stricmp( token, "animMap" ) || !Q_stricmp( token, "clampAnimMap" ) ) + GetTokenAppend( shaderText, qfalse ); + + /* get an image */ + GetTokenAppend( shaderText, qfalse ); + if( token[ 0 ] != '*' && token[ 0 ] != '$' ) + { + strcpy( si->lightImagePath, token ); + DefaultExtension( si->lightImagePath, ".tga" ); + + /* debug code */ + //% Sys_FPrintf( SYS_VRB, "Deduced shader image: %s\n", si->lightImagePath ); + } + } + } + } + } + + + /* ----------------------------------------------------------------- + surfaceparm * directives + ----------------------------------------------------------------- */ + + /* match surfaceparm */ + else if( !Q_stricmp( token, "surfaceparm" ) ) + { + GetTokenAppend( shaderText, qfalse ); + if( ApplySurfaceParm( token, &si->contentFlags, &si->surfaceFlags, &si->compileFlags ) == qfalse ) + Sys_Printf( "WARNING: Unknown surfaceparm: \"%s\"\n", token ); + } + + + /* ----------------------------------------------------------------- + game-related shader directives + ----------------------------------------------------------------- */ + + /* ydnar: fogparms (for determining fog volumes) */ + else if( !Q_stricmp( token, "fogparms" ) ) + si->fogParms = qtrue; + + /* ydnar: polygonoffset (for no culling) */ + else if( !Q_stricmp( token, "polygonoffset" ) ) + si->polygonOffset = qtrue; + + /* tesssize is used to force liquid surfaces to subdivide */ + else if( !Q_stricmp( token, "tessSize" ) || !Q_stricmp( token, "q3map_tessSize" ) /* sof2 */ ) + { + GetTokenAppend( shaderText, qfalse ); + si->subdivisions = atof( token ); + } + + /* cull none will set twoSided (ydnar: added disable too) */ + else if ( !Q_stricmp( token, "cull" ) ) + { + GetTokenAppend( shaderText, qfalse ); + if( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "disable" ) || !Q_stricmp( token, "twosided" ) ) + si->twoSided = qtrue; + } + + /* deformVertexes autosprite[ 2 ] + we catch this so autosprited surfaces become point + lights instead of area lights */ + else if( !Q_stricmp( token, "deformVertexes" ) ) + { + GetTokenAppend( shaderText, qfalse ); + + /* deformVertexes autosprite(2) */ + if( !Q_strncasecmp( token, "autosprite", 10 ) ) + { + /* set it as autosprite and detail */ + si->autosprite = qtrue; + ApplySurfaceParm( "detail", &si->contentFlags, &si->surfaceFlags, &si->compileFlags ); + + /* ydnar: gs mods: added these useful things */ + si->noClip = qtrue; + si->notjunc = qtrue; + } + + /* deformVertexes move (ydnar: for particle studio support) */ + if( !Q_stricmp( token, "move") ) + { + vec3_t amt, mins, maxs; + float base, amp; + + + /* get move amount */ + GetTokenAppend( shaderText, qfalse ); amt[ 0 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); amt[ 1 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); amt[ 2 ] = atof( token ); + + /* skip func */ + GetTokenAppend( shaderText, qfalse ); + + /* get base and amplitude */ + GetTokenAppend( shaderText, qfalse ); base = atof( token ); + GetTokenAppend( shaderText, qfalse ); amp = atof( token ); + + /* calculate */ + VectorScale( amt, base, mins ); + VectorMA( mins, amp, amt, maxs ); + VectorAdd( si->mins, mins, si->mins ); + VectorAdd( si->maxs, maxs, si->maxs ); + } + } + + /* light (old-style flare specification) */ + else if( !Q_stricmp( token, "light" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->flareShader, "flareshader" ); + } + + /* ydnar: damageShader (sof2 mods) */ + else if( !Q_stricmp( token, "damageShader" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->damageShader, token ); + GetTokenAppend( shaderText, qfalse ); /* don't do anything with health */ + } + + /* ydnar: enemy territory implicit shaders */ + else if( !Q_stricmp( token, "implicitMap" ) ) + { + si->implicitMap = IM_OPAQUE; + GetTokenAppend( shaderText, qfalse ); + if( token[ 0 ] == '-' && token[ 1 ] == '\0' ) + sprintf( si->implicitImagePath, "%s.tga", si->shader ); + else + strcpy( si->implicitImagePath, token ); + } + + else if( !Q_stricmp( token, "implicitMask" ) ) + { + si->implicitMap = IM_MASKED; + GetTokenAppend( shaderText, qfalse ); + if( token[ 0 ] == '-' && token[ 1 ] == '\0' ) + sprintf( si->implicitImagePath, "%s.tga", si->shader ); + else + strcpy( si->implicitImagePath, token ); + } + + else if( !Q_stricmp( token, "implicitBlend" ) ) + { + si->implicitMap = IM_MASKED; + GetTokenAppend( shaderText, qfalse ); + if( token[ 0 ] == '-' && token[ 1 ] == '\0' ) + sprintf( si->implicitImagePath, "%s.tga", si->shader ); + else + strcpy( si->implicitImagePath, token ); + } + + + /* ----------------------------------------------------------------- + image directives + ----------------------------------------------------------------- */ + + /* qer_editorimage */ + else if( !Q_stricmp( token, "qer_editorImage" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->editorImagePath, token ); + DefaultExtension( si->editorImagePath, ".tga" ); + } + + /* ydnar: q3map_normalimage (bumpmapping normal map) */ + else if( !Q_stricmp( token, "q3map_normalImage" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->normalImagePath, token ); + DefaultExtension( si->normalImagePath, ".tga" ); + } + + /* q3map_lightimage */ + else if( !Q_stricmp( token, "q3map_lightImage" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->lightImagePath, token ); + DefaultExtension( si->lightImagePath, ".tga" ); + } + + /* ydnar: skyparms */ + else if( !Q_stricmp( token, "skyParms" ) ) + { + /* get image base */ + GetTokenAppend( shaderText, qfalse ); + + /* ignore bogus paths */ + if( Q_stricmp( token, "-" ) && Q_stricmp( token, "full" ) ) + { + strcpy( si->skyParmsImageBase, token ); + + /* use top image as sky light image */ + if( si->lightImagePath[ 0 ] == '\0' ) + sprintf( si->lightImagePath, "%s_up.tga", si->skyParmsImageBase ); + } + + /* skip rest of line */ + GetTokenAppend( shaderText, qfalse ); + GetTokenAppend( shaderText, qfalse ); + } + + /* ----------------------------------------------------------------- + q3map_* directives + ----------------------------------------------------------------- */ + + /* q3map_sun + color will be normalized, so it doesn't matter what range you use + intensity falls off with angle but not distance 100 is a fairly bright sun + degree of 0 = from the east, 90 = north, etc. altitude of 0 = sunrise/set, 90 = noon + ydnar: sof2map has bareword 'sun' token, so we support that as well */ + else if( !Q_stricmp( token, "sun" ) /* sof2 */ || !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) ) + { + float a, b; + sun_t *sun; + qboolean ext; + + + /* ydnar: extended sun directive? */ + if( !Q_stricmp( token, "q3map_sunext" ) ) + ext = qtrue; + + /* allocate sun */ + sun = safe_malloc( sizeof( *sun ) ); + memset( sun, 0, sizeof( *sun ) ); + + /* get color */ + GetTokenAppend( shaderText, qfalse ); + sun->color[ 0 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + sun->color[ 1 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + sun->color[ 2 ] = atof( token ); + + /* normalize it */ + VectorNormalize( sun->color, sun->color ); + + /* scale color by brightness */ + GetTokenAppend( shaderText, qfalse ); + sun->photons = atof( token ); + + /* get sun angle/elevation */ + GetTokenAppend( shaderText, qfalse ); + a = atof( token ); + a = a / 180.0f * Q_PI; + + GetTokenAppend( shaderText, qfalse ); + b = atof( token ); + b = b / 180.0f * Q_PI; + + sun->direction[ 0 ] = cos( a ) * cos( b ); + sun->direction[ 1 ] = sin( a ) * cos( b ); + sun->direction[ 2 ] = sin( b ); + + /* get filter radius from shader */ + sun->filterRadius = si->lightFilterRadius; + + /* ydnar: get sun angular deviance/samples */ + if( ext && TokenAvailable() ) + { + GetTokenAppend( shaderText, qfalse ); + sun->deviance = atof( token ); + sun->deviance = sun->deviance / 180.0f * Q_PI; + + GetTokenAppend( shaderText, qfalse ); + sun->numSamples = atoi( token ); + } + + /* store sun */ + sun->next = si->sun; + si->sun = sun; + + /* apply sky surfaceparm */ + ApplySurfaceParm( "sky", &si->contentFlags, &si->surfaceFlags, &si->compileFlags ); + + /* don't process any more tokens on this line */ + continue; + } + + /* match q3map_ */ + else if( !Q_strncasecmp( token, "q3map_", 6 ) ) + { + /* ydnar: q3map_baseShader (inherit this shader's parameters) */ + if( !Q_stricmp( token, "q3map_baseShader" ) ) + { + shaderInfo_t *si2; + qboolean oldWarnImage; + + + /* get shader */ + GetTokenAppend( shaderText, qfalse ); + //% Sys_FPrintf( SYS_VRB, "Shader %s has base shader %s\n", si->shader, token ); + oldWarnImage = warnImage; + warnImage = qfalse; + si2 = ShaderInfoForShader( token ); + warnImage = oldWarnImage; + + /* subclass it */ + if( si2 != NULL ) + { + /* preserve name */ + strcpy( temp, si->shader ); + + /* copy shader */ + memcpy( si, si2, sizeof( *si ) ); + + /* restore name and set to unfinished */ + strcpy( si->shader, temp ); + si->finished = qfalse; + } + } + + /* ydnar: q3map_surfacemodel */ + else if( !Q_stricmp( token, "q3map_surfacemodel" ) ) + { + surfaceModel_t *model; + + + /* allocate new model and attach it */ + model = safe_malloc( sizeof( *model ) ); + memset( model, 0, sizeof( *model ) ); + model->next = si->surfaceModel; + si->surfaceModel = model; + + /* get parameters */ + GetTokenAppend( shaderText, qfalse ); + strcpy( model->model, token ); + + GetTokenAppend( shaderText, qfalse ); + model->density = atof( token ); + GetTokenAppend( shaderText, qfalse ); + model->odds = atof( token ); + + GetTokenAppend( shaderText, qfalse ); + model->minScale = atof( token ); + GetTokenAppend( shaderText, qfalse ); + model->maxScale = atof( token ); + + GetTokenAppend( shaderText, qfalse ); + model->minAngle = atof( token ); + GetTokenAppend( shaderText, qfalse ); + model->maxAngle = atof( token ); + + GetTokenAppend( shaderText, qfalse ); + model->oriented = (token[ 0 ] == '1' ? qtrue : qfalse); + } + + /* ydnar/sd: q3map_foliage */ + else if( !Q_stricmp( token, "q3map_foliage" ) ) + { + foliage_t *foliage; + + + /* allocate new foliage struct and attach it */ + foliage = safe_malloc( sizeof( *foliage ) ); + memset( foliage, 0, sizeof( *foliage ) ); + foliage->next = si->foliage; + si->foliage = foliage; + + /* get parameters */ + GetTokenAppend( shaderText, qfalse ); + strcpy( foliage->model, token ); + + GetTokenAppend( shaderText, qfalse ); + foliage->scale = atof( token ); + GetTokenAppend( shaderText, qfalse ); + foliage->density = atof( token ); + GetTokenAppend( shaderText, qfalse ); + foliage->odds = atof( token ); + GetTokenAppend( shaderText, qfalse ); + foliage->inverseAlpha = atoi( token ); + } + + /* ydnar: q3map_bounce (fraction of light to re-emit during radiosity passes) */ + else if( !Q_stricmp( token, "q3map_bounce" ) || !Q_stricmp( token, "q3map_bounceScale" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->bounceScale = atof( token ); + } + + /* ydnar/splashdamage: q3map_skylight */ + else if( !Q_stricmp( token, "q3map_skylight" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->skyLightValue = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->skyLightIterations = atoi( token ); + + /* clamp */ + if( si->skyLightValue < 0.0f ) + si->skyLightValue = 0.0f; + if( si->skyLightIterations < 2 ) + si->skyLightIterations = 2; + } + + /* q3map_surfacelight */ + else if( !Q_stricmp( token, "q3map_surfacelight" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->value = atof( token ); + } + + + /* q3map_lightStyle (sof2/jk2 lightstyle) */ + else if( !Q_stricmp( token, "q3map_lightStyle" ) ) + { + GetTokenAppend( shaderText, qfalse ); + val = atoi( token ); + if( val < 0 ) + val = 0; + else if( val > LS_NONE ) + val = LS_NONE; + si->lightStyle = val; + } + + /* wolf: q3map_lightRGB */ + else if( !Q_stricmp( token, "q3map_lightRGB" ) ) + { + VectorClear( si->color ); + GetTokenAppend( shaderText, qfalse ); + si->color[ 0 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->color[ 1 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->color[ 2 ] = atof( token ); + ColorNormalize( si->color, si->color ); + } + + /* q3map_lightSubdivide */ + else if( !Q_stricmp( token, "q3map_lightSubdivide" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->lightSubdivide = atoi( token ); + } + + /* q3map_backsplash */ + else if( !Q_stricmp( token, "q3map_backsplash" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->backsplashFraction = atof( token ) * 0.01f; + GetTokenAppend( shaderText, qfalse ); + si->backsplashDistance = atof( token ); + } + + /* q3map_lightmapSampleSize */ + else if( !Q_stricmp( token, "q3map_lightmapSampleSize" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->lightmapSampleSize = atoi( token ); + } + + /* q3map_lightmapSampleSffset */ + else if( !Q_stricmp( token, "q3map_lightmapSampleOffset" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->lightmapSampleOffset = atof( token ); + } + + /* ydnar: q3map_lightmapFilterRadius */ + else if( !Q_stricmp( token, "q3map_lightmapFilterRadius" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->lmFilterRadius = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->lightFilterRadius = atof( token ); + } + + /* ydnar: q3map_lightmapAxis [xyz] */ + else if( !Q_stricmp( token, "q3map_lightmapAxis" ) ) + { + GetTokenAppend( shaderText, qfalse ); + if( !Q_stricmp( token, "x" ) ) + VectorSet( si->lightmapAxis, 1, 0, 0 ); + else if( !Q_stricmp( token, "y" ) ) + VectorSet( si->lightmapAxis, 0, 1, 0 ); + else if( !Q_stricmp( token, "z" ) ) + VectorSet( si->lightmapAxis, 0, 0, 1 ); + else + { + Sys_Printf( "WARNING: Unknown value for lightmap axis: %s\n", token ); + VectorClear( si->lightmapAxis ); + } + } + + /* ydnar: q3map_lightmapSize (for autogenerated shaders + external tga lightmaps) */ + else if( !Q_stricmp( token, "q3map_lightmapSize" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->lmCustomWidth = atoi( token ); + GetTokenAppend( shaderText, qfalse ); + si->lmCustomHeight = atoi( token ); + + /* must be a power of 2 */ + if( ((si->lmCustomWidth - 1) & si->lmCustomWidth) || + ((si->lmCustomHeight - 1) & si->lmCustomHeight) ) + { + Sys_Printf( "WARNING: Non power-of-two lightmap size specified (%d, %d)\n", + si->lmCustomWidth, si->lmCustomHeight ); + si->lmCustomWidth = LIGHTMAP_WIDTH; + si->lmCustomHeight = LIGHTMAP_HEIGHT; + } + } + + /* ydnar: q3map_lightmapGamma N (for autogenerated shaders + external tga lightmaps) */ + else if( !Q_stricmp( token, "q3map_lightmapGamma" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->lmGamma = atof( token ); + if( si->lmGamma < 0 ) + si->lmGamma = 1.0; + } + + /* q3map_vertexScale (scale vertex lighting by this fraction) */ + else if( !Q_stricmp( token, "q3map_vertexScale" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->vertexScale = atof( token ); + } + + /* q3map_flare */ + else if( !Q_stricmp( token, "q3map_flare" ) || !Q_stricmp( token, "q3map_flareShader" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->flareShader, token ); + } + + /* q3map_backShader */ + else if( !Q_stricmp( token, "q3map_backShader" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->backShader, token ); + } + + /* ydnar: q3map_offset */ + else if( !Q_stricmp( token, "q3map_offset" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->offset = atof( token ); + } + + /* ydnar: q3map_cloneShader */ + else if ( !Q_stricmp( token, "q3map_cloneShader" ) ) + { + GetTokenAppend( shaderText, qfalse ); + strcpy( si->cloneShader, token ); + } + + /* ydnar: q3map_textureSize (substitute for q3map_lightimage derivation for terrain) */ + else if( !Q_stricmp( token, "q3map_fur" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->furNumLayers = atoi( token ); + GetTokenAppend( shaderText, qfalse ); + si->furOffset = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->furFade = atof( token ); + } + + /* ydnar: gs mods: legacy support for terrain/terrain2 shaders */ + else if( !Q_stricmp( token, "q3map_terrain" ) ) + { + /* team arena terrain is assumed to be nonplanar, with full normal averaging, + passed through the metatriangle surface pipeline, with a lightmap axis on z */ + si->legacyTerrain = qtrue; + si->noClip = qtrue; + si->notjunc = qtrue; + si->indexed = qtrue; + si->nonplanar = qtrue; + si->forceMeta = qtrue; + si->shadeAngleDegrees = 179.0f; + //% VectorSet( si->lightmapAxis, 0, 0, 1 ); /* ydnar 2002-09-21: turning this off for better lightmapping of cliff faces */ + } + + /* ydnar: picomodel: q3map_forceMeta (forces brush faces and/or triangle models to go through the metasurface pipeline) */ + else if( !Q_stricmp( token, "q3map_forceMeta" ) ) + { + si->forceMeta = qtrue; + } + + /* ydnar: gs mods: q3map_shadeAngle */ + else if( !Q_stricmp( token, "q3map_shadeAngle" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->shadeAngleDegrees = atof( token ); + } + + /* ydnar: q3map_textureSize (substitute for q3map_lightimage derivation for terrain) */ + else if( !Q_stricmp( token, "q3map_textureSize" ) ) + { + GetTokenAppend( shaderText, qfalse ); + si->shaderWidth = atoi( token ); + GetTokenAppend( shaderText, qfalse ); + si->shaderHeight = atoi( token ); + } + + /* ydnar: gs mods: q3map_tcGen

10.2 Run the Conversion